162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2020 Theobroma Systems Design und Consulting GmbH
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <linux/delay.h>
762306a36Sopenharmony_ci#include <linux/gpio/consumer.h>
862306a36Sopenharmony_ci#include <linux/media-bus-format.h>
962306a36Sopenharmony_ci#include <linux/module.h>
1062306a36Sopenharmony_ci#include <linux/of.h>
1162306a36Sopenharmony_ci#include <linux/regulator/consumer.h>
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include <video/display_timing.h>
1462306a36Sopenharmony_ci#include <video/mipi_display.h>
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci#include <drm/drm_mipi_dsi.h>
1762306a36Sopenharmony_ci#include <drm/drm_modes.h>
1862306a36Sopenharmony_ci#include <drm/drm_panel.h>
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_cistruct ltk050h3146w_cmd {
2162306a36Sopenharmony_ci	char cmd;
2262306a36Sopenharmony_ci	char data;
2362306a36Sopenharmony_ci};
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_cistruct ltk050h3146w;
2662306a36Sopenharmony_cistruct ltk050h3146w_desc {
2762306a36Sopenharmony_ci	const struct drm_display_mode *mode;
2862306a36Sopenharmony_ci	int (*init)(struct ltk050h3146w *ctx);
2962306a36Sopenharmony_ci};
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_cistruct ltk050h3146w {
3262306a36Sopenharmony_ci	struct device *dev;
3362306a36Sopenharmony_ci	struct drm_panel panel;
3462306a36Sopenharmony_ci	struct gpio_desc *reset_gpio;
3562306a36Sopenharmony_ci	struct regulator *vci;
3662306a36Sopenharmony_ci	struct regulator *iovcc;
3762306a36Sopenharmony_ci	const struct ltk050h3146w_desc *panel_desc;
3862306a36Sopenharmony_ci	bool prepared;
3962306a36Sopenharmony_ci};
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_cistatic const struct ltk050h3146w_cmd page1_cmds[] = {
4262306a36Sopenharmony_ci	{ 0x22, 0x0A }, /* BGR SS GS */
4362306a36Sopenharmony_ci	{ 0x31, 0x00 }, /* column inversion */
4462306a36Sopenharmony_ci	{ 0x53, 0xA2 }, /* VCOM1 */
4562306a36Sopenharmony_ci	{ 0x55, 0xA2 }, /* VCOM2 */
4662306a36Sopenharmony_ci	{ 0x50, 0x81 }, /* VREG1OUT=5V */
4762306a36Sopenharmony_ci	{ 0x51, 0x85 }, /* VREG2OUT=-5V */
4862306a36Sopenharmony_ci	{ 0x62, 0x0D }, /* EQT Time setting */
4962306a36Sopenharmony_ci/*
5062306a36Sopenharmony_ci * The vendor init selected page 1 here _again_
5162306a36Sopenharmony_ci * Is this supposed to be page 2?
5262306a36Sopenharmony_ci */
5362306a36Sopenharmony_ci	{ 0xA0, 0x00 },
5462306a36Sopenharmony_ci	{ 0xA1, 0x1A },
5562306a36Sopenharmony_ci	{ 0xA2, 0x28 },
5662306a36Sopenharmony_ci	{ 0xA3, 0x13 },
5762306a36Sopenharmony_ci	{ 0xA4, 0x16 },
5862306a36Sopenharmony_ci	{ 0xA5, 0x29 },
5962306a36Sopenharmony_ci	{ 0xA6, 0x1D },
6062306a36Sopenharmony_ci	{ 0xA7, 0x1E },
6162306a36Sopenharmony_ci	{ 0xA8, 0x84 },
6262306a36Sopenharmony_ci	{ 0xA9, 0x1C },
6362306a36Sopenharmony_ci	{ 0xAA, 0x28 },
6462306a36Sopenharmony_ci	{ 0xAB, 0x75 },
6562306a36Sopenharmony_ci	{ 0xAC, 0x1A },
6662306a36Sopenharmony_ci	{ 0xAD, 0x19 },
6762306a36Sopenharmony_ci	{ 0xAE, 0x4D },
6862306a36Sopenharmony_ci	{ 0xAF, 0x22 },
6962306a36Sopenharmony_ci	{ 0xB0, 0x28 },
7062306a36Sopenharmony_ci	{ 0xB1, 0x54 },
7162306a36Sopenharmony_ci	{ 0xB2, 0x66 },
7262306a36Sopenharmony_ci	{ 0xB3, 0x39 },
7362306a36Sopenharmony_ci	{ 0xC0, 0x00 },
7462306a36Sopenharmony_ci	{ 0xC1, 0x1A },
7562306a36Sopenharmony_ci	{ 0xC2, 0x28 },
7662306a36Sopenharmony_ci	{ 0xC3, 0x13 },
7762306a36Sopenharmony_ci	{ 0xC4, 0x16 },
7862306a36Sopenharmony_ci	{ 0xC5, 0x29 },
7962306a36Sopenharmony_ci	{ 0xC6, 0x1D },
8062306a36Sopenharmony_ci	{ 0xC7, 0x1E },
8162306a36Sopenharmony_ci	{ 0xC8, 0x84 },
8262306a36Sopenharmony_ci	{ 0xC9, 0x1C },
8362306a36Sopenharmony_ci	{ 0xCA, 0x28 },
8462306a36Sopenharmony_ci	{ 0xCB, 0x75 },
8562306a36Sopenharmony_ci	{ 0xCC, 0x1A },
8662306a36Sopenharmony_ci	{ 0xCD, 0x19 },
8762306a36Sopenharmony_ci	{ 0xCE, 0x4D },
8862306a36Sopenharmony_ci	{ 0xCF, 0x22 },
8962306a36Sopenharmony_ci	{ 0xD0, 0x28 },
9062306a36Sopenharmony_ci	{ 0xD1, 0x54 },
9162306a36Sopenharmony_ci	{ 0xD2, 0x66 },
9262306a36Sopenharmony_ci	{ 0xD3, 0x39 },
9362306a36Sopenharmony_ci};
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_cistatic const struct ltk050h3146w_cmd page3_cmds[] = {
9662306a36Sopenharmony_ci	{ 0x01, 0x00 },
9762306a36Sopenharmony_ci	{ 0x02, 0x00 },
9862306a36Sopenharmony_ci	{ 0x03, 0x73 },
9962306a36Sopenharmony_ci	{ 0x04, 0x00 },
10062306a36Sopenharmony_ci	{ 0x05, 0x00 },
10162306a36Sopenharmony_ci	{ 0x06, 0x0a },
10262306a36Sopenharmony_ci	{ 0x07, 0x00 },
10362306a36Sopenharmony_ci	{ 0x08, 0x00 },
10462306a36Sopenharmony_ci	{ 0x09, 0x01 },
10562306a36Sopenharmony_ci	{ 0x0a, 0x00 },
10662306a36Sopenharmony_ci	{ 0x0b, 0x00 },
10762306a36Sopenharmony_ci	{ 0x0c, 0x01 },
10862306a36Sopenharmony_ci	{ 0x0d, 0x00 },
10962306a36Sopenharmony_ci	{ 0x0e, 0x00 },
11062306a36Sopenharmony_ci	{ 0x0f, 0x1d },
11162306a36Sopenharmony_ci	{ 0x10, 0x1d },
11262306a36Sopenharmony_ci	{ 0x11, 0x00 },
11362306a36Sopenharmony_ci	{ 0x12, 0x00 },
11462306a36Sopenharmony_ci	{ 0x13, 0x00 },
11562306a36Sopenharmony_ci	{ 0x14, 0x00 },
11662306a36Sopenharmony_ci	{ 0x15, 0x00 },
11762306a36Sopenharmony_ci	{ 0x16, 0x00 },
11862306a36Sopenharmony_ci	{ 0x17, 0x00 },
11962306a36Sopenharmony_ci	{ 0x18, 0x00 },
12062306a36Sopenharmony_ci	{ 0x19, 0x00 },
12162306a36Sopenharmony_ci	{ 0x1a, 0x00 },
12262306a36Sopenharmony_ci	{ 0x1b, 0x00 },
12362306a36Sopenharmony_ci	{ 0x1c, 0x00 },
12462306a36Sopenharmony_ci	{ 0x1d, 0x00 },
12562306a36Sopenharmony_ci	{ 0x1e, 0x40 },
12662306a36Sopenharmony_ci	{ 0x1f, 0x80 },
12762306a36Sopenharmony_ci	{ 0x20, 0x06 },
12862306a36Sopenharmony_ci	{ 0x21, 0x02 },
12962306a36Sopenharmony_ci	{ 0x22, 0x00 },
13062306a36Sopenharmony_ci	{ 0x23, 0x00 },
13162306a36Sopenharmony_ci	{ 0x24, 0x00 },
13262306a36Sopenharmony_ci	{ 0x25, 0x00 },
13362306a36Sopenharmony_ci	{ 0x26, 0x00 },
13462306a36Sopenharmony_ci	{ 0x27, 0x00 },
13562306a36Sopenharmony_ci	{ 0x28, 0x33 },
13662306a36Sopenharmony_ci	{ 0x29, 0x03 },
13762306a36Sopenharmony_ci	{ 0x2a, 0x00 },
13862306a36Sopenharmony_ci	{ 0x2b, 0x00 },
13962306a36Sopenharmony_ci	{ 0x2c, 0x00 },
14062306a36Sopenharmony_ci	{ 0x2d, 0x00 },
14162306a36Sopenharmony_ci	{ 0x2e, 0x00 },
14262306a36Sopenharmony_ci	{ 0x2f, 0x00 },
14362306a36Sopenharmony_ci	{ 0x30, 0x00 },
14462306a36Sopenharmony_ci	{ 0x31, 0x00 },
14562306a36Sopenharmony_ci	{ 0x32, 0x00 },
14662306a36Sopenharmony_ci	{ 0x33, 0x00 },
14762306a36Sopenharmony_ci	{ 0x34, 0x04 },
14862306a36Sopenharmony_ci	{ 0x35, 0x00 },
14962306a36Sopenharmony_ci	{ 0x36, 0x00 },
15062306a36Sopenharmony_ci	{ 0x37, 0x00 },
15162306a36Sopenharmony_ci	{ 0x38, 0x3C },
15262306a36Sopenharmony_ci	{ 0x39, 0x35 },
15362306a36Sopenharmony_ci	{ 0x3A, 0x01 },
15462306a36Sopenharmony_ci	{ 0x3B, 0x40 },
15562306a36Sopenharmony_ci	{ 0x3C, 0x00 },
15662306a36Sopenharmony_ci	{ 0x3D, 0x01 },
15762306a36Sopenharmony_ci	{ 0x3E, 0x00 },
15862306a36Sopenharmony_ci	{ 0x3F, 0x00 },
15962306a36Sopenharmony_ci	{ 0x40, 0x00 },
16062306a36Sopenharmony_ci	{ 0x41, 0x88 },
16162306a36Sopenharmony_ci	{ 0x42, 0x00 },
16262306a36Sopenharmony_ci	{ 0x43, 0x00 },
16362306a36Sopenharmony_ci	{ 0x44, 0x1F },
16462306a36Sopenharmony_ci	{ 0x50, 0x01 },
16562306a36Sopenharmony_ci	{ 0x51, 0x23 },
16662306a36Sopenharmony_ci	{ 0x52, 0x45 },
16762306a36Sopenharmony_ci	{ 0x53, 0x67 },
16862306a36Sopenharmony_ci	{ 0x54, 0x89 },
16962306a36Sopenharmony_ci	{ 0x55, 0xab },
17062306a36Sopenharmony_ci	{ 0x56, 0x01 },
17162306a36Sopenharmony_ci	{ 0x57, 0x23 },
17262306a36Sopenharmony_ci	{ 0x58, 0x45 },
17362306a36Sopenharmony_ci	{ 0x59, 0x67 },
17462306a36Sopenharmony_ci	{ 0x5a, 0x89 },
17562306a36Sopenharmony_ci	{ 0x5b, 0xab },
17662306a36Sopenharmony_ci	{ 0x5c, 0xcd },
17762306a36Sopenharmony_ci	{ 0x5d, 0xef },
17862306a36Sopenharmony_ci	{ 0x5e, 0x11 },
17962306a36Sopenharmony_ci	{ 0x5f, 0x01 },
18062306a36Sopenharmony_ci	{ 0x60, 0x00 },
18162306a36Sopenharmony_ci	{ 0x61, 0x15 },
18262306a36Sopenharmony_ci	{ 0x62, 0x14 },
18362306a36Sopenharmony_ci	{ 0x63, 0x0E },
18462306a36Sopenharmony_ci	{ 0x64, 0x0F },
18562306a36Sopenharmony_ci	{ 0x65, 0x0C },
18662306a36Sopenharmony_ci	{ 0x66, 0x0D },
18762306a36Sopenharmony_ci	{ 0x67, 0x06 },
18862306a36Sopenharmony_ci	{ 0x68, 0x02 },
18962306a36Sopenharmony_ci	{ 0x69, 0x07 },
19062306a36Sopenharmony_ci	{ 0x6a, 0x02 },
19162306a36Sopenharmony_ci	{ 0x6b, 0x02 },
19262306a36Sopenharmony_ci	{ 0x6c, 0x02 },
19362306a36Sopenharmony_ci	{ 0x6d, 0x02 },
19462306a36Sopenharmony_ci	{ 0x6e, 0x02 },
19562306a36Sopenharmony_ci	{ 0x6f, 0x02 },
19662306a36Sopenharmony_ci	{ 0x70, 0x02 },
19762306a36Sopenharmony_ci	{ 0x71, 0x02 },
19862306a36Sopenharmony_ci	{ 0x72, 0x02 },
19962306a36Sopenharmony_ci	{ 0x73, 0x02 },
20062306a36Sopenharmony_ci	{ 0x74, 0x02 },
20162306a36Sopenharmony_ci	{ 0x75, 0x01 },
20262306a36Sopenharmony_ci	{ 0x76, 0x00 },
20362306a36Sopenharmony_ci	{ 0x77, 0x14 },
20462306a36Sopenharmony_ci	{ 0x78, 0x15 },
20562306a36Sopenharmony_ci	{ 0x79, 0x0E },
20662306a36Sopenharmony_ci	{ 0x7a, 0x0F },
20762306a36Sopenharmony_ci	{ 0x7b, 0x0C },
20862306a36Sopenharmony_ci	{ 0x7c, 0x0D },
20962306a36Sopenharmony_ci	{ 0x7d, 0x06 },
21062306a36Sopenharmony_ci	{ 0x7e, 0x02 },
21162306a36Sopenharmony_ci	{ 0x7f, 0x07 },
21262306a36Sopenharmony_ci	{ 0x80, 0x02 },
21362306a36Sopenharmony_ci	{ 0x81, 0x02 },
21462306a36Sopenharmony_ci	{ 0x82, 0x02 },
21562306a36Sopenharmony_ci	{ 0x83, 0x02 },
21662306a36Sopenharmony_ci	{ 0x84, 0x02 },
21762306a36Sopenharmony_ci	{ 0x85, 0x02 },
21862306a36Sopenharmony_ci	{ 0x86, 0x02 },
21962306a36Sopenharmony_ci	{ 0x87, 0x02 },
22062306a36Sopenharmony_ci	{ 0x88, 0x02 },
22162306a36Sopenharmony_ci	{ 0x89, 0x02 },
22262306a36Sopenharmony_ci	{ 0x8A, 0x02 },
22362306a36Sopenharmony_ci};
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_cistatic const struct ltk050h3146w_cmd page4_cmds[] = {
22662306a36Sopenharmony_ci	{ 0x70, 0x00 },
22762306a36Sopenharmony_ci	{ 0x71, 0x00 },
22862306a36Sopenharmony_ci	{ 0x82, 0x0F }, /* VGH_MOD clamp level=15v */
22962306a36Sopenharmony_ci	{ 0x84, 0x0F }, /* VGH clamp level 15V */
23062306a36Sopenharmony_ci	{ 0x85, 0x0D }, /* VGL clamp level (-10V) */
23162306a36Sopenharmony_ci	{ 0x32, 0xAC },
23262306a36Sopenharmony_ci	{ 0x8C, 0x80 },
23362306a36Sopenharmony_ci	{ 0x3C, 0xF5 },
23462306a36Sopenharmony_ci	{ 0xB5, 0x07 }, /* GAMMA OP */
23562306a36Sopenharmony_ci	{ 0x31, 0x45 }, /* SOURCE OP */
23662306a36Sopenharmony_ci	{ 0x3A, 0x24 }, /* PS_EN OFF */
23762306a36Sopenharmony_ci	{ 0x88, 0x33 }, /* LVD */
23862306a36Sopenharmony_ci};
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_cistatic inline
24162306a36Sopenharmony_cistruct ltk050h3146w *panel_to_ltk050h3146w(struct drm_panel *panel)
24262306a36Sopenharmony_ci{
24362306a36Sopenharmony_ci	return container_of(panel, struct ltk050h3146w, panel);
24462306a36Sopenharmony_ci}
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_cistatic int ltk050h3146w_init_sequence(struct ltk050h3146w *ctx)
24762306a36Sopenharmony_ci{
24862306a36Sopenharmony_ci	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
24962306a36Sopenharmony_ci	int ret;
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	/*
25262306a36Sopenharmony_ci	 * Init sequence was supplied by the panel vendor without much
25362306a36Sopenharmony_ci	 * documentation.
25462306a36Sopenharmony_ci	 */
25562306a36Sopenharmony_ci	mipi_dsi_dcs_write_seq(dsi, 0xdf, 0x93, 0x65, 0xf8);
25662306a36Sopenharmony_ci	mipi_dsi_dcs_write_seq(dsi, 0xb0, 0x01, 0x03, 0x02, 0x00, 0x64, 0x06,
25762306a36Sopenharmony_ci			       0x01);
25862306a36Sopenharmony_ci	mipi_dsi_dcs_write_seq(dsi, 0xb2, 0x00, 0xb5);
25962306a36Sopenharmony_ci	mipi_dsi_dcs_write_seq(dsi, 0xb3, 0x00, 0xb5);
26062306a36Sopenharmony_ci	mipi_dsi_dcs_write_seq(dsi, 0xb7, 0x00, 0xbf, 0x00, 0x00, 0xbf, 0x00);
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	mipi_dsi_dcs_write_seq(dsi, 0xb9, 0x00, 0xc4, 0x23, 0x07);
26362306a36Sopenharmony_ci	mipi_dsi_dcs_write_seq(dsi, 0xbb, 0x02, 0x01, 0x24, 0x00, 0x28, 0x0f,
26462306a36Sopenharmony_ci			       0x28, 0x04, 0xcc, 0xcc, 0xcc);
26562306a36Sopenharmony_ci	mipi_dsi_dcs_write_seq(dsi, 0xbc, 0x0f, 0x04);
26662306a36Sopenharmony_ci	mipi_dsi_dcs_write_seq(dsi, 0xbe, 0x1e, 0xf2);
26762306a36Sopenharmony_ci	mipi_dsi_dcs_write_seq(dsi, 0xc0, 0x26, 0x03);
26862306a36Sopenharmony_ci	mipi_dsi_dcs_write_seq(dsi, 0xc1, 0x00, 0x12);
26962306a36Sopenharmony_ci	mipi_dsi_dcs_write_seq(dsi, 0xc3, 0x04, 0x02, 0x02, 0x76, 0x01, 0x80,
27062306a36Sopenharmony_ci			       0x80);
27162306a36Sopenharmony_ci	mipi_dsi_dcs_write_seq(dsi, 0xc4, 0x24, 0x80, 0xb4, 0x81, 0x12, 0x0f,
27262306a36Sopenharmony_ci			       0x16, 0x00, 0x00);
27362306a36Sopenharmony_ci	mipi_dsi_dcs_write_seq(dsi, 0xc8, 0x7f, 0x72, 0x67, 0x5d, 0x5d, 0x50,
27462306a36Sopenharmony_ci			       0x56, 0x41, 0x59, 0x57, 0x55, 0x70, 0x5b, 0x5f,
27562306a36Sopenharmony_ci			       0x4f, 0x47, 0x38, 0x23, 0x08, 0x7f, 0x72, 0x67,
27662306a36Sopenharmony_ci			       0x5d, 0x5d, 0x50, 0x56, 0x41, 0x59, 0x57, 0x55,
27762306a36Sopenharmony_ci			       0x70, 0x5b, 0x5f, 0x4f, 0x47, 0x38, 0x23, 0x08);
27862306a36Sopenharmony_ci	mipi_dsi_dcs_write_seq(dsi, 0xd0, 0x1e, 0x1f, 0x57, 0x58, 0x48, 0x4a,
27962306a36Sopenharmony_ci			       0x44, 0x46, 0x40, 0x1f, 0x42, 0x1f, 0x1f, 0x1f,
28062306a36Sopenharmony_ci			       0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f);
28162306a36Sopenharmony_ci	mipi_dsi_dcs_write_seq(dsi, 0xd1, 0x1e, 0x1f, 0x57, 0x58, 0x49, 0x4b,
28262306a36Sopenharmony_ci			       0x45, 0x47, 0x41, 0x1f, 0x43, 0x1f, 0x1f, 0x1f,
28362306a36Sopenharmony_ci			       0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f);
28462306a36Sopenharmony_ci	mipi_dsi_dcs_write_seq(dsi, 0xd2, 0x1f, 0x1e, 0x17, 0x18, 0x07, 0x05,
28562306a36Sopenharmony_ci			       0x0b, 0x09, 0x03, 0x1f, 0x01, 0x1f, 0x1f, 0x1f,
28662306a36Sopenharmony_ci			       0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f);
28762306a36Sopenharmony_ci	mipi_dsi_dcs_write_seq(dsi, 0xd3, 0x1f, 0x1e, 0x17, 0x18, 0x06, 0x04,
28862306a36Sopenharmony_ci			       0x0a, 0x08, 0x02, 0x1f, 0x00, 0x1f, 0x1f, 0x1f,
28962306a36Sopenharmony_ci			       0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f);
29062306a36Sopenharmony_ci	mipi_dsi_dcs_write_seq(dsi, 0xd4, 0x00, 0x00, 0x00, 0x0c, 0x06, 0x20,
29162306a36Sopenharmony_ci			       0x01, 0x02, 0x00, 0x60, 0x15, 0xb0, 0x30, 0x03,
29262306a36Sopenharmony_ci			       0x04, 0x00, 0x60, 0x72, 0x0a, 0x00, 0x60, 0x08);
29362306a36Sopenharmony_ci	mipi_dsi_dcs_write_seq(dsi, 0xd5, 0x00, 0x06, 0x06, 0x00, 0x30, 0x00,
29462306a36Sopenharmony_ci			       0x00, 0x00, 0x00, 0x00, 0xbc, 0x50, 0x00, 0x05,
29562306a36Sopenharmony_ci			       0x21, 0x00, 0x60);
29662306a36Sopenharmony_ci	mipi_dsi_dcs_write_seq(dsi, 0xdd, 0x2c, 0xa3, 0x00);
29762306a36Sopenharmony_ci	mipi_dsi_dcs_write_seq(dsi, 0xde, 0x02);
29862306a36Sopenharmony_ci	mipi_dsi_dcs_write_seq(dsi, 0xb2, 0x32, 0x1c);
29962306a36Sopenharmony_ci	mipi_dsi_dcs_write_seq(dsi, 0xb7, 0x3b, 0x70, 0x00, 0x04);
30062306a36Sopenharmony_ci	mipi_dsi_dcs_write_seq(dsi, 0xc1, 0x11);
30162306a36Sopenharmony_ci	mipi_dsi_dcs_write_seq(dsi, 0xbb, 0x21, 0x22, 0x23, 0x24, 0x36, 0x37);
30262306a36Sopenharmony_ci	mipi_dsi_dcs_write_seq(dsi, 0xc2, 0x20, 0x38, 0x1e, 0x84);
30362306a36Sopenharmony_ci	mipi_dsi_dcs_write_seq(dsi, 0xde, 0x00);
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci	ret = mipi_dsi_dcs_set_tear_on(dsi, 1);
30662306a36Sopenharmony_ci	if (ret < 0) {
30762306a36Sopenharmony_ci		dev_err(ctx->dev, "failed to set tear on: %d\n", ret);
30862306a36Sopenharmony_ci		return ret;
30962306a36Sopenharmony_ci	}
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	msleep(60);
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	return 0;
31462306a36Sopenharmony_ci}
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_cistatic const struct drm_display_mode ltk050h3146w_mode = {
31762306a36Sopenharmony_ci	.hdisplay	= 720,
31862306a36Sopenharmony_ci	.hsync_start	= 720 + 42,
31962306a36Sopenharmony_ci	.hsync_end	= 720 + 42 + 8,
32062306a36Sopenharmony_ci	.htotal		= 720 + 42 + 8 + 42,
32162306a36Sopenharmony_ci	.vdisplay	= 1280,
32262306a36Sopenharmony_ci	.vsync_start	= 1280 + 12,
32362306a36Sopenharmony_ci	.vsync_end	= 1280 + 12 + 4,
32462306a36Sopenharmony_ci	.vtotal		= 1280 + 12 + 4 + 18,
32562306a36Sopenharmony_ci	.clock		= 64018,
32662306a36Sopenharmony_ci	.width_mm	= 62,
32762306a36Sopenharmony_ci	.height_mm	= 110,
32862306a36Sopenharmony_ci};
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_cistatic const struct ltk050h3146w_desc ltk050h3146w_data = {
33162306a36Sopenharmony_ci	.mode = &ltk050h3146w_mode,
33262306a36Sopenharmony_ci	.init = ltk050h3146w_init_sequence,
33362306a36Sopenharmony_ci};
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_cistatic int ltk050h3146w_a2_select_page(struct ltk050h3146w *ctx, int page)
33662306a36Sopenharmony_ci{
33762306a36Sopenharmony_ci	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
33862306a36Sopenharmony_ci	u8 d[3] = { 0x98, 0x81, page };
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	return mipi_dsi_dcs_write(dsi, 0xff, d, ARRAY_SIZE(d));
34162306a36Sopenharmony_ci}
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_cistatic int ltk050h3146w_a2_write_page(struct ltk050h3146w *ctx, int page,
34462306a36Sopenharmony_ci				      const struct ltk050h3146w_cmd *cmds,
34562306a36Sopenharmony_ci				      int num)
34662306a36Sopenharmony_ci{
34762306a36Sopenharmony_ci	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
34862306a36Sopenharmony_ci	int i, ret;
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	ret = ltk050h3146w_a2_select_page(ctx, page);
35162306a36Sopenharmony_ci	if (ret < 0) {
35262306a36Sopenharmony_ci		dev_err(ctx->dev, "failed to select page %d: %d\n", page, ret);
35362306a36Sopenharmony_ci		return ret;
35462306a36Sopenharmony_ci	}
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	for (i = 0; i < num; i++) {
35762306a36Sopenharmony_ci		ret = mipi_dsi_generic_write(dsi, &cmds[i],
35862306a36Sopenharmony_ci					     sizeof(struct ltk050h3146w_cmd));
35962306a36Sopenharmony_ci		if (ret < 0) {
36062306a36Sopenharmony_ci			dev_err(ctx->dev, "failed to write page %d init cmds: %d\n", page, ret);
36162306a36Sopenharmony_ci			return ret;
36262306a36Sopenharmony_ci		}
36362306a36Sopenharmony_ci	}
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	return 0;
36662306a36Sopenharmony_ci}
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_cistatic int ltk050h3146w_a2_init_sequence(struct ltk050h3146w *ctx)
36962306a36Sopenharmony_ci{
37062306a36Sopenharmony_ci	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
37162306a36Sopenharmony_ci	int ret;
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci	/*
37462306a36Sopenharmony_ci	 * Init sequence was supplied by the panel vendor without much
37562306a36Sopenharmony_ci	 * documentation.
37662306a36Sopenharmony_ci	 */
37762306a36Sopenharmony_ci	ret = ltk050h3146w_a2_write_page(ctx, 3, page3_cmds,
37862306a36Sopenharmony_ci					 ARRAY_SIZE(page3_cmds));
37962306a36Sopenharmony_ci	if (ret < 0)
38062306a36Sopenharmony_ci		return ret;
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci	ret = ltk050h3146w_a2_write_page(ctx, 4, page4_cmds,
38362306a36Sopenharmony_ci					 ARRAY_SIZE(page4_cmds));
38462306a36Sopenharmony_ci	if (ret < 0)
38562306a36Sopenharmony_ci		return ret;
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	ret = ltk050h3146w_a2_write_page(ctx, 1, page1_cmds,
38862306a36Sopenharmony_ci					 ARRAY_SIZE(page1_cmds));
38962306a36Sopenharmony_ci	if (ret < 0)
39062306a36Sopenharmony_ci		return ret;
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci	ret = ltk050h3146w_a2_select_page(ctx, 0);
39362306a36Sopenharmony_ci	if (ret < 0) {
39462306a36Sopenharmony_ci		dev_err(ctx->dev, "failed to select page 0: %d\n", ret);
39562306a36Sopenharmony_ci		return ret;
39662306a36Sopenharmony_ci	}
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci	/* vendor code called this without param, where there should be one */
39962306a36Sopenharmony_ci	ret = mipi_dsi_dcs_set_tear_on(dsi, 0);
40062306a36Sopenharmony_ci	if (ret < 0) {
40162306a36Sopenharmony_ci		dev_err(ctx->dev, "failed to set tear on: %d\n", ret);
40262306a36Sopenharmony_ci		return ret;
40362306a36Sopenharmony_ci	}
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	msleep(60);
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci	return 0;
40862306a36Sopenharmony_ci}
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_cistatic const struct drm_display_mode ltk050h3146w_a2_mode = {
41162306a36Sopenharmony_ci	.hdisplay	= 720,
41262306a36Sopenharmony_ci	.hsync_start	= 720 + 42,
41362306a36Sopenharmony_ci	.hsync_end	= 720 + 42 + 10,
41462306a36Sopenharmony_ci	.htotal		= 720 + 42 + 10 + 60,
41562306a36Sopenharmony_ci	.vdisplay	= 1280,
41662306a36Sopenharmony_ci	.vsync_start	= 1280 + 18,
41762306a36Sopenharmony_ci	.vsync_end	= 1280 + 18 + 4,
41862306a36Sopenharmony_ci	.vtotal		= 1280 + 18 + 4 + 12,
41962306a36Sopenharmony_ci	.clock		= 65595,
42062306a36Sopenharmony_ci	.width_mm	= 62,
42162306a36Sopenharmony_ci	.height_mm	= 110,
42262306a36Sopenharmony_ci};
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_cistatic const struct ltk050h3146w_desc ltk050h3146w_a2_data = {
42562306a36Sopenharmony_ci	.mode = &ltk050h3146w_a2_mode,
42662306a36Sopenharmony_ci	.init = ltk050h3146w_a2_init_sequence,
42762306a36Sopenharmony_ci};
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_cistatic int ltk050h3146w_unprepare(struct drm_panel *panel)
43062306a36Sopenharmony_ci{
43162306a36Sopenharmony_ci	struct ltk050h3146w *ctx = panel_to_ltk050h3146w(panel);
43262306a36Sopenharmony_ci	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
43362306a36Sopenharmony_ci	int ret;
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	if (!ctx->prepared)
43662306a36Sopenharmony_ci		return 0;
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	ret = mipi_dsi_dcs_set_display_off(dsi);
43962306a36Sopenharmony_ci	if (ret < 0) {
44062306a36Sopenharmony_ci		dev_err(ctx->dev, "failed to set display off: %d\n", ret);
44162306a36Sopenharmony_ci		return ret;
44262306a36Sopenharmony_ci	}
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci	mipi_dsi_dcs_enter_sleep_mode(dsi);
44562306a36Sopenharmony_ci	if (ret < 0) {
44662306a36Sopenharmony_ci		dev_err(ctx->dev, "failed to enter sleep mode: %d\n", ret);
44762306a36Sopenharmony_ci		return ret;
44862306a36Sopenharmony_ci	}
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci	regulator_disable(ctx->iovcc);
45162306a36Sopenharmony_ci	regulator_disable(ctx->vci);
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci	ctx->prepared = false;
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci	return 0;
45662306a36Sopenharmony_ci}
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_cistatic int ltk050h3146w_prepare(struct drm_panel *panel)
45962306a36Sopenharmony_ci{
46062306a36Sopenharmony_ci	struct ltk050h3146w *ctx = panel_to_ltk050h3146w(panel);
46162306a36Sopenharmony_ci	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
46262306a36Sopenharmony_ci	int ret;
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci	if (ctx->prepared)
46562306a36Sopenharmony_ci		return 0;
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci	dev_dbg(ctx->dev, "Resetting the panel\n");
46862306a36Sopenharmony_ci	ret = regulator_enable(ctx->vci);
46962306a36Sopenharmony_ci	if (ret < 0) {
47062306a36Sopenharmony_ci		dev_err(ctx->dev, "Failed to enable vci supply: %d\n", ret);
47162306a36Sopenharmony_ci		return ret;
47262306a36Sopenharmony_ci	}
47362306a36Sopenharmony_ci	ret = regulator_enable(ctx->iovcc);
47462306a36Sopenharmony_ci	if (ret < 0) {
47562306a36Sopenharmony_ci		dev_err(ctx->dev, "Failed to enable iovcc supply: %d\n", ret);
47662306a36Sopenharmony_ci		goto disable_vci;
47762306a36Sopenharmony_ci	}
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci	gpiod_set_value_cansleep(ctx->reset_gpio, 1);
48062306a36Sopenharmony_ci	usleep_range(5000, 6000);
48162306a36Sopenharmony_ci	gpiod_set_value_cansleep(ctx->reset_gpio, 0);
48262306a36Sopenharmony_ci	msleep(20);
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci	ret = ctx->panel_desc->init(ctx);
48562306a36Sopenharmony_ci	if (ret < 0) {
48662306a36Sopenharmony_ci		dev_err(ctx->dev, "Panel init sequence failed: %d\n", ret);
48762306a36Sopenharmony_ci		goto disable_iovcc;
48862306a36Sopenharmony_ci	}
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
49162306a36Sopenharmony_ci	if (ret < 0) {
49262306a36Sopenharmony_ci		dev_err(ctx->dev, "Failed to exit sleep mode: %d\n", ret);
49362306a36Sopenharmony_ci		goto disable_iovcc;
49462306a36Sopenharmony_ci	}
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci	/* T9: 120ms */
49762306a36Sopenharmony_ci	msleep(120);
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci	ret = mipi_dsi_dcs_set_display_on(dsi);
50062306a36Sopenharmony_ci	if (ret < 0) {
50162306a36Sopenharmony_ci		dev_err(ctx->dev, "Failed to set display on: %d\n", ret);
50262306a36Sopenharmony_ci		goto disable_iovcc;
50362306a36Sopenharmony_ci	}
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci	msleep(50);
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci	ctx->prepared = true;
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci	return 0;
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_cidisable_iovcc:
51262306a36Sopenharmony_ci	regulator_disable(ctx->iovcc);
51362306a36Sopenharmony_cidisable_vci:
51462306a36Sopenharmony_ci	regulator_disable(ctx->vci);
51562306a36Sopenharmony_ci	return ret;
51662306a36Sopenharmony_ci}
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_cistatic int ltk050h3146w_get_modes(struct drm_panel *panel,
51962306a36Sopenharmony_ci				  struct drm_connector *connector)
52062306a36Sopenharmony_ci{
52162306a36Sopenharmony_ci	struct ltk050h3146w *ctx = panel_to_ltk050h3146w(panel);
52262306a36Sopenharmony_ci	struct drm_display_mode *mode;
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci	mode = drm_mode_duplicate(connector->dev, ctx->panel_desc->mode);
52562306a36Sopenharmony_ci	if (!mode)
52662306a36Sopenharmony_ci		return -ENOMEM;
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci	drm_mode_set_name(mode);
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
53162306a36Sopenharmony_ci	connector->display_info.width_mm = mode->width_mm;
53262306a36Sopenharmony_ci	connector->display_info.height_mm = mode->height_mm;
53362306a36Sopenharmony_ci	drm_mode_probed_add(connector, mode);
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci	return 1;
53662306a36Sopenharmony_ci}
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_cistatic const struct drm_panel_funcs ltk050h3146w_funcs = {
53962306a36Sopenharmony_ci	.unprepare	= ltk050h3146w_unprepare,
54062306a36Sopenharmony_ci	.prepare	= ltk050h3146w_prepare,
54162306a36Sopenharmony_ci	.get_modes	= ltk050h3146w_get_modes,
54262306a36Sopenharmony_ci};
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_cistatic int ltk050h3146w_probe(struct mipi_dsi_device *dsi)
54562306a36Sopenharmony_ci{
54662306a36Sopenharmony_ci	struct device *dev = &dsi->dev;
54762306a36Sopenharmony_ci	struct ltk050h3146w *ctx;
54862306a36Sopenharmony_ci	int ret;
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ci	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
55162306a36Sopenharmony_ci	if (!ctx)
55262306a36Sopenharmony_ci		return -ENOMEM;
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci	ctx->panel_desc = of_device_get_match_data(dev);
55562306a36Sopenharmony_ci	if (!ctx->panel_desc)
55662306a36Sopenharmony_ci		return -EINVAL;
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci	ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
55962306a36Sopenharmony_ci	if (IS_ERR(ctx->reset_gpio)) {
56062306a36Sopenharmony_ci		dev_err(dev, "cannot get reset gpio\n");
56162306a36Sopenharmony_ci		return PTR_ERR(ctx->reset_gpio);
56262306a36Sopenharmony_ci	}
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_ci	ctx->vci = devm_regulator_get(dev, "vci");
56562306a36Sopenharmony_ci	if (IS_ERR(ctx->vci)) {
56662306a36Sopenharmony_ci		ret = PTR_ERR(ctx->vci);
56762306a36Sopenharmony_ci		if (ret != -EPROBE_DEFER)
56862306a36Sopenharmony_ci			dev_err(dev, "Failed to request vci regulator: %d\n", ret);
56962306a36Sopenharmony_ci		return ret;
57062306a36Sopenharmony_ci	}
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_ci	ctx->iovcc = devm_regulator_get(dev, "iovcc");
57362306a36Sopenharmony_ci	if (IS_ERR(ctx->iovcc)) {
57462306a36Sopenharmony_ci		ret = PTR_ERR(ctx->iovcc);
57562306a36Sopenharmony_ci		if (ret != -EPROBE_DEFER)
57662306a36Sopenharmony_ci			dev_err(dev, "Failed to request iovcc regulator: %d\n", ret);
57762306a36Sopenharmony_ci		return ret;
57862306a36Sopenharmony_ci	}
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci	mipi_dsi_set_drvdata(dsi, ctx);
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci	ctx->dev = dev;
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci	dsi->lanes = 4;
58562306a36Sopenharmony_ci	dsi->format = MIPI_DSI_FMT_RGB888;
58662306a36Sopenharmony_ci	dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
58762306a36Sopenharmony_ci			  MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_NO_EOT_PACKET;
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_ci	drm_panel_init(&ctx->panel, &dsi->dev, &ltk050h3146w_funcs,
59062306a36Sopenharmony_ci		       DRM_MODE_CONNECTOR_DSI);
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_ci	ret = drm_panel_of_backlight(&ctx->panel);
59362306a36Sopenharmony_ci	if (ret)
59462306a36Sopenharmony_ci		return ret;
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci	drm_panel_add(&ctx->panel);
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci	ret = mipi_dsi_attach(dsi);
59962306a36Sopenharmony_ci	if (ret < 0) {
60062306a36Sopenharmony_ci		dev_err(dev, "mipi_dsi_attach failed: %d\n", ret);
60162306a36Sopenharmony_ci		drm_panel_remove(&ctx->panel);
60262306a36Sopenharmony_ci		return ret;
60362306a36Sopenharmony_ci	}
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci	return 0;
60662306a36Sopenharmony_ci}
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_cistatic void ltk050h3146w_shutdown(struct mipi_dsi_device *dsi)
60962306a36Sopenharmony_ci{
61062306a36Sopenharmony_ci	struct ltk050h3146w *ctx = mipi_dsi_get_drvdata(dsi);
61162306a36Sopenharmony_ci	int ret;
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci	ret = drm_panel_unprepare(&ctx->panel);
61462306a36Sopenharmony_ci	if (ret < 0)
61562306a36Sopenharmony_ci		dev_err(&dsi->dev, "Failed to unprepare panel: %d\n", ret);
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_ci	ret = drm_panel_disable(&ctx->panel);
61862306a36Sopenharmony_ci	if (ret < 0)
61962306a36Sopenharmony_ci		dev_err(&dsi->dev, "Failed to disable panel: %d\n", ret);
62062306a36Sopenharmony_ci}
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_cistatic void ltk050h3146w_remove(struct mipi_dsi_device *dsi)
62362306a36Sopenharmony_ci{
62462306a36Sopenharmony_ci	struct ltk050h3146w *ctx = mipi_dsi_get_drvdata(dsi);
62562306a36Sopenharmony_ci	int ret;
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci	ltk050h3146w_shutdown(dsi);
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_ci	ret = mipi_dsi_detach(dsi);
63062306a36Sopenharmony_ci	if (ret < 0)
63162306a36Sopenharmony_ci		dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret);
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_ci	drm_panel_remove(&ctx->panel);
63462306a36Sopenharmony_ci}
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_cistatic const struct of_device_id ltk050h3146w_of_match[] = {
63762306a36Sopenharmony_ci	{
63862306a36Sopenharmony_ci		.compatible = "leadtek,ltk050h3146w",
63962306a36Sopenharmony_ci		.data = &ltk050h3146w_data,
64062306a36Sopenharmony_ci	},
64162306a36Sopenharmony_ci	{
64262306a36Sopenharmony_ci		.compatible = "leadtek,ltk050h3146w-a2",
64362306a36Sopenharmony_ci		.data = &ltk050h3146w_a2_data,
64462306a36Sopenharmony_ci	},
64562306a36Sopenharmony_ci	{ /* sentinel */ }
64662306a36Sopenharmony_ci};
64762306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, ltk050h3146w_of_match);
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_cistatic struct mipi_dsi_driver ltk050h3146w_driver = {
65062306a36Sopenharmony_ci	.driver = {
65162306a36Sopenharmony_ci		.name = "panel-leadtek-ltk050h3146w",
65262306a36Sopenharmony_ci		.of_match_table = ltk050h3146w_of_match,
65362306a36Sopenharmony_ci	},
65462306a36Sopenharmony_ci	.probe	= ltk050h3146w_probe,
65562306a36Sopenharmony_ci	.remove = ltk050h3146w_remove,
65662306a36Sopenharmony_ci	.shutdown = ltk050h3146w_shutdown,
65762306a36Sopenharmony_ci};
65862306a36Sopenharmony_cimodule_mipi_dsi_driver(ltk050h3146w_driver);
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ciMODULE_AUTHOR("Heiko Stuebner <heiko.stuebner@theobroma-systems.com>");
66162306a36Sopenharmony_ciMODULE_DESCRIPTION("DRM driver for Leadtek LTK050H3146W MIPI DSI panel");
66262306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
663