Linux 5.9.7
[linux/fpc-iii.git] / drivers / gpu / drm / panel / panel-sitronix-st7703.c
blob8996ced2b721a8313054a74819d0c137fa05e27c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Driver for panels based on Sitronix ST7703 controller, souch as:
5 * - Rocktech jh057n00900 5.5" MIPI-DSI panel
7 * Copyright (C) Purism SPC 2019
8 */
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_device.h>
17 #include <linux/regulator/consumer.h>
19 #include <video/display_timing.h>
20 #include <video/mipi_display.h>
22 #include <drm/drm_mipi_dsi.h>
23 #include <drm/drm_modes.h>
24 #include <drm/drm_panel.h>
25 #include <drm/drm_print.h>
27 #define DRV_NAME "panel-sitronix-st7703"
29 /* Manufacturer specific Commands send via DSI */
30 #define ST7703_CMD_ALL_PIXEL_OFF 0x22
31 #define ST7703_CMD_ALL_PIXEL_ON 0x23
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_SETPANEL 0xCC
46 #define ST7703_CMD_UNKNOWN_C6 0xC6
47 #define ST7703_CMD_SETGAMMA 0xE0
48 #define ST7703_CMD_SETEQ 0xE3
49 #define ST7703_CMD_SETGIP1 0xE9
50 #define ST7703_CMD_SETGIP2 0xEA
52 struct st7703 {
53 struct device *dev;
54 struct drm_panel panel;
55 struct gpio_desc *reset_gpio;
56 struct regulator *vcc;
57 struct regulator *iovcc;
58 bool prepared;
60 struct dentry *debugfs;
61 const struct st7703_panel_desc *desc;
64 struct st7703_panel_desc {
65 const struct drm_display_mode *mode;
66 unsigned int lanes;
67 unsigned long mode_flags;
68 enum mipi_dsi_pixel_format format;
69 int (*init_sequence)(struct st7703 *ctx);
72 static inline struct st7703 *panel_to_st7703(struct drm_panel *panel)
74 return container_of(panel, struct st7703, panel);
77 #define dsi_generic_write_seq(dsi, seq...) do { \
78 static const u8 d[] = { seq }; \
79 int ret; \
80 ret = mipi_dsi_generic_write(dsi, d, ARRAY_SIZE(d)); \
81 if (ret < 0) \
82 return ret; \
83 } while (0)
85 static int jh057n_init_sequence(struct st7703 *ctx)
87 struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
90 * Init sequence was supplied by the panel vendor. Most of the commands
91 * resemble the ST7703 but the number of parameters often don't match
92 * so it's likely a clone.
94 dsi_generic_write_seq(dsi, ST7703_CMD_SETEXTC,
95 0xF1, 0x12, 0x83);
96 dsi_generic_write_seq(dsi, ST7703_CMD_SETRGBIF,
97 0x10, 0x10, 0x05, 0x05, 0x03, 0xFF, 0x00, 0x00,
98 0x00, 0x00);
99 dsi_generic_write_seq(dsi, ST7703_CMD_SETSCR,
100 0x73, 0x73, 0x50, 0x50, 0x00, 0x00, 0x08, 0x70,
101 0x00);
102 dsi_generic_write_seq(dsi, ST7703_CMD_SETVDC, 0x4E);
103 dsi_generic_write_seq(dsi, ST7703_CMD_SETPANEL, 0x0B);
104 dsi_generic_write_seq(dsi, ST7703_CMD_SETCYC, 0x80);
105 dsi_generic_write_seq(dsi, ST7703_CMD_SETDISP, 0xF0, 0x12, 0x30);
106 dsi_generic_write_seq(dsi, ST7703_CMD_SETEQ,
107 0x07, 0x07, 0x0B, 0x0B, 0x03, 0x0B, 0x00, 0x00,
108 0x00, 0x00, 0xFF, 0x00, 0xC0, 0x10);
109 dsi_generic_write_seq(dsi, ST7703_CMD_SETBGP, 0x08, 0x08);
110 msleep(20);
112 dsi_generic_write_seq(dsi, ST7703_CMD_SETVCOM, 0x3F, 0x3F);
113 dsi_generic_write_seq(dsi, ST7703_CMD_UNKNOWN_BF, 0x02, 0x11, 0x00);
114 dsi_generic_write_seq(dsi, ST7703_CMD_SETGIP1,
115 0x82, 0x10, 0x06, 0x05, 0x9E, 0x0A, 0xA5, 0x12,
116 0x31, 0x23, 0x37, 0x83, 0x04, 0xBC, 0x27, 0x38,
117 0x0C, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0C, 0x00,
118 0x03, 0x00, 0x00, 0x00, 0x75, 0x75, 0x31, 0x88,
119 0x88, 0x88, 0x88, 0x88, 0x88, 0x13, 0x88, 0x64,
120 0x64, 0x20, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
121 0x02, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
122 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
123 dsi_generic_write_seq(dsi, ST7703_CMD_SETGIP2,
124 0x02, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
125 0x00, 0x00, 0x00, 0x00, 0x02, 0x46, 0x02, 0x88,
126 0x88, 0x88, 0x88, 0x88, 0x88, 0x64, 0x88, 0x13,
127 0x57, 0x13, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
128 0x75, 0x88, 0x23, 0x14, 0x00, 0x00, 0x02, 0x00,
129 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
130 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x0A,
131 0xA5, 0x00, 0x00, 0x00, 0x00);
132 dsi_generic_write_seq(dsi, ST7703_CMD_SETGAMMA,
133 0x00, 0x09, 0x0E, 0x29, 0x2D, 0x3C, 0x41, 0x37,
134 0x07, 0x0B, 0x0D, 0x10, 0x11, 0x0F, 0x10, 0x11,
135 0x18, 0x00, 0x09, 0x0E, 0x29, 0x2D, 0x3C, 0x41,
136 0x37, 0x07, 0x0B, 0x0D, 0x10, 0x11, 0x0F, 0x10,
137 0x11, 0x18);
139 return 0;
142 static const struct drm_display_mode jh057n00900_mode = {
143 .hdisplay = 720,
144 .hsync_start = 720 + 90,
145 .hsync_end = 720 + 90 + 20,
146 .htotal = 720 + 90 + 20 + 20,
147 .vdisplay = 1440,
148 .vsync_start = 1440 + 20,
149 .vsync_end = 1440 + 20 + 4,
150 .vtotal = 1440 + 20 + 4 + 12,
151 .clock = 75276,
152 .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
153 .width_mm = 65,
154 .height_mm = 130,
157 struct st7703_panel_desc jh057n00900_panel_desc = {
158 .mode = &jh057n00900_mode,
159 .lanes = 4,
160 .mode_flags = MIPI_DSI_MODE_VIDEO |
161 MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_VIDEO_SYNC_PULSE,
162 .format = MIPI_DSI_FMT_RGB888,
163 .init_sequence = jh057n_init_sequence,
166 #define dsi_dcs_write_seq(dsi, cmd, seq...) do { \
167 static const u8 d[] = { seq }; \
168 int ret; \
169 ret = mipi_dsi_dcs_write(dsi, cmd, d, ARRAY_SIZE(d)); \
170 if (ret < 0) \
171 return ret; \
172 } while (0)
175 static int xbd599_init_sequence(struct st7703 *ctx)
177 struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
180 * Init sequence was supplied by the panel vendor.
183 /* Magic sequence to unlock user commands below. */
184 dsi_dcs_write_seq(dsi, ST7703_CMD_SETEXTC, 0xF1, 0x12, 0x83);
186 dsi_dcs_write_seq(dsi, ST7703_CMD_SETMIPI,
187 0x33, /* VC_main = 0, Lane_Number = 3 (4 lanes) */
188 0x81, /* DSI_LDO_SEL = 1.7V, RTERM = 90 Ohm */
189 0x05, /* IHSRX = x6 (Low High Speed driving ability) */
190 0xF9, /* TX_CLK_SEL = fDSICLK/16 */
191 0x0E, /* HFP_OSC (min. HFP number in DSI mode) */
192 0x0E, /* HBP_OSC (min. HBP number in DSI mode) */
193 /* The rest is undocumented in ST7703 datasheet */
194 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
195 0x44, 0x25, 0x00, 0x91, 0x0a, 0x00, 0x00, 0x02,
196 0x4F, 0x11, 0x00, 0x00, 0x37);
198 dsi_dcs_write_seq(dsi, ST7703_CMD_SETPOWER_EXT,
199 0x25, /* PCCS = 2, ECP_DC_DIV = 1/4 HSYNC */
200 0x22, /* DT = 15ms XDK_ECP = x2 */
201 0x20, /* PFM_DC_DIV = /1 */
202 0x03 /* ECP_SYNC_EN = 1, VGX_SYNC_EN = 1 */);
204 /* RGB I/F porch timing */
205 dsi_dcs_write_seq(dsi, ST7703_CMD_SETRGBIF,
206 0x10, /* VBP_RGB_GEN */
207 0x10, /* VFP_RGB_GEN */
208 0x05, /* DE_BP_RGB_GEN */
209 0x05, /* DE_FP_RGB_GEN */
210 /* The rest is undocumented in ST7703 datasheet */
211 0x03, 0xFF,
212 0x00, 0x00,
213 0x00, 0x00);
215 /* Source driving settings. */
216 dsi_dcs_write_seq(dsi, ST7703_CMD_SETSCR,
217 0x73, /* N_POPON */
218 0x73, /* N_NOPON */
219 0x50, /* I_POPON */
220 0x50, /* I_NOPON */
221 0x00, /* SCR[31,24] */
222 0xC0, /* SCR[23,16] */
223 0x08, /* SCR[15,8] */
224 0x70, /* SCR[7,0] */
225 0x00 /* Undocumented */);
227 /* NVDDD_SEL = -1.8V, VDDD_SEL = out of range (possibly 1.9V?) */
228 dsi_dcs_write_seq(dsi, ST7703_CMD_SETVDC, 0x4E);
231 * SS_PANEL = 1 (reverse scan), GS_PANEL = 0 (normal scan)
232 * REV_PANEL = 1 (normally black panel), BGR_PANEL = 1 (BGR)
234 dsi_dcs_write_seq(dsi, ST7703_CMD_SETPANEL, 0x0B);
236 /* Zig-Zag Type C column inversion. */
237 dsi_dcs_write_seq(dsi, ST7703_CMD_SETCYC, 0x80);
239 /* Set display resolution. */
240 dsi_dcs_write_seq(dsi, ST7703_CMD_SETDISP,
241 0xF0, /* NL = 240 */
242 0x12, /* RES_V_LSB = 0, BLK_CON = VSSD,
243 * RESO_SEL = 720RGB
245 0xF0 /* WHITE_GND_EN = 1 (GND),
246 * WHITE_FRAME_SEL = 7 frames,
247 * ISC = 0 frames
248 */);
250 dsi_dcs_write_seq(dsi, ST7703_CMD_SETEQ,
251 0x00, /* PNOEQ */
252 0x00, /* NNOEQ */
253 0x0B, /* PEQGND */
254 0x0B, /* NEQGND */
255 0x10, /* PEQVCI */
256 0x10, /* NEQVCI */
257 0x00, /* PEQVCI1 */
258 0x00, /* NEQVCI1 */
259 0x00, /* reserved */
260 0x00, /* reserved */
261 0xFF, /* reserved */
262 0x00, /* reserved */
263 0xC0, /* ESD_DET_DATA_WHITE = 1, ESD_WHITE_EN = 1 */
264 0x10 /* SLPIN_OPTION = 1 (no need vsync after sleep-in)
265 * VEDIO_NO_CHECK_EN = 0
266 * ESD_WHITE_GND_EN = 0
267 * ESD_DET_TIME_SEL = 0 frames
268 */);
270 /* Undocumented command. */
271 dsi_dcs_write_seq(dsi, ST7703_CMD_UNKNOWN_C6, 0x01, 0x00, 0xFF, 0xFF, 0x00);
273 dsi_dcs_write_seq(dsi, ST7703_CMD_SETPOWER,
274 0x74, /* VBTHS, VBTLS: VGH = 17V, VBL = -11V */
275 0x00, /* FBOFF_VGH = 0, FBOFF_VGL = 0 */
276 0x32, /* VRP */
277 0x32, /* VRN */
278 0x77, /* reserved */
279 0xF1, /* APS = 1 (small),
280 * VGL_DET_EN = 1, VGH_DET_EN = 1,
281 * VGL_TURBO = 1, VGH_TURBO = 1
283 0xFF, /* VGH1_L_DIV, VGL1_L_DIV (1.5MHz) */
284 0xFF, /* VGH1_R_DIV, VGL1_R_DIV (1.5MHz) */
285 0xCC, /* VGH2_L_DIV, VGL2_L_DIV (2.6MHz) */
286 0xCC, /* VGH2_R_DIV, VGL2_R_DIV (2.6MHz) */
287 0x77, /* VGH3_L_DIV, VGL3_L_DIV (4.5MHz) */
288 0x77 /* VGH3_R_DIV, VGL3_R_DIV (4.5MHz) */);
290 /* Reference voltage. */
291 dsi_dcs_write_seq(dsi, ST7703_CMD_SETBGP,
292 0x07, /* VREF_SEL = 4.2V */
293 0x07 /* NVREF_SEL = 4.2V */);
294 msleep(20);
296 dsi_dcs_write_seq(dsi, ST7703_CMD_SETVCOM,
297 0x2C, /* VCOMDC_F = -0.67V */
298 0x2C /* VCOMDC_B = -0.67V */);
300 /* Undocumented command. */
301 dsi_dcs_write_seq(dsi, ST7703_CMD_UNKNOWN_BF, 0x02, 0x11, 0x00);
303 /* This command is to set forward GIP timing. */
304 dsi_dcs_write_seq(dsi, ST7703_CMD_SETGIP1,
305 0x82, 0x10, 0x06, 0x05, 0xA2, 0x0A, 0xA5, 0x12,
306 0x31, 0x23, 0x37, 0x83, 0x04, 0xBC, 0x27, 0x38,
307 0x0C, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0C, 0x00,
308 0x03, 0x00, 0x00, 0x00, 0x75, 0x75, 0x31, 0x88,
309 0x88, 0x88, 0x88, 0x88, 0x88, 0x13, 0x88, 0x64,
310 0x64, 0x20, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
311 0x02, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
312 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
314 /* This command is to set backward GIP timing. */
315 dsi_dcs_write_seq(dsi, ST7703_CMD_SETGIP2,
316 0x02, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
317 0x00, 0x00, 0x00, 0x00, 0x02, 0x46, 0x02, 0x88,
318 0x88, 0x88, 0x88, 0x88, 0x88, 0x64, 0x88, 0x13,
319 0x57, 0x13, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
320 0x75, 0x88, 0x23, 0x14, 0x00, 0x00, 0x02, 0x00,
321 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
322 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0A,
323 0xA5, 0x00, 0x00, 0x00, 0x00);
325 /* Adjust the gamma characteristics of the panel. */
326 dsi_dcs_write_seq(dsi, ST7703_CMD_SETGAMMA,
327 0x00, 0x09, 0x0D, 0x23, 0x27, 0x3C, 0x41, 0x35,
328 0x07, 0x0D, 0x0E, 0x12, 0x13, 0x10, 0x12, 0x12,
329 0x18, 0x00, 0x09, 0x0D, 0x23, 0x27, 0x3C, 0x41,
330 0x35, 0x07, 0x0D, 0x0E, 0x12, 0x13, 0x10, 0x12,
331 0x12, 0x18);
333 return 0;
336 static const struct drm_display_mode xbd599_mode = {
337 .hdisplay = 720,
338 .hsync_start = 720 + 40,
339 .hsync_end = 720 + 40 + 40,
340 .htotal = 720 + 40 + 40 + 40,
341 .vdisplay = 1440,
342 .vsync_start = 1440 + 18,
343 .vsync_end = 1440 + 18 + 10,
344 .vtotal = 1440 + 18 + 10 + 17,
345 .clock = 69000,
346 .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
347 .width_mm = 68,
348 .height_mm = 136,
351 static const struct st7703_panel_desc xbd599_desc = {
352 .mode = &xbd599_mode,
353 .lanes = 4,
354 .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE,
355 .format = MIPI_DSI_FMT_RGB888,
356 .init_sequence = xbd599_init_sequence,
359 static int st7703_enable(struct drm_panel *panel)
361 struct st7703 *ctx = panel_to_st7703(panel);
362 struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
363 int ret;
365 ret = ctx->desc->init_sequence(ctx);
366 if (ret < 0) {
367 DRM_DEV_ERROR(ctx->dev, "Panel init sequence failed: %d\n",
368 ret);
369 return ret;
372 msleep(20);
374 ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
375 if (ret < 0) {
376 DRM_DEV_ERROR(ctx->dev, "Failed to exit sleep mode: %d\n", ret);
377 return ret;
380 /* Panel is operational 120 msec after reset */
381 msleep(60);
383 ret = mipi_dsi_dcs_set_display_on(dsi);
384 if (ret)
385 return ret;
387 DRM_DEV_DEBUG_DRIVER(ctx->dev, "Panel init sequence done\n");
389 return 0;
392 static int st7703_disable(struct drm_panel *panel)
394 struct st7703 *ctx = panel_to_st7703(panel);
395 struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
396 int ret;
398 ret = mipi_dsi_dcs_set_display_off(dsi);
399 if (ret < 0)
400 DRM_DEV_ERROR(ctx->dev,
401 "Failed to turn off the display: %d\n", ret);
403 ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
404 if (ret < 0)
405 DRM_DEV_ERROR(ctx->dev,
406 "Failed to enter sleep mode: %d\n", ret);
408 return 0;
411 static int st7703_unprepare(struct drm_panel *panel)
413 struct st7703 *ctx = panel_to_st7703(panel);
415 if (!ctx->prepared)
416 return 0;
418 gpiod_set_value_cansleep(ctx->reset_gpio, 1);
419 regulator_disable(ctx->iovcc);
420 regulator_disable(ctx->vcc);
421 ctx->prepared = false;
423 return 0;
426 static int st7703_prepare(struct drm_panel *panel)
428 struct st7703 *ctx = panel_to_st7703(panel);
429 int ret;
431 if (ctx->prepared)
432 return 0;
434 DRM_DEV_DEBUG_DRIVER(ctx->dev, "Resetting the panel\n");
435 ret = regulator_enable(ctx->vcc);
436 if (ret < 0) {
437 DRM_DEV_ERROR(ctx->dev,
438 "Failed to enable vcc supply: %d\n", ret);
439 return ret;
441 ret = regulator_enable(ctx->iovcc);
442 if (ret < 0) {
443 DRM_DEV_ERROR(ctx->dev,
444 "Failed to enable iovcc supply: %d\n", ret);
445 goto disable_vcc;
448 gpiod_set_value_cansleep(ctx->reset_gpio, 1);
449 usleep_range(20, 40);
450 gpiod_set_value_cansleep(ctx->reset_gpio, 0);
451 msleep(20);
453 ctx->prepared = true;
455 return 0;
457 disable_vcc:
458 regulator_disable(ctx->vcc);
459 return ret;
462 static int st7703_get_modes(struct drm_panel *panel,
463 struct drm_connector *connector)
465 struct st7703 *ctx = panel_to_st7703(panel);
466 struct drm_display_mode *mode;
468 mode = drm_mode_duplicate(connector->dev, ctx->desc->mode);
469 if (!mode) {
470 DRM_DEV_ERROR(ctx->dev, "Failed to add mode %ux%u@%u\n",
471 ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay,
472 drm_mode_vrefresh(ctx->desc->mode));
473 return -ENOMEM;
476 drm_mode_set_name(mode);
478 mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
479 connector->display_info.width_mm = mode->width_mm;
480 connector->display_info.height_mm = mode->height_mm;
481 drm_mode_probed_add(connector, mode);
483 return 1;
486 static const struct drm_panel_funcs st7703_drm_funcs = {
487 .disable = st7703_disable,
488 .unprepare = st7703_unprepare,
489 .prepare = st7703_prepare,
490 .enable = st7703_enable,
491 .get_modes = st7703_get_modes,
494 static int allpixelson_set(void *data, u64 val)
496 struct st7703 *ctx = data;
497 struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
499 DRM_DEV_DEBUG_DRIVER(ctx->dev, "Setting all pixels on\n");
500 dsi_generic_write_seq(dsi, ST7703_CMD_ALL_PIXEL_ON);
501 msleep(val * 1000);
502 /* Reset the panel to get video back */
503 drm_panel_disable(&ctx->panel);
504 drm_panel_unprepare(&ctx->panel);
505 drm_panel_prepare(&ctx->panel);
506 drm_panel_enable(&ctx->panel);
508 return 0;
511 DEFINE_SIMPLE_ATTRIBUTE(allpixelson_fops, NULL,
512 allpixelson_set, "%llu\n");
514 static void st7703_debugfs_init(struct st7703 *ctx)
516 ctx->debugfs = debugfs_create_dir(DRV_NAME, NULL);
518 debugfs_create_file("allpixelson", 0600, ctx->debugfs, ctx,
519 &allpixelson_fops);
522 static void st7703_debugfs_remove(struct st7703 *ctx)
524 debugfs_remove_recursive(ctx->debugfs);
525 ctx->debugfs = NULL;
528 static int st7703_probe(struct mipi_dsi_device *dsi)
530 struct device *dev = &dsi->dev;
531 struct st7703 *ctx;
532 int ret;
534 ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
535 if (!ctx)
536 return -ENOMEM;
538 ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
539 if (IS_ERR(ctx->reset_gpio)) {
540 DRM_DEV_ERROR(dev, "cannot get reset gpio\n");
541 return PTR_ERR(ctx->reset_gpio);
544 mipi_dsi_set_drvdata(dsi, ctx);
546 ctx->dev = dev;
547 ctx->desc = of_device_get_match_data(dev);
549 dsi->mode_flags = ctx->desc->mode_flags;
550 dsi->format = ctx->desc->format;
551 dsi->lanes = ctx->desc->lanes;
553 ctx->vcc = devm_regulator_get(dev, "vcc");
554 if (IS_ERR(ctx->vcc)) {
555 ret = PTR_ERR(ctx->vcc);
556 if (ret != -EPROBE_DEFER)
557 DRM_DEV_ERROR(dev,
558 "Failed to request vcc regulator: %d\n",
559 ret);
560 return ret;
562 ctx->iovcc = devm_regulator_get(dev, "iovcc");
563 if (IS_ERR(ctx->iovcc)) {
564 ret = PTR_ERR(ctx->iovcc);
565 if (ret != -EPROBE_DEFER)
566 DRM_DEV_ERROR(dev,
567 "Failed to request iovcc regulator: %d\n",
568 ret);
569 return ret;
572 drm_panel_init(&ctx->panel, dev, &st7703_drm_funcs,
573 DRM_MODE_CONNECTOR_DSI);
575 ret = drm_panel_of_backlight(&ctx->panel);
576 if (ret)
577 return ret;
579 drm_panel_add(&ctx->panel);
581 ret = mipi_dsi_attach(dsi);
582 if (ret < 0) {
583 DRM_DEV_ERROR(dev,
584 "mipi_dsi_attach failed (%d). Is host ready?\n",
585 ret);
586 drm_panel_remove(&ctx->panel);
587 return ret;
590 DRM_DEV_INFO(dev, "%ux%u@%u %ubpp dsi %udl - ready\n",
591 ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay,
592 drm_mode_vrefresh(ctx->desc->mode),
593 mipi_dsi_pixel_format_to_bpp(dsi->format), dsi->lanes);
595 st7703_debugfs_init(ctx);
596 return 0;
599 static void st7703_shutdown(struct mipi_dsi_device *dsi)
601 struct st7703 *ctx = mipi_dsi_get_drvdata(dsi);
602 int ret;
604 ret = drm_panel_unprepare(&ctx->panel);
605 if (ret < 0)
606 DRM_DEV_ERROR(&dsi->dev, "Failed to unprepare panel: %d\n",
607 ret);
609 ret = drm_panel_disable(&ctx->panel);
610 if (ret < 0)
611 DRM_DEV_ERROR(&dsi->dev, "Failed to disable panel: %d\n",
612 ret);
615 static int st7703_remove(struct mipi_dsi_device *dsi)
617 struct st7703 *ctx = mipi_dsi_get_drvdata(dsi);
618 int ret;
620 st7703_shutdown(dsi);
622 ret = mipi_dsi_detach(dsi);
623 if (ret < 0)
624 DRM_DEV_ERROR(&dsi->dev, "Failed to detach from DSI host: %d\n",
625 ret);
627 drm_panel_remove(&ctx->panel);
629 st7703_debugfs_remove(ctx);
631 return 0;
634 static const struct of_device_id st7703_of_match[] = {
635 { .compatible = "rocktech,jh057n00900", .data = &jh057n00900_panel_desc },
636 { .compatible = "xingbangda,xbd599", .data = &xbd599_desc },
637 { /* sentinel */ }
639 MODULE_DEVICE_TABLE(of, st7703_of_match);
641 static struct mipi_dsi_driver st7703_driver = {
642 .probe = st7703_probe,
643 .remove = st7703_remove,
644 .shutdown = st7703_shutdown,
645 .driver = {
646 .name = DRV_NAME,
647 .of_match_table = st7703_of_match,
650 module_mipi_dsi_driver(st7703_driver);
652 MODULE_AUTHOR("Guido Günther <agx@sigxcpu.org>");
653 MODULE_DESCRIPTION("DRM driver for Sitronix ST7703 based MIPI DSI panels");
654 MODULE_LICENSE("GPL v2");