生活随笔
收集整理的這篇文章主要介紹了
基于FT5x06嵌入式Linux电容触摸屏驱动
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
***************************************************************************************************************************
作者:EasyWave ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 時間:2013.02.06
類別:Linux?內核驅動源碼分析??????????????????????????????????????????????????????聲明:轉載,請保留鏈接
注意:如有錯誤,歡迎指正。這些是我學習的日志文章......
***************************************************************************************************************************
一:FT5X06電容觸摸IC簡介
?????FT5x06系列ICs是單芯片電容式觸摸屏控制器IC,帶有一個內置的8位微控制器單元(MCU)。采用互電容的方法,在配合的相互的電容式觸摸面板,它支持真正的多點觸摸功能。FT5x06具有用戶友好的輸入的功能,這可以應用在許多便攜式設備,例如蜂窩式電話,移動互聯網設備,上網本和筆記本個人電腦。FT5x06系列IC包括FT5206/FT5306/FT5406。具體的功能如下圖所示:
?
二:硬件接口設計
從FT5X06的datasheet中,我們可以看到,FT5X06既可以工作的SPI的接口方式,也可以工作在I2C的接口方式,不管工作在SPI,還是工作在I2C,從硬件的接口設計上來說,這下面的幾個控制口,都是需要要接的。如下圖所示:
1):INT引腳,這個腳是一個中端信號,它用來通知HOST端FT5X06已經準備好,可以進行讀操作了。
2):WAKE引腳:這個功能主要的作用是將FT5X06從睡眠狀態轉換到工作狀態。
3):/RST引腳:FT5X06的芯片復位信號。
如何來設計硬件接口呢,這個我們可以從FT5X06的datasheet看出來,首先我們來看下FT5X06的上電時序,如下圖所示:
FT5X06的上電時序
FT5X06的RESET時序
FT5X06的wakeup時序
各自的最小的時間限制如下所所示:
因此,從上面的圖片和表格中,我們可以看出,在poweron中,必須確保在上電后,wakeup的電平為高電平,至于INT信號,只要確保無INT信號時,這個INT為高即可,這個可以從poweron的時序可以看出,它是一個低電平的動作,這個是驅動中來做的事情了。
接下來就是確定I2C的從地址,如下圖所示:[以下引用自網絡]
從地址高位必須為:3,低位必須根據i2ccon設定的值來確定。
根據FT5406數據手冊上的指令,我們先了解下驅動如何實現電容屏的多點觸摸,其實很簡單,主要需要觸摸屏IC FT5406 能夠捕獲多點數據,這點電容屏基本多能支持到捕獲2點以上,而FT5406 可以捕獲5個觸摸點,編寫驅動時,只要去獲取這幾個點的數據,然后上報就可以了。如下圖所示:[以下引用自網絡]
02H :捕獲的觸摸點個數????????????? 03H- 1EH?:對應每個點的x,y坐標數值。
?
三:Linux驅動源碼
??????? I2C的驅動需要根據具體的ARM芯片,一般來說,IC原廠,一般會將在linux的bsp中都會有I2C的驅動,這個部分不需要我們去寫的,我們只需要將FT5X06和BSP包中的I2C驅動匹配起來就好了。而整個FT5X06也是這樣做的。在linu內核中關于i2c的一般會有這個函數:i2c_board_info()i2c_board_info用于構建信息表來列出存在的I2C設備。這一信息用于增長新型I2C驅動的驅動模型樹。對于主板,它使用i2c_register_board_info()來靜態創建。對于子板,利用已知的適配器使用i2c_new_device()動態創建。
[cpp]?view plaincopyprint?
struct?i2c_board_info?{??????char?type[I2C_NAME_SIZE];????????unsigned?short?flags;????????unsigned?short?addr;????????void?*platform_data;????????struct?dev_archdata?*archdata;????????int?irq;????};??static?struct?i2c_board_info?i2c_devs0[]?__initdata?=?{??#ifdef?CONFIG_TOUCHSCREEN_CDTLCD??{??I2C_BOARD_INFO("ft5x0x_ts",?0x3x),??.irq?=?IRQ_EINT1,??},??#endif???};??
最后在內核初始化的部分調用int i2c_register_board_info(int busnum, struct i2c_board_info const *info, unsigned len);函數即可。如下詳細的解釋:
@busnum: 指定這些設備屬于哪個總線
@info: I2C設備描述符向量
@len: 向量中描述符的數量;為了預留特定的總線號,可以是0。
i2c_register_board_info(0, i2c_devs0, ARRAY_SIZE(i2c_devs0));
下面貼出部分代碼:[下面的代碼是Android下的Linux驅動,如果要修改到通用的Linux內核中,需要修改代碼的]
[cpp]?view plaincopyprint?
static?int???ft5x0x_ts_probe(struct?i2c_client?*client,?const?struct?i2c_device_id?*id)??{??????struct?ft5x0x_ts_data?*ft5x0x_ts;??????struct?input_dev?*input_dev;??????int?err?=?0;??????unsigned?char?uc_reg_value;???#if?CFG_SUPPORT_TOUCH_KEY??????int?i;??#endif????????????printk("[FTS]?ft5x0x_ts_probe,?driver?version?is?%s.\n",?CFG_FTS_CTP_DRIVER_VERSION);????????????if?(!i2c_check_functionality(client->adapter,?I2C_FUNC_I2C))?{??????????err?=?-ENODEV;??????????goto?exit_check_functionality_failed;??????}????????ft5x0x_ts?=?kzalloc(sizeof(struct?ft5x0x_ts_data),?GFP_KERNEL);????????????if?(!ft5x0x_ts)?{??????????err?=?-ENOMEM;??????????goto?exit_alloc_data_failed;??????}??????????????this_client?=?client;??????i2c_set_clientdata(client,?ft5x0x_ts);????????mutex_init(&ft5x0x_ts->device_mode_mutex);??????INIT_WORK(&ft5x0x_ts->pen_event_work,?ft5x0x_ts_pen_irq_work);????????ft5x0x_ts->ts_workqueue?=?create_singlethread_workqueue(dev_name(&client->dev));??????if?(!ft5x0x_ts->ts_workqueue)?{??????????err?=?-ESRCH;??????????goto?exit_create_singlethread;??????}??????????err?=?request_irq(IRQ_EINT(6),?ft5x0x_ts_interrupt,?IRQF_TRIGGER_FALLING,?"ft5x0x_ts",?ft5x0x_ts);??????if?(err?<?0)?{??????????dev_err(&client->dev,?"ft5x0x_probe:?request?irq?failed\n");??????????goto?exit_irq_request_failed;??????}??????????disable_irq(IRQ_EINT(6));????????input_dev?=?input_allocate_device();??????if?(!input_dev)?{??????????err?=?-ENOMEM;??????????dev_err(&client->dev,?"failed?to?allocate?input?device\n");??????????goto?exit_input_dev_alloc_failed;??????}????????????ft5x0x_ts->input_dev?=?input_dev;????????set_bit(ABS_MT_TOUCH_MAJOR,?input_dev->absbit);??????set_bit(ABS_MT_POSITION_X,?input_dev->absbit);??????set_bit(ABS_MT_POSITION_Y,?input_dev->absbit);??????set_bit(ABS_MT_WIDTH_MAJOR,?input_dev->absbit);????????input_set_abs_params(input_dev,???????????????????ABS_MT_POSITION_X,?0,?SCREEN_MAX_X,?0,?0);??????input_set_abs_params(input_dev,???????????????????ABS_MT_POSITION_Y,?0,?SCREEN_MAX_Y,?0,?0);??????input_set_abs_params(input_dev,???????????????????ABS_MT_TOUCH_MAJOR,?0,?PRESS_MAX,?0,?0);??????input_set_abs_params(input_dev,???????????????????ABS_MT_WIDTH_MAJOR,?0,?200,?0,?0);??????input_set_abs_params(input_dev,???????????????????ABS_MT_TRACKING_ID,?0,?5,?0,?0);??????????set_bit(EV_KEY,?input_dev->evbit);??????set_bit(EV_ABS,?input_dev->evbit);????#if?CFG_SUPPORT_TOUCH_KEY????????????set_bit(EV_SYN,?input_dev->evbit);??????set_bit(BTN_TOUCH,?input_dev->keybit);??????input_dev->keycode?=?tsp_keycodes;??????for(i?=?0;?i?<?CFG_NUMOFKEYS;?i++)??????{??????????input_set_capability(input_dev,?EV_KEY,?((int*)input_dev->keycode)[i]);??????????tsp_keystatus[i]?=?KEY_RELEASE;??????}??#endif????????input_dev->name??????=?FT5X0X_NAME;????????????err?=?input_register_device(input_dev);??????if?(err)?{??????????dev_err(&client->dev,??????????"ft5x0x_ts_probe:?failed?to?register?input?device:?%s\n",??????????dev_name(&client->dev));??????????goto?exit_input_register_device_failed;??????}????#ifdef?CONFIG_HAS_EARLYSUSPEND??????printk("==register_early_suspend?=\n");??????ft5x0x_ts->early_suspend.level?=?EARLY_SUSPEND_LEVEL_BLANK_SCREEN?+?1;??????ft5x0x_ts->early_suspend.suspend?=?ft5x0x_ts_suspend;??????ft5x0x_ts->early_suspend.resume??=?ft5x0x_ts_resume;??????register_early_suspend(&ft5x0x_ts->early_suspend);??#endif????????msleep(150);????????????????????uc_reg_value?=?ft5x0x_read_fw_ver();??????printk("[FTS]?Firmware?version?=?0x%x\n",?uc_reg_value);??????ft5x0x_read_reg(FT5X0X_REG_PERIODACTIVE,?&uc_reg_value);??????printk("[FTS]?report?rate?is?%dHz.\n",?uc_reg_value?*?10);??????ft5x0x_read_reg(FT5X0X_REG_THGROUP,?&uc_reg_value);??????printk("[FTS]?touch?threshold?is?%d.\n",?uc_reg_value?*?4);????#if?CFG_SUPPORT_AUTO_UPG??????fts_ctpm_auto_upg();??#endif????????#if?CFG_SUPPORT_UPDATE_PROJECT_SETTING??????fts_ctpm_update_project_setting();??#endif????????enable_irq(IRQ_EINT(6));??????????err?=?sysfs_create_group(&client->dev.kobj,?&ft5x0x_attribute_group);?????if?(0?!=?err)????{??????dev_err(&client->dev,?"%s()?-?ERROR:?sysfs_create_group()?failed:?%d\n",?__FUNCTION__,?err);??????sysfs_remove_group(&client->dev.kobj,?&ft5x0x_attribute_group);????}?????else??????{??????????printk("ft5x0x:%s()?-?sysfs_create_group()?succeeded.\n",?__FUNCTION__);??????}????????printk("[FTS]?==probe?over?=\n");??????return?0;????exit_input_register_device_failed:??????input_free_device(input_dev);??exit_input_dev_alloc_failed:????????free_irq(IRQ_EINT(6),?ft5x0x_ts);??exit_irq_request_failed:????????cancel_work_sync(&ft5x0x_ts->pen_event_work);??????destroy_workqueue(ft5x0x_ts->ts_workqueue);??exit_create_singlethread:??????printk("==singlethread?error?=\n");??????i2c_set_clientdata(client,?NULL);??????kfree(ft5x0x_ts);??exit_alloc_data_failed:??exit_check_functionality_failed:??????return?err;??}??static?int?__devexit?ft5x0x_ts_remove(struct?i2c_client?*client)??{??????struct?ft5x0x_ts_data?*ft5x0x_ts;??????printk("==ft5x0x_ts_remove=\n");??????ft5x0x_ts?=?i2c_get_clientdata(client);??????unregister_early_suspend(&ft5x0x_ts->early_suspend);????????mutex_destroy(&ft5x0x_ts->device_mode_mutex);??????free_irq(IRQ_EINT(6),?ft5x0x_ts);??????input_unregister_device(ft5x0x_ts->input_dev);??????kfree(ft5x0x_ts);??????cancel_work_sync(&ft5x0x_ts->pen_event_work);??????destroy_workqueue(ft5x0x_ts->ts_workqueue);??????i2c_set_clientdata(client,?NULL);???????del_timer(&test_timer);??????return?0;??}????static?const?struct?i2c_device_id?ft5x0x_ts_id[]?=?{??????{?FT5X0X_NAME,?0x3x?},{?}??};??????MODULE_DEVICE_TABLE(i2c,?ft5x0x_ts_id);????static?struct?i2c_driver?ft5x0x_ts_driver?=?{??????.probe??????=?ft5x0x_ts_probe,??????.remove?????=?__devexit_p(ft5x0x_ts_remove),??????.id_table???=?ft5x0x_ts_id,??????.driver?=?{??????????.name???=?FT5X0X_NAME,??????????.owner??=?THIS_MODULE,??????},??};????static?int?__init?ft5x0x_ts_init(void)??{??????int?ret;??????printk("==ft5x0x_ts_init==\n");??????ret?=?i2c_add_driver(&ft5x0x_ts_driver);??????printk("ret=%d\n",ret);??????return?ret;??}????static?void?__exit?ft5x0x_ts_exit(void)??{??????printk("==ft5x0x_ts_exit==\n");??????i2c_del_driver(&ft5x0x_ts_driver);??}????module_init(ft5x0x_ts_init);??module_exit(ft5x0x_ts_exit);????MODULE_AUTHOR("<wenfs@Focaltech-systems.com>");??MODULE_DESCRIPTION("FocalTech?ft5x0x?TouchScreen?driver");??MODULE_LICENSE("GPL");??
移植到通用的Linux的內核中,就不寫出來了,自己去研究吧。
總結
以上是生活随笔為你收集整理的基于FT5x06嵌入式Linux电容触摸屏驱动的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。