TP驱动调试笔记

     以在mtk6737平台移植汇顶的GT910举例,建议正式调试的前一天把代码完整编译一遍,假如时间来不及,至少要先编译内核,编译

eng或者userdebug版本。一般要提前准备:主板、TP模组、串口线、硬件原理图,供应商提供芯片手册、规格书、驱动代码和cfg参数

等。调试最开始首先要了解TP芯片的型号、屏幕分辨率、主板上面TP座子位置、供电方式、中断和复位脚的GPIO号、用到哪组i2c总线

核对主板座子和规格书里面排线线序是否一致。接下来第一个小目标就是调通i2c,读到正确的ID值。

 

     TP(触摸屏)的大致工作流程是:主控芯片与TP芯片通过i2c总线通讯,它们之间一般有6个引脚相连接,分别是VDD、RESET、SCL、

SDA、INT、GND。开机过程中系统会对TP芯片进行上电初始化,之后TP处于待命状态。当TP模组表面有触摸时,会产生中断,接着

在中断处理函数中唤醒触摸事件的线程,在线程里面通过i2c读取点座标信息上报给系统层。

 

1、移植芯片driver驱动代码

把厂家提供的GT910的代码复制到以下目录,有时候要把另外提供的CFG参数替换到gt9xx_config.h的CTP_CFG_GROUP1中

kernel-3.18/drivers/input/touchscreen/mediatek/

 

驱动代码gt9xx_driver.c中需要重点关注的一些函数:

static int __init tpd_driver_init(void); /*一般阅读驱动的代码是从最下面的module_init里面的函数开始*/

void tpd_get_dts_info(void); /*读取设备树touch节点的属性*/

static int tpd_local_init(void); /*在这里添加i2c driver*/

static s32 tpd_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id); /*i2c driver与device匹配成功才调用这个函数*/

static int tpd_power_on(struct i2c_client *client); /*上电和复位*/

s32 gtp_read_version(struct i2c_client *client, u16 *version); /*读取版本号,在这里可以确认i2c通讯是否成功*/

static s32 gtp_init_panel(struct i2c_client *client); /*TP芯片的初始化*/

static int tpd_irq_registration(void); /*申请中断*/

static int touch_event_handler(void *unused); /*触摸事件处理线程,中断产生时会唤醒这个线程*/

static void tpd_down(s32 x, s32 y, s32 size, s32 id); /*上报点座标*/

 

如果感兴趣,可以等驱动调通后再更加仔细地阅读代码,在内核中用dump_stack(); 函数可以查看当前函数被哪些函数调用,对

跟读代码很有帮助。

 

供电方面要注意,确认是采用pmic输出2.8V,还是外部独立的LDO供电,根据硬件原理图来定。

//pmic输出2.8V的部分控制代码

tpd->reg = regulator_get(tpd->tpd_dev, "vtouch");

ret = regulator_set_voltage(tpd->reg, 2800000, 2800000); /*set 2.8v*/

if (ret) {

printk("regulator_set_voltage(%d) failed!\n", ret);

return -1;

}

ret = regulator_enable(tpd->reg); /*使能电源*/

 

//独立的LDO供电方式,则是控制某个gpio输出高、低电平

#define GTP_POWER_PORT  (GPIO22 | 0x80000000) 

/*MTK旧的平台可以直接这样调用GPIO,Android7.0及以后建议改用从dts里面读取*/

 

mt_set_gpio_mode(GTP_POWER_PORT, GPIO_MODE_00);

mt_set_gpio_dir(GTP_POWER_PORT, GPIO_DIR_OUT);

mt_set_gpio_out (GTP_POWER_PORT, 1); //输出高电平,使能LDO的2.8V

 

2、修改Makefile和Kconfig

kernel-3.18/arch/arm/configs/产品_debug_defconfig  (注意:64位系统选择arm64目录,32位系统选择arm目录)

+CONFIG_TOUCHSCREEN_MTK_GT910=y

-CONFIG_TOUCHSCREEN_MTK_FT5X0X=y

+# CONFIG_TOUCHSCREEN_MTK_FT5X0X is not set   #把旧型号的config注释掉,前面加# 末尾改成is not set

 

kernel-3.18/arch/arm/configs/产品_defconfig

+CONFIG_TOUCHSCREEN_MTK_GT910=y

-CONFIG_TOUCHSCREEN_MTK_FT5X0X=y

+# CONFIG_TOUCHSCREEN_MTK_FT5X0X is not set

 

kernel-3.18/drivers/input/touchscreen/mediatek/Makefile

