君正 Halley6 开发板调试SPI LCD

本文详细介绍了在Linux 4.4.94内核中为X1600开发板添加LCD(LQ035)驱动和PWM背光驱动的步骤。包括设备树配置、驱动程序代码的修改以及kernel编译配置。针对LCD,重点讲述了初始化代码的添加和分辨率设置,以及控制pin的上电时序。对于PWM背光驱动,主要涉及设备树配置和kernel配置。此外,还简单提及了添加TP驱动的一般流程。
摘要由CSDN通过智能技术生成

kernel版本:linux-4.4.94

CPU: X1600

LCD: 3.5 寸TFT(320×240),Model Name LQ035NC111

本⽂以芯⽚x1600, 开发板halley6⽬前使⽤的群创的spi lcd为例

添加⼀款新的lcd驱动可以分为两部分,添加背光驱动和添加lcd驱动。下边分别介绍添加两部分驱动的步骤。
1.kernel中添加pwm背光驱动

添加驱动⼀般需要添加两部分,⼀部分是设备树dts配置, 另⼀部分是驱动程序代码。

1.1 设备树dts配置

代码位置

kernel-4.4.94/arch/mips/boot/dts/ingenic/halley6_v10.dts

kernel-4.4.94/arch/mips/boot/dts/ingenic/halley6_lcd/RD_X1600_HALLEY6_RGB_SPI_LCD_1V0.dtsi

1 &pwm { 
2 	pinctrl-names = "default"; 
3 	pinctrl-0 = <&pwm0_pc>; //这⾥需要查看原理图, 确定连接的pwm 
4 	status = "okay"; 
5 };
1 backlight { 
2 	compatible = "pwm-backlight"; 
3 	pwms = <&pwm 0 1000000>; //这⾥需要注意pwm是⼏ 
4 	brightness-levels = <0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15>; 
5 	default-brightness-level = <4>; 
6 }
1.2 驱动程序代码

代码位置

drivers/video/backlight/pwm_bl.c

pws背光驱动代码⽆需更改。

1.3 kernel编译配置
1 Symbol: PWM_INGENIC_V3 [=y]
2 │ Type : bool 
3 │ Defined at module_drivers/drivers/pwm/Kconfig:24
4 │ Prompt: Ingenic V3 PWM support
5 │ Depends on: SOC_X1600 [=y]
6 │ Location: 
7 │ -> Ingenic device-drivers Configurations
8 │ -> [PWM] drivers

正确配置, 可以看到背光点亮。

2. kernel中添加lcd驱动
2.1 设备树dts配置

代码位置

kernel-4.4.94/arch/mips/boot/dts/ingenic/halley6_lcd/RD_X1600_HALLEY6_RGB_SPI_LCD_1V0.dtsi

/ {
    display-dbi {
        compatible = "simple-bus";
        #interrupt-cells = <1>;
        #address-cells = <1>;
        #size-cells = <1>;
        ranges = <>;
        panel_lq035 {
            compatible = "ingenic,lq035"; // 跟lcd驱动代码中compatible = "ingenic,lq035"; 保持⼀致
            status = "okay";
            //定义了数据pin, 定义位置:module_drivers/dts/x1600-pinctrl.dtsi
            pinctrl-names = "default", "i2c-func", "sda-high", "sda-low", "sck-high", "sck-low";
            pinctrl-0 = <&tft_lcd_pa_rgb888>;     //lsun
            pinctrl-1 = <&i2c1_pb_f2>;
            pinctrl-2 = <&fw040_sda_out_high>;
            pinctrl-3 = <&fw040_sda_out_low>;
            pinctrl-4 = <&fw040_sck_out_high>;
            pinctrl-5 = <&fw040_sck_out_low>;
			//以下四个gpio根 据原理图
/*          ingenic,lcd-pwm-gpio = <&gpc 0 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>;*/
            ingenic,vdd-en-gpio = <&gpa 31 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>;  
            ingenic,rst-gpio = <&gpb 13 GPIO_ACTIVE_LOW INGENIC_GPIO_NOBIAS>;
            ingenic,de-gpio = <&gpa 27 GPIO_ACTIVE_LOW INGENIC_GPIO_NOBIAS>;    //lsun
            ingenic,lcd-cs-gpio = <&gpb 14 GPIO_ACTIVE_LOW INGENIC_GPIO_NOBIAS>;
            port {
                panel_lq035_ep: endpoint {
                    remote-endpoint = <&dpu_out_ep>;  //与下边dpu配置相对应
                };
            };
        };
    };
    backlight {
        compatible = "pwm-backlight";
        pwms = <&pwm 0 1000000>;
        brightness-levels = <0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15>;
        default-brightness-level = <4>;
    };
};
&dpu {
    status = "okay";
    port {
        dpu_out_ep: endpoint {
        remote-endpoint = <&panel_lq035_ep>;   //与上边lcd配置相对应
    ¦   };
    };
};
2.2 添加驱动程序代码

