十五、电容触摸屏驱动

 

在读者学习本章以及后续章节之前,最好拥有ADC和触摸屏裸机基础,可以参考:ADC和触摸屏编程。

 

和按键驱动类似,触摸屏也是通过电平来体现按下或松开。因此如果想要写出通用的触摸屏驱动,需要使用输入子系统完成。

考虑到我是用的并不是之前的TINY4412,在此给出下文所分析的文件:

https://files.cnblogs.com/files/Lioker/15_ts.zip

 

 

一、电容触摸屏检测原理

此段来源于百度百科,读者可查看:电容式触摸屏。

电容式触摸屏技术是利用人体的电流感应进行工作的。

电容式触摸屏是一块四层复合玻璃屏,玻璃屏的内表面和夹层各涂有一层ITO(导电玻璃),最外层是一薄层矽土玻璃保护层,夹层ITO涂层作为工作面,四个角上引出四个电极,内层ITO为屏蔽层以保证良好的工作环境。

当用户触摸电容屏时,由于人体电场,用户手指和工作面形成一个耦合电容,因为工作面上接有高频信号,于是手指吸收走一个很小的电流,这个电流分别从屏的四个角上的电极中流出,且理论上流经四个电极的电流与手指头到四角的距离成比例,控制器通过对四个电流比例的精密计算得出位置。可以达到99%的精确度,具备小于3ms的响应速度。

十五、电容触摸屏驱动_第1张图片

 

 

二、电容触摸屏控制芯片驱动分析

我使用的开发板iTOP4412的触摸屏IC为ft5406,对应的驱动文件是drivers/input/touchscreen/ft5x06_ts.c。下面来分析此文件。

首先从init()函数分析:

 1 static int __init ft5x0x_ts_init(void)
 2 {
 3     int ret;
 4     int type;
 5 
 6     type = get_lcd_type();
 7 
 8     /* 设置GPIO引脚 */
 9     ret = gpio_request(EXYNOS4_GPL0(2), "TP1_EN");
10 ...
11     gpio_direction_output(EXYNOS4_GPL0(2), 1);
12 
13     s3c_gpio_cfgpin(EXYNOS4_GPL0(2), S3C_GPIO_OUTPUT);
14     gpio_free(EXYNOS4_GPL0(2));
15 
16     mdelay(5);
17 
18     printk("==%s: reset==\n", __FUNCTION__);
19     ret = gpio_request(EXYNOS4_GPX0(3), "GPX0_3");
20 ...
21     gpio_direction_output(EXYNOS4_GPX0(3), 0);
22     mdelay(200);
23     /* 给触摸芯片复位 */
24     gpio_direction_output(EXYNOS4_GPX0(3), 1);
25 
26     s3c_gpio_cfgpin(EXYNOS4_GPX0(3), S3C_GPIO_OUTPUT);
27     gpio_free(EXYNOS4_GPX0(3));
28     msleep(300);
29 ...
30     /* 注册I2C驱动 */
31     return i2c_add_driver(&ft5x0x_ts_driver);
32 }

 

此触摸屏使用的是i2c驱动,我们来看看此驱动结构体定义了什么。

1 static struct i2c_driver ft5x0x_ts_driver = {
2     .probe        = ft5x0x_ts_probe,
3     .remove        = __devexit_p(ft5x0x_ts_remove),
4     .id_table    = ft5x0x_ts_id,
5     .driver    = {
6         .name    = FT5X0X_NAME,    // #define FT5X0X_NAME "ft5x0x_ts"
7         .owner    = THIS_MODULE,
8     },
9 };

 

