15、電容觸摸屏驅動


 

在讀者學習本章以及后續章節之前,最好擁有ADC和觸摸屏裸機基礎,可以參考:ADC和觸摸屏編程

 

和按鍵驅動類似,觸摸屏也是通過電平來體現按下或松開。因此如果想要寫出通用的觸摸屏驅動,需要使用輸入子系統完成。

考慮到我是用的並不是之前的TINY4412,在此給出下文所分析的文件:

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

 

 

一、電容觸摸屏檢測原理

此段來源於百度百科,讀者可查看:電容式觸摸屏

電容式觸摸屏技術是利用人體的電流感應進行工作的。

電容式觸摸屏是一塊四層復合玻璃屏,玻璃屏的內表面和夾層各塗有一層ITO(導電玻璃),最外層是一薄層矽土玻璃保護層,夾層ITO塗層作為工作面,四個角上引出四個電極,內層ITO為屏蔽層以保證良好的工作環境。

當用戶觸摸電容屏時,由於人體電場,用戶手指和工作面形成一個耦合電容,因為工作面上接有高頻信號,於是手指吸收走一個很小的電流,這個電流分別從屏的四個角上的電極中流出,且理論上流經四個電極的電流與手指頭到四角的距離成比例,控制器通過對四個電流比例的精密計算得出位置。可以達到99%的精確度,具備小於3ms的響應速度。

 

 

二、電容觸摸屏控制芯片驅動分析

我使用的開發板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 <linux/init.h>
  2 #include <linux/module.h>
  3 #include <linux/kernel.h>
  4 #include <linux/i2c.h>
  5 #include <linux/slab.h>
  6 #include <linux/input.h>
  7 #include <linux/delay.h>
  8 #include <linux/fs.h>
  9 #include <linux/irq.h>
 10 #include <linux/workqueue.h>
 11 #include <linux/interrupt.h>
 12 #include <linux/mod_devicetable.h>
 13 #include <linux/platform_device.h>
 14 #include <linux/regulator/consumer.h>
 15 
 16 #include <asm/io.h>
 17 #include <asm/uaccess.h>
 18 
 19 #include <mach/gpio.h>
 20 #include <mach/regs-gpio.h>
 21 
 22 #include <plat/gpio-cfg.h>
 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自己的觸摸屏驅動,點擊屏幕可發現如下現象:

 

 

下一章  16、USB驅動

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM