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)

 

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