+obj-$(CONFIG_TOUCHSCREEN_MTK_GT910) += GT910/

 

kernel-3.18/drivers/input/touchscreen/mediatek/Kconfig

+source "drivers/input/touchscreen/mediatek/GT910/Kconfig"

   

注意:凡是修改了config文件,编译前要删除out目录中的.config文件(下面的产品名称根据自己的项目来定)

rm -rf out/target/product/产品/obj/KERNEL_OBJ/.config

 

3、修改设备树dts文件

kernel-3.18/arch/arm/boot/dts/产品.dts

 

&touch {  # tpd_get_dts_info函数里面会读取这里的一些参数

    tpd-resolution = <480 800>; #修改分辨率,与LCD的一致

    use-tpd-button = <0>;  #TP的底部是否带触摸按键,配置为0表示不带

    tpd-key-num = <3>;

    tpd-key-local= <139 172 158 0>;

    tpd-key-dim-local = <90 883 100 40 230 883 100 40 370 883 100 40 0 0 0 0>;

    tpd-max-touch-num = <5>;  #最多支持5点触摸

    tpd-filter-enable = <0>;

    tpd-filter-pixel-density = <146>;

    tpd-filter-custom-prameters = <0 0 0 0 0 0 0 0 0 0 0 0>;

    tpd-filter-custom-speed = <0 0 0>;

    pinctrl-names = "default", "state_eint_as_int", "state_eint_output0", "state_eint_output1",

        "state_rst_output0", "state_rst_output1";  #mtk_tpd.c里面会根据这些名称来匹配pinctrl_state,用来控制gpio

    pinctrl-0 = <&CTP_pins_default>;

    pinctrl-1 = <&CTP_pins_eint_as_int>;

    pinctrl-2 = <&CTP_pins_eint_output0>;

    pinctrl-3 = <&CTP_pins_eint_output1>;

    pinctrl-4 = <&CTP_pins_rst_output0>;

    pinctrl-5 = <&CTP_pins_rst_output1>;

    status = "okay";

};

&pio {

    CTP_pins_default: eint0default {

    };

    CTP_pins_eint_as_int: eint@0 {

        pins_cmd_dat {

            pins = <PINMUX_GPIO124__FUNC_GPIO124>; #根据原理图修改中断脚的gpio

            slew-rate = <0>;  #配置成0表示输入

            bias-disable;  #取消内部上下拉

        };

    };

    CTP_pins_eint_output0: eintoutput0 {

        pins_cmd_dat {

            pins = <PINMUX_GPIO124__FUNC_GPIO124>;

            slew-rate = <1>;  #配置成1表示输出

            output-low;  #输出低

        };

    };

    CTP_pins_eint_output1: eintoutput1 {

        pins_cmd_dat {

            pins = <PINMUX_GPIO124__FUNC_GPIO124>;

            slew-rate = <1>;

            output-high;  #输出高

        };

    };

    CTP_pins_rst_output0: rstoutput0 {

        pins_cmd_dat {

            pins = <PINMUX_GPIO123__FUNC_GPIO123>; #根据原理图修改复位脚的gpio

            slew-rate = <1>;

            output-low;

        };

    };

    CTP_pins_rst_output1: rstoutput1 {

        pins_cmd_dat {

            pins = <PINMUX_GPIO123__FUNC_GPIO123>;

            slew-rate = <1>;

            output-high;

        };

    };

};

 

凡是dts有修改的,编译bootimage前要先删除下面目录(不是每次编译前都要删除,有修改了才需要删)

rm -rf out/target/product/产品/obj/KERNEL_OBJ/arch/arm/boot/dts/

 

4、配置dws文件

DCT编辑工具位置:

vendor\mediatek\proprietary\bootable\bootloader\preloader\tools\dct\old_dct\DrvGen.exe

DWS文件位置:

vendor\mediatek\proprietary\bootable\bootloader\preloader\custom\产品\dct\dct\codegen.dws

vendor\mediatek\proprietary\bootable\bootloader\lk\target\产品\dct\dct\codegen.dws

kernel-3.18\drivers\misc\mediatek\mach\平台\产品\dct\dct\codegen.dws

 

a、打开I2C选项栏,选择TP的i2c设备名称i2c总线、填入i2c地址

     dws中的Slave Device名称要与驱动代码中.compatible的cap_touch”名称一致,dws中的设备名称一般用大写如下图所示。

    TP芯片用到哪组i2c总线,根据硬件原理图来确定。TP的i2c地址可以在数据手册里面找到或者直接问FAE。

 

     如果Slave Device名称找不到,可以在下面的文件中自定义增加名称,然后重新打开dct编辑工具,就可以在Slave Device下拉

     列表中找到。

     vendor/mediatek/proprietary/bootable/bootloader/preloader/tools/dct/old_dct/I2C_YuSu.cmp

 