代码位置:module_drivers/drivers/video/fbdev/ingenic/fb_stage/displays/panel-lq035.c

2.2.1 lcd初始化代码添加

调试显⽰屏, ⼀般情况下屏⼚不会提供直接可⽤的驱动,lcd驱动需要在代码库中找⼀份lcd驱动进⾏改写, 屏⼚会提供显⽰屏的初始化代码, 根据屏⼚提供的初始化代码, 按照⼀定规则在驱动中填写初始化代码。

lq035这款屏的初始化代码如下:

void initial_3.5tft_spi(void)/*********3.5TFT****************/
{
write_SPI(0x001);
delayms(50);
write_SPI(0x011);
delayms(50);
write_SPI(0x003);
delayms(50);
write_SPI(0x020);
delayms(50);

write_SPI(0x036);
write_SPI(0x100);//0x1c0

write_SPI(0x038);
write_SPI(0x03A);
write_SPI(0x150);
write_SPI(0x0B0);
write_SPI(0x132);
write_SPI(0x0B1);
write_SPI(0x1AC);
write_SPI(0x0B2);

write_SPI(0x141);//0x141

write_SPI(0x0B3);
write_SPI(0x123);//0x123

write_SPI(0x0B4);
write_SPI(0x100);

write_SPI(0x0C2);
write_SPI(0x109); //0x109
                         
write_SPI(0x0C3);
write_SPI(0x1dc);//0x1dc

write_SPI(0x0C4);
write_SPI(0x100);
write_SPI(0x0C5);
write_SPI(0x100);
write_SPI(0x0C9);
write_SPI(0x181);
write_SPI(0x0D4);
write_SPI(0x100);
write_SPI(0x0D5);
write_SPI(0x100);
write_SPI(0x0D6);
write_SPI(0x11c);
write_SPI(0x0D7);
write_SPI(0x117);
write_SPI(0x0D8);
write_SPI(0x100);
write_SPI(0x0D9);
write_SPI(0x104); 
delayms(50);

write_SPI(0x0D2);
write_SPI(0x123);
write_SPI(0x129);
write_SPI(0x121);
write_SPI(0x121);
write_SPI(0x100);
write_SPI(0x102);
write_SPI(0x101);
write_SPI(0x12b);
write_SPI(0x136);
write_SPI(0x13f);

write_SPI(0x0D3);
write_SPI(0x125);//0x125
write_SPI(0x029);
delayms(50);

}

void write_SPI(unsigned int par)//9bit spi
{ 
    unsigned char n;
       
    LCD_CSB = 0;    
    LCD_SCL = 1;
     
    for(n=0; n<9; n++)
    {           
     LCD_SCL = 0;
     LCD_SDA = (par>>(8-n))&0x01;
     LCD_SCL = 1;
            
    }  
     LCD_CSB = 1;
}

因为每个屏⼚给的初始化代码没有统⼀固定格式, 所以没有固定的改写⽅式, 这⾥只描述⼀下将初始化代码添加的位置

void write_SPI(unsigned int par) //9bit spi
{
        unsigned char n;

        //LCD_CSB = 0;
        CS(0);
        //LCD_SCL = 1;
        SCK_HIGH();

        for (n = 0; n < 9; n++) {
                //LCD_SCL = 0;
                SCK_LOW();
                //LCD_SDA = (par >> (8 - n)) & 0x01;
                if((par >> (8 - n)) & 0x01)
                        SDA_HIGH();
                else
                        SDA_LOW();
                //LCD_SCL = 1;
                SCK_HIGH();
        }
        //LCD_CSB = 1;
        CS(1);
}

