1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* |
3 | * Copyright (c) 2019 Radxa Limited |
4 | * Copyright (c) 2022 Edgeble AI Technologies Pvt. Ltd. |
5 | * |
6 | * Author: |
7 | * - Jagan Teki <jagan@amarulasolutions.com> |
8 | * - Stephen Chen <stephen@radxa.com> |
9 | */ |
10 | |
11 | #include <drm/drm_mipi_dsi.h> |
12 | #include <drm/drm_modes.h> |
13 | #include <drm/drm_panel.h> |
14 | #include <drm/drm_print.h> |
15 | |
16 | #include <linux/gpio/consumer.h> |
17 | #include <linux/delay.h> |
18 | #include <linux/module.h> |
19 | #include <linux/of.h> |
20 | #include <linux/regulator/consumer.h> |
21 | |
22 | #define JD9365DA_INIT_CMD_LEN 2 |
23 | |
24 | struct jadard_init_cmd { |
25 | u8 data[JD9365DA_INIT_CMD_LEN]; |
26 | }; |
27 | |
28 | struct jadard_panel_desc { |
29 | const struct drm_display_mode mode; |
30 | unsigned int lanes; |
31 | enum mipi_dsi_pixel_format format; |
32 | const struct jadard_init_cmd *init_cmds; |
33 | u32 num_init_cmds; |
34 | }; |
35 | |
36 | struct jadard { |
37 | struct drm_panel panel; |
38 | struct mipi_dsi_device *dsi; |
39 | const struct jadard_panel_desc *desc; |
40 | |
41 | struct regulator *vdd; |
42 | struct regulator *vccio; |
43 | struct gpio_desc *reset; |
44 | }; |
45 | |
46 | static inline struct jadard *panel_to_jadard(struct drm_panel *panel) |
47 | { |
48 | return container_of(panel, struct jadard, panel); |
49 | } |
50 | |
51 | static int jadard_enable(struct drm_panel *panel) |
52 | { |
53 | struct device *dev = panel->dev; |
54 | struct jadard *jadard = panel_to_jadard(panel); |
55 | const struct jadard_panel_desc *desc = jadard->desc; |
56 | struct mipi_dsi_device *dsi = jadard->dsi; |
57 | unsigned int i; |
58 | int err; |
59 | |
60 | msleep(msecs: 10); |
61 | |
62 | for (i = 0; i < desc->num_init_cmds; i++) { |
63 | const struct jadard_init_cmd *cmd = &desc->init_cmds[i]; |
64 | |
65 | err = mipi_dsi_dcs_write_buffer(dsi, data: cmd->data, JD9365DA_INIT_CMD_LEN); |
66 | if (err < 0) |
67 | return err; |
68 | } |
69 | |
70 | msleep(msecs: 120); |
71 | |
72 | err = mipi_dsi_dcs_exit_sleep_mode(dsi); |
73 | if (err < 0) |
74 | DRM_DEV_ERROR(dev, "failed to exit sleep mode ret = %d\n" , err); |
75 | |
76 | err = mipi_dsi_dcs_set_display_on(dsi); |
77 | if (err < 0) |
78 | DRM_DEV_ERROR(dev, "failed to set display on ret = %d\n" , err); |
79 | |
80 | return 0; |
81 | } |
82 | |
83 | static int jadard_disable(struct drm_panel *panel) |
84 | { |
85 | struct device *dev = panel->dev; |
86 | struct jadard *jadard = panel_to_jadard(panel); |
87 | int ret; |
88 | |
89 | ret = mipi_dsi_dcs_set_display_off(dsi: jadard->dsi); |
90 | if (ret < 0) |
91 | DRM_DEV_ERROR(dev, "failed to set display off: %d\n" , ret); |
92 | |
93 | ret = mipi_dsi_dcs_enter_sleep_mode(dsi: jadard->dsi); |
94 | if (ret < 0) |
95 | DRM_DEV_ERROR(dev, "failed to enter sleep mode: %d\n" , ret); |
96 | |
97 | return 0; |
98 | } |
99 | |
100 | static int jadard_prepare(struct drm_panel *panel) |
101 | { |
102 | struct jadard *jadard = panel_to_jadard(panel); |
103 | int ret; |
104 | |
105 | ret = regulator_enable(regulator: jadard->vccio); |
106 | if (ret) |
107 | return ret; |
108 | |
109 | ret = regulator_enable(regulator: jadard->vdd); |
110 | if (ret) |
111 | return ret; |
112 | |
113 | gpiod_set_value(desc: jadard->reset, value: 1); |
114 | msleep(msecs: 5); |
115 | |
116 | gpiod_set_value(desc: jadard->reset, value: 0); |
117 | msleep(msecs: 10); |
118 | |
119 | gpiod_set_value(desc: jadard->reset, value: 1); |
120 | msleep(msecs: 120); |
121 | |
122 | return 0; |
123 | } |
124 | |
125 | static int jadard_unprepare(struct drm_panel *panel) |
126 | { |
127 | struct jadard *jadard = panel_to_jadard(panel); |
128 | |
129 | gpiod_set_value(desc: jadard->reset, value: 1); |
130 | msleep(msecs: 120); |
131 | |
132 | regulator_disable(regulator: jadard->vdd); |
133 | regulator_disable(regulator: jadard->vccio); |
134 | |
135 | return 0; |
136 | } |
137 | |
138 | static int jadard_get_modes(struct drm_panel *panel, |
139 | struct drm_connector *connector) |
140 | { |
141 | struct jadard *jadard = panel_to_jadard(panel); |
142 | const struct drm_display_mode *desc_mode = &jadard->desc->mode; |
143 | struct drm_display_mode *mode; |
144 | |
145 | mode = drm_mode_duplicate(dev: connector->dev, mode: desc_mode); |
146 | if (!mode) { |
147 | DRM_DEV_ERROR(&jadard->dsi->dev, "failed to add mode %ux%ux@%u\n" , |
148 | desc_mode->hdisplay, desc_mode->vdisplay, |
149 | drm_mode_vrefresh(desc_mode)); |
150 | return -ENOMEM; |
151 | } |
152 | |
153 | drm_mode_set_name(mode); |
154 | drm_mode_probed_add(connector, mode); |
155 | |
156 | connector->display_info.width_mm = mode->width_mm; |
157 | connector->display_info.height_mm = mode->height_mm; |
158 | |
159 | return 1; |
160 | } |
161 | |
162 | static const struct drm_panel_funcs jadard_funcs = { |
163 | .disable = jadard_disable, |
164 | .unprepare = jadard_unprepare, |
165 | .prepare = jadard_prepare, |
166 | .enable = jadard_enable, |
167 | .get_modes = jadard_get_modes, |
168 | }; |
169 | |
170 | static const struct jadard_init_cmd radxa_display_8hd_ad002_init_cmds[] = { |
171 | { .data = { 0xE0, 0x00 } }, |
172 | { .data = { 0xE1, 0x93 } }, |
173 | { .data = { 0xE2, 0x65 } }, |
174 | { .data = { 0xE3, 0xF8 } }, |
175 | { .data = { 0x80, 0x03 } }, |
176 | { .data = { 0xE0, 0x01 } }, |
177 | { .data = { 0x00, 0x00 } }, |
178 | { .data = { 0x01, 0x7E } }, |
179 | { .data = { 0x03, 0x00 } }, |
180 | { .data = { 0x04, 0x65 } }, |
181 | { .data = { 0x0C, 0x74 } }, |
182 | { .data = { 0x17, 0x00 } }, |
183 | { .data = { 0x18, 0xB7 } }, |
184 | { .data = { 0x19, 0x00 } }, |
185 | { .data = { 0x1A, 0x00 } }, |
186 | { .data = { 0x1B, 0xB7 } }, |
187 | { .data = { 0x1C, 0x00 } }, |
188 | { .data = { 0x24, 0xFE } }, |
189 | { .data = { 0x37, 0x19 } }, |
190 | { .data = { 0x38, 0x05 } }, |
191 | { .data = { 0x39, 0x00 } }, |
192 | { .data = { 0x3A, 0x01 } }, |
193 | { .data = { 0x3B, 0x01 } }, |
194 | { .data = { 0x3C, 0x70 } }, |
195 | { .data = { 0x3D, 0xFF } }, |
196 | { .data = { 0x3E, 0xFF } }, |
197 | { .data = { 0x3F, 0xFF } }, |
198 | { .data = { 0x40, 0x06 } }, |
199 | { .data = { 0x41, 0xA0 } }, |
200 | { .data = { 0x43, 0x1E } }, |
201 | { .data = { 0x44, 0x0F } }, |
202 | { .data = { 0x45, 0x28 } }, |
203 | { .data = { 0x4B, 0x04 } }, |
204 | { .data = { 0x55, 0x02 } }, |
205 | { .data = { 0x56, 0x01 } }, |
206 | { .data = { 0x57, 0xA9 } }, |
207 | { .data = { 0x58, 0x0A } }, |
208 | { .data = { 0x59, 0x0A } }, |
209 | { .data = { 0x5A, 0x37 } }, |
210 | { .data = { 0x5B, 0x19 } }, |
211 | { .data = { 0x5D, 0x78 } }, |
212 | { .data = { 0x5E, 0x63 } }, |
213 | { .data = { 0x5F, 0x54 } }, |
214 | { .data = { 0x60, 0x49 } }, |
215 | { .data = { 0x61, 0x45 } }, |
216 | { .data = { 0x62, 0x38 } }, |
217 | { .data = { 0x63, 0x3D } }, |
218 | { .data = { 0x64, 0x28 } }, |
219 | { .data = { 0x65, 0x43 } }, |
220 | { .data = { 0x66, 0x41 } }, |
221 | { .data = { 0x67, 0x43 } }, |
222 | { .data = { 0x68, 0x62 } }, |
223 | { .data = { 0x69, 0x50 } }, |
224 | { .data = { 0x6A, 0x57 } }, |
225 | { .data = { 0x6B, 0x49 } }, |
226 | { .data = { 0x6C, 0x44 } }, |
227 | { .data = { 0x6D, 0x37 } }, |
228 | { .data = { 0x6E, 0x23 } }, |
229 | { .data = { 0x6F, 0x10 } }, |
230 | { .data = { 0x70, 0x78 } }, |
231 | { .data = { 0x71, 0x63 } }, |
232 | { .data = { 0x72, 0x54 } }, |
233 | { .data = { 0x73, 0x49 } }, |
234 | { .data = { 0x74, 0x45 } }, |
235 | { .data = { 0x75, 0x38 } }, |
236 | { .data = { 0x76, 0x3D } }, |
237 | { .data = { 0x77, 0x28 } }, |
238 | { .data = { 0x78, 0x43 } }, |
239 | { .data = { 0x79, 0x41 } }, |
240 | { .data = { 0x7A, 0x43 } }, |
241 | { .data = { 0x7B, 0x62 } }, |
242 | { .data = { 0x7C, 0x50 } }, |
243 | { .data = { 0x7D, 0x57 } }, |
244 | { .data = { 0x7E, 0x49 } }, |
245 | { .data = { 0x7F, 0x44 } }, |
246 | { .data = { 0x80, 0x37 } }, |
247 | { .data = { 0x81, 0x23 } }, |
248 | { .data = { 0x82, 0x10 } }, |
249 | { .data = { 0xE0, 0x02 } }, |
250 | { .data = { 0x00, 0x47 } }, |
251 | { .data = { 0x01, 0x47 } }, |
252 | { .data = { 0x02, 0x45 } }, |
253 | { .data = { 0x03, 0x45 } }, |
254 | { .data = { 0x04, 0x4B } }, |
255 | { .data = { 0x05, 0x4B } }, |
256 | { .data = { 0x06, 0x49 } }, |
257 | { .data = { 0x07, 0x49 } }, |
258 | { .data = { 0x08, 0x41 } }, |
259 | { .data = { 0x09, 0x1F } }, |
260 | { .data = { 0x0A, 0x1F } }, |
261 | { .data = { 0x0B, 0x1F } }, |
262 | { .data = { 0x0C, 0x1F } }, |
263 | { .data = { 0x0D, 0x1F } }, |
264 | { .data = { 0x0E, 0x1F } }, |
265 | { .data = { 0x0F, 0x5F } }, |
266 | { .data = { 0x10, 0x5F } }, |
267 | { .data = { 0x11, 0x57 } }, |
268 | { .data = { 0x12, 0x77 } }, |
269 | { .data = { 0x13, 0x35 } }, |
270 | { .data = { 0x14, 0x1F } }, |
271 | { .data = { 0x15, 0x1F } }, |
272 | { .data = { 0x16, 0x46 } }, |
273 | { .data = { 0x17, 0x46 } }, |
274 | { .data = { 0x18, 0x44 } }, |
275 | { .data = { 0x19, 0x44 } }, |
276 | { .data = { 0x1A, 0x4A } }, |
277 | { .data = { 0x1B, 0x4A } }, |
278 | { .data = { 0x1C, 0x48 } }, |
279 | { .data = { 0x1D, 0x48 } }, |
280 | { .data = { 0x1E, 0x40 } }, |
281 | { .data = { 0x1F, 0x1F } }, |
282 | { .data = { 0x20, 0x1F } }, |
283 | { .data = { 0x21, 0x1F } }, |
284 | { .data = { 0x22, 0x1F } }, |
285 | { .data = { 0x23, 0x1F } }, |
286 | { .data = { 0x24, 0x1F } }, |
287 | { .data = { 0x25, 0x5F } }, |
288 | { .data = { 0x26, 0x5F } }, |
289 | { .data = { 0x27, 0x57 } }, |
290 | { .data = { 0x28, 0x77 } }, |
291 | { .data = { 0x29, 0x35 } }, |
292 | { .data = { 0x2A, 0x1F } }, |
293 | { .data = { 0x2B, 0x1F } }, |
294 | { .data = { 0x58, 0x40 } }, |
295 | { .data = { 0x59, 0x00 } }, |
296 | { .data = { 0x5A, 0x00 } }, |
297 | { .data = { 0x5B, 0x10 } }, |
298 | { .data = { 0x5C, 0x06 } }, |
299 | { .data = { 0x5D, 0x40 } }, |
300 | { .data = { 0x5E, 0x01 } }, |
301 | { .data = { 0x5F, 0x02 } }, |
302 | { .data = { 0x60, 0x30 } }, |
303 | { .data = { 0x61, 0x01 } }, |
304 | { .data = { 0x62, 0x02 } }, |
305 | { .data = { 0x63, 0x03 } }, |
306 | { .data = { 0x64, 0x6B } }, |
307 | { .data = { 0x65, 0x05 } }, |
308 | { .data = { 0x66, 0x0C } }, |
309 | { .data = { 0x67, 0x73 } }, |
310 | { .data = { 0x68, 0x09 } }, |
311 | { .data = { 0x69, 0x03 } }, |
312 | { .data = { 0x6A, 0x56 } }, |
313 | { .data = { 0x6B, 0x08 } }, |
314 | { .data = { 0x6C, 0x00 } }, |
315 | { .data = { 0x6D, 0x04 } }, |
316 | { .data = { 0x6E, 0x04 } }, |
317 | { .data = { 0x6F, 0x88 } }, |
318 | { .data = { 0x70, 0x00 } }, |
319 | { .data = { 0x71, 0x00 } }, |
320 | { .data = { 0x72, 0x06 } }, |
321 | { .data = { 0x73, 0x7B } }, |
322 | { .data = { 0x74, 0x00 } }, |
323 | { .data = { 0x75, 0xF8 } }, |
324 | { .data = { 0x76, 0x00 } }, |
325 | { .data = { 0x77, 0xD5 } }, |
326 | { .data = { 0x78, 0x2E } }, |
327 | { .data = { 0x79, 0x12 } }, |
328 | { .data = { 0x7A, 0x03 } }, |
329 | { .data = { 0x7B, 0x00 } }, |
330 | { .data = { 0x7C, 0x00 } }, |
331 | { .data = { 0x7D, 0x03 } }, |
332 | { .data = { 0x7E, 0x7B } }, |
333 | { .data = { 0xE0, 0x04 } }, |
334 | { .data = { 0x00, 0x0E } }, |
335 | { .data = { 0x02, 0xB3 } }, |
336 | { .data = { 0x09, 0x60 } }, |
337 | { .data = { 0x0E, 0x2A } }, |
338 | { .data = { 0x36, 0x59 } }, |
339 | { .data = { 0xE0, 0x00 } }, |
340 | }; |
341 | |
342 | static const struct jadard_panel_desc radxa_display_8hd_ad002_desc = { |
343 | .mode = { |
344 | .clock = 70000, |
345 | |
346 | .hdisplay = 800, |
347 | .hsync_start = 800 + 40, |
348 | .hsync_end = 800 + 40 + 18, |
349 | .htotal = 800 + 40 + 18 + 20, |
350 | |
351 | .vdisplay = 1280, |
352 | .vsync_start = 1280 + 20, |
353 | .vsync_end = 1280 + 20 + 4, |
354 | .vtotal = 1280 + 20 + 4 + 20, |
355 | |
356 | .width_mm = 127, |
357 | .height_mm = 199, |
358 | .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED, |
359 | }, |
360 | .lanes = 4, |
361 | .format = MIPI_DSI_FMT_RGB888, |
362 | .init_cmds = radxa_display_8hd_ad002_init_cmds, |
363 | .num_init_cmds = ARRAY_SIZE(radxa_display_8hd_ad002_init_cmds), |
364 | }; |
365 | |
366 | static const struct jadard_init_cmd cz101b4001_init_cmds[] = { |
367 | { .data = { 0xE0, 0x00 } }, |
368 | { .data = { 0xE1, 0x93 } }, |
369 | { .data = { 0xE2, 0x65 } }, |
370 | { .data = { 0xE3, 0xF8 } }, |
371 | { .data = { 0x80, 0x03 } }, |
372 | { .data = { 0xE0, 0x01 } }, |
373 | { .data = { 0x00, 0x00 } }, |
374 | { .data = { 0x01, 0x3B } }, |
375 | { .data = { 0x0C, 0x74 } }, |
376 | { .data = { 0x17, 0x00 } }, |
377 | { .data = { 0x18, 0xAF } }, |
378 | { .data = { 0x19, 0x00 } }, |
379 | { .data = { 0x1A, 0x00 } }, |
380 | { .data = { 0x1B, 0xAF } }, |
381 | { .data = { 0x1C, 0x00 } }, |
382 | { .data = { 0x35, 0x26 } }, |
383 | { .data = { 0x37, 0x09 } }, |
384 | { .data = { 0x38, 0x04 } }, |
385 | { .data = { 0x39, 0x00 } }, |
386 | { .data = { 0x3A, 0x01 } }, |
387 | { .data = { 0x3C, 0x78 } }, |
388 | { .data = { 0x3D, 0xFF } }, |
389 | { .data = { 0x3E, 0xFF } }, |
390 | { .data = { 0x3F, 0x7F } }, |
391 | { .data = { 0x40, 0x06 } }, |
392 | { .data = { 0x41, 0xA0 } }, |
393 | { .data = { 0x42, 0x81 } }, |
394 | { .data = { 0x43, 0x14 } }, |
395 | { .data = { 0x44, 0x23 } }, |
396 | { .data = { 0x45, 0x28 } }, |
397 | { .data = { 0x55, 0x02 } }, |
398 | { .data = { 0x57, 0x69 } }, |
399 | { .data = { 0x59, 0x0A } }, |
400 | { .data = { 0x5A, 0x2A } }, |
401 | { .data = { 0x5B, 0x17 } }, |
402 | { .data = { 0x5D, 0x7F } }, |
403 | { .data = { 0x5E, 0x6B } }, |
404 | { .data = { 0x5F, 0x5C } }, |
405 | { .data = { 0x60, 0x4F } }, |
406 | { .data = { 0x61, 0x4D } }, |
407 | { .data = { 0x62, 0x3F } }, |
408 | { .data = { 0x63, 0x42 } }, |
409 | { .data = { 0x64, 0x2B } }, |
410 | { .data = { 0x65, 0x44 } }, |
411 | { .data = { 0x66, 0x43 } }, |
412 | { .data = { 0x67, 0x43 } }, |
413 | { .data = { 0x68, 0x63 } }, |
414 | { .data = { 0x69, 0x52 } }, |
415 | { .data = { 0x6A, 0x5A } }, |
416 | { .data = { 0x6B, 0x4F } }, |
417 | { .data = { 0x6C, 0x4E } }, |
418 | { .data = { 0x6D, 0x20 } }, |
419 | { .data = { 0x6E, 0x0F } }, |
420 | { .data = { 0x6F, 0x00 } }, |
421 | { .data = { 0x70, 0x7F } }, |
422 | { .data = { 0x71, 0x6B } }, |
423 | { .data = { 0x72, 0x5C } }, |
424 | { .data = { 0x73, 0x4F } }, |
425 | { .data = { 0x74, 0x4D } }, |
426 | { .data = { 0x75, 0x3F } }, |
427 | { .data = { 0x76, 0x42 } }, |
428 | { .data = { 0x77, 0x2B } }, |
429 | { .data = { 0x78, 0x44 } }, |
430 | { .data = { 0x79, 0x43 } }, |
431 | { .data = { 0x7A, 0x43 } }, |
432 | { .data = { 0x7B, 0x63 } }, |
433 | { .data = { 0x7C, 0x52 } }, |
434 | { .data = { 0x7D, 0x5A } }, |
435 | { .data = { 0x7E, 0x4F } }, |
436 | { .data = { 0x7F, 0x4E } }, |
437 | { .data = { 0x80, 0x20 } }, |
438 | { .data = { 0x81, 0x0F } }, |
439 | { .data = { 0x82, 0x00 } }, |
440 | { .data = { 0xE0, 0x02 } }, |
441 | { .data = { 0x00, 0x02 } }, |
442 | { .data = { 0x01, 0x02 } }, |
443 | { .data = { 0x02, 0x00 } }, |
444 | { .data = { 0x03, 0x00 } }, |
445 | { .data = { 0x04, 0x1E } }, |
446 | { .data = { 0x05, 0x1E } }, |
447 | { .data = { 0x06, 0x1F } }, |
448 | { .data = { 0x07, 0x1F } }, |
449 | { .data = { 0x08, 0x1F } }, |
450 | { .data = { 0x09, 0x17 } }, |
451 | { .data = { 0x0A, 0x17 } }, |
452 | { .data = { 0x0B, 0x37 } }, |
453 | { .data = { 0x0C, 0x37 } }, |
454 | { .data = { 0x0D, 0x47 } }, |
455 | { .data = { 0x0E, 0x47 } }, |
456 | { .data = { 0x0F, 0x45 } }, |
457 | { .data = { 0x10, 0x45 } }, |
458 | { .data = { 0x11, 0x4B } }, |
459 | { .data = { 0x12, 0x4B } }, |
460 | { .data = { 0x13, 0x49 } }, |
461 | { .data = { 0x14, 0x49 } }, |
462 | { .data = { 0x15, 0x1F } }, |
463 | { .data = { 0x16, 0x01 } }, |
464 | { .data = { 0x17, 0x01 } }, |
465 | { .data = { 0x18, 0x00 } }, |
466 | { .data = { 0x19, 0x00 } }, |
467 | { .data = { 0x1A, 0x1E } }, |
468 | { .data = { 0x1B, 0x1E } }, |
469 | { .data = { 0x1C, 0x1F } }, |
470 | { .data = { 0x1D, 0x1F } }, |
471 | { .data = { 0x1E, 0x1F } }, |
472 | { .data = { 0x1F, 0x17 } }, |
473 | { .data = { 0x20, 0x17 } }, |
474 | { .data = { 0x21, 0x37 } }, |
475 | { .data = { 0x22, 0x37 } }, |
476 | { .data = { 0x23, 0x46 } }, |
477 | { .data = { 0x24, 0x46 } }, |
478 | { .data = { 0x25, 0x44 } }, |
479 | { .data = { 0x26, 0x44 } }, |
480 | { .data = { 0x27, 0x4A } }, |
481 | { .data = { 0x28, 0x4A } }, |
482 | { .data = { 0x29, 0x48 } }, |
483 | { .data = { 0x2A, 0x48 } }, |
484 | { .data = { 0x2B, 0x1F } }, |
485 | { .data = { 0x2C, 0x01 } }, |
486 | { .data = { 0x2D, 0x01 } }, |
487 | { .data = { 0x2E, 0x00 } }, |
488 | { .data = { 0x2F, 0x00 } }, |
489 | { .data = { 0x30, 0x1F } }, |
490 | { .data = { 0x31, 0x1F } }, |
491 | { .data = { 0x32, 0x1E } }, |
492 | { .data = { 0x33, 0x1E } }, |
493 | { .data = { 0x34, 0x1F } }, |
494 | { .data = { 0x35, 0x17 } }, |
495 | { .data = { 0x36, 0x17 } }, |
496 | { .data = { 0x37, 0x37 } }, |
497 | { .data = { 0x38, 0x37 } }, |
498 | { .data = { 0x39, 0x08 } }, |
499 | { .data = { 0x3A, 0x08 } }, |
500 | { .data = { 0x3B, 0x0A } }, |
501 | { .data = { 0x3C, 0x0A } }, |
502 | { .data = { 0x3D, 0x04 } }, |
503 | { .data = { 0x3E, 0x04 } }, |
504 | { .data = { 0x3F, 0x06 } }, |
505 | { .data = { 0x40, 0x06 } }, |
506 | { .data = { 0x41, 0x1F } }, |
507 | { .data = { 0x42, 0x02 } }, |
508 | { .data = { 0x43, 0x02 } }, |
509 | { .data = { 0x44, 0x00 } }, |
510 | { .data = { 0x45, 0x00 } }, |
511 | { .data = { 0x46, 0x1F } }, |
512 | { .data = { 0x47, 0x1F } }, |
513 | { .data = { 0x48, 0x1E } }, |
514 | { .data = { 0x49, 0x1E } }, |
515 | { .data = { 0x4A, 0x1F } }, |
516 | { .data = { 0x4B, 0x17 } }, |
517 | { .data = { 0x4C, 0x17 } }, |
518 | { .data = { 0x4D, 0x37 } }, |
519 | { .data = { 0x4E, 0x37 } }, |
520 | { .data = { 0x4F, 0x09 } }, |
521 | { .data = { 0x50, 0x09 } }, |
522 | { .data = { 0x51, 0x0B } }, |
523 | { .data = { 0x52, 0x0B } }, |
524 | { .data = { 0x53, 0x05 } }, |
525 | { .data = { 0x54, 0x05 } }, |
526 | { .data = { 0x55, 0x07 } }, |
527 | { .data = { 0x56, 0x07 } }, |
528 | { .data = { 0x57, 0x1F } }, |
529 | { .data = { 0x58, 0x40 } }, |
530 | { .data = { 0x5B, 0x30 } }, |
531 | { .data = { 0x5C, 0x16 } }, |
532 | { .data = { 0x5D, 0x34 } }, |
533 | { .data = { 0x5E, 0x05 } }, |
534 | { .data = { 0x5F, 0x02 } }, |
535 | { .data = { 0x63, 0x00 } }, |
536 | { .data = { 0x64, 0x6A } }, |
537 | { .data = { 0x67, 0x73 } }, |
538 | { .data = { 0x68, 0x1D } }, |
539 | { .data = { 0x69, 0x08 } }, |
540 | { .data = { 0x6A, 0x6A } }, |
541 | { .data = { 0x6B, 0x08 } }, |
542 | { .data = { 0x6C, 0x00 } }, |
543 | { .data = { 0x6D, 0x00 } }, |
544 | { .data = { 0x6E, 0x00 } }, |
545 | { .data = { 0x6F, 0x88 } }, |
546 | { .data = { 0x75, 0xFF } }, |
547 | { .data = { 0x77, 0xDD } }, |
548 | { .data = { 0x78, 0x3F } }, |
549 | { .data = { 0x79, 0x15 } }, |
550 | { .data = { 0x7A, 0x17 } }, |
551 | { .data = { 0x7D, 0x14 } }, |
552 | { .data = { 0x7E, 0x82 } }, |
553 | { .data = { 0xE0, 0x04 } }, |
554 | { .data = { 0x00, 0x0E } }, |
555 | { .data = { 0x02, 0xB3 } }, |
556 | { .data = { 0x09, 0x61 } }, |
557 | { .data = { 0x0E, 0x48 } }, |
558 | { .data = { 0xE0, 0x00 } }, |
559 | { .data = { 0xE6, 0x02 } }, |
560 | { .data = { 0xE7, 0x0C } }, |
561 | }; |
562 | |
563 | static const struct jadard_panel_desc cz101b4001_desc = { |
564 | .mode = { |
565 | .clock = 70000, |
566 | |
567 | .hdisplay = 800, |
568 | .hsync_start = 800 + 40, |
569 | .hsync_end = 800 + 40 + 18, |
570 | .htotal = 800 + 40 + 18 + 20, |
571 | |
572 | .vdisplay = 1280, |
573 | .vsync_start = 1280 + 20, |
574 | .vsync_end = 1280 + 20 + 4, |
575 | .vtotal = 1280 + 20 + 4 + 20, |
576 | |
577 | .width_mm = 62, |
578 | .height_mm = 110, |
579 | .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED, |
580 | }, |
581 | .lanes = 4, |
582 | .format = MIPI_DSI_FMT_RGB888, |
583 | .init_cmds = cz101b4001_init_cmds, |
584 | .num_init_cmds = ARRAY_SIZE(cz101b4001_init_cmds), |
585 | }; |
586 | |
587 | static int jadard_dsi_probe(struct mipi_dsi_device *dsi) |
588 | { |
589 | struct device *dev = &dsi->dev; |
590 | const struct jadard_panel_desc *desc; |
591 | struct jadard *jadard; |
592 | int ret; |
593 | |
594 | jadard = devm_kzalloc(dev: &dsi->dev, size: sizeof(*jadard), GFP_KERNEL); |
595 | if (!jadard) |
596 | return -ENOMEM; |
597 | |
598 | desc = of_device_get_match_data(dev); |
599 | dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | |
600 | MIPI_DSI_MODE_NO_EOT_PACKET; |
601 | dsi->format = desc->format; |
602 | dsi->lanes = desc->lanes; |
603 | |
604 | jadard->reset = devm_gpiod_get(dev, con_id: "reset" , flags: GPIOD_OUT_LOW); |
605 | if (IS_ERR(ptr: jadard->reset)) { |
606 | DRM_DEV_ERROR(&dsi->dev, "failed to get our reset GPIO\n" ); |
607 | return PTR_ERR(ptr: jadard->reset); |
608 | } |
609 | |
610 | jadard->vdd = devm_regulator_get(dev, id: "vdd" ); |
611 | if (IS_ERR(ptr: jadard->vdd)) { |
612 | DRM_DEV_ERROR(&dsi->dev, "failed to get vdd regulator\n" ); |
613 | return PTR_ERR(ptr: jadard->vdd); |
614 | } |
615 | |
616 | jadard->vccio = devm_regulator_get(dev, id: "vccio" ); |
617 | if (IS_ERR(ptr: jadard->vccio)) { |
618 | DRM_DEV_ERROR(&dsi->dev, "failed to get vccio regulator\n" ); |
619 | return PTR_ERR(ptr: jadard->vccio); |
620 | } |
621 | |
622 | drm_panel_init(panel: &jadard->panel, dev, funcs: &jadard_funcs, |
623 | DRM_MODE_CONNECTOR_DSI); |
624 | |
625 | ret = drm_panel_of_backlight(panel: &jadard->panel); |
626 | if (ret) |
627 | return ret; |
628 | |
629 | drm_panel_add(panel: &jadard->panel); |
630 | |
631 | mipi_dsi_set_drvdata(dsi, data: jadard); |
632 | jadard->dsi = dsi; |
633 | jadard->desc = desc; |
634 | |
635 | ret = mipi_dsi_attach(dsi); |
636 | if (ret < 0) |
637 | drm_panel_remove(panel: &jadard->panel); |
638 | |
639 | return ret; |
640 | } |
641 | |
642 | static void jadard_dsi_remove(struct mipi_dsi_device *dsi) |
643 | { |
644 | struct jadard *jadard = mipi_dsi_get_drvdata(dsi); |
645 | |
646 | mipi_dsi_detach(dsi); |
647 | drm_panel_remove(panel: &jadard->panel); |
648 | } |
649 | |
650 | static const struct of_device_id jadard_of_match[] = { |
651 | { |
652 | .compatible = "chongzhou,cz101b4001" , |
653 | .data = &cz101b4001_desc |
654 | }, |
655 | { |
656 | .compatible = "radxa,display-10hd-ad001" , |
657 | .data = &cz101b4001_desc |
658 | }, |
659 | { |
660 | .compatible = "radxa,display-8hd-ad002" , |
661 | .data = &radxa_display_8hd_ad002_desc |
662 | }, |
663 | { /* sentinel */ } |
664 | }; |
665 | MODULE_DEVICE_TABLE(of, jadard_of_match); |
666 | |
667 | static struct mipi_dsi_driver jadard_driver = { |
668 | .probe = jadard_dsi_probe, |
669 | .remove = jadard_dsi_remove, |
670 | .driver = { |
671 | .name = "jadard-jd9365da" , |
672 | .of_match_table = jadard_of_match, |
673 | }, |
674 | }; |
675 | module_mipi_dsi_driver(jadard_driver); |
676 | |
677 | MODULE_AUTHOR("Jagan Teki <jagan@edgeble.ai>" ); |
678 | MODULE_AUTHOR("Stephen Chen <stephen@radxa.com>" ); |
679 | MODULE_DESCRIPTION("Jadard JD9365DA-H3 WXGA DSI panel" ); |
680 | MODULE_LICENSE("GPL" ); |
681 | |