]>
Commit | Line | Data |
---|---|---|
d4c402ff DM |
1 | /* |
2 | * FB driver for the ST7789V LCD Controller | |
3 | * | |
4 | * Copyright (C) 2015 Dennis Menschel | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or modify | |
7 | * it under the terms of the GNU General Public License as published by | |
8 | * the Free Software Foundation; either version 2 of the License, or | |
9 | * (at your option) any later version. | |
10 | * | |
11 | * This program is distributed in the hope that it will be useful, | |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | * GNU General Public License for more details. | |
15 | */ | |
16 | ||
17 | #include <linux/bitops.h> | |
ef8f3177 | 18 | #include <linux/delay.h> |
d4c402ff DM |
19 | #include <linux/init.h> |
20 | #include <linux/kernel.h> | |
21 | #include <linux/module.h> | |
598af18a | 22 | #include <video/mipi_display.h> |
d4c402ff DM |
23 | |
24 | #include "fbtft.h" | |
25 | ||
26 | #define DRVNAME "fb_st7789v" | |
27 | ||
28 | #define DEFAULT_GAMMA \ | |
29 | "70 2C 2E 15 10 09 48 33 53 0B 19 18 20 25\n" \ | |
30 | "70 2C 2E 15 10 09 48 33 53 0B 19 18 20 25" | |
31 | ||
32 | /** | |
33 | * enum st7789v_command - ST7789V display controller commands | |
34 | * | |
d4c402ff DM |
35 | * @PORCTRL: porch setting |
36 | * @GCTRL: gate control | |
37 | * @VCOMS: VCOM setting | |
38 | * @VDVVRHEN: VDV and VRH command enable | |
39 | * @VRHS: VRH set | |
40 | * @VDVS: VDV set | |
41 | * @VCMOFSET: VCOM offset set | |
42 | * @PWCTRL1: power control 1 | |
43 | * @PVGAMCTRL: positive voltage gamma control | |
44 | * @NVGAMCTRL: negative voltage gamma control | |
45 | * | |
46 | * The command names are the same as those found in the datasheet to ease | |
47 | * looking up their semantics and usage. | |
48 | * | |
49 | * Note that the ST7789V display controller offers quite a few more commands | |
50 | * which have been omitted from this list as they are not used at the moment. | |
598af18a DM |
51 | * Furthermore, commands that are compliant with the MIPI DCS have been left |
52 | * out as well to avoid duplicate entries. | |
d4c402ff DM |
53 | */ |
54 | enum st7789v_command { | |
d4c402ff DM |
55 | PORCTRL = 0xB2, |
56 | GCTRL = 0xB7, | |
57 | VCOMS = 0xBB, | |
58 | VDVVRHEN = 0xC2, | |
59 | VRHS = 0xC3, | |
60 | VDVS = 0xC4, | |
61 | VCMOFSET = 0xC5, | |
62 | PWCTRL1 = 0xD0, | |
63 | PVGAMCTRL = 0xE0, | |
64 | NVGAMCTRL = 0xE1, | |
65 | }; | |
66 | ||
67 | #define MADCTL_BGR BIT(3) /* bitmask for RGB/BGR order */ | |
68 | #define MADCTL_MV BIT(5) /* bitmask for page/column order */ | |
69 | #define MADCTL_MX BIT(6) /* bitmask for column address order */ | |
70 | #define MADCTL_MY BIT(7) /* bitmask for page address order */ | |
71 | ||
72 | /** | |
ef8f3177 | 73 | * init_display() - initialize the display controller |
d4c402ff | 74 | * |
ef8f3177 DM |
75 | * @par: FBTFT parameter object |
76 | * | |
77 | * Most of the commands in this init function set their parameters to the | |
d4c402ff DM |
78 | * same default values which are already in place after the display has been |
79 | * powered up. (The main exception to this rule is the pixel format which | |
80 | * would default to 18 instead of 16 bit per pixel.) | |
81 | * Nonetheless, this sequence can be used as a template for concrete | |
82 | * displays which usually need some adjustments. | |
ef8f3177 DM |
83 | * |
84 | * Return: 0 on success, < 0 if error occurred. | |
d4c402ff | 85 | */ |
ef8f3177 DM |
86 | static int init_display(struct fbtft_par *par) |
87 | { | |
d4c402ff | 88 | /* turn off sleep mode */ |
ef8f3177 DM |
89 | write_reg(par, MIPI_DCS_EXIT_SLEEP_MODE); |
90 | mdelay(120); | |
d4c402ff DM |
91 | |
92 | /* set pixel format to RGB-565 */ | |
ef8f3177 | 93 | write_reg(par, MIPI_DCS_SET_PIXEL_FORMAT, MIPI_DCS_PIXEL_FMT_16BIT); |
d4c402ff | 94 | |
ef8f3177 | 95 | write_reg(par, PORCTRL, 0x08, 0x08, 0x00, 0x22, 0x22); |
d4c402ff DM |
96 | |
97 | /* | |
98 | * VGH = 13.26V | |
99 | * VGL = -10.43V | |
100 | */ | |
ef8f3177 | 101 | write_reg(par, GCTRL, 0x35); |
d4c402ff DM |
102 | |
103 | /* | |
104 | * VDV and VRH register values come from command write | |
105 | * (instead of NVM) | |
106 | */ | |
ef8f3177 | 107 | write_reg(par, VDVVRHEN, 0x01, 0xFF); |
d4c402ff DM |
108 | |
109 | /* | |
110 | * VAP = 4.1V + (VCOM + VCOM offset + 0.5 * VDV) | |
111 | * VAN = -4.1V + (VCOM + VCOM offset + 0.5 * VDV) | |
112 | */ | |
ef8f3177 | 113 | write_reg(par, VRHS, 0x0B); |
d4c402ff DM |
114 | |
115 | /* VDV = 0V */ | |
ef8f3177 | 116 | write_reg(par, VDVS, 0x20); |
d4c402ff DM |
117 | |
118 | /* VCOM = 0.9V */ | |
ef8f3177 | 119 | write_reg(par, VCOMS, 0x20); |
d4c402ff DM |
120 | |
121 | /* VCOM offset = 0V */ | |
ef8f3177 | 122 | write_reg(par, VCMOFSET, 0x20); |
d4c402ff DM |
123 | |
124 | /* | |
125 | * AVDD = 6.8V | |
126 | * AVCL = -4.8V | |
127 | * VDS = 2.3V | |
128 | */ | |
ef8f3177 | 129 | write_reg(par, PWCTRL1, 0xA4, 0xA1); |
d4c402ff | 130 | |
ef8f3177 DM |
131 | write_reg(par, MIPI_DCS_SET_DISPLAY_ON); |
132 | return 0; | |
133 | } | |
d4c402ff | 134 | |
d4c402ff DM |
135 | /** |
136 | * set_var() - apply LCD properties like rotation and BGR mode | |
137 | * | |
138 | * @par: FBTFT parameter object | |
139 | * | |
140 | * Return: 0 on success, < 0 if error occurred. | |
141 | */ | |
142 | static int set_var(struct fbtft_par *par) | |
143 | { | |
144 | u8 madctl_par = 0; | |
145 | ||
146 | if (par->bgr) | |
147 | madctl_par |= MADCTL_BGR; | |
148 | switch (par->info->var.rotate) { | |
149 | case 0: | |
150 | break; | |
151 | case 90: | |
152 | madctl_par |= (MADCTL_MV | MADCTL_MY); | |
153 | break; | |
154 | case 180: | |
155 | madctl_par |= (MADCTL_MX | MADCTL_MY); | |
156 | break; | |
157 | case 270: | |
158 | madctl_par |= (MADCTL_MV | MADCTL_MX); | |
159 | break; | |
160 | default: | |
161 | return -EINVAL; | |
162 | } | |
598af18a | 163 | write_reg(par, MIPI_DCS_SET_ADDRESS_MODE, madctl_par); |
d4c402ff DM |
164 | return 0; |
165 | } | |
166 | ||
167 | /** | |
168 | * set_gamma() - set gamma curves | |
169 | * | |
170 | * @par: FBTFT parameter object | |
171 | * @curves: gamma curves | |
172 | * | |
173 | * Before the gamma curves are applied, they are preprocessed with a bitmask | |
174 | * to ensure syntactically correct input for the display controller. | |
175 | * This implies that the curves input parameter might be changed by this | |
176 | * function and that illegal gamma values are auto-corrected and not | |
177 | * reported as errors. | |
178 | * | |
179 | * Return: 0 on success, < 0 if error occurred. | |
180 | */ | |
22eb36b8 | 181 | static int set_gamma(struct fbtft_par *par, u32 *curves) |
d4c402ff DM |
182 | { |
183 | int i; | |
184 | int j; | |
185 | int c; /* curve index offset */ | |
186 | ||
187 | /* | |
188 | * Bitmasks for gamma curve command parameters. | |
189 | * The masks are the same for both positive and negative voltage | |
190 | * gamma curves. | |
191 | */ | |
192 | const u8 gamma_par_mask[] = { | |
193 | 0xFF, /* V63[3:0], V0[3:0]*/ | |
194 | 0x3F, /* V1[5:0] */ | |
195 | 0x3F, /* V2[5:0] */ | |
196 | 0x1F, /* V4[4:0] */ | |
197 | 0x1F, /* V6[4:0] */ | |
198 | 0x3F, /* J0[1:0], V13[3:0] */ | |
199 | 0x7F, /* V20[6:0] */ | |
200 | 0x77, /* V36[2:0], V27[2:0] */ | |
201 | 0x7F, /* V43[6:0] */ | |
202 | 0x3F, /* J1[1:0], V50[3:0] */ | |
203 | 0x1F, /* V57[4:0] */ | |
204 | 0x1F, /* V59[4:0] */ | |
205 | 0x3F, /* V61[5:0] */ | |
206 | 0x3F, /* V62[5:0] */ | |
207 | }; | |
208 | ||
209 | for (i = 0; i < par->gamma.num_curves; i++) { | |
210 | c = i * par->gamma.num_values; | |
211 | for (j = 0; j < par->gamma.num_values; j++) | |
212 | curves[c + j] &= gamma_par_mask[j]; | |
213 | write_reg( | |
214 | par, PVGAMCTRL + i, | |
215 | curves[c + 0], curves[c + 1], curves[c + 2], | |
216 | curves[c + 3], curves[c + 4], curves[c + 5], | |
217 | curves[c + 6], curves[c + 7], curves[c + 8], | |
218 | curves[c + 9], curves[c + 10], curves[c + 11], | |
219 | curves[c + 12], curves[c + 13]); | |
220 | } | |
221 | return 0; | |
222 | } | |
223 | ||
224 | /** | |
225 | * blank() - blank the display | |
226 | * | |
227 | * @par: FBTFT parameter object | |
228 | * @on: whether to enable or disable blanking the display | |
229 | * | |
230 | * Return: 0 on success, < 0 if error occurred. | |
231 | */ | |
232 | static int blank(struct fbtft_par *par, bool on) | |
233 | { | |
234 | if (on) | |
598af18a | 235 | write_reg(par, MIPI_DCS_SET_DISPLAY_OFF); |
d4c402ff | 236 | else |
598af18a | 237 | write_reg(par, MIPI_DCS_SET_DISPLAY_ON); |
d4c402ff DM |
238 | return 0; |
239 | } | |
240 | ||
241 | static struct fbtft_display display = { | |
242 | .regwidth = 8, | |
243 | .width = 240, | |
244 | .height = 320, | |
d4c402ff DM |
245 | .gamma_num = 2, |
246 | .gamma_len = 14, | |
247 | .gamma = DEFAULT_GAMMA, | |
248 | .fbtftops = { | |
ef8f3177 | 249 | .init_display = init_display, |
d4c402ff DM |
250 | .set_var = set_var, |
251 | .set_gamma = set_gamma, | |
252 | .blank = blank, | |
253 | }, | |
254 | }; | |
255 | ||
256 | FBTFT_REGISTER_DRIVER(DRVNAME, "sitronix,st7789v", &display); | |
257 | ||
258 | MODULE_ALIAS("spi:" DRVNAME); | |
259 | MODULE_ALIAS("platform:" DRVNAME); | |
260 | MODULE_ALIAS("spi:st7789v"); | |
261 | MODULE_ALIAS("platform:st7789v"); | |
262 | ||
263 | MODULE_DESCRIPTION("FB driver for the ST7789V LCD Controller"); | |
264 | MODULE_AUTHOR("Dennis Menschel"); | |
265 | MODULE_LICENSE("GPL"); |