1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * NewVision NV3052C IPS LCD panel driver |
4 | * |
5 | * Copyright (C) 2020, Paul Cercueil <paul@crapouillou.net> |
6 | * Copyright (C) 2022, Christophe Branchereau <cbranchereau@gmail.com> |
7 | */ |
8 | |
9 | #include <linux/delay.h> |
10 | #include <linux/device.h> |
11 | #include <linux/gpio/consumer.h> |
12 | #include <linux/media-bus-format.h> |
13 | #include <linux/module.h> |
14 | #include <linux/of.h> |
15 | #include <linux/platform_device.h> |
16 | #include <linux/regulator/consumer.h> |
17 | #include <linux/spi/spi.h> |
18 | #include <video/mipi_display.h> |
19 | #include <drm/drm_mipi_dbi.h> |
20 | #include <drm/drm_modes.h> |
21 | #include <drm/drm_panel.h> |
22 | |
23 | struct nv3052c_reg { |
24 | u8 cmd; |
25 | u8 val; |
26 | }; |
27 | |
28 | struct nv3052c_panel_info { |
29 | const struct drm_display_mode *display_modes; |
30 | unsigned int num_modes; |
31 | u16 width_mm, height_mm; |
32 | u32 bus_format, bus_flags; |
33 | const struct nv3052c_reg *panel_regs; |
34 | unsigned int panel_regs_len; |
35 | }; |
36 | |
37 | struct nv3052c { |
38 | struct device *dev; |
39 | struct drm_panel panel; |
40 | struct mipi_dbi dbi; |
41 | const struct nv3052c_panel_info *panel_info; |
42 | struct regulator *supply; |
43 | struct gpio_desc *reset_gpio; |
44 | }; |
45 | |
46 | static const struct nv3052c_reg ltk035c5444t_panel_regs[] = { |
47 | // EXTC Command set enable, select page 1 |
48 | { 0xff, 0x30 }, { 0xff, 0x52 }, { 0xff, 0x01 }, |
49 | // Mostly unknown registers |
50 | { 0xe3, 0x00 }, |
51 | { 0x40, 0x00 }, |
52 | { 0x03, 0x40 }, |
53 | { 0x04, 0x00 }, |
54 | { 0x05, 0x03 }, |
55 | { 0x08, 0x00 }, |
56 | { 0x09, 0x07 }, |
57 | { 0x0a, 0x01 }, |
58 | { 0x0b, 0x32 }, |
59 | { 0x0c, 0x32 }, |
60 | { 0x0d, 0x0b }, |
61 | { 0x0e, 0x00 }, |
62 | { 0x23, 0xa0 }, |
63 | { 0x24, 0x0c }, |
64 | { 0x25, 0x06 }, |
65 | { 0x26, 0x14 }, |
66 | { 0x27, 0x14 }, |
67 | { 0x38, 0xcc }, // VCOM_ADJ1 |
68 | { 0x39, 0xd7 }, // VCOM_ADJ2 |
69 | { 0x3a, 0x4a }, // VCOM_ADJ3 |
70 | { 0x28, 0x40 }, |
71 | { 0x29, 0x01 }, |
72 | { 0x2a, 0xdf }, |
73 | { 0x49, 0x3c }, |
74 | { 0x91, 0x77 }, // EXTPW_CTRL2 |
75 | { 0x92, 0x77 }, // EXTPW_CTRL3 |
76 | { 0xa0, 0x55 }, |
77 | { 0xa1, 0x50 }, |
78 | { 0xa4, 0x9c }, |
79 | { 0xa7, 0x02 }, |
80 | { 0xa8, 0x01 }, |
81 | { 0xa9, 0x01 }, |
82 | { 0xaa, 0xfc }, |
83 | { 0xab, 0x28 }, |
84 | { 0xac, 0x06 }, |
85 | { 0xad, 0x06 }, |
86 | { 0xae, 0x06 }, |
87 | { 0xaf, 0x03 }, |
88 | { 0xb0, 0x08 }, |
89 | { 0xb1, 0x26 }, |
90 | { 0xb2, 0x28 }, |
91 | { 0xb3, 0x28 }, |
92 | { 0xb4, 0x33 }, |
93 | { 0xb5, 0x08 }, |
94 | { 0xb6, 0x26 }, |
95 | { 0xb7, 0x08 }, |
96 | { 0xb8, 0x26 }, |
97 | { 0xf0, 0x00 }, |
98 | { 0xf6, 0xc0 }, |
99 | // EXTC Command set enable, select page 2 |
100 | { 0xff, 0x30 }, { 0xff, 0x52 }, { 0xff, 0x02 }, |
101 | // Set gray scale voltage to adjust gamma |
102 | { 0xb0, 0x0b }, // PGAMVR0 |
103 | { 0xb1, 0x16 }, // PGAMVR1 |
104 | { 0xb2, 0x17 }, // PGAMVR2 |
105 | { 0xb3, 0x2c }, // PGAMVR3 |
106 | { 0xb4, 0x32 }, // PGAMVR4 |
107 | { 0xb5, 0x3b }, // PGAMVR5 |
108 | { 0xb6, 0x29 }, // PGAMPR0 |
109 | { 0xb7, 0x40 }, // PGAMPR1 |
110 | { 0xb8, 0x0d }, // PGAMPK0 |
111 | { 0xb9, 0x05 }, // PGAMPK1 |
112 | { 0xba, 0x12 }, // PGAMPK2 |
113 | { 0xbb, 0x10 }, // PGAMPK3 |
114 | { 0xbc, 0x12 }, // PGAMPK4 |
115 | { 0xbd, 0x15 }, // PGAMPK5 |
116 | { 0xbe, 0x19 }, // PGAMPK6 |
117 | { 0xbf, 0x0e }, // PGAMPK7 |
118 | { 0xc0, 0x16 }, // PGAMPK8 |
119 | { 0xc1, 0x0a }, // PGAMPK9 |
120 | // Set gray scale voltage to adjust gamma |
121 | { 0xd0, 0x0c }, // NGAMVR0 |
122 | { 0xd1, 0x17 }, // NGAMVR0 |
123 | { 0xd2, 0x14 }, // NGAMVR1 |
124 | { 0xd3, 0x2e }, // NGAMVR2 |
125 | { 0xd4, 0x32 }, // NGAMVR3 |
126 | { 0xd5, 0x3c }, // NGAMVR4 |
127 | { 0xd6, 0x22 }, // NGAMPR0 |
128 | { 0xd7, 0x3d }, // NGAMPR1 |
129 | { 0xd8, 0x0d }, // NGAMPK0 |
130 | { 0xd9, 0x07 }, // NGAMPK1 |
131 | { 0xda, 0x13 }, // NGAMPK2 |
132 | { 0xdb, 0x13 }, // NGAMPK3 |
133 | { 0xdc, 0x11 }, // NGAMPK4 |
134 | { 0xdd, 0x15 }, // NGAMPK5 |
135 | { 0xde, 0x19 }, // NGAMPK6 |
136 | { 0xdf, 0x10 }, // NGAMPK7 |
137 | { 0xe0, 0x17 }, // NGAMPK8 |
138 | { 0xe1, 0x0a }, // NGAMPK9 |
139 | // EXTC Command set enable, select page 3 |
140 | { 0xff, 0x30 }, { 0xff, 0x52 }, { 0xff, 0x03 }, |
141 | // Set various timing settings |
142 | { 0x00, 0x2a }, // GIP_VST_1 |
143 | { 0x01, 0x2a }, // GIP_VST_2 |
144 | { 0x02, 0x2a }, // GIP_VST_3 |
145 | { 0x03, 0x2a }, // GIP_VST_4 |
146 | { 0x04, 0x61 }, // GIP_VST_5 |
147 | { 0x05, 0x80 }, // GIP_VST_6 |
148 | { 0x06, 0xc7 }, // GIP_VST_7 |
149 | { 0x07, 0x01 }, // GIP_VST_8 |
150 | { 0x08, 0x03 }, // GIP_VST_9 |
151 | { 0x09, 0x04 }, // GIP_VST_10 |
152 | { 0x70, 0x22 }, // GIP_ECLK1 |
153 | { 0x71, 0x80 }, // GIP_ECLK2 |
154 | { 0x30, 0x2a }, // GIP_CLK_1 |
155 | { 0x31, 0x2a }, // GIP_CLK_2 |
156 | { 0x32, 0x2a }, // GIP_CLK_3 |
157 | { 0x33, 0x2a }, // GIP_CLK_4 |
158 | { 0x34, 0x61 }, // GIP_CLK_5 |
159 | { 0x35, 0xc5 }, // GIP_CLK_6 |
160 | { 0x36, 0x80 }, // GIP_CLK_7 |
161 | { 0x37, 0x23 }, // GIP_CLK_8 |
162 | { 0x40, 0x03 }, // GIP_CLKA_1 |
163 | { 0x41, 0x04 }, // GIP_CLKA_2 |
164 | { 0x42, 0x05 }, // GIP_CLKA_3 |
165 | { 0x43, 0x06 }, // GIP_CLKA_4 |
166 | { 0x44, 0x11 }, // GIP_CLKA_5 |
167 | { 0x45, 0xe8 }, // GIP_CLKA_6 |
168 | { 0x46, 0xe9 }, // GIP_CLKA_7 |
169 | { 0x47, 0x11 }, // GIP_CLKA_8 |
170 | { 0x48, 0xea }, // GIP_CLKA_9 |
171 | { 0x49, 0xeb }, // GIP_CLKA_10 |
172 | { 0x50, 0x07 }, // GIP_CLKB_1 |
173 | { 0x51, 0x08 }, // GIP_CLKB_2 |
174 | { 0x52, 0x09 }, // GIP_CLKB_3 |
175 | { 0x53, 0x0a }, // GIP_CLKB_4 |
176 | { 0x54, 0x11 }, // GIP_CLKB_5 |
177 | { 0x55, 0xec }, // GIP_CLKB_6 |
178 | { 0x56, 0xed }, // GIP_CLKB_7 |
179 | { 0x57, 0x11 }, // GIP_CLKB_8 |
180 | { 0x58, 0xef }, // GIP_CLKB_9 |
181 | { 0x59, 0xf0 }, // GIP_CLKB_10 |
182 | // Map internal GOA signals to GOA output pad |
183 | { 0xb1, 0x01 }, // PANELD2U2 |
184 | { 0xb4, 0x15 }, // PANELD2U5 |
185 | { 0xb5, 0x16 }, // PANELD2U6 |
186 | { 0xb6, 0x09 }, // PANELD2U7 |
187 | { 0xb7, 0x0f }, // PANELD2U8 |
188 | { 0xb8, 0x0d }, // PANELD2U9 |
189 | { 0xb9, 0x0b }, // PANELD2U10 |
190 | { 0xba, 0x00 }, // PANELD2U11 |
191 | { 0xc7, 0x02 }, // PANELD2U24 |
192 | { 0xca, 0x17 }, // PANELD2U27 |
193 | { 0xcb, 0x18 }, // PANELD2U28 |
194 | { 0xcc, 0x0a }, // PANELD2U29 |
195 | { 0xcd, 0x10 }, // PANELD2U30 |
196 | { 0xce, 0x0e }, // PANELD2U31 |
197 | { 0xcf, 0x0c }, // PANELD2U32 |
198 | { 0xd0, 0x00 }, // PANELD2U33 |
199 | // Map internal GOA signals to GOA output pad |
200 | { 0x81, 0x00 }, // PANELU2D2 |
201 | { 0x84, 0x15 }, // PANELU2D5 |
202 | { 0x85, 0x16 }, // PANELU2D6 |
203 | { 0x86, 0x10 }, // PANELU2D7 |
204 | { 0x87, 0x0a }, // PANELU2D8 |
205 | { 0x88, 0x0c }, // PANELU2D9 |
206 | { 0x89, 0x0e }, // PANELU2D10 |
207 | { 0x8a, 0x02 }, // PANELU2D11 |
208 | { 0x97, 0x00 }, // PANELU2D24 |
209 | { 0x9a, 0x17 }, // PANELU2D27 |
210 | { 0x9b, 0x18 }, // PANELU2D28 |
211 | { 0x9c, 0x0f }, // PANELU2D29 |
212 | { 0x9d, 0x09 }, // PANELU2D30 |
213 | { 0x9e, 0x0b }, // PANELU2D31 |
214 | { 0x9f, 0x0d }, // PANELU2D32 |
215 | { 0xa0, 0x01 }, // PANELU2D33 |
216 | // EXTC Command set enable, select page 2 |
217 | { 0xff, 0x30 }, { 0xff, 0x52 }, { 0xff, 0x02 }, |
218 | // Unknown registers |
219 | { 0x01, 0x01 }, |
220 | { 0x02, 0xda }, |
221 | { 0x03, 0xba }, |
222 | { 0x04, 0xa8 }, |
223 | { 0x05, 0x9a }, |
224 | { 0x06, 0x70 }, |
225 | { 0x07, 0xff }, |
226 | { 0x08, 0x91 }, |
227 | { 0x09, 0x90 }, |
228 | { 0x0a, 0xff }, |
229 | { 0x0b, 0x8f }, |
230 | { 0x0c, 0x60 }, |
231 | { 0x0d, 0x58 }, |
232 | { 0x0e, 0x48 }, |
233 | { 0x0f, 0x38 }, |
234 | { 0x10, 0x2b }, |
235 | // EXTC Command set enable, select page 0 |
236 | { 0xff, 0x30 }, { 0xff, 0x52 }, { 0xff, 0x00 }, |
237 | // Display Access Control |
238 | { 0x36, 0x0a }, // bgr = 1, ss = 1, gs = 0 |
239 | }; |
240 | |
241 | static const struct nv3052c_reg fs035vg158_panel_regs[] = { |
242 | // EXTC Command set enable, select page 1 |
243 | { 0xff, 0x30 }, { 0xff, 0x52 }, { 0xff, 0x01 }, |
244 | // Mostly unknown registers |
245 | { 0xe3, 0x00 }, |
246 | { 0x40, 0x00 }, |
247 | { 0x03, 0x40 }, |
248 | { 0x04, 0x00 }, |
249 | { 0x05, 0x03 }, |
250 | { 0x08, 0x00 }, |
251 | { 0x09, 0x07 }, |
252 | { 0x0a, 0x01 }, |
253 | { 0x0b, 0x32 }, |
254 | { 0x0c, 0x32 }, |
255 | { 0x0d, 0x0b }, |
256 | { 0x0e, 0x00 }, |
257 | { 0x23, 0x20 }, // RGB interface control: DE MODE PCLK-N |
258 | { 0x24, 0x0c }, |
259 | { 0x25, 0x06 }, |
260 | { 0x26, 0x14 }, |
261 | { 0x27, 0x14 }, |
262 | { 0x38, 0x9c }, //VCOM_ADJ1, different to ltk035c5444t |
263 | { 0x39, 0xa7 }, //VCOM_ADJ2, different to ltk035c5444t |
264 | { 0x3a, 0x50 }, //VCOM_ADJ3, different to ltk035c5444t |
265 | { 0x28, 0x40 }, |
266 | { 0x29, 0x01 }, |
267 | { 0x2a, 0xdf }, |
268 | { 0x49, 0x3c }, |
269 | { 0x91, 0x57 }, //EXTPW_CTRL2, different to ltk035c5444t |
270 | { 0x92, 0x57 }, //EXTPW_CTRL3, different to ltk035c5444t |
271 | { 0xa0, 0x55 }, |
272 | { 0xa1, 0x50 }, |
273 | { 0xa4, 0x9c }, |
274 | { 0xa7, 0x02 }, |
275 | { 0xa8, 0x01 }, |
276 | { 0xa9, 0x01 }, |
277 | { 0xaa, 0xfc }, |
278 | { 0xab, 0x28 }, |
279 | { 0xac, 0x06 }, |
280 | { 0xad, 0x06 }, |
281 | { 0xae, 0x06 }, |
282 | { 0xaf, 0x03 }, |
283 | { 0xb0, 0x08 }, |
284 | { 0xb1, 0x26 }, |
285 | { 0xb2, 0x28 }, |
286 | { 0xb3, 0x28 }, |
287 | { 0xb4, 0x03 }, // Unknown, different to ltk035c5444 |
288 | { 0xb5, 0x08 }, |
289 | { 0xb6, 0x26 }, |
290 | { 0xb7, 0x08 }, |
291 | { 0xb8, 0x26 }, |
292 | { 0xf0, 0x00 }, |
293 | { 0xf6, 0xc0 }, |
294 | // EXTC Command set enable, select page 0 |
295 | { 0xff, 0x30 }, { 0xff, 0x52 }, { 0xff, 0x02 }, |
296 | // Set gray scale voltage to adjust gamma |
297 | { 0xb0, 0x0b }, // PGAMVR0 |
298 | { 0xb1, 0x16 }, // PGAMVR1 |
299 | { 0xb2, 0x17 }, // PGAMVR2 |
300 | { 0xb3, 0x2c }, // PGAMVR3 |
301 | { 0xb4, 0x32 }, // PGAMVR4 |
302 | { 0xb5, 0x3b }, // PGAMVR5 |
303 | { 0xb6, 0x29 }, // PGAMPR0 |
304 | { 0xb7, 0x40 }, // PGAMPR1 |
305 | { 0xb8, 0x0d }, // PGAMPK0 |
306 | { 0xb9, 0x05 }, // PGAMPK1 |
307 | { 0xba, 0x12 }, // PGAMPK2 |
308 | { 0xbb, 0x10 }, // PGAMPK3 |
309 | { 0xbc, 0x12 }, // PGAMPK4 |
310 | { 0xbd, 0x15 }, // PGAMPK5 |
311 | { 0xbe, 0x19 }, // PGAMPK6 |
312 | { 0xbf, 0x0e }, // PGAMPK7 |
313 | { 0xc0, 0x16 }, // PGAMPK8 |
314 | { 0xc1, 0x0a }, // PGAMPK9 |
315 | // Set gray scale voltage to adjust gamma |
316 | { 0xd0, 0x0c }, // NGAMVR0 |
317 | { 0xd1, 0x17 }, // NGAMVR0 |
318 | { 0xd2, 0x14 }, // NGAMVR1 |
319 | { 0xd3, 0x2e }, // NGAMVR2 |
320 | { 0xd4, 0x32 }, // NGAMVR3 |
321 | { 0xd5, 0x3c }, // NGAMVR4 |
322 | { 0xd6, 0x22 }, // NGAMPR0 |
323 | { 0xd7, 0x3d }, // NGAMPR1 |
324 | { 0xd8, 0x0d }, // NGAMPK0 |
325 | { 0xd9, 0x07 }, // NGAMPK1 |
326 | { 0xda, 0x13 }, // NGAMPK2 |
327 | { 0xdb, 0x13 }, // NGAMPK3 |
328 | { 0xdc, 0x11 }, // NGAMPK4 |
329 | { 0xdd, 0x15 }, // NGAMPK5 |
330 | { 0xde, 0x19 }, // NGAMPK6 |
331 | { 0xdf, 0x10 }, // NGAMPK7 |
332 | { 0xe0, 0x17 }, // NGAMPK8 |
333 | { 0xe1, 0x0a }, // NGAMPK9 |
334 | // EXTC Command set enable, select page 3 |
335 | { 0xff, 0x30 }, { 0xff, 0x52 }, { 0xff, 0x03 }, |
336 | // Set various timing settings |
337 | { 0x00, 0x2a }, // GIP_VST_1 |
338 | { 0x01, 0x2a }, // GIP_VST_2 |
339 | { 0x02, 0x2a }, // GIP_VST_3 |
340 | { 0x03, 0x2a }, // GIP_VST_4 |
341 | { 0x04, 0x61 }, // GIP_VST_5 |
342 | { 0x05, 0x80 }, // GIP_VST_6 |
343 | { 0x06, 0xc7 }, // GIP_VST_7 |
344 | { 0x07, 0x01 }, // GIP_VST_8 |
345 | { 0x08, 0x03 }, // GIP_VST_9 |
346 | { 0x09, 0x04 }, // GIP_VST_10 |
347 | { 0x70, 0x22 }, // GIP_ECLK1 |
348 | { 0x71, 0x80 }, // GIP_ECLK2 |
349 | { 0x30, 0x2a }, // GIP_CLK_1 |
350 | { 0x31, 0x2a }, // GIP_CLK_2 |
351 | { 0x32, 0x2a }, // GIP_CLK_3 |
352 | { 0x33, 0x2a }, // GIP_CLK_4 |
353 | { 0x34, 0x61 }, // GIP_CLK_5 |
354 | { 0x35, 0xc5 }, // GIP_CLK_6 |
355 | { 0x36, 0x80 }, // GIP_CLK_7 |
356 | { 0x37, 0x23 }, // GIP_CLK_8 |
357 | { 0x40, 0x03 }, // GIP_CLKA_1 |
358 | { 0x41, 0x04 }, // GIP_CLKA_2 |
359 | { 0x42, 0x05 }, // GIP_CLKA_3 |
360 | { 0x43, 0x06 }, // GIP_CLKA_4 |
361 | { 0x44, 0x11 }, // GIP_CLKA_5 |
362 | { 0x45, 0xe8 }, // GIP_CLKA_6 |
363 | { 0x46, 0xe9 }, // GIP_CLKA_7 |
364 | { 0x47, 0x11 }, // GIP_CLKA_8 |
365 | { 0x48, 0xea }, // GIP_CLKA_9 |
366 | { 0x49, 0xeb }, // GIP_CLKA_10 |
367 | { 0x50, 0x07 }, // GIP_CLKB_1 |
368 | { 0x51, 0x08 }, // GIP_CLKB_2 |
369 | { 0x52, 0x09 }, // GIP_CLKB_3 |
370 | { 0x53, 0x0a }, // GIP_CLKB_4 |
371 | { 0x54, 0x11 }, // GIP_CLKB_5 |
372 | { 0x55, 0xec }, // GIP_CLKB_6 |
373 | { 0x56, 0xed }, // GIP_CLKB_7 |
374 | { 0x57, 0x11 }, // GIP_CLKB_8 |
375 | { 0x58, 0xef }, // GIP_CLKB_9 |
376 | { 0x59, 0xf0 }, // GIP_CLKB_10 |
377 | // Map internal GOA signals to GOA output pad |
378 | { 0xb1, 0x01 }, // PANELD2U2 |
379 | { 0xb4, 0x15 }, // PANELD2U5 |
380 | { 0xb5, 0x16 }, // PANELD2U6 |
381 | { 0xb6, 0x09 }, // PANELD2U7 |
382 | { 0xb7, 0x0f }, // PANELD2U8 |
383 | { 0xb8, 0x0d }, // PANELD2U9 |
384 | { 0xb9, 0x0b }, // PANELD2U10 |
385 | { 0xba, 0x00 }, // PANELD2U11 |
386 | { 0xc7, 0x02 }, // PANELD2U24 |
387 | { 0xca, 0x17 }, // PANELD2U27 |
388 | { 0xcb, 0x18 }, // PANELD2U28 |
389 | { 0xcc, 0x0a }, // PANELD2U29 |
390 | { 0xcd, 0x10 }, // PANELD2U30 |
391 | { 0xce, 0x0e }, // PANELD2U31 |
392 | { 0xcf, 0x0c }, // PANELD2U32 |
393 | { 0xd0, 0x00 }, // PANELD2U33 |
394 | // Map internal GOA signals to GOA output pad |
395 | { 0x81, 0x00 }, // PANELU2D2 |
396 | { 0x84, 0x15 }, // PANELU2D5 |
397 | { 0x85, 0x16 }, // PANELU2D6 |
398 | { 0x86, 0x10 }, // PANELU2D7 |
399 | { 0x87, 0x0a }, // PANELU2D8 |
400 | { 0x88, 0x0c }, // PANELU2D9 |
401 | { 0x89, 0x0e }, // PANELU2D10 |
402 | { 0x8a, 0x02 }, // PANELU2D11 |
403 | { 0x97, 0x00 }, // PANELU2D24 |
404 | { 0x9a, 0x17 }, // PANELU2D27 |
405 | { 0x9b, 0x18 }, // PANELU2D28 |
406 | { 0x9c, 0x0f }, // PANELU2D29 |
407 | { 0x9d, 0x09 }, // PANELU2D30 |
408 | { 0x9e, 0x0b }, // PANELU2D31 |
409 | { 0x9f, 0x0d }, // PANELU2D32 |
410 | { 0xa0, 0x01 }, // PANELU2D33 |
411 | // EXTC Command set enable, select page 2 |
412 | { 0xff, 0x30 }, { 0xff, 0x52 }, { 0xff, 0x02 }, |
413 | // Unknown registers |
414 | { 0x01, 0x01 }, |
415 | { 0x02, 0xda }, |
416 | { 0x03, 0xba }, |
417 | { 0x04, 0xa8 }, |
418 | { 0x05, 0x9a }, |
419 | { 0x06, 0x70 }, |
420 | { 0x07, 0xff }, |
421 | { 0x08, 0x91 }, |
422 | { 0x09, 0x90 }, |
423 | { 0x0a, 0xff }, |
424 | { 0x0b, 0x8f }, |
425 | { 0x0c, 0x60 }, |
426 | { 0x0d, 0x58 }, |
427 | { 0x0e, 0x48 }, |
428 | { 0x0f, 0x38 }, |
429 | { 0x10, 0x2b }, |
430 | // EXTC Command set enable, select page 0 |
431 | { 0xff, 0x30 }, { 0xff, 0x52 }, { 0xff, 0x00 }, |
432 | // Display Access Control |
433 | { 0x36, 0x0a }, // bgr = 1, ss = 1, gs = 0 |
434 | }; |
435 | |
436 | |
437 | static const struct nv3052c_reg wl_355608_a8_panel_regs[] = { |
438 | // EXTC Command set enable, select page 1 |
439 | { 0xff, 0x30 }, { 0xff, 0x52 }, { 0xff, 0x01 }, |
440 | // Mostly unknown registers |
441 | { 0xe3, 0x00 }, |
442 | { 0x40, 0x00 }, |
443 | { 0x03, 0x40 }, |
444 | { 0x04, 0x00 }, |
445 | { 0x05, 0x03 }, |
446 | { 0x08, 0x00 }, |
447 | { 0x09, 0x07 }, |
448 | { 0x0a, 0x01 }, |
449 | { 0x0b, 0x32 }, |
450 | { 0x0c, 0x32 }, |
451 | { 0x0d, 0x0b }, |
452 | { 0x0e, 0x00 }, |
453 | { 0x23, 0xa0 }, |
454 | { 0x24, 0x0c }, |
455 | { 0x25, 0x06 }, |
456 | { 0x26, 0x14 }, |
457 | { 0x27, 0x14 }, |
458 | { 0x38, 0xcc }, // VCOM_ADJ1 |
459 | { 0x39, 0xd7 }, // VCOM_ADJ2 |
460 | { 0x3a, 0x44 }, // VCOM_ADJ3 |
461 | { 0x28, 0x40 }, |
462 | { 0x29, 0x01 }, |
463 | { 0x2a, 0xdf }, |
464 | { 0x49, 0x3c }, |
465 | { 0x91, 0x77 }, // EXTPW_CTRL2 |
466 | { 0x92, 0x77 }, // EXTPW_CTRL3 |
467 | { 0xa0, 0x55 }, |
468 | { 0xa1, 0x50 }, |
469 | { 0xa4, 0x9c }, |
470 | { 0xa7, 0x02 }, |
471 | { 0xa8, 0x01 }, |
472 | { 0xa9, 0x01 }, |
473 | { 0xaa, 0xfc }, |
474 | { 0xab, 0x28 }, |
475 | { 0xac, 0x06 }, |
476 | { 0xad, 0x06 }, |
477 | { 0xae, 0x06 }, |
478 | { 0xaf, 0x03 }, |
479 | { 0xb0, 0x08 }, |
480 | { 0xb1, 0x26 }, |
481 | { 0xb2, 0x28 }, |
482 | { 0xb3, 0x28 }, |
483 | { 0xb4, 0x33 }, |
484 | { 0xb5, 0x08 }, |
485 | { 0xb6, 0x26 }, |
486 | { 0xb7, 0x08 }, |
487 | { 0xb8, 0x26 }, |
488 | { 0xf0, 0x00 }, |
489 | { 0xf6, 0xc0 }, |
490 | // EXTC Command set enable, select page 2 |
491 | { 0xff, 0x30 }, { 0xff, 0x52 }, { 0xff, 0x02 }, |
492 | // Set gray scale voltage to adjust gamma |
493 | { 0xb0, 0x0b }, // PGAMVR0 |
494 | { 0xb1, 0x16 }, // PGAMVR1 |
495 | { 0xb2, 0x17 }, // PGAMVR2 |
496 | { 0xb3, 0x2c }, // PGAMVR3 |
497 | { 0xb4, 0x32 }, // PGAMVR4 |
498 | { 0xb5, 0x3b }, // PGAMVR5 |
499 | { 0xb6, 0x29 }, // PGAMPR0 |
500 | { 0xb7, 0x40 }, // PGAMPR1 |
501 | { 0xb8, 0x0d }, // PGAMPK0 |
502 | { 0xb9, 0x05 }, // PGAMPK1 |
503 | { 0xba, 0x12 }, // PGAMPK2 |
504 | { 0xbb, 0x10 }, // PGAMPK3 |
505 | { 0xbc, 0x12 }, // PGAMPK4 |
506 | { 0xbd, 0x15 }, // PGAMPK5 |
507 | { 0xbe, 0x19 }, // PGAMPK6 |
508 | { 0xbf, 0x0e }, // PGAMPK7 |
509 | { 0xc0, 0x16 }, // PGAMPK8 |
510 | { 0xc1, 0x0a }, // PGAMPK9 |
511 | // Set gray scale voltage to adjust gamma |
512 | { 0xd0, 0x0c }, // NGAMVR0 |
513 | { 0xd1, 0x17 }, // NGAMVR0 |
514 | { 0xd2, 0x14 }, // NGAMVR1 |
515 | { 0xd3, 0x2e }, // NGAMVR2 |
516 | { 0xd4, 0x32 }, // NGAMVR3 |
517 | { 0xd5, 0x3c }, // NGAMVR4 |
518 | { 0xd6, 0x22 }, // NGAMPR0 |
519 | { 0xd7, 0x3d }, // NGAMPR1 |
520 | { 0xd8, 0x0d }, // NGAMPK0 |
521 | { 0xd9, 0x07 }, // NGAMPK1 |
522 | { 0xda, 0x13 }, // NGAMPK2 |
523 | { 0xdb, 0x13 }, // NGAMPK3 |
524 | { 0xdc, 0x11 }, // NGAMPK4 |
525 | { 0xdd, 0x15 }, // NGAMPK5 |
526 | { 0xde, 0x19 }, // NGAMPK6 |
527 | { 0xdf, 0x10 }, // NGAMPK7 |
528 | { 0xe0, 0x17 }, // NGAMPK8 |
529 | { 0xe1, 0x0a }, // NGAMPK9 |
530 | // EXTC Command set enable, select page 3 |
531 | { 0xff, 0x30 }, { 0xff, 0x52 }, { 0xff, 0x03 }, |
532 | // Set various timing settings |
533 | { 0x00, 0x2a }, // GIP_VST_1 |
534 | { 0x01, 0x2a }, // GIP_VST_2 |
535 | { 0x02, 0x2a }, // GIP_VST_3 |
536 | { 0x03, 0x2a }, // GIP_VST_4 |
537 | { 0x04, 0x61 }, // GIP_VST_5 |
538 | { 0x05, 0x80 }, // GIP_VST_6 |
539 | { 0x06, 0xc7 }, // GIP_VST_7 |
540 | { 0x07, 0x01 }, // GIP_VST_8 |
541 | { 0x08, 0x03 }, // GIP_VST_9 |
542 | { 0x09, 0x04 }, // GIP_VST_10 |
543 | { 0x70, 0x22 }, // GIP_ECLK1 |
544 | { 0x71, 0x80 }, // GIP_ECLK2 |
545 | { 0x30, 0x2a }, // GIP_CLK_1 |
546 | { 0x31, 0x2a }, // GIP_CLK_2 |
547 | { 0x32, 0x2a }, // GIP_CLK_3 |
548 | { 0x33, 0x2a }, // GIP_CLK_4 |
549 | { 0x34, 0x61 }, // GIP_CLK_5 |
550 | { 0x35, 0xc5 }, // GIP_CLK_6 |
551 | { 0x36, 0x80 }, // GIP_CLK_7 |
552 | { 0x37, 0x23 }, // GIP_CLK_8 |
553 | { 0x40, 0x03 }, // GIP_CLKA_1 |
554 | { 0x41, 0x04 }, // GIP_CLKA_2 |
555 | { 0x42, 0x05 }, // GIP_CLKA_3 |
556 | { 0x43, 0x06 }, // GIP_CLKA_4 |
557 | { 0x44, 0x11 }, // GIP_CLKA_5 |
558 | { 0x45, 0xe8 }, // GIP_CLKA_6 |
559 | { 0x46, 0xe9 }, // GIP_CLKA_7 |
560 | { 0x47, 0x11 }, // GIP_CLKA_8 |
561 | { 0x48, 0xea }, // GIP_CLKA_9 |
562 | { 0x49, 0xeb }, // GIP_CLKA_10 |
563 | { 0x50, 0x07 }, // GIP_CLKB_1 |
564 | { 0x51, 0x08 }, // GIP_CLKB_2 |
565 | { 0x52, 0x09 }, // GIP_CLKB_3 |
566 | { 0x53, 0x0a }, // GIP_CLKB_4 |
567 | { 0x54, 0x11 }, // GIP_CLKB_5 |
568 | { 0x55, 0xec }, // GIP_CLKB_6 |
569 | { 0x56, 0xed }, // GIP_CLKB_7 |
570 | { 0x57, 0x11 }, // GIP_CLKB_8 |
571 | { 0x58, 0xef }, // GIP_CLKB_9 |
572 | { 0x59, 0xf0 }, // GIP_CLKB_10 |
573 | // Map internal GOA signals to GOA output pad |
574 | { 0xb1, 0x01 }, // PANELD2U2 |
575 | { 0xb4, 0x15 }, // PANELD2U5 |
576 | { 0xb5, 0x16 }, // PANELD2U6 |
577 | { 0xb6, 0x09 }, // PANELD2U7 |
578 | { 0xb7, 0x0f }, // PANELD2U8 |
579 | { 0xb8, 0x0d }, // PANELD2U9 |
580 | { 0xb9, 0x0b }, // PANELD2U10 |
581 | { 0xba, 0x00 }, // PANELD2U11 |
582 | { 0xc7, 0x02 }, // PANELD2U24 |
583 | { 0xca, 0x17 }, // PANELD2U27 |
584 | { 0xcb, 0x18 }, // PANELD2U28 |
585 | { 0xcc, 0x0a }, // PANELD2U29 |
586 | { 0xcd, 0x10 }, // PANELD2U30 |
587 | { 0xce, 0x0e }, // PANELD2U31 |
588 | { 0xcf, 0x0c }, // PANELD2U32 |
589 | { 0xd0, 0x00 }, // PANELD2U33 |
590 | // Map internal GOA signals to GOA output pad |
591 | { 0x81, 0x00 }, // PANELU2D2 |
592 | { 0x84, 0x15 }, // PANELU2D5 |
593 | { 0x85, 0x16 }, // PANELU2D6 |
594 | { 0x86, 0x10 }, // PANELU2D7 |
595 | { 0x87, 0x0a }, // PANELU2D8 |
596 | { 0x88, 0x0c }, // PANELU2D9 |
597 | { 0x89, 0x0e }, // PANELU2D10 |
598 | { 0x8a, 0x02 }, // PANELU2D11 |
599 | { 0x97, 0x00 }, // PANELU2D24 |
600 | { 0x9a, 0x17 }, // PANELU2D27 |
601 | { 0x9b, 0x18 }, // PANELU2D28 |
602 | { 0x9c, 0x0f }, // PANELU2D29 |
603 | { 0x9d, 0x09 }, // PANELU2D30 |
604 | { 0x9e, 0x0b }, // PANELU2D31 |
605 | { 0x9f, 0x0d }, // PANELU2D32 |
606 | { 0xa0, 0x01 }, // PANELU2D33 |
607 | // EXTC Command set enable, select page 2 |
608 | { 0xff, 0x30 }, { 0xff, 0x52 }, { 0xff, 0x02 }, |
609 | // Unknown registers |
610 | { 0x01, 0x01 }, |
611 | { 0x02, 0xda }, |
612 | { 0x03, 0xba }, |
613 | { 0x04, 0xa8 }, |
614 | { 0x05, 0x9a }, |
615 | { 0x06, 0x70 }, |
616 | { 0x07, 0xff }, |
617 | { 0x08, 0x91 }, |
618 | { 0x09, 0x90 }, |
619 | { 0x0a, 0xff }, |
620 | { 0x0b, 0x8f }, |
621 | { 0x0c, 0x60 }, |
622 | { 0x0d, 0x58 }, |
623 | { 0x0e, 0x48 }, |
624 | { 0x0f, 0x38 }, |
625 | { 0x10, 0x2b }, |
626 | // EXTC Command set enable, select page 0 |
627 | { 0xff, 0x30 }, { 0xff, 0x52 }, { 0xff, 0x00 }, |
628 | // Display Access Control |
629 | { 0x36, 0x0a }, // bgr = 1, ss = 1, gs = 0 |
630 | }; |
631 | |
632 | static inline struct nv3052c *to_nv3052c(struct drm_panel *panel) |
633 | { |
634 | return container_of(panel, struct nv3052c, panel); |
635 | } |
636 | |
637 | static int nv3052c_prepare(struct drm_panel *panel) |
638 | { |
639 | struct nv3052c *priv = to_nv3052c(panel); |
640 | const struct nv3052c_reg *panel_regs = priv->panel_info->panel_regs; |
641 | unsigned int panel_regs_len = priv->panel_info->panel_regs_len; |
642 | struct mipi_dbi *dbi = &priv->dbi; |
643 | unsigned int i; |
644 | int err; |
645 | |
646 | err = regulator_enable(regulator: priv->supply); |
647 | if (err) { |
648 | dev_err(priv->dev, "Failed to enable power supply: %d\n" , err); |
649 | return err; |
650 | } |
651 | |
652 | /* Reset the chip */ |
653 | gpiod_set_value_cansleep(desc: priv->reset_gpio, value: 1); |
654 | usleep_range(min: 10, max: 1000); |
655 | gpiod_set_value_cansleep(desc: priv->reset_gpio, value: 0); |
656 | usleep_range(min: 5000, max: 20000); |
657 | |
658 | for (i = 0; i < panel_regs_len; i++) { |
659 | err = mipi_dbi_command(dbi, panel_regs[i].cmd, |
660 | panel_regs[i].val); |
661 | |
662 | if (err) { |
663 | dev_err(priv->dev, "Unable to set register: %d\n" , err); |
664 | goto err_disable_regulator; |
665 | } |
666 | } |
667 | |
668 | err = mipi_dbi_command(dbi, MIPI_DCS_EXIT_SLEEP_MODE); |
669 | if (err) { |
670 | dev_err(priv->dev, "Unable to exit sleep mode: %d\n" , err); |
671 | goto err_disable_regulator; |
672 | } |
673 | |
674 | return 0; |
675 | |
676 | err_disable_regulator: |
677 | regulator_disable(regulator: priv->supply); |
678 | return err; |
679 | } |
680 | |
681 | static int nv3052c_unprepare(struct drm_panel *panel) |
682 | { |
683 | struct nv3052c *priv = to_nv3052c(panel); |
684 | struct mipi_dbi *dbi = &priv->dbi; |
685 | int err; |
686 | |
687 | err = mipi_dbi_command(dbi, MIPI_DCS_ENTER_SLEEP_MODE); |
688 | if (err) |
689 | dev_err(priv->dev, "Unable to enter sleep mode: %d\n" , err); |
690 | |
691 | gpiod_set_value_cansleep(desc: priv->reset_gpio, value: 1); |
692 | regulator_disable(regulator: priv->supply); |
693 | |
694 | return 0; |
695 | } |
696 | |
697 | static int nv3052c_enable(struct drm_panel *panel) |
698 | { |
699 | struct nv3052c *priv = to_nv3052c(panel); |
700 | struct mipi_dbi *dbi = &priv->dbi; |
701 | int err; |
702 | |
703 | err = mipi_dbi_command(dbi, MIPI_DCS_SET_DISPLAY_ON); |
704 | if (err) { |
705 | dev_err(priv->dev, "Unable to enable display: %d\n" , err); |
706 | return err; |
707 | } |
708 | |
709 | if (panel->backlight) { |
710 | /* Wait for the picture to be ready before enabling backlight */ |
711 | msleep(msecs: 120); |
712 | } |
713 | |
714 | return 0; |
715 | } |
716 | |
717 | static int nv3052c_disable(struct drm_panel *panel) |
718 | { |
719 | struct nv3052c *priv = to_nv3052c(panel); |
720 | struct mipi_dbi *dbi = &priv->dbi; |
721 | int err; |
722 | |
723 | err = mipi_dbi_command(dbi, MIPI_DCS_SET_DISPLAY_OFF); |
724 | if (err) { |
725 | dev_err(priv->dev, "Unable to disable display: %d\n" , err); |
726 | return err; |
727 | } |
728 | |
729 | return 0; |
730 | } |
731 | |
732 | static int nv3052c_get_modes(struct drm_panel *panel, |
733 | struct drm_connector *connector) |
734 | { |
735 | struct nv3052c *priv = to_nv3052c(panel); |
736 | const struct nv3052c_panel_info *panel_info = priv->panel_info; |
737 | struct drm_display_mode *mode; |
738 | unsigned int i; |
739 | |
740 | for (i = 0; i < panel_info->num_modes; i++) { |
741 | mode = drm_mode_duplicate(dev: connector->dev, |
742 | mode: &panel_info->display_modes[i]); |
743 | if (!mode) |
744 | return -ENOMEM; |
745 | |
746 | drm_mode_set_name(mode); |
747 | |
748 | mode->type = DRM_MODE_TYPE_DRIVER; |
749 | if (panel_info->num_modes == 1) |
750 | mode->type |= DRM_MODE_TYPE_PREFERRED; |
751 | |
752 | drm_mode_probed_add(connector, mode); |
753 | } |
754 | |
755 | connector->display_info.bpc = 8; |
756 | connector->display_info.width_mm = panel_info->width_mm; |
757 | connector->display_info.height_mm = panel_info->height_mm; |
758 | |
759 | drm_display_info_set_bus_formats(info: &connector->display_info, |
760 | formats: &panel_info->bus_format, num_formats: 1); |
761 | connector->display_info.bus_flags = panel_info->bus_flags; |
762 | |
763 | return panel_info->num_modes; |
764 | } |
765 | |
766 | static const struct drm_panel_funcs nv3052c_funcs = { |
767 | .prepare = nv3052c_prepare, |
768 | .unprepare = nv3052c_unprepare, |
769 | .enable = nv3052c_enable, |
770 | .disable = nv3052c_disable, |
771 | .get_modes = nv3052c_get_modes, |
772 | }; |
773 | |
774 | static int nv3052c_probe(struct spi_device *spi) |
775 | { |
776 | struct device *dev = &spi->dev; |
777 | struct nv3052c *priv; |
778 | int err; |
779 | |
780 | priv = devm_kzalloc(dev, size: sizeof(*priv), GFP_KERNEL); |
781 | if (!priv) |
782 | return -ENOMEM; |
783 | |
784 | priv->dev = dev; |
785 | |
786 | priv->panel_info = of_device_get_match_data(dev); |
787 | if (!priv->panel_info) |
788 | return -EINVAL; |
789 | |
790 | priv->supply = devm_regulator_get(dev, id: "power" ); |
791 | if (IS_ERR(ptr: priv->supply)) |
792 | return dev_err_probe(dev, err: PTR_ERR(ptr: priv->supply), fmt: "Failed to get power supply\n" ); |
793 | |
794 | priv->reset_gpio = devm_gpiod_get(dev, con_id: "reset" , flags: GPIOD_OUT_HIGH); |
795 | if (IS_ERR(ptr: priv->reset_gpio)) |
796 | return dev_err_probe(dev, err: PTR_ERR(ptr: priv->reset_gpio), fmt: "Failed to get reset GPIO\n" ); |
797 | |
798 | err = mipi_dbi_spi_init(spi, dbi: &priv->dbi, NULL); |
799 | if (err) |
800 | return dev_err_probe(dev, err, fmt: "MIPI DBI init failed\n" ); |
801 | |
802 | priv->dbi.read_commands = NULL; |
803 | |
804 | spi_set_drvdata(spi, data: priv); |
805 | |
806 | drm_panel_init(panel: &priv->panel, dev, funcs: &nv3052c_funcs, |
807 | DRM_MODE_CONNECTOR_DPI); |
808 | |
809 | err = drm_panel_of_backlight(panel: &priv->panel); |
810 | if (err) |
811 | return dev_err_probe(dev, err, fmt: "Failed to attach backlight\n" ); |
812 | |
813 | drm_panel_add(panel: &priv->panel); |
814 | |
815 | return 0; |
816 | } |
817 | |
818 | static void nv3052c_remove(struct spi_device *spi) |
819 | { |
820 | struct nv3052c *priv = spi_get_drvdata(spi); |
821 | |
822 | drm_panel_remove(panel: &priv->panel); |
823 | drm_panel_disable(panel: &priv->panel); |
824 | drm_panel_unprepare(panel: &priv->panel); |
825 | } |
826 | |
827 | static const struct drm_display_mode ltk035c5444t_modes[] = { |
828 | { /* 60 Hz */ |
829 | .clock = 24000, |
830 | .hdisplay = 640, |
831 | .hsync_start = 640 + 96, |
832 | .hsync_end = 640 + 96 + 16, |
833 | .htotal = 640 + 96 + 16 + 48, |
834 | .vdisplay = 480, |
835 | .vsync_start = 480 + 5, |
836 | .vsync_end = 480 + 5 + 2, |
837 | .vtotal = 480 + 5 + 2 + 13, |
838 | .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC, |
839 | }, |
840 | { /* 50 Hz */ |
841 | .clock = 18000, |
842 | .hdisplay = 640, |
843 | .hsync_start = 640 + 39, |
844 | .hsync_end = 640 + 39 + 2, |
845 | .htotal = 640 + 39 + 2 + 39, |
846 | .vdisplay = 480, |
847 | .vsync_start = 480 + 5, |
848 | .vsync_end = 480 + 5 + 2, |
849 | .vtotal = 480 + 5 + 2 + 13, |
850 | .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC, |
851 | }, |
852 | }; |
853 | |
854 | static const struct drm_display_mode fs035vg158_modes[] = { |
855 | { /* 60 Hz */ |
856 | .clock = 21000, |
857 | .hdisplay = 640, |
858 | .hsync_start = 640 + 34, |
859 | .hsync_end = 640 + 34 + 4, |
860 | .htotal = 640 + 34 + 4 + 20, |
861 | .vdisplay = 480, |
862 | .vsync_start = 480 + 12, |
863 | .vsync_end = 480 + 12 + 4, |
864 | .vtotal = 480 + 12 + 4 + 6, |
865 | .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC, |
866 | }, |
867 | }; |
868 | |
869 | static const struct drm_display_mode wl_355608_a8_mode[] = { |
870 | { |
871 | .clock = 24000, |
872 | .hdisplay = 640, |
873 | .hsync_start = 640 + 64, |
874 | .hsync_end = 640 + 64 + 20, |
875 | .htotal = 640 + 64 + 20 + 46, |
876 | .vdisplay = 480, |
877 | .vsync_start = 480 + 21, |
878 | .vsync_end = 480 + 21 + 4, |
879 | .vtotal = 480 + 21 + 4 + 15, |
880 | .flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC, |
881 | }, |
882 | }; |
883 | |
884 | static const struct nv3052c_panel_info ltk035c5444t_panel_info = { |
885 | .display_modes = ltk035c5444t_modes, |
886 | .num_modes = ARRAY_SIZE(ltk035c5444t_modes), |
887 | .width_mm = 77, |
888 | .height_mm = 64, |
889 | .bus_format = MEDIA_BUS_FMT_RGB888_1X24, |
890 | .bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE, |
891 | .panel_regs = ltk035c5444t_panel_regs, |
892 | .panel_regs_len = ARRAY_SIZE(ltk035c5444t_panel_regs), |
893 | }; |
894 | |
895 | static const struct nv3052c_panel_info fs035vg158_panel_info = { |
896 | .display_modes = fs035vg158_modes, |
897 | .num_modes = ARRAY_SIZE(fs035vg158_modes), |
898 | .width_mm = 70, |
899 | .height_mm = 53, |
900 | .bus_format = MEDIA_BUS_FMT_RGB888_1X24, |
901 | .bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE, |
902 | .panel_regs = fs035vg158_panel_regs, |
903 | .panel_regs_len = ARRAY_SIZE(fs035vg158_panel_regs), |
904 | }; |
905 | |
906 | static const struct nv3052c_panel_info wl_355608_a8_panel_info = { |
907 | .display_modes = wl_355608_a8_mode, |
908 | .num_modes = ARRAY_SIZE(wl_355608_a8_mode), |
909 | .width_mm = 150, |
910 | .height_mm = 94, |
911 | .bus_format = MEDIA_BUS_FMT_RGB888_1X24, |
912 | .bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE, |
913 | .panel_regs = wl_355608_a8_panel_regs, |
914 | .panel_regs_len = ARRAY_SIZE(wl_355608_a8_panel_regs), |
915 | }; |
916 | |
917 | static const struct spi_device_id nv3052c_ids[] = { |
918 | { "ltk035c5444t" , }, |
919 | { "fs035vg158" , }, |
920 | { "rg35xx-plus-panel" , }, |
921 | { /* sentinel */ } |
922 | }; |
923 | MODULE_DEVICE_TABLE(spi, nv3052c_ids); |
924 | |
925 | static const struct of_device_id nv3052c_of_match[] = { |
926 | { .compatible = "leadtek,ltk035c5444t" , .data = <k035c5444t_panel_info }, |
927 | { .compatible = "fascontek,fs035vg158" , .data = &fs035vg158_panel_info }, |
928 | { .compatible = "anbernic,rg35xx-plus-panel" , .data = &wl_355608_a8_panel_info }, |
929 | { /* sentinel */ } |
930 | }; |
931 | MODULE_DEVICE_TABLE(of, nv3052c_of_match); |
932 | |
933 | static struct spi_driver nv3052c_driver = { |
934 | .driver = { |
935 | .name = "nv3052c" , |
936 | .of_match_table = nv3052c_of_match, |
937 | }, |
938 | .id_table = nv3052c_ids, |
939 | .probe = nv3052c_probe, |
940 | .remove = nv3052c_remove, |
941 | }; |
942 | module_spi_driver(nv3052c_driver); |
943 | |
944 | MODULE_AUTHOR("Paul Cercueil <paul@crapouillou.net>" ); |
945 | MODULE_AUTHOR("Christophe Branchereau <cbranchereau@gmail.com>" ); |
946 | MODULE_AUTHOR("Ryan Walklin <ryan@testtoast.com" ); |
947 | MODULE_DESCRIPTION("NewVision NV3052C IPS LCD panel driver" ); |
948 | MODULE_LICENSE("GPL v2" ); |
949 | |