Linux Audio

Check our new training course

Loading...
Note: File does not exist in v4.6.
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Driver for panels based on Himax HX83102 controller, such as:
  4 *
  5 * - Starry 10.51" WUXGA MIPI-DSI panel
  6 *
  7 * Based on drivers/gpu/drm/panel/panel-himax-hx8394.c
  8 */
  9
 10#include <linux/delay.h>
 11#include <linux/gpio/consumer.h>
 12#include <linux/module.h>
 13#include <linux/of.h>
 14#include <linux/regulator/consumer.h>
 15
 16#include <drm/drm_connector.h>
 17#include <drm/drm_crtc.h>
 18#include <drm/drm_mipi_dsi.h>
 19#include <drm/drm_panel.h>
 20
 21#include <video/mipi_display.h>
 22
 23/* Manufacturer specific DSI commands */
 24#define HX83102_SETPOWER	0xb1
 25#define HX83102_SETDISP		0xb2
 26#define HX83102_SETCYC		0xb4
 27#define HX83102_SETEXTC		0xb9
 28#define HX83102_SETMIPI		0xba
 29#define HX83102_SETVDC		0xbc
 30#define HX83102_SETBANK		0xbd
 31#define HX83102_UNKNOWN_BE	0xbe
 32#define HX83102_SETPTBA		0xbf
 33#define HX83102_SETSTBA		0xc0
 34#define HX83102_SETTCON		0xc7
 35#define HX83102_SETRAMDMY	0xc8
 36#define HX83102_SETPWM		0xc9
 37#define HX83102_SETCLOCK	0xcb
 38#define HX83102_SETPANEL	0xcc
 39#define HX83102_SETCASCADE	0xd0
 40#define HX83102_SETPCTRL	0xd1
 41#define HX83102_UNKNOWN_D2	0xd2
 42#define HX83102_SETGIP0		0xd3
 43#define HX83102_SETGIP1		0xd5
 44#define HX83102_SETGIP2		0xd6
 45#define HX83102_SETGIP3		0xd8
 46#define HX83102_SETGMA		0xe0
 47#define HX83102_UNKNOWN_E1	0xe1
 48#define HX83102_SETTP1		0xe7
 49#define HX83102_SETSPCCMD	0xe9
 50
 51struct hx83102 {
 52	struct drm_panel base;
 53	struct mipi_dsi_device *dsi;
 54
 55	const struct hx83102_panel_desc *desc;
 56
 57	enum drm_panel_orientation orientation;
 58	struct regulator *pp1800;
 59	struct regulator *avee;
 60	struct regulator *avdd;
 61	struct gpio_desc *enable_gpio;
 62};
 63
 64struct hx83102_panel_desc {
 65	const struct drm_display_mode *modes;
 66
 67	/**
 68	 * @width_mm: width of the panel's active display area
 69	 * @height_mm: height of the panel's active display area
 70	 */
 71	struct {
 72		unsigned int width_mm;
 73		unsigned int height_mm;
 74	} size;
 75
 76	int (*init)(struct hx83102 *ctx);
 77};
 78
 79static inline struct hx83102 *panel_to_hx83102(struct drm_panel *panel)
 80{
 81	return container_of(panel, struct hx83102, base);
 82}
 83
 84static void hx83102_enable_extended_cmds(struct mipi_dsi_multi_context *dsi_ctx, bool enable)
 85{
 86	if (enable)
 87		mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX83102_SETEXTC, 0x83, 0x10, 0x21, 0x55, 0x00);
 88	else
 89		mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX83102_SETEXTC, 0x00, 0x00, 0x00);
 90}
 91
 92static int starry_himax83102_j02_init(struct hx83102 *ctx)
 93{
 94	struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi };
 95
 96	hx83102_enable_extended_cmds(&dsi_ctx, true);
 97	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETPOWER, 0x2c, 0xb5, 0xb5, 0x31, 0xf1,
 98				     0x31, 0xd7, 0x2f, 0x36, 0x36, 0x36, 0x36, 0x1a, 0x8b, 0x11,
 99				     0x65, 0x00, 0x88, 0xfa, 0xff, 0xff, 0x8f, 0xff, 0x08, 0x74,
