1 // SPDX-License-Identifier: GPL-2.0
3 * Rockteck jh057n00900 5.5" MIPI-DSI panel driver
5 * Copyright (C) Purism SPC 2019
8 #include <linux/debugfs.h>
9 #include <linux/delay.h>
10 #include <linux/gpio/consumer.h>
11 #include <linux/media-bus-format.h>
12 #include <linux/mod_devicetable.h>
13 #include <linux/module.h>
14 #include <linux/regulator/consumer.h>
16 #include <video/display_timing.h>
17 #include <video/mipi_display.h>
19 #include <drm/drm_mipi_dsi.h>
20 #include <drm/drm_modes.h>
21 #include <drm/drm_panel.h>
22 #include <drm/drm_print.h>
24 #define DRV_NAME "panel-rocktech-jh057n00900"
26 /* Manufacturer specific Commands send via DSI */
27 #define ST7703_CMD_ALL_PIXEL_OFF 0x22
28 #define ST7703_CMD_ALL_PIXEL_ON 0x23
29 #define ST7703_CMD_SETDISP 0xB2
30 #define ST7703_CMD_SETRGBIF 0xB3
31 #define ST7703_CMD_SETCYC 0xB4
32 #define ST7703_CMD_SETBGP 0xB5
33 #define ST7703_CMD_SETVCOM 0xB6
34 #define ST7703_CMD_SETOTP 0xB7
35 #define ST7703_CMD_SETPOWER_EXT 0xB8
36 #define ST7703_CMD_SETEXTC 0xB9
37 #define ST7703_CMD_SETMIPI 0xBA
38 #define ST7703_CMD_SETVDC 0xBC
39 #define ST7703_CMD_UNKNOWN0 0xBF
40 #define ST7703_CMD_SETSCR 0xC0
41 #define ST7703_CMD_SETPOWER 0xC1
42 #define ST7703_CMD_SETPANEL 0xCC
43 #define ST7703_CMD_SETGAMMA 0xE0
44 #define ST7703_CMD_SETEQ 0xE3
45 #define ST7703_CMD_SETGIP1 0xE9
46 #define ST7703_CMD_SETGIP2 0xEA
50 struct drm_panel panel
;
51 struct gpio_desc
*reset_gpio
;
52 struct regulator
*vcc
;
53 struct regulator
*iovcc
;
56 struct dentry
*debugfs
;
59 static inline struct jh057n
*panel_to_jh057n(struct drm_panel
*panel
)
61 return container_of(panel
, struct jh057n
, panel
);
64 #define dsi_generic_write_seq(dsi, seq...) do { \
65 static const u8 d[] = { seq }; \
67 ret = mipi_dsi_generic_write(dsi, d, ARRAY_SIZE(d)); \
72 static int jh057n_init_sequence(struct jh057n
*ctx
)
74 struct mipi_dsi_device
*dsi
= to_mipi_dsi_device(ctx
->dev
);
75 struct device
*dev
= ctx
->dev
;
79 * Init sequence was supplied by the panel vendor. Most of the commands
80 * resemble the ST7703 but the number of parameters often don't match
81 * so it's likely a clone.
83 dsi_generic_write_seq(dsi
, ST7703_CMD_SETEXTC
,
85 dsi_generic_write_seq(dsi
, ST7703_CMD_SETRGBIF
,
86 0x10, 0x10, 0x05, 0x05, 0x03, 0xFF, 0x00, 0x00,
88 dsi_generic_write_seq(dsi
, ST7703_CMD_SETSCR
,
89 0x73, 0x73, 0x50, 0x50, 0x00, 0x00, 0x08, 0x70,
91 dsi_generic_write_seq(dsi
, ST7703_CMD_SETVDC
, 0x4E);
92 dsi_generic_write_seq(dsi
, ST7703_CMD_SETPANEL
, 0x0B);
93 dsi_generic_write_seq(dsi
, ST7703_CMD_SETCYC
, 0x80);
94 dsi_generic_write_seq(dsi
, ST7703_CMD_SETDISP
, 0xF0, 0x12, 0x30);
95 dsi_generic_write_seq(dsi
, ST7703_CMD_SETEQ
,
96 0x07, 0x07, 0x0B, 0x0B, 0x03, 0x0B, 0x00, 0x00,
97 0x00, 0x00, 0xFF, 0x00, 0xC0, 0x10);
98 dsi_generic_write_seq(dsi
, ST7703_CMD_SETBGP
, 0x08, 0x08);
101 dsi_generic_write_seq(dsi
, ST7703_CMD_SETVCOM
, 0x3F, 0x3F);
102 dsi_generic_write_seq(dsi
, ST7703_CMD_UNKNOWN0
, 0x02, 0x11, 0x00);
103 dsi_generic_write_seq(dsi
, ST7703_CMD_SETGIP1
,
104 0x82, 0x10, 0x06, 0x05, 0x9E, 0x0A, 0xA5, 0x12,
105 0x31, 0x23, 0x37, 0x83, 0x04, 0xBC, 0x27, 0x38,
106 0x0C, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0C, 0x00,
107 0x03, 0x00, 0x00, 0x00, 0x75, 0x75, 0x31, 0x88,
108 0x88, 0x88, 0x88, 0x88, 0x88, 0x13, 0x88, 0x64,
109 0x64, 0x20, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
110 0x02, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
111 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
112 dsi_generic_write_seq(dsi
, ST7703_CMD_SETGIP2
,
113 0x02, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
114 0x00, 0x00, 0x00, 0x00, 0x02, 0x46, 0x02, 0x88,
115 0x88, 0x88, 0x88, 0x88, 0x88, 0x64, 0x88, 0x13,
116 0x57, 0x13, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
117 0x75, 0x88, 0x23, 0x14, 0x00, 0x00, 0x02, 0x00,
118 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
119 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x0A,
120 0xA5, 0x00, 0x00, 0x00, 0x00);
121 dsi_generic_write_seq(dsi
, ST7703_CMD_SETGAMMA
,
122 0x00, 0x09, 0x0E, 0x29, 0x2D, 0x3C, 0x41, 0x37,
123 0x07, 0x0B, 0x0D, 0x10, 0x11, 0x0F, 0x10, 0x11,
124 0x18, 0x00, 0x09, 0x0E, 0x29, 0x2D, 0x3C, 0x41,
125 0x37, 0x07, 0x0B, 0x0D, 0x10, 0x11, 0x0F, 0x10,
129 ret
= mipi_dsi_dcs_exit_sleep_mode(dsi
);
131 DRM_DEV_ERROR(dev
, "Failed to exit sleep mode: %d\n", ret
);
134 /* Panel is operational 120 msec after reset */
136 ret
= mipi_dsi_dcs_set_display_on(dsi
);
140 DRM_DEV_DEBUG_DRIVER(dev
, "Panel init sequence done\n");
144 static int jh057n_enable(struct drm_panel
*panel
)
146 struct jh057n
*ctx
= panel_to_jh057n(panel
);
149 ret
= jh057n_init_sequence(ctx
);
151 DRM_DEV_ERROR(ctx
->dev
, "Panel init sequence failed: %d\n",
159 static int jh057n_disable(struct drm_panel
*panel
)
161 struct jh057n
*ctx
= panel_to_jh057n(panel
);
162 struct mipi_dsi_device
*dsi
= to_mipi_dsi_device(ctx
->dev
);
164 return mipi_dsi_dcs_set_display_off(dsi
);
167 static int jh057n_unprepare(struct drm_panel
*panel
)
169 struct jh057n
*ctx
= panel_to_jh057n(panel
);
174 regulator_disable(ctx
->iovcc
);
175 regulator_disable(ctx
->vcc
);
176 ctx
->prepared
= false;
181 static int jh057n_prepare(struct drm_panel
*panel
)
183 struct jh057n
*ctx
= panel_to_jh057n(panel
);
189 DRM_DEV_DEBUG_DRIVER(ctx
->dev
, "Resetting the panel\n");
190 ret
= regulator_enable(ctx
->vcc
);
192 DRM_DEV_ERROR(ctx
->dev
,
193 "Failed to enable vcc supply: %d\n", ret
);
196 ret
= regulator_enable(ctx
->iovcc
);
198 DRM_DEV_ERROR(ctx
->dev
,
199 "Failed to enable iovcc supply: %d\n", ret
);
203 gpiod_set_value_cansleep(ctx
->reset_gpio
, 1);
204 usleep_range(20, 40);
205 gpiod_set_value_cansleep(ctx
->reset_gpio
, 0);
208 ctx
->prepared
= true;
213 regulator_disable(ctx
->vcc
);
217 static const struct drm_display_mode default_mode
= {
219 .hsync_start
= 720 + 90,
220 .hsync_end
= 720 + 90 + 20,
221 .htotal
= 720 + 90 + 20 + 20,
223 .vsync_start
= 1440 + 20,
224 .vsync_end
= 1440 + 20 + 4,
225 .vtotal
= 1440 + 20 + 4 + 12,
228 .flags
= DRM_MODE_FLAG_NHSYNC
| DRM_MODE_FLAG_NVSYNC
,
233 static int jh057n_get_modes(struct drm_panel
*panel
,
234 struct drm_connector
*connector
)
236 struct jh057n
*ctx
= panel_to_jh057n(panel
);
237 struct drm_display_mode
*mode
;
239 mode
= drm_mode_duplicate(connector
->dev
, &default_mode
);
241 DRM_DEV_ERROR(ctx
->dev
, "Failed to add mode %ux%u@%u\n",
242 default_mode
.hdisplay
, default_mode
.vdisplay
,
243 default_mode
.vrefresh
);
247 drm_mode_set_name(mode
);
249 mode
->type
= DRM_MODE_TYPE_DRIVER
| DRM_MODE_TYPE_PREFERRED
;
250 connector
->display_info
.width_mm
= mode
->width_mm
;
251 connector
->display_info
.height_mm
= mode
->height_mm
;
252 drm_mode_probed_add(connector
, mode
);
257 static const struct drm_panel_funcs jh057n_drm_funcs
= {
258 .disable
= jh057n_disable
,
259 .unprepare
= jh057n_unprepare
,
260 .prepare
= jh057n_prepare
,
261 .enable
= jh057n_enable
,
262 .get_modes
= jh057n_get_modes
,
265 static int allpixelson_set(void *data
, u64 val
)
267 struct jh057n
*ctx
= data
;
268 struct mipi_dsi_device
*dsi
= to_mipi_dsi_device(ctx
->dev
);
270 DRM_DEV_DEBUG_DRIVER(ctx
->dev
, "Setting all pixels on\n");
271 dsi_generic_write_seq(dsi
, ST7703_CMD_ALL_PIXEL_ON
);
273 /* Reset the panel to get video back */
274 drm_panel_disable(&ctx
->panel
);
275 drm_panel_unprepare(&ctx
->panel
);
276 drm_panel_prepare(&ctx
->panel
);
277 drm_panel_enable(&ctx
->panel
);
282 DEFINE_SIMPLE_ATTRIBUTE(allpixelson_fops
, NULL
,
283 allpixelson_set
, "%llu\n");
285 static void jh057n_debugfs_init(struct jh057n
*ctx
)
287 ctx
->debugfs
= debugfs_create_dir(DRV_NAME
, NULL
);
289 debugfs_create_file("allpixelson", 0600, ctx
->debugfs
, ctx
,
293 static void jh057n_debugfs_remove(struct jh057n
*ctx
)
295 debugfs_remove_recursive(ctx
->debugfs
);
299 static int jh057n_probe(struct mipi_dsi_device
*dsi
)
301 struct device
*dev
= &dsi
->dev
;
305 ctx
= devm_kzalloc(dev
, sizeof(*ctx
), GFP_KERNEL
);
309 ctx
->reset_gpio
= devm_gpiod_get(dev
, "reset", GPIOD_OUT_LOW
);
310 if (IS_ERR(ctx
->reset_gpio
)) {
311 DRM_DEV_ERROR(dev
, "cannot get reset gpio\n");
312 return PTR_ERR(ctx
->reset_gpio
);
315 mipi_dsi_set_drvdata(dsi
, ctx
);
320 dsi
->format
= MIPI_DSI_FMT_RGB888
;
321 dsi
->mode_flags
= MIPI_DSI_MODE_VIDEO
|
322 MIPI_DSI_MODE_VIDEO_BURST
| MIPI_DSI_MODE_VIDEO_SYNC_PULSE
;
324 ctx
->vcc
= devm_regulator_get(dev
, "vcc");
325 if (IS_ERR(ctx
->vcc
)) {
326 ret
= PTR_ERR(ctx
->vcc
);
327 if (ret
!= -EPROBE_DEFER
)
329 "Failed to request vcc regulator: %d\n",
333 ctx
->iovcc
= devm_regulator_get(dev
, "iovcc");
334 if (IS_ERR(ctx
->iovcc
)) {
335 ret
= PTR_ERR(ctx
->iovcc
);
336 if (ret
!= -EPROBE_DEFER
)
338 "Failed to request iovcc regulator: %d\n",
343 drm_panel_init(&ctx
->panel
, dev
, &jh057n_drm_funcs
,
344 DRM_MODE_CONNECTOR_DSI
);
346 ret
= drm_panel_of_backlight(&ctx
->panel
);
350 drm_panel_add(&ctx
->panel
);
352 ret
= mipi_dsi_attach(dsi
);
355 "mipi_dsi_attach failed (%d). Is host ready?\n",
357 drm_panel_remove(&ctx
->panel
);
361 DRM_DEV_INFO(dev
, "%ux%u@%u %ubpp dsi %udl - ready\n",
362 default_mode
.hdisplay
, default_mode
.vdisplay
,
363 default_mode
.vrefresh
,
364 mipi_dsi_pixel_format_to_bpp(dsi
->format
), dsi
->lanes
);
366 jh057n_debugfs_init(ctx
);
370 static void jh057n_shutdown(struct mipi_dsi_device
*dsi
)
372 struct jh057n
*ctx
= mipi_dsi_get_drvdata(dsi
);
375 ret
= drm_panel_unprepare(&ctx
->panel
);
377 DRM_DEV_ERROR(&dsi
->dev
, "Failed to unprepare panel: %d\n",
380 ret
= drm_panel_disable(&ctx
->panel
);
382 DRM_DEV_ERROR(&dsi
->dev
, "Failed to disable panel: %d\n",
386 static int jh057n_remove(struct mipi_dsi_device
*dsi
)
388 struct jh057n
*ctx
= mipi_dsi_get_drvdata(dsi
);
391 jh057n_shutdown(dsi
);
393 ret
= mipi_dsi_detach(dsi
);
395 DRM_DEV_ERROR(&dsi
->dev
, "Failed to detach from DSI host: %d\n",
398 drm_panel_remove(&ctx
->panel
);
400 jh057n_debugfs_remove(ctx
);
405 static const struct of_device_id jh057n_of_match
[] = {
406 { .compatible
= "rocktech,jh057n00900" },
409 MODULE_DEVICE_TABLE(of
, jh057n_of_match
);
411 static struct mipi_dsi_driver jh057n_driver
= {
412 .probe
= jh057n_probe
,
413 .remove
= jh057n_remove
,
414 .shutdown
= jh057n_shutdown
,
417 .of_match_table
= jh057n_of_match
,
420 module_mipi_dsi_driver(jh057n_driver
);
422 MODULE_AUTHOR("Guido Günther <agx@sigxcpu.org>");
423 MODULE_DESCRIPTION("DRM driver for Rocktech JH057N00900 MIPI DSI panel");
424 MODULE_LICENSE("GPL v2");