1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2019, Huaqin Telecom Technology Co., Ltd
4  *
5  * Author: Jerry Han <jerry.han.hq@gmail.com>
6  *
7  */
8 
9 #include <linux/delay.h>
10 #include <linux/kernel.h>
11 #include <linux/module.h>
12 #include <linux/of.h>
13 
14 #include <linux/gpio/consumer.h>
15 #include <linux/regulator/consumer.h>
16 
17 #include <drm/drm_device.h>
18 #include <drm/drm_mipi_dsi.h>
19 #include <drm/drm_modes.h>
20 #include <drm/drm_panel.h>
21 
22 #include <video/mipi_display.h>
23 
24 struct panel_cmd {
25 	char cmd;
26 	char data;
27 };
28 
29 struct panel_desc {
30 	const struct drm_display_mode *display_mode;
31 	unsigned int bpc;
32 	unsigned int width_mm;
33 	unsigned int height_mm;
34 
35 	unsigned long mode_flags;
36 	enum mipi_dsi_pixel_format format;
37 	unsigned int lanes;
38 	const struct panel_cmd *on_cmds;
39 	unsigned int on_cmds_num;
40 };
41 
42 struct panel_info {
43 	struct drm_panel base;
44 	struct mipi_dsi_device *link;
45 	const struct panel_desc *desc;
46 
47 	struct gpio_desc *enable_gpio;
48 	struct gpio_desc *pp33_gpio;
49 	struct gpio_desc *pp18_gpio;
50 };
51 
to_panel_info(struct drm_panel * panel)52 static inline struct panel_info *to_panel_info(struct drm_panel *panel)
53 {
54 	return container_of(panel, struct panel_info, base);
55 }
56 
disable_gpios(struct panel_info * pinfo)57 static void disable_gpios(struct panel_info *pinfo)
58 {
59 	gpiod_set_value(pinfo->enable_gpio, 0);
60 	gpiod_set_value(pinfo->pp33_gpio, 0);
61 	gpiod_set_value(pinfo->pp18_gpio, 0);
62 }
63 
send_mipi_cmds(struct drm_panel * panel,const struct panel_cmd * cmds)64 static int send_mipi_cmds(struct drm_panel *panel, const struct panel_cmd *cmds)
65 {
66 	struct panel_info *pinfo = to_panel_info(panel);
67 	unsigned int i = 0;
68 	int err;
69 
70 	for (i = 0; i < pinfo->desc->on_cmds_num; i++) {
71 		err = mipi_dsi_dcs_write_buffer(pinfo->link, &cmds[i],
72 						sizeof(struct panel_cmd));
73 
74 		if (err < 0)
75 			return err;
76 	}
77 
78 	return 0;
79 }
80 
boe_panel_disable(struct drm_panel * panel)81 static int boe_panel_disable(struct drm_panel *panel)
82 {
83 	struct panel_info *pinfo = to_panel_info(panel);
84 	int err;
85 
86 	err = mipi_dsi_dcs_set_display_off(pinfo->link);
87 	if (err < 0) {
88 		dev_err(panel->dev, "failed to set display off: %d\n", err);
89 		return err;
90 	}
91 
92 	return 0;
93 }
94 
boe_panel_unprepare(struct drm_panel * panel)95 static int boe_panel_unprepare(struct drm_panel *panel)
96 {
97 	struct panel_info *pinfo = to_panel_info(panel);
98 	int err;
99 
100 	err = mipi_dsi_dcs_set_display_off(pinfo->link);
101 	if (err < 0)
102 		dev_err(panel->dev, "failed to set display off: %d\n", err);
103 
104 	err = mipi_dsi_dcs_enter_sleep_mode(pinfo->link);
105 	if (err < 0)
106 		dev_err(panel->dev, "failed to enter sleep mode: %d\n", err);
107 
108 	/* sleep_mode_delay: 1ms - 2ms */
109 	usleep_range(1000, 2000);
110 
111 	disable_gpios(pinfo);
112 
113 	return 0;
114 }
115 
boe_panel_prepare(struct drm_panel * panel)116 static int boe_panel_prepare(struct drm_panel *panel)
117 {
118 	struct panel_info *pinfo = to_panel_info(panel);
119 	int err;
120 
121 	gpiod_set_value(pinfo->pp18_gpio, 1);
122 	/* T1: 5ms - 6ms */
123 	usleep_range(5000, 6000);
124 	gpiod_set_value(pinfo->pp33_gpio, 1);
125 
126 	/* reset sequence */
127 	/* T2: 14ms - 15ms */
128 	usleep_range(14000, 15000);
129 	gpiod_set_value(pinfo->enable_gpio, 1);
130 
131 	/* T3: 1ms - 2ms */
132 	usleep_range(1000, 2000);
133 	gpiod_set_value(pinfo->enable_gpio, 0);
134 
135 	/* T4: 1ms - 2ms */
136 	usleep_range(1000, 2000);
137 	gpiod_set_value(pinfo->enable_gpio, 1);
138 
139 	/* T5: 5ms - 6ms */
140 	usleep_range(5000, 6000);
141 
142 	/* send init code */
143 	err = send_mipi_cmds(panel, pinfo->desc->on_cmds);
144 	if (err < 0) {
145 		dev_err(panel->dev, "failed to send DCS Init Code: %d\n", err);
146 		goto poweroff;
147 	}
148 
149 	err = mipi_dsi_dcs_exit_sleep_mode(pinfo->link);
150 	if (err < 0) {
151 		dev_err(panel->dev, "failed to exit sleep mode: %d\n", err);
152 		goto poweroff;
153 	}
154 
155 	/* T6: 120ms - 121ms */
156 	usleep_range(120000, 121000);
157 
158 	err = mipi_dsi_dcs_set_display_on(pinfo->link);
159 	if (err < 0) {
160 		dev_err(panel->dev, "failed to set display on: %d\n", err);
161 		goto poweroff;
162 	}
163 
164 	/* T7: 20ms - 21ms */
165 	usleep_range(20000, 21000);
166 
167 	return 0;
168 
169 poweroff:
170 	disable_gpios(pinfo);
171 	return err;
172 }
173 
boe_panel_enable(struct drm_panel * panel)174 static int boe_panel_enable(struct drm_panel *panel)
175 {
176 	struct panel_info *pinfo = to_panel_info(panel);
177 	int ret;
178 
179 	usleep_range(120000, 121000);
180 
181 	ret = mipi_dsi_dcs_set_display_on(pinfo->link);
182 	if (ret < 0) {
183 		dev_err(panel->dev, "failed to set display on: %d\n", ret);
184 		return ret;
185 	}
186 
187 	return 0;
188 }
189 
boe_panel_get_modes(struct drm_panel * panel,struct drm_connector * connector)190 static int boe_panel_get_modes(struct drm_panel *panel,
191 			       struct drm_connector *connector)
192 {
193 	struct panel_info *pinfo = to_panel_info(panel);
194 	const struct drm_display_mode *m = pinfo->desc->display_mode;
195 	struct drm_display_mode *mode;
196 
197 	mode = drm_mode_duplicate(connector->dev, m);
198 	if (!mode) {
199 		dev_err(pinfo->base.dev, "failed to add mode %ux%u@%u\n",
200 			m->hdisplay, m->vdisplay, drm_mode_vrefresh(m));
201 		return -ENOMEM;
202 	}
203 
204 	drm_mode_set_name(mode);
205 
206 	drm_mode_probed_add(connector, mode);
207 
208 	connector->display_info.width_mm = pinfo->desc->width_mm;
209 	connector->display_info.height_mm = pinfo->desc->height_mm;
210 	connector->display_info.bpc = pinfo->desc->bpc;
211 
212 	return 1;
213 }
214 
215 static const struct drm_panel_funcs panel_funcs = {
216 	.disable = boe_panel_disable,
217 	.unprepare = boe_panel_unprepare,
218 	.prepare = boe_panel_prepare,
219 	.enable = boe_panel_enable,
220 	.get_modes = boe_panel_get_modes,
221 };
222 
223 static const struct drm_display_mode default_display_mode = {
224 	.clock = 159420,
225 	.hdisplay = 1200,
226 	.hsync_start = 1200 + 80,
227 	.hsync_end = 1200 + 80 + 60,
228 	.htotal = 1200 + 80 + 60 + 24,
229 	.vdisplay = 1920,
230 	.vsync_start = 1920 + 10,
231 	.vsync_end = 1920 + 10 + 14,
232 	.vtotal = 1920 + 10 + 14 + 4,
233 };
234 
235 /* 8 inch */
236 static const struct panel_cmd boe_himax8279d8p_on_cmds[] = {
237 	{ 0xB0, 0x05 },
238 	{ 0xB1, 0xE5 },
239 	{ 0xB3, 0x52 },
240 	{ 0xC0, 0x00 },
241 	{ 0xC2, 0x57 },
242 	{ 0xD9, 0x85 },
243 	{ 0xB0, 0x01 },
244 	{ 0xC8, 0x00 },
245 	{ 0xC9, 0x00 },
246 	{ 0xCC, 0x26 },
247 	{ 0xCD, 0x26 },
248 	{ 0xDC, 0x00 },
249 	{ 0xDD, 0x00 },
250 	{ 0xE0, 0x26 },
251 	{ 0xE1, 0x26 },
252 	{ 0xB0, 0x03 },
253 	{ 0xC3, 0x2A },
254 	{ 0xE7, 0x2A },
255 	{ 0xC5, 0x2A },
256 	{ 0xDE, 0x2A },
257 	{ 0xBC, 0x02 },
258 	{ 0xCB, 0x02 },
259 	{ 0xB0, 0x00 },
260 	{ 0xB6, 0x03 },
261 	{ 0xBA, 0x8B },
262 	{ 0xBF, 0x15 },
263 	{ 0xC0, 0x18 },
264 	{ 0xC2, 0x14 },
265 	{ 0xC3, 0x02 },
266 	{ 0xC4, 0x14 },
267 	{ 0xC5, 0x02 },
268 	{ 0xCC, 0x0A },
269 	{ 0xB0, 0x06 },
270 	{ 0xC0, 0xA5 },
271 	{ 0xD5, 0x20 },
272 	{ 0xC0, 0x00 },
273 	{ 0xB0, 0x02 },
274 	{ 0xC0, 0x00 },
275 	{ 0xC1, 0x02 },
276 	{ 0xC2, 0x06 },
277 	{ 0xC3, 0x16 },
278 	{ 0xC4, 0x0E },
279 	{ 0xC5, 0x18 },
280 	{ 0xC6, 0x26 },
281 	{ 0xC7, 0x32 },
282 	{ 0xC8, 0x3F },
283 	{ 0xC9, 0x3F },
284 	{ 0xCA, 0x3F },
285 	{ 0xCB, 0x3F },
286 	{ 0xCC, 0x3D },
287 	{ 0xCD, 0x2F },
288 	{ 0xCE, 0x2F },
289 	{ 0xCF, 0x2F },
290 	{ 0xD0, 0x07 },
291 	{ 0xD2, 0x00 },
292 	{ 0xD3, 0x02 },
293 	{ 0xD4, 0x06 },
294 	{ 0xD5, 0x12 },
295 	{ 0xD6, 0x0A },
296 	{ 0xD7, 0x14 },
297 	{ 0xD8, 0x22 },
298 	{ 0xD9, 0x2E },
299 	{ 0xDA, 0x3D },
300 	{ 0xDB, 0x3F },
301 	{ 0xDC, 0x3F },
302 	{ 0xDD, 0x3F },
303 	{ 0xDE, 0x3D },
304 	{ 0xDF, 0x2F },
305 	{ 0xE0, 0x2F },
306 	{ 0xE1, 0x2F },
307 	{ 0xE2, 0x07 },
308 	{ 0xB0, 0x07 },
309 	{ 0xB1, 0x18 },
310 	{ 0xB2, 0x19 },
311 	{ 0xB3, 0x2E },
312 	{ 0xB4, 0x52 },
313 	{ 0xB5, 0x72 },
314 	{ 0xB6, 0x8C },
315 	{ 0xB7, 0xBD },
316 	{ 0xB8, 0xEB },
317 	{ 0xB9, 0x47 },
318 	{ 0xBA, 0x96 },
319 	{ 0xBB, 0x1E },
320 	{ 0xBC, 0x90 },
321 	{ 0xBD, 0x93 },
322 	{ 0xBE, 0xFA },
323 	{ 0xBF, 0x56 },
324 	{ 0xC0, 0x8C },
325 	{ 0xC1, 0xB7 },
326 	{ 0xC2, 0xCC },
327 	{ 0xC3, 0xDF },
328 	{ 0xC4, 0xE8 },
329 	{ 0xC5, 0xF0 },
330 	{ 0xC6, 0xF8 },
331 	{ 0xC7, 0xFA },
332 	{ 0xC8, 0xFC },
333 	{ 0xC9, 0x00 },
334 	{ 0xCA, 0x00 },
335 	{ 0xCB, 0x5A },
336 	{ 0xCC, 0xAF },
337 	{ 0xCD, 0xFF },
338 	{ 0xCE, 0xFF },
339 	{ 0xB0, 0x08 },
340 	{ 0xB1, 0x04 },
341 	{ 0xB2, 0x15 },
342 	{ 0xB3, 0x2D },
343 	{ 0xB4, 0x51 },
344 	{ 0xB5, 0x72 },
345 	{ 0xB6, 0x8D },
346 	{ 0xB7, 0xBE },
347 	{ 0xB8, 0xED },
348 	{ 0xB9, 0x4A },
349 	{ 0xBA, 0x9A },
350 	{ 0xBB, 0x23 },
351 	{ 0xBC, 0x95 },
352 	{ 0xBD, 0x98 },
353 	{ 0xBE, 0xFF },
354 	{ 0xBF, 0x59 },
355 	{ 0xC0, 0x8E },
356 	{ 0xC1, 0xB9 },
357 	{ 0xC2, 0xCD },
358 	{ 0xC3, 0xDF },
359 	{ 0xC4, 0xE8 },
360 	{ 0xC5, 0xF0 },
361 	{ 0xC6, 0xF8 },
362 	{ 0xC7, 0xFA },
363 	{ 0xC8, 0xFC },
364 	{ 0xC9, 0x00 },
365 	{ 0xCA, 0x00 },
366 	{ 0xCB, 0x5A },
367 	{ 0xCC, 0xAF },
368 	{ 0xCD, 0xFF },
369 	{ 0xCE, 0xFF },
370 	{ 0xB0, 0x09 },
371 	{ 0xB1, 0x04 },
372 	{ 0xB2, 0x2C },
373 	{ 0xB3, 0x36 },
374 	{ 0xB4, 0x53 },
375 	{ 0xB5, 0x73 },
376 	{ 0xB6, 0x8E },
377 	{ 0xB7, 0xC0 },
378 	{ 0xB8, 0xEF },
379 	{ 0xB9, 0x4C },
380 	{ 0xBA, 0x9D },
381 	{ 0xBB, 0x25 },
382 	{ 0xBC, 0x96 },
383 	{ 0xBD, 0x9A },
384 	{ 0xBE, 0x01 },
385 	{ 0xBF, 0x59 },
386 	{ 0xC0, 0x8E },
387 	{ 0xC1, 0xB9 },
388 	{ 0xC2, 0xCD },
389 	{ 0xC3, 0xDF },
390 	{ 0xC4, 0xE8 },
391 	{ 0xC5, 0xF0 },
392 	{ 0xC6, 0xF8 },
393 	{ 0xC7, 0xFA },
394 	{ 0xC8, 0xFC },
395 	{ 0xC9, 0x00 },
396 	{ 0xCA, 0x00 },
397 	{ 0xCB, 0x5A },
398 	{ 0xCC, 0xBF },
399 	{ 0xCD, 0xFF },
400 	{ 0xCE, 0xFF },
401 	{ 0xB0, 0x0A },
402 	{ 0xB1, 0x18 },
403 	{ 0xB2, 0x19 },
404 	{ 0xB3, 0x2E },
405 	{ 0xB4, 0x52 },
406 	{ 0xB5, 0x72 },
407 	{ 0xB6, 0x8C },
408 	{ 0xB7, 0xBD },
409 	{ 0xB8, 0xEB },
410 	{ 0xB9, 0x47 },
411 	{ 0xBA, 0x96 },
412 	{ 0xBB, 0x1E },
413 	{ 0xBC, 0x90 },
414 	{ 0xBD, 0x93 },
415 	{ 0xBE, 0xFA },
416 	{ 0xBF, 0x56 },
417 	{ 0xC0, 0x8C },
418 	{ 0xC1, 0xB7 },
419 	{ 0xC2, 0xCC },
420 	{ 0xC3, 0xDF },
421 	{ 0xC4, 0xE8 },
422 	{ 0xC5, 0xF0 },
423 	{ 0xC6, 0xF8 },
424 	{ 0xC7, 0xFA },
425 	{ 0xC8, 0xFC },
426 	{ 0xC9, 0x00 },
427 	{ 0xCA, 0x00 },
428 	{ 0xCB, 0x5A },
429 	{ 0xCC, 0xAF },
430 	{ 0xCD, 0xFF },
431 	{ 0xCE, 0xFF },
432 	{ 0xB0, 0x0B },
433 	{ 0xB1, 0x04 },
434 	{ 0xB2, 0x15 },
435 	{ 0xB3, 0x2D },
436 	{ 0xB4, 0x51 },
437 	{ 0xB5, 0x72 },
438 	{ 0xB6, 0x8D },
439 	{ 0xB7, 0xBE },
440 	{ 0xB8, 0xED },
441 	{ 0xB9, 0x4A },
442 	{ 0xBA, 0x9A },
443 	{ 0xBB, 0x23 },
444 	{ 0xBC, 0x95 },
445 	{ 0xBD, 0x98 },
446 	{ 0xBE, 0xFF },
447 	{ 0xBF, 0x59 },
448 	{ 0xC0, 0x8E },
449 	{ 0xC1, 0xB9 },
450 	{ 0xC2, 0xCD },
451 	{ 0xC3, 0xDF },
452 	{ 0xC4, 0xE8 },
453 	{ 0xC5, 0xF0 },
454 	{ 0xC6, 0xF8 },
455 	{ 0xC7, 0xFA },
456 	{ 0xC8, 0xFC },
457 	{ 0xC9, 0x00 },
458 	{ 0xCA, 0x00 },
459 	{ 0xCB, 0x5A },
460 	{ 0xCC, 0xAF },
461 	{ 0xCD, 0xFF },
462 	{ 0xCE, 0xFF },
463 	{ 0xB0, 0x0C },
464 	{ 0xB1, 0x04 },
465 	{ 0xB2, 0x2C },
466 	{ 0xB3, 0x36 },
467 	{ 0xB4, 0x53 },
468 	{ 0xB5, 0x73 },
469 	{ 0xB6, 0x8E },
470 	{ 0xB7, 0xC0 },
471 	{ 0xB8, 0xEF },
472 	{ 0xB9, 0x4C },
473 	{ 0xBA, 0x9D },
474 	{ 0xBB, 0x25 },
475 	{ 0xBC, 0x96 },
476 	{ 0xBD, 0x9A },
477 	{ 0xBE, 0x01 },
478 	{ 0xBF, 0x59 },
479 	{ 0xC0, 0x8E },
480 	{ 0xC1, 0xB9 },
481 	{ 0xC2, 0xCD },
482 	{ 0xC3, 0xDF },
483 	{ 0xC4, 0xE8 },
484 	{ 0xC5, 0xF0 },
485 	{ 0xC6, 0xF8 },
486 	{ 0xC7, 0xFA },
487 	{ 0xC8, 0xFC },
488 	{ 0xC9, 0x00 },
489 	{ 0xCA, 0x00 },
490 	{ 0xCB, 0x5A },
491 	{ 0xCC, 0xBF },
492 	{ 0xCD, 0xFF },
493 	{ 0xCE, 0xFF },
494 	{ 0xB0, 0x04 },
495 	{ 0xB5, 0x02 },
496 	{ 0xB6, 0x01 },
497 };
498 
499 static const struct panel_desc boe_himax8279d8p_panel_desc = {
500 	.display_mode = &default_display_mode,
501 	.bpc = 8,
502 	.width_mm = 107,
503 	.height_mm = 172,
504 	.mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
505 			MIPI_DSI_CLOCK_NON_CONTINUOUS | MIPI_DSI_MODE_LPM,
506 	.format = MIPI_DSI_FMT_RGB888,
507 	.lanes = 4,
508 	.on_cmds = boe_himax8279d8p_on_cmds,
509 	.on_cmds_num = 260,
510 };
511 
512 /* 10 inch */
513 static const struct panel_cmd boe_himax8279d10p_on_cmds[] = {
514 	{ 0xB0, 0x05 },
515 	{ 0xB1, 0xE5 },
516 	{ 0xB3, 0x52 },
517 	{ 0xB0, 0x00 },
518 	{ 0xB6, 0x03 },
519 	{ 0xBA, 0x8B },
520 	{ 0xBF, 0x1A },
521 	{ 0xC0, 0x0F },
522 	{ 0xC2, 0x0C },
523 	{ 0xC3, 0x02 },
524 	{ 0xC4, 0x0C },
525 	{ 0xC5, 0x02 },
526 	{ 0xB0, 0x01 },
527 	{ 0xE0, 0x26 },
528 	{ 0xE1, 0x26 },
529 	{ 0xDC, 0x00 },
530 	{ 0xDD, 0x00 },
531 	{ 0xCC, 0x26 },
532 	{ 0xCD, 0x26 },
533 	{ 0xC8, 0x00 },
534 	{ 0xC9, 0x00 },
535 	{ 0xD2, 0x03 },
536 	{ 0xD3, 0x03 },
537 	{ 0xE6, 0x04 },
538 	{ 0xE7, 0x04 },
539 	{ 0xC4, 0x09 },
540 	{ 0xC5, 0x09 },
541 	{ 0xD8, 0x0A },
542 	{ 0xD9, 0x0A },
543 	{ 0xC2, 0x0B },
544 	{ 0xC3, 0x0B },
545 	{ 0xD6, 0x0C },
546 	{ 0xD7, 0x0C },
547 	{ 0xC0, 0x05 },
548 	{ 0xC1, 0x05 },
549 	{ 0xD4, 0x06 },
550 	{ 0xD5, 0x06 },
551 	{ 0xCA, 0x07 },
552 	{ 0xCB, 0x07 },
553 	{ 0xDE, 0x08 },
554 	{ 0xDF, 0x08 },
555 	{ 0xB0, 0x02 },
556 	{ 0xC0, 0x00 },
557 	{ 0xC1, 0x0D },
558 	{ 0xC2, 0x17 },
559 	{ 0xC3, 0x26 },
560 	{ 0xC4, 0x31 },
561 	{ 0xC5, 0x1C },
562 	{ 0xC6, 0x2C },
563 	{ 0xC7, 0x33 },
564 	{ 0xC8, 0x31 },
565 	{ 0xC9, 0x37 },
566 	{ 0xCA, 0x37 },
567 	{ 0xCB, 0x37 },
568 	{ 0xCC, 0x39 },
569 	{ 0xCD, 0x2E },
570 	{ 0xCE, 0x2F },
571 	{ 0xCF, 0x2F },
572 	{ 0xD0, 0x07 },
573 	{ 0xD2, 0x00 },
574 	{ 0xD3, 0x0D },
575 	{ 0xD4, 0x17 },
576 	{ 0xD5, 0x26 },
577 	{ 0xD6, 0x31 },
578 	{ 0xD7, 0x3F },
579 	{ 0xD8, 0x3F },
580 	{ 0xD9, 0x3F },
581 	{ 0xDA, 0x3F },
582 	{ 0xDB, 0x37 },
583 	{ 0xDC, 0x37 },
584 	{ 0xDD, 0x37 },
585 	{ 0xDE, 0x39 },
586 	{ 0xDF, 0x2E },
587 	{ 0xE0, 0x2F },
588 	{ 0xE1, 0x2F },
589 	{ 0xE2, 0x07 },
590 	{ 0xB0, 0x03 },
591 	{ 0xC8, 0x0B },
592 	{ 0xC9, 0x07 },
593 	{ 0xC3, 0x00 },
594 	{ 0xE7, 0x00 },
595 	{ 0xC5, 0x2A },
596 	{ 0xDE, 0x2A },
597 	{ 0xCA, 0x43 },
598 	{ 0xC9, 0x07 },
599 	{ 0xE4, 0xC0 },
600 	{ 0xE5, 0x0D },
601 	{ 0xCB, 0x01 },
602 	{ 0xBC, 0x01 },
603 	{ 0xB0, 0x06 },
604 	{ 0xB8, 0xA5 },
605 	{ 0xC0, 0xA5 },
606 	{ 0xC7, 0x0F },
607 	{ 0xD5, 0x32 },
608 	{ 0xB8, 0x00 },
609 	{ 0xC0, 0x00 },
610 	{ 0xBC, 0x00 },
611 	{ 0xB0, 0x07 },
612 	{ 0xB1, 0x00 },
613 	{ 0xB2, 0x05 },
614 	{ 0xB3, 0x10 },
615 	{ 0xB4, 0x22 },
616 	{ 0xB5, 0x36 },
617 	{ 0xB6, 0x4A },
618 	{ 0xB7, 0x6C },
619 	{ 0xB8, 0x9A },
620 	{ 0xB9, 0xD7 },
621 	{ 0xBA, 0x17 },
622 	{ 0xBB, 0x92 },
623 	{ 0xBC, 0x15 },
624 	{ 0xBD, 0x18 },
625 	{ 0xBE, 0x8C },
626 	{ 0xBF, 0x00 },
627 	{ 0xC0, 0x3A },
628 	{ 0xC1, 0x72 },
629 	{ 0xC2, 0x8C },
630 	{ 0xC3, 0xA5 },
631 	{ 0xC4, 0xB1 },
632 	{ 0xC5, 0xBE },
633 	{ 0xC6, 0xCA },
634 	{ 0xC7, 0xD1 },
635 	{ 0xC8, 0xD4 },
636 	{ 0xC9, 0x00 },
637 	{ 0xCA, 0x00 },
638 	{ 0xCB, 0x16 },
639 	{ 0xCC, 0xAF },
640 	{ 0xCD, 0xFF },
641 	{ 0xCE, 0xFF },
642 	{ 0xB0, 0x08 },
643 	{ 0xB1, 0x04 },
644 	{ 0xB2, 0x05 },
645 	{ 0xB3, 0x11 },
646 	{ 0xB4, 0x24 },
647 	{ 0xB5, 0x39 },
648 	{ 0xB6, 0x4E },
649 	{ 0xB7, 0x72 },
650 	{ 0xB8, 0xA3 },
651 	{ 0xB9, 0xE1 },
652 	{ 0xBA, 0x25 },
653 	{ 0xBB, 0xA8 },
654 	{ 0xBC, 0x2E },
655 	{ 0xBD, 0x32 },
656 	{ 0xBE, 0xAD },
657 	{ 0xBF, 0x28 },
658 	{ 0xC0, 0x63 },
659 	{ 0xC1, 0x9B },
660 	{ 0xC2, 0xB5 },
661 	{ 0xC3, 0xCF },
662 	{ 0xC4, 0xDB },
663 	{ 0xC5, 0xE8 },
664 	{ 0xC6, 0xF5 },
665 	{ 0xC7, 0xFA },
666 	{ 0xC8, 0xFC },
667 	{ 0xC9, 0x00 },
668 	{ 0xCA, 0x00 },
669 	{ 0xCB, 0x16 },
670 	{ 0xCC, 0xAF },
671 	{ 0xCD, 0xFF },
672 	{ 0xCE, 0xFF },
673 	{ 0xB0, 0x09 },
674 	{ 0xB1, 0x04 },
675 	{ 0xB2, 0x04 },
676 	{ 0xB3, 0x0F },
677 	{ 0xB4, 0x22 },
678 	{ 0xB5, 0x37 },
679 	{ 0xB6, 0x4D },
680 	{ 0xB7, 0x71 },
681 	{ 0xB8, 0xA2 },
682 	{ 0xB9, 0xE1 },
683 	{ 0xBA, 0x26 },
684 	{ 0xBB, 0xA9 },
685 	{ 0xBC, 0x2F },
686 	{ 0xBD, 0x33 },
687 	{ 0xBE, 0xAC },
688 	{ 0xBF, 0x24 },
689 	{ 0xC0, 0x5D },
690 	{ 0xC1, 0x94 },
691 	{ 0xC2, 0xAC },
692 	{ 0xC3, 0xC5 },
693 	{ 0xC4, 0xD1 },
694 	{ 0xC5, 0xDC },
695 	{ 0xC6, 0xE8 },
696 	{ 0xC7, 0xED },
697 	{ 0xC8, 0xF0 },
698 	{ 0xC9, 0x00 },
699 	{ 0xCA, 0x00 },
700 	{ 0xCB, 0x16 },
701 	{ 0xCC, 0xAF },
702 	{ 0xCD, 0xFF },
703 	{ 0xCE, 0xFF },
704 	{ 0xB0, 0x0A },
705 	{ 0xB1, 0x00 },
706 	{ 0xB2, 0x05 },
707 	{ 0xB3, 0x10 },
708 	{ 0xB4, 0x22 },
709 	{ 0xB5, 0x36 },
710 	{ 0xB6, 0x4A },
711 	{ 0xB7, 0x6C },
712 	{ 0xB8, 0x9A },
713 	{ 0xB9, 0xD7 },
714 	{ 0xBA, 0x17 },
715 	{ 0xBB, 0x92 },
716 	{ 0xBC, 0x15 },
717 	{ 0xBD, 0x18 },
718 	{ 0xBE, 0x8C },
719 	{ 0xBF, 0x00 },
720 	{ 0xC0, 0x3A },
721 	{ 0xC1, 0x72 },
722 	{ 0xC2, 0x8C },
723 	{ 0xC3, 0xA5 },
724 	{ 0xC4, 0xB1 },
725 	{ 0xC5, 0xBE },
726 	{ 0xC6, 0xCA },
727 	{ 0xC7, 0xD1 },
728 	{ 0xC8, 0xD4 },
729 	{ 0xC9, 0x00 },
730 	{ 0xCA, 0x00 },
731 	{ 0xCB, 0x16 },
732 	{ 0xCC, 0xAF },
733 	{ 0xCD, 0xFF },
734 	{ 0xCE, 0xFF },
735 	{ 0xB0, 0x0B },
736 	{ 0xB1, 0x04 },
737 	{ 0xB2, 0x05 },
738 	{ 0xB3, 0x11 },
739 	{ 0xB4, 0x24 },
740 	{ 0xB5, 0x39 },
741 	{ 0xB6, 0x4E },
742 	{ 0xB7, 0x72 },
743 	{ 0xB8, 0xA3 },
744 	{ 0xB9, 0xE1 },
745 	{ 0xBA, 0x25 },
746 	{ 0xBB, 0xA8 },
747 	{ 0xBC, 0x2E },
748 	{ 0xBD, 0x32 },
749 	{ 0xBE, 0xAD },
750 	{ 0xBF, 0x28 },
751 	{ 0xC0, 0x63 },
752 	{ 0xC1, 0x9B },
753 	{ 0xC2, 0xB5 },
754 	{ 0xC3, 0xCF },
755 	{ 0xC4, 0xDB },
756 	{ 0xC5, 0xE8 },
757 	{ 0xC6, 0xF5 },
758 	{ 0xC7, 0xFA },
759 	{ 0xC8, 0xFC },
760 	{ 0xC9, 0x00 },
761 	{ 0xCA, 0x00 },
762 	{ 0xCB, 0x16 },
763 	{ 0xCC, 0xAF },
764 	{ 0xCD, 0xFF },
765 	{ 0xCE, 0xFF },
766 	{ 0xB0, 0x0C },
767 	{ 0xB1, 0x04 },
768 	{ 0xB2, 0x04 },
769 	{ 0xB3, 0x0F },
770 	{ 0xB4, 0x22 },
771 	{ 0xB5, 0x37 },
772 	{ 0xB6, 0x4D },
773 	{ 0xB7, 0x71 },
774 	{ 0xB8, 0xA2 },
775 	{ 0xB9, 0xE1 },
776 	{ 0xBA, 0x26 },
777 	{ 0xBB, 0xA9 },
778 	{ 0xBC, 0x2F },
779 	{ 0xBD, 0x33 },
780 	{ 0xBE, 0xAC },
781 	{ 0xBF, 0x24 },
782 	{ 0xC0, 0x5D },
783 	{ 0xC1, 0x94 },
784 	{ 0xC2, 0xAC },
785 	{ 0xC3, 0xC5 },
786 	{ 0xC4, 0xD1 },
787 	{ 0xC5, 0xDC },
788 	{ 0xC6, 0xE8 },
789 	{ 0xC7, 0xED },
790 	{ 0xC8, 0xF0 },
791 	{ 0xC9, 0x00 },
792 	{ 0xCA, 0x00 },
793 	{ 0xCB, 0x16 },
794 	{ 0xCC, 0xAF },
795 	{ 0xCD, 0xFF },
796 	{ 0xCE, 0xFF },
797 };
798 
799 static const struct panel_desc boe_himax8279d10p_panel_desc = {
800 	.display_mode = &default_display_mode,
801 	.bpc = 8,
802 	.width_mm = 135,
803 	.height_mm = 216,
804 	.mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
805 			MIPI_DSI_CLOCK_NON_CONTINUOUS | MIPI_DSI_MODE_LPM,
806 	.format = MIPI_DSI_FMT_RGB888,
807 	.lanes = 4,
808 	.on_cmds = boe_himax8279d10p_on_cmds,
809 	.on_cmds_num = 283,
810 };
811 
812 static const struct of_device_id panel_of_match[] = {
813 	{
814 		.compatible = "boe,himax8279d8p",
815 		.data = &boe_himax8279d8p_panel_desc,
816 	},
817 	{
818 		.compatible = "boe,himax8279d10p",
819 		.data = &boe_himax8279d10p_panel_desc,
820 	},
821 	{
822 		/* sentinel */
823 	}
824 };
825 MODULE_DEVICE_TABLE(of, panel_of_match);
826 
panel_add(struct panel_info * pinfo)827 static int panel_add(struct panel_info *pinfo)
828 {
829 	struct device *dev = &pinfo->link->dev;
830 	int ret;
831 
832 	pinfo->pp18_gpio = devm_gpiod_get(dev, "pp18", GPIOD_OUT_HIGH);
833 	if (IS_ERR(pinfo->pp18_gpio)) {
834 		return dev_err_probe(dev, PTR_ERR(pinfo->pp18_gpio),
835 							 "failed to get pp18 gpio\n");
836 	}
837 
838 	pinfo->pp33_gpio = devm_gpiod_get(dev, "pp33", GPIOD_OUT_HIGH);
839 	if (IS_ERR(pinfo->pp33_gpio)) {
840 		return	dev_err_probe(dev, PTR_ERR(pinfo->pp33_gpio),
841 							 "failed to get pp33 gpio\n");
842 	}
843 
844 	pinfo->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_HIGH);
845 	if (IS_ERR(pinfo->enable_gpio)) {
846 		return	dev_err_probe(dev, PTR_ERR(pinfo->enable_gpio),
847 						 "failed to get enable gpio\n");
848 	}
849 
850 	drm_panel_init(&pinfo->base, dev, &panel_funcs,
851 		       DRM_MODE_CONNECTOR_DSI);
852 
853 	ret = drm_panel_of_backlight(&pinfo->base);
854 	if (ret)
855 		return ret;
856 
857 	drm_panel_add(&pinfo->base);
858 
859 	return 0;
860 }
861 
panel_probe(struct mipi_dsi_device * dsi)862 static int panel_probe(struct mipi_dsi_device *dsi)
863 {
864 	struct panel_info *pinfo;
865 	const struct panel_desc *desc;
866 	int err;
867 
868 	pinfo = devm_kzalloc(&dsi->dev, sizeof(*pinfo), GFP_KERNEL);
869 	if (!pinfo)
870 		return -ENOMEM;
871 
872 	desc = of_device_get_match_data(&dsi->dev);
873 	dsi->mode_flags = desc->mode_flags;
874 	dsi->format = desc->format;
875 	dsi->lanes = desc->lanes;
876 	pinfo->desc = desc;
877 
878 	pinfo->link = dsi;
879 	mipi_dsi_set_drvdata(dsi, pinfo);
880 
881 	err = panel_add(pinfo);
882 	if (err < 0)
883 		return err;
884 
885 	err = mipi_dsi_attach(dsi);
886 	if (err < 0)
887 		drm_panel_remove(&pinfo->base);
888 
889 	return err;
890 }
891 
panel_remove(struct mipi_dsi_device * dsi)892 static void panel_remove(struct mipi_dsi_device *dsi)
893 {
894 	struct panel_info *pinfo = mipi_dsi_get_drvdata(dsi);
895 	int err;
896 
897 	err = mipi_dsi_detach(dsi);
898 	if (err < 0)
899 		dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", err);
900 
901 	drm_panel_remove(&pinfo->base);
902 }
903 
904 static struct mipi_dsi_driver panel_driver = {
905 	.driver = {
906 		.name = "panel-boe-himax8279d",
907 		.of_match_table = panel_of_match,
908 	},
909 	.probe = panel_probe,
910 	.remove = panel_remove,
911 };
912 module_mipi_dsi_driver(panel_driver);
913 
914 MODULE_AUTHOR("Jerry Han <jerry.han.hq@gmail.com>");
915 MODULE_DESCRIPTION("Boe Himax8279d driver");
916 MODULE_LICENSE("GPL v2");
917