android平台的s5pc110触摸屏驱动分析
来源:互联网 发布:土豆for mac下载 编辑:程序博客网 时间:2024/05/22 15:29
内核linux2.6.35 andorid2.3 触摸屏型号ft5xo6
首先给出该触摸屏的一些结构体---->drivers/input/touchscreen/ft5x06_ts.h
还有一些在ft5x06_ts.c中
触摸屏属于I2C子设备,按照I2C子系统来写驱动,首先添加I2C信息。---->arch/arm/mach-s5pv210/smdkc110.c
在arch/arm/mach-s5pv210/mach-smdkc110.c中的machine_init()函数中会调用i2c_register_board_info(1, i2c_devs1, ARRAY_SIZE(i2c_devs1));函数注册i2c子设备
之后,系统会创建一个i2c_devinfo结构体,然后将其挂如控制器设备链表中。代码如下:
当i2c控制器驱动加载时回去扫描这条链表,调用流程为匹配i2c控制器设备,调用probe函数,在probe函数中调用i2c_add_numbered_adapter或i2c_add_adapter。在添加adapter时调用i2c_register_adapter()-->
i2c_scan_static_board_info()--->i2c_new_device创建client,注册client设备(device_register)。
触摸屏设备驱动
drivers/input/touchscreen/ft5x06_ts.c
首先:
ft5x0x_ts_driver如下:
i2c_add_driver()分析
i2c_register_driver()分析:
probe函数分析
ft5x06_hw_init();分析
i2c读写函数
工作队列函数实现
读取事件数据函数实现ft5x0x_read_data
上报数据
中断函数实现
要完全贯通的理解整个原理,还需要input子系统,i2c子系统,工作队列机制,中断机制和上层应用的结合。
首先给出该触摸屏的一些结构体---->drivers/input/touchscreen/ft5x06_ts.h
点击(此处)折叠或打开
- #ifndef __LINUX_FT5X0X_TS_H__
- #define __LINUX_FT5X0X_TS_H__
- #define SCREEN_MIN_X 0
- #define SCREEN_MAX_X 320
- #define SCREEN_MIN_Y 0
- #define SCREEN_MAX_Y 240
- #define PRESS_MAX 255
- #define MIN_X_CTP 0
- #define MAX_X_CTP 896
- #define MIN_Y_CTP 0
- #define MAX_Y_CTP 640
- #define EVENT_PENDOWN 0
- #define EVENT_REPEAT 2
- #define EVENT_PENUP 1
- #define I2C_CTPM_ADDRESS 0x38
- #define FT5X0X_NAME "ft5x06-ts"//"synaptics_i2c_rmi"//"synaptics-rmi-ts"//
- struct ft5x0x_ts_platform_data{
- u16 intr; /* irq number */
- };
- #ifndef ABS_MT_TOUCH_MAJOR
- #define ABS_MT_TOUCH_MAJOR 0x30 /* touching ellipse*/
- #define ABS_MT_TOUCH_MINOR 0x31 /*(omit if circular)*/
- #define ABS_MT_WIDTH_MAJOR 0x32 /* approaching ellipse*/
- #define ABS_MT_WIDTH_MINOR 0x33 /*(omit if circular)*/
- #define ABS_MT_ORIENTATION 0x34 /* Ellipse orientation*/
- #define ABS_MT_POSITION_X 0x35 /* Center X ellipse position*/
- #define ABS_MT_POSITION_Y 0x36 /* Center Y ellipse position*/
- #define ABS_MT_TOOL_TYPE 0x37 /* Type of touching device*/
- #define ABS_MT_BLOB_ID 0x38 /* Groupset of pkts as blob */
- #define ABS_MT_TRACKING_ID 0x39 /* Unique ID of initiated contact*/
- #endif /* ABS_MT_TOUCH_MAJOR*/
- #endif
点击(此处)折叠或打开
- struct ts_event {
- u16 x1;
- u16 y1;
- u16 x2;
- u16 y2;
- u16 x3;
- u16 y3;
- u16 x4;
- u16 y4;
- u16 x5;
- u16 y5;
- u16 pressure;
- u8 touch_point;
- };
- struct ft5x0x_ts_data {
- struct input_dev *input_dev;
- struct ts_event event;
- struct work_struct pen_event_work;
- struct workqueue_struct *ts_workqueue;
- struct early_suspend early_suspend;
- };
点击(此处)折叠或打开
- static struct i2c_board_info i2c_devs1[] __initdata= {
- #ifdef CONFIG_VIDEO_TV20
- {
- I2C_BOARD_INFO("ft5x06-ts",(0x38)),//初始化i2c_board_info的type和addr成员(#define I2C_BOARD_INFO(dev_type, dev_addr) \.type = dev_type, .addr = (dev_addr))
- .irq = IRQ_EINT(2),//中断号
- },
- #endif
- };
之后,系统会创建一个i2c_devinfo结构体,然后将其挂如控制器设备链表中。代码如下:
点击(此处)折叠或打开
- int __init i2c_register_board_info(int busnum, struct i2c_board_info const *info, unsigned len)
- {
- int status;
- down_write(&__i2c_board_lock);
- /* dynamic bus numbers will be assigned after the last static one*/
- if (busnum>= __i2c_first_dynamic_bus_num)
- __i2c_first_dynamic_bus_num = busnum+ 1;
- for (status= 0; len; len--, info++) {//i2c_dev(x)数组有几个成员,就创建几个i2c_devinfo结构体
- struct i2c_devinfo *devinfo;
- devinfo = kzalloc(sizeof(*devinfo), GFP_KERNEL);
- if (!devinfo) {
- pr_debug("i2c-core: can't register boardinfo!\n");
- status = -ENOMEM;
- break;
- }
- devinfo->busnum= busnum;//挂接在那个i2c控制器上
- devinfo->board_info= *info;//type 和addr
- list_add_tail(&devinfo->list, &__i2c_board_list);//将devinfo添加到控制器的设备链表
- }
- up_write(&__i2c_board_lock);
- return status
i2c_scan_static_board_info()--->i2c_new_device创建client,注册client设备(device_register)。
触摸屏设备驱动
drivers/input/touchscreen/ft5x06_ts.c
首先:
点击(此处)折叠或打开
- static int __init ft5x0x_ts_init(void)
- {
- return i2c_add_driver(&ft5x0x_ts_driver);//设备驱动结构体
- }
- static void __exit ft5x0x_ts_exit(void)
- {
- i2c_del_driver(&ft5x0x_ts_driver);
- }
点击(此处)折叠或打开
- static const struct i2c_device_id ft5x0x_ts_id[]= {
- { FT5X0X_NAME, 0},{}
- };
- MODULE_DEVICE_TABLE(i2c, ft5x0x_ts_id);
- static struct i2c_driver ft5x0x_ts_driver ={
- .driver ={
- .name = FT5X0X_NAME,
- },
- .probe = ft5x0x_ts_probe,
- .remove = ft5x0x_ts_remove,
- .id_table = ft5x0x_ts_id,//id_table如上
-
- };
点击(此处)折叠或打开
- static inline int i2c_add_driver(struct i2c_driver*driver)
- {
- return i2c_register_driver(THIS_MODULE, driver);
- }
点击(此处)折叠或打开
- int i2c_register_driver(struct module*owner, struct i2c_driver*driver)
- {
- int res;
- /* Can't registeruntil after driver model init */
- if (unlikely(WARN_ON(!i2c_bus_type.p)))//调试用
- return -EAGAIN;
- /* add the driverto the list of i2c drivers in the driver core */
- driver->driver.owner= owner;
- driver->driver.bus= &i2c_bus_type;
- /* When registration returns, the driver core
- * will have called probe()for all matching-but-unbound devices.
- */
- res = driver_register(&driver->driver);//注册,匹配成功会调用触摸屏的probe函数
- if (res)
- return res;
- pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name);
- INIT_LIST_HEAD(&driver->clients);
- /* Walk the adapters that are already present*/
- mutex_lock(&core_lock);
- bus_for_each_dev(&i2c_bus_type,NULL, driver, __process_new_driver);
- mutex_unlock(&core_lock);
- return 0;
- }
点击(此处)折叠或打开
- static int ft5x0x_ts_probe(struct i2c_client*client, const struct i2c_device_id *id)
- {
- struct ft5x0x_ts_data *ft5x0x_ts;//在ft5x06_ts.h中定义
- struct input_dev *input_dev;
- int err= 0;
- unsigned char uc_reg_value;
-
- printk("==ft5x0x_ts_probe=\n");
-
- if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)){//验证i2c控制器的能力,实现了那些函数,这里验证是否实现了I2C_FUNC_I2C函数
- err =-ENODEV;
- goto exit_check_functionality_failed;
- }
- printk("==kzalloc=\n");
- ft5x0x_ts = kzalloc(sizeof(*ft5x0x_ts), GFP_KERNEL);//分配空间
- if (!ft5x0x_ts) {
- err =-ENOMEM;
- goto exit_alloc_data_failed;
- }
- this_client = client;
- i2c_set_clientdata(client, ft5x0x_ts);//设置屏相关的数据client->dev->p->driver_data = data;
- 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(client->irq, ft5x0x_ts_interrupt, IRQF_TRIGGER_FALLING, "ft5x06_ts", ft5x0x_ts);//申请中断
- if (err< 0) {
- dev_err(&client->dev,"ft5x0x_probe: request irq failed\n");
- goto exit_irq_request_failed;
- }
- disable_irq(this_client->irq);//关闭中断
- input_dev = input_allocate_device();//分配input_dev结构体
- 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;
- #ifdef CONFIG_FT5X0X_MULTITOUCH//多点触摸
- set_bit(EV_ABS, input_dev->evbit);//那类事件
- set_bit(ABS_MT_TOUCH_MAJOR, input_dev->absbit);//设置adsbit代表那些事件
- 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-1, 0, 0);
- input_set_abs_params(input_dev,
- ABS_MT_POSITION_Y, 0, SCREEN_MAX_Y-1, 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);
- #else
- set_bit(ABS_X, input_dev->absbit);
- set_bit(ABS_Y, input_dev->absbit);
- set_bit(ABS_PRESSURE, input_dev->absbit);
- set_bit(BTN_TOUCH, input_dev->keybit);
- input_set_abs_params(input_dev, ABS_X, 0, SCREEN_MAX_X, 0, 0);
- input_set_abs_params(input_dev, ABS_Y, 0, SCREEN_MAX_Y, 0, 0);
- input_set_abs_params(input_dev,
- ABS_PRESSURE, 0, PRESS_MAX, 0, 0);
- #endif
- set_bit(EV_SYN, input_dev->evbit);
- set_bit(BTN_TOUCH, input_dev->keybit);
- set_bit(EV_KEY, input_dev->evbit);
- input_dev->name = FT5X0X_NAME; //dev_name(&client->dev)//以上是设置input_dev
- err = input_register_device(input_dev);//注册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;
- }
- ft5x06_hw_init();//硬件相关初始化
- msleep(50);
- uc_reg_value = ft5x0x_read_fw_ver();//读取硬件版本
- printk("[FST] Firmware version = 0x%x\n", uc_reg_value);
- enable_irq(this_client->irq);//使能中断
- printk("==probe over =\n");
- return 0;
- exit_input_register_device_failed://以下是错误处理
- input_free_device(input_dev);
- exit_input_dev_alloc_failed:
- free_irq(client->irq, 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 void ft5x06_hw_init(void)
- {
- if ((gpio_request(S5PV210_GPG3(2),"ft5406 wake-up"))< 0)
- {
- printk("gpio_request failed for GPIOWake[%d]\n\n",S5PV210_GPG3(2));
- }
- else if((gpio_direction_output(S5PV210_GPG3(2),1))< 0)//将触摸屏从睡眠模式唤醒
- {
- printk("gpio_direction_output failed for GPIOWake[%d]\n\n",S5PV210_GPG3(2));
- gpio_free(S5PV210_GPG3(2));
- }
-
- msleep(5);
- gpio_free(S5PV210_GPG3(2));
- }
点击(此处)折叠或打开
- static int ft5x0x_i2c_rxdata(char*rxdata, int length)
- {
- int ret;
- struct i2c_msg msgs[]= {
- {
- .addr = this_client->addr,
- .flags = 0,//写
- .len = 1,//数据长度,单位字节
- .buf = rxdata,是//护具
- },
- {
- .addr = this_client->addr,
- .flags = I2C_M_RD,//读
- .len = length,//读的字节数
- .buf = rxdata,//存放数据的位置
- },
- };
- ret = i2c_transfer(this_client->adapter, msgs, 2);
- if (ret< 0)
- pr_err("msg %s i2c read error: %d\n", __func__, ret);
-
- return ret;
- }
- static int ft5x0x_i2c_txdata(char*txdata, int length)
- {
- int ret;
- struct i2c_msg msg[]= {
- {
- .addr = this_client->addr,
- .flags = 0,//写
- .len = length,//写的字节数
- .buf = txdata,//要写的数据
- },
- };
- ret = i2c_transfer(this_client->adapter, msg, 1);
- if (ret< 0)
- pr_err("%s i2c write error: %d\n", __func__, ret);
- return ret;
- }
点击(此处)折叠或打开
- static void ft5x0x_ts_pen_irq_work(struct work_struct*work)
- {
- int ret =-1;
- ret = ft5x0x_read_data();
- if (ret== 0){
- ft5x0x_report_value();
- }
- enable_irq(this_client->irq);
- }
点击(此处)折叠或打开
- static int ft5x0x_read_data(void)
- {
- struct ft5x0x_ts_data *data = i2c_get_clientdata(this_client);
- struct ts_event *event = &data->event;
- u8 buf[26]= {0};
- unsigned long x_tmp[5]={0},y_tmp[5]={0};
-
- int ret =-1;
- buf[0]=0xf9;
- ret = ft5x0x_i2c_rxdata(buf, 26);
- if (ret< 0) {
- printk("%s read_data i2c_rxdata failed: %d\n", __func__, ret);
- return ret;
- }
- memset(event, 0, sizeof(struct ts_event));
- event->touch_point= buf[3]& 0x07;// 000 0111
- if (event->touch_point== 0){
- ft5x0x_ts_release();
- return 1;
- }
- switch (event->touch_point){
- case 5:
- x_tmp[4]= (((buf[21]& 0x0f) << 8 | buf[22]))*SCREEN_MAX_X;
- do_div(x_tmp[4],MAX_X_CTP);
- event->x5=(s16)x_tmp[4];
- y_tmp[4]= (((buf[23]& 0x0f) << 8 | buf[24]))*SCREEN_MAX_Y;
- do_div(y_tmp[4],MAX_Y_CTP);
- event->y5=(s16)y_tmp[4];
-
- case 4:
- x_tmp[3]= (((buf[17]& 0x0f) << 8 | buf[18]))*SCREEN_MAX_X;
- do_div(x_tmp[3],MAX_X_CTP);
- event->x4= (s16)x_tmp[3];
- y_tmp[3]= (((buf[19]& 0x0f) << 8 | buf[20]))*SCREEN_MAX_Y;
- do_div(y_tmp[3],MAX_Y_CTP);
- event->y4=(s16)y_tmp[3];
- case 3:
- x_tmp[2]= (((buf[13]& 0x0f) << 8 | buf[14]))*SCREEN_MAX_X;
- do_div(x_tmp[2],MAX_X_CTP);
- event->x3= (s16)x_tmp[2];
- y_tmp[2]= (((buf[15]& 0x0f) << 8 | buf[16]))*SCREEN_MAX_Y;
- do_div(y_tmp[2],MAX_Y_CTP);
- event->y3=(s16)y_tmp[2];
- case 2:
- x_tmp[1]= (((buf[9]& 0x0f) << 8 | buf[10]))*SCREEN_MAX_X;
- do_div(x_tmp[1],MAX_X_CTP);
- event->x2= (s16)x_tmp[1];
- y_tmp[1]= (((buf[11]& 0x0f) << 8 | buf[12]))*SCREEN_MAX_Y;
- do_div(y_tmp[1],MAX_Y_CTP);
- event->y2=(s16)y_tmp[1];
-
- case 1:
- x_tmp[0]= (((buf[5]& 0x0f) << 8 | buf[6]))*SCREEN_MAX_X;
- do_div(x_tmp[0],MAX_X_CTP);
- event->x1= (s16)x_tmp[0];
- y_tmp[0]= (((buf[7]& 0x0f) << 8 | buf[8]))*SCREEN_MAX_Y;
- do_div(y_tmp[0],MAX_Y_CTP);
- event->y1=(s16)y_tmp[0];
- break;
- default:
- return -1;
- }
- event->pressure= 200;
- dev_dbg(&this_client->dev,"%s: 1:%d %d 2:%d %d \n", __func__,
- event->x1, event->y1, event->x2, event->y2);
- return 0;
- }
点击(此处)折叠或打开
- static void ft5x0x_report_value(void)
- {
- struct ft5x0x_ts_data *data = i2c_get_clientdata(this_client);
- struct ts_event *event = &data->event;
- switch(event->touch_point){
- case 5:
- input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR, event->pressure);
- input_report_abs(data->input_dev, ABS_MT_POSITION_X, event->x5);
- input_report_abs(data->input_dev, ABS_MT_POSITION_Y, event->y5);
- input_report_abs(data->input_dev, ABS_MT_WIDTH_MAJOR, 1);
- input_report_key(data->input_dev, BTN_TOUCH, 1);
- input_mt_sync(data->input_dev);
- printk("===x2 = %d,y2 = %d ====\n",event->x2,event->y2);
- case 4:
- input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR, event->pressure);
- input_report_abs(data->input_dev, ABS_MT_POSITION_X, event->x4);
- input_report_abs(data->input_dev, ABS_MT_POSITION_Y, event->y4);
- input_report_abs(data->input_dev, ABS_MT_WIDTH_MAJOR, 1);
- input_report_key(data->input_dev, BTN_TOUCH, 1);
- input_mt_sync(data->input_dev);
- printk("===x2 = %d,y2 = %d ====\n",event->x2,event->y2);
- case 3:
- input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR, event->pressure);
- input_report_abs(data->input_dev, ABS_MT_POSITION_X, event->x3);
- input_report_abs(data->input_dev, ABS_MT_POSITION_Y, event->y3);
- input_report_abs(data->input_dev, ABS_MT_WIDTH_MAJOR, 1);
- input_report_key(data->input_dev, BTN_TOUCH, 1);
- input_mt_sync(data->input_dev);
- printk("===x2 = %d,y2 = %d ====\n",event->x2,event->y2);
- case 2:
- input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR, event->pressure);
- input_report_abs(data->input_dev, ABS_MT_POSITION_X, event->x2);
- input_report_abs(data->input_dev, ABS_MT_POSITION_Y, event->y2);
- input_report_abs(data->input_dev, ABS_MT_WIDTH_MAJOR, 1);
- input_report_key(data->input_dev, BTN_TOUCH, 1);
- input_mt_sync(data->input_dev);
- printk("===x2 = %d,y2 = %d ====\n",event->x2,event->y2);
- case 1:
- input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR, event->pressure);
- input_report_abs(data->input_dev, ABS_MT_POSITION_X, event->x1);
- input_report_abs(data->input_dev, ABS_MT_POSITION_Y, event->y1);
- input_report_abs(data->input_dev, ABS_MT_WIDTH_MAJOR, 1);
- input_report_key(data->input_dev, BTN_TOUCH, 1);
- input_mt_sync(data->input_dev);
- printk("===x1 = %d,y1 = %d ====\n",event->x1,event->y1);
- break;
- default:
- printk("==touch_point default =\n");
- break;
- }
- input_sync(data->input_dev);
- dev_dbg(&this_client->dev,"%s: 1:%d %d 2:%d %d \n", __func__,
- event->x1, event->y1, event->x2, event->y2);
- } /*end ft5x0x_report_value*/
中断函数实现
点击(此处)折叠或打开
- static irqreturn_t ft5x0x_ts_interrupt(int irq, void*dev_id)
- {
- struct ft5x0x_ts_data *ft5x0x_ts = dev_id;
- disable_irq_nosync(this_client->irq);
-
- if (!work_pending(&ft5x0x_ts->pen_event_work)){
- queue_work(ft5x0x_ts->ts_workqueue,&ft5x0x_ts->pen_event_work);
- }
-
- return IRQ_HANDLED;
- }
- android平台的s5pc110触摸屏驱动分析
- Android 平台电容式触摸屏的驱动基本原理
- MTK平台tp触摸屏驱动分析
- GPIO驱动分析 & GPIO使用方法 -- S5PC110、S5PC210
- GPIO驱动分析 & GPIO使用方法 -- S5PC110
- GPIO驱动分析 & GPIO使用方法 -- S5PC110
- GPIO驱动分析 & GPIO使用方法 -- S5PC110、S5PC210
- rk3188--6.android 触摸屏驱动分析
- 基于linux的mini2440触摸屏驱动分析
- linux 触摸屏驱动分析
- 触摸屏驱动分析
- linux 触摸屏驱动分析
- Mini2440 触摸屏驱动分析
- Linux 触摸屏驱动分析
- Mini2440 触摸屏驱动分析
- linux触摸屏驱动分析
- X210触摸屏驱动分析
- 触摸屏驱动分析
- 新版淘宝的代码
- Android关机和重启的调用代码
- 最长公共子序列(连续)
- Flex4.6类似迅雷的果冻弹窗效果的类
- HDU 4455 Substrings
- android平台的s5pc110触摸屏驱动分析
- windows xp 中无损转换磁盘格式
- Splay的几种操作(代码)
- asp.net Mvc验证码
- 60个开发者不容错过的免费资源库
- bp和bpx的区别
- 史上最全的CSS hack方式一览
- poj1193
- window.close()不提示