HamsterBear Linux ST7789V FBTFT驱动适配
作者:互联网
HamsterBear Linux ST7789V FBTFT驱动适配
平台
- F1C200sLinux版本
- 5.18TFT屏
- 1.69寸IPS高清ST7789V
修改设备树,在spi0节点下添加
&spi0 {
pinctrl-names = "default";
pinctrl-0 = <&spi0_pd_pins>;
status = "okay";
spi-max-frequency = <50000000>;
st7789v: st7789v@0 {
#address-cells = <1>;
#size-cells = <1>;
compatible = "sitronix,st7789v";
reg = <0>;
spi-max-frequency = <50000000>;
rgb;
buswidth = <8>;
rotate = <90>;
fps = <60>;
spi-cpol;
spi-cpha;
reset-gpios = <&pio 4 10 GPIO_ACTIVE_HIGH>; /* PE10 */
dc-gpios = <&pio 2 3 GPIO_ACTIVE_LOW>; /* PC3 */
debug = <1>;
};
};
确定内核config打开
需要注意的是,fbtft的驱动只有在内核framebuffer相关驱动开启后才会出现,所以要先开启fb驱动支持
Device Drivers -> Graphics support -> Frame buffer Devices --->,编译进内核
可根据需要将控制台映射到fb功能开启
这里我同时选择了16色的Tux 启动logo
然后寻找fbtft驱动,路径如下:
Device Drivers -> Staging drivers -> Support for small TFT LCD display modules --->,编译进内核
修改drivers/staging/fbtft/fb_st7789v.c
,如下几处
- 修改init函数,该初始化序列参考自厂家
static int init_display(struct fbtft_par *par)
{
int rc;
par->fbtftops.reset(par);
rc = init_tearing_effect_line(par);
if (rc)
return rc;
write_reg(par, 0x11); //Sleep out
mdelay(120); //Delay 120ms
//************* Start Initial Sequence **********//
write_reg(par, 0x36, 0x00);
write_reg(par, 0x3A, 0x05);
write_reg(par, 0xB2,0x0C,0x0C,0x00,0x33,0x33);
write_reg(par, 0xB7,0x35);
/* VCOM = 1.35V */
write_reg(par, 0xBB, 0x32);
write_reg(par, 0xC2, 0x01);
/* GVDD = 4.8V */
write_reg(par, 0xC3,0x15);
/* VDX = 0V */
write_reg(par, 0xC4, 0x20);
/* FPS = 60Hz */
write_reg(par, 0xC6,0x0F);
write_reg(par, 0xD0, 0xA4, 0xA1);
write_reg(par, 0xE0,0xD0,0x08,0x0E,0x09,0x09,0x05,0x31,0x33,0x48,0x17,0x14,0x15,0x31,0x34);
write_reg(par, 0xE1,0xD0,0x08,0x0E,0x09,0x09,0x15,0x31,0x33,0x48,0x17,0x14,0x15,0x31,0x34);
write_reg(par, MIPI_DCS_ENTER_INVERT_MODE);
write_reg(par, MIPI_DCS_SET_DISPLAY_ON);
return 0;
}
2, 修改display参数
static struct fbtft_display display = {
.regwidth = 8,
.width = 240,
.height = 280, /* 根据你的屏幕分辨率确定 */
.gamma_num = 2,
.gamma_len = 14,
.gamma = HSD20_IPS_GAMMA,
.fbtftops = {
.init_display = init_display,
.write_vmem = write_vmem,
.set_var = set_var,
.set_gamma = set_gamma,
.blank = blank,
},
};
修改drivers/staging/fbtft/fbtft-core.c
,如下几处
- 添加头文件
#include <linux/of.h>
#include <linux/of_gpio.h>
- 修改
fbtft_request_one_gpio
函数
static int fbtft_request_one_gpio(struct fbtft_par *par,
const char *name, int index,
struct gpio_desc **gpiop)
{
int ret, gpio;
struct device *dev = par->info->device;
struct device_node *np = dev->of_node;
*gpiop = devm_gpiod_get_index_optional(dev, name, index,
GPIOD_OUT_LOW);
/* Get GPIO from device tree */
gpio = of_get_named_gpio(np, name, 0);
if (gpio < 0) {
dev_err(dev, "Failed to retrieve %s from dts.\n", name);
return 0;
}
ret = devm_gpio_request_one(dev, gpio, GPIOF_OUT_INIT_HIGH, dev->driver->name);
if (ret) {
dev_err(dev, "Failed to request %s GPIO%d\n", name, gpio);
return -ENODEV;
}
*gpiop = gpio_to_desc(gpio);
fbtft_par_dbg(DEBUG_REQUEST_GPIOS, par, "%s: '%s' GPIO%d\n",
__func__, name, gpio);
return 0;
}
- 修改
fbtft_request_gpios
函数
static int fbtft_request_gpios(struct fbtft_par *par)
{
int i;
int ret;
ret = fbtft_request_one_gpio(par, "reset-gpios", 0, &par->gpio.reset);
if (ret)
return ret;
ret = fbtft_request_one_gpio(par, "dc-gpios", 0, &par->gpio.dc);
if (ret)
return ret;
ret = fbtft_request_one_gpio(par, "rd-gpios", 0, &par->gpio.rd);
if (ret)
return ret;
ret = fbtft_request_one_gpio(par, "wr-gpios", 0, &par->gpio.wr);
if (ret)
return ret;
ret = fbtft_request_one_gpio(par, "cs-gpios", 0, &par->gpio.cs);
if (ret)
return ret;
ret = fbtft_request_one_gpio(par, "latch-gpios", 0, &par->gpio.latch);
if (ret)
return ret;
for (i = 0; i < 16; i++) {
ret = fbtft_request_one_gpio(par, "db-gpios", i,
&par->gpio.db[i]);
if (ret)
return ret;
ret = fbtft_request_one_gpio(par, "led-gpios", i,
&par->gpio.led[i]);
if (ret)
return ret;
ret = fbtft_request_one_gpio(par, "aux-gpios", i,
&par->gpio.aux[i]);
if (ret)
return ret;
}
return 0;
}
- 修改
fbtft_set_win_addr
函数
因为st7789v支持到240x320的分辨率,但是我这块屏是240*280,所以x start和x end都有偏移,
这个偏移值也是我从厂家源码中参考的。
static void fbtft_set_addr_win(struct fbtft_par *par, int xs, int ys, int xe,
int ye)
{
xs = xs + 20;
xe = xe + 20;
write_reg(par, MIPI_DCS_SET_COLUMN_ADDRESS,
(xs >> 8) & 0xFF, xs & 0xFF, (xe >> 8) & 0xFF, xe & 0xFF);
write_reg(par, MIPI_DCS_SET_PAGE_ADDRESS,
(ys >> 8) & 0xFF, ys & 0xFF, (ye >> 8) & 0xFF, ye & 0xFF);
write_reg(par, MIPI_DCS_WRITE_MEMORY_START);
}
- 修改
fbtft_reset
函数
st7789v是low level reset
static void fbtft_reset(struct fbtft_par *par)
{
if (!par->gpio.reset)
return;
fbtft_par_dbg(DEBUG_RESET, par, "%s()\n", __func__);
gpiod_set_value_cansleep(par->gpio.reset, 1);
usleep_range(20, 40);
gpiod_set_value_cansleep(par->gpio.reset, 0); /* Low level reset */
msleep(120);
gpiod_set_value_cansleep(par->gpio.reset, 1); /* Activate chip */
}
最后附上两个文件的直观patch
diff --git a/drivers/staging/fbtft/fb_st7789v.c b/drivers/staging/fbtft/fb_st7789v.c
index 861a154144e6..c09063ca3085 100644
--- a/drivers/staging/fbtft/fb_st7789v.c
+++ b/drivers/staging/fbtft/fb_st7789v.c
@@ -150,6 +150,7 @@ static int init_display(struct fbtft_par *par)
if (rc)
return rc;
+#if 0
/* turn off sleep mode */
write_reg(par, MIPI_DCS_EXIT_SLEEP_MODE);
mdelay(120);
@@ -213,7 +214,43 @@ static int init_display(struct fbtft_par *par)
if (HSD20_IPS)
write_reg(par, MIPI_DCS_ENTER_INVERT_MODE);
+#endif
+ write_reg(par, 0x11); //Sleep out
+ mdelay(120); //Delay 120ms
+ //************* Start Initial Sequence **********//
+ write_reg(par, 0x36, 0x00);
+
+ write_reg(par, 0x3A, 0x05);
+
+ write_reg(par, 0xB2,0x0C,0x0C,0x00,0x33,0x33);
+
+ write_reg(par, 0xB7,0x35);
+
+ /* VCOM = 1.35V */
+ write_reg(par, 0xBB, 0x32);
+
+ write_reg(par, 0xC2, 0x01);
+
+ /* GVDD = 4.8V */
+ write_reg(par, 0xC3,0x15);
+
+ /* VDX = 0V */
+ write_reg(par, 0xC4, 0x20);
+
+ /* FPS = 60Hz */
+ write_reg(par, 0xC6,0x0F);
+
+ write_reg(par, 0xD0, 0xA4, 0xA1);
+
+ write_reg(par, 0xE0,0xD0,0x08,0x0E,0x09,0x09,0x05,0x31,0x33,0x48,0x17,0x14,0x15,0x31,0x34);
+
+ write_reg(par, 0xE1,0xD0,0x08,0x0E,0x09,0x09,0x15,0x31,0x33,0x48,0x17,0x14,0x15,0x31,0x34);
+
+ write_reg(par, MIPI_DCS_ENTER_INVERT_MODE);
+
+ write_reg(par, MIPI_DCS_SET_DISPLAY_ON);
+
return 0;
}
@@ -369,7 +406,7 @@ static int blank(struct fbtft_par *par, bool on)
static struct fbtft_display display = {
.regwidth = 8,
.width = 240,
- .height = 320,
+ .height = 280,
.gamma_num = 2,
.gamma_len = 14,
.gamma = HSD20_IPS_GAMMA,
diff --git a/drivers/staging/fbtft/fbtft-core.c b/drivers/staging/fbtft/fbtft-core.c
index 9c4d797e7ae4..f15b8d89afe4 100644
--- a/drivers/staging/fbtft/fbtft-core.c
+++ b/drivers/staging/fbtft/fbtft-core.c
@@ -16,6 +16,8 @@
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/fb.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/spi/spi.h>
#include <linux/delay.h>
@@ -74,15 +76,30 @@ static int fbtft_request_one_gpio(struct fbtft_par *par,
const char *name, int index,
struct gpio_desc **gpiop)
{
+ int ret, gpio;
struct device *dev = par->info->device;
+ struct device_node *np = dev->of_node;
*gpiop = devm_gpiod_get_index_optional(dev, name, index,
GPIOD_OUT_LOW);
- if (IS_ERR(*gpiop))
- return dev_err_probe(dev, PTR_ERR(*gpiop), "Failed to request %s GPIO\n", name);
- fbtft_par_dbg(DEBUG_REQUEST_GPIOS, par, "%s: '%s' GPIO\n",
- __func__, name);
+ /* Get GPIO from device tree */
+ gpio = of_get_named_gpio(np, name, 0);
+ if (gpio < 0) {
+ dev_err(dev, "Failed to retrieve %s from dts.\n", name);
+ return 0;
+ return 0;
+ return 0;
+ }
+
+ ret = devm_gpio_request_one(dev, gpio, GPIOF_OUT_INIT_HIGH, dev->driver->name);
+ if (ret) {
+ dev_err(dev, "Failed to request %s GPIO%d\n", name, gpio);
+ return -ENODEV;
+ }
+
+ *gpiop = gpio_to_desc(gpio);
+
+ fbtft_par_dbg(DEBUG_REQUEST_GPIOS, par, "%s: '%s' GPIO%d\n",
+ __func__, name, gpio);
return 0;
}
@@ -92,34 +109,34 @@ static int fbtft_request_gpios(struct fbtft_par *par)
int i;
int ret;
- ret = fbtft_request_one_gpio(par, "reset", 0, &par->gpio.reset);
+ ret = fbtft_request_one_gpio(par, "reset-gpios", 0, &par->gpio.reset);
if (ret)
return ret;
- ret = fbtft_request_one_gpio(par, "dc", 0, &par->gpio.dc);
+ ret = fbtft_request_one_gpio(par, "dc-gpios", 0, &par->gpio.dc);
if (ret)
return ret;
- ret = fbtft_request_one_gpio(par, "rd", 0, &par->gpio.rd);
+ ret = fbtft_request_one_gpio(par, "rd-gpios", 0, &par->gpio.rd);
if (ret)
return ret;
- ret = fbtft_request_one_gpio(par, "wr", 0, &par->gpio.wr);
+ ret = fbtft_request_one_gpio(par, "wr-gpios", 0, &par->gpio.wr);
if (ret)
return ret;
- ret = fbtft_request_one_gpio(par, "cs", 0, &par->gpio.cs);
+ ret = fbtft_request_one_gpio(par, "cs-gpios", 0, &par->gpio.cs);
if (ret)
return ret;
- ret = fbtft_request_one_gpio(par, "latch", 0, &par->gpio.latch);
+ ret = fbtft_request_one_gpio(par, "latch-gpios", 0, &par->gpio.latch);
if (ret)
return ret;
for (i = 0; i < 16; i++) {
- ret = fbtft_request_one_gpio(par, "db", i,
+ ret = fbtft_request_one_gpio(par, "db-gpios", i,
&par->gpio.db[i]);
if (ret)
return ret;
- ret = fbtft_request_one_gpio(par, "led", i,
+ ret = fbtft_request_one_gpio(par, "led-gpios", i,
&par->gpio.led[i]);
if (ret)
return ret;
- ret = fbtft_request_one_gpio(par, "aux", i,
+ ret = fbtft_request_one_gpio(par, "aux-gpios", i,
&par->gpio.aux[i]);
if (ret)
return ret;
@@ -203,6 +220,8 @@ EXPORT_SYMBOL(fbtft_register_backlight);
static void fbtft_set_addr_win(struct fbtft_par *par, int xs, int ys, int xe,
int ye)
{
+ xs = xs + 20;
+ xe = xe + 20;
write_reg(par, MIPI_DCS_SET_COLUMN_ADDRESS,
(xs >> 8) & 0xFF, xs & 0xFF, (xe >> 8) & 0xFF, xe & 0xFF);
@@ -221,10 +240,10 @@ static void fbtft_reset(struct fbtft_par *par)
gpiod_set_value_cansleep(par->gpio.reset, 1);
usleep_range(20, 40);
- gpiod_set_value_cansleep(par->gpio.reset, 0);
+ gpiod_set_value_cansleep(par->gpio.reset, 0); /* Low level reset */
msleep(120);
- gpiod_set_value_cansleep(par->gpio.cs, 1); /* Activate chip */
+ gpiod_set_value_cansleep(par->gpio.reset, 1); /* Activate chip */
}
标签:par,HamsterBear,适配,ST7789V,request,ret,fbtft,write,gpio 来源: https://www.cnblogs.com/hfwz/p/16028968.html