xref: /linux/drivers/gpu/drm/panel/panel-sitronix-st7703.c (revision a23e1966932464e1c5226cb9ac4ce1d5fc10ba22)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Driver for panels based on Sitronix ST7703 controller, souch as:
4  *
5  * - Rocktech jh057n00900 5.5" MIPI-DSI panel
6  *
7  * Copyright (C) Purism SPC 2019
8  */
9 
10 #include <linux/debugfs.h>
11 #include <linux/delay.h>
12 #include <linux/gpio/consumer.h>
13 #include <linux/media-bus-format.h>
14 #include <linux/mod_devicetable.h>
15 #include <linux/module.h>
16 #include <linux/of.h>
17 #include <linux/regulator/consumer.h>
18 
19 #include <video/display_timing.h>
20 #include <video/mipi_display.h>
21 
22 #include <drm/drm_mipi_dsi.h>
23 #include <drm/drm_modes.h>
24 #include <drm/drm_panel.h>
25 
26 #define DRV_NAME "panel-sitronix-st7703"
27 
28 /* Manufacturer specific Commands send via DSI */
29 #define ST7703_CMD_ALL_PIXEL_OFF 0x22
30 #define ST7703_CMD_ALL_PIXEL_ON	 0x23
31 #define ST7703_CMD_SETAPID	 0xB1
32 #define ST7703_CMD_SETDISP	 0xB2
33 #define ST7703_CMD_SETRGBIF	 0xB3
34 #define ST7703_CMD_SETCYC	 0xB4
35 #define ST7703_CMD_SETBGP	 0xB5
36 #define ST7703_CMD_SETVCOM	 0xB6
37 #define ST7703_CMD_SETOTP	 0xB7
38 #define ST7703_CMD_SETPOWER_EXT	 0xB8
39 #define ST7703_CMD_SETEXTC	 0xB9
40 #define ST7703_CMD_SETMIPI	 0xBA
41 #define ST7703_CMD_SETVDC	 0xBC
42 #define ST7703_CMD_UNKNOWN_BF	 0xBF
43 #define ST7703_CMD_SETSCR	 0xC0
44 #define ST7703_CMD_SETPOWER	 0xC1
45 #define ST7703_CMD_SETECO	 0xC6
46 #define ST7703_CMD_SETIO	 0xC7
47 #define ST7703_CMD_SETCABC	 0xC8
48 #define ST7703_CMD_SETPANEL	 0xCC
49 #define ST7703_CMD_SETGAMMA	 0xE0
50 #define ST7703_CMD_SETEQ	 0xE3
51 #define ST7703_CMD_SETGIP1	 0xE9
52 #define ST7703_CMD_SETGIP2	 0xEA
53 #define ST7703_CMD_UNKNOWN_EF	 0xEF
54 
55 struct st7703 {
56 	struct device *dev;
57 	struct drm_panel panel;
58 	struct gpio_desc *reset_gpio;
59 	struct regulator *vcc;
60 	struct regulator *iovcc;
61 	bool prepared;
62 
63 	struct dentry *debugfs;
64 	const struct st7703_panel_desc *desc;
65 	enum drm_panel_orientation orientation;
66 };
67 
68 struct st7703_panel_desc {
69 	const struct drm_display_mode *mode;
70 	unsigned int lanes;
71 	unsigned long mode_flags;
72 	enum mipi_dsi_pixel_format format;
73 	int (*init_sequence)(struct st7703 *ctx);
74 };
75 
76 static inline struct st7703 *panel_to_st7703(struct drm_panel *panel)
77 {
78 	return container_of(panel, struct st7703, panel);
79 }
80 
81 static int jh057n_init_sequence(struct st7703 *ctx)
82 {
83 	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
84 
85 	/*
86 	 * Init sequence was supplied by the panel vendor. Most of the commands
87 	 * resemble the ST7703 but the number of parameters often don't match
88 	 * so it's likely a clone.
89 	 */
90 	mipi_dsi_generic_write_seq(dsi, ST7703_CMD_SETEXTC,
91 				   0xF1, 0x12, 0x83);
92 	mipi_dsi_generic_write_seq(dsi, ST7703_CMD_SETRGBIF,
93 				   0x10, 0x10, 0x05, 0x05, 0x03, 0xFF, 0x00, 0x00,
94 				   0x00, 0x00);
95 	mipi_dsi_generic_write_seq(dsi, ST7703_CMD_SETSCR,
96 				   0x73, 0x73, 0x50, 0x50, 0x00, 0x00, 0x08, 0x70,
97 				   0x00);
98 	mipi_dsi_generic_write_seq(dsi, ST7703_CMD_SETVDC, 0x4E);
99 	mipi_dsi_generic_write_seq(dsi, ST7703_CMD_SETPANEL, 0x0B);
100 	mipi_dsi_generic_write_seq(dsi, ST7703_CMD_SETCYC, 0x80);
101 	mipi_dsi_generic_write_seq(dsi, ST7703_CMD_SETDISP, 0xF0, 0x12, 0x30);
102 	mipi_dsi_generic_write_seq(dsi, ST7703_CMD_SETEQ,
103 				   0x07, 0x07, 0x0B, 0x0B, 0x03, 0x0B, 0x00, 0x00,
104 				   0x00, 0x00, 0xFF, 0x00, 0xC0, 0x10);
105 	mipi_dsi_generic_write_seq(dsi, ST7703_CMD_SETBGP, 0x08, 0x08);
106 	msleep(20);
107 
108 	mipi_dsi_generic_write_seq(dsi, ST7703_CMD_SETVCOM, 0x3F, 0x3F);
109 	mipi_dsi_generic_write_seq(dsi, ST7703_CMD_UNKNOWN_BF, 0x02, 0x11, 0x00);
110 	mipi_dsi_generic_write_seq(dsi, ST7703_CMD_SETGIP1,
111 				   0x82, 0x10, 0x06, 0x05, 0x9E, 0x0A, 0xA5, 0x12,
112 				   0x31, 0x23, 0x37, 0x83, 0x04, 0xBC, 0x27, 0x38,
113 				   0x0C, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0C, 0x00,
114 				   0x03, 0x00, 0x00, 0x00, 0x75, 0x75, 0x31, 0x88,
115 				   0x88, 0x88, 0x88, 0x88, 0x88, 0x13, 0x88, 0x64,
116 				   0x64, 0x20, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
117 				   0x02, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
118 				   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
119 	mipi_dsi_generic_write_seq(dsi, ST7703_CMD_SETGIP2,
120 				   0x02, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
121 				   0x00, 0x00, 0x00, 0x00, 0x02, 0x46, 0x02, 0x88,
122 				   0x88, 0x88, 0x88, 0x88, 0x88, 0x64, 0x88, 0x13,
123 				   0x57, 0x13, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
124 				   0x75, 0x88, 0x23, 0x14, 0x00, 0x00, 0x02, 0x00,
125 				   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
126 				   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x0A,
127 				   0xA5, 0x00, 0x00, 0x00, 0x00);
128 	mipi_dsi_generic_write_seq(dsi, ST7703_CMD_SETGAMMA,
129 				   0x00, 0x09, 0x0E, 0x29, 0x2D, 0x3C, 0x41, 0x37,
130 				   0x07, 0x0B, 0x0D, 0x10, 0x11, 0x0F, 0x10, 0x11,
131 				   0x18, 0x00, 0x09, 0x0E, 0x29, 0x2D, 0x3C, 0x41,
132 				   0x37, 0x07, 0x0B, 0x0D, 0x10, 0x11, 0x0F, 0x10,
133 				   0x11, 0x18);
134 	msleep(20);
135 
136 	return 0;
137 }
138 
139 static const struct drm_display_mode jh057n00900_mode = {
140 	.hdisplay    = 720,
141 	.hsync_start = 720 + 90,
142 	.hsync_end   = 720 + 90 + 20,
143 	.htotal	     = 720 + 90 + 20 + 20,
144 	.vdisplay    = 1440,
145 	.vsync_start = 1440 + 20,
146 	.vsync_end   = 1440 + 20 + 4,
147 	.vtotal	     = 1440 + 20 + 4 + 12,
148 	.clock	     = 75276,
149 	.flags	     = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
150 	.width_mm    = 65,
151 	.height_mm   = 130,
152 };
153 
154 static const struct st7703_panel_desc jh057n00900_panel_desc = {
155 	.mode = &jh057n00900_mode,
156 	.lanes = 4,
157 	.mode_flags = MIPI_DSI_MODE_VIDEO |
158 		MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_VIDEO_SYNC_PULSE,
159 	.format = MIPI_DSI_FMT_RGB888,
160 	.init_sequence = jh057n_init_sequence,
161 };
162 
163 static int xbd599_init_sequence(struct st7703 *ctx)
164 {
165 	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
166 
167 	/*
168 	 * Init sequence was supplied by the panel vendor.
169 	 */
170 
171 	/* Magic sequence to unlock user commands below. */
172 	mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETEXTC, 0xF1, 0x12, 0x83);
173 
174 	mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETMIPI,
175 			       0x33, /* VC_main = 0, Lane_Number = 3 (4 lanes) */
176 			       0x81, /* DSI_LDO_SEL = 1.7V, RTERM = 90 Ohm */
177 			       0x05, /* IHSRX = x6 (Low High Speed driving ability) */
178 			       0xF9, /* TX_CLK_SEL = fDSICLK/16 */
179 			       0x0E, /* HFP_OSC (min. HFP number in DSI mode) */
180 			       0x0E, /* HBP_OSC (min. HBP number in DSI mode) */
181 			       /* The rest is undocumented in ST7703 datasheet */
182 			       0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
183 			       0x44, 0x25, 0x00, 0x91, 0x0a, 0x00, 0x00, 0x02,
184 			       0x4F, 0x11, 0x00, 0x00, 0x37);
185 
186 	mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETPOWER_EXT,
187 			       0x25, /* PCCS = 2, ECP_DC_DIV = 1/4 HSYNC */
188 			       0x22, /* DT = 15ms XDK_ECP = x2 */
189 			       0x20, /* PFM_DC_DIV = /1 */
190 			       0x03  /* ECP_SYNC_EN = 1, VGX_SYNC_EN = 1 */);
191 
192 	/* RGB I/F porch timing */
193 	mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETRGBIF,
194 			       0x10, /* VBP_RGB_GEN */
195 			       0x10, /* VFP_RGB_GEN */
196 			       0x05, /* DE_BP_RGB_GEN */
197 			       0x05, /* DE_FP_RGB_GEN */
198 			       /* The rest is undocumented in ST7703 datasheet */
199 			       0x03, 0xFF,
200 			       0x00, 0x00,
201 			       0x00, 0x00);
202 
203 	/* Source driving settings. */
204 	mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETSCR,
205 			       0x73, /* N_POPON */
206 			       0x73, /* N_NOPON */
207 			       0x50, /* I_POPON */
208 			       0x50, /* I_NOPON */
209 			       0x00, /* SCR[31,24] */
210 			       0xC0, /* SCR[23,16] */
211 			       0x08, /* SCR[15,8] */
212 			       0x70, /* SCR[7,0] */
213 			       0x00  /* Undocumented */);
214 
215 	/* NVDDD_SEL = -1.8V, VDDD_SEL = out of range (possibly 1.9V?) */
216 	mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETVDC, 0x4E);
217 
218 	/*
219 	 * SS_PANEL = 1 (reverse scan), GS_PANEL = 0 (normal scan)
220 	 * REV_PANEL = 1 (normally black panel), BGR_PANEL = 1 (BGR)
221 	 */
222 	mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETPANEL, 0x0B);
223 
224 	/* Zig-Zag Type C column inversion. */
225 	mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETCYC, 0x80);
226 
227 	/* Set display resolution. */
228 	mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETDISP,
229 			       0xF0, /* NL = 240 */
230 			       0x12, /* RES_V_LSB = 0, BLK_CON = VSSD,
231 				      * RESO_SEL = 720RGB
232 				      */
233 			       0xF0  /* WHITE_GND_EN = 1 (GND),
234 				      * WHITE_FRAME_SEL = 7 frames,
235 				      * ISC = 0 frames
236 				      */);
237 
238 	mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETEQ,
239 			       0x00, /* PNOEQ */
240 			       0x00, /* NNOEQ */
241 			       0x0B, /* PEQGND */
242 			       0x0B, /* NEQGND */
243 			       0x10, /* PEQVCI */
244 			       0x10, /* NEQVCI */
245 			       0x00, /* PEQVCI1 */
246 			       0x00, /* NEQVCI1 */
247 			       0x00, /* reserved */
248 			       0x00, /* reserved */
249 			       0xFF, /* reserved */
250 			       0x00, /* reserved */
251 			       0xC0, /* ESD_DET_DATA_WHITE = 1, ESD_WHITE_EN = 1 */
252 			       0x10  /* SLPIN_OPTION = 1 (no need vsync after sleep-in)
253 				      * VEDIO_NO_CHECK_EN = 0
254 				      * ESD_WHITE_GND_EN = 0
255 				      * ESD_DET_TIME_SEL = 0 frames
256 				      */);
257 
258 	mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETECO, 0x01, 0x00, 0xFF, 0xFF, 0x00);
259 
260 	mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETPOWER,
261 			       0x74, /* VBTHS, VBTLS: VGH = 17V, VBL = -11V */
262 			       0x00, /* FBOFF_VGH = 0, FBOFF_VGL = 0 */
263 			       0x32, /* VRP  */
264 			       0x32, /* VRN */
265 			       0x77, /* reserved */
266 			       0xF1, /* APS = 1 (small),
267 				      * VGL_DET_EN = 1, VGH_DET_EN = 1,
268 				      * VGL_TURBO = 1, VGH_TURBO = 1
269 				      */
270 			       0xFF, /* VGH1_L_DIV, VGL1_L_DIV (1.5MHz) */
271 			       0xFF, /* VGH1_R_DIV, VGL1_R_DIV (1.5MHz) */
272 			       0xCC, /* VGH2_L_DIV, VGL2_L_DIV (2.6MHz) */
273 			       0xCC, /* VGH2_R_DIV, VGL2_R_DIV (2.6MHz) */
274 			       0x77, /* VGH3_L_DIV, VGL3_L_DIV (4.5MHz) */
275 			       0x77  /* VGH3_R_DIV, VGL3_R_DIV (4.5MHz) */);
276 
277 	/* Reference voltage. */
278 	mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETBGP,
279 			       0x07, /* VREF_SEL = 4.2V */
280 			       0x07  /* NVREF_SEL = 4.2V */);
281 
282 	mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETVCOM,
283 			       0x2C, /* VCOMDC_F = -0.67V */
284 			       0x2C  /* VCOMDC_B = -0.67V */);
285 
286 	/* Undocumented command. */
287 	mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_UNKNOWN_BF, 0x02, 0x11, 0x00);
288 
289 	/* This command is to set forward GIP timing. */
290 	mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETGIP1,
291 			       0x82, 0x10, 0x06, 0x05, 0xA2, 0x0A, 0xA5, 0x12,
292 			       0x31, 0x23, 0x37, 0x83, 0x04, 0xBC, 0x27, 0x38,
293 			       0x0C, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0C, 0x00,
294 			       0x03, 0x00, 0x00, 0x00, 0x75, 0x75, 0x31, 0x88,
295 			       0x88, 0x88, 0x88, 0x88, 0x88, 0x13, 0x88, 0x64,
296 			       0x64, 0x20, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
297 			       0x02, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
298 			       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
299 
300 	/* This command is to set backward GIP timing. */
301 	mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETGIP2,
302 			       0x02, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
303 			       0x00, 0x00, 0x00, 0x00, 0x02, 0x46, 0x02, 0x88,
304 			       0x88, 0x88, 0x88, 0x88, 0x88, 0x64, 0x88, 0x13,
305 			       0x57, 0x13, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
306 			       0x75, 0x88, 0x23, 0x14, 0x00, 0x00, 0x02, 0x00,
307 			       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
308 			       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0A,
309 			       0xA5, 0x00, 0x00, 0x00, 0x00);
310 
311 	/* Adjust the gamma characteristics of the panel. */
312 	mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETGAMMA,
313 			       0x00, 0x09, 0x0D, 0x23, 0x27, 0x3C, 0x41, 0x35,
314 			       0x07, 0x0D, 0x0E, 0x12, 0x13, 0x10, 0x12, 0x12,
315 			       0x18, 0x00, 0x09, 0x0D, 0x23, 0x27, 0x3C, 0x41,
316 			       0x35, 0x07, 0x0D, 0x0E, 0x12, 0x13, 0x10, 0x12,
317 			       0x12, 0x18);
318 
319 	return 0;
320 }
321 
322 static const struct drm_display_mode xbd599_mode = {
323 	.hdisplay    = 720,
324 	.hsync_start = 720 + 40,
325 	.hsync_end   = 720 + 40 + 40,
326 	.htotal	     = 720 + 40 + 40 + 40,
327 	.vdisplay    = 1440,
328 	.vsync_start = 1440 + 18,
329 	.vsync_end   = 1440 + 18 + 10,
330 	.vtotal	     = 1440 + 18 + 10 + 17,
331 	.clock	     = 69000,
332 	.flags	     = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
333 	.width_mm    = 68,
334 	.height_mm   = 136,
335 };
336 
337 static const struct st7703_panel_desc xbd599_desc = {
338 	.mode = &xbd599_mode,
339 	.lanes = 4,
340 	.mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE,
341 	.format = MIPI_DSI_FMT_RGB888,
342 	.init_sequence = xbd599_init_sequence,
343 };
344 
345 static int rg353v2_init_sequence(struct st7703 *ctx)
346 {
347 	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
348 
349 	/*
350 	 * Init sequence was supplied by the panel vendor.
351 	 */
352 
353 	mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETEXTC, 0xf1, 0x12, 0x83);
354 	mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETAPID, 0x00, 0x00, 0x00,
355 			       0xda, 0x80);
356 	mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETDISP, 0x00, 0x13, 0x70);
357 	mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETRGBIF, 0x10, 0x10, 0x28,
358 			       0x28, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00);
359 	mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETCYC, 0x80);
360 	mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETBGP, 0x0a, 0x0a);
361 	mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETVCOM, 0x92, 0x92);
362 	mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETPOWER_EXT, 0x25, 0x22,
363 			       0xf0, 0x63);
364 	mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETMIPI, 0x33, 0x81, 0x05,
365 			       0xf9, 0x0e, 0x0e, 0x20, 0x00, 0x00, 0x00, 0x00,
366 			       0x00, 0x00, 0x00, 0x44, 0x25, 0x00, 0x90, 0x0a,
367 			       0x00, 0x00, 0x01, 0x4f, 0x01, 0x00, 0x00, 0x37);
368 	mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETVDC, 0x47);
369 	mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_UNKNOWN_BF, 0x02, 0x11, 0x00);
370 	mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETSCR, 0x73, 0x73, 0x50, 0x50,
371 			       0x00, 0x00, 0x12, 0x50, 0x00);
372 	mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETPOWER, 0x53, 0xc0, 0x32,
373 			       0x32, 0x77, 0xe1, 0xdd, 0xdd, 0x77, 0x77, 0x33,
374 			       0x33);
375 	mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETECO, 0x82, 0x00, 0xbf, 0xff,
376 			       0x00, 0xff);
377 	mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETIO, 0xb8, 0x00, 0x0a, 0x00,
378 			       0x00, 0x00);
379 	mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETCABC, 0x10, 0x40, 0x1e,
380 			       0x02);
381 	mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETPANEL, 0x0b);
382 	mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETGAMMA, 0x00, 0x07, 0x0d,
383 			       0x37, 0x35, 0x3f, 0x41, 0x44, 0x06, 0x0c, 0x0d,
384 			       0x0f, 0x11, 0x10, 0x12, 0x14, 0x1a, 0x00, 0x07,
385 			       0x0d, 0x37, 0x35, 0x3f, 0x41, 0x44, 0x06, 0x0c,
386 			       0x0d, 0x0f, 0x11, 0x10, 0x12, 0x14, 0x1a);
387 	mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETEQ, 0x07, 0x07, 0x0b, 0x0b,
388 			       0x0b, 0x0b, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
389 			       0xc0, 0x10);
390 	mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETGIP1, 0xc8, 0x10, 0x02, 0x00,
391 			       0x00, 0xb0, 0xb1, 0x11, 0x31, 0x23, 0x28, 0x80,
392 			       0xb0, 0xb1, 0x27, 0x08, 0x00, 0x04, 0x02, 0x00,
393 			       0x00, 0x00, 0x00, 0x04, 0x02, 0x00, 0x00, 0x00,
394 			       0x88, 0x88, 0xba, 0x60, 0x24, 0x08, 0x88, 0x88,
395 			       0x88, 0x88, 0x88, 0x88, 0x88, 0xba, 0x71, 0x35,
396 			       0x18, 0x88, 0x88, 0x88, 0x88, 0x88, 0x00, 0x00,
397 			       0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
398 			       0x00, 0x00, 0x00);
399 	mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETGIP2, 0x97, 0x0a, 0x82, 0x02,
400 			       0x03, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
401 			       0x81, 0x88, 0xba, 0x17, 0x53, 0x88, 0x88, 0x88,
402 			       0x88, 0x88, 0x88, 0x80, 0x88, 0xba, 0x06, 0x42,
403 			       0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x23, 0x00,
404 			       0x00, 0x02, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
405 			       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
406 			       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
407 			       0x00);
408 	mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_UNKNOWN_EF, 0xff, 0xff, 0x01);
409 
410 	return 0;
411 }
412 
413 static const struct drm_display_mode rg353v2_mode = {
414 	.hdisplay	= 640,
415 	.hsync_start	= 640 + 40,
416 	.hsync_end	= 640 + 40 + 2,
417 	.htotal		= 640 + 40 + 2 + 80,
418 	.vdisplay	= 480,
419 	.vsync_start	= 480 + 18,
420 	.vsync_end	= 480 + 18 + 2,
421 	.vtotal		= 480 + 18 + 2 + 28,
422 	.clock		= 24150,
423 	.flags		= DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
424 	.width_mm	= 70,
425 	.height_mm	= 57,
426 };
427 
428 static const struct st7703_panel_desc rg353v2_desc = {
429 	.mode = &rg353v2_mode,
430 	.lanes = 4,
431 	.mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
432 		      MIPI_DSI_MODE_NO_EOT_PACKET | MIPI_DSI_MODE_LPM,
433 	.format = MIPI_DSI_FMT_RGB888,
434 	.init_sequence = rg353v2_init_sequence,
435 };
436 
437 static int rgb30panel_init_sequence(struct st7703 *ctx)
438 {
439 	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
440 
441 	/* Init sequence extracted from Powkiddy RGB30 BSP kernel. */
442 
443 	/*
444 	 * For some reason this specific panel must be taken out of sleep
445 	 * before the full init sequence, or else it will not display.
446 	 */
447 	mipi_dsi_dcs_exit_sleep_mode(dsi);
448 	msleep(250);
449 
450 	mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETEXTC, 0xf1, 0x12, 0x83);
451 	mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETMIPI, 0x33, 0x81, 0x05, 0xf9,
452 			       0x0e, 0x0e, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,
453 			       0x00, 0x00, 0x44, 0x25, 0x00, 0x90, 0x0a, 0x00,
454 			       0x00, 0x01, 0x4f, 0x01, 0x00, 0x00, 0x37);
455 	mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETPOWER_EXT, 0x25, 0x22, 0xf0,
456 			       0x63);
457 	mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_UNKNOWN_BF, 0x02, 0x11, 0x00);
458 	mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETRGBIF, 0x10, 0x10, 0x28,
459 			       0x28, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00);
460 	mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETSCR, 0x73, 0x73, 0x50, 0x50,
461 			       0x00, 0x00, 0x12, 0x70, 0x00);
462 	mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETVDC, 0x46);
463 	mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETPANEL, 0x0b);
464 	mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETCYC, 0x80);
465 	mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETDISP, 0x3c, 0x12, 0x30);
466 	mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETEQ, 0x07, 0x07, 0x0b, 0x0b,
467 			       0x03, 0x0b, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
468 			       0xc0, 0x10);
469 	mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETPOWER, 0x36, 0x00, 0x32,
470 			       0x32, 0x77, 0xf1, 0xcc, 0xcc, 0x77, 0x77, 0x33,
471 			       0x33);
472 	mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETBGP, 0x0a, 0x0a);
473 	mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETVCOM, 0x88, 0x88);
474 	mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETGIP1, 0xc8, 0x10, 0x0a, 0x10,
475 			       0x0f, 0xa1, 0x80, 0x12, 0x31, 0x23, 0x47, 0x86,
476 			       0xa1, 0x80, 0x47, 0x08, 0x00, 0x00, 0x0d, 0x00,
477 			       0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
478 			       0x48, 0x02, 0x8b, 0xaf, 0x46, 0x02, 0x88, 0x88,
479 			       0x88, 0x88, 0x88, 0x48, 0x13, 0x8b, 0xaf, 0x57,
480 			       0x13, 0x88, 0x88, 0x88, 0x88, 0x88, 0x00, 0x00,
481 			       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
482 			       0x00, 0x00, 0x00);
483 	mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETGIP2, 0x96, 0x12, 0x01, 0x01,
484 			       0x01, 0x78, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
485 			       0x4f, 0x31, 0x8b, 0xa8, 0x31, 0x75, 0x88, 0x88,
486 			       0x88, 0x88, 0x88, 0x4f, 0x20, 0x8b, 0xa8, 0x20,
487 			       0x64, 0x88, 0x88, 0x88, 0x88, 0x88, 0x23, 0x00,
488 			       0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
489 			       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
490 			       0x00, 0x00, 0x40, 0xa1, 0x80, 0x00, 0x00, 0x00,
491 			       0x00);
492 	mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETGAMMA, 0x00, 0x0a, 0x0f,
493 			       0x29, 0x3b, 0x3f, 0x42, 0x39, 0x06, 0x0d, 0x10,
494 			       0x13, 0x15, 0x14, 0x15, 0x10, 0x17, 0x00, 0x0a,
495 			       0x0f, 0x29, 0x3b, 0x3f, 0x42, 0x39, 0x06, 0x0d,
496 			       0x10, 0x13, 0x15, 0x14, 0x15, 0x10, 0x17);
497 
498 	return 0;
499 }
500 
501 static const struct drm_display_mode rgb30panel_mode = {
502 	.hdisplay	= 720,
503 	.hsync_start	= 720 + 45,
504 	.hsync_end	= 720 + 45 + 4,
505 	.htotal		= 720 + 45 + 4 + 45,
506 	.vdisplay	= 720,
507 	.vsync_start	= 720 + 15,
508 	.vsync_end	= 720 + 15 + 3,
509 	.vtotal		= 720 + 15 + 3 + 11,
510 	.clock		= 36570,
511 	.flags		= DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
512 	.width_mm	= 76,
513 	.height_mm	= 76,
514 };
515 
516 static const struct st7703_panel_desc rgb30panel_desc = {
517 	.mode = &rgb30panel_mode,
518 	.lanes = 4,
519 	.mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
520 		      MIPI_DSI_MODE_NO_EOT_PACKET | MIPI_DSI_MODE_LPM,
521 	.format = MIPI_DSI_FMT_RGB888,
522 	.init_sequence = rgb30panel_init_sequence,
523 };
524 
525 static int rgb10max3_panel_init_sequence(struct st7703 *ctx)
526 {
527 	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
528 
529 	/* Init sequence extracted from Powkiddy RGB10MAX3 BSP kernel. */
530 
531 	mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETEXTC, 0xf1, 0x12, 0x83);
532 	mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETAPID, 0x00, 0x00, 0x00, 0xda,
533 			       0x80);
534 	mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETDISP, 0xc8, 0x02, 0x30);
535 	mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETRGBIF, 0x10, 0x10, 0x28,
536 			       0x28, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00);
537 	mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETCYC, 0x80);
538 	mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETBGP, 0x04, 0x04);
539 	mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETVCOM, 0x78, 0x78);
540 	mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETPOWER_EXT, 0x25, 0x22, 0xf0,
541 			       0x63);
542 	mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETMIPI, 0x33, 0x81, 0x05, 0xf9,
543 			       0x0e, 0x0e, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,
544 			       0x00, 0x00, 0x44, 0x25, 0x00, 0x90, 0x0a, 0x00,
545 			       0x00, 0x01, 0x4f, 0x01, 0x00, 0x00, 0x37);
546 	mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETVDC, 0x47);
547 	mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_UNKNOWN_BF, 0x02, 0x11, 0x00);
548 	mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETSCR, 0x73, 0x73, 0x50, 0x50,
549 			       0x00, 0x00, 0x12, 0x70, 0x00);
550 	mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETPOWER, 0x25, 0x00, 0x32,
551 			       0x32, 0x77, 0xe1, 0xff, 0xff, 0xcc, 0xcc, 0x77,
552 			       0x77);
553 	mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETECO, 0x82, 0x00, 0xbf, 0xff,
554 			       0x00, 0xff);
555 	mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETIO, 0xb8, 0x00, 0x0a, 0x00,
556 			       0x00, 0x00);
557 	mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETCABC, 0x10, 0x40, 0x1e,
558 			       0x02);
559 	mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETPANEL, 0x0b);
560 	mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETGAMMA, 0x00, 0x04, 0x07,
561 			       0x2a, 0x39, 0x3f, 0x36, 0x31, 0x06, 0x0b, 0x0e,
562 			       0x12, 0x14, 0x12, 0x13, 0x0f, 0x17, 0x00, 0x04,
563 			       0x07, 0x2a, 0x39, 0x3f, 0x36, 0x31, 0x06, 0x0b,
564 			       0x0e, 0x12, 0x14, 0x12, 0x13, 0x0f, 0x17);
565 	mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETEQ, 0x03, 0x03, 0x03, 0x03,
566 			       0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0xff, 0x80,
567 			       0xc0, 0x10);
568 	mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETGIP1, 0xc8, 0x10, 0x08, 0x00,
569 			       0x00, 0x41, 0xf8, 0x12, 0x31, 0x23, 0x37, 0x86,
570 			       0x11, 0xc8, 0x37, 0x2a, 0x00, 0x00, 0x0c, 0x00,
571 			       0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
572 			       0x88, 0x20, 0x46, 0x02, 0x88, 0x88, 0x88, 0x88,
573 			       0x88, 0x88, 0xff, 0x88, 0x31, 0x57, 0x13, 0x88,
574 			       0x88, 0x88, 0x88, 0x88, 0x88, 0xff, 0x00, 0x00,
575 			       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
576 			       0x00, 0x00, 0x00);
577 	mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETGIP2, 0x00, 0x1a, 0x00, 0x00,
578 			       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
579 			       0x8f, 0x13, 0x31, 0x75, 0x88, 0x88, 0x88, 0x88,
580 			       0x88, 0x88, 0xf8, 0x8f, 0x02, 0x20, 0x64, 0x88,
581 			       0x88, 0x88, 0x88, 0x88, 0x88, 0xf8, 0x00, 0x00,
582 			       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
583 			       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
584 			       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
585 			       0x00);
586 	mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_UNKNOWN_EF, 0xff, 0xff, 0x01);
587 
588 	return 0;
589 }
590 
591 static const struct drm_display_mode rgb10max3_panel_mode = {
592 	.hdisplay	= 720,
593 	.hsync_start	= 720 + 40,
594 	.hsync_end	= 720 + 40 + 10,
595 	.htotal		= 720 + 40 + 10 + 40,
596 	.vdisplay	= 1280,
597 	.vsync_start	= 1280 + 16,
598 	.vsync_end	= 1280 + 16 + 4,
599 	.vtotal		= 1280 + 16 + 4 + 14,
600 	.clock		= 63800,
601 	.flags		= DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
602 	.width_mm	= 62,
603 	.height_mm	= 109,
604 };
605 
606 static const struct st7703_panel_desc rgb10max3_panel_desc = {
607 	.mode = &rgb10max3_panel_mode,
608 	.lanes = 4,
609 	.mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
610 		      MIPI_DSI_MODE_NO_EOT_PACKET | MIPI_DSI_MODE_LPM,
611 	.format = MIPI_DSI_FMT_RGB888,
612 	.init_sequence = rgb10max3_panel_init_sequence,
613 };
614 
615 static int st7703_enable(struct drm_panel *panel)
616 {
617 	struct st7703 *ctx = panel_to_st7703(panel);
618 	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
619 	int ret;
620 
621 	ret = ctx->desc->init_sequence(ctx);
622 	if (ret < 0) {
623 		dev_err(ctx->dev, "Panel init sequence failed: %d\n", ret);
624 		return ret;
625 	}
626 
627 	ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
628 	if (ret < 0) {
629 		dev_err(ctx->dev, "Failed to exit sleep mode: %d\n", ret);
630 		return ret;
631 	}
632 
633 	/* It takes the controller 120 msec to wake up after sleep. */
634 	msleep(120);
635 
636 	ret = mipi_dsi_dcs_set_display_on(dsi);
637 	if (ret)
638 		return ret;
639 
640 	dev_dbg(ctx->dev, "Panel init sequence done\n");
641 
642 	return 0;
643 }
644 
645 static int st7703_disable(struct drm_panel *panel)
646 {
647 	struct st7703 *ctx = panel_to_st7703(panel);
648 	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
649 	int ret;
650 
651 	ret = mipi_dsi_dcs_set_display_off(dsi);
652 	if (ret < 0)
653 		dev_err(ctx->dev, "Failed to turn off the display: %d\n", ret);
654 
655 	ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
656 	if (ret < 0)
657 		dev_err(ctx->dev, "Failed to enter sleep mode: %d\n", ret);
658 
659 	/* It takes the controller 120 msec to enter sleep mode. */
660 	msleep(120);
661 
662 	return 0;
663 }
664 
665 static int st7703_unprepare(struct drm_panel *panel)
666 {
667 	struct st7703 *ctx = panel_to_st7703(panel);
668 
669 	if (!ctx->prepared)
670 		return 0;
671 
672 	gpiod_set_value_cansleep(ctx->reset_gpio, 1);
673 	regulator_disable(ctx->iovcc);
674 	regulator_disable(ctx->vcc);
675 	ctx->prepared = false;
676 
677 	return 0;
678 }
679 
680 static int st7703_prepare(struct drm_panel *panel)
681 {
682 	struct st7703 *ctx = panel_to_st7703(panel);
683 	int ret;
684 
685 	if (ctx->prepared)
686 		return 0;
687 
688 	dev_dbg(ctx->dev, "Resetting the panel\n");
689 	gpiod_set_value_cansleep(ctx->reset_gpio, 1);
690 
691 	ret = regulator_enable(ctx->iovcc);
692 	if (ret < 0) {
693 		dev_err(ctx->dev, "Failed to enable iovcc supply: %d\n", ret);
694 		return ret;
695 	}
696 
697 	ret = regulator_enable(ctx->vcc);
698 	if (ret < 0) {
699 		dev_err(ctx->dev, "Failed to enable vcc supply: %d\n", ret);
700 		regulator_disable(ctx->iovcc);
701 		return ret;
702 	}
703 
704 	/* Give power supplies time to stabilize before deasserting reset. */
705 	usleep_range(10000, 20000);
706 
707 	gpiod_set_value_cansleep(ctx->reset_gpio, 0);
708 	usleep_range(15000, 20000);
709 
710 	ctx->prepared = true;
711 
712 	return 0;
713 }
714 
715 static const u32 mantix_bus_formats[] = {
716 	MEDIA_BUS_FMT_RGB888_1X24,
717 };
718 
719 static int st7703_get_modes(struct drm_panel *panel,
720 			    struct drm_connector *connector)
721 {
722 	struct st7703 *ctx = panel_to_st7703(panel);
723 	struct drm_display_mode *mode;
724 
725 	mode = drm_mode_duplicate(connector->dev, ctx->desc->mode);
726 	if (!mode) {
727 		dev_err(ctx->dev, "Failed to add mode %ux%u@%u\n",
728 			ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay,
729 			drm_mode_vrefresh(ctx->desc->mode));
730 		return -ENOMEM;
731 	}
732 
733 	drm_mode_set_name(mode);
734 
735 	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
736 	connector->display_info.width_mm = mode->width_mm;
737 	connector->display_info.height_mm = mode->height_mm;
738 	drm_mode_probed_add(connector, mode);
739 
740 	drm_display_info_set_bus_formats(&connector->display_info,
741 					 mantix_bus_formats,
742 					 ARRAY_SIZE(mantix_bus_formats));
743 
744 	return 1;
745 }
746 
747 static enum drm_panel_orientation st7703_get_orientation(struct drm_panel *panel)
748 {
749 	struct st7703 *st7703 = panel_to_st7703(panel);
750 
751 	return st7703->orientation;
752 }
753 
754 static const struct drm_panel_funcs st7703_drm_funcs = {
755 	.disable   = st7703_disable,
756 	.unprepare = st7703_unprepare,
757 	.prepare   = st7703_prepare,
758 	.enable	   = st7703_enable,
759 	.get_modes = st7703_get_modes,
760 	.get_orientation = st7703_get_orientation,
761 };
762 
763 static int allpixelson_set(void *data, u64 val)
764 {
765 	struct st7703 *ctx = data;
766 	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
767 
768 	dev_dbg(ctx->dev, "Setting all pixels on\n");
769 	mipi_dsi_generic_write_seq(dsi, ST7703_CMD_ALL_PIXEL_ON);
770 	msleep(val * 1000);
771 	/* Reset the panel to get video back */
772 	drm_panel_disable(&ctx->panel);
773 	drm_panel_unprepare(&ctx->panel);
774 	drm_panel_prepare(&ctx->panel);
775 	drm_panel_enable(&ctx->panel);
776 
777 	return 0;
778 }
779 
780 DEFINE_SIMPLE_ATTRIBUTE(allpixelson_fops, NULL,
781 			allpixelson_set, "%llu\n");
782 
783 static void st7703_debugfs_init(struct st7703 *ctx)
784 {
785 	ctx->debugfs = debugfs_create_dir(DRV_NAME, NULL);
786 
787 	debugfs_create_file("allpixelson", 0600, ctx->debugfs, ctx,
788 			    &allpixelson_fops);
789 }
790 
791 static void st7703_debugfs_remove(struct st7703 *ctx)
792 {
793 	debugfs_remove_recursive(ctx->debugfs);
794 	ctx->debugfs = NULL;
795 }
796 
797 static int st7703_probe(struct mipi_dsi_device *dsi)
798 {
799 	struct device *dev = &dsi->dev;
800 	struct st7703 *ctx;
801 	int ret;
802 
803 	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
804 	if (!ctx)
805 		return -ENOMEM;
806 
807 	ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
808 	if (IS_ERR(ctx->reset_gpio))
809 		return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), "Failed to get reset gpio\n");
810 
811 	mipi_dsi_set_drvdata(dsi, ctx);
812 
813 	ctx->dev = dev;
814 	ctx->desc = of_device_get_match_data(dev);
815 
816 	dsi->mode_flags = ctx->desc->mode_flags;
817 	dsi->format = ctx->desc->format;
818 	dsi->lanes = ctx->desc->lanes;
819 
820 	ctx->vcc = devm_regulator_get(dev, "vcc");
821 	if (IS_ERR(ctx->vcc))
822 		return dev_err_probe(dev, PTR_ERR(ctx->vcc), "Failed to request vcc regulator\n");
823 
824 	ctx->iovcc = devm_regulator_get(dev, "iovcc");
825 	if (IS_ERR(ctx->iovcc))
826 		return dev_err_probe(dev, PTR_ERR(ctx->iovcc),
827 				     "Failed to request iovcc regulator\n");
828 
829 	ret = of_drm_get_panel_orientation(dsi->dev.of_node, &ctx->orientation);
830 	if (ret < 0)
831 		return dev_err_probe(&dsi->dev, ret, "Failed to get orientation\n");
832 
833 	drm_panel_init(&ctx->panel, dev, &st7703_drm_funcs,
834 		       DRM_MODE_CONNECTOR_DSI);
835 
836 	ret = drm_panel_of_backlight(&ctx->panel);
837 	if (ret)
838 		return ret;
839 
840 	drm_panel_add(&ctx->panel);
841 
842 	ret = mipi_dsi_attach(dsi);
843 	if (ret < 0) {
844 		dev_err(dev, "mipi_dsi_attach failed (%d). Is host ready?\n", ret);
845 		drm_panel_remove(&ctx->panel);
846 		return ret;
847 	}
848 
849 	dev_info(dev, "%ux%u@%u %ubpp dsi %udl - ready\n",
850 		 ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay,
851 		 drm_mode_vrefresh(ctx->desc->mode),
852 		 mipi_dsi_pixel_format_to_bpp(dsi->format), dsi->lanes);
853 
854 	st7703_debugfs_init(ctx);
855 	return 0;
856 }
857 
858 static void st7703_shutdown(struct mipi_dsi_device *dsi)
859 {
860 	struct st7703 *ctx = mipi_dsi_get_drvdata(dsi);
861 	int ret;
862 
863 	ret = drm_panel_unprepare(&ctx->panel);
864 	if (ret < 0)
865 		dev_err(&dsi->dev, "Failed to unprepare panel: %d\n", ret);
866 
867 	ret = drm_panel_disable(&ctx->panel);
868 	if (ret < 0)
869 		dev_err(&dsi->dev, "Failed to disable panel: %d\n", ret);
870 }
871 
872 static void st7703_remove(struct mipi_dsi_device *dsi)
873 {
874 	struct st7703 *ctx = mipi_dsi_get_drvdata(dsi);
875 	int ret;
876 
877 	st7703_shutdown(dsi);
878 
879 	ret = mipi_dsi_detach(dsi);
880 	if (ret < 0)
881 		dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret);
882 
883 	drm_panel_remove(&ctx->panel);
884 
885 	st7703_debugfs_remove(ctx);
886 }
887 
888 static const struct of_device_id st7703_of_match[] = {
889 	{ .compatible = "anbernic,rg353v-panel-v2", .data = &rg353v2_desc },
890 	{ .compatible = "powkiddy,rgb10max3-panel", .data = &rgb10max3_panel_desc },
891 	{ .compatible = "powkiddy,rgb30-panel", .data = &rgb30panel_desc },
892 	{ .compatible = "rocktech,jh057n00900", .data = &jh057n00900_panel_desc },
893 	{ .compatible = "xingbangda,xbd599", .data = &xbd599_desc },
894 	{ /* sentinel */ }
895 };
896 MODULE_DEVICE_TABLE(of, st7703_of_match);
897 
898 static struct mipi_dsi_driver st7703_driver = {
899 	.probe	= st7703_probe,
900 	.remove = st7703_remove,
901 	.shutdown = st7703_shutdown,
902 	.driver = {
903 		.name = DRV_NAME,
904 		.of_match_table = st7703_of_match,
905 	},
906 };
907 module_mipi_dsi_driver(st7703_driver);
908 
909 MODULE_AUTHOR("Guido Günther <agx@sigxcpu.org>");
910 MODULE_DESCRIPTION("DRM driver for Sitronix ST7703 based MIPI DSI panels");
911 MODULE_LICENSE("GPL v2");
912