]> Git Repo - J-linux.git/blob - drivers/gpu/drm/panel/panel-leadtek-ltk050h3146w.c
Merge tag 'vfs-6.13-rc7.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
[J-linux.git] / drivers / gpu / drm / panel / panel-leadtek-ltk050h3146w.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2020 Theobroma Systems Design und Consulting GmbH
4  */
5
6 #include <linux/delay.h>
7 #include <linux/gpio/consumer.h>
8 #include <linux/media-bus-format.h>
9 #include <linux/module.h>
10 #include <linux/of.h>
11 #include <linux/regulator/consumer.h>
12
13 #include <video/display_timing.h>
14 #include <video/mipi_display.h>
15
16 #include <drm/drm_mipi_dsi.h>
17 #include <drm/drm_modes.h>
18 #include <drm/drm_panel.h>
19
20 struct ltk050h3146w_cmd {
21         char cmd;
22         char data;
23 };
24
25 struct ltk050h3146w;
26 struct ltk050h3146w_desc {
27         const unsigned long mode_flags;
28         const struct drm_display_mode *mode;
29         void (*init)(struct mipi_dsi_multi_context *dsi_ctx);
30 };
31
32 struct ltk050h3146w {
33         struct device *dev;
34         struct drm_panel panel;
35         struct gpio_desc *reset_gpio;
36         struct regulator *vci;
37         struct regulator *iovcc;
38         const struct ltk050h3146w_desc *panel_desc;
39 };
40
41 static const struct ltk050h3146w_cmd page1_cmds[] = {
42         { 0x22, 0x0A }, /* BGR SS GS */
43         { 0x31, 0x00 }, /* column inversion */
44         { 0x53, 0xA2 }, /* VCOM1 */
45         { 0x55, 0xA2 }, /* VCOM2 */
46         { 0x50, 0x81 }, /* VREG1OUT=5V */
47         { 0x51, 0x85 }, /* VREG2OUT=-5V */
48         { 0x62, 0x0D }, /* EQT Time setting */
49 /*
50  * The vendor init selected page 1 here _again_
51  * Is this supposed to be page 2?
52  */
53         { 0xA0, 0x00 },
54         { 0xA1, 0x1A },
55         { 0xA2, 0x28 },
56         { 0xA3, 0x13 },
57         { 0xA4, 0x16 },
58         { 0xA5, 0x29 },
59         { 0xA6, 0x1D },
60         { 0xA7, 0x1E },
61         { 0xA8, 0x84 },
62         { 0xA9, 0x1C },
63         { 0xAA, 0x28 },
64         { 0xAB, 0x75 },
65         { 0xAC, 0x1A },
66         { 0xAD, 0x19 },
67         { 0xAE, 0x4D },
68         { 0xAF, 0x22 },
69         { 0xB0, 0x28 },
70         { 0xB1, 0x54 },
71         { 0xB2, 0x66 },
72         { 0xB3, 0x39 },
73         { 0xC0, 0x00 },
74         { 0xC1, 0x1A },
75         { 0xC2, 0x28 },
76         { 0xC3, 0x13 },
77         { 0xC4, 0x16 },
78         { 0xC5, 0x29 },
79         { 0xC6, 0x1D },
80         { 0xC7, 0x1E },
81         { 0xC8, 0x84 },
82         { 0xC9, 0x1C },
83         { 0xCA, 0x28 },
84         { 0xCB, 0x75 },
85         { 0xCC, 0x1A },
86         { 0xCD, 0x19 },
87         { 0xCE, 0x4D },
88         { 0xCF, 0x22 },
89         { 0xD0, 0x28 },
90         { 0xD1, 0x54 },
91         { 0xD2, 0x66 },
92         { 0xD3, 0x39 },
93 };
94
95 static const struct ltk050h3146w_cmd page3_cmds[] = {
96         { 0x01, 0x00 },
97         { 0x02, 0x00 },
98         { 0x03, 0x73 },
99         { 0x04, 0x00 },
100         { 0x05, 0x00 },
101         { 0x06, 0x0a },
102         { 0x07, 0x00 },
103         { 0x08, 0x00 },
104         { 0x09, 0x01 },
105         { 0x0a, 0x00 },
106         { 0x0b, 0x00 },
107         { 0x0c, 0x01 },
108         { 0x0d, 0x00 },
109         { 0x0e, 0x00 },
110         { 0x0f, 0x1d },
111         { 0x10, 0x1d },
112         { 0x11, 0x00 },
113         { 0x12, 0x00 },
114         { 0x13, 0x00 },
115         { 0x14, 0x00 },
116         { 0x15, 0x00 },
117         { 0x16, 0x00 },
118         { 0x17, 0x00 },
119         { 0x18, 0x00 },
120         { 0x19, 0x00 },
121         { 0x1a, 0x00 },
122         { 0x1b, 0x00 },
123         { 0x1c, 0x00 },
124         { 0x1d, 0x00 },
125         { 0x1e, 0x40 },
126         { 0x1f, 0x80 },
127         { 0x20, 0x06 },
128         { 0x21, 0x02 },
129         { 0x22, 0x00 },
130         { 0x23, 0x00 },
131         { 0x24, 0x00 },
132         { 0x25, 0x00 },
133         { 0x26, 0x00 },
134         { 0x27, 0x00 },
135         { 0x28, 0x33 },
136         { 0x29, 0x03 },
137         { 0x2a, 0x00 },
138         { 0x2b, 0x00 },
139         { 0x2c, 0x00 },
140         { 0x2d, 0x00 },
141         { 0x2e, 0x00 },
142         { 0x2f, 0x00 },
143         { 0x30, 0x00 },
144         { 0x31, 0x00 },
145         { 0x32, 0x00 },
146         { 0x33, 0x00 },
147         { 0x34, 0x04 },
148         { 0x35, 0x00 },
149         { 0x36, 0x00 },
150         { 0x37, 0x00 },
151         { 0x38, 0x3C },
152         { 0x39, 0x35 },
153         { 0x3A, 0x01 },
154         { 0x3B, 0x40 },
155         { 0x3C, 0x00 },
156         { 0x3D, 0x01 },
157         { 0x3E, 0x00 },
158         { 0x3F, 0x00 },
159         { 0x40, 0x00 },
160         { 0x41, 0x88 },
161         { 0x42, 0x00 },
162         { 0x43, 0x00 },
163         { 0x44, 0x1F },
164         { 0x50, 0x01 },
165         { 0x51, 0x23 },
166         { 0x52, 0x45 },
167         { 0x53, 0x67 },
168         { 0x54, 0x89 },
169         { 0x55, 0xab },
170         { 0x56, 0x01 },
171         { 0x57, 0x23 },
172         { 0x58, 0x45 },
173         { 0x59, 0x67 },
174         { 0x5a, 0x89 },
175         { 0x5b, 0xab },
176         { 0x5c, 0xcd },
177         { 0x5d, 0xef },
178         { 0x5e, 0x11 },
179         { 0x5f, 0x01 },
180         { 0x60, 0x00 },
181         { 0x61, 0x15 },
182         { 0x62, 0x14 },
183         { 0x63, 0x0E },
184         { 0x64, 0x0F },
185         { 0x65, 0x0C },
186         { 0x66, 0x0D },
187         { 0x67, 0x06 },
188         { 0x68, 0x02 },
189         { 0x69, 0x07 },
190         { 0x6a, 0x02 },
191         { 0x6b, 0x02 },
192         { 0x6c, 0x02 },
193         { 0x6d, 0x02 },
194         { 0x6e, 0x02 },
195         { 0x6f, 0x02 },
196         { 0x70, 0x02 },
197         { 0x71, 0x02 },
198         { 0x72, 0x02 },
199         { 0x73, 0x02 },
200         { 0x74, 0x02 },
201         { 0x75, 0x01 },
202         { 0x76, 0x00 },
203         { 0x77, 0x14 },
204         { 0x78, 0x15 },
205         { 0x79, 0x0E },
206         { 0x7a, 0x0F },
207         { 0x7b, 0x0C },
208         { 0x7c, 0x0D },
209         { 0x7d, 0x06 },
210         { 0x7e, 0x02 },
211         { 0x7f, 0x07 },
212         { 0x80, 0x02 },
213         { 0x81, 0x02 },
214         { 0x82, 0x02 },
215         { 0x83, 0x02 },
216         { 0x84, 0x02 },
217         { 0x85, 0x02 },
218         { 0x86, 0x02 },
219         { 0x87, 0x02 },
220         { 0x88, 0x02 },
221         { 0x89, 0x02 },
222         { 0x8A, 0x02 },
223 };
224
225 static const struct ltk050h3146w_cmd page4_cmds[] = {
226         { 0x70, 0x00 },
227         { 0x71, 0x00 },
228         { 0x82, 0x0F }, /* VGH_MOD clamp level=15v */
229         { 0x84, 0x0F }, /* VGH clamp level 15V */
230         { 0x85, 0x0D }, /* VGL clamp level (-10V) */
231         { 0x32, 0xAC },
232         { 0x8C, 0x80 },
233         { 0x3C, 0xF5 },
234         { 0xB5, 0x07 }, /* GAMMA OP */
235         { 0x31, 0x45 }, /* SOURCE OP */
236         { 0x3A, 0x24 }, /* PS_EN OFF */
237         { 0x88, 0x33 }, /* LVD */
238 };
239
240 static inline
241 struct ltk050h3146w *panel_to_ltk050h3146w(struct drm_panel *panel)
242 {
243         return container_of(panel, struct ltk050h3146w, panel);
244 }
245
246 static void ltk050h3148w_init_sequence(struct mipi_dsi_multi_context *dsi_ctx)
247 {
248         /*
249          * Init sequence was supplied by the panel vendor without much
250          * documentation.
251          */
252         mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb9, 0xff, 0x83, 0x94);
253         mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb1, 0x50, 0x15, 0x75, 0x09, 0x32, 0x44,
254                                      0x71, 0x31, 0x55, 0x2f);
255         mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xba, 0x63, 0x03, 0x68, 0x6b, 0xb2, 0xc0);
256         mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xd2, 0x88);
257         mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb2, 0x00, 0x80, 0x64, 0x10, 0x07);
258         mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb4, 0x05, 0x70, 0x05, 0x70, 0x01, 0x70,
259                                      0x01, 0x0c, 0x86, 0x75, 0x00, 0x3f, 0x01, 0x74,
260                                      0x01, 0x74, 0x01, 0x74, 0x01, 0x0c, 0x86);
261         mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xd3, 0x00, 0x00, 0x07, 0x07, 0x40, 0x1e,
262                                      0x08, 0x00, 0x32, 0x10, 0x08, 0x00, 0x08, 0x54,
263                                      0x15, 0x10, 0x05, 0x04, 0x02, 0x12, 0x10, 0x05,
264                                      0x07, 0x33, 0x34, 0x0c, 0x0c, 0x37, 0x10, 0x07,
265                                      0x17, 0x11, 0x40);
266         mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xd5, 0x19, 0x19, 0x18, 0x18, 0x1b, 0x1b,
267                                      0x1a, 0x1a, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01,
268                                      0x02, 0x03, 0x20, 0x21, 0x18, 0x18, 0x22, 0x23,
269                                      0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
270                                      0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
271                                      0x18, 0x18, 0x18, 0x18, 0x18, 0x18);
272         mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xd6, 0x18, 0x18, 0x19, 0x19, 0x1b, 0x1b,
273                                      0x1a, 0x1a, 0x03, 0x02, 0x01, 0x00, 0x07, 0x06,
274                                      0x05, 0x04, 0x23, 0x22, 0x18, 0x18, 0x21, 0x20,
275                                      0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
276                                      0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
277                                      0x18, 0x18, 0x18, 0x18, 0x18, 0x18);
278         mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xe0, 0x00, 0x03, 0x09, 0x11, 0x11, 0x14,
279                                      0x18, 0x16, 0x2e, 0x3d, 0x4d, 0x4d, 0x58, 0x6c,
280                                      0x72, 0x78, 0x88, 0x8b, 0x86, 0xa4, 0xb2, 0x58,
281                                      0x55, 0x59, 0x5b, 0x5d, 0x60, 0x64, 0x7f, 0x00,
282                                      0x03, 0x09, 0x0f, 0x11, 0x14, 0x18, 0x16, 0x2e,
283                                      0x3d, 0x4d, 0x4d, 0x58, 0x6d, 0x73, 0x78, 0x88,
284                                      0x8b, 0x87, 0xa5, 0xb2, 0x58, 0x55, 0x58, 0x5b,
285                                      0x5d, 0x61, 0x65, 0x7f);
286         mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xcc, 0x0b);
287         mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xc0, 0x1f, 0x31);
288         mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb6, 0xc4, 0xc4);
289         mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x01);
290         mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb1, 0x00);
291         mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbd, 0x00);
292         mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xc6, 0xef);
293         mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xd4, 0x02);
294
295         mipi_dsi_dcs_set_tear_on_multi(dsi_ctx, 1);
296         mipi_dsi_msleep(dsi_ctx, 60);
297 }
298
299 static const struct drm_display_mode ltk050h3148w_mode = {
300         .hdisplay       = 720,
301         .hsync_start    = 720 + 12,
302         .hsync_end      = 720 + 12 + 6,
303         .htotal         = 720 + 12 + 6 + 24,
304         .vdisplay       = 1280,
305         .vsync_start    = 1280 + 9,
306         .vsync_end      = 1280 + 9 + 2,
307         .vtotal         = 1280 + 9 + 2 + 16,
308         .clock          = 59756,
309         .width_mm       = 62,
310         .height_mm      = 110,
311 };
312
313 static const struct ltk050h3146w_desc ltk050h3148w_data = {
314         .mode = &ltk050h3148w_mode,
315         .init = ltk050h3148w_init_sequence,
316         .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
317                       MIPI_DSI_MODE_VIDEO_BURST,
318 };
319
320 static void ltk050h3146w_init_sequence(struct mipi_dsi_multi_context *dsi_ctx)
321 {
322         /*
323          * Init sequence was supplied by the panel vendor without much
324          * documentation.
325          */
326         mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xdf, 0x93, 0x65, 0xf8);
327         mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb0, 0x01, 0x03, 0x02, 0x00, 0x64, 0x06,
328                                      0x01);
329         mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb2, 0x00, 0xb5);
330         mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb3, 0x00, 0xb5);
331         mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb7, 0x00, 0xbf, 0x00, 0x00, 0xbf, 0x00);
332
333         mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb9, 0x00, 0xc4, 0x23, 0x07);
334         mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbb, 0x02, 0x01, 0x24, 0x00, 0x28, 0x0f,
335                                      0x28, 0x04, 0xcc, 0xcc, 0xcc);
336         mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbc, 0x0f, 0x04);
337         mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbe, 0x1e, 0xf2);
338         mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xc0, 0x26, 0x03);
339         mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xc1, 0x00, 0x12);
340         mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xc3, 0x04, 0x02, 0x02, 0x76, 0x01, 0x80,
341                                      0x80);
342         mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xc4, 0x24, 0x80, 0xb4, 0x81, 0x12, 0x0f,
343                                      0x16, 0x00, 0x00);
344         mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xc8, 0x7f, 0x72, 0x67, 0x5d, 0x5d, 0x50,
345                                      0x56, 0x41, 0x59, 0x57, 0x55, 0x70, 0x5b, 0x5f,
346                                      0x4f, 0x47, 0x38, 0x23, 0x08, 0x7f, 0x72, 0x67,
347                                      0x5d, 0x5d, 0x50, 0x56, 0x41, 0x59, 0x57, 0x55,
348                                      0x70, 0x5b, 0x5f, 0x4f, 0x47, 0x38, 0x23, 0x08);
349         mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xd0, 0x1e, 0x1f, 0x57, 0x58, 0x48, 0x4a,
350                                      0x44, 0x46, 0x40, 0x1f, 0x42, 0x1f, 0x1f, 0x1f,
351                                      0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f);
352         mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xd1, 0x1e, 0x1f, 0x57, 0x58, 0x49, 0x4b,
353                                      0x45, 0x47, 0x41, 0x1f, 0x43, 0x1f, 0x1f, 0x1f,
354                                      0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f);
355         mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xd2, 0x1f, 0x1e, 0x17, 0x18, 0x07, 0x05,
356                                      0x0b, 0x09, 0x03, 0x1f, 0x01, 0x1f, 0x1f, 0x1f,
357                                      0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f);
358         mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xd3, 0x1f, 0x1e, 0x17, 0x18, 0x06, 0x04,
359                                      0x0a, 0x08, 0x02, 0x1f, 0x00, 0x1f, 0x1f, 0x1f,
360                                      0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f);
361         mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xd4, 0x00, 0x00, 0x00, 0x0c, 0x06, 0x20,
362                                      0x01, 0x02, 0x00, 0x60, 0x15, 0xb0, 0x30, 0x03,
363                                      0x04, 0x00, 0x60, 0x72, 0x0a, 0x00, 0x60, 0x08);
364         mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xd5, 0x00, 0x06, 0x06, 0x00, 0x30, 0x00,
365                                      0x00, 0x00, 0x00, 0x00, 0xbc, 0x50, 0x00, 0x05,
366                                      0x21, 0x00, 0x60);
367         mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xdd, 0x2c, 0xa3, 0x00);
368         mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xde, 0x02);
369         mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb2, 0x32, 0x1c);
370         mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xb7, 0x3b, 0x70, 0x00, 0x04);
371         mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xc1, 0x11);
372         mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xbb, 0x21, 0x22, 0x23, 0x24, 0x36, 0x37);
373         mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xc2, 0x20, 0x38, 0x1e, 0x84);
374         mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0xde, 0x00);
375
376         mipi_dsi_dcs_set_tear_on_multi(dsi_ctx, 1);
377         mipi_dsi_msleep(dsi_ctx, 60);
378 }
379
380 static const struct drm_display_mode ltk050h3146w_mode = {
381         .hdisplay       = 720,
382         .hsync_start    = 720 + 42,
383         .hsync_end      = 720 + 42 + 8,
384         .htotal         = 720 + 42 + 8 + 42,
385         .vdisplay       = 1280,
386         .vsync_start    = 1280 + 12,
387         .vsync_end      = 1280 + 12 + 4,
388         .vtotal         = 1280 + 12 + 4 + 18,
389         .clock          = 64018,
390         .width_mm       = 62,
391         .height_mm      = 110,
392 };
393
394 static const struct ltk050h3146w_desc ltk050h3146w_data = {
395         .mode = &ltk050h3146w_mode,
396         .init = ltk050h3146w_init_sequence,
397         .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
398                 MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_NO_EOT_PACKET,
399 };
400
401 static void ltk050h3146w_a2_select_page(struct mipi_dsi_multi_context *dsi_ctx, int page)
402 {
403         u8 d[4] = { 0xff, 0x98, 0x81, page };
404
405         mipi_dsi_dcs_write_buffer_multi(dsi_ctx, d, ARRAY_SIZE(d));
406 }
407
408 static void ltk050h3146w_a2_write_page(struct mipi_dsi_multi_context *dsi_ctx, int page,
409                                       const struct ltk050h3146w_cmd *cmds,
410                                       int num)
411 {
412         ltk050h3146w_a2_select_page(dsi_ctx, page);
413
414         for (int i = 0; i < num; i++)
415                 mipi_dsi_generic_write_multi(dsi_ctx, &cmds[i],
416                                              sizeof(struct ltk050h3146w_cmd));
417 }
418
419 static void ltk050h3146w_a2_init_sequence(struct mipi_dsi_multi_context *dsi_ctx)
420 {
421         /*
422          * Init sequence was supplied by the panel vendor without much
423          * documentation.
424          */
425         ltk050h3146w_a2_write_page(dsi_ctx, 3, page3_cmds,
426                                          ARRAY_SIZE(page3_cmds));
427         ltk050h3146w_a2_write_page(dsi_ctx, 4, page4_cmds,
428                                          ARRAY_SIZE(page4_cmds));
429         ltk050h3146w_a2_write_page(dsi_ctx, 1, page1_cmds,
430                                          ARRAY_SIZE(page1_cmds));
431         ltk050h3146w_a2_select_page(dsi_ctx, 0);
432
433         /* vendor code called this without param, where there should be one */
434         mipi_dsi_dcs_set_tear_on_multi(dsi_ctx, 0);
435
436         mipi_dsi_msleep(dsi_ctx, 60);
437 }
438
439 static const struct drm_display_mode ltk050h3146w_a2_mode = {
440         .hdisplay       = 720,
441         .hsync_start    = 720 + 42,
442         .hsync_end      = 720 + 42 + 10,
443         .htotal         = 720 + 42 + 10 + 60,
444         .vdisplay       = 1280,
445         .vsync_start    = 1280 + 18,
446         .vsync_end      = 1280 + 18 + 4,
447         .vtotal         = 1280 + 18 + 4 + 12,
448         .clock          = 65595,
449         .width_mm       = 62,
450         .height_mm      = 110,
451 };
452
453 static const struct ltk050h3146w_desc ltk050h3146w_a2_data = {
454         .mode = &ltk050h3146w_a2_mode,
455         .init = ltk050h3146w_a2_init_sequence,
456         .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
457                 MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_NO_EOT_PACKET,
458 };
459
460 static int ltk050h3146w_unprepare(struct drm_panel *panel)
461 {
462         struct ltk050h3146w *ctx = panel_to_ltk050h3146w(panel);
463         struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
464         struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi };
465
466         mipi_dsi_dcs_set_display_off_multi(&dsi_ctx);
467         mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx);
468         if (dsi_ctx.accum_err)
469                 return dsi_ctx.accum_err;
470
471         regulator_disable(ctx->iovcc);
472         regulator_disable(ctx->vci);
473
474         return 0;
475 }
476
477 static int ltk050h3146w_prepare(struct drm_panel *panel)
478 {
479         struct ltk050h3146w *ctx = panel_to_ltk050h3146w(panel);
480         struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
481         struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi };
482
483         dev_dbg(ctx->dev, "Resetting the panel\n");
484         dsi_ctx.accum_err = regulator_enable(ctx->vci);
485         if (dsi_ctx.accum_err) {
486                 dev_err(ctx->dev, "Failed to enable vci supply: %d\n", dsi_ctx.accum_err);
487                 return dsi_ctx.accum_err;
488         }
489         dsi_ctx.accum_err = regulator_enable(ctx->iovcc);
490         if (dsi_ctx.accum_err) {
491                 dev_err(ctx->dev, "Failed to enable iovcc supply: %d\n", dsi_ctx.accum_err);
492                 goto disable_vci;
493         }
494
495         gpiod_set_value_cansleep(ctx->reset_gpio, 1);
496         usleep_range(5000, 6000);
497         gpiod_set_value_cansleep(ctx->reset_gpio, 0);
498         msleep(20);
499
500         ctx->panel_desc->init(&dsi_ctx);
501         mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx);
502         /* T9: 120ms */
503         mipi_dsi_msleep(&dsi_ctx, 120);
504         mipi_dsi_dcs_set_display_on_multi(&dsi_ctx);
505         mipi_dsi_msleep(&dsi_ctx, 50);
506
507         if (dsi_ctx.accum_err)
508                 goto disable_iovcc;
509
510         return 0;
511
512 disable_iovcc:
513         regulator_disable(ctx->iovcc);
514 disable_vci:
515         regulator_disable(ctx->vci);
516         return dsi_ctx.accum_err;
517 }
518
519 static int ltk050h3146w_get_modes(struct drm_panel *panel,
520                                   struct drm_connector *connector)
521 {
522         struct ltk050h3146w *ctx = panel_to_ltk050h3146w(panel);
523         struct drm_display_mode *mode;
524
525         mode = drm_mode_duplicate(connector->dev, ctx->panel_desc->mode);
526         if (!mode)
527                 return -ENOMEM;
528
529         drm_mode_set_name(mode);
530
531         mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
532         connector->display_info.width_mm = mode->width_mm;
533         connector->display_info.height_mm = mode->height_mm;
534         drm_mode_probed_add(connector, mode);
535
536         return 1;
537 }
538
539 static const struct drm_panel_funcs ltk050h3146w_funcs = {
540         .unprepare      = ltk050h3146w_unprepare,
541         .prepare        = ltk050h3146w_prepare,
542         .get_modes      = ltk050h3146w_get_modes,
543 };
544
545 static int ltk050h3146w_probe(struct mipi_dsi_device *dsi)
546 {
547         struct device *dev = &dsi->dev;
548         struct ltk050h3146w *ctx;
549         int ret;
550
551         ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
552         if (!ctx)
553                 return -ENOMEM;
554
555         ctx->panel_desc = of_device_get_match_data(dev);
556         if (!ctx->panel_desc)
557                 return -EINVAL;
558
559         ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
560         if (IS_ERR(ctx->reset_gpio))
561                 return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), "cannot get reset gpio\n");
562
563         ctx->vci = devm_regulator_get(dev, "vci");
564         if (IS_ERR(ctx->vci))
565                 return dev_err_probe(dev, PTR_ERR(ctx->vci), "Failed to request vci regulator\n");
566
567         ctx->iovcc = devm_regulator_get(dev, "iovcc");
568         if (IS_ERR(ctx->iovcc))
569                 return dev_err_probe(dev, PTR_ERR(ctx->iovcc),
570                                      "Failed to request iovcc regulator\n");
571
572         mipi_dsi_set_drvdata(dsi, ctx);
573
574         ctx->dev = dev;
575
576         dsi->lanes = 4;
577         dsi->format = MIPI_DSI_FMT_RGB888;
578         dsi->mode_flags = ctx->panel_desc->mode_flags;
579
580         drm_panel_init(&ctx->panel, &dsi->dev, &ltk050h3146w_funcs,
581                        DRM_MODE_CONNECTOR_DSI);
582
583         ret = drm_panel_of_backlight(&ctx->panel);
584         if (ret)
585                 return ret;
586
587         drm_panel_add(&ctx->panel);
588
589         ret = mipi_dsi_attach(dsi);
590         if (ret < 0) {
591                 dev_err(dev, "mipi_dsi_attach failed: %d\n", ret);
592                 drm_panel_remove(&ctx->panel);
593                 return ret;
594         }
595
596         return 0;
597 }
598
599 static void ltk050h3146w_remove(struct mipi_dsi_device *dsi)
600 {
601         struct ltk050h3146w *ctx = mipi_dsi_get_drvdata(dsi);
602         int ret;
603
604         ret = mipi_dsi_detach(dsi);
605         if (ret < 0)
606                 dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret);
607
608         drm_panel_remove(&ctx->panel);
609 }
610
611 static const struct of_device_id ltk050h3146w_of_match[] = {
612         {
613                 .compatible = "leadtek,ltk050h3146w",
614                 .data = &ltk050h3146w_data,
615         },
616         {
617                 .compatible = "leadtek,ltk050h3146w-a2",
618                 .data = &ltk050h3146w_a2_data,
619         },
620         {
621                 .compatible = "leadtek,ltk050h3148w",
622                 .data = &ltk050h3148w_data,
623         },
624         { /* sentinel */ }
625 };
626 MODULE_DEVICE_TABLE(of, ltk050h3146w_of_match);
627
628 static struct mipi_dsi_driver ltk050h3146w_driver = {
629         .driver = {
630                 .name = "panel-leadtek-ltk050h3146w",
631                 .of_match_table = ltk050h3146w_of_match,
632         },
633         .probe  = ltk050h3146w_probe,
634         .remove = ltk050h3146w_remove,
635 };
636 module_mipi_dsi_driver(ltk050h3146w_driver);
637
638 MODULE_AUTHOR("Heiko Stuebner <[email protected]>");
639 MODULE_DESCRIPTION("DRM driver for Leadtek LTK050H3146W MIPI DSI panel");
640 MODULE_LICENSE("GPL v2");
This page took 0.06493 seconds and 4 git commands to generate.