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/regulator/consumer.h>
13 #include <video/display_timing.h>
14 #include <video/mipi_display.h>
16 #include <drm/drm_mipi_dsi.h>
17 #include <drm/drm_modes.h>
18 #include <drm/drm_panel.h>
20 struct ltk050h3146w_cmd {
26 struct ltk050h3146w_desc {
27 const struct drm_display_mode *mode;
28 int (*init)(struct ltk050h3146w *ctx);
33 struct drm_panel panel;
34 struct gpio_desc *reset_gpio;
35 struct regulator *vci;
36 struct regulator *iovcc;
37 const struct ltk050h3146w_desc *panel_desc;
41 static const struct ltk050h3146w_cmd page1_cmds[] = {
42 { 0x22, 0x0A }, /* BGR SS GS */
43 { 0x31, 0x00 }, /* column inversion */
44 { 0x53, 0xA2 }, /* VCOM1 */
45 { 0x55, 0xA2 }, /* VCOM2 */
46 { 0x50, 0x81 }, /* VREG1OUT=5V */
47 { 0x51, 0x85 }, /* VREG2OUT=-5V */
48 { 0x62, 0x0D }, /* EQT Time setting */
50 * The vendor init selected page 1 here _again_
51 * Is this supposed to be page 2?
95 static const struct ltk050h3146w_cmd page3_cmds[] = {
225 static const struct ltk050h3146w_cmd page4_cmds[] = {
228 { 0x82, 0x0F }, /* VGH_MOD clamp level=15v */
229 { 0x84, 0x0F }, /* VGH clamp level 15V */
230 { 0x85, 0x0D }, /* VGL clamp level (-10V) */
234 { 0xB5, 0x07 }, /* GAMMA OP */
235 { 0x31, 0x45 }, /* SOURCE OP */
236 { 0x3A, 0x24 }, /* PS_EN OFF */
237 { 0x88, 0x33 }, /* LVD */
241 struct ltk050h3146w *panel_to_ltk050h3146w(struct drm_panel *panel)
243 return container_of(panel, struct ltk050h3146w, panel);
246 static int ltk050h3146w_init_sequence(struct ltk050h3146w *ctx)
248 struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
252 * Init sequence was supplied by the panel vendor without much
255 mipi_dsi_dcs_write_seq(dsi, 0xdf, 0x93, 0x65, 0xf8);
256 mipi_dsi_dcs_write_seq(dsi, 0xb0, 0x01, 0x03, 0x02, 0x00, 0x64, 0x06,
258 mipi_dsi_dcs_write_seq(dsi, 0xb2, 0x00, 0xb5);
259 mipi_dsi_dcs_write_seq(dsi, 0xb3, 0x00, 0xb5);
260 mipi_dsi_dcs_write_seq(dsi, 0xb7, 0x00, 0xbf, 0x00, 0x00, 0xbf, 0x00);
262 mipi_dsi_dcs_write_seq(dsi, 0xb9, 0x00, 0xc4, 0x23, 0x07);
263 mipi_dsi_dcs_write_seq(dsi, 0xbb, 0x02, 0x01, 0x24, 0x00, 0x28, 0x0f,
264 0x28, 0x04, 0xcc, 0xcc, 0xcc);
265 mipi_dsi_dcs_write_seq(dsi, 0xbc, 0x0f, 0x04);
266 mipi_dsi_dcs_write_seq(dsi, 0xbe, 0x1e, 0xf2);
267 mipi_dsi_dcs_write_seq(dsi, 0xc0, 0x26, 0x03);
268 mipi_dsi_dcs_write_seq(dsi, 0xc1, 0x00, 0x12);
269 mipi_dsi_dcs_write_seq(dsi, 0xc3, 0x04, 0x02, 0x02, 0x76, 0x01, 0x80,
271 mipi_dsi_dcs_write_seq(dsi, 0xc4, 0x24, 0x80, 0xb4, 0x81, 0x12, 0x0f,
273 mipi_dsi_dcs_write_seq(dsi, 0xc8, 0x7f, 0x72, 0x67, 0x5d, 0x5d, 0x50,
274 0x56, 0x41, 0x59, 0x57, 0x55, 0x70, 0x5b, 0x5f,
275 0x4f, 0x47, 0x38, 0x23, 0x08, 0x7f, 0x72, 0x67,
276 0x5d, 0x5d, 0x50, 0x56, 0x41, 0x59, 0x57, 0x55,
277 0x70, 0x5b, 0x5f, 0x4f, 0x47, 0x38, 0x23, 0x08);
278 mipi_dsi_dcs_write_seq(dsi, 0xd0, 0x1e, 0x1f, 0x57, 0x58, 0x48, 0x4a,
279 0x44, 0x46, 0x40, 0x1f, 0x42, 0x1f, 0x1f, 0x1f,
280 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f);
281 mipi_dsi_dcs_write_seq(dsi, 0xd1, 0x1e, 0x1f, 0x57, 0x58, 0x49, 0x4b,
282 0x45, 0x47, 0x41, 0x1f, 0x43, 0x1f, 0x1f, 0x1f,
283 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f);
284 mipi_dsi_dcs_write_seq(dsi, 0xd2, 0x1f, 0x1e, 0x17, 0x18, 0x07, 0x05,
285 0x0b, 0x09, 0x03, 0x1f, 0x01, 0x1f, 0x1f, 0x1f,
286 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f);
287 mipi_dsi_dcs_write_seq(dsi, 0xd3, 0x1f, 0x1e, 0x17, 0x18, 0x06, 0x04,
288 0x0a, 0x08, 0x02, 0x1f, 0x00, 0x1f, 0x1f, 0x1f,
289 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f);
290 mipi_dsi_dcs_write_seq(dsi, 0xd4, 0x00, 0x00, 0x00, 0x0c, 0x06, 0x20,
291 0x01, 0x02, 0x00, 0x60, 0x15, 0xb0, 0x30, 0x03,
292 0x04, 0x00, 0x60, 0x72, 0x0a, 0x00, 0x60, 0x08);
293 mipi_dsi_dcs_write_seq(dsi, 0xd5, 0x00, 0x06, 0x06, 0x00, 0x30, 0x00,
294 0x00, 0x00, 0x00, 0x00, 0xbc, 0x50, 0x00, 0x05,
296 mipi_dsi_dcs_write_seq(dsi, 0xdd, 0x2c, 0xa3, 0x00);
297 mipi_dsi_dcs_write_seq(dsi, 0xde, 0x02);
298 mipi_dsi_dcs_write_seq(dsi, 0xb2, 0x32, 0x1c);
299 mipi_dsi_dcs_write_seq(dsi, 0xb7, 0x3b, 0x70, 0x00, 0x04);
300 mipi_dsi_dcs_write_seq(dsi, 0xc1, 0x11);
301 mipi_dsi_dcs_write_seq(dsi, 0xbb, 0x21, 0x22, 0x23, 0x24, 0x36, 0x37);
302 mipi_dsi_dcs_write_seq(dsi, 0xc2, 0x20, 0x38, 0x1e, 0x84);
303 mipi_dsi_dcs_write_seq(dsi, 0xde, 0x00);
305 ret = mipi_dsi_dcs_set_tear_on(dsi, 1);
307 dev_err(ctx->dev, "failed to set tear on: %d\n", ret);
316 static const struct drm_display_mode ltk050h3146w_mode = {
318 .hsync_start = 720 + 42,
319 .hsync_end = 720 + 42 + 8,
320 .htotal = 720 + 42 + 8 + 42,
322 .vsync_start = 1280 + 12,
323 .vsync_end = 1280 + 12 + 4,
324 .vtotal = 1280 + 12 + 4 + 18,
330 static const struct ltk050h3146w_desc ltk050h3146w_data = {
331 .mode = <k050h3146w_mode,
332 .init = ltk050h3146w_init_sequence,
335 static int ltk050h3146w_a2_select_page(struct ltk050h3146w *ctx, int page)
337 struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
338 u8 d[3] = { 0x98, 0x81, page };
340 return mipi_dsi_dcs_write(dsi, 0xff, d, ARRAY_SIZE(d));
343 static int ltk050h3146w_a2_write_page(struct ltk050h3146w *ctx, int page,
344 const struct ltk050h3146w_cmd *cmds,
347 struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
350 ret = ltk050h3146w_a2_select_page(ctx, page);
352 dev_err(ctx->dev, "failed to select page %d: %d\n", page, ret);
356 for (i = 0; i < num; i++) {
357 ret = mipi_dsi_generic_write(dsi, &cmds[i],
358 sizeof(struct ltk050h3146w_cmd));
360 dev_err(ctx->dev, "failed to write page %d init cmds: %d\n", page, ret);
368 static int ltk050h3146w_a2_init_sequence(struct ltk050h3146w *ctx)
370 struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
374 * Init sequence was supplied by the panel vendor without much
377 ret = ltk050h3146w_a2_write_page(ctx, 3, page3_cmds,
378 ARRAY_SIZE(page3_cmds));
382 ret = ltk050h3146w_a2_write_page(ctx, 4, page4_cmds,
383 ARRAY_SIZE(page4_cmds));
387 ret = ltk050h3146w_a2_write_page(ctx, 1, page1_cmds,
388 ARRAY_SIZE(page1_cmds));
392 ret = ltk050h3146w_a2_select_page(ctx, 0);
394 dev_err(ctx->dev, "failed to select page 0: %d\n", ret);
398 /* vendor code called this without param, where there should be one */
399 ret = mipi_dsi_dcs_set_tear_on(dsi, 0);
401 dev_err(ctx->dev, "failed to set tear on: %d\n", ret);
410 static const struct drm_display_mode ltk050h3146w_a2_mode = {
412 .hsync_start = 720 + 42,
413 .hsync_end = 720 + 42 + 10,
414 .htotal = 720 + 42 + 10 + 60,
416 .vsync_start = 1280 + 18,
417 .vsync_end = 1280 + 18 + 4,
418 .vtotal = 1280 + 18 + 4 + 12,
424 static const struct ltk050h3146w_desc ltk050h3146w_a2_data = {
425 .mode = <k050h3146w_a2_mode,
426 .init = ltk050h3146w_a2_init_sequence,
429 static int ltk050h3146w_unprepare(struct drm_panel *panel)
431 struct ltk050h3146w *ctx = panel_to_ltk050h3146w(panel);
432 struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
438 ret = mipi_dsi_dcs_set_display_off(dsi);
440 dev_err(ctx->dev, "failed to set display off: %d\n", ret);
444 mipi_dsi_dcs_enter_sleep_mode(dsi);
446 dev_err(ctx->dev, "failed to enter sleep mode: %d\n", ret);
450 regulator_disable(ctx->iovcc);
451 regulator_disable(ctx->vci);
453 ctx->prepared = false;
458 static int ltk050h3146w_prepare(struct drm_panel *panel)
460 struct ltk050h3146w *ctx = panel_to_ltk050h3146w(panel);
461 struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
467 dev_dbg(ctx->dev, "Resetting the panel\n");
468 ret = regulator_enable(ctx->vci);
470 dev_err(ctx->dev, "Failed to enable vci supply: %d\n", ret);
473 ret = regulator_enable(ctx->iovcc);
475 dev_err(ctx->dev, "Failed to enable iovcc supply: %d\n", ret);
479 gpiod_set_value_cansleep(ctx->reset_gpio, 1);
480 usleep_range(5000, 6000);
481 gpiod_set_value_cansleep(ctx->reset_gpio, 0);
484 ret = ctx->panel_desc->init(ctx);
486 dev_err(ctx->dev, "Panel init sequence failed: %d\n", ret);
490 ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
492 dev_err(ctx->dev, "Failed to exit sleep mode: %d\n", ret);
499 ret = mipi_dsi_dcs_set_display_on(dsi);
501 dev_err(ctx->dev, "Failed to set display on: %d\n", ret);
507 ctx->prepared = true;
512 regulator_disable(ctx->iovcc);
514 regulator_disable(ctx->vci);
518 static int ltk050h3146w_get_modes(struct drm_panel *panel,
519 struct drm_connector *connector)
521 struct ltk050h3146w *ctx = panel_to_ltk050h3146w(panel);
522 struct drm_display_mode *mode;
524 mode = drm_mode_duplicate(connector->dev, ctx->panel_desc->mode);
528 drm_mode_set_name(mode);
530 mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
531 connector->display_info.width_mm = mode->width_mm;
532 connector->display_info.height_mm = mode->height_mm;
533 drm_mode_probed_add(connector, mode);
538 static const struct drm_panel_funcs ltk050h3146w_funcs = {
539 .unprepare = ltk050h3146w_unprepare,
540 .prepare = ltk050h3146w_prepare,
541 .get_modes = ltk050h3146w_get_modes,
544 static int ltk050h3146w_probe(struct mipi_dsi_device *dsi)
546 struct device *dev = &dsi->dev;
547 struct ltk050h3146w *ctx;
550 ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
554 ctx->panel_desc = of_device_get_match_data(dev);
555 if (!ctx->panel_desc)
558 ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
559 if (IS_ERR(ctx->reset_gpio)) {
560 dev_err(dev, "cannot get reset gpio\n");
561 return PTR_ERR(ctx->reset_gpio);
564 ctx->vci = devm_regulator_get(dev, "vci");
565 if (IS_ERR(ctx->vci)) {
566 ret = PTR_ERR(ctx->vci);
567 if (ret != -EPROBE_DEFER)
568 dev_err(dev, "Failed to request vci regulator: %d\n", ret);
572 ctx->iovcc = devm_regulator_get(dev, "iovcc");
573 if (IS_ERR(ctx->iovcc)) {
574 ret = PTR_ERR(ctx->iovcc);
575 if (ret != -EPROBE_DEFER)
576 dev_err(dev, "Failed to request iovcc regulator: %d\n", ret);
580 mipi_dsi_set_drvdata(dsi, ctx);
585 dsi->format = MIPI_DSI_FMT_RGB888;
586 dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
587 MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_NO_EOT_PACKET;
589 drm_panel_init(&ctx->panel, &dsi->dev, <k050h3146w_funcs,
590 DRM_MODE_CONNECTOR_DSI);
592 ret = drm_panel_of_backlight(&ctx->panel);
596 drm_panel_add(&ctx->panel);
598 ret = mipi_dsi_attach(dsi);
600 dev_err(dev, "mipi_dsi_attach failed: %d\n", ret);
601 drm_panel_remove(&ctx->panel);
608 static void ltk050h3146w_shutdown(struct mipi_dsi_device *dsi)
610 struct ltk050h3146w *ctx = mipi_dsi_get_drvdata(dsi);
613 ret = drm_panel_unprepare(&ctx->panel);
615 dev_err(&dsi->dev, "Failed to unprepare panel: %d\n", ret);
617 ret = drm_panel_disable(&ctx->panel);
619 dev_err(&dsi->dev, "Failed to disable panel: %d\n", ret);
622 static void ltk050h3146w_remove(struct mipi_dsi_device *dsi)
624 struct ltk050h3146w *ctx = mipi_dsi_get_drvdata(dsi);
627 ltk050h3146w_shutdown(dsi);
629 ret = mipi_dsi_detach(dsi);
631 dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret);
633 drm_panel_remove(&ctx->panel);
636 static const struct of_device_id ltk050h3146w_of_match[] = {
638 .compatible = "leadtek,ltk050h3146w",
639 .data = <k050h3146w_data,
642 .compatible = "leadtek,ltk050h3146w-a2",
643 .data = <k050h3146w_a2_data,
647 MODULE_DEVICE_TABLE(of, ltk050h3146w_of_match);
649 static struct mipi_dsi_driver ltk050h3146w_driver = {
651 .name = "panel-leadtek-ltk050h3146w",
652 .of_match_table = ltk050h3146w_of_match,
654 .probe = ltk050h3146w_probe,
655 .remove = ltk050h3146w_remove,
656 .shutdown = ltk050h3146w_shutdown,
658 module_mipi_dsi_driver(ltk050h3146w_driver);
660 MODULE_AUTHOR("Heiko Stuebner <heiko.stuebner@theobroma-systems.com>");
661 MODULE_DESCRIPTION("DRM driver for Leadtek LTK050H3146W MIPI DSI panel");
662 MODULE_LICENSE("GPL v2");