1
2
3
4
5
6
7#define pr_fmt(fmt) "fbtft_device: " fmt
8#include <linux/module.h>
9#include <linux/kernel.h>
10#include <linux/init.h>
11#include <linux/gpio/consumer.h>
12#include <linux/spi/spi.h>
13#include <video/mipi_display.h>
14
15#include "fbtft.h"
16
17#define MAX_GPIOS 32
18
19static struct spi_device *spi_device;
20static struct platform_device *p_device;
21
22static char *name;
23module_param(name, charp, 0000);
24MODULE_PARM_DESC(name,
25 "Devicename (required). name=list => list all supported devices.");
26
27static unsigned int rotate;
28module_param(rotate, uint, 0000);
29MODULE_PARM_DESC(rotate,
30 "Angle to rotate display counter clockwise: 0, 90, 180, 270");
31
32static unsigned int busnum;
33module_param(busnum, uint, 0000);
34MODULE_PARM_DESC(busnum, "SPI bus number (default=0)");
35
36static unsigned int cs;
37module_param(cs, uint, 0000);
38MODULE_PARM_DESC(cs, "SPI chip select (default=0)");
39
40static unsigned int speed;
41module_param(speed, uint, 0000);
42MODULE_PARM_DESC(speed, "SPI speed (override device default)");
43
44static int mode = -1;
45module_param(mode, int, 0000);
46MODULE_PARM_DESC(mode, "SPI mode (override device default)");
47
48static unsigned int fps;
49module_param(fps, uint, 0000);
50MODULE_PARM_DESC(fps, "Frames per second (override driver default)");
51
52static char *gamma;
53module_param(gamma, charp, 0000);
54MODULE_PARM_DESC(gamma,
55 "String representation of Gamma Curve(s). Driver specific.");
56
57static int txbuflen;
58module_param(txbuflen, int, 0000);
59MODULE_PARM_DESC(txbuflen, "txbuflen (override driver default)");
60
61static int bgr = -1;
62module_param(bgr, int, 0000);
63MODULE_PARM_DESC(bgr,
64 "BGR bit (supported by some drivers).");
65
66static unsigned int startbyte;
67module_param(startbyte, uint, 0000);
68MODULE_PARM_DESC(startbyte, "Sets the Start byte used by some SPI displays.");
69
70static bool custom;
71module_param(custom, bool, 0000);
72MODULE_PARM_DESC(custom, "Add a custom display device. Use speed= argument to make it a SPI device, else platform_device");
73
74static unsigned int width;
75module_param(width, uint, 0000);
76MODULE_PARM_DESC(width, "Display width, used with the custom argument");
77
78static unsigned int height;
79module_param(height, uint, 0000);
80MODULE_PARM_DESC(height, "Display height, used with the custom argument");
81
82static unsigned int buswidth = 8;
83module_param(buswidth, uint, 0000);
84MODULE_PARM_DESC(buswidth, "Display bus width, used with the custom argument");
85
86static s16 init[FBTFT_MAX_INIT_SEQUENCE];
87static int init_num;
88module_param_array(init, short, &init_num, 0000);
89MODULE_PARM_DESC(init, "Init sequence, used with the custom argument");
90
91static unsigned long debug;
92module_param(debug, ulong, 0000);
93MODULE_PARM_DESC(debug,
94 "level: 0-7 (the remaining 29 bits is for advanced usage)");
95
96static unsigned int verbose = 3;
97module_param(verbose, uint, 0000);
98MODULE_PARM_DESC(verbose,
99 "0 silent, >1 show devices, >2 show devices before (default=3)");
100
101struct fbtft_device_display {
102 char *name;
103 struct spi_board_info *spi;
104 struct platform_device *pdev;
105};
106
107static void fbtft_device_pdev_release(struct device *dev);
108
109static int write_gpio16_wr_slow(struct fbtft_par *par, void *buf, size_t len);
110static void adafruit18_green_tab_set_addr_win(struct fbtft_par *par,
111 int xs, int ys, int xe, int ye);
112
113#define ADAFRUIT18_GAMMA \
114 "02 1c 07 12 37 32 29 2d 29 25 2B 39 00 01 03 10\n" \
115 "03 1d 07 06 2E 2C 29 2D 2E 2E 37 3F 00 00 02 10"
116
117#define CBERRY28_GAMMA \
118 "D0 00 14 15 13 2C 42 43 4E 09 16 14 18 21\n" \
119 "D0 00 14 15 13 0B 43 55 53 0C 17 14 23 20"
120
121static const s16 cberry28_init_sequence[] = {
122
123 -1, MIPI_DCS_EXIT_SLEEP_MODE,
124 -2, 120,
125
126
127 -1, MIPI_DCS_SET_PIXEL_FORMAT, MIPI_DCS_PIXEL_FMT_16BIT,
128
129 -1, 0xB2, 0x0C, 0x0C, 0x00, 0x33, 0x33,
130
131
132
133
134
135 -1, 0xB7, 0x35,
136
137
138
139
140
141 -1, 0xC2, 0x01, 0xFF,
142
143
144
145
146
147 -1, 0xC3, 0x17,
148
149
150 -1, 0xC4, 0x20,
151
152
153 -1, 0xBB, 0x17,
154
155
156 -1, 0xC5, 0x20,
157
158
159
160
161
162
163 -1, 0xD0, 0xA4, 0xA1,
164
165 -1, MIPI_DCS_SET_DISPLAY_ON,
166
167 -3,
168};
169
170static const s16 hy28b_init_sequence[] = {
171 -1, 0x00e7, 0x0010, -1, 0x0000, 0x0001,
172 -1, 0x0001, 0x0100, -1, 0x0002, 0x0700,
173 -1, 0x0003, 0x1030, -1, 0x0004, 0x0000,
174 -1, 0x0008, 0x0207, -1, 0x0009, 0x0000,
175 -1, 0x000a, 0x0000, -1, 0x000c, 0x0001,
176 -1, 0x000d, 0x0000, -1, 0x000f, 0x0000,
177 -1, 0x0010, 0x0000, -1, 0x0011, 0x0007,
178 -1, 0x0012, 0x0000, -1, 0x0013, 0x0000,
179 -2, 50, -1, 0x0010, 0x1590, -1, 0x0011,
180 0x0227, -2, 50, -1, 0x0012, 0x009c, -2, 50,
181 -1, 0x0013, 0x1900, -1, 0x0029, 0x0023,
182 -1, 0x002b, 0x000e, -2, 50,
183 -1, 0x0020, 0x0000, -1, 0x0021, 0x0000,
184 -2, 50, -1, 0x0050, 0x0000,
185 -1, 0x0051, 0x00ef, -1, 0x0052, 0x0000,
186 -1, 0x0053, 0x013f, -1, 0x0060, 0xa700,
187 -1, 0x0061, 0x0001, -1, 0x006a, 0x0000,
188 -1, 0x0080, 0x0000, -1, 0x0081, 0x0000,
189 -1, 0x0082, 0x0000, -1, 0x0083, 0x0000,
190 -1, 0x0084, 0x0000, -1, 0x0085, 0x0000,
191 -1, 0x0090, 0x0010, -1, 0x0092, 0x0000,
192 -1, 0x0093, 0x0003, -1, 0x0095, 0x0110,
193 -1, 0x0097, 0x0000, -1, 0x0098, 0x0000,
194 -1, 0x0007, 0x0133, -1, 0x0020, 0x0000,
195 -1, 0x0021, 0x0000, -2, 100, -3 };
196
197#define HY28B_GAMMA \
198 "04 1F 4 7 7 0 7 7 6 0\n" \
199 "0F 00 1 7 4 0 0 0 6 7"
200
201static const s16 pitft_init_sequence[] = {
202 -1, MIPI_DCS_SOFT_RESET,
203 -2, 5,
204 -1, MIPI_DCS_SET_DISPLAY_OFF,
205 -1, 0xEF, 0x03, 0x80, 0x02,
206 -1, 0xCF, 0x00, 0xC1, 0x30,
207 -1, 0xED, 0x64, 0x03, 0x12, 0x81,
208 -1, 0xE8, 0x85, 0x00, 0x78,
209 -1, 0xCB, 0x39, 0x2C, 0x00, 0x34, 0x02,
210 -1, 0xF7, 0x20,
211 -1, 0xEA, 0x00, 0x00,
212 -1, 0xC0, 0x23,
213 -1, 0xC1, 0x10,
214 -1, 0xC5, 0x3E, 0x28,
215 -1, 0xC7, 0x86,
216 -1, MIPI_DCS_SET_PIXEL_FORMAT, 0x55,
217 -1, 0xB1, 0x00, 0x18,
218 -1, 0xB6, 0x08, 0x82, 0x27,
219 -1, 0xF2, 0x00,
220 -1, MIPI_DCS_SET_GAMMA_CURVE, 0x01,
221 -1, 0xE0, 0x0F, 0x31, 0x2B, 0x0C, 0x0E, 0x08, 0x4E,
222 0xF1, 0x37, 0x07, 0x10, 0x03, 0x0E, 0x09, 0x00,
223 -1, 0xE1, 0x00, 0x0E, 0x14, 0x03, 0x11, 0x07, 0x31,
224 0xC1, 0x48, 0x08, 0x0F, 0x0C, 0x31, 0x36, 0x0F,
225 -1, MIPI_DCS_EXIT_SLEEP_MODE,
226 -2, 100,
227 -1, MIPI_DCS_SET_DISPLAY_ON,
228 -2, 20,
229 -3
230};
231
232static const s16 waveshare32b_init_sequence[] = {
233 -1, 0xCB, 0x39, 0x2C, 0x00, 0x34, 0x02,
234 -1, 0xCF, 0x00, 0xC1, 0x30,
235 -1, 0xE8, 0x85, 0x00, 0x78,
236 -1, 0xEA, 0x00, 0x00,
237 -1, 0xED, 0x64, 0x03, 0x12, 0x81,
238 -1, 0xF7, 0x20,
239 -1, 0xC0, 0x23,
240 -1, 0xC1, 0x10,
241 -1, 0xC5, 0x3E, 0x28,
242 -1, 0xC7, 0x86,
243 -1, MIPI_DCS_SET_ADDRESS_MODE, 0x28,
244 -1, MIPI_DCS_SET_PIXEL_FORMAT, 0x55,
245 -1, 0xB1, 0x00, 0x18,
246 -1, 0xB6, 0x08, 0x82, 0x27,
247 -1, 0xF2, 0x00,
248 -1, MIPI_DCS_SET_GAMMA_CURVE, 0x01,
249 -1, 0xE0, 0x0F, 0x31, 0x2B, 0x0C, 0x0E, 0x08, 0x4E,
250 0xF1, 0x37, 0x07, 0x10, 0x03, 0x0E, 0x09, 0x00,
251 -1, 0xE1, 0x00, 0x0E, 0x14, 0x03, 0x11, 0x07, 0x31,
252 0xC1, 0x48, 0x08, 0x0F, 0x0C, 0x31, 0x36, 0x0F,
253 -1, MIPI_DCS_EXIT_SLEEP_MODE,
254 -2, 120,
255 -1, MIPI_DCS_SET_DISPLAY_ON,
256 -1, MIPI_DCS_WRITE_MEMORY_START,
257 -3
258};
259
260#define PIOLED_GAMMA "0 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 " \
261 "2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 " \
262 "3 3 3 4 4 4 4 4 4 4 4 4 4 4 4"
263
264
265static struct fbtft_device_display displays[] = {
266 {
267 .name = "adafruit18",
268 .spi = &(struct spi_board_info) {
269 .modalias = "fb_st7735r",
270 .max_speed_hz = 32000000,
271 .mode = SPI_MODE_0,
272 .platform_data = &(struct fbtft_platform_data) {
273 .display = {
274 .buswidth = 8,
275 .backlight = 1,
276 },
277 .gamma = ADAFRUIT18_GAMMA,
278 }
279 }
280 }, {
281 .name = "adafruit18_green",
282 .spi = &(struct spi_board_info) {
283 .modalias = "fb_st7735r",
284 .max_speed_hz = 4000000,
285 .mode = SPI_MODE_0,
286 .platform_data = &(struct fbtft_platform_data) {
287 .display = {
288 .buswidth = 8,
289 .backlight = 1,
290 .fbtftops.set_addr_win =
291 adafruit18_green_tab_set_addr_win,
292 },
293 .bgr = true,
294 .gamma = ADAFRUIT18_GAMMA,
295 }
296 }
297 }, {
298 .name = "adafruit22",
299 .spi = &(struct spi_board_info) {
300 .modalias = "fb_hx8340bn",
301 .max_speed_hz = 32000000,
302 .mode = SPI_MODE_0,
303 .platform_data = &(struct fbtft_platform_data) {
304 .display = {
305 .buswidth = 9,
306 .backlight = 1,
307 },
308 .bgr = true,
309 }
310 }
311 }, {
312 .name = "adafruit22a",
313 .spi = &(struct spi_board_info) {
314 .modalias = "fb_ili9340",
315 .max_speed_hz = 32000000,
316 .mode = SPI_MODE_0,
317 .platform_data = &(struct fbtft_platform_data) {
318 .display = {
319 .buswidth = 8,
320 .backlight = 1,
321 },
322 .bgr = true,
323 }
324 }
325 }, {
326 .name = "adafruit28",
327 .spi = &(struct spi_board_info) {
328 .modalias = "fb_ili9341",
329 .max_speed_hz = 32000000,
330 .mode = SPI_MODE_0,
331 .platform_data = &(struct fbtft_platform_data) {
332 .display = {
333 .buswidth = 8,
334 .backlight = 1,
335 },
336 .bgr = true,
337 }
338 }
339 }, {
340 .name = "adafruit13m",
341 .spi = &(struct spi_board_info) {
342 .modalias = "fb_ssd1306",
343 .max_speed_hz = 16000000,
344 .mode = SPI_MODE_0,
345 .platform_data = &(struct fbtft_platform_data) {
346 .display = {
347 .buswidth = 8,
348 },
349 }
350 }
351 }, {
352 .name = "admatec_c-berry28",
353 .spi = &(struct spi_board_info) {
354 .modalias = "fb_st7789v",
355 .max_speed_hz = 48000000,
356 .mode = SPI_MODE_0,
357 .platform_data = &(struct fbtft_platform_data) {
358 .display = {
359 .buswidth = 8,
360 .backlight = 1,
361 .init_sequence = cberry28_init_sequence,
362 },
363 .gamma = CBERRY28_GAMMA,
364 }
365 }
366 }, {
367 .name = "agm1264k-fl",
368 .pdev = &(struct platform_device) {
369 .name = "fb_agm1264k-fl",
370 .id = 0,
371 .dev = {
372 .release = fbtft_device_pdev_release,
373 .platform_data = &(struct fbtft_platform_data) {
374 .display = {
375 .buswidth = 8,
376 .backlight = FBTFT_ONBOARD_BACKLIGHT,
377 },
378 },
379 }
380 }
381 }, {
382 .name = "dogs102",
383 .spi = &(struct spi_board_info) {
384 .modalias = "fb_uc1701",
385 .max_speed_hz = 8000000,
386 .mode = SPI_MODE_0,
387 .platform_data = &(struct fbtft_platform_data) {
388 .display = {
389 .buswidth = 8,
390 },
391 .bgr = true,
392 }
393 }
394 }, {
395 .name = "er_tftm050_2",
396 .spi = &(struct spi_board_info) {
397 .modalias = "fb_ra8875",
398 .max_speed_hz = 5000000,
399 .mode = SPI_MODE_3,
400 .platform_data = &(struct fbtft_platform_data) {
401 .display = {
402 .buswidth = 8,
403 .backlight = 1,
404 .width = 480,
405 .height = 272,
406 },
407 .bgr = true,
408 }
409 }
410 }, {
411 .name = "er_tftm070_5",
412 .spi = &(struct spi_board_info) {
413 .modalias = "fb_ra8875",
414 .max_speed_hz = 5000000,
415 .mode = SPI_MODE_3,
416 .platform_data = &(struct fbtft_platform_data) {
417 .display = {
418 .buswidth = 8,
419 .backlight = 1,
420 .width = 800,
421 .height = 480,
422 },
423 .bgr = true,
424 }
425 }
426 }, {
427 .name = "ew24ha0",
428 .spi = &(struct spi_board_info) {
429 .modalias = "fb_uc1611",
430 .max_speed_hz = 32000000,
431 .mode = SPI_MODE_3,
432 .platform_data = &(struct fbtft_platform_data) {
433 .display = {
434 .buswidth = 8,
435 },
436 }
437 }
438 }, {
439 .name = "ew24ha0_9bit",
440 .spi = &(struct spi_board_info) {
441 .modalias = "fb_uc1611",
442 .max_speed_hz = 32000000,
443 .mode = SPI_MODE_3,
444 .platform_data = &(struct fbtft_platform_data) {
445 .display = {
446 .buswidth = 9,
447 },
448 }
449 }
450 }, {
451 .name = "flexfb",
452 .spi = &(struct spi_board_info) {
453 .modalias = "flexfb",
454 .max_speed_hz = 32000000,
455 .mode = SPI_MODE_0,
456 }
457 }, {
458 .name = "flexpfb",
459 .pdev = &(struct platform_device) {
460 .name = "flexpfb",
461 .id = 0,
462 .dev = {
463 .release = fbtft_device_pdev_release,
464 }
465 }
466 }, {
467 .name = "freetronicsoled128",
468 .spi = &(struct spi_board_info) {
469 .modalias = "fb_ssd1351",
470 .max_speed_hz = 20000000,
471 .mode = SPI_MODE_0,
472 .platform_data = &(struct fbtft_platform_data) {
473 .display = {
474 .buswidth = 8,
475 .backlight = FBTFT_ONBOARD_BACKLIGHT,
476 },
477 .bgr = true,
478 }
479 }
480 }, {
481 .name = "hx8353d",
482 .spi = &(struct spi_board_info) {
483 .modalias = "fb_hx8353d",
484 .max_speed_hz = 16000000,
485 .mode = SPI_MODE_0,
486 .platform_data = &(struct fbtft_platform_data) {
487 .display = {
488 .buswidth = 8,
489 .backlight = 1,
490 },
491 }
492 }
493 }, {
494 .name = "hy28a",
495 .spi = &(struct spi_board_info) {
496 .modalias = "fb_ili9320",
497 .max_speed_hz = 32000000,
498 .mode = SPI_MODE_3,
499 .platform_data = &(struct fbtft_platform_data) {
500 .display = {
501 .buswidth = 8,
502 .backlight = 1,
503 },
504 .startbyte = 0x70,
505 .bgr = true,
506 }
507 }
508 }, {
509 .name = "hy28b",
510 .spi = &(struct spi_board_info) {
511 .modalias = "fb_ili9325",
512 .max_speed_hz = 48000000,
513 .mode = SPI_MODE_3,
514 .platform_data = &(struct fbtft_platform_data) {
515 .display = {
516 .buswidth = 8,
517 .backlight = 1,
518 .init_sequence = hy28b_init_sequence,
519 },
520 .startbyte = 0x70,
521 .bgr = true,
522 .fps = 50,
523 .gamma = HY28B_GAMMA,
524 }
525 }
526 }, {
527 .name = "ili9481",
528 .spi = &(struct spi_board_info) {
529 .modalias = "fb_ili9481",
530 .max_speed_hz = 32000000,
531 .mode = SPI_MODE_0,
532 .platform_data = &(struct fbtft_platform_data) {
533 .display = {
534 .regwidth = 16,
535 .buswidth = 8,
536 .backlight = 1,
537 },
538 .bgr = true,
539 }
540 }
541 }, {
542 .name = "itdb24",
543 .pdev = &(struct platform_device) {
544 .name = "fb_s6d1121",
545 .id = 0,
546 .dev = {
547 .release = fbtft_device_pdev_release,
548 .platform_data = &(struct fbtft_platform_data) {
549 .display = {
550 .buswidth = 8,
551 .backlight = 1,
552 },
553 .bgr = false,
554 },
555 }
556 }
557 }, {
558 .name = "itdb28",
559 .pdev = &(struct platform_device) {
560 .name = "fb_ili9325",
561 .id = 0,
562 .dev = {
563 .release = fbtft_device_pdev_release,
564 .platform_data = &(struct fbtft_platform_data) {
565 .display = {
566 .buswidth = 8,
567 .backlight = 1,
568 },
569 .bgr = true,
570 },
571 }
572 }
573 }, {
574 .name = "itdb28_spi",
575 .spi = &(struct spi_board_info) {
576 .modalias = "fb_ili9325",
577 .max_speed_hz = 32000000,
578 .mode = SPI_MODE_0,
579 .platform_data = &(struct fbtft_platform_data) {
580 .display = {
581 .buswidth = 8,
582 .backlight = 1,
583 },
584 .bgr = true,
585 }
586 }
587 }, {
588 .name = "mi0283qt-2",
589 .spi = &(struct spi_board_info) {
590 .modalias = "fb_hx8347d",
591 .max_speed_hz = 32000000,
592 .mode = SPI_MODE_0,
593 .platform_data = &(struct fbtft_platform_data) {
594 .display = {
595 .buswidth = 8,
596 .backlight = 1,
597 },
598 .startbyte = 0x70,
599 .bgr = true,
600 }
601 }
602 }, {
603 .name = "mi0283qt-9a",
604 .spi = &(struct spi_board_info) {
605 .modalias = "fb_ili9341",
606 .max_speed_hz = 32000000,
607 .mode = SPI_MODE_0,
608 .platform_data = &(struct fbtft_platform_data) {
609 .display = {
610 .buswidth = 9,
611 .backlight = 1,
612 },
613 .bgr = true,
614 }
615 }
616 }, {
617 .name = "mi0283qt-v2",
618 .spi = &(struct spi_board_info) {
619 .modalias = "fb_watterott",
620 .max_speed_hz = 4000000,
621 .mode = SPI_MODE_3,
622 .platform_data = &(struct fbtft_platform_data) {
623 }
624 }
625 }, {
626 .name = "nokia3310",
627 .spi = &(struct spi_board_info) {
628 .modalias = "fb_pcd8544",
629 .max_speed_hz = 400000,
630 .mode = SPI_MODE_0,
631 .platform_data = &(struct fbtft_platform_data) {
632 .display = {
633 .buswidth = 8,
634 },
635 }
636 }
637 }, {
638 .name = "nokia3310a",
639 .spi = &(struct spi_board_info) {
640 .modalias = "fb_tls8204",
641 .max_speed_hz = 1000000,
642 .mode = SPI_MODE_0,
643 .platform_data = &(struct fbtft_platform_data) {
644 .display = {
645 .buswidth = 8,
646 },
647 }
648 }
649 }, {
650 .name = "nokia5110",
651 .spi = &(struct spi_board_info) {
652 .modalias = "fb_ili9163",
653 .max_speed_hz = 12000000,
654 .mode = SPI_MODE_0,
655 .platform_data = &(struct fbtft_platform_data) {
656 .display = {
657 .buswidth = 8,
658 .backlight = 1,
659 },
660 .bgr = true,
661 }
662 }
663 }, {
664 .name = "piscreen",
665 .spi = &(struct spi_board_info) {
666 .modalias = "fb_ili9486",
667 .max_speed_hz = 32000000,
668 .mode = SPI_MODE_0,
669 .platform_data = &(struct fbtft_platform_data) {
670 .display = {
671 .regwidth = 16,
672 .buswidth = 8,
673 .backlight = 1,
674 },
675 .bgr = true,
676 }
677 }
678 }, {
679 .name = "pitft",
680 .spi = &(struct spi_board_info) {
681 .modalias = "fb_ili9340",
682 .max_speed_hz = 32000000,
683 .mode = SPI_MODE_0,
684 .chip_select = 0,
685 .platform_data = &(struct fbtft_platform_data) {
686 .display = {
687 .buswidth = 8,
688 .backlight = 1,
689 .init_sequence = pitft_init_sequence,
690 },
691 .bgr = true,
692 }
693 }
694 }, {
695 .name = "pioled",
696 .spi = &(struct spi_board_info) {
697 .modalias = "fb_ssd1351",
698 .max_speed_hz = 20000000,
699 .mode = SPI_MODE_0,
700 .platform_data = &(struct fbtft_platform_data) {
701 .display = {
702 .buswidth = 8,
703 },
704 .bgr = true,
705 .gamma = PIOLED_GAMMA
706 }
707 }
708 }, {
709 .name = "rpi-display",
710 .spi = &(struct spi_board_info) {
711 .modalias = "fb_ili9341",
712 .max_speed_hz = 32000000,
713 .mode = SPI_MODE_0,
714 .platform_data = &(struct fbtft_platform_data) {
715 .display = {
716 .buswidth = 8,
717 .backlight = 1,
718 },
719 .bgr = true,
720 }
721 }
722 }, {
723 .name = "s6d02a1",
724 .spi = &(struct spi_board_info) {
725 .modalias = "fb_s6d02a1",
726 .max_speed_hz = 32000000,
727 .mode = SPI_MODE_0,
728 .platform_data = &(struct fbtft_platform_data) {
729 .display = {
730 .buswidth = 8,
731 .backlight = 1,
732 },
733 .bgr = true,
734 }
735 }
736 }, {
737 .name = "sainsmart18",
738 .spi = &(struct spi_board_info) {
739 .modalias = "fb_st7735r",
740 .max_speed_hz = 32000000,
741 .mode = SPI_MODE_0,
742 .platform_data = &(struct fbtft_platform_data) {
743 .display = {
744 .buswidth = 8,
745 },
746 }
747 }
748 }, {
749 .name = "sainsmart32",
750 .pdev = &(struct platform_device) {
751 .name = "fb_ssd1289",
752 .id = 0,
753 .dev = {
754 .release = fbtft_device_pdev_release,
755 .platform_data = &(struct fbtft_platform_data) {
756 .display = {
757 .buswidth = 16,
758 .txbuflen = -2,
759 .backlight = 1,
760 .fbtftops.write = write_gpio16_wr_slow,
761 },
762 .bgr = true,
763 },
764 },
765 }
766 }, {
767 .name = "sainsmart32_fast",
768 .pdev = &(struct platform_device) {
769 .name = "fb_ssd1289",
770 .id = 0,
771 .dev = {
772 .release = fbtft_device_pdev_release,
773 .platform_data = &(struct fbtft_platform_data) {
774 .display = {
775 .buswidth = 16,
776 .txbuflen = -2,
777 .backlight = 1,
778 },
779 .bgr = true,
780 },
781 },
782 }
783 }, {
784 .name = "sainsmart32_latched",
785 .pdev = &(struct platform_device) {
786 .name = "fb_ssd1289",
787 .id = 0,
788 .dev = {
789 .release = fbtft_device_pdev_release,
790 .platform_data = &(struct fbtft_platform_data) {
791 .display = {
792 .buswidth = 16,
793 .txbuflen = -2,
794 .backlight = 1,
795 .fbtftops.write =
796 fbtft_write_gpio16_wr_latched,
797 },
798 .bgr = true,
799 },
800 },
801 }
802 }, {
803 .name = "sainsmart32_spi",
804 .spi = &(struct spi_board_info) {
805 .modalias = "fb_ssd1289",
806 .max_speed_hz = 16000000,
807 .mode = SPI_MODE_0,
808 .platform_data = &(struct fbtft_platform_data) {
809 .display = {
810 .buswidth = 8,
811 .backlight = 1,
812 },
813 .bgr = true,
814 }
815 }
816 }, {
817 .name = "spidev",
818 .spi = &(struct spi_board_info) {
819 .modalias = "spidev",
820 .max_speed_hz = 500000,
821 .bus_num = 0,
822 .chip_select = 0,
823 .mode = SPI_MODE_0,
824 .platform_data = &(struct fbtft_platform_data) {
825 }
826 }
827 }, {
828 .name = "ssd1331",
829 .spi = &(struct spi_board_info) {
830 .modalias = "fb_ssd1331",
831 .max_speed_hz = 20000000,
832 .mode = SPI_MODE_3,
833 .platform_data = &(struct fbtft_platform_data) {
834 .display = {
835 .buswidth = 8,
836 },
837 }
838 }
839 }, {
840 .name = "tinylcd35",
841 .spi = &(struct spi_board_info) {
842 .modalias = "fb_tinylcd",
843 .max_speed_hz = 32000000,
844 .mode = SPI_MODE_0,
845 .platform_data = &(struct fbtft_platform_data) {
846 .display = {
847 .buswidth = 8,
848 .backlight = 1,
849 },
850 .bgr = true,
851 }
852 }
853 }, {
854 .name = "tm022hdh26",
855 .spi = &(struct spi_board_info) {
856 .modalias = "fb_ili9341",
857 .max_speed_hz = 32000000,
858 .mode = SPI_MODE_0,
859 .platform_data = &(struct fbtft_platform_data) {
860 .display = {
861 .buswidth = 8,
862 .backlight = 1,
863 },
864 .bgr = true,
865 }
866 }
867 }, {
868 .name = "tontec35_9481",
869 .spi = &(struct spi_board_info) {
870 .modalias = "fb_ili9481",
871 .max_speed_hz = 128000000,
872 .mode = SPI_MODE_3,
873 .platform_data = &(struct fbtft_platform_data) {
874 .display = {
875 .buswidth = 8,
876 .backlight = 1,
877 },
878 .bgr = true,
879 }
880 }
881 }, {
882 .name = "tontec35_9486",
883 .spi = &(struct spi_board_info) {
884 .modalias = "fb_ili9486",
885 .max_speed_hz = 128000000,
886 .mode = SPI_MODE_3,
887 .platform_data = &(struct fbtft_platform_data) {
888 .display = {
889 .buswidth = 8,
890 .backlight = 1,
891 },
892 .bgr = true,
893 }
894 }
895 }, {
896 .name = "upd161704",
897 .spi = &(struct spi_board_info) {
898 .modalias = "fb_upd161704",
899 .max_speed_hz = 32000000,
900 .mode = SPI_MODE_0,
901 .platform_data = &(struct fbtft_platform_data) {
902 .display = {
903 .buswidth = 8,
904 },
905 }
906 }
907 }, {
908 .name = "waveshare32b",
909 .spi = &(struct spi_board_info) {
910 .modalias = "fb_ili9340",
911 .max_speed_hz = 48000000,
912 .mode = SPI_MODE_0,
913 .platform_data = &(struct fbtft_platform_data) {
914 .display = {
915 .buswidth = 8,
916 .backlight = 1,
917 .init_sequence =
918 waveshare32b_init_sequence,
919 },
920 .bgr = true,
921 }
922 }
923 }, {
924 .name = "waveshare22",
925 .spi = &(struct spi_board_info) {
926 .modalias = "fb_bd663474",
927 .max_speed_hz = 32000000,
928 .mode = SPI_MODE_3,
929 .platform_data = &(struct fbtft_platform_data) {
930 .display = {
931 .buswidth = 8,
932 },
933 }
934 }
935 }, {
936
937
938
939 .name = "",
940 .spi = &(struct spi_board_info) {
941 .modalias = "",
942 .max_speed_hz = 0,
943 .mode = SPI_MODE_0,
944 .platform_data = &(struct fbtft_platform_data) {
945 }
946 },
947 .pdev = &(struct platform_device) {
948 .name = "",
949 .id = 0,
950 .dev = {
951 .release = fbtft_device_pdev_release,
952 .platform_data = &(struct fbtft_platform_data) {
953 },
954 },
955 },
956 }
957};
958
959static int write_gpio16_wr_slow(struct fbtft_par *par, void *buf, size_t len)
960{
961 u16 data;
962 int i;
963#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO
964 static u16 prev_data;
965#endif
966
967 fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len,
968 "%s(len=%zu): ", __func__, len);
969
970 while (len) {
971 data = *(u16 *)buf;
972
973
974 gpiod_set_value(par->gpio.wr, 0);
975
976
977#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO
978 if (data == prev_data) {
979 gpiod_set_value(par->gpio.wr, 0);
980 } else {
981 for (i = 0; i < 16; i++) {
982 if ((data & 1) != (prev_data & 1))
983 gpiod_set_value(par->gpio.db[i],
984 data & 1);
985 data >>= 1;
986 prev_data >>= 1;
987 }
988 }
989#else
990 for (i = 0; i < 16; i++) {
991 gpiod_set_value(par->gpio.db[i], data & 1);
992 data >>= 1;
993 }
994#endif
995
996
997 gpiod_set_value(par->gpio.wr, 1);
998
999#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO
1000 prev_data = *(u16 *)buf;
1001#endif
1002 buf += 2;
1003 len -= 2;
1004 }
1005
1006 return 0;
1007}
1008
1009static void adafruit18_green_tab_set_addr_win(struct fbtft_par *par,
1010 int xs, int ys, int xe, int ye)
1011{
1012 write_reg(par, 0x2A, 0, xs + 2, 0, xe + 2);
1013 write_reg(par, 0x2B, 0, ys + 1, 0, ye + 1);
1014 write_reg(par, 0x2C);
1015}
1016
1017static void fbtft_device_pdev_release(struct device *dev)
1018{
1019
1020
1021
1022
1023}
1024
1025static int spi_device_found(struct device *dev, void *data)
1026{
1027 struct spi_device *spi = to_spi_device(dev);
1028
1029 dev_info(dev, "%s %s %dkHz %d bits mode=0x%02X\n", spi->modalias,
1030 dev_name(dev), spi->max_speed_hz / 1000, spi->bits_per_word,
1031 spi->mode);
1032
1033 return 0;
1034}
1035
1036static void pr_spi_devices(void)
1037{
1038 pr_debug("SPI devices registered:\n");
1039 bus_for_each_dev(&spi_bus_type, NULL, NULL, spi_device_found);
1040}
1041
1042static int p_device_found(struct device *dev, void *data)
1043{
1044 struct platform_device
1045 *pdev = to_platform_device(dev);
1046
1047 if (strstr(pdev->name, "fb"))
1048 dev_info(dev, "%s id=%d pdata? %s\n", pdev->name, pdev->id,
1049 pdev->dev.platform_data ? "yes" : "no");
1050
1051 return 0;
1052}
1053
1054static void pr_p_devices(void)
1055{
1056 pr_debug("'fb' Platform devices registered:\n");
1057 bus_for_each_dev(&platform_bus_type, NULL, NULL, p_device_found);
1058}
1059
1060#ifdef MODULE
1061static void fbtft_device_spi_delete(struct spi_master *master, unsigned int cs)
1062{
1063 struct device *dev;
1064 char str[32];
1065
1066 snprintf(str, sizeof(str), "%s.%u", dev_name(&master->dev), cs);
1067
1068 dev = bus_find_device_by_name(&spi_bus_type, NULL, str);
1069 if (dev) {
1070 if (verbose)
1071 dev_info(dev, "Deleting %s\n", str);
1072 device_del(dev);
1073 }
1074}
1075
1076static int fbtft_device_spi_device_register(struct spi_board_info *spi)
1077{
1078 struct spi_master *master;
1079
1080 master = spi_busnum_to_master(spi->bus_num);
1081 if (!master) {
1082 pr_err("spi_busnum_to_master(%d) returned NULL\n",
1083 spi->bus_num);
1084 return -EINVAL;
1085 }
1086
1087 fbtft_device_spi_delete(master, spi->chip_select);
1088 spi_device = spi_new_device(master, spi);
1089 put_device(&master->dev);
1090 if (!spi_device) {
1091 dev_err(&master->dev, "spi_new_device() returned NULL\n");
1092 return -EPERM;
1093 }
1094 return 0;
1095}
1096#else
1097static int fbtft_device_spi_device_register(struct spi_board_info *spi)
1098{
1099 return spi_register_board_info(spi, 1);
1100}
1101#endif
1102
1103static int __init fbtft_device_init(void)
1104{
1105 struct spi_board_info *spi = NULL;
1106 struct fbtft_platform_data *pdata;
1107 bool found = false;
1108 int i = 0;
1109 int ret = 0;
1110
1111 if (!name) {
1112#ifdef MODULE
1113 pr_err("missing module parameter: 'name'\n");
1114 return -EINVAL;
1115#else
1116 return 0;
1117#endif
1118 }
1119
1120 if (init_num > FBTFT_MAX_INIT_SEQUENCE) {
1121 pr_err("init parameter: exceeded max array size: %d\n",
1122 FBTFT_MAX_INIT_SEQUENCE);
1123 return -EINVAL;
1124 }
1125
1126 if (verbose > 2) {
1127 pr_spi_devices();
1128 pr_p_devices();
1129 }
1130
1131 pr_debug("name='%s', busnum=%d, cs=%d\n", name, busnum, cs);
1132
1133 if (rotate > 0 && rotate < 4) {
1134 rotate = (4 - rotate) * 90;
1135 pr_warn("argument 'rotate' should be an angle. Values 1-3 is deprecated. Setting it to %d.\n",
1136 rotate);
1137 }
1138 if (rotate != 0 && rotate != 90 && rotate != 180 && rotate != 270) {
1139 pr_warn("argument 'rotate' illegal value: %d. Setting it to 0.\n",
1140 rotate);
1141 rotate = 0;
1142 }
1143
1144
1145 if (strcmp(name, "list") == 0) {
1146 pr_info("Supported displays:\n");
1147
1148 for (i = 0; i < ARRAY_SIZE(displays); i++)
1149 pr_info("%s\n", displays[i].name);
1150 return -ECANCELED;
1151 }
1152
1153 if (custom) {
1154 i = ARRAY_SIZE(displays) - 1;
1155 displays[i].name = name;
1156 if (speed == 0) {
1157 displays[i].pdev->name = name;
1158 displays[i].spi = NULL;
1159 } else {
1160 size_t len;
1161
1162 len = strlcpy(displays[i].spi->modalias, name,
1163 SPI_NAME_SIZE);
1164 if (len >= SPI_NAME_SIZE)
1165 pr_warn("modalias (name) truncated to: %s\n",
1166 displays[i].spi->modalias);
1167 displays[i].pdev = NULL;
1168 }
1169 }
1170
1171 for (i = 0; i < ARRAY_SIZE(displays); i++) {
1172 if (strncmp(name, displays[i].name, SPI_NAME_SIZE) == 0) {
1173 if (displays[i].spi) {
1174 spi = displays[i].spi;
1175 spi->chip_select = cs;
1176 spi->bus_num = busnum;
1177 if (speed)
1178 spi->max_speed_hz = speed;
1179 if (mode != -1)
1180 spi->mode = mode;
1181 pdata = (void *)spi->platform_data;
1182 } else if (displays[i].pdev) {
1183 p_device = displays[i].pdev;
1184 pdata = p_device->dev.platform_data;
1185 } else {
1186 pr_err("broken displays array\n");
1187 return -EINVAL;
1188 }
1189
1190 pdata->rotate = rotate;
1191 if (bgr == 0)
1192 pdata->bgr = false;
1193 else if (bgr == 1)
1194 pdata->bgr = true;
1195 if (startbyte)
1196 pdata->startbyte = startbyte;
1197 if (gamma)
1198 pdata->gamma = gamma;
1199 pdata->display.debug = debug;
1200 if (fps)
1201 pdata->fps = fps;
1202 if (txbuflen)
1203 pdata->txbuflen = txbuflen;
1204 if (init_num)
1205 pdata->display.init_sequence = init;
1206 if (custom) {
1207 pdata->display.width = width;
1208 pdata->display.height = height;
1209 pdata->display.buswidth = buswidth;
1210 pdata->display.backlight = 1;
1211 }
1212
1213 if (displays[i].spi) {
1214 ret = fbtft_device_spi_device_register(spi);
1215 if (ret) {
1216 pr_err("failed to register SPI device\n");
1217 return ret;
1218 }
1219 } else {
1220 ret = platform_device_register(p_device);
1221 if (ret < 0) {
1222 pr_err("platform_device_register() returned %d\n",
1223 ret);
1224 return ret;
1225 }
1226 }
1227 found = true;
1228 break;
1229 }
1230 }
1231
1232 if (!found) {
1233 pr_err("display not supported: '%s'\n", name);
1234 return -EINVAL;
1235 }
1236
1237 if (spi_device && (verbose > 1))
1238 pr_spi_devices();
1239 if (p_device && (verbose > 1))
1240 pr_p_devices();
1241
1242 return 0;
1243}
1244
1245static void __exit fbtft_device_exit(void)
1246{
1247 if (spi_device) {
1248 device_del(&spi_device->dev);
1249 kfree(spi_device);
1250 }
1251
1252 if (p_device)
1253 platform_device_unregister(p_device);
1254}
1255
1256arch_initcall(fbtft_device_init);
1257module_exit(fbtft_device_exit);
1258
1259MODULE_DESCRIPTION("Add a FBTFT device.");
1260MODULE_AUTHOR("Noralf Tronnes");
1261MODULE_LICENSE("GPL");
1262