void Initial_IC(void)
{
        write_SPI(0x001);
        mdelay(50);
        write_SPI(0x011);
        mdelay(50);
        write_SPI(0x003);
        mdelay(50);
        write_SPI(0x020);
        mdelay(50);

        write_SPI(0x036);
        write_SPI(0x100);//0x1c0

        write_SPI(0x038);
        write_SPI(0x03A);
        write_SPI(0x150);
        write_SPI(0x0B0);
        write_SPI(0x132);
        write_SPI(0x0B1);
        write_SPI(0x1AC);
        write_SPI(0x0B2);

        write_SPI(0x141);//0x141

        write_SPI(0x0B3);
        write_SPI(0x123);//0x123

        write_SPI(0x0B4);
        write_SPI(0x100);

        write_SPI(0x0C2);
        write_SPI(0x109); //0x109

        write_SPI(0x0C3);
        write_SPI(0x1dc);//0x1dc

        write_SPI(0x0C4);
        write_SPI(0x100);
        write_SPI(0x0C5);
        write_SPI(0x100);
        write_SPI(0x0C9);
        write_SPI(0x181);
        write_SPI(0x0D4);
        write_SPI(0x100);
        write_SPI(0x0D5);
        write_SPI(0x100);
        write_SPI(0x0D6);
        write_SPI(0x11c);
        write_SPI(0x0D7);
        write_SPI(0x117);
        write_SPI(0x0D8);
        write_SPI(0x100);
        write_SPI(0x0D9);
        write_SPI(0x104);
        mdelay(50);

        write_SPI(0x0D2);
        write_SPI(0x123);
        write_SPI(0x129);
        write_SPI(0x121);
        write_SPI(0x121);
        write_SPI(0x100);
        write_SPI(0x102);
        write_SPI(0x101);
        write_SPI(0x12b);
        write_SPI(0x136);
        write_SPI(0x13f);

        write_SPI(0x0D3);
        write_SPI(0x125);//0x125
        write_SPI(0x029);
        mdelay(50);
}
2.2.2 lcd分辨率正确配置

LCD 的参数设定是需要根据LCD的手册来设定kernel-4.4.94/module_drivers/drivers/video/fbdev/ingenic/fb_stage/displays/panel-lq035.c里面的struct fb_videomode panel_modes[]结构体

例如从LQ035NC111的手册可以得到如下一个表

在这里插入图片描述

该表描述了该款并行LCD的所有时钟需求,在这里我参照的全是典型值“Typ”一栏

一个很具有参考价值的文档文件是Documentation/fb/framebuffer.txt文件,里面给我们描述了一个架构
在这里插入图片描述

对应我们 LQ035NC111 Spec上的时序如下
在这里插入图片描述

还有一个很有用的公式

Pixelclock = HTOTAL * VTOTAL * 60 /* HTOTAL是指Hsync Period,VTOTAL是指Vsync Period*/ 单位是HZ

pixclock = 1000000000000 / Pixelclock 单位是皮秒

再结合结构体

static struct fb_videomode panel_modes[] = {
    [0] = {
        .name                   = "lq035",
        .refresh                = 30,
        .xres                   = 320,
        .yres                   = 240,
//      .pixclock               = KHZ2PICOS(14000),
        .pixclock               = 125000,
        .left_margin            = 71,
        .right_margin           = 18,
        .upper_margin           = 14,
        .lower_margin           = 10,

        .hsync_len              = 2,
        .vsync_len              = 2,
        .sync                   = FB_SYNC_HOR_HIGH_ACT & FB_SYNC_VERT_HIGH_ACT,
        .vmode                  = FB_VMODE_NONINTERLACED,
        .flag                   = 0,
    },
};
static struct tft_config fw040_cfg = {
        .pix_clk_inv = 1,                                       //特别注意:PCLK的极性, x1600发出去的和lcd那边需要一致
        .de_dl = 0,
        .sync_dl = 0,
        .vsync_dl = 0,
        .color_even = TFT_LCD_COLOR_EVEN_RGB,
        .color_odd = TFT_LCD_COLOR_ODD_RGB,
        .mode = TFT_LCD_MODE_PARALLEL_888,    //lsun
};

struct lcd_panel lcd_panel = {
        .name = "lq035",
        .num_modes = ARRAY_SIZE(panel_modes),
        .modes = panel_modes,
        .bpp = 24,                                                      //lsun
        .width = 320,
        .height = 240,

        .lcd_type = LCD_TYPE_TFT,

