1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (C) 2020 BayLibre, SAS
4 * Author: Neil Armstrong <narmstrong@baylibre.com>
5 */
6
7#include <linux/delay.h>
8#include <linux/gpio/consumer.h>
9#include <linux/module.h>
10#include <linux/of.h>
11#include <linux/regulator/consumer.h>
12
13#include <video/mipi_display.h>
14
15#include <drm/drm_crtc.h>
16#include <drm/drm_device.h>
17#include <drm/drm_mipi_dsi.h>
18#include <drm/drm_modes.h>
19#include <drm/drm_panel.h>
20
21struct khadas_ts050_panel {
22 struct drm_panel base;
23 struct mipi_dsi_device *link;
24
25 struct regulator *supply;
26 struct gpio_desc *reset_gpio;
27 struct gpio_desc *enable_gpio;
28
29 bool prepared;
30 bool enabled;
31};
32
33struct khadas_ts050_panel_cmd {
34 u8 cmd;
35 u8 data;
36};
37
38/* Only the CMD1 User Command set is documented */
39static const struct khadas_ts050_panel_cmd init_code[] = {
40 /* Select Unknown CMD Page (Undocumented) */
41 {0xff, 0xee},
42 /* Reload CMD1: Don't reload default value to register */
43 {0xfb, 0x01},
44 {0x1f, 0x45},
45 {0x24, 0x4f},
46 {0x38, 0xc8},
47 {0x39, 0x27},
48 {0x1e, 0x77},
49 {0x1d, 0x0f},
50 {0x7e, 0x71},
51 {0x7c, 0x03},
52 {0xff, 0x00},
53 {0xfb, 0x01},
54 {0x35, 0x01},
55 /* Select CMD2 Page0 (Undocumented) */
56 {0xff, 0x01},
57 /* Reload CMD1: Don't reload default value to register */
58 {0xfb, 0x01},
59 {0x00, 0x01},
60 {0x01, 0x55},
61 {0x02, 0x40},
62 {0x05, 0x40},
63 {0x06, 0x4a},
64 {0x07, 0x24},
65 {0x08, 0x0c},
66 {0x0b, 0x7d},
67 {0x0c, 0x7d},
68 {0x0e, 0xb0},
69 {0x0f, 0xae},
70 {0x11, 0x10},
71 {0x12, 0x10},
72 {0x13, 0x03},
73 {0x14, 0x4a},
74 {0x15, 0x12},
75 {0x16, 0x12},
76 {0x18, 0x00},
77 {0x19, 0x77},
78 {0x1a, 0x55},
79 {0x1b, 0x13},
80 {0x1c, 0x00},
81 {0x1d, 0x00},
82 {0x1e, 0x13},
83 {0x1f, 0x00},
84 {0x23, 0x00},
85 {0x24, 0x00},
86 {0x25, 0x00},
87 {0x26, 0x00},
88 {0x27, 0x00},
89 {0x28, 0x00},
90 {0x35, 0x00},
91 {0x66, 0x00},
92 {0x58, 0x82},
93 {0x59, 0x02},
94 {0x5a, 0x02},
95 {0x5b, 0x02},
96 {0x5c, 0x82},
97 {0x5d, 0x82},
98 {0x5e, 0x02},
99 {0x5f, 0x02},
100 {0x72, 0x31},
101 /* Select CMD2 Page4 (Undocumented) */
102 {0xff, 0x05},
103 /* Reload CMD1: Don't reload default value to register */
104 {0xfb, 0x01},
105 {0x00, 0x01},
106 {0x01, 0x0b},
107 {0x02, 0x0c},
108 {0x03, 0x09},
109 {0x04, 0x0a},
110 {0x05, 0x00},
111 {0x06, 0x0f},
112 {0x07, 0x10},
113 {0x08, 0x00},
114 {0x09, 0x00},
115 {0x0a, 0x00},
116 {0x0b, 0x00},
117 {0x0c, 0x00},
118 {0x0d, 0x13},
119 {0x0e, 0x15},
120 {0x0f, 0x17},
121 {0x10, 0x01},
122 {0x11, 0x0b},
123 {0x12, 0x0c},
124 {0x13, 0x09},
125 {0x14, 0x0a},
126 {0x15, 0x00},
127 {0x16, 0x0f},
128 {0x17, 0x10},
129 {0x18, 0x00},
130 {0x19, 0x00},
131 {0x1a, 0x00},
132 {0x1b, 0x00},
133 {0x1c, 0x00},
134 {0x1d, 0x13},
135 {0x1e, 0x15},
136 {0x1f, 0x17},
137 {0x20, 0x00},
138 {0x21, 0x03},
139 {0x22, 0x01},
140 {0x23, 0x40},
141 {0x24, 0x40},
142 {0x25, 0xed},
143 {0x29, 0x58},
144 {0x2a, 0x12},
145 {0x2b, 0x01},
146 {0x4b, 0x06},
147 {0x4c, 0x11},
148 {0x4d, 0x20},
149 {0x4e, 0x02},
150 {0x4f, 0x02},
151 {0x50, 0x20},
152 {0x51, 0x61},
153 {0x52, 0x01},
154 {0x53, 0x63},
155 {0x54, 0x77},
156 {0x55, 0xed},
157 {0x5b, 0x00},
158 {0x5c, 0x00},
159 {0x5d, 0x00},
160 {0x5e, 0x00},
161 {0x5f, 0x15},
162 {0x60, 0x75},
163 {0x61, 0x00},
164 {0x62, 0x00},
165 {0x63, 0x00},
166 {0x64, 0x00},
167 {0x65, 0x00},
168 {0x66, 0x00},
169 {0x67, 0x00},
170 {0x68, 0x04},
171 {0x69, 0x00},
172 {0x6a, 0x00},
173 {0x6c, 0x40},
174 {0x75, 0x01},
175 {0x76, 0x01},
176 {0x7a, 0x80},
177 {0x7b, 0xa3},
178 {0x7c, 0xd8},
179 {0x7d, 0x60},
180 {0x7f, 0x15},
181 {0x80, 0x81},
182 {0x83, 0x05},
183 {0x93, 0x08},
184 {0x94, 0x10},
185 {0x8a, 0x00},
186 {0x9b, 0x0f},
187 {0xea, 0xff},
188 {0xec, 0x00},
189 /* Select CMD2 Page0 (Undocumented) */
190 {0xff, 0x01},
191 /* Reload CMD1: Don't reload default value to register */
192 {0xfb, 0x01},
193 {0x75, 0x00},
194 {0x76, 0xdf},
195 {0x77, 0x00},
196 {0x78, 0xe4},
197 {0x79, 0x00},
198 {0x7a, 0xed},
199 {0x7b, 0x00},
200 {0x7c, 0xf6},
201 {0x7d, 0x00},
202 {0x7e, 0xff},
203 {0x7f, 0x01},
204 {0x80, 0x07},
205 {0x81, 0x01},
206 {0x82, 0x10},
207 {0x83, 0x01},
208 {0x84, 0x18},
209 {0x85, 0x01},
210 {0x86, 0x20},
211 {0x87, 0x01},
212 {0x88, 0x3d},
213 {0x89, 0x01},
214 {0x8a, 0x56},
215 {0x8b, 0x01},
216 {0x8c, 0x84},
217 {0x8d, 0x01},
218 {0x8e, 0xab},
219 {0x8f, 0x01},
220 {0x90, 0xec},
221 {0x91, 0x02},
222 {0x92, 0x22},
223 {0x93, 0x02},
224 {0x94, 0x23},
225 {0x95, 0x02},
226 {0x96, 0x55},
227 {0x97, 0x02},
228 {0x98, 0x8b},
229 {0x99, 0x02},
230 {0x9a, 0xaf},
231 {0x9b, 0x02},
232 {0x9c, 0xdf},
233 {0x9d, 0x03},
234 {0x9e, 0x01},
235 {0x9f, 0x03},
236 {0xa0, 0x2c},
237 {0xa2, 0x03},
238 {0xa3, 0x39},
239 {0xa4, 0x03},
240 {0xa5, 0x47},
241 {0xa6, 0x03},
242 {0xa7, 0x56},
243 {0xa9, 0x03},
244 {0xaa, 0x66},
245 {0xab, 0x03},
246 {0xac, 0x76},
247 {0xad, 0x03},
248 {0xae, 0x85},
249 {0xaf, 0x03},
250 {0xb0, 0x90},
251 {0xb1, 0x03},
252 {0xb2, 0xcb},
253 {0xb3, 0x00},
254 {0xb4, 0xdf},
255 {0xb5, 0x00},
256 {0xb6, 0xe4},
257 {0xb7, 0x00},
258 {0xb8, 0xed},
259 {0xb9, 0x00},
260 {0xba, 0xf6},
261 {0xbb, 0x00},
262 {0xbc, 0xff},
263 {0xbd, 0x01},
264 {0xbe, 0x07},
265 {0xbf, 0x01},
266 {0xc0, 0x10},
267 {0xc1, 0x01},
268 {0xc2, 0x18},
269 {0xc3, 0x01},
270 {0xc4, 0x20},
271 {0xc5, 0x01},
272 {0xc6, 0x3d},
273 {0xc7, 0x01},
274 {0xc8, 0x56},
275 {0xc9, 0x01},
276 {0xca, 0x84},
277 {0xcb, 0x01},
278 {0xcc, 0xab},
279 {0xcd, 0x01},
280 {0xce, 0xec},
281 {0xcf, 0x02},
282 {0xd0, 0x22},
283 {0xd1, 0x02},
284 {0xd2, 0x23},
285 {0xd3, 0x02},
286 {0xd4, 0x55},
287 {0xd5, 0x02},
288 {0xd6, 0x8b},
289 {0xd7, 0x02},
290 {0xd8, 0xaf},
291 {0xd9, 0x02},
292 {0xda, 0xdf},
293 {0xdb, 0x03},
294 {0xdc, 0x01},
295 {0xdd, 0x03},
296 {0xde, 0x2c},
297 {0xdf, 0x03},
298 {0xe0, 0x39},
299 {0xe1, 0x03},
300 {0xe2, 0x47},
301 {0xe3, 0x03},
302 {0xe4, 0x56},
303 {0xe5, 0x03},
304 {0xe6, 0x66},
305 {0xe7, 0x03},
306 {0xe8, 0x76},
307 {0xe9, 0x03},
308 {0xea, 0x85},
309 {0xeb, 0x03},
310 {0xec, 0x90},
311 {0xed, 0x03},
312 {0xee, 0xcb},
313 {0xef, 0x00},
314 {0xf0, 0xbb},
315 {0xf1, 0x00},
316 {0xf2, 0xc0},
317 {0xf3, 0x00},
318 {0xf4, 0xcc},
319 {0xf5, 0x00},
320 {0xf6, 0xd6},
321 {0xf7, 0x00},
322 {0xf8, 0xe1},
323 {0xf9, 0x00},
324 {0xfa, 0xea},
325 /* Select CMD2 Page2 (Undocumented) */
326 {0xff, 0x02},
327 /* Reload CMD1: Don't reload default value to register */
328 {0xfb, 0x01},
329 {0x00, 0x00},
330 {0x01, 0xf4},
331 {0x02, 0x00},
332 {0x03, 0xef},
333 {0x04, 0x01},
334 {0x05, 0x07},
335 {0x06, 0x01},
336 {0x07, 0x28},
337 {0x08, 0x01},
338 {0x09, 0x44},
339 {0x0a, 0x01},
340 {0x0b, 0x76},
341 {0x0c, 0x01},
342 {0x0d, 0xa0},
343 {0x0e, 0x01},
344 {0x0f, 0xe7},
345 {0x10, 0x02},
346 {0x11, 0x1f},
347 {0x12, 0x02},
348 {0x13, 0x22},
349 {0x14, 0x02},
350 {0x15, 0x54},
351 {0x16, 0x02},
352 {0x17, 0x8b},
353 {0x18, 0x02},
354 {0x19, 0xaf},
355 {0x1a, 0x02},
356 {0x1b, 0xe0},
357 {0x1c, 0x03},
358 {0x1d, 0x01},
359 {0x1e, 0x03},
360 {0x1f, 0x2d},
361 {0x20, 0x03},
362 {0x21, 0x39},
363 {0x22, 0x03},
364 {0x23, 0x47},
365 {0x24, 0x03},
366 {0x25, 0x57},
367 {0x26, 0x03},
368 {0x27, 0x65},
369 {0x28, 0x03},
370 {0x29, 0x77},
371 {0x2a, 0x03},
372 {0x2b, 0x85},
373 {0x2d, 0x03},
374 {0x2f, 0x8f},
375 {0x30, 0x03},
376 {0x31, 0xcb},
377 {0x32, 0x00},
378 {0x33, 0xbb},
379 {0x34, 0x00},
380 {0x35, 0xc0},
381 {0x36, 0x00},
382 {0x37, 0xcc},
383 {0x38, 0x00},
384 {0x39, 0xd6},
385 {0x3a, 0x00},
386 {0x3b, 0xe1},
387 {0x3d, 0x00},
388 {0x3f, 0xea},
389 {0x40, 0x00},
390 {0x41, 0xf4},
391 {0x42, 0x00},
392 {0x43, 0xfe},
393 {0x44, 0x01},
394 {0x45, 0x07},
395 {0x46, 0x01},
396 {0x47, 0x28},
397 {0x48, 0x01},
398 {0x49, 0x44},
399 {0x4a, 0x01},
400 {0x4b, 0x76},
401 {0x4c, 0x01},
402 {0x4d, 0xa0},
403 {0x4e, 0x01},
404 {0x4f, 0xe7},
405 {0x50, 0x02},
406 {0x51, 0x1f},
407 {0x52, 0x02},
408 {0x53, 0x22},
409 {0x54, 0x02},
410 {0x55, 0x54},
411 {0x56, 0x02},
412 {0x58, 0x8b},
413 {0x59, 0x02},
414 {0x5a, 0xaf},
415 {0x5b, 0x02},
416 {0x5c, 0xe0},
417 {0x5d, 0x03},
418 {0x5e, 0x01},
419 {0x5f, 0x03},
420 {0x60, 0x2d},
421 {0x61, 0x03},
422 {0x62, 0x39},
423 {0x63, 0x03},
424 {0x64, 0x47},
425 {0x65, 0x03},
426 {0x66, 0x57},
427 {0x67, 0x03},
428 {0x68, 0x65},
429 {0x69, 0x03},
430 {0x6a, 0x77},
431 {0x6b, 0x03},
432 {0x6c, 0x85},
433 {0x6d, 0x03},
434 {0x6e, 0x8f},
435 {0x6f, 0x03},
436 {0x70, 0xcb},
437 {0x71, 0x00},
438 {0x72, 0x00},
439 {0x73, 0x00},
440 {0x74, 0x21},
441 {0x75, 0x00},
442 {0x76, 0x4c},
443 {0x77, 0x00},
444 {0x78, 0x6b},
445 {0x79, 0x00},
446 {0x7a, 0x85},
447 {0x7b, 0x00},
448 {0x7c, 0x9a},
449 {0x7d, 0x00},
450 {0x7e, 0xad},
451 {0x7f, 0x00},
452 {0x80, 0xbe},
453 {0x81, 0x00},
454 {0x82, 0xcd},
455 {0x83, 0x01},
456 {0x84, 0x01},
457 {0x85, 0x01},
458 {0x86, 0x29},
459 {0x87, 0x01},
460 {0x88, 0x68},
461 {0x89, 0x01},
462 {0x8a, 0x98},
463 {0x8b, 0x01},
464 {0x8c, 0xe5},
465 {0x8d, 0x02},
466 {0x8e, 0x1e},
467 {0x8f, 0x02},
468 {0x90, 0x30},
469 {0x91, 0x02},
470 {0x92, 0x52},
471 {0x93, 0x02},
472 {0x94, 0x88},
473 {0x95, 0x02},
474 {0x96, 0xaa},
475 {0x97, 0x02},
476 {0x98, 0xd7},
477 {0x99, 0x02},
478 {0x9a, 0xf7},
479 {0x9b, 0x03},
480 {0x9c, 0x21},
481 {0x9d, 0x03},
482 {0x9e, 0x2e},
483 {0x9f, 0x03},
484 {0xa0, 0x3d},
485 {0xa2, 0x03},
486 {0xa3, 0x4c},
487 {0xa4, 0x03},
488 {0xa5, 0x5e},
489 {0xa6, 0x03},
490 {0xa7, 0x71},
491 {0xa9, 0x03},
492 {0xaa, 0x86},
493 {0xab, 0x03},
494 {0xac, 0x94},
495 {0xad, 0x03},
496 {0xae, 0xfa},
497 {0xaf, 0x00},
498 {0xb0, 0x00},
499 {0xb1, 0x00},
500 {0xb2, 0x21},
501 {0xb3, 0x00},
502 {0xb4, 0x4c},
503 {0xb5, 0x00},
504 {0xb6, 0x6b},
505 {0xb7, 0x00},
506 {0xb8, 0x85},
507 {0xb9, 0x00},
508 {0xba, 0x9a},
509 {0xbb, 0x00},
510 {0xbc, 0xad},
511 {0xbd, 0x00},
512 {0xbe, 0xbe},
513 {0xbf, 0x00},
514 {0xc0, 0xcd},
515 {0xc1, 0x01},
516 {0xc2, 0x01},
517 {0xc3, 0x01},
518 {0xc4, 0x29},
519 {0xc5, 0x01},
520 {0xc6, 0x68},
521 {0xc7, 0x01},
522 {0xc8, 0x98},
523 {0xc9, 0x01},
524 {0xca, 0xe5},
525 {0xcb, 0x02},
526 {0xcc, 0x1e},
527 {0xcd, 0x02},
528 {0xce, 0x20},
529 {0xcf, 0x02},
530 {0xd0, 0x52},
531 {0xd1, 0x02},
532 {0xd2, 0x88},
533 {0xd3, 0x02},
534 {0xd4, 0xaa},
535 {0xd5, 0x02},
536 {0xd6, 0xd7},
537 {0xd7, 0x02},
538 {0xd8, 0xf7},
539 {0xd9, 0x03},
540 {0xda, 0x21},
541 {0xdb, 0x03},
542 {0xdc, 0x2e},
543 {0xdd, 0x03},
544 {0xde, 0x3d},
545 {0xdf, 0x03},
546 {0xe0, 0x4c},
547 {0xe1, 0x03},
548 {0xe2, 0x5e},
549 {0xe3, 0x03},
550 {0xe4, 0x71},
551 {0xe5, 0x03},
552 {0xe6, 0x86},
553 {0xe7, 0x03},
554 {0xe8, 0x94},
555 {0xe9, 0x03},
556 {0xea, 0xfa},
557 /* Select CMD2 Page0 (Undocumented) */
558 {0xff, 0x01},
559 /* Reload CMD1: Don't reload default value to register */
560 {0xfb, 0x01},
561 /* Select CMD2 Page1 (Undocumented) */
562 {0xff, 0x02},
563 /* Reload CMD1: Don't reload default value to register */
564 {0xfb, 0x01},
565 /* Select CMD2 Page3 (Undocumented) */
566 {0xff, 0x04},
567 /* Reload CMD1: Don't reload default value to register */
568 {0xfb, 0x01},
569 /* Select CMD1 */
570 {0xff, 0x00},
571 {0xd3, 0x22}, /* RGBMIPICTRL: VSYNC back porch = 34 */
572 {0xd4, 0x04}, /* RGBMIPICTRL: VSYNC front porch = 4 */
573};
574
575static inline
576struct khadas_ts050_panel *to_khadas_ts050_panel(struct drm_panel *panel)
577{
578 return container_of(panel, struct khadas_ts050_panel, base);
579}
580
581static int khadas_ts050_panel_prepare(struct drm_panel *panel)
582{
583 struct khadas_ts050_panel *khadas_ts050 = to_khadas_ts050_panel(panel);
584 unsigned int i;
585 int err;
586
587 if (khadas_ts050->prepared)
588 return 0;
589
590 gpiod_set_value_cansleep(desc: khadas_ts050->enable_gpio, value: 0);
591
592 err = regulator_enable(regulator: khadas_ts050->supply);
593 if (err < 0)
594 return err;
595
596 gpiod_set_value_cansleep(desc: khadas_ts050->enable_gpio, value: 1);
597
598 msleep(msecs: 60);
599
600 gpiod_set_value_cansleep(desc: khadas_ts050->reset_gpio, value: 1);
601
602 usleep_range(min: 10000, max: 11000);
603
604 gpiod_set_value_cansleep(desc: khadas_ts050->reset_gpio, value: 0);
605
606 /* Select CMD2 page 4 (Undocumented) */
607 mipi_dsi_dcs_write(dsi: khadas_ts050->link, cmd: 0xff, data: (u8[]){ 0x05 }, len: 1);
608
609 /* Reload CMD1: Don't reload default value to register */
610 mipi_dsi_dcs_write(dsi: khadas_ts050->link, cmd: 0xfb, data: (u8[]){ 0x01 }, len: 1);
611
612 mipi_dsi_dcs_write(dsi: khadas_ts050->link, cmd: 0xc5, data: (u8[]){ 0x01 }, len: 1);
613
614 msleep(msecs: 100);
615
616 for (i = 0; i < ARRAY_SIZE(init_code); i++) {
617 err = mipi_dsi_dcs_write(dsi: khadas_ts050->link,
618 cmd: init_code[i].cmd,
619 data: &init_code[i].data, len: 1);
620 if (err < 0) {
621 dev_err(panel->dev, "failed write cmds: %d\n", err);
622 goto poweroff;
623 }
624 }
625
626 err = mipi_dsi_dcs_exit_sleep_mode(dsi: khadas_ts050->link);
627 if (err < 0) {
628 dev_err(panel->dev, "failed to exit sleep mode: %d\n", err);
629 goto poweroff;
630 }
631
632 msleep(msecs: 120);
633
634 /* Select CMD1 */
635 mipi_dsi_dcs_write(dsi: khadas_ts050->link, cmd: 0xff, data: (u8[]){ 0x00 }, len: 1);
636
637 err = mipi_dsi_dcs_set_tear_on(khadas_ts050->link,
638 MIPI_DSI_DCS_TEAR_MODE_VBLANK);
639 if (err < 0) {
640 dev_err(panel->dev, "failed to set tear on: %d\n", err);
641 goto poweroff;
642 }
643
644 err = mipi_dsi_dcs_set_display_on(khadas_ts050->link);
645 if (err < 0) {
646 dev_err(panel->dev, "failed to set display on: %d\n", err);
647 goto poweroff;
648 }
649
650 usleep_range(10000, 11000);
651
652 khadas_ts050->prepared = true;
653
654 return 0;
655
656poweroff:
657 gpiod_set_value_cansleep(khadas_ts050->enable_gpio, 0);
658 gpiod_set_value_cansleep(khadas_ts050->reset_gpio, 1);
659
660 regulator_disable(khadas_ts050->supply);
661
662 return err;
663}
664
665static int khadas_ts050_panel_unprepare(struct drm_panel *panel)
666{
667 struct khadas_ts050_panel *khadas_ts050 = to_khadas_ts050_panel(panel);
668 int err;
669
670 if (!khadas_ts050->prepared)
671 return 0;
672
673 khadas_ts050->prepared = false;
674
675 err = mipi_dsi_dcs_enter_sleep_mode(dsi: khadas_ts050->link);
676 if (err < 0)
677 dev_err(panel->dev, "failed to enter sleep mode: %d\n", err);
678
679 msleep(msecs: 150);
680
681 gpiod_set_value_cansleep(desc: khadas_ts050->enable_gpio, value: 0);
682 gpiod_set_value_cansleep(desc: khadas_ts050->reset_gpio, value: 1);
683
684 err = regulator_disable(regulator: khadas_ts050->supply);
685 if (err < 0)
686 return err;
687
688 return 0;
689}
690
691static int khadas_ts050_panel_enable(struct drm_panel *panel)
692{
693 struct khadas_ts050_panel *khadas_ts050 = to_khadas_ts050_panel(panel);
694
695 khadas_ts050->enabled = true;
696
697 return 0;
698}
699
700static int khadas_ts050_panel_disable(struct drm_panel *panel)
701{
702 struct khadas_ts050_panel *khadas_ts050 = to_khadas_ts050_panel(panel);
703 int err;
704
705 if (!khadas_ts050->enabled)
706 return 0;
707
708 err = mipi_dsi_dcs_set_display_off(dsi: khadas_ts050->link);
709 if (err < 0)
710 dev_err(panel->dev, "failed to set display off: %d\n", err);
711
712 usleep_range(min: 10000, max: 11000);
713
714 khadas_ts050->enabled = false;
715
716 return 0;
717}
718
719static const struct drm_display_mode default_mode = {
720 .clock = 160000,
721 .hdisplay = 1080,
722 .hsync_start = 1080 + 117,
723 .hsync_end = 1080 + 117 + 5,
724 .htotal = 1080 + 117 + 5 + 160,
725 .vdisplay = 1920,
726 .vsync_start = 1920 + 4,
727 .vsync_end = 1920 + 4 + 3,
728 .vtotal = 1920 + 4 + 3 + 31,
729 .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
730};
731
732static int khadas_ts050_panel_get_modes(struct drm_panel *panel,
733 struct drm_connector *connector)
734{
735 struct drm_display_mode *mode;
736
737 mode = drm_mode_duplicate(dev: connector->dev, mode: &default_mode);
738 if (!mode) {
739 dev_err(panel->dev, "failed to add mode %ux%u@%u\n",
740 default_mode.hdisplay, default_mode.vdisplay,
741 drm_mode_vrefresh(&default_mode));
742 return -ENOMEM;
743 }
744
745 drm_mode_set_name(mode);
746
747 drm_mode_probed_add(connector, mode);
748
749 connector->display_info.width_mm = 64;
750 connector->display_info.height_mm = 118;
751 connector->display_info.bpc = 8;
752
753 return 1;
754}
755
756static const struct drm_panel_funcs khadas_ts050_panel_funcs = {
757 .prepare = khadas_ts050_panel_prepare,
758 .unprepare = khadas_ts050_panel_unprepare,
759 .enable = khadas_ts050_panel_enable,
760 .disable = khadas_ts050_panel_disable,
761 .get_modes = khadas_ts050_panel_get_modes,
762};
763
764static const struct of_device_id khadas_ts050_of_match[] = {
765 { .compatible = "khadas,ts050", },
766 { /* sentinel */ }
767};
768MODULE_DEVICE_TABLE(of, khadas_ts050_of_match);
769
770static int khadas_ts050_panel_add(struct khadas_ts050_panel *khadas_ts050)
771{
772 struct device *dev = &khadas_ts050->link->dev;
773 int err;
774
775 khadas_ts050->supply = devm_regulator_get(dev, id: "power");
776 if (IS_ERR(ptr: khadas_ts050->supply))
777 return dev_err_probe(dev, err: PTR_ERR(ptr: khadas_ts050->supply),
778 fmt: "failed to get power supply");
779
780 khadas_ts050->reset_gpio = devm_gpiod_get(dev, con_id: "reset",
781 flags: GPIOD_OUT_LOW);
782 if (IS_ERR(ptr: khadas_ts050->reset_gpio))
783 return dev_err_probe(dev, err: PTR_ERR(ptr: khadas_ts050->reset_gpio),
784 fmt: "failed to get reset gpio");
785
786 khadas_ts050->enable_gpio = devm_gpiod_get(dev, con_id: "enable",
787 flags: GPIOD_OUT_HIGH);
788 if (IS_ERR(ptr: khadas_ts050->enable_gpio))
789 return dev_err_probe(dev, err: PTR_ERR(ptr: khadas_ts050->enable_gpio),
790 fmt: "failed to get enable gpio");
791
792 drm_panel_init(panel: &khadas_ts050->base, dev: &khadas_ts050->link->dev,
793 funcs: &khadas_ts050_panel_funcs, DRM_MODE_CONNECTOR_DSI);
794
795 err = drm_panel_of_backlight(panel: &khadas_ts050->base);
796 if (err)
797 return err;
798
799 drm_panel_add(panel: &khadas_ts050->base);
800
801 return 0;
802}
803
804static int khadas_ts050_panel_probe(struct mipi_dsi_device *dsi)
805{
806 struct khadas_ts050_panel *khadas_ts050;
807 int err;
808
809 dsi->lanes = 4;
810 dsi->format = MIPI_DSI_FMT_RGB888;
811 dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
812 MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_NO_EOT_PACKET;
813
814 khadas_ts050 = devm_kzalloc(dev: &dsi->dev, size: sizeof(*khadas_ts050),
815 GFP_KERNEL);
816 if (!khadas_ts050)
817 return -ENOMEM;
818
819 mipi_dsi_set_drvdata(dsi, data: khadas_ts050);
820 khadas_ts050->link = dsi;
821
822 err = khadas_ts050_panel_add(khadas_ts050);
823 if (err < 0)
824 return err;
825
826 err = mipi_dsi_attach(dsi);
827 if (err)
828 drm_panel_remove(panel: &khadas_ts050->base);
829
830 return err;
831}
832
833static void khadas_ts050_panel_remove(struct mipi_dsi_device *dsi)
834{
835 struct khadas_ts050_panel *khadas_ts050 = mipi_dsi_get_drvdata(dsi);
836 int err;
837
838 err = mipi_dsi_detach(dsi);
839 if (err < 0)
840 dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", err);
841
842 drm_panel_remove(panel: &khadas_ts050->base);
843 drm_panel_disable(panel: &khadas_ts050->base);
844 drm_panel_unprepare(panel: &khadas_ts050->base);
845}
846
847static void khadas_ts050_panel_shutdown(struct mipi_dsi_device *dsi)
848{
849 struct khadas_ts050_panel *khadas_ts050 = mipi_dsi_get_drvdata(dsi);
850
851 drm_panel_disable(panel: &khadas_ts050->base);
852 drm_panel_unprepare(panel: &khadas_ts050->base);
853}
854
855static struct mipi_dsi_driver khadas_ts050_panel_driver = {
856 .driver = {
857 .name = "panel-khadas-ts050",
858 .of_match_table = khadas_ts050_of_match,
859 },
860 .probe = khadas_ts050_panel_probe,
861 .remove = khadas_ts050_panel_remove,
862 .shutdown = khadas_ts050_panel_shutdown,
863};
864module_mipi_dsi_driver(khadas_ts050_panel_driver);
865
866MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
867MODULE_DESCRIPTION("Khadas TS050 panel driver");
868MODULE_LICENSE("GPL v2");
869

source code of linux/drivers/gpu/drm/panel/panel-khadas-ts050.c