xref: /linux/drivers/gpu/drm/panel/panel-himax-hx83102.c (revision 55d0969c451159cff86949b38c39171cab962069)
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 
51 struct 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 
64 struct 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 
79 static inline struct hx83102 *panel_to_hx83102(struct drm_panel *panel)
80 {
81 	return container_of(panel, struct hx83102, base);
82 }
83 
84 static 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 
92 static 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 
189 static 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 
294 static 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 
399 static 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 
412 static 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 
421 static 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 
434 static 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 
443 static 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 
456 static 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 
465 static int hx83102_enable(struct drm_panel *panel)
466 {
467 	msleep(130);
468 	return 0;
469 }
470 
471 static 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 
487 static 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 
501 static 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 
548 poweroff:
549 	gpiod_set_value(ctx->enable_gpio, 0);
550 	regulator_disable(ctx->avee);
551 poweroffavdd:
552 	regulator_disable(ctx->avdd);
553 poweroff1v8:
554 	usleep_range(5000, 7000);
555 	regulator_disable(ctx->pp1800);
556 
557 	return dsi_ctx.accum_err;
558 }
559 
560 static 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 
569 	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
570 	drm_mode_set_name(mode);
571 	drm_mode_probed_add(connector, mode);
572 
573 	connector->display_info.width_mm = ctx->desc->size.width_mm;
574 	connector->display_info.height_mm = ctx->desc->size.height_mm;
575 	connector->display_info.bpc = 8;
576 
577 	return 1;
578 }
579 
580 static enum drm_panel_orientation hx83102_get_orientation(struct drm_panel *panel)
581 {
582 	struct hx83102 *ctx = panel_to_hx83102(panel);
583 
584 	return ctx->orientation;
585 }
586 
587 static const struct drm_panel_funcs hx83102_drm_funcs = {
588 	.disable   = hx83102_disable,
589 	.unprepare = hx83102_unprepare,
590 	.prepare   = hx83102_prepare,
591 	.enable    = hx83102_enable,
592 	.get_modes = hx83102_get_modes,
593 	.get_orientation = hx83102_get_orientation,
594 };
595 
596 static int hx83102_panel_add(struct hx83102 *ctx)
597 {
598 	struct device *dev = &ctx->dsi->dev;
599 	int err;
600 
601 	ctx->avdd = devm_regulator_get(dev, "avdd");
602 	if (IS_ERR(ctx->avdd))
603 		return PTR_ERR(ctx->avdd);
604 
605 	ctx->avee = devm_regulator_get(dev, "avee");
606 	if (IS_ERR(ctx->avee))
607 		return PTR_ERR(ctx->avee);
608 
609 	ctx->pp1800 = devm_regulator_get(dev, "pp1800");
610 	if (IS_ERR(ctx->pp1800))
611 		return PTR_ERR(ctx->pp1800);
612 
613 	ctx->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW);
614 	if (IS_ERR(ctx->enable_gpio))
615 		return dev_err_probe(dev, PTR_ERR(ctx->enable_gpio), "Cannot get enable GPIO\n");
616 
617 	ctx->base.prepare_prev_first = true;
618 
619 	drm_panel_init(&ctx->base, dev, &hx83102_drm_funcs,
620 		       DRM_MODE_CONNECTOR_DSI);
621 	err = of_drm_get_panel_orientation(dev->of_node, &ctx->orientation);
622 	if (err < 0)
623 		return dev_err_probe(dev, err, "failed to get orientation\n");
624 
625 	err = drm_panel_of_backlight(&ctx->base);
626 	if (err)
627 		return err;
628 
629 	ctx->base.funcs = &hx83102_drm_funcs;
630 	ctx->base.dev = &ctx->dsi->dev;
631 
632 	drm_panel_add(&ctx->base);
633 
634 	return 0;
635 }
636 
637 static int hx83102_probe(struct mipi_dsi_device *dsi)
638 {
639 	struct hx83102 *ctx;
640 	int ret;
641 	const struct hx83102_panel_desc *desc;
642 
643 	ctx = devm_kzalloc(&dsi->dev, sizeof(*ctx), GFP_KERNEL);
644 	if (!ctx)
645 		return -ENOMEM;
646 
647 	desc = of_device_get_match_data(&dsi->dev);
648 	dsi->lanes = 4;
649 	dsi->format = MIPI_DSI_FMT_RGB888;
650 	dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
651 					  MIPI_DSI_MODE_LPM;
652 	ctx->desc = desc;
653 	ctx->dsi = dsi;
654 	ret = hx83102_panel_add(ctx);
655 	if (ret < 0)
656 		return ret;
657 
658 	mipi_dsi_set_drvdata(dsi, ctx);
659 
660 	ret = mipi_dsi_attach(dsi);
661 	if (ret)
662 		drm_panel_remove(&ctx->base);
663 
664 	return ret;
665 }
666 
667 static void hx83102_remove(struct mipi_dsi_device *dsi)
668 {
669 	struct hx83102 *ctx = mipi_dsi_get_drvdata(dsi);
670 	int ret;
671 
672 	ret = mipi_dsi_detach(dsi);
673 	if (ret < 0)
674 		dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", ret);
675 
676 	if (ctx->base.dev)
677 		drm_panel_remove(&ctx->base);
678 }
679 
680 static const struct of_device_id hx83102_of_match[] = {
681 	{ .compatible = "boe,nv110wum-l60",
682 	.data = &boe_nv110wum_desc
683 	},
684 	{ .compatible = "ivo,t109nw41",
685 	  .data = &ivo_t109nw41_desc
686 	},
687 	{ .compatible = "starry,himax83102-j02",
688 	  .data = &starry_desc
689 	},
690 	{ /* sentinel */ }
691 };
692 MODULE_DEVICE_TABLE(of, hx83102_of_match);
693 
694 static struct mipi_dsi_driver hx83102_driver = {
695 	.probe	= hx83102_probe,
696 	.remove = hx83102_remove,
697 	.driver = {
698 		.name = "panel-himax-hx83102",
699 		.of_match_table = hx83102_of_match,
700 	},
701 };
702 module_mipi_dsi_driver(hx83102_driver);
703 
704 MODULE_AUTHOR("Cong Yang <yangcong5@huaqin.corp-partner.google.com>");
705 MODULE_DESCRIPTION("DRM driver for Himax HX83102 based MIPI DSI panels");
706 MODULE_LICENSE("GPL");
707