Merge tag 'sound-5.13-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai...
[linux-2.6-microblaze.git] / drivers / gpu / drm / panel / panel-khadas-ts050.c
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
21 struct 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
33 struct khadas_ts050_panel_cmd {
34         u8 cmd;
35         u8 data;
36 };
37
38 /* Only the CMD1 User Command set is documented */
39 static 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, 0x05}, /* RGBMIPICTRL: VSYNC back porch = 5 */
572         {0xd4, 0x04}, /* RGBMIPICTRL: VSYNC front porch = 4 */
573 };
574
575 static inline
576 struct khadas_ts050_panel *to_khadas_ts050_panel(struct drm_panel *panel)
577 {
578         return container_of(panel, struct khadas_ts050_panel, base);
579 }
580
581 static 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(khadas_ts050->enable_gpio, 0);
591
592         err = regulator_enable(khadas_ts050->supply);
593         if (err < 0)
594                 return err;
595
596         gpiod_set_value_cansleep(khadas_ts050->enable_gpio, 1);
597
598         msleep(60);
599
600         gpiod_set_value_cansleep(khadas_ts050->reset_gpio, 1);
601
602         usleep_range(10000, 11000);
603
604         gpiod_set_value_cansleep(khadas_ts050->reset_gpio, 0);
605
606         /* Select CMD2 page 4 (Undocumented) */
607         mipi_dsi_dcs_write(khadas_ts050->link, 0xff, (u8[]){ 0x05 }, 1);
608
609         /* Reload CMD1: Don't reload default value to register */
610         mipi_dsi_dcs_write(khadas_ts050->link, 0xfb, (u8[]){ 0x01 }, 1);
611
612         mipi_dsi_dcs_write(khadas_ts050->link, 0xc5, (u8[]){ 0x01 }, 1);
613
614         msleep(100);
615
616         for (i = 0; i < ARRAY_SIZE(init_code); i++) {
617                 err = mipi_dsi_dcs_write(khadas_ts050->link,
618                                          init_code[i].cmd,
619                                          &init_code[i].data, 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(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(120);
633
634         /* Select CMD1 */
635         mipi_dsi_dcs_write(khadas_ts050->link, 0xff, (u8[]){ 0x00 }, 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
656 poweroff:
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
665 static 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(khadas_ts050->link);
676         if (err < 0)
677                 dev_err(panel->dev, "failed to enter sleep mode: %d\n", err);
678
679         msleep(150);
680
681         gpiod_set_value_cansleep(khadas_ts050->enable_gpio, 0);
682         gpiod_set_value_cansleep(khadas_ts050->reset_gpio, 1);
683
684         err = regulator_disable(khadas_ts050->supply);
685         if (err < 0)
686                 return err;
687
688         return 0;
689 }
690
691 static 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
700 static 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(khadas_ts050->link);
709         if (err < 0)
710                 dev_err(panel->dev, "failed to set display off: %d\n", err);
711
712         usleep_range(10000, 11000);
713
714         khadas_ts050->enabled = false;
715
716         return 0;
717 }
718
719 static const struct drm_display_mode default_mode = {
720         .clock = 120000,
721         .hdisplay = 1088,
722         .hsync_start = 1088 + 104,
723         .hsync_end = 1088 + 104 + 4,
724         .htotal = 1088 + 104 + 4 + 127,
725         .vdisplay = 1920,
726         .vsync_start = 1920 + 4,
727         .vsync_end = 1920 + 4 + 2,
728         .vtotal = 1920 + 4 + 2 + 3,
729         .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
730 };
731
732 static 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(connector->dev, &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
756 static 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
764 static const struct of_device_id khadas_ts050_of_match[] = {
765         { .compatible = "khadas,ts050", },
766         { /* sentinel */ }
767 };
768 MODULE_DEVICE_TABLE(of, khadas_ts050_of_match);
769
770 static 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, "power");
776         if (IS_ERR(khadas_ts050->supply))
777                 return dev_err_probe(dev, PTR_ERR(khadas_ts050->supply),
778                                      "failed to get power supply");
779
780         khadas_ts050->reset_gpio = devm_gpiod_get(dev, "reset",
781                                                   GPIOD_OUT_LOW);
782         if (IS_ERR(khadas_ts050->reset_gpio))
783                 return dev_err_probe(dev, PTR_ERR(khadas_ts050->reset_gpio),
784                                      "failed to get reset gpio");
785
786         khadas_ts050->enable_gpio = devm_gpiod_get(dev, "enable",
787                                                    GPIOD_OUT_HIGH);
788         if (IS_ERR(khadas_ts050->enable_gpio))
789                 return dev_err_probe(dev, PTR_ERR(khadas_ts050->enable_gpio),
790                                      "failed to get enable gpio");
791
792         drm_panel_init(&khadas_ts050->base, &khadas_ts050->link->dev,
793                        &khadas_ts050_panel_funcs, DRM_MODE_CONNECTOR_DSI);
794
795         err = drm_panel_of_backlight(&khadas_ts050->base);
796         if (err)
797                 return err;
798
799         drm_panel_add(&khadas_ts050->base);
800
801         return 0;
802 }
803
804 static 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_EOT_PACKET;
813
814         khadas_ts050 = devm_kzalloc(&dsi->dev, sizeof(*khadas_ts050),
815                                     GFP_KERNEL);
816         if (!khadas_ts050)
817                 return -ENOMEM;
818
819         mipi_dsi_set_drvdata(dsi, 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(&khadas_ts050->base);
829
830         return err;
831 }
832
833 static int 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(&khadas_ts050->base);
843         drm_panel_disable(&khadas_ts050->base);
844         drm_panel_unprepare(&khadas_ts050->base);
845
846         return 0;
847 }
848
849 static void khadas_ts050_panel_shutdown(struct mipi_dsi_device *dsi)
850 {
851         struct khadas_ts050_panel *khadas_ts050 = mipi_dsi_get_drvdata(dsi);
852
853         drm_panel_disable(&khadas_ts050->base);
854         drm_panel_unprepare(&khadas_ts050->base);
855 }
856
857 static struct mipi_dsi_driver khadas_ts050_panel_driver = {
858         .driver = {
859                 .name = "panel-khadas-ts050",
860                 .of_match_table = khadas_ts050_of_match,
861         },
862         .probe = khadas_ts050_panel_probe,
863         .remove = khadas_ts050_panel_remove,
864         .shutdown = khadas_ts050_panel_shutdown,
865 };
866 module_mipi_dsi_driver(khadas_ts050_panel_driver);
867
868 MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
869 MODULE_DESCRIPTION("Khadas TS050 panel driver");
870 MODULE_LICENSE("GPL v2");