16ea4383bSHeiko Stuebner // SPDX-License-Identifier: GPL-2.0
26ea4383bSHeiko Stuebner /*
36ea4383bSHeiko Stuebner * Copyright (C) 2020 Theobroma Systems Design und Consulting GmbH
46ea4383bSHeiko Stuebner */
56ea4383bSHeiko Stuebner
66ea4383bSHeiko Stuebner #include <linux/delay.h>
76ea4383bSHeiko Stuebner #include <linux/gpio/consumer.h>
86ea4383bSHeiko Stuebner #include <linux/media-bus-format.h>
96ea4383bSHeiko Stuebner #include <linux/module.h>
106ea4383bSHeiko Stuebner #include <linux/of.h>
116ea4383bSHeiko Stuebner #include <linux/regulator/consumer.h>
126ea4383bSHeiko Stuebner
136ea4383bSHeiko Stuebner #include <video/display_timing.h>
146ea4383bSHeiko Stuebner #include <video/mipi_display.h>
156ea4383bSHeiko Stuebner
166ea4383bSHeiko Stuebner #include <drm/drm_mipi_dsi.h>
176ea4383bSHeiko Stuebner #include <drm/drm_modes.h>
186ea4383bSHeiko Stuebner #include <drm/drm_panel.h>
196ea4383bSHeiko Stuebner
206ea4383bSHeiko Stuebner struct ltk050h3146w_cmd {
216ea4383bSHeiko Stuebner char cmd;
226ea4383bSHeiko Stuebner char data;
236ea4383bSHeiko Stuebner };
246ea4383bSHeiko Stuebner
256ea4383bSHeiko Stuebner struct ltk050h3146w;
266ea4383bSHeiko Stuebner struct ltk050h3146w_desc {
276ea4383bSHeiko Stuebner const struct drm_display_mode *mode;
286ea4383bSHeiko Stuebner int (*init)(struct ltk050h3146w *ctx);
296ea4383bSHeiko Stuebner };
306ea4383bSHeiko Stuebner
316ea4383bSHeiko Stuebner struct ltk050h3146w {
326ea4383bSHeiko Stuebner struct device *dev;
336ea4383bSHeiko Stuebner struct drm_panel panel;
346ea4383bSHeiko Stuebner struct gpio_desc *reset_gpio;
356ea4383bSHeiko Stuebner struct regulator *vci;
366ea4383bSHeiko Stuebner struct regulator *iovcc;
376ea4383bSHeiko Stuebner const struct ltk050h3146w_desc *panel_desc;
386ea4383bSHeiko Stuebner bool prepared;
396ea4383bSHeiko Stuebner };
406ea4383bSHeiko Stuebner
416ea4383bSHeiko Stuebner static const struct ltk050h3146w_cmd page1_cmds[] = {
426ea4383bSHeiko Stuebner { 0x22, 0x0A }, /* BGR SS GS */
436ea4383bSHeiko Stuebner { 0x31, 0x00 }, /* column inversion */
446ea4383bSHeiko Stuebner { 0x53, 0xA2 }, /* VCOM1 */
456ea4383bSHeiko Stuebner { 0x55, 0xA2 }, /* VCOM2 */
466ea4383bSHeiko Stuebner { 0x50, 0x81 }, /* VREG1OUT=5V */
476ea4383bSHeiko Stuebner { 0x51, 0x85 }, /* VREG2OUT=-5V */
486ea4383bSHeiko Stuebner { 0x62, 0x0D }, /* EQT Time setting */
496ea4383bSHeiko Stuebner /*
506ea4383bSHeiko Stuebner * The vendor init selected page 1 here _again_
516ea4383bSHeiko Stuebner * Is this supposed to be page 2?
526ea4383bSHeiko Stuebner */
536ea4383bSHeiko Stuebner { 0xA0, 0x00 },
546ea4383bSHeiko Stuebner { 0xA1, 0x1A },
556ea4383bSHeiko Stuebner { 0xA2, 0x28 },
566ea4383bSHeiko Stuebner { 0xA3, 0x13 },
576ea4383bSHeiko Stuebner { 0xA4, 0x16 },
586ea4383bSHeiko Stuebner { 0xA5, 0x29 },
596ea4383bSHeiko Stuebner { 0xA6, 0x1D },
606ea4383bSHeiko Stuebner { 0xA7, 0x1E },
616ea4383bSHeiko Stuebner { 0xA8, 0x84 },
626ea4383bSHeiko Stuebner { 0xA9, 0x1C },
636ea4383bSHeiko Stuebner { 0xAA, 0x28 },
646ea4383bSHeiko Stuebner { 0xAB, 0x75 },
656ea4383bSHeiko Stuebner { 0xAC, 0x1A },
666ea4383bSHeiko Stuebner { 0xAD, 0x19 },
676ea4383bSHeiko Stuebner { 0xAE, 0x4D },
686ea4383bSHeiko Stuebner { 0xAF, 0x22 },
696ea4383bSHeiko Stuebner { 0xB0, 0x28 },
706ea4383bSHeiko Stuebner { 0xB1, 0x54 },
716ea4383bSHeiko Stuebner { 0xB2, 0x66 },
726ea4383bSHeiko Stuebner { 0xB3, 0x39 },
736ea4383bSHeiko Stuebner { 0xC0, 0x00 },
746ea4383bSHeiko Stuebner { 0xC1, 0x1A },
756ea4383bSHeiko Stuebner { 0xC2, 0x28 },
766ea4383bSHeiko Stuebner { 0xC3, 0x13 },
776ea4383bSHeiko Stuebner { 0xC4, 0x16 },
786ea4383bSHeiko Stuebner { 0xC5, 0x29 },
796ea4383bSHeiko Stuebner { 0xC6, 0x1D },
806ea4383bSHeiko Stuebner { 0xC7, 0x1E },
816ea4383bSHeiko Stuebner { 0xC8, 0x84 },
826ea4383bSHeiko Stuebner { 0xC9, 0x1C },
836ea4383bSHeiko Stuebner { 0xCA, 0x28 },
846ea4383bSHeiko Stuebner { 0xCB, 0x75 },
856ea4383bSHeiko Stuebner { 0xCC, 0x1A },
866ea4383bSHeiko Stuebner { 0xCD, 0x19 },
876ea4383bSHeiko Stuebner { 0xCE, 0x4D },
886ea4383bSHeiko Stuebner { 0xCF, 0x22 },
896ea4383bSHeiko Stuebner { 0xD0, 0x28 },
906ea4383bSHeiko Stuebner { 0xD1, 0x54 },
916ea4383bSHeiko Stuebner { 0xD2, 0x66 },
926ea4383bSHeiko Stuebner { 0xD3, 0x39 },
936ea4383bSHeiko Stuebner };
946ea4383bSHeiko Stuebner
956ea4383bSHeiko Stuebner static const struct ltk050h3146w_cmd page3_cmds[] = {
966ea4383bSHeiko Stuebner { 0x01, 0x00 },
976ea4383bSHeiko Stuebner { 0x02, 0x00 },
986ea4383bSHeiko Stuebner { 0x03, 0x73 },
996ea4383bSHeiko Stuebner { 0x04, 0x00 },
1006ea4383bSHeiko Stuebner { 0x05, 0x00 },
1016ea4383bSHeiko Stuebner { 0x06, 0x0a },
1026ea4383bSHeiko Stuebner { 0x07, 0x00 },
1036ea4383bSHeiko Stuebner { 0x08, 0x00 },
1046ea4383bSHeiko Stuebner { 0x09, 0x01 },
1056ea4383bSHeiko Stuebner { 0x0a, 0x00 },
1066ea4383bSHeiko Stuebner { 0x0b, 0x00 },
1076ea4383bSHeiko Stuebner { 0x0c, 0x01 },
1086ea4383bSHeiko Stuebner { 0x0d, 0x00 },
1096ea4383bSHeiko Stuebner { 0x0e, 0x00 },
1106ea4383bSHeiko Stuebner { 0x0f, 0x1d },
1116ea4383bSHeiko Stuebner { 0x10, 0x1d },
1126ea4383bSHeiko Stuebner { 0x11, 0x00 },
1136ea4383bSHeiko Stuebner { 0x12, 0x00 },
1146ea4383bSHeiko Stuebner { 0x13, 0x00 },
1156ea4383bSHeiko Stuebner { 0x14, 0x00 },
1166ea4383bSHeiko Stuebner { 0x15, 0x00 },
1176ea4383bSHeiko Stuebner { 0x16, 0x00 },
1186ea4383bSHeiko Stuebner { 0x17, 0x00 },
1196ea4383bSHeiko Stuebner { 0x18, 0x00 },
1206ea4383bSHeiko Stuebner { 0x19, 0x00 },
1216ea4383bSHeiko Stuebner { 0x1a, 0x00 },
1226ea4383bSHeiko Stuebner { 0x1b, 0x00 },
1236ea4383bSHeiko Stuebner { 0x1c, 0x00 },
1246ea4383bSHeiko Stuebner { 0x1d, 0x00 },
1256ea4383bSHeiko Stuebner { 0x1e, 0x40 },
1266ea4383bSHeiko Stuebner { 0x1f, 0x80 },
1276ea4383bSHeiko Stuebner { 0x20, 0x06 },
1286ea4383bSHeiko Stuebner { 0x21, 0x02 },
1296ea4383bSHeiko Stuebner { 0x22, 0x00 },
1306ea4383bSHeiko Stuebner { 0x23, 0x00 },
1316ea4383bSHeiko Stuebner { 0x24, 0x00 },
1326ea4383bSHeiko Stuebner { 0x25, 0x00 },
1336ea4383bSHeiko Stuebner { 0x26, 0x00 },
1346ea4383bSHeiko Stuebner { 0x27, 0x00 },
1356ea4383bSHeiko Stuebner { 0x28, 0x33 },
1366ea4383bSHeiko Stuebner { 0x29, 0x03 },
1376ea4383bSHeiko Stuebner { 0x2a, 0x00 },
1386ea4383bSHeiko Stuebner { 0x2b, 0x00 },
1396ea4383bSHeiko Stuebner { 0x2c, 0x00 },
1406ea4383bSHeiko Stuebner { 0x2d, 0x00 },
1416ea4383bSHeiko Stuebner { 0x2e, 0x00 },
1426ea4383bSHeiko Stuebner { 0x2f, 0x00 },
1436ea4383bSHeiko Stuebner { 0x30, 0x00 },
1446ea4383bSHeiko Stuebner { 0x31, 0x00 },
1456ea4383bSHeiko Stuebner { 0x32, 0x00 },
1466ea4383bSHeiko Stuebner { 0x33, 0x00 },
1476ea4383bSHeiko Stuebner { 0x34, 0x04 },
1486ea4383bSHeiko Stuebner { 0x35, 0x00 },
1496ea4383bSHeiko Stuebner { 0x36, 0x00 },
1506ea4383bSHeiko Stuebner { 0x37, 0x00 },
1516ea4383bSHeiko Stuebner { 0x38, 0x3C },
1526ea4383bSHeiko Stuebner { 0x39, 0x35 },
1536ea4383bSHeiko Stuebner { 0x3A, 0x01 },
1546ea4383bSHeiko Stuebner { 0x3B, 0x40 },
1556ea4383bSHeiko Stuebner { 0x3C, 0x00 },
1566ea4383bSHeiko Stuebner { 0x3D, 0x01 },
1576ea4383bSHeiko Stuebner { 0x3E, 0x00 },
1586ea4383bSHeiko Stuebner { 0x3F, 0x00 },
1596ea4383bSHeiko Stuebner { 0x40, 0x00 },
1606ea4383bSHeiko Stuebner { 0x41, 0x88 },
1616ea4383bSHeiko Stuebner { 0x42, 0x00 },
1626ea4383bSHeiko Stuebner { 0x43, 0x00 },
1636ea4383bSHeiko Stuebner { 0x44, 0x1F },
1646ea4383bSHeiko Stuebner { 0x50, 0x01 },
1656ea4383bSHeiko Stuebner { 0x51, 0x23 },
1666ea4383bSHeiko Stuebner { 0x52, 0x45 },
1676ea4383bSHeiko Stuebner { 0x53, 0x67 },
1686ea4383bSHeiko Stuebner { 0x54, 0x89 },
1696ea4383bSHeiko Stuebner { 0x55, 0xab },
1706ea4383bSHeiko Stuebner { 0x56, 0x01 },
1716ea4383bSHeiko Stuebner { 0x57, 0x23 },
1726ea4383bSHeiko Stuebner { 0x58, 0x45 },
1736ea4383bSHeiko Stuebner { 0x59, 0x67 },
1746ea4383bSHeiko Stuebner { 0x5a, 0x89 },
1756ea4383bSHeiko Stuebner { 0x5b, 0xab },
1766ea4383bSHeiko Stuebner { 0x5c, 0xcd },
1776ea4383bSHeiko Stuebner { 0x5d, 0xef },
1786ea4383bSHeiko Stuebner { 0x5e, 0x11 },
1796ea4383bSHeiko Stuebner { 0x5f, 0x01 },
1806ea4383bSHeiko Stuebner { 0x60, 0x00 },
1816ea4383bSHeiko Stuebner { 0x61, 0x15 },
1826ea4383bSHeiko Stuebner { 0x62, 0x14 },
1836ea4383bSHeiko Stuebner { 0x63, 0x0E },
1846ea4383bSHeiko Stuebner { 0x64, 0x0F },
1856ea4383bSHeiko Stuebner { 0x65, 0x0C },
1866ea4383bSHeiko Stuebner { 0x66, 0x0D },
1876ea4383bSHeiko Stuebner { 0x67, 0x06 },
1886ea4383bSHeiko Stuebner { 0x68, 0x02 },
1896ea4383bSHeiko Stuebner { 0x69, 0x07 },
1906ea4383bSHeiko Stuebner { 0x6a, 0x02 },
1916ea4383bSHeiko Stuebner { 0x6b, 0x02 },
1926ea4383bSHeiko Stuebner { 0x6c, 0x02 },
1936ea4383bSHeiko Stuebner { 0x6d, 0x02 },
1946ea4383bSHeiko Stuebner { 0x6e, 0x02 },
1956ea4383bSHeiko Stuebner { 0x6f, 0x02 },
1966ea4383bSHeiko Stuebner { 0x70, 0x02 },
1976ea4383bSHeiko Stuebner { 0x71, 0x02 },
1986ea4383bSHeiko Stuebner { 0x72, 0x02 },
1996ea4383bSHeiko Stuebner { 0x73, 0x02 },
2006ea4383bSHeiko Stuebner { 0x74, 0x02 },
2016ea4383bSHeiko Stuebner { 0x75, 0x01 },
2026ea4383bSHeiko Stuebner { 0x76, 0x00 },
2036ea4383bSHeiko Stuebner { 0x77, 0x14 },
2046ea4383bSHeiko Stuebner { 0x78, 0x15 },
2056ea4383bSHeiko Stuebner { 0x79, 0x0E },
2066ea4383bSHeiko Stuebner { 0x7a, 0x0F },
2076ea4383bSHeiko Stuebner { 0x7b, 0x0C },
2086ea4383bSHeiko Stuebner { 0x7c, 0x0D },
2096ea4383bSHeiko Stuebner { 0x7d, 0x06 },
2106ea4383bSHeiko Stuebner { 0x7e, 0x02 },
2116ea4383bSHeiko Stuebner { 0x7f, 0x07 },
2126ea4383bSHeiko Stuebner { 0x80, 0x02 },
2136ea4383bSHeiko Stuebner { 0x81, 0x02 },
2146ea4383bSHeiko Stuebner { 0x82, 0x02 },
2156ea4383bSHeiko Stuebner { 0x83, 0x02 },
2166ea4383bSHeiko Stuebner { 0x84, 0x02 },
2176ea4383bSHeiko Stuebner { 0x85, 0x02 },
2186ea4383bSHeiko Stuebner { 0x86, 0x02 },
2196ea4383bSHeiko Stuebner { 0x87, 0x02 },
2206ea4383bSHeiko Stuebner { 0x88, 0x02 },
2216ea4383bSHeiko Stuebner { 0x89, 0x02 },
2226ea4383bSHeiko Stuebner { 0x8A, 0x02 },
2236ea4383bSHeiko Stuebner };
2246ea4383bSHeiko Stuebner
2256ea4383bSHeiko Stuebner static const struct ltk050h3146w_cmd page4_cmds[] = {
2266ea4383bSHeiko Stuebner { 0x70, 0x00 },
2276ea4383bSHeiko Stuebner { 0x71, 0x00 },
2286ea4383bSHeiko Stuebner { 0x82, 0x0F }, /* VGH_MOD clamp level=15v */
2296ea4383bSHeiko Stuebner { 0x84, 0x0F }, /* VGH clamp level 15V */
2306ea4383bSHeiko Stuebner { 0x85, 0x0D }, /* VGL clamp level (-10V) */
2316ea4383bSHeiko Stuebner { 0x32, 0xAC },
2326ea4383bSHeiko Stuebner { 0x8C, 0x80 },
2336ea4383bSHeiko Stuebner { 0x3C, 0xF5 },
2346ea4383bSHeiko Stuebner { 0xB5, 0x07 }, /* GAMMA OP */
2356ea4383bSHeiko Stuebner { 0x31, 0x45 }, /* SOURCE OP */
2366ea4383bSHeiko Stuebner { 0x3A, 0x24 }, /* PS_EN OFF */
2376ea4383bSHeiko Stuebner { 0x88, 0x33 }, /* LVD */
2386ea4383bSHeiko Stuebner };
2396ea4383bSHeiko Stuebner
2406ea4383bSHeiko Stuebner static inline
panel_to_ltk050h3146w(struct drm_panel * panel)2416ea4383bSHeiko Stuebner struct ltk050h3146w *panel_to_ltk050h3146w(struct drm_panel *panel)
2426ea4383bSHeiko Stuebner {
2436ea4383bSHeiko Stuebner return container_of(panel, struct ltk050h3146w, panel);
2446ea4383bSHeiko Stuebner }
2456ea4383bSHeiko Stuebner
ltk050h3146w_init_sequence(struct ltk050h3146w * ctx)2466ea4383bSHeiko Stuebner static int ltk050h3146w_init_sequence(struct ltk050h3146w *ctx)
2476ea4383bSHeiko Stuebner {
2486ea4383bSHeiko Stuebner struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
2496ea4383bSHeiko Stuebner int ret;
2506ea4383bSHeiko Stuebner
2516ea4383bSHeiko Stuebner /*
2526ea4383bSHeiko Stuebner * Init sequence was supplied by the panel vendor without much
2536ea4383bSHeiko Stuebner * documentation.
2546ea4383bSHeiko Stuebner */
255*6497ca70SJavier Martinez Canillas mipi_dsi_dcs_write_seq(dsi, 0xdf, 0x93, 0x65, 0xf8);
256*6497ca70SJavier Martinez Canillas mipi_dsi_dcs_write_seq(dsi, 0xb0, 0x01, 0x03, 0x02, 0x00, 0x64, 0x06,
2576ea4383bSHeiko Stuebner 0x01);
258*6497ca70SJavier Martinez Canillas mipi_dsi_dcs_write_seq(dsi, 0xb2, 0x00, 0xb5);
259*6497ca70SJavier Martinez Canillas mipi_dsi_dcs_write_seq(dsi, 0xb3, 0x00, 0xb5);
260*6497ca70SJavier Martinez Canillas mipi_dsi_dcs_write_seq(dsi, 0xb7, 0x00, 0xbf, 0x00, 0x00, 0xbf, 0x00);
2616ea4383bSHeiko Stuebner
262*6497ca70SJavier Martinez Canillas mipi_dsi_dcs_write_seq(dsi, 0xb9, 0x00, 0xc4, 0x23, 0x07);
263*6497ca70SJavier Martinez Canillas mipi_dsi_dcs_write_seq(dsi, 0xbb, 0x02, 0x01, 0x24, 0x00, 0x28, 0x0f,
2646ea4383bSHeiko Stuebner 0x28, 0x04, 0xcc, 0xcc, 0xcc);
265*6497ca70SJavier Martinez Canillas mipi_dsi_dcs_write_seq(dsi, 0xbc, 0x0f, 0x04);
266*6497ca70SJavier Martinez Canillas mipi_dsi_dcs_write_seq(dsi, 0xbe, 0x1e, 0xf2);
267*6497ca70SJavier Martinez Canillas mipi_dsi_dcs_write_seq(dsi, 0xc0, 0x26, 0x03);
268*6497ca70SJavier Martinez Canillas mipi_dsi_dcs_write_seq(dsi, 0xc1, 0x00, 0x12);
269*6497ca70SJavier Martinez Canillas mipi_dsi_dcs_write_seq(dsi, 0xc3, 0x04, 0x02, 0x02, 0x76, 0x01, 0x80,
2706ea4383bSHeiko Stuebner 0x80);
271*6497ca70SJavier Martinez Canillas mipi_dsi_dcs_write_seq(dsi, 0xc4, 0x24, 0x80, 0xb4, 0x81, 0x12, 0x0f,
2726ea4383bSHeiko Stuebner 0x16, 0x00, 0x00);
273*6497ca70SJavier Martinez Canillas mipi_dsi_dcs_write_seq(dsi, 0xc8, 0x7f, 0x72, 0x67, 0x5d, 0x5d, 0x50,
2746ea4383bSHeiko Stuebner 0x56, 0x41, 0x59, 0x57, 0x55, 0x70, 0x5b, 0x5f,
2756ea4383bSHeiko Stuebner 0x4f, 0x47, 0x38, 0x23, 0x08, 0x7f, 0x72, 0x67,
2766ea4383bSHeiko Stuebner 0x5d, 0x5d, 0x50, 0x56, 0x41, 0x59, 0x57, 0x55,
2776ea4383bSHeiko Stuebner 0x70, 0x5b, 0x5f, 0x4f, 0x47, 0x38, 0x23, 0x08);
278*6497ca70SJavier Martinez Canillas mipi_dsi_dcs_write_seq(dsi, 0xd0, 0x1e, 0x1f, 0x57, 0x58, 0x48, 0x4a,
2796ea4383bSHeiko Stuebner 0x44, 0x46, 0x40, 0x1f, 0x42, 0x1f, 0x1f, 0x1f,
2806ea4383bSHeiko Stuebner 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f);
281*6497ca70SJavier Martinez Canillas mipi_dsi_dcs_write_seq(dsi, 0xd1, 0x1e, 0x1f, 0x57, 0x58, 0x49, 0x4b,
2826ea4383bSHeiko Stuebner 0x45, 0x47, 0x41, 0x1f, 0x43, 0x1f, 0x1f, 0x1f,
2836ea4383bSHeiko Stuebner 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f);
284*6497ca70SJavier Martinez Canillas mipi_dsi_dcs_write_seq(dsi, 0xd2, 0x1f, 0x1e, 0x17, 0x18, 0x07, 0x05,
2856ea4383bSHeiko Stuebner 0x0b, 0x09, 0x03, 0x1f, 0x01, 0x1f, 0x1f, 0x1f,
2866ea4383bSHeiko Stuebner 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f);
287*6497ca70SJavier Martinez Canillas mipi_dsi_dcs_write_seq(dsi, 0xd3, 0x1f, 0x1e, 0x17, 0x18, 0x06, 0x04,
2886ea4383bSHeiko Stuebner 0x0a, 0x08, 0x02, 0x1f, 0x00, 0x1f, 0x1f, 0x1f,
2896ea4383bSHeiko Stuebner 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f);
290*6497ca70SJavier Martinez Canillas mipi_dsi_dcs_write_seq(dsi, 0xd4, 0x00, 0x00, 0x00, 0x0c, 0x06, 0x20,
2916ea4383bSHeiko Stuebner 0x01, 0x02, 0x00, 0x60, 0x15, 0xb0, 0x30, 0x03,
2926ea4383bSHeiko Stuebner 0x04, 0x00, 0x60, 0x72, 0x0a, 0x00, 0x60, 0x08);
293*6497ca70SJavier Martinez Canillas mipi_dsi_dcs_write_seq(dsi, 0xd5, 0x00, 0x06, 0x06, 0x00, 0x30, 0x00,
2946ea4383bSHeiko Stuebner 0x00, 0x00, 0x00, 0x00, 0xbc, 0x50, 0x00, 0x05,
2956ea4383bSHeiko Stuebner 0x21, 0x00, 0x60);
296*6497ca70SJavier Martinez Canillas mipi_dsi_dcs_write_seq(dsi, 0xdd, 0x2c, 0xa3, 0x00);
297*6497ca70SJavier Martinez Canillas mipi_dsi_dcs_write_seq(dsi, 0xde, 0x02);
298*6497ca70SJavier Martinez Canillas mipi_dsi_dcs_write_seq(dsi, 0xb2, 0x32, 0x1c);
299*6497ca70SJavier Martinez Canillas mipi_dsi_dcs_write_seq(dsi, 0xb7, 0x3b, 0x70, 0x00, 0x04);
300*6497ca70SJavier Martinez Canillas mipi_dsi_dcs_write_seq(dsi, 0xc1, 0x11);
301*6497ca70SJavier Martinez Canillas mipi_dsi_dcs_write_seq(dsi, 0xbb, 0x21, 0x22, 0x23, 0x24, 0x36, 0x37);
302*6497ca70SJavier Martinez Canillas mipi_dsi_dcs_write_seq(dsi, 0xc2, 0x20, 0x38, 0x1e, 0x84);
303*6497ca70SJavier Martinez Canillas mipi_dsi_dcs_write_seq(dsi, 0xde, 0x00);
3046ea4383bSHeiko Stuebner
3056ea4383bSHeiko Stuebner ret = mipi_dsi_dcs_set_tear_on(dsi, 1);
3066ea4383bSHeiko Stuebner if (ret < 0) {
307b75efff5SSam Ravnborg dev_err(ctx->dev, "failed to set tear on: %d\n", ret);
3086ea4383bSHeiko Stuebner return ret;
3096ea4383bSHeiko Stuebner }
3106ea4383bSHeiko Stuebner
3116ea4383bSHeiko Stuebner msleep(60);
3126ea4383bSHeiko Stuebner
3136ea4383bSHeiko Stuebner return 0;
3146ea4383bSHeiko Stuebner }
3156ea4383bSHeiko Stuebner
3166ea4383bSHeiko Stuebner static const struct drm_display_mode ltk050h3146w_mode = {
3176ea4383bSHeiko Stuebner .hdisplay = 720,
3186ea4383bSHeiko Stuebner .hsync_start = 720 + 42,
3196ea4383bSHeiko Stuebner .hsync_end = 720 + 42 + 8,
3206ea4383bSHeiko Stuebner .htotal = 720 + 42 + 8 + 42,
3216ea4383bSHeiko Stuebner .vdisplay = 1280,
3226ea4383bSHeiko Stuebner .vsync_start = 1280 + 12,
3236ea4383bSHeiko Stuebner .vsync_end = 1280 + 12 + 4,
3246ea4383bSHeiko Stuebner .vtotal = 1280 + 12 + 4 + 18,
3256ea4383bSHeiko Stuebner .clock = 64018,
3266ea4383bSHeiko Stuebner .width_mm = 62,
3276ea4383bSHeiko Stuebner .height_mm = 110,
3286ea4383bSHeiko Stuebner };
3296ea4383bSHeiko Stuebner
3306ea4383bSHeiko Stuebner static const struct ltk050h3146w_desc ltk050h3146w_data = {
3316ea4383bSHeiko Stuebner .mode = <k050h3146w_mode,
3326ea4383bSHeiko Stuebner .init = ltk050h3146w_init_sequence,
3336ea4383bSHeiko Stuebner };
3346ea4383bSHeiko Stuebner
ltk050h3146w_a2_select_page(struct ltk050h3146w * ctx,int page)3356ea4383bSHeiko Stuebner static int ltk050h3146w_a2_select_page(struct ltk050h3146w *ctx, int page)
3366ea4383bSHeiko Stuebner {
3376ea4383bSHeiko Stuebner struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
3386ea4383bSHeiko Stuebner u8 d[3] = { 0x98, 0x81, page };
3396ea4383bSHeiko Stuebner
3406ea4383bSHeiko Stuebner return mipi_dsi_dcs_write(dsi, 0xff, d, ARRAY_SIZE(d));
3416ea4383bSHeiko Stuebner }
3426ea4383bSHeiko Stuebner
ltk050h3146w_a2_write_page(struct ltk050h3146w * ctx,int page,const struct ltk050h3146w_cmd * cmds,int num)3436ea4383bSHeiko Stuebner static int ltk050h3146w_a2_write_page(struct ltk050h3146w *ctx, int page,
3446ea4383bSHeiko Stuebner const struct ltk050h3146w_cmd *cmds,
3456ea4383bSHeiko Stuebner int num)
3466ea4383bSHeiko Stuebner {
3476ea4383bSHeiko Stuebner struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
3486ea4383bSHeiko Stuebner int i, ret;
3496ea4383bSHeiko Stuebner
3506ea4383bSHeiko Stuebner ret = ltk050h3146w_a2_select_page(ctx, page);
3516ea4383bSHeiko Stuebner if (ret < 0) {
352b75efff5SSam Ravnborg dev_err(ctx->dev, "failed to select page %d: %d\n", page, ret);
3536ea4383bSHeiko Stuebner return ret;
3546ea4383bSHeiko Stuebner }
3556ea4383bSHeiko Stuebner
3566ea4383bSHeiko Stuebner for (i = 0; i < num; i++) {
3576ea4383bSHeiko Stuebner ret = mipi_dsi_generic_write(dsi, &cmds[i],
3586ea4383bSHeiko Stuebner sizeof(struct ltk050h3146w_cmd));
3596ea4383bSHeiko Stuebner if (ret < 0) {
360b75efff5SSam Ravnborg dev_err(ctx->dev, "failed to write page %d init cmds: %d\n", page, ret);
3616ea4383bSHeiko Stuebner return ret;
3626ea4383bSHeiko Stuebner }
3636ea4383bSHeiko Stuebner }
3646ea4383bSHeiko Stuebner
3656ea4383bSHeiko Stuebner return 0;
3666ea4383bSHeiko Stuebner }
3676ea4383bSHeiko Stuebner
ltk050h3146w_a2_init_sequence(struct ltk050h3146w * ctx)3686ea4383bSHeiko Stuebner static int ltk050h3146w_a2_init_sequence(struct ltk050h3146w *ctx)
3696ea4383bSHeiko Stuebner {
3706ea4383bSHeiko Stuebner struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
3716ea4383bSHeiko Stuebner int ret;
3726ea4383bSHeiko Stuebner
3736ea4383bSHeiko Stuebner /*
3746ea4383bSHeiko Stuebner * Init sequence was supplied by the panel vendor without much
3756ea4383bSHeiko Stuebner * documentation.
3766ea4383bSHeiko Stuebner */
3776ea4383bSHeiko Stuebner ret = ltk050h3146w_a2_write_page(ctx, 3, page3_cmds,
3786ea4383bSHeiko Stuebner ARRAY_SIZE(page3_cmds));
3796ea4383bSHeiko Stuebner if (ret < 0)
3806ea4383bSHeiko Stuebner return ret;
3816ea4383bSHeiko Stuebner
3826ea4383bSHeiko Stuebner ret = ltk050h3146w_a2_write_page(ctx, 4, page4_cmds,
3836ea4383bSHeiko Stuebner ARRAY_SIZE(page4_cmds));
3846ea4383bSHeiko Stuebner if (ret < 0)
3856ea4383bSHeiko Stuebner return ret;
3866ea4383bSHeiko Stuebner
3876ea4383bSHeiko Stuebner ret = ltk050h3146w_a2_write_page(ctx, 1, page1_cmds,
3886ea4383bSHeiko Stuebner ARRAY_SIZE(page1_cmds));
3896ea4383bSHeiko Stuebner if (ret < 0)
3906ea4383bSHeiko Stuebner return ret;
3916ea4383bSHeiko Stuebner
3926ea4383bSHeiko Stuebner ret = ltk050h3146w_a2_select_page(ctx, 0);
3936ea4383bSHeiko Stuebner if (ret < 0) {
394b75efff5SSam Ravnborg dev_err(ctx->dev, "failed to select page 0: %d\n", ret);
3956ea4383bSHeiko Stuebner return ret;
3966ea4383bSHeiko Stuebner }
3976ea4383bSHeiko Stuebner
3986ea4383bSHeiko Stuebner /* vendor code called this without param, where there should be one */
3996ea4383bSHeiko Stuebner ret = mipi_dsi_dcs_set_tear_on(dsi, 0);
4006ea4383bSHeiko Stuebner if (ret < 0) {
401b75efff5SSam Ravnborg dev_err(ctx->dev, "failed to set tear on: %d\n", ret);
4026ea4383bSHeiko Stuebner return ret;
4036ea4383bSHeiko Stuebner }
4046ea4383bSHeiko Stuebner
4056ea4383bSHeiko Stuebner msleep(60);
4066ea4383bSHeiko Stuebner
4076ea4383bSHeiko Stuebner return 0;
4086ea4383bSHeiko Stuebner }
4096ea4383bSHeiko Stuebner
4106ea4383bSHeiko Stuebner static const struct drm_display_mode ltk050h3146w_a2_mode = {
4116ea4383bSHeiko Stuebner .hdisplay = 720,
4126ea4383bSHeiko Stuebner .hsync_start = 720 + 42,
4136ea4383bSHeiko Stuebner .hsync_end = 720 + 42 + 10,
4146ea4383bSHeiko Stuebner .htotal = 720 + 42 + 10 + 60,
4156ea4383bSHeiko Stuebner .vdisplay = 1280,
4166ea4383bSHeiko Stuebner .vsync_start = 1280 + 18,
4176ea4383bSHeiko Stuebner .vsync_end = 1280 + 18 + 4,
4186ea4383bSHeiko Stuebner .vtotal = 1280 + 18 + 4 + 12,
4196ea4383bSHeiko Stuebner .clock = 65595,
4206ea4383bSHeiko Stuebner .width_mm = 62,
4216ea4383bSHeiko Stuebner .height_mm = 110,
4226ea4383bSHeiko Stuebner };
4236ea4383bSHeiko Stuebner
4246ea4383bSHeiko Stuebner static const struct ltk050h3146w_desc ltk050h3146w_a2_data = {
4256ea4383bSHeiko Stuebner .mode = <k050h3146w_a2_mode,
4266ea4383bSHeiko Stuebner .init = ltk050h3146w_a2_init_sequence,
4276ea4383bSHeiko Stuebner };
4286ea4383bSHeiko Stuebner
ltk050h3146w_unprepare(struct drm_panel * panel)4296ea4383bSHeiko Stuebner static int ltk050h3146w_unprepare(struct drm_panel *panel)
4306ea4383bSHeiko Stuebner {
4316ea4383bSHeiko Stuebner struct ltk050h3146w *ctx = panel_to_ltk050h3146w(panel);
4326ea4383bSHeiko Stuebner struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
4336ea4383bSHeiko Stuebner int ret;
4346ea4383bSHeiko Stuebner
4356ea4383bSHeiko Stuebner if (!ctx->prepared)
4366ea4383bSHeiko Stuebner return 0;
4376ea4383bSHeiko Stuebner
4386ea4383bSHeiko Stuebner ret = mipi_dsi_dcs_set_display_off(dsi);
4396ea4383bSHeiko Stuebner if (ret < 0) {
440b75efff5SSam Ravnborg dev_err(ctx->dev, "failed to set display off: %d\n", ret);
4416ea4383bSHeiko Stuebner return ret;
4426ea4383bSHeiko Stuebner }
4436ea4383bSHeiko Stuebner
4446ea4383bSHeiko Stuebner mipi_dsi_dcs_enter_sleep_mode(dsi);
4456ea4383bSHeiko Stuebner if (ret < 0) {
446b75efff5SSam Ravnborg dev_err(ctx->dev, "failed to enter sleep mode: %d\n", ret);
4476ea4383bSHeiko Stuebner return ret;
4486ea4383bSHeiko Stuebner }
4496ea4383bSHeiko Stuebner
4506ea4383bSHeiko Stuebner regulator_disable(ctx->iovcc);
4516ea4383bSHeiko Stuebner regulator_disable(ctx->vci);
4526ea4383bSHeiko Stuebner
4536ea4383bSHeiko Stuebner ctx->prepared = false;
4546ea4383bSHeiko Stuebner
4556ea4383bSHeiko Stuebner return 0;
4566ea4383bSHeiko Stuebner }
4576ea4383bSHeiko Stuebner
ltk050h3146w_prepare(struct drm_panel * panel)4586ea4383bSHeiko Stuebner static int ltk050h3146w_prepare(struct drm_panel *panel)
4596ea4383bSHeiko Stuebner {
4606ea4383bSHeiko Stuebner struct ltk050h3146w *ctx = panel_to_ltk050h3146w(panel);
4616ea4383bSHeiko Stuebner struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
4626ea4383bSHeiko Stuebner int ret;
4636ea4383bSHeiko Stuebner
4646ea4383bSHeiko Stuebner if (ctx->prepared)
4656ea4383bSHeiko Stuebner return 0;
4666ea4383bSHeiko Stuebner
467b75efff5SSam Ravnborg dev_dbg(ctx->dev, "Resetting the panel\n");
4686ea4383bSHeiko Stuebner ret = regulator_enable(ctx->vci);
4696ea4383bSHeiko Stuebner if (ret < 0) {
470b75efff5SSam Ravnborg dev_err(ctx->dev, "Failed to enable vci supply: %d\n", ret);
4716ea4383bSHeiko Stuebner return ret;
4726ea4383bSHeiko Stuebner }
4736ea4383bSHeiko Stuebner ret = regulator_enable(ctx->iovcc);
4746ea4383bSHeiko Stuebner if (ret < 0) {
475b75efff5SSam Ravnborg dev_err(ctx->dev, "Failed to enable iovcc supply: %d\n", ret);
4766ea4383bSHeiko Stuebner goto disable_vci;
4776ea4383bSHeiko Stuebner }
4786ea4383bSHeiko Stuebner
4796ea4383bSHeiko Stuebner gpiod_set_value_cansleep(ctx->reset_gpio, 1);
4806ea4383bSHeiko Stuebner usleep_range(5000, 6000);
4816ea4383bSHeiko Stuebner gpiod_set_value_cansleep(ctx->reset_gpio, 0);
4826ea4383bSHeiko Stuebner msleep(20);
4836ea4383bSHeiko Stuebner
4846ea4383bSHeiko Stuebner ret = ctx->panel_desc->init(ctx);
4856ea4383bSHeiko Stuebner if (ret < 0) {
486b75efff5SSam Ravnborg dev_err(ctx->dev, "Panel init sequence failed: %d\n", ret);
4876ea4383bSHeiko Stuebner goto disable_iovcc;
4886ea4383bSHeiko Stuebner }
4896ea4383bSHeiko Stuebner
4906ea4383bSHeiko Stuebner ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
4916ea4383bSHeiko Stuebner if (ret < 0) {
492b75efff5SSam Ravnborg dev_err(ctx->dev, "Failed to exit sleep mode: %d\n", ret);
4936ea4383bSHeiko Stuebner goto disable_iovcc;
4946ea4383bSHeiko Stuebner }
4956ea4383bSHeiko Stuebner
4966ea4383bSHeiko Stuebner /* T9: 120ms */
4976ea4383bSHeiko Stuebner msleep(120);
4986ea4383bSHeiko Stuebner
4996ea4383bSHeiko Stuebner ret = mipi_dsi_dcs_set_display_on(dsi);
5006ea4383bSHeiko Stuebner if (ret < 0) {
501b75efff5SSam Ravnborg dev_err(ctx->dev, "Failed to set display on: %d\n", ret);
5026ea4383bSHeiko Stuebner goto disable_iovcc;
5036ea4383bSHeiko Stuebner }
5046ea4383bSHeiko Stuebner
5056ea4383bSHeiko Stuebner msleep(50);
5066ea4383bSHeiko Stuebner
5076ea4383bSHeiko Stuebner ctx->prepared = true;
5086ea4383bSHeiko Stuebner
5096ea4383bSHeiko Stuebner return 0;
5106ea4383bSHeiko Stuebner
5116ea4383bSHeiko Stuebner disable_iovcc:
5126ea4383bSHeiko Stuebner regulator_disable(ctx->iovcc);
5136ea4383bSHeiko Stuebner disable_vci:
5146ea4383bSHeiko Stuebner regulator_disable(ctx->vci);
5156ea4383bSHeiko Stuebner return ret;
5166ea4383bSHeiko Stuebner }
5176ea4383bSHeiko Stuebner
ltk050h3146w_get_modes(struct drm_panel * panel,struct drm_connector * connector)5186ea4383bSHeiko Stuebner static int ltk050h3146w_get_modes(struct drm_panel *panel,
5196ea4383bSHeiko Stuebner struct drm_connector *connector)
5206ea4383bSHeiko Stuebner {
5216ea4383bSHeiko Stuebner struct ltk050h3146w *ctx = panel_to_ltk050h3146w(panel);
5226ea4383bSHeiko Stuebner struct drm_display_mode *mode;
5236ea4383bSHeiko Stuebner
5246ea4383bSHeiko Stuebner mode = drm_mode_duplicate(connector->dev, ctx->panel_desc->mode);
5256ea4383bSHeiko Stuebner if (!mode)
5266ea4383bSHeiko Stuebner return -ENOMEM;
5276ea4383bSHeiko Stuebner
5286ea4383bSHeiko Stuebner drm_mode_set_name(mode);
5296ea4383bSHeiko Stuebner
5306ea4383bSHeiko Stuebner mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
5316ea4383bSHeiko Stuebner connector->display_info.width_mm = mode->width_mm;
5326ea4383bSHeiko Stuebner connector->display_info.height_mm = mode->height_mm;
5336ea4383bSHeiko Stuebner drm_mode_probed_add(connector, mode);
5346ea4383bSHeiko Stuebner
5356ea4383bSHeiko Stuebner return 1;
5366ea4383bSHeiko Stuebner }
5376ea4383bSHeiko Stuebner
5386ea4383bSHeiko Stuebner static const struct drm_panel_funcs ltk050h3146w_funcs = {
5396ea4383bSHeiko Stuebner .unprepare = ltk050h3146w_unprepare,
5406ea4383bSHeiko Stuebner .prepare = ltk050h3146w_prepare,
5416ea4383bSHeiko Stuebner .get_modes = ltk050h3146w_get_modes,
5426ea4383bSHeiko Stuebner };
5436ea4383bSHeiko Stuebner
ltk050h3146w_probe(struct mipi_dsi_device * dsi)5446ea4383bSHeiko Stuebner static int ltk050h3146w_probe(struct mipi_dsi_device *dsi)
5456ea4383bSHeiko Stuebner {
5466ea4383bSHeiko Stuebner struct device *dev = &dsi->dev;
5476ea4383bSHeiko Stuebner struct ltk050h3146w *ctx;
5486ea4383bSHeiko Stuebner int ret;
5496ea4383bSHeiko Stuebner
5506ea4383bSHeiko Stuebner ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
5516ea4383bSHeiko Stuebner if (!ctx)
5526ea4383bSHeiko Stuebner return -ENOMEM;
5536ea4383bSHeiko Stuebner
5546ea4383bSHeiko Stuebner ctx->panel_desc = of_device_get_match_data(dev);
5556ea4383bSHeiko Stuebner if (!ctx->panel_desc)
5566ea4383bSHeiko Stuebner return -EINVAL;
5576ea4383bSHeiko Stuebner
5586ea4383bSHeiko Stuebner ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
5596ea4383bSHeiko Stuebner if (IS_ERR(ctx->reset_gpio)) {
560b75efff5SSam Ravnborg dev_err(dev, "cannot get reset gpio\n");
5616ea4383bSHeiko Stuebner return PTR_ERR(ctx->reset_gpio);
5626ea4383bSHeiko Stuebner }
5636ea4383bSHeiko Stuebner
5646ea4383bSHeiko Stuebner ctx->vci = devm_regulator_get(dev, "vci");
5656ea4383bSHeiko Stuebner if (IS_ERR(ctx->vci)) {
5666ea4383bSHeiko Stuebner ret = PTR_ERR(ctx->vci);
5676ea4383bSHeiko Stuebner if (ret != -EPROBE_DEFER)
568b75efff5SSam Ravnborg dev_err(dev, "Failed to request vci regulator: %d\n", ret);
5696ea4383bSHeiko Stuebner return ret;
5706ea4383bSHeiko Stuebner }
5716ea4383bSHeiko Stuebner
5726ea4383bSHeiko Stuebner ctx->iovcc = devm_regulator_get(dev, "iovcc");
5736ea4383bSHeiko Stuebner if (IS_ERR(ctx->iovcc)) {
5746ea4383bSHeiko Stuebner ret = PTR_ERR(ctx->iovcc);
5756ea4383bSHeiko Stuebner if (ret != -EPROBE_DEFER)
576b75efff5SSam Ravnborg dev_err(dev, "Failed to request iovcc regulator: %d\n", ret);
5776ea4383bSHeiko Stuebner return ret;
5786ea4383bSHeiko Stuebner }
5796ea4383bSHeiko Stuebner
5806ea4383bSHeiko Stuebner mipi_dsi_set_drvdata(dsi, ctx);
5816ea4383bSHeiko Stuebner
5826ea4383bSHeiko Stuebner ctx->dev = dev;
5836ea4383bSHeiko Stuebner
5846ea4383bSHeiko Stuebner dsi->lanes = 4;
5856ea4383bSHeiko Stuebner dsi->format = MIPI_DSI_FMT_RGB888;
5866ea4383bSHeiko Stuebner dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
5870f3b68b6SNicolas Boichat MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_NO_EOT_PACKET;
5886ea4383bSHeiko Stuebner
5896ea4383bSHeiko Stuebner drm_panel_init(&ctx->panel, &dsi->dev, <k050h3146w_funcs,
5906ea4383bSHeiko Stuebner DRM_MODE_CONNECTOR_DSI);
5916ea4383bSHeiko Stuebner
5926ea4383bSHeiko Stuebner ret = drm_panel_of_backlight(&ctx->panel);
5936ea4383bSHeiko Stuebner if (ret)
5946ea4383bSHeiko Stuebner return ret;
5956ea4383bSHeiko Stuebner
5966ea4383bSHeiko Stuebner drm_panel_add(&ctx->panel);
5976ea4383bSHeiko Stuebner
5986ea4383bSHeiko Stuebner ret = mipi_dsi_attach(dsi);
5996ea4383bSHeiko Stuebner if (ret < 0) {
600b75efff5SSam Ravnborg dev_err(dev, "mipi_dsi_attach failed: %d\n", ret);
6016ea4383bSHeiko Stuebner drm_panel_remove(&ctx->panel);
6026ea4383bSHeiko Stuebner return ret;
6036ea4383bSHeiko Stuebner }
6046ea4383bSHeiko Stuebner
6056ea4383bSHeiko Stuebner return 0;
6066ea4383bSHeiko Stuebner }
6076ea4383bSHeiko Stuebner
ltk050h3146w_shutdown(struct mipi_dsi_device * dsi)6086ea4383bSHeiko Stuebner static void ltk050h3146w_shutdown(struct mipi_dsi_device *dsi)
6096ea4383bSHeiko Stuebner {
6106ea4383bSHeiko Stuebner struct ltk050h3146w *ctx = mipi_dsi_get_drvdata(dsi);
6116ea4383bSHeiko Stuebner int ret;
6126ea4383bSHeiko Stuebner
6136ea4383bSHeiko Stuebner ret = drm_panel_unprepare(&ctx->panel);
6146ea4383bSHeiko Stuebner if (ret < 0)
615b75efff5SSam Ravnborg dev_err(&dsi->dev, "Failed to unprepare panel: %d\n", ret);
6166ea4383bSHeiko Stuebner
6176ea4383bSHeiko Stuebner ret = drm_panel_disable(&ctx->panel);
6186ea4383bSHeiko Stuebner if (ret < 0)
619b75efff5SSam Ravnborg dev_err(&dsi->dev, "Failed to disable panel: %d\n", ret);
6206ea4383bSHeiko Stuebner }
6216ea4383bSHeiko Stuebner
ltk050h3146w_remove(struct mipi_dsi_device * dsi)62279abca2bSUwe Kleine-König static void ltk050h3146w_remove(struct mipi_dsi_device *dsi)
6236ea4383bSHeiko Stuebner {
6246ea4383bSHeiko Stuebner struct ltk050h3146w *ctx = mipi_dsi_get_drvdata(dsi);
6256ea4383bSHeiko Stuebner int ret;
6266ea4383bSHeiko Stuebner
6276ea4383bSHeiko Stuebner ltk050h3146w_shutdown(dsi);
6286ea4383bSHeiko Stuebner
6296ea4383bSHeiko Stuebner ret = mipi_dsi_detach(dsi);
6306ea4383bSHeiko Stuebner if (ret < 0)
631b75efff5SSam Ravnborg dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret);
6326ea4383bSHeiko Stuebner
6336ea4383bSHeiko Stuebner drm_panel_remove(&ctx->panel);
6346ea4383bSHeiko Stuebner }
6356ea4383bSHeiko Stuebner
6366ea4383bSHeiko Stuebner static const struct of_device_id ltk050h3146w_of_match[] = {
6376ea4383bSHeiko Stuebner {
6386ea4383bSHeiko Stuebner .compatible = "leadtek,ltk050h3146w",
6396ea4383bSHeiko Stuebner .data = <k050h3146w_data,
6406ea4383bSHeiko Stuebner },
6416ea4383bSHeiko Stuebner {
6426ea4383bSHeiko Stuebner .compatible = "leadtek,ltk050h3146w-a2",
6436ea4383bSHeiko Stuebner .data = <k050h3146w_a2_data,
6446ea4383bSHeiko Stuebner },
6456ea4383bSHeiko Stuebner { /* sentinel */ }
6466ea4383bSHeiko Stuebner };
6476ea4383bSHeiko Stuebner MODULE_DEVICE_TABLE(of, ltk050h3146w_of_match);
6486ea4383bSHeiko Stuebner
6496ea4383bSHeiko Stuebner static struct mipi_dsi_driver ltk050h3146w_driver = {
6506ea4383bSHeiko Stuebner .driver = {
6516ea4383bSHeiko Stuebner .name = "panel-leadtek-ltk050h3146w",
6526ea4383bSHeiko Stuebner .of_match_table = ltk050h3146w_of_match,
6536ea4383bSHeiko Stuebner },
6546ea4383bSHeiko Stuebner .probe = ltk050h3146w_probe,
6556ea4383bSHeiko Stuebner .remove = ltk050h3146w_remove,
6566ea4383bSHeiko Stuebner .shutdown = ltk050h3146w_shutdown,
6576ea4383bSHeiko Stuebner };
6586ea4383bSHeiko Stuebner module_mipi_dsi_driver(ltk050h3146w_driver);
6596ea4383bSHeiko Stuebner
6606ea4383bSHeiko Stuebner MODULE_AUTHOR("Heiko Stuebner <heiko.stuebner@theobroma-systems.com>");
6616ea4383bSHeiko Stuebner MODULE_DESCRIPTION("DRM driver for Leadtek LTK050H3146W MIPI DSI panel");
6626ea4383bSHeiko Stuebner MODULE_LICENSE("GPL v2");
663