接下来,我们来查看probe()函数:

  1 static int ft5x0x_ts_probe(struct i2c_client *client, const struct i2c_device_id *id)
  2 {
  3     struct ft5x0x_i2c_platform_data *pdata;
  4     struct ft5x0x_ts_data *ts;
  5     struct input_dev *input_dev;
  6     unsigned char val;
  7     int err = -EINVAL;
  8     /* 判断是否为i2c设备 */
  9     if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
 10 ...
 11     }
 12     /* 分配空间,此结构体用于存储坐标, 压力值, 事件 */
 13     ts = kzalloc(sizeof(*ts), GFP_KERNEL);
 14 ...
 15     /* 获取dev的平台数据 */
 16     pdata = client->dev.platform_data;
 17 
 18     ts->screen_max_x = pdata->screen_max_x;
 19     ts->screen_max_y = pdata->screen_max_y;
 20     ts->pressure_max = pdata->pressure_max;
 21     /* 设置引脚为中断模式 */
 22     ts->gpio_irq = pdata->gpio_irq;
 23     if (ts->gpio_irq != -EINVAL) {
 24         client->irq = gpio_to_irq(ts->gpio_irq);
 25     } else {
 26         goto exit_no_pdata;
 27     }
 28     if (pdata->irq_cfg) {
 29         s3c_gpio_cfgpin(ts->gpio_irq, pdata->irq_cfg);
 30         s3c_gpio_setpull(ts->gpio_irq, S3C_GPIO_PULL_NONE);
 31     }
 32 
 33     ts->gpio_wakeup = pdata->gpio_wakeup;
 34     ts->gpio_reset = pdata->gpio_reset;
 35     /* 创建工作队列 */
 36     INIT_WORK(&ts->work, ft5x0x_ts_pen_irq_work);
 37     this_client = client;
 38     i2c_set_clientdata(client, ts);
 39 
 40     ts->queue = create_singlethread_workqueue(dev_name(&client->dev));
 41 ...
 42     /* 分配设置注册输入子系统 */
 43     input_dev = input_allocate_device();
 44     ts->input_dev = input_dev;
 45 
 46     set_bit(EV_SYN, input_dev->evbit);    /* 同步事件 */
 47     set_bit(EV_ABS, input_dev->evbit);    /* 绝对位移事件,存储坐标 */
 48     set_bit(EV_KEY, input_dev->evbit);    /* 按键事件 */
 49 
 50 #ifdef CONFIG_FT5X0X_MULTITOUCH
 51     set_bit(ABS_MT_TRACKING_ID, input_dev->absbit);
 52     set_bit(ABS_MT_TOUCH_MAJOR, input_dev->absbit);
 53     set_bit(ABS_MT_WIDTH_MAJOR, input_dev->absbit);
 54     set_bit(ABS_MT_POSITION_X, input_dev->absbit);
 55     set_bit(ABS_MT_POSITION_Y, input_dev->absbit);
 56 
 57     input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0, ts->screen_max_x, 0, 0);
 58     input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0, ts->screen_max_y, 0, 0);
 59     input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, ts->pressure_max, 0, 0);
 60     input_set_abs_params(input_dev, ABS_MT_WIDTH_MAJOR, 0, 200, 0, 0);
 61     input_set_abs_params(input_dev, ABS_MT_TRACKING_ID, 0, FT5X0X_PT_MAX, 0, 0);
 62 #else
 63     set_bit(ABS_X, input_dev->absbit);    /* 绝对位移事件中的x坐标 */
 64     set_bit(ABS_Y, input_dev->absbit);    /* 绝对位移事件中的y坐标 */
 65     set_bit(ABS_PRESSURE, input_dev->absbit);    /* 绝对位移事件中的压力值 */
 66     set_bit(BTN_TOUCH, input_dev->keybit);        /* 按键事件中的触摸屏事件 */
 67     /* 设置x, y, 压力值的范围和初始值 */
 68     input_set_abs_params(input_dev, ABS_X, 0, ts->screen_max_x, 0, 0);
 69     input_set_abs_params(input_dev, ABS_Y, 0, ts->screen_max_y, 0, 0);
 70     input_set_abs_params(input_dev, ABS_PRESSURE, 0, ts->pressure_max, 0 , 0);
 71 #endif
 72 
 73     input_dev->name = FT5X0X_NAME;
 74     input_dev->id.bustype = BUS_I2C;
 75     input_dev->id.vendor = 0x12FA;
 76     input_dev->id.product = 0x2143;
 77     input_dev->id.version = 0x0100;
 78 
 79     err = input_register_device(input_dev);
 80 ...
 81     /* 读取芯片硬件信息 */
 82     msleep(3);
 83     err = ft5x0x_read_fw_ver(&val);
 84 
 85     err = request_irq(client->irq, ft5x0x_ts_interrupt, IRQ_TYPE_EDGE_FALLING, "ft5x0x_ts", ts);
 86     disable_irq(client->irq);
 87     dev_info(&client->dev, "Firmware version 0x%02x\n", val);
 88     /* 支持休眠功能 */
 89 #ifdef CONFIG_HAS_EARLYSUSPEND
 90     ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN;//EARLY_SUSPEND_LEVEL_DISABLE_FB + 1;
 91     ts->early_suspend.suspend = ft5x0x_ts_suspend;
 92     ts->early_suspend.resume = ft5x0x_ts_resume;
 93     register_early_suspend(&ts->early_suspend);
 94 #endif
 95 
 96     enable_irq(client->irq);
 97 
 98     dev_info(&client->dev, "FocalTech ft5x0x TouchScreen initialized\n");
 99 
100     return err;
101 }
View Code

probe()函数所做的事情主要有:

1. 判断是否为i2c设备

2. 分配并设置struct ft5x0x_ts_data,此结构体中存储有最大y坐标,最大压力值,工作队列等。

 1 struct ft5x0x_ts_data {
 2     struct input_dev *input_dev;
 3     struct ft5x0x_event event;
 4 
 5     uint32_t gpio_irq;
 6     uint32_t gpio_wakeup;
 7     uint32_t gpio_reset;
 8 
 9     int screen_max_x;
10     int screen_max_y;
11     int pressure_max;
12 
13     struct work_struct work;
14     struct workqueue_struct *queue;
15 
16 #ifdef CONFIG_HAS_EARLYSUSPEND
17     struct early_suspend early_suspend;
18 #endif
19 };
View Code

3. 设置中断

4. 初始化工作队列(工作队列可以休眠)

5. 分配、设置并注册input_device

 

当有触摸屏事件发生时,会跳转到probe()函数中注册的中断处理函数ft5x0x_ts_interrupt()中执行,由于在probe()函数中设置了工作队列,因此中断函数会跳转至工作队列函数ft5x0x_ts_pen_irq_work():

 1 static irqreturn_t ft5x0x_ts_interrupt(int irq, void *dev_id) {
 2     struct ft5x0x_ts_data *ts = dev_id;
 3 
 4     disable_irq_nosync(this_client->irq);
 5 
 6     if (!work_pending(&ts->work)) {
 7         queue_work(ts->queue, &ts->work);
 8     }
 9 
10     return IRQ_HANDLED;
11 }

由于i2c读取函数底层可能拥有休眠操作,但是中断中并不允许休眠,因此需要设置工作队列。

 

在工作队列函数中,首先完成读取x,y和压力值等参数的工作,之后完成参数的上报工作。

  1 static int ft5x0x_read_data(struct ft5x0x_ts_data *ts) {
  2     struct ft5x0x_event *event = &ts->event;
  3     u8 buf[64] = { 0 };
  4     int ret;
  5 ...
  6     ret = ft5x0x_i2c_rxdata(buf, 7);
  7 ...
  8     memset(event, 0, sizeof(struct ft5x0x_event));
  9     event->touch_point = buf[2] & 0x0F;
 10 
 11     if (!event->touch_point) {
 12         ft5x0x_ts_release(ts);
 13         return 1;
 14     }
 15     /* 判断有几个点按下,也就是支持多指触控 */
 16 #ifdef CONFIG_FT5X0X_MULTITOUCH
 17     switch (event->touch_point) {
 18         case 10:
 19             event->x[9] = (s16)(buf[57] & 0x0F)<<8 | (s16)buf[58];
 20             event->y[9] = (s16)(buf[59] & 0x0F)<<8 | (s16)buf[60];
 21         case 9:
 22             event->x[8] = (s16)(buf[51] & 0x0F)<<8 | (s16)buf[52];
 23             event->y[8] = (s16)(buf[53] & 0x0F)<<8 | (s16)buf[54];
 24         case 8:
 25             event->x[7] = (s16)(buf[45] & 0x0F)<<8 | (s16)buf[46];
 26             event->y[7] = (s16)(buf[47] & 0x0F)<<8 | (s16)buf[48];
 27         case 7:
 28             event->x[6] = (s16)(buf[39] & 0x0F)<<8 | (s16)buf[40];
 29             event->y[6] = (s16)(buf[41] & 0x0F)<<8 | (s16)buf[42];
 30         case 6:
 31             event->x[5] = (s16)(buf[33] & 0x0F)<<8 | (s16)buf[34];
 32             event->y[5] = (s16)(buf[35] & 0x0F)<<8 | (s16)buf[36];
 33         case 5:
 34             event->x[4] = (s16)(buf[0x1b] & 0x0F)<<8 | (s16)buf[0x1c];
 35             event->y[4] = (s16)(buf[0x1d] & 0x0F)<<8 | (s16)buf[0x1e];
 36         case 4:
 37             event->x[3] = (s16)(buf[0x15] & 0x0F)<<8 | (s16)buf[0x16];
 38             event->y[3] = (s16)(buf[0x17] & 0x0F)<<8 | (s16)buf[0x18];
 39             //printk("x:%d, y:%d\n", event->x[3], event->y[3]);
 40         case 3:
 41             event->x[2] = (s16)(buf[0x0f] & 0x0F)<<8 | (s16)buf[0x10];
 42             event->y[2] = (s16)(buf[0x11] & 0x0F)<<8 | (s16)buf[0x12];
 43             //printk("x:%d, y:%d\n", event->x[2], event->y[2]);
 44         case 2:
 45             event->x[1] = (s16)(buf[0x09] & 0x0F)<<8 | (s16)buf[0x0a];
 46             event->y[1] = (s16)(buf[0x0b] & 0x0F)<<8 | (s16)buf[0x0c];
 47             //printk("x:%d, y:%d\n", event->x[1], event->y[1]);
 48         case 1:
 49             event->x[0] = (s16)(buf[0x03] & 0x0F)<<8 | (s16)buf[0x04];
 50             event->y[0] = (s16)(buf[0x05] & 0x0F)<<8 | (s16)buf[0x06];
 51             //printk("x:%d, y:%d\n", event->x[0], event->y[0]);
 52             break;
 53         default:
 54             printk("%s: invalid touch data, %d\n", __func__, event->touch_point);
 55             return -1;
 56     }
 57 #else
 58     if (event->touch_point == 1) {
 59         event->x[0] = (s16)(buf[0x03] & 0x0F)<<8 | (s16)buf[0x04];
 60         event->y[0] = (s16)(buf[0x05] & 0x0F)<<8 | (s16)buf[0x06];
 61     }
 62 #endif
 63 
 64     event->pressure = 200;
 65 
 66     return 0;
 67 }
 68 
 69 static void ft5x0x_ts_report(struct ft5x0x_ts_data *ts) {
 70     struct ft5x0x_event *event = &ts->event;
 71     int x, y;
 72     int i = 0;
 73     /* 上报事件 */
 74     if (event->touch_point == 1) {
 75         if (swap_xy) {
 76             x = event->y[i];
 77             y = event->x[i];
 78         } else {
 79             x = event->x[i];
 80             y = event->y[i];
 81         }
 82 
 83         if (scal_xy) {
 84             x = (x * ts->screen_max_x) / TOUCH_MAX_X;
 85             y = (y * ts->screen_max_y) / TOUCH_MAX_Y;
 86         }
 87 
 88         input_report_abs(ts->input_dev, ABS_X, x);
 89         input_report_abs(ts->input_dev, ABS_Y, y);
 90         input_report_abs(ts->input_dev, ABS_PRESSURE, event->pressure);
 91     }
 92 
 93     input_report_key(ts->input_dev, BTN_TOUCH, 1);
 94 
 95     input_sync(ts->input_dev);
 96 }
 97 
 98 static void ft5x0x_ts_pen_irq_work(struct work_struct *work) {
 99     struct ft5x0x_ts_data *ts = container_of(work, struct ft5x0x_ts_data, work);
100 
101     if (!ft5x0x_read_data(ts)) {
102         ft5x0x_ts_report(ts);
103     }
104 
105     enable_irq(this_client->irq);
106 }

 

下面我们来总结一下整体过程:

1. 设置GPIO引脚

2. 注册i2c设备驱动

3. 分配、设置和注册struct input_dev

4. 设置、注册触摸屏中断,注册触摸屏中断函数底半部函数

5. 中断函数中调用工作队列

6. 工作队列中读取数据后上报数据

 

 

下一章我们根据分析的文件来自己实现触摸屏驱动。

三、自己实现触摸屏驱动

触摸屏驱动源代码:

  1 #include 
  2 #include 
  3 #include 
  4 #include 
  5 #include 
  6 #include 
  7 #include 
  8 #include 
  9 #include 
 10 #include 
 11 #include 
 12 #include 
 13 #include 
 14 #include 
 15 
 16 #include 
 17 #include 
 18 
 19 #include 
 20 #include 
 21 
 22 #include 
 23 
 24 static struct work_struct wq;
 25 
 26 struct ft5x0x_event {
 27     int touch_point;
 28     u16 x[2];
 29     u16 y[2];
 30     u16 pressure;
 31 };
 32 
 33 int TOUCH_MAX_X = 1024;
 34 int TOUCH_MAX_Y = 768;
 35 
 36 static struct input_dev *ftinput;
 37 
 38 static struct i2c_client *ft5x0x_client;
 39 
 40 static int swap_xy;
 41 static int touch_size;
 42 
 43 static void ft5x0x_release(void)
 44 {
 45     input_report_abs(ftinput, ABS_PRESSURE, 0);
 46     input_report_key(ftinput, BTN_TOUCH, 0);
 47     input_sync(ftinput);
 48 }
 49 
 50 static void ft5x0x_report(struct ft5x0x_event *event)
 51 {
 52     int x, y;
 53     int i = 0;
 54 
 55     if (swap_xy) {
 56         x = event->y[i];
 57         y = event->x[i];
 58     }
 59     else {
 60         x = event->x[i];
 61         y = event->y[i];
 62     }
 63 
 64     input_report_abs(ftinput, ABS_X, x);
 65     input_report_abs(ftinput, ABS_Y, y);
 66     input_report_abs(ftinput, ABS_PRESSURE, event->pressure);
 67 
 68     input_report_key(ftinput, BTN_TOUCH, 1);
 69 
 70     input_sync(ftinput);
 71 }
 72 
 73 
 74 static int master_rx(char *rxdata, int length) {
 75     int ret;
 76     struct i2c_msg msgs[] = {
 77         {
 78             .addr    = ft5x0x_client->addr,
 79             .flags    = 0,
 80             .len    = 1,
 81             .buf    = rxdata,
 82         },
 83         {
 84             .addr    = ft5x0x_client->addr,
 85             .flags    = I2C_M_RD,
 86             .len    = length,
 87             .buf    = rxdata,
 88         },
 89     };
 90 
 91     ret = i2c_transfer(ft5x0x_client->adapter, msgs, 2);
 92     if (ret < 0)
 93         printk(KERN_ERR "i2c_transfer error\n");
 94 
 95     return ret;
 96 }
 97 
 98 static int ft5x0x_read_data(struct ft5x0x_event *event)
 99 {
100     int ret;
101     u8 buf[64] = { 0 };
102 
103     ret = master_rx(buf, 7);
104 
105     memset(event, 0, sizeof(struct ft5x0x_event));
106 
107     event->touch_point = buf[2] & 0x0F;
108     if (!event->touch_point) {
109         ft5x0x_release();
110         return 1;
111     }
112 
113     event->x[0] = (s16)(buf[0x03] & 0x0F)<<8 | (s16)buf[0x04];
114     event->y[0] = (s16)(buf[0x05] & 0x0F)<<8 | (s16)buf[0x06];
115 
116     event->pressure = 200;
117 
118     return 0;
119 }
120 
121 static void i2c_wq_irq(unsigned long arg)
122 {
123     struct ft5x0x_event event;
124     
125     if (!ft5x0x_read_data(&event)) {
126         ft5x0x_report(&event);
127     }
128     
129     printk("(%d, %d)\n", event.x[0], event.y[0]);
130 }
131 
132 static irqreturn_t ft5x0x_irq(int irq, void *arg)
133 {
134     schedule_work(&wq);
135     return IRQ_HANDLED;
136 }
137 
138 static int read_device_info(u8 addr, u8 *val) 
139 {
140     int ret;
141     u8 buf = { 0 };
142     struct i2c_msg msgs[2];
143 
144     msgs[0].addr  = ft5x0x_client->addr;
145     msgs[0].buf      = &buf;
146     msgs[0].flags = 0;
147     msgs[0].len   = 1;
148 
149     msgs[1].addr  = ft5x0x_client->addr;
150     msgs[1].buf      = &buf;
151     msgs[1].flags = 1;
152     msgs[1].len   = 1;
153 
154     buf = addr;
155     ret = i2c_transfer(ft5x0x_client->adapter, msgs, 2);
156     if (ret < 0)
157         printk(KERN_ERR "i2c_transfer addr 0x%02x error!", buf);
158     else
159         *val = buf;
160 
161     return ret;
162 }
163 
164 static int device_info(unsigned char *val)
165 {
166     int ret;
167 
168     ret = read_device_info(0xA6, val);
169 
170     printk("device_info: %d\n",*val);
171 
172     return ret;
173 }
174 
175 static int ft5x0x_probe(struct i2c_client *client, const struct i2c_device_id *id)
176 {
177     int ret;
178     ft5x0x_client = client;
179     unsigned char val = 0;
180 
181     /* 设置中断引脚 */
182     client->irq = gpio_to_irq(EXYNOS4_GPX0(4));
183     s3c_gpio_cfgpin(client->irq, S3C_GPIO_SFN(0xf));
184     s3c_gpio_setpull(client->irq, S3C_GPIO_PULL_NONE);
185 
186     /* 分配设置input_device */
187     ftinput = input_allocate_device();
188 
189     set_bit(EV_ABS, ftinput->evbit);
190     set_bit(EV_KEY, ftinput->evbit);
191     set_bit(EV_SYN, ftinput->evbit);
192     
193     set_bit(ABS_X, ftinput->absbit);
194     set_bit(ABS_Y, ftinput->absbit);
195     set_bit(ABS_PRESSURE, ftinput->absbit);
196     set_bit(BTN_TOUCH, ftinput->keybit);
197 
198     input_set_abs_params(ftinput, ABS_X, 0, 768, 0, 0);
199     input_set_abs_params(ftinput, ABS_Y, 0, 1024, 0, 0);
200     input_set_abs_params(ftinput, ABS_PRESSURE, 0, 255, 0 , 0);
201 
202     ftinput->name = "ft5x0x";
203     ftinput->id.bustype = BUS_I2C;
204 
205     ret = input_register_device(ftinput);
206     if (ret) {
207         printk(KERN_ERR "input_register_device error\n");
208         input_free_device(ftinput);
209     }
210 
211     ret = request_irq(client->irq, ft5x0x_irq, IRQ_TYPE_EDGE_FALLING, "ft5x0x", NULL);
212     if (ret < 0) {
213         printk(KERN_ERR "request_irq %d error\n", client->irq);
214         goto exit_irq_request_failed;
215     }
216 
217     /* 注册中断底半部 */
218     INIT_WORK(&wq, i2c_wq_irq);
219     
220     device_info(&val);
221     
222     return 0;
223 
224 exit_irq_request_failed:
225     input_unregister_device(ftinput);
226 
227     return ret;
228 }
229 
230 static int ft5x0x_remove(struct i2c_client *client)
231 {
232     /* 镜像注销 */
233     input_unregister_device(ftinput);
234     cancel_work_sync(&wq);
235     client->irq = gpio_to_irq(EXYNOS4_GPX0(4));
236     free_irq(client->irq, NULL);
237     
238     return 0;
239 }
240 
241 static const struct i2c_device_id ft5x0x_table[] = {
242     { "ft5x0x", 0 },
243     { },
244 };
245 
246 static struct i2c_driver ft5x0x_driver = {
247     .driver = {
248         .name    = "ft5x0x",
249         .owner    = THIS_MODULE,
250     },
251     .probe        = ft5x0x_probe,
252     .remove        = __devexit_p(ft5x0x_remove),
253     .id_table    = ft5x0x_table,
254 };
255 
256 static int ft5x0x_init(void)
257 {
258     int ret;
259     ret = gpio_request(EXYNOS4_GPL0(2), "TP1_EN");
260     if (ret)
261         printk(KERN_ERR "failed to request TP1_EN for I2C control\n");
262     
263     gpio_direction_output(EXYNOS4_GPL0(2), 1);
264 
265     s3c_gpio_cfgpin(EXYNOS4_GPL0(2), S3C_GPIO_OUTPUT);
266     gpio_free(EXYNOS4_GPL0(2));
267 
268     mdelay(5);
269     
270     ret = gpio_request(EXYNOS4_GPX0(3), "GPX0_3");
271     if (ret) {
272         gpio_free(EXYNOS4_GPX0(3));
273         ret = gpio_request(EXYNOS4_GPX0(3), "GPX0_3");
274         if (ret) {
275             printk(KERN_ERR "failed to request GPX0_3 \n");
276         }
277     }
278     gpio_direction_output(EXYNOS4_GPX0(3), 0);
279     mdelay(200);
280 
281     gpio_direction_output(EXYNOS4_GPX0(3), 1);
282 
283     s3c_gpio_cfgpin(EXYNOS4_GPX0(3), S3C_GPIO_OUTPUT);
284     gpio_free(EXYNOS4_GPX0(3));
285     msleep(300);
286 
287     touch_size = 1;
288     swap_xy = 1;
289     
290     return i2c_add_driver(&ft5x0x_driver);
291 }
292 
293 static void ft5x0x_exit(void)
294 {
295     i2c_del_driver(&ft5x0x_driver);
296 }
297 
298 module_init(ft5x0x_init);
299 module_exit(ft5x0x_exit);
300 
301 MODULE_LICENSE("GPL");
View Code

Makefile:

 1 KERN_DIR = /work/itop4412/tools/linux-3.5
 2 
 3 all:
 4     make -C $(KERN_DIR) M=`pwd` modules 
 5 
 6 clean:
 7     make -C $(KERN_DIR) M=`pwd` modules clean
 8     rm -rf modules.order
 9 
10 obj-m    += ts.o
View Code

 

由于触摸屏驱动已经被编译到了内核,我们要先取消它:

$ make menuconfig

Device Drivers --->

Input device support --->

Touchscreens --->

去掉FT5X0X based touchscreens

 

我并没有编写i2c_client层,而是在mach-itop4412.c中进行更改:

在第2078行代码的基础上,加入#else内容:

#if defined(CONFIG_TOUCHSCREEN_FT5X0X)
    {
        I2C_BOARD_INFO("ft5x0x_ts", 0x70>>1),
        .irq = IRQ_EINT(4),
        .platform_data = &ft5x0x_pdata,
    },
/* 加入的代码 */
#else
    {
        I2C_BOARD_INFO("ft5x0x", 0x70 >> 1),
    },
#endif

 

在重新编译烧写内核后,insmod自己的触摸屏驱动,点击屏幕可发现如下现象:

十五、电容触摸屏驱动_第2张图片

 

 

下一章  十六、USB驱动

 

转载于:https://www.cnblogs.com/Lioker/p/10990633.html

你可能感兴趣的:(十五、电容触摸屏驱动)