xref: /linux/drivers/gpu/drm/panel/panel-himax-hx8394.c (revision c532de5a67a70f8533d495f8f2aaa9a0491c3ad0)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Driver for panels based on Himax HX8394 controller, such as:
4  *
5  * - HannStar HSD060BHW4 5.99" MIPI-DSI panel
6  *
7  * Copyright (C) 2021 Kamil Trzciński
8  *
9  * Based on drivers/gpu/drm/panel/panel-sitronix-st7703.c
10  * Copyright (C) Purism SPC 2019
11  */
12 
13 #include <linux/delay.h>
14 #include <linux/gpio/consumer.h>
15 #include <linux/media-bus-format.h>
16 #include <linux/mod_devicetable.h>
17 #include <linux/module.h>
18 #include <linux/of.h>
19 #include <linux/regulator/consumer.h>
20 
21 #include <video/mipi_display.h>
22 
23 #include <drm/drm_mipi_dsi.h>
24 #include <drm/drm_modes.h>
25 #include <drm/drm_panel.h>
26 
27 #define DRV_NAME "panel-himax-hx8394"
28 
29 /* Manufacturer specific commands sent via DSI, listed in HX8394-F datasheet */
30 #define HX8394_CMD_SETSEQUENCE	  0xb0
31 #define HX8394_CMD_SETPOWER	  0xb1
32 #define HX8394_CMD_SETDISP	  0xb2
33 #define HX8394_CMD_SETCYC	  0xb4
34 #define HX8394_CMD_SETVCOM	  0xb6
35 #define HX8394_CMD_SETTE	  0xb7
36 #define HX8394_CMD_SETSENSOR	  0xb8
37 #define HX8394_CMD_SETEXTC	  0xb9
38 #define HX8394_CMD_SETMIPI	  0xba
39 #define HX8394_CMD_SETOTP	  0xbb
40 #define HX8394_CMD_SETREGBANK	  0xbd
41 #define HX8394_CMD_UNKNOWN5	  0xbf
42 #define HX8394_CMD_UNKNOWN1	  0xc0
43 #define HX8394_CMD_SETDGCLUT	  0xc1
44 #define HX8394_CMD_SETID	  0xc3
45 #define HX8394_CMD_SETDDB	  0xc4
46 #define HX8394_CMD_UNKNOWN2	  0xc6
47 #define HX8394_CMD_SETCABC	  0xc9
48 #define HX8394_CMD_SETCABCGAIN	  0xca
49 #define HX8394_CMD_SETPANEL	  0xcc
50 #define HX8394_CMD_SETOFFSET	  0xd2
51 #define HX8394_CMD_SETGIP0	  0xd3
52 #define HX8394_CMD_UNKNOWN3	  0xd4
53 #define HX8394_CMD_SETGIP1	  0xd5
54 #define HX8394_CMD_SETGIP2	  0xd6
55 #define HX8394_CMD_SETGPO	  0xd6
56 #define HX8394_CMD_UNKNOWN4	  0xd8
57 #define HX8394_CMD_SETSCALING	  0xdd
58 #define HX8394_CMD_SETIDLE	  0xdf
59 #define HX8394_CMD_SETGAMMA	  0xe0
60 #define HX8394_CMD_SETCHEMODE_DYN 0xe4
61 #define HX8394_CMD_SETCHE	  0xe5
62 #define HX8394_CMD_SETCESEL	  0xe6
63 #define HX8394_CMD_SET_SP_CMD	  0xe9
64 #define HX8394_CMD_SETREADINDEX	  0xfe
65 #define HX8394_CMD_GETSPIREAD	  0xff
66 
67 struct hx8394 {
68 	struct device *dev;
69 	struct drm_panel panel;
70 	struct gpio_desc *reset_gpio;
71 	struct regulator *vcc;
72 	struct regulator *iovcc;
73 	enum drm_panel_orientation orientation;
74 
75 	const struct hx8394_panel_desc *desc;
76 };
77 
78 struct hx8394_panel_desc {
79 	const struct drm_display_mode *mode;
80 	unsigned int lanes;
81 	unsigned long mode_flags;
82 	enum mipi_dsi_pixel_format format;
83 	int (*init_sequence)(struct hx8394 *ctx);
84 };
85 
86 static inline struct hx8394 *panel_to_hx8394(struct drm_panel *panel)
87 {
88 	return container_of(panel, struct hx8394, panel);
89 }
90 
91 static int hsd060bhw4_init_sequence(struct hx8394 *ctx)
92 {
93 	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
94 
95 	/* 5.19.8 SETEXTC: Set extension command (B9h) */
96 	mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETEXTC,
97 			       0xff, 0x83, 0x94);
98 
99 	/* 5.19.2 SETPOWER: Set power (B1h) */
100 	mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETPOWER,
101 			       0x48, 0x11, 0x71, 0x09, 0x32, 0x24, 0x71, 0x31, 0x55, 0x30);
102 
103 	/* 5.19.9 SETMIPI: Set MIPI control (BAh) */
104 	mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETMIPI,
105 			       0x63, 0x03, 0x68, 0x6b, 0xb2, 0xc0);
106 
107 	/* 5.19.3 SETDISP: Set display related register (B2h) */
108 	mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETDISP,
109 			       0x00, 0x80, 0x78, 0x0c, 0x07);
110 
111 	/* 5.19.4 SETCYC: Set display waveform cycles (B4h) */
112 	mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETCYC,
113 			       0x12, 0x63, 0x12, 0x63, 0x12, 0x63, 0x01, 0x0c, 0x7c, 0x55,
114 			       0x00, 0x3f, 0x12, 0x6b, 0x12, 0x6b, 0x12, 0x6b, 0x01, 0x0c,
115 			       0x7c);
116 
117 	/* 5.19.19 SETGIP0: Set GIP Option0 (D3h) */
118 	mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETGIP0,
119 			       0x00, 0x00, 0x00, 0x00, 0x3c, 0x1c, 0x00, 0x00, 0x32, 0x10,
120 			       0x09, 0x00, 0x09, 0x32, 0x15, 0xad, 0x05, 0xad, 0x32, 0x00,
121 			       0x00, 0x00, 0x00, 0x37, 0x03, 0x0b, 0x0b, 0x37, 0x00, 0x00,
122 			       0x00, 0x0c, 0x40);
123 
124 	/* 5.19.20 Set GIP Option1 (D5h) */
125 	mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETGIP1,
126 			       0x19, 0x19, 0x18, 0x18, 0x1b, 0x1b, 0x1a, 0x1a, 0x00, 0x01,
127 			       0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x20, 0x21, 0x18, 0x18,
128 			       0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
129 			       0x24, 0x25, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
130 			       0x18, 0x18, 0x18, 0x18, 0x18, 0x18);
131 
132 	/* 5.19.21 Set GIP Option2 (D6h) */
133 	mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETGIP2,
134 			       0x18, 0x18, 0x19, 0x19, 0x1b, 0x1b, 0x1a, 0x1a, 0x07, 0x06,
135 			       0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x25, 0x24, 0x18, 0x18,
136 			       0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
137 			       0x21, 0x20, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
138 			       0x18, 0x18, 0x18, 0x18, 0x18, 0x18);
139 
140 	/* 5.19.25 SETGAMMA: Set gamma curve related setting (E0h) */
141 	mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETGAMMA,
142 			       0x00, 0x04, 0x0c, 0x12, 0x14, 0x18, 0x1a, 0x18, 0x31, 0x3f,
143 			       0x4d, 0x4c, 0x54, 0x65, 0x6b, 0x70, 0x7f, 0x82, 0x7e, 0x8a,
144 			       0x99, 0x4a, 0x48, 0x49, 0x4b, 0x4a, 0x4c, 0x4b, 0x7f, 0x00,
145 			       0x04, 0x0c, 0x11, 0x13, 0x17, 0x1a, 0x18, 0x31,
146 			       0x3f, 0x4d, 0x4c, 0x54, 0x65, 0x6b, 0x70, 0x7f,
147 			       0x82, 0x7e, 0x8a, 0x99, 0x4a, 0x48, 0x49, 0x4b,
148 			       0x4a, 0x4c, 0x4b, 0x7f);
149 
150 	/* 5.19.17 SETPANEL (CCh) */
151 	mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETPANEL,
152 			       0x0b);
153 
154 	/* Unknown command, not listed in the HX8394-F datasheet */
155 	mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_UNKNOWN1,
156 			       0x1f, 0x31);
157 
158 	/* 5.19.5 SETVCOM: Set VCOM voltage (B6h) */
159 	mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETVCOM,
160 			       0x7d, 0x7d);
161 
162 	/* Unknown command, not listed in the HX8394-F datasheet */
163 	mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_UNKNOWN3,
164 			       0x02);
165 
166 	/* 5.19.11 Set register bank (BDh) */
167 	mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETREGBANK,
168 			       0x01);
169 
170 	/* 5.19.2 SETPOWER: Set power (B1h) */
171 	mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETPOWER,
172 			       0x00);
173 
174 	/* 5.19.11 Set register bank (BDh) */
175 	mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETREGBANK,
176 			       0x00);
177 
178 	/* Unknown command, not listed in the HX8394-F datasheet */
179 	mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_UNKNOWN3,
180 			       0xed);
181 
182 	return 0;
183 }
184 
185 static const struct drm_display_mode hsd060bhw4_mode = {
186 	.hdisplay    = 720,
187 	.hsync_start = 720 + 40,
188 	.hsync_end   = 720 + 40 + 46,
189 	.htotal	     = 720 + 40 + 46 + 40,
190 	.vdisplay    = 1440,
191 	.vsync_start = 1440 + 9,
192 	.vsync_end   = 1440 + 9 + 7,
193 	.vtotal	     = 1440 + 9 + 7 + 7,
194 	.clock	     = 74250,
195 	.flags	     = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
196 	.width_mm    = 68,
197 	.height_mm   = 136,
198 };
199 
200 static const struct hx8394_panel_desc hsd060bhw4_desc = {
201 	.mode = &hsd060bhw4_mode,
202 	.lanes = 4,
203 	.mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST,
204 	.format = MIPI_DSI_FMT_RGB888,
205 	.init_sequence = hsd060bhw4_init_sequence,
206 };
207 
208 static int powkiddy_x55_init_sequence(struct hx8394 *ctx)
209 {
210 	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
211 
212 	/* 5.19.8 SETEXTC: Set extension command (B9h) */
213 	mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETEXTC,
214 			       0xff, 0x83, 0x94);
215 
216 	/* 5.19.9 SETMIPI: Set MIPI control (BAh) */
217 	mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETMIPI,
218 			       0x63, 0x03, 0x68, 0x6b, 0xb2, 0xc0);
219 
220 	/* 5.19.2 SETPOWER: Set power (B1h) */
221 	mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETPOWER,
222 			       0x48, 0x12, 0x72, 0x09, 0x32, 0x54, 0x71, 0x71, 0x57, 0x47);
223 
224 	/* 5.19.3 SETDISP: Set display related register (B2h) */
225 	mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETDISP,
226 			       0x00, 0x80, 0x64, 0x2c, 0x16, 0x2f);
227 
228 	/* 5.19.4 SETCYC: Set display waveform cycles (B4h) */
229 	mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETCYC,
230 			       0x73, 0x74, 0x73, 0x74, 0x73, 0x74, 0x01, 0x0c, 0x86, 0x75,
231 			       0x00, 0x3f, 0x73, 0x74, 0x73, 0x74, 0x73, 0x74, 0x01, 0x0c,
232 			       0x86);
233 
234 	/* 5.19.5 SETVCOM: Set VCOM voltage (B6h) */
235 	mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETVCOM,
236 			       0x6e, 0x6e);
237 
238 	/* 5.19.19 SETGIP0: Set GIP Option0 (D3h) */
239 	mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETGIP0,
240 			       0x00, 0x00, 0x07, 0x07, 0x40, 0x07, 0x0c, 0x00, 0x08, 0x10,
241 			       0x08, 0x00, 0x08, 0x54, 0x15, 0x0a, 0x05, 0x0a, 0x02, 0x15,
242 			       0x06, 0x05, 0x06, 0x47, 0x44, 0x0a, 0x0a, 0x4b, 0x10, 0x07,
243 			       0x07, 0x0c, 0x40);
244 
245 	/* 5.19.20 Set GIP Option1 (D5h) */
246 	mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETGIP1,
247 			       0x1c, 0x1c, 0x1d, 0x1d, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
248 			       0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x24, 0x25, 0x18, 0x18,
249 			       0x26, 0x27, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
250 			       0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x20, 0x21,
251 			       0x18, 0x18, 0x18, 0x18);
252 
253 	/* 5.19.21 Set GIP Option2 (D6h) */
254 	mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETGIP2,
255 			       0x1c, 0x1c, 0x1d, 0x1d, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02,
256 			       0x01, 0x00, 0x0b, 0x0a, 0x09, 0x08, 0x21, 0x20, 0x18, 0x18,
257 			       0x27, 0x26, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
258 			       0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x25, 0x24,
259 			       0x18, 0x18, 0x18, 0x18);
260 
261 	/* 5.19.25 SETGAMMA: Set gamma curve related setting (E0h) */
262 	mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETGAMMA,
263 			       0x00, 0x0a, 0x15, 0x1b, 0x1e, 0x21, 0x24, 0x22, 0x47, 0x56,
264 			       0x65, 0x66, 0x6e, 0x82, 0x88, 0x8b, 0x9a, 0x9d, 0x98, 0xa8,
265 			       0xb9, 0x5d, 0x5c, 0x61, 0x66, 0x6a, 0x6f, 0x7f, 0x7f, 0x00,
266 			       0x0a, 0x15, 0x1b, 0x1e, 0x21, 0x24, 0x22, 0x47, 0x56, 0x65,
267 			       0x65, 0x6e, 0x81, 0x87, 0x8b, 0x98, 0x9d, 0x99, 0xa8, 0xba,
268 			       0x5d, 0x5d, 0x62, 0x67, 0x6b, 0x72, 0x7f, 0x7f);
269 
270 	/* Unknown command, not listed in the HX8394-F datasheet */
271 	mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_UNKNOWN1,
272 			       0x1f, 0x31);
273 
274 	/* 5.19.17 SETPANEL (CCh) */
275 	mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETPANEL,
276 			       0x0b);
277 
278 	/* Unknown command, not listed in the HX8394-F datasheet */
279 	mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_UNKNOWN3,
280 			       0x02);
281 
282 	/* 5.19.11 Set register bank (BDh) */
283 	mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETREGBANK,
284 			       0x02);
285 
286 	/* Unknown command, not listed in the HX8394-F datasheet */
287 	mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_UNKNOWN4,
288 			       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
289 			       0xff, 0xff);
290 
291 	/* 5.19.11 Set register bank (BDh) */
292 	mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETREGBANK,
293 			       0x00);
294 
295 	/* 5.19.11 Set register bank (BDh) */
296 	mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETREGBANK,
297 			       0x01);
298 
299 	/* 5.19.2 SETPOWER: Set power (B1h) */
300 	mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETPOWER,
301 			       0x00);
302 
303 	/* 5.19.11 Set register bank (BDh) */
304 	mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETREGBANK,
305 			       0x00);
306 
307 	/* Unknown command, not listed in the HX8394-F datasheet */
308 	mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_UNKNOWN5,
309 			       0x40, 0x81, 0x50, 0x00, 0x1a, 0xfc, 0x01);
310 
311 	/* Unknown command, not listed in the HX8394-F datasheet */
312 	mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_UNKNOWN2,
313 			       0xed);
314 
315 	return 0;
316 }
317 
318 static const struct drm_display_mode powkiddy_x55_mode = {
319 	.hdisplay	= 720,
320 	.hsync_start	= 720 + 44,
321 	.hsync_end	= 720 + 44 + 20,
322 	.htotal		= 720 + 44 + 20 + 20,
323 	.vdisplay	= 1280,
324 	.vsync_start	= 1280 + 12,
325 	.vsync_end	= 1280 + 12 + 10,
326 	.vtotal		= 1280 + 12 + 10 + 10,
327 	.clock		= 63290,
328 	.flags		= DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
329 	.width_mm	= 67,
330 	.height_mm	= 121,
331 };
332 
333 static const struct hx8394_panel_desc powkiddy_x55_desc = {
334 	.mode = &powkiddy_x55_mode,
335 	.lanes = 4,
336 	.mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
337 		      MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_NO_EOT_PACKET,
338 	.format = MIPI_DSI_FMT_RGB888,
339 	.init_sequence = powkiddy_x55_init_sequence,
340 };
341 
342 static int mchp_ac40t08a_init_sequence(struct hx8394 *ctx)
343 {
344 	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
345 
346 	/* DCS commands do not seem to be sent correclty without this delay */
347 	msleep(20);
348 
349 	/* 5.19.8 SETEXTC: Set extension command (B9h) */
350 	mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETEXTC,
351 			       0xff, 0x83, 0x94);
352 
353 	/* 5.19.9 SETMIPI: Set MIPI control (BAh) */
354 	mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETMIPI,
355 			       0x63, 0x03, 0x68, 0x6b, 0xb2, 0xc0);
356 
357 	/* 5.19.2 SETPOWER: Set power (B1h) */
358 	mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETPOWER,
359 			       0x48, 0x12, 0x72, 0x09, 0x32, 0x54,
360 			       0x71, 0x71, 0x57, 0x47);
361 
362 	/* 5.19.3 SETDISP: Set display related register (B2h) */
363 	mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETDISP,
364 			       0x00, 0x80, 0x64, 0x0c, 0x0d, 0x2f);
365 
366 	/* 5.19.4 SETCYC: Set display waveform cycles (B4h) */
367 	mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETCYC,
368 			       0x73, 0x74, 0x73, 0x74, 0x73, 0x74,
369 			       0x01, 0x0c, 0x86, 0x75, 0x00, 0x3f,
370 			       0x73, 0x74, 0x73, 0x74, 0x73, 0x74,
371 			       0x01, 0x0c, 0x86);
372 
373 	/* 5.19.5 SETVCOM: Set VCOM voltage (B6h) */
374 	mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETVCOM,
375 			       0x6e, 0x6e);
376 
377 	/* 5.19.19 SETGIP0: Set GIP Option0 (D3h) */
378 	mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETGIP0,
379 			       0x00, 0x00, 0x07, 0x07, 0x40, 0x07,
380 			       0x0c, 0x00, 0x08, 0x10, 0x08, 0x00,
381 			       0x08, 0x54, 0x15, 0x0a, 0x05, 0x0a,
382 			       0x02, 0x15, 0x06, 0x05, 0x06, 0x47,
383 			       0x44, 0x0a, 0x0a, 0x4b, 0x10, 0x07,
384 			       0x07, 0x0c, 0x40);
385 
386 	/* 5.19.20 Set GIP Option1 (D5h) */
387 	mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETGIP1,
388 			       0x1c, 0x1c, 0x1d, 0x1d, 0x00, 0x01,
389 			       0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
390 			       0x08, 0x09, 0x0a, 0x0b, 0x24, 0x25,
391 			       0x18, 0x18, 0x26, 0x27, 0x18, 0x18,
392 			       0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
393 			       0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
394 			       0x18, 0x18, 0x20, 0x21, 0x18, 0x18,
395 			       0x18, 0x18);
396 
397 	/* 5.19.21 Set GIP Option2 (D6h) */
398 	mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETGIP2,
399 			       0x1c, 0x1c, 0x1d, 0x1d, 0x07, 0x06,
400 			       0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
401 			       0x0b, 0x0a, 0x09, 0x08, 0x21, 0x20,
402 			       0x18, 0x18, 0x27, 0x26, 0x18, 0x18,
403 			       0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
404 			       0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
405 			       0x18, 0x18, 0x25, 0x24, 0x18, 0x18,
406 			       0x18, 0x18);
407 
408 	/* 5.19.25 SETGAMMA: Set gamma curve related setting (E0h) */
409 	mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETGAMMA,
410 			       0x00, 0x0a, 0x15, 0x1b, 0x1e, 0x21,
411 			       0x24, 0x22, 0x47, 0x56, 0x65, 0x66,
412 			       0x6e, 0x82, 0x88, 0x8b, 0x9a, 0x9d,
413 			       0x98, 0xa8, 0xb9, 0x5d, 0x5c, 0x61,
414 			       0x66, 0x6a, 0x6f, 0x7f, 0x7f, 0x00,
415 			       0x0a, 0x15, 0x1b, 0x1e, 0x21, 0x24,
416 			       0x22, 0x47, 0x56, 0x65, 0x65, 0x6e,
417 			       0x81, 0x87, 0x8b, 0x98, 0x9d, 0x99,
418 			       0xa8, 0xba, 0x5d, 0x5d, 0x62, 0x67,
419 			       0x6b, 0x72, 0x7f, 0x7f);
420 
421 	/* Unknown command, not listed in the HX8394-F datasheet (C0H) */
422 	mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_UNKNOWN1,
423 			       0x1f, 0x73);
424 
425 	/* Set CABC control (C9h)*/
426 	mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETCABC,
427 			       0x76, 0x00, 0x30);
428 
429 	/* 5.19.17 SETPANEL (CCh) */
430 	mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETPANEL,
431 			       0x0b);
432 
433 	/* Unknown command, not listed in the HX8394-F datasheet (D4h) */
434 	mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_UNKNOWN3,
435 			       0x02);
436 
437 	/* 5.19.11 Set register bank (BDh) */
438 	mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETREGBANK,
439 			       0x02);
440 
441 	/* 5.19.11 Set register bank (D8h) */
442 	mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_UNKNOWN4,
443 			       0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
444 			       0xff, 0xff, 0xff, 0xff, 0xff, 0xff);
445 
446 	/* 5.19.11 Set register bank (BDh) */
447 	mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETREGBANK,
448 			       0x00);
449 
450 	/* 5.19.11 Set register bank (BDh) */
451 	mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETREGBANK,
452 			       0x01);
453 
454 	/* 5.19.2 SETPOWER: Set power (B1h) */
455 	mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETPOWER,
456 			       0x00);
457 
458 	/* 5.19.11 Set register bank (BDh) */
459 	mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETREGBANK,
460 			       0x00);
461 
462 	/* Unknown command, not listed in the HX8394-F datasheet (C6h) */
463 	mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_UNKNOWN2,
464 			       0xed);
465 
466 	return 0;
467 }
468 
469 static const struct drm_display_mode mchp_ac40t08a_mode = {
470 	.hdisplay    = 720,
471 	.hsync_start = 720 + 12,
472 	.hsync_end   = 720 + 12 + 24,
473 	.htotal	     = 720 + 12 + 12 + 24,
474 	.vdisplay    = 1280,
475 	.vsync_start = 1280 + 13,
476 	.vsync_end   = 1280 + 14,
477 	.vtotal	     = 1280 + 14 + 13,
478 	.clock	     = 60226,
479 	.flags	     = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
480 	.width_mm    = 76,
481 	.height_mm   = 132,
482 };
483 
484 static const struct hx8394_panel_desc mchp_ac40t08a_desc = {
485 	.mode = &mchp_ac40t08a_mode,
486 	.lanes = 4,
487 	.mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST,
488 	.format = MIPI_DSI_FMT_RGB888,
489 	.init_sequence = mchp_ac40t08a_init_sequence,
490 };
491 
492 static int hx8394_enable(struct drm_panel *panel)
493 {
494 	struct hx8394 *ctx = panel_to_hx8394(panel);
495 	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
496 	int ret;
497 
498 	ret = ctx->desc->init_sequence(ctx);
499 	if (ret) {
500 		dev_err(ctx->dev, "Panel init sequence failed: %d\n", ret);
501 		return ret;
502 	}
503 
504 	ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
505 	if (ret) {
506 		dev_err(ctx->dev, "Failed to exit sleep mode: %d\n", ret);
507 		return ret;
508 	}
509 
510 	/* Panel is operational 120 msec after reset */
511 	msleep(120);
512 
513 	ret = mipi_dsi_dcs_set_display_on(dsi);
514 	if (ret) {
515 		dev_err(ctx->dev, "Failed to turn on the display: %d\n", ret);
516 		goto sleep_in;
517 	}
518 
519 	return 0;
520 
521 sleep_in:
522 	/* This will probably fail, but let's try orderly power off anyway. */
523 	if (!mipi_dsi_dcs_enter_sleep_mode(dsi))
524 		msleep(50);
525 
526 	return ret;
527 }
528 
529 static int hx8394_disable(struct drm_panel *panel)
530 {
531 	struct hx8394 *ctx = panel_to_hx8394(panel);
532 	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
533 	int ret;
534 
535 	ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
536 	if (ret) {
537 		dev_err(ctx->dev, "Failed to enter sleep mode: %d\n", ret);
538 		return ret;
539 	}
540 
541 	msleep(50); /* about 3 frames */
542 
543 	return 0;
544 }
545 
546 static int hx8394_unprepare(struct drm_panel *panel)
547 {
548 	struct hx8394 *ctx = panel_to_hx8394(panel);
549 
550 	gpiod_set_value_cansleep(ctx->reset_gpio, 1);
551 
552 	regulator_disable(ctx->iovcc);
553 	regulator_disable(ctx->vcc);
554 
555 	return 0;
556 }
557 
558 static int hx8394_prepare(struct drm_panel *panel)
559 {
560 	struct hx8394 *ctx = panel_to_hx8394(panel);
561 	int ret;
562 
563 	gpiod_set_value_cansleep(ctx->reset_gpio, 1);
564 
565 	ret = regulator_enable(ctx->vcc);
566 	if (ret) {
567 		dev_err(ctx->dev, "Failed to enable vcc supply: %d\n", ret);
568 		return ret;
569 	}
570 
571 	ret = regulator_enable(ctx->iovcc);
572 	if (ret) {
573 		dev_err(ctx->dev, "Failed to enable iovcc supply: %d\n", ret);
574 		goto disable_vcc;
575 	}
576 
577 	gpiod_set_value_cansleep(ctx->reset_gpio, 0);
578 
579 	msleep(180);
580 
581 	return 0;
582 
583 disable_vcc:
584 	gpiod_set_value_cansleep(ctx->reset_gpio, 1);
585 	regulator_disable(ctx->vcc);
586 	return ret;
587 }
588 
589 static int hx8394_get_modes(struct drm_panel *panel,
590 			    struct drm_connector *connector)
591 {
592 	struct hx8394 *ctx = panel_to_hx8394(panel);
593 	struct drm_display_mode *mode;
594 
595 	mode = drm_mode_duplicate(connector->dev, ctx->desc->mode);
596 	if (!mode) {
597 		dev_err(ctx->dev, "Failed to add mode %ux%u@%u\n",
598 			ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay,
599 			drm_mode_vrefresh(ctx->desc->mode));
600 		return -ENOMEM;
601 	}
602 
603 	drm_mode_set_name(mode);
604 
605 	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
606 	connector->display_info.width_mm = mode->width_mm;
607 	connector->display_info.height_mm = mode->height_mm;
608 	drm_mode_probed_add(connector, mode);
609 
610 	return 1;
611 }
612 
613 static enum drm_panel_orientation hx8394_get_orientation(struct drm_panel *panel)
614 {
615 	struct hx8394 *ctx = panel_to_hx8394(panel);
616 
617 	return ctx->orientation;
618 }
619 
620 static const struct drm_panel_funcs hx8394_drm_funcs = {
621 	.disable   = hx8394_disable,
622 	.unprepare = hx8394_unprepare,
623 	.prepare   = hx8394_prepare,
624 	.enable	   = hx8394_enable,
625 	.get_modes = hx8394_get_modes,
626 	.get_orientation = hx8394_get_orientation,
627 };
628 
629 static int hx8394_probe(struct mipi_dsi_device *dsi)
630 {
631 	struct device *dev = &dsi->dev;
632 	struct hx8394 *ctx;
633 	int ret;
634 
635 	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
636 	if (!ctx)
637 		return -ENOMEM;
638 
639 	ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
640 	if (IS_ERR(ctx->reset_gpio))
641 		return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio),
642 				     "Failed to get reset gpio\n");
643 
644 	ret = of_drm_get_panel_orientation(dev->of_node, &ctx->orientation);
645 	if (ret < 0) {
646 		dev_err(dev, "%pOF: failed to get orientation %d\n", dev->of_node, ret);
647 		return ret;
648 	}
649 
650 	mipi_dsi_set_drvdata(dsi, ctx);
651 
652 	ctx->dev = dev;
653 	ctx->desc = of_device_get_match_data(dev);
654 
655 	dsi->mode_flags = ctx->desc->mode_flags;
656 	dsi->format = ctx->desc->format;
657 	dsi->lanes = ctx->desc->lanes;
658 
659 	ctx->vcc = devm_regulator_get(dev, "vcc");
660 	if (IS_ERR(ctx->vcc))
661 		return dev_err_probe(dev, PTR_ERR(ctx->vcc),
662 				     "Failed to request vcc regulator\n");
663 
664 	ctx->iovcc = devm_regulator_get(dev, "iovcc");
665 	if (IS_ERR(ctx->iovcc))
666 		return dev_err_probe(dev, PTR_ERR(ctx->iovcc),
667 				     "Failed to request iovcc regulator\n");
668 
669 	drm_panel_init(&ctx->panel, dev, &hx8394_drm_funcs,
670 		       DRM_MODE_CONNECTOR_DSI);
671 
672 	ret = drm_panel_of_backlight(&ctx->panel);
673 	if (ret)
674 		return ret;
675 
676 	drm_panel_add(&ctx->panel);
677 
678 	ret = mipi_dsi_attach(dsi);
679 	if (ret < 0) {
680 		dev_err_probe(dev, ret, "mipi_dsi_attach failed\n");
681 		drm_panel_remove(&ctx->panel);
682 		return ret;
683 	}
684 
685 	dev_dbg(dev, "%ux%u@%u %ubpp dsi %udl - ready\n",
686 		ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay,
687 		drm_mode_vrefresh(ctx->desc->mode),
688 		mipi_dsi_pixel_format_to_bpp(dsi->format), dsi->lanes);
689 
690 	return 0;
691 }
692 
693 static void hx8394_remove(struct mipi_dsi_device *dsi)
694 {
695 	struct hx8394 *ctx = mipi_dsi_get_drvdata(dsi);
696 	int ret;
697 
698 	ret = mipi_dsi_detach(dsi);
699 	if (ret < 0)
700 		dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret);
701 
702 	drm_panel_remove(&ctx->panel);
703 }
704 
705 static const struct of_device_id hx8394_of_match[] = {
706 	{ .compatible = "hannstar,hsd060bhw4", .data = &hsd060bhw4_desc },
707 	{ .compatible = "powkiddy,x55-panel", .data = &powkiddy_x55_desc },
708 	{ .compatible = "microchip,ac40t08a-mipi-panel", .data = &mchp_ac40t08a_desc },
709 	{ /* sentinel */ }
710 };
711 MODULE_DEVICE_TABLE(of, hx8394_of_match);
712 
713 static struct mipi_dsi_driver hx8394_driver = {
714 	.probe	= hx8394_probe,
715 	.remove = hx8394_remove,
716 	.driver = {
717 		.name = DRV_NAME,
718 		.of_match_table = hx8394_of_match,
719 	},
720 };
721 module_mipi_dsi_driver(hx8394_driver);
722 
723 MODULE_AUTHOR("Kamil Trzciński <ayufan@ayufan.eu>");
724 MODULE_DESCRIPTION("DRM driver for Himax HX8394 based MIPI DSI panels");
725 MODULE_LICENSE("GPL");
726