Linux Audio

Check our new training course

Embedded Linux training

Mar 31-Apr 8, 2025
Register
Loading...
Note: File does not exist in v3.1.
  1// SPDX-License-Identifier: GPL-2.0-only
  2// Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
  3
  4#include <linux/delay.h>
  5#include <linux/gpio/consumer.h>
  6#include <linux/module.h>
  7#include <linux/of.h>
  8#include <linux/regulator/consumer.h>
  9
 10#include <drm/drm_mipi_dsi.h>
 11#include <drm/drm_modes.h>
 12#include <drm/drm_panel.h>
 13
 14#include <video/mipi_display.h>
 15
 16static const char * const regulator_names[] = {
 17	"vddi",
 18	"avdd",
 19	"avee",
 20};
 21
 22static const unsigned long regulator_enable_loads[] = {
 23	62000,
 24	100000,
 25	100000,
 26};
 27
 28struct panel_desc {
 29	const struct drm_display_mode *display_mode;
 30	u32 width_mm;
 31	u32 height_mm;
 32	unsigned long mode_flags;
 33	enum mipi_dsi_pixel_format format;
 34	unsigned int lanes;
 35	const char *panel_name;
 36	void (*init_sequence)(struct mipi_dsi_multi_context *ctx);
 37};
 38
 39struct nt36672e_panel {
 40	struct drm_panel panel;
 41	struct mipi_dsi_device *dsi;
 42	struct gpio_desc *reset_gpio;
 43	struct regulator_bulk_data supplies[3];
 44	const struct panel_desc *desc;
 45};
 46
 47#define NT36672E_DCS_SWITCH_PAGE	0xff
 48
 49#define nt36672e_switch_page(ctx, page) \
 50	mipi_dsi_dcs_write_seq_multi(ctx, NT36672E_DCS_SWITCH_PAGE, (page))
 51
 52static void nt36672e_enable_reload_cmds(struct mipi_dsi_multi_context *ctx)
 53{
 54	mipi_dsi_dcs_write_seq_multi(ctx, 0xfb, 0x01);
 55}
 56
 57static inline struct nt36672e_panel *to_nt36672e_panel(struct drm_panel *panel)
 58{
 59	return container_of(panel, struct nt36672e_panel, panel);
 60}
 61
 62static void nt36672e_1080x2408_60hz_init(struct mipi_dsi_multi_context *ctx)
 63{
 64	nt36672e_switch_page(ctx, 0x10);
 65	nt36672e_enable_reload_cmds(ctx);
 66	mipi_dsi_dcs_write_seq_multi(ctx, 0xb0, 0x00);
 67	mipi_dsi_dcs_write_seq_multi(ctx, 0xc0, 0x00);
 68	mipi_dsi_dcs_write_seq_multi(ctx, 0xc1, 0x89, 0x28, 0x00, 0x08, 0x00, 0xaa, 0x02,
 69				     0x0e, 0x00, 0x2b, 0x00, 0x07, 0x0d, 0xb7, 0x0c, 0xb7);
 70	mipi_dsi_dcs_write_seq_multi(ctx, 0xc2, 0x1b, 0xa0);
 71
 72	nt36672e_switch_page(ctx, 0x20);
 73	nt36672e_enable_reload_cmds(ctx);
 74	mipi_dsi_dcs_write_seq_multi(ctx, 0x01, 0x66);
 75	mipi_dsi_dcs_write_seq_multi(ctx, 0x06, 0x40);
 76	mipi_dsi_dcs_write_seq_multi(ctx, 0x07, 0x38);
 77	mipi_dsi_dcs_write_seq_multi(ctx, 0x2f, 0x83);
 78	mipi_dsi_dcs_write_seq_multi(ctx, 0x69, 0x91);
 79	mipi_dsi_dcs_write_seq_multi(ctx, 0x95, 0xd1);
 80	mipi_dsi_dcs_write_seq_multi(ctx, 0x96, 0xd1);
 81	mipi_dsi_dcs_write_seq_multi(ctx, 0xf2, 0x64);
 82	mipi_dsi_dcs_write_seq_multi(ctx, 0xf3, 0x54);
 83	mipi_dsi_dcs_write_seq_multi(ctx, 0xf4, 0x64);
 84	mipi_dsi_dcs_write_seq_multi(ctx, 0xf5, 0x54);
 85	mipi_dsi_dcs_write_seq_multi(ctx, 0xf6, 0x64);
 86	mipi_dsi_dcs_write_seq_multi(ctx, 0xf7, 0x54);
 87	mipi_dsi_dcs_write_seq_multi(ctx, 0xf8, 0x64);
 88	mipi_dsi_dcs_write_seq_multi(ctx, 0xf9, 0x54);
 89
 90	nt36672e_switch_page(ctx, 0x24);
 91	nt36672e_enable_reload_cmds(ctx);
 92	mipi_dsi_dcs_write_seq_multi(ctx, 0x01, 0x0f);
 93	mipi_dsi_dcs_write_seq_multi(ctx, 0x03, 0x0c);
 94	mipi_dsi_dcs_write_seq_multi(ctx, 0x05, 0x1d);
 95	mipi_dsi_dcs_write_seq_multi(ctx, 0x08, 0x2f);
 96	mipi_dsi_dcs_write_seq_multi(ctx, 0x09, 0x2e);
 97	mipi_dsi_dcs_write_seq_multi(ctx, 0x0a, 0x2d);
 98	mipi_dsi_dcs_write_seq_multi(ctx, 0x0b, 0x2c);
 99	mipi_dsi_dcs_write_seq_multi(ctx, 0x11, 0x17);
100	mipi_dsi_dcs_write_seq_multi(ctx, 0x12, 0x13);
101	mipi_dsi_dcs_write_seq_multi(ctx, 0x13, 0x15);
102	mipi_dsi_dcs_write_seq_multi(ctx, 0x15, 0x14);
103	mipi_dsi_dcs_write_seq_multi(ctx, 0x16, 0x16);
104	mipi_dsi_dcs_write_seq_multi(ctx, 0x17, 0x18);
105	mipi_dsi_dcs_write_seq_multi(ctx, 0x1b, 0x01);
106	mipi_dsi_dcs_write_seq_multi(ctx, 0x1d, 0x1d);
107	mipi_dsi_dcs_write_seq_multi(ctx, 0x20, 0x2f);
108	mipi_dsi_dcs_write_seq_multi(ctx, 0x21, 0x2e);
109	mipi_dsi_dcs_write_seq_multi(ctx, 0x22, 0x2d);
110	mipi_dsi_dcs_write_seq_multi(ctx, 0x23, 0x2c);
111	mipi_dsi_dcs_write_seq_multi(ctx, 0x29, 0x17);
112	mipi_dsi_dcs_write_seq_multi(ctx, 0x2a, 0x13);
113	mipi_dsi_dcs_write_seq_multi(ctx, 0x2b, 0x15);
114	mipi_dsi_dcs_write_seq_multi(ctx, 0x2f, 0x14);
115	mipi_dsi_dcs_write_seq_multi(ctx, 0x30, 0x16);
116	mipi_dsi_dcs_write_seq_multi(ctx, 0x31, 0x18);
117	mipi_dsi_dcs_write_seq_multi(ctx, 0x32, 0x04);
118	mipi_dsi_dcs_write_seq_multi(ctx, 0x34, 0x10);
119	mipi_dsi_dcs_write_seq_multi(ctx, 0x35, 0x1f);
120	mipi_dsi_dcs_write_seq_multi(ctx, 0x36, 0x1f);
121	mipi_dsi_dcs_write_seq_multi(ctx, 0x4d, 0x14);
122	mipi_dsi_dcs_write_seq_multi(ctx, 0x4e, 0x36);
123	mipi_dsi_dcs_write_seq_multi(ctx, 0x4f, 0x36);
124	mipi_dsi_dcs_write_seq_multi(ctx, 0x53, 0x36);
125	mipi_dsi_dcs_write_seq_multi(ctx, 0x71, 0x30);
126	mipi_dsi_dcs_write_seq_multi(ctx, 0x79, 0x11);
127	mipi_dsi_dcs_write_seq_multi(ctx, 0x7a, 0x82);
128	mipi_dsi_dcs_write_seq_multi(ctx, 0x7b, 0x8f);
129	mipi_dsi_dcs_write_seq_multi(ctx, 0x7d, 0x04);
130	mipi_dsi_dcs_write_seq_multi(ctx, 0x80, 0x04);
131	mipi_dsi_dcs_write_seq_multi(ctx, 0x81, 0x04);
132	mipi_dsi_dcs_write_seq_multi(ctx, 0x82, 0x13);
133	mipi_dsi_dcs_write_seq_multi(ctx, 0x84, 0x31);
134	mipi_dsi_dcs_write_seq_multi(ctx, 0x85, 0x00);
135	mipi_dsi_dcs_write_seq_multi(ctx, 0x86, 0x00);
136	mipi_dsi_dcs_write_seq_multi(ctx, 0x87, 0x00);
137	mipi_dsi_dcs_write_seq_multi(ctx, 0x90, 0x13);
138	mipi_dsi_dcs_write_seq_multi(ctx, 0x92, 0x31);
139	mipi_dsi_dcs_write_seq_multi(ctx, 0x93, 0x00);
140	mipi_dsi_dcs_write_seq_multi(ctx, 0x94, 0x00);
141	mipi_dsi_dcs_write_seq_multi(ctx, 0x95, 0x00);
142	mipi_dsi_dcs_write_seq_multi(ctx, 0x9c, 0xf4);
143	mipi_dsi_dcs_write_seq_multi(ctx, 0x9d, 0x01);
144	mipi_dsi_dcs_write_seq_multi(ctx, 0xa0, 0x0f);
145	mipi_dsi_dcs_write_seq_multi(ctx, 0xa2, 0x0f);
146	mipi_dsi_dcs_write_seq_multi(ctx, 0xa3, 0x02);
147	mipi_dsi_dcs_write_seq_multi(ctx, 0xa4, 0x04);
148	mipi_dsi_dcs_write_seq_multi(ctx, 0xa5, 0x04);
149	mipi_dsi_dcs_write_seq_multi(ctx, 0xc6, 0xc0);
150	mipi_dsi_dcs_write_seq_multi(ctx, 0xc9, 0x00);
151	mipi_dsi_dcs_write_seq_multi(ctx, 0xd9, 0x80);
152	mipi_dsi_dcs_write_seq_multi(ctx, 0xe9, 0x02);
153
154	nt36672e_switch_page(ctx, 0x25);
155	nt36672e_enable_reload_cmds(ctx);
156	mipi_dsi_dcs_write_seq_multi(ctx, 0x18, 0x22);
157	mipi_dsi_dcs_write_seq_multi(ctx, 0x19, 0xe4);
158	mipi_dsi_dcs_write_seq_multi(ctx, 0x21, 0x40);
159	mipi_dsi_dcs_write_seq_multi(ctx, 0x66, 0xd8);
160	mipi_dsi_dcs_write_seq_multi(ctx, 0x68, 0x50);
161	mipi_dsi_dcs_write_seq_multi(ctx, 0x69, 0x10);
162	mipi_dsi_dcs_write_seq_multi(ctx, 0x6b, 0x00);
163	mipi_dsi_dcs_write_seq_multi(ctx, 0x6d, 0x0d);
164	mipi_dsi_dcs_write_seq_multi(ctx, 0x6e, 0x48);
165	mipi_dsi_dcs_write_seq_multi(ctx, 0x72, 0x41);
166	mipi_dsi_dcs_write_seq_multi(ctx, 0x73, 0x4a);
167	mipi_dsi_dcs_write_seq_multi(ctx, 0x74, 0xd0);
168	mipi_dsi_dcs_write_seq_multi(ctx, 0x77, 0x62);
169	mipi_dsi_dcs_write_seq_multi(ctx, 0x79, 0x7e);
170	mipi_dsi_dcs_write_seq_multi(ctx, 0x7d, 0x03);
171	mipi_dsi_dcs_write_seq_multi(ctx, 0x7e, 0x15);
172	mipi_dsi_dcs_write_seq_multi(ctx, 0x7f, 0x00);
173	mipi_dsi_dcs_write_seq_multi(ctx, 0x84, 0x4d);
174	mipi_dsi_dcs_write_seq_multi(ctx, 0xcf, 0x80);
175	mipi_dsi_dcs_write_seq_multi(ctx, 0xd6, 0x80);
176	mipi_dsi_dcs_write_seq_multi(ctx, 0xd7, 0x80);
177	mipi_dsi_dcs_write_seq_multi(ctx, 0xef, 0x20);
178	mipi_dsi_dcs_write_seq_multi(ctx, 0xf0, 0x84);
179
180	nt36672e_switch_page(ctx, 0x26);
181	nt36672e_enable_reload_cmds(ctx);
182	mipi_dsi_dcs_write_seq_multi(ctx, 0x81, 0x0f);
183	mipi_dsi_dcs_write_seq_multi(ctx, 0x83, 0x01);
184	mipi_dsi_dcs_write_seq_multi(ctx, 0x84, 0x03);
185	mipi_dsi_dcs_write_seq_multi(ctx, 0x85, 0x01);
186	mipi_dsi_dcs_write_seq_multi(ctx, 0x86, 0x03);
187	mipi_dsi_dcs_write_seq_multi(ctx, 0x87, 0x01);
188	mipi_dsi_dcs_write_seq_multi(ctx, 0x88, 0x05);
189	mipi_dsi_dcs_write_seq_multi(ctx, 0x8a, 0x1a);
190	mipi_dsi_dcs_write_seq_multi(ctx, 0x8b, 0x11);
191	mipi_dsi_dcs_write_seq_multi(ctx, 0x8c, 0x24);
192	mipi_dsi_dcs_write_seq_multi(ctx, 0x8e, 0x42);
193	mipi_dsi_dcs_write_seq_multi(ctx, 0x8f, 0x11);
194	mipi_dsi_dcs_write_seq_multi(ctx, 0x90, 0x11);
195	mipi_dsi_dcs_write_seq_multi(ctx, 0x91, 0x11);
196	mipi_dsi_dcs_write_seq_multi(ctx, 0x9a, 0x80);
197	mipi_dsi_dcs_write_seq_multi(ctx, 0x9b, 0x04);
198	mipi_dsi_dcs_write_seq_multi(ctx, 0x9c, 0x00);
199	mipi_dsi_dcs_write_seq_multi(ctx, 0x9d, 0x00);
200	mipi_dsi_dcs_write_seq_multi(ctx, 0x9e, 0x00);
201
202	nt36672e_switch_page(ctx, 0x27);
203	nt36672e_enable_reload_cmds(ctx);
204	mipi_dsi_dcs_write_seq_multi(ctx, 0x01, 0x68);
205	mipi_dsi_dcs_write_seq_multi(ctx, 0x20, 0x81);
206	mipi_dsi_dcs_write_seq_multi(ctx, 0x21, 0x6a);
207	mipi_dsi_dcs_write_seq_multi(ctx, 0x25, 0x81);
208	mipi_dsi_dcs_write_seq_multi(ctx, 0x26, 0x94);
209	mipi_dsi_dcs_write_seq_multi(ctx, 0x6e, 0x00);
210	mipi_dsi_dcs_write_seq_multi(ctx, 0x6f, 0x00);
211	mipi_dsi_dcs_write_seq_multi(ctx, 0x70, 0x00);
212	mipi_dsi_dcs_write_seq_multi(ctx, 0x71, 0x00);
213	mipi_dsi_dcs_write_seq_multi(ctx, 0x72, 0x00);
214	mipi_dsi_dcs_write_seq_multi(ctx, 0x75, 0x00);
215	mipi_dsi_dcs_write_seq_multi(ctx, 0x76, 0x00);
216	mipi_dsi_dcs_write_seq_multi(ctx, 0x77, 0x00);
217	mipi_dsi_dcs_write_seq_multi(ctx, 0x7d, 0x09);
218	mipi_dsi_dcs_write_seq_multi(ctx, 0x7e, 0x67);
219	mipi_dsi_dcs_write_seq_multi(ctx, 0x80, 0x23);
220	mipi_dsi_dcs_write_seq_multi(ctx, 0x82, 0x09);
221	mipi_dsi_dcs_write_seq_multi(ctx, 0x83, 0x67);
222	mipi_dsi_dcs_write_seq_multi(ctx, 0x88, 0x01);
223	mipi_dsi_dcs_write_seq_multi(ctx, 0x89, 0x10);
224	mipi_dsi_dcs_write_seq_multi(ctx, 0xa5, 0x10);
225	mipi_dsi_dcs_write_seq_multi(ctx, 0xa6, 0x23);
226	mipi_dsi_dcs_write_seq_multi(ctx, 0xa7, 0x01);
227	mipi_dsi_dcs_write_seq_multi(ctx, 0xb6, 0x40);
228	mipi_dsi_dcs_write_seq_multi(ctx, 0xe5, 0x02);
229	mipi_dsi_dcs_write_seq_multi(ctx, 0xe6, 0xd3);
230	mipi_dsi_dcs_write_seq_multi(ctx, 0xeb, 0x03);
231	mipi_dsi_dcs_write_seq_multi(ctx, 0xec, 0x28);
232
233	nt36672e_switch_page(ctx, 0x2a);
234	nt36672e_enable_reload_cmds(ctx);
235	mipi_dsi_dcs_write_seq_multi(ctx, 0x00, 0x91);
236	mipi_dsi_dcs_write_seq_multi(ctx, 0x03, 0x20);
237	mipi_dsi_dcs_write_seq_multi(ctx, 0x07, 0x50);
238	mipi_dsi_dcs_write_seq_multi(ctx, 0x0a, 0x70);
239	mipi_dsi_dcs_write_seq_multi(ctx, 0x0c, 0x04);
240	mipi_dsi_dcs_write_seq_multi(ctx, 0x0d, 0x40);
241	mipi_dsi_dcs_write_seq_multi(ctx, 0x0f, 0x01);
242	mipi_dsi_dcs_write_seq_multi(ctx, 0x11, 0xe0);
243	mipi_dsi_dcs_write_seq_multi(ctx, 0x15, 0x0f);
244	mipi_dsi_dcs_write_seq_multi(ctx, 0x16, 0xa4);
245	mipi_dsi_dcs_write_seq_multi(ctx, 0x19, 0x0f);
246	mipi_dsi_dcs_write_seq_multi(ctx, 0x1a, 0x78);
247	mipi_dsi_dcs_write_seq_multi(ctx, 0x1b, 0x23);
248	mipi_dsi_dcs_write_seq_multi(ctx, 0x1d, 0x36);
249	mipi_dsi_dcs_write_seq_multi(ctx, 0x1e, 0x3e);
250	mipi_dsi_dcs_write_seq_multi(ctx, 0x1f, 0x3e);
251	mipi_dsi_dcs_write_seq_multi(ctx, 0x20, 0x3e);
252	mipi_dsi_dcs_write_seq_multi(ctx, 0x28, 0xfd);
253	mipi_dsi_dcs_write_seq_multi(ctx, 0x29, 0x12);
254	mipi_dsi_dcs_write_seq_multi(ctx, 0x2a, 0xe1);
255	mipi_dsi_dcs_write_seq_multi(ctx, 0x2d, 0x0a);
256	mipi_dsi_dcs_write_seq_multi(ctx, 0x30, 0x49);
257	mipi_dsi_dcs_write_seq_multi(ctx, 0x33, 0x96);
258	mipi_dsi_dcs_write_seq_multi(ctx, 0x34, 0xff);
259	mipi_dsi_dcs_write_seq_multi(ctx, 0x35, 0x40);
260	mipi_dsi_dcs_write_seq_multi(ctx, 0x36, 0xde);
261	mipi_dsi_dcs_write_seq_multi(ctx, 0x37, 0xf9);
262	mipi_dsi_dcs_write_seq_multi(ctx, 0x38, 0x45);
263	mipi_dsi_dcs_write_seq_multi(ctx, 0x39, 0xd9);
264	mipi_dsi_dcs_write_seq_multi(ctx, 0x3a, 0x49);
265	mipi_dsi_dcs_write_seq_multi(ctx, 0x4a, 0xf0);
266	mipi_dsi_dcs_write_seq_multi(ctx, 0x7a, 0x09);
267	mipi_dsi_dcs_write_seq_multi(ctx, 0x7b, 0x40);
268	mipi_dsi_dcs_write_seq_multi(ctx, 0x7f, 0xf0);
269	mipi_dsi_dcs_write_seq_multi(ctx, 0x83, 0x0f);
270	mipi_dsi_dcs_write_seq_multi(ctx, 0x84, 0xa4);
271	mipi_dsi_dcs_write_seq_multi(ctx, 0x87, 0x0f);
272	mipi_dsi_dcs_write_seq_multi(ctx, 0x88, 0x78);
273	mipi_dsi_dcs_write_seq_multi(ctx, 0x89, 0x23);
274	mipi_dsi_dcs_write_seq_multi(ctx, 0x8b, 0x36);
275	mipi_dsi_dcs_write_seq_multi(ctx, 0x8c, 0x7d);
276	mipi_dsi_dcs_write_seq_multi(ctx, 0x8d, 0x7d);
277	mipi_dsi_dcs_write_seq_multi(ctx, 0x8e, 0x7d);
278
279	nt36672e_switch_page(ctx, 0x20);
280	nt36672e_enable_reload_cmds(ctx);
281	mipi_dsi_dcs_write_seq_multi(ctx, 0xb0, 0x00, 0x00, 0x00, 0x17, 0x00, 0x49, 0x00,
282				     0x6a, 0x00, 0x89, 0x00, 0x9f, 0x00, 0xb6, 0x00, 0xc8);
283	mipi_dsi_dcs_write_seq_multi(ctx, 0xb1, 0x00, 0xd9, 0x01, 0x10, 0x01, 0x3a, 0x01,
284				     0x7a, 0x01, 0xa9, 0x01, 0xf2, 0x02, 0x2d, 0x02, 0x2e);
285	mipi_dsi_dcs_write_seq_multi(ctx, 0xb2, 0x02, 0x64, 0x02, 0xa3, 0x02, 0xca, 0x03,
286				     0x00, 0x03, 0x1e, 0x03, 0x4a, 0x03, 0x59, 0x03, 0x6a);
287	mipi_dsi_dcs_write_seq_multi(ctx, 0xb3, 0x03, 0x7d, 0x03, 0x93, 0x03, 0xab, 0x03,
288				     0xc8, 0x03, 0xec, 0x03, 0xfe, 0x00, 0x00);
289	mipi_dsi_dcs_write_seq_multi(ctx, 0xb4, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x51, 0x00,
290				     0x71, 0x00, 0x90, 0x00, 0xa7, 0x00, 0xbf, 0x00, 0xd1);
291	mipi_dsi_dcs_write_seq_multi(ctx, 0xb5, 0x00, 0xe2, 0x01, 0x1a, 0x01, 0x43, 0x01,
292				     0x83, 0x01, 0xb2, 0x01, 0xfa, 0x02, 0x34, 0x02, 0x36);
293	mipi_dsi_dcs_write_seq_multi(ctx, 0xb6, 0x02, 0x6b, 0x02, 0xa8, 0x02, 0xd0, 0x03,
294				     0x03, 0x03, 0x21, 0x03, 0x4d, 0x03, 0x5b, 0x03, 0x6b);
295	mipi_dsi_dcs_write_seq_multi(ctx, 0xb7, 0x03, 0x7e, 0x03, 0x94, 0x03, 0xac, 0x03,
296				     0xc8, 0x03, 0xec, 0x03, 0xfe, 0x00, 0x00);
297	mipi_dsi_dcs_write_seq_multi(ctx, 0xb8, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x51, 0x00,
298				     0x72, 0x00, 0x92, 0x00, 0xa8, 0x00, 0xbf, 0x00, 0xd1);
299	mipi_dsi_dcs_write_seq_multi(ctx, 0xb9, 0x00, 0xe2, 0x01, 0x18, 0x01, 0x42, 0x01,
300				     0x81, 0x01, 0xaf, 0x01, 0xf5, 0x02, 0x2f, 0x02, 0x31);
301	mipi_dsi_dcs_write_seq_multi(ctx, 0xba, 0x02, 0x68, 0x02, 0xa6, 0x02, 0xcd, 0x03,
302				     0x01, 0x03, 0x1f, 0x03, 0x4a, 0x03, 0x59, 0x03, 0x6a);
303	mipi_dsi_dcs_write_seq_multi(ctx, 0xbb, 0x03, 0x7d, 0x03, 0x93, 0x03, 0xab, 0x03,
304				     0xc8, 0x03, 0xec, 0x03, 0xfe, 0x00, 0x00);
305
306	nt36672e_switch_page(ctx, 0x21);
307	nt36672e_enable_reload_cmds(ctx);
308	mipi_dsi_dcs_write_seq_multi(ctx, 0xb0, 0x00, 0x00, 0x00, 0x17, 0x00, 0x49, 0x00,
309				     0x6a, 0x00, 0x89, 0x00, 0x9f, 0x00, 0xb6, 0x00, 0xc8);
310	mipi_dsi_dcs_write_seq_multi(ctx, 0xb1, 0x00, 0xd9, 0x01, 0x10, 0x01, 0x3a, 0x01,
311				     0x7a, 0x01, 0xa9, 0x01, 0xf2, 0x02, 0x2d, 0x02, 0x2e);
312	mipi_dsi_dcs_write_seq_multi(ctx, 0xb2, 0x02, 0x64, 0x02, 0xa3, 0x02, 0xca, 0x03,
313				     0x00, 0x03, 0x1e, 0x03, 0x4a, 0x03, 0x59, 0x03, 0x6a);
314	mipi_dsi_dcs_write_seq_multi(ctx, 0xb3, 0x03, 0x7d, 0x03, 0x93, 0x03, 0xab, 0x03,
315				     0xc8, 0x03, 0xec, 0x03, 0xfe, 0x00, 0x00);
316	mipi_dsi_dcs_write_seq_multi(ctx, 0xb4, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x51, 0x00,
317				     0x71, 0x00, 0x90, 0x00, 0xa7, 0x00, 0xbf, 0x00, 0xd1);
318	mipi_dsi_dcs_write_seq_multi(ctx, 0xb5, 0x00, 0xe2, 0x01, 0x1a, 0x01, 0x43, 0x01,
319				     0x83, 0x01, 0xb2, 0x01, 0xfa, 0x02, 0x34, 0x02, 0x36);
320	mipi_dsi_dcs_write_seq_multi(ctx, 0xb6, 0x02, 0x6b, 0x02, 0xa8, 0x02, 0xd0, 0x03,
321				     0x03, 0x03, 0x21, 0x03, 0x4d, 0x03, 0x5b, 0x03, 0x6b);
322	mipi_dsi_dcs_write_seq_multi(ctx, 0xb7, 0x03, 0x7e, 0x03, 0x94, 0x03, 0xac, 0x03,
323				     0xc8, 0x03, 0xec, 0x03, 0xfe, 0x00, 0x00);
324	mipi_dsi_dcs_write_seq_multi(ctx, 0xb8, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x51, 0x00,
325				     0x72, 0x00, 0x92, 0x00, 0xa8, 0x00, 0xbf, 0x00, 0xd1);
326	mipi_dsi_dcs_write_seq_multi(ctx, 0xb9, 0x00, 0xe2, 0x01, 0x18, 0x01, 0x42, 0x01,
327				     0x81, 0x01, 0xaf, 0x01, 0xf5, 0x02, 0x2f, 0x02, 0x31);
328	mipi_dsi_dcs_write_seq_multi(ctx, 0xba, 0x02, 0x68, 0x02, 0xa6, 0x02, 0xcd, 0x03,
329				     0x01, 0x03, 0x1f, 0x03, 0x4a, 0x03, 0x59, 0x03, 0x6a);
330	mipi_dsi_dcs_write_seq_multi(ctx, 0xbb, 0x03, 0x7d, 0x03, 0x93, 0x03, 0xab, 0x03,
331				     0xc8, 0x03, 0xec, 0x03, 0xfe, 0x00, 0x00);
332
333	nt36672e_switch_page(ctx, 0x2c);
334	nt36672e_enable_reload_cmds(ctx);
335	mipi_dsi_dcs_write_seq_multi(ctx, 0x61, 0x1f);
336	mipi_dsi_dcs_write_seq_multi(ctx, 0x62, 0x1f);
337	mipi_dsi_dcs_write_seq_multi(ctx, 0x7e, 0x03);
338	mipi_dsi_dcs_write_seq_multi(ctx, 0x6a, 0x14);
339	mipi_dsi_dcs_write_seq_multi(ctx, 0x6b, 0x36);
340	mipi_dsi_dcs_write_seq_multi(ctx, 0x6c, 0x36);
341	mipi_dsi_dcs_write_seq_multi(ctx, 0x6d, 0x36);
342	mipi_dsi_dcs_write_seq_multi(ctx, 0x53, 0x04);
343	mipi_dsi_dcs_write_seq_multi(ctx, 0x54, 0x04);
344	mipi_dsi_dcs_write_seq_multi(ctx, 0x55, 0x04);
345	mipi_dsi_dcs_write_seq_multi(ctx, 0x56, 0x0f);
346	mipi_dsi_dcs_write_seq_multi(ctx, 0x58, 0x0f);
347	mipi_dsi_dcs_write_seq_multi(ctx, 0x59, 0x0f);
348
349	nt36672e_switch_page(ctx, 0xf0);
350	nt36672e_enable_reload_cmds(ctx);
351	mipi_dsi_dcs_write_seq_multi(ctx, 0x5a, 0x00);
352
353	nt36672e_switch_page(ctx, 0x10);
354	nt36672e_enable_reload_cmds(ctx);
355	mipi_dsi_dcs_write_seq_multi(ctx, 0x51, 0xff);
356	mipi_dsi_dcs_write_seq_multi(ctx, 0x53, 0x24);
357	mipi_dsi_dcs_write_seq_multi(ctx, 0x55, 0x01);
358}
359
360static int nt36672e_power_on(struct nt36672e_panel *ctx)
361{
362	struct mipi_dsi_device *dsi = ctx->dsi;
363	int ret;
364
365	ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
366	if (ret < 0) {
367		dev_err(&dsi->dev, "regulator bulk enable failed: %d\n", ret);
368		return ret;
369	}
370
371	/*
372	 * Reset sequence of nt36672e panel requires the panel to be out of reset
373	 * for 10ms, followed by being held in reset for 10ms and then out again.
374	 */
375	gpiod_set_value(ctx->reset_gpio, 1);
376	usleep_range(10000, 20000);
377	gpiod_set_value(ctx->reset_gpio, 0);
378	usleep_range(10000, 20000);
379	gpiod_set_value(ctx->reset_gpio, 1);
380	usleep_range(10000, 20000);
381
382	return 0;
383}
384
385static int nt36672e_power_off(struct nt36672e_panel *ctx)
386{
387	struct mipi_dsi_device *dsi = ctx->dsi;
388	int ret = 0;
389
390	gpiod_set_value(ctx->reset_gpio, 0);
391
392	ret = regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
393	if (ret)
394		dev_err(&dsi->dev, "regulator bulk disable failed: %d\n", ret);
395
396	return ret;
397}
398
399static int nt36672e_on(struct nt36672e_panel *nt36672e)
400{
401	struct mipi_dsi_multi_context ctx = { .dsi = nt36672e->dsi };
402	const struct panel_desc *desc = nt36672e->desc;
403
404	nt36672e->dsi->mode_flags |= MIPI_DSI_MODE_LPM;
405
406	if (desc->init_sequence)
407		desc->init_sequence(&ctx);
408
409	mipi_dsi_dcs_exit_sleep_mode_multi(&ctx);
410	mipi_dsi_msleep(&ctx, 120);
411
412	mipi_dsi_dcs_set_display_on_multi(&ctx);
413
414	mipi_dsi_msleep(&ctx, 100);
415
416	return ctx.accum_err;
417}
418
419static int nt36672e_off(struct nt36672e_panel *panel)
420{
421	struct mipi_dsi_multi_context ctx = { .dsi = panel->dsi };
422
423	panel->dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
424
425	mipi_dsi_dcs_set_display_off_multi(&ctx);
426	mipi_dsi_msleep(&ctx, 20);
427
428	mipi_dsi_dcs_enter_sleep_mode_multi(&ctx);
429	mipi_dsi_msleep(&ctx, 60);
430
431	return ctx.accum_err;
432}
433
434static int nt36672e_panel_prepare(struct drm_panel *panel)
435{
436	struct nt36672e_panel *ctx = to_nt36672e_panel(panel);
437	struct mipi_dsi_device *dsi = ctx->dsi;
438	int ret;
439
440	ret = nt36672e_power_on(ctx);
441	if (ret < 0)
442		return ret;
443
444	ret = nt36672e_on(ctx);
445	if (ret < 0) {
446		if (nt36672e_power_off(ctx))
447			dev_err(&dsi->dev, "power off failed\n");
448		return ret;
449	}
450
451	return 0;
452}
453
454static int nt36672e_panel_unprepare(struct drm_panel *panel)
455{
456	struct nt36672e_panel *ctx = to_nt36672e_panel(panel);
457	struct mipi_dsi_device *dsi = ctx->dsi;
458	int ret;
459
460	nt36672e_off(ctx);
461
462	ret = nt36672e_power_off(ctx);
463	if (ret < 0)
464		dev_err(&dsi->dev, "power off failed: %d\n", ret);
465
466	return 0;
467}
468
469static const struct drm_display_mode nt36672e_1080x2408_60hz = {
470	.name = "1080x2408",
471	.clock = 181690,
472	.hdisplay = 1080,
473	.hsync_start = 1080 + 76,
474	.hsync_end = 1080 + 76 + 12,
475	.htotal = 1080 + 76 + 12 + 56,
476	.vdisplay = 2408,
477	.vsync_start = 2408 + 46,
478	.vsync_end = 2408 + 46 + 10,
479	.vtotal = 2408 + 46 + 10 + 10,
480	.flags = 0,
481};
482
483static const struct panel_desc nt36672e_panel_desc = {
484	.display_mode = &nt36672e_1080x2408_60hz,
485	.width_mm = 74,
486	.height_mm = 131,
487	.mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_LPM | MIPI_DSI_CLOCK_NON_CONTINUOUS,
488	.format = MIPI_DSI_FMT_RGB888,
489	.lanes = 4,
490	.panel_name = "nt36672e fhd plus panel",
491	.init_sequence = nt36672e_1080x2408_60hz_init,
492};
493
494static int nt36672e_panel_get_modes(struct drm_panel *panel, struct drm_connector *connector)
495{
496	struct nt36672e_panel *ctx = to_nt36672e_panel(panel);
497	struct drm_display_mode *mode;
498
499	mode = drm_mode_duplicate(connector->dev, ctx->desc->display_mode);
500	if (!mode)
501		return -ENOMEM;
502
503	drm_mode_set_name(mode);
504
505	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
506	connector->display_info.width_mm = ctx->desc->width_mm;
507	connector->display_info.height_mm = ctx->desc->height_mm;
508	drm_mode_probed_add(connector, mode);
509
510	return 1;
511}
512
513static const struct drm_panel_funcs nt36672e_drm_funcs = {
514	.prepare = nt36672e_panel_prepare,
515	.unprepare = nt36672e_panel_unprepare,
516	.get_modes = nt36672e_panel_get_modes,
517};
518
519static int nt36672e_panel_probe(struct mipi_dsi_device *dsi)
520{
521	struct device *dev = &dsi->dev;
522	struct nt36672e_panel *ctx;
523	int i, ret = 0;
524
525	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
526	if (!ctx)
527		return -ENOMEM;
528
529	ctx->desc = of_device_get_match_data(dev);
530	if (!ctx->desc) {
531		dev_err(dev, "missing device configuration\n");
532		return -ENODEV;
533	}
534
535	for (i = 0; i < ARRAY_SIZE(ctx->supplies); i++) {
536		ctx->supplies[i].supply = regulator_names[i];
537		ctx->supplies[i].init_load_uA = regulator_enable_loads[i];
538	}
539
540	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies),
541			ctx->supplies);
542	if (ret < 0)
543		return ret;
544
545	ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
546	if (IS_ERR(ctx->reset_gpio))
547		return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), "Failed to get reset-gpios\n");
548
549	ctx->dsi = dsi;
550	mipi_dsi_set_drvdata(dsi, ctx);
551
552	dsi->lanes = ctx->desc->lanes;
553	dsi->format = ctx->desc->format;
554	dsi->mode_flags = ctx->desc->mode_flags;
555
556	drm_panel_init(&ctx->panel, dev, &nt36672e_drm_funcs, DRM_MODE_CONNECTOR_DSI);
557
558	ret = drm_panel_of_backlight(&ctx->panel);
559	if (ret)
560		return dev_err_probe(dev, ret, "Failed to get backlight\n");
561
562	ctx->panel.prepare_prev_first = true;
563
564	drm_panel_add(&ctx->panel);
565
566	ret = mipi_dsi_attach(dsi);
567	if (ret < 0) {
568		dev_err(dev, "Failed to attach to DSI host: %d\n", ret);
569		goto err_dsi_attach;
570	}
571
572	return 0;
573
574err_dsi_attach:
575	drm_panel_remove(&ctx->panel);
576	return ret;
577}
578
579static void nt36672e_panel_remove(struct mipi_dsi_device *dsi)
580{
581	struct nt36672e_panel *ctx = mipi_dsi_get_drvdata(dsi);
582
583	mipi_dsi_detach(ctx->dsi);
584	drm_panel_remove(&ctx->panel);
585}
586
587static const struct of_device_id nt36672e_of_match[] = {
588	{
589		.compatible = "novatek,nt36672e",
590		.data = &nt36672e_panel_desc,
591	},
592	{ }
593};
594MODULE_DEVICE_TABLE(of, nt36672e_of_match);
595
596static struct mipi_dsi_driver nt36672e_panel_driver = {
597	.driver = {
598		.name = "panel-novatek-nt36672e",
599		.of_match_table = nt36672e_of_match,
600	},
601	.probe = nt36672e_panel_probe,
602	.remove = nt36672e_panel_remove,
603};
604module_mipi_dsi_driver(nt36672e_panel_driver);
605
606MODULE_AUTHOR("Ritesh Kumar <quic_riteshk@quicinc.com>");
607MODULE_DESCRIPTION("Novatek NT36672E DSI Panel Driver");
608MODULE_LICENSE("GPL");