        .tft_config = &fw040_cfg,

        .dither_enable = 0,
        .dither.dither_red = 0,
        .dither.dither_green = 0,
        .dither.dither_blue = 0,

        .ops = &panel_ops,
};

width、height的设定这个就没什么歧义了,对应320和240

bpp:其实我的这个LCD手册上说该屏是支持24位色的,但是这里填写16位,有空可以试试24位

显示一行时序为: HSPW -> HBPD -> 扫描数据 -> HFPD

垂直扫描一帧的时序: VSPW -> VBPD -> 扫描有效行 -> VFPD

其他的参数:其他参数对应第3节的表填写

xres <=> TEP <=> 320
yres <=> Tvd <=> 240
left_margin <=> Thf <=> 20 /* front porch /
right_margin <=> Thb <=> 38 /
back porch /
hsync_len <=> THS <=> 30 /
hsync width /
upper_margin <=> Tvf <=> 4 /
front porch /
lower_margin <=> Tvb <=> 15 /
back porch /
vsync_len <=> Tvs <=> 3 /
vsync width */

tvp 即 VSPW
tvb 即 VBPD
tvf 即 VFPD
thp 即 HSPW
thb 即 HBPD
thf 即 HFPD

VBPD(vertical back porch):表示在一帧图像開始时,垂直同步信号以后的无效的行数
VFPD(vertical front porch):表示在一帧图像结束后,垂直同步信号曾经的无效的行数
VSPW(vertical sync pulse width):表示垂直同步脉冲的宽度,用行数计算
HBPD(horizontal back porch):表示从水平同步信号開始到一行的有效数据開始之间的VCLK的个数
HFPD(horizontal front porth):表示一行的有效数据结束到下一个水平同步信号開始之间的VCLK的个数
HSPW(horizontal sync pulse width):表示水平同步信号的宽度

按理说,对于一个已知尺寸(即水平显示尺寸HOZVAL和垂直显示尺寸LINEVAL已知)的LCD屏,仅仅要确定了VCLK值,行频和场频就应该知道了。但这样还不行的,由于在每一帧时钟信号中,还会有一些与屏显示无关的时钟出现,这就给确定行频和场频带来了一定的复杂性。如在HSYNC信号先后会有水平同步信号前肩(HFPD)和水平同步信号后肩(HBPD)出现,在VSYNC信号先后会有垂直同步信号前肩(VFPD)和垂直同步信号后肩(VBPD)出现,在这些信号时序内,不会有有效像素信号出现,另外HSYNC和VSYNC信号有效时,其电平要保持一定的时间,它们分别叫做水平同步信号脉宽HSPW和垂直同步信号脉宽VSPW,这段时间也不能有像素信号。因此计算行频和场频时,一定要包含这些信号。HBPD、HFPD和HSPW的单位是一个VCLK的时间,而VSPW、VFPD和VBPD的单位是扫描一行所用的时间。

LCD一般须要三个时序信号:VSYNC、HSYNC和VCLK。

VSYNC是垂直同步信号(帧同步信号),在每进行一个帧(即一个屏)的扫描之前,该信号就有效一次,由该信号能够确定LCD的场频,即每秒屏幕刷新的次数(单位Hz)。
HSYNC是水平同步信号(行同步信号),在每进行一行的扫描之前,该信号就有效一次,由该信号能够确定LCD的行频,即每秒屏幕从左到右扫描一行的次数(单位Hz)。
VCLK是像素时钟信号。

2.2.3 lcd控制pin的上电时序及操作⽅式

主要有哪些控制pin, 如何控制, 不同的屏有不同的⽅式, 需要查看<屏幕规格书>, <屏幕driverIC的⼿册>

驱动中解析dts中的控制pin:

