1
2
3
4
5
6
7
8#include <linux/bitops.h>
9#include <linux/delay.h>
10#include <linux/init.h>
11#include <linux/kernel.h>
12#include <linux/module.h>
13#include <video/mipi_display.h>
14
15#include "fbtft.h"
16
17#define DRVNAME "fb_st7789v"
18
19#define DEFAULT_GAMMA \
20 "70 2C 2E 15 10 09 48 33 53 0B 19 18 20 25\n" \
21 "70 2C 2E 15 10 09 48 33 53 0B 19 18 20 25"
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45enum st7789v_command {
46 PORCTRL = 0xB2,
47 GCTRL = 0xB7,
48 VCOMS = 0xBB,
49 VDVVRHEN = 0xC2,
50 VRHS = 0xC3,
51 VDVS = 0xC4,
52 VCMOFSET = 0xC5,
53 PWCTRL1 = 0xD0,
54 PVGAMCTRL = 0xE0,
55 NVGAMCTRL = 0xE1,
56};
57
58#define MADCTL_BGR BIT(3)
59#define MADCTL_MV BIT(5)
60#define MADCTL_MX BIT(6)
61#define MADCTL_MY BIT(7)
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77static int init_display(struct fbtft_par *par)
78{
79
80 write_reg(par, MIPI_DCS_EXIT_SLEEP_MODE);
81 mdelay(120);
82
83
84 write_reg(par, MIPI_DCS_SET_PIXEL_FORMAT, MIPI_DCS_PIXEL_FMT_16BIT);
85
86 write_reg(par, PORCTRL, 0x08, 0x08, 0x00, 0x22, 0x22);
87
88
89
90
91
92 write_reg(par, GCTRL, 0x35);
93
94
95
96
97
98 write_reg(par, VDVVRHEN, 0x01, 0xFF);
99
100
101
102
103
104 write_reg(par, VRHS, 0x0B);
105
106
107 write_reg(par, VDVS, 0x20);
108
109
110 write_reg(par, VCOMS, 0x20);
111
112
113 write_reg(par, VCMOFSET, 0x20);
114
115
116
117
118
119
120 write_reg(par, PWCTRL1, 0xA4, 0xA1);
121
122 write_reg(par, MIPI_DCS_SET_DISPLAY_ON);
123 return 0;
124}
125
126
127
128
129
130
131
132
133static int set_var(struct fbtft_par *par)
134{
135 u8 madctl_par = 0;
136
137 if (par->bgr)
138 madctl_par |= MADCTL_BGR;
139 switch (par->info->var.rotate) {
140 case 0:
141 break;
142 case 90:
143 madctl_par |= (MADCTL_MV | MADCTL_MY);
144 break;
145 case 180:
146 madctl_par |= (MADCTL_MX | MADCTL_MY);
147 break;
148 case 270:
149 madctl_par |= (MADCTL_MV | MADCTL_MX);
150 break;
151 default:
152 return -EINVAL;
153 }
154 write_reg(par, MIPI_DCS_SET_ADDRESS_MODE, madctl_par);
155 return 0;
156}
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172static int set_gamma(struct fbtft_par *par, u32 *curves)
173{
174 int i;
175 int j;
176 int c;
177
178
179
180
181
182
183 static const u8 gamma_par_mask[] = {
184 0xFF,
185 0x3F,
186 0x3F,
187 0x1F,
188 0x1F,
189 0x3F,
190 0x7F,
191 0x77,
192 0x7F,
193 0x3F,
194 0x1F,
195 0x1F,
196 0x3F,
197 0x3F,
198 };
199
200 for (i = 0; i < par->gamma.num_curves; i++) {
201 c = i * par->gamma.num_values;
202 for (j = 0; j < par->gamma.num_values; j++)
203 curves[c + j] &= gamma_par_mask[j];
204 write_reg(
205 par, PVGAMCTRL + i,
206 curves[c + 0], curves[c + 1], curves[c + 2],
207 curves[c + 3], curves[c + 4], curves[c + 5],
208 curves[c + 6], curves[c + 7], curves[c + 8],
209 curves[c + 9], curves[c + 10], curves[c + 11],
210 curves[c + 12], curves[c + 13]);
211 }
212 return 0;
213}
214
215
216
217
218
219
220
221
222
223static int blank(struct fbtft_par *par, bool on)
224{
225 if (on)
226 write_reg(par, MIPI_DCS_SET_DISPLAY_OFF);
227 else
228 write_reg(par, MIPI_DCS_SET_DISPLAY_ON);
229 return 0;
230}
231
232static struct fbtft_display display = {
233 .regwidth = 8,
234 .width = 240,
235 .height = 320,
236 .gamma_num = 2,
237 .gamma_len = 14,
238 .gamma = DEFAULT_GAMMA,
239 .fbtftops = {
240 .init_display = init_display,
241 .set_var = set_var,
242 .set_gamma = set_gamma,
243 .blank = blank,
244 },
245};
246
247FBTFT_REGISTER_DRIVER(DRVNAME, "sitronix,st7789v", &display);
248
249MODULE_ALIAS("spi:" DRVNAME);
250MODULE_ALIAS("platform:" DRVNAME);
251MODULE_ALIAS("spi:st7789v");
252MODULE_ALIAS("platform:st7789v");
253
254MODULE_DESCRIPTION("FB driver for the ST7789V LCD Controller");
255MODULE_AUTHOR("Dennis Menschel");
256MODULE_LICENSE("GPL");
257