b、打开GPIO选项栏,配置gpio默认属性

     gpio124是中断脚,勾选中断、内部上下拉使能、上拉高电平;

     gpio123是复位脚,配置成普通GPIO(Def.Mode选0:),勾选内部上下拉使能,由于没有勾选上拉所以默认是下拉输出低电平。  

c、打开EINT选项栏,配置中断名称、防抖时间、极性、触发类型、是否有防抖  

d、修改dws后的编译注意

     凡是dws有修改的,要先删除下面的3个目录,再重新编译pl、lk、bootimage

     rm -rf out/target/product/产品/obj/KERNEL_OBJ/arch/arm/boot/dts/

     rm -rf out/target/product/产品/obj/BOOTLOADER_OBJ/

     rm -rf out/target/product/产品/obj/PRELOADER_OBJ/

 

     make pl -j16 ; make lk -j16 ; make bootimage -j16

 

5、排除编译报错, boot、pl、lk编译通过后刷机测试

      移植GT910驱动代码后的第一次编译,先删除下面的目录再编译,里面有其它旧型号的驱动.o文件

      rm -rf out/target/product/产品/obj/KERNEL_OBJ/drivers/input/touchscreen/

 

           查看开机串口log里面,有没有调用tpd_i2c_probe函数,probe匹配原理是:驱动代码中tpd_of_match的compatible名称与dws

      编译出来的I2C Slave Device compatible名称对比。看到调用probe后,接着看上电、复位、读取芯片ID、芯片初始化、申请中断

      等有没有成功。确认开机初始化通过后,触摸TP看看界面是否响应。调试过程可以在代码中多增加printk打印log,方便了解驱动

      代码运行到哪一步。

 

6、调试过程遇到一些问题的处理方法

      a、开机过程没有调用probe函数

           检查驱动代码有没有编译到,tpd_of_match中compatible里逗号后面的名称是否与dws中的I2C Slave Device名称一致。检查上

           面提到的一些注意事项,凡是config、dws或dts有修改,编译前要删除out目录中的一些编译输出文件。

      b、开机过程中i2c报错

           检查供电、复位脚时序、软件中i2c总线有没有选对,核对i2c地址,核对座子和TP排线的线序,如果有必要可以使用示波器测

           量波形。有时候可更换主板或TP模组试试,排除硬件物料问题。实在找不到问题点,可以找硬件设计人员、FAE一起协助分析。

      c、开机初始化没有报错,读ID正常,但触摸无响应

           在中断函数里面加log打印或者使用示波器测量中断脚波形,看有没有中断产生。检查驱动代码里面中断脚有没有配置正确。有

           时候要更新cfg参数或者固件,多跟FAE沟通。

     d、报点错乱、划线断线(系统设置开发者选项里面开启”指针位置”后,在屏幕划线时会有点轨迹)、触摸不灵敏等效果问题

           需要找FAE协助优化,更新cfg参数或者固件。

 

7、开机初始化时tpd_i2c_probe的调用过程

     驱动代码gt9xx_driver.c:

     static int tpd_local_init(void)

       \if (i2c_add_driver(&tpd_i2c_driver) != 0) {

          \int i2c_register_driver(struct module *owner, struct i2c_driver *driver)

             \int driver_register(struct device_driver *drv)

                 \int bus_add_driver(struct device_driver *drv)

                     \int driver_attach(struct device_driver *drv)

                         \int bus_for_each_dev(struct bus_type *bus, struct device *start, /*在这里遍历所有的设备*/

                             \static int __driver_attach(struct device *dev, void *data)

                                 \ if (!driver_match_device(drv, dev))  /*如果这里匹配不成功,则直接返回0,不会往下调用driver_probe_device*/

                                    \ static inline int driver_match_device(struct device_driver *drv,

                                        \static int i2c_device_match(struct device *dev, struct device_driver *drv)

                                            \ static inline int of_driver_match_device(struct device *dev,

                                               \ const struct of_device_id *__of_match_node(const struct of_device_id *matches,

                                                   \ static int __of_device_is_compatible(const struct device_node *device, /*最终对比compatible名称*/

                                \int driver_probe_device(struct device_driver *drv, struct device *dev)

                                    \static int really_probe(struct device *dev, struct device_driver *drv)

                                         \ret = dev->bus->probe(dev);

                                             \static s32 tpd_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章