ICode9

精准搜索请尝试: 精确搜索
首页 > 系统相关> 文章详细

HamsterBear Linux ST7789V FBTFT驱动适配

2022-05-10 02:00:28  阅读:236  来源: 互联网

标签:par HamsterBear 适配 ST7789V request ret fbtft write gpio


HamsterBear Linux ST7789V FBTFT驱动适配

  • 平台 - F1C200s
  • Linux版本 - 5.18
  • TFT屏 - 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 --->,编译进内核
image

可根据需要将控制台映射到fb功能开启
image

这里我同时选择了16色的Tux 启动logo
image

然后寻找fbtft驱动,路径如下:
Device Drivers -> Staging drivers -> Support for small TFT LCD display modules --->,编译进内核
image

修改drivers/staging/fbtft/fb_st7789v.c,如下几处

  1. 修改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,如下几处

  1. 添加头文件
#include <linux/of.h>
#include <linux/of_gpio.h>
  1. 修改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;
}
  1. 修改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;
}
  1. 修改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);
}
  1. 修改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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有