-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
staging: fbtft: add support for ST7789V display controller
This patch adds support for the Sitronix ST7789V display controller. The controller is intended for small color displays with a resolution of up to 320x240 pixels. Signed-off-by: Dennis Menschel <menschel-d@posteo.de> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
- Loading branch information
Dennis Menschel
authored and
Greg Kroah-Hartman
committed
Oct 13, 2015
1 parent
56b3152
commit d4c402f
Showing
3 changed files
with
301 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,290 @@ | ||
/* | ||
* FB driver for the ST7789V LCD Controller | ||
* | ||
* Copyright (C) 2015 Dennis Menschel | ||
* | ||
* This program is free software; you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License as published by | ||
* the Free Software Foundation; either version 2 of the License, or | ||
* (at your option) any later version. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU General Public License for more details. | ||
*/ | ||
|
||
#include <linux/bitops.h> | ||
#include <linux/init.h> | ||
#include <linux/kernel.h> | ||
#include <linux/module.h> | ||
|
||
#include "fbtft.h" | ||
|
||
#define DRVNAME "fb_st7789v" | ||
|
||
#define DEFAULT_GAMMA \ | ||
"70 2C 2E 15 10 09 48 33 53 0B 19 18 20 25\n" \ | ||
"70 2C 2E 15 10 09 48 33 53 0B 19 18 20 25" | ||
|
||
/** | ||
* enum st7789v_command - ST7789V display controller commands | ||
* | ||
* @SLPOUT: sleep out | ||
* @DISPOFF: display off | ||
* @DISPON: display on | ||
* @CASET: column address set | ||
* @RASET: row address set | ||
* @RAMRW: memory write | ||
* @MADCTL: memory data access control | ||
* @COLMOD: interface pixel format | ||
* @PORCTRL: porch setting | ||
* @GCTRL: gate control | ||
* @VCOMS: VCOM setting | ||
* @VDVVRHEN: VDV and VRH command enable | ||
* @VRHS: VRH set | ||
* @VDVS: VDV set | ||
* @VCMOFSET: VCOM offset set | ||
* @PWCTRL1: power control 1 | ||
* @PVGAMCTRL: positive voltage gamma control | ||
* @NVGAMCTRL: negative voltage gamma control | ||
* | ||
* The command names are the same as those found in the datasheet to ease | ||
* looking up their semantics and usage. | ||
* | ||
* Note that the ST7789V display controller offers quite a few more commands | ||
* which have been omitted from this list as they are not used at the moment. | ||
*/ | ||
enum st7789v_command { | ||
SLPOUT = 0x11, | ||
DISPOFF = 0x28, | ||
DISPON = 0x29, | ||
CASET = 0x2A, | ||
RASET = 0x2B, | ||
RAMRW = 0x2C, | ||
MADCTL = 0x36, | ||
COLMOD = 0x3A, | ||
PORCTRL = 0xB2, | ||
GCTRL = 0xB7, | ||
VCOMS = 0xBB, | ||
VDVVRHEN = 0xC2, | ||
VRHS = 0xC3, | ||
VDVS = 0xC4, | ||
VCMOFSET = 0xC5, | ||
PWCTRL1 = 0xD0, | ||
PVGAMCTRL = 0xE0, | ||
NVGAMCTRL = 0xE1, | ||
}; | ||
|
||
#define MADCTL_BGR BIT(3) /* bitmask for RGB/BGR order */ | ||
#define MADCTL_MV BIT(5) /* bitmask for page/column order */ | ||
#define MADCTL_MX BIT(6) /* bitmask for column address order */ | ||
#define MADCTL_MY BIT(7) /* bitmask for page address order */ | ||
|
||
/** | ||
* default_init_sequence - default initialization sequence for ST7789V | ||
* | ||
* Most of the commands in this init sequence set their parameters to the | ||
* same default values which are already in place after the display has been | ||
* powered up. (The main exception to this rule is the pixel format which | ||
* would default to 18 instead of 16 bit per pixel.) | ||
* Nonetheless, this sequence can be used as a template for concrete | ||
* displays which usually need some adjustments. | ||
*/ | ||
static int default_init_sequence[] = { | ||
/* turn off sleep mode */ | ||
-1, SLPOUT, | ||
-2, 120, | ||
|
||
/* set pixel format to RGB-565 */ | ||
-1, COLMOD, 0x05, | ||
|
||
-1, PORCTRL, 0x08, 0x08, 0x00, 0x22, 0x22, | ||
|
||
/* | ||
* VGH = 13.26V | ||
* VGL = -10.43V | ||
*/ | ||
-1, GCTRL, 0x35, | ||
|
||
/* | ||
* VDV and VRH register values come from command write | ||
* (instead of NVM) | ||
*/ | ||
-1, VDVVRHEN, 0x01, 0xFF, | ||
|
||
/* | ||
* VAP = 4.1V + (VCOM + VCOM offset + 0.5 * VDV) | ||
* VAN = -4.1V + (VCOM + VCOM offset + 0.5 * VDV) | ||
*/ | ||
-1, VRHS, 0x0B, | ||
|
||
/* VDV = 0V */ | ||
-1, VDVS, 0x20, | ||
|
||
/* VCOM = 0.9V */ | ||
-1, VCOMS, 0x20, | ||
|
||
/* VCOM offset = 0V */ | ||
-1, VCMOFSET, 0x20, | ||
|
||
/* | ||
* AVDD = 6.8V | ||
* AVCL = -4.8V | ||
* VDS = 2.3V | ||
*/ | ||
-1, PWCTRL1, 0xA4, 0xA1, | ||
|
||
-1, DISPON, | ||
|
||
-3, | ||
}; | ||
|
||
/** | ||
* set_addr_win() - configure display area to use | ||
* | ||
* @par: FBTFT parameter object | ||
* @xs: first active pixel of x-axis | ||
* @ys: first active pixel of y-axis | ||
* @xe: last active pixel of x-axis | ||
* @ye: last active pixel of y-axis | ||
*/ | ||
static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) | ||
{ | ||
write_reg(par, CASET, xs >> 8, xs & 0xFF, xe >> 8, xe & 0xFF); | ||
write_reg(par, RASET, ys >> 8, ys & 0xFF, ye >> 8, ye & 0xFF); | ||
write_reg(par, RAMRW); | ||
} | ||
|
||
/** | ||
* set_var() - apply LCD properties like rotation and BGR mode | ||
* | ||
* @par: FBTFT parameter object | ||
* | ||
* Return: 0 on success, < 0 if error occurred. | ||
*/ | ||
static int set_var(struct fbtft_par *par) | ||
{ | ||
u8 madctl_par = 0; | ||
|
||
if (par->bgr) | ||
madctl_par |= MADCTL_BGR; | ||
switch (par->info->var.rotate) { | ||
case 0: | ||
break; | ||
case 90: | ||
madctl_par |= (MADCTL_MV | MADCTL_MY); | ||
break; | ||
case 180: | ||
madctl_par |= (MADCTL_MX | MADCTL_MY); | ||
break; | ||
case 270: | ||
madctl_par |= (MADCTL_MV | MADCTL_MX); | ||
break; | ||
default: | ||
return -EINVAL; | ||
} | ||
write_reg(par, MADCTL, madctl_par); | ||
return 0; | ||
} | ||
|
||
/** | ||
* set_gamma() - set gamma curves | ||
* | ||
* @par: FBTFT parameter object | ||
* @curves: gamma curves | ||
* | ||
* Before the gamma curves are applied, they are preprocessed with a bitmask | ||
* to ensure syntactically correct input for the display controller. | ||
* This implies that the curves input parameter might be changed by this | ||
* function and that illegal gamma values are auto-corrected and not | ||
* reported as errors. | ||
* | ||
* Return: 0 on success, < 0 if error occurred. | ||
*/ | ||
static int set_gamma(struct fbtft_par *par, unsigned long *curves) | ||
{ | ||
int i; | ||
int j; | ||
int c; /* curve index offset */ | ||
|
||
/* | ||
* Bitmasks for gamma curve command parameters. | ||
* The masks are the same for both positive and negative voltage | ||
* gamma curves. | ||
*/ | ||
const u8 gamma_par_mask[] = { | ||
0xFF, /* V63[3:0], V0[3:0]*/ | ||
0x3F, /* V1[5:0] */ | ||
0x3F, /* V2[5:0] */ | ||
0x1F, /* V4[4:0] */ | ||
0x1F, /* V6[4:0] */ | ||
0x3F, /* J0[1:0], V13[3:0] */ | ||
0x7F, /* V20[6:0] */ | ||
0x77, /* V36[2:0], V27[2:0] */ | ||
0x7F, /* V43[6:0] */ | ||
0x3F, /* J1[1:0], V50[3:0] */ | ||
0x1F, /* V57[4:0] */ | ||
0x1F, /* V59[4:0] */ | ||
0x3F, /* V61[5:0] */ | ||
0x3F, /* V62[5:0] */ | ||
}; | ||
|
||
for (i = 0; i < par->gamma.num_curves; i++) { | ||
c = i * par->gamma.num_values; | ||
for (j = 0; j < par->gamma.num_values; j++) | ||
curves[c + j] &= gamma_par_mask[j]; | ||
write_reg( | ||
par, PVGAMCTRL + i, | ||
curves[c + 0], curves[c + 1], curves[c + 2], | ||
curves[c + 3], curves[c + 4], curves[c + 5], | ||
curves[c + 6], curves[c + 7], curves[c + 8], | ||
curves[c + 9], curves[c + 10], curves[c + 11], | ||
curves[c + 12], curves[c + 13]); | ||
} | ||
return 0; | ||
} | ||
|
||
/** | ||
* blank() - blank the display | ||
* | ||
* @par: FBTFT parameter object | ||
* @on: whether to enable or disable blanking the display | ||
* | ||
* Return: 0 on success, < 0 if error occurred. | ||
*/ | ||
static int blank(struct fbtft_par *par, bool on) | ||
{ | ||
if (on) | ||
write_reg(par, DISPOFF); | ||
else | ||
write_reg(par, DISPON); | ||
return 0; | ||
} | ||
|
||
static struct fbtft_display display = { | ||
.regwidth = 8, | ||
.width = 240, | ||
.height = 320, | ||
.init_sequence = default_init_sequence, | ||
.gamma_num = 2, | ||
.gamma_len = 14, | ||
.gamma = DEFAULT_GAMMA, | ||
.fbtftops = { | ||
.set_addr_win = set_addr_win, | ||
.set_var = set_var, | ||
.set_gamma = set_gamma, | ||
.blank = blank, | ||
}, | ||
}; | ||
|
||
FBTFT_REGISTER_DRIVER(DRVNAME, "sitronix,st7789v", &display); | ||
|
||
MODULE_ALIAS("spi:" DRVNAME); | ||
MODULE_ALIAS("platform:" DRVNAME); | ||
MODULE_ALIAS("spi:st7789v"); | ||
MODULE_ALIAS("platform:st7789v"); | ||
|
||
MODULE_DESCRIPTION("FB driver for the ST7789V LCD Controller"); | ||
MODULE_AUTHOR("Dennis Menschel"); | ||
MODULE_LICENSE("GPL"); |