18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2020 Theobroma Systems Design und Consulting GmbH
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include <linux/delay.h>
78c2ecf20Sopenharmony_ci#include <linux/gpio/consumer.h>
88c2ecf20Sopenharmony_ci#include <linux/media-bus-format.h>
98c2ecf20Sopenharmony_ci#include <linux/module.h>
108c2ecf20Sopenharmony_ci#include <linux/of.h>
118c2ecf20Sopenharmony_ci#include <linux/of_device.h>
128c2ecf20Sopenharmony_ci#include <linux/regulator/consumer.h>
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#include <video/display_timing.h>
158c2ecf20Sopenharmony_ci#include <video/mipi_display.h>
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#include <drm/drm_mipi_dsi.h>
188c2ecf20Sopenharmony_ci#include <drm/drm_modes.h>
198c2ecf20Sopenharmony_ci#include <drm/drm_panel.h>
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_cistruct ltk050h3146w_cmd {
228c2ecf20Sopenharmony_ci	char cmd;
238c2ecf20Sopenharmony_ci	char data;
248c2ecf20Sopenharmony_ci};
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_cistruct ltk050h3146w;
278c2ecf20Sopenharmony_cistruct ltk050h3146w_desc {
288c2ecf20Sopenharmony_ci	const struct drm_display_mode *mode;
298c2ecf20Sopenharmony_ci	int (*init)(struct ltk050h3146w *ctx);
308c2ecf20Sopenharmony_ci};
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_cistruct ltk050h3146w {
338c2ecf20Sopenharmony_ci	struct device *dev;
348c2ecf20Sopenharmony_ci	struct drm_panel panel;
358c2ecf20Sopenharmony_ci	struct gpio_desc *reset_gpio;
368c2ecf20Sopenharmony_ci	struct regulator *vci;
378c2ecf20Sopenharmony_ci	struct regulator *iovcc;
388c2ecf20Sopenharmony_ci	const struct ltk050h3146w_desc *panel_desc;
398c2ecf20Sopenharmony_ci	bool prepared;
408c2ecf20Sopenharmony_ci};
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_cistatic const struct ltk050h3146w_cmd page1_cmds[] = {
438c2ecf20Sopenharmony_ci	{ 0x22, 0x0A }, /* BGR SS GS */
448c2ecf20Sopenharmony_ci	{ 0x31, 0x00 }, /* column inversion */
458c2ecf20Sopenharmony_ci	{ 0x53, 0xA2 }, /* VCOM1 */
468c2ecf20Sopenharmony_ci	{ 0x55, 0xA2 }, /* VCOM2 */
478c2ecf20Sopenharmony_ci	{ 0x50, 0x81 }, /* VREG1OUT=5V */
488c2ecf20Sopenharmony_ci	{ 0x51, 0x85 }, /* VREG2OUT=-5V */
498c2ecf20Sopenharmony_ci	{ 0x62, 0x0D }, /* EQT Time setting */
508c2ecf20Sopenharmony_ci/*
518c2ecf20Sopenharmony_ci * The vendor init selected page 1 here _again_
528c2ecf20Sopenharmony_ci * Is this supposed to be page 2?
538c2ecf20Sopenharmony_ci */
548c2ecf20Sopenharmony_ci	{ 0xA0, 0x00 },
558c2ecf20Sopenharmony_ci	{ 0xA1, 0x1A },
568c2ecf20Sopenharmony_ci	{ 0xA2, 0x28 },
578c2ecf20Sopenharmony_ci	{ 0xA3, 0x13 },
588c2ecf20Sopenharmony_ci	{ 0xA4, 0x16 },
598c2ecf20Sopenharmony_ci	{ 0xA5, 0x29 },
608c2ecf20Sopenharmony_ci	{ 0xA6, 0x1D },
618c2ecf20Sopenharmony_ci	{ 0xA7, 0x1E },
628c2ecf20Sopenharmony_ci	{ 0xA8, 0x84 },
638c2ecf20Sopenharmony_ci	{ 0xA9, 0x1C },
648c2ecf20Sopenharmony_ci	{ 0xAA, 0x28 },
658c2ecf20Sopenharmony_ci	{ 0xAB, 0x75 },
668c2ecf20Sopenharmony_ci	{ 0xAC, 0x1A },
678c2ecf20Sopenharmony_ci	{ 0xAD, 0x19 },
688c2ecf20Sopenharmony_ci	{ 0xAE, 0x4D },
698c2ecf20Sopenharmony_ci	{ 0xAF, 0x22 },
708c2ecf20Sopenharmony_ci	{ 0xB0, 0x28 },
718c2ecf20Sopenharmony_ci	{ 0xB1, 0x54 },
728c2ecf20Sopenharmony_ci	{ 0xB2, 0x66 },
738c2ecf20Sopenharmony_ci	{ 0xB3, 0x39 },
748c2ecf20Sopenharmony_ci	{ 0xC0, 0x00 },
758c2ecf20Sopenharmony_ci	{ 0xC1, 0x1A },
768c2ecf20Sopenharmony_ci	{ 0xC2, 0x28 },
778c2ecf20Sopenharmony_ci	{ 0xC3, 0x13 },
788c2ecf20Sopenharmony_ci	{ 0xC4, 0x16 },
798c2ecf20Sopenharmony_ci	{ 0xC5, 0x29 },
808c2ecf20Sopenharmony_ci	{ 0xC6, 0x1D },
818c2ecf20Sopenharmony_ci	{ 0xC7, 0x1E },
828c2ecf20Sopenharmony_ci	{ 0xC8, 0x84 },
838c2ecf20Sopenharmony_ci	{ 0xC9, 0x1C },
848c2ecf20Sopenharmony_ci	{ 0xCA, 0x28 },
858c2ecf20Sopenharmony_ci	{ 0xCB, 0x75 },
868c2ecf20Sopenharmony_ci	{ 0xCC, 0x1A },
878c2ecf20Sopenharmony_ci	{ 0xCD, 0x19 },
888c2ecf20Sopenharmony_ci	{ 0xCE, 0x4D },
898c2ecf20Sopenharmony_ci	{ 0xCF, 0x22 },
908c2ecf20Sopenharmony_ci	{ 0xD0, 0x28 },
918c2ecf20Sopenharmony_ci	{ 0xD1, 0x54 },
928c2ecf20Sopenharmony_ci	{ 0xD2, 0x66 },
938c2ecf20Sopenharmony_ci	{ 0xD3, 0x39 },
948c2ecf20Sopenharmony_ci};
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_cistatic const struct ltk050h3146w_cmd page3_cmds[] = {
978c2ecf20Sopenharmony_ci	{ 0x01, 0x00 },
988c2ecf20Sopenharmony_ci	{ 0x02, 0x00 },
998c2ecf20Sopenharmony_ci	{ 0x03, 0x73 },
1008c2ecf20Sopenharmony_ci	{ 0x04, 0x00 },
1018c2ecf20Sopenharmony_ci	{ 0x05, 0x00 },
1028c2ecf20Sopenharmony_ci	{ 0x06, 0x0a },
1038c2ecf20Sopenharmony_ci	{ 0x07, 0x00 },
1048c2ecf20Sopenharmony_ci	{ 0x08, 0x00 },
1058c2ecf20Sopenharmony_ci	{ 0x09, 0x01 },
1068c2ecf20Sopenharmony_ci	{ 0x0a, 0x00 },
1078c2ecf20Sopenharmony_ci	{ 0x0b, 0x00 },
1088c2ecf20Sopenharmony_ci	{ 0x0c, 0x01 },
1098c2ecf20Sopenharmony_ci	{ 0x0d, 0x00 },
1108c2ecf20Sopenharmony_ci	{ 0x0e, 0x00 },
1118c2ecf20Sopenharmony_ci	{ 0x0f, 0x1d },
1128c2ecf20Sopenharmony_ci	{ 0x10, 0x1d },
1138c2ecf20Sopenharmony_ci	{ 0x11, 0x00 },
1148c2ecf20Sopenharmony_ci	{ 0x12, 0x00 },
1158c2ecf20Sopenharmony_ci	{ 0x13, 0x00 },
1168c2ecf20Sopenharmony_ci	{ 0x14, 0x00 },
1178c2ecf20Sopenharmony_ci	{ 0x15, 0x00 },
1188c2ecf20Sopenharmony_ci	{ 0x16, 0x00 },
1198c2ecf20Sopenharmony_ci	{ 0x17, 0x00 },
1208c2ecf20Sopenharmony_ci	{ 0x18, 0x00 },
1218c2ecf20Sopenharmony_ci	{ 0x19, 0x00 },
1228c2ecf20Sopenharmony_ci	{ 0x1a, 0x00 },
1238c2ecf20Sopenharmony_ci	{ 0x1b, 0x00 },
1248c2ecf20Sopenharmony_ci	{ 0x1c, 0x00 },
1258c2ecf20Sopenharmony_ci	{ 0x1d, 0x00 },
1268c2ecf20Sopenharmony_ci	{ 0x1e, 0x40 },
1278c2ecf20Sopenharmony_ci	{ 0x1f, 0x80 },
1288c2ecf20Sopenharmony_ci	{ 0x20, 0x06 },
1298c2ecf20Sopenharmony_ci	{ 0x21, 0x02 },
1308c2ecf20Sopenharmony_ci	{ 0x22, 0x00 },
1318c2ecf20Sopenharmony_ci	{ 0x23, 0x00 },
1328c2ecf20Sopenharmony_ci	{ 0x24, 0x00 },
1338c2ecf20Sopenharmony_ci	{ 0x25, 0x00 },
1348c2ecf20Sopenharmony_ci	{ 0x26, 0x00 },
1358c2ecf20Sopenharmony_ci	{ 0x27, 0x00 },
1368c2ecf20Sopenharmony_ci	{ 0x28, 0x33 },
1378c2ecf20Sopenharmony_ci	{ 0x29, 0x03 },
1388c2ecf20Sopenharmony_ci	{ 0x2a, 0x00 },
1398c2ecf20Sopenharmony_ci	{ 0x2b, 0x00 },
1408c2ecf20Sopenharmony_ci	{ 0x2c, 0x00 },
1418c2ecf20Sopenharmony_ci	{ 0x2d, 0x00 },
1428c2ecf20Sopenharmony_ci	{ 0x2e, 0x00 },
1438c2ecf20Sopenharmony_ci	{ 0x2f, 0x00 },
1448c2ecf20Sopenharmony_ci	{ 0x30, 0x00 },
1458c2ecf20Sopenharmony_ci	{ 0x31, 0x00 },
1468c2ecf20Sopenharmony_ci	{ 0x32, 0x00 },
1478c2ecf20Sopenharmony_ci	{ 0x33, 0x00 },
1488c2ecf20Sopenharmony_ci	{ 0x34, 0x04 },
1498c2ecf20Sopenharmony_ci	{ 0x35, 0x00 },
1508c2ecf20Sopenharmony_ci	{ 0x36, 0x00 },
1518c2ecf20Sopenharmony_ci	{ 0x37, 0x00 },
1528c2ecf20Sopenharmony_ci	{ 0x38, 0x3C },
1538c2ecf20Sopenharmony_ci	{ 0x39, 0x35 },
1548c2ecf20Sopenharmony_ci	{ 0x3A, 0x01 },
1558c2ecf20Sopenharmony_ci	{ 0x3B, 0x40 },
1568c2ecf20Sopenharmony_ci	{ 0x3C, 0x00 },
1578c2ecf20Sopenharmony_ci	{ 0x3D, 0x01 },
1588c2ecf20Sopenharmony_ci	{ 0x3E, 0x00 },
1598c2ecf20Sopenharmony_ci	{ 0x3F, 0x00 },
1608c2ecf20Sopenharmony_ci	{ 0x40, 0x00 },
1618c2ecf20Sopenharmony_ci	{ 0x41, 0x88 },
1628c2ecf20Sopenharmony_ci	{ 0x42, 0x00 },
1638c2ecf20Sopenharmony_ci	{ 0x43, 0x00 },
1648c2ecf20Sopenharmony_ci	{ 0x44, 0x1F },
1658c2ecf20Sopenharmony_ci	{ 0x50, 0x01 },
1668c2ecf20Sopenharmony_ci	{ 0x51, 0x23 },
1678c2ecf20Sopenharmony_ci	{ 0x52, 0x45 },
1688c2ecf20Sopenharmony_ci	{ 0x53, 0x67 },
1698c2ecf20Sopenharmony_ci	{ 0x54, 0x89 },
1708c2ecf20Sopenharmony_ci	{ 0x55, 0xab },
1718c2ecf20Sopenharmony_ci	{ 0x56, 0x01 },
1728c2ecf20Sopenharmony_ci	{ 0x57, 0x23 },
1738c2ecf20Sopenharmony_ci	{ 0x58, 0x45 },
1748c2ecf20Sopenharmony_ci	{ 0x59, 0x67 },
1758c2ecf20Sopenharmony_ci	{ 0x5a, 0x89 },
1768c2ecf20Sopenharmony_ci	{ 0x5b, 0xab },
1778c2ecf20Sopenharmony_ci	{ 0x5c, 0xcd },
1788c2ecf20Sopenharmony_ci	{ 0x5d, 0xef },
1798c2ecf20Sopenharmony_ci	{ 0x5e, 0x11 },
1808c2ecf20Sopenharmony_ci	{ 0x5f, 0x01 },
1818c2ecf20Sopenharmony_ci	{ 0x60, 0x00 },
1828c2ecf20Sopenharmony_ci	{ 0x61, 0x15 },
1838c2ecf20Sopenharmony_ci	{ 0x62, 0x14 },
1848c2ecf20Sopenharmony_ci	{ 0x63, 0x0E },
1858c2ecf20Sopenharmony_ci	{ 0x64, 0x0F },
1868c2ecf20Sopenharmony_ci	{ 0x65, 0x0C },
1878c2ecf20Sopenharmony_ci	{ 0x66, 0x0D },
1888c2ecf20Sopenharmony_ci	{ 0x67, 0x06 },
1898c2ecf20Sopenharmony_ci	{ 0x68, 0x02 },
1908c2ecf20Sopenharmony_ci	{ 0x69, 0x07 },
1918c2ecf20Sopenharmony_ci	{ 0x6a, 0x02 },
1928c2ecf20Sopenharmony_ci	{ 0x6b, 0x02 },
1938c2ecf20Sopenharmony_ci	{ 0x6c, 0x02 },
1948c2ecf20Sopenharmony_ci	{ 0x6d, 0x02 },
1958c2ecf20Sopenharmony_ci	{ 0x6e, 0x02 },
1968c2ecf20Sopenharmony_ci	{ 0x6f, 0x02 },
1978c2ecf20Sopenharmony_ci	{ 0x70, 0x02 },
1988c2ecf20Sopenharmony_ci	{ 0x71, 0x02 },
1998c2ecf20Sopenharmony_ci	{ 0x72, 0x02 },
2008c2ecf20Sopenharmony_ci	{ 0x73, 0x02 },
2018c2ecf20Sopenharmony_ci	{ 0x74, 0x02 },
2028c2ecf20Sopenharmony_ci	{ 0x75, 0x01 },
2038c2ecf20Sopenharmony_ci	{ 0x76, 0x00 },
2048c2ecf20Sopenharmony_ci	{ 0x77, 0x14 },
2058c2ecf20Sopenharmony_ci	{ 0x78, 0x15 },
2068c2ecf20Sopenharmony_ci	{ 0x79, 0x0E },
2078c2ecf20Sopenharmony_ci	{ 0x7a, 0x0F },
2088c2ecf20Sopenharmony_ci	{ 0x7b, 0x0C },
2098c2ecf20Sopenharmony_ci	{ 0x7c, 0x0D },
2108c2ecf20Sopenharmony_ci	{ 0x7d, 0x06 },
2118c2ecf20Sopenharmony_ci	{ 0x7e, 0x02 },
2128c2ecf20Sopenharmony_ci	{ 0x7f, 0x07 },
2138c2ecf20Sopenharmony_ci	{ 0x80, 0x02 },
2148c2ecf20Sopenharmony_ci	{ 0x81, 0x02 },
2158c2ecf20Sopenharmony_ci	{ 0x82, 0x02 },
2168c2ecf20Sopenharmony_ci	{ 0x83, 0x02 },
2178c2ecf20Sopenharmony_ci	{ 0x84, 0x02 },
2188c2ecf20Sopenharmony_ci	{ 0x85, 0x02 },
2198c2ecf20Sopenharmony_ci	{ 0x86, 0x02 },
2208c2ecf20Sopenharmony_ci	{ 0x87, 0x02 },
2218c2ecf20Sopenharmony_ci	{ 0x88, 0x02 },
2228c2ecf20Sopenharmony_ci	{ 0x89, 0x02 },
2238c2ecf20Sopenharmony_ci	{ 0x8A, 0x02 },
2248c2ecf20Sopenharmony_ci};
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_cistatic const struct ltk050h3146w_cmd page4_cmds[] = {
2278c2ecf20Sopenharmony_ci	{ 0x70, 0x00 },
2288c2ecf20Sopenharmony_ci	{ 0x71, 0x00 },
2298c2ecf20Sopenharmony_ci	{ 0x82, 0x0F }, /* VGH_MOD clamp level=15v */
2308c2ecf20Sopenharmony_ci	{ 0x84, 0x0F }, /* VGH clamp level 15V */
2318c2ecf20Sopenharmony_ci	{ 0x85, 0x0D }, /* VGL clamp level (-10V) */
2328c2ecf20Sopenharmony_ci	{ 0x32, 0xAC },
2338c2ecf20Sopenharmony_ci	{ 0x8C, 0x80 },
2348c2ecf20Sopenharmony_ci	{ 0x3C, 0xF5 },
2358c2ecf20Sopenharmony_ci	{ 0xB5, 0x07 }, /* GAMMA OP */
2368c2ecf20Sopenharmony_ci	{ 0x31, 0x45 }, /* SOURCE OP */
2378c2ecf20Sopenharmony_ci	{ 0x3A, 0x24 }, /* PS_EN OFF */
2388c2ecf20Sopenharmony_ci	{ 0x88, 0x33 }, /* LVD */
2398c2ecf20Sopenharmony_ci};
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_cistatic inline
2428c2ecf20Sopenharmony_cistruct ltk050h3146w *panel_to_ltk050h3146w(struct drm_panel *panel)
2438c2ecf20Sopenharmony_ci{
2448c2ecf20Sopenharmony_ci	return container_of(panel, struct ltk050h3146w, panel);
2458c2ecf20Sopenharmony_ci}
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci#define dsi_dcs_write_seq(dsi, cmd, seq...) do {			\
2488c2ecf20Sopenharmony_ci		static const u8 b[] = { cmd, seq };			\
2498c2ecf20Sopenharmony_ci		int ret;						\
2508c2ecf20Sopenharmony_ci		ret = mipi_dsi_dcs_write_buffer(dsi, b, ARRAY_SIZE(b));	\
2518c2ecf20Sopenharmony_ci		if (ret < 0)						\
2528c2ecf20Sopenharmony_ci			return ret;					\
2538c2ecf20Sopenharmony_ci	} while (0)
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_cistatic int ltk050h3146w_init_sequence(struct ltk050h3146w *ctx)
2568c2ecf20Sopenharmony_ci{
2578c2ecf20Sopenharmony_ci	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
2588c2ecf20Sopenharmony_ci	int ret;
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci	/*
2618c2ecf20Sopenharmony_ci	 * Init sequence was supplied by the panel vendor without much
2628c2ecf20Sopenharmony_ci	 * documentation.
2638c2ecf20Sopenharmony_ci	 */
2648c2ecf20Sopenharmony_ci	dsi_dcs_write_seq(dsi, 0xdf, 0x93, 0x65, 0xf8);
2658c2ecf20Sopenharmony_ci	dsi_dcs_write_seq(dsi, 0xb0, 0x01, 0x03, 0x02, 0x00, 0x64, 0x06,
2668c2ecf20Sopenharmony_ci			  0x01);
2678c2ecf20Sopenharmony_ci	dsi_dcs_write_seq(dsi, 0xb2, 0x00, 0xb5);
2688c2ecf20Sopenharmony_ci	dsi_dcs_write_seq(dsi, 0xb3, 0x00, 0xb5);
2698c2ecf20Sopenharmony_ci	dsi_dcs_write_seq(dsi, 0xb7, 0x00, 0xbf, 0x00, 0x00, 0xbf, 0x00);
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci	dsi_dcs_write_seq(dsi, 0xb9, 0x00, 0xc4, 0x23, 0x07);
2728c2ecf20Sopenharmony_ci	dsi_dcs_write_seq(dsi, 0xbb, 0x02, 0x01, 0x24, 0x00, 0x28, 0x0f,
2738c2ecf20Sopenharmony_ci			  0x28, 0x04, 0xcc, 0xcc, 0xcc);
2748c2ecf20Sopenharmony_ci	dsi_dcs_write_seq(dsi, 0xbc, 0x0f, 0x04);
2758c2ecf20Sopenharmony_ci	dsi_dcs_write_seq(dsi, 0xbe, 0x1e, 0xf2);
2768c2ecf20Sopenharmony_ci	dsi_dcs_write_seq(dsi, 0xc0, 0x26, 0x03);
2778c2ecf20Sopenharmony_ci	dsi_dcs_write_seq(dsi, 0xc1, 0x00, 0x12);
2788c2ecf20Sopenharmony_ci	dsi_dcs_write_seq(dsi, 0xc3, 0x04, 0x02, 0x02, 0x76, 0x01, 0x80,
2798c2ecf20Sopenharmony_ci			  0x80);
2808c2ecf20Sopenharmony_ci	dsi_dcs_write_seq(dsi, 0xc4, 0x24, 0x80, 0xb4, 0x81, 0x12, 0x0f,
2818c2ecf20Sopenharmony_ci			  0x16, 0x00, 0x00);
2828c2ecf20Sopenharmony_ci	dsi_dcs_write_seq(dsi, 0xc8, 0x7f, 0x72, 0x67, 0x5d, 0x5d, 0x50,
2838c2ecf20Sopenharmony_ci			  0x56, 0x41, 0x59, 0x57, 0x55, 0x70, 0x5b, 0x5f,
2848c2ecf20Sopenharmony_ci			  0x4f, 0x47, 0x38, 0x23, 0x08, 0x7f, 0x72, 0x67,
2858c2ecf20Sopenharmony_ci			  0x5d, 0x5d, 0x50, 0x56, 0x41, 0x59, 0x57, 0x55,
2868c2ecf20Sopenharmony_ci			  0x70, 0x5b, 0x5f, 0x4f, 0x47, 0x38, 0x23, 0x08);
2878c2ecf20Sopenharmony_ci	dsi_dcs_write_seq(dsi, 0xd0, 0x1e, 0x1f, 0x57, 0x58, 0x48, 0x4a,
2888c2ecf20Sopenharmony_ci			  0x44, 0x46, 0x40, 0x1f, 0x42, 0x1f, 0x1f, 0x1f,
2898c2ecf20Sopenharmony_ci			  0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f);
2908c2ecf20Sopenharmony_ci	dsi_dcs_write_seq(dsi, 0xd1, 0x1e, 0x1f, 0x57, 0x58, 0x49, 0x4b,
2918c2ecf20Sopenharmony_ci			  0x45, 0x47, 0x41, 0x1f, 0x43, 0x1f, 0x1f, 0x1f,
2928c2ecf20Sopenharmony_ci			  0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f);
2938c2ecf20Sopenharmony_ci	dsi_dcs_write_seq(dsi, 0xd2, 0x1f, 0x1e, 0x17, 0x18, 0x07, 0x05,
2948c2ecf20Sopenharmony_ci			  0x0b, 0x09, 0x03, 0x1f, 0x01, 0x1f, 0x1f, 0x1f,
2958c2ecf20Sopenharmony_ci			  0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f);
2968c2ecf20Sopenharmony_ci	dsi_dcs_write_seq(dsi, 0xd3, 0x1f, 0x1e, 0x17, 0x18, 0x06, 0x04,
2978c2ecf20Sopenharmony_ci			  0x0a, 0x08, 0x02, 0x1f, 0x00, 0x1f, 0x1f, 0x1f,
2988c2ecf20Sopenharmony_ci			  0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f);
2998c2ecf20Sopenharmony_ci	dsi_dcs_write_seq(dsi, 0xd4, 0x00, 0x00, 0x00, 0x0c, 0x06, 0x20,
3008c2ecf20Sopenharmony_ci			  0x01, 0x02, 0x00, 0x60, 0x15, 0xb0, 0x30, 0x03,
3018c2ecf20Sopenharmony_ci			  0x04, 0x00, 0x60, 0x72, 0x0a, 0x00, 0x60, 0x08);
3028c2ecf20Sopenharmony_ci	dsi_dcs_write_seq(dsi, 0xd5, 0x00, 0x06, 0x06, 0x00, 0x30, 0x00,
3038c2ecf20Sopenharmony_ci			  0x00, 0x00, 0x00, 0x00, 0xbc, 0x50, 0x00, 0x05,
3048c2ecf20Sopenharmony_ci			  0x21, 0x00, 0x60);
3058c2ecf20Sopenharmony_ci	dsi_dcs_write_seq(dsi, 0xdd, 0x2c, 0xa3, 0x00);
3068c2ecf20Sopenharmony_ci	dsi_dcs_write_seq(dsi, 0xde, 0x02);
3078c2ecf20Sopenharmony_ci	dsi_dcs_write_seq(dsi, 0xb2, 0x32, 0x1c);
3088c2ecf20Sopenharmony_ci	dsi_dcs_write_seq(dsi, 0xb7, 0x3b, 0x70, 0x00, 0x04);
3098c2ecf20Sopenharmony_ci	dsi_dcs_write_seq(dsi, 0xc1, 0x11);
3108c2ecf20Sopenharmony_ci	dsi_dcs_write_seq(dsi, 0xbb, 0x21, 0x22, 0x23, 0x24, 0x36, 0x37);
3118c2ecf20Sopenharmony_ci	dsi_dcs_write_seq(dsi, 0xc2, 0x20, 0x38, 0x1e, 0x84);
3128c2ecf20Sopenharmony_ci	dsi_dcs_write_seq(dsi, 0xde, 0x00);
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	ret = mipi_dsi_dcs_set_tear_on(dsi, 1);
3158c2ecf20Sopenharmony_ci	if (ret < 0) {
3168c2ecf20Sopenharmony_ci		dev_err(ctx->dev, "failed to set tear on: %d\n", ret);
3178c2ecf20Sopenharmony_ci		return ret;
3188c2ecf20Sopenharmony_ci	}
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci	msleep(60);
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	return 0;
3238c2ecf20Sopenharmony_ci}
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_cistatic const struct drm_display_mode ltk050h3146w_mode = {
3268c2ecf20Sopenharmony_ci	.hdisplay	= 720,
3278c2ecf20Sopenharmony_ci	.hsync_start	= 720 + 42,
3288c2ecf20Sopenharmony_ci	.hsync_end	= 720 + 42 + 8,
3298c2ecf20Sopenharmony_ci	.htotal		= 720 + 42 + 8 + 42,
3308c2ecf20Sopenharmony_ci	.vdisplay	= 1280,
3318c2ecf20Sopenharmony_ci	.vsync_start	= 1280 + 12,
3328c2ecf20Sopenharmony_ci	.vsync_end	= 1280 + 12 + 4,
3338c2ecf20Sopenharmony_ci	.vtotal		= 1280 + 12 + 4 + 18,
3348c2ecf20Sopenharmony_ci	.clock		= 64018,
3358c2ecf20Sopenharmony_ci	.width_mm	= 62,
3368c2ecf20Sopenharmony_ci	.height_mm	= 110,
3378c2ecf20Sopenharmony_ci};
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_cistatic const struct ltk050h3146w_desc ltk050h3146w_data = {
3408c2ecf20Sopenharmony_ci	.mode = &ltk050h3146w_mode,
3418c2ecf20Sopenharmony_ci	.init = ltk050h3146w_init_sequence,
3428c2ecf20Sopenharmony_ci};
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_cistatic int ltk050h3146w_a2_select_page(struct ltk050h3146w *ctx, int page)
3458c2ecf20Sopenharmony_ci{
3468c2ecf20Sopenharmony_ci	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
3478c2ecf20Sopenharmony_ci	u8 d[3] = { 0x98, 0x81, page };
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci	return mipi_dsi_dcs_write(dsi, 0xff, d, ARRAY_SIZE(d));
3508c2ecf20Sopenharmony_ci}
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_cistatic int ltk050h3146w_a2_write_page(struct ltk050h3146w *ctx, int page,
3538c2ecf20Sopenharmony_ci				      const struct ltk050h3146w_cmd *cmds,
3548c2ecf20Sopenharmony_ci				      int num)
3558c2ecf20Sopenharmony_ci{
3568c2ecf20Sopenharmony_ci	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
3578c2ecf20Sopenharmony_ci	int i, ret;
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci	ret = ltk050h3146w_a2_select_page(ctx, page);
3608c2ecf20Sopenharmony_ci	if (ret < 0) {
3618c2ecf20Sopenharmony_ci		dev_err(ctx->dev, "failed to select page %d: %d\n", page, ret);
3628c2ecf20Sopenharmony_ci		return ret;
3638c2ecf20Sopenharmony_ci	}
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	for (i = 0; i < num; i++) {
3668c2ecf20Sopenharmony_ci		ret = mipi_dsi_generic_write(dsi, &cmds[i],
3678c2ecf20Sopenharmony_ci					     sizeof(struct ltk050h3146w_cmd));
3688c2ecf20Sopenharmony_ci		if (ret < 0) {
3698c2ecf20Sopenharmony_ci			dev_err(ctx->dev, "failed to write page %d init cmds: %d\n", page, ret);
3708c2ecf20Sopenharmony_ci			return ret;
3718c2ecf20Sopenharmony_ci		}
3728c2ecf20Sopenharmony_ci	}
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci	return 0;
3758c2ecf20Sopenharmony_ci}
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_cistatic int ltk050h3146w_a2_init_sequence(struct ltk050h3146w *ctx)
3788c2ecf20Sopenharmony_ci{
3798c2ecf20Sopenharmony_ci	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
3808c2ecf20Sopenharmony_ci	int ret;
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ci	/*
3838c2ecf20Sopenharmony_ci	 * Init sequence was supplied by the panel vendor without much
3848c2ecf20Sopenharmony_ci	 * documentation.
3858c2ecf20Sopenharmony_ci	 */
3868c2ecf20Sopenharmony_ci	ret = ltk050h3146w_a2_write_page(ctx, 3, page3_cmds,
3878c2ecf20Sopenharmony_ci					 ARRAY_SIZE(page3_cmds));
3888c2ecf20Sopenharmony_ci	if (ret < 0)
3898c2ecf20Sopenharmony_ci		return ret;
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci	ret = ltk050h3146w_a2_write_page(ctx, 4, page4_cmds,
3928c2ecf20Sopenharmony_ci					 ARRAY_SIZE(page4_cmds));
3938c2ecf20Sopenharmony_ci	if (ret < 0)
3948c2ecf20Sopenharmony_ci		return ret;
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci	ret = ltk050h3146w_a2_write_page(ctx, 1, page1_cmds,
3978c2ecf20Sopenharmony_ci					 ARRAY_SIZE(page1_cmds));
3988c2ecf20Sopenharmony_ci	if (ret < 0)
3998c2ecf20Sopenharmony_ci		return ret;
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci	ret = ltk050h3146w_a2_select_page(ctx, 0);
4028c2ecf20Sopenharmony_ci	if (ret < 0) {
4038c2ecf20Sopenharmony_ci		dev_err(ctx->dev, "failed to select page 0: %d\n", ret);
4048c2ecf20Sopenharmony_ci		return ret;
4058c2ecf20Sopenharmony_ci	}
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci	/* vendor code called this without param, where there should be one */
4088c2ecf20Sopenharmony_ci	ret = mipi_dsi_dcs_set_tear_on(dsi, 0);
4098c2ecf20Sopenharmony_ci	if (ret < 0) {
4108c2ecf20Sopenharmony_ci		dev_err(ctx->dev, "failed to set tear on: %d\n", ret);
4118c2ecf20Sopenharmony_ci		return ret;
4128c2ecf20Sopenharmony_ci	}
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ci	msleep(60);
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_ci	return 0;
4178c2ecf20Sopenharmony_ci}
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_cistatic const struct drm_display_mode ltk050h3146w_a2_mode = {
4208c2ecf20Sopenharmony_ci	.hdisplay	= 720,
4218c2ecf20Sopenharmony_ci	.hsync_start	= 720 + 42,
4228c2ecf20Sopenharmony_ci	.hsync_end	= 720 + 42 + 10,
4238c2ecf20Sopenharmony_ci	.htotal		= 720 + 42 + 10 + 60,
4248c2ecf20Sopenharmony_ci	.vdisplay	= 1280,
4258c2ecf20Sopenharmony_ci	.vsync_start	= 1280 + 18,
4268c2ecf20Sopenharmony_ci	.vsync_end	= 1280 + 18 + 4,
4278c2ecf20Sopenharmony_ci	.vtotal		= 1280 + 18 + 4 + 12,
4288c2ecf20Sopenharmony_ci	.clock		= 65595,
4298c2ecf20Sopenharmony_ci	.width_mm	= 62,
4308c2ecf20Sopenharmony_ci	.height_mm	= 110,
4318c2ecf20Sopenharmony_ci};
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_cistatic const struct ltk050h3146w_desc ltk050h3146w_a2_data = {
4348c2ecf20Sopenharmony_ci	.mode = &ltk050h3146w_a2_mode,
4358c2ecf20Sopenharmony_ci	.init = ltk050h3146w_a2_init_sequence,
4368c2ecf20Sopenharmony_ci};
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_cistatic int ltk050h3146w_unprepare(struct drm_panel *panel)
4398c2ecf20Sopenharmony_ci{
4408c2ecf20Sopenharmony_ci	struct ltk050h3146w *ctx = panel_to_ltk050h3146w(panel);
4418c2ecf20Sopenharmony_ci	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
4428c2ecf20Sopenharmony_ci	int ret;
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_ci	if (!ctx->prepared)
4458c2ecf20Sopenharmony_ci		return 0;
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci	ret = mipi_dsi_dcs_set_display_off(dsi);
4488c2ecf20Sopenharmony_ci	if (ret < 0) {
4498c2ecf20Sopenharmony_ci		dev_err(ctx->dev, "failed to set display off: %d\n", ret);
4508c2ecf20Sopenharmony_ci		return ret;
4518c2ecf20Sopenharmony_ci	}
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci	mipi_dsi_dcs_enter_sleep_mode(dsi);
4548c2ecf20Sopenharmony_ci	if (ret < 0) {
4558c2ecf20Sopenharmony_ci		dev_err(ctx->dev, "failed to enter sleep mode: %d\n", ret);
4568c2ecf20Sopenharmony_ci		return ret;
4578c2ecf20Sopenharmony_ci	}
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci	regulator_disable(ctx->iovcc);
4608c2ecf20Sopenharmony_ci	regulator_disable(ctx->vci);
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci	ctx->prepared = false;
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_ci	return 0;
4658c2ecf20Sopenharmony_ci}
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_cistatic int ltk050h3146w_prepare(struct drm_panel *panel)
4688c2ecf20Sopenharmony_ci{
4698c2ecf20Sopenharmony_ci	struct ltk050h3146w *ctx = panel_to_ltk050h3146w(panel);
4708c2ecf20Sopenharmony_ci	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
4718c2ecf20Sopenharmony_ci	int ret;
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_ci	if (ctx->prepared)
4748c2ecf20Sopenharmony_ci		return 0;
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_ci	dev_dbg(ctx->dev, "Resetting the panel\n");
4778c2ecf20Sopenharmony_ci	ret = regulator_enable(ctx->vci);
4788c2ecf20Sopenharmony_ci	if (ret < 0) {
4798c2ecf20Sopenharmony_ci		dev_err(ctx->dev, "Failed to enable vci supply: %d\n", ret);
4808c2ecf20Sopenharmony_ci		return ret;
4818c2ecf20Sopenharmony_ci	}
4828c2ecf20Sopenharmony_ci	ret = regulator_enable(ctx->iovcc);
4838c2ecf20Sopenharmony_ci	if (ret < 0) {
4848c2ecf20Sopenharmony_ci		dev_err(ctx->dev, "Failed to enable iovcc supply: %d\n", ret);
4858c2ecf20Sopenharmony_ci		goto disable_vci;
4868c2ecf20Sopenharmony_ci	}
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ci	gpiod_set_value_cansleep(ctx->reset_gpio, 1);
4898c2ecf20Sopenharmony_ci	usleep_range(5000, 6000);
4908c2ecf20Sopenharmony_ci	gpiod_set_value_cansleep(ctx->reset_gpio, 0);
4918c2ecf20Sopenharmony_ci	msleep(20);
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_ci	ret = ctx->panel_desc->init(ctx);
4948c2ecf20Sopenharmony_ci	if (ret < 0) {
4958c2ecf20Sopenharmony_ci		dev_err(ctx->dev, "Panel init sequence failed: %d\n", ret);
4968c2ecf20Sopenharmony_ci		goto disable_iovcc;
4978c2ecf20Sopenharmony_ci	}
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci	ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
5008c2ecf20Sopenharmony_ci	if (ret < 0) {
5018c2ecf20Sopenharmony_ci		dev_err(ctx->dev, "Failed to exit sleep mode: %d\n", ret);
5028c2ecf20Sopenharmony_ci		goto disable_iovcc;
5038c2ecf20Sopenharmony_ci	}
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ci	/* T9: 120ms */
5068c2ecf20Sopenharmony_ci	msleep(120);
5078c2ecf20Sopenharmony_ci
5088c2ecf20Sopenharmony_ci	ret = mipi_dsi_dcs_set_display_on(dsi);
5098c2ecf20Sopenharmony_ci	if (ret < 0) {
5108c2ecf20Sopenharmony_ci		dev_err(ctx->dev, "Failed to set display on: %d\n", ret);
5118c2ecf20Sopenharmony_ci		goto disable_iovcc;
5128c2ecf20Sopenharmony_ci	}
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ci	msleep(50);
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_ci	ctx->prepared = true;
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_ci	return 0;
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_cidisable_iovcc:
5218c2ecf20Sopenharmony_ci	regulator_disable(ctx->iovcc);
5228c2ecf20Sopenharmony_cidisable_vci:
5238c2ecf20Sopenharmony_ci	regulator_disable(ctx->vci);
5248c2ecf20Sopenharmony_ci	return ret;
5258c2ecf20Sopenharmony_ci}
5268c2ecf20Sopenharmony_ci
5278c2ecf20Sopenharmony_cistatic int ltk050h3146w_get_modes(struct drm_panel *panel,
5288c2ecf20Sopenharmony_ci				  struct drm_connector *connector)
5298c2ecf20Sopenharmony_ci{
5308c2ecf20Sopenharmony_ci	struct ltk050h3146w *ctx = panel_to_ltk050h3146w(panel);
5318c2ecf20Sopenharmony_ci	struct drm_display_mode *mode;
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ci	mode = drm_mode_duplicate(connector->dev, ctx->panel_desc->mode);
5348c2ecf20Sopenharmony_ci	if (!mode)
5358c2ecf20Sopenharmony_ci		return -ENOMEM;
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_ci	drm_mode_set_name(mode);
5388c2ecf20Sopenharmony_ci
5398c2ecf20Sopenharmony_ci	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
5408c2ecf20Sopenharmony_ci	connector->display_info.width_mm = mode->width_mm;
5418c2ecf20Sopenharmony_ci	connector->display_info.height_mm = mode->height_mm;
5428c2ecf20Sopenharmony_ci	drm_mode_probed_add(connector, mode);
5438c2ecf20Sopenharmony_ci
5448c2ecf20Sopenharmony_ci	return 1;
5458c2ecf20Sopenharmony_ci}
5468c2ecf20Sopenharmony_ci
5478c2ecf20Sopenharmony_cistatic const struct drm_panel_funcs ltk050h3146w_funcs = {
5488c2ecf20Sopenharmony_ci	.unprepare	= ltk050h3146w_unprepare,
5498c2ecf20Sopenharmony_ci	.prepare	= ltk050h3146w_prepare,
5508c2ecf20Sopenharmony_ci	.get_modes	= ltk050h3146w_get_modes,
5518c2ecf20Sopenharmony_ci};
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_cistatic int ltk050h3146w_probe(struct mipi_dsi_device *dsi)
5548c2ecf20Sopenharmony_ci{
5558c2ecf20Sopenharmony_ci	struct device *dev = &dsi->dev;
5568c2ecf20Sopenharmony_ci	struct ltk050h3146w *ctx;
5578c2ecf20Sopenharmony_ci	int ret;
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_ci	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
5608c2ecf20Sopenharmony_ci	if (!ctx)
5618c2ecf20Sopenharmony_ci		return -ENOMEM;
5628c2ecf20Sopenharmony_ci
5638c2ecf20Sopenharmony_ci	ctx->panel_desc = of_device_get_match_data(dev);
5648c2ecf20Sopenharmony_ci	if (!ctx->panel_desc)
5658c2ecf20Sopenharmony_ci		return -EINVAL;
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_ci	ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
5688c2ecf20Sopenharmony_ci	if (IS_ERR(ctx->reset_gpio)) {
5698c2ecf20Sopenharmony_ci		dev_err(dev, "cannot get reset gpio\n");
5708c2ecf20Sopenharmony_ci		return PTR_ERR(ctx->reset_gpio);
5718c2ecf20Sopenharmony_ci	}
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_ci	ctx->vci = devm_regulator_get(dev, "vci");
5748c2ecf20Sopenharmony_ci	if (IS_ERR(ctx->vci)) {
5758c2ecf20Sopenharmony_ci		ret = PTR_ERR(ctx->vci);
5768c2ecf20Sopenharmony_ci		if (ret != -EPROBE_DEFER)
5778c2ecf20Sopenharmony_ci			dev_err(dev, "Failed to request vci regulator: %d\n", ret);
5788c2ecf20Sopenharmony_ci		return ret;
5798c2ecf20Sopenharmony_ci	}
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_ci	ctx->iovcc = devm_regulator_get(dev, "iovcc");
5828c2ecf20Sopenharmony_ci	if (IS_ERR(ctx->iovcc)) {
5838c2ecf20Sopenharmony_ci		ret = PTR_ERR(ctx->iovcc);
5848c2ecf20Sopenharmony_ci		if (ret != -EPROBE_DEFER)
5858c2ecf20Sopenharmony_ci			dev_err(dev, "Failed to request iovcc regulator: %d\n", ret);
5868c2ecf20Sopenharmony_ci		return ret;
5878c2ecf20Sopenharmony_ci	}
5888c2ecf20Sopenharmony_ci
5898c2ecf20Sopenharmony_ci	mipi_dsi_set_drvdata(dsi, ctx);
5908c2ecf20Sopenharmony_ci
5918c2ecf20Sopenharmony_ci	ctx->dev = dev;
5928c2ecf20Sopenharmony_ci
5938c2ecf20Sopenharmony_ci	dsi->lanes = 4;
5948c2ecf20Sopenharmony_ci	dsi->format = MIPI_DSI_FMT_RGB888;
5958c2ecf20Sopenharmony_ci	dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
5968c2ecf20Sopenharmony_ci			  MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_EOT_PACKET;
5978c2ecf20Sopenharmony_ci
5988c2ecf20Sopenharmony_ci	drm_panel_init(&ctx->panel, &dsi->dev, &ltk050h3146w_funcs,
5998c2ecf20Sopenharmony_ci		       DRM_MODE_CONNECTOR_DSI);
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_ci	ret = drm_panel_of_backlight(&ctx->panel);
6028c2ecf20Sopenharmony_ci	if (ret)
6038c2ecf20Sopenharmony_ci		return ret;
6048c2ecf20Sopenharmony_ci
6058c2ecf20Sopenharmony_ci	drm_panel_add(&ctx->panel);
6068c2ecf20Sopenharmony_ci
6078c2ecf20Sopenharmony_ci	ret = mipi_dsi_attach(dsi);
6088c2ecf20Sopenharmony_ci	if (ret < 0) {
6098c2ecf20Sopenharmony_ci		dev_err(dev, "mipi_dsi_attach failed: %d\n", ret);
6108c2ecf20Sopenharmony_ci		drm_panel_remove(&ctx->panel);
6118c2ecf20Sopenharmony_ci		return ret;
6128c2ecf20Sopenharmony_ci	}
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_ci	return 0;
6158c2ecf20Sopenharmony_ci}
6168c2ecf20Sopenharmony_ci
6178c2ecf20Sopenharmony_cistatic void ltk050h3146w_shutdown(struct mipi_dsi_device *dsi)
6188c2ecf20Sopenharmony_ci{
6198c2ecf20Sopenharmony_ci	struct ltk050h3146w *ctx = mipi_dsi_get_drvdata(dsi);
6208c2ecf20Sopenharmony_ci	int ret;
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_ci	ret = drm_panel_unprepare(&ctx->panel);
6238c2ecf20Sopenharmony_ci	if (ret < 0)
6248c2ecf20Sopenharmony_ci		dev_err(&dsi->dev, "Failed to unprepare panel: %d\n", ret);
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_ci	ret = drm_panel_disable(&ctx->panel);
6278c2ecf20Sopenharmony_ci	if (ret < 0)
6288c2ecf20Sopenharmony_ci		dev_err(&dsi->dev, "Failed to disable panel: %d\n", ret);
6298c2ecf20Sopenharmony_ci}
6308c2ecf20Sopenharmony_ci
6318c2ecf20Sopenharmony_cistatic int ltk050h3146w_remove(struct mipi_dsi_device *dsi)
6328c2ecf20Sopenharmony_ci{
6338c2ecf20Sopenharmony_ci	struct ltk050h3146w *ctx = mipi_dsi_get_drvdata(dsi);
6348c2ecf20Sopenharmony_ci	int ret;
6358c2ecf20Sopenharmony_ci
6368c2ecf20Sopenharmony_ci	ltk050h3146w_shutdown(dsi);
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_ci	ret = mipi_dsi_detach(dsi);
6398c2ecf20Sopenharmony_ci	if (ret < 0)
6408c2ecf20Sopenharmony_ci		dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret);
6418c2ecf20Sopenharmony_ci
6428c2ecf20Sopenharmony_ci	drm_panel_remove(&ctx->panel);
6438c2ecf20Sopenharmony_ci
6448c2ecf20Sopenharmony_ci	return 0;
6458c2ecf20Sopenharmony_ci}
6468c2ecf20Sopenharmony_ci
6478c2ecf20Sopenharmony_cistatic const struct of_device_id ltk050h3146w_of_match[] = {
6488c2ecf20Sopenharmony_ci	{
6498c2ecf20Sopenharmony_ci		.compatible = "leadtek,ltk050h3146w",
6508c2ecf20Sopenharmony_ci		.data = &ltk050h3146w_data,
6518c2ecf20Sopenharmony_ci	},
6528c2ecf20Sopenharmony_ci	{
6538c2ecf20Sopenharmony_ci		.compatible = "leadtek,ltk050h3146w-a2",
6548c2ecf20Sopenharmony_ci		.data = &ltk050h3146w_a2_data,
6558c2ecf20Sopenharmony_ci	},
6568c2ecf20Sopenharmony_ci	{ /* sentinel */ }
6578c2ecf20Sopenharmony_ci};
6588c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, ltk050h3146w_of_match);
6598c2ecf20Sopenharmony_ci
6608c2ecf20Sopenharmony_cistatic struct mipi_dsi_driver ltk050h3146w_driver = {
6618c2ecf20Sopenharmony_ci	.driver = {
6628c2ecf20Sopenharmony_ci		.name = "panel-leadtek-ltk050h3146w",
6638c2ecf20Sopenharmony_ci		.of_match_table = ltk050h3146w_of_match,
6648c2ecf20Sopenharmony_ci	},
6658c2ecf20Sopenharmony_ci	.probe	= ltk050h3146w_probe,
6668c2ecf20Sopenharmony_ci	.remove = ltk050h3146w_remove,
6678c2ecf20Sopenharmony_ci	.shutdown = ltk050h3146w_shutdown,
6688c2ecf20Sopenharmony_ci};
6698c2ecf20Sopenharmony_cimodule_mipi_dsi_driver(ltk050h3146w_driver);
6708c2ecf20Sopenharmony_ci
6718c2ecf20Sopenharmony_ciMODULE_AUTHOR("Heiko Stuebner <heiko.stuebner@theobroma-systems.com>");
6728c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("DRM driver for Leadtek LTK050H3146W MIPI DSI panel");
6738c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
674