static int of_panel_parse(struct device *dev)
{
        struct panel_dev *panel = dev_get_drvdata(dev);
        struct device_node *np = dev->of_node;
        enum of_gpio_flags flags;
        int ret = 0;

        panel->vdd_en.gpio = of_get_named_gpio_flags(np, "ingenic,vdd-en-gpio", 0, &flags);
        if(gpio_is_valid(panel->vdd_en.gpio)) {
                panel->vdd_en.active_level = (flags & OF_GPIO_ACTIVE_LOW) ? 0 : 1;
                ret = gpio_request_one(panel->vdd_en.gpio, GPIOF_DIR_OUT, "vdd_en");
                if(ret < 0) {
                        dev_err(dev, "Failed to request vdd_en pin!\n");
                        return ret;
                }
        } else {
                dev_warn(dev, "invalid gpio vdd_en.gpio: %d\n", panel->vdd_en.gpio);
        }

        panel->rst.gpio = of_get_named_gpio_flags(np, "ingenic,rst-gpio", 0, &flags);
        if(gpio_is_valid(panel->rst.gpio)) {
                panel->rst.active_level = (flags & OF_GPIO_ACTIVE_LOW) ? 0 : 1;
                ret = gpio_request_one(panel->rst.gpio, GPIOF_DIR_OUT, "rst");
                if(ret < 0) {
                        dev_err(dev, "Failed to request rst pin!\n");
                        goto err_request_rst;
                }
        } else {
                dev_warn(dev, "invalid gpio rst.gpio: %d\n", panel->rst.gpio);
        }

        panel->pwm.gpio = of_get_named_gpio_flags(np, "ingenic,lcd-pwm-gpio", 0, &flags);
        if(gpio_is_valid(panel->pwm.gpio)) {
                panel->pwm.active_level = (flags & OF_GPIO_ACTIVE_LOW) ? 0 : 1;
                ret = gpio_request_one(panel->pwm.gpio, GPIOF_DIR_OUT, "pwm");
                if(ret < 0) {
                        dev_err(dev, "Failed to request pwm pin!\n");
                        goto err_request_pwm;
                }
        } else {
                dev_warn(dev, "invalid gpio pwm.gpio: %d\n", panel->pwm.gpio);
        }
#if 1
        panel->de.gpio = of_get_named_gpio_flags(np, "ingenic,de-gpio", 0, &flags);
        if(gpio_is_valid(panel->de.gpio)) {
                panel->de.active_level = (flags & OF_GPIO_ACTIVE_LOW) ? 0 : 1;
                ret = gpio_request_one(panel->de.gpio, GPIOF_DIR_OUT, "de");
                if(ret < 0) {
                        dev_err(dev, "Failed to request de pin!\n");
                        goto err_request_de;
                }
        } else {
                dev_warn(dev, "invalid gpio de.gpio: %d\n", panel->de.gpio);
        }
#endif
        panel->spi.cs = of_get_named_gpio_flags(np, "ingenic,lcd-cs-gpio", 0, &flags);
        if(gpio_is_valid(panel->spi.cs)) {
                ret = gpio_request_one(panel->spi.cs, GPIOF_DIR_OUT, "cs");
                if(ret < 0) {
                        dev_err(dev, "Failed to request cs pin!\n");
                        goto err_request_cs;
                }
        } else {
                dev_warn(dev, "invalid gpio spi.cs: %d\n", panel->spi.cs);
        }

        state->i2c = pinctrl_lookup_state(p, "i2c-func");
        state->sda_high = pinctrl_lookup_state(p, "sda-high");
        state->sda_low = pinctrl_lookup_state(p, "sda-low");
        state->sck_high = pinctrl_lookup_state(p, "sck-high");
        state->sck_low = pinctrl_lookup_state(p, "sck-low");

        return 0;
err_request_cs:
        if(gpio_is_valid(panel->spi.sck))
                gpio_free(panel->spi.sck);
err_request_sck:
        if(gpio_is_valid(panel->spi.sdo))
                gpio_free(panel->spi.sdo);
err_request_sdo:
        if(gpio_is_valid(panel->pwm.gpio))
                gpio_free(panel->pwm.gpio);
err_request_pwm:
        if(gpio_is_valid(panel->rst.gpio))
                gpio_free(panel->rst.gpio);
err_request_de:                                                                 //lsun
        if(gpio_is_valid(panel->de.gpio))
                gpio_free(panel->de.gpio);
err_request_rst:
        if(gpio_is_valid(panel->vdd_en.gpio))
                gpio_free(panel->vdd_en.gpio);
        return ret;
}

不同的显⽰屏控制pin也有所不同, 上电时序也有变化, 所以需要具体来看。

驱动中控制pin的操作,上电时序:

