1. 添加I2C 設備shell
TP 通常採用的是I2C 做爲數據和命令接口,因此TP 驅動也能夠歸類爲I2C 驅動。TP驅動的主要邏輯不在這裏,可是瞭解了Linux 的I2C 體系架構,就能夠對整個驅動流程有了架構
更加清晰的認識,但這裏不詳細展開討論I2C 的體系架構,只圍繞怎麼移植開發TP 驅動展開討論。函數
在板級文件中,也就是瑞星微的代碼文件board-rk30-sdk.c 中,實例化一個i2c_board_info結構體,該結構抽象描述一個具體的i2c 設備,而後將該實例添加到__i2c_board_list 全局鏈表中。舉個實例:編碼
#if defined (CONFIG_TOUCHSCREEN_PIXCIR)操作系統
{.net
.type = "pixcir_ts",調試
.addr = 0x5c,code
.flags =0,orm
.irq = RK30_PIN4_PC2,blog
.platform_data = &pixcir_info,
},
#endif
瞭解I2C 體系架構的應該都知道,Linux 系統在能成功找到I2C adapter 以後,也就是找到I2C 控制器以後,就會掃描__i2c_board_list 這個鏈表,每找到一個i2c_board_info,就會生成一個i2c_client,i2c_client 的部分信息來自於i2c_board_info,一部分來自於i2c_adapter。i2c_client 就表示一個真真切切的i2c 設備,由於它既有描述它基本屬性的信息,也有描述它行爲的方法,通俗的說就是I2C 的傳輸方法。
如今咱們能夠回過頭來詳細說說前面的提到的i2c_board_info結構體中各個成員的意義了。type成員用來賦給後來生成的i2c_client中的name成員,i2c_client中的name就表示這個i2c_client的名字。addr是這個i2c設備的地址,它和I2C控制器一塊兒表示表示這個i2c設備,假如咱們的TP是掛載在控制器0上,那麼0-005c則表示是這個i2c設備,0-005c咱們也能夠在sys系統裏面找到。Flag是i2c讀寫的標誌,爲0表示爲寫,1表示讀。Irq是這個i2c設備的中斷腳。Platform_data是在驅動註冊時用到。
2. 添加I2C驅動
熟悉Linux設備驅動模型的人都瞭解設備,驅動,總線的關係,上面咱們講的是設備,光有設備不行,還得有驅動。通常TP供應商都會有驅動提供給咱們,這裏咱們以瑞星微SDK中的pixcir_i2c_ts.c來做個例子。
第一步是添加i2c驅動:
i2c_add_driver(&pixcir_i2c_ts_driver);
這裏就不展開討論這個函數了,pixcir_i2c_ts_driver的定義以下:
static struct i2c_driver pixcir_i2c_ts_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "pixcir_i2c_ts_v3.3.09",
#ifdef PIX_DRV_ATTR
.groups = pixcir_drv_grp,
#endif
},
#ifndef CONFIG_HAS_EARLYSUSPEND
.suspend = pixcir_i2c_ts_suspend,
.resume = pixcir_i2c_ts_resume,
#endif
.probe = pixcir_i2c_ts_probe,
.remove = __devexit_p(pixcir_i2c_ts_remove),
.id_table = pixcir_i2c_ts_id,
};
按照Linux設備驅動模型,一旦總線上有新的驅動加入,則系統會自動去搜索掛載在這個總線上的全部設備,而後拿每一個設備的name跟驅動的id_table比較,若是兩個的名字同樣,那麼接下來就會執行驅動裏面的probe函數。
3. TP驅動中的Probe
不管是什麼樣的TP驅動,在probe中不外乎就作如下幾件事情:
1) 申請TP相應的IO口,而後重啓一下設備
2) 申請TP中斷,熟悉Linux中斷的人都應該知道中斷的頂半部和底半部機制,因而要申請一個工做隊列和初始化一個工做任務。
INIT_WORK(&tsdata->work.work, pixcir_ts_poscheck);
pixcir_wq = create_singlethread_workqueue("pixcir_wq");
TP的數據上報流程是,當人手按下的時候,TP則產生一箇中斷,在中斷服務程序中,將數據讀出而且經過輸入子系統將數據上報給操做系統。
3) TP在硬件上經過I2C接口告訴人們它的數據,在軟件上則是經過輸入子系統告訴操做系統它的數據,而使用輸入子系統的第一步則是申請一個輸入子設備:
input_allocate_device();
這裏不詳細展開討論這個函數裏面的東西了,輸入子系統通訊的基本單位是事件,事件有三種屬性:類型(type),編碼(code),值(value)。輸入子系統支持不少種事件,不少種事件編碼,因此在使用輸入設備前,要先設置這個設備支持何種類型的事件,何種事件編碼。
4)通常的TP驅動支持的是如下幾種事件
__set_bit(EV_KEY, input->evbit);
__set_bit(EV_ABS, input->evbit);
__set_bit(EV_SYN, input->evbit);
5)肯定多點觸摸的協議。多點觸摸的協議有A協議跟B協議之分。A類在每次報點後加 input_mt_sync(touch_dev->input_dev);
B類須要在probe中執行input_mt_init_slots(ts->input_dev, ts->max_touch_num);再在每次報點前input_mt_slot(ts->input_dev, index);
6) 向輸入子系統註冊設備:
input_register_device(ts->input_dev);
4. 觸摸屏調試常見問題參考:
1)在加載了驅動後,解不了鎖。
能夠先用USB鼠標解鎖。若是能夠用adb的話,也能夠直接用adb shell input keyevent 82解鎖
2)點擊屏幕沒反應
肯定i2c設備供電正常,肯定probe被執行了沒,若是被執行了,再肯定IO有沒有先進行初始化,有沒有重啓設備,再肯定I2C通不通,點擊屏幕可否進入中斷。
3)probe沒被執行。檢查i2c_board_info終端的type成員定義是否跟i2c_driver中的id_table同樣。
4)I2C不通。檢查供電正常否,有沒有重啓設備,i2c地址有沒有錯誤,有的i2c設備是用7位,有的是用8位,8位的則必須右移一位
5)最常發生的問題,TP的報點不對。
這個問題到目前爲止還沒總結出一個方法論。我的調試經驗覺得,這個跟LCD的分辨率,TP的分辨率,輸入子系統設置都有關係。
先討論一個對例子肯定屏幕的分辨率,假如分辨率爲800 * 1280,那麼應該是下圖的樣子:
圖表 1 LCD屏幕表示圖
假如TP的分辨率也是800 * 1280
圖表 2 TP分辨率表示圖
如上面兩幅圖所示,LCD和TP的分辨率是同樣的,而且原點同樣,假如這時輸入子系統參數設置爲:
input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X, 0, 800, 0, 0);
input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y, 0, 1280, 0, 0);
那麼此時上報的點應該是不用通過任何轉換的,也就是說上報的點是對的。
咱們再討論另一種狀況,假如TP的分辨率爲:
圖表 3 TP分辨率標示圖
值得一提的是,TP的x,y軸能夠互換,可是原點是不會變化的。如圖3的TP跟圖1的LCD,因爲LCD的原點跟TP的原點不同,那麼上報的點則必須通過驅動轉換。轉換的公式爲:
X=800 - y1;
Y=x1;
6)如何找LCD原點跟TP原點。
LCD原點應該是在系統沒作任何翻轉以前,在系統點亮的時候,小企鵝出現的地方
TP的原點,應該是在TP驅動裏x,y沒通過邏輯轉換以前,用printk打印出點信息。