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