diff options
Diffstat (limited to 'meta/recipes-kernel/linux/linux-netbook-2.6.33.2/linux-2.6.34-cypress-touch-driver.patch')
-rw-r--r-- | meta/recipes-kernel/linux/linux-netbook-2.6.33.2/linux-2.6.34-cypress-touch-driver.patch | 870 |
1 files changed, 870 insertions, 0 deletions
diff --git a/meta/recipes-kernel/linux/linux-netbook-2.6.33.2/linux-2.6.34-cypress-touch-driver.patch b/meta/recipes-kernel/linux/linux-netbook-2.6.33.2/linux-2.6.34-cypress-touch-driver.patch new file mode 100644 index 0000000000..2dae9ed82d --- /dev/null +++ b/meta/recipes-kernel/linux/linux-netbook-2.6.33.2/linux-2.6.34-cypress-touch-driver.patch | |||
@@ -0,0 +1,870 @@ | |||
1 | From 03e11a278286392dc20de57a24cadbc16d9aac3a Mon Sep 17 00:00:00 2001 | ||
2 | From: Priya Vijayan <priya.vijayan@intel.com> | ||
3 | Date: Tue, 27 Apr 2010 11:23:00 -0700 | ||
4 | Subject: [PATCH] Touchscreen driver for Cypress panels | ||
5 | |||
6 | This driver is from aava | ||
7 | |||
8 | Signed-off-by: Priya Vijayan <priya.vijayan@intel.com> | ||
9 | --- | ||
10 | drivers/input/touchscreen/Kconfig | 8 + | ||
11 | drivers/input/touchscreen/Makefile | 1 + | ||
12 | drivers/input/touchscreen/cy8ctmg110_ts.c | 815 +++++++++++++++++++++++++++++ | ||
13 | 3 files changed, 824 insertions(+), 0 deletions(-) | ||
14 | create mode 100644 drivers/input/touchscreen/cy8ctmg110_ts.c | ||
15 | |||
16 | diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig | ||
17 | index 6dd2674..5ecf00d 100644 | ||
18 | --- a/drivers/input/touchscreen/Kconfig | ||
19 | +++ b/drivers/input/touchscreen/Kconfig | ||
20 | @@ -103,6 +103,14 @@ config TOUCHSCREEN_CORGI | ||
21 | NOTE: this driver is deprecated, try enable SPI and generic | ||
22 | ADS7846-based touchscreen driver. | ||
23 | |||
24 | +config TOUCHSCREEN_CY8CTMG110 | ||
25 | + tristate "cy8ctmg110 touchscreen" | ||
26 | + depends on I2C | ||
27 | + default y | ||
28 | + help | ||
29 | + Say Y here if you have a cy8ctmg110 touchscreen capasitive touchscreen | ||
30 | + If unsure, say N. | ||
31 | + | ||
32 | config TOUCHSCREEN_DA9034 | ||
33 | tristate "Touchscreen support for Dialog Semiconductor DA9034" | ||
34 | depends on PMIC_DA903X | ||
35 | diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile | ||
36 | index 15ad257..e5b5fae 100644 | ||
37 | --- a/drivers/input/touchscreen/Makefile | ||
38 | +++ b/drivers/input/touchscreen/Makefile | ||
39 | @@ -12,6 +12,7 @@ obj-$(CONFIG_TOUCHSCREEN_ADS7846) += ads7846.o | ||
40 | obj-$(CONFIG_TOUCHSCREEN_ATMEL_TSADCC) += atmel_tsadcc.o | ||
41 | obj-$(CONFIG_TOUCHSCREEN_BITSY) += h3600_ts_input.o | ||
42 | obj-$(CONFIG_TOUCHSCREEN_CORGI) += corgi_ts.o | ||
43 | +obj-$(CONFIG_TOUCHSCREEN_CY8CTMG110) += cy8ctmg110_ts.o | ||
44 | obj-$(CONFIG_TOUCHSCREEN_DYNAPRO) += dynapro.o | ||
45 | obj-$(CONFIG_TOUCHSCREEN_GUNZE) += gunze.o | ||
46 | obj-$(CONFIG_TOUCHSCREEN_EETI) += eeti_ts.o | ||
47 | diff --git a/drivers/input/touchscreen/cy8ctmg110_ts.c b/drivers/input/touchscreen/cy8ctmg110_ts.c | ||
48 | new file mode 100644 | ||
49 | index 0000000..5587385 | ||
50 | --- /dev/null | ||
51 | +++ b/drivers/input/touchscreen/cy8ctmg110_ts.c | ||
52 | @@ -0,0 +1,815 @@ | ||
53 | +/* | ||
54 | + * cy8ctmg110_ts.c Driver for cypress touch screen controller | ||
55 | + * Copyright (c) 2009 Aava Mobile | ||
56 | + * | ||
57 | + * This program is free software; you can redistribute it and/or modify | ||
58 | + * it under the terms of the GNU General Public License version 2 as | ||
59 | + * published by the Free Software Foundation. | ||
60 | + * | ||
61 | + * This program is distributed in the hope that it will be useful, | ||
62 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
63 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
64 | + * GNU General Public License for more details. | ||
65 | + * | ||
66 | + * You should have received a copy of the GNU General Public License | ||
67 | + * along with this program; if not, write to the Free Software | ||
68 | + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
69 | + */ | ||
70 | + | ||
71 | +#include <linux/module.h> | ||
72 | +#include <linux/kernel.h> | ||
73 | +#include <linux/input.h> | ||
74 | +#include <linux/interrupt.h> | ||
75 | +#include <asm/io.h> | ||
76 | +#include <linux/i2c.h> | ||
77 | +#include <linux/timer.h> | ||
78 | +#include <linux/gpio.h> | ||
79 | +#include <linux/hrtimer.h> | ||
80 | + | ||
81 | +#include <linux/platform_device.h> | ||
82 | +#include <linux/delay.h> | ||
83 | +#include <linux/fs.h> | ||
84 | +#include <asm/ioctl.h> | ||
85 | +#include <asm/ipc_defs.h> | ||
86 | +#include <asm/uaccess.h> | ||
87 | +#include <linux/device.h> | ||
88 | +#include <linux/module.h> | ||
89 | +#include <linux/platform_device.h> | ||
90 | +#include <linux/delay.h> | ||
91 | +#include <linux/fs.h> | ||
92 | +#include <asm/ioctl.h> | ||
93 | +#include <linux/fs.h> | ||
94 | +#include <linux/init.h> | ||
95 | +#include <linux/miscdevice.h> | ||
96 | +#include <linux/module.h> | ||
97 | + | ||
98 | + | ||
99 | +#define CY8CTMG110_DRIVER_NAME "cy8ctmg110" | ||
100 | +#define CY8CTMG110_DRIVER_NAME_EXT "cy8ctmg110 ext" | ||
101 | +/*#define MOORESTOWN_CDK*/ | ||
102 | +/*#define CY8CTMG110_DEBUG_INFO*/ | ||
103 | +/*#define POLL_TOUCH_EVENTS*/ | ||
104 | + | ||
105 | + | ||
106 | + | ||
107 | +/*HW definations*/ | ||
108 | + | ||
109 | +/*Main touch specific*/ | ||
110 | +#define CY8CTMG110_I2C_ADDR 0x38 | ||
111 | +#define CY8CTMG110_RESET_PIN_GPIO 43 | ||
112 | +#define CY8CTMG110_IRQ_PIN_GPIO 59 | ||
113 | + | ||
114 | +/*Extended specific*/ | ||
115 | +#define CY8CTMG110_I2C_ADDR_EXT 0x39 | ||
116 | +#define CY8CTMG110_RESET_PIN_GPIO_EXT 39 | ||
117 | +#define CY8CTMG110_IRQ_PIN_GPIO_EXT 31 | ||
118 | + | ||
119 | + | ||
120 | +#define CY8CTMG110_TOUCH_LENGHT 9787 | ||
121 | +#define CY8CTMG110_SCREEN_LENGHT 8424 | ||
122 | + | ||
123 | + | ||
124 | +/*Main Touch coordinates*/ | ||
125 | +#define CY8CTMG110_X_MIN 0 | ||
126 | +#define CY8CTMG110_Y_MIN 0 | ||
127 | +#define CY8CTMG110_X_MAX 864 | ||
128 | +#define CY8CTMG110_Y_MAX 480 | ||
129 | + | ||
130 | + | ||
131 | +/*cy8ctmg110 registers defination*/ | ||
132 | +#define CY8CTMG110_TOUCH_WAKEUP_TIME 0 | ||
133 | +#define CY8CTMG110_TOUCH_SLEEP_TIME 2 | ||
134 | +#define CY8CTMG110_TOUCH_X1 3 | ||
135 | +#define CY8CTMG110_TOUCH_Y1 5 | ||
136 | +#define CY8CTMG110_TOUCH_X2 7 | ||
137 | +#define CY8CTMG110_TOUCH_Y2 9 | ||
138 | +#define CY8CTMG110_FINGERS 11 | ||
139 | +#define CY8CTMG110_GESTURE 12 | ||
140 | +#define CY8CTMG110_VERSIONID 13 //not supported in touchpanel FW | ||
141 | +#define CY8CTMG110_REG_MAX 13 | ||
142 | + | ||
143 | +#ifdef POLL_TOUCH_EVENTS | ||
144 | + #define CY8CTMG110_POLL_TIMER_DELAY 1000*1000*100 | ||
145 | + #define TOUCH_MAX_I2C_FAILS 50 | ||
146 | +#endif | ||
147 | + | ||
148 | +#define CY8CTMG110_POLL_TIMER_DELAY 1000*1000*100 | ||
149 | + | ||
150 | +/* Scale factors for coordinates */ | ||
151 | +#define X_SCALE_FACTOR 9387/8424 | ||
152 | +#define Y_SCALE_FACTOR 97/100 | ||
153 | + | ||
154 | +/* For tracing */ | ||
155 | +static u16 g_y_trace_coord = 0; | ||
156 | + | ||
157 | +/*if soutcanyon*/ | ||
158 | +static bool isSc = false; | ||
159 | + | ||
160 | + | ||
161 | +/* | ||
162 | + * Touchtype | ||
163 | + */ | ||
164 | +enum touch_type { | ||
165 | + TOUCH_KOSKI=1, | ||
166 | + TOUCH_SC, | ||
167 | + TOUCH_EXT, | ||
168 | +}; | ||
169 | + | ||
170 | +/* | ||
171 | + * The touch position structure. | ||
172 | + */ | ||
173 | +struct ts_event { | ||
174 | + int x1; | ||
175 | + int y1; | ||
176 | + int x2; | ||
177 | + int y2; | ||
178 | + bool event_sended; | ||
179 | +}; | ||
180 | + | ||
181 | +/* | ||
182 | + * The touch driver structure. | ||
183 | + */ | ||
184 | +struct cy8ctmg110 { | ||
185 | + struct input_dev *input; | ||
186 | + char phys[32]; | ||
187 | + struct ts_event tc; | ||
188 | + struct i2c_client *client; | ||
189 | + bool pending; | ||
190 | + spinlock_t lock; | ||
191 | + bool initController; | ||
192 | + bool sleepmode; | ||
193 | + int irq_gpio; | ||
194 | + int reset_gpio; | ||
195 | + char driver_name[20]; | ||
196 | + struct delayed_work work; | ||
197 | + enum touch_type version_id; | ||
198 | +#ifdef POLL_TOUCH_EVENTS | ||
199 | + struct hrtimer timer; | ||
200 | + int i2c_fail_count; | ||
201 | +#endif | ||
202 | +}; | ||
203 | + | ||
204 | +/* | ||
205 | + * cy8ctmg110_poweroff is the routine that is called when touch hardware | ||
206 | + * will powered off | ||
207 | + */ | ||
208 | +static void cy8ctmg110_power(struct cy8ctmg110 *ts,bool poweron) | ||
209 | +{ | ||
210 | +#ifdef CY8CTMG110_DEBUG_INFO | ||
211 | + printk("%s power:%d\n",ts->driver_name,poweron); | ||
212 | +#endif | ||
213 | + if (poweron) | ||
214 | + gpio_direction_output(ts->reset_gpio, 0); | ||
215 | + else | ||
216 | + gpio_direction_output(ts->reset_gpio, 1); | ||
217 | +} | ||
218 | +/* | ||
219 | + * cy8ctmg110_write_req write regs to the i2c devices | ||
220 | + * | ||
221 | + */ | ||
222 | +static int cy8ctmg110_write_req(struct cy8ctmg110 *tsc,unsigned char reg,unsigned char len,unsigned char *value) | ||
223 | +{ | ||
224 | + struct i2c_client *client = tsc->client; | ||
225 | + unsigned int ret; | ||
226 | + unsigned char i2c_data[]={0,0,0,0,0,0}; | ||
227 | +#ifdef CY8CTMG110_DEBUG_INFO | ||
228 | + printk("cy8ctmg110_init_req:\n"); | ||
229 | +#endif | ||
230 | + | ||
231 | + i2c_data[0]=reg; | ||
232 | + memcpy(i2c_data+1,value,len); | ||
233 | + | ||
234 | + { | ||
235 | + struct i2c_msg msg[] = { | ||
236 | + { client->addr, 0, len+1, i2c_data }, | ||
237 | + }; | ||
238 | + | ||
239 | + ret = i2c_transfer(client->adapter, msg, 1); | ||
240 | + | ||
241 | + if (ret != 1) { | ||
242 | + printk("cy8ctmg110 touch : i2c write data cmd failed \n"); | ||
243 | + return ret; | ||
244 | + } | ||
245 | + } | ||
246 | + | ||
247 | + return 0; | ||
248 | +} | ||
249 | +/* | ||
250 | + * get_time | ||
251 | + * | ||
252 | + */ | ||
253 | +#ifdef CY8CTMG110_DEBUG_INFO | ||
254 | +static inline long cy8ctmg110_get_time(void) | ||
255 | +{ | ||
256 | + struct timeval t; | ||
257 | + do_gettimeofday(&t); | ||
258 | + return t.tv_usec; | ||
259 | +} | ||
260 | +#endif | ||
261 | +/* | ||
262 | + * cy8ctmg110_read_req read regs from i2c devise | ||
263 | + * | ||
264 | + */ | ||
265 | +static int cy8ctmg110_read_req(struct cy8ctmg110 *tsc,unsigned char *i2c_data,unsigned char len ,unsigned char cmd) | ||
266 | +{ | ||
267 | + struct i2c_client *client = tsc->client; | ||
268 | + unsigned int ret; | ||
269 | + unsigned char regs_cmd[2]={0,0}; | ||
270 | +#ifdef CY8CTMG110_DEBUG_INFO | ||
271 | + long starttime = cy8ctmg110_get_time(); | ||
272 | +#endif | ||
273 | + regs_cmd[0]=cmd; | ||
274 | + | ||
275 | + | ||
276 | + /* first write slave position to i2c devices*/ | ||
277 | + { | ||
278 | + struct i2c_msg msg1[] = { | ||
279 | + { client->addr, 0, 1, regs_cmd }, | ||
280 | + }; | ||
281 | + | ||
282 | + ret = i2c_transfer(client->adapter, msg1, 1); | ||
283 | + | ||
284 | + if (ret != 1) { | ||
285 | +#ifdef POLL_TOUCH_EVENTS | ||
286 | + tsc->i2c_fail_count++; | ||
287 | +#endif | ||
288 | + return ret; | ||
289 | + } | ||
290 | + } | ||
291 | + | ||
292 | + | ||
293 | + /* Second read data from position*/ | ||
294 | + { | ||
295 | + struct i2c_msg msg2[] = { | ||
296 | + { client->addr, I2C_M_RD, len, i2c_data }, | ||
297 | + }; | ||
298 | + | ||
299 | + ret = i2c_transfer(client->adapter, msg2, 1); | ||
300 | + | ||
301 | + | ||
302 | + if (ret != 1) { | ||
303 | +#ifdef POLL_TOUCH_EVENTS | ||
304 | + tsc->i2c_fail_count++; | ||
305 | +#endif | ||
306 | + return ret; | ||
307 | + } | ||
308 | + } | ||
309 | +#ifdef CY8CTMG110_DEBUG_INFO | ||
310 | + printk("%s time to get data bytes read:%d time:%d\n",tsc->driver_name,len,(cy8ctmg110_get_time()-starttime)); | ||
311 | +#endif | ||
312 | + return 0; | ||
313 | +} | ||
314 | +/* | ||
315 | + * cy8ctmg110_send_event delevery touch event to the userpace | ||
316 | + * function use normal input interface | ||
317 | + */ | ||
318 | +static void cy8ctmg110_send_event(void *tsc,int x,int y) | ||
319 | +{ | ||
320 | + struct cy8ctmg110 *ts = tsc; | ||
321 | + struct input_dev *input = ts->input; | ||
322 | + u16 x2, y2; | ||
323 | +#ifdef CY8CTMG110_DEBUG_INFO | ||
324 | + printk("cy8ctmg110_send_event\n"); | ||
325 | +#endif | ||
326 | + | ||
327 | + if(ts->tc.event_sended == false){ | ||
328 | + | ||
329 | + if (ts->client->addr==CY8CTMG110_I2C_ADDR_EXT){ | ||
330 | + /*Extended touchpanel*/ | ||
331 | + input_report_key(input, BTN_TOUCH, 1); | ||
332 | + | ||
333 | + | ||
334 | + if ( ts->pending == true){ | ||
335 | + input_report_rel(input, REL_Y, (ts->tc.x1-x)*2); | ||
336 | + input_report_rel(input, REL_X, (y - ts->tc.y1)*3); | ||
337 | + ts->tc.y1 = y; | ||
338 | + ts->tc.x1 = x; | ||
339 | + } | ||
340 | + else{ | ||
341 | + ts->pending = true; | ||
342 | + ts->tc.y1 = y; | ||
343 | + ts->tc.x1 = x; | ||
344 | + } | ||
345 | + | ||
346 | + | ||
347 | + } | ||
348 | + else{ | ||
349 | + /*Main touchpanel*/ | ||
350 | + ts->tc.y1 = y; | ||
351 | + ts->tc.x1 = x; | ||
352 | + ts->pending = true; | ||
353 | + input_report_key(input, BTN_TOUCH, 1); | ||
354 | + | ||
355 | + x2 = y; | ||
356 | + y2 = x; | ||
357 | + | ||
358 | + if (isSc == false){ | ||
359 | + /*Main touchpanel in koski*/ | ||
360 | + x2 = (u16)(y*X_SCALE_FACTOR); | ||
361 | + y2 = (u16)(x*Y_SCALE_FACTOR); | ||
362 | + } | ||
363 | + | ||
364 | + input_report_abs(input, ABS_X, x2); | ||
365 | + input_report_abs(input, ABS_Y, y2); | ||
366 | + } | ||
367 | + | ||
368 | + input_sync(input); | ||
369 | + if(g_y_trace_coord) | ||
370 | + printk("%s touch position X:%d (was = %d) Y:%d (was = %d)\n",ts->driver_name, x2, y, y2, x); | ||
371 | + } | ||
372 | + | ||
373 | +} | ||
374 | + | ||
375 | +/* | ||
376 | + * cy8ctmg110_touch_pos check touch position from i2c devices | ||
377 | + * | ||
378 | + */ | ||
379 | +static int cy8ctmg110_touch_pos(struct cy8ctmg110 *tsc) | ||
380 | +{ | ||
381 | + unsigned char reg_p[CY8CTMG110_REG_MAX]; | ||
382 | + | ||
383 | + memset(reg_p,0,CY8CTMG110_REG_MAX); | ||
384 | + | ||
385 | + /*Reading coordinates*/ | ||
386 | + if (cy8ctmg110_read_req(tsc,reg_p,1,CY8CTMG110_FINGERS)==0){ | ||
387 | + | ||
388 | + /*number of touch*/ | ||
389 | + if (reg_p[0]==0){ | ||
390 | + if (tsc->pending == true){ | ||
391 | + struct input_dev *input = tsc->input; | ||
392 | + | ||
393 | + input_report_key(input, BTN_TOUCH, 0); | ||
394 | + | ||
395 | + input_sync(input); | ||
396 | + tsc->tc.event_sended = true; | ||
397 | +#ifdef CY8CTMG110_DEBUG_INFO | ||
398 | + printk("cy8ctmg110_send_event ts->pending = true;\n"); | ||
399 | +#endif | ||
400 | + tsc->pending = false; | ||
401 | + } | ||
402 | + } | ||
403 | + else { | ||
404 | + | ||
405 | + if (cy8ctmg110_read_req(tsc,reg_p,4,CY8CTMG110_TOUCH_X1)==0){ | ||
406 | + int x = 0,y = 0; | ||
407 | + y = reg_p[2]<<8 | reg_p[3]; | ||
408 | + x = reg_p[0]<<8 | reg_p[1]; | ||
409 | + | ||
410 | + if (tsc->tc.x1 != x || tsc->tc.y1 != y){ | ||
411 | + tsc->tc.event_sended = false; | ||
412 | + cy8ctmg110_send_event(tsc,x,y); | ||
413 | + } | ||
414 | + } | ||
415 | + } | ||
416 | + } | ||
417 | + else{ | ||
418 | +#ifdef CY8CTMG110_DEBUG_INFO | ||
419 | + printk("cy8ctmg110 i2c reading error\n"); | ||
420 | +#endif | ||
421 | + } | ||
422 | + | ||
423 | + return 0; | ||
424 | +} | ||
425 | +/* | ||
426 | + * cy8ctmg110_read_versionid delevery touch event to the userpace | ||
427 | + * function use normal input interface | ||
428 | + */ | ||
429 | +static void cy8ctmg110_read_versionid(void *tsc) | ||
430 | +{ | ||
431 | + struct cy8ctmg110 *ts = tsc; | ||
432 | + unsigned char reg_p[2]; | ||
433 | + | ||
434 | + | ||
435 | + if (cy8ctmg110_read_req(ts,reg_p,1,CY8CTMG110_VERSIONID)==0){ | ||
436 | + printk("%s id 0x%x\n",ts->driver_name,reg_p[0]); | ||
437 | + | ||
438 | + /*Ugly hack solution if SC | ||
439 | + */ | ||
440 | + | ||
441 | + if(ts->client->addr==CY8CTMG110_I2C_ADDR_EXT) | ||
442 | + isSc = true; | ||
443 | + | ||
444 | + switch (reg_p[0]){ | ||
445 | + case 0x01: | ||
446 | + ts->version_id = TOUCH_EXT; | ||
447 | + break; | ||
448 | + case 0x02: | ||
449 | + ts->version_id = TOUCH_SC; | ||
450 | + break; | ||
451 | + case 0x03: | ||
452 | + ts->version_id = TOUCH_KOSKI; | ||
453 | + break; | ||
454 | + default: | ||
455 | + ts->version_id = TOUCH_KOSKI; | ||
456 | + break; | ||
457 | + } | ||
458 | + } | ||
459 | +} | ||
460 | + | ||
461 | + | ||
462 | +#ifdef POLL_TOUCH_EVENTS | ||
463 | +/* | ||
464 | + * if interup is'n in use the touch positions can reads by polling | ||
465 | + * | ||
466 | + */ | ||
467 | +static enum hrtimer_restart cy8ctmg110_timer(struct hrtimer *handle) | ||
468 | +{ | ||
469 | + struct cy8ctmg110 *ts = container_of(handle, struct cy8ctmg110, timer); | ||
470 | + unsigned long flags; | ||
471 | + | ||
472 | + spin_lock_irqsave(&ts->lock, flags); | ||
473 | +#ifdef CY8CTMG110_DEBUG_INFO | ||
474 | + printk("cy8ctmg110_timer\n"); | ||
475 | +#endif | ||
476 | + | ||
477 | + cy8ctmg110_touch_pos(ts); | ||
478 | + | ||
479 | + if (ts->i2c_fail_count<TOUCH_MAX_I2C_FAILS) | ||
480 | + hrtimer_start(&ts->timer, ktime_set(0, CY8CTMG110_POLL_TIMER_DELAY), | ||
481 | + HRTIMER_MODE_REL); | ||
482 | + | ||
483 | + spin_unlock_irqrestore(&ts->lock, flags); | ||
484 | + | ||
485 | + return HRTIMER_NORESTART; | ||
486 | +} | ||
487 | +#endif | ||
488 | +/* | ||
489 | + * cy8ctmg110_init_controller set init value to touchcontroller | ||
490 | + * | ||
491 | + */ | ||
492 | +static bool cy8ctmg110_set_sleepmode(struct cy8ctmg110 *ts) | ||
493 | +{ | ||
494 | + unsigned char reg_p[3]; | ||
495 | + | ||
496 | + if(ts->sleepmode==true){ | ||
497 | + reg_p[0] = 0x00; reg_p[1] =0xff; reg_p[2] =5; | ||
498 | + }else{ | ||
499 | + reg_p[0] = 0x10;reg_p[1] =0xff;reg_p[2] =0; | ||
500 | + } | ||
501 | + | ||
502 | + if (cy8ctmg110_write_req(ts,CY8CTMG110_TOUCH_WAKEUP_TIME,3,reg_p)){ | ||
503 | + return false; | ||
504 | + } | ||
505 | + ts->initController = true; | ||
506 | + | ||
507 | + return true; | ||
508 | +} | ||
509 | + | ||
510 | + | ||
511 | + | ||
512 | +static void cy8ctmg110_work(struct work_struct *work) | ||
513 | +{ | ||
514 | + struct cy8ctmg110 *ts = | ||
515 | + container_of(to_delayed_work(work), struct cy8ctmg110, work); | ||
516 | + | ||
517 | + cy8ctmg110_touch_pos(ts); | ||
518 | +} | ||
519 | + | ||
520 | + | ||
521 | +/* | ||
522 | + * cy8ctmg110_irq_handler irq handling function | ||
523 | + * | ||
524 | + */ | ||
525 | +static irqreturn_t cy8ctmg110_irq_handler(int irq, void *handle) | ||
526 | +{ | ||
527 | + struct cy8ctmg110 * tsc = (struct cy8ctmg110 *)handle; | ||
528 | + | ||
529 | +#ifdef CY8CTMG110_DEBUG_INFO | ||
530 | + printk("%s cy8ctmg110_irq_handler\n",tsc->driver_name); | ||
531 | +#endif | ||
532 | + if (tsc->initController == false){ | ||
533 | + if (cy8ctmg110_set_sleepmode(tsc) == true) | ||
534 | + tsc->initController = true; | ||
535 | + } | ||
536 | + else | ||
537 | + { | ||
538 | + schedule_delayed_work(&tsc->work, | ||
539 | + msecs_to_jiffies(1)); | ||
540 | + } | ||
541 | + | ||
542 | +#ifdef POLL_TOUCH_EVENTS | ||
543 | + /*if interrupt supported in the touch controller | ||
544 | + timer polling need to stop*/ | ||
545 | + tsc->i2c_fail_count = TOUCH_MAX_I2C_FAILS; | ||
546 | +#endif | ||
547 | + return IRQ_HANDLED; | ||
548 | +} | ||
549 | + | ||
550 | + | ||
551 | +static int cy8ctmg110_probe(struct i2c_client *client, | ||
552 | + const struct i2c_device_id *id) | ||
553 | +{ | ||
554 | + struct cy8ctmg110 *ts; | ||
555 | + struct input_dev *input_dev; | ||
556 | + int err; | ||
557 | + | ||
558 | + if (!i2c_check_functionality(client->adapter, | ||
559 | + I2C_FUNC_SMBUS_READ_WORD_DATA)) | ||
560 | + return -EIO; | ||
561 | + | ||
562 | + ts = kzalloc(sizeof(struct cy8ctmg110), GFP_KERNEL); | ||
563 | + input_dev = input_allocate_device(); | ||
564 | + | ||
565 | + if (!ts || !input_dev) { | ||
566 | + err = -ENOMEM; | ||
567 | + goto err_free_mem; | ||
568 | + } | ||
569 | + | ||
570 | + ts->client = client; | ||
571 | + i2c_set_clientdata(client, ts); | ||
572 | + | ||
573 | + ts->input = input_dev; | ||
574 | + ts->pending = false; | ||
575 | + ts->sleepmode = false; | ||
576 | + | ||
577 | + | ||
578 | + if(client->addr==CY8CTMG110_I2C_ADDR){ | ||
579 | + ts->reset_gpio = CY8CTMG110_RESET_PIN_GPIO; | ||
580 | + input_dev->name = CY8CTMG110_DRIVER_NAME" Touchscreen"; | ||
581 | + snprintf(ts->driver_name, sizeof(ts->driver_name),"%s", CY8CTMG110_DRIVER_NAME); | ||
582 | + } | ||
583 | + else if (client->addr==CY8CTMG110_I2C_ADDR_EXT){ | ||
584 | + ts->reset_gpio = CY8CTMG110_RESET_PIN_GPIO_EXT; | ||
585 | + input_dev->name = CY8CTMG110_DRIVER_NAME_EXT" Touchscreen"; | ||
586 | + snprintf(ts->driver_name, sizeof(ts->driver_name),"%s", CY8CTMG110_DRIVER_NAME_EXT); | ||
587 | + } | ||
588 | + | ||
589 | + snprintf(ts->phys, sizeof(ts->phys), | ||
590 | + "%s/input0", dev_name(&client->dev)); | ||
591 | + | ||
592 | + INIT_DELAYED_WORK(&ts->work, cy8ctmg110_work); | ||
593 | + | ||
594 | + input_dev->phys = ts->phys; | ||
595 | + input_dev->id.bustype = BUS_I2C; | ||
596 | + | ||
597 | + spin_lock_init(&ts->lock); | ||
598 | + | ||
599 | + input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP) | | ||
600 | + BIT_MASK(EV_REL) | BIT_MASK(EV_ABS); | ||
601 | + | ||
602 | + input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); | ||
603 | + | ||
604 | + input_set_capability(input_dev, EV_KEY, KEY_F); | ||
605 | + | ||
606 | + | ||
607 | + input_set_abs_params(input_dev, ABS_X, CY8CTMG110_X_MIN, CY8CTMG110_X_MAX, 0, 0); | ||
608 | + input_set_abs_params(input_dev, ABS_Y, CY8CTMG110_Y_MIN, CY8CTMG110_Y_MAX, 0, 0); | ||
609 | + input_dev->relbit[BIT_WORD(REL_X)] = BIT_MASK(REL_X)| BIT_MASK(REL_Y); | ||
610 | + | ||
611 | + err = gpio_request(ts->reset_gpio, NULL); | ||
612 | + | ||
613 | + if (err) { | ||
614 | + printk("GPIO pin %d failed to request.\n", ts->reset_gpio); | ||
615 | + goto err_free_thread; | ||
616 | + } | ||
617 | + | ||
618 | + cy8ctmg110_power(ts,true); | ||
619 | + | ||
620 | + ts->initController = false; | ||
621 | +#ifdef POLL_TOUCH_EVENTS | ||
622 | + ts->i2c_fail_count = 0; | ||
623 | + hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); | ||
624 | + ts->timer.function = cy8ctmg110_timer; | ||
625 | + | ||
626 | + hrtimer_start(&ts->timer, ktime_set(10, 0), | ||
627 | + HRTIMER_MODE_REL); | ||
628 | +#endif | ||
629 | + err = gpio_request(client->irq, "touch_irq_key"); | ||
630 | + | ||
631 | + if (err < 0) { | ||
632 | + printk("%s gpio-keys: failed to request GPIO %d," | ||
633 | + " error %d\n",ts->driver_name,client->irq, err); | ||
634 | + goto err_free_thread; | ||
635 | + } | ||
636 | + | ||
637 | + err= gpio_direction_input(client->irq); | ||
638 | + | ||
639 | + if (err < 0) { | ||
640 | + pr_err("%s gpio-keys: failed to configure input" | ||
641 | + " direction for GPIO %d, error %d\n",ts->driver_name,client->irq, err); | ||
642 | + gpio_free(client->irq); | ||
643 | + goto err_free_thread; | ||
644 | + } | ||
645 | + | ||
646 | + ts->irq_gpio = gpio_to_irq(client->irq); | ||
647 | + | ||
648 | + if (ts->irq_gpio < 0) { | ||
649 | + err = ts->irq_gpio; | ||
650 | + pr_err("cy8ctmg110 gpio-keys: Unable to get irq number" | ||
651 | + " for GPIO %d, error %d\n", | ||
652 | + ts->irq_gpio, err); | ||
653 | + gpio_free(ts->irq_gpio); | ||
654 | + goto err_free_thread; | ||
655 | + } | ||
656 | + | ||
657 | + if (client->addr!=CY8CTMG110_I2C_ADDR_EXT){ | ||
658 | + err = request_irq(ts->irq_gpio, cy8ctmg110_irq_handler, | ||
659 | + IRQF_TRIGGER_RISING | IRQF_SHARED, | ||
660 | + "touch_reset_key", | ||
661 | + ts); | ||
662 | + } | ||
663 | + | ||
664 | + if (err < 0) { | ||
665 | + dev_err(&client->dev, "cy8ctmg110 irq %d busy? error %d\n", ts->irq_gpio ,err); | ||
666 | + goto err_free_thread; | ||
667 | + } | ||
668 | + | ||
669 | + err = input_register_device(input_dev); | ||
670 | + cy8ctmg110_read_versionid(ts); | ||
671 | + | ||
672 | + if (err) | ||
673 | + goto err_free_irq; | ||
674 | + | ||
675 | + return 0; | ||
676 | + | ||
677 | + err_free_irq: | ||
678 | + printk("%s err_free_irq\n",ts->driver_name); | ||
679 | + free_irq(client->irq, ts); | ||
680 | + err_free_thread: | ||
681 | + printk("%s err_free_thread\n",ts->driver_name); | ||
682 | + err_free_mem: | ||
683 | + printk("%s err_free_mem\n",ts->driver_name); | ||
684 | + input_free_device(input_dev); | ||
685 | + kfree(ts); | ||
686 | + | ||
687 | + return err; | ||
688 | +} | ||
689 | +/* | ||
690 | + * cy8ctmg110_suspend | ||
691 | + * | ||
692 | + */ | ||
693 | +static int cy8ctmg110_suspend(struct i2c_client *client, pm_message_t mesg) | ||
694 | +{ | ||
695 | + if (device_may_wakeup(&client->dev)) | ||
696 | + enable_irq_wake(client->irq); | ||
697 | + | ||
698 | + return 0; | ||
699 | +} | ||
700 | +/* | ||
701 | + * cy8ctmg110_resume | ||
702 | + * | ||
703 | + */ | ||
704 | +static int cy8ctmg110_resume(struct i2c_client *client) | ||
705 | +{ | ||
706 | + if (device_may_wakeup(&client->dev)) | ||
707 | + disable_irq_wake(client->irq); | ||
708 | + | ||
709 | + return 0; | ||
710 | +} | ||
711 | +/* | ||
712 | + * cy8ctmg110_remove | ||
713 | + * | ||
714 | + */ | ||
715 | +static int cy8ctmg110_remove(struct i2c_client *client) | ||
716 | +{ | ||
717 | + struct cy8ctmg110 *ts = i2c_get_clientdata(client); | ||
718 | + | ||
719 | +#ifdef CY8CTMG110_DEBUG_INFO | ||
720 | + printk("cy8ctmg110_remove\n"); | ||
721 | +#endif | ||
722 | + | ||
723 | + cy8ctmg110_power(ts,false); | ||
724 | +#ifdef POLL_TOUCH_EVENTS | ||
725 | + hrtimer_cancel(&ts->timer); | ||
726 | +#endif | ||
727 | + | ||
728 | + free_irq(client->irq, ts); | ||
729 | + input_unregister_device(ts->input); | ||
730 | + kfree(ts); | ||
731 | + | ||
732 | + return 0; | ||
733 | +} | ||
734 | + | ||
735 | +static struct i2c_device_id cy8ctmg110_idtable[] = { | ||
736 | + { CY8CTMG110_DRIVER_NAME, 1 }, | ||
737 | + { CY8CTMG110_DRIVER_NAME_EXT, 1 }, | ||
738 | + { } | ||
739 | +}; | ||
740 | + | ||
741 | +MODULE_DEVICE_TABLE(i2c, cy8ctmg110_idtable); | ||
742 | + | ||
743 | +static struct i2c_driver cy8ctmg110_driver = { | ||
744 | + .driver = { | ||
745 | + .owner = THIS_MODULE, | ||
746 | + .name = CY8CTMG110_DRIVER_NAME, | ||
747 | + .bus = &i2c_bus_type, | ||
748 | + }, | ||
749 | + .id_table = cy8ctmg110_idtable, | ||
750 | + .probe = cy8ctmg110_probe, | ||
751 | + .remove = cy8ctmg110_remove, | ||
752 | + .suspend = cy8ctmg110_suspend, | ||
753 | + .resume = cy8ctmg110_resume, | ||
754 | +}; | ||
755 | + | ||
756 | + | ||
757 | +static int __init cy8ctmg110_init(void) | ||
758 | +{ | ||
759 | + printk("cy8ctmg110_init\n"); | ||
760 | + | ||
761 | + return i2c_add_driver(&cy8ctmg110_driver); | ||
762 | +} | ||
763 | + | ||
764 | +static void __exit cy8ctmg110_exit(void) | ||
765 | +{ | ||
766 | +#ifdef CY8CTMG110_DEBUG_INFO | ||
767 | + printk("cy8ctmg110_exit\n"); | ||
768 | +#endif | ||
769 | + i2c_del_driver(&cy8ctmg110_driver); | ||
770 | +} | ||
771 | + | ||
772 | +module_init(cy8ctmg110_init); | ||
773 | +module_exit(cy8ctmg110_exit); | ||
774 | + | ||
775 | + | ||
776 | +struct i2c_board_info __initdata koski_i2c_board_info2[] = { | ||
777 | + { | ||
778 | + I2C_BOARD_INFO(CY8CTMG110_DRIVER_NAME, CY8CTMG110_I2C_ADDR), | ||
779 | + .irq = CY8CTMG110_IRQ_PIN_GPIO | ||
780 | + }, | ||
781 | + { | ||
782 | + I2C_BOARD_INFO(CY8CTMG110_DRIVER_NAME_EXT, CY8CTMG110_I2C_ADDR_EXT), | ||
783 | + .irq = CY8CTMG110_IRQ_PIN_GPIO_EXT | ||
784 | + }, | ||
785 | +}; | ||
786 | + | ||
787 | + | ||
788 | +static int __init koski_i2c_init(void) | ||
789 | +{ | ||
790 | + printk("init koski board\n"); | ||
791 | + | ||
792 | +#ifdef MOORESTOWN_CDK | ||
793 | + /*init koski i2c*/ | ||
794 | + i2c_register_board_info(1, koski_i2c_board_info2, | ||
795 | + ARRAY_SIZE(koski_i2c_board_info2)); | ||
796 | +#else | ||
797 | + /*init koski i2c*/ | ||
798 | + i2c_register_board_info(0, koski_i2c_board_info2, | ||
799 | + ARRAY_SIZE(koski_i2c_board_info2)); | ||
800 | +#endif | ||
801 | + return 0; | ||
802 | +} | ||
803 | + | ||
804 | +module_init(koski_i2c_init); | ||
805 | + | ||
806 | +MODULE_AUTHOR("Samuli Konttila <samuli.konttila@aavamobile.com>"); | ||
807 | +MODULE_DESCRIPTION("cy8ctmg110 TouchScreen Driver"); | ||
808 | +MODULE_LICENSE("GPL v2"); | ||
809 | + | ||
810 | + | ||
811 | +// Aava access from sysfs begin | ||
812 | +static ssize_t aava_query_fw_info_func(struct class *class, char *buf) | ||
813 | +{ | ||
814 | + ssize_t status; | ||
815 | + int i = 0; | ||
816 | + unsigned char mrst_fw_ver_info[16]; | ||
817 | + | ||
818 | + printk("!!! aava_query_fw_info_func() ENTER\n"); | ||
819 | + | ||
820 | + status = mrst_get_firmware_version(mrst_fw_ver_info); | ||
821 | + for (i = 0; i < 16; i++){ | ||
822 | + printk("%x\n", mrst_fw_ver_info[i]); | ||
823 | + buf[i] = mrst_fw_ver_info[i]; | ||
824 | + } | ||
825 | + | ||
826 | + return 16; | ||
827 | +} | ||
828 | + | ||
829 | +static ssize_t aava_enable_touch_traces_func(struct class *class, \ | ||
830 | + const char *buf, size_t len) | ||
831 | +{ | ||
832 | + ssize_t status; | ||
833 | + unsigned long value; | ||
834 | + | ||
835 | + status = strict_strtoul(buf, 0, &value); | ||
836 | + printk("!!! aava_enable_touch_traces_func() = %d\n", (int)value); | ||
837 | + | ||
838 | + g_y_trace_coord = value; | ||
839 | + | ||
840 | + return len; | ||
841 | +} | ||
842 | + | ||
843 | +static struct class_attribute aava_class_attrs[] = { | ||
844 | + __ATTR(aava_query_fw_info, 0444, aava_query_fw_info_func, NULL), | ||
845 | + __ATTR(aava_enable_touch_traces, 0200, NULL, aava_enable_touch_traces_func), | ||
846 | + __ATTR_NULL, | ||
847 | +}; | ||
848 | + | ||
849 | +static struct class aava_class = { | ||
850 | + .name = "aava", | ||
851 | + .owner = THIS_MODULE, | ||
852 | + | ||
853 | + .class_attrs = aava_class_attrs, | ||
854 | +}; | ||
855 | + | ||
856 | +static int __init aava_sysfs_init(void) | ||
857 | +{ | ||
858 | + int status; | ||
859 | + | ||
860 | + status = class_register(&aava_class); | ||
861 | + if (status < 0) | ||
862 | + return status; | ||
863 | + | ||
864 | + return status; | ||
865 | +} | ||
866 | +postcore_initcall(aava_sysfs_init); | ||
867 | +// Aava access from sysfs end | ||
868 | -- | ||
869 | 1.6.2.2 | ||
870 | |||