1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * FB driver for the ST7789V LCD Controller 4 * 5 * Copyright (C) 2015 Dennis Menschel 6 */ 7 8 #include <linux/bitops.h> 9 #include <linux/delay.h> 10 #include <linux/gpio/consumer.h> 11 #include <linux/init.h> 12 #include <linux/kernel.h> 13 #include <linux/interrupt.h> 14 #include <linux/completion.h> 15 #include <linux/module.h> 16 17 #include <video/mipi_display.h> 18 19 #include "fbtft.h" 20 21 #define DRVNAME "fb_st7789v" 22 23 #define DEFAULT_GAMMA \ 24 "70 2C 2E 15 10 09 48 33 53 0B 19 18 20 25\n" \ 25 "70 2C 2E 15 10 09 48 33 53 0B 19 18 20 25" 26 27 #define HSD20_IPS_GAMMA \ 28 "D0 05 0A 09 08 05 2E 44 45 0F 17 16 2B 33\n" \ 29 "D0 05 0A 09 08 05 2E 43 45 0F 16 16 2B 33" 30 31 #define HSD20_IPS 1 32 33 /** 34 * enum st7789v_command - ST7789V display controller commands 35 * 36 * @PORCTRL: porch setting 37 * @GCTRL: gate control 38 * @VCOMS: VCOM setting 39 * @VDVVRHEN: VDV and VRH command enable 40 * @VRHS: VRH set 41 * @VDVS: VDV set 42 * @VCMOFSET: VCOM offset set 43 * @PWCTRL1: power control 1 44 * @PVGAMCTRL: positive voltage gamma control 45 * @NVGAMCTRL: negative voltage gamma control 46 * 47 * The command names are the same as those found in the datasheet to ease 48 * looking up their semantics and usage. 49 * 50 * Note that the ST7789V display controller offers quite a few more commands 51 * which have been omitted from this list as they are not used at the moment. 52 * Furthermore, commands that are compliant with the MIPI DCS have been left 53 * out as well to avoid duplicate entries. 54 */ 55 enum st7789v_command { 56 PORCTRL = 0xB2, 57 GCTRL = 0xB7, 58 VCOMS = 0xBB, 59 VDVVRHEN = 0xC2, 60 VRHS = 0xC3, 61 VDVS = 0xC4, 62 VCMOFSET = 0xC5, 63 PWCTRL1 = 0xD0, 64 PVGAMCTRL = 0xE0, 65 NVGAMCTRL = 0xE1, 66 }; 67 68 #define MADCTL_BGR BIT(3) /* bitmask for RGB/BGR order */ 69 #define MADCTL_MV BIT(5) /* bitmask for page/column order */ 70 #define MADCTL_MX BIT(6) /* bitmask for column address order */ 71 #define MADCTL_MY BIT(7) /* bitmask for page address order */ 72 73 /* 60Hz for 16.6ms, configured as 2*16.6ms */ 74 #define PANEL_TE_TIMEOUT_MS 33 75 76 static struct completion panel_te; /* completion for panel TE line */ 77 static int irq_te; /* Linux IRQ for LCD TE line */ 78 79 static irqreturn_t panel_te_handler(int irq, void *data) 80 { 81 complete(&panel_te); 82 return IRQ_HANDLED; 83 } 84 85 /* 86 * init_tearing_effect_line() - init tearing effect line. 87 * @par: FBTFT parameter object. 88 * 89 * Return: 0 on success, or a negative error code otherwise. 90 */ 91 static int init_tearing_effect_line(struct fbtft_par *par) 92 { 93 struct device *dev = par->info->device; 94 struct gpio_desc *te; 95 int rc, irq; 96 97 te = gpiod_get_optional(dev, "te", GPIOD_IN); 98 if (IS_ERR(te)) 99 return dev_err_probe(dev, PTR_ERR(te), "Failed to request te GPIO\n"); 100 101 /* if te is NULL, indicating no configuration, directly return success */ 102 if (!te) { 103 irq_te = 0; 104 return 0; 105 } 106 107 irq = gpiod_to_irq(te); 108 109 /* GPIO is locked as an IRQ, we may drop the reference */ 110 gpiod_put(te); 111 112 if (irq < 0) 113 return irq; 114 115 irq_te = irq; 116 init_completion(&panel_te); 117 118 /* The effective state is high and lasts no more than 1000 microseconds */ 119 rc = devm_request_irq(dev, irq_te, panel_te_handler, 120 IRQF_TRIGGER_RISING, "TE_GPIO", par); 121 if (rc) 122 return dev_err_probe(dev, rc, "TE IRQ request failed.\n"); 123 124 disable_irq_nosync(irq_te); 125 126 return 0; 127 } 128 129 /** 130 * init_display() - initialize the display controller 131 * 132 * @par: FBTFT parameter object 133 * 134 * Most of the commands in this init function set their parameters to the 135 * same default values which are already in place after the display has been 136 * powered up. (The main exception to this rule is the pixel format which 137 * would default to 18 instead of 16 bit per pixel.) 138 * Nonetheless, this sequence can be used as a template for concrete 139 * displays which usually need some adjustments. 140 * 141 * Return: 0 on success, < 0 if error occurred. 142 */ 143 static int init_display(struct fbtft_par *par) 144 { 145 int rc; 146 147 rc = init_tearing_effect_line(par); 148 if (rc) 149 return rc; 150 151 /* turn off sleep mode */ 152 write_reg(par, MIPI_DCS_EXIT_SLEEP_MODE); 153 mdelay(120); 154 155 /* set pixel format to RGB-565 */ 156 write_reg(par, MIPI_DCS_SET_PIXEL_FORMAT, MIPI_DCS_PIXEL_FMT_16BIT); 157 if (HSD20_IPS) 158 write_reg(par, PORCTRL, 0x05, 0x05, 0x00, 0x33, 0x33); 159 160 else 161 write_reg(par, PORCTRL, 0x08, 0x08, 0x00, 0x22, 0x22); 162 163 /* 164 * VGH = 13.26V 165 * VGL = -10.43V 166 */ 167 if (HSD20_IPS) 168 write_reg(par, GCTRL, 0x75); 169 else 170 write_reg(par, GCTRL, 0x35); 171 172 /* 173 * VDV and VRH register values come from command write 174 * (instead of NVM) 175 */ 176 write_reg(par, VDVVRHEN, 0x01, 0xFF); 177 178 /* 179 * VAP = 4.1V + (VCOM + VCOM offset + 0.5 * VDV) 180 * VAN = -4.1V + (VCOM + VCOM offset + 0.5 * VDV) 181 */ 182 if (HSD20_IPS) 183 write_reg(par, VRHS, 0x13); 184 else 185 write_reg(par, VRHS, 0x0B); 186 187 /* VDV = 0V */ 188 write_reg(par, VDVS, 0x20); 189 190 /* VCOM = 0.9V */ 191 if (HSD20_IPS) 192 write_reg(par, VCOMS, 0x22); 193 else 194 write_reg(par, VCOMS, 0x20); 195 196 /* VCOM offset = 0V */ 197 write_reg(par, VCMOFSET, 0x20); 198 199 /* 200 * AVDD = 6.8V 201 * AVCL = -4.8V 202 * VDS = 2.3V 203 */ 204 write_reg(par, PWCTRL1, 0xA4, 0xA1); 205 206 /* TE line output is off by default when powering on */ 207 if (irq_te) 208 write_reg(par, MIPI_DCS_SET_TEAR_ON, 0x00); 209 210 write_reg(par, MIPI_DCS_SET_DISPLAY_ON); 211 212 if (HSD20_IPS) 213 write_reg(par, MIPI_DCS_ENTER_INVERT_MODE); 214 215 return 0; 216 } 217 218 /* 219 * write_vmem() - write data to display. 220 * @par: FBTFT parameter object. 221 * @offset: offset from screen_buffer. 222 * @len: the length of data to be writte. 223 * 224 * Return: 0 on success, or a negative error code otherwise. 225 */ 226 static int write_vmem(struct fbtft_par *par, size_t offset, size_t len) 227 { 228 struct device *dev = par->info->device; 229 int ret; 230 231 if (irq_te) { 232 enable_irq(irq_te); 233 reinit_completion(&panel_te); 234 ret = wait_for_completion_timeout(&panel_te, 235 msecs_to_jiffies(PANEL_TE_TIMEOUT_MS)); 236 if (ret == 0) 237 dev_err(dev, "wait panel TE timeout\n"); 238 239 disable_irq(irq_te); 240 } 241 242 switch (par->pdata->display.buswidth) { 243 case 8: 244 ret = fbtft_write_vmem16_bus8(par, offset, len); 245 break; 246 case 9: 247 ret = fbtft_write_vmem16_bus9(par, offset, len); 248 break; 249 case 16: 250 ret = fbtft_write_vmem16_bus16(par, offset, len); 251 break; 252 default: 253 dev_err(dev, "Unsupported buswidth %d\n", 254 par->pdata->display.buswidth); 255 ret = 0; 256 break; 257 } 258 259 return ret; 260 } 261 262 /** 263 * set_var() - apply LCD properties like rotation and BGR mode 264 * 265 * @par: FBTFT parameter object 266 * 267 * Return: 0 on success, < 0 if error occurred. 268 */ 269 static int set_var(struct fbtft_par *par) 270 { 271 u8 madctl_par = 0; 272 273 if (par->bgr) 274 madctl_par |= MADCTL_BGR; 275 switch (par->info->var.rotate) { 276 case 0: 277 break; 278 case 90: 279 madctl_par |= (MADCTL_MV | MADCTL_MY); 280 break; 281 case 180: 282 madctl_par |= (MADCTL_MX | MADCTL_MY); 283 break; 284 case 270: 285 madctl_par |= (MADCTL_MV | MADCTL_MX); 286 break; 287 default: 288 return -EINVAL; 289 } 290 write_reg(par, MIPI_DCS_SET_ADDRESS_MODE, madctl_par); 291 return 0; 292 } 293 294 /** 295 * set_gamma() - set gamma curves 296 * 297 * @par: FBTFT parameter object 298 * @curves: gamma curves 299 * 300 * Before the gamma curves are applied, they are preprocessed with a bitmask 301 * to ensure syntactically correct input for the display controller. 302 * This implies that the curves input parameter might be changed by this 303 * function and that illegal gamma values are auto-corrected and not 304 * reported as errors. 305 * 306 * Return: 0 on success, < 0 if error occurred. 307 */ 308 static int set_gamma(struct fbtft_par *par, u32 *curves) 309 { 310 int i; 311 int j; 312 int c; /* curve index offset */ 313 314 /* 315 * Bitmasks for gamma curve command parameters. 316 * The masks are the same for both positive and negative voltage 317 * gamma curves. 318 */ 319 static const u8 gamma_par_mask[] = { 320 0xFF, /* V63[3:0], V0[3:0]*/ 321 0x3F, /* V1[5:0] */ 322 0x3F, /* V2[5:0] */ 323 0x1F, /* V4[4:0] */ 324 0x1F, /* V6[4:0] */ 325 0x3F, /* J0[1:0], V13[3:0] */ 326 0x7F, /* V20[6:0] */ 327 0x77, /* V36[2:0], V27[2:0] */ 328 0x7F, /* V43[6:0] */ 329 0x3F, /* J1[1:0], V50[3:0] */ 330 0x1F, /* V57[4:0] */ 331 0x1F, /* V59[4:0] */ 332 0x3F, /* V61[5:0] */ 333 0x3F, /* V62[5:0] */ 334 }; 335 336 for (i = 0; i < par->gamma.num_curves; i++) { 337 c = i * par->gamma.num_values; 338 for (j = 0; j < par->gamma.num_values; j++) 339 curves[c + j] &= gamma_par_mask[j]; 340 write_reg(par, PVGAMCTRL + i, 341 curves[c + 0], curves[c + 1], curves[c + 2], 342 curves[c + 3], curves[c + 4], curves[c + 5], 343 curves[c + 6], curves[c + 7], curves[c + 8], 344 curves[c + 9], curves[c + 10], curves[c + 11], 345 curves[c + 12], curves[c + 13]); 346 } 347 return 0; 348 } 349 350 /** 351 * blank() - blank the display 352 * 353 * @par: FBTFT parameter object 354 * @on: whether to enable or disable blanking the display 355 * 356 * Return: 0 on success, < 0 if error occurred. 357 */ 358 static int blank(struct fbtft_par *par, bool on) 359 { 360 if (on) 361 write_reg(par, MIPI_DCS_SET_DISPLAY_OFF); 362 else 363 write_reg(par, MIPI_DCS_SET_DISPLAY_ON); 364 return 0; 365 } 366 367 static struct fbtft_display display = { 368 .regwidth = 8, 369 .width = 240, 370 .height = 320, 371 .gamma_num = 2, 372 .gamma_len = 14, 373 .gamma = HSD20_IPS_GAMMA, 374 .fbtftops = { 375 .init_display = init_display, 376 .write_vmem = write_vmem, 377 .set_var = set_var, 378 .set_gamma = set_gamma, 379 .blank = blank, 380 }, 381 }; 382 383 FBTFT_REGISTER_DRIVER(DRVNAME, "sitronix,st7789v", &display); 384 385 MODULE_ALIAS("spi:" DRVNAME); 386 MODULE_ALIAS("platform:" DRVNAME); 387 MODULE_ALIAS("spi:st7789v"); 388 MODULE_ALIAS("platform:st7789v"); 389 390 MODULE_DESCRIPTION("FB driver for the ST7789V LCD Controller"); 391 MODULE_AUTHOR("Dennis Menschel"); 392 MODULE_LICENSE("GPL"); 393