#define POWER_IS_ON(pwr)        ((pwr) <= FB_BLANK_NORMAL)
static int panel_set_power(struct lcd_device *lcd, int power)
{
        struct panel_dev *panel = lcd_get_data(lcd);
        struct board_gpio *vdd_en = &panel->vdd_en;
        struct board_gpio *rst = &panel->rst;
        struct board_gpio *pwm = &panel->pwm;

        if(!POWER_IS_ON(power) && POWER_IS_ON(panel->power)) {
                gpio_direction_output(vdd_en->gpio, 0);
                gpio_direction_output(rst->gpio, 0);
        }else{
                if(gpio_is_valid(pwm->gpio)){
                        gpio_direction_output(pwm->gpio, 1);
                        msleep(180);
                }
#if 0
                gpio_direction_output(vdd_en->gpio, 0);
                gpio_direction_output(rst->gpio, 1);
                msleep(100);

                gpio_direction_output(vdd_en->gpio, 1);
                msleep(180);

                gpio_direction_output(rst->gpio, 0);
                msleep(20);
                gpio_direction_output(rst->gpio, 1);
                msleep(20);
#else
                gpio_direction_output(vdd_en->gpio, 0);
                gpio_direction_output(rst->gpio, 0);
                msleep(100);

                gpio_direction_output(vdd_en->gpio, 1);
                msleep(10);

                gpio_direction_output(rst->gpio, 1);
                msleep(10);
#endif
                Initial_IC();
                pinctrl_select_state(p, state->i2c);
                gpio_free(panel->spi.cs);
        }

        panel->power = power;
        return 0;
}

以上就是新添加⼀款显⽰屏, ⼤致需要添加的配置和代码, 因为由于屏⼚提供的资料和每款显⽰ 屏的不同, 具体实现时会差别, 以上内容可作为参考。

注意

在这里插入图片描述

根据Spec的说明要使用Parallel RGB的565或者888的模式一定要确保硬件上sel2、sel1、sel0是接地的即下图的Pin48、Pin49、Pin50接地
在这里插入图片描述

其次,要确定下图中方的Pin52是接地使能,因为Spec中有明确说明
在这里插入图片描述

3.添加TP驱动

⽬前市⾯上使⽤居多的是显⽰+触摸⼀体的模组, 接下来介绍⼀下如何添加⼀款tp驱动.但我们这款屏不带触摸所以暂以其他屏做简单说明

tp⼚⼀般提供的资料⽐较全, 会提供完整的驱动, 所以添加tp驱动相对来说简单⼀些。

3.1 设备树dts配置

位置:module_drivers/dts/halley6_lcd/RD_X1600_HALLEY6_RGB_SLCD_1V0.dtsi

1 &i2c1 { 							//查看原理图, 确定tp使⽤的i2c 
2 	clock-frequency = <400000>; 
3 	pinctrl-names = "default"; 
4 	status = "okay"; 
5 	pinctrl-0 = <&i2c1_pb_f2>; 		//这⾥需要确定i2c pin是哪⼀组, 位置: module_drivers/dts/x1600-pinctrl.dtsi 
6 
7	goodix@0x38{ 					//以下是tp的配置, 这个⼀般会跟驱动配到提供, 根据原理图, 需要修改⼀下rst pin, int pin
8 		compatible = "goodix,ft6236"; /* do not modify */
9 		reg = <0x38>; /* do not modify */ //tp的i2c地址
10 		interrupt-parent = <&gpa>; /* INT pin */ //interrupt pin使⽤的是哪⼀组gpio
11 		interrupts = <9>;
12 		reset-gpios = <&gpb 14 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>; /* RST pin */ //rst pin配置
13 		irq-gpios = <&gpb 17 IRQ_TYPE_EDGE_FALLING INGENIC_GPIO_NOBIAS>; /* INT pin */ //int pin配置
14 		touchscreen-max-x = <480>;
15 		touchscreen-max-y = <800>;
16 		touchscreen-invert-x = <0>;
17 		touchscreen-invert-y = <0>;
18 		ft6236,swap-x2y = <0>;
19 		irq-flags = <2>; /* 1 rising, 2 falling */
20 	};
21 };

以上pin的配置均需要从原理图上获得。

3.2 tp驱动代码添加

⼀般情况, tp驱动不需要做更改, 可以直接放到kernel代码结构中,

位置:module_drivers/drivers/input/touchscreen/

放到touchscreen⽂件夹下, 然后修改touchscreen⽂件下的Kconfig, Makefile,添加编译选项。

以上就是添加⼀款tp驱动的⽅法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值