100				     0x33);
101	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETDISP, 0x00, 0x47, 0xb0, 0x80, 0x00,
102				     0x12, 0x72, 0x3c, 0xa3, 0x03, 0x03, 0x00, 0x00, 0x88, 0xf5);
103	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETCYC, 0x76, 0x76, 0x76, 0x76, 0x76,
104				     0x76, 0x63, 0x5c, 0x63, 0x5c, 0x01, 0x9e);
105	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0xcd);
106	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETMIPI, 0x84);
107	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0x3f);
108	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETVDC, 0x1b, 0x04);
109	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_UNKNOWN_BE, 0x20);
110	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETPTBA, 0xfc, 0xc4);
111	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSTBA, 0x36, 0x36, 0x22, 0x11, 0x22,
112				     0xa0, 0x61, 0x08, 0xf5, 0x03);
113	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0xcc);
114	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETTCON, 0x80);
115	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0x3f);
116	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0xc6);
117	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETRAMDMY, 0x97);
118	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0x3f);
119	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETPWM, 0x00, 0x1e, 0x13, 0x88, 0x01);
120	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETCLOCK, 0x08, 0x13, 0x07, 0x00, 0x0f, 0x33);
121	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETPANEL, 0x02);
122	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0xc4);
123	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETCASCADE, 0x03);
124	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0x3f);
125	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETPCTRL, 0x37, 0x06, 0x00, 0x02, 0x04, 0x0c,
126				     0xff);
127	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_UNKNOWN_D2, 0x1f, 0x11, 0x1f);
128	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETGIP0, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00,
129				     0x08, 0x00, 0x08, 0x37, 0x47, 0x34, 0x3b, 0x12, 0x12, 0x03, 0x03,
130				     0x32, 0x10, 0x10, 0x00, 0x10, 0x32, 0x10, 0x08, 0x00, 0x08, 0x32,
131				     0x17, 0x94, 0x07, 0x94, 0x00, 0x00);
132	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETGIP1, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
133				     0x18, 0x18, 0x18, 0x18, 0x19, 0x19, 0x40, 0x40, 0x1a, 0x1a, 0x1b,
134				     0x1b, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x20, 0x21,
135				     0x28, 0x29, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
136				     0x18, 0x18, 0x18, 0x18, 0x18);
137	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETGIP2, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
138				     0x18, 0x18, 0x18, 0x18, 0x40, 0x40, 0x19, 0x19, 0x1a, 0x1a, 0x1b,
139				     0x1b, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x29, 0x28,
140				     0x21, 0x20, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
141				     0x18, 0x18, 0x18, 0x18, 0x18);
142	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETGIP3, 0xaa, 0xba, 0xea, 0xaa, 0xaa, 0xa0,
143				     0xaa, 0xba, 0xea, 0xaa, 0xaa, 0xa0, 0xaa, 0xba, 0xea, 0xaa, 0xaa,
144				     0xa0, 0xaa, 0xba, 0xea, 0xaa, 0xaa, 0xa0, 0xaa, 0xba, 0xea, 0xaa,
145				     0xaa, 0xa0, 0xaa, 0xba, 0xea, 0xaa, 0xaa, 0xa0);
146	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETGMA, 0x00, 0x09, 0x14, 0x1e, 0x26, 0x48,
147				     0x61, 0x67, 0x6c, 0x67, 0x7d, 0x7f, 0x80, 0x8b, 0x87, 0x8f, 0x98,
148				     0xab, 0xab, 0x55, 0x5c, 0x68, 0x73, 0x00, 0x09, 0x14, 0x1e, 0x26,
149				     0x48, 0x61, 0x67, 0x6c, 0x67, 0x7d, 0x7f, 0x80, 0x8b, 0x87, 0x8f,
150				     0x98, 0xab, 0xab, 0x55, 0x5c, 0x68, 0x73);
151	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETTP1, 0x0e, 0x10, 0x10, 0x21, 0x2b, 0x9a,
152				     0x02, 0x54, 0x9a, 0x14, 0x14, 0x00, 0x00, 0x00, 0x00, 0x12, 0x05,
153				     0x02, 0x02, 0x10);
154	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETBANK, 0x01);
155	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETPOWER, 0x01, 0xbf, 0x11);
156	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETCLOCK, 0x86);
157	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_UNKNOWN_D2, 0x3c, 0xfa);
158	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETGIP0, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00,
159				     0x00, 0x00, 0x80, 0x0c, 0x01);
160	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETTP1, 0x02, 0x00, 0x28, 0x01, 0x7e, 0x0f,
161				     0x7e, 0x10, 0xa0, 0x00, 0x00, 0x20, 0x40, 0x50, 0x40);
162	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETBANK, 0x02);
163	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETGIP3, 0xff, 0xff, 0xbf, 0xfe, 0xaa, 0xa0,
164				     0xff, 0xff, 0xbf, 0xfe, 0xaa, 0xa0);
165	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETTP1, 0xfe, 0x04, 0xfe, 0x04, 0xfe, 0x04,
166				     0x03, 0x03, 0x03, 0x26, 0x00, 0x26, 0x81, 0x02, 0x40, 0x00, 0x20,
167				     0x9e, 0x04, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00);
168	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETBANK, 0x03);
169	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0xc6);
170	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETCYC, 0x03, 0xff, 0xf8);
171	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0x3f);
172	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETGIP3, 0x00, 0x2a, 0xaa, 0xa8, 0x00, 0x00,
173				     0x00, 0x2a, 0xaa, 0xa8, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xfc, 0x00,
174				     0x00, 0x00, 0x3f, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x2a, 0xaa, 0xa8,
175				     0x00, 0x00, 0x00, 0x2a, 0xaa, 0xa8, 0x00, 0x00);
176	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETBANK, 0x00);
177	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0xc4);
178	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETMIPI, 0x96);
179	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0x3f);
180	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETBANK, 0x01);
181	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0xc5);
182	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETMIPI, 0x4f);
183	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0x3f);
184	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETBANK, 0x00);
185
186	return dsi_ctx.accum_err;
187};
188
189static int boe_nv110wum_init(struct hx83102 *ctx)
190{
191	struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi };
192
193	msleep(60);
194
195	hx83102_enable_extended_cmds(&dsi_ctx, true);
196	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETPOWER, 0x2c, 0xaf, 0xaf, 0x2b, 0xeb, 0x42,
197				     0xe1, 0x4d, 0x36, 0x36, 0x36, 0x36, 0x1a, 0x8b, 0x11, 0x65, 0x00,
198				     0x88, 0xfa, 0xff, 0xff, 0x8f, 0xff, 0x08, 0x9a, 0x33);
199	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETDISP, 0x00, 0x47, 0xb0, 0x80, 0x00, 0x12,
200				     0x71, 0x3c, 0xa3, 0x11, 0x00, 0x00, 0x00, 0x88, 0xf5, 0x22, 0x8f);
201	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETCYC, 0x49, 0x49, 0x32, 0x32, 0x14, 0x32,
202				     0x84, 0x6e, 0x84, 0x6e, 0x01, 0x9c);
203	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0xcd);
204	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETMIPI, 0x84);
205	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0x3f);
206	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETVDC, 0x1b, 0x04);
207	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_UNKNOWN_BE, 0x20);
208	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETPTBA, 0xfc, 0x84);
209	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSTBA, 0x36, 0x36, 0x22, 0x00, 0x00, 0xa0,
210				     0x61, 0x08, 0xf5, 0x03);
211	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0xcc);
212	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETTCON, 0x80);
213	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0x3f);
214	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0xc6);
215	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETRAMDMY, 0x97);
216	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0x3f);
217	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETPWM, 0x00, 0x1e, 0x30, 0xd4, 0x01);
218	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETCLOCK, 0x08, 0x13, 0x07, 0x00, 0x0f, 0x34);
219	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETPANEL, 0x02, 0x03, 0x44);
220	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0xc4);
221	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETCASCADE, 0x03);
222	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0x3f);
223	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETPCTRL, 0x37, 0x06, 0x00, 0x02, 0x04, 0x0c, 0xff);
224	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_UNKNOWN_D2, 0x1f, 0x11, 0x1f, 0x11);
225	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETGIP0, 0x06, 0x00, 0x00, 0x00, 0x00, 0x04,
226				     0x08, 0x04, 0x08, 0x37, 0x37, 0x64, 0x4b, 0x11, 0x11, 0x03, 0x03, 0x32,
227				     0x10, 0x0e, 0x00, 0x0e, 0x32, 0x10, 0x0a, 0x00, 0x0a, 0x32, 0x17, 0x98,
228				     0x07, 0x98, 0x00, 0x00);
229	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETGIP1, 0x18, 0x18, 0x18, 0x18, 0x1e, 0x1e,
230				     0x1e, 0x1e, 0x1f, 0x1f, 0x1f, 0x1f, 0x24, 0x24, 0x24, 0x24, 0x07, 0x06,
231				     0x07, 0x06, 0x05, 0x04, 0x05, 0x04, 0x03, 0x02, 0x03, 0x02, 0x01, 0x00,
232				     0x01, 0x00, 0x21, 0x20, 0x21, 0x20, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
233				     0x18, 0x18);
234	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETGIP3, 0xaf, 0xaa, 0xaa, 0xaa, 0xaa, 0xa0,
235				     0xaf, 0xaa, 0xaa, 0xaa, 0xaa, 0xa0);
236	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETGMA, 0x00, 0x05, 0x0d, 0x14, 0x1b, 0x2c,
237				     0x44, 0x49, 0x51, 0x4c, 0x67, 0x6c, 0x71, 0x80, 0x7d, 0x84, 0x8d, 0xa0,
238				     0xa0, 0x4f, 0x58, 0x64, 0x73, 0x00, 0x05, 0x0d, 0x14, 0x1b, 0x2c, 0x44,
239				     0x49, 0x51, 0x4c, 0x67, 0x6c, 0x71, 0x80, 0x7d, 0x84, 0x8d, 0xa0, 0xa0,
240				     0x4f, 0x58, 0x64, 0x73);
241	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETTP1, 0x07, 0x10, 0x10, 0x1a, 0x26, 0x9e,
242				     0x00, 0x53, 0x9b, 0x14, 0x14);
243	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_UNKNOWN_E1, 0x11, 0x00, 0x00, 0x89, 0x30, 0x80,
244				     0x07, 0x80, 0x02, 0x58, 0x00, 0x14, 0x02, 0x58, 0x02, 0x58, 0x02, 0x00,
245				     0x02, 0x2c, 0x00, 0x20, 0x02, 0x02, 0x00, 0x08, 0x00, 0x0c, 0x05, 0x0e,
246				     0x04, 0x94, 0x18, 0x00, 0x10, 0xf0, 0x03, 0x0c, 0x20, 0x00, 0x06, 0x0b,
247				     0x0b, 0x33, 0x0e);
248	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETBANK, 0x01);
249	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETGIP3, 0xff, 0xff, 0xff, 0xff, 0xfa, 0xa0,
250				     0xff, 0xff, 0xff, 0xff, 0xfa, 0xa0);
251	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETPOWER, 0x01, 0xbf, 0x11);
252	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETCLOCK, 0x86);
253	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_UNKNOWN_D2, 0x96);
254	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0xc9);
255	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETGIP0, 0x84);
256	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0x3f);
257	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0xd1);
258	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_UNKNOWN_E1, 0xf6, 0x2b, 0x34, 0x2b, 0x74, 0x3b,
259				     0x74, 0x6b, 0x74);
260	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0x3f);
261	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETTP1, 0x02, 0x00, 0x2b, 0x01, 0x7e, 0x0f,
262				     0x7e, 0x10, 0xa0, 0x00, 0x00);
263	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETBANK, 0x02);
264	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETCYC, 0x02, 0x00, 0xbb, 0x11);
265	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETGIP3, 0xff, 0xaf, 0xff, 0xff, 0xfa, 0xa0,
266				     0xff, 0xaf, 0xff, 0xff, 0xfa, 0xa0);
267	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETTP1, 0xfe, 0x01, 0xfe, 0x01, 0xfe, 0x01,
268				     0x00, 0x00, 0x00, 0x23, 0x00, 0x23, 0x81, 0x02, 0x40, 0x00, 0x20, 0x65,
269				     0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00);
270	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETBANK, 0x03);
271	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETGIP3, 0xaa, 0xaf, 0xaa, 0xaa, 0xa0, 0x00,
272				     0xaa, 0xaf, 0xaa, 0xaa, 0xa0, 0x00, 0xaa, 0xaf, 0xaa, 0xaa, 0xa0, 0x00,
273				     0xaa, 0xaf, 0xaa, 0xaa, 0xa0, 0x00);
274	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0xc6);
275	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETCYC, 0x03, 0xff, 0xf8);
276	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0x3f);
277	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_UNKNOWN_E1, 0x00);
278	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETBANK, 0x00);
279	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0xc4);
280	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETMIPI, 0x96);
281	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0x3f);
282	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETBANK, 0x01);
283	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0xc5);
284	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETMIPI, 0x4f);
285	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0x3f);
286	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETBANK, 0x00);
287	hx83102_enable_extended_cmds(&dsi_ctx, false);
288
289	mipi_dsi_msleep(&dsi_ctx, 50);
290
291	return dsi_ctx.accum_err;
292};
293
294static int ivo_t109nw41_init(struct hx83102 *ctx)
295{
296	struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi };
297
298	msleep(60);
299
300	hx83102_enable_extended_cmds(&dsi_ctx, true);
301	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETPOWER, 0x2c, 0xed, 0xed, 0x27, 0xe7, 0x52,
302				     0xf5, 0x39, 0x36, 0x36, 0x36, 0x36, 0x32, 0x8b, 0x11, 0x65, 0x00, 0x88,
303				     0xfa, 0xff, 0xff, 0x8f, 0xff, 0x08, 0xd6, 0x33);
304	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETDISP, 0x00, 0x47, 0xb0, 0x80, 0x00, 0x12,
305				     0x71, 0x3c, 0xa3, 0x22, 0x20, 0x00, 0x00, 0x88, 0x01);
306	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETCYC, 0x35, 0x35, 0x43, 0x43, 0x35, 0x35,
307				     0x30, 0x7a, 0x30, 0x7a, 0x01, 0x9d);
308	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0xcd);
309	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETMIPI, 0x84);
310	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0x3f);
311	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETVDC, 0x1b, 0x04);
312	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_UNKNOWN_BE, 0x20);
313	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETPTBA, 0xfc, 0xc4);
314	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSTBA, 0x34, 0x34, 0x22, 0x11, 0x22, 0xa0,
315				     0x31, 0x08, 0xf5, 0x03);
316	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0xcc);
317	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETTCON, 0x80);
318	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0x3f);
319	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0xd3);
320	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETTCON, 0x22);
321	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0x3f);
322	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0xc6);
323	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETRAMDMY, 0x97);
324	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0x3f);
325	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETPWM, 0x00, 0x1e, 0x13, 0x88, 0x01);
326	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETCLOCK, 0x08, 0x13, 0x07, 0x00, 0x0f, 0x34);
327	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETPANEL, 0x02, 0x03, 0x44);
328	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0xc4);
329	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETCASCADE, 0x03);
330	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0x3f);
331	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETPCTRL, 0x07, 0x06, 0x00, 0x02, 0x04, 0x2c,
332				     0xff);
333	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETGIP0, 0x06, 0x00, 0x00, 0x00, 0x00, 0x08,
334				     0x08, 0x08, 0x08, 0x37, 0x07, 0x64, 0x7c, 0x11, 0x11, 0x03, 0x03, 0x32,
335				     0x10, 0x0e, 0x00, 0x0e, 0x32, 0x17, 0x97, 0x07, 0x97, 0x32, 0x00, 0x02,
336				     0x00, 0x02, 0x00, 0x00);
337	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETGIP1, 0x25, 0x24, 0x25, 0x24, 0x18, 0x18,
338				     0x18, 0x18, 0x07, 0x06, 0x07, 0x06, 0x05, 0x04, 0x05, 0x04, 0x03, 0x02,
339				     0x03, 0x02, 0x01, 0x00, 0x01, 0x00, 0x1e, 0x1e, 0x1e, 0x1e, 0x1f, 0x1f,
340				     0x1f, 0x1f, 0x21, 0x20, 0x21, 0x20, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
341				     0x18, 0x18);
342	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETGIP3, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xa0,
343				     0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
344				     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
345				     0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
346	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETGMA, 0x00, 0x07, 0x10, 0x17, 0x1c, 0x33,
347				     0x48, 0x50, 0x57, 0x50, 0x68, 0x6e, 0x71, 0x7f, 0x81, 0x8a, 0x8e, 0x9b,
348				     0x9c, 0x4d, 0x56, 0x5d, 0x73, 0x00, 0x07, 0x10, 0x17, 0x1c, 0x33, 0x48,
349				     0x50, 0x57, 0x50, 0x68, 0x6e, 0x71, 0x7f, 0x81, 0x8a, 0x8e, 0x9b, 0x9c,
350				     0x4d, 0x56, 0x5d, 0x73);
351	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETTP1, 0x07, 0x10, 0x10, 0x1a, 0x26, 0x9e,
352				     0x00, 0x4f, 0xa0, 0x14, 0x14, 0x00, 0x00, 0x00, 0x00, 0x12, 0x0a, 0x02,
353				     0x02, 0x00, 0x33, 0x02, 0x04, 0x18, 0x01);
354	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETBANK, 0x01);
355	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETPOWER, 0x01, 0x7f, 0x11, 0xfd);
356	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETCLOCK, 0x86);
357	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETGIP0, 0x00, 0x00, 0x04, 0x00, 0x00);
358	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETGIP3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
359				     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xa0,
360				     0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
361				     0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
362	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETTP1, 0x02, 0x00, 0x2b, 0x01, 0x7e, 0x0f,
363				     0x7e, 0x10, 0xa0, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00);
364	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETBANK, 0x02);
365	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETPTBA, 0xf2);
366	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETCLOCK, 0x03, 0x07, 0x00, 0x10, 0x79);
367	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETGIP3, 0xff, 0xff, 0xff, 0xff, 0xfa, 0xa0,
368				     0xff, 0xff, 0xff, 0xff, 0xfa, 0xa0);
369	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETTP1, 0xfe, 0x01, 0xfe, 0x01, 0xfe, 0x01,
370				     0x00, 0x00, 0x00, 0x23, 0x00, 0x23, 0x81, 0x02, 0x40, 0x00, 0x20, 0x6e,
371				     0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
372	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETBANK, 0x03);
373	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xa0,
374				     0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xa0, 0xff, 0xff, 0xff, 0xff, 0xfa, 0xa0,
375				     0xff, 0xff, 0xff, 0xff, 0xfa, 0xa0, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xa0,
376				     0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
377				     0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
378	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0xc6);
379	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETCYC, 0x03, 0xff, 0xf8);
380	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0x3f);
381	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_UNKNOWN_E1, 0x00);
382	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETBANK, 0x00);
383	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_UNKNOWN_D2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff);
384	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0xc4);
385	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETMIPI, 0x96);
386	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0x3f);
387	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETBANK, 0x01);
388	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0xc5);
389	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETMIPI, 0x4f);
390	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0x3f);
391	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETBANK, 0x00);
392	hx83102_enable_extended_cmds(&dsi_ctx, false);
393
394	mipi_dsi_msleep(&dsi_ctx, 60);
395
396	return dsi_ctx.accum_err;
397};
398
399static const struct drm_display_mode starry_mode = {
400	.clock = 162680,
401	.hdisplay = 1200,
402	.hsync_start = 1200 + 60,
403	.hsync_end = 1200 + 60 + 20,
404	.htotal = 1200 + 60 + 20 + 40,
405	.vdisplay = 1920,
406	.vsync_start = 1920 + 116,
407	.vsync_end = 1920 + 116 + 8,
408	.vtotal = 1920 + 116 + 8 + 12,
409	.type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
410};
411
412static const struct hx83102_panel_desc starry_desc = {
413	.modes = &starry_mode,
414	.size = {
415		.width_mm = 141,
416		.height_mm = 226,
417	},
418	.init = starry_himax83102_j02_init,
419};
420
421static const struct drm_display_mode boe_tv110wum_default_mode = {
422	.clock = 167700,
423	.hdisplay = 1200,
424	.hsync_start = 1200 + 75,
425	.hsync_end = 1200 + 75 + 20,
426	.htotal = 1200 + 75 + 20 + 65,
427	.vdisplay = 1920,
428	.vsync_start = 1920 + 115,
429	.vsync_end = 1920 + 115 + 8,
430	.vtotal = 1920 + 115 + 8 + 12,
431	.type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
432};
433
434static const struct hx83102_panel_desc boe_nv110wum_desc = {
435	.modes = &boe_tv110wum_default_mode,
436	.size = {
437		.width_mm = 147,
438		.height_mm = 235,
439	},
440	.init = boe_nv110wum_init,
441};
442
443static const struct drm_display_mode ivo_t109nw41_default_mode = {
444	.clock = 167700,
445	.hdisplay = 1200,
446	.hsync_start = 1200 + 75,
447	.hsync_end = 1200 + 75 + 20,
448	.htotal = 1200 + 75 + 20 + 65,
449	.vdisplay = 1920,
450	.vsync_start = 1920 + 115,
451	.vsync_end = 1920 + 115 + 8,
452	.vtotal = 1920 + 115 + 8 + 12,
453	.type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
454};
455
456static const struct hx83102_panel_desc ivo_t109nw41_desc = {
457	.modes = &ivo_t109nw41_default_mode,
458	.size = {
459		.width_mm = 147,
460		.height_mm = 235,
461	},
462	.init = ivo_t109nw41_init,
463};
464
465static int hx83102_enable(struct drm_panel *panel)
466{
467	msleep(130);
468	return 0;
469}
470
471static int hx83102_disable(struct drm_panel *panel)
472{
473	struct hx83102 *ctx = panel_to_hx83102(panel);
474	struct mipi_dsi_device *dsi = ctx->dsi;
475	struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi };
476
477	dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
478
479	mipi_dsi_dcs_set_display_off_multi(&dsi_ctx);
480	mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx);
481
482	mipi_dsi_msleep(&dsi_ctx, 150);
483
484	return dsi_ctx.accum_err;
485}
486
487static int hx83102_unprepare(struct drm_panel *panel)
488{
489	struct hx83102 *ctx = panel_to_hx83102(panel);
490
491	gpiod_set_value(ctx->enable_gpio, 0);
492	usleep_range(1000, 2000);
493	regulator_disable(ctx->avee);
494	regulator_disable(ctx->avdd);
495	usleep_range(5000, 7000);
496	regulator_disable(ctx->pp1800);
497
498	return 0;
499}
500
501static int hx83102_prepare(struct drm_panel *panel)
502{
503	struct hx83102 *ctx = panel_to_hx83102(panel);
504	struct mipi_dsi_device *dsi = ctx->dsi;
505	struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi };
506
507	gpiod_set_value(ctx->enable_gpio, 0);
508	usleep_range(1000, 1500);
509
510	dsi_ctx.accum_err = regulator_enable(ctx->pp1800);
511	if (dsi_ctx.accum_err)
512		return dsi_ctx.accum_err;
513
514	usleep_range(3000, 5000);
515
516	dsi_ctx.accum_err = regulator_enable(ctx->avdd);
517	if (dsi_ctx.accum_err)
518		goto poweroff1v8;
519	dsi_ctx.accum_err = regulator_enable(ctx->avee);
520	if (dsi_ctx.accum_err)
521		goto poweroffavdd;
522
523	usleep_range(10000, 11000);
524
525	mipi_dsi_dcs_nop_multi(&dsi_ctx);
526	if (dsi_ctx.accum_err)
527		goto poweroff;
528
529	usleep_range(1000, 2000);
530
531	gpiod_set_value(ctx->enable_gpio, 1);
532	usleep_range(1000, 2000);
533	gpiod_set_value(ctx->enable_gpio, 0);
534	usleep_range(1000, 2000);
535	gpiod_set_value(ctx->enable_gpio, 1);
536	usleep_range(6000, 10000);
537
538	dsi_ctx.accum_err = ctx->desc->init(ctx);
539
540	mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx);
541	mipi_dsi_msleep(&dsi_ctx, 120);
542	mipi_dsi_dcs_set_display_on_multi(&dsi_ctx);
543	if (dsi_ctx.accum_err)
544		goto poweroff;
545
546	return 0;
547
548poweroff:
549	gpiod_set_value(ctx->enable_gpio, 0);
550	regulator_disable(ctx->avee);
551poweroffavdd:
552	regulator_disable(ctx->avdd);
553poweroff1v8:
554	usleep_range(5000, 7000);
555	regulator_disable(ctx->pp1800);
556
557	return dsi_ctx.accum_err;
558}
559
560static int hx83102_get_modes(struct drm_panel *panel,
561			    struct drm_connector *connector)
562{
563	struct hx83102 *ctx = panel_to_hx83102(panel);
564	const struct drm_display_mode *m = ctx->desc->modes;
565	struct drm_display_mode *mode;
566
567	mode = drm_mode_duplicate(connector->dev, m);
568	if (!mode)
569		return -ENOMEM;
570
571	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
572	drm_mode_set_name(mode);
573	drm_mode_probed_add(connector, mode);
574
575	connector->display_info.width_mm = ctx->desc->size.width_mm;
576	connector->display_info.height_mm = ctx->desc->size.height_mm;
577	connector->display_info.bpc = 8;
578
579	return 1;
580}
581
582static enum drm_panel_orientation hx83102_get_orientation(struct drm_panel *panel)
583{
584	struct hx83102 *ctx = panel_to_hx83102(panel);
585
586	return ctx->orientation;
587}
588
589static const struct drm_panel_funcs hx83102_drm_funcs = {
590	.disable   = hx83102_disable,
591	.unprepare = hx83102_unprepare,
592	.prepare   = hx83102_prepare,
593	.enable    = hx83102_enable,
594	.get_modes = hx83102_get_modes,
595	.get_orientation = hx83102_get_orientation,
596};
597
598static int hx83102_panel_add(struct hx83102 *ctx)
599{
600	struct device *dev = &ctx->dsi->dev;
601	int err;
602
603	ctx->avdd = devm_regulator_get(dev, "avdd");
604	if (IS_ERR(ctx->avdd))
605		return PTR_ERR(ctx->avdd);
606
607	ctx->avee = devm_regulator_get(dev, "avee");
608	if (IS_ERR(ctx->avee))
609		return PTR_ERR(ctx->avee);
610
611	ctx->pp1800 = devm_regulator_get(dev, "pp1800");
612	if (IS_ERR(ctx->pp1800))
613		return PTR_ERR(ctx->pp1800);
614
615	ctx->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW);
616	if (IS_ERR(ctx->enable_gpio))
617		return dev_err_probe(dev, PTR_ERR(ctx->enable_gpio), "Cannot get enable GPIO\n");
618
619	ctx->base.prepare_prev_first = true;
620
621	drm_panel_init(&ctx->base, dev, &hx83102_drm_funcs,
622		       DRM_MODE_CONNECTOR_DSI);
623	err = of_drm_get_panel_orientation(dev->of_node, &ctx->orientation);
624	if (err < 0)
625		return dev_err_probe(dev, err, "failed to get orientation\n");
626
627	err = drm_panel_of_backlight(&ctx->base);
628	if (err)
629		return err;
630
631	ctx->base.funcs = &hx83102_drm_funcs;
632	ctx->base.dev = &ctx->dsi->dev;
633
634	drm_panel_add(&ctx->base);
635
636	return 0;
637}
638
639static int hx83102_probe(struct mipi_dsi_device *dsi)
640{
641	struct hx83102 *ctx;
642	int ret;
643	const struct hx83102_panel_desc *desc;
644
645	ctx = devm_kzalloc(&dsi->dev, sizeof(*ctx), GFP_KERNEL);
646	if (!ctx)
647		return -ENOMEM;
648
649	desc = of_device_get_match_data(&dsi->dev);
650	dsi->lanes = 4;
651	dsi->format = MIPI_DSI_FMT_RGB888;
652	dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
653					  MIPI_DSI_MODE_LPM;
654	ctx->desc = desc;
655	ctx->dsi = dsi;
656	ret = hx83102_panel_add(ctx);
657	if (ret < 0)
658		return ret;
659
660	mipi_dsi_set_drvdata(dsi, ctx);
661
662	ret = mipi_dsi_attach(dsi);
663	if (ret)
664		drm_panel_remove(&ctx->base);
665
666	return ret;
667}
668
669static void hx83102_remove(struct mipi_dsi_device *dsi)
670{
671	struct hx83102 *ctx = mipi_dsi_get_drvdata(dsi);
672	int ret;
673
674	ret = mipi_dsi_detach(dsi);
675	if (ret < 0)
676		dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", ret);
677
678	if (ctx->base.dev)
679		drm_panel_remove(&ctx->base);
680}
681
682static const struct of_device_id hx83102_of_match[] = {
683	{ .compatible = "boe,nv110wum-l60",
684	.data = &boe_nv110wum_desc
685	},
686	{ .compatible = "ivo,t109nw41",
687	  .data = &ivo_t109nw41_desc
688	},
689	{ .compatible = "starry,himax83102-j02",
690	  .data = &starry_desc
691	},
692	{ /* sentinel */ }
693};
694MODULE_DEVICE_TABLE(of, hx83102_of_match);
695
696static struct mipi_dsi_driver hx83102_driver = {
697	.probe	= hx83102_probe,
698	.remove = hx83102_remove,
699	.driver = {
700		.name = "panel-himax-hx83102",
701		.of_match_table = hx83102_of_match,
702	},
703};
704module_mipi_dsi_driver(hx83102_driver);
705
706MODULE_AUTHOR("Cong Yang <yangcong5@huaqin.corp-partner.google.com>");
707MODULE_DESCRIPTION("DRM driver for Himax HX83102 based MIPI DSI panels");
708MODULE_LICENSE("GPL");