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