以在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)