1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2020 Theobroma Systems Design und Consulting GmbH
6 #include <linux/delay.h>
7 #include <linux/gpio/consumer.h>
8 #include <linux/media-bus-format.h>
9 #include <linux/module.h>
11 #include <linux/of_device.h>
12 #include <linux/regulator/consumer.h>
14 #include <video/display_timing.h>
15 #include <video/mipi_display.h>
17 #include <drm/drm_mipi_dsi.h>
18 #include <drm/drm_modes.h>
19 #include <drm/drm_panel.h>
21 struct ltk050h3146w_cmd
{
27 struct ltk050h3146w_desc
{
28 const struct drm_display_mode
*mode
;
29 int (*init
)(struct ltk050h3146w
*ctx
);
34 struct drm_panel panel
;
35 struct gpio_desc
*reset_gpio
;
36 struct regulator
*vci
;
37 struct regulator
*iovcc
;
38 const struct ltk050h3146w_desc
*panel_desc
;
42 static const struct ltk050h3146w_cmd page1_cmds
[] = {
43 { 0x22, 0x0A }, /* BGR SS GS */
44 { 0x31, 0x00 }, /* column inversion */
45 { 0x53, 0xA2 }, /* VCOM1 */
46 { 0x55, 0xA2 }, /* VCOM2 */
47 { 0x50, 0x81 }, /* VREG1OUT=5V */
48 { 0x51, 0x85 }, /* VREG2OUT=-5V */
49 { 0x62, 0x0D }, /* EQT Time setting */
51 * The vendor init selected page 1 here _again_
52 * Is this supposed to be page 2?
96 static const struct ltk050h3146w_cmd page3_cmds
[] = {
226 static const struct ltk050h3146w_cmd page4_cmds
[] = {
229 { 0x82, 0x0F }, /* VGH_MOD clamp level=15v */
230 { 0x84, 0x0F }, /* VGH clamp level 15V */
231 { 0x85, 0x0D }, /* VGL clamp level (-10V) */
235 { 0xB5, 0x07 }, /* GAMMA OP */
236 { 0x31, 0x45 }, /* SOURCE OP */
237 { 0x3A, 0x24 }, /* PS_EN OFF */
238 { 0x88, 0x33 }, /* LVD */
242 struct ltk050h3146w
*panel_to_ltk050h3146w(struct drm_panel
*panel
)
244 return container_of(panel
, struct ltk050h3146w
, panel
);
247 #define dsi_dcs_write_seq(dsi, cmd, seq...) do { \
248 static const u8 b[] = { cmd, seq }; \
250 ret = mipi_dsi_dcs_write_buffer(dsi, b, ARRAY_SIZE(b)); \
255 static int ltk050h3146w_init_sequence(struct ltk050h3146w
*ctx
)
257 struct mipi_dsi_device
*dsi
= to_mipi_dsi_device(ctx
->dev
);
261 * Init sequence was supplied by the panel vendor without much
264 dsi_dcs_write_seq(dsi
, 0xdf, 0x93, 0x65, 0xf8);
265 dsi_dcs_write_seq(dsi
, 0xb0, 0x01, 0x03, 0x02, 0x00, 0x64, 0x06,
267 dsi_dcs_write_seq(dsi
, 0xb2, 0x00, 0xb5);
268 dsi_dcs_write_seq(dsi
, 0xb3, 0x00, 0xb5);
269 dsi_dcs_write_seq(dsi
, 0xb7, 0x00, 0xbf, 0x00, 0x00, 0xbf, 0x00);
271 dsi_dcs_write_seq(dsi
, 0xb9, 0x00, 0xc4, 0x23, 0x07);
272 dsi_dcs_write_seq(dsi
, 0xbb, 0x02, 0x01, 0x24, 0x00, 0x28, 0x0f,
273 0x28, 0x04, 0xcc, 0xcc, 0xcc);
274 dsi_dcs_write_seq(dsi
, 0xbc, 0x0f, 0x04);
275 dsi_dcs_write_seq(dsi
, 0xbe, 0x1e, 0xf2);
276 dsi_dcs_write_seq(dsi
, 0xc0, 0x26, 0x03);
277 dsi_dcs_write_seq(dsi
, 0xc1, 0x00, 0x12);
278 dsi_dcs_write_seq(dsi
, 0xc3, 0x04, 0x02, 0x02, 0x76, 0x01, 0x80,
280 dsi_dcs_write_seq(dsi
, 0xc4, 0x24, 0x80, 0xb4, 0x81, 0x12, 0x0f,
282 dsi_dcs_write_seq(dsi
, 0xc8, 0x7f, 0x72, 0x67, 0x5d, 0x5d, 0x50,
283 0x56, 0x41, 0x59, 0x57, 0x55, 0x70, 0x5b, 0x5f,
284 0x4f, 0x47, 0x38, 0x23, 0x08, 0x7f, 0x72, 0x67,
285 0x5d, 0x5d, 0x50, 0x56, 0x41, 0x59, 0x57, 0x55,
286 0x70, 0x5b, 0x5f, 0x4f, 0x47, 0x38, 0x23, 0x08);
287 dsi_dcs_write_seq(dsi
, 0xd0, 0x1e, 0x1f, 0x57, 0x58, 0x48, 0x4a,
288 0x44, 0x46, 0x40, 0x1f, 0x42, 0x1f, 0x1f, 0x1f,
289 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f);
290 dsi_dcs_write_seq(dsi
, 0xd1, 0x1e, 0x1f, 0x57, 0x58, 0x49, 0x4b,
291 0x45, 0x47, 0x41, 0x1f, 0x43, 0x1f, 0x1f, 0x1f,
292 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f);
293 dsi_dcs_write_seq(dsi
, 0xd2, 0x1f, 0x1e, 0x17, 0x18, 0x07, 0x05,
294 0x0b, 0x09, 0x03, 0x1f, 0x01, 0x1f, 0x1f, 0x1f,
295 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f);
296 dsi_dcs_write_seq(dsi
, 0xd3, 0x1f, 0x1e, 0x17, 0x18, 0x06, 0x04,
297 0x0a, 0x08, 0x02, 0x1f, 0x00, 0x1f, 0x1f, 0x1f,
298 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f);
299 dsi_dcs_write_seq(dsi
, 0xd4, 0x00, 0x00, 0x00, 0x0c, 0x06, 0x20,
300 0x01, 0x02, 0x00, 0x60, 0x15, 0xb0, 0x30, 0x03,
301 0x04, 0x00, 0x60, 0x72, 0x0a, 0x00, 0x60, 0x08);
302 dsi_dcs_write_seq(dsi
, 0xd5, 0x00, 0x06, 0x06, 0x00, 0x30, 0x00,
303 0x00, 0x00, 0x00, 0x00, 0xbc, 0x50, 0x00, 0x05,
305 dsi_dcs_write_seq(dsi
, 0xdd, 0x2c, 0xa3, 0x00);
306 dsi_dcs_write_seq(dsi
, 0xde, 0x02);
307 dsi_dcs_write_seq(dsi
, 0xb2, 0x32, 0x1c);
308 dsi_dcs_write_seq(dsi
, 0xb7, 0x3b, 0x70, 0x00, 0x04);
309 dsi_dcs_write_seq(dsi
, 0xc1, 0x11);
310 dsi_dcs_write_seq(dsi
, 0xbb, 0x21, 0x22, 0x23, 0x24, 0x36, 0x37);
311 dsi_dcs_write_seq(dsi
, 0xc2, 0x20, 0x38, 0x1e, 0x84);
312 dsi_dcs_write_seq(dsi
, 0xde, 0x00);
314 ret
= mipi_dsi_dcs_set_tear_on(dsi
, 1);
316 dev_err(ctx
->dev
, "failed to set tear on: %d\n", ret
);
325 static const struct drm_display_mode ltk050h3146w_mode
= {
327 .hsync_start
= 720 + 42,
328 .hsync_end
= 720 + 42 + 8,
329 .htotal
= 720 + 42 + 8 + 42,
331 .vsync_start
= 1280 + 12,
332 .vsync_end
= 1280 + 12 + 4,
333 .vtotal
= 1280 + 12 + 4 + 18,
339 static const struct ltk050h3146w_desc ltk050h3146w_data
= {
340 .mode
= <k050h3146w_mode
,
341 .init
= ltk050h3146w_init_sequence
,
344 static int ltk050h3146w_a2_select_page(struct ltk050h3146w
*ctx
, int page
)
346 struct mipi_dsi_device
*dsi
= to_mipi_dsi_device(ctx
->dev
);
347 u8 d
[3] = { 0x98, 0x81, page
};
349 return mipi_dsi_dcs_write(dsi
, 0xff, d
, ARRAY_SIZE(d
));
352 static int ltk050h3146w_a2_write_page(struct ltk050h3146w
*ctx
, int page
,
353 const struct ltk050h3146w_cmd
*cmds
,
356 struct mipi_dsi_device
*dsi
= to_mipi_dsi_device(ctx
->dev
);
359 ret
= ltk050h3146w_a2_select_page(ctx
, page
);
361 dev_err(ctx
->dev
, "failed to select page %d: %d\n", page
, ret
);
365 for (i
= 0; i
< num
; i
++) {
366 ret
= mipi_dsi_generic_write(dsi
, &cmds
[i
],
367 sizeof(struct ltk050h3146w_cmd
));
369 dev_err(ctx
->dev
, "failed to write page %d init cmds: %d\n", page
, ret
);
377 static int ltk050h3146w_a2_init_sequence(struct ltk050h3146w
*ctx
)
379 struct mipi_dsi_device
*dsi
= to_mipi_dsi_device(ctx
->dev
);
383 * Init sequence was supplied by the panel vendor without much
386 ret
= ltk050h3146w_a2_write_page(ctx
, 3, page3_cmds
,
387 ARRAY_SIZE(page3_cmds
));
391 ret
= ltk050h3146w_a2_write_page(ctx
, 4, page4_cmds
,
392 ARRAY_SIZE(page4_cmds
));
396 ret
= ltk050h3146w_a2_write_page(ctx
, 1, page1_cmds
,
397 ARRAY_SIZE(page1_cmds
));
401 ret
= ltk050h3146w_a2_select_page(ctx
, 0);
403 dev_err(ctx
->dev
, "failed to select page 0: %d\n", ret
);
407 /* vendor code called this without param, where there should be one */
408 ret
= mipi_dsi_dcs_set_tear_on(dsi
, 0);
410 dev_err(ctx
->dev
, "failed to set tear on: %d\n", ret
);
419 static const struct drm_display_mode ltk050h3146w_a2_mode
= {
421 .hsync_start
= 720 + 42,
422 .hsync_end
= 720 + 42 + 10,
423 .htotal
= 720 + 42 + 10 + 60,
425 .vsync_start
= 1280 + 18,
426 .vsync_end
= 1280 + 18 + 4,
427 .vtotal
= 1280 + 18 + 4 + 12,
433 static const struct ltk050h3146w_desc ltk050h3146w_a2_data
= {
434 .mode
= <k050h3146w_a2_mode
,
435 .init
= ltk050h3146w_a2_init_sequence
,
438 static int ltk050h3146w_unprepare(struct drm_panel
*panel
)
440 struct ltk050h3146w
*ctx
= panel_to_ltk050h3146w(panel
);
441 struct mipi_dsi_device
*dsi
= to_mipi_dsi_device(ctx
->dev
);
447 ret
= mipi_dsi_dcs_set_display_off(dsi
);
449 dev_err(ctx
->dev
, "failed to set display off: %d\n", ret
);
453 mipi_dsi_dcs_enter_sleep_mode(dsi
);
455 dev_err(ctx
->dev
, "failed to enter sleep mode: %d\n", ret
);
459 regulator_disable(ctx
->iovcc
);
460 regulator_disable(ctx
->vci
);
462 ctx
->prepared
= false;
467 static int ltk050h3146w_prepare(struct drm_panel
*panel
)
469 struct ltk050h3146w
*ctx
= panel_to_ltk050h3146w(panel
);
470 struct mipi_dsi_device
*dsi
= to_mipi_dsi_device(ctx
->dev
);
476 dev_dbg(ctx
->dev
, "Resetting the panel\n");
477 ret
= regulator_enable(ctx
->vci
);
479 dev_err(ctx
->dev
, "Failed to enable vci supply: %d\n", ret
);
482 ret
= regulator_enable(ctx
->iovcc
);
484 dev_err(ctx
->dev
, "Failed to enable iovcc supply: %d\n", ret
);
488 gpiod_set_value_cansleep(ctx
->reset_gpio
, 1);
489 usleep_range(5000, 6000);
490 gpiod_set_value_cansleep(ctx
->reset_gpio
, 0);
493 ret
= ctx
->panel_desc
->init(ctx
);
495 dev_err(ctx
->dev
, "Panel init sequence failed: %d\n", ret
);
499 ret
= mipi_dsi_dcs_exit_sleep_mode(dsi
);
501 dev_err(ctx
->dev
, "Failed to exit sleep mode: %d\n", ret
);
508 ret
= mipi_dsi_dcs_set_display_on(dsi
);
510 dev_err(ctx
->dev
, "Failed to set display on: %d\n", ret
);
516 ctx
->prepared
= true;
521 regulator_disable(ctx
->iovcc
);
523 regulator_disable(ctx
->vci
);
527 static int ltk050h3146w_get_modes(struct drm_panel
*panel
,
528 struct drm_connector
*connector
)
530 struct ltk050h3146w
*ctx
= panel_to_ltk050h3146w(panel
);
531 struct drm_display_mode
*mode
;
533 mode
= drm_mode_duplicate(connector
->dev
, ctx
->panel_desc
->mode
);
537 drm_mode_set_name(mode
);
539 mode
->type
= DRM_MODE_TYPE_DRIVER
| DRM_MODE_TYPE_PREFERRED
;
540 connector
->display_info
.width_mm
= mode
->width_mm
;
541 connector
->display_info
.height_mm
= mode
->height_mm
;
542 drm_mode_probed_add(connector
, mode
);
547 static const struct drm_panel_funcs ltk050h3146w_funcs
= {
548 .unprepare
= ltk050h3146w_unprepare
,
549 .prepare
= ltk050h3146w_prepare
,
550 .get_modes
= ltk050h3146w_get_modes
,
553 static int ltk050h3146w_probe(struct mipi_dsi_device
*dsi
)
555 struct device
*dev
= &dsi
->dev
;
556 struct ltk050h3146w
*ctx
;
559 ctx
= devm_kzalloc(dev
, sizeof(*ctx
), GFP_KERNEL
);
563 ctx
->panel_desc
= of_device_get_match_data(dev
);
564 if (!ctx
->panel_desc
)
567 ctx
->reset_gpio
= devm_gpiod_get_optional(dev
, "reset", GPIOD_OUT_LOW
);
568 if (IS_ERR(ctx
->reset_gpio
)) {
569 dev_err(dev
, "cannot get reset gpio\n");
570 return PTR_ERR(ctx
->reset_gpio
);
573 ctx
->vci
= devm_regulator_get(dev
, "vci");
574 if (IS_ERR(ctx
->vci
)) {
575 ret
= PTR_ERR(ctx
->vci
);
576 if (ret
!= -EPROBE_DEFER
)
577 dev_err(dev
, "Failed to request vci regulator: %d\n", ret
);
581 ctx
->iovcc
= devm_regulator_get(dev
, "iovcc");
582 if (IS_ERR(ctx
->iovcc
)) {
583 ret
= PTR_ERR(ctx
->iovcc
);
584 if (ret
!= -EPROBE_DEFER
)
585 dev_err(dev
, "Failed to request iovcc regulator: %d\n", ret
);
589 mipi_dsi_set_drvdata(dsi
, ctx
);
594 dsi
->format
= MIPI_DSI_FMT_RGB888
;
595 dsi
->mode_flags
= MIPI_DSI_MODE_VIDEO
| MIPI_DSI_MODE_VIDEO_BURST
|
596 MIPI_DSI_MODE_LPM
| MIPI_DSI_MODE_EOT_PACKET
;
598 drm_panel_init(&ctx
->panel
, &dsi
->dev
, <k050h3146w_funcs
,
599 DRM_MODE_CONNECTOR_DSI
);
601 ret
= drm_panel_of_backlight(&ctx
->panel
);
605 drm_panel_add(&ctx
->panel
);
607 ret
= mipi_dsi_attach(dsi
);
609 dev_err(dev
, "mipi_dsi_attach failed: %d\n", ret
);
610 drm_panel_remove(&ctx
->panel
);
617 static void ltk050h3146w_shutdown(struct mipi_dsi_device
*dsi
)
619 struct ltk050h3146w
*ctx
= mipi_dsi_get_drvdata(dsi
);
622 ret
= drm_panel_unprepare(&ctx
->panel
);
624 dev_err(&dsi
->dev
, "Failed to unprepare panel: %d\n", ret
);
626 ret
= drm_panel_disable(&ctx
->panel
);
628 dev_err(&dsi
->dev
, "Failed to disable panel: %d\n", ret
);
631 static int ltk050h3146w_remove(struct mipi_dsi_device
*dsi
)
633 struct ltk050h3146w
*ctx
= mipi_dsi_get_drvdata(dsi
);
636 ltk050h3146w_shutdown(dsi
);
638 ret
= mipi_dsi_detach(dsi
);
640 dev_err(&dsi
->dev
, "Failed to detach from DSI host: %d\n", ret
);
642 drm_panel_remove(&ctx
->panel
);
647 static const struct of_device_id ltk050h3146w_of_match
[] = {
649 .compatible
= "leadtek,ltk050h3146w",
650 .data
= <k050h3146w_data
,
653 .compatible
= "leadtek,ltk050h3146w-a2",
654 .data
= <k050h3146w_a2_data
,
658 MODULE_DEVICE_TABLE(of
, ltk050h3146w_of_match
);
660 static struct mipi_dsi_driver ltk050h3146w_driver
= {
662 .name
= "panel-leadtek-ltk050h3146w",
663 .of_match_table
= ltk050h3146w_of_match
,
665 .probe
= ltk050h3146w_probe
,
666 .remove
= ltk050h3146w_remove
,
667 .shutdown
= ltk050h3146w_shutdown
,
669 module_mipi_dsi_driver(ltk050h3146w_driver
);
671 MODULE_AUTHOR("Heiko Stuebner <heiko.stuebner@theobroma-systems.com>");
672 MODULE_DESCRIPTION("DRM driver for Leadtek LTK050H3146W MIPI DSI panel");
673 MODULE_LICENSE("GPL v2");