1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* |
3 | * FB driver for the S6D02A1 LCD Controller |
4 | * |
5 | * Based on fb_st7735r.c by Noralf Tronnes |
6 | * Init code from UTFT library by Henning Karlsen |
7 | */ |
8 | |
9 | #include <linux/module.h> |
10 | #include <linux/kernel.h> |
11 | #include <linux/init.h> |
12 | #include <video/mipi_display.h> |
13 | |
14 | #include "fbtft.h" |
15 | |
16 | #define DRVNAME "fb_s6d02a1" |
17 | |
18 | static const s16 default_init_sequence[] = { |
19 | -1, 0xf0, 0x5a, 0x5a, |
20 | |
21 | -1, 0xfc, 0x5a, 0x5a, |
22 | |
23 | -1, 0xfa, 0x02, 0x1f, 0x00, 0x10, 0x22, 0x30, 0x38, |
24 | 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3d, 0x02, 0x01, |
25 | |
26 | -1, 0xfb, 0x21, 0x00, 0x02, 0x04, 0x07, 0x0a, 0x0b, |
27 | 0x0c, 0x0c, 0x16, 0x1e, 0x30, 0x3f, 0x01, 0x02, |
28 | |
29 | /* power setting sequence */ |
30 | -1, 0xfd, 0x00, 0x00, 0x00, 0x17, 0x10, 0x00, 0x01, |
31 | 0x01, 0x00, 0x1f, 0x1f, |
32 | |
33 | -1, 0xf4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x3f, |
34 | 0x07, 0x00, 0x3C, 0x36, 0x00, 0x3C, 0x36, 0x00, |
35 | |
36 | -1, 0xf5, 0x00, 0x70, 0x66, 0x00, 0x00, 0x00, 0x00, |
37 | 0x00, 0x00, 0x00, 0x6d, 0x66, 0x06, |
38 | |
39 | -1, 0xf6, 0x02, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x02, |
40 | 0x00, 0x06, 0x01, 0x00, |
41 | |
42 | -1, 0xf2, 0x00, 0x01, 0x03, 0x08, 0x08, 0x04, 0x00, |
43 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x04, 0x08, 0x08, |
44 | |
45 | -1, 0xf8, 0x11, |
46 | |
47 | -1, 0xf7, 0xc8, 0x20, 0x00, 0x00, |
48 | |
49 | -1, 0xf3, 0x00, 0x00, |
50 | |
51 | -1, MIPI_DCS_EXIT_SLEEP_MODE, |
52 | -2, 50, |
53 | |
54 | -1, 0xf3, 0x00, 0x01, |
55 | -2, 50, |
56 | -1, 0xf3, 0x00, 0x03, |
57 | -2, 50, |
58 | -1, 0xf3, 0x00, 0x07, |
59 | -2, 50, |
60 | -1, 0xf3, 0x00, 0x0f, |
61 | -2, 50, |
62 | |
63 | -1, 0xf4, 0x00, 0x04, 0x00, 0x00, 0x00, 0x3f, 0x3f, |
64 | 0x07, 0x00, 0x3C, 0x36, 0x00, 0x3C, 0x36, 0x00, |
65 | -2, 50, |
66 | |
67 | -1, 0xf3, 0x00, 0x1f, |
68 | -2, 50, |
69 | -1, 0xf3, 0x00, 0x7f, |
70 | -2, 50, |
71 | |
72 | -1, 0xf3, 0x00, 0xff, |
73 | -2, 50, |
74 | |
75 | -1, 0xfd, 0x00, 0x00, 0x00, 0x17, 0x10, 0x00, 0x00, |
76 | 0x01, 0x00, 0x16, 0x16, |
77 | |
78 | -1, 0xf4, 0x00, 0x09, 0x00, 0x00, 0x00, 0x3f, 0x3f, |
79 | 0x07, 0x00, 0x3C, 0x36, 0x00, 0x3C, 0x36, 0x00, |
80 | |
81 | /* initializing sequence */ |
82 | |
83 | -1, MIPI_DCS_SET_ADDRESS_MODE, 0x08, |
84 | |
85 | -1, MIPI_DCS_SET_TEAR_ON, 0x00, |
86 | |
87 | -1, MIPI_DCS_SET_PIXEL_FORMAT, 0x05, |
88 | |
89 | /* gamma setting - possible values 0x01, 0x02, 0x04, 0x08 */ |
90 | -1, MIPI_DCS_SET_GAMMA_CURVE, 0x01, |
91 | |
92 | -2, 150, |
93 | -1, MIPI_DCS_SET_DISPLAY_ON, |
94 | -1, MIPI_DCS_WRITE_MEMORY_START, |
95 | /* end marker */ |
96 | -3 |
97 | |
98 | }; |
99 | |
100 | static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) |
101 | { |
102 | write_reg(par, MIPI_DCS_SET_COLUMN_ADDRESS, |
103 | xs >> 8, xs & 0xFF, xe >> 8, xe & 0xFF); |
104 | |
105 | write_reg(par, MIPI_DCS_SET_PAGE_ADDRESS, |
106 | ys >> 8, ys & 0xFF, ye >> 8, ye & 0xFF); |
107 | |
108 | write_reg(par, MIPI_DCS_WRITE_MEMORY_START); |
109 | } |
110 | |
111 | #define MY BIT(7) |
112 | #define MX BIT(6) |
113 | #define MV BIT(5) |
114 | static int set_var(struct fbtft_par *par) |
115 | { |
116 | /* |
117 | * Memory data access control (0x36h) |
118 | * RGB/BGR: |
119 | * 1. Mode selection pin SRGB |
120 | * RGB H/W pin for color filter setting: 0=RGB, 1=BGR |
121 | * 2. MADCTL RGB bit |
122 | * RGB-BGR ORDER color filter panel: 0=RGB, 1=BGR |
123 | */ |
124 | switch (par->info->var.rotate) { |
125 | case 0: |
126 | write_reg(par, MIPI_DCS_SET_ADDRESS_MODE, |
127 | MX | MY | (par->bgr << 3)); |
128 | break; |
129 | case 270: |
130 | write_reg(par, MIPI_DCS_SET_ADDRESS_MODE, |
131 | MY | MV | (par->bgr << 3)); |
132 | break; |
133 | case 180: |
134 | write_reg(par, MIPI_DCS_SET_ADDRESS_MODE, |
135 | par->bgr << 3); |
136 | break; |
137 | case 90: |
138 | write_reg(par, MIPI_DCS_SET_ADDRESS_MODE, |
139 | MX | MV | (par->bgr << 3)); |
140 | break; |
141 | } |
142 | |
143 | return 0; |
144 | } |
145 | |
146 | static struct fbtft_display display = { |
147 | .regwidth = 8, |
148 | .width = 128, |
149 | .height = 160, |
150 | .init_sequence = default_init_sequence, |
151 | .fbtftops = { |
152 | .set_addr_win = set_addr_win, |
153 | .set_var = set_var, |
154 | }, |
155 | }; |
156 | |
157 | FBTFT_REGISTER_DRIVER(DRVNAME, "samsung,s6d02a1" , &display); |
158 | |
159 | MODULE_ALIAS("spi:" DRVNAME); |
160 | MODULE_ALIAS("platform:" DRVNAME); |
161 | MODULE_ALIAS("spi:s6d02a1" ); |
162 | MODULE_ALIAS("platform:s6d02a1" ); |
163 | |
164 | MODULE_DESCRIPTION("FB driver for the S6D02A1 LCD Controller" ); |
165 | MODULE_AUTHOR("WOLFGANG BUENING" ); |
166 | MODULE_LICENSE("GPL" ); |
167 | |