diff options
author | Christopher Kenna <cjk@cs.unc.edu> | 2012-09-28 13:46:28 -0400 |
---|---|---|
committer | Christopher Kenna <cjk@cs.unc.edu> | 2012-09-28 14:50:15 -0400 |
commit | daa22703f14c007e93b464c45fa60019a36f546d (patch) | |
tree | a1a130b6e128dc9d57c35c026977e1b4953105e1 /drivers/input | |
parent | 5aa287dcf1b5879aa0150b0511833c52885f5b4c (diff) |
Apply k4412 kernel from HardKernel for ODROID-X.
Diffstat (limited to 'drivers/input')
37 files changed, 8808 insertions, 20 deletions
diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig index 23e82e46656..c0e639c1b17 100644 --- a/drivers/input/Kconfig +++ b/drivers/input/Kconfig | |||
@@ -161,6 +161,15 @@ config INPUT_APMPOWER | |||
161 | To compile this driver as a module, choose M here: the | 161 | To compile this driver as a module, choose M here: the |
162 | module will be called apm-power. | 162 | module will be called apm-power. |
163 | 163 | ||
164 | config INPUT_KEYRESET | ||
165 | tristate "Reset key" | ||
166 | depends on INPUT | ||
167 | ---help--- | ||
168 | Say Y here if you want to reboot when some keys are pressed; | ||
169 | |||
170 | To compile this driver as a module, choose M here: the | ||
171 | module will be called keyreset. | ||
172 | |||
164 | comment "Input Device Drivers" | 173 | comment "Input Device Drivers" |
165 | 174 | ||
166 | source "drivers/input/keyboard/Kconfig" | 175 | source "drivers/input/keyboard/Kconfig" |
diff --git a/drivers/input/Makefile b/drivers/input/Makefile index 0c789490e0b..5d4593d3101 100644 --- a/drivers/input/Makefile +++ b/drivers/input/Makefile | |||
@@ -24,3 +24,4 @@ obj-$(CONFIG_INPUT_TOUCHSCREEN) += touchscreen/ | |||
24 | obj-$(CONFIG_INPUT_MISC) += misc/ | 24 | obj-$(CONFIG_INPUT_MISC) += misc/ |
25 | 25 | ||
26 | obj-$(CONFIG_INPUT_APMPOWER) += apm-power.o | 26 | obj-$(CONFIG_INPUT_APMPOWER) += apm-power.o |
27 | obj-$(CONFIG_INPUT_KEYRESET) += keyreset.o | ||
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index 4cf25347b01..5c5f9db2807 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/input.h> | 23 | #include <linux/input.h> |
24 | #include <linux/major.h> | 24 | #include <linux/major.h> |
25 | #include <linux/device.h> | 25 | #include <linux/device.h> |
26 | #include <linux/wakelock.h> | ||
26 | #include "input-compat.h" | 27 | #include "input-compat.h" |
27 | 28 | ||
28 | struct evdev { | 29 | struct evdev { |
@@ -43,6 +44,8 @@ struct evdev_client { | |||
43 | unsigned int tail; | 44 | unsigned int tail; |
44 | unsigned int packet_head; /* [future] position of the first element of next packet */ | 45 | unsigned int packet_head; /* [future] position of the first element of next packet */ |
45 | spinlock_t buffer_lock; /* protects access to buffer, head and tail */ | 46 | spinlock_t buffer_lock; /* protects access to buffer, head and tail */ |
47 | struct wake_lock wake_lock; | ||
48 | char name[28]; | ||
46 | struct fasync_struct *fasync; | 49 | struct fasync_struct *fasync; |
47 | struct evdev *evdev; | 50 | struct evdev *evdev; |
48 | struct list_head node; | 51 | struct list_head node; |
@@ -59,6 +62,7 @@ static void evdev_pass_event(struct evdev_client *client, | |||
59 | /* Interrupts are disabled, just acquire the lock. */ | 62 | /* Interrupts are disabled, just acquire the lock. */ |
60 | spin_lock(&client->buffer_lock); | 63 | spin_lock(&client->buffer_lock); |
61 | 64 | ||
65 | wake_lock_timeout(&client->wake_lock, 5 * HZ); | ||
62 | client->buffer[client->head++] = *event; | 66 | client->buffer[client->head++] = *event; |
63 | client->head &= client->bufsize - 1; | 67 | client->head &= client->bufsize - 1; |
64 | 68 | ||
@@ -94,8 +98,11 @@ static void evdev_event(struct input_handle *handle, | |||
94 | struct evdev *evdev = handle->private; | 98 | struct evdev *evdev = handle->private; |
95 | struct evdev_client *client; | 99 | struct evdev_client *client; |
96 | struct input_event event; | 100 | struct input_event event; |
101 | struct timespec ts; | ||
97 | 102 | ||
98 | do_gettimeofday(&event.time); | 103 | ktime_get_ts(&ts); |
104 | event.time.tv_sec = ts.tv_sec; | ||
105 | event.time.tv_usec = ts.tv_nsec / NSEC_PER_USEC; | ||
99 | event.type = type; | 106 | event.type = type; |
100 | event.code = code; | 107 | event.code = code; |
101 | event.value = value; | 108 | event.value = value; |
@@ -255,6 +262,7 @@ static int evdev_release(struct inode *inode, struct file *file) | |||
255 | mutex_unlock(&evdev->mutex); | 262 | mutex_unlock(&evdev->mutex); |
256 | 263 | ||
257 | evdev_detach_client(evdev, client); | 264 | evdev_detach_client(evdev, client); |
265 | wake_lock_destroy(&client->wake_lock); | ||
258 | kfree(client); | 266 | kfree(client); |
259 | 267 | ||
260 | evdev_close_device(evdev); | 268 | evdev_close_device(evdev); |
@@ -306,6 +314,9 @@ static int evdev_open(struct inode *inode, struct file *file) | |||
306 | 314 | ||
307 | client->bufsize = bufsize; | 315 | client->bufsize = bufsize; |
308 | spin_lock_init(&client->buffer_lock); | 316 | spin_lock_init(&client->buffer_lock); |
317 | snprintf(client->name, sizeof(client->name), "%s-%d", | ||
318 | dev_name(&evdev->dev), task_tgid_vnr(current)); | ||
319 | wake_lock_init(&client->wake_lock, WAKE_LOCK_SUSPEND, client->name); | ||
309 | client->evdev = evdev; | 320 | client->evdev = evdev; |
310 | evdev_attach_client(evdev, client); | 321 | evdev_attach_client(evdev, client); |
311 | 322 | ||
@@ -320,6 +331,7 @@ static int evdev_open(struct inode *inode, struct file *file) | |||
320 | 331 | ||
321 | err_free_client: | 332 | err_free_client: |
322 | evdev_detach_client(evdev, client); | 333 | evdev_detach_client(evdev, client); |
334 | wake_lock_destroy(&client->wake_lock); | ||
323 | kfree(client); | 335 | kfree(client); |
324 | err_put_evdev: | 336 | err_put_evdev: |
325 | put_device(&evdev->dev); | 337 | put_device(&evdev->dev); |
@@ -369,10 +381,12 @@ static int evdev_fetch_next_event(struct evdev_client *client, | |||
369 | 381 | ||
370 | spin_lock_irq(&client->buffer_lock); | 382 | spin_lock_irq(&client->buffer_lock); |
371 | 383 | ||
372 | have_event = client->head != client->tail; | 384 | have_event = client->packet_head != client->tail; |
373 | if (have_event) { | 385 | if (have_event) { |
374 | *event = client->buffer[client->tail++]; | 386 | *event = client->buffer[client->tail++]; |
375 | client->tail &= client->bufsize - 1; | 387 | client->tail &= client->bufsize - 1; |
388 | if (client->head == client->tail) | ||
389 | wake_unlock(&client->wake_lock); | ||
376 | } | 390 | } |
377 | 391 | ||
378 | spin_unlock_irq(&client->buffer_lock); | 392 | spin_unlock_irq(&client->buffer_lock); |
@@ -391,14 +405,12 @@ static ssize_t evdev_read(struct file *file, char __user *buffer, | |||
391 | if (count < input_event_size()) | 405 | if (count < input_event_size()) |
392 | return -EINVAL; | 406 | return -EINVAL; |
393 | 407 | ||
394 | if (client->packet_head == client->tail && evdev->exist && | 408 | if (!(file->f_flags & O_NONBLOCK)) { |
395 | (file->f_flags & O_NONBLOCK)) | 409 | retval = wait_event_interruptible(evdev->wait, |
396 | return -EAGAIN; | 410 | client->packet_head != client->tail || !evdev->exist); |
397 | 411 | if (retval) | |
398 | retval = wait_event_interruptible(evdev->wait, | 412 | return retval; |
399 | client->packet_head != client->tail || !evdev->exist); | 413 | } |
400 | if (retval) | ||
401 | return retval; | ||
402 | 414 | ||
403 | if (!evdev->exist) | 415 | if (!evdev->exist) |
404 | return -ENODEV; | 416 | return -ENODEV; |
@@ -412,6 +424,8 @@ static ssize_t evdev_read(struct file *file, char __user *buffer, | |||
412 | retval += input_event_size(); | 424 | retval += input_event_size(); |
413 | } | 425 | } |
414 | 426 | ||
427 | if (retval == 0 && file->f_flags & O_NONBLOCK) | ||
428 | retval = -EAGAIN; | ||
415 | return retval; | 429 | return retval; |
416 | } | 430 | } |
417 | 431 | ||
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index b4dee9d5a05..2d2201a3f5f 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig | |||
@@ -563,4 +563,10 @@ config KEYBOARD_W90P910 | |||
563 | To compile this driver as a module, choose M here: the | 563 | To compile this driver as a module, choose M here: the |
564 | module will be called w90p910_keypad. | 564 | module will be called w90p910_keypad. |
565 | 565 | ||
566 | config KEYBOARD_ODROID | ||
567 | bool "ODROID-Q, ODROID-A4 Exynos DEV Keypad support" | ||
568 | help | ||
569 | Say Y here to enable the gpio keypad on evaluation board | ||
570 | based on ODROID-EXYNOS. | ||
571 | |||
566 | endif | 572 | endif |
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile index ddde0fd476f..64700d7899a 100644 --- a/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile | |||
@@ -51,3 +51,4 @@ obj-$(CONFIG_KEYBOARD_TNETV107X) += tnetv107x-keypad.o | |||
51 | obj-$(CONFIG_KEYBOARD_TWL4030) += twl4030_keypad.o | 51 | obj-$(CONFIG_KEYBOARD_TWL4030) += twl4030_keypad.o |
52 | obj-$(CONFIG_KEYBOARD_XTKBD) += xtkbd.o | 52 | obj-$(CONFIG_KEYBOARD_XTKBD) += xtkbd.o |
53 | obj-$(CONFIG_KEYBOARD_W90P910) += w90p910_keypad.o | 53 | obj-$(CONFIG_KEYBOARD_W90P910) += w90p910_keypad.o |
54 | obj-$(CONFIG_KEYBOARD_ODROID) += odroid-keypad.o | ||
diff --git a/drivers/input/keyboard/odroid-keypad.c b/drivers/input/keyboard/odroid-keypad.c new file mode 100644 index 00000000000..b4fdc4129cb --- /dev/null +++ b/drivers/input/keyboard/odroid-keypad.c | |||
@@ -0,0 +1,575 @@ | |||
1 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
2 | /* | ||
3 | * | ||
4 | * ODROID Dev Board keypad driver (charles.park) | ||
5 | * | ||
6 | */ | ||
7 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
8 | #include <linux/module.h> | ||
9 | #include <linux/kernel.h> | ||
10 | #include <linux/init.h> | ||
11 | #include <linux/interrupt.h> | ||
12 | #include <linux/input.h> | ||
13 | #include <linux/platform_device.h> | ||
14 | #include <linux/clk.h> | ||
15 | #include <linux/hrtimer.h> | ||
16 | #include <linux/slab.h> | ||
17 | |||
18 | #include <linux/gpio.h> | ||
19 | #include <linux/delay.h> | ||
20 | #include <asm/io.h> | ||
21 | #include <plat/gpio-cfg.h> | ||
22 | #include <mach/regs-gpio.h> | ||
23 | #include <mach/regs-pmu.h> | ||
24 | |||
25 | // Debug message enable flag | ||
26 | #define DEBUG_MSG | ||
27 | #define DEBUG_PM_MSG | ||
28 | |||
29 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
30 | #include "odroid-keypad.h" | ||
31 | |||
32 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
33 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
34 | static void __exit odroid_keypad_exit (void); | ||
35 | static int __init odroid_keypad_init (void); | ||
36 | static int __devexit odroid_keypad_remove (struct platform_device *pdev); | ||
37 | static int __devinit odroid_keypad_probe (struct platform_device *pdev); | ||
38 | static void odroid_keypad_config (odroid_keypad_t *keypad); | ||
39 | static int odroid_keypad_suspend (struct platform_device *pdev, pm_message_t state); | ||
40 | static int odroid_keypad_resume (struct platform_device *pdev); | ||
41 | static void odroid_keypad_release_device(struct device *dev); | ||
42 | static void odroid_keypad_close (struct input_dev *dev); | ||
43 | static int odroid_keypad_open (struct input_dev *dev); | ||
44 | static void odroid_keypad_control (odroid_keypad_t *keypad); | ||
45 | static int odroid_keypad_get_data (void); | ||
46 | static void generate_keycode (odroid_keypad_t *keypad, unsigned short prev_key, unsigned short cur_key, int *key_table); | ||
47 | |||
48 | static enum hrtimer_restart odroid_keypad_timer (struct hrtimer *timer); | ||
49 | static enum hrtimer_restart odroid_poweroff_timer (struct hrtimer *timer); | ||
50 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
51 | static struct platform_driver odroid_platform_device_driver = { | ||
52 | .probe = odroid_keypad_probe, | ||
53 | .remove = odroid_keypad_remove, | ||
54 | .suspend = odroid_keypad_suspend, | ||
55 | .resume = odroid_keypad_resume, | ||
56 | .driver = { | ||
57 | .owner = THIS_MODULE, | ||
58 | .name = DEVICE_NAME, | ||
59 | }, | ||
60 | }; | ||
61 | |||
62 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
63 | static struct platform_device odroid_platform_device = { | ||
64 | .name = DEVICE_NAME, | ||
65 | .id = -1, | ||
66 | .num_resources = 0, | ||
67 | .dev = { | ||
68 | .release = odroid_keypad_release_device, | ||
69 | }, | ||
70 | }; | ||
71 | |||
72 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
73 | module_init(odroid_keypad_init); | ||
74 | module_exit(odroid_keypad_exit); | ||
75 | |||
76 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
77 | MODULE_AUTHOR("Hard-Kernel"); | ||
78 | MODULE_LICENSE("GPL"); | ||
79 | MODULE_DESCRIPTION("Keypad interface for ODROID-Dev board"); | ||
80 | |||
81 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
82 | // Control GPIO Define | ||
83 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
84 | // GPIO Index Define | ||
85 | enum { | ||
86 | // KEY CONTROL | ||
87 | KEYPAD_POWER, | ||
88 | #if !defined(CONFIG_BOARD_ODROID_X) | ||
89 | #if defined(CONFIG_FB_S5P_S6E8AA1) | ||
90 | KEYPAD_MODE, | ||
91 | KEYPAD_PLAYPAUSE, | ||
92 | #else | ||
93 | KEYPAD_VOLUME_UP, | ||
94 | KEYPAD_VOLUME_DOWN, | ||
95 | #endif | ||
96 | KEYPAD_POWER_LED, | ||
97 | #endif // #if !defined(CONFIG_BOARD_ODROID_X) | ||
98 | GPIO_INDEX_END | ||
99 | }; | ||
100 | |||
101 | static struct { | ||
102 | int gpio_index; // Control Index | ||
103 | int gpio; // GPIO Number | ||
104 | char *name; // GPIO Name == sysfs attr name (must) | ||
105 | bool output; // 1 = Output, 0 = Input | ||
106 | int value; // Default Value(only for output) | ||
107 | int pud; // Pull up/down register setting : S3C_GPIO_PULL_DOWN, UP, NONE | ||
108 | } sControlGpios[] = { | ||
109 | { KEYPAD_POWER, EXYNOS4_GPX1(3), "KEY POWER" , 0, 0, S3C_GPIO_PULL_NONE}, | ||
110 | #if !defined(CONFIG_BOARD_ODROID_X) | ||
111 | #if defined(CONFIG_FB_S5P_S6E8AA1) | ||
112 | { KEYPAD_MODE, EXYNOS4_GPX1(7), "KEY MODE" , 0, 0, S3C_GPIO_PULL_DOWN}, | ||
113 | { KEYPAD_PLAYPAUSE, EXYNOS4_GPX2(0), "KEY PLAYPAUSE" , 0, 0, S3C_GPIO_PULL_DOWN}, | ||
114 | #else | ||
115 | { KEYPAD_VOLUME_UP, EXYNOS4_GPX1(7), "KEY VOLUME UP" , 0, 0, S3C_GPIO_PULL_DOWN}, | ||
116 | { KEYPAD_VOLUME_DOWN, EXYNOS4_GPX2(0), "KEY VOLUME DOWN" , 0, 0, S3C_GPIO_PULL_DOWN}, | ||
117 | #endif | ||
118 | { KEYPAD_POWER_LED, EXYNOS4_GPA1(0), "POWER LED" , 1, 1, S3C_GPIO_PULL_NONE}, | ||
119 | #endif // #if !defined(CONFIG_BOARD_ODROID_X) | ||
120 | }; | ||
121 | |||
122 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
123 | #define MAX_KEYCODE_CNT 3 | ||
124 | |||
125 | int Keycode[MAX_KEYCODE_CNT] = { | ||
126 | KEY_POWER, | ||
127 | #if !defined(CONFIG_BOARD_ODROID_X) | ||
128 | #if defined(CONFIG_FB_S5P_S6E8AA1) | ||
129 | KEY_0, | ||
130 | KEY_1, | ||
131 | #else | ||
132 | KEY_VOLUMEUP, | ||
133 | KEY_VOLUMEDOWN, | ||
134 | #endif | ||
135 | #endif // #if !defined(CONFIG_BOARD_ODROID_X) | ||
136 | }; | ||
137 | |||
138 | #if defined(DEBUG_MSG) | ||
139 | const char KeyMapStr[MAX_KEYCODE_CNT][20] = { | ||
140 | "KEY_POWER\n", | ||
141 | #if !defined(CONFIG_BOARD_ODROID_X) | ||
142 | #if defined(CONFIG_FB_S5P_S6E8AA1) | ||
143 | "KEY_MODE\n", | ||
144 | "KEY_PLAYPAUSE\n", | ||
145 | #else | ||
146 | "KEY_VOLUME_UP\n", | ||
147 | "KEY_VOLUME_DOWN\n", | ||
148 | #endif | ||
149 | #endif // #if !defined(CONFIG_BOARD_ODROID_X) | ||
150 | }; | ||
151 | #endif // DEBUG_MSG | ||
152 | |||
153 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
154 | static enum hrtimer_restart odroid_poweroff_timer(struct hrtimer *timer) | ||
155 | { | ||
156 | #if defined(CONFIG_BOARD_ODROID_X) | ||
157 | odroid_keypad_t *keypad = container_of(timer, odroid_keypad_t, poweroff_timer); | ||
158 | #endif | ||
159 | |||
160 | #if !defined(CONFIG_BOARD_ODROID_X) | ||
161 | gpio_direction_output (sControlGpios[KEYPAD_POWER_LED].gpio, 0); // POWER LED OFF | ||
162 | #endif | ||
163 | |||
164 | #if defined(CONFIG_BOARD_ODROID_X) | ||
165 | hrtimer_cancel(&keypad->led_timer); | ||
166 | gpio_direction_output (LED_STATUS_PORT, 1); | ||
167 | #endif | ||
168 | printk(KERN_EMERG "%s : setting GPIO_PDA_PS_HOLD low.\n", __func__); | ||
169 | (*(unsigned long *)(S5P_PMUREG(0x330C))) = 0x5200; | ||
170 | return HRTIMER_NORESTART; | ||
171 | } | ||
172 | |||
173 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
174 | #if defined(CONFIG_FB_S5P_S6E8AA1) | ||
175 | static enum hrtimer_restart odroid_long_timer(struct hrtimer *timer) | ||
176 | { | ||
177 | odroid_keypad_t *keypad = container_of(timer, odroid_keypad_t, long_timer); | ||
178 | |||
179 | static unsigned char status = false; | ||
180 | |||
181 | status = !status; | ||
182 | |||
183 | if(status) input_report_switch(keypad->input, SW_LID, 1); | ||
184 | else input_report_switch(keypad->input, SW_LID, 0); | ||
185 | input_sync(keypad->input); | ||
186 | |||
187 | keypad->long_status = false; | ||
188 | |||
189 | #if defined(DEBUG_MSG) | ||
190 | printk("%s : slide notifiy send (%d)\n", __func__, status); | ||
191 | #endif | ||
192 | |||
193 | return HRTIMER_NORESTART; | ||
194 | } | ||
195 | #endif | ||
196 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
197 | #if defined(CONFIG_BOARD_ODROID_X) | ||
198 | static enum hrtimer_restart odroid_led_timer(struct hrtimer *timer) | ||
199 | { | ||
200 | odroid_keypad_t *keypad = container_of(timer, odroid_keypad_t, led_timer); | ||
201 | |||
202 | static unsigned char status = false; | ||
203 | |||
204 | status = !status; | ||
205 | |||
206 | gpio_direction_output (LED_STATUS_PORT, !status); | ||
207 | |||
208 | hrtimer_start(&keypad->led_timer, ktime_set(LED_STATUS_PERIOD, 0), HRTIMER_MODE_REL); | ||
209 | |||
210 | return HRTIMER_NORESTART; | ||
211 | } | ||
212 | #endif | ||
213 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
214 | static void generate_keycode(odroid_keypad_t *keypad, unsigned short prev_key, unsigned short cur_key, int *key_table) | ||
215 | { | ||
216 | unsigned short press_key, release_key, i; | ||
217 | |||
218 | press_key = (cur_key ^ prev_key) & cur_key; | ||
219 | release_key = (cur_key ^ prev_key) & prev_key; | ||
220 | |||
221 | i = 0; | ||
222 | while(press_key) { | ||
223 | if(press_key & 0x01) { | ||
224 | #if defined(CONFIG_FB_S5P_S6E8AA1) | ||
225 | if(key_table[i] == KEY_0) { | ||
226 | keypad->long_status = true; | ||
227 | hrtimer_start(&keypad->long_timer, ktime_set(LONGKEY_CHECK_PERIOD, 0), HRTIMER_MODE_REL); | ||
228 | } | ||
229 | else if(key_table[i] == KEY_1) { | ||
230 | keypad->pause = keypad->pause ? 0 : 1; | ||
231 | |||
232 | if(keypad->pause) | ||
233 | input_report_key(keypad->input, key_table[i], KEY_PRESS); | ||
234 | else | ||
235 | input_report_key(keypad->input, KEY_2, KEY_PRESS); | ||
236 | } | ||
237 | else | ||
238 | #endif | ||
239 | input_report_key(keypad->input, key_table[i], KEY_PRESS); | ||
240 | |||
241 | // POWER OFF PRESS | ||
242 | if(key_table[i] == KEY_POWER) | ||
243 | hrtimer_start(&keypad->poweroff_timer, ktime_set(POWEROFF_CHECK_PERIOD, 0), HRTIMER_MODE_REL); | ||
244 | } | ||
245 | i++; press_key >>= 1; | ||
246 | } | ||
247 | |||
248 | i = 0; | ||
249 | while(release_key) { | ||
250 | if(release_key & 0x01) { | ||
251 | |||
252 | #if defined(CONFIG_FB_S5P_S6E8AA1) | ||
253 | if(key_table[i] == KEY_0) { | ||
254 | if(keypad->long_status) { | ||
255 | keypad->long_status = true; | ||
256 | hrtimer_cancel(&keypad->long_timer); | ||
257 | input_report_key(keypad->input, key_table[i], KEY_PRESS); | ||
258 | input_report_key(keypad->input, key_table[i], KEY_RELEASE); | ||
259 | } | ||
260 | } | ||
261 | else if(key_table[i] == KEY_1) { | ||
262 | if(keypad->pause) | ||
263 | input_report_key(keypad->input, key_table[i], KEY_RELEASE); | ||
264 | else | ||
265 | input_report_key(keypad->input, KEY_2, KEY_RELEASE); | ||
266 | } | ||
267 | else | ||
268 | #endif | ||
269 | input_report_key(keypad->input, key_table[i], KEY_RELEASE); | ||
270 | |||
271 | // POWER OFF (RELEASE) | ||
272 | if(key_table[i] == KEY_POWER) | ||
273 | hrtimer_cancel(&keypad->poweroff_timer); | ||
274 | } | ||
275 | i++; release_key >>= 1; | ||
276 | } | ||
277 | } | ||
278 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
279 | #if defined(DEBUG_MSG) | ||
280 | static void debug_keycode_printf(unsigned short prev_key, unsigned short cur_key, const char *key_table) | ||
281 | { | ||
282 | unsigned short press_key, release_key, i; | ||
283 | |||
284 | press_key = (cur_key ^ prev_key) & cur_key; | ||
285 | release_key = (cur_key ^ prev_key) & prev_key; | ||
286 | |||
287 | i = 0; | ||
288 | while(press_key) { | ||
289 | if(press_key & 0x01) printk("PRESS KEY : %s", (char *)&key_table[i * 20]); | ||
290 | i++; press_key >>= 1; | ||
291 | } | ||
292 | |||
293 | i = 0; | ||
294 | while(release_key) { | ||
295 | if(release_key & 0x01) printk("RELEASE KEY : %s", (char *)&key_table[i * 20]); | ||
296 | i++; release_key >>= 1; | ||
297 | } | ||
298 | } | ||
299 | #endif | ||
300 | |||
301 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
302 | static int odroid_keypad_get_data(void) | ||
303 | { | ||
304 | int key_data = 0; | ||
305 | |||
306 | key_data |= (gpio_get_value(sControlGpios[KEYPAD_POWER].gpio) ? 0 : 0x01); | ||
307 | #if !defined(CONFIG_BOARD_ODROID_X) | ||
308 | #if defined(CONFIG_FB_S5P_S6E8AA1) | ||
309 | key_data |= (gpio_get_value(sControlGpios[KEYPAD_MODE].gpio) ? 0x02 : 0); | ||
310 | key_data |= (gpio_get_value(sControlGpios[KEYPAD_PLAYPAUSE].gpio) ? 0x04 : 0); | ||
311 | #else | ||
312 | key_data |= (gpio_get_value(sControlGpios[KEYPAD_VOLUME_UP].gpio) ? 0x02 : 0); | ||
313 | key_data |= (gpio_get_value(sControlGpios[KEYPAD_VOLUME_DOWN].gpio) ? 0x04 : 0); | ||
314 | #endif | ||
315 | #endif // #if !defined(CONFIG_BOARD_ODROID_X) | ||
316 | return key_data; | ||
317 | } | ||
318 | |||
319 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
320 | static void odroid_keypad_control(odroid_keypad_t *keypad) | ||
321 | { | ||
322 | static unsigned short prev_keypad_data = 0, cur_keypad_data = 0; | ||
323 | |||
324 | // key data process | ||
325 | cur_keypad_data = odroid_keypad_get_data(); | ||
326 | |||
327 | if(prev_keypad_data != cur_keypad_data) { | ||
328 | |||
329 | generate_keycode(keypad, prev_keypad_data, cur_keypad_data, &Keycode[0]); | ||
330 | |||
331 | #if defined(DEBUG_MSG) | ||
332 | debug_keycode_printf(prev_keypad_data, cur_keypad_data, &KeyMapStr[0][0]); | ||
333 | #endif | ||
334 | |||
335 | prev_keypad_data = cur_keypad_data; | ||
336 | |||
337 | input_sync(keypad->input); | ||
338 | } | ||
339 | } | ||
340 | |||
341 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
342 | static enum hrtimer_restart odroid_keypad_timer(struct hrtimer *timer) | ||
343 | { | ||
344 | odroid_keypad_t *keypad = container_of(timer, odroid_keypad_t, timer); | ||
345 | |||
346 | odroid_keypad_control(keypad); | ||
347 | hrtimer_start(&keypad->timer, ktime_set(0, KEYPAD_TIMER_PERIOD), HRTIMER_MODE_REL); | ||
348 | |||
349 | return HRTIMER_NORESTART; | ||
350 | } | ||
351 | |||
352 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
353 | static int odroid_keypad_open(struct input_dev *dev) | ||
354 | { | ||
355 | #if defined(DEBUG_MSG) | ||
356 | printk("%s\n", __FUNCTION__); | ||
357 | #endif | ||
358 | |||
359 | return 0; | ||
360 | } | ||
361 | |||
362 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
363 | static void odroid_keypad_close(struct input_dev *dev) | ||
364 | { | ||
365 | #if defined(DEBUG_MSG) | ||
366 | printk("%s\n", __FUNCTION__); | ||
367 | #endif | ||
368 | } | ||
369 | |||
370 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
371 | static void odroid_keypad_release_device(struct device *dev) | ||
372 | { | ||
373 | #if defined(DEBUG_MSG) | ||
374 | printk("%s\n", __FUNCTION__); | ||
375 | #endif | ||
376 | } | ||
377 | |||
378 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
379 | static int odroid_keypad_resume(struct platform_device *pdev) | ||
380 | { | ||
381 | odroid_keypad_t *keypad = dev_get_drvdata(&pdev->dev); | ||
382 | |||
383 | #if defined(DEBUG_PM_MSG) | ||
384 | printk("%s\n", __FUNCTION__); | ||
385 | #endif | ||
386 | |||
387 | hrtimer_start(&keypad->timer, ktime_set(0, KEYPAD_TIMER_PERIOD), HRTIMER_MODE_REL); | ||
388 | |||
389 | return 0; | ||
390 | } | ||
391 | |||
392 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
393 | static int odroid_keypad_suspend(struct platform_device *pdev, pm_message_t state) | ||
394 | { | ||
395 | odroid_keypad_t *keypad = dev_get_drvdata(&pdev->dev); | ||
396 | |||
397 | #if defined(DEBUG_PM_MSG) | ||
398 | printk("%s\n", __FUNCTION__); | ||
399 | #endif | ||
400 | |||
401 | hrtimer_cancel(&keypad->timer); | ||
402 | |||
403 | return 0; | ||
404 | } | ||
405 | |||
406 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
407 | static void odroid_keypad_config(odroid_keypad_t *keypad) | ||
408 | { | ||
409 | int i; | ||
410 | |||
411 | // Control GPIO Init | ||
412 | for (i = 0; i < ARRAY_SIZE(sControlGpios); i++) { | ||
413 | if(gpio_request(sControlGpios[i].gpio, sControlGpios[i].name)) { | ||
414 | printk("--------------------------------------------\n"); | ||
415 | printk("%s : %s gpio reqest err!\n", __FUNCTION__, sControlGpios[i].name); | ||
416 | printk("--------------------------------------------\n"); | ||
417 | } | ||
418 | else { | ||
419 | if(sControlGpios[i].output) gpio_direction_output (sControlGpios[i].gpio, sControlGpios[i].value); | ||
420 | else gpio_direction_input (sControlGpios[i].gpio); | ||
421 | |||
422 | s3c_gpio_setpull(sControlGpios[i].gpio, sControlGpios[i].pud); | ||
423 | } | ||
424 | } | ||
425 | |||
426 | hrtimer_start(&keypad->timer, ktime_set(0, KEYPAD_TIMER_PERIOD), HRTIMER_MODE_REL); | ||
427 | } | ||
428 | |||
429 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
430 | static int __devinit odroid_keypad_probe(struct platform_device *pdev) | ||
431 | { | ||
432 | int key, code; | ||
433 | odroid_keypad_t *keypad; | ||
434 | |||
435 | if(!(keypad = kzalloc(sizeof(*keypad), GFP_KERNEL))) return -ENOMEM; | ||
436 | |||
437 | dev_set_drvdata(&pdev->dev, keypad); | ||
438 | |||
439 | if(!(keypad->input = input_allocate_device())) goto err_free_input_mem; | ||
440 | |||
441 | snprintf(keypad->phys, sizeof(keypad->phys), "%s/input0", DEVICE_NAME); | ||
442 | |||
443 | keypad->input->name = DEVICE_NAME; | ||
444 | keypad->input->phys = keypad->phys; | ||
445 | keypad->input->id.bustype = BUS_HOST; | ||
446 | keypad->input->id.vendor = 0x16B4; | ||
447 | keypad->input->id.product = 0x0701; | ||
448 | keypad->input->id.version = 0x0001; | ||
449 | keypad->input->keycode = Keycode; | ||
450 | keypad->input->open = odroid_keypad_open; | ||
451 | keypad->input->close = odroid_keypad_close; | ||
452 | |||
453 | set_bit(EV_KEY, keypad->input->evbit); | ||
454 | |||
455 | #if defined(CONFIG_FB_S5P_S6E8AA1) | ||
456 | set_bit(EV_SW , keypad->input->evbit); | ||
457 | set_bit(SW_LID & SW_MAX, keypad->input->swbit); | ||
458 | #endif | ||
459 | |||
460 | for(key = 0; key < MAX_KEYCODE_CNT; key++){ | ||
461 | code = Keycode[key]; | ||
462 | if(code <= 0) continue; | ||
463 | set_bit(code & KEY_MAX, keypad->input->keybit); | ||
464 | } | ||
465 | #if defined(CONFIG_FB_S5P_S6E8AA1) | ||
466 | set_bit(KEY_2 & KEY_MAX, keypad->input->keybit); | ||
467 | #endif | ||
468 | if(input_register_device(keypad->input)) { | ||
469 | printk("--------------------------------------------------------\n"); | ||
470 | printk("%s input register device fail!!\n", DEVICE_NAME); | ||
471 | printk("--------------------------------------------------------\n"); | ||
472 | goto err_free_all; | ||
473 | } | ||
474 | |||
475 | hrtimer_init(&keypad->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); | ||
476 | keypad->timer.function = odroid_keypad_timer; | ||
477 | |||
478 | hrtimer_init(&keypad->poweroff_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); | ||
479 | keypad->poweroff_timer.function = odroid_poweroff_timer; | ||
480 | |||
481 | #if defined(CONFIG_FB_S5P_S6E8AA1) | ||
482 | hrtimer_init(&keypad->long_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); | ||
483 | keypad->long_timer.function = odroid_long_timer; | ||
484 | #endif | ||
485 | |||
486 | odroid_keypad_config(keypad); | ||
487 | |||
488 | #if defined(CONFIG_BOARD_ODROID_X) | ||
489 | if(gpio_request(LED_STATUS_PORT, LED_STATUS_PORT_NAME)) { | ||
490 | printk("%s : %s gpio reqest err!\n", __FUNCTION__, LED_STATUS_PORT_NAME); | ||
491 | } | ||
492 | else { | ||
493 | gpio_direction_output (LED_STATUS_PORT, 1); | ||
494 | s3c_gpio_setpull (LED_STATUS_PORT, S3C_GPIO_PULL_NONE); | ||
495 | } | ||
496 | |||
497 | hrtimer_init(&keypad->led_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); | ||
498 | keypad->led_timer.function = odroid_led_timer; | ||
499 | hrtimer_start(&keypad->led_timer, ktime_set(LED_STATUS_PERIOD, 0), HRTIMER_MODE_REL); | ||
500 | #endif | ||
501 | |||
502 | printk("--------------------------------------------------------\n"); | ||
503 | printk("%s driver initialized!! Ver 1.0\n", DEVICE_NAME); | ||
504 | printk("--------------------------------------------------------\n"); | ||
505 | |||
506 | return 0; | ||
507 | |||
508 | err_free_all: | ||
509 | input_free_device(keypad->input); | ||
510 | err_free_input_mem: | ||
511 | kfree(keypad); | ||
512 | return -ENODEV; | ||
513 | } | ||
514 | |||
515 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
516 | static int __devexit odroid_keypad_remove(struct platform_device *pdev) | ||
517 | { | ||
518 | int i; | ||
519 | odroid_keypad_t *keypad = dev_get_drvdata(&pdev->dev); | ||
520 | |||
521 | input_unregister_device(keypad->input); | ||
522 | |||
523 | hrtimer_cancel(&keypad->timer); | ||
524 | |||
525 | dev_set_drvdata(&pdev->dev, NULL); | ||
526 | |||
527 | for (i = 0; i < ARRAY_SIZE(sControlGpios); i++) gpio_free(sControlGpios[i].gpio); | ||
528 | |||
529 | #if defined(CONFIG_BOARD_ODROID_X) | ||
530 | gpio_free(LED_STATUS_PORT); | ||
531 | hrtimer_cancel(&keypad->led_timer); | ||
532 | #endif | ||
533 | |||
534 | #if defined(DEBUG_MSG) | ||
535 | printk("%s\n", __FUNCTION__); | ||
536 | #endif | ||
537 | |||
538 | kfree(keypad); | ||
539 | |||
540 | return 0; | ||
541 | } | ||
542 | |||
543 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
544 | static int __init odroid_keypad_init(void) | ||
545 | { | ||
546 | int ret = platform_driver_register(&odroid_platform_device_driver); | ||
547 | |||
548 | #if defined(DEBUG_MSG) | ||
549 | printk("%s\n", __FUNCTION__); | ||
550 | #endif | ||
551 | |||
552 | if(!ret) { | ||
553 | ret = platform_device_register(&odroid_platform_device); | ||
554 | |||
555 | #if defined(DEBUG_MSG) | ||
556 | printk("platform_driver_register %d \n", ret); | ||
557 | #endif | ||
558 | |||
559 | if(ret) platform_driver_unregister(&odroid_platform_device_driver); | ||
560 | } | ||
561 | return ret; | ||
562 | } | ||
563 | |||
564 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
565 | static void __exit odroid_keypad_exit(void) | ||
566 | { | ||
567 | #if defined(DEBUG_MSG) | ||
568 | printk("%s\n",__FUNCTION__); | ||
569 | #endif | ||
570 | |||
571 | platform_device_unregister(&odroid_platform_device); | ||
572 | platform_driver_unregister(&odroid_platform_device_driver); | ||
573 | } | ||
574 | |||
575 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
diff --git a/drivers/input/keyboard/odroid-keypad.h b/drivers/input/keyboard/odroid-keypad.h new file mode 100644 index 00000000000..31d126b46f4 --- /dev/null +++ b/drivers/input/keyboard/odroid-keypad.h | |||
@@ -0,0 +1,54 @@ | |||
1 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
2 | /* | ||
3 | * | ||
4 | * ODROID Dev Board key-pad header file (charles.park) | ||
5 | * | ||
6 | */ | ||
7 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
8 | #ifndef _ODROID_KEYPAD_H_ | ||
9 | #define _ODROID_KEYPAD_H_ | ||
10 | |||
11 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
12 | #define DEVICE_NAME "odroid-keypad" | ||
13 | |||
14 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
15 | #define KEY_PRESS 1 | ||
16 | #define KEY_RELEASE 0 | ||
17 | |||
18 | #define KEYPAD_TIMER_PERIOD 100000000 // ns : ktime_set(sec, nsec) | ||
19 | #define POWEROFF_CHECK_PERIOD 5 // sec : ktime_set(sec, nsec) | ||
20 | |||
21 | #if defined(CONFIG_FB_S5P_S6E8AA1) | ||
22 | #define LONGKEY_CHECK_PERIOD 3 | ||
23 | #endif | ||
24 | #if defined(CONFIG_BOARD_ODROID_X) | ||
25 | #define LED_STATUS_PERIOD 1 | ||
26 | #define LED_STATUS_PORT EXYNOS4_GPC1(0) | ||
27 | #define LED_STATUS_PORT_NAME "STATUS LED" | ||
28 | #endif | ||
29 | |||
30 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
31 | typedef struct odroid_keypad__t { | ||
32 | |||
33 | // keypad control | ||
34 | struct input_dev *input; // input driver | ||
35 | char phys[32]; | ||
36 | |||
37 | struct hrtimer timer; // keypad timer | ||
38 | struct hrtimer poweroff_timer; // force power off control | ||
39 | #if defined(CONFIG_FB_S5P_S6E8AA1) | ||
40 | char pause; | ||
41 | struct hrtimer long_timer; // long key support | ||
42 | unsigned char long_status; | ||
43 | #endif | ||
44 | |||
45 | #if defined(CONFIG_BOARD_ODROID_X) | ||
46 | struct hrtimer led_timer; // long key support | ||
47 | #endif | ||
48 | |||
49 | } odroid_keypad_t; | ||
50 | |||
51 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
52 | #endif /* _ODROID_KEYPAD_H_*/ | ||
53 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
54 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
diff --git a/drivers/input/keyreset.c b/drivers/input/keyreset.c new file mode 100644 index 00000000000..36208fe0baa --- /dev/null +++ b/drivers/input/keyreset.c | |||
@@ -0,0 +1,239 @@ | |||
1 | /* drivers/input/keyreset.c | ||
2 | * | ||
3 | * Copyright (C) 2008 Google, Inc. | ||
4 | * | ||
5 | * This software is licensed under the terms of the GNU General Public | ||
6 | * License version 2, as published by the Free Software Foundation, and | ||
7 | * may be copied, distributed, and modified under those terms. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | */ | ||
15 | |||
16 | #include <linux/input.h> | ||
17 | #include <linux/keyreset.h> | ||
18 | #include <linux/module.h> | ||
19 | #include <linux/platform_device.h> | ||
20 | #include <linux/reboot.h> | ||
21 | #include <linux/sched.h> | ||
22 | #include <linux/slab.h> | ||
23 | #include <linux/syscalls.h> | ||
24 | |||
25 | |||
26 | struct keyreset_state { | ||
27 | struct input_handler input_handler; | ||
28 | unsigned long keybit[BITS_TO_LONGS(KEY_CNT)]; | ||
29 | unsigned long upbit[BITS_TO_LONGS(KEY_CNT)]; | ||
30 | unsigned long key[BITS_TO_LONGS(KEY_CNT)]; | ||
31 | spinlock_t lock; | ||
32 | int key_down_target; | ||
33 | int key_down; | ||
34 | int key_up; | ||
35 | int restart_disabled; | ||
36 | int (*reset_fn)(void); | ||
37 | }; | ||
38 | |||
39 | int restart_requested; | ||
40 | static void deferred_restart(struct work_struct *dummy) | ||
41 | { | ||
42 | restart_requested = 2; | ||
43 | sys_sync(); | ||
44 | restart_requested = 3; | ||
45 | kernel_restart(NULL); | ||
46 | } | ||
47 | static DECLARE_WORK(restart_work, deferred_restart); | ||
48 | |||
49 | static void keyreset_event(struct input_handle *handle, unsigned int type, | ||
50 | unsigned int code, int value) | ||
51 | { | ||
52 | unsigned long flags; | ||
53 | struct keyreset_state *state = handle->private; | ||
54 | |||
55 | if (type != EV_KEY) | ||
56 | return; | ||
57 | |||
58 | if (code >= KEY_MAX) | ||
59 | return; | ||
60 | |||
61 | if (!test_bit(code, state->keybit)) | ||
62 | return; | ||
63 | |||
64 | spin_lock_irqsave(&state->lock, flags); | ||
65 | if (!test_bit(code, state->key) == !value) | ||
66 | goto done; | ||
67 | __change_bit(code, state->key); | ||
68 | if (test_bit(code, state->upbit)) { | ||
69 | if (value) { | ||
70 | state->restart_disabled = 1; | ||
71 | state->key_up++; | ||
72 | } else | ||
73 | state->key_up--; | ||
74 | } else { | ||
75 | if (value) | ||
76 | state->key_down++; | ||
77 | else | ||
78 | state->key_down--; | ||
79 | } | ||
80 | if (state->key_down == 0 && state->key_up == 0) | ||
81 | state->restart_disabled = 0; | ||
82 | |||
83 | pr_debug("reset key changed %d %d new state %d-%d-%d\n", code, value, | ||
84 | state->key_down, state->key_up, state->restart_disabled); | ||
85 | |||
86 | if (value && !state->restart_disabled && | ||
87 | state->key_down == state->key_down_target) { | ||
88 | state->restart_disabled = 1; | ||
89 | if (restart_requested) | ||
90 | panic("keyboard reset failed, %d", restart_requested); | ||
91 | if (state->reset_fn) { | ||
92 | restart_requested = state->reset_fn(); | ||
93 | } else { | ||
94 | pr_info("keyboard reset\n"); | ||
95 | schedule_work(&restart_work); | ||
96 | restart_requested = 1; | ||
97 | } | ||
98 | } | ||
99 | done: | ||
100 | spin_unlock_irqrestore(&state->lock, flags); | ||
101 | } | ||
102 | |||
103 | static int keyreset_connect(struct input_handler *handler, | ||
104 | struct input_dev *dev, | ||
105 | const struct input_device_id *id) | ||
106 | { | ||
107 | int i; | ||
108 | int ret; | ||
109 | struct input_handle *handle; | ||
110 | struct keyreset_state *state = | ||
111 | container_of(handler, struct keyreset_state, input_handler); | ||
112 | |||
113 | for (i = 0; i < KEY_MAX; i++) { | ||
114 | if (test_bit(i, state->keybit) && test_bit(i, dev->keybit)) | ||
115 | break; | ||
116 | } | ||
117 | if (i == KEY_MAX) | ||
118 | return -ENODEV; | ||
119 | |||
120 | handle = kzalloc(sizeof(*handle), GFP_KERNEL); | ||
121 | if (!handle) | ||
122 | return -ENOMEM; | ||
123 | |||
124 | handle->dev = dev; | ||
125 | handle->handler = handler; | ||
126 | handle->name = "keyreset"; | ||
127 | handle->private = state; | ||
128 | |||
129 | ret = input_register_handle(handle); | ||
130 | if (ret) | ||
131 | goto err_input_register_handle; | ||
132 | |||
133 | ret = input_open_device(handle); | ||
134 | if (ret) | ||
135 | goto err_input_open_device; | ||
136 | |||
137 | pr_info("using input dev %s for key reset\n", dev->name); | ||
138 | |||
139 | return 0; | ||
140 | |||
141 | err_input_open_device: | ||
142 | input_unregister_handle(handle); | ||
143 | err_input_register_handle: | ||
144 | kfree(handle); | ||
145 | return ret; | ||
146 | } | ||
147 | |||
148 | static void keyreset_disconnect(struct input_handle *handle) | ||
149 | { | ||
150 | input_close_device(handle); | ||
151 | input_unregister_handle(handle); | ||
152 | kfree(handle); | ||
153 | } | ||
154 | |||
155 | static const struct input_device_id keyreset_ids[] = { | ||
156 | { | ||
157 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT, | ||
158 | .evbit = { BIT_MASK(EV_KEY) }, | ||
159 | }, | ||
160 | { }, | ||
161 | }; | ||
162 | MODULE_DEVICE_TABLE(input, keyreset_ids); | ||
163 | |||
164 | static int keyreset_probe(struct platform_device *pdev) | ||
165 | { | ||
166 | int ret; | ||
167 | int key, *keyp; | ||
168 | struct keyreset_state *state; | ||
169 | struct keyreset_platform_data *pdata = pdev->dev.platform_data; | ||
170 | |||
171 | if (!pdata) | ||
172 | return -EINVAL; | ||
173 | |||
174 | state = kzalloc(sizeof(*state), GFP_KERNEL); | ||
175 | if (!state) | ||
176 | return -ENOMEM; | ||
177 | |||
178 | spin_lock_init(&state->lock); | ||
179 | keyp = pdata->keys_down; | ||
180 | while ((key = *keyp++)) { | ||
181 | if (key >= KEY_MAX) | ||
182 | continue; | ||
183 | state->key_down_target++; | ||
184 | __set_bit(key, state->keybit); | ||
185 | } | ||
186 | if (pdata->keys_up) { | ||
187 | keyp = pdata->keys_up; | ||
188 | while ((key = *keyp++)) { | ||
189 | if (key >= KEY_MAX) | ||
190 | continue; | ||
191 | __set_bit(key, state->keybit); | ||
192 | __set_bit(key, state->upbit); | ||
193 | } | ||
194 | } | ||
195 | |||
196 | if (pdata->reset_fn) | ||
197 | state->reset_fn = pdata->reset_fn; | ||
198 | |||
199 | state->input_handler.event = keyreset_event; | ||
200 | state->input_handler.connect = keyreset_connect; | ||
201 | state->input_handler.disconnect = keyreset_disconnect; | ||
202 | state->input_handler.name = KEYRESET_NAME; | ||
203 | state->input_handler.id_table = keyreset_ids; | ||
204 | ret = input_register_handler(&state->input_handler); | ||
205 | if (ret) { | ||
206 | kfree(state); | ||
207 | return ret; | ||
208 | } | ||
209 | platform_set_drvdata(pdev, state); | ||
210 | return 0; | ||
211 | } | ||
212 | |||
213 | int keyreset_remove(struct platform_device *pdev) | ||
214 | { | ||
215 | struct keyreset_state *state = platform_get_drvdata(pdev); | ||
216 | input_unregister_handler(&state->input_handler); | ||
217 | kfree(state); | ||
218 | return 0; | ||
219 | } | ||
220 | |||
221 | |||
222 | struct platform_driver keyreset_driver = { | ||
223 | .driver.name = KEYRESET_NAME, | ||
224 | .probe = keyreset_probe, | ||
225 | .remove = keyreset_remove, | ||
226 | }; | ||
227 | |||
228 | static int __init keyreset_init(void) | ||
229 | { | ||
230 | return platform_driver_register(&keyreset_driver); | ||
231 | } | ||
232 | |||
233 | static void __exit keyreset_exit(void) | ||
234 | { | ||
235 | return platform_driver_unregister(&keyreset_driver); | ||
236 | } | ||
237 | |||
238 | module_init(keyreset_init); | ||
239 | module_exit(keyreset_exit); | ||
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 45dc6aa62ba..e4571056464 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig | |||
@@ -193,6 +193,17 @@ config INPUT_ATI_REMOTE2 | |||
193 | To compile this driver as a module, choose M here: the module will be | 193 | To compile this driver as a module, choose M here: the module will be |
194 | called ati_remote2. | 194 | called ati_remote2. |
195 | 195 | ||
196 | config INPUT_KEYCHORD | ||
197 | tristate "Key chord input driver support" | ||
198 | help | ||
199 | Say Y here if you want to enable the key chord driver | ||
200 | accessible at /dev/keychord. This driver can be used | ||
201 | for receiving notifications when client specified key | ||
202 | combinations are pressed. | ||
203 | |||
204 | To compile this driver as a module, choose M here: the | ||
205 | module will be called keychord. | ||
206 | |||
196 | config INPUT_KEYSPAN_REMOTE | 207 | config INPUT_KEYSPAN_REMOTE |
197 | tristate "Keyspan DMR USB remote control (EXPERIMENTAL)" | 208 | tristate "Keyspan DMR USB remote control (EXPERIMENTAL)" |
198 | depends on EXPERIMENTAL | 209 | depends on EXPERIMENTAL |
@@ -294,6 +305,11 @@ config INPUT_SGI_BTNS | |||
294 | To compile this driver as a module, choose M here: the | 305 | To compile this driver as a module, choose M here: the |
295 | module will be called sgi_btns. | 306 | module will be called sgi_btns. |
296 | 307 | ||
308 | config INPUT_GPIO | ||
309 | tristate "GPIO driver support" | ||
310 | help | ||
311 | Say Y here if you want to support gpio based keys, wheels etc... | ||
312 | |||
297 | config HP_SDC_RTC | 313 | config HP_SDC_RTC |
298 | tristate "HP SDC Real Time Clock" | 314 | tristate "HP SDC Real Time Clock" |
299 | depends on (GSC || HP300) && SERIO | 315 | depends on (GSC || HP300) && SERIO |
@@ -478,4 +494,10 @@ config INPUT_XEN_KBDDEV_FRONTEND | |||
478 | To compile this driver as a module, choose M here: the | 494 | To compile this driver as a module, choose M here: the |
479 | module will be called xen-kbdfront. | 495 | module will be called xen-kbdfront. |
480 | 496 | ||
497 | config INPUT_ISA1200 | ||
498 | tristate "ISA1200 Haptic Driver" | ||
499 | depends on I2C && HAVE_PWM | ||
500 | help | ||
501 | This option enables support for the Imagis ISA1200 Haptic Driver. | ||
502 | |||
481 | endif | 503 | endif |
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index 38efb2cb182..f28a4ffc834 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile | |||
@@ -22,8 +22,10 @@ obj-$(CONFIG_INPUT_CMA3000) += cma3000_d0x.o | |||
22 | obj-$(CONFIG_INPUT_CMA3000_I2C) += cma3000_d0x_i2c.o | 22 | obj-$(CONFIG_INPUT_CMA3000_I2C) += cma3000_d0x_i2c.o |
23 | obj-$(CONFIG_INPUT_COBALT_BTNS) += cobalt_btns.o | 23 | obj-$(CONFIG_INPUT_COBALT_BTNS) += cobalt_btns.o |
24 | obj-$(CONFIG_INPUT_DM355EVM) += dm355evm_keys.o | 24 | obj-$(CONFIG_INPUT_DM355EVM) += dm355evm_keys.o |
25 | obj-$(CONFIG_INPUT_GPIO) += gpio_event.o gpio_matrix.o gpio_input.o gpio_output.o gpio_axis.o | ||
25 | obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.o | 26 | obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.o |
26 | obj-$(CONFIG_INPUT_IXP4XX_BEEPER) += ixp4xx-beeper.o | 27 | obj-$(CONFIG_INPUT_IXP4XX_BEEPER) += ixp4xx-beeper.o |
28 | obj-$(CONFIG_INPUT_KEYCHORD) += keychord.o | ||
27 | obj-$(CONFIG_INPUT_KEYSPAN_REMOTE) += keyspan_remote.o | 29 | obj-$(CONFIG_INPUT_KEYSPAN_REMOTE) += keyspan_remote.o |
28 | obj-$(CONFIG_INPUT_M68K_BEEP) += m68kspkr.o | 30 | obj-$(CONFIG_INPUT_M68K_BEEP) += m68kspkr.o |
29 | obj-$(CONFIG_INPUT_MAX8925_ONKEY) += max8925_onkey.o | 31 | obj-$(CONFIG_INPUT_MAX8925_ONKEY) += max8925_onkey.o |
@@ -45,4 +47,5 @@ obj-$(CONFIG_INPUT_WISTRON_BTNS) += wistron_btns.o | |||
45 | obj-$(CONFIG_INPUT_WM831X_ON) += wm831x-on.o | 47 | obj-$(CONFIG_INPUT_WM831X_ON) += wm831x-on.o |
46 | obj-$(CONFIG_INPUT_XEN_KBDDEV_FRONTEND) += xen-kbdfront.o | 48 | obj-$(CONFIG_INPUT_XEN_KBDDEV_FRONTEND) += xen-kbdfront.o |
47 | obj-$(CONFIG_INPUT_YEALINK) += yealink.o | 49 | obj-$(CONFIG_INPUT_YEALINK) += yealink.o |
48 | 50 | # for ODROID | |
51 | obj-$(CONFIG_INPUT_ISA1200) += isa1200.o | ||
diff --git a/drivers/input/misc/gpio_axis.c b/drivers/input/misc/gpio_axis.c new file mode 100644 index 00000000000..0acf4a576f5 --- /dev/null +++ b/drivers/input/misc/gpio_axis.c | |||
@@ -0,0 +1,192 @@ | |||
1 | /* drivers/input/misc/gpio_axis.c | ||
2 | * | ||
3 | * Copyright (C) 2007 Google, Inc. | ||
4 | * | ||
5 | * This software is licensed under the terms of the GNU General Public | ||
6 | * License version 2, as published by the Free Software Foundation, and | ||
7 | * may be copied, distributed, and modified under those terms. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | */ | ||
15 | |||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/gpio.h> | ||
18 | #include <linux/gpio_event.h> | ||
19 | #include <linux/interrupt.h> | ||
20 | #include <linux/slab.h> | ||
21 | |||
22 | struct gpio_axis_state { | ||
23 | struct gpio_event_input_devs *input_devs; | ||
24 | struct gpio_event_axis_info *info; | ||
25 | uint32_t pos; | ||
26 | }; | ||
27 | |||
28 | uint16_t gpio_axis_4bit_gray_map_table[] = { | ||
29 | [0x0] = 0x0, [0x1] = 0x1, /* 0000 0001 */ | ||
30 | [0x3] = 0x2, [0x2] = 0x3, /* 0011 0010 */ | ||
31 | [0x6] = 0x4, [0x7] = 0x5, /* 0110 0111 */ | ||
32 | [0x5] = 0x6, [0x4] = 0x7, /* 0101 0100 */ | ||
33 | [0xc] = 0x8, [0xd] = 0x9, /* 1100 1101 */ | ||
34 | [0xf] = 0xa, [0xe] = 0xb, /* 1111 1110 */ | ||
35 | [0xa] = 0xc, [0xb] = 0xd, /* 1010 1011 */ | ||
36 | [0x9] = 0xe, [0x8] = 0xf, /* 1001 1000 */ | ||
37 | }; | ||
38 | uint16_t gpio_axis_4bit_gray_map(struct gpio_event_axis_info *info, uint16_t in) | ||
39 | { | ||
40 | return gpio_axis_4bit_gray_map_table[in]; | ||
41 | } | ||
42 | |||
43 | uint16_t gpio_axis_5bit_singletrack_map_table[] = { | ||
44 | [0x10] = 0x00, [0x14] = 0x01, [0x1c] = 0x02, /* 10000 10100 11100 */ | ||
45 | [0x1e] = 0x03, [0x1a] = 0x04, [0x18] = 0x05, /* 11110 11010 11000 */ | ||
46 | [0x08] = 0x06, [0x0a] = 0x07, [0x0e] = 0x08, /* 01000 01010 01110 */ | ||
47 | [0x0f] = 0x09, [0x0d] = 0x0a, [0x0c] = 0x0b, /* 01111 01101 01100 */ | ||
48 | [0x04] = 0x0c, [0x05] = 0x0d, [0x07] = 0x0e, /* 00100 00101 00111 */ | ||
49 | [0x17] = 0x0f, [0x16] = 0x10, [0x06] = 0x11, /* 10111 10110 00110 */ | ||
50 | [0x02] = 0x12, [0x12] = 0x13, [0x13] = 0x14, /* 00010 10010 10011 */ | ||
51 | [0x1b] = 0x15, [0x0b] = 0x16, [0x03] = 0x17, /* 11011 01011 00011 */ | ||
52 | [0x01] = 0x18, [0x09] = 0x19, [0x19] = 0x1a, /* 00001 01001 11001 */ | ||
53 | [0x1d] = 0x1b, [0x15] = 0x1c, [0x11] = 0x1d, /* 11101 10101 10001 */ | ||
54 | }; | ||
55 | uint16_t gpio_axis_5bit_singletrack_map( | ||
56 | struct gpio_event_axis_info *info, uint16_t in) | ||
57 | { | ||
58 | return gpio_axis_5bit_singletrack_map_table[in]; | ||
59 | } | ||
60 | |||
61 | static void gpio_event_update_axis(struct gpio_axis_state *as, int report) | ||
62 | { | ||
63 | struct gpio_event_axis_info *ai = as->info; | ||
64 | int i; | ||
65 | int change; | ||
66 | uint16_t state = 0; | ||
67 | uint16_t pos; | ||
68 | uint16_t old_pos = as->pos; | ||
69 | for (i = ai->count - 1; i >= 0; i--) | ||
70 | state = (state << 1) | gpio_get_value(ai->gpio[i]); | ||
71 | pos = ai->map(ai, state); | ||
72 | if (ai->flags & GPIOEAF_PRINT_RAW) | ||
73 | pr_info("axis %d-%d raw %x, pos %d -> %d\n", | ||
74 | ai->type, ai->code, state, old_pos, pos); | ||
75 | if (report && pos != old_pos) { | ||
76 | if (ai->type == EV_REL) { | ||
77 | change = (ai->decoded_size + pos - old_pos) % | ||
78 | ai->decoded_size; | ||
79 | if (change > ai->decoded_size / 2) | ||
80 | change -= ai->decoded_size; | ||
81 | if (change == ai->decoded_size / 2) { | ||
82 | if (ai->flags & GPIOEAF_PRINT_EVENT) | ||
83 | pr_info("axis %d-%d unknown direction, " | ||
84 | "pos %d -> %d\n", ai->type, | ||
85 | ai->code, old_pos, pos); | ||
86 | change = 0; /* no closest direction */ | ||
87 | } | ||
88 | if (ai->flags & GPIOEAF_PRINT_EVENT) | ||
89 | pr_info("axis %d-%d change %d\n", | ||
90 | ai->type, ai->code, change); | ||
91 | input_report_rel(as->input_devs->dev[ai->dev], | ||
92 | ai->code, change); | ||
93 | } else { | ||
94 | if (ai->flags & GPIOEAF_PRINT_EVENT) | ||
95 | pr_info("axis %d-%d now %d\n", | ||
96 | ai->type, ai->code, pos); | ||
97 | input_event(as->input_devs->dev[ai->dev], | ||
98 | ai->type, ai->code, pos); | ||
99 | } | ||
100 | input_sync(as->input_devs->dev[ai->dev]); | ||
101 | } | ||
102 | as->pos = pos; | ||
103 | } | ||
104 | |||
105 | static irqreturn_t gpio_axis_irq_handler(int irq, void *dev_id) | ||
106 | { | ||
107 | struct gpio_axis_state *as = dev_id; | ||
108 | gpio_event_update_axis(as, 1); | ||
109 | return IRQ_HANDLED; | ||
110 | } | ||
111 | |||
112 | int gpio_event_axis_func(struct gpio_event_input_devs *input_devs, | ||
113 | struct gpio_event_info *info, void **data, int func) | ||
114 | { | ||
115 | int ret; | ||
116 | int i; | ||
117 | int irq; | ||
118 | struct gpio_event_axis_info *ai; | ||
119 | struct gpio_axis_state *as; | ||
120 | |||
121 | ai = container_of(info, struct gpio_event_axis_info, info); | ||
122 | if (func == GPIO_EVENT_FUNC_SUSPEND) { | ||
123 | for (i = 0; i < ai->count; i++) | ||
124 | disable_irq(gpio_to_irq(ai->gpio[i])); | ||
125 | return 0; | ||
126 | } | ||
127 | if (func == GPIO_EVENT_FUNC_RESUME) { | ||
128 | for (i = 0; i < ai->count; i++) | ||
129 | enable_irq(gpio_to_irq(ai->gpio[i])); | ||
130 | return 0; | ||
131 | } | ||
132 | |||
133 | if (func == GPIO_EVENT_FUNC_INIT) { | ||
134 | *data = as = kmalloc(sizeof(*as), GFP_KERNEL); | ||
135 | if (as == NULL) { | ||
136 | ret = -ENOMEM; | ||
137 | goto err_alloc_axis_state_failed; | ||
138 | } | ||
139 | as->input_devs = input_devs; | ||
140 | as->info = ai; | ||
141 | if (ai->dev >= input_devs->count) { | ||
142 | pr_err("gpio_event_axis: bad device index %d >= %d " | ||
143 | "for %d:%d\n", ai->dev, input_devs->count, | ||
144 | ai->type, ai->code); | ||
145 | ret = -EINVAL; | ||
146 | goto err_bad_device_index; | ||
147 | } | ||
148 | |||
149 | input_set_capability(input_devs->dev[ai->dev], | ||
150 | ai->type, ai->code); | ||
151 | if (ai->type == EV_ABS) { | ||
152 | input_set_abs_params(input_devs->dev[ai->dev], ai->code, | ||
153 | 0, ai->decoded_size - 1, 0, 0); | ||
154 | } | ||
155 | for (i = 0; i < ai->count; i++) { | ||
156 | ret = gpio_request(ai->gpio[i], "gpio_event_axis"); | ||
157 | if (ret < 0) | ||
158 | goto err_request_gpio_failed; | ||
159 | ret = gpio_direction_input(ai->gpio[i]); | ||
160 | if (ret < 0) | ||
161 | goto err_gpio_direction_input_failed; | ||
162 | ret = irq = gpio_to_irq(ai->gpio[i]); | ||
163 | if (ret < 0) | ||
164 | goto err_get_irq_num_failed; | ||
165 | ret = request_irq(irq, gpio_axis_irq_handler, | ||
166 | IRQF_TRIGGER_RISING | | ||
167 | IRQF_TRIGGER_FALLING, | ||
168 | "gpio_event_axis", as); | ||
169 | if (ret < 0) | ||
170 | goto err_request_irq_failed; | ||
171 | } | ||
172 | gpio_event_update_axis(as, 0); | ||
173 | return 0; | ||
174 | } | ||
175 | |||
176 | ret = 0; | ||
177 | as = *data; | ||
178 | for (i = ai->count - 1; i >= 0; i--) { | ||
179 | free_irq(gpio_to_irq(ai->gpio[i]), as); | ||
180 | err_request_irq_failed: | ||
181 | err_get_irq_num_failed: | ||
182 | err_gpio_direction_input_failed: | ||
183 | gpio_free(ai->gpio[i]); | ||
184 | err_request_gpio_failed: | ||
185 | ; | ||
186 | } | ||
187 | err_bad_device_index: | ||
188 | kfree(as); | ||
189 | *data = NULL; | ||
190 | err_alloc_axis_state_failed: | ||
191 | return ret; | ||
192 | } | ||
diff --git a/drivers/input/misc/gpio_event.c b/drivers/input/misc/gpio_event.c new file mode 100644 index 00000000000..a98be67d1ab --- /dev/null +++ b/drivers/input/misc/gpio_event.c | |||
@@ -0,0 +1,260 @@ | |||
1 | /* drivers/input/misc/gpio_event.c | ||
2 | * | ||
3 | * Copyright (C) 2007 Google, Inc. | ||
4 | * | ||
5 | * This software is licensed under the terms of the GNU General Public | ||
6 | * License version 2, as published by the Free Software Foundation, and | ||
7 | * may be copied, distributed, and modified under those terms. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | */ | ||
15 | |||
16 | #include <linux/earlysuspend.h> | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/input.h> | ||
19 | #include <linux/gpio_event.h> | ||
20 | #include <linux/hrtimer.h> | ||
21 | #include <linux/platform_device.h> | ||
22 | #include <linux/slab.h> | ||
23 | |||
24 | struct gpio_event { | ||
25 | struct gpio_event_input_devs *input_devs; | ||
26 | const struct gpio_event_platform_data *info; | ||
27 | struct early_suspend early_suspend; | ||
28 | void *state[0]; | ||
29 | }; | ||
30 | |||
31 | static int gpio_input_event( | ||
32 | struct input_dev *dev, unsigned int type, unsigned int code, int value) | ||
33 | { | ||
34 | int i; | ||
35 | int devnr; | ||
36 | int ret = 0; | ||
37 | int tmp_ret; | ||
38 | struct gpio_event_info **ii; | ||
39 | struct gpio_event *ip = input_get_drvdata(dev); | ||
40 | |||
41 | for (devnr = 0; devnr < ip->input_devs->count; devnr++) | ||
42 | if (ip->input_devs->dev[devnr] == dev) | ||
43 | break; | ||
44 | if (devnr == ip->input_devs->count) { | ||
45 | pr_err("gpio_input_event: unknown device %p\n", dev); | ||
46 | return -EIO; | ||
47 | } | ||
48 | |||
49 | for (i = 0, ii = ip->info->info; i < ip->info->info_count; i++, ii++) { | ||
50 | if ((*ii)->event) { | ||
51 | tmp_ret = (*ii)->event(ip->input_devs, *ii, | ||
52 | &ip->state[i], | ||
53 | devnr, type, code, value); | ||
54 | if (tmp_ret) | ||
55 | ret = tmp_ret; | ||
56 | } | ||
57 | } | ||
58 | return ret; | ||
59 | } | ||
60 | |||
61 | static int gpio_event_call_all_func(struct gpio_event *ip, int func) | ||
62 | { | ||
63 | int i; | ||
64 | int ret; | ||
65 | struct gpio_event_info **ii; | ||
66 | |||
67 | if (func == GPIO_EVENT_FUNC_INIT || func == GPIO_EVENT_FUNC_RESUME) { | ||
68 | ii = ip->info->info; | ||
69 | for (i = 0; i < ip->info->info_count; i++, ii++) { | ||
70 | if ((*ii)->func == NULL) { | ||
71 | ret = -ENODEV; | ||
72 | pr_err("gpio_event_probe: Incomplete pdata, " | ||
73 | "no function\n"); | ||
74 | goto err_no_func; | ||
75 | } | ||
76 | if (func == GPIO_EVENT_FUNC_RESUME && (*ii)->no_suspend) | ||
77 | continue; | ||
78 | ret = (*ii)->func(ip->input_devs, *ii, &ip->state[i], | ||
79 | func); | ||
80 | if (ret) { | ||
81 | pr_err("gpio_event_probe: function failed\n"); | ||
82 | goto err_func_failed; | ||
83 | } | ||
84 | } | ||
85 | return 0; | ||
86 | } | ||
87 | |||
88 | ret = 0; | ||
89 | i = ip->info->info_count; | ||
90 | ii = ip->info->info + i; | ||
91 | while (i > 0) { | ||
92 | i--; | ||
93 | ii--; | ||
94 | if ((func & ~1) == GPIO_EVENT_FUNC_SUSPEND && (*ii)->no_suspend) | ||
95 | continue; | ||
96 | (*ii)->func(ip->input_devs, *ii, &ip->state[i], func & ~1); | ||
97 | err_func_failed: | ||
98 | err_no_func: | ||
99 | ; | ||
100 | } | ||
101 | return ret; | ||
102 | } | ||
103 | |||
104 | #ifdef CONFIG_HAS_EARLYSUSPEND | ||
105 | void gpio_event_suspend(struct early_suspend *h) | ||
106 | { | ||
107 | struct gpio_event *ip; | ||
108 | ip = container_of(h, struct gpio_event, early_suspend); | ||
109 | gpio_event_call_all_func(ip, GPIO_EVENT_FUNC_SUSPEND); | ||
110 | ip->info->power(ip->info, 0); | ||
111 | } | ||
112 | |||
113 | void gpio_event_resume(struct early_suspend *h) | ||
114 | { | ||
115 | struct gpio_event *ip; | ||
116 | ip = container_of(h, struct gpio_event, early_suspend); | ||
117 | ip->info->power(ip->info, 1); | ||
118 | gpio_event_call_all_func(ip, GPIO_EVENT_FUNC_RESUME); | ||
119 | } | ||
120 | #endif | ||
121 | |||
122 | static int gpio_event_probe(struct platform_device *pdev) | ||
123 | { | ||
124 | int err; | ||
125 | struct gpio_event *ip; | ||
126 | struct gpio_event_platform_data *event_info; | ||
127 | int dev_count = 1; | ||
128 | int i; | ||
129 | int registered = 0; | ||
130 | |||
131 | event_info = pdev->dev.platform_data; | ||
132 | if (event_info == NULL) { | ||
133 | pr_err("gpio_event_probe: No pdata\n"); | ||
134 | return -ENODEV; | ||
135 | } | ||
136 | if ((!event_info->name && !event_info->names[0]) || | ||
137 | !event_info->info || !event_info->info_count) { | ||
138 | pr_err("gpio_event_probe: Incomplete pdata\n"); | ||
139 | return -ENODEV; | ||
140 | } | ||
141 | if (!event_info->name) | ||
142 | while (event_info->names[dev_count]) | ||
143 | dev_count++; | ||
144 | ip = kzalloc(sizeof(*ip) + | ||
145 | sizeof(ip->state[0]) * event_info->info_count + | ||
146 | sizeof(*ip->input_devs) + | ||
147 | sizeof(ip->input_devs->dev[0]) * dev_count, GFP_KERNEL); | ||
148 | if (ip == NULL) { | ||
149 | err = -ENOMEM; | ||
150 | pr_err("gpio_event_probe: Failed to allocate private data\n"); | ||
151 | goto err_kp_alloc_failed; | ||
152 | } | ||
153 | ip->input_devs = (void*)&ip->state[event_info->info_count]; | ||
154 | platform_set_drvdata(pdev, ip); | ||
155 | |||
156 | for (i = 0; i < dev_count; i++) { | ||
157 | struct input_dev *input_dev = input_allocate_device(); | ||
158 | if (input_dev == NULL) { | ||
159 | err = -ENOMEM; | ||
160 | pr_err("gpio_event_probe: " | ||
161 | "Failed to allocate input device\n"); | ||
162 | goto err_input_dev_alloc_failed; | ||
163 | } | ||
164 | input_set_drvdata(input_dev, ip); | ||
165 | input_dev->name = event_info->name ? | ||
166 | event_info->name : event_info->names[i]; | ||
167 | input_dev->event = gpio_input_event; | ||
168 | ip->input_devs->dev[i] = input_dev; | ||
169 | } | ||
170 | ip->input_devs->count = dev_count; | ||
171 | ip->info = event_info; | ||
172 | if (event_info->power) { | ||
173 | #ifdef CONFIG_HAS_EARLYSUSPEND | ||
174 | ip->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; | ||
175 | ip->early_suspend.suspend = gpio_event_suspend; | ||
176 | ip->early_suspend.resume = gpio_event_resume; | ||
177 | register_early_suspend(&ip->early_suspend); | ||
178 | #endif | ||
179 | ip->info->power(ip->info, 1); | ||
180 | } | ||
181 | |||
182 | err = gpio_event_call_all_func(ip, GPIO_EVENT_FUNC_INIT); | ||
183 | if (err) | ||
184 | goto err_call_all_func_failed; | ||
185 | |||
186 | for (i = 0; i < dev_count; i++) { | ||
187 | err = input_register_device(ip->input_devs->dev[i]); | ||
188 | if (err) { | ||
189 | pr_err("gpio_event_probe: Unable to register %s " | ||
190 | "input device\n", ip->input_devs->dev[i]->name); | ||
191 | goto err_input_register_device_failed; | ||
192 | } | ||
193 | registered++; | ||
194 | } | ||
195 | |||
196 | return 0; | ||
197 | |||
198 | err_input_register_device_failed: | ||
199 | gpio_event_call_all_func(ip, GPIO_EVENT_FUNC_UNINIT); | ||
200 | err_call_all_func_failed: | ||
201 | if (event_info->power) { | ||
202 | #ifdef CONFIG_HAS_EARLYSUSPEND | ||
203 | unregister_early_suspend(&ip->early_suspend); | ||
204 | #endif | ||
205 | ip->info->power(ip->info, 0); | ||
206 | } | ||
207 | for (i = 0; i < registered; i++) | ||
208 | input_unregister_device(ip->input_devs->dev[i]); | ||
209 | for (i = dev_count - 1; i >= registered; i--) { | ||
210 | input_free_device(ip->input_devs->dev[i]); | ||
211 | err_input_dev_alloc_failed: | ||
212 | ; | ||
213 | } | ||
214 | kfree(ip); | ||
215 | err_kp_alloc_failed: | ||
216 | return err; | ||
217 | } | ||
218 | |||
219 | static int gpio_event_remove(struct platform_device *pdev) | ||
220 | { | ||
221 | struct gpio_event *ip = platform_get_drvdata(pdev); | ||
222 | int i; | ||
223 | |||
224 | gpio_event_call_all_func(ip, GPIO_EVENT_FUNC_UNINIT); | ||
225 | if (ip->info->power) { | ||
226 | #ifdef CONFIG_HAS_EARLYSUSPEND | ||
227 | unregister_early_suspend(&ip->early_suspend); | ||
228 | #endif | ||
229 | ip->info->power(ip->info, 0); | ||
230 | } | ||
231 | for (i = 0; i < ip->input_devs->count; i++) | ||
232 | input_unregister_device(ip->input_devs->dev[i]); | ||
233 | kfree(ip); | ||
234 | return 0; | ||
235 | } | ||
236 | |||
237 | static struct platform_driver gpio_event_driver = { | ||
238 | .probe = gpio_event_probe, | ||
239 | .remove = gpio_event_remove, | ||
240 | .driver = { | ||
241 | .name = GPIO_EVENT_DEV_NAME, | ||
242 | }, | ||
243 | }; | ||
244 | |||
245 | static int __devinit gpio_event_init(void) | ||
246 | { | ||
247 | return platform_driver_register(&gpio_event_driver); | ||
248 | } | ||
249 | |||
250 | static void __exit gpio_event_exit(void) | ||
251 | { | ||
252 | platform_driver_unregister(&gpio_event_driver); | ||
253 | } | ||
254 | |||
255 | module_init(gpio_event_init); | ||
256 | module_exit(gpio_event_exit); | ||
257 | |||
258 | MODULE_DESCRIPTION("GPIO Event Driver"); | ||
259 | MODULE_LICENSE("GPL"); | ||
260 | |||
diff --git a/drivers/input/misc/gpio_input.c b/drivers/input/misc/gpio_input.c new file mode 100644 index 00000000000..6a0c3151096 --- /dev/null +++ b/drivers/input/misc/gpio_input.c | |||
@@ -0,0 +1,376 @@ | |||
1 | /* drivers/input/misc/gpio_input.c | ||
2 | * | ||
3 | * Copyright (C) 2007 Google, Inc. | ||
4 | * | ||
5 | * This software is licensed under the terms of the GNU General Public | ||
6 | * License version 2, as published by the Free Software Foundation, and | ||
7 | * may be copied, distributed, and modified under those terms. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | */ | ||
15 | |||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/gpio.h> | ||
18 | #include <linux/gpio_event.h> | ||
19 | #include <linux/hrtimer.h> | ||
20 | #include <linux/input.h> | ||
21 | #include <linux/interrupt.h> | ||
22 | #include <linux/slab.h> | ||
23 | #include <linux/wakelock.h> | ||
24 | |||
25 | enum { | ||
26 | DEBOUNCE_UNSTABLE = BIT(0), /* Got irq, while debouncing */ | ||
27 | DEBOUNCE_PRESSED = BIT(1), | ||
28 | DEBOUNCE_NOTPRESSED = BIT(2), | ||
29 | DEBOUNCE_WAIT_IRQ = BIT(3), /* Stable irq state */ | ||
30 | DEBOUNCE_POLL = BIT(4), /* Stable polling state */ | ||
31 | |||
32 | DEBOUNCE_UNKNOWN = | ||
33 | DEBOUNCE_PRESSED | DEBOUNCE_NOTPRESSED, | ||
34 | }; | ||
35 | |||
36 | struct gpio_key_state { | ||
37 | struct gpio_input_state *ds; | ||
38 | uint8_t debounce; | ||
39 | }; | ||
40 | |||
41 | struct gpio_input_state { | ||
42 | struct gpio_event_input_devs *input_devs; | ||
43 | const struct gpio_event_input_info *info; | ||
44 | struct hrtimer timer; | ||
45 | int use_irq; | ||
46 | int debounce_count; | ||
47 | spinlock_t irq_lock; | ||
48 | struct wake_lock wake_lock; | ||
49 | struct gpio_key_state key_state[0]; | ||
50 | }; | ||
51 | |||
52 | static enum hrtimer_restart gpio_event_input_timer_func(struct hrtimer *timer) | ||
53 | { | ||
54 | int i; | ||
55 | int pressed; | ||
56 | struct gpio_input_state *ds = | ||
57 | container_of(timer, struct gpio_input_state, timer); | ||
58 | unsigned gpio_flags = ds->info->flags; | ||
59 | unsigned npolarity; | ||
60 | int nkeys = ds->info->keymap_size; | ||
61 | const struct gpio_event_direct_entry *key_entry; | ||
62 | struct gpio_key_state *key_state; | ||
63 | unsigned long irqflags; | ||
64 | uint8_t debounce; | ||
65 | bool sync_needed; | ||
66 | |||
67 | #if 0 | ||
68 | key_entry = kp->keys_info->keymap; | ||
69 | key_state = kp->key_state; | ||
70 | for (i = 0; i < nkeys; i++, key_entry++, key_state++) | ||
71 | pr_info("gpio_read_detect_status %d %d\n", key_entry->gpio, | ||
72 | gpio_read_detect_status(key_entry->gpio)); | ||
73 | #endif | ||
74 | key_entry = ds->info->keymap; | ||
75 | key_state = ds->key_state; | ||
76 | sync_needed = false; | ||
77 | spin_lock_irqsave(&ds->irq_lock, irqflags); | ||
78 | for (i = 0; i < nkeys; i++, key_entry++, key_state++) { | ||
79 | debounce = key_state->debounce; | ||
80 | if (debounce & DEBOUNCE_WAIT_IRQ) | ||
81 | continue; | ||
82 | if (key_state->debounce & DEBOUNCE_UNSTABLE) { | ||
83 | debounce = key_state->debounce = DEBOUNCE_UNKNOWN; | ||
84 | enable_irq(gpio_to_irq(key_entry->gpio)); | ||
85 | if (gpio_flags & GPIOEDF_PRINT_KEY_UNSTABLE) | ||
86 | pr_info("gpio_keys_scan_keys: key %x-%x, %d " | ||
87 | "(%d) continue debounce\n", | ||
88 | ds->info->type, key_entry->code, | ||
89 | i, key_entry->gpio); | ||
90 | } | ||
91 | npolarity = !(gpio_flags & GPIOEDF_ACTIVE_HIGH); | ||
92 | pressed = gpio_get_value(key_entry->gpio) ^ npolarity; | ||
93 | if (debounce & DEBOUNCE_POLL) { | ||
94 | if (pressed == !(debounce & DEBOUNCE_PRESSED)) { | ||
95 | ds->debounce_count++; | ||
96 | key_state->debounce = DEBOUNCE_UNKNOWN; | ||
97 | if (gpio_flags & GPIOEDF_PRINT_KEY_DEBOUNCE) | ||
98 | pr_info("gpio_keys_scan_keys: key %x-" | ||
99 | "%x, %d (%d) start debounce\n", | ||
100 | ds->info->type, key_entry->code, | ||
101 | i, key_entry->gpio); | ||
102 | } | ||
103 | continue; | ||
104 | } | ||
105 | if (pressed && (debounce & DEBOUNCE_NOTPRESSED)) { | ||
106 | if (gpio_flags & GPIOEDF_PRINT_KEY_DEBOUNCE) | ||
107 | pr_info("gpio_keys_scan_keys: key %x-%x, %d " | ||
108 | "(%d) debounce pressed 1\n", | ||
109 | ds->info->type, key_entry->code, | ||
110 | i, key_entry->gpio); | ||
111 | key_state->debounce = DEBOUNCE_PRESSED; | ||
112 | continue; | ||
113 | } | ||
114 | if (!pressed && (debounce & DEBOUNCE_PRESSED)) { | ||
115 | if (gpio_flags & GPIOEDF_PRINT_KEY_DEBOUNCE) | ||
116 | pr_info("gpio_keys_scan_keys: key %x-%x, %d " | ||
117 | "(%d) debounce pressed 0\n", | ||
118 | ds->info->type, key_entry->code, | ||
119 | i, key_entry->gpio); | ||
120 | key_state->debounce = DEBOUNCE_NOTPRESSED; | ||
121 | continue; | ||
122 | } | ||
123 | /* key is stable */ | ||
124 | ds->debounce_count--; | ||
125 | if (ds->use_irq) | ||
126 | key_state->debounce |= DEBOUNCE_WAIT_IRQ; | ||
127 | else | ||
128 | key_state->debounce |= DEBOUNCE_POLL; | ||
129 | if (gpio_flags & GPIOEDF_PRINT_KEYS) | ||
130 | pr_info("gpio_keys_scan_keys: key %x-%x, %d (%d) " | ||
131 | "changed to %d\n", ds->info->type, | ||
132 | key_entry->code, i, key_entry->gpio, pressed); | ||
133 | input_event(ds->input_devs->dev[key_entry->dev], ds->info->type, | ||
134 | key_entry->code, pressed); | ||
135 | sync_needed = true; | ||
136 | } | ||
137 | if (sync_needed) { | ||
138 | for (i = 0; i < ds->input_devs->count; i++) | ||
139 | input_sync(ds->input_devs->dev[i]); | ||
140 | } | ||
141 | |||
142 | #if 0 | ||
143 | key_entry = kp->keys_info->keymap; | ||
144 | key_state = kp->key_state; | ||
145 | for (i = 0; i < nkeys; i++, key_entry++, key_state++) { | ||
146 | pr_info("gpio_read_detect_status %d %d\n", key_entry->gpio, | ||
147 | gpio_read_detect_status(key_entry->gpio)); | ||
148 | } | ||
149 | #endif | ||
150 | |||
151 | if (ds->debounce_count) | ||
152 | hrtimer_start(timer, ds->info->debounce_time, HRTIMER_MODE_REL); | ||
153 | else if (!ds->use_irq) | ||
154 | hrtimer_start(timer, ds->info->poll_time, HRTIMER_MODE_REL); | ||
155 | else | ||
156 | wake_unlock(&ds->wake_lock); | ||
157 | |||
158 | spin_unlock_irqrestore(&ds->irq_lock, irqflags); | ||
159 | |||
160 | return HRTIMER_NORESTART; | ||
161 | } | ||
162 | |||
163 | static irqreturn_t gpio_event_input_irq_handler(int irq, void *dev_id) | ||
164 | { | ||
165 | struct gpio_key_state *ks = dev_id; | ||
166 | struct gpio_input_state *ds = ks->ds; | ||
167 | int keymap_index = ks - ds->key_state; | ||
168 | const struct gpio_event_direct_entry *key_entry; | ||
169 | unsigned long irqflags; | ||
170 | int pressed; | ||
171 | |||
172 | if (!ds->use_irq) | ||
173 | return IRQ_HANDLED; | ||
174 | |||
175 | key_entry = &ds->info->keymap[keymap_index]; | ||
176 | |||
177 | if (ds->info->debounce_time.tv64) { | ||
178 | spin_lock_irqsave(&ds->irq_lock, irqflags); | ||
179 | if (ks->debounce & DEBOUNCE_WAIT_IRQ) { | ||
180 | ks->debounce = DEBOUNCE_UNKNOWN; | ||
181 | if (ds->debounce_count++ == 0) { | ||
182 | wake_lock(&ds->wake_lock); | ||
183 | hrtimer_start( | ||
184 | &ds->timer, ds->info->debounce_time, | ||
185 | HRTIMER_MODE_REL); | ||
186 | } | ||
187 | if (ds->info->flags & GPIOEDF_PRINT_KEY_DEBOUNCE) | ||
188 | pr_info("gpio_event_input_irq_handler: " | ||
189 | "key %x-%x, %d (%d) start debounce\n", | ||
190 | ds->info->type, key_entry->code, | ||
191 | keymap_index, key_entry->gpio); | ||
192 | } else { | ||
193 | disable_irq_nosync(irq); | ||
194 | ks->debounce = DEBOUNCE_UNSTABLE; | ||
195 | } | ||
196 | spin_unlock_irqrestore(&ds->irq_lock, irqflags); | ||
197 | } else { | ||
198 | pressed = gpio_get_value(key_entry->gpio) ^ | ||
199 | !(ds->info->flags & GPIOEDF_ACTIVE_HIGH); | ||
200 | if (ds->info->flags & GPIOEDF_PRINT_KEYS) | ||
201 | pr_info("gpio_event_input_irq_handler: key %x-%x, %d " | ||
202 | "(%d) changed to %d\n", | ||
203 | ds->info->type, key_entry->code, keymap_index, | ||
204 | key_entry->gpio, pressed); | ||
205 | input_event(ds->input_devs->dev[key_entry->dev], ds->info->type, | ||
206 | key_entry->code, pressed); | ||
207 | input_sync(ds->input_devs->dev[key_entry->dev]); | ||
208 | } | ||
209 | return IRQ_HANDLED; | ||
210 | } | ||
211 | |||
212 | static int gpio_event_input_request_irqs(struct gpio_input_state *ds) | ||
213 | { | ||
214 | int i; | ||
215 | int err; | ||
216 | unsigned int irq; | ||
217 | unsigned long req_flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING; | ||
218 | |||
219 | for (i = 0; i < ds->info->keymap_size; i++) { | ||
220 | err = irq = gpio_to_irq(ds->info->keymap[i].gpio); | ||
221 | if (err < 0) | ||
222 | goto err_gpio_get_irq_num_failed; | ||
223 | err = request_irq(irq, gpio_event_input_irq_handler, | ||
224 | req_flags, "gpio_keys", &ds->key_state[i]); | ||
225 | if (err) { | ||
226 | pr_err("gpio_event_input_request_irqs: request_irq " | ||
227 | "failed for input %d, irq %d\n", | ||
228 | ds->info->keymap[i].gpio, irq); | ||
229 | goto err_request_irq_failed; | ||
230 | } | ||
231 | if (ds->info->info.no_suspend) { | ||
232 | err = enable_irq_wake(irq); | ||
233 | if (err) { | ||
234 | pr_err("gpio_event_input_request_irqs: " | ||
235 | "enable_irq_wake failed for input %d, " | ||
236 | "irq %d\n", | ||
237 | ds->info->keymap[i].gpio, irq); | ||
238 | goto err_enable_irq_wake_failed; | ||
239 | } | ||
240 | } | ||
241 | } | ||
242 | return 0; | ||
243 | |||
244 | for (i = ds->info->keymap_size - 1; i >= 0; i--) { | ||
245 | irq = gpio_to_irq(ds->info->keymap[i].gpio); | ||
246 | if (ds->info->info.no_suspend) | ||
247 | disable_irq_wake(irq); | ||
248 | err_enable_irq_wake_failed: | ||
249 | free_irq(irq, &ds->key_state[i]); | ||
250 | err_request_irq_failed: | ||
251 | err_gpio_get_irq_num_failed: | ||
252 | ; | ||
253 | } | ||
254 | return err; | ||
255 | } | ||
256 | |||
257 | int gpio_event_input_func(struct gpio_event_input_devs *input_devs, | ||
258 | struct gpio_event_info *info, void **data, int func) | ||
259 | { | ||
260 | int ret; | ||
261 | int i; | ||
262 | unsigned long irqflags; | ||
263 | struct gpio_event_input_info *di; | ||
264 | struct gpio_input_state *ds = *data; | ||
265 | |||
266 | di = container_of(info, struct gpio_event_input_info, info); | ||
267 | |||
268 | if (func == GPIO_EVENT_FUNC_SUSPEND) { | ||
269 | if (ds->use_irq) | ||
270 | for (i = 0; i < di->keymap_size; i++) | ||
271 | disable_irq(gpio_to_irq(di->keymap[i].gpio)); | ||
272 | hrtimer_cancel(&ds->timer); | ||
273 | return 0; | ||
274 | } | ||
275 | if (func == GPIO_EVENT_FUNC_RESUME) { | ||
276 | spin_lock_irqsave(&ds->irq_lock, irqflags); | ||
277 | if (ds->use_irq) | ||
278 | for (i = 0; i < di->keymap_size; i++) | ||
279 | enable_irq(gpio_to_irq(di->keymap[i].gpio)); | ||
280 | hrtimer_start(&ds->timer, ktime_set(0, 0), HRTIMER_MODE_REL); | ||
281 | spin_unlock_irqrestore(&ds->irq_lock, irqflags); | ||
282 | return 0; | ||
283 | } | ||
284 | |||
285 | if (func == GPIO_EVENT_FUNC_INIT) { | ||
286 | if (ktime_to_ns(di->poll_time) <= 0) | ||
287 | di->poll_time = ktime_set(0, 20 * NSEC_PER_MSEC); | ||
288 | |||
289 | *data = ds = kzalloc(sizeof(*ds) + sizeof(ds->key_state[0]) * | ||
290 | di->keymap_size, GFP_KERNEL); | ||
291 | if (ds == NULL) { | ||
292 | ret = -ENOMEM; | ||
293 | pr_err("gpio_event_input_func: " | ||
294 | "Failed to allocate private data\n"); | ||
295 | goto err_ds_alloc_failed; | ||
296 | } | ||
297 | ds->debounce_count = di->keymap_size; | ||
298 | ds->input_devs = input_devs; | ||
299 | ds->info = di; | ||
300 | wake_lock_init(&ds->wake_lock, WAKE_LOCK_SUSPEND, "gpio_input"); | ||
301 | spin_lock_init(&ds->irq_lock); | ||
302 | |||
303 | for (i = 0; i < di->keymap_size; i++) { | ||
304 | int dev = di->keymap[i].dev; | ||
305 | if (dev >= input_devs->count) { | ||
306 | pr_err("gpio_event_input_func: bad device " | ||
307 | "index %d >= %d for key code %d\n", | ||
308 | dev, input_devs->count, | ||
309 | di->keymap[i].code); | ||
310 | ret = -EINVAL; | ||
311 | goto err_bad_keymap; | ||
312 | } | ||
313 | input_set_capability(input_devs->dev[dev], di->type, | ||
314 | di->keymap[i].code); | ||
315 | ds->key_state[i].ds = ds; | ||
316 | ds->key_state[i].debounce = DEBOUNCE_UNKNOWN; | ||
317 | } | ||
318 | |||
319 | for (i = 0; i < di->keymap_size; i++) { | ||
320 | ret = gpio_request(di->keymap[i].gpio, "gpio_kp_in"); | ||
321 | if (ret) { | ||
322 | pr_err("gpio_event_input_func: gpio_request " | ||
323 | "failed for %d\n", di->keymap[i].gpio); | ||
324 | goto err_gpio_request_failed; | ||
325 | } | ||
326 | ret = gpio_direction_input(di->keymap[i].gpio); | ||
327 | if (ret) { | ||
328 | pr_err("gpio_event_input_func: " | ||
329 | "gpio_direction_input failed for %d\n", | ||
330 | di->keymap[i].gpio); | ||
331 | goto err_gpio_configure_failed; | ||
332 | } | ||
333 | } | ||
334 | |||
335 | ret = gpio_event_input_request_irqs(ds); | ||
336 | |||
337 | spin_lock_irqsave(&ds->irq_lock, irqflags); | ||
338 | ds->use_irq = ret == 0; | ||
339 | |||
340 | pr_info("GPIO Input Driver: Start gpio inputs for %s%s in %s " | ||
341 | "mode\n", input_devs->dev[0]->name, | ||
342 | (input_devs->count > 1) ? "..." : "", | ||
343 | ret == 0 ? "interrupt" : "polling"); | ||
344 | |||
345 | hrtimer_init(&ds->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); | ||
346 | ds->timer.function = gpio_event_input_timer_func; | ||
347 | hrtimer_start(&ds->timer, ktime_set(0, 0), HRTIMER_MODE_REL); | ||
348 | spin_unlock_irqrestore(&ds->irq_lock, irqflags); | ||
349 | return 0; | ||
350 | } | ||
351 | |||
352 | ret = 0; | ||
353 | spin_lock_irqsave(&ds->irq_lock, irqflags); | ||
354 | hrtimer_cancel(&ds->timer); | ||
355 | if (ds->use_irq) { | ||
356 | for (i = di->keymap_size - 1; i >= 0; i--) { | ||
357 | int irq = gpio_to_irq(di->keymap[i].gpio); | ||
358 | if (ds->info->info.no_suspend) | ||
359 | disable_irq_wake(irq); | ||
360 | free_irq(irq, &ds->key_state[i]); | ||
361 | } | ||
362 | } | ||
363 | spin_unlock_irqrestore(&ds->irq_lock, irqflags); | ||
364 | |||
365 | for (i = di->keymap_size - 1; i >= 0; i--) { | ||
366 | err_gpio_configure_failed: | ||
367 | gpio_free(di->keymap[i].gpio); | ||
368 | err_gpio_request_failed: | ||
369 | ; | ||
370 | } | ||
371 | err_bad_keymap: | ||
372 | wake_lock_destroy(&ds->wake_lock); | ||
373 | kfree(ds); | ||
374 | err_ds_alloc_failed: | ||
375 | return ret; | ||
376 | } | ||
diff --git a/drivers/input/misc/gpio_matrix.c b/drivers/input/misc/gpio_matrix.c new file mode 100644 index 00000000000..eaa9e89d473 --- /dev/null +++ b/drivers/input/misc/gpio_matrix.c | |||
@@ -0,0 +1,441 @@ | |||
1 | /* drivers/input/misc/gpio_matrix.c | ||
2 | * | ||
3 | * Copyright (C) 2007 Google, Inc. | ||
4 | * | ||
5 | * This software is licensed under the terms of the GNU General Public | ||
6 | * License version 2, as published by the Free Software Foundation, and | ||
7 | * may be copied, distributed, and modified under those terms. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | */ | ||
15 | |||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/gpio.h> | ||
18 | #include <linux/gpio_event.h> | ||
19 | #include <linux/hrtimer.h> | ||
20 | #include <linux/interrupt.h> | ||
21 | #include <linux/slab.h> | ||
22 | #include <linux/wakelock.h> | ||
23 | |||
24 | struct gpio_kp { | ||
25 | struct gpio_event_input_devs *input_devs; | ||
26 | struct gpio_event_matrix_info *keypad_info; | ||
27 | struct hrtimer timer; | ||
28 | struct wake_lock wake_lock; | ||
29 | int current_output; | ||
30 | unsigned int use_irq:1; | ||
31 | unsigned int key_state_changed:1; | ||
32 | unsigned int last_key_state_changed:1; | ||
33 | unsigned int some_keys_pressed:2; | ||
34 | unsigned int disabled_irq:1; | ||
35 | unsigned long keys_pressed[0]; | ||
36 | }; | ||
37 | |||
38 | static void clear_phantom_key(struct gpio_kp *kp, int out, int in) | ||
39 | { | ||
40 | struct gpio_event_matrix_info *mi = kp->keypad_info; | ||
41 | int key_index = out * mi->ninputs + in; | ||
42 | unsigned short keyentry = mi->keymap[key_index]; | ||
43 | unsigned short keycode = keyentry & MATRIX_KEY_MASK; | ||
44 | unsigned short dev = keyentry >> MATRIX_CODE_BITS; | ||
45 | |||
46 | if (!test_bit(keycode, kp->input_devs->dev[dev]->key)) { | ||
47 | if (mi->flags & GPIOKPF_PRINT_PHANTOM_KEYS) | ||
48 | pr_info("gpiomatrix: phantom key %x, %d-%d (%d-%d) " | ||
49 | "cleared\n", keycode, out, in, | ||
50 | mi->output_gpios[out], mi->input_gpios[in]); | ||
51 | __clear_bit(key_index, kp->keys_pressed); | ||
52 | } else { | ||
53 | if (mi->flags & GPIOKPF_PRINT_PHANTOM_KEYS) | ||
54 | pr_info("gpiomatrix: phantom key %x, %d-%d (%d-%d) " | ||
55 | "not cleared\n", keycode, out, in, | ||
56 | mi->output_gpios[out], mi->input_gpios[in]); | ||
57 | } | ||
58 | } | ||
59 | |||
60 | static int restore_keys_for_input(struct gpio_kp *kp, int out, int in) | ||
61 | { | ||
62 | int rv = 0; | ||
63 | int key_index; | ||
64 | |||
65 | key_index = out * kp->keypad_info->ninputs + in; | ||
66 | while (out < kp->keypad_info->noutputs) { | ||
67 | if (test_bit(key_index, kp->keys_pressed)) { | ||
68 | rv = 1; | ||
69 | clear_phantom_key(kp, out, in); | ||
70 | } | ||
71 | key_index += kp->keypad_info->ninputs; | ||
72 | out++; | ||
73 | } | ||
74 | return rv; | ||
75 | } | ||
76 | |||
77 | static void remove_phantom_keys(struct gpio_kp *kp) | ||
78 | { | ||
79 | int out, in, inp; | ||
80 | int key_index; | ||
81 | |||
82 | if (kp->some_keys_pressed < 3) | ||
83 | return; | ||
84 | |||
85 | for (out = 0; out < kp->keypad_info->noutputs; out++) { | ||
86 | inp = -1; | ||
87 | key_index = out * kp->keypad_info->ninputs; | ||
88 | for (in = 0; in < kp->keypad_info->ninputs; in++, key_index++) { | ||
89 | if (test_bit(key_index, kp->keys_pressed)) { | ||
90 | if (inp == -1) { | ||
91 | inp = in; | ||
92 | continue; | ||
93 | } | ||
94 | if (inp >= 0) { | ||
95 | if (!restore_keys_for_input(kp, out + 1, | ||
96 | inp)) | ||
97 | break; | ||
98 | clear_phantom_key(kp, out, inp); | ||
99 | inp = -2; | ||
100 | } | ||
101 | restore_keys_for_input(kp, out, in); | ||
102 | } | ||
103 | } | ||
104 | } | ||
105 | } | ||
106 | |||
107 | static void report_key(struct gpio_kp *kp, int key_index, int out, int in) | ||
108 | { | ||
109 | struct gpio_event_matrix_info *mi = kp->keypad_info; | ||
110 | int pressed = test_bit(key_index, kp->keys_pressed); | ||
111 | unsigned short keyentry = mi->keymap[key_index]; | ||
112 | unsigned short keycode = keyentry & MATRIX_KEY_MASK; | ||
113 | unsigned short dev = keyentry >> MATRIX_CODE_BITS; | ||
114 | |||
115 | if (pressed != test_bit(keycode, kp->input_devs->dev[dev]->key)) { | ||
116 | if (keycode == KEY_RESERVED) { | ||
117 | if (mi->flags & GPIOKPF_PRINT_UNMAPPED_KEYS) | ||
118 | pr_info("gpiomatrix: unmapped key, %d-%d " | ||
119 | "(%d-%d) changed to %d\n", | ||
120 | out, in, mi->output_gpios[out], | ||
121 | mi->input_gpios[in], pressed); | ||
122 | } else { | ||
123 | if (mi->flags & GPIOKPF_PRINT_MAPPED_KEYS) | ||
124 | pr_info("gpiomatrix: key %x, %d-%d (%d-%d) " | ||
125 | "changed to %d\n", keycode, | ||
126 | out, in, mi->output_gpios[out], | ||
127 | mi->input_gpios[in], pressed); | ||
128 | input_report_key(kp->input_devs->dev[dev], keycode, pressed); | ||
129 | } | ||
130 | } | ||
131 | } | ||
132 | |||
133 | static void report_sync(struct gpio_kp *kp) | ||
134 | { | ||
135 | int i; | ||
136 | |||
137 | for (i = 0; i < kp->input_devs->count; i++) | ||
138 | input_sync(kp->input_devs->dev[i]); | ||
139 | } | ||
140 | |||
141 | static enum hrtimer_restart gpio_keypad_timer_func(struct hrtimer *timer) | ||
142 | { | ||
143 | int out, in; | ||
144 | int key_index; | ||
145 | int gpio; | ||
146 | struct gpio_kp *kp = container_of(timer, struct gpio_kp, timer); | ||
147 | struct gpio_event_matrix_info *mi = kp->keypad_info; | ||
148 | unsigned gpio_keypad_flags = mi->flags; | ||
149 | unsigned polarity = !!(gpio_keypad_flags & GPIOKPF_ACTIVE_HIGH); | ||
150 | |||
151 | out = kp->current_output; | ||
152 | if (out == mi->noutputs) { | ||
153 | out = 0; | ||
154 | kp->last_key_state_changed = kp->key_state_changed; | ||
155 | kp->key_state_changed = 0; | ||
156 | kp->some_keys_pressed = 0; | ||
157 | } else { | ||
158 | key_index = out * mi->ninputs; | ||
159 | for (in = 0; in < mi->ninputs; in++, key_index++) { | ||
160 | gpio = mi->input_gpios[in]; | ||
161 | if (gpio_get_value(gpio) ^ !polarity) { | ||
162 | if (kp->some_keys_pressed < 3) | ||
163 | kp->some_keys_pressed++; | ||
164 | kp->key_state_changed |= !__test_and_set_bit( | ||
165 | key_index, kp->keys_pressed); | ||
166 | } else | ||
167 | kp->key_state_changed |= __test_and_clear_bit( | ||
168 | key_index, kp->keys_pressed); | ||
169 | } | ||
170 | gpio = mi->output_gpios[out]; | ||
171 | if (gpio_keypad_flags & GPIOKPF_DRIVE_INACTIVE) | ||
172 | gpio_set_value(gpio, !polarity); | ||
173 | else | ||
174 | gpio_direction_input(gpio); | ||
175 | out++; | ||
176 | } | ||
177 | kp->current_output = out; | ||
178 | if (out < mi->noutputs) { | ||
179 | gpio = mi->output_gpios[out]; | ||
180 | if (gpio_keypad_flags & GPIOKPF_DRIVE_INACTIVE) | ||
181 | gpio_set_value(gpio, polarity); | ||
182 | else | ||
183 | gpio_direction_output(gpio, polarity); | ||
184 | hrtimer_start(timer, mi->settle_time, HRTIMER_MODE_REL); | ||
185 | return HRTIMER_NORESTART; | ||
186 | } | ||
187 | if (gpio_keypad_flags & GPIOKPF_DEBOUNCE) { | ||
188 | if (kp->key_state_changed) { | ||
189 | hrtimer_start(&kp->timer, mi->debounce_delay, | ||
190 | HRTIMER_MODE_REL); | ||
191 | return HRTIMER_NORESTART; | ||
192 | } | ||
193 | kp->key_state_changed = kp->last_key_state_changed; | ||
194 | } | ||
195 | if (kp->key_state_changed) { | ||
196 | if (gpio_keypad_flags & GPIOKPF_REMOVE_SOME_PHANTOM_KEYS) | ||
197 | remove_phantom_keys(kp); | ||
198 | key_index = 0; | ||
199 | for (out = 0; out < mi->noutputs; out++) | ||
200 | for (in = 0; in < mi->ninputs; in++, key_index++) | ||
201 | report_key(kp, key_index, out, in); | ||
202 | report_sync(kp); | ||
203 | } | ||
204 | if (!kp->use_irq || kp->some_keys_pressed) { | ||
205 | hrtimer_start(timer, mi->poll_time, HRTIMER_MODE_REL); | ||
206 | return HRTIMER_NORESTART; | ||
207 | } | ||
208 | |||
209 | /* No keys are pressed, reenable interrupt */ | ||
210 | for (out = 0; out < mi->noutputs; out++) { | ||
211 | if (gpio_keypad_flags & GPIOKPF_DRIVE_INACTIVE) | ||
212 | gpio_set_value(mi->output_gpios[out], polarity); | ||
213 | else | ||
214 | gpio_direction_output(mi->output_gpios[out], polarity); | ||
215 | } | ||
216 | for (in = 0; in < mi->ninputs; in++) | ||
217 | enable_irq(gpio_to_irq(mi->input_gpios[in])); | ||
218 | wake_unlock(&kp->wake_lock); | ||
219 | return HRTIMER_NORESTART; | ||
220 | } | ||
221 | |||
222 | static irqreturn_t gpio_keypad_irq_handler(int irq_in, void *dev_id) | ||
223 | { | ||
224 | int i; | ||
225 | struct gpio_kp *kp = dev_id; | ||
226 | struct gpio_event_matrix_info *mi = kp->keypad_info; | ||
227 | unsigned gpio_keypad_flags = mi->flags; | ||
228 | |||
229 | if (!kp->use_irq) { | ||
230 | /* ignore interrupt while registering the handler */ | ||
231 | kp->disabled_irq = 1; | ||
232 | disable_irq_nosync(irq_in); | ||
233 | return IRQ_HANDLED; | ||
234 | } | ||
235 | |||
236 | for (i = 0; i < mi->ninputs; i++) | ||
237 | disable_irq_nosync(gpio_to_irq(mi->input_gpios[i])); | ||
238 | for (i = 0; i < mi->noutputs; i++) { | ||
239 | if (gpio_keypad_flags & GPIOKPF_DRIVE_INACTIVE) | ||
240 | gpio_set_value(mi->output_gpios[i], | ||
241 | !(gpio_keypad_flags & GPIOKPF_ACTIVE_HIGH)); | ||
242 | else | ||
243 | gpio_direction_input(mi->output_gpios[i]); | ||
244 | } | ||
245 | wake_lock(&kp->wake_lock); | ||
246 | hrtimer_start(&kp->timer, ktime_set(0, 0), HRTIMER_MODE_REL); | ||
247 | return IRQ_HANDLED; | ||
248 | } | ||
249 | |||
250 | static int gpio_keypad_request_irqs(struct gpio_kp *kp) | ||
251 | { | ||
252 | int i; | ||
253 | int err; | ||
254 | unsigned int irq; | ||
255 | unsigned long request_flags; | ||
256 | struct gpio_event_matrix_info *mi = kp->keypad_info; | ||
257 | |||
258 | switch (mi->flags & (GPIOKPF_ACTIVE_HIGH|GPIOKPF_LEVEL_TRIGGERED_IRQ)) { | ||
259 | default: | ||
260 | request_flags = IRQF_TRIGGER_FALLING; | ||
261 | break; | ||
262 | case GPIOKPF_ACTIVE_HIGH: | ||
263 | request_flags = IRQF_TRIGGER_RISING; | ||
264 | break; | ||
265 | case GPIOKPF_LEVEL_TRIGGERED_IRQ: | ||
266 | request_flags = IRQF_TRIGGER_LOW; | ||
267 | break; | ||
268 | case GPIOKPF_LEVEL_TRIGGERED_IRQ | GPIOKPF_ACTIVE_HIGH: | ||
269 | request_flags = IRQF_TRIGGER_HIGH; | ||
270 | break; | ||
271 | } | ||
272 | |||
273 | for (i = 0; i < mi->ninputs; i++) { | ||
274 | err = irq = gpio_to_irq(mi->input_gpios[i]); | ||
275 | if (err < 0) | ||
276 | goto err_gpio_get_irq_num_failed; | ||
277 | err = request_irq(irq, gpio_keypad_irq_handler, request_flags, | ||
278 | "gpio_kp", kp); | ||
279 | if (err) { | ||
280 | pr_err("gpiomatrix: request_irq failed for input %d, " | ||
281 | "irq %d\n", mi->input_gpios[i], irq); | ||
282 | goto err_request_irq_failed; | ||
283 | } | ||
284 | err = enable_irq_wake(irq); | ||
285 | if (err) { | ||
286 | pr_err("gpiomatrix: set_irq_wake failed for input %d, " | ||
287 | "irq %d\n", mi->input_gpios[i], irq); | ||
288 | } | ||
289 | disable_irq(irq); | ||
290 | if (kp->disabled_irq) { | ||
291 | kp->disabled_irq = 0; | ||
292 | enable_irq(irq); | ||
293 | } | ||
294 | } | ||
295 | return 0; | ||
296 | |||
297 | for (i = mi->noutputs - 1; i >= 0; i--) { | ||
298 | free_irq(gpio_to_irq(mi->input_gpios[i]), kp); | ||
299 | err_request_irq_failed: | ||
300 | err_gpio_get_irq_num_failed: | ||
301 | ; | ||
302 | } | ||
303 | return err; | ||
304 | } | ||
305 | |||
306 | int gpio_event_matrix_func(struct gpio_event_input_devs *input_devs, | ||
307 | struct gpio_event_info *info, void **data, int func) | ||
308 | { | ||
309 | int i; | ||
310 | int err; | ||
311 | int key_count; | ||
312 | struct gpio_kp *kp; | ||
313 | struct gpio_event_matrix_info *mi; | ||
314 | |||
315 | mi = container_of(info, struct gpio_event_matrix_info, info); | ||
316 | if (func == GPIO_EVENT_FUNC_SUSPEND || func == GPIO_EVENT_FUNC_RESUME) { | ||
317 | /* TODO: disable scanning */ | ||
318 | return 0; | ||
319 | } | ||
320 | |||
321 | if (func == GPIO_EVENT_FUNC_INIT) { | ||
322 | if (mi->keymap == NULL || | ||
323 | mi->input_gpios == NULL || | ||
324 | mi->output_gpios == NULL) { | ||
325 | err = -ENODEV; | ||
326 | pr_err("gpiomatrix: Incomplete pdata\n"); | ||
327 | goto err_invalid_platform_data; | ||
328 | } | ||
329 | key_count = mi->ninputs * mi->noutputs; | ||
330 | |||
331 | *data = kp = kzalloc(sizeof(*kp) + sizeof(kp->keys_pressed[0]) * | ||
332 | BITS_TO_LONGS(key_count), GFP_KERNEL); | ||
333 | if (kp == NULL) { | ||
334 | err = -ENOMEM; | ||
335 | pr_err("gpiomatrix: Failed to allocate private data\n"); | ||
336 | goto err_kp_alloc_failed; | ||
337 | } | ||
338 | kp->input_devs = input_devs; | ||
339 | kp->keypad_info = mi; | ||
340 | for (i = 0; i < key_count; i++) { | ||
341 | unsigned short keyentry = mi->keymap[i]; | ||
342 | unsigned short keycode = keyentry & MATRIX_KEY_MASK; | ||
343 | unsigned short dev = keyentry >> MATRIX_CODE_BITS; | ||
344 | if (dev >= input_devs->count) { | ||
345 | pr_err("gpiomatrix: bad device index %d >= " | ||
346 | "%d for key code %d\n", | ||
347 | dev, input_devs->count, keycode); | ||
348 | err = -EINVAL; | ||
349 | goto err_bad_keymap; | ||
350 | } | ||
351 | if (keycode && keycode <= KEY_MAX) | ||
352 | input_set_capability(input_devs->dev[dev], | ||
353 | EV_KEY, keycode); | ||
354 | } | ||
355 | |||
356 | for (i = 0; i < mi->noutputs; i++) { | ||
357 | err = gpio_request(mi->output_gpios[i], "gpio_kp_out"); | ||
358 | if (err) { | ||
359 | pr_err("gpiomatrix: gpio_request failed for " | ||
360 | "output %d\n", mi->output_gpios[i]); | ||
361 | goto err_request_output_gpio_failed; | ||
362 | } | ||
363 | if (gpio_cansleep(mi->output_gpios[i])) { | ||
364 | pr_err("gpiomatrix: unsupported output gpio %d," | ||
365 | " can sleep\n", mi->output_gpios[i]); | ||
366 | err = -EINVAL; | ||
367 | goto err_output_gpio_configure_failed; | ||
368 | } | ||
369 | if (mi->flags & GPIOKPF_DRIVE_INACTIVE) | ||
370 | err = gpio_direction_output(mi->output_gpios[i], | ||
371 | !(mi->flags & GPIOKPF_ACTIVE_HIGH)); | ||
372 | else | ||
373 | err = gpio_direction_input(mi->output_gpios[i]); | ||
374 | if (err) { | ||
375 | pr_err("gpiomatrix: gpio_configure failed for " | ||
376 | "output %d\n", mi->output_gpios[i]); | ||
377 | goto err_output_gpio_configure_failed; | ||
378 | } | ||
379 | } | ||
380 | for (i = 0; i < mi->ninputs; i++) { | ||
381 | err = gpio_request(mi->input_gpios[i], "gpio_kp_in"); | ||
382 | if (err) { | ||
383 | pr_err("gpiomatrix: gpio_request failed for " | ||
384 | "input %d\n", mi->input_gpios[i]); | ||
385 | goto err_request_input_gpio_failed; | ||
386 | } | ||
387 | err = gpio_direction_input(mi->input_gpios[i]); | ||
388 | if (err) { | ||
389 | pr_err("gpiomatrix: gpio_direction_input failed" | ||
390 | " for input %d\n", mi->input_gpios[i]); | ||
391 | goto err_gpio_direction_input_failed; | ||
392 | } | ||
393 | } | ||
394 | kp->current_output = mi->noutputs; | ||
395 | kp->key_state_changed = 1; | ||
396 | |||
397 | hrtimer_init(&kp->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); | ||
398 | kp->timer.function = gpio_keypad_timer_func; | ||
399 | wake_lock_init(&kp->wake_lock, WAKE_LOCK_SUSPEND, "gpio_kp"); | ||
400 | err = gpio_keypad_request_irqs(kp); | ||
401 | kp->use_irq = err == 0; | ||
402 | |||
403 | pr_info("GPIO Matrix Keypad Driver: Start keypad matrix for " | ||
404 | "%s%s in %s mode\n", input_devs->dev[0]->name, | ||
405 | (input_devs->count > 1) ? "..." : "", | ||
406 | kp->use_irq ? "interrupt" : "polling"); | ||
407 | |||
408 | if (kp->use_irq) | ||
409 | wake_lock(&kp->wake_lock); | ||
410 | hrtimer_start(&kp->timer, ktime_set(0, 0), HRTIMER_MODE_REL); | ||
411 | |||
412 | return 0; | ||
413 | } | ||
414 | |||
415 | err = 0; | ||
416 | kp = *data; | ||
417 | |||
418 | if (kp->use_irq) | ||
419 | for (i = mi->noutputs - 1; i >= 0; i--) | ||
420 | free_irq(gpio_to_irq(mi->input_gpios[i]), kp); | ||
421 | |||
422 | hrtimer_cancel(&kp->timer); | ||
423 | wake_lock_destroy(&kp->wake_lock); | ||
424 | for (i = mi->noutputs - 1; i >= 0; i--) { | ||
425 | err_gpio_direction_input_failed: | ||
426 | gpio_free(mi->input_gpios[i]); | ||
427 | err_request_input_gpio_failed: | ||
428 | ; | ||
429 | } | ||
430 | for (i = mi->noutputs - 1; i >= 0; i--) { | ||
431 | err_output_gpio_configure_failed: | ||
432 | gpio_free(mi->output_gpios[i]); | ||
433 | err_request_output_gpio_failed: | ||
434 | ; | ||
435 | } | ||
436 | err_bad_keymap: | ||
437 | kfree(kp); | ||
438 | err_kp_alloc_failed: | ||
439 | err_invalid_platform_data: | ||
440 | return err; | ||
441 | } | ||
diff --git a/drivers/input/misc/gpio_output.c b/drivers/input/misc/gpio_output.c new file mode 100644 index 00000000000..2aac2fad0a1 --- /dev/null +++ b/drivers/input/misc/gpio_output.c | |||
@@ -0,0 +1,97 @@ | |||
1 | /* drivers/input/misc/gpio_output.c | ||
2 | * | ||
3 | * Copyright (C) 2007 Google, Inc. | ||
4 | * | ||
5 | * This software is licensed under the terms of the GNU General Public | ||
6 | * License version 2, as published by the Free Software Foundation, and | ||
7 | * may be copied, distributed, and modified under those terms. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | */ | ||
15 | |||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/gpio.h> | ||
18 | #include <linux/gpio_event.h> | ||
19 | |||
20 | int gpio_event_output_event( | ||
21 | struct gpio_event_input_devs *input_devs, struct gpio_event_info *info, | ||
22 | void **data, unsigned int dev, unsigned int type, | ||
23 | unsigned int code, int value) | ||
24 | { | ||
25 | int i; | ||
26 | struct gpio_event_output_info *oi; | ||
27 | oi = container_of(info, struct gpio_event_output_info, info); | ||
28 | if (type != oi->type) | ||
29 | return 0; | ||
30 | if (!(oi->flags & GPIOEDF_ACTIVE_HIGH)) | ||
31 | value = !value; | ||
32 | for (i = 0; i < oi->keymap_size; i++) | ||
33 | if (dev == oi->keymap[i].dev && code == oi->keymap[i].code) | ||
34 | gpio_set_value(oi->keymap[i].gpio, value); | ||
35 | return 0; | ||
36 | } | ||
37 | |||
38 | int gpio_event_output_func( | ||
39 | struct gpio_event_input_devs *input_devs, struct gpio_event_info *info, | ||
40 | void **data, int func) | ||
41 | { | ||
42 | int ret; | ||
43 | int i; | ||
44 | struct gpio_event_output_info *oi; | ||
45 | oi = container_of(info, struct gpio_event_output_info, info); | ||
46 | |||
47 | if (func == GPIO_EVENT_FUNC_SUSPEND || func == GPIO_EVENT_FUNC_RESUME) | ||
48 | return 0; | ||
49 | |||
50 | if (func == GPIO_EVENT_FUNC_INIT) { | ||
51 | int output_level = !(oi->flags & GPIOEDF_ACTIVE_HIGH); | ||
52 | |||
53 | for (i = 0; i < oi->keymap_size; i++) { | ||
54 | int dev = oi->keymap[i].dev; | ||
55 | if (dev >= input_devs->count) { | ||
56 | pr_err("gpio_event_output_func: bad device " | ||
57 | "index %d >= %d for key code %d\n", | ||
58 | dev, input_devs->count, | ||
59 | oi->keymap[i].code); | ||
60 | ret = -EINVAL; | ||
61 | goto err_bad_keymap; | ||
62 | } | ||
63 | input_set_capability(input_devs->dev[dev], oi->type, | ||
64 | oi->keymap[i].code); | ||
65 | } | ||
66 | |||
67 | for (i = 0; i < oi->keymap_size; i++) { | ||
68 | ret = gpio_request(oi->keymap[i].gpio, | ||
69 | "gpio_event_output"); | ||
70 | if (ret) { | ||
71 | pr_err("gpio_event_output_func: gpio_request " | ||
72 | "failed for %d\n", oi->keymap[i].gpio); | ||
73 | goto err_gpio_request_failed; | ||
74 | } | ||
75 | ret = gpio_direction_output(oi->keymap[i].gpio, | ||
76 | output_level); | ||
77 | if (ret) { | ||
78 | pr_err("gpio_event_output_func: " | ||
79 | "gpio_direction_output failed for %d\n", | ||
80 | oi->keymap[i].gpio); | ||
81 | goto err_gpio_direction_output_failed; | ||
82 | } | ||
83 | } | ||
84 | return 0; | ||
85 | } | ||
86 | |||
87 | ret = 0; | ||
88 | for (i = oi->keymap_size - 1; i >= 0; i--) { | ||
89 | err_gpio_direction_output_failed: | ||
90 | gpio_free(oi->keymap[i].gpio); | ||
91 | err_gpio_request_failed: | ||
92 | ; | ||
93 | } | ||
94 | err_bad_keymap: | ||
95 | return ret; | ||
96 | } | ||
97 | |||
diff --git a/drivers/input/misc/isa1200.c b/drivers/input/misc/isa1200.c new file mode 100644 index 00000000000..deafa5ca2f7 --- /dev/null +++ b/drivers/input/misc/isa1200.c | |||
@@ -0,0 +1,324 @@ | |||
1 | /* | ||
2 | * ISA1200 linear virbrator driver | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public License | ||
6 | * as published by the Free Software Foundation; either version 2 | ||
7 | * of the License, or (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, | ||
17 | * MA 02110-1301, USA. | ||
18 | */ | ||
19 | #include <linux/delay.h> | ||
20 | #include <linux/errno.h> | ||
21 | #include <linux/i2c.h> | ||
22 | #include <linux/init.h> | ||
23 | #include <linux/hrtimer.h> | ||
24 | #include <linux/platform_device.h> | ||
25 | #include <linux/device.h> | ||
26 | #include <linux/kernel.h> | ||
27 | #include <linux/slab.h> | ||
28 | #include <linux/types.h> | ||
29 | #include <linux/gpio.h> | ||
30 | #include <linux/earlysuspend.h> | ||
31 | #include <linux/input/isa1200.h> | ||
32 | #include <linux/pwm.h> | ||
33 | |||
34 | #include <plat/gpio-cfg.h> | ||
35 | #include "../../staging/android/timed_output.h" | ||
36 | |||
37 | #define ISA1200_VERSION "1.0.0" | ||
38 | #define ISA1200_NAME "isa1200" | ||
39 | |||
40 | //----------------------------------------------------------------------------- | ||
41 | //----------------------------------------------------------------------------- | ||
42 | /* | ||
43 | * driver private data | ||
44 | */ | ||
45 | struct isa1200_chip { | ||
46 | struct i2c_client *i2c; | ||
47 | struct isa1200_platform_data *pdata; | ||
48 | |||
49 | struct pwm_device *pwm; | ||
50 | struct timed_output_dev timed_output; | ||
51 | |||
52 | int period; | ||
53 | int duty; | ||
54 | int pwm_id; | ||
55 | }; | ||
56 | |||
57 | //----------------------------------------------------------------------------- | ||
58 | //----------------------------------------------------------------------------- | ||
59 | enum | ||
60 | { | ||
61 | HCTRL_0 = 0x30, | ||
62 | HCTRL_1, | ||
63 | HCTRL_2, | ||
64 | HCTRL_3, | ||
65 | HCTRL_4, | ||
66 | HCTRL_5, | ||
67 | HCTRL_6, | ||
68 | HCTRL_7, | ||
69 | HCTRL_8, | ||
70 | HCTRL_9, | ||
71 | HCTRL_A, | ||
72 | HCTRL_B, | ||
73 | HCTRL_C, | ||
74 | HCTRL_D, | ||
75 | HCTRL_E, | ||
76 | HCTRL_F, | ||
77 | HCTRL_MAX = 0x40 | ||
78 | }; | ||
79 | |||
80 | //----------------------------------------------------------------------------- | ||
81 | //----------------------------------------------------------------------------- | ||
82 | static int isa1200_hw_init(struct isa1200_chip *chip) | ||
83 | { | ||
84 | struct i2c_client *client = chip->i2c; | ||
85 | int ret =0; | ||
86 | unsigned val=0; | ||
87 | |||
88 | // gpio_hen enable | ||
89 | ret = gpio_is_valid(chip->pdata->gpio_hen); | ||
90 | if (ret) { | ||
91 | ret = gpio_request(chip->pdata->gpio_hen, "gpio_hen"); | ||
92 | if (ret) { | ||
93 | dev_err(&client->dev, "gpio %d request failed\n", | ||
94 | chip->pdata->gpio_hen); | ||
95 | return -EIO; | ||
96 | } | ||
97 | ret = gpio_direction_output(chip->pdata->gpio_hen, 1); | ||
98 | if (ret) { | ||
99 | dev_err(&client->dev, "gpio %d set direction failed\n", | ||
100 | chip->pdata->gpio_hen); | ||
101 | return -EIO; | ||
102 | } | ||
103 | gpio_free(chip->pdata->gpio_hen); | ||
104 | } | ||
105 | else return -EIO; | ||
106 | |||
107 | mdelay(1); | ||
108 | |||
109 | // gpio_len enable | ||
110 | ret = gpio_is_valid(chip->pdata->gpio_len); | ||
111 | if (ret) { | ||
112 | ret = gpio_request(chip->pdata->gpio_len, "gpio_len"); | ||
113 | if (ret) { | ||
114 | dev_err(&client->dev, "gpio %d request failed\n", | ||
115 | chip->pdata->gpio_len); | ||
116 | return -EIO; | ||
117 | } | ||
118 | ret = gpio_direction_output(chip->pdata->gpio_len, 1); | ||
119 | if (ret) { | ||
120 | dev_err(&client->dev, "gpio %d set direction failed\n", | ||
121 | chip->pdata->gpio_len); | ||
122 | return -EIO; | ||
123 | } | ||
124 | gpio_free(chip->pdata->gpio_len); | ||
125 | } | ||
126 | else return -EIO; | ||
127 | |||
128 | //pwm port pin_func init | ||
129 | if (gpio_is_valid(chip->pdata->pwm_gpio)) { | ||
130 | ret = gpio_request(chip->pdata->pwm_gpio, "pwm_gpio"); | ||
131 | if (ret) | ||
132 | printk(KERN_ERR "failed to get GPIO for PWM0\n"); | ||
133 | s3c_gpio_cfgpin(chip->pdata->pwm_gpio, chip->pdata->pwm_func); | ||
134 | gpio_free(chip->pdata->pwm_gpio); | ||
135 | } | ||
136 | |||
137 | mdelay (1); | ||
138 | i2c_smbus_write_byte_data(client, HCTRL_2, 0x80); //Software reset enable | ||
139 | mdelay (1); | ||
140 | i2c_smbus_write_byte_data(client, HCTRL_2, 0x00); //Software reset disable | ||
141 | mdelay (1); | ||
142 | i2c_smbus_write_byte_data(client, HCTRL_0, 0x88); // PWM_INPUT Mode | ||
143 | |||
144 | val = i2c_smbus_read_byte_data(client, 0x00); | ||
145 | printk("%s : read val = 0x%02x\n",__func__,val); | ||
146 | |||
147 | return 0; | ||
148 | } | ||
149 | |||
150 | //----------------------------------------------------------------------------- | ||
151 | //----------------------------------------------------------------------------- | ||
152 | static void isa1200_vibrator_enable (struct timed_output_dev *dev, int value) | ||
153 | { | ||
154 | struct isa1200_chip *chip = container_of(dev, struct isa1200_chip, timed_output); | ||
155 | |||
156 | if(10<value) { | ||
157 | |||
158 | if(5<value) value -=5; | ||
159 | pwm_disable(chip->pwm); | ||
160 | pwm_config(chip->pwm, chip->duty * chip->period / 255, chip->period); | ||
161 | pwm_enable(chip->pwm); | ||
162 | msleep_interruptible(value); | ||
163 | pwm_disable(chip->pwm); | ||
164 | } | ||
165 | return; | ||
166 | } | ||
167 | |||
168 | //----------------------------------------------------------------------------- | ||
169 | //----------------------------------------------------------------------------- | ||
170 | static int isa1200_vibrator_get_time (struct timed_output_dev *dev) | ||
171 | { | ||
172 | return 0; | ||
173 | } | ||
174 | |||
175 | //----------------------------------------------------------------------------- | ||
176 | //----------------------------------------------------------------------------- | ||
177 | static struct timed_output_dev isa1200_vibrator = { | ||
178 | .name = "vibrator", | ||
179 | .get_time = isa1200_vibrator_get_time, | ||
180 | .enable = isa1200_vibrator_enable, | ||
181 | }; | ||
182 | |||
183 | //----------------------------------------------------------------------------- | ||
184 | //----------------------------------------------------------------------------- | ||
185 | static int isa1200_i2c_probe (struct i2c_client *client, const struct i2c_device_id *id) | ||
186 | { | ||
187 | struct isa1200_chip *chip; | ||
188 | struct device *dev = &client->dev; | ||
189 | int err; | ||
190 | |||
191 | /* setup i2c client */ | ||
192 | if (!i2c_check_functionality (client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { | ||
193 | dev_err(&client->dev, "i2c byte data not supported\n"); | ||
194 | return -EIO; | ||
195 | } | ||
196 | if (!client->dev.platform_data) { | ||
197 | dev_err(&client->dev, "pdata is not available\n"); | ||
198 | return -EINVAL; | ||
199 | } | ||
200 | |||
201 | chip = kzalloc (sizeof (struct isa1200_chip), GFP_KERNEL); | ||
202 | if (!chip) | ||
203 | return -ENOMEM; | ||
204 | |||
205 | chip->pdata = client->dev.platform_data; | ||
206 | chip->i2c = client; | ||
207 | i2c_set_clientdata (client, chip); | ||
208 | |||
209 | chip->pwm = pwm_request(chip->pdata->pwm_id, id->name); | ||
210 | chip->period = chip->pdata->pwm_periode_ns; | ||
211 | chip->duty = chip->pdata->pwm_duty; | ||
212 | |||
213 | pwm_disable(chip->pwm); | ||
214 | |||
215 | isa1200_hw_init(chip); | ||
216 | |||
217 | chip->timed_output = isa1200_vibrator; | ||
218 | err = timed_output_dev_register (&chip->timed_output); | ||
219 | if (err < 0) | ||
220 | goto error; | ||
221 | |||
222 | dev_set_drvdata(dev, chip); | ||
223 | |||
224 | return 0; | ||
225 | |||
226 | error: | ||
227 | kfree (chip); | ||
228 | return -1; | ||
229 | } | ||
230 | |||
231 | //----------------------------------------------------------------------------- | ||
232 | //----------------------------------------------------------------------------- | ||
233 | static int isa1200_i2c_remove (struct i2c_client *client) | ||
234 | { | ||
235 | struct isa1200_chip *isa1200 = i2c_get_clientdata (client); | ||
236 | |||
237 | timed_output_dev_unregister (&isa1200->timed_output); | ||
238 | i2c_set_clientdata (client, NULL); | ||
239 | kfree (isa1200); | ||
240 | |||
241 | return 0; | ||
242 | } | ||
243 | |||
244 | //----------------------------------------------------------------------------- | ||
245 | //----------------------------------------------------------------------------- | ||
246 | #ifdef CONFIG_PM | ||
247 | #ifdef CONFIG_HAS_EARLYSUSPEND | ||
248 | static void isa1200_early_suspend(struct early_suspend *h) | ||
249 | { | ||
250 | printk("\t%s [%d]\n",__FUNCTION__,__LINE__); | ||
251 | return; | ||
252 | } | ||
253 | |||
254 | //----------------------------------------------------------------------------- | ||
255 | //----------------------------------------------------------------------------- | ||
256 | static void isa1200_late_resume(struct early_suspend *h) | ||
257 | { | ||
258 | printk("%s\n",__FUNCTION__); | ||
259 | return; | ||
260 | } | ||
261 | |||
262 | //----------------------------------------------------------------------------- | ||
263 | //----------------------------------------------------------------------------- | ||
264 | static struct early_suspend isa1200_early_suspend_desc = { | ||
265 | .level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN, | ||
266 | .suspend = isa1200_early_suspend, | ||
267 | .resume = isa1200_late_resume | ||
268 | }; | ||
269 | #endif //CONFIG_HAS_EARLYSUSPEND | ||
270 | #endif //CONFIG_PM | ||
271 | |||
272 | //----------------------------------------------------------------------------- | ||
273 | //----------------------------------------------------------------------------- | ||
274 | static const struct i2c_device_id isa1200_id[] = { | ||
275 | {ISA1200_NAME, 0}, | ||
276 | {}, | ||
277 | }; | ||
278 | MODULE_DEVICE_TABLE (i2c, isa1200_id); | ||
279 | |||
280 | //----------------------------------------------------------------------------- | ||
281 | //----------------------------------------------------------------------------- | ||
282 | struct i2c_driver isa1200_driver = { | ||
283 | .driver = { | ||
284 | .name = "isa1200", | ||
285 | .owner = THIS_MODULE, | ||
286 | }, | ||
287 | .probe = isa1200_i2c_probe, | ||
288 | .remove = isa1200_i2c_remove, | ||
289 | .id_table = isa1200_id, | ||
290 | }; | ||
291 | |||
292 | //----------------------------------------------------------------------------- | ||
293 | //----------------------------------------------------------------------------- | ||
294 | static int __init isa1200_init (void) | ||
295 | { | ||
296 | int ret; | ||
297 | |||
298 | ret = i2c_add_driver (&isa1200_driver); | ||
299 | if (ret) { | ||
300 | printk(KERN_ERR "i2c add driver Failed %d\n", ret); | ||
301 | return -1; | ||
302 | } | ||
303 | #ifdef CONFIG_HAS_EARLYSUSPEND | ||
304 | register_early_suspend(&isa1200_early_suspend_desc); | ||
305 | #endif | ||
306 | return 0; | ||
307 | } | ||
308 | module_init (isa1200_init); | ||
309 | |||
310 | //----------------------------------------------------------------------------- | ||
311 | //----------------------------------------------------------------------------- | ||
312 | static void __exit isa1200_exit (void) | ||
313 | { | ||
314 | #ifdef CONFIG_HAS_EARLYSUSPEND | ||
315 | unregister_early_suspend(&isa1200_early_suspend_desc); | ||
316 | #endif | ||
317 | i2c_del_driver (&isa1200_driver); | ||
318 | } | ||
319 | module_exit (isa1200_exit); | ||
320 | |||
321 | |||
322 | MODULE_LICENSE ("GPL"); | ||
323 | MODULE_DESCRIPTION ("ISA1200 linear virbrator driver"); | ||
324 | MODULE_VERSION (ISA1200_VERSION); | ||
diff --git a/drivers/input/misc/keychord.c b/drivers/input/misc/keychord.c new file mode 100644 index 00000000000..3ffab6da411 --- /dev/null +++ b/drivers/input/misc/keychord.c | |||
@@ -0,0 +1,387 @@ | |||
1 | /* | ||
2 | * drivers/input/misc/keychord.c | ||
3 | * | ||
4 | * Copyright (C) 2008 Google, Inc. | ||
5 | * Author: Mike Lockwood <lockwood@android.com> | ||
6 | * | ||
7 | * This software is licensed under the terms of the GNU General Public | ||
8 | * License version 2, as published by the Free Software Foundation, and | ||
9 | * may be copied, distributed, and modified under those terms. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | */ | ||
17 | |||
18 | #include <linux/poll.h> | ||
19 | #include <linux/slab.h> | ||
20 | #include <linux/module.h> | ||
21 | #include <linux/init.h> | ||
22 | #include <linux/spinlock.h> | ||
23 | #include <linux/fs.h> | ||
24 | #include <linux/miscdevice.h> | ||
25 | #include <linux/keychord.h> | ||
26 | #include <linux/sched.h> | ||
27 | |||
28 | #define KEYCHORD_NAME "keychord" | ||
29 | #define BUFFER_SIZE 16 | ||
30 | |||
31 | MODULE_AUTHOR("Mike Lockwood <lockwood@android.com>"); | ||
32 | MODULE_DESCRIPTION("Key chord input driver"); | ||
33 | MODULE_SUPPORTED_DEVICE("keychord"); | ||
34 | MODULE_LICENSE("GPL"); | ||
35 | |||
36 | #define NEXT_KEYCHORD(kc) ((struct input_keychord *) \ | ||
37 | ((char *)kc + sizeof(struct input_keychord) + \ | ||
38 | kc->count * sizeof(kc->keycodes[0]))) | ||
39 | |||
40 | struct keychord_device { | ||
41 | struct input_handler input_handler; | ||
42 | int registered; | ||
43 | |||
44 | /* list of keychords to monitor */ | ||
45 | struct input_keychord *keychords; | ||
46 | int keychord_count; | ||
47 | |||
48 | /* bitmask of keys contained in our keychords */ | ||
49 | unsigned long keybit[BITS_TO_LONGS(KEY_CNT)]; | ||
50 | /* current state of the keys */ | ||
51 | unsigned long keystate[BITS_TO_LONGS(KEY_CNT)]; | ||
52 | /* number of keys that are currently pressed */ | ||
53 | int key_down; | ||
54 | |||
55 | /* second input_device_id is needed for null termination */ | ||
56 | struct input_device_id device_ids[2]; | ||
57 | |||
58 | spinlock_t lock; | ||
59 | wait_queue_head_t waitq; | ||
60 | unsigned char head; | ||
61 | unsigned char tail; | ||
62 | __u16 buff[BUFFER_SIZE]; | ||
63 | }; | ||
64 | |||
65 | static int check_keychord(struct keychord_device *kdev, | ||
66 | struct input_keychord *keychord) | ||
67 | { | ||
68 | int i; | ||
69 | |||
70 | if (keychord->count != kdev->key_down) | ||
71 | return 0; | ||
72 | |||
73 | for (i = 0; i < keychord->count; i++) { | ||
74 | if (!test_bit(keychord->keycodes[i], kdev->keystate)) | ||
75 | return 0; | ||
76 | } | ||
77 | |||
78 | /* we have a match */ | ||
79 | return 1; | ||
80 | } | ||
81 | |||
82 | static void keychord_event(struct input_handle *handle, unsigned int type, | ||
83 | unsigned int code, int value) | ||
84 | { | ||
85 | struct keychord_device *kdev = handle->private; | ||
86 | struct input_keychord *keychord; | ||
87 | unsigned long flags; | ||
88 | int i, got_chord = 0; | ||
89 | |||
90 | if (type != EV_KEY || code >= KEY_MAX) | ||
91 | return; | ||
92 | |||
93 | spin_lock_irqsave(&kdev->lock, flags); | ||
94 | /* do nothing if key state did not change */ | ||
95 | if (!test_bit(code, kdev->keystate) == !value) | ||
96 | goto done; | ||
97 | __change_bit(code, kdev->keystate); | ||
98 | if (value) | ||
99 | kdev->key_down++; | ||
100 | else | ||
101 | kdev->key_down--; | ||
102 | |||
103 | /* don't notify on key up */ | ||
104 | if (!value) | ||
105 | goto done; | ||
106 | /* ignore this event if it is not one of the keys we are monitoring */ | ||
107 | if (!test_bit(code, kdev->keybit)) | ||
108 | goto done; | ||
109 | |||
110 | keychord = kdev->keychords; | ||
111 | if (!keychord) | ||
112 | goto done; | ||
113 | |||
114 | /* check to see if the keyboard state matches any keychords */ | ||
115 | for (i = 0; i < kdev->keychord_count; i++) { | ||
116 | if (check_keychord(kdev, keychord)) { | ||
117 | kdev->buff[kdev->head] = keychord->id; | ||
118 | kdev->head = (kdev->head + 1) % BUFFER_SIZE; | ||
119 | got_chord = 1; | ||
120 | break; | ||
121 | } | ||
122 | /* skip to next keychord */ | ||
123 | keychord = NEXT_KEYCHORD(keychord); | ||
124 | } | ||
125 | |||
126 | done: | ||
127 | spin_unlock_irqrestore(&kdev->lock, flags); | ||
128 | |||
129 | if (got_chord) | ||
130 | wake_up_interruptible(&kdev->waitq); | ||
131 | } | ||
132 | |||
133 | static int keychord_connect(struct input_handler *handler, | ||
134 | struct input_dev *dev, | ||
135 | const struct input_device_id *id) | ||
136 | { | ||
137 | int i, ret; | ||
138 | struct input_handle *handle; | ||
139 | struct keychord_device *kdev = | ||
140 | container_of(handler, struct keychord_device, input_handler); | ||
141 | |||
142 | /* | ||
143 | * ignore this input device if it does not contain any keycodes | ||
144 | * that we are monitoring | ||
145 | */ | ||
146 | for (i = 0; i < KEY_MAX; i++) { | ||
147 | if (test_bit(i, kdev->keybit) && test_bit(i, dev->keybit)) | ||
148 | break; | ||
149 | } | ||
150 | if (i == KEY_MAX) | ||
151 | return -ENODEV; | ||
152 | |||
153 | handle = kzalloc(sizeof(*handle), GFP_KERNEL); | ||
154 | if (!handle) | ||
155 | return -ENOMEM; | ||
156 | |||
157 | handle->dev = dev; | ||
158 | handle->handler = handler; | ||
159 | handle->name = KEYCHORD_NAME; | ||
160 | handle->private = kdev; | ||
161 | |||
162 | ret = input_register_handle(handle); | ||
163 | if (ret) | ||
164 | goto err_input_register_handle; | ||
165 | |||
166 | ret = input_open_device(handle); | ||
167 | if (ret) | ||
168 | goto err_input_open_device; | ||
169 | |||
170 | pr_info("keychord: using input dev %s for fevent\n", dev->name); | ||
171 | |||
172 | return 0; | ||
173 | |||
174 | err_input_open_device: | ||
175 | input_unregister_handle(handle); | ||
176 | err_input_register_handle: | ||
177 | kfree(handle); | ||
178 | return ret; | ||
179 | } | ||
180 | |||
181 | static void keychord_disconnect(struct input_handle *handle) | ||
182 | { | ||
183 | input_close_device(handle); | ||
184 | input_unregister_handle(handle); | ||
185 | kfree(handle); | ||
186 | } | ||
187 | |||
188 | /* | ||
189 | * keychord_read is used to read keychord events from the driver | ||
190 | */ | ||
191 | static ssize_t keychord_read(struct file *file, char __user *buffer, | ||
192 | size_t count, loff_t *ppos) | ||
193 | { | ||
194 | struct keychord_device *kdev = file->private_data; | ||
195 | __u16 id; | ||
196 | int retval; | ||
197 | unsigned long flags; | ||
198 | |||
199 | if (count < sizeof(id)) | ||
200 | return -EINVAL; | ||
201 | count = sizeof(id); | ||
202 | |||
203 | if (kdev->head == kdev->tail && (file->f_flags & O_NONBLOCK)) | ||
204 | return -EAGAIN; | ||
205 | |||
206 | retval = wait_event_interruptible(kdev->waitq, | ||
207 | kdev->head != kdev->tail); | ||
208 | if (retval) | ||
209 | return retval; | ||
210 | |||
211 | spin_lock_irqsave(&kdev->lock, flags); | ||
212 | /* pop a keychord ID off the queue */ | ||
213 | id = kdev->buff[kdev->tail]; | ||
214 | kdev->tail = (kdev->tail + 1) % BUFFER_SIZE; | ||
215 | spin_unlock_irqrestore(&kdev->lock, flags); | ||
216 | |||
217 | if (copy_to_user(buffer, &id, count)) | ||
218 | return -EFAULT; | ||
219 | |||
220 | return count; | ||
221 | } | ||
222 | |||
223 | /* | ||
224 | * keychord_write is used to configure the driver | ||
225 | */ | ||
226 | static ssize_t keychord_write(struct file *file, const char __user *buffer, | ||
227 | size_t count, loff_t *ppos) | ||
228 | { | ||
229 | struct keychord_device *kdev = file->private_data; | ||
230 | struct input_keychord *keychords = 0; | ||
231 | struct input_keychord *keychord, *next, *end; | ||
232 | int ret, i, key; | ||
233 | unsigned long flags; | ||
234 | |||
235 | if (count < sizeof(struct input_keychord)) | ||
236 | return -EINVAL; | ||
237 | keychords = kzalloc(count, GFP_KERNEL); | ||
238 | if (!keychords) | ||
239 | return -ENOMEM; | ||
240 | |||
241 | /* read list of keychords from userspace */ | ||
242 | if (copy_from_user(keychords, buffer, count)) { | ||
243 | kfree(keychords); | ||
244 | return -EFAULT; | ||
245 | } | ||
246 | |||
247 | /* unregister handler before changing configuration */ | ||
248 | if (kdev->registered) { | ||
249 | input_unregister_handler(&kdev->input_handler); | ||
250 | kdev->registered = 0; | ||
251 | } | ||
252 | |||
253 | spin_lock_irqsave(&kdev->lock, flags); | ||
254 | /* clear any existing configuration */ | ||
255 | kfree(kdev->keychords); | ||
256 | kdev->keychords = 0; | ||
257 | kdev->keychord_count = 0; | ||
258 | kdev->key_down = 0; | ||
259 | memset(kdev->keybit, 0, sizeof(kdev->keybit)); | ||
260 | memset(kdev->keystate, 0, sizeof(kdev->keystate)); | ||
261 | kdev->head = kdev->tail = 0; | ||
262 | |||
263 | keychord = keychords; | ||
264 | end = (struct input_keychord *)((char *)keychord + count); | ||
265 | |||
266 | while (keychord < end) { | ||
267 | next = NEXT_KEYCHORD(keychord); | ||
268 | if (keychord->count <= 0 || next > end) { | ||
269 | pr_err("keychord: invalid keycode count %d\n", | ||
270 | keychord->count); | ||
271 | goto err_unlock_return; | ||
272 | } | ||
273 | if (keychord->version != KEYCHORD_VERSION) { | ||
274 | pr_err("keychord: unsupported version %d\n", | ||
275 | keychord->version); | ||
276 | goto err_unlock_return; | ||
277 | } | ||
278 | |||
279 | /* keep track of the keys we are monitoring in keybit */ | ||
280 | for (i = 0; i < keychord->count; i++) { | ||
281 | key = keychord->keycodes[i]; | ||
282 | if (key < 0 || key >= KEY_CNT) { | ||
283 | pr_err("keychord: keycode %d out of range\n", | ||
284 | key); | ||
285 | goto err_unlock_return; | ||
286 | } | ||
287 | __set_bit(key, kdev->keybit); | ||
288 | } | ||
289 | |||
290 | kdev->keychord_count++; | ||
291 | keychord = next; | ||
292 | } | ||
293 | |||
294 | kdev->keychords = keychords; | ||
295 | spin_unlock_irqrestore(&kdev->lock, flags); | ||
296 | |||
297 | ret = input_register_handler(&kdev->input_handler); | ||
298 | if (ret) { | ||
299 | kfree(keychords); | ||
300 | kdev->keychords = 0; | ||
301 | return ret; | ||
302 | } | ||
303 | kdev->registered = 1; | ||
304 | |||
305 | return count; | ||
306 | |||
307 | err_unlock_return: | ||
308 | spin_unlock_irqrestore(&kdev->lock, flags); | ||
309 | kfree(keychords); | ||
310 | return -EINVAL; | ||
311 | } | ||
312 | |||
313 | static unsigned int keychord_poll(struct file *file, poll_table *wait) | ||
314 | { | ||
315 | struct keychord_device *kdev = file->private_data; | ||
316 | |||
317 | poll_wait(file, &kdev->waitq, wait); | ||
318 | |||
319 | if (kdev->head != kdev->tail) | ||
320 | return POLLIN | POLLRDNORM; | ||
321 | |||
322 | return 0; | ||
323 | } | ||
324 | |||
325 | static int keychord_open(struct inode *inode, struct file *file) | ||
326 | { | ||
327 | struct keychord_device *kdev; | ||
328 | |||
329 | kdev = kzalloc(sizeof(struct keychord_device), GFP_KERNEL); | ||
330 | if (!kdev) | ||
331 | return -ENOMEM; | ||
332 | |||
333 | spin_lock_init(&kdev->lock); | ||
334 | init_waitqueue_head(&kdev->waitq); | ||
335 | |||
336 | kdev->input_handler.event = keychord_event; | ||
337 | kdev->input_handler.connect = keychord_connect; | ||
338 | kdev->input_handler.disconnect = keychord_disconnect; | ||
339 | kdev->input_handler.name = KEYCHORD_NAME; | ||
340 | kdev->input_handler.id_table = kdev->device_ids; | ||
341 | |||
342 | kdev->device_ids[0].flags = INPUT_DEVICE_ID_MATCH_EVBIT; | ||
343 | __set_bit(EV_KEY, kdev->device_ids[0].evbit); | ||
344 | |||
345 | file->private_data = kdev; | ||
346 | |||
347 | return 0; | ||
348 | } | ||
349 | |||
350 | static int keychord_release(struct inode *inode, struct file *file) | ||
351 | { | ||
352 | struct keychord_device *kdev = file->private_data; | ||
353 | |||
354 | if (kdev->registered) | ||
355 | input_unregister_handler(&kdev->input_handler); | ||
356 | kfree(kdev); | ||
357 | |||
358 | return 0; | ||
359 | } | ||
360 | |||
361 | static const struct file_operations keychord_fops = { | ||
362 | .owner = THIS_MODULE, | ||
363 | .open = keychord_open, | ||
364 | .release = keychord_release, | ||
365 | .read = keychord_read, | ||
366 | .write = keychord_write, | ||
367 | .poll = keychord_poll, | ||
368 | }; | ||
369 | |||
370 | static struct miscdevice keychord_misc = { | ||
371 | .fops = &keychord_fops, | ||
372 | .name = KEYCHORD_NAME, | ||
373 | .minor = MISC_DYNAMIC_MINOR, | ||
374 | }; | ||
375 | |||
376 | static int __init keychord_init(void) | ||
377 | { | ||
378 | return misc_register(&keychord_misc); | ||
379 | } | ||
380 | |||
381 | static void __exit keychord_exit(void) | ||
382 | { | ||
383 | misc_deregister(&keychord_misc); | ||
384 | } | ||
385 | |||
386 | module_init(keychord_init); | ||
387 | module_exit(keychord_exit); | ||
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index cabd9e54863..9548d1ac272 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig | |||
@@ -11,6 +11,19 @@ menuconfig INPUT_TOUCHSCREEN | |||
11 | 11 | ||
12 | if INPUT_TOUCHSCREEN | 12 | if INPUT_TOUCHSCREEN |
13 | 13 | ||
14 | config TOUCHSCREEN_DUMMY | ||
15 | bool "ODROID Dummy touchscreen driver" | ||
16 | depends on MACH_ODROID_4210 || MACH_ODROID_4X12 | ||
17 | default n | ||
18 | ---help--- | ||
19 | This enables support for ODROID default Touch panel | ||
20 | |||
21 | config TOUCHSCREEN_SOLOMON_MT | ||
22 | bool "Solomon 10.1\" WXGA multi touch panel(I2C Driver)" | ||
23 | default n | ||
24 | ---help--- | ||
25 | This enables support for ODROID-Q 10.1\" WXGA Touch panel (Multi-Touch) | ||
26 | |||
14 | config TOUCHSCREEN_88PM860X | 27 | config TOUCHSCREEN_88PM860X |
15 | tristate "Marvell 88PM860x touchscreen" | 28 | tristate "Marvell 88PM860x touchscreen" |
16 | depends on MFD_88PM860X | 29 | depends on MFD_88PM860X |
@@ -192,8 +205,7 @@ config TOUCHSCREEN_FUJITSU | |||
192 | 205 | ||
193 | config TOUCHSCREEN_S3C2410 | 206 | config TOUCHSCREEN_S3C2410 |
194 | tristate "Samsung S3C2410/generic touchscreen input driver" | 207 | tristate "Samsung S3C2410/generic touchscreen input driver" |
195 | depends on ARCH_S3C2410 || SAMSUNG_DEV_TS | 208 | depends on ARCH_S3C2410 || SAMSUNG_DEV_TS && S3C_ADC |
196 | select S3C_ADC | ||
197 | help | 209 | help |
198 | Say Y here if you have the s3c2410 touchscreen. | 210 | Say Y here if you have the s3c2410 touchscreen. |
199 | 211 | ||
@@ -202,6 +214,24 @@ config TOUCHSCREEN_S3C2410 | |||
202 | To compile this driver as a module, choose M here: the | 214 | To compile this driver as a module, choose M here: the |
203 | module will be called s3c2410_ts. | 215 | module will be called s3c2410_ts. |
204 | 216 | ||
217 | config TOUCHSCREEN_EXYNOS4 | ||
218 | tristate "Samsung EXYNOS4 10.1\" touchscreen input driver" | ||
219 | depends on ARCH_EXYNOS4 | ||
220 | help | ||
221 | Say Y here if you have the EXYNOS4 touchscreen. | ||
222 | |||
223 | config TOUCHSCREEN_PIXCIR | ||
224 | tristate "PIXCIR 5\" touchscreen input driver" | ||
225 | depends on ARCH_EXYNOS4 | ||
226 | help | ||
227 | Say Y here if you have the Pixcir 5" touchscreen. | ||
228 | |||
229 | config TOUCHSCREEN_EGALAX | ||
230 | tristate "EGALAX 10.1\" touchscreen input driver" | ||
231 | depends on ARCH_EXYNOS5 | ||
232 | help | ||
233 | Say Y here if you have the Egalax 10.1\" touchscreen. | ||
234 | |||
205 | config TOUCHSCREEN_GUNZE | 235 | config TOUCHSCREEN_GUNZE |
206 | tristate "Gunze AHL-51S touchscreen" | 236 | tristate "Gunze AHL-51S touchscreen" |
207 | select SERIO | 237 | select SERIO |
@@ -383,6 +413,12 @@ config TOUCHSCREEN_TNETV107X | |||
383 | To compile this driver as a module, choose M here: the | 413 | To compile this driver as a module, choose M here: the |
384 | module will be called tnetv107x-ts. | 414 | module will be called tnetv107x-ts. |
385 | 415 | ||
416 | config TOUCHSCREEN_SYNAPTICS_I2C_RMI | ||
417 | tristate "Synaptics i2c touchscreen" | ||
418 | depends on I2C | ||
419 | help | ||
420 | This enables support for Synaptics RMI over I2C based touchscreens. | ||
421 | |||
386 | config TOUCHSCREEN_TOUCHRIGHT | 422 | config TOUCHSCREEN_TOUCHRIGHT |
387 | tristate "Touchright serial touchscreen" | 423 | tristate "Touchright serial touchscreen" |
388 | select SERIO | 424 | select SERIO |
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 282d6f76ae2..0223142024f 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile | |||
@@ -22,6 +22,7 @@ obj-$(CONFIG_TOUCHSCREEN_DYNAPRO) += dynapro.o | |||
22 | obj-$(CONFIG_TOUCHSCREEN_HAMPSHIRE) += hampshire.o | 22 | obj-$(CONFIG_TOUCHSCREEN_HAMPSHIRE) += hampshire.o |
23 | obj-$(CONFIG_TOUCHSCREEN_GUNZE) += gunze.o | 23 | obj-$(CONFIG_TOUCHSCREEN_GUNZE) += gunze.o |
24 | obj-$(CONFIG_TOUCHSCREEN_EETI) += eeti_ts.o | 24 | obj-$(CONFIG_TOUCHSCREEN_EETI) += eeti_ts.o |
25 | obj-$(CONFIG_TOUCHSCREEN_EGALAX) += egalax_i2c.o | ||
25 | obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o | 26 | obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o |
26 | obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o | 27 | obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o |
27 | obj-$(CONFIG_TOUCHSCREEN_INEXIO) += inexio.o | 28 | obj-$(CONFIG_TOUCHSCREEN_INEXIO) += inexio.o |
@@ -40,9 +41,12 @@ obj-$(CONFIG_TOUCHSCREEN_USB_COMPOSITE) += usbtouchscreen.o | |||
40 | obj-$(CONFIG_TOUCHSCREEN_PCAP) += pcap_ts.o | 41 | obj-$(CONFIG_TOUCHSCREEN_PCAP) += pcap_ts.o |
41 | obj-$(CONFIG_TOUCHSCREEN_PENMOUNT) += penmount.o | 42 | obj-$(CONFIG_TOUCHSCREEN_PENMOUNT) += penmount.o |
42 | obj-$(CONFIG_TOUCHSCREEN_S3C2410) += s3c2410_ts.o | 43 | obj-$(CONFIG_TOUCHSCREEN_S3C2410) += s3c2410_ts.o |
44 | obj-$(CONFIG_TOUCHSCREEN_EXYNOS4) += s5pc210_ts.o s5pc210_ts_gpio_i2c.o s5pc210_ts_sysfs.o | ||
45 | obj-$(CONFIG_TOUCHSCREEN_PIXCIR) += pixcir_i2c_ts.o | ||
43 | obj-$(CONFIG_TOUCHSCREEN_ST1232) += st1232.o | 46 | obj-$(CONFIG_TOUCHSCREEN_ST1232) += st1232.o |
44 | obj-$(CONFIG_TOUCHSCREEN_STMPE) += stmpe-ts.o | 47 | obj-$(CONFIG_TOUCHSCREEN_STMPE) += stmpe-ts.o |
45 | obj-$(CONFIG_TOUCHSCREEN_TNETV107X) += tnetv107x-ts.o | 48 | obj-$(CONFIG_TOUCHSCREEN_TNETV107X) += tnetv107x-ts.o |
49 | obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI) += synaptics_i2c_rmi.o | ||
46 | obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213) += touchit213.o | 50 | obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213) += touchit213.o |
47 | obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o | 51 | obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o |
48 | obj-$(CONFIG_TOUCHSCREEN_TOUCHWIN) += touchwin.o | 52 | obj-$(CONFIG_TOUCHSCREEN_TOUCHWIN) += touchwin.o |
@@ -60,3 +64,6 @@ obj-$(CONFIG_TOUCHSCREEN_WM97XX_MAINSTONE) += mainstone-wm97xx.o | |||
60 | obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE) += zylonite-wm97xx.o | 64 | obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE) += zylonite-wm97xx.o |
61 | obj-$(CONFIG_TOUCHSCREEN_W90X900) += w90p910_ts.o | 65 | obj-$(CONFIG_TOUCHSCREEN_W90X900) += w90p910_ts.o |
62 | obj-$(CONFIG_TOUCHSCREEN_TPS6507X) += tps6507x-ts.o | 66 | obj-$(CONFIG_TOUCHSCREEN_TPS6507X) += tps6507x-ts.o |
67 | # for ODROID-Q | ||
68 | obj-$(CONFIG_TOUCHSCREEN_SOLOMON_MT) += touch.o touch-i2c.o touch-sysfs.o odroidq-touch.o | ||
69 | obj-$(CONFIG_TOUCHSCREEN_DUMMY) += touch.o touch-i2c.o touch-sysfs.o | ||
diff --git a/drivers/input/touchscreen/egalax_i2c.c b/drivers/input/touchscreen/egalax_i2c.c new file mode 100644 index 00000000000..c47f98c48f7 --- /dev/null +++ b/drivers/input/touchscreen/egalax_i2c.c | |||
@@ -0,0 +1,962 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Touch Screen I2C Driver for EETI Controller | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | */ | ||
16 | |||
17 | #include <linux/module.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/kernel.h> | ||
20 | #include <linux/interrupt.h> | ||
21 | #include <linux/wait.h> | ||
22 | #include <linux/delay.h> | ||
23 | #include <linux/platform_device.h> | ||
24 | #include <linux/freezer.h> | ||
25 | #include <linux/proc_fs.h> | ||
26 | #include <linux/clk.h> | ||
27 | #include <linux/i2c.h> | ||
28 | #include <mach/regs-gpio.h> | ||
29 | #include <linux/gpio.h> | ||
30 | #include <linux/device.h> | ||
31 | #include <linux/cdev.h> | ||
32 | #include <linux/io.h> | ||
33 | #include <asm/system.h> | ||
34 | #include <linux/uaccess.h> | ||
35 | #include <linux/poll.h> | ||
36 | #include <linux/kfifo.h> | ||
37 | #include <linux/version.h> | ||
38 | #include <linux/input.h> | ||
39 | #include <linux/irq.h> | ||
40 | #include <linux/timer.h> | ||
41 | #include <linux/proc_fs.h> | ||
42 | #include <plat/gpio-cfg.h> | ||
43 | #include <mach/regs-gpio.h> | ||
44 | #include <mach/gpio.h> | ||
45 | |||
46 | #ifdef CONFIG_HAS_EARLYSUSPEND | ||
47 | #include <linux/earlysuspend.h> | ||
48 | static struct early_suspend egalax_early_suspend; | ||
49 | #endif | ||
50 | |||
51 | /* Global define to enable function */ | ||
52 | #define _ENABLE_DBG_LEVEL | ||
53 | |||
54 | static int global_major; /* dynamic major by default */ | ||
55 | static int global_minor; | ||
56 | |||
57 | #define MAX_I2C_LEN 10 | ||
58 | #define FIFO_SIZE PAGE_SIZE | ||
59 | #define MAX_SUPPORT_POINT 5 | ||
60 | #define REPORTID_MOUSE 0x01 | ||
61 | #define REPORTID_VENDOR 0x03 | ||
62 | #define REPORTID_MTOUCH 0x04 | ||
63 | |||
64 | /* ioctl command */ | ||
65 | #define EGALAX_IOC_MAGIC 0x72 | ||
66 | #define EGALAX_IOCWAKEUP _IO(EGALAX_IOC_MAGIC, 1) | ||
67 | #define EGALAX_IOC_MAXNR 1 | ||
68 | |||
69 | /* running mode */ | ||
70 | #define MODE_STOP 0 | ||
71 | #define MODE_WORKING 1 | ||
72 | #define MODE_IDLE 2 | ||
73 | #define MODE_SUSPEND 3 | ||
74 | |||
75 | #define EGALAX_MAX 2048 | ||
76 | #define SCREEN_WIDTH 1280 | ||
77 | #define SCREEN_HIGH 800 | ||
78 | |||
79 | struct point_data { | ||
80 | short Status; | ||
81 | short X; | ||
82 | short Y; | ||
83 | }; | ||
84 | |||
85 | struct egalax_i2c_platform_data { | ||
86 | unsigned int gpio_int; | ||
87 | unsigned int gpio_en; | ||
88 | unsigned int gpio_rst; | ||
89 | }; | ||
90 | |||
91 | struct _egalax_i2c { | ||
92 | struct egalax_i2c_platform_data *pdata; | ||
93 | struct workqueue_struct *ktouch_wq; | ||
94 | struct work_struct work_irq; | ||
95 | struct work_struct work_idle; | ||
96 | struct mutex mutex_wq; | ||
97 | struct i2c_client *client; | ||
98 | unsigned char work_state; | ||
99 | unsigned char skip_packet; | ||
100 | unsigned char downCnt; | ||
101 | struct timer_list idle_timer; | ||
102 | }; | ||
103 | |||
104 | struct egalax_char_dev { | ||
105 | int OpenCnts; | ||
106 | struct cdev cdev; | ||
107 | struct kfifo DataKFiFo; | ||
108 | unsigned char *pFiFoBuf; | ||
109 | spinlock_t FiFoLock; | ||
110 | struct semaphore sem; | ||
111 | wait_queue_head_t fifo_inq; | ||
112 | }; | ||
113 | |||
114 | static struct _egalax_i2c *p_egalax_i2c_dev; | ||
115 | static struct egalax_char_dev *p_char_dev; | ||
116 | static atomic_t egalax_char_available = ATOMIC_INIT(1); | ||
117 | static atomic_t wait_command_ack = ATOMIC_INIT(0); | ||
118 | static struct class *egalax_class; | ||
119 | static struct input_dev *input_dev; | ||
120 | static struct point_data PointBuf[MAX_SUPPORT_POINT]; | ||
121 | |||
122 | struct mutex i2c_lock; | ||
123 | |||
124 | #define DBG_MODULE 0x00000001 | ||
125 | #define DBG_CDEV 0x00000002 | ||
126 | #define DBG_PROC 0x00000004 | ||
127 | #define DBG_POINT 0x00000008 | ||
128 | #define DBG_INT 0x00000010 | ||
129 | #define DBG_I2C 0x00000020 | ||
130 | #define DBG_SUSP 0x00000040 | ||
131 | #define DBG_INPUT 0x00000080 | ||
132 | #define DBG_CONST 0x00000100 | ||
133 | #define DBG_IDLE 0x00000200 | ||
134 | #define DBG_WAKEUP 0x00000400 | ||
135 | #define DBG_BUTTON 0x00000800 | ||
136 | static unsigned int DbgLevel; /* DBG_INT|DBG_MODULE|DBG_SUSP|DBG_WAKEUP */ | ||
137 | |||
138 | #ifdef _ENABLE_DBG_LEVEL | ||
139 | #define PROC_FS_NAME "egalax_dbg" | ||
140 | #define PROC_FS_MAX_LEN 8 | ||
141 | static struct proc_dir_entry *dbgProcFile; | ||
142 | #endif | ||
143 | |||
144 | #define EGALAX_DBG(level, fmt, args...) { if ((level&DbgLevel) > 0) \ | ||
145 | printk(KERN_INFO "[egalax_i2c]: " fmt, ## args); } | ||
146 | #define IDLE_INTERVAL HZ/20 /* 50ms */ | ||
147 | |||
148 | static int sendLoopback(struct i2c_client *client) | ||
149 | { | ||
150 | u8 cmdbuf[MAX_I2C_LEN] = {0x03, 0x03, 0x0A, 0x01, 0x41, 0, 0, 0, 0, 0}; | ||
151 | int ret; | ||
152 | ret = 0; | ||
153 | mutex_lock(&i2c_lock); | ||
154 | if (i2c_master_send(client, cmdbuf, MAX_I2C_LEN) != MAX_I2C_LEN) { | ||
155 | ret = -1; | ||
156 | printk("TS-SendLoopback (I2C Write)Error\n"); | ||
157 | } | ||
158 | mutex_unlock(&i2c_lock); | ||
159 | return ret; | ||
160 | } | ||
161 | |||
162 | static int wakeup_controller(int irq) | ||
163 | { | ||
164 | int ret = 0; | ||
165 | int gpio = p_egalax_i2c_dev->pdata->gpio_int; | ||
166 | |||
167 | if (gpio_get_value(gpio)) { | ||
168 | gpio_direction_output(gpio, 0); | ||
169 | barrier(); | ||
170 | mdelay(5); | ||
171 | } | ||
172 | |||
173 | gpio_direction_output(gpio, 1); | ||
174 | gpio_direction_input(gpio); | ||
175 | EGALAX_DBG(DBG_WAKEUP, " INT wakeup touch controller done\n"); | ||
176 | |||
177 | return ret; | ||
178 | } | ||
179 | |||
180 | static int egalax_cdev_open(struct inode *inode, struct file *filp) | ||
181 | { | ||
182 | struct egalax_char_dev *cdev; | ||
183 | |||
184 | cdev = container_of(inode->i_cdev, struct egalax_char_dev, cdev); | ||
185 | if (cdev == NULL) { | ||
186 | EGALAX_DBG(DBG_CDEV, "No such char device node\n"); | ||
187 | return -ENODEV; | ||
188 | } | ||
189 | |||
190 | if (!atomic_dec_and_test(&egalax_char_available)) { | ||
191 | atomic_inc(&egalax_char_available); | ||
192 | return -EBUSY; /* already open */ | ||
193 | } | ||
194 | |||
195 | cdev->OpenCnts++; | ||
196 | filp->private_data = cdev;/* Used by the read and write metheds */ | ||
197 | |||
198 | /* check and wakeup controller if necessary */ | ||
199 | del_timer_sync(&p_egalax_i2c_dev->idle_timer); | ||
200 | cancel_work_sync(&p_egalax_i2c_dev->work_idle); | ||
201 | if (p_egalax_i2c_dev->work_state == MODE_IDLE) | ||
202 | wakeup_controller(p_egalax_i2c_dev->client->irq); | ||
203 | |||
204 | EGALAX_DBG(DBG_CDEV, " CDev open done!\n"); | ||
205 | try_module_get(THIS_MODULE); | ||
206 | return 0; | ||
207 | } | ||
208 | |||
209 | static int egalax_cdev_release(struct inode *inode, struct file *filp) | ||
210 | { | ||
211 | struct egalax_char_dev *cdev;/* device information */ | ||
212 | |||
213 | cdev = container_of(inode->i_cdev, struct egalax_char_dev, cdev); | ||
214 | if (cdev == NULL) { | ||
215 | EGALAX_DBG(DBG_CDEV, "No such char device node\n"); | ||
216 | return -ENODEV; | ||
217 | } | ||
218 | |||
219 | atomic_inc(&egalax_char_available); /* release the device */ | ||
220 | |||
221 | filp->private_data = NULL; | ||
222 | cdev->OpenCnts--; | ||
223 | |||
224 | kfifo_reset(&cdev->DataKFiFo); | ||
225 | |||
226 | mod_timer(&p_egalax_i2c_dev->idle_timer, jiffies+IDLE_INTERVAL); | ||
227 | |||
228 | EGALAX_DBG(DBG_CDEV, "CDev release done!\n"); | ||
229 | module_put(THIS_MODULE); | ||
230 | return 0; | ||
231 | } | ||
232 | |||
233 | #define MAX_READ_BUF_LEN 50 | ||
234 | static char fifo_read_buf[MAX_READ_BUF_LEN]; | ||
235 | static ssize_t egalax_cdev_read(struct file *file, char __user *buf, | ||
236 | size_t count, loff_t *offset) | ||
237 | { | ||
238 | int read_cnt, ret, fifoLen; | ||
239 | struct egalax_char_dev *cdev = file->private_data; | ||
240 | |||
241 | if (down_interruptible(&cdev->sem)) | ||
242 | return -ERESTARTSYS; | ||
243 | |||
244 | fifoLen = kfifo_len(&cdev->DataKFiFo); | ||
245 | |||
246 | while (fifoLen < 1) { /* nothing to read */ | ||
247 | up(&cdev->sem); /* release the lock */ | ||
248 | if (file->f_flags & O_NONBLOCK) | ||
249 | return -EAGAIN; | ||
250 | |||
251 | if (wait_event_interruptible(cdev->fifo_inq, | ||
252 | kfifo_len(&cdev->DataKFiFo) > 0)) { | ||
253 | return -ERESTARTSYS; | ||
254 | } | ||
255 | |||
256 | if (down_interruptible(&cdev->sem)) | ||
257 | return -ERESTARTSYS; | ||
258 | } | ||
259 | |||
260 | if (count > MAX_READ_BUF_LEN) | ||
261 | count = MAX_READ_BUF_LEN; | ||
262 | |||
263 | EGALAX_DBG(DBG_CDEV, " \"%s\" reading fifo data\n", current->comm); | ||
264 | read_cnt = kfifo_out_locked(&cdev->DataKFiFo, fifo_read_buf, | ||
265 | count, &cdev->FiFoLock); | ||
266 | |||
267 | ret = copy_to_user(buf, fifo_read_buf, read_cnt) ? -EFAULT : read_cnt; | ||
268 | |||
269 | up(&cdev->sem); | ||
270 | |||
271 | return ret; | ||
272 | } | ||
273 | |||
274 | static ssize_t egalax_cdev_write(struct file *file, const char __user *buf, | ||
275 | size_t count, loff_t *offset) | ||
276 | { | ||
277 | struct egalax_char_dev *cdev = file->private_data; | ||
278 | int ret = 0; | ||
279 | char *tmp; | ||
280 | |||
281 | if (down_interruptible(&cdev->sem)) | ||
282 | return -ERESTARTSYS; | ||
283 | |||
284 | if (count > MAX_I2C_LEN) | ||
285 | count = MAX_I2C_LEN; | ||
286 | |||
287 | tmp = kmalloc(count, GFP_KERNEL); | ||
288 | if (tmp == NULL) { | ||
289 | up(&cdev->sem); | ||
290 | return -ENOMEM; | ||
291 | } | ||
292 | |||
293 | if (copy_from_user(tmp, buf, count)) { | ||
294 | up(&cdev->sem); | ||
295 | kfree(tmp); | ||
296 | return -EFAULT; | ||
297 | } | ||
298 | |||
299 | ret = i2c_master_send(p_egalax_i2c_dev->client, tmp, count); | ||
300 | |||
301 | up(&cdev->sem); | ||
302 | EGALAX_DBG(DBG_CDEV, " I2C writing %zu bytes.\n", count); | ||
303 | kfree(tmp); | ||
304 | |||
305 | return ret; | ||
306 | } | ||
307 | |||
308 | #ifdef _ENABLE_DBG_LEVEL | ||
309 | static int egalax_proc_read(char *buffer, char **buffer_location, off_t offset, | ||
310 | int buffer_length, int *eof, void *data) | ||
311 | { | ||
312 | int ret; | ||
313 | |||
314 | EGALAX_DBG(DBG_PROC, " \"%s\" call proc_read\n", current->comm); | ||
315 | |||
316 | if (offset > 0) /* we have finished to read, return 0 */ | ||
317 | ret = 0; | ||
318 | else | ||
319 | ret = sprintf(buffer, "Debug Level: 0x%08X\n", DbgLevel); | ||
320 | |||
321 | return ret; | ||
322 | } | ||
323 | |||
324 | static int egalax_proc_write(struct file *file, const char *buffer, | ||
325 | unsigned long count, void *data) | ||
326 | { | ||
327 | char procfs_buffer_size = 0; | ||
328 | int i; | ||
329 | unsigned char procfs_buf[PROC_FS_MAX_LEN] = {0}; | ||
330 | |||
331 | EGALAX_DBG(DBG_PROC, " \"%s\" call proc_write\n", current->comm); | ||
332 | |||
333 | procfs_buffer_size = count; | ||
334 | if (procfs_buffer_size > PROC_FS_MAX_LEN) | ||
335 | procfs_buffer_size = PROC_FS_MAX_LEN+1; | ||
336 | |||
337 | if (copy_from_user(procfs_buf, buffer, procfs_buffer_size)) { | ||
338 | EGALAX_DBG(DBG_PROC, " proc_write faied at copy_from_user\n"); | ||
339 | return -EFAULT; | ||
340 | } | ||
341 | |||
342 | DbgLevel = 0; | ||
343 | for (i = 0 ; i < procfs_buffer_size-1; i++) { | ||
344 | if (procfs_buf[i] >= '0' && procfs_buf[i] <= '9') | ||
345 | DbgLevel |= (procfs_buf[i] - '0'); | ||
346 | else if (procfs_buf[i] >= 'A' && procfs_buf[i] <= 'F') | ||
347 | DbgLevel |= (procfs_buf[i] - 'A' + 10); | ||
348 | else if (procfs_buf[i] >= 'a' && procfs_buf[i] <= 'f') | ||
349 | DbgLevel |= (procfs_buf[i] - 'a' + 10); | ||
350 | |||
351 | if (i != procfs_buffer_size - 2) | ||
352 | DbgLevel <<= 4; | ||
353 | } | ||
354 | |||
355 | DbgLevel = DbgLevel&0xFFFFFFFF; | ||
356 | |||
357 | EGALAX_DBG(DBG_PROC, " Switch Debug Level to 0x%08X\n", DbgLevel); | ||
358 | |||
359 | return count; /* procfs_buffer_size */ | ||
360 | } | ||
361 | #endif /* #ifdef _ENABLE_DBG_LEVEL */ | ||
362 | |||
363 | static long egalax_cdev_ioctl(struct file *filp, unsigned int cmd, | ||
364 | unsigned long args) | ||
365 | { | ||
366 | int ret = 0; | ||
367 | |||
368 | if (_IOC_TYPE(cmd) != EGALAX_IOC_MAGIC) | ||
369 | return -ENOTTY; | ||
370 | if (_IOC_NR(cmd) > EGALAX_IOC_MAXNR) | ||
371 | return -ENOTTY; | ||
372 | |||
373 | if (_IOC_DIR(cmd) & _IOC_READ) | ||
374 | ret = !access_ok(VERIFY_WRITE, (void __user *)args, | ||
375 | _IOC_SIZE(cmd)); | ||
376 | else if (_IOC_DIR(cmd) & _IOC_WRITE) | ||
377 | ret = !access_ok(VERIFY_READ, (void __user *)args, | ||
378 | _IOC_SIZE(cmd)); | ||
379 | |||
380 | if (ret) | ||
381 | return -EFAULT; | ||
382 | |||
383 | EGALAX_DBG(DBG_CDEV, "Handle device ioctl command\n"); | ||
384 | switch (cmd) { | ||
385 | case EGALAX_IOCWAKEUP: | ||
386 | ret = wakeup_controller(p_egalax_i2c_dev->client->irq); | ||
387 | break; | ||
388 | default: | ||
389 | ret = -ENOTTY; | ||
390 | break; | ||
391 | } | ||
392 | |||
393 | return ret; | ||
394 | } | ||
395 | |||
396 | static unsigned int egalax_cdev_poll(struct file *filp, | ||
397 | struct poll_table_struct *wait) | ||
398 | { | ||
399 | struct egalax_char_dev *cdev = filp->private_data; | ||
400 | unsigned int mask = 0; | ||
401 | int fifoLen; | ||
402 | |||
403 | down(&cdev->sem); | ||
404 | poll_wait(filp, &cdev->fifo_inq, wait); | ||
405 | |||
406 | fifoLen = kfifo_len(&cdev->DataKFiFo); | ||
407 | |||
408 | if (fifoLen > 0) | ||
409 | mask |= POLLIN | POLLRDNORM; /* readable */ | ||
410 | if ((FIFO_SIZE - fifoLen) > MAX_I2C_LEN) | ||
411 | mask |= POLLOUT | POLLWRNORM; /* writable */ | ||
412 | |||
413 | up(&cdev->sem); | ||
414 | return mask; | ||
415 | } | ||
416 | |||
417 | static int LastUpdateID; | ||
418 | static void ProcessReport(unsigned char *buf, struct _egalax_i2c *p_egalax_i2c) | ||
419 | { | ||
420 | int i, cnt_down = 0, cnt_up = 0; | ||
421 | short X, Y, ContactID, Status; | ||
422 | bool bNeedReport = false; | ||
423 | int skip_point = 0; | ||
424 | |||
425 | Status = buf[1]&0x01; | ||
426 | ContactID = (buf[1]&0x7C)>>2; | ||
427 | X = ((buf[3]<<8) + buf[2])>>4; | ||
428 | X = X * SCREEN_WIDTH / EGALAX_MAX; | ||
429 | Y = ((buf[5]<<8) + buf[4])>>4; | ||
430 | Y = Y * SCREEN_HIGH / EGALAX_MAX; | ||
431 | |||
432 | if (!(ContactID >= 0 && ContactID < MAX_SUPPORT_POINT)) { | ||
433 | EGALAX_DBG(DBG_POINT, "Get I2C Point data error [%02X][%02X]\ | ||
434 | [%02X][%02X][%02X][%02X]\n", buf[0], buf[1], | ||
435 | buf[2], buf[3], buf[4], buf[5]); | ||
436 | return; | ||
437 | } | ||
438 | |||
439 | #ifdef CONFIG_TC4_PORTRAIT_MODE | ||
440 | PointBuf[ContactID].X = EGALAX_MAX-Y; | ||
441 | PointBuf[ContactID].Y = X; | ||
442 | #else | ||
443 | PointBuf[ContactID].X = X; | ||
444 | PointBuf[ContactID].Y = Y; | ||
445 | #endif | ||
446 | if (PointBuf[ContactID].Status != Status) { | ||
447 | if (Status) | ||
448 | p_egalax_i2c->downCnt++; | ||
449 | else if (PointBuf[ContactID].Status > 0) | ||
450 | p_egalax_i2c->downCnt--; | ||
451 | |||
452 | PointBuf[ContactID].Status = Status; | ||
453 | bNeedReport = true; | ||
454 | } | ||
455 | |||
456 | /* Send point report */ | ||
457 | if ((bNeedReport || (ContactID <= LastUpdateID)) && (skip_point == 0)) { | ||
458 | for (i = 0; i < MAX_SUPPORT_POINT; i++) { | ||
459 | if (PointBuf[i].Status > 0) { | ||
460 | input_report_abs(input_dev, | ||
461 | ABS_MT_TRACKING_ID, i); | ||
462 | input_report_abs(input_dev, | ||
463 | ABS_MT_TOUCH_MAJOR, PointBuf[i].Status); | ||
464 | input_report_abs(input_dev, | ||
465 | ABS_MT_WIDTH_MAJOR, 0); | ||
466 | input_report_abs(input_dev, | ||
467 | ABS_MT_POSITION_X, PointBuf[ContactID].X); | ||
468 | input_report_abs(input_dev, | ||
469 | ABS_MT_POSITION_Y, PointBuf[ContactID].Y); | ||
470 | input_mt_sync(input_dev); | ||
471 | cnt_down++; | ||
472 | } else if (PointBuf[i].Status == 0) { | ||
473 | PointBuf[i].Status--; | ||
474 | cnt_up++; | ||
475 | input_mt_sync(input_dev); | ||
476 | } | ||
477 | } | ||
478 | input_sync(input_dev); | ||
479 | EGALAX_DBG(DBG_POINT, " Input sync point data done! (Down:%d Up:%d)\n", | ||
480 | cnt_down, cnt_up); | ||
481 | } | ||
482 | |||
483 | LastUpdateID = ContactID; | ||
484 | } | ||
485 | |||
486 | static struct input_dev *allocate_Input_Dev(void) | ||
487 | { | ||
488 | int ret; | ||
489 | struct input_dev *pInputDev; | ||
490 | |||
491 | pInputDev = input_allocate_device(); | ||
492 | if (pInputDev == NULL) { | ||
493 | EGALAX_DBG(DBG_MODULE, "Failed to allocate input device\n"); | ||
494 | return NULL; | ||
495 | } | ||
496 | |||
497 | pInputDev->name = "egalax_i2c"; | ||
498 | pInputDev->phys = "I2C"; | ||
499 | pInputDev->id.bustype = BUS_I2C; | ||
500 | pInputDev->id.vendor = 0x0EEF; | ||
501 | pInputDev->id.product = 0x0020; | ||
502 | pInputDev->id.version = 0x0001; | ||
503 | |||
504 | set_bit(EV_ABS, pInputDev->evbit); | ||
505 | input_set_abs_params(pInputDev, ABS_MT_POSITION_X, | ||
506 | 0, SCREEN_WIDTH, 0, 0); | ||
507 | input_set_abs_params(pInputDev, ABS_MT_POSITION_Y, | ||
508 | 0, SCREEN_HIGH, 0, 0); | ||
509 | input_set_abs_params(pInputDev, ABS_MT_TOUCH_MAJOR, | ||
510 | 0, 255, 0, 0); | ||
511 | input_set_abs_params(pInputDev, ABS_MT_WIDTH_MAJOR, | ||
512 | 0, 255, 0, 0); | ||
513 | input_set_abs_params(pInputDev, ABS_MT_TRACKING_ID, | ||
514 | 0, MAX_SUPPORT_POINT, 0, 0); | ||
515 | |||
516 | ret = input_register_device(pInputDev); | ||
517 | if (ret) { | ||
518 | EGALAX_DBG(DBG_MODULE, "Unable to register input device.\n"); | ||
519 | input_free_device(pInputDev); | ||
520 | pInputDev = NULL; | ||
521 | } | ||
522 | |||
523 | return pInputDev; | ||
524 | } | ||
525 | |||
526 | static int egalax_i2c_measure(struct _egalax_i2c *egalax_i2c) | ||
527 | { | ||
528 | struct i2c_client *client = egalax_i2c->client; | ||
529 | u8 x_buf[MAX_I2C_LEN]; | ||
530 | int count, loop = 3; | ||
531 | |||
532 | EGALAX_DBG(DBG_INT, "egalax_i2c_measure\n"); | ||
533 | |||
534 | do { | ||
535 | mutex_lock(&i2c_lock); | ||
536 | count = i2c_master_recv(client, x_buf, MAX_I2C_LEN); | ||
537 | mutex_unlock(&i2c_lock); | ||
538 | } while (count == EAGAIN && --loop); | ||
539 | |||
540 | if (count < 0 || (x_buf[0] != REPORTID_VENDOR && x_buf[0] | ||
541 | != REPORTID_MTOUCH)) { | ||
542 | EGALAX_DBG(DBG_I2C, "I2C read error data\ | ||
543 | with Len=%d hedaer=%d\n", count, x_buf[0]); | ||
544 | return -1; | ||
545 | } | ||
546 | |||
547 | EGALAX_DBG(DBG_I2C, " I2C read data with Len=%d\n", count); | ||
548 | if (x_buf[0] == REPORTID_VENDOR) { | ||
549 | atomic_set(&wait_command_ack, 1); | ||
550 | EGALAX_DBG(DBG_I2C, " I2C get vendor command packet\n"); | ||
551 | } | ||
552 | |||
553 | if (egalax_i2c->skip_packet > 0) | ||
554 | return count; | ||
555 | |||
556 | /* check buffer len & header */ | ||
557 | if (count == MAX_I2C_LEN && x_buf[0] == REPORTID_MTOUCH) { | ||
558 | ProcessReport(x_buf, egalax_i2c); | ||
559 | return count; | ||
560 | } | ||
561 | |||
562 | /* If someone reading now! put the data into the buffer! */ | ||
563 | if (count > 0 && p_char_dev->OpenCnts > 0) { | ||
564 | kfifo_in_locked(&p_char_dev->DataKFiFo, x_buf, | ||
565 | count, &p_char_dev->FiFoLock); | ||
566 | wake_up_interruptible(&p_char_dev->fifo_inq); | ||
567 | } | ||
568 | |||
569 | return count; | ||
570 | } | ||
571 | |||
572 | static void egalax_i2c_wq_irq(struct work_struct *work) | ||
573 | { | ||
574 | struct _egalax_i2c *egalax_i2c = | ||
575 | container_of(work, struct _egalax_i2c, work_irq); | ||
576 | struct i2c_client *client = egalax_i2c->client; | ||
577 | int gpio = egalax_i2c->pdata->gpio_int; | ||
578 | |||
579 | EGALAX_DBG(DBG_INT, " egalax_i2c_wq run\n"); | ||
580 | |||
581 | mutex_lock(&egalax_i2c->mutex_wq); | ||
582 | /*continue recv data*/ | ||
583 | while (!gpio_get_value(gpio)) { | ||
584 | egalax_i2c_measure(egalax_i2c); | ||
585 | schedule(); | ||
586 | } | ||
587 | |||
588 | if (egalax_i2c->skip_packet > 0) | ||
589 | egalax_i2c->skip_packet = 0; | ||
590 | |||
591 | if (p_char_dev->OpenCnts <= 0 && egalax_i2c->work_state == MODE_WORKING) | ||
592 | mod_timer(&egalax_i2c->idle_timer, jiffies+IDLE_INTERVAL); | ||
593 | |||
594 | mutex_unlock(&egalax_i2c->mutex_wq); | ||
595 | |||
596 | enable_irq(client->irq); | ||
597 | |||
598 | EGALAX_DBG(DBG_INT, " egalax_i2c_wq leave\n"); | ||
599 | } | ||
600 | |||
601 | static irqreturn_t egalax_i2c_interrupt(int irq, void *dev_id) | ||
602 | { | ||
603 | struct _egalax_i2c *egalax_i2c = (struct _egalax_i2c *)dev_id; | ||
604 | |||
605 | EGALAX_DBG(DBG_INT, " INT with irq:%d\n", irq); | ||
606 | |||
607 | del_timer(&egalax_i2c->idle_timer); | ||
608 | if (egalax_i2c->work_state == MODE_IDLE) | ||
609 | egalax_i2c->work_state = MODE_WORKING; | ||
610 | |||
611 | disable_irq_nosync(irq); | ||
612 | queue_work(egalax_i2c->ktouch_wq, &egalax_i2c->work_irq); | ||
613 | |||
614 | return IRQ_HANDLED; | ||
615 | } | ||
616 | |||
617 | static void egalax_i2c_wq_idle(struct work_struct *work) | ||
618 | { | ||
619 | struct _egalax_i2c *egalax_i2c = | ||
620 | container_of(work, struct _egalax_i2c, work_idle); | ||
621 | unsigned char buf[] = {0x03, 0x06, 0x0A, 0x04, 0x36, | ||
622 | 0x3F, 0x01, 0x00, 0, 0}; | ||
623 | int ret = 0; | ||
624 | |||
625 | if (egalax_i2c->work_state == MODE_WORKING) { | ||
626 | mutex_lock(&i2c_lock); | ||
627 | ret = i2c_master_send(egalax_i2c->client, buf, MAX_I2C_LEN); | ||
628 | mutex_unlock(&i2c_lock); | ||
629 | if (ret == MAX_I2C_LEN) { | ||
630 | egalax_i2c->work_state = MODE_IDLE; | ||
631 | EGALAX_DBG(DBG_IDLE, " Set controller to idle mode\n"); | ||
632 | } else | ||
633 | EGALAX_DBG(DBG_IDLE, " Try to set controller\ | ||
634 | to idle failed:%d\n", ret); | ||
635 | } | ||
636 | } | ||
637 | |||
638 | static void egalax_idle_timer_routine(unsigned long data) | ||
639 | { | ||
640 | struct _egalax_i2c *egalax_i2c = (struct _egalax_i2c *)data; | ||
641 | |||
642 | queue_work(egalax_i2c->ktouch_wq, &egalax_i2c->work_idle); | ||
643 | } | ||
644 | |||
645 | |||
646 | |||
647 | #ifdef CONFIG_HAS_EARLYSUSPEND | ||
648 | static void egalax_i2c_early_suspend(struct early_suspend *handler) | ||
649 | { | ||
650 | mod_timer(&p_egalax_i2c_dev->idle_timer, jiffies); | ||
651 | |||
652 | return; | ||
653 | } | ||
654 | |||
655 | #endif // #ifdef CONFIG_HAS_EARLYSUSPEND | ||
656 | |||
657 | static int __devinit egalax_i2c_probe(struct i2c_client *client, | ||
658 | const struct i2c_device_id *id) | ||
659 | { | ||
660 | int i, ret = 0; | ||
661 | int gpio; | ||
662 | |||
663 | EGALAX_DBG(DBG_MODULE, " Start probe\n"); | ||
664 | |||
665 | p_egalax_i2c_dev = kzalloc(sizeof(struct _egalax_i2c), GFP_KERNEL); | ||
666 | if (!p_egalax_i2c_dev) { | ||
667 | EGALAX_DBG(DBG_MODULE, "Request memory failed\n"); | ||
668 | ret = -ENOMEM; | ||
669 | goto fail1; | ||
670 | } | ||
671 | |||
672 | p_egalax_i2c_dev->pdata = kmalloc(sizeof(*(p_egalax_i2c_dev->pdata)), | ||
673 | GFP_KERNEL); | ||
674 | if (NULL == p_egalax_i2c_dev->pdata) { | ||
675 | dev_err(&client->dev, "fail to allocate mem for pdata\n"); | ||
676 | goto fail1_1; | ||
677 | } | ||
678 | |||
679 | memcpy(p_egalax_i2c_dev->pdata, client->dev.platform_data, | ||
680 | sizeof(*(p_egalax_i2c_dev->pdata))); | ||
681 | |||
682 | gpio = p_egalax_i2c_dev->pdata->gpio_int; | ||
683 | |||
684 | input_dev = allocate_Input_Dev(); | ||
685 | if (input_dev == NULL) { | ||
686 | EGALAX_DBG(DBG_MODULE, " allocate_Input_Dev failed\n"); | ||
687 | ret = -EINVAL; | ||
688 | goto fail2; | ||
689 | } | ||
690 | |||
691 | EGALAX_DBG(DBG_MODULE, " Register input device done\n"); | ||
692 | |||
693 | for (i = 0; i < MAX_SUPPORT_POINT; i++) { | ||
694 | PointBuf[i].Status = -1; | ||
695 | PointBuf[i].X = PointBuf[i].Y = 0; | ||
696 | } | ||
697 | |||
698 | p_egalax_i2c_dev->client = client; | ||
699 | mutex_init(&p_egalax_i2c_dev->mutex_wq); | ||
700 | mutex_init(&i2c_lock); /* cuiwenpin:i2c read write protection */ | ||
701 | |||
702 | p_egalax_i2c_dev->ktouch_wq = | ||
703 | create_singlethread_workqueue("egalax_touch_wq"); | ||
704 | INIT_WORK(&p_egalax_i2c_dev->work_irq, egalax_i2c_wq_irq); | ||
705 | INIT_WORK(&p_egalax_i2c_dev->work_idle, egalax_i2c_wq_idle); | ||
706 | |||
707 | i2c_set_clientdata(client, p_egalax_i2c_dev); | ||
708 | |||
709 | sendLoopback(client); | ||
710 | |||
711 | if (gpio_get_value(gpio)) | ||
712 | p_egalax_i2c_dev->skip_packet = 0; | ||
713 | else | ||
714 | p_egalax_i2c_dev->skip_packet = 1; | ||
715 | |||
716 | p_egalax_i2c_dev->work_state = MODE_WORKING; | ||
717 | |||
718 | /* setup timer */ | ||
719 | setup_timer(&p_egalax_i2c_dev->idle_timer, egalax_idle_timer_routine, | ||
720 | (unsigned long)p_egalax_i2c_dev); | ||
721 | mod_timer(&p_egalax_i2c_dev->idle_timer, jiffies); | ||
722 | |||
723 | ret = request_irq(client->irq, egalax_i2c_interrupt, | ||
724 | IRQF_DISABLED | IRQF_TRIGGER_FALLING, | ||
725 | client->name, p_egalax_i2c_dev); | ||
726 | if (ret) { | ||
727 | EGALAX_DBG(DBG_MODULE, "Request irq(%d) failed\n", client->irq); | ||
728 | goto fail3; | ||
729 | } | ||
730 | |||
731 | #ifdef CONFIG_HAS_EARLYSUSPEND | ||
732 | egalax_early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN; | ||
733 | egalax_early_suspend.suspend = egalax_i2c_early_suspend; | ||
734 | egalax_early_suspend.resume = NULL; | ||
735 | register_early_suspend(&egalax_early_suspend); | ||
736 | EGALAX_DBG(DBG_MODULE, " Register early_suspend done\n"); | ||
737 | #endif | ||
738 | |||
739 | EGALAX_DBG(DBG_MODULE, "Request irq(%d) gpio(%d) with result:%d\n", | ||
740 | client->irq, gpio, ret); | ||
741 | |||
742 | |||
743 | EGALAX_DBG(DBG_MODULE, " I2C probe done\n"); | ||
744 | return 0; | ||
745 | |||
746 | fail3: | ||
747 | i2c_set_clientdata(client, NULL); | ||
748 | destroy_workqueue(p_egalax_i2c_dev->ktouch_wq); | ||
749 | free_irq(client->irq, p_egalax_i2c_dev); | ||
750 | input_unregister_device(input_dev); | ||
751 | input_dev = NULL; | ||
752 | fail2: | ||
753 | kfree(p_egalax_i2c_dev->pdata); | ||
754 | fail1_1: | ||
755 | kfree(p_egalax_i2c_dev); | ||
756 | fail1: | ||
757 | p_egalax_i2c_dev = NULL; | ||
758 | |||
759 | EGALAX_DBG(DBG_MODULE, " I2C probe failed\n"); | ||
760 | return ret; | ||
761 | } | ||
762 | |||
763 | static int __devexit egalax_i2c_remove(struct i2c_client *client) | ||
764 | { | ||
765 | struct _egalax_i2c *egalax_i2c = i2c_get_clientdata(client); | ||
766 | |||
767 | egalax_i2c->work_state = MODE_STOP; | ||
768 | |||
769 | cancel_work_sync(&egalax_i2c->work_irq); | ||
770 | del_timer_sync(&egalax_i2c->idle_timer); | ||
771 | cancel_work_sync(&egalax_i2c->work_idle); | ||
772 | |||
773 | if (client->irq) { | ||
774 | disable_irq(client->irq); | ||
775 | free_irq(client->irq, egalax_i2c); | ||
776 | } | ||
777 | |||
778 | if (egalax_i2c->ktouch_wq) | ||
779 | destroy_workqueue(egalax_i2c->ktouch_wq); | ||
780 | |||
781 | #ifdef CONFIG_HAS_EARLYSUSPEND | ||
782 | unregister_early_suspend(&egalax_early_suspend); | ||
783 | #endif | ||
784 | |||
785 | if (input_dev) { | ||
786 | EGALAX_DBG(DBG_MODULE, " Unregister input device\n"); | ||
787 | input_unregister_device(input_dev); | ||
788 | input_dev = NULL; | ||
789 | } | ||
790 | |||
791 | i2c_set_clientdata(client, NULL); | ||
792 | kfree(egalax_i2c->pdata); | ||
793 | kfree(egalax_i2c); | ||
794 | p_egalax_i2c_dev = NULL; | ||
795 | |||
796 | return 0; | ||
797 | } | ||
798 | |||
799 | static const struct i2c_device_id egalax_i2c_idtable[] = { | ||
800 | { "egalax_i2c", 0 }, | ||
801 | {} | ||
802 | }; | ||
803 | |||
804 | MODULE_DEVICE_TABLE(i2c, egalax_i2c_idtable); | ||
805 | |||
806 | static struct i2c_driver egalax_i2c_driver = { | ||
807 | .driver = { | ||
808 | .name = "egalax_i2c", | ||
809 | }, | ||
810 | .id_table = egalax_i2c_idtable, | ||
811 | .probe = egalax_i2c_probe, | ||
812 | .remove = __devexit_p(egalax_i2c_remove), | ||
813 | }; | ||
814 | |||
815 | static const struct file_operations egalax_cdev_fops = { | ||
816 | .owner = THIS_MODULE, | ||
817 | .read = egalax_cdev_read, | ||
818 | .write = egalax_cdev_write, | ||
819 | .unlocked_ioctl = egalax_cdev_ioctl, | ||
820 | .poll = egalax_cdev_poll, | ||
821 | .open = egalax_cdev_open, | ||
822 | .release = egalax_cdev_release, | ||
823 | }; | ||
824 | |||
825 | static void egalax_i2c_ts_exit(void) | ||
826 | { | ||
827 | dev_t devno = MKDEV(global_major, global_minor); | ||
828 | |||
829 | if (p_char_dev) { | ||
830 | EGALAX_DBG(DBG_MODULE, "Unregister character device\n"); | ||
831 | kfree(p_char_dev->pFiFoBuf); | ||
832 | |||
833 | cdev_del(&p_char_dev->cdev); | ||
834 | kfree(p_char_dev); | ||
835 | p_char_dev = NULL; | ||
836 | } | ||
837 | |||
838 | unregister_chrdev_region(devno, 1); | ||
839 | |||
840 | if (!IS_ERR(egalax_class)) { | ||
841 | device_destroy(egalax_class, devno); | ||
842 | class_destroy(egalax_class); | ||
843 | } | ||
844 | |||
845 | i2c_del_driver(&egalax_i2c_driver); | ||
846 | |||
847 | #ifdef _ENABLE_DBG_LEVEL | ||
848 | remove_proc_entry(PROC_FS_NAME, NULL); | ||
849 | #endif | ||
850 | |||
851 | EGALAX_DBG(DBG_MODULE, " Exit driver done!\n"); | ||
852 | } | ||
853 | |||
854 | static struct egalax_char_dev *setup_chardev(dev_t dev) | ||
855 | { | ||
856 | struct egalax_char_dev *pCharDev; | ||
857 | int result; | ||
858 | |||
859 | pCharDev = kmalloc(1 * sizeof(struct egalax_char_dev), GFP_KERNEL); | ||
860 | if (!pCharDev) | ||
861 | goto fail_cdev; | ||
862 | |||
863 | memset(pCharDev, 0, sizeof(struct egalax_char_dev)); | ||
864 | |||
865 | spin_lock_init(&pCharDev->FiFoLock); | ||
866 | pCharDev->pFiFoBuf = kmalloc(sizeof(unsigned char)*FIFO_SIZE, | ||
867 | GFP_KERNEL); | ||
868 | if (!pCharDev->pFiFoBuf) | ||
869 | goto fail_fifobuf; | ||
870 | memset(pCharDev->pFiFoBuf, 0, sizeof(unsigned char)*FIFO_SIZE); | ||
871 | |||
872 | kfifo_init(&pCharDev->DataKFiFo, pCharDev->pFiFoBuf, FIFO_SIZE); | ||
873 | if (!kfifo_initialized(&pCharDev->DataKFiFo)) | ||
874 | goto fail_kfifo; | ||
875 | |||
876 | pCharDev->OpenCnts = 0; | ||
877 | cdev_init(&pCharDev->cdev, &egalax_cdev_fops); | ||
878 | pCharDev->cdev.owner = THIS_MODULE; | ||
879 | sema_init(&pCharDev->sem, 1); | ||
880 | init_waitqueue_head(&pCharDev->fifo_inq); | ||
881 | |||
882 | result = cdev_add(&pCharDev->cdev, dev, 1); | ||
883 | if (result) { | ||
884 | EGALAX_DBG(DBG_MODULE, " Failed at cdev added\n"); | ||
885 | goto fail_kfifo; | ||
886 | } | ||
887 | |||
888 | return pCharDev; | ||
889 | |||
890 | fail_kfifo: | ||
891 | kfree(pCharDev->pFiFoBuf); | ||
892 | fail_fifobuf: | ||
893 | kfree(pCharDev); | ||
894 | fail_cdev: | ||
895 | return NULL; | ||
896 | } | ||
897 | |||
898 | static int egalax_i2c_ts_init(void) | ||
899 | { | ||
900 | int result; | ||
901 | dev_t devno = 0; | ||
902 | |||
903 | /* Asking for a dynamic major unless directed otherwise at load time. */ | ||
904 | if (global_major) { | ||
905 | devno = MKDEV(global_major, global_minor); | ||
906 | result = register_chrdev_region(devno, 1, "egalax_i2c"); | ||
907 | } else { | ||
908 | result = alloc_chrdev_region(&devno, global_minor, | ||
909 | 1, "egalax_i2c"); | ||
910 | global_major = MAJOR(devno); | ||
911 | } | ||
912 | |||
913 | if (result < 0) { | ||
914 | EGALAX_DBG(DBG_MODULE, " Cdev can't get major number\n"); | ||
915 | return 0; | ||
916 | } | ||
917 | |||
918 | /* allocate the character device */ | ||
919 | p_char_dev = setup_chardev(devno); | ||
920 | if (!p_char_dev) { | ||
921 | result = -ENOMEM; | ||
922 | goto fail; | ||
923 | } | ||
924 | |||
925 | egalax_class = class_create(THIS_MODULE, "egalax_i2c"); | ||
926 | if (IS_ERR(egalax_class)) { | ||
927 | EGALAX_DBG(DBG_MODULE, " Failed in creating class.\n"); | ||
928 | result = -EFAULT; | ||
929 | goto fail; | ||
930 | } | ||
931 | |||
932 | device_create(egalax_class, NULL, devno, NULL, "egalax_i2c"); | ||
933 | EGALAX_DBG(DBG_MODULE, "Register egalax_i2c cdev, major: %d\n", | ||
934 | global_major); | ||
935 | |||
936 | #ifdef _ENABLE_DBG_LEVEL | ||
937 | dbgProcFile = create_proc_entry(PROC_FS_NAME, 0666, NULL); | ||
938 | if (dbgProcFile == NULL) { | ||
939 | remove_proc_entry(PROC_FS_NAME, NULL); | ||
940 | EGALAX_DBG(DBG_MODULE, "Could not initialize /proc/%s\n", | ||
941 | PROC_FS_NAME); | ||
942 | } else { | ||
943 | dbgProcFile->read_proc = egalax_proc_read; | ||
944 | dbgProcFile->write_proc = egalax_proc_write; | ||
945 | EGALAX_DBG(DBG_MODULE, " /proc/%s created\n", PROC_FS_NAME); | ||
946 | } | ||
947 | #endif /* #ifdef _ENABLE_DBG_LEVEL */ | ||
948 | |||
949 | EGALAX_DBG(DBG_MODULE, " Driver init done!\n"); | ||
950 | return i2c_add_driver(&egalax_i2c_driver); | ||
951 | |||
952 | fail: | ||
953 | egalax_i2c_ts_exit(); | ||
954 | return result; | ||
955 | } | ||
956 | |||
957 | module_init(egalax_i2c_ts_init); | ||
958 | module_exit(egalax_i2c_ts_exit); | ||
959 | |||
960 | MODULE_AUTHOR("EETI <touch_fae@eeti.com>"); | ||
961 | MODULE_DESCRIPTION("egalax touch screen i2c driver"); | ||
962 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/input/touchscreen/odroidq-config.h b/drivers/input/touchscreen/odroidq-config.h new file mode 100644 index 00000000000..8fa8fbcaccb --- /dev/null +++ b/drivers/input/touchscreen/odroidq-config.h | |||
@@ -0,0 +1,151 @@ | |||
1 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
2 | // | ||
3 | // | ||
4 | // HardKernel(ODROID-Q) Touchscreen driver | ||
5 | // 2011.12.12 | ||
6 | // | ||
7 | // | ||
8 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
9 | #ifndef _ODROIDQ_CONFIG_H_ | ||
10 | #define _ODROIDQ_CONFIG_H_ | ||
11 | |||
12 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
13 | struct ChipSetting { | ||
14 | unsigned char No; | ||
15 | unsigned char Reg; | ||
16 | unsigned char Data1; | ||
17 | unsigned char Data2; | ||
18 | }; | ||
19 | |||
20 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
21 | struct ChipSetting Config[]={ | ||
22 | { 0, 0x04, 0x00, 0x00}, // SSD2533 wakeup | ||
23 | {-1, 0x30, 0x00, 0x00}, // mdelay | ||
24 | |||
25 | // { 1, 0xAC, 0x01, 0x00}, // SelfCap IIR filter | ||
26 | // { 1, 0xAD, 0x03, 0x00}, // Scan Rate | ||
27 | // { 1, 0xAE, 0x0F, 0x00}, // SelfCap Enable | ||
28 | // { 1, 0xAF, 0x30, 0x00}, // SelfCap Threshold | ||
29 | // { 1, 0xBC, 0x01, 0x00}, // Selfcap Enable | ||
30 | |||
31 | // 2012.06 new option | ||
32 | { 1, 0xac, 0x03, 0x00}, | ||
33 | { 1, 0xad, 0x02, 0x00}, | ||
34 | { 1, 0xae, 0x0f, 0x00}, | ||
35 | { 1, 0xaf, 0x40, 0x00}, | ||
36 | { 1, 0xb0, 0x00, 0x00}, | ||
37 | { 1, 0xbb, 0x00, 0x00}, | ||
38 | { 1, 0xbc, 0x01, 0x00}, | ||
39 | // | ||
40 | |||
41 | { 1, 0x06, DRIVE_LINE_COUNT-1, 0x00}, //Set drive line 0=1, 1F= | ||
42 | { 1, 0x07, SENSE_LINE_COUNT-1, 0x00}, //Set sense line 0=1, 3F= | ||
43 | |||
44 | { 2, 0x08, 0x00, 0x8B}, //Set 1 drive line reg | ||
45 | { 2, 0x09, 0x00, 0x8C}, //Set 2 drive line reg | ||
46 | { 2, 0x0A, 0x00, 0x8D}, //Set 3 drive line reg | ||
47 | { 2, 0x0B, 0x00, 0x8E}, //Set 4 drive line reg | ||
48 | { 2, 0x0C, 0x00, 0x8F}, //Set 5 drive line reg | ||
49 | { 2, 0x0D, 0x00, 0x90}, //Set 6 drive line reg | ||
50 | { 2, 0x0E, 0x00, 0x91}, //Set 7 drive line reg | ||
51 | { 2, 0x0F, 0x00, 0x92}, //Set 8 drive line reg | ||
52 | { 2, 0x10, 0x00, 0x93}, //Set 9 drive line reg | ||
53 | { 2, 0x11, 0x00, 0x94}, //Set 10 drive line reg | ||
54 | { 2, 0x12, 0x00, 0x95}, //Set 11 drive line reg | ||
55 | { 2, 0x13, 0x00, 0x96}, //Set 12 drive line reg | ||
56 | { 2, 0x14, 0x01, 0x80}, //Set 13 drive line reg | ||
57 | { 2, 0x15, 0x01, 0x81}, //Set 14 drive line reg | ||
58 | { 2, 0x16, 0x01, 0x82}, //Set 15 drive line reg | ||
59 | { 2, 0x17, 0x01, 0x83}, //Set 16 drive line reg | ||
60 | { 2, 0x18, 0x01, 0x84}, //Set 17 drive line reg | ||
61 | { 2, 0x19, 0x01, 0x85}, //Set 18 drive line reg | ||
62 | { 2, 0x1A, 0x01, 0x86}, //Set 19 drive line reg | ||
63 | { 2, 0x1B, 0x01, 0x87}, //Set 20 drive line reg | ||
64 | { 2, 0x1C, 0x01, 0x88}, //Set 21 drive line reg | ||
65 | { 2, 0x1D, 0x01, 0x89}, //Set 20 drive line reg | ||
66 | { 2, 0x1E, 0x01, 0x8A}, //Set 21 drive line reg | ||
67 | |||
68 | //{ 1, 0xD5, 0x03, 0x00}, //Set Driving voltage 0(5.5V) to 7(9V) | ||
69 | //{ 1, 0xD8, 0x07, 0x00}, //Sense Bias R (2012/01/09) | ||
70 | // 2012.06 new option | ||
71 | { 1, 0xd5, 0x06, 0x00}, | ||
72 | { 1, 0xd8, 0x04, 0x00}, | ||
73 | // | ||
74 | |||
75 | { 1, 0x2A, 0x07, 0x00}, //Set sub-frame default=1, range 0 to F | ||
76 | { 1, 0x2C, 0x01, 0x00}, //Median Filter 0:disable to 1:enable | ||
77 | { 1, 0x2E, 0x0B, 0x00}, //Sub-frame Drive pulse number default=0x17 | ||
78 | |||
79 | { 1, 0x2F, 0x01, 0x00}, //Integration Gain | ||
80 | |||
81 | // 2012.06 new option | ||
82 | //{ 1, 0x8b, 0x01, 0x00}, //added | ||
83 | //{ 1, 0x8c, 0xb0, 0x00}, //added | ||
84 | // | ||
85 | |||
86 | { 1, 0x30, 0x03, 0x00}, //start integrate 125ns/div | ||
87 | |||
88 | { 1, 0x31, 0x0B, 0x00}, //stop integrate 125n/div (2012/01/09) | ||
89 | |||
90 | //{ 1, 0xD7, 0x02, 0x00}, //ADC range default=4, 0 to 7 (2012/01/09) | ||
91 | // 2012.06 new option | ||
92 | { 1, 0xd7, 0x04, 0x00}, | ||
93 | // | ||
94 | |||
95 | { 1, 0xDB, 0x02, 0x00}, //Set integration cap default=0, 0 to 7 (2012/01/09) | ||
96 | |||
97 | { 2, 0x33, 0x00, 0x00}, //Set Min. Finger area (2012/01/09) | ||
98 | { 2, 0x34, 0x00, 0x28}, //Set Min. Finger level (2012/01/09) | ||
99 | { 2, 0x35, 0x00, 0x00}, //Set Min. Finger weight | ||
100 | { 2, 0x36, 0x00, 0x1F}, //Set Max. Finger weight | ||
101 | |||
102 | { 1, 0x37, 0x00, 0x00}, //Segmentation Depth | ||
103 | { 1, 0x3D, 0x01, 0x00}, // 2D filter | ||
104 | |||
105 | // 2012.06 new option | ||
106 | { 1, 0x39, 0x02, 0x00}, //added | ||
107 | { 1, 0x40, 0xfa, 0x00}, //added | ||
108 | { 1, 0x44, 0x01, 0x00}, //added | ||
109 | // | ||
110 | |||
111 | { 1, 0x53, EVENT_MOVE_TOL, 0x00}, //Event move tolerance | ||
112 | { 2, 0x54, 0x00, X_TRACKING}, //X tracking | ||
113 | { 2, 0x55, 0x00, Y_TRACKING}, //Y tracking | ||
114 | |||
115 | { 1, 0x56, MOVE_AVR_FILTER, 0x00}, //Moving Average Filter 0:null, 1:5-3(Set), 2:6-2 3:7-1 | ||
116 | { 1, 0x58, 0x00, 0x00}, //Finger weight scaling | ||
117 | { 1, 0x59, 0x01, 0x00}, //Enable Random walk | ||
118 | { 1, 0x5B, 0x01, 0x00}, //Set Random walk window ++++ | ||
119 | { 1, 0x65, ORIENTATION, 0x00}, //XY Mapping | ||
120 | |||
121 | { 2, 0x66, 0x8A, 0x90}, | ||
122 | { 2, 0x67, 0x95, 0x00}, //0x8F, 0x00 | ||
123 | //{ 2, 0x67, 0x8F, 0x00}, | ||
124 | |||
125 | #if defined(IRQ_MODE_EVENT) || defined(IRQ_MODE_HYBRID) || defined(IRQ_MODE_POLLING) | ||
126 | #if defined(IRQ_MODE_EVENT) | ||
127 | // Event | ||
128 | { 2, 0x7A, 0xFF, 0xC7}, //Event Mask - Enable Leave Event | ||
129 | { 2, 0x7B, 0xFF, 0xF0}, //IRQ Mask - Mask off All Fingers interrupt except Event | ||
130 | { 1, 0x89, 0x00, 0x00}, //Enable Event IRQ mode | ||
131 | #else // IRQ_MODE_HYBRID or IRQ_MODE_POLLING | ||
132 | // Frame | ||
133 | { 2, 0x7A, 0xFF, 0xFF}, //Event Mask - Enable Leave Event | ||
134 | { 2, 0x7B, 0x00, 0x03}, //IRQ Mask - Mask off Unused Event | ||
135 | { 1, 0x89, 0x00, 0x00}, //Enable Event IRQ mode | ||
136 | #endif | ||
137 | #else // Frame IRQ Mode | ||
138 | { 2, 0x7A, 0xFF, 0xFF}, //Event Mask - Enable Leave Event | ||
139 | { 2, 0x7B, 0xFF, 0xFF}, //IRQ Mask - Mask off All Fingers & EVENT | ||
140 | { 1, 0x89, 0x01, 0x00}, //Enable Frame IRQ mode | ||
141 | #endif | ||
142 | |||
143 | { 1, 0x8A, MAX_FINGERS, 0x00}, //Max finger | ||
144 | //{ 1, 0x8B, 0x10, 0x00}, //Edge Remap | ||
145 | { 1, 0x8C, 0xB0, 0x00}, //Edge Suppress | ||
146 | |||
147 | { 1, 0x25, SCAN_MODE, 0x00}, //Set scan mode A | ||
148 | }; | ||
149 | |||
150 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
151 | #endif //_ODROIDQ_CONFIG_H_ | ||
diff --git a/drivers/input/touchscreen/odroidq-touch.c b/drivers/input/touchscreen/odroidq-touch.c new file mode 100644 index 00000000000..0fea5400c8a --- /dev/null +++ b/drivers/input/touchscreen/odroidq-touch.c | |||
@@ -0,0 +1,364 @@ | |||
1 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
2 | // | ||
3 | // | ||
4 | // | ||
5 | // I2C Touchscreen driver | ||
6 | // 2012.01.17 | ||
7 | // | ||
8 | // | ||
9 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
10 | #include <linux/device.h> | ||
11 | #include <linux/init.h> | ||
12 | #include <linux/input.h> | ||
13 | #include <linux/interrupt.h> | ||
14 | #include <linux/irq.h> | ||
15 | #include <linux/slab.h> | ||
16 | #include <linux/hrtimer.h> | ||
17 | #include <asm/unaligned.h> | ||
18 | #include <linux/firmware.h> | ||
19 | #include <linux/delay.h> | ||
20 | #include <linux/gpio.h> | ||
21 | #include <linux/i2c.h> | ||
22 | |||
23 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
24 | #if defined(CONFIG_HAS_EARLYSUSPEND) | ||
25 | #include <linux/wakelock.h> | ||
26 | #include <linux/earlysuspend.h> | ||
27 | #include <linux/suspend.h> | ||
28 | #endif | ||
29 | |||
30 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
31 | #include <linux/input/touch-pdata.h> | ||
32 | #include <linux/input/odroidq-touch.h> | ||
33 | #include "touch.h" | ||
34 | #include "odroidq-config.h" | ||
35 | |||
36 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
37 | //#define DEBUG_TOUCH | ||
38 | #define DEBUG_TOUCH_KEY | ||
39 | |||
40 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
41 | // function prototype define | ||
42 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
43 | // Touch data processing function | ||
44 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
45 | static void odroidq_sw_config (struct touch *ts); | ||
46 | static void odroidq_fifo_clear (struct touch *ts); | ||
47 | void odroidq_work (struct touch *ts); | ||
48 | int odroidq_calibration (struct touch *ts); | ||
49 | int odroidq_i2c_read (struct i2c_client *client, unsigned char *cmd, unsigned int cmd_len, unsigned char *data, unsigned int len); | ||
50 | void odroidq_enable (struct touch *ts); | ||
51 | void odroidq_disable (struct touch *ts); | ||
52 | int odroidq_early_probe (struct touch *ts); | ||
53 | int odroidq_probe (struct touch *ts); | ||
54 | #ifdef CONFIG_HAS_EARLYSUSPEND | ||
55 | void odroidq_suspend (struct early_suspend *h); | ||
56 | void odroidq_resume (struct early_suspend *h); | ||
57 | #endif | ||
58 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
59 | // | ||
60 | // i2c control function | ||
61 | // | ||
62 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
63 | int odroidq_i2c_read(struct i2c_client *client, unsigned char *cmd, unsigned int cmd_len, unsigned char *data, unsigned int len) | ||
64 | { | ||
65 | struct i2c_msg msg[2]; | ||
66 | int ret; | ||
67 | unsigned char temp[10]; | ||
68 | unsigned char i; | ||
69 | |||
70 | if((len == 0) || (data == NULL)) { | ||
71 | dev_err(&client->dev, "I2C read error: Null pointer or length == 0\n"); | ||
72 | return -1; | ||
73 | } | ||
74 | |||
75 | memset(msg, 0x00, sizeof(msg)); | ||
76 | |||
77 | msg[0].addr = client->addr; | ||
78 | msg[0].flags = 0; | ||
79 | msg[0].len = cmd_len; | ||
80 | msg[0].buf = cmd; | ||
81 | |||
82 | msg[1].addr = client->addr; | ||
83 | msg[1].flags = I2C_M_RD; | ||
84 | msg[1].len = len; | ||
85 | msg[1].buf = temp; | ||
86 | |||
87 | if ((ret = i2c_transfer(client->adapter, msg, 2)) != 2) { | ||
88 | dev_err(&client->dev, "I2C read error: (%d) reg: 0x%X len: %d\n", ret, cmd[0], len); | ||
89 | return -EIO; | ||
90 | } | ||
91 | |||
92 | if(len) { | ||
93 | for(i = 0; i < len; i++) data[i] = temp[len - i -1]; | ||
94 | } | ||
95 | |||
96 | return len; | ||
97 | } | ||
98 | |||
99 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
100 | int odroidq_calibration (struct touch *ts) | ||
101 | { | ||
102 | if(ts->pdata->reset_gpio) gpio_set_value(ts->pdata->reset_gpio, ts->pdata->reset_level); mdelay(10); | ||
103 | if(ts->pdata->reset_gpio) gpio_set_value(ts->pdata->reset_gpio, ts->pdata->reset_level ? 0 : 1); mdelay(10); | ||
104 | |||
105 | odroidq_sw_config(ts); odroidq_fifo_clear(ts); | ||
106 | |||
107 | return 0; | ||
108 | } | ||
109 | |||
110 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
111 | // | ||
112 | // Touch data processing function | ||
113 | // | ||
114 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
115 | static void odroidq_sw_config (struct touch *ts) | ||
116 | { | ||
117 | unsigned char i, wdata[2], cmd; | ||
118 | |||
119 | for(i = 0; i < sizeof(Config) / sizeof(Config[0]); i++) | ||
120 | { | ||
121 | wdata[0] = Config[i].Data1; wdata[1] = Config[i].Data2; | ||
122 | cmd = Config[i].Reg; | ||
123 | |||
124 | if(Config[i].No == 0xFF) mdelay(cmd); | ||
125 | else { | ||
126 | ts->pdata->i2c_write(ts->client, (unsigned char *)&cmd, sizeof(cmd), &wdata[0], Config[i].No); | ||
127 | } | ||
128 | } | ||
129 | mdelay(10); | ||
130 | } | ||
131 | |||
132 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
133 | static void odroidq_fifo_clear (struct touch *ts) | ||
134 | { | ||
135 | unsigned char wdata = 0x01, cmd = EVENT_FIFO_SCLR; | ||
136 | |||
137 | ts->pdata->i2c_write(ts->client, (unsigned char *)&cmd, sizeof(cmd), (unsigned char *)&wdata, sizeof(wdata)); // clear Event FiFo | ||
138 | } | ||
139 | |||
140 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
141 | static unsigned char odroidq_id_tracking (struct touch *ts, unsigned char find_id) | ||
142 | { | ||
143 | unsigned char i, find_slot = 0xFF; | ||
144 | |||
145 | for(i = 0; i < ts->pdata->max_fingers; i++) { | ||
146 | |||
147 | if(ts->finger[i].id == find_id) find_slot = i; | ||
148 | |||
149 | if((ts->finger[i].event == TS_EVENT_UNKNOWN) && (find_slot == 0xFF)) find_slot = i; | ||
150 | } | ||
151 | return find_slot; | ||
152 | } | ||
153 | |||
154 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
155 | #if defined(SOFT_AVR_FILTER_ENABLE) | ||
156 | |||
157 | typedef struct soft_filter__t { | ||
158 | unsigned int x[SOFT_AVR_COUNT]; | ||
159 | unsigned int y[SOFT_AVR_COUNT]; | ||
160 | unsigned int pos, cnt; | ||
161 | } __attribute__ ((packed)) soft_filter_t; | ||
162 | |||
163 | static soft_filter_t *pSoftFilter; | ||
164 | |||
165 | static unsigned char odroidq_soft_avr_filter(struct touch *ts, event_stack_u *event_stack, unsigned char find_slot) | ||
166 | { | ||
167 | unsigned int i, x, y; | ||
168 | |||
169 | if(ts->finger[find_slot].event != TS_EVENT_MOVE) { | ||
170 | pSoftFilter[find_slot].pos = 0; pSoftFilter[find_slot].cnt = 0; | ||
171 | return true; | ||
172 | } | ||
173 | |||
174 | x = (((event_stack->bits.msb_x << 8) & 0xF00) | event_stack->bits.lsb_x); | ||
175 | y = (((event_stack->bits.msb_y << 8) & 0xF00) | event_stack->bits.lsb_y); | ||
176 | |||
177 | if(y > 15) y -= 15; | ||
178 | else y = 1; | ||
179 | |||
180 | ts->finger[find_slot].id = event_stack->bits.number + 1; | ||
181 | ts->finger[find_slot].pressure = | ||
182 | (unsigned int)(event_stack->bits.pressure); | ||
183 | |||
184 | if(pSoftFilter[find_slot].cnt == 1) { | ||
185 | if((abs(pSoftFilter[find_slot].x[0] - x) < SOFT_AVR_MOVE_TOL_X) && | ||
186 | (abs(pSoftFilter[find_slot].y[0] - y) < SOFT_AVR_MOVE_TOL_Y)) return false; | ||
187 | } | ||
188 | |||
189 | if(event_stack->bits.speed < SOFT_AVR_ENABLE_SPEED) { | ||
190 | pSoftFilter[find_slot].x[pSoftFilter[find_slot].pos] = x; | ||
191 | pSoftFilter[find_slot].y[pSoftFilter[find_slot].pos] = y; | ||
192 | |||
193 | pSoftFilter[find_slot].pos++; pSoftFilter[find_slot].pos %= SOFT_AVR_COUNT; | ||
194 | |||
195 | if(pSoftFilter[find_slot].cnt < SOFT_AVR_COUNT) pSoftFilter[find_slot].cnt++; | ||
196 | |||
197 | for(i = 0, x = 0, y = 0; i < pSoftFilter[find_slot].cnt; i++) { | ||
198 | x += pSoftFilter[find_slot].x[i]; y += pSoftFilter[find_slot].y[i]; | ||
199 | } | ||
200 | |||
201 | ts->finger[find_slot].x = x / pSoftFilter[find_slot].cnt; | ||
202 | ts->finger[find_slot].y = y / pSoftFilter[find_slot].cnt; | ||
203 | } | ||
204 | else { | ||
205 | pSoftFilter[find_slot].pos = 0; pSoftFilter[find_slot].cnt = 0; | ||
206 | |||
207 | ts->finger[find_slot].x = x; ts->finger[find_slot].y = y; | ||
208 | } | ||
209 | |||
210 | return true; | ||
211 | } | ||
212 | |||
213 | #endif // #if defined(SOFT_AVR_FILTER_ENABLE) | ||
214 | |||
215 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
216 | void odroidq_work (struct touch *ts) | ||
217 | { | ||
218 | status_u status; | ||
219 | button_u button; | ||
220 | event_stack_u event_stack; | ||
221 | unsigned char cmd, find_slot; | ||
222 | |||
223 | cmd = TOUCH_STATUS; | ||
224 | if(ts->pdata->i2c_read(ts->client, (unsigned char *)&cmd, sizeof(cmd), (unsigned char *)&status.byte[0], sizeof(status_u)) < 0) return; | ||
225 | |||
226 | if(ts->pdata->keycode) { | ||
227 | cmd = BUTTON_STATUS; | ||
228 | if(ts->pdata->i2c_read(ts->client, (unsigned char *)&cmd, sizeof(cmd), (unsigned char *)&button.ubyte, sizeof(button_u)) < 0) return; | ||
229 | ts->pdata->key_report(ts, button.ubyte); | ||
230 | } | ||
231 | |||
232 | if(status.bits.fifo_overflow || status.bits.large_object || status.bits.abnomal_status) { | ||
233 | printk("[Error Status] fifo_overflow(%d), large_object(%d), abnomal_status(%d)\n" , status.bits.fifo_overflow | ||
234 | , status.bits.large_object | ||
235 | , status.bits.abnomal_status); | ||
236 | // Error reconfig | ||
237 | ts->pdata->disable(ts); ts->pdata->enable(ts); | ||
238 | |||
239 | return; | ||
240 | } | ||
241 | |||
242 | do { | ||
243 | cmd = EVENT_STACK; | ||
244 | ts->pdata->i2c_read(ts->client, (unsigned char *)&cmd, sizeof(cmd), (unsigned char *)&event_stack.byte[0], sizeof(event_stack_u)); | ||
245 | |||
246 | if(status.bits.fifo_valid) { | ||
247 | |||
248 | if((find_slot = odroidq_id_tracking(ts, event_stack.bits.number + 1)) == 0xFF) { | ||
249 | printk("ERROR(%s) : Empty slot not found", __func__); continue; | ||
250 | } | ||
251 | if((event_stack.bits.event != EVENT_UNKNOWN) && (event_stack.bits.number < ts->pdata->max_fingers)) { | ||
252 | if((event_stack.bits.event == EVENT_PRESS) || (event_stack.bits.event == EVENT_MOVE)) { | ||
253 | |||
254 | ts->finger[find_slot].status = true; | ||
255 | ts->finger[find_slot].event = TS_EVENT_MOVE; | ||
256 | |||
257 | #if defined(SOFT_AVR_FILTER_ENABLE) | ||
258 | ts->finger[find_slot].status = odroidq_soft_avr_filter(ts, &event_stack, find_slot); | ||
259 | #else | ||
260 | ts->finger[find_slot].id = event_stack.bits.number + 1; | ||
261 | ts->finger[find_slot].x = | ||
262 | (unsigned int)(((event_stack.bits.msb_x << 8) & 0xF00) | event_stack.bits.lsb_x); | ||
263 | ts->finger[find_slot].y = | ||
264 | (unsigned int)(((event_stack.bits.msb_y << 8) & 0xF00) | event_stack.bits.lsb_y); | ||
265 | |||
266 | if(ts->finger[find_slot].y > 15) ts->finger[find_slot].y -= 15; | ||
267 | else ts->finger[find_slot].y = 1; | ||
268 | |||
269 | ts->finger[find_slot].pressure = | ||
270 | (unsigned int)(event_stack.bits.pressure); | ||
271 | #endif | ||
272 | } | ||
273 | else { | ||
274 | if(ts->finger[find_slot].event == TS_EVENT_MOVE) { | ||
275 | ts->finger[find_slot].status = true; | ||
276 | ts->finger[find_slot].event = TS_EVENT_RELEASE; | ||
277 | } | ||
278 | else { | ||
279 | ts->finger[find_slot].status = false; | ||
280 | ts->finger[find_slot].event = TS_EVENT_UNKNOWN; | ||
281 | } | ||
282 | #if defined(SOFT_AVR_FILTER_ENABLE) | ||
283 | odroidq_soft_avr_filter(ts, &event_stack, find_slot); | ||
284 | #endif | ||
285 | } | ||
286 | ts->pdata->report(ts); | ||
287 | } | ||
288 | } | ||
289 | } while(!gpio_get_value(ts->pdata->irq_gpio)); | ||
290 | } | ||
291 | |||
292 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
293 | void odroidq_enable (struct touch *ts) | ||
294 | { | ||
295 | if(ts->disabled) { | ||
296 | odroidq_calibration(ts); | ||
297 | |||
298 | enable_irq(ts->irq); ts->disabled = false; | ||
299 | } | ||
300 | } | ||
301 | |||
302 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
303 | void odroidq_disable (struct touch *ts) | ||
304 | { | ||
305 | if(!ts->disabled) { | ||
306 | disable_irq(ts->irq); ts->disabled = true; | ||
307 | |||
308 | if(ts->pdata->event_clear) ts->pdata->event_clear(ts); | ||
309 | |||
310 | if(ts->pdata->reset_gpio) gpio_set_value(ts->pdata->reset_gpio, ts->pdata->reset_level); | ||
311 | } | ||
312 | } | ||
313 | |||
314 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
315 | int odroidq_early_probe (struct touch *ts) | ||
316 | { | ||
317 | #if defined(SOFT_AVR_FILTER_ENABLE) | ||
318 | if(ts->pdata->max_fingers) { | ||
319 | if(!(pSoftFilter = kzalloc(sizeof(soft_filter_t) * ts->pdata->max_fingers, GFP_KERNEL))) { | ||
320 | printk("touch soft-filter struct malloc error!\n"); return -ENOMEM; | ||
321 | } | ||
322 | } | ||
323 | #endif | ||
324 | |||
325 | odroidq_calibration(ts); | ||
326 | |||
327 | return 0; | ||
328 | } | ||
329 | |||
330 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
331 | int odroidq_probe (struct touch *ts) | ||
332 | { | ||
333 | int ret; | ||
334 | unsigned short rd; | ||
335 | unsigned char cmd; | ||
336 | |||
337 | // Get Touch screen information | ||
338 | cmd = DEVICE_ID; rd = 0; | ||
339 | ret = ts->pdata->i2c_read(ts->client, (unsigned char *)&cmd, sizeof(cmd), (unsigned char *)&rd, sizeof(rd)); | ||
340 | |||
341 | #if defined(DEBUG_TOUCH) // 0x2533 | ||
342 | printk("DEVICE ID = 0x%04X\n", rd); | ||
343 | #endif | ||
344 | |||
345 | cmd = VERSION_ID; rd = 0; | ||
346 | ret = ts->pdata->i2c_read(ts->client, (unsigned char *)&cmd, sizeof(cmd), (unsigned char *)&rd, sizeof(rd)); | ||
347 | |||
348 | #if defined(DEBUG_TOUCH) | ||
349 | printk("VERSION = 0x%04X\n", rd); | ||
350 | #endif | ||
351 | |||
352 | ts->fw_version = ((rd >> 8) & 0xFF) * 100 + (rd & 0xFF); | ||
353 | |||
354 | return ret; | ||
355 | } | ||
356 | |||
357 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
358 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
359 | MODULE_AUTHOR("HardKernel Co., Ltd."); | ||
360 | MODULE_LICENSE("GPL"); | ||
361 | MODULE_DESCRIPTION("Touchscreen Driver"); | ||
362 | |||
363 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
364 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c new file mode 100644 index 00000000000..a1b496a8c7c --- /dev/null +++ b/drivers/input/touchscreen/pixcir_i2c_ts.c | |||
@@ -0,0 +1,1008 @@ | |||
1 | /* drivers/input/touchscreen/pixcir_i2c_ts.c | ||
2 | * | ||
3 | * This software is licensed under the terms of the GNU General Public | ||
4 | * License version 2, as published by the Free Software Foundation, and | ||
5 | * may be copied, distributed, and modified under those terms. | ||
6 | * | ||
7 | * This program is distributed in the hope that it will be useful, | ||
8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
10 | * GNU General Public License for more details. | ||
11 | * | ||
12 | * You should have received a copy of the GNU General Public | ||
13 | * License along with this library; if not, write to the Free Software | ||
14 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
15 | * | ||
16 | * Copyright 2010 Pixcir, Inc. | ||
17 | * Copyright 2010 Bee <http://www.pixcir.com.cn> | ||
18 | * Copyright 2011 Dongsu Ha <dsfine.ha@samsung.com> | ||
19 | * Copyright 2011 Samsung Electronics <http://www.samsung.com> | ||
20 | */ | ||
21 | |||
22 | #include <linux/module.h> | ||
23 | #include <linux/interrupt.h> | ||
24 | #include <linux/input.h> | ||
25 | #include <linux/i2c.h> | ||
26 | #include <linux/smp.h> | ||
27 | #include <linux/delay.h> | ||
28 | #include <linux/slab.h> | ||
29 | #include <linux/uaccess.h> | ||
30 | |||
31 | #include <plat/gpio-cfg.h> | ||
32 | #include <mach/gpio.h> | ||
33 | #include <mach/board_rev.h> | ||
34 | |||
35 | #define PIXCIR_DEBUG 0 | ||
36 | |||
37 | #define ATTB samsung_board_rev_is_0_0() ? EXYNOS4_GPX1(7) : EXYNOS4_GPX2(6) | ||
38 | #define RESET samsung_board_rev_is_0_0() ? EXYNOS4_GPX1(6) : EXYNOS4212_GPM3(4) | ||
39 | #define GPIO_NAME samsung_board_rev_is_0_0() ? "GPX1" : "GPM3" | ||
40 | #define get_attb_value gpio_get_value | ||
41 | #define RESETPIN_CFG s3c_gpio_cfgpin(RESET, S3C_GPIO_OUTPUT) | ||
42 | #define RESETPIN_SET0 gpio_direction_output(RESET,0) | ||
43 | #define RESETPIN_SET1 gpio_direction_output(RESET,1) | ||
44 | |||
45 | #define SLAVE_ADDR 0x5c | ||
46 | #define BOOTLOADER_ADDR 0x5d | ||
47 | |||
48 | #ifndef I2C_MAJOR | ||
49 | #define I2C_MAJOR 125 | ||
50 | #endif | ||
51 | |||
52 | #define I2C_MINORS 256 | ||
53 | |||
54 | #define CALIBRATION_FLAG 1 | ||
55 | #define NORMAL_MODE 8 | ||
56 | #define PIXCIR_DEBUG_MODE 3 | ||
57 | #define VERSION_FLAG 6 | ||
58 | #define BOOTLOADER_MODE 7 | ||
59 | #define RD_EEPROM 12 | ||
60 | #define WR_EEPROM 13 | ||
61 | |||
62 | #define ENABLE_IRQ 10 | ||
63 | #define DISABLE_IRQ 11 | ||
64 | |||
65 | #define SPECOP 0x37 | ||
66 | |||
67 | #define reset | ||
68 | |||
69 | #define MAXX 32 | ||
70 | #define MAXY 32 | ||
71 | #define TOUCHSCREEN_MINX 0 | ||
72 | #define TOUCHSCREEN_MAXX 480 | ||
73 | #define TOUCHSCREEN_MINY 0 | ||
74 | #define TOUCHSCREEN_MAXY 800 | ||
75 | |||
76 | int global_irq; | ||
77 | |||
78 | static unsigned char status_reg; | ||
79 | unsigned char read_XN_YN_flag; | ||
80 | |||
81 | unsigned char global_touching, global_oldtouching; | ||
82 | unsigned char global_posx1_low, global_posx1_high, global_posy1_low, | ||
83 | global_posy1_high, global_posx2_low, global_posx2_high, | ||
84 | global_posy2_low, global_posy2_high; | ||
85 | |||
86 | unsigned char Tango_number; | ||
87 | |||
88 | unsigned char interrupt_flag; | ||
89 | |||
90 | unsigned char x_nb_electrodes; | ||
91 | unsigned char y_nb_electrodes; | ||
92 | unsigned char x2_nb_electrodes; | ||
93 | unsigned char x1_x2_nb_electrodes; | ||
94 | |||
95 | signed char xy_raw1[(MAXX * 2 + 3)]; | ||
96 | signed char xy_raw2[MAXX * 2]; | ||
97 | signed char xy_raw12[(MAXX * 4 + 3)]; | ||
98 | |||
99 | unsigned char data2eep[3], op2eep[2]; | ||
100 | |||
101 | struct i2c_dev { | ||
102 | struct list_head list; | ||
103 | struct i2c_adapter *adap; | ||
104 | struct device *dev; | ||
105 | }; | ||
106 | |||
107 | static struct i2c_driver pixcir_i2c_ts_driver; | ||
108 | static struct class *i2c_dev_class; | ||
109 | static LIST_HEAD(i2c_dev_list); | ||
110 | static DEFINE_SPINLOCK(i2c_dev_list_lock); | ||
111 | |||
112 | static void return_i2c_dev(struct i2c_dev *i2c_dev) | ||
113 | { | ||
114 | spin_lock(&i2c_dev_list_lock); | ||
115 | list_del(&i2c_dev->list); | ||
116 | spin_unlock(&i2c_dev_list_lock); | ||
117 | kfree(i2c_dev); | ||
118 | } | ||
119 | |||
120 | static struct i2c_dev *i2c_dev_get_by_minor(unsigned index) | ||
121 | { | ||
122 | struct i2c_dev *i2c_dev; | ||
123 | i2c_dev = NULL; | ||
124 | |||
125 | spin_lock(&i2c_dev_list_lock); | ||
126 | list_for_each_entry(i2c_dev, &i2c_dev_list, list) { | ||
127 | if (i2c_dev->adap->nr == index) | ||
128 | goto found; | ||
129 | } | ||
130 | i2c_dev = NULL; | ||
131 | found: | ||
132 | spin_unlock(&i2c_dev_list_lock); | ||
133 | |||
134 | return i2c_dev; | ||
135 | } | ||
136 | |||
137 | static struct i2c_dev *get_free_i2c_dev(struct i2c_adapter *adap) | ||
138 | { | ||
139 | struct i2c_dev *i2c_dev; | ||
140 | |||
141 | if (adap->nr >= I2C_MINORS) { | ||
142 | printk(KERN_ERR "i2c-dev: Out of device minors (%d)\n", | ||
143 | adap->nr); | ||
144 | return ERR_PTR(-ENODEV); | ||
145 | } | ||
146 | |||
147 | i2c_dev = kzalloc(sizeof(*i2c_dev), GFP_KERNEL); | ||
148 | if (!i2c_dev) | ||
149 | return ERR_PTR(-ENOMEM); | ||
150 | i2c_dev->adap = adap; | ||
151 | |||
152 | spin_lock(&i2c_dev_list_lock); | ||
153 | list_add_tail(&i2c_dev->list, &i2c_dev_list); | ||
154 | spin_unlock(&i2c_dev_list_lock); | ||
155 | |||
156 | return i2c_dev; | ||
157 | } | ||
158 | |||
159 | void read_XN_YN_value(struct i2c_client *client) | ||
160 | { | ||
161 | char Wrbuf[4], Rdbuf[2]; | ||
162 | |||
163 | memset(Wrbuf, 0, sizeof(Wrbuf)); | ||
164 | memset(Rdbuf, 0, sizeof(Rdbuf)); | ||
165 | |||
166 | Wrbuf[0] = SPECOP; | ||
167 | Wrbuf[1] = 1; | ||
168 | |||
169 | Wrbuf[2] = 64; | ||
170 | Wrbuf[3] = 0; | ||
171 | |||
172 | i2c_master_send(client, Wrbuf, 4); | ||
173 | mdelay(8); | ||
174 | i2c_master_recv(client, Rdbuf, 2); | ||
175 | x_nb_electrodes = Rdbuf[0]; | ||
176 | |||
177 | if (Tango_number == 1) { | ||
178 | x2_nb_electrodes = 0; | ||
179 | |||
180 | memset(Wrbuf, 0, sizeof(Wrbuf)); | ||
181 | memset(Rdbuf, 0, sizeof(Rdbuf)); | ||
182 | |||
183 | Wrbuf[0] = SPECOP; | ||
184 | Wrbuf[1] = 1; | ||
185 | Wrbuf[2] = 203; | ||
186 | Wrbuf[3] = 0; | ||
187 | |||
188 | i2c_master_send(client, Wrbuf, 4); | ||
189 | mdelay(4); | ||
190 | |||
191 | i2c_master_recv(client, Rdbuf, 2); | ||
192 | y_nb_electrodes = Rdbuf[0]; | ||
193 | } else if (Tango_number == 2) { | ||
194 | memset(Wrbuf, 0, sizeof(Wrbuf)); | ||
195 | memset(Rdbuf, 0, sizeof(Rdbuf)); | ||
196 | |||
197 | Wrbuf[0] = SPECOP; | ||
198 | Wrbuf[1] = 1; | ||
199 | |||
200 | i2c_master_send(client, Wrbuf, 4); | ||
201 | mdelay(4); | ||
202 | i2c_master_recv(client, Rdbuf, 2); | ||
203 | x2_nb_electrodes = Rdbuf[0]; | ||
204 | |||
205 | memset(Wrbuf, 0, sizeof(Wrbuf)); | ||
206 | memset(Rdbuf, 0, sizeof(Rdbuf)); | ||
207 | |||
208 | Wrbuf[0] = SPECOP; | ||
209 | Wrbuf[1] = 1; | ||
210 | |||
211 | i2c_master_send(client, Wrbuf, 4); | ||
212 | mdelay(4); | ||
213 | |||
214 | i2c_master_recv(client, Rdbuf, 2); | ||
215 | y_nb_electrodes = Rdbuf[0]; | ||
216 | } | ||
217 | if (x2_nb_electrodes) | ||
218 | x1_x2_nb_electrodes = x_nb_electrodes + x2_nb_electrodes - 1; | ||
219 | else | ||
220 | x1_x2_nb_electrodes = x_nb_electrodes; | ||
221 | |||
222 | read_XN_YN_flag = 1; | ||
223 | } | ||
224 | |||
225 | void read_XY_tables(struct i2c_client *client, signed char *xy_raw1_buf, | ||
226 | signed char *xy_raw2_buf) | ||
227 | { | ||
228 | u_int8_t Wrbuf[1]; | ||
229 | |||
230 | memset(Wrbuf, 0, sizeof(Wrbuf)); | ||
231 | |||
232 | i2c_master_send(client, Wrbuf, 1); | ||
233 | i2c_master_recv(client, xy_raw1_buf, (MAXX - 1) * 2); | ||
234 | i2c_master_send(client, Wrbuf, 1); | ||
235 | i2c_master_recv(client, xy_raw2_buf, (MAXX - 1) * 2); | ||
236 | } | ||
237 | |||
238 | static struct workqueue_struct *pixcir_wq; | ||
239 | |||
240 | struct pixcir_i2c_ts_data { | ||
241 | struct i2c_client *client; | ||
242 | struct input_dev *input; | ||
243 | struct input_dev *input_key; | ||
244 | struct delayed_work work; | ||
245 | int irq; | ||
246 | }; | ||
247 | |||
248 | static unsigned char pixcir_keycode[] = {KEY_D, KEY_A, KEY_B}; | ||
249 | |||
250 | static void pixcir_ts_poscheck(struct work_struct *work) | ||
251 | { | ||
252 | struct pixcir_i2c_ts_data *tsdata = | ||
253 | container_of(work, struct pixcir_i2c_ts_data, work.work); | ||
254 | unsigned char touching = 0; | ||
255 | unsigned char oldtouching = 0; | ||
256 | int posx1, posy1, posx2, posy2; | ||
257 | unsigned char Rdbuf[10], Wrbuf[1]; | ||
258 | int z = 50; | ||
259 | int w = 15; | ||
260 | static int pressed_keycode = -1; | ||
261 | |||
262 | interrupt_flag = 1; | ||
263 | |||
264 | memset(Wrbuf, 0, sizeof(Wrbuf)); | ||
265 | memset(Rdbuf, 0, sizeof(Rdbuf)); | ||
266 | |||
267 | Wrbuf[0] = 0; | ||
268 | |||
269 | i2c_master_send(tsdata->client, Wrbuf, 1); | ||
270 | i2c_master_recv(tsdata->client, Rdbuf, sizeof(Rdbuf)); | ||
271 | |||
272 | posx1 = ((Rdbuf[5] << 8) | Rdbuf[4]); | ||
273 | posy1 = ((Rdbuf[3] << 8) | Rdbuf[2]); | ||
274 | posx2 = ((Rdbuf[9] << 8) | Rdbuf[8]); | ||
275 | posy2 = ((Rdbuf[7] << 8) | Rdbuf[6]); | ||
276 | |||
277 | posx1 = TOUCHSCREEN_MAXX - posx1; | ||
278 | posx2 = TOUCHSCREEN_MAXX - posx2; | ||
279 | |||
280 | touching = Rdbuf[0]; | ||
281 | oldtouching = Rdbuf[1]; | ||
282 | |||
283 | if (touching == 1 && posy1 > 800) { | ||
284 | if (posx1 < 100) /* MENU KEY */ | ||
285 | pressed_keycode = 0; | ||
286 | else if (posx1 > (240 - 50) && posx1 < (240 + 50)) /* HOME KEY */ | ||
287 | pressed_keycode = 1; | ||
288 | else if (posx1 > (480 - 100)) /* BACK KEY */ | ||
289 | pressed_keycode = 2; | ||
290 | else | ||
291 | pressed_keycode = -1; | ||
292 | |||
293 | if (pressed_keycode != -1) { | ||
294 | input_event(tsdata->input_key, EV_MSC, MSC_SCAN, | ||
295 | pressed_keycode); | ||
296 | input_report_key(tsdata->input_key, | ||
297 | pixcir_keycode[pressed_keycode], 1); | ||
298 | input_sync(tsdata->input_key); | ||
299 | } | ||
300 | } else { | ||
301 | if (touching) { | ||
302 | input_report_abs(tsdata->input, ABS_X, posx1); | ||
303 | input_report_abs(tsdata->input, ABS_Y, posy1); | ||
304 | input_report_key(tsdata->input, BTN_TOUCH, 1); | ||
305 | input_report_abs(tsdata->input, ABS_PRESSURE, 1); | ||
306 | } else { | ||
307 | input_report_key(tsdata->input, BTN_TOUCH, 0); | ||
308 | input_report_abs(tsdata->input, ABS_PRESSURE, 0); | ||
309 | } | ||
310 | |||
311 | if (!(touching)) { | ||
312 | z = 0; | ||
313 | w = 0; | ||
314 | } | ||
315 | if (touching == 1) { | ||
316 | input_report_abs(tsdata->input, ABS_MT_TOUCH_MAJOR, z); | ||
317 | input_report_abs(tsdata->input, ABS_MT_WIDTH_MAJOR, w); | ||
318 | input_report_abs(tsdata->input, ABS_MT_POSITION_X, posx1); | ||
319 | input_report_abs(tsdata->input, ABS_MT_POSITION_Y, posy1); | ||
320 | input_mt_sync(tsdata->input); | ||
321 | } else if (touching == 2) { | ||
322 | input_report_abs(tsdata->input, ABS_MT_TOUCH_MAJOR, z); | ||
323 | input_report_abs(tsdata->input, ABS_MT_WIDTH_MAJOR, w); | ||
324 | input_report_abs(tsdata->input, ABS_MT_POSITION_X, posx1); | ||
325 | input_report_abs(tsdata->input, ABS_MT_POSITION_Y, posy1); | ||
326 | input_mt_sync(tsdata->input); | ||
327 | |||
328 | input_report_abs(tsdata->input, ABS_MT_TOUCH_MAJOR, z); | ||
329 | input_report_abs(tsdata->input, ABS_MT_WIDTH_MAJOR, w); | ||
330 | input_report_abs(tsdata->input, ABS_MT_POSITION_X, posx2); | ||
331 | input_report_abs(tsdata->input, ABS_MT_POSITION_Y, posy2); | ||
332 | input_mt_sync(tsdata->input); | ||
333 | } | ||
334 | input_sync(tsdata->input); | ||
335 | } | ||
336 | |||
337 | if (touching == 0) { | ||
338 | if (pressed_keycode != -1) { | ||
339 | input_event (tsdata->input_key, EV_MSC, MSC_SCAN, pressed_keycode); | ||
340 | input_report_key (tsdata->input_key, pixcir_keycode[pressed_keycode], 0); | ||
341 | input_sync(tsdata->input_key); | ||
342 | pressed_keycode = -1; | ||
343 | } | ||
344 | else { | ||
345 | input_mt_sync(tsdata->input); | ||
346 | input_sync(tsdata->input); | ||
347 | } | ||
348 | } | ||
349 | |||
350 | if (status_reg == NORMAL_MODE) { | ||
351 | global_touching = touching; | ||
352 | global_oldtouching = oldtouching; | ||
353 | global_posx1_low = Rdbuf[2]; | ||
354 | global_posx1_high = Rdbuf[3]; | ||
355 | global_posy1_low = Rdbuf[4]; | ||
356 | global_posy1_high = Rdbuf[5]; | ||
357 | global_posx2_low = Rdbuf[6]; | ||
358 | global_posx2_high = Rdbuf[7]; | ||
359 | global_posy2_low = Rdbuf[8]; | ||
360 | global_posy2_high = Rdbuf[9]; | ||
361 | } | ||
362 | |||
363 | enable_irq(tsdata->irq); | ||
364 | } | ||
365 | |||
366 | static irqreturn_t pixcir_ts_isr(int irq, void *dev_id) | ||
367 | { | ||
368 | struct pixcir_i2c_ts_data *tsdata = dev_id; | ||
369 | |||
370 | if ((status_reg == 0) || (status_reg == NORMAL_MODE)) { | ||
371 | disable_irq_nosync(irq); | ||
372 | queue_work(pixcir_wq, &tsdata->work.work); | ||
373 | } | ||
374 | |||
375 | return IRQ_HANDLED; | ||
376 | } | ||
377 | |||
378 | static int pixcir_ts_open(struct input_dev *dev) | ||
379 | { | ||
380 | return 0; | ||
381 | } | ||
382 | |||
383 | static void pixcir_ts_close(struct input_dev *dev) | ||
384 | { | ||
385 | } | ||
386 | |||
387 | static int pixcir_i2c_ts_probe(struct i2c_client *client, | ||
388 | const struct i2c_device_id *id) | ||
389 | { | ||
390 | struct pixcir_i2c_ts_data *tsdata; | ||
391 | struct input_dev *input; | ||
392 | struct input_dev *input_key; | ||
393 | struct device *dev; | ||
394 | struct i2c_dev *i2c_dev; | ||
395 | int error = 0; | ||
396 | |||
397 | tsdata = kzalloc(sizeof(*tsdata), GFP_KERNEL); | ||
398 | if (!tsdata) { | ||
399 | dev_err(&client->dev, "failed to allocate driver data!\n"); | ||
400 | error = -ENOMEM; | ||
401 | dev_set_drvdata(&client->dev, NULL); | ||
402 | return error; | ||
403 | } | ||
404 | |||
405 | dev_set_drvdata(&client->dev, tsdata); | ||
406 | |||
407 | input = input_allocate_device(); | ||
408 | if (!input) { | ||
409 | dev_err(&client->dev, "failed to allocate input device!\n"); | ||
410 | error = -ENOMEM; | ||
411 | goto err_free_tsdata; | ||
412 | } | ||
413 | |||
414 | set_bit(EV_SYN, input->evbit); | ||
415 | set_bit(EV_KEY, input->evbit); | ||
416 | set_bit(EV_ABS, input->evbit); | ||
417 | set_bit(BTN_TOUCH, input->keybit); | ||
418 | input_set_abs_params(input, ABS_X, TOUCHSCREEN_MINX, | ||
419 | TOUCHSCREEN_MAXX, 0, 0); | ||
420 | input_set_abs_params(input, ABS_Y, TOUCHSCREEN_MINY, | ||
421 | TOUCHSCREEN_MAXY, 0, 0); | ||
422 | input_set_abs_params(input, ABS_MT_POSITION_X, | ||
423 | TOUCHSCREEN_MINX, TOUCHSCREEN_MAXX, 0, 0); | ||
424 | input_set_abs_params(input, ABS_MT_POSITION_Y, | ||
425 | TOUCHSCREEN_MINY, TOUCHSCREEN_MAXY, 0, 0); | ||
426 | input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0); | ||
427 | input_set_abs_params(input, ABS_MT_WIDTH_MAJOR, 0, 25, 0, 0); | ||
428 | |||
429 | input->name = "pixcir-i2c-ts"; | ||
430 | input->phys = "pixcir_ts/input1"; | ||
431 | input->id.bustype = BUS_I2C; | ||
432 | input->dev.parent = &client->dev; | ||
433 | input->open = pixcir_ts_open; | ||
434 | input->close = pixcir_ts_close; | ||
435 | |||
436 | input_set_drvdata(input, tsdata); | ||
437 | |||
438 | tsdata->client = client; | ||
439 | tsdata->input = input; | ||
440 | |||
441 | INIT_WORK(&tsdata->work.work, pixcir_ts_poscheck); | ||
442 | |||
443 | tsdata->irq = client->irq; | ||
444 | global_irq = client->irq; | ||
445 | |||
446 | if (input_register_device(input)) { | ||
447 | error = -EIO; | ||
448 | goto err_free_input; | ||
449 | } | ||
450 | |||
451 | /* for keypad */ | ||
452 | input_key = input_allocate_device(); | ||
453 | if (!input_key) { | ||
454 | dev_err(&client->dev, "failed to allocate input device!\n"); | ||
455 | error = -ENOMEM; | ||
456 | goto err_unregister_input; | ||
457 | } | ||
458 | |||
459 | input_key->evbit[0] = BIT_MASK(EV_KEY); | ||
460 | input_set_capability(input_key, EV_MSC, MSC_SCAN); | ||
461 | |||
462 | input_key->keycode = pixcir_keycode; | ||
463 | input_key->keycodesize = sizeof(unsigned char); | ||
464 | input_key->keycodemax = ARRAY_SIZE(pixcir_keycode); | ||
465 | |||
466 | __set_bit(pixcir_keycode[0], input_key->keybit); | ||
467 | __set_bit(pixcir_keycode[1], input_key->keybit); | ||
468 | __set_bit(pixcir_keycode[2], input_key->keybit); | ||
469 | __clear_bit(KEY_RESERVED, input_key->keybit); | ||
470 | |||
471 | input_key->name = "pixcir-i2c-ts_key"; | ||
472 | input_key->phys = "pixcir_ts/input2"; | ||
473 | input_key->id.bustype = BUS_I2C; | ||
474 | input_key->dev.parent = &client->dev; | ||
475 | input_key->open = pixcir_ts_open; | ||
476 | input_key->close = pixcir_ts_close; | ||
477 | |||
478 | tsdata->input_key = input_key; | ||
479 | |||
480 | if (input_register_device(input_key)) { | ||
481 | error = -EIO; | ||
482 | goto err_free_input_key; | ||
483 | } | ||
484 | |||
485 | if (gpio_request(RESET, GPIO_NAME)) { | ||
486 | error = -EIO; | ||
487 | goto err_unregister_input_key; | ||
488 | } | ||
489 | RESETPIN_CFG; | ||
490 | RESETPIN_SET0; | ||
491 | mdelay(20); | ||
492 | RESETPIN_SET1; | ||
493 | |||
494 | mdelay(30); | ||
495 | |||
496 | error = request_irq(tsdata->irq, pixcir_ts_isr, IRQF_TRIGGER_FALLING, | ||
497 | "pixcir_ts_irq", tsdata); | ||
498 | if (error) { | ||
499 | dev_err(&client->dev, "Unable to request touchscreen IRQ.\n"); | ||
500 | goto err_unregister_input_key; | ||
501 | } | ||
502 | |||
503 | s3c_gpio_setpull(ATTB, S3C_GPIO_PULL_NONE); | ||
504 | |||
505 | device_init_wakeup(&client->dev, 0); | ||
506 | |||
507 | i2c_dev = get_free_i2c_dev(client->adapter); | ||
508 | if (IS_ERR(i2c_dev)) { | ||
509 | error = PTR_ERR(i2c_dev); | ||
510 | goto err_free_irq; | ||
511 | } | ||
512 | |||
513 | dev = device_create(i2c_dev_class, &client->adapter->dev, | ||
514 | MKDEV(I2C_MAJOR, client->adapter->nr), NULL, | ||
515 | "pixcir_i2c_ts%d", 0); | ||
516 | if (IS_ERR(dev)) { | ||
517 | error = PTR_ERR(dev); | ||
518 | goto err_free_irq; | ||
519 | } | ||
520 | |||
521 | dev_err(&tsdata->client->dev, "insmod successfully!\n"); | ||
522 | |||
523 | return 0; | ||
524 | |||
525 | err_free_irq: | ||
526 | free_irq(tsdata->irq, input); | ||
527 | err_unregister_input_key: | ||
528 | input_unregister_device(input_key); | ||
529 | err_free_input_key: | ||
530 | input_free_device(input_key); | ||
531 | err_unregister_input: | ||
532 | input_unregister_device(input); | ||
533 | err_free_input: | ||
534 | input_free_device(input); | ||
535 | err_free_tsdata: | ||
536 | kfree(tsdata); | ||
537 | |||
538 | return error; | ||
539 | } | ||
540 | |||
541 | static int pixcir_i2c_ts_remove(struct i2c_client *client) | ||
542 | { | ||
543 | int error; | ||
544 | struct i2c_dev *i2c_dev; | ||
545 | struct pixcir_i2c_ts_data *tsdata = dev_get_drvdata(&client->dev); | ||
546 | |||
547 | free_irq(tsdata->irq, tsdata); | ||
548 | i2c_dev = get_free_i2c_dev(client->adapter); | ||
549 | if (IS_ERR(i2c_dev)) { | ||
550 | error = PTR_ERR(i2c_dev); | ||
551 | return error; | ||
552 | } | ||
553 | return_i2c_dev(i2c_dev); | ||
554 | device_destroy(i2c_dev_class, MKDEV(I2C_MAJOR, client->adapter->nr)); | ||
555 | input_unregister_device(tsdata->input); | ||
556 | input_free_device(tsdata->input); | ||
557 | input_unregister_device(tsdata->input_key); | ||
558 | input_free_device(tsdata->input_key); | ||
559 | kfree(tsdata); | ||
560 | dev_set_drvdata(&client->dev, NULL); | ||
561 | |||
562 | return 0; | ||
563 | } | ||
564 | |||
565 | static int pixcir_i2c_ts_suspend(struct i2c_client *client, pm_message_t mesg) | ||
566 | { | ||
567 | struct pixcir_i2c_ts_data *tsdata = dev_get_drvdata(&client->dev); | ||
568 | |||
569 | if (device_may_wakeup(&client->dev)) | ||
570 | enable_irq_wake(tsdata->irq); | ||
571 | |||
572 | return 0; | ||
573 | } | ||
574 | |||
575 | static int pixcir_i2c_ts_resume(struct i2c_client *client) | ||
576 | { | ||
577 | struct pixcir_i2c_ts_data *tsdata = dev_get_drvdata(&client->dev); | ||
578 | |||
579 | if (device_may_wakeup(&client->dev)) | ||
580 | disable_irq_wake(tsdata->irq); | ||
581 | |||
582 | return 0; | ||
583 | } | ||
584 | |||
585 | static int pixcir_open(struct inode *inode, struct file *file) | ||
586 | { | ||
587 | int subminor; | ||
588 | struct i2c_client *client; | ||
589 | struct i2c_adapter *adapter; | ||
590 | struct i2c_dev *i2c_dev; | ||
591 | |||
592 | subminor = iminor(inode); | ||
593 | |||
594 | i2c_dev = i2c_dev_get_by_minor(subminor); | ||
595 | if (!i2c_dev) { | ||
596 | printk(KERN_ERR "error i2c_dev\n"); | ||
597 | return -ENODEV; | ||
598 | } | ||
599 | |||
600 | adapter = i2c_get_adapter(i2c_dev->adap->nr); | ||
601 | if (!adapter) | ||
602 | return -ENODEV; | ||
603 | |||
604 | client = kzalloc(sizeof(*client), GFP_KERNEL); | ||
605 | if (!client) { | ||
606 | i2c_put_adapter(adapter); | ||
607 | return -ENOMEM; | ||
608 | } | ||
609 | snprintf(client->name, I2C_NAME_SIZE, "pixcir_i2c_ts%d", adapter->nr); | ||
610 | client->driver = &pixcir_i2c_ts_driver; | ||
611 | client->adapter = adapter; | ||
612 | file->private_data = client; | ||
613 | |||
614 | return 0; | ||
615 | } | ||
616 | |||
617 | static long pixcir_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | ||
618 | { | ||
619 | struct i2c_client *client = | ||
620 | (struct i2c_client *) file->private_data; | ||
621 | |||
622 | switch (cmd) { | ||
623 | case CALIBRATION_FLAG: | ||
624 | client->addr = SLAVE_ADDR; | ||
625 | status_reg = 0; | ||
626 | status_reg = CALIBRATION_FLAG; | ||
627 | break; | ||
628 | |||
629 | case NORMAL_MODE: | ||
630 | client->addr = SLAVE_ADDR; | ||
631 | status_reg = 0; | ||
632 | status_reg = NORMAL_MODE; | ||
633 | break; | ||
634 | |||
635 | case PIXCIR_DEBUG_MODE: | ||
636 | client->addr = SLAVE_ADDR; | ||
637 | status_reg = 0; | ||
638 | status_reg = PIXCIR_DEBUG_MODE; | ||
639 | |||
640 | Tango_number = arg; | ||
641 | break; | ||
642 | |||
643 | case BOOTLOADER_MODE: | ||
644 | status_reg = 0; | ||
645 | status_reg = BOOTLOADER_MODE; | ||
646 | disable_irq_nosync(global_irq); | ||
647 | |||
648 | #ifdef reset | ||
649 | client->addr = BOOTLOADER_ADDR; | ||
650 | |||
651 | RESETPIN_CFG; | ||
652 | RESETPIN_SET0; | ||
653 | mdelay(20); | ||
654 | RESETPIN_SET1; | ||
655 | |||
656 | mdelay(30); | ||
657 | #else | ||
658 | client->addr = SLAVE_ADDR; | ||
659 | tmp[0] = SPECOP; | ||
660 | tmp[1] = 5; | ||
661 | i2c_master_send(client, tmp, 2); | ||
662 | |||
663 | client->addr = BOOTLOADER_ADDR; | ||
664 | #endif | ||
665 | break; | ||
666 | |||
667 | case ENABLE_IRQ: | ||
668 | enable_irq(global_irq); | ||
669 | status_reg = 0; | ||
670 | break; | ||
671 | |||
672 | case DISABLE_IRQ: | ||
673 | disable_irq_nosync(global_irq); | ||
674 | break; | ||
675 | |||
676 | case RD_EEPROM: | ||
677 | client->addr = SLAVE_ADDR; | ||
678 | status_reg = 0; | ||
679 | status_reg = RD_EEPROM; | ||
680 | break; | ||
681 | |||
682 | case WR_EEPROM: | ||
683 | client->addr = SLAVE_ADDR; | ||
684 | status_reg = 0; | ||
685 | status_reg = WR_EEPROM; | ||
686 | break; | ||
687 | |||
688 | case VERSION_FLAG: | ||
689 | client->addr = SLAVE_ADDR; | ||
690 | status_reg = 0; | ||
691 | status_reg = VERSION_FLAG; | ||
692 | |||
693 | Tango_number = arg; | ||
694 | break; | ||
695 | |||
696 | default: | ||
697 | break; | ||
698 | } | ||
699 | return 0; | ||
700 | } | ||
701 | |||
702 | static ssize_t pixcir_read(struct file *file, | ||
703 | char __user *buf, size_t count, loff_t *offset) | ||
704 | { | ||
705 | struct i2c_client *client = | ||
706 | (struct i2c_client *)file->private_data; | ||
707 | int ret = 0; | ||
708 | unsigned char normal_tmp[10]; | ||
709 | |||
710 | switch (status_reg) { | ||
711 | case NORMAL_MODE: | ||
712 | memset(normal_tmp, 0, sizeof(normal_tmp)); | ||
713 | if (interrupt_flag) { | ||
714 | normal_tmp[0] = global_touching; | ||
715 | normal_tmp[1] = global_oldtouching; | ||
716 | normal_tmp[2] = global_posx1_low; | ||
717 | normal_tmp[3] = global_posx1_high; | ||
718 | normal_tmp[4] = global_posy1_low; | ||
719 | normal_tmp[5] = global_posy1_high; | ||
720 | normal_tmp[6] = global_posx2_low; | ||
721 | normal_tmp[7] = global_posx2_high; | ||
722 | normal_tmp[8] = global_posy2_low; | ||
723 | normal_tmp[9] = global_posy2_high; | ||
724 | if (copy_to_user(buf, normal_tmp, 10)) { | ||
725 | dev_err(&client->dev, "error : copy_to_user\n"); | ||
726 | return -EFAULT; | ||
727 | } | ||
728 | |||
729 | } | ||
730 | interrupt_flag = 0; | ||
731 | break; | ||
732 | |||
733 | case PIXCIR_DEBUG_MODE: | ||
734 | if (read_XN_YN_flag == 0) { | ||
735 | unsigned char buf[2]; | ||
736 | memset(buf, 0, sizeof(buf)); | ||
737 | |||
738 | read_XN_YN_value(client); | ||
739 | |||
740 | buf[0] = 194; | ||
741 | buf[1] = 0; | ||
742 | i2c_master_send(client, buf, 2); | ||
743 | } else { | ||
744 | memset(xy_raw1, 0, sizeof(xy_raw1)); | ||
745 | memset(xy_raw2, 0, sizeof(xy_raw2)); | ||
746 | read_XY_tables(client, xy_raw1, xy_raw2); | ||
747 | } | ||
748 | |||
749 | if (Tango_number == 1) { | ||
750 | xy_raw1[MAXX * 2] = x_nb_electrodes; | ||
751 | xy_raw1[MAXX * 2 + 1] = y_nb_electrodes; | ||
752 | |||
753 | if (copy_to_user(buf, xy_raw1, MAXX * 2 + 2)) { | ||
754 | dev_err(&client->dev, "error : copy_to_user\n"); | ||
755 | return -EFAULT; | ||
756 | } | ||
757 | |||
758 | } else if (Tango_number == 2) { | ||
759 | xy_raw1[MAXX * 2] = x_nb_electrodes; | ||
760 | xy_raw1[MAXX * 2 + 1] = y_nb_electrodes; | ||
761 | xy_raw1[MAXX * 2 + 2] = x2_nb_electrodes; | ||
762 | |||
763 | for (ret = 0; ret < (MAXX * 2 + 3); ret++) | ||
764 | xy_raw12[ret] = xy_raw1[ret]; | ||
765 | |||
766 | for (ret = 0; ret < (MAXX * 2 - 1); ret++) | ||
767 | xy_raw12[(MAXX * 2 + 3) + ret] = xy_raw2[ret]; | ||
768 | |||
769 | if (copy_to_user(buf, xy_raw12, MAXX * 4 + 3)) { | ||
770 | dev_err(&client->dev, "error : copy_to_user\n"); | ||
771 | return -EFAULT; | ||
772 | } | ||
773 | } | ||
774 | break; | ||
775 | |||
776 | case RD_EEPROM: { | ||
777 | unsigned char epmbytbuf[512]; | ||
778 | |||
779 | memset(epmbytbuf, 0, sizeof(epmbytbuf)); | ||
780 | i2c_master_recv(client, epmbytbuf, count); | ||
781 | |||
782 | if (copy_to_user(buf, epmbytbuf, count)) { | ||
783 | dev_err(&client->dev, "error : copy_to_user\n"); | ||
784 | return -EFAULT; | ||
785 | } | ||
786 | |||
787 | break; | ||
788 | } | ||
789 | |||
790 | case VERSION_FLAG: { | ||
791 | unsigned char vaddbuf[1], verbuf[5]; | ||
792 | |||
793 | memset(vaddbuf, 0, sizeof(vaddbuf)); | ||
794 | memset(verbuf, 0, sizeof(verbuf)); | ||
795 | vaddbuf[0] = 48; | ||
796 | i2c_master_send(client, vaddbuf, 1); | ||
797 | i2c_master_recv(client, verbuf, 5); | ||
798 | |||
799 | if (copy_to_user(buf, verbuf, 5)) { | ||
800 | dev_err(&client->dev, "error : copy_to_user\n"); | ||
801 | return -EFAULT; | ||
802 | } | ||
803 | |||
804 | break; | ||
805 | } | ||
806 | |||
807 | default: | ||
808 | break; | ||
809 | } | ||
810 | |||
811 | return ret; | ||
812 | } | ||
813 | |||
814 | static ssize_t pixcir_write(struct file *file, | ||
815 | const char __user *buf, size_t count, loff_t *ppos) | ||
816 | { | ||
817 | struct i2c_client *client; | ||
818 | char *tmp, bootload_data[143], Rdbuf[1]; | ||
819 | int ret = 0, stu; | ||
820 | int re_value = 0; | ||
821 | |||
822 | client = file->private_data; | ||
823 | |||
824 | switch (status_reg) { | ||
825 | case CALIBRATION_FLAG: | ||
826 | tmp = kmalloc(count, GFP_KERNEL); | ||
827 | if (tmp == NULL) | ||
828 | return -ENOMEM; | ||
829 | |||
830 | if (copy_from_user(tmp, buf, count)) { | ||
831 | dev_err(&client->dev, "error : copy_from_user\n"); | ||
832 | kfree(tmp); | ||
833 | return -EFAULT; | ||
834 | } | ||
835 | i2c_master_send(client, tmp, count); | ||
836 | mdelay(100); | ||
837 | |||
838 | kfree(tmp); | ||
839 | |||
840 | status_reg = 0; | ||
841 | break; | ||
842 | |||
843 | case BOOTLOADER_MODE: | ||
844 | memset(bootload_data, 0, sizeof(bootload_data)); | ||
845 | memset(Rdbuf, 0, sizeof(Rdbuf)); | ||
846 | |||
847 | if (copy_from_user(bootload_data, buf, count)) { | ||
848 | dev_err(&client->dev, "error : copy_from_user\n"); | ||
849 | return -EFAULT; | ||
850 | } | ||
851 | |||
852 | stu = bootload_data[0]; | ||
853 | |||
854 | i2c_master_send(client, bootload_data, count); | ||
855 | |||
856 | if (stu != 0x01) { | ||
857 | mdelay(1); | ||
858 | while (get_attb_value(ATTB)) | ||
859 | ; | ||
860 | mdelay(1); | ||
861 | |||
862 | i2c_master_recv(client, Rdbuf, 1); | ||
863 | re_value = Rdbuf[0]; | ||
864 | } else { | ||
865 | mdelay(100); | ||
866 | status_reg = 0; | ||
867 | enable_irq(global_irq); | ||
868 | } | ||
869 | |||
870 | if ((re_value & 0x80) && (stu != 0x01)) { | ||
871 | printk(KERN_ERR "Failed : (re_value & 0x80) && (stu != 0x01) = 1\n"); | ||
872 | ret = 0; | ||
873 | } | ||
874 | break; | ||
875 | |||
876 | case RD_EEPROM: { | ||
877 | unsigned char epmdatabuf[2], wr2eep[4]; | ||
878 | |||
879 | memset(epmdatabuf, 0, sizeof(epmdatabuf)); | ||
880 | memset(wr2eep, 0, sizeof(wr2eep)); | ||
881 | |||
882 | if (copy_from_user(epmdatabuf, buf, count)) { | ||
883 | dev_err(&client->dev, "error : copy_from_user\n"); | ||
884 | return -EFAULT; | ||
885 | } | ||
886 | |||
887 | wr2eep[0] = SPECOP; | ||
888 | wr2eep[1] = 1; | ||
889 | wr2eep[2] = epmdatabuf[0]; | ||
890 | wr2eep[3] = epmdatabuf[1]; | ||
891 | i2c_master_send(client, wr2eep, 4); | ||
892 | |||
893 | break; | ||
894 | } | ||
895 | |||
896 | case WR_EEPROM: { | ||
897 | unsigned char epmdatabuf[2]; | ||
898 | |||
899 | memset(epmdatabuf, 0, sizeof(epmdatabuf)); | ||
900 | |||
901 | if (copy_from_user(epmdatabuf, buf, count)) { | ||
902 | dev_err(&client->dev, "error : copy_from_user\n"); | ||
903 | return -EFAULT; | ||
904 | } | ||
905 | |||
906 | if (2 == count) { | ||
907 | op2eep[0] = SPECOP; | ||
908 | op2eep[1] = 2; | ||
909 | data2eep[0] = epmdatabuf[0]; | ||
910 | data2eep[1] = epmdatabuf[1]; | ||
911 | } else if (1 == count) { | ||
912 | data2eep[2] = epmdatabuf[0]; | ||
913 | i2c_master_send(client, op2eep, 2); | ||
914 | i2c_master_send(client, data2eep, 3); | ||
915 | mdelay(4); | ||
916 | i2c_master_recv(client, data2eep, 1); | ||
917 | mdelay(100); | ||
918 | } | ||
919 | break; | ||
920 | } | ||
921 | |||
922 | default: | ||
923 | break; | ||
924 | } | ||
925 | return ret; | ||
926 | } | ||
927 | |||
928 | static int pixcir_release(struct inode *inode, struct file *file) | ||
929 | { | ||
930 | struct i2c_client *client = file->private_data; | ||
931 | |||
932 | i2c_put_adapter(client->adapter); | ||
933 | kfree(client); | ||
934 | file->private_data = NULL; | ||
935 | |||
936 | return 0; | ||
937 | } | ||
938 | |||
939 | static const struct file_operations pixcir_i2c_ts_fops = { | ||
940 | .owner = THIS_MODULE, | ||
941 | .read = pixcir_read, | ||
942 | .write = pixcir_write, | ||
943 | .open = pixcir_open, | ||
944 | .unlocked_ioctl = pixcir_ioctl, | ||
945 | .release = pixcir_release, | ||
946 | }; | ||
947 | |||
948 | static const struct i2c_device_id pixcir_i2c_ts_id[] = { | ||
949 | {"pixcir-ts", 0}, | ||
950 | { } | ||
951 | }; | ||
952 | MODULE_DEVICE_TABLE(i2c, pixcir_i2c_ts_id); | ||
953 | |||
954 | static struct i2c_driver pixcir_i2c_ts_driver = { | ||
955 | .driver = { | ||
956 | .owner = THIS_MODULE, | ||
957 | .name = "pixcir-i2c-ts", | ||
958 | }, | ||
959 | .probe = pixcir_i2c_ts_probe, | ||
960 | .remove = pixcir_i2c_ts_remove, | ||
961 | .suspend = pixcir_i2c_ts_suspend, | ||
962 | .resume = pixcir_i2c_ts_resume, | ||
963 | .id_table = pixcir_i2c_ts_id, | ||
964 | }; | ||
965 | |||
966 | static int __init pixcir_i2c_ts_init(void) | ||
967 | { | ||
968 | int ret; | ||
969 | |||
970 | pixcir_wq = create_singlethread_workqueue("pixcir_wq"); | ||
971 | |||
972 | if (!pixcir_wq) | ||
973 | return -ENOMEM; | ||
974 | |||
975 | ret = register_chrdev(I2C_MAJOR, "pixcir_i2c_ts", &pixcir_i2c_ts_fops); | ||
976 | if (ret) { | ||
977 | printk(KERN_ERR "%s:register chrdev failed\n", __FILE__); | ||
978 | return ret; | ||
979 | } | ||
980 | |||
981 | i2c_dev_class = class_create(THIS_MODULE, "pixcir_i2c_dev"); | ||
982 | |||
983 | if (IS_ERR(i2c_dev_class)) { | ||
984 | ret = PTR_ERR(i2c_dev_class); | ||
985 | class_destroy(i2c_dev_class); | ||
986 | } | ||
987 | |||
988 | return i2c_add_driver(&pixcir_i2c_ts_driver); | ||
989 | } | ||
990 | |||
991 | static void __exit pixcir_i2c_ts_exit(void) | ||
992 | { | ||
993 | i2c_del_driver(&pixcir_i2c_ts_driver); | ||
994 | class_destroy(i2c_dev_class); | ||
995 | unregister_chrdev(I2C_MAJOR, "pixcir_i2c_ts"); | ||
996 | if (pixcir_wq) | ||
997 | destroy_workqueue(pixcir_wq); | ||
998 | } | ||
999 | |||
1000 | module_init(pixcir_i2c_ts_init); | ||
1001 | module_exit(pixcir_i2c_ts_exit); | ||
1002 | |||
1003 | MODULE_AUTHOR("Dongsu Ha <dsfine.ha@samsung.com>, " | ||
1004 | "Bee<http://www.pixcir.com.cn>, " | ||
1005 | "Samsung Electronics <http://www.samsung.com>"); | ||
1006 | |||
1007 | MODULE_DESCRIPTION("Pixcir Touchscreen driver"); | ||
1008 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/input/touchscreen/s3c2410_ts.c b/drivers/input/touchscreen/s3c2410_ts.c index 8feb7f3c8be..c57956c3e93 100644 --- a/drivers/input/touchscreen/s3c2410_ts.c +++ b/drivers/input/touchscreen/s3c2410_ts.c | |||
@@ -68,10 +68,16 @@ | |||
68 | * @io: Pointer to the IO base. | 68 | * @io: Pointer to the IO base. |
69 | * @xp: The accumulated X position data. | 69 | * @xp: The accumulated X position data. |
70 | * @yp: The accumulated Y position data. | 70 | * @yp: The accumulated Y position data. |
71 | * @xp_pre: The previous X position data. | ||
72 | * @yp_pre: The previous Y position data. | ||
71 | * @irq_tc: The interrupt number for pen up/down interrupt | 73 | * @irq_tc: The interrupt number for pen up/down interrupt |
72 | * @count: The number of samples collected. | 74 | * @count: The number of samples collected. |
73 | * @shift: The log2 of the maximum count to read in one go. | 75 | * @shift: The log2 of the maximum count to read in one go. |
74 | * @features: The features supported by the TSADC MOdule. | 76 | * @features: The features supported by the TSADC MOdule. |
77 | * @cal_enable: The flag of enabling calibration. | ||
78 | * @cal_x_max: The maximum value of calibrated X. | ||
79 | * @cal_y_max: The maximum value of calibrated Y. | ||
80 | * @cal_param: The parameters for calibration. | ||
75 | */ | 81 | */ |
76 | struct s3c2410ts { | 82 | struct s3c2410ts { |
77 | struct s3c_adc_client *client; | 83 | struct s3c_adc_client *client; |
@@ -81,14 +87,85 @@ struct s3c2410ts { | |||
81 | void __iomem *io; | 87 | void __iomem *io; |
82 | unsigned long xp; | 88 | unsigned long xp; |
83 | unsigned long yp; | 89 | unsigned long yp; |
90 | unsigned long xp_pre; | ||
91 | unsigned long yp_pre; | ||
92 | |||
84 | int irq_tc; | 93 | int irq_tc; |
85 | int count; | 94 | int count; |
86 | int shift; | 95 | int shift; |
87 | int features; | 96 | int features; |
97 | bool request_done; | ||
98 | |||
99 | int cal_enable; | ||
100 | int cal_x_max; | ||
101 | int cal_y_max; | ||
102 | int cal_param[7]; | ||
88 | }; | 103 | }; |
89 | 104 | ||
90 | static struct s3c2410ts ts; | 105 | static struct s3c2410ts ts; |
91 | 106 | ||
107 | struct cal_data { | ||
108 | int cal_x_max; | ||
109 | int cal_y_max; | ||
110 | int cal_param[7]; | ||
111 | }; | ||
112 | |||
113 | static ssize_t set_ts_cal(struct device *dev, | ||
114 | struct device_attribute *attr, | ||
115 | const char *buf, size_t count) | ||
116 | { | ||
117 | int i; | ||
118 | struct cal_data *b = (struct cal_data *) buf; | ||
119 | |||
120 | if (count < sizeof(struct cal_data)) | ||
121 | return 0; | ||
122 | |||
123 | dev_dbg(ts.dev, "%s : cal_x_max : %d cal_y_max : %d " | ||
124 | "cal_param : %d %d %d %d %d %d %d\n", __func__, | ||
125 | b->cal_x_max, b->cal_y_max, b->cal_param[0], | ||
126 | b->cal_param[1], b->cal_param[2], b->cal_param[3], | ||
127 | b->cal_param[4], b->cal_param[5], b->cal_param[6]); | ||
128 | |||
129 | ts.cal_x_max = b->cal_x_max; | ||
130 | ts.cal_y_max = b->cal_y_max; | ||
131 | |||
132 | for (i = 0; i < 7; i++) | ||
133 | ts.cal_param[i] = b->cal_param[i]; | ||
134 | |||
135 | input_set_abs_params(ts.input, ABS_X, 0, ts.cal_x_max, 0, 0); | ||
136 | input_set_abs_params(ts.input, ABS_Y, 0, ts.cal_y_max, 0, 0); | ||
137 | |||
138 | ts.cal_enable = 1; | ||
139 | |||
140 | return sizeof(struct cal_data); | ||
141 | } | ||
142 | |||
143 | static ssize_t reset_ts_cal(struct device *dev, | ||
144 | struct device_attribute *attr, | ||
145 | const char *buf, size_t count) | ||
146 | { | ||
147 | input_set_abs_params(ts.input, ABS_X, 0, 0x3ff, 0, 0); | ||
148 | input_set_abs_params(ts.input, ABS_Y, 0, 0x3ff, 0, 0); | ||
149 | |||
150 | ts.cal_enable = 0; | ||
151 | |||
152 | return count; | ||
153 | } | ||
154 | |||
155 | static DEVICE_ATTR(set_tscal, S_IRWXUGO, NULL, set_ts_cal); | ||
156 | static DEVICE_ATTR(reset_tscal, S_IRWXUGO, NULL, reset_ts_cal); | ||
157 | |||
158 | static struct attribute *s5pv310_ts_sysfs_entries[] = { | ||
159 | &dev_attr_set_tscal.attr, | ||
160 | &dev_attr_reset_tscal.attr, | ||
161 | NULL | ||
162 | }; | ||
163 | |||
164 | static struct attribute_group s5pv310_ts_attr_group = { | ||
165 | .name = NULL, | ||
166 | .attrs = s5pv310_ts_sysfs_entries, | ||
167 | }; | ||
168 | |||
92 | /** | 169 | /** |
93 | * get_down - return the down state of the pen | 170 | * get_down - return the down state of the pen |
94 | * @data0: The data read from ADCDAT0 register. | 171 | * @data0: The data read from ADCDAT0 register. |
@@ -103,6 +180,18 @@ static inline bool get_down(unsigned long data0, unsigned long data1) | |||
103 | !(data1 & S3C2410_ADCDAT0_UPDOWN)); | 180 | !(data1 & S3C2410_ADCDAT0_UPDOWN)); |
104 | } | 181 | } |
105 | 182 | ||
183 | static void ts_calibrate(void) | ||
184 | { | ||
185 | int x, y; | ||
186 | x = (int)ts.xp; | ||
187 | y = (int)ts.yp; | ||
188 | |||
189 | ts.xp = (long)((ts.cal_param[2] + (ts.cal_param[0] * x) + | ||
190 | (ts.cal_param[1] * y)) / ts.cal_param[6]); | ||
191 | ts.yp = (long)((ts.cal_param[5] + (ts.cal_param[3] * x) + | ||
192 | (ts.cal_param[4] * y)) / ts.cal_param[6]); | ||
193 | } | ||
194 | |||
106 | static void touch_timer_fire(unsigned long data) | 195 | static void touch_timer_fire(unsigned long data) |
107 | { | 196 | { |
108 | unsigned long data0; | 197 | unsigned long data0; |
@@ -119,6 +208,9 @@ static void touch_timer_fire(unsigned long data) | |||
119 | ts.xp >>= ts.shift; | 208 | ts.xp >>= ts.shift; |
120 | ts.yp >>= ts.shift; | 209 | ts.yp >>= ts.shift; |
121 | 210 | ||
211 | if (ts.cal_enable) | ||
212 | ts_calibrate(); | ||
213 | |||
122 | dev_dbg(ts.dev, "%s: X=%lu, Y=%lu, count=%d\n", | 214 | dev_dbg(ts.dev, "%s: X=%lu, Y=%lu, count=%d\n", |
123 | __func__, ts.xp, ts.yp, ts.count); | 215 | __func__, ts.xp, ts.yp, ts.count); |
124 | 216 | ||
@@ -128,6 +220,9 @@ static void touch_timer_fire(unsigned long data) | |||
128 | input_report_key(ts.input, BTN_TOUCH, 1); | 220 | input_report_key(ts.input, BTN_TOUCH, 1); |
129 | input_sync(ts.input); | 221 | input_sync(ts.input); |
130 | 222 | ||
223 | ts.xp_pre = ts.xp; | ||
224 | ts.yp_pre = ts.yp; | ||
225 | |||
131 | ts.xp = 0; | 226 | ts.xp = 0; |
132 | ts.yp = 0; | 227 | ts.yp = 0; |
133 | ts.count = 0; | 228 | ts.count = 0; |
@@ -139,10 +234,15 @@ static void touch_timer_fire(unsigned long data) | |||
139 | ts.yp = 0; | 234 | ts.yp = 0; |
140 | ts.count = 0; | 235 | ts.count = 0; |
141 | 236 | ||
237 | input_report_abs(ts.input, ABS_X, ts.xp_pre); | ||
238 | input_report_abs(ts.input, ABS_Y, ts.yp_pre); | ||
239 | |||
142 | input_report_key(ts.input, BTN_TOUCH, 0); | 240 | input_report_key(ts.input, BTN_TOUCH, 0); |
143 | input_sync(ts.input); | 241 | input_sync(ts.input); |
144 | 242 | ||
145 | writel(WAIT4INT | INT_DOWN, ts.io + S3C2410_ADCTSC); | 243 | writel(WAIT4INT | INT_DOWN, ts.io + S3C2410_ADCTSC); |
244 | |||
245 | ts.request_done = true; | ||
146 | } | 246 | } |
147 | } | 247 | } |
148 | 248 | ||
@@ -170,10 +270,12 @@ static irqreturn_t stylus_irq(int irq, void *dev_id) | |||
170 | * the timer is running, but maybe we ought to verify that the | 270 | * the timer is running, but maybe we ought to verify that the |
171 | * timer isn't running anyways. */ | 271 | * timer isn't running anyways. */ |
172 | 272 | ||
173 | if (down) | 273 | if (down && ts.request_done) { |
274 | ts.request_done = false; | ||
174 | s3c_adc_start(ts.client, 0, 1 << ts.shift); | 275 | s3c_adc_start(ts.client, 0, 1 << ts.shift); |
175 | else | 276 | } else { |
176 | dev_dbg(ts.dev, "%s: count=%d\n", __func__, ts.count); | 277 | dev_dbg(ts.dev, "%s: count=%d\n", __func__, ts.count); |
278 | } | ||
177 | 279 | ||
178 | if (ts.features & FEAT_PEN_IRQ) { | 280 | if (ts.features & FEAT_PEN_IRQ) { |
179 | /* Clear pen down/up interrupt */ | 281 | /* Clear pen down/up interrupt */ |
@@ -244,7 +346,13 @@ static int __devinit s3c2410ts_probe(struct platform_device *pdev) | |||
244 | struct device *dev = &pdev->dev; | 346 | struct device *dev = &pdev->dev; |
245 | struct input_dev *input_dev; | 347 | struct input_dev *input_dev; |
246 | struct resource *res; | 348 | struct resource *res; |
247 | int ret = -EINVAL; | 349 | int i, ret = -EINVAL; |
350 | |||
351 | ret = sysfs_create_group(&pdev->dev.kobj, &s5pv310_ts_attr_group); | ||
352 | if (ret < 0) { | ||
353 | dev_err(dev, "can not create sysfs\n"); | ||
354 | return ret; | ||
355 | } | ||
248 | 356 | ||
249 | /* Initialise input stuff */ | 357 | /* Initialise input stuff */ |
250 | memset(&ts, 0, sizeof(struct s3c2410ts)); | 358 | memset(&ts, 0, sizeof(struct s3c2410ts)); |
@@ -259,7 +367,7 @@ static int __devinit s3c2410ts_probe(struct platform_device *pdev) | |||
259 | 367 | ||
260 | dev_dbg(dev, "initialising touchscreen\n"); | 368 | dev_dbg(dev, "initialising touchscreen\n"); |
261 | 369 | ||
262 | ts.clock = clk_get(dev, "adc"); | 370 | ts.clock = clk_get(NULL, "adc"); |
263 | if (IS_ERR(ts.clock)) { | 371 | if (IS_ERR(ts.clock)) { |
264 | dev_err(dev, "cannot get adc clock source\n"); | 372 | dev_err(dev, "cannot get adc clock source\n"); |
265 | return -ENOENT; | 373 | return -ENOENT; |
@@ -316,10 +424,21 @@ static int __devinit s3c2410ts_probe(struct platform_device *pdev) | |||
316 | ts.input = input_dev; | 424 | ts.input = input_dev; |
317 | ts.input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); | 425 | ts.input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); |
318 | ts.input->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); | 426 | ts.input->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); |
319 | input_set_abs_params(ts.input, ABS_X, 0, 0x3FF, 0, 0); | ||
320 | input_set_abs_params(ts.input, ABS_Y, 0, 0x3FF, 0, 0); | ||
321 | 427 | ||
322 | ts.input->name = "S3C24XX TouchScreen"; | 428 | if (info->cal_x_max == 0 || info->cal_y_max == 0) { |
429 | ts.cal_enable = 0; | ||
430 | input_set_abs_params(ts.input, ABS_X, 0, 0x3FF, 32, 0); | ||
431 | input_set_abs_params(ts.input, ABS_Y, 0, 0x3FF, 32, 0); | ||
432 | } else { | ||
433 | for (i = 0; i < 7; i++) | ||
434 | ts.cal_param[i] = info->cal_param[i]; | ||
435 | |||
436 | ts.cal_enable = 1; | ||
437 | input_set_abs_params(ts.input, ABS_X, 0, info->cal_x_max, 32, 0); | ||
438 | input_set_abs_params(ts.input, ABS_Y, 0, info->cal_y_max, 32, 0); | ||
439 | } | ||
440 | |||
441 | ts.input->name = "S3C24XX_TouchScreen"; | ||
323 | ts.input->id.bustype = BUS_HOST; | 442 | ts.input->id.bustype = BUS_HOST; |
324 | ts.input->id.vendor = 0xDEAD; | 443 | ts.input->id.vendor = 0xDEAD; |
325 | ts.input->id.product = 0xBEEF; | 444 | ts.input->id.product = 0xBEEF; |
@@ -327,6 +446,7 @@ static int __devinit s3c2410ts_probe(struct platform_device *pdev) | |||
327 | 446 | ||
328 | ts.shift = info->oversampling_shift; | 447 | ts.shift = info->oversampling_shift; |
329 | ts.features = platform_get_device_id(pdev)->driver_data; | 448 | ts.features = platform_get_device_id(pdev)->driver_data; |
449 | ts.request_done = true; | ||
330 | 450 | ||
331 | ret = request_irq(ts.irq_tc, stylus_irq, IRQF_DISABLED, | 451 | ret = request_irq(ts.irq_tc, stylus_irq, IRQF_DISABLED, |
332 | "s3c2410_ts_pen", ts.input); | 452 | "s3c2410_ts_pen", ts.input); |
diff --git a/drivers/input/touchscreen/s5pc210_ts.c b/drivers/input/touchscreen/s5pc210_ts.c new file mode 100644 index 00000000000..568b480c205 --- /dev/null +++ b/drivers/input/touchscreen/s5pc210_ts.c | |||
@@ -0,0 +1,488 @@ | |||
1 | /* drivers/input/touschcreen/s5pc210_ts.c | ||
2 | * | ||
3 | * Copyright (c) 2011 Samsung Electronics Co., Ltd. | ||
4 | * http://www.samsung.com | ||
5 | * | ||
6 | * Samsung S5PC210 10.1" touchscreen driver | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the term of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
21 | * | ||
22 | * Copyright 2010 Hardkernel Co.,Ltd. <odroid@hardkernel.com> | ||
23 | * Copyright 2010 Samsung Electronics <samsung.com> | ||
24 | * | ||
25 | */ | ||
26 | #include <linux/module.h> | ||
27 | #include <linux/kernel.h> | ||
28 | #include <linux/init.h> | ||
29 | #include <linux/irq.h> | ||
30 | #include <linux/interrupt.h> | ||
31 | #include <linux/platform_device.h> | ||
32 | #include <linux/device.h> | ||
33 | #include <linux/input.h> | ||
34 | #include <linux/delay.h> | ||
35 | #include <linux/fs.h> | ||
36 | #include <linux/gpio.h> | ||
37 | |||
38 | #include <asm/system.h> | ||
39 | |||
40 | #include <plat/gpio-cfg.h> | ||
41 | #include <plat/cpu.h> | ||
42 | |||
43 | #include <mach/irqs.h> | ||
44 | #include <mach/regs-gpio.h> | ||
45 | |||
46 | #include "s5pc210_ts.h" | ||
47 | #include "s5pc210_ts_gpio_i2c.h" | ||
48 | #include "s5pc210_ts_sysfs.h" | ||
49 | |||
50 | static int s5pv310_ts_open(struct input_dev *dev); | ||
51 | static void s5pv310_ts_close(struct input_dev *dev); | ||
52 | |||
53 | static void s5pv310_ts_release_device(struct device *dev); | ||
54 | static void s5pv310_ts_config(unsigned char state); | ||
55 | |||
56 | unsigned int irq_count; | ||
57 | struct s5pv310_ts_t s5pv310_ts; | ||
58 | |||
59 | #define CONFIG_DEBUG_S5PV310_TS_MSG 1 | ||
60 | #define CAL_DELAY 1000 | ||
61 | |||
62 | static int s5pv310_ts_cal(void) | ||
63 | { | ||
64 | unsigned char wdata; | ||
65 | |||
66 | /* INT_mode : disable interrupt */ | ||
67 | wdata = 0x00; | ||
68 | if (s5pv310_ts_write(MODULE_INTMODE, &wdata, 1)) { | ||
69 | #ifdef CONFIG_DEBUG_S5PV310_TS_MSG | ||
70 | printk(KERN_ERR "failed to write disable.\n"); | ||
71 | #endif | ||
72 | return -1; | ||
73 | } | ||
74 | |||
75 | /* touch calibration */ | ||
76 | wdata = 0x03; | ||
77 | /* set mode */ | ||
78 | if (s5pv310_ts_write(MODULE_CALIBRATION, &wdata, 1)) { | ||
79 | #ifdef CONFIG_DEBUG_S5PV310_TS_MSG | ||
80 | printk(KERN_ERR "failed to write cal.\n"); | ||
81 | #endif | ||
82 | return -1; | ||
83 | } | ||
84 | |||
85 | #ifdef CONFIG_DEBUG_S5PV310_TS_MSG | ||
86 | printk(KERN_DEBUG "calibration!!!\n"); | ||
87 | #endif | ||
88 | mdelay(CAL_DELAY); | ||
89 | |||
90 | /* INT_mode : enable interrupt, low-active, periodically*/ | ||
91 | wdata = 0x09; | ||
92 | if (s5pv310_ts_write(MODULE_INTMODE, &wdata, 1)) { | ||
93 | #ifdef CONFIG_DEBUG_S5PV310_TS_MSG | ||
94 | printk(KERN_ERR "failed to write enable.\n"); | ||
95 | #endif | ||
96 | return -1; | ||
97 | } | ||
98 | |||
99 | return 0; | ||
100 | } | ||
101 | |||
102 | static void s5pv310_ts_process_data(struct touch_process_data_t *ts_data) | ||
103 | { | ||
104 | /* read address setup */ | ||
105 | s5pv310_ts_write(0x00, NULL, 0x00); | ||
106 | |||
107 | /* Acc data read */ | ||
108 | write_seqlock(&s5pv310_ts.lock); | ||
109 | s5pv310_ts_read(&s5pv310_ts.rd[0], 10); | ||
110 | |||
111 | write_sequnlock(&s5pv310_ts.lock); | ||
112 | |||
113 | ts_data->finger_cnt = s5pv310_ts.rd[0] & 0x03; | ||
114 | |||
115 | if ((ts_data->x1 = ((s5pv310_ts.rd[3] << 8) | s5pv310_ts.rd[2]))) { | ||
116 | ts_data->x1 = (ts_data->x1 * 134) / 100; | ||
117 | #ifdef CONFIG_S5PV310_TS_FLIP | ||
118 | #else | ||
119 | /* flip X & resize */ | ||
120 | ts_data->x1 = TS_ABS_MAX_X - ts_data->x1; | ||
121 | #endif | ||
122 | } | ||
123 | |||
124 | /* resize */ | ||
125 | if ((ts_data->y1 = ((s5pv310_ts.rd[5] << 8) | s5pv310_ts.rd[4]))) { | ||
126 | ts_data->y1 = (ts_data->y1 * 134) / 100; | ||
127 | #ifdef CONFIG_S5PV310_TS_FLIP | ||
128 | /* flip Y & resize */ | ||
129 | ts_data->y1 = TS_ABS_MAX_Y - ts_data->y1; | ||
130 | #else | ||
131 | #endif | ||
132 | } | ||
133 | if (ts_data->finger_cnt > 1) { | ||
134 | /* flip X & resize */ | ||
135 | if ((ts_data->x2 = ((s5pv310_ts.rd[7] << 8) | s5pv310_ts.rd[6]))) { | ||
136 | ts_data->x2 = (ts_data->x2 * 133) / 100; | ||
137 | #ifdef CONFIG_S5PV310_TS_FLIP | ||
138 | #else | ||
139 | ts_data->x2 = TS_ABS_MAX_X - ts_data->x2; | ||
140 | #endif | ||
141 | } | ||
142 | /* resize */ | ||
143 | if ((ts_data->y2 = ((s5pv310_ts.rd[9] << 8) | s5pv310_ts.rd[8]))) { | ||
144 | |||
145 | ts_data->y2 = (ts_data->y2 * 128) / 100; | ||
146 | #ifdef CONFIG_S5PV310_TS_FLIP | ||
147 | /* flip Y & resize */ | ||
148 | ts_data->y2 = TS_ABS_MAX_Y - ts_data->y2; | ||
149 | #else | ||
150 | #endif | ||
151 | } | ||
152 | } | ||
153 | } | ||
154 | |||
155 | static void s5pv310_ts_get_data(void) | ||
156 | { | ||
157 | struct touch_process_data_t ts_data; | ||
158 | |||
159 | memset(&ts_data, 0x00, sizeof(ts_data)); | ||
160 | |||
161 | s5pv310_ts_process_data(&ts_data); | ||
162 | #ifdef CONFIG_DEBUG_S5PV310_TS_MSG | ||
163 | printk(KERN_DEBUG "finger: %d\n", ts_data.finger_cnt); | ||
164 | printk(KERN_DEBUG "x1: %d, y1: %d\n", ts_data.x1, ts_data.y1); | ||
165 | printk(KERN_DEBUG "x2: %d, y2: %d\n", ts_data.x2, ts_data.y2); | ||
166 | #endif | ||
167 | |||
168 | if (ts_data.finger_cnt == 0 && ts_data.x1 == 0 && ts_data.y1 == 0) { | ||
169 | if (irq_count > 10) { | ||
170 | s5pv310_ts_cal(); | ||
171 | irq_count = 0; | ||
172 | } | ||
173 | irq_count++; | ||
174 | } | ||
175 | |||
176 | if (ts_data.finger_cnt > 0 && ts_data.finger_cnt < 3) { | ||
177 | s5pv310_ts.x = ts_data.x1; | ||
178 | s5pv310_ts.y = ts_data.y1; | ||
179 | /* press */ | ||
180 | input_report_abs(s5pv310_ts.driver, | ||
181 | ABS_MT_TOUCH_MAJOR, 200); | ||
182 | input_report_abs(s5pv310_ts.driver, | ||
183 | ABS_MT_WIDTH_MAJOR, 10); | ||
184 | input_report_abs(s5pv310_ts.driver, | ||
185 | ABS_MT_POSITION_X, s5pv310_ts.x); | ||
186 | input_report_abs(s5pv310_ts.driver, | ||
187 | ABS_MT_POSITION_Y, s5pv310_ts.y); | ||
188 | input_mt_sync(s5pv310_ts.driver); | ||
189 | |||
190 | if (ts_data.finger_cnt == 2) { | ||
191 | s5pv310_ts.x = ts_data.x2; | ||
192 | s5pv310_ts.y = ts_data.y2; | ||
193 | /* press */ | ||
194 | input_report_abs(s5pv310_ts.driver, | ||
195 | ABS_MT_TOUCH_MAJOR, 200); | ||
196 | input_report_abs(s5pv310_ts.driver, | ||
197 | ABS_MT_WIDTH_MAJOR, 10); | ||
198 | input_report_abs(s5pv310_ts.driver, | ||
199 | ABS_MT_POSITION_X, s5pv310_ts.x); | ||
200 | input_report_abs(s5pv310_ts.driver, | ||
201 | ABS_MT_POSITION_Y, s5pv310_ts.y); | ||
202 | input_mt_sync(s5pv310_ts.driver); | ||
203 | } | ||
204 | input_sync(s5pv310_ts.driver); | ||
205 | irq_count = 0; | ||
206 | } else { | ||
207 | /* up */ | ||
208 | input_mt_sync(s5pv310_ts.driver); | ||
209 | input_sync(s5pv310_ts.driver); | ||
210 | } | ||
211 | } | ||
212 | |||
213 | irqreturn_t s5pv310_ts_irq(int irq, void *dev_id) | ||
214 | { | ||
215 | unsigned long flags; | ||
216 | |||
217 | local_irq_save(flags); | ||
218 | local_irq_disable(); | ||
219 | s5pv310_ts_get_data(); | ||
220 | local_irq_restore(flags); | ||
221 | return IRQ_HANDLED; | ||
222 | } | ||
223 | |||
224 | static int s5pv310_ts_open(struct input_dev *dev) | ||
225 | { | ||
226 | #ifdef CONFIG_DEBUG_S5PV310_TS_MSG | ||
227 | printk(KERN_DEBUG "%s\n", __func__); | ||
228 | #endif | ||
229 | |||
230 | return 0; | ||
231 | } | ||
232 | |||
233 | static void s5pv310_ts_close(struct input_dev *dev) | ||
234 | { | ||
235 | #ifdef CONFIG_DEBUG_S5PV310_TS_MSG | ||
236 | printk(KERN_DEBUG "%s\n", __func__); | ||
237 | #endif | ||
238 | } | ||
239 | |||
240 | static void s5pv310_ts_release_device(struct device *dev) | ||
241 | { | ||
242 | #ifdef CONFIG_DEBUG_S5PV310_TS_MSG | ||
243 | printk(KERN_DEBUG "%s\n", __func__); | ||
244 | #endif | ||
245 | } | ||
246 | |||
247 | static void s5pv310_ts_config(unsigned char state) | ||
248 | { | ||
249 | unsigned char wdata; | ||
250 | |||
251 | /* s5pc210_ts_reset(); */ | ||
252 | s5pv310_ts_port_init(); | ||
253 | mdelay(500); | ||
254 | |||
255 | /* Touchscreen Active mode */ | ||
256 | wdata = 0x00; | ||
257 | s5pv310_ts_write(MODULE_POWERMODE, &wdata, 1); | ||
258 | mdelay(100); | ||
259 | |||
260 | if (state == TOUCH_STATE_BOOT) { | ||
261 | /* INT_mode : disable interrupt */ | ||
262 | wdata = 0x00; | ||
263 | s5pv310_ts_write(MODULE_INTMODE, &wdata, 1); | ||
264 | |||
265 | if ((soc_is_exynos4212() || soc_is_exynos4412()) && | ||
266 | samsung_board_rev_is_0_1()) { | ||
267 | s5p_register_gpio_interrupt(TS_ATTB); | ||
268 | s3c_gpio_cfgpin(TS_ATTB, S3C_GPIO_SFN(0xf)); | ||
269 | } | ||
270 | |||
271 | if (!request_irq(S5PV310_TS_IRQ, s5pv310_ts_irq, | ||
272 | IRQF_DISABLED, "s5pc210-Touch IRQ", | ||
273 | (void *)&s5pv310_ts)) | ||
274 | printk(KERN_DEBUG "MT TOUCH request_irq = %d\r\n", | ||
275 | S5PV310_TS_IRQ); | ||
276 | else | ||
277 | printk(KERN_ERR "MT TOUCH request_irq = %d error!! \r\n", | ||
278 | S5PV310_TS_IRQ); | ||
279 | |||
280 | if (gpio_is_valid(TS_ATTB)) { | ||
281 | if (gpio_request(TS_ATTB, "TS_ATTB")) | ||
282 | printk(KERN_ERR "failed to request GPH1 for TS_ATTB..\n"); | ||
283 | } | ||
284 | |||
285 | s3c_gpio_cfgpin(TS_ATTB, (0xf << 20)); | ||
286 | s3c_gpio_setpull(TS_ATTB, S3C_GPIO_PULL_NONE); | ||
287 | |||
288 | irq_set_irq_type(S5PV310_TS_IRQ, IRQ_TYPE_EDGE_RISING); | ||
289 | |||
290 | /* seqlock init */ | ||
291 | seqlock_init(&s5pv310_ts.lock); | ||
292 | |||
293 | s5pv310_ts.seq = 0; | ||
294 | |||
295 | } else { | ||
296 | /* INT_mode : disable interrupt, low-active, finger moving */ | ||
297 | wdata = 0x01; | ||
298 | if (s5pv310_ts_write(MODULE_INTMODE, &wdata, 1)) { | ||
299 | #ifdef CONFIG_DEBUG_S5PV310_TS_MSG | ||
300 | printk(KERN_ERR "failed to write disable.\n"); | ||
301 | #endif | ||
302 | } | ||
303 | |||
304 | mdelay(CAL_DELAY); | ||
305 | /* INT_mode : enable interrupt, low-active, finger moving */ | ||
306 | wdata = 0x09; | ||
307 | if (s5pv310_ts_write(MODULE_INTMODE, &wdata, 1)) { | ||
308 | #ifdef CONFIG_DEBUG_S5PV310_TS_MSG | ||
309 | printk(KERN_ERR "failed to write enable.\n"); | ||
310 | #endif | ||
311 | } | ||
312 | mdelay(100); | ||
313 | } | ||
314 | } | ||
315 | |||
316 | static int __devinit s5pv310_ts_probe(struct platform_device *pdev) | ||
317 | { | ||
318 | int rc; | ||
319 | |||
320 | irq_count = 0; | ||
321 | /* struct init */ | ||
322 | memset(&s5pv310_ts, 0x00, sizeof(s5pv310_ts)); | ||
323 | |||
324 | /* create sys_fs */ | ||
325 | rc = s5pv310_ts_sysfs_create(pdev); | ||
326 | if (rc) { | ||
327 | printk(KERN_ERR "%s : sysfs_create fail.\n", __func__); | ||
328 | return rc; | ||
329 | } | ||
330 | |||
331 | s5pv310_ts.driver = input_allocate_device(); | ||
332 | |||
333 | if (!(s5pv310_ts.driver)) { | ||
334 | printk(KERN_ERR "%s : cdev_alloc() no memory.\n", __func__); | ||
335 | s5pv310_ts_sysfs_remove(pdev); | ||
336 | return -ENOMEM; | ||
337 | } | ||
338 | |||
339 | s5pv310_ts.driver->name = S5PV310_TS_DEVICE_NAME; | ||
340 | s5pv310_ts.driver->phys = "s5pv310_ts/input1"; | ||
341 | s5pv310_ts.driver->open = s5pv310_ts_open; | ||
342 | s5pv310_ts.driver->close = s5pv310_ts_close; | ||
343 | |||
344 | s5pv310_ts.driver->id.bustype = BUS_HOST; | ||
345 | s5pv310_ts.driver->id.vendor = 0x16B4; | ||
346 | s5pv310_ts.driver->id.product = 0x0702; | ||
347 | s5pv310_ts.driver->id.version = 0x0001; | ||
348 | |||
349 | set_bit(EV_ABS, s5pv310_ts.driver->evbit); | ||
350 | |||
351 | /* multi touch */ | ||
352 | input_set_abs_params(s5pv310_ts.driver, ABS_MT_POSITION_X, | ||
353 | TS_ABS_MIN_X, TS_ABS_MAX_X, 0, 0); | ||
354 | input_set_abs_params(s5pv310_ts.driver, ABS_MT_POSITION_Y, | ||
355 | TS_ABS_MIN_Y, TS_ABS_MAX_Y, 0, 0); | ||
356 | input_set_abs_params(s5pv310_ts.driver, ABS_MT_TOUCH_MAJOR, | ||
357 | 0, 255, 2, 0); | ||
358 | input_set_abs_params(s5pv310_ts.driver, ABS_MT_WIDTH_MAJOR, | ||
359 | 0, 15, 2, 0); | ||
360 | |||
361 | if (input_register_device(s5pv310_ts.driver)) { | ||
362 | printk(KERN_ERR "S5PC210 TS input register device fail.\n"); | ||
363 | s5pv310_ts_sysfs_remove(pdev); | ||
364 | input_free_device(s5pv310_ts.driver); | ||
365 | return -ENODEV; | ||
366 | } | ||
367 | |||
368 | s5pv310_ts_config(TOUCH_STATE_BOOT); | ||
369 | s5pv310_ts_cal(); | ||
370 | |||
371 | printk(KERN_DEBUG "SMDKC210(MT) Touch driver initialized.\n"); | ||
372 | |||
373 | return 0; | ||
374 | } | ||
375 | |||
376 | static int __devexit s5pv310_ts_remove(struct platform_device *pdev) | ||
377 | { | ||
378 | #ifdef CONFIG_DEBUG_S5PV310_TS_MSG | ||
379 | printk(KERN_DEBUG "%s\n", __func__); | ||
380 | #endif | ||
381 | |||
382 | free_irq(S5PV310_TS_IRQ, (void *)&s5pv310_ts); | ||
383 | |||
384 | s5pv310_ts_sysfs_remove(pdev); | ||
385 | |||
386 | input_unregister_device(s5pv310_ts.driver); | ||
387 | |||
388 | return 0; | ||
389 | } | ||
390 | |||
391 | #ifdef CONFIG_PM | ||
392 | static int s5pv310_ts_resume(struct platform_device *dev) | ||
393 | { | ||
394 | s5pv310_ts_config(TOUCH_STATE_RESUME); | ||
395 | |||
396 | /* interrupt enable */ | ||
397 | enable_irq(S5PV310_TS_IRQ); | ||
398 | |||
399 | return 0; | ||
400 | } | ||
401 | |||
402 | static int s5pv310_ts_suspend(struct platform_device *dev, pm_message_t state) | ||
403 | { | ||
404 | unsigned char wdata; | ||
405 | |||
406 | wdata = 0x00; | ||
407 | s5pv310_ts_write(MODULE_POWERMODE, &wdata, 1); | ||
408 | mdelay(CAL_DELAY); | ||
409 | |||
410 | /* INT_mode : disable interrupt */ | ||
411 | wdata = 0x00; | ||
412 | s5pv310_ts_write(MODULE_INTMODE, &wdata, 1); | ||
413 | mdelay(CAL_DELAY); | ||
414 | |||
415 | /* Touchscreen enter freeze mode : */ | ||
416 | wdata = 0x01; | ||
417 | s5pv310_ts_write(MODULE_POWERMODE, &wdata, 1); | ||
418 | mdelay(100); | ||
419 | |||
420 | /* interrupt disable */ | ||
421 | disable_irq(S5PV310_TS_IRQ); | ||
422 | |||
423 | return 0; | ||
424 | } | ||
425 | #else | ||
426 | static int s5pv310_ts_resume(struct platform_device *dev) | ||
427 | { | ||
428 | return 0; | ||
429 | } | ||
430 | static int s5pv310_ts_suspend(struct platform_device *dev, pm_message_t state) | ||
431 | { | ||
432 | return 0; | ||
433 | } | ||
434 | #endif | ||
435 | |||
436 | static struct platform_driver s5pv310_ts_platform_device_driver = { | ||
437 | .probe = s5pv310_ts_probe, | ||
438 | .remove = s5pv310_ts_remove, | ||
439 | .suspend = s5pv310_ts_suspend, | ||
440 | .resume = s5pv310_ts_resume, | ||
441 | .driver = { | ||
442 | .owner = THIS_MODULE, | ||
443 | .name = S5PV310_TS_DEVICE_NAME, | ||
444 | }, | ||
445 | }; | ||
446 | |||
447 | static struct platform_device s5pv310_ts_platform_device = { | ||
448 | .name = S5PV310_TS_DEVICE_NAME, | ||
449 | .id = -1, | ||
450 | .num_resources = 0, | ||
451 | .dev = { | ||
452 | .release= s5pv310_ts_release_device, | ||
453 | }, | ||
454 | }; | ||
455 | |||
456 | static int __init s5pv310_ts_init(void) | ||
457 | { | ||
458 | int ret = platform_driver_register(&s5pv310_ts_platform_device_driver); | ||
459 | |||
460 | if (!ret) { | ||
461 | ret = platform_device_register(&s5pv310_ts_platform_device); | ||
462 | |||
463 | #ifdef CONFIG_DEBUG_S5PV310_TS_MSG | ||
464 | printk(KERN_DEBUG "platform_driver_register %d\n", ret); | ||
465 | #endif | ||
466 | |||
467 | if (ret) | ||
468 | platform_driver_unregister( | ||
469 | &s5pv310_ts_platform_device_driver); | ||
470 | } | ||
471 | return ret; | ||
472 | } | ||
473 | |||
474 | static void __exit s5pv310_ts_exit(void) | ||
475 | { | ||
476 | #ifdef CONFIG_DEBUG_S5PV310_TS_MSG | ||
477 | printk(KERN_DEBUG "%s\n", __func__); | ||
478 | #endif | ||
479 | platform_device_unregister(&s5pv310_ts_platform_device); | ||
480 | platform_driver_unregister(&s5pv310_ts_platform_device_driver); | ||
481 | } | ||
482 | module_init(s5pv310_ts_init); | ||
483 | module_exit(s5pv310_ts_exit); | ||
484 | |||
485 | MODULE_DESCRIPTION("Samsung 10.1\" Touchscreen driver"); | ||
486 | MODULE_AUTHOR("Dongsu Ha <dsfine.ha@samsung.com>"); | ||
487 | MODULE_AUTHOR("HardKernel"); | ||
488 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/input/touchscreen/s5pc210_ts.h b/drivers/input/touchscreen/s5pc210_ts.h new file mode 100644 index 00000000000..fc5cecb54ee --- /dev/null +++ b/drivers/input/touchscreen/s5pc210_ts.h | |||
@@ -0,0 +1,120 @@ | |||
1 | /* driver/input/touchscreen/s5pc210_ts.h | ||
2 | * | ||
3 | * Copyright (c) 2011 Samsung Electronics Co., Ltd. | ||
4 | * http://www.samsung.com | ||
5 | * | ||
6 | * S5PC210 10.1" Touchscreen driver information | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #ifndef _S5PV310_TS_H_ | ||
14 | #define _S5PV310_TS_H_ | ||
15 | |||
16 | #ifdef CONFIG_HAS_EARLYSUSPEND | ||
17 | #include <linux/earlysuspend.h> | ||
18 | #endif | ||
19 | |||
20 | #include <mach/board_rev.h> | ||
21 | |||
22 | #define S5PV310_TS_DEVICE_NAME "s5pc210_ts" | ||
23 | |||
24 | #define TOUCH_PRESS 1 | ||
25 | #define TOUCH_RELEASE 0 | ||
26 | |||
27 | /* Touch Configuration */ | ||
28 | |||
29 | /* Touch Interrupt define */ | ||
30 | #ifdef CONFIG_MACH_SMDK4X12 | ||
31 | |||
32 | #define TS_ATTB samsung_board_rev_is_0_0() ? EXYNOS4_GPX1(6) : EXYNOS4212_GPM3(4) | ||
33 | #define S5PV310_TS_IRQ gpio_to_irq(TS_ATTB) | ||
34 | |||
35 | /* Touch should be reset before using. In order to reset it, the reset pin | ||
36 | should be set OUTPUT HIGH. The Reset pin is EXYNOS4_GPX1(5) (XEINT 13). | ||
37 | However, the SMDK4X12 uses this pin for resetting both LCD and touchscreen. | ||
38 | Therefore, it assumes that LCD driver will reset them by this pin. */ | ||
39 | |||
40 | #elif defined (CONFIG_MACH_SMDKV310) | ||
41 | |||
42 | #define S5PV310_TS_IRQ gpio_to_irq(EXYNOS4_GPX3(5)) | ||
43 | #define TS_ATTB (EXYNOS4_GPX3(5)) | ||
44 | |||
45 | #else | ||
46 | #error Unsupported board! | ||
47 | #endif | ||
48 | |||
49 | #define TS_ABS_MIN_X 0 | ||
50 | #define TS_ABS_MIN_Y 0 | ||
51 | #define TS_ABS_MAX_X 1366 | ||
52 | #define TS_ABS_MAX_Y 768 | ||
53 | |||
54 | #define TS_X_THRESHOLD 1 | ||
55 | #define TS_Y_THRESHOLD 1 | ||
56 | |||
57 | |||
58 | /* touch register */ | ||
59 | #define MODULE_CALIBRATION 0x37 | ||
60 | #define MODULE_POWERMODE 0x14 | ||
61 | #define MODULE_INTMODE 0x15 | ||
62 | #define MODULE_INTWIDTH 0x16 | ||
63 | |||
64 | #define PERIOD_10MS (HZ/100) /* 10ms */ | ||
65 | #define PERIOD_20MS (HZ/50) /* 20ms */ | ||
66 | #define PERIOD_50MS (HZ/20) /* 50ms */ | ||
67 | |||
68 | #define TOUCH_STATE_BOOT 0 | ||
69 | #define TOUCH_STATE_RESUME 1 | ||
70 | |||
71 | /* Touch hold event */ | ||
72 | #define SW_TOUCH_HOLD 0x09 | ||
73 | |||
74 | #if defined(CONFIG_TOUCHSCREEN_EXYNOS4) | ||
75 | /* multi-touch data process struct */ | ||
76 | struct touch_process_data_t { | ||
77 | unsigned char finger_cnt; | ||
78 | unsigned int x1; | ||
79 | unsigned int y1; | ||
80 | unsigned int x2; | ||
81 | unsigned int y2; | ||
82 | }; | ||
83 | #endif | ||
84 | |||
85 | struct s5pv310_ts_t { | ||
86 | struct input_dev *driver; | ||
87 | |||
88 | /* seqlock_t */ | ||
89 | seqlock_t lock; | ||
90 | unsigned int seq; | ||
91 | |||
92 | /* timer */ | ||
93 | struct timer_list penup_timer; | ||
94 | |||
95 | /* data store */ | ||
96 | unsigned int status; | ||
97 | unsigned int x; | ||
98 | unsigned int y; | ||
99 | unsigned char rd[10]; | ||
100 | |||
101 | /* sysfs used */ | ||
102 | unsigned char hold_status; | ||
103 | unsigned char sampling_rate; | ||
104 | |||
105 | /* x data threshold (0-10) : default 3 */ | ||
106 | unsigned char threshold_x; | ||
107 | /* y data threshold (0-10) : default 3 */ | ||
108 | unsigned char threshold_y; | ||
109 | /* touch sensitivity (0-255) : default 0x14 */ | ||
110 | unsigned char sensitivity; | ||
111 | |||
112 | #if defined CONFIG_TOUCHSCREEN_EXYNOS4 | ||
113 | #ifdef CONFIG_HAS_EARLYSUSPEND | ||
114 | struct early_suspend power; | ||
115 | #endif | ||
116 | #endif | ||
117 | }; | ||
118 | |||
119 | extern struct s5pv310_ts_t s5pv310_ts; | ||
120 | #endif | ||
diff --git a/drivers/input/touchscreen/s5pc210_ts_gpio_i2c.c b/drivers/input/touchscreen/s5pc210_ts_gpio_i2c.c new file mode 100644 index 00000000000..90b5fe19d14 --- /dev/null +++ b/drivers/input/touchscreen/s5pc210_ts_gpio_i2c.c | |||
@@ -0,0 +1,366 @@ | |||
1 | /* drivers/input/touschcreen/s5pc210_ts_gpio_i2c.c | ||
2 | * | ||
3 | * Copyright (c) 2011 Samsung Electronics Co., Ltd. | ||
4 | * http://www.samsung.com | ||
5 | * | ||
6 | * Samsung S5PC210 10.1" touchscreen gpio driver | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the term of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
21 | * | ||
22 | * Copyright 2010 Hardkernel Co.,Ltd. <odroid@hardkernel.com> | ||
23 | * Copyright 2010 Samsung Electronics <samsung.com> | ||
24 | * | ||
25 | */ | ||
26 | #include <linux/module.h> | ||
27 | #include <linux/kernel.h> | ||
28 | #include <linux/init.h> | ||
29 | #include <linux/irq.h> | ||
30 | #include <linux/interrupt.h> | ||
31 | #include <linux/platform_device.h> | ||
32 | #include <linux/device.h> | ||
33 | #include <linux/input.h> | ||
34 | #include <linux/fs.h> | ||
35 | |||
36 | #include <mach/irqs.h> | ||
37 | #include <asm/system.h> | ||
38 | |||
39 | #include <linux/delay.h> | ||
40 | #include <mach/regs-gpio.h> | ||
41 | |||
42 | #include "s5pc210_ts_gpio_i2c.h" | ||
43 | #include "s5pc210_ts.h" | ||
44 | |||
45 | |||
46 | /* Touch I2C Address Define */ | ||
47 | #define TOUCH_WR_ADDR 0xB8 | ||
48 | #define TOUCH_RD_ADDR 0xB9 | ||
49 | |||
50 | /* Touch I2C Port define */ | ||
51 | #ifdef CONFIG_MACH_SMDK4X12 | ||
52 | |||
53 | #define GPD0CON (S5P_VA_GPIO + 0xA0) | ||
54 | #define GPD0DAT (S5P_VA_GPIO + 0xA4) | ||
55 | |||
56 | #define SDA_CON_PORT (*(unsigned long *)GPD0CON) | ||
57 | #define SDA_DAT_PORT (*(unsigned long *)GPD0DAT) | ||
58 | #define SDA_PIN 2 | ||
59 | |||
60 | #define CLK_CON_PORT (*(unsigned long *)GPD0CON) | ||
61 | #define CLK_DAT_PORT (*(unsigned long *)GPD0DAT) | ||
62 | #define CLK_PIN 3 | ||
63 | |||
64 | #elif defined (CONFIG_MACH_SMDKV310) | ||
65 | |||
66 | #define GPB1CON (S5P_VA_GPIO + 0x40) | ||
67 | #define GPB1DAT (S5P_VA_GPIO + 0x44) | ||
68 | |||
69 | #define SDA_CON_PORT (*(unsigned long *)GPB1CON) | ||
70 | #define SDA_DAT_PORT (*(unsigned long *)GPB1DAT) | ||
71 | #define SDA_PIN 6 | ||
72 | |||
73 | #define CLK_CON_PORT (*(unsigned long *)GPB1CON) | ||
74 | #define CLK_DAT_PORT (*(unsigned long *)GPB1DAT) | ||
75 | #define CLK_PIN 7 | ||
76 | |||
77 | #else | ||
78 | #error Unsupported board! | ||
79 | #endif | ||
80 | |||
81 | #define DELAY_TIME 5 | ||
82 | #define PORT_CHANGE_DELAY_TIME 5 | ||
83 | #define CON_PORT_MASK 0xF | ||
84 | #define CON_PORT_OFFSET 0x4 | ||
85 | |||
86 | #define GPIO_CON_INPUT 0x0 | ||
87 | #define GPIO_CON_OUTPUT 0x1 | ||
88 | |||
89 | #define HIGH 1 | ||
90 | #define LOW 0 | ||
91 | |||
92 | static void gpio_i2c_sda_port_control(unsigned char inout); | ||
93 | static void gpio_i2c_clk_port_control(unsigned char inout); | ||
94 | static unsigned char gpio_i2c_get_sda(void); | ||
95 | static void gpio_i2c_set_sda(unsigned char hi_lo); | ||
96 | static void gpio_i2c_set_clk(unsigned char hi_lo); | ||
97 | static void gpio_i2c_start(void); | ||
98 | static void gpio_i2c_stop(void); | ||
99 | static void gpio_i2c_send_ack(void); | ||
100 | static void gpio_i2c_send_noack(void); | ||
101 | static unsigned char gpio_i2c_chk_ack(void); | ||
102 | static void gpio_i2c_byte_write(unsigned char wdata); | ||
103 | static void gpio_i2c_byte_read(unsigned char *rdata); | ||
104 | |||
105 | static void gpio_i2c_sda_port_control(unsigned char inout) | ||
106 | { | ||
107 | SDA_CON_PORT &= (unsigned long)(~(CON_PORT_MASK << | ||
108 | (SDA_PIN * CON_PORT_OFFSET))); | ||
109 | SDA_CON_PORT |= (unsigned long)((inout << | ||
110 | (SDA_PIN * CON_PORT_OFFSET))); | ||
111 | } | ||
112 | |||
113 | static void gpio_i2c_clk_port_control(unsigned char inout) | ||
114 | { | ||
115 | CLK_CON_PORT &= (unsigned long)(~(CON_PORT_MASK << | ||
116 | (CLK_PIN * CON_PORT_OFFSET))); | ||
117 | CLK_CON_PORT |= (unsigned long)((inout << | ||
118 | (CLK_PIN * CON_PORT_OFFSET))); | ||
119 | } | ||
120 | |||
121 | static unsigned char gpio_i2c_get_sda(void) | ||
122 | { | ||
123 | return SDA_DAT_PORT & (HIGH << SDA_PIN) ? 1 : 0; | ||
124 | } | ||
125 | |||
126 | static void gpio_i2c_set_sda(unsigned char hi_lo) | ||
127 | { | ||
128 | if (hi_lo) { | ||
129 | gpio_i2c_sda_port_control(GPIO_CON_INPUT); | ||
130 | udelay(PORT_CHANGE_DELAY_TIME); | ||
131 | } else { | ||
132 | SDA_DAT_PORT &= ~(HIGH << SDA_PIN); | ||
133 | gpio_i2c_sda_port_control(GPIO_CON_OUTPUT); | ||
134 | udelay(PORT_CHANGE_DELAY_TIME); | ||
135 | } | ||
136 | } | ||
137 | |||
138 | static void gpio_i2c_set_clk(unsigned char hi_lo) | ||
139 | { | ||
140 | if (hi_lo) { | ||
141 | gpio_i2c_clk_port_control(GPIO_CON_INPUT); | ||
142 | udelay(PORT_CHANGE_DELAY_TIME); | ||
143 | } else { | ||
144 | CLK_DAT_PORT &= ~(HIGH << CLK_PIN); | ||
145 | gpio_i2c_clk_port_control(GPIO_CON_OUTPUT); | ||
146 | udelay(PORT_CHANGE_DELAY_TIME); | ||
147 | } | ||
148 | } | ||
149 | |||
150 | static void gpio_i2c_start(void) | ||
151 | { | ||
152 | /* Setup SDA, CLK output High */ | ||
153 | gpio_i2c_set_sda(HIGH); | ||
154 | gpio_i2c_set_clk(HIGH); | ||
155 | |||
156 | udelay(DELAY_TIME); | ||
157 | |||
158 | /* SDA low before CLK low */ | ||
159 | gpio_i2c_set_sda(LOW); | ||
160 | udelay(DELAY_TIME); | ||
161 | gpio_i2c_set_clk(LOW); | ||
162 | udelay(DELAY_TIME); | ||
163 | } | ||
164 | |||
165 | static void gpio_i2c_stop(void) | ||
166 | { | ||
167 | /* Setup SDA, CLK output low */ | ||
168 | gpio_i2c_set_sda(LOW); | ||
169 | gpio_i2c_set_clk(LOW); | ||
170 | |||
171 | udelay(DELAY_TIME); | ||
172 | |||
173 | /* SDA high after CLK high */ | ||
174 | gpio_i2c_set_clk(HIGH); | ||
175 | udelay(DELAY_TIME); | ||
176 | gpio_i2c_set_sda(HIGH); | ||
177 | udelay(DELAY_TIME); | ||
178 | } | ||
179 | |||
180 | static void gpio_i2c_send_ack(void) | ||
181 | { | ||
182 | /* SDA Low */ | ||
183 | gpio_i2c_set_sda(LOW); | ||
184 | udelay(DELAY_TIME); | ||
185 | gpio_i2c_set_clk(HIGH); | ||
186 | udelay(DELAY_TIME); | ||
187 | gpio_i2c_set_clk(LOW); | ||
188 | udelay(DELAY_TIME); | ||
189 | } | ||
190 | |||
191 | static void gpio_i2c_send_noack(void) | ||
192 | { | ||
193 | /* SDA High */ | ||
194 | gpio_i2c_set_sda(HIGH); | ||
195 | udelay(DELAY_TIME); | ||
196 | gpio_i2c_set_clk(HIGH); | ||
197 | udelay(DELAY_TIME); | ||
198 | gpio_i2c_set_clk(LOW); | ||
199 | udelay(DELAY_TIME); | ||
200 | } | ||
201 | |||
202 | static unsigned char gpio_i2c_chk_ack(void) | ||
203 | { | ||
204 | unsigned char count = 0, ret = 0; | ||
205 | |||
206 | gpio_i2c_set_sda(LOW); | ||
207 | udelay(DELAY_TIME); | ||
208 | gpio_i2c_set_clk(HIGH); | ||
209 | udelay(DELAY_TIME); | ||
210 | |||
211 | gpio_i2c_sda_port_control(GPIO_CON_INPUT); | ||
212 | udelay(PORT_CHANGE_DELAY_TIME); | ||
213 | |||
214 | while (gpio_i2c_get_sda()) { | ||
215 | if (count++ > 100) { | ||
216 | ret = 1; | ||
217 | break; | ||
218 | } else | ||
219 | udelay(DELAY_TIME); | ||
220 | } | ||
221 | |||
222 | gpio_i2c_set_clk(LOW); | ||
223 | udelay(DELAY_TIME); | ||
224 | |||
225 | #if defined(DEBUG_GPIO_I2C) | ||
226 | if (ret) | ||
227 | printk(KERN_DEBUG "%s %d: no ack\n", __func__, ret); | ||
228 | else | ||
229 | printk(KERN_DEBUG "%s %d: ack\n" , __func__, ret); | ||
230 | #endif | ||
231 | |||
232 | return ret; | ||
233 | } | ||
234 | |||
235 | static void gpio_i2c_byte_write(unsigned char wdata) | ||
236 | { | ||
237 | unsigned char cnt, mask; | ||
238 | |||
239 | for (cnt = 0, mask = 0x80; cnt < 8; cnt++, mask >>= 1) { | ||
240 | if (wdata & mask) | ||
241 | gpio_i2c_set_sda(HIGH); | ||
242 | else | ||
243 | gpio_i2c_set_sda(LOW); | ||
244 | |||
245 | gpio_i2c_set_clk(HIGH); | ||
246 | udelay(DELAY_TIME); | ||
247 | gpio_i2c_set_clk(LOW); | ||
248 | udelay(DELAY_TIME); | ||
249 | } | ||
250 | } | ||
251 | |||
252 | static void gpio_i2c_byte_read(unsigned char *rdata) | ||
253 | { | ||
254 | unsigned char cnt, mask; | ||
255 | |||
256 | gpio_i2c_sda_port_control(GPIO_CON_INPUT); | ||
257 | udelay(PORT_CHANGE_DELAY_TIME); | ||
258 | |||
259 | for (cnt = 0, mask = 0x80, *rdata = 0; cnt < 8; cnt++, mask >>= 1) { | ||
260 | gpio_i2c_set_clk(HIGH); | ||
261 | udelay(DELAY_TIME); | ||
262 | |||
263 | if (gpio_i2c_get_sda()) | ||
264 | *rdata |= mask; | ||
265 | |||
266 | gpio_i2c_set_clk(LOW); | ||
267 | udelay(DELAY_TIME); | ||
268 | } | ||
269 | } | ||
270 | |||
271 | int s5pv310_ts_write(unsigned char addr, unsigned char *wdata, | ||
272 | unsigned char wsize) | ||
273 | { | ||
274 | unsigned char cnt, ack; | ||
275 | |||
276 | /* start */ | ||
277 | gpio_i2c_start(); | ||
278 | |||
279 | /* i2c address */ | ||
280 | gpio_i2c_byte_write(TOUCH_WR_ADDR); | ||
281 | |||
282 | ack = gpio_i2c_chk_ack(); | ||
283 | if (ack) { | ||
284 | #if defined(DEBUG_GPIO_I2C) | ||
285 | printk(KERN_DEBUG "%s [write addr] : no ack\n", __func__); | ||
286 | #endif | ||
287 | goto write_stop; | ||
288 | } | ||
289 | |||
290 | /* register */ | ||
291 | gpio_i2c_byte_write(addr); | ||
292 | |||
293 | ack = gpio_i2c_chk_ack(); | ||
294 | if (ack) { | ||
295 | #if defined(DEBUG_GPIO_I2C) | ||
296 | printk(KERN_DEBUG "%s [write reg] : no ack\n", __func__); | ||
297 | #endif | ||
298 | } | ||
299 | |||
300 | if (wsize) { | ||
301 | for (cnt = 0; cnt < wsize; cnt++) { | ||
302 | gpio_i2c_byte_write(wdata[cnt]); | ||
303 | ack = gpio_i2c_chk_ack(); | ||
304 | if (ack) { | ||
305 | #if defined(DEBUG_GPIO_I2C) | ||
306 | printk(KERN_DEBUG "%s [write reg]:no ack\n", __func__); | ||
307 | #endif | ||
308 | goto write_stop; | ||
309 | } | ||
310 | } | ||
311 | } | ||
312 | |||
313 | write_stop: | ||
314 | #if defined(CONFIG_TOUCHSCREEN_EXYNOS4) | ||
315 | if (wsize) | ||
316 | gpio_i2c_stop(); | ||
317 | #else | ||
318 | gpio_i2c_stop(); | ||
319 | #endif | ||
320 | |||
321 | #if defined(DEBUG_GPIO_I2C) | ||
322 | printk(KERN_DEBUG "%s : %d\n", __func__, ack); | ||
323 | #endif | ||
324 | return ack; | ||
325 | } | ||
326 | |||
327 | int s5pv310_ts_read(unsigned char *rdata, unsigned char rsize) | ||
328 | { | ||
329 | unsigned char ack, cnt; | ||
330 | |||
331 | /* start */ | ||
332 | gpio_i2c_start(); | ||
333 | |||
334 | /* i2c address */ | ||
335 | gpio_i2c_byte_write(TOUCH_RD_ADDR); | ||
336 | |||
337 | ack = gpio_i2c_chk_ack(); | ||
338 | if (ack) { | ||
339 | #if defined(DEBUG_GPIO_I2C) | ||
340 | printk(KERN_DEBUG "%s [write addr] : no ack\n", __func__); | ||
341 | #endif | ||
342 | goto read_stop; | ||
343 | } | ||
344 | |||
345 | for (cnt = 0; cnt < rsize; cnt++) { | ||
346 | gpio_i2c_byte_read(&rdata[cnt]); | ||
347 | |||
348 | if (cnt == rsize - 1) | ||
349 | gpio_i2c_send_noack(); | ||
350 | else | ||
351 | gpio_i2c_send_ack(); | ||
352 | } | ||
353 | |||
354 | read_stop: | ||
355 | gpio_i2c_stop(); | ||
356 | #if defined(DEBUG_GPIO_I2C) | ||
357 | printk(KERN_DEBUG "%s : %d\n", __func__, ack); | ||
358 | #endif | ||
359 | return ack; | ||
360 | } | ||
361 | |||
362 | void s5pv310_ts_port_init(void) | ||
363 | { | ||
364 | gpio_i2c_set_sda(HIGH); | ||
365 | gpio_i2c_set_clk(HIGH); | ||
366 | } | ||
diff --git a/drivers/input/touchscreen/s5pc210_ts_gpio_i2c.h b/drivers/input/touchscreen/s5pc210_ts_gpio_i2c.h new file mode 100644 index 00000000000..c0b936481da --- /dev/null +++ b/drivers/input/touchscreen/s5pc210_ts_gpio_i2c.h | |||
@@ -0,0 +1,21 @@ | |||
1 | /* driver/input/touchscreen/s5pc210_ts_gpio_i2c.h | ||
2 | * | ||
3 | * Copyright (c) 2011 Samsung Electronics Co., LTD. | ||
4 | * http://www.samsung.com | ||
5 | * | ||
6 | * S5PC210 10.1" Touchscreen gpio i2c information | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #ifndef _S5PV310_TS_GPIO_I2C_H_ | ||
14 | #define _S5PV310_TS_GPIO_I2C_H_ | ||
15 | |||
16 | extern int s5pv310_ts_write(unsigned char addr, unsigned char *wdata, | ||
17 | unsigned char wsize); | ||
18 | extern int s5pv310_ts_read(unsigned char *rdata, unsigned char rsize); | ||
19 | extern void s5pv310_ts_port_init(void); | ||
20 | |||
21 | #endif /*_S5PV310_TS_GPIO_I2C_H_*/ | ||
diff --git a/drivers/input/touchscreen/s5pc210_ts_sysfs.c b/drivers/input/touchscreen/s5pc210_ts_sysfs.c new file mode 100644 index 00000000000..fbdc3deaf3e --- /dev/null +++ b/drivers/input/touchscreen/s5pc210_ts_sysfs.c | |||
@@ -0,0 +1,287 @@ | |||
1 | /* drivers/input/touschcreen/s5pc210_ts_sysfs.c | ||
2 | * | ||
3 | * Copyright (c) 2011 Samsung Electronics Co., Ltd. | ||
4 | * http://www.samsung.com | ||
5 | * | ||
6 | * Samsung S5PC210 10.1" touchscreen sensor interface driver | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the term of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
21 | * | ||
22 | * Copyright 2010 Hardkernel Co.,Ltd. <odroid@hardkernel.com> | ||
23 | * Copyright 2010 Samsung Electronics <samsung.com> | ||
24 | * | ||
25 | */ | ||
26 | #include <linux/kernel.h> | ||
27 | #include <linux/types.h> | ||
28 | #include <linux/module.h> | ||
29 | #include <linux/device.h> | ||
30 | #include <linux/platform_device.h> | ||
31 | #include <linux/delay.h> | ||
32 | #include <linux/irq.h> | ||
33 | #include <linux/interrupt.h> | ||
34 | #include <linux/sysfs.h> | ||
35 | |||
36 | #include "s5pc210_ts_gpio_i2c.h" | ||
37 | #include "s5pc210_ts.h" | ||
38 | |||
39 | /* sysfs function prototype define */ | ||
40 | /* screen hold control (on -> hold, off -> normal mode) */ | ||
41 | static ssize_t show_hold_state(struct device *dev, | ||
42 | struct device_attribute *attr, char *buf); | ||
43 | static ssize_t set_hold_state(struct device *dev, struct device_attribute *attr, | ||
44 | const char *buf, size_t count); | ||
45 | static DEVICE_ATTR(hold_state, S_IRWXUGO, show_hold_state, set_hold_state); | ||
46 | |||
47 | /* touch sampling rate control (5, 10, 20 : unit msec) */ | ||
48 | static ssize_t show_sampling_rate(struct device *dev, | ||
49 | struct device_attribute *attr, char *buf); | ||
50 | static ssize_t set_sampling_rate(struct device *dev, | ||
51 | struct device_attribute *attr, const char *buf, | ||
52 | size_t count); | ||
53 | static DEVICE_ATTR(sampling_rate, S_IRWXUGO, show_sampling_rate, | ||
54 | set_sampling_rate); | ||
55 | |||
56 | /* touch threshold control (range 0 - 10) : default 3 */ | ||
57 | #define THRESHOLD_MAX 10 | ||
58 | |||
59 | static ssize_t show_threshold_x(struct device *dev, | ||
60 | struct device_attribute *attr, char *buf); | ||
61 | static ssize_t set_threshold_x(struct device *dev, | ||
62 | struct device_attribute *attr, const char *buf, | ||
63 | size_t count); | ||
64 | static DEVICE_ATTR(threshold_x, S_IRWXUGO, show_threshold_x, set_threshold_x); | ||
65 | |||
66 | static ssize_t show_threshold_y(struct device *dev, | ||
67 | struct device_attribute *attr, char *buf); | ||
68 | static ssize_t set_threshold_y(struct device *dev, | ||
69 | struct device_attribute *attr, const char *buf, | ||
70 | size_t count); | ||
71 | static DEVICE_ATTR(threshold_y, S_IRWXUGO, show_threshold_y, set_threshold_y); | ||
72 | |||
73 | /* touch calibration */ | ||
74 | #if defined(CONFIG_TOUCHSCREEN_EXYNOS4) | ||
75 | static ssize_t set_ts_cal(struct device *dev, | ||
76 | struct device_attribute *attr, const char *buf, | ||
77 | size_t count); | ||
78 | static DEVICE_ATTR(ts_cal, S_IWUGO, NULL, set_ts_cal); | ||
79 | #endif | ||
80 | |||
81 | static struct attribute *s5pv310_ts_sysfs_entries[] = { | ||
82 | &dev_attr_hold_state.attr, | ||
83 | &dev_attr_sampling_rate.attr, | ||
84 | &dev_attr_threshold_x.attr, | ||
85 | &dev_attr_threshold_y.attr, | ||
86 | #if defined(CONFIG_TOUCHSCREEN_EXYNOS4) | ||
87 | &dev_attr_ts_cal.attr, | ||
88 | #endif | ||
89 | NULL | ||
90 | }; | ||
91 | |||
92 | static struct attribute_group s5pv310_ts_attr_group = { | ||
93 | .name = NULL, | ||
94 | .attrs = s5pv310_ts_sysfs_entries, | ||
95 | }; | ||
96 | |||
97 | static ssize_t show_hold_state(struct device *dev, | ||
98 | struct device_attribute *attr, char *buf) | ||
99 | { | ||
100 | if (s5pv310_ts.hold_status) | ||
101 | return sprintf(buf, "on\n"); | ||
102 | else | ||
103 | return sprintf(buf, "off\n"); | ||
104 | } | ||
105 | |||
106 | static ssize_t set_hold_state(struct device *dev, | ||
107 | struct device_attribute *attr, const char *buf, | ||
108 | size_t count) | ||
109 | { | ||
110 | unsigned long flags; | ||
111 | unsigned char wdata; | ||
112 | |||
113 | local_irq_save(flags); | ||
114 | |||
115 | if (!strcmp(buf, "on\n")) | ||
116 | s5pv310_ts.hold_status = 1; | ||
117 | else { | ||
118 | #if defined(CONFIG_TOUCHSCREEN_EXYNOS4) | ||
119 | /* INT_mode : disable interrupt, low-active, finger moving */ | ||
120 | wdata = 0x01; | ||
121 | s5pv310_ts_write(MODULE_INTMODE, &wdata, 1); | ||
122 | mdelay(10); | ||
123 | /* INT_mode : enable interrupt, low-active, finger moving */ | ||
124 | wdata = 0x09; | ||
125 | s5pv310_ts_write(MODULE_INTMODE, &wdata, 1); | ||
126 | mdelay(10); | ||
127 | #endif | ||
128 | s5pv310_ts.hold_status = 0; | ||
129 | } | ||
130 | |||
131 | local_irq_restore(flags); | ||
132 | |||
133 | return count; | ||
134 | } | ||
135 | |||
136 | static ssize_t show_sampling_rate(struct device *dev, | ||
137 | struct device_attribute *attr, char *buf) | ||
138 | { | ||
139 | switch (s5pv310_ts.sampling_rate) { | ||
140 | default: | ||
141 | s5pv310_ts.sampling_rate = 0; | ||
142 | case 0: | ||
143 | return sprintf(buf, "10 msec\n"); | ||
144 | case 1: | ||
145 | return sprintf(buf, "20 msec\n"); | ||
146 | case 2: | ||
147 | return sprintf(buf, "50 msec\n"); | ||
148 | } | ||
149 | } | ||
150 | |||
151 | static ssize_t set_sampling_rate(struct device *dev, | ||
152 | struct device_attribute *attr, const char *buf, | ||
153 | size_t count) | ||
154 | { | ||
155 | unsigned long flags; | ||
156 | unsigned int val; | ||
157 | |||
158 | if (!(sscanf(buf, "%u\n", &val))) | ||
159 | return -EINVAL; | ||
160 | |||
161 | local_irq_save(flags); | ||
162 | if (val > 20) | ||
163 | s5pv310_ts.sampling_rate = 2; | ||
164 | else if (val > 10) | ||
165 | s5pv310_ts.sampling_rate = 1; | ||
166 | else | ||
167 | s5pv310_ts.sampling_rate = 0; | ||
168 | |||
169 | local_irq_restore(flags); | ||
170 | |||
171 | return count; | ||
172 | } | ||
173 | |||
174 | static ssize_t show_threshold_x(struct device *dev, | ||
175 | struct device_attribute *attr, char *buf) | ||
176 | { | ||
177 | if (s5pv310_ts.threshold_x > THRESHOLD_MAX) | ||
178 | s5pv310_ts.threshold_x = THRESHOLD_MAX; | ||
179 | |||
180 | return sprintf(buf, "%d\n", s5pv310_ts.threshold_x); | ||
181 | } | ||
182 | |||
183 | static ssize_t set_threshold_x(struct device *dev, | ||
184 | struct device_attribute *attr, const char *buf, | ||
185 | size_t count) | ||
186 | { | ||
187 | unsigned long flags; | ||
188 | unsigned int val; | ||
189 | |||
190 | if (!(sscanf(buf, "%u\n", &val))) | ||
191 | return -EINVAL; | ||
192 | |||
193 | local_irq_save(flags); | ||
194 | |||
195 | if (val < 0) | ||
196 | val *= (-1); | ||
197 | |||
198 | if (val > THRESHOLD_MAX) | ||
199 | val = THRESHOLD_MAX; | ||
200 | |||
201 | s5pv310_ts.threshold_x = val; | ||
202 | |||
203 | local_irq_restore(flags); | ||
204 | |||
205 | return count; | ||
206 | } | ||
207 | static ssize_t show_threshold_y(struct device *dev, | ||
208 | struct device_attribute *attr, char *buf) | ||
209 | { | ||
210 | if (s5pv310_ts.threshold_y > THRESHOLD_MAX) | ||
211 | s5pv310_ts.threshold_y = THRESHOLD_MAX; | ||
212 | |||
213 | return sprintf(buf, "%d\n", s5pv310_ts.threshold_y); | ||
214 | } | ||
215 | static ssize_t set_threshold_y(struct device *dev, | ||
216 | struct device_attribute *attr, const char *buf, | ||
217 | size_t count) | ||
218 | { | ||
219 | unsigned long flags; | ||
220 | unsigned int val; | ||
221 | |||
222 | if (!(sscanf(buf, "%u\n", &val))) | ||
223 | return -EINVAL; | ||
224 | |||
225 | local_irq_save(flags); | ||
226 | |||
227 | if (val < 0) | ||
228 | val *= (-1); | ||
229 | |||
230 | if (val > THRESHOLD_MAX) | ||
231 | val = THRESHOLD_MAX; | ||
232 | |||
233 | s5pv310_ts.threshold_y = val; | ||
234 | |||
235 | local_irq_restore(flags); | ||
236 | |||
237 | return count; | ||
238 | } | ||
239 | |||
240 | #if defined(CONFIG_TOUCHSCREEN_EXYNOS4) | ||
241 | static ssize_t set_ts_cal(struct device *dev, | ||
242 | struct device_attribute *attr, const char *buf, | ||
243 | size_t count) | ||
244 | { | ||
245 | unsigned char wdata; | ||
246 | unsigned long flags; | ||
247 | |||
248 | local_irq_save(flags); | ||
249 | |||
250 | /* INT_mode : disable interrupt */ | ||
251 | wdata = 0x00; | ||
252 | s5pv310_ts_write(MODULE_INTMODE, &wdata, 1); | ||
253 | |||
254 | /* touch calibration */ | ||
255 | wdata = 0x03; | ||
256 | s5pv310_ts_write(MODULE_CALIBRATION, &wdata, 1); | ||
257 | |||
258 | mdelay(500); | ||
259 | |||
260 | /* INT_mode : enable interrupt, low-active, periodically*/ | ||
261 | wdata = 0x09; | ||
262 | s5pv310_ts_write(MODULE_INTMODE, &wdata, 1); | ||
263 | |||
264 | local_irq_restore(flags); | ||
265 | |||
266 | return count; | ||
267 | } | ||
268 | #endif | ||
269 | |||
270 | int s5pv310_ts_sysfs_create(struct platform_device *pdev) | ||
271 | { | ||
272 | /* variable init */ | ||
273 | s5pv310_ts.hold_status = 0; | ||
274 | |||
275 | /* 5 msec sampling */ | ||
276 | s5pv310_ts.sampling_rate = 0; | ||
277 | /* x data threshold (0~10) */ | ||
278 | s5pv310_ts.threshold_x = TS_X_THRESHOLD; | ||
279 | /* y data threshold (0~10) */ | ||
280 | s5pv310_ts.threshold_y = TS_Y_THRESHOLD; | ||
281 | |||
282 | return sysfs_create_group(&pdev->dev.kobj, &s5pv310_ts_attr_group); | ||
283 | } | ||
284 | void s5pv310_ts_sysfs_remove(struct platform_device *pdev) | ||
285 | { | ||
286 | sysfs_remove_group(&pdev->dev.kobj, &s5pv310_ts_attr_group); | ||
287 | } | ||
diff --git a/drivers/input/touchscreen/s5pc210_ts_sysfs.h b/drivers/input/touchscreen/s5pc210_ts_sysfs.h new file mode 100644 index 00000000000..1edeee47a45 --- /dev/null +++ b/drivers/input/touchscreen/s5pc210_ts_sysfs.h | |||
@@ -0,0 +1,19 @@ | |||
1 | /* driver/input/touchscreen/s5pc210_ts_sysfs.h | ||
2 | * | ||
3 | * Copyright (c) 2011 Samsung Electronics Co., LTD. | ||
4 | * http://www.samsung.com | ||
5 | * | ||
6 | * S5PC210 10.1" Touchscreen sysfs information | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #ifndef _S5PV310_TS_SYSFS_H_ | ||
14 | #define _S5PV310_TS_SYSFS_H_ | ||
15 | |||
16 | extern int s5pv310_ts_sysfs_create(struct platform_device *pdev); | ||
17 | extern void s5pv310_ts_sysfs_remove(struct platform_device *pdev); | ||
18 | |||
19 | #endif /* _S5PV310_TS_SYSFS_H_ */ | ||
diff --git a/drivers/input/touchscreen/synaptics_i2c_rmi.c b/drivers/input/touchscreen/synaptics_i2c_rmi.c new file mode 100644 index 00000000000..5729602cbb6 --- /dev/null +++ b/drivers/input/touchscreen/synaptics_i2c_rmi.c | |||
@@ -0,0 +1,675 @@ | |||
1 | /* drivers/input/keyboard/synaptics_i2c_rmi.c | ||
2 | * | ||
3 | * Copyright (C) 2007 Google, Inc. | ||
4 | * | ||
5 | * This software is licensed under the terms of the GNU General Public | ||
6 | * License version 2, as published by the Free Software Foundation, and | ||
7 | * may be copied, distributed, and modified under those terms. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | */ | ||
15 | |||
16 | #include <linux/module.h> | ||
17 | #include <linux/delay.h> | ||
18 | #include <linux/earlysuspend.h> | ||
19 | #include <linux/hrtimer.h> | ||
20 | #include <linux/i2c.h> | ||
21 | #include <linux/input.h> | ||
22 | #include <linux/interrupt.h> | ||
23 | #include <linux/io.h> | ||
24 | #include <linux/platform_device.h> | ||
25 | #include <linux/slab.h> | ||
26 | #include <linux/synaptics_i2c_rmi.h> | ||
27 | |||
28 | static struct workqueue_struct *synaptics_wq; | ||
29 | |||
30 | struct synaptics_ts_data { | ||
31 | uint16_t addr; | ||
32 | struct i2c_client *client; | ||
33 | struct input_dev *input_dev; | ||
34 | int use_irq; | ||
35 | bool has_relative_report; | ||
36 | struct hrtimer timer; | ||
37 | struct work_struct work; | ||
38 | uint16_t max[2]; | ||
39 | int snap_state[2][2]; | ||
40 | int snap_down_on[2]; | ||
41 | int snap_down_off[2]; | ||
42 | int snap_up_on[2]; | ||
43 | int snap_up_off[2]; | ||
44 | int snap_down[2]; | ||
45 | int snap_up[2]; | ||
46 | uint32_t flags; | ||
47 | int reported_finger_count; | ||
48 | int8_t sensitivity_adjust; | ||
49 | int (*power)(int on); | ||
50 | struct early_suspend early_suspend; | ||
51 | }; | ||
52 | |||
53 | #ifdef CONFIG_HAS_EARLYSUSPEND | ||
54 | static void synaptics_ts_early_suspend(struct early_suspend *h); | ||
55 | static void synaptics_ts_late_resume(struct early_suspend *h); | ||
56 | #endif | ||
57 | |||
58 | static int synaptics_init_panel(struct synaptics_ts_data *ts) | ||
59 | { | ||
60 | int ret; | ||
61 | |||
62 | ret = i2c_smbus_write_byte_data(ts->client, 0xff, 0x10); /* page select = 0x10 */ | ||
63 | if (ret < 0) { | ||
64 | printk(KERN_ERR "i2c_smbus_write_byte_data failed for page select\n"); | ||
65 | goto err_page_select_failed; | ||
66 | } | ||
67 | ret = i2c_smbus_write_byte_data(ts->client, 0x41, 0x04); /* Set "No Clip Z" */ | ||
68 | if (ret < 0) | ||
69 | printk(KERN_ERR "i2c_smbus_write_byte_data failed for No Clip Z\n"); | ||
70 | |||
71 | ret = i2c_smbus_write_byte_data(ts->client, 0x44, | ||
72 | ts->sensitivity_adjust); | ||
73 | if (ret < 0) | ||
74 | pr_err("synaptics_ts: failed to set Sensitivity Adjust\n"); | ||
75 | |||
76 | err_page_select_failed: | ||
77 | ret = i2c_smbus_write_byte_data(ts->client, 0xff, 0x04); /* page select = 0x04 */ | ||
78 | if (ret < 0) | ||
79 | printk(KERN_ERR "i2c_smbus_write_byte_data failed for page select\n"); | ||
80 | ret = i2c_smbus_write_byte_data(ts->client, 0xf0, 0x81); /* normal operation, 80 reports per second */ | ||
81 | if (ret < 0) | ||
82 | printk(KERN_ERR "synaptics_ts_resume: i2c_smbus_write_byte_data failed\n"); | ||
83 | return ret; | ||
84 | } | ||
85 | |||
86 | static void synaptics_ts_work_func(struct work_struct *work) | ||
87 | { | ||
88 | int i; | ||
89 | int ret; | ||
90 | int bad_data = 0; | ||
91 | struct i2c_msg msg[2]; | ||
92 | uint8_t start_reg; | ||
93 | uint8_t buf[15]; | ||
94 | struct synaptics_ts_data *ts = container_of(work, struct synaptics_ts_data, work); | ||
95 | int buf_len = ts->has_relative_report ? 15 : 13; | ||
96 | |||
97 | msg[0].addr = ts->client->addr; | ||
98 | msg[0].flags = 0; | ||
99 | msg[0].len = 1; | ||
100 | msg[0].buf = &start_reg; | ||
101 | start_reg = 0x00; | ||
102 | msg[1].addr = ts->client->addr; | ||
103 | msg[1].flags = I2C_M_RD; | ||
104 | msg[1].len = buf_len; | ||
105 | msg[1].buf = buf; | ||
106 | |||
107 | /* printk("synaptics_ts_work_func\n"); */ | ||
108 | for (i = 0; i < ((ts->use_irq && !bad_data) ? 1 : 10); i++) { | ||
109 | ret = i2c_transfer(ts->client->adapter, msg, 2); | ||
110 | if (ret < 0) { | ||
111 | printk(KERN_ERR "synaptics_ts_work_func: i2c_transfer failed\n"); | ||
112 | bad_data = 1; | ||
113 | } else { | ||
114 | /* printk("synaptics_ts_work_func: %x %x %x %x %x %x" */ | ||
115 | /* " %x %x %x %x %x %x %x %x %x, ret %d\n", */ | ||
116 | /* buf[0], buf[1], buf[2], buf[3], */ | ||
117 | /* buf[4], buf[5], buf[6], buf[7], */ | ||
118 | /* buf[8], buf[9], buf[10], buf[11], */ | ||
119 | /* buf[12], buf[13], buf[14], ret); */ | ||
120 | if ((buf[buf_len - 1] & 0xc0) != 0x40) { | ||
121 | printk(KERN_WARNING "synaptics_ts_work_func:" | ||
122 | " bad read %x %x %x %x %x %x %x %x %x" | ||
123 | " %x %x %x %x %x %x, ret %d\n", | ||
124 | buf[0], buf[1], buf[2], buf[3], | ||
125 | buf[4], buf[5], buf[6], buf[7], | ||
126 | buf[8], buf[9], buf[10], buf[11], | ||
127 | buf[12], buf[13], buf[14], ret); | ||
128 | if (bad_data) | ||
129 | synaptics_init_panel(ts); | ||
130 | bad_data = 1; | ||
131 | continue; | ||
132 | } | ||
133 | bad_data = 0; | ||
134 | if ((buf[buf_len - 1] & 1) == 0) { | ||
135 | /* printk("read %d coordinates\n", i); */ | ||
136 | break; | ||
137 | } else { | ||
138 | int pos[2][2]; | ||
139 | int f, a; | ||
140 | int base; | ||
141 | /* int x = buf[3] | (uint16_t)(buf[2] & 0x1f) << 8; */ | ||
142 | /* int y = buf[5] | (uint16_t)(buf[4] & 0x1f) << 8; */ | ||
143 | int z = buf[1]; | ||
144 | int w = buf[0] >> 4; | ||
145 | int finger = buf[0] & 7; | ||
146 | |||
147 | /* int x2 = buf[3+6] | (uint16_t)(buf[2+6] & 0x1f) << 8; */ | ||
148 | /* int y2 = buf[5+6] | (uint16_t)(buf[4+6] & 0x1f) << 8; */ | ||
149 | /* int z2 = buf[1+6]; */ | ||
150 | /* int w2 = buf[0+6] >> 4; */ | ||
151 | /* int finger2 = buf[0+6] & 7; */ | ||
152 | |||
153 | /* int dx = (int8_t)buf[12]; */ | ||
154 | /* int dy = (int8_t)buf[13]; */ | ||
155 | int finger2_pressed; | ||
156 | |||
157 | /* printk("x %4d, y %4d, z %3d, w %2d, F %d, 2nd: x %4d, y %4d, z %3d, w %2d, F %d, dx %4d, dy %4d\n", */ | ||
158 | /* x, y, z, w, finger, */ | ||
159 | /* x2, y2, z2, w2, finger2, */ | ||
160 | /* dx, dy); */ | ||
161 | |||
162 | base = 2; | ||
163 | for (f = 0; f < 2; f++) { | ||
164 | uint32_t flip_flag = SYNAPTICS_FLIP_X; | ||
165 | for (a = 0; a < 2; a++) { | ||
166 | int p = buf[base + 1]; | ||
167 | p |= (uint16_t)(buf[base] & 0x1f) << 8; | ||
168 | if (ts->flags & flip_flag) | ||
169 | p = ts->max[a] - p; | ||
170 | if (ts->flags & SYNAPTICS_SNAP_TO_INACTIVE_EDGE) { | ||
171 | if (ts->snap_state[f][a]) { | ||
172 | if (p <= ts->snap_down_off[a]) | ||
173 | p = ts->snap_down[a]; | ||
174 | else if (p >= ts->snap_up_off[a]) | ||
175 | p = ts->snap_up[a]; | ||
176 | else | ||
177 | ts->snap_state[f][a] = 0; | ||
178 | } else { | ||
179 | if (p <= ts->snap_down_on[a]) { | ||
180 | p = ts->snap_down[a]; | ||
181 | ts->snap_state[f][a] = 1; | ||
182 | } else if (p >= ts->snap_up_on[a]) { | ||
183 | p = ts->snap_up[a]; | ||
184 | ts->snap_state[f][a] = 1; | ||
185 | } | ||
186 | } | ||
187 | } | ||
188 | pos[f][a] = p; | ||
189 | base += 2; | ||
190 | flip_flag <<= 1; | ||
191 | } | ||
192 | base += 2; | ||
193 | if (ts->flags & SYNAPTICS_SWAP_XY) | ||
194 | swap(pos[f][0], pos[f][1]); | ||
195 | } | ||
196 | if (z) { | ||
197 | input_report_abs(ts->input_dev, ABS_X, pos[0][0]); | ||
198 | input_report_abs(ts->input_dev, ABS_Y, pos[0][1]); | ||
199 | } | ||
200 | input_report_abs(ts->input_dev, ABS_PRESSURE, z); | ||
201 | input_report_abs(ts->input_dev, ABS_TOOL_WIDTH, w); | ||
202 | input_report_key(ts->input_dev, BTN_TOUCH, finger); | ||
203 | finger2_pressed = finger > 1 && finger != 7; | ||
204 | input_report_key(ts->input_dev, BTN_2, finger2_pressed); | ||
205 | if (finger2_pressed) { | ||
206 | input_report_abs(ts->input_dev, ABS_HAT0X, pos[1][0]); | ||
207 | input_report_abs(ts->input_dev, ABS_HAT0Y, pos[1][1]); | ||
208 | } | ||
209 | |||
210 | if (!finger) | ||
211 | z = 0; | ||
212 | input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, z); | ||
213 | input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, w); | ||
214 | input_report_abs(ts->input_dev, ABS_MT_POSITION_X, pos[0][0]); | ||
215 | input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, pos[0][1]); | ||
216 | input_mt_sync(ts->input_dev); | ||
217 | if (finger2_pressed) { | ||
218 | input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, z); | ||
219 | input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, w); | ||
220 | input_report_abs(ts->input_dev, ABS_MT_POSITION_X, pos[1][0]); | ||
221 | input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, pos[1][1]); | ||
222 | input_mt_sync(ts->input_dev); | ||
223 | } else if (ts->reported_finger_count > 1) { | ||
224 | input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0); | ||
225 | input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0); | ||
226 | input_mt_sync(ts->input_dev); | ||
227 | } | ||
228 | ts->reported_finger_count = finger; | ||
229 | input_sync(ts->input_dev); | ||
230 | } | ||
231 | } | ||
232 | } | ||
233 | if (ts->use_irq) | ||
234 | enable_irq(ts->client->irq); | ||
235 | } | ||
236 | |||
237 | static enum hrtimer_restart synaptics_ts_timer_func(struct hrtimer *timer) | ||
238 | { | ||
239 | struct synaptics_ts_data *ts = container_of(timer, struct synaptics_ts_data, timer); | ||
240 | /* printk("synaptics_ts_timer_func\n"); */ | ||
241 | |||
242 | queue_work(synaptics_wq, &ts->work); | ||
243 | |||
244 | hrtimer_start(&ts->timer, ktime_set(0, 12500000), HRTIMER_MODE_REL); | ||
245 | return HRTIMER_NORESTART; | ||
246 | } | ||
247 | |||
248 | static irqreturn_t synaptics_ts_irq_handler(int irq, void *dev_id) | ||
249 | { | ||
250 | struct synaptics_ts_data *ts = dev_id; | ||
251 | |||
252 | /* printk("synaptics_ts_irq_handler\n"); */ | ||
253 | disable_irq_nosync(ts->client->irq); | ||
254 | queue_work(synaptics_wq, &ts->work); | ||
255 | return IRQ_HANDLED; | ||
256 | } | ||
257 | |||
258 | static int synaptics_ts_probe( | ||
259 | struct i2c_client *client, const struct i2c_device_id *id) | ||
260 | { | ||
261 | struct synaptics_ts_data *ts; | ||
262 | uint8_t buf0[4]; | ||
263 | uint8_t buf1[8]; | ||
264 | struct i2c_msg msg[2]; | ||
265 | int ret = 0; | ||
266 | uint16_t max_x, max_y; | ||
267 | int fuzz_x, fuzz_y, fuzz_p, fuzz_w; | ||
268 | struct synaptics_i2c_rmi_platform_data *pdata; | ||
269 | unsigned long irqflags; | ||
270 | int inactive_area_left; | ||
271 | int inactive_area_right; | ||
272 | int inactive_area_top; | ||
273 | int inactive_area_bottom; | ||
274 | int snap_left_on; | ||
275 | int snap_left_off; | ||
276 | int snap_right_on; | ||
277 | int snap_right_off; | ||
278 | int snap_top_on; | ||
279 | int snap_top_off; | ||
280 | int snap_bottom_on; | ||
281 | int snap_bottom_off; | ||
282 | uint32_t panel_version; | ||
283 | |||
284 | if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { | ||
285 | printk(KERN_ERR "synaptics_ts_probe: need I2C_FUNC_I2C\n"); | ||
286 | ret = -ENODEV; | ||
287 | goto err_check_functionality_failed; | ||
288 | } | ||
289 | |||
290 | ts = kzalloc(sizeof(*ts), GFP_KERNEL); | ||
291 | if (ts == NULL) { | ||
292 | ret = -ENOMEM; | ||
293 | goto err_alloc_data_failed; | ||
294 | } | ||
295 | INIT_WORK(&ts->work, synaptics_ts_work_func); | ||
296 | ts->client = client; | ||
297 | i2c_set_clientdata(client, ts); | ||
298 | pdata = client->dev.platform_data; | ||
299 | if (pdata) | ||
300 | ts->power = pdata->power; | ||
301 | if (ts->power) { | ||
302 | ret = ts->power(1); | ||
303 | if (ret < 0) { | ||
304 | printk(KERN_ERR "synaptics_ts_probe power on failed\n"); | ||
305 | goto err_power_failed; | ||
306 | } | ||
307 | } | ||
308 | |||
309 | ret = i2c_smbus_write_byte_data(ts->client, 0xf4, 0x01); /* device command = reset */ | ||
310 | if (ret < 0) { | ||
311 | printk(KERN_ERR "i2c_smbus_write_byte_data failed\n"); | ||
312 | /* fail? */ | ||
313 | } | ||
314 | { | ||
315 | int retry = 10; | ||
316 | while (retry-- > 0) { | ||
317 | ret = i2c_smbus_read_byte_data(ts->client, 0xe4); | ||
318 | if (ret >= 0) | ||
319 | break; | ||
320 | msleep(100); | ||
321 | } | ||
322 | } | ||
323 | if (ret < 0) { | ||
324 | printk(KERN_ERR "i2c_smbus_read_byte_data failed\n"); | ||
325 | goto err_detect_failed; | ||
326 | } | ||
327 | printk(KERN_INFO "synaptics_ts_probe: Product Major Version %x\n", ret); | ||
328 | panel_version = ret << 8; | ||
329 | ret = i2c_smbus_read_byte_data(ts->client, 0xe5); | ||
330 | if (ret < 0) { | ||
331 | printk(KERN_ERR "i2c_smbus_read_byte_data failed\n"); | ||
332 | goto err_detect_failed; | ||
333 | } | ||
334 | printk(KERN_INFO "synaptics_ts_probe: Product Minor Version %x\n", ret); | ||
335 | panel_version |= ret; | ||
336 | |||
337 | ret = i2c_smbus_read_byte_data(ts->client, 0xe3); | ||
338 | if (ret < 0) { | ||
339 | printk(KERN_ERR "i2c_smbus_read_byte_data failed\n"); | ||
340 | goto err_detect_failed; | ||
341 | } | ||
342 | printk(KERN_INFO "synaptics_ts_probe: product property %x\n", ret); | ||
343 | |||
344 | if (pdata) { | ||
345 | while (pdata->version > panel_version) | ||
346 | pdata++; | ||
347 | ts->flags = pdata->flags; | ||
348 | ts->sensitivity_adjust = pdata->sensitivity_adjust; | ||
349 | irqflags = pdata->irqflags; | ||
350 | inactive_area_left = pdata->inactive_left; | ||
351 | inactive_area_right = pdata->inactive_right; | ||
352 | inactive_area_top = pdata->inactive_top; | ||
353 | inactive_area_bottom = pdata->inactive_bottom; | ||
354 | snap_left_on = pdata->snap_left_on; | ||
355 | snap_left_off = pdata->snap_left_off; | ||
356 | snap_right_on = pdata->snap_right_on; | ||
357 | snap_right_off = pdata->snap_right_off; | ||
358 | snap_top_on = pdata->snap_top_on; | ||
359 | snap_top_off = pdata->snap_top_off; | ||
360 | snap_bottom_on = pdata->snap_bottom_on; | ||
361 | snap_bottom_off = pdata->snap_bottom_off; | ||
362 | fuzz_x = pdata->fuzz_x; | ||
363 | fuzz_y = pdata->fuzz_y; | ||
364 | fuzz_p = pdata->fuzz_p; | ||
365 | fuzz_w = pdata->fuzz_w; | ||
366 | } else { | ||
367 | irqflags = 0; | ||
368 | inactive_area_left = 0; | ||
369 | inactive_area_right = 0; | ||
370 | inactive_area_top = 0; | ||
371 | inactive_area_bottom = 0; | ||
372 | snap_left_on = 0; | ||
373 | snap_left_off = 0; | ||
374 | snap_right_on = 0; | ||
375 | snap_right_off = 0; | ||
376 | snap_top_on = 0; | ||
377 | snap_top_off = 0; | ||
378 | snap_bottom_on = 0; | ||
379 | snap_bottom_off = 0; | ||
380 | fuzz_x = 0; | ||
381 | fuzz_y = 0; | ||
382 | fuzz_p = 0; | ||
383 | fuzz_w = 0; | ||
384 | } | ||
385 | |||
386 | ret = i2c_smbus_read_byte_data(ts->client, 0xf0); | ||
387 | if (ret < 0) { | ||
388 | printk(KERN_ERR "i2c_smbus_read_byte_data failed\n"); | ||
389 | goto err_detect_failed; | ||
390 | } | ||
391 | printk(KERN_INFO "synaptics_ts_probe: device control %x\n", ret); | ||
392 | |||
393 | ret = i2c_smbus_read_byte_data(ts->client, 0xf1); | ||
394 | if (ret < 0) { | ||
395 | printk(KERN_ERR "i2c_smbus_read_byte_data failed\n"); | ||
396 | goto err_detect_failed; | ||
397 | } | ||
398 | printk(KERN_INFO "synaptics_ts_probe: interrupt enable %x\n", ret); | ||
399 | |||
400 | ret = i2c_smbus_write_byte_data(ts->client, 0xf1, 0); /* disable interrupt */ | ||
401 | if (ret < 0) { | ||
402 | printk(KERN_ERR "i2c_smbus_write_byte_data failed\n"); | ||
403 | goto err_detect_failed; | ||
404 | } | ||
405 | |||
406 | msg[0].addr = ts->client->addr; | ||
407 | msg[0].flags = 0; | ||
408 | msg[0].len = 1; | ||
409 | msg[0].buf = buf0; | ||
410 | buf0[0] = 0xe0; | ||
411 | msg[1].addr = ts->client->addr; | ||
412 | msg[1].flags = I2C_M_RD; | ||
413 | msg[1].len = 8; | ||
414 | msg[1].buf = buf1; | ||
415 | ret = i2c_transfer(ts->client->adapter, msg, 2); | ||
416 | if (ret < 0) { | ||
417 | printk(KERN_ERR "i2c_transfer failed\n"); | ||
418 | goto err_detect_failed; | ||
419 | } | ||
420 | printk(KERN_INFO "synaptics_ts_probe: 0xe0: %x %x %x %x %x %x %x %x\n", | ||
421 | buf1[0], buf1[1], buf1[2], buf1[3], | ||
422 | buf1[4], buf1[5], buf1[6], buf1[7]); | ||
423 | |||
424 | ret = i2c_smbus_write_byte_data(ts->client, 0xff, 0x10); /* page select = 0x10 */ | ||
425 | if (ret < 0) { | ||
426 | printk(KERN_ERR "i2c_smbus_write_byte_data failed for page select\n"); | ||
427 | goto err_detect_failed; | ||
428 | } | ||
429 | ret = i2c_smbus_read_word_data(ts->client, 0x02); | ||
430 | if (ret < 0) { | ||
431 | printk(KERN_ERR "i2c_smbus_read_word_data failed\n"); | ||
432 | goto err_detect_failed; | ||
433 | } | ||
434 | ts->has_relative_report = !(ret & 0x100); | ||
435 | printk(KERN_INFO "synaptics_ts_probe: Sensor properties %x\n", ret); | ||
436 | ret = i2c_smbus_read_word_data(ts->client, 0x04); | ||
437 | if (ret < 0) { | ||
438 | printk(KERN_ERR "i2c_smbus_read_word_data failed\n"); | ||
439 | goto err_detect_failed; | ||
440 | } | ||
441 | ts->max[0] = max_x = (ret >> 8 & 0xff) | ((ret & 0x1f) << 8); | ||
442 | ret = i2c_smbus_read_word_data(ts->client, 0x06); | ||
443 | if (ret < 0) { | ||
444 | printk(KERN_ERR "i2c_smbus_read_word_data failed\n"); | ||
445 | goto err_detect_failed; | ||
446 | } | ||
447 | ts->max[1] = max_y = (ret >> 8 & 0xff) | ((ret & 0x1f) << 8); | ||
448 | if (ts->flags & SYNAPTICS_SWAP_XY) | ||
449 | swap(max_x, max_y); | ||
450 | |||
451 | ret = synaptics_init_panel(ts); /* will also switch back to page 0x04 */ | ||
452 | if (ret < 0) { | ||
453 | printk(KERN_ERR "synaptics_init_panel failed\n"); | ||
454 | goto err_detect_failed; | ||
455 | } | ||
456 | |||
457 | ts->input_dev = input_allocate_device(); | ||
458 | if (ts->input_dev == NULL) { | ||
459 | ret = -ENOMEM; | ||
460 | printk(KERN_ERR "synaptics_ts_probe: Failed to allocate input device\n"); | ||
461 | goto err_input_dev_alloc_failed; | ||
462 | } | ||
463 | ts->input_dev->name = "synaptics-rmi-touchscreen"; | ||
464 | set_bit(EV_SYN, ts->input_dev->evbit); | ||
465 | set_bit(EV_KEY, ts->input_dev->evbit); | ||
466 | set_bit(BTN_TOUCH, ts->input_dev->keybit); | ||
467 | set_bit(BTN_2, ts->input_dev->keybit); | ||
468 | set_bit(EV_ABS, ts->input_dev->evbit); | ||
469 | inactive_area_left = inactive_area_left * max_x / 0x10000; | ||
470 | inactive_area_right = inactive_area_right * max_x / 0x10000; | ||
471 | inactive_area_top = inactive_area_top * max_y / 0x10000; | ||
472 | inactive_area_bottom = inactive_area_bottom * max_y / 0x10000; | ||
473 | snap_left_on = snap_left_on * max_x / 0x10000; | ||
474 | snap_left_off = snap_left_off * max_x / 0x10000; | ||
475 | snap_right_on = snap_right_on * max_x / 0x10000; | ||
476 | snap_right_off = snap_right_off * max_x / 0x10000; | ||
477 | snap_top_on = snap_top_on * max_y / 0x10000; | ||
478 | snap_top_off = snap_top_off * max_y / 0x10000; | ||
479 | snap_bottom_on = snap_bottom_on * max_y / 0x10000; | ||
480 | snap_bottom_off = snap_bottom_off * max_y / 0x10000; | ||
481 | fuzz_x = fuzz_x * max_x / 0x10000; | ||
482 | fuzz_y = fuzz_y * max_y / 0x10000; | ||
483 | ts->snap_down[!!(ts->flags & SYNAPTICS_SWAP_XY)] = -inactive_area_left; | ||
484 | ts->snap_up[!!(ts->flags & SYNAPTICS_SWAP_XY)] = max_x + inactive_area_right; | ||
485 | ts->snap_down[!(ts->flags & SYNAPTICS_SWAP_XY)] = -inactive_area_top; | ||
486 | ts->snap_up[!(ts->flags & SYNAPTICS_SWAP_XY)] = max_y + inactive_area_bottom; | ||
487 | ts->snap_down_on[!!(ts->flags & SYNAPTICS_SWAP_XY)] = snap_left_on; | ||
488 | ts->snap_down_off[!!(ts->flags & SYNAPTICS_SWAP_XY)] = snap_left_off; | ||
489 | ts->snap_up_on[!!(ts->flags & SYNAPTICS_SWAP_XY)] = max_x - snap_right_on; | ||
490 | ts->snap_up_off[!!(ts->flags & SYNAPTICS_SWAP_XY)] = max_x - snap_right_off; | ||
491 | ts->snap_down_on[!(ts->flags & SYNAPTICS_SWAP_XY)] = snap_top_on; | ||
492 | ts->snap_down_off[!(ts->flags & SYNAPTICS_SWAP_XY)] = snap_top_off; | ||
493 | ts->snap_up_on[!(ts->flags & SYNAPTICS_SWAP_XY)] = max_y - snap_bottom_on; | ||
494 | ts->snap_up_off[!(ts->flags & SYNAPTICS_SWAP_XY)] = max_y - snap_bottom_off; | ||
495 | printk(KERN_INFO "synaptics_ts_probe: max_x %d, max_y %d\n", max_x, max_y); | ||
496 | printk(KERN_INFO "synaptics_ts_probe: inactive_x %d %d, inactive_y %d %d\n", | ||
497 | inactive_area_left, inactive_area_right, | ||
498 | inactive_area_top, inactive_area_bottom); | ||
499 | printk(KERN_INFO "synaptics_ts_probe: snap_x %d-%d %d-%d, snap_y %d-%d %d-%d\n", | ||
500 | snap_left_on, snap_left_off, snap_right_on, snap_right_off, | ||
501 | snap_top_on, snap_top_off, snap_bottom_on, snap_bottom_off); | ||
502 | input_set_abs_params(ts->input_dev, ABS_X, -inactive_area_left, max_x + inactive_area_right, fuzz_x, 0); | ||
503 | input_set_abs_params(ts->input_dev, ABS_Y, -inactive_area_top, max_y + inactive_area_bottom, fuzz_y, 0); | ||
504 | input_set_abs_params(ts->input_dev, ABS_PRESSURE, 0, 255, fuzz_p, 0); | ||
505 | input_set_abs_params(ts->input_dev, ABS_TOOL_WIDTH, 0, 15, fuzz_w, 0); | ||
506 | input_set_abs_params(ts->input_dev, ABS_HAT0X, -inactive_area_left, max_x + inactive_area_right, fuzz_x, 0); | ||
507 | input_set_abs_params(ts->input_dev, ABS_HAT0Y, -inactive_area_top, max_y + inactive_area_bottom, fuzz_y, 0); | ||
508 | input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X, -inactive_area_left, max_x + inactive_area_right, fuzz_x, 0); | ||
509 | input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y, -inactive_area_top, max_y + inactive_area_bottom, fuzz_y, 0); | ||
510 | input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, fuzz_p, 0); | ||
511 | input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0, 15, fuzz_w, 0); | ||
512 | /* ts->input_dev->name = ts->keypad_info->name; */ | ||
513 | ret = input_register_device(ts->input_dev); | ||
514 | if (ret) { | ||
515 | printk(KERN_ERR "synaptics_ts_probe: Unable to register %s input device\n", ts->input_dev->name); | ||
516 | goto err_input_register_device_failed; | ||
517 | } | ||
518 | if (client->irq) { | ||
519 | ret = request_irq(client->irq, synaptics_ts_irq_handler, irqflags, client->name, ts); | ||
520 | if (ret == 0) { | ||
521 | ret = i2c_smbus_write_byte_data(ts->client, 0xf1, 0x01); /* enable abs int */ | ||
522 | if (ret) | ||
523 | free_irq(client->irq, ts); | ||
524 | } | ||
525 | if (ret == 0) | ||
526 | ts->use_irq = 1; | ||
527 | else | ||
528 | dev_err(&client->dev, "request_irq failed\n"); | ||
529 | } | ||
530 | if (!ts->use_irq) { | ||
531 | hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); | ||
532 | ts->timer.function = synaptics_ts_timer_func; | ||
533 | hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL); | ||
534 | } | ||
535 | #ifdef CONFIG_HAS_EARLYSUSPEND | ||
536 | ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; | ||
537 | ts->early_suspend.suspend = synaptics_ts_early_suspend; | ||
538 | ts->early_suspend.resume = synaptics_ts_late_resume; | ||
539 | register_early_suspend(&ts->early_suspend); | ||
540 | #endif | ||
541 | |||
542 | printk(KERN_INFO "synaptics_ts_probe: Start touchscreen %s in %s mode\n", ts->input_dev->name, ts->use_irq ? "interrupt" : "polling"); | ||
543 | |||
544 | return 0; | ||
545 | |||
546 | err_input_register_device_failed: | ||
547 | input_free_device(ts->input_dev); | ||
548 | |||
549 | err_input_dev_alloc_failed: | ||
550 | err_detect_failed: | ||
551 | err_power_failed: | ||
552 | kfree(ts); | ||
553 | err_alloc_data_failed: | ||
554 | err_check_functionality_failed: | ||
555 | return ret; | ||
556 | } | ||
557 | |||
558 | static int synaptics_ts_remove(struct i2c_client *client) | ||
559 | { | ||
560 | struct synaptics_ts_data *ts = i2c_get_clientdata(client); | ||
561 | unregister_early_suspend(&ts->early_suspend); | ||
562 | if (ts->use_irq) | ||
563 | free_irq(client->irq, ts); | ||
564 | else | ||
565 | hrtimer_cancel(&ts->timer); | ||
566 | input_unregister_device(ts->input_dev); | ||
567 | kfree(ts); | ||
568 | return 0; | ||
569 | } | ||
570 | |||
571 | static int synaptics_ts_suspend(struct i2c_client *client, pm_message_t mesg) | ||
572 | { | ||
573 | int ret; | ||
574 | struct synaptics_ts_data *ts = i2c_get_clientdata(client); | ||
575 | |||
576 | if (ts->use_irq) | ||
577 | disable_irq(client->irq); | ||
578 | else | ||
579 | hrtimer_cancel(&ts->timer); | ||
580 | ret = cancel_work_sync(&ts->work); | ||
581 | if (ret && ts->use_irq) /* if work was pending disable-count is now 2 */ | ||
582 | enable_irq(client->irq); | ||
583 | ret = i2c_smbus_write_byte_data(ts->client, 0xf1, 0); /* disable interrupt */ | ||
584 | if (ret < 0) | ||
585 | printk(KERN_ERR "synaptics_ts_suspend: i2c_smbus_write_byte_data failed\n"); | ||
586 | |||
587 | ret = i2c_smbus_write_byte_data(client, 0xf0, 0x86); /* deep sleep */ | ||
588 | if (ret < 0) | ||
589 | printk(KERN_ERR "synaptics_ts_suspend: i2c_smbus_write_byte_data failed\n"); | ||
590 | if (ts->power) { | ||
591 | ret = ts->power(0); | ||
592 | if (ret < 0) | ||
593 | printk(KERN_ERR "synaptics_ts_resume power off failed\n"); | ||
594 | } | ||
595 | return 0; | ||
596 | } | ||
597 | |||
598 | static int synaptics_ts_resume(struct i2c_client *client) | ||
599 | { | ||
600 | int ret; | ||
601 | struct synaptics_ts_data *ts = i2c_get_clientdata(client); | ||
602 | |||
603 | if (ts->power) { | ||
604 | ret = ts->power(1); | ||
605 | if (ret < 0) | ||
606 | printk(KERN_ERR "synaptics_ts_resume power on failed\n"); | ||
607 | } | ||
608 | |||
609 | synaptics_init_panel(ts); | ||
610 | |||
611 | if (ts->use_irq) | ||
612 | enable_irq(client->irq); | ||
613 | |||
614 | if (!ts->use_irq) | ||
615 | hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL); | ||
616 | else | ||
617 | i2c_smbus_write_byte_data(ts->client, 0xf1, 0x01); /* enable abs int */ | ||
618 | |||
619 | return 0; | ||
620 | } | ||
621 | |||
622 | #ifdef CONFIG_HAS_EARLYSUSPEND | ||
623 | static void synaptics_ts_early_suspend(struct early_suspend *h) | ||
624 | { | ||
625 | struct synaptics_ts_data *ts; | ||
626 | ts = container_of(h, struct synaptics_ts_data, early_suspend); | ||
627 | synaptics_ts_suspend(ts->client, PMSG_SUSPEND); | ||
628 | } | ||
629 | |||
630 | static void synaptics_ts_late_resume(struct early_suspend *h) | ||
631 | { | ||
632 | struct synaptics_ts_data *ts; | ||
633 | ts = container_of(h, struct synaptics_ts_data, early_suspend); | ||
634 | synaptics_ts_resume(ts->client); | ||
635 | } | ||
636 | #endif | ||
637 | |||
638 | static const struct i2c_device_id synaptics_ts_id[] = { | ||
639 | { SYNAPTICS_I2C_RMI_NAME, 0 }, | ||
640 | { } | ||
641 | }; | ||
642 | |||
643 | static struct i2c_driver synaptics_ts_driver = { | ||
644 | .probe = synaptics_ts_probe, | ||
645 | .remove = synaptics_ts_remove, | ||
646 | #ifndef CONFIG_HAS_EARLYSUSPEND | ||
647 | .suspend = synaptics_ts_suspend, | ||
648 | .resume = synaptics_ts_resume, | ||
649 | #endif | ||
650 | .id_table = synaptics_ts_id, | ||
651 | .driver = { | ||
652 | .name = SYNAPTICS_I2C_RMI_NAME, | ||
653 | }, | ||
654 | }; | ||
655 | |||
656 | static int __devinit synaptics_ts_init(void) | ||
657 | { | ||
658 | synaptics_wq = create_singlethread_workqueue("synaptics_wq"); | ||
659 | if (!synaptics_wq) | ||
660 | return -ENOMEM; | ||
661 | return i2c_add_driver(&synaptics_ts_driver); | ||
662 | } | ||
663 | |||
664 | static void __exit synaptics_ts_exit(void) | ||
665 | { | ||
666 | i2c_del_driver(&synaptics_ts_driver); | ||
667 | if (synaptics_wq) | ||
668 | destroy_workqueue(synaptics_wq); | ||
669 | } | ||
670 | |||
671 | module_init(synaptics_ts_init); | ||
672 | module_exit(synaptics_ts_exit); | ||
673 | |||
674 | MODULE_DESCRIPTION("Synaptics Touchscreen Driver"); | ||
675 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/input/touchscreen/touch-i2c.c b/drivers/input/touchscreen/touch-i2c.c new file mode 100644 index 00000000000..8526d896150 --- /dev/null +++ b/drivers/input/touchscreen/touch-i2c.c | |||
@@ -0,0 +1,170 @@ | |||
1 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
2 | // | ||
3 | // | ||
4 | // | ||
5 | // I2C Touchscreen driver | ||
6 | // 2012.01.17 | ||
7 | // | ||
8 | // | ||
9 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
10 | #include <linux/input.h> /* BUS_I2C */ | ||
11 | #include <linux/i2c.h> | ||
12 | #include <linux/module.h> | ||
13 | |||
14 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
15 | #include <linux/input/touch-pdata.h> | ||
16 | #include "touch.h" | ||
17 | |||
18 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
19 | // | ||
20 | // function prototype | ||
21 | // | ||
22 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
23 | static void __exit touch_i2c_exit (void); | ||
24 | static int __init touch_i2c_init (void); | ||
25 | static int __devexit touch_i2c_remove (struct i2c_client *client); | ||
26 | static int __devinit touch_i2c_probe (struct i2c_client *client, const struct i2c_device_id *id); | ||
27 | int touch_i2c_read (struct i2c_client *client, unsigned char *cmd, unsigned int cmd_len, unsigned char *data, unsigned int len); | ||
28 | int touch_i2c_write (struct i2c_client *client, unsigned char *cmd, unsigned int cmd_len, unsigned char *data, unsigned int len); | ||
29 | |||
30 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
31 | #ifdef CONFIG_PM | ||
32 | static int touch_i2c_suspend(struct i2c_client *client, pm_message_t message) | ||
33 | { | ||
34 | #ifndef CONFIG_HAS_EARLYSUSPEND | ||
35 | struct touch *ts = i2c_get_clientdata(client); | ||
36 | |||
37 | ts->pdata->suspend(&client->dev); | ||
38 | #endif | ||
39 | |||
40 | return 0; | ||
41 | } | ||
42 | |||
43 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
44 | static int touch_i2c_resume(struct i2c_client *client) | ||
45 | { | ||
46 | #ifndef CONFIG_HAS_EARLYSUSPEND | ||
47 | struct touch *ts = i2c_get_clientdata(client); | ||
48 | |||
49 | ts->pdata->resume(&cliet->dev); | ||
50 | #endif | ||
51 | |||
52 | return 0; | ||
53 | } | ||
54 | |||
55 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
56 | #else | ||
57 | #define touch_i2c_suspend NULL | ||
58 | #define touch_i2c_resume NULL | ||
59 | #endif | ||
60 | |||
61 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
62 | int touch_i2c_read(struct i2c_client *client, unsigned char *cmd, unsigned int cmd_len, unsigned char *data, unsigned int len) | ||
63 | { | ||
64 | struct i2c_msg msg[2]; | ||
65 | int ret; | ||
66 | |||
67 | if((len == 0) || (data == NULL)) { | ||
68 | dev_err(&client->dev, "I2C read error: Null pointer or length == 0\n"); | ||
69 | return -1; | ||
70 | } | ||
71 | |||
72 | memset(msg, 0x00, sizeof(msg)); | ||
73 | |||
74 | msg[0].addr = client->addr; | ||
75 | msg[0].flags = 0; | ||
76 | msg[0].len = cmd_len; | ||
77 | msg[0].buf = cmd; | ||
78 | |||
79 | msg[1].addr = client->addr; | ||
80 | msg[1].flags = I2C_M_RD; | ||
81 | msg[1].len = len; | ||
82 | msg[1].buf = data; | ||
83 | |||
84 | if ((ret = i2c_transfer(client->adapter, msg, 2)) != 2) { | ||
85 | dev_err(&client->dev, "I2C read error: (%d) reg: 0x%X len: %d\n", ret, cmd[0], len); | ||
86 | return -EIO; | ||
87 | } | ||
88 | |||
89 | return len; | ||
90 | } | ||
91 | |||
92 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
93 | int touch_i2c_write(struct i2c_client *client, unsigned char *cmd, unsigned int cmd_len, unsigned char *data, unsigned int len) | ||
94 | { | ||
95 | int ret; | ||
96 | unsigned char block_data[10]; | ||
97 | |||
98 | if((cmd_len + len) >= sizeof(block_data)) { | ||
99 | dev_err(&client->dev, "I2C write error: wdata overflow reg: 0x%X len: %d\n", cmd[0], cmd_len + len); | ||
100 | return -1; | ||
101 | } | ||
102 | |||
103 | memset(block_data, 0x00, sizeof(block_data)); | ||
104 | |||
105 | if(cmd_len) memcpy(&block_data[0] , &cmd[0] , cmd_len); | ||
106 | if(len) memcpy(&block_data[cmd_len] , &data[0] , len); | ||
107 | |||
108 | if ((ret = i2c_master_send(client, block_data, (cmd_len + len)))< 0) { | ||
109 | dev_err(&client->dev, "I2C write error: (%d) reg: 0x%X len: %d\n", ret, cmd[0], len); | ||
110 | return ret; | ||
111 | } | ||
112 | |||
113 | return len; | ||
114 | } | ||
115 | |||
116 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
117 | static int __devinit touch_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) | ||
118 | { | ||
119 | return touch_probe(client); | ||
120 | } | ||
121 | |||
122 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
123 | static int __devexit touch_i2c_remove(struct i2c_client *client) | ||
124 | { | ||
125 | return touch_remove(&client->dev); | ||
126 | } | ||
127 | |||
128 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
129 | static const struct i2c_device_id touch_id[] = { | ||
130 | { I2C_TOUCH_NAME, 0 }, | ||
131 | { } | ||
132 | }; | ||
133 | |||
134 | MODULE_DEVICE_TABLE(i2c, touch_id); | ||
135 | |||
136 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
137 | static struct i2c_driver touch_i2c_driver = { | ||
138 | .driver = { | ||
139 | .name = I2C_TOUCH_NAME, | ||
140 | .owner = THIS_MODULE, | ||
141 | }, | ||
142 | .probe = touch_i2c_probe, | ||
143 | .remove = __devexit_p(touch_i2c_remove), | ||
144 | .suspend = touch_i2c_suspend, | ||
145 | .resume = touch_i2c_resume, | ||
146 | .id_table = touch_id, | ||
147 | }; | ||
148 | |||
149 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
150 | static int __init touch_i2c_init(void) | ||
151 | { | ||
152 | return i2c_add_driver(&touch_i2c_driver); | ||
153 | } | ||
154 | module_init(touch_i2c_init); | ||
155 | |||
156 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
157 | static void __exit touch_i2c_exit(void) | ||
158 | { | ||
159 | i2c_del_driver(&touch_i2c_driver); | ||
160 | } | ||
161 | module_exit(touch_i2c_exit); | ||
162 | |||
163 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
164 | MODULE_AUTHOR("HardKernel Co., Ltd."); | ||
165 | MODULE_LICENSE("GPL"); | ||
166 | MODULE_DESCRIPTION("Touchscreen I2C bus driver"); | ||
167 | MODULE_ALIAS("i2c:touch"); | ||
168 | |||
169 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
170 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
diff --git a/drivers/input/touchscreen/touch-i2c.h b/drivers/input/touchscreen/touch-i2c.h new file mode 100644 index 00000000000..b976f46e838 --- /dev/null +++ b/drivers/input/touchscreen/touch-i2c.h | |||
@@ -0,0 +1,23 @@ | |||
1 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
2 | // | ||
3 | // | ||
4 | // | ||
5 | // I2C Touchscreen driver | ||
6 | // 2012.01.17 | ||
7 | // | ||
8 | // | ||
9 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
10 | #ifndef _TOUCH_I2C_H_ | ||
11 | #define _TOUCH_I2C_H_ | ||
12 | |||
13 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
14 | // extern function define | ||
15 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
16 | extern int touch_i2c_read (struct i2c_client *client, unsigned char *cmd, unsigned int cmd_len, unsigned char *data, unsigned int len); | ||
17 | extern int touch_i2c_write (struct i2c_client *client, unsigned char *cmd, unsigned int cmd_len, unsigned char *data, unsigned int len); | ||
18 | |||
19 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
20 | #endif /* _TOUCH_I2C_H_ */ | ||
21 | |||
22 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
23 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
diff --git a/drivers/input/touchscreen/touch-sysfs.c b/drivers/input/touchscreen/touch-sysfs.c new file mode 100644 index 00000000000..184d717fb5a --- /dev/null +++ b/drivers/input/touchscreen/touch-sysfs.c | |||
@@ -0,0 +1,250 @@ | |||
1 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
2 | // | ||
3 | // | ||
4 | // | ||
5 | // I2C Touchscreen driver | ||
6 | // 2012.01.17 | ||
7 | // | ||
8 | // | ||
9 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
10 | #include <linux/device.h> | ||
11 | #include <linux/init.h> | ||
12 | #include <linux/input.h> | ||
13 | #include <linux/interrupt.h> | ||
14 | #include <linux/irq.h> | ||
15 | #include <linux/slab.h> | ||
16 | #include <linux/workqueue.h> | ||
17 | #include <linux/hrtimer.h> | ||
18 | #include <asm/unaligned.h> | ||
19 | #include <linux/firmware.h> | ||
20 | #include <linux/delay.h> | ||
21 | #include <linux/fs.h> | ||
22 | |||
23 | #include <linux/string.h> | ||
24 | |||
25 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
26 | #include <linux/input/touch-pdata.h> | ||
27 | #include "touch.h" | ||
28 | |||
29 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
30 | // | ||
31 | // sysfs function prototype define | ||
32 | // | ||
33 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
34 | // disablel (1 -> disable irq, cancel work, 0 -> enable irq), show irq state | ||
35 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
36 | static ssize_t show_disable (struct device *dev, struct device_attribute *attr, char *buf); | ||
37 | static ssize_t store_disable (struct device *dev, struct device_attribute *attr, const char *buf, size_t count); | ||
38 | static DEVICE_ATTR(disable, S_IRWXUGO, show_disable, store_disable); | ||
39 | |||
40 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
41 | // fw version display | ||
42 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
43 | static ssize_t show_fw_version (struct device *dev, struct device_attribute *attr, char *buf); | ||
44 | static DEVICE_ATTR(fw_version, S_IRWXUGO, show_fw_version, NULL); | ||
45 | |||
46 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
47 | // fw data load : fw load status, fw data load | ||
48 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
49 | static ssize_t show_fw (struct device *dev, struct device_attribute *attr, char *buf); | ||
50 | static ssize_t store_fw (struct device *dev, struct device_attribute *attr, const char *buf, size_t count); | ||
51 | static DEVICE_ATTR(fw, S_IRWXUGO, show_fw, store_fw); | ||
52 | |||
53 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
54 | // fw status : fw status | ||
55 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
56 | static ssize_t show_fw_status (struct device *dev, struct device_attribute *attr, char *buf); | ||
57 | static ssize_t store_fw_status (struct device *dev, struct device_attribute *attr, const char *buf, size_t count); | ||
58 | static DEVICE_ATTR(fw_status, S_IRWXUGO, show_fw_status, store_fw_status); | ||
59 | |||
60 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
61 | // update_fw : 1 -> update fw (load fw) | ||
62 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
63 | static ssize_t store_update_fw (struct device *dev, struct device_attribute *attr, const char *buf, size_t count); | ||
64 | static DEVICE_ATTR(update_fw, S_IRWXUGO, NULL, store_update_fw); | ||
65 | |||
66 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
67 | // calibration (1 -> update calibration, 0 -> nothing), show -> NULL | ||
68 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
69 | static ssize_t store_calibration (struct device *dev, struct device_attribute *attr, const char *buf, size_t count); | ||
70 | static DEVICE_ATTR(calibration, S_IRWXUGO, NULL, store_calibration); | ||
71 | |||
72 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
73 | // hw reset | ||
74 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
75 | static ssize_t store_reset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count); | ||
76 | static DEVICE_ATTR(reset, S_IRWXUGO, NULL, store_reset); | ||
77 | |||
78 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
79 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
80 | static struct attribute *touch_sysfs_entries[] = { | ||
81 | &dev_attr_disable.attr, | ||
82 | &dev_attr_fw_version.attr, | ||
83 | &dev_attr_fw.attr, | ||
84 | &dev_attr_fw_status.attr, | ||
85 | &dev_attr_update_fw.attr, | ||
86 | &dev_attr_calibration.attr, | ||
87 | &dev_attr_reset.attr, | ||
88 | NULL | ||
89 | }; | ||
90 | |||
91 | static struct attribute_group touch_attr_group = { | ||
92 | .name = NULL, | ||
93 | .attrs = touch_sysfs_entries, | ||
94 | }; | ||
95 | |||
96 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
97 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
98 | static ssize_t store_reset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | ||
99 | { | ||
100 | struct touch *ts = dev_get_drvdata(dev); | ||
101 | unsigned long val; | ||
102 | int err; | ||
103 | |||
104 | if ((err = strict_strtoul(buf, 10, &val))) return err; | ||
105 | |||
106 | if((ts->pdata->reset_gpio) && (val == 1)) touch_hw_reset(ts); | ||
107 | |||
108 | return count; | ||
109 | } | ||
110 | |||
111 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
112 | // disablel (1 -> disable irq, cancel work, 0 -> enable irq), show irq state | ||
113 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
114 | static ssize_t show_disable (struct device *dev, struct device_attribute *attr, char *buf) | ||
115 | { | ||
116 | struct touch *ts = dev_get_drvdata(dev); | ||
117 | |||
118 | return sprintf(buf, "%u\n", ts->disabled); | ||
119 | } | ||
120 | |||
121 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
122 | static ssize_t store_disable (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | ||
123 | { | ||
124 | struct touch *ts = dev_get_drvdata(dev); | ||
125 | unsigned long val; | ||
126 | int err; | ||
127 | |||
128 | if ((err = strict_strtoul(buf, 10, &val))) return err; | ||
129 | |||
130 | if (val) ts->pdata->disable(ts); // interrupt disable | ||
131 | else ts->pdata->enable(ts); // interrupt enable | ||
132 | |||
133 | return count; | ||
134 | } | ||
135 | |||
136 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
137 | // firmware version display | ||
138 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
139 | static ssize_t show_fw_version (struct device *dev, struct device_attribute *attr, char *buf) | ||
140 | { | ||
141 | struct touch *ts = dev_get_drvdata(dev); | ||
142 | |||
143 | return sprintf(buf, "%d\n", ts->fw_version); | ||
144 | } | ||
145 | |||
146 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
147 | // update_fw | ||
148 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
149 | |||
150 | static ssize_t store_fw (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | ||
151 | { | ||
152 | struct touch *ts = dev_get_drvdata(dev); | ||
153 | |||
154 | if(ts->fw_buf != NULL) { | ||
155 | |||
156 | if(ts->fw_size < ts->pdata->fw_filesize) memcpy(&ts->fw_buf[ts->fw_size], buf, count); | ||
157 | |||
158 | ts->fw_size += count; | ||
159 | } | ||
160 | |||
161 | return count; | ||
162 | } | ||
163 | |||
164 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
165 | static ssize_t show_fw (struct device *dev, struct device_attribute *attr, char *buf) | ||
166 | { | ||
167 | struct touch *ts = dev_get_drvdata(dev); | ||
168 | |||
169 | return sprintf(buf, "%d\n", ts->fw_size); | ||
170 | } | ||
171 | |||
172 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
173 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
174 | static ssize_t store_fw_status (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | ||
175 | { | ||
176 | struct touch *ts = dev_get_drvdata(dev); | ||
177 | int err; | ||
178 | unsigned long val; | ||
179 | |||
180 | if ((err = strict_strtoul(buf, 10, &val))) return err; | ||
181 | |||
182 | if(ts->pdata->fw_control) ts->pdata->fw_control(ts, val); | ||
183 | |||
184 | return count; | ||
185 | } | ||
186 | |||
187 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
188 | static ssize_t show_fw_status (struct device *dev, struct device_attribute *attr, char *buf) | ||
189 | { | ||
190 | struct touch *ts = dev_get_drvdata(dev); | ||
191 | |||
192 | return sprintf(buf, "0x%08X\n", ts->fw_status); | ||
193 | } | ||
194 | |||
195 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
196 | static ssize_t store_update_fw (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | ||
197 | { | ||
198 | unsigned long val; | ||
199 | int err; | ||
200 | struct touch *ts = dev_get_drvdata(dev); | ||
201 | |||
202 | if ((err = strict_strtoul(buf, 10, &val))) return err; | ||
203 | |||
204 | if (val == 1) { | ||
205 | if(ts->pdata->flash_firmware) { | ||
206 | if(ts->pdata->fw_filename) ts->pdata->flash_firmware(dev, ts->pdata->fw_filename); | ||
207 | } | ||
208 | } | ||
209 | |||
210 | return count; | ||
211 | } | ||
212 | |||
213 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
214 | // calibration (1 -> update calibration, 0 -> nothing), show -> NULL | ||
215 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
216 | static ssize_t store_calibration (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | ||
217 | { | ||
218 | struct touch *ts = dev_get_drvdata(dev); | ||
219 | unsigned long val; | ||
220 | int err; | ||
221 | |||
222 | if ((err = strict_strtoul(buf, 10, &val))) return err; | ||
223 | |||
224 | if (val == 1) { | ||
225 | ts->pdata->disable(ts); // interrupt disable | ||
226 | if(ts->pdata->calibration) ts->pdata->calibration(ts); | ||
227 | ts->pdata->enable(ts); // interrupt enable | ||
228 | } | ||
229 | |||
230 | return count; | ||
231 | } | ||
232 | |||
233 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
234 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
235 | int touch_sysfs_create (struct device *dev) | ||
236 | { | ||
237 | return sysfs_create_group(&dev->kobj, &touch_attr_group); | ||
238 | } | ||
239 | |||
240 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
241 | void touch_sysfs_remove (struct device *dev) | ||
242 | { | ||
243 | sysfs_remove_group(&dev->kobj, &touch_attr_group); | ||
244 | } | ||
245 | |||
246 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
247 | MODULE_AUTHOR("HardKernel Co., Ltd."); | ||
248 | MODULE_LICENSE("GPL"); | ||
249 | MODULE_DESCRIPTION("Touchscreen Driver"); | ||
250 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
diff --git a/drivers/input/touchscreen/touch-sysfs.h b/drivers/input/touchscreen/touch-sysfs.h new file mode 100644 index 00000000000..dd4bc94885e --- /dev/null +++ b/drivers/input/touchscreen/touch-sysfs.h | |||
@@ -0,0 +1,23 @@ | |||
1 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
2 | // | ||
3 | // | ||
4 | // | ||
5 | // I2C Touchscreen driver | ||
6 | // 2012.01.17 | ||
7 | // | ||
8 | // | ||
9 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
10 | #ifndef _TOUCH_SYSFS_H_ | ||
11 | #define _TOUCH_SYSFS_H_ | ||
12 | |||
13 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
14 | // extern function define | ||
15 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
16 | extern int touch_sysfs_create (struct device *dev); | ||
17 | extern void touch_sysfs_remove (struct device *dev); | ||
18 | |||
19 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
20 | #endif /* _TOUCH_SYSFS_H_ */ | ||
21 | |||
22 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
23 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
diff --git a/drivers/input/touchscreen/touch.c b/drivers/input/touchscreen/touch.c new file mode 100644 index 00000000000..e6c0cc2324e --- /dev/null +++ b/drivers/input/touchscreen/touch.c | |||
@@ -0,0 +1,672 @@ | |||
1 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
2 | // | ||
3 | // | ||
4 | // | ||
5 | // I2C Touchscreen driver | ||
6 | // 2012.01.17 | ||
7 | // | ||
8 | // | ||
9 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
10 | #include <linux/device.h> | ||
11 | #include <linux/init.h> | ||
12 | #include <linux/input.h> | ||
13 | #include <linux/interrupt.h> | ||
14 | #include <linux/irq.h> | ||
15 | #include <linux/slab.h> | ||
16 | #include <linux/hrtimer.h> | ||
17 | #include <asm/unaligned.h> | ||
18 | #include <linux/firmware.h> | ||
19 | #include <linux/delay.h> | ||
20 | #include <linux/gpio.h> | ||
21 | #include <linux/i2c.h> | ||
22 | |||
23 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
24 | #if defined(CONFIG_HAS_EARLYSUSPEND) | ||
25 | #include <linux/wakelock.h> | ||
26 | #include <linux/earlysuspend.h> | ||
27 | #include <linux/suspend.h> | ||
28 | #endif | ||
29 | |||
30 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
31 | #include <linux/input/mt.h> | ||
32 | #include <linux/input/touch-pdata.h> | ||
33 | |||
34 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
35 | #include "touch.h" | ||
36 | #include "touch-i2c.h" | ||
37 | #include "touch-sysfs.h" | ||
38 | |||
39 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
40 | //#define DEBUG_TOUCH | ||
41 | |||
42 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
43 | // function prototype define | ||
44 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
45 | #ifdef CONFIG_HAS_EARLYSUSPEND | ||
46 | static void touch_suspend (struct early_suspend *h); | ||
47 | static void touch_resume (struct early_suspend *h); | ||
48 | #endif | ||
49 | |||
50 | irqreturn_t touch_irq (int irq, void *handle); | ||
51 | static void touch_work (struct touch *ts); | ||
52 | static void touch_work_q (struct work_struct *work); | ||
53 | |||
54 | static void touch_key_report (struct touch *ts, unsigned char button_data); | ||
55 | static void touch_report_protocol_a (struct touch *ts); | ||
56 | static void touch_report_protocol_b (struct touch *ts); | ||
57 | |||
58 | static void touch_event_clear (struct touch *ts); | ||
59 | static void touch_enable (struct touch *ts); | ||
60 | static void touch_disable (struct touch *ts); | ||
61 | static void touch_input_close (struct input_dev *input); | ||
62 | static int touch_input_open (struct input_dev *input); | ||
63 | static int touch_check_functionality (struct touch_pdata *pdata); | ||
64 | |||
65 | void touch_hw_reset (struct touch *ts); | ||
66 | int touch_info_display (struct touch *ts); | ||
67 | int touch_probe (struct i2c_client *client); | ||
68 | int touch_remove (struct device *dev); | ||
69 | |||
70 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
71 | irqreturn_t touch_irq (int irq, void *handle) | ||
72 | { | ||
73 | struct touch *ts = handle; | ||
74 | |||
75 | if(ts->pdata->irq_mode) queue_work(ts->work_queue, &ts->work); // normal mode (work q used) | ||
76 | else ts->pdata->touch_work(ts); // thread mode | ||
77 | |||
78 | return IRQ_HANDLED; | ||
79 | } | ||
80 | |||
81 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
82 | static void touch_work (struct touch *ts) | ||
83 | { | ||
84 | printk("error : undefined touch work function!!\n"); | ||
85 | } | ||
86 | |||
87 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
88 | static void touch_work_q (struct work_struct *work) | ||
89 | { | ||
90 | struct touch *ts = container_of(work, struct touch, work); | ||
91 | |||
92 | ts->pdata->touch_work(ts); | ||
93 | } | ||
94 | |||
95 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
96 | static void touch_key_report (struct touch *ts, unsigned char button_data) | ||
97 | { | ||
98 | static button_u button_old; | ||
99 | button_u button_new; | ||
100 | |||
101 | button_new.ubyte = button_data; | ||
102 | if(button_old.ubyte != button_new.ubyte) { | ||
103 | if((button_old.bits.bt0_press != button_new.bits.bt0_press) && (ts->pdata->keycnt > 0)) { | ||
104 | if(button_new.bits.bt0_press) input_report_key(ts->input, ts->pdata->keycode[0], true); | ||
105 | else input_report_key(ts->input, ts->pdata->keycode[0], false); | ||
106 | #if defined(DEBUG_TOUCH_KEY) | ||
107 | printk("keycode[0](0x%04X) %s\n", ts->pdata->keycode[0], button_new.bits.bt0_press ? "press":"release"); | ||
108 | #endif | ||
109 | } | ||
110 | if((button_old.bits.bt1_press != button_new.bits.bt1_press) && (ts->pdata->keycnt > 1)) { | ||
111 | if(button_new.bits.bt1_press) input_report_key(ts->input, ts->pdata->keycode[1], true); | ||
112 | else input_report_key(ts->input, ts->pdata->keycode[1], false); | ||
113 | #if defined(DEBUG_TOUCH_KEY) | ||
114 | printk("keycode[1](0x%04X) %s\n", ts->pdata->keycode[1], button_new.bits.bt1_press ? "press":"release"); | ||
115 | #endif | ||
116 | } | ||
117 | if((button_old.bits.bt2_press != button_new.bits.bt2_press) && (ts->pdata->keycnt > 2)) { | ||
118 | if(button_new.bits.bt2_press) input_report_key(ts->input, ts->pdata->keycode[2], true); | ||
119 | else input_report_key(ts->input, ts->pdata->keycode[2], false); | ||
120 | #if defined(DEBUG_TOUCH_KEY) | ||
121 | printk("keycode[2](0x%04X) %s\n", ts->pdata->keycode[2], button_new.bits.bt2_press ? "press":"release"); | ||
122 | #endif | ||
123 | } | ||
124 | if((button_old.bits.bt3_press != button_new.bits.bt3_press) && (ts->pdata->keycnt > 3)) { | ||
125 | if(button_new.bits.bt3_press) input_report_key(ts->input, ts->pdata->keycode[3], true); | ||
126 | else input_report_key(ts->input, ts->pdata->keycode[3], false); | ||
127 | #if defined(DEBUG_TOUCH_KEY) | ||
128 | printk("keycode[3](0x%04X) %s\n", ts->pdata->keycode[3], button_new.bits.bt3_press ? "press":"release"); | ||
129 | #endif | ||
130 | } | ||
131 | if((button_old.bits.bt4_press != button_new.bits.bt4_press) && (ts->pdata->keycnt > 4)) { | ||
132 | if(button_new.bits.bt4_press) input_report_key(ts->input, ts->pdata->keycode[4], true); | ||
133 | else input_report_key(ts->input, ts->pdata->keycode[4], false); | ||
134 | #if defined(DEBUG_TOUCH_KEY) | ||
135 | printk("keycode[4](0x%04X) %s\n", ts->pdata->keycode[4], button_new.bits.bt4_press ? "press":"release"); | ||
136 | #endif | ||
137 | } | ||
138 | if((button_old.bits.bt5_press != button_new.bits.bt5_press) && (ts->pdata->keycnt > 5)) { | ||
139 | if(button_new.bits.bt5_press) input_report_key(ts->input, ts->pdata->keycode[5], true); | ||
140 | else input_report_key(ts->input, ts->pdata->keycode[5], false); | ||
141 | #if defined(DEBUG_TOUCH_KEY) | ||
142 | printk("keycode[5](0x%04X) %s\n", ts->pdata->keycode[5], button_new.bits.bt5_press ? "press":"release"); | ||
143 | #endif | ||
144 | } | ||
145 | if((button_old.bits.bt6_press != button_new.bits.bt6_press) && (ts->pdata->keycnt > 6)) { | ||
146 | if(button_new.bits.bt6_press) input_report_key(ts->input, ts->pdata->keycode[6], true); | ||
147 | else input_report_key(ts->input, ts->pdata->keycode[6], false); | ||
148 | #if defined(DEBUG_TOUCH_KEY) | ||
149 | printk("keycode[6](0x%04X) %s\n", ts->pdata->keycode[6], button_new.bits.bt6_press ? "press":"release"); | ||
150 | #endif | ||
151 | } | ||
152 | if((button_old.bits.bt7_press != button_new.bits.bt7_press) && (ts->pdata->keycnt > 7)) { | ||
153 | if(button_new.bits.bt7_press) input_report_key(ts->input, ts->pdata->keycode[7], true); | ||
154 | else input_report_key(ts->input, ts->pdata->keycode[7], false); | ||
155 | #if defined(DEBUG_TOUCH_KEY) | ||
156 | printk("keycode[7](0x%04X) %s\n", ts->pdata->keycode[7], button_new.bits.bt7_press ? "press":"release"); | ||
157 | #endif | ||
158 | } | ||
159 | button_old.ubyte = button_new.ubyte; | ||
160 | } | ||
161 | } | ||
162 | |||
163 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
164 | static void touch_report_single (struct touch *ts) | ||
165 | { | ||
166 | if(ts->finger[0].event == TS_EVENT_UNKNOWN) return; | ||
167 | |||
168 | if(ts->finger[0].event != TS_EVENT_RELEASE) { | ||
169 | // for single touch | ||
170 | input_report_key(ts->input, BTN_TOUCH, 1); | ||
171 | input_report_abs(ts->input, ABS_X, ts->finger[0].x); | ||
172 | input_report_abs(ts->input, ABS_Y, ts->finger[0].y); | ||
173 | |||
174 | #if defined(DEBUG_TOUCH) | ||
175 | printk("%s : id = %d, x = %d, y = %d\n", __func__, ts->finger[0].id, ts->finger[0].x, ts->finger[0].y); | ||
176 | #endif | ||
177 | } | ||
178 | else { | ||
179 | // for single touch | ||
180 | input_report_key(ts->input, BTN_TOUCH, 0); | ||
181 | |||
182 | ts->finger[0].event = TS_EVENT_UNKNOWN; | ||
183 | |||
184 | #if defined(DEBUG_TOUCH) | ||
185 | printk("%s : release id = %d\n", __func__, ts->finger[0].id); | ||
186 | #endif | ||
187 | } | ||
188 | input_sync(ts->input); | ||
189 | } | ||
190 | |||
191 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
192 | static void touch_report_protocol_a (struct touch *ts) | ||
193 | { | ||
194 | int id; | ||
195 | |||
196 | for(id = 0; id < ts->pdata->max_fingers; id++) { | ||
197 | |||
198 | if(ts->finger[id].event == TS_EVENT_UNKNOWN) continue; | ||
199 | |||
200 | if(ts->finger[id].event != TS_EVENT_RELEASE) { | ||
201 | if(ts->pdata->id_max) input_report_abs(ts->input, ABS_MT_TRACKING_ID, ts->finger[id].id); | ||
202 | if(ts->pdata->area_max) input_report_abs(ts->input, ABS_MT_TOUCH_MAJOR, ts->finger[id].area ? ts->finger[id].area : 10); | ||
203 | if(ts->pdata->press_max) input_report_abs(ts->input, ABS_MT_PRESSURE, ts->finger[id].pressure); | ||
204 | |||
205 | input_report_abs(ts->input, ABS_MT_POSITION_X, ts->finger[id].x); | ||
206 | input_report_abs(ts->input, ABS_MT_POSITION_Y, ts->finger[id].y); | ||
207 | |||
208 | #if defined(DEBUG_TOUCH) | ||
209 | printk("%s : id = %d, x = %d, y = %d\n", __func__, ts->finger[id].id, ts->finger[id].x, ts->finger[id].y); | ||
210 | #endif | ||
211 | } | ||
212 | else { | ||
213 | ts->finger[id].event = TS_EVENT_UNKNOWN; | ||
214 | |||
215 | #if defined(DEBUG_TOUCH) | ||
216 | printk("%s : release id = %d\n", __func__, ts->finger[id].id); | ||
217 | #endif | ||
218 | } | ||
219 | |||
220 | input_mt_sync(ts->input); | ||
221 | } | ||
222 | |||
223 | input_sync(ts->input); | ||
224 | } | ||
225 | |||
226 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
227 | static void touch_report_protocol_b (struct touch *ts) | ||
228 | { | ||
229 | int id; | ||
230 | |||
231 | for(id = 0; id < ts->pdata->max_fingers; id++) { | ||
232 | |||
233 | if((ts->finger[id].event == TS_EVENT_UNKNOWN) || (ts->finger[id].status == false)) continue; | ||
234 | |||
235 | input_mt_slot(ts->input, id); ts->finger[id].status = false; | ||
236 | |||
237 | if(ts->finger[id].event != TS_EVENT_RELEASE) { | ||
238 | input_report_abs(ts->input, ABS_MT_TRACKING_ID, ts->finger[id].id); | ||
239 | input_report_abs(ts->input, ABS_MT_POSITION_X, ts->finger[id].x); | ||
240 | input_report_abs(ts->input, ABS_MT_POSITION_Y, ts->finger[id].y); | ||
241 | |||
242 | if(ts->pdata->area_max) input_report_abs(ts->input, ABS_MT_TOUCH_MAJOR, ts->finger[id].area ? ts->finger[id].area : 10); | ||
243 | if(ts->pdata->press_max) input_report_abs(ts->input, ABS_MT_PRESSURE, ts->finger[id].pressure); | ||
244 | |||
245 | #if defined(DEBUG_TOUCH) | ||
246 | printk("%s : slot = %d, id = %d, x = %d, y = %d\n", __func__, id, ts->finger[id].id, ts->finger[id].x, ts->finger[id].y); | ||
247 | #endif | ||
248 | } | ||
249 | else { | ||
250 | ts->finger[id].event = TS_EVENT_UNKNOWN; | ||
251 | input_report_abs(ts->input, ABS_MT_TRACKING_ID, -1); | ||
252 | |||
253 | #if defined(DEBUG_TOUCH) | ||
254 | printk("%s : release slot = %d, id = %d\n", __func__, id, ts->finger[id].id); | ||
255 | #endif | ||
256 | } | ||
257 | } | ||
258 | input_sync(ts->input); | ||
259 | } | ||
260 | |||
261 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
262 | static void touch_event_clear (struct touch *ts) | ||
263 | { | ||
264 | unsigned char id; | ||
265 | |||
266 | for(id = 0; id < ts->pdata->max_fingers; id++) { | ||
267 | if(ts->finger[id].event == TS_EVENT_MOVE) { | ||
268 | ts->finger[id].status = true; | ||
269 | ts->finger[id].event = TS_EVENT_RELEASE; | ||
270 | } | ||
271 | } | ||
272 | ts->pdata->report(ts); | ||
273 | if(ts->pdata->keycode) ts->pdata->key_report(ts, 0x00); | ||
274 | } | ||
275 | |||
276 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
277 | static void touch_enable (struct touch *ts) | ||
278 | { | ||
279 | if(ts->disabled) { | ||
280 | if(ts->irq) enable_irq(ts->irq); | ||
281 | ts->disabled = false; | ||
282 | } | ||
283 | } | ||
284 | |||
285 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
286 | static void touch_disable (struct touch *ts) | ||
287 | { | ||
288 | if(!ts->disabled) { | ||
289 | if(ts->irq) disable_irq(ts->irq); | ||
290 | ts->disabled = true; | ||
291 | } | ||
292 | } | ||
293 | |||
294 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
295 | static int touch_input_open (struct input_dev *input) | ||
296 | { | ||
297 | struct touch *ts = input_get_drvdata(input); | ||
298 | |||
299 | ts->pdata->enable(ts); | ||
300 | |||
301 | printk("%s\n", __func__); | ||
302 | |||
303 | return 0; | ||
304 | } | ||
305 | |||
306 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
307 | static void touch_input_close (struct input_dev *input) | ||
308 | { | ||
309 | struct touch *ts = input_get_drvdata(input); | ||
310 | |||
311 | ts->pdata->disable(ts); | ||
312 | |||
313 | printk("%s\n", __func__); | ||
314 | } | ||
315 | |||
316 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
317 | static int touch_check_functionality (struct touch_pdata *pdata) | ||
318 | { | ||
319 | if(!pdata) { | ||
320 | printk("Error : Platform data is NULL pointer!\n"); return -1; | ||
321 | } | ||
322 | |||
323 | if(!pdata->i2c_read) pdata->i2c_read = touch_i2c_read; | ||
324 | if(!pdata->i2c_write) pdata->i2c_write = touch_i2c_write; | ||
325 | |||
326 | if(!pdata->i2c_boot_read) pdata->i2c_boot_read = touch_i2c_read; | ||
327 | if(!pdata->i2c_boot_write) pdata->i2c_boot_write = touch_i2c_write; | ||
328 | |||
329 | if(!pdata->enable) pdata->enable = touch_enable; | ||
330 | if(!pdata->disable) pdata->disable = touch_disable; | ||
331 | |||
332 | if(!pdata->report) { | ||
333 | if(pdata->max_fingers == 1) pdata->report = touch_report_single; | ||
334 | else { | ||
335 | if(pdata->id_max) pdata->report = touch_report_protocol_b; | ||
336 | else pdata->report = touch_report_protocol_a; | ||
337 | } | ||
338 | } | ||
339 | |||
340 | if(!pdata->key_report) pdata->key_report = touch_key_report; | ||
341 | |||
342 | if(!pdata->touch_work) pdata->touch_work = touch_work; | ||
343 | if(!pdata->irq_func) pdata->irq_func = touch_irq; | ||
344 | |||
345 | if(!pdata->event_clear) pdata->event_clear = touch_event_clear; | ||
346 | |||
347 | #ifdef CONFIG_HAS_EARLYSUSPEND | ||
348 | if(!pdata->resume) pdata->resume = touch_resume; | ||
349 | if(!pdata->suspend) pdata->suspend = touch_suspend; | ||
350 | #endif | ||
351 | |||
352 | return 0; | ||
353 | } | ||
354 | |||
355 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
356 | void touch_hw_reset (struct touch *ts) | ||
357 | { | ||
358 | if(ts->pdata->reset_gpio) { | ||
359 | if(gpio_request(ts->pdata->reset_gpio, "touch reset")) { | ||
360 | printk("--------------------------------------------------------\n"); | ||
361 | printk("%s : request port error!\n", "touch reset"); | ||
362 | printk("--------------------------------------------------------\n"); | ||
363 | } | ||
364 | else { | ||
365 | gpio_direction_output(ts->pdata->reset_gpio, ts->pdata->reset_level ? 0 : 1); | ||
366 | mdelay(10); | ||
367 | |||
368 | gpio_direction_output(ts->pdata->reset_gpio, ts->pdata->reset_level ? 1 : 0); | ||
369 | mdelay(10); | ||
370 | |||
371 | gpio_direction_output(ts->pdata->reset_gpio, ts->pdata->reset_level ? 0 : 1); | ||
372 | mdelay(10); | ||
373 | |||
374 | gpio_free(ts->pdata->reset_gpio); | ||
375 | } | ||
376 | } | ||
377 | } | ||
378 | |||
379 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
380 | int touch_info_display (struct touch *ts) | ||
381 | { | ||
382 | printk("--------------------------------------------------------\n"); | ||
383 | printk(" TOUCH SCREEN INFORMATION\n"); | ||
384 | printk("--------------------------------------------------------\n"); | ||
385 | if(ts->pdata->irq_gpio && ts->pdata->max_fingers) { | ||
386 | printk("TOUCH INPUT Name = %s\n", ts->pdata->name); | ||
387 | |||
388 | switch(ts->pdata->irq_mode) { | ||
389 | default : | ||
390 | case IRQ_MODE_THREAD: printk("TOUCH IRQ Mode = %s\n", "IRQ_MODE_THREAD"); break; | ||
391 | case IRQ_MODE_NORMAL: printk("TOUCH IRQ Mode = %s\n", "IRQ_MODE_NORMAL"); break; | ||
392 | case IRQ_MODE_POLLING: printk("TOUCH IRQ Mode = %s\n", "IRQ_MODE_POLLING"); break; | ||
393 | } | ||
394 | printk("TOUCH F/W Version = %d.%02d\n", ts->fw_version / 100, ts->fw_version % 100); | ||
395 | |||
396 | printk("TOUCH FINGRES MAX = %d\n", ts->pdata->max_fingers); | ||
397 | printk("TOUCH ABS X MAX = %d, TOUCH ABS X MIN = %d\n", ts->pdata->abs_max_x, ts->pdata->abs_min_x); | ||
398 | printk("TOUCH ABS Y MAX = %d, TOUCH ABS Y MIN = %d\n", ts->pdata->abs_max_y, ts->pdata->abs_min_y); | ||
399 | |||
400 | if(ts->pdata->area_max) | ||
401 | printk("TOUCH MAJOR MAX = %d, TOUCH MAJOR MIN = %d\n", ts->pdata->area_max, ts->pdata->area_min); | ||
402 | |||
403 | if(ts->pdata->press_max) | ||
404 | printk("TOUCH PRESS MAX = %d, TOUCH PRESS MIN = %d\n", ts->pdata->press_max, ts->pdata->press_min); | ||
405 | |||
406 | if(ts->pdata->max_fingers == 1) { | ||
407 | printk("Single Touch Protocol Used.\n"); | ||
408 | } | ||
409 | else { | ||
410 | if(ts->pdata->id_max) { | ||
411 | printk("TOUCH ID MAX = %d, TOUCH ID MIN = %d\n", ts->pdata->id_max, ts->pdata->id_min); | ||
412 | printk("Mulit-Touch Protocol-B Used.\n"); | ||
413 | } | ||
414 | else | ||
415 | printk("Mulit-Touch Protocol-A Used.\n"); | ||
416 | } | ||
417 | |||
418 | if(ts->pdata->gpio_init) | ||
419 | printk("GPIO early-init function implemented\n"); | ||
420 | |||
421 | if(ts->pdata->reset_gpio) | ||
422 | printk("H/W Reset function implemented\n"); | ||
423 | |||
424 | #ifdef CONFIG_HAS_EARLYSUSPEND | ||
425 | printk("Early-suspend function implemented\n"); | ||
426 | #endif | ||
427 | if(ts->pdata->fw_control) | ||
428 | printk("Firmware update function(sysfs control) implemented\n"); | ||
429 | |||
430 | if(ts->pdata->flash_firmware) | ||
431 | printk("Firmware update function(udev control) implemented\n"); | ||
432 | |||
433 | if(ts->pdata->calibration) | ||
434 | printk("Calibration function implemented\n"); | ||
435 | } | ||
436 | else { | ||
437 | printk("TOUCH INPUT Name = %s\n", ts->pdata->name); | ||
438 | printk("Dummy Touchscreen driver!\n"); | ||
439 | } | ||
440 | |||
441 | printk("--------------------------------------------------------\n"); | ||
442 | |||
443 | return 0; | ||
444 | } | ||
445 | |||
446 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
447 | int touch_probe (struct i2c_client *client) | ||
448 | { | ||
449 | int rc = -1; | ||
450 | struct device *dev = &client->dev; | ||
451 | struct touch *ts; | ||
452 | |||
453 | if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { | ||
454 | dev_err(&client->dev, "i2c byte data not supported\n"); | ||
455 | return -EIO; | ||
456 | } | ||
457 | |||
458 | if (touch_check_functionality(client->dev.platform_data) < 0) { | ||
459 | dev_err(&client->dev, "Platform data is not available!\n"); | ||
460 | return -EINVAL; | ||
461 | } | ||
462 | |||
463 | if(!(ts = kzalloc(sizeof(struct touch), GFP_KERNEL))) { | ||
464 | printk("touch struct malloc error!\n"); return -ENOMEM; | ||
465 | } | ||
466 | ts->client = client; | ||
467 | ts->pdata = client->dev.platform_data; | ||
468 | |||
469 | if(ts->pdata->irq_gpio) ts->irq = gpio_to_irq(ts->pdata->irq_gpio); | ||
470 | |||
471 | i2c_set_clientdata(client, ts); | ||
472 | |||
473 | if(ts->pdata->max_fingers) { | ||
474 | if(!(ts->finger = kzalloc(sizeof(finger_t) * ts->pdata->max_fingers, GFP_KERNEL))) { | ||
475 | kfree(ts); | ||
476 | printk("touch data struct malloc error!\n"); return -ENOMEM; | ||
477 | } | ||
478 | } | ||
479 | |||
480 | if(ts->pdata->gpio_init) ts->pdata->gpio_init(); | ||
481 | if(ts->pdata->reset_gpio) touch_hw_reset(ts); | ||
482 | |||
483 | if(ts->pdata->early_probe) { | ||
484 | if((rc = ts->pdata->early_probe(ts)) < 0) goto err_free_mem; | ||
485 | } | ||
486 | |||
487 | dev_set_drvdata(dev, ts); | ||
488 | |||
489 | if(!(ts->input = input_allocate_device())) goto err_free_mem; | ||
490 | |||
491 | snprintf(ts->phys, sizeof(ts->phys), "%s/input0", ts->pdata->name); | ||
492 | |||
493 | if(!ts->pdata->input_open) ts->input->open = touch_input_open; | ||
494 | else ts->input->open = ts->pdata->input_open; | ||
495 | if(!ts->pdata->input_close) ts->input->close = touch_input_close; | ||
496 | else ts->input->close = ts->pdata->input_close; | ||
497 | |||
498 | ts->input->name = ts->pdata->name; | ||
499 | ts->input->phys = ts->phys; | ||
500 | ts->input->dev.parent = dev; | ||
501 | ts->input->id.bustype = BUS_I2C; | ||
502 | |||
503 | ts->input->id.vendor = ts->pdata->vendor; | ||
504 | ts->input->id.product = ts->pdata->product; | ||
505 | ts->input->id.version = ts->pdata->version; | ||
506 | |||
507 | set_bit(EV_SYN, ts->input->evbit); | ||
508 | set_bit(EV_ABS, ts->input->evbit); | ||
509 | |||
510 | // Touch Key Event | ||
511 | if(ts->pdata->keycode) { | ||
512 | int key; | ||
513 | |||
514 | set_bit(EV_KEY, ts->input->evbit); | ||
515 | |||
516 | for(key = 0; key < ts->pdata->keycnt; key++) { | ||
517 | if(ts->pdata->keycode[key] <= 0) continue; | ||
518 | set_bit(ts->pdata->keycode[key] & KEY_MAX, ts->input->keybit); | ||
519 | } | ||
520 | } | ||
521 | |||
522 | input_set_drvdata(ts->input, ts); | ||
523 | |||
524 | if(ts->pdata->max_fingers == 1) { | ||
525 | /* For single touch */ | ||
526 | set_bit(EV_KEY, ts->input->evbit); set_bit(BTN_TOUCH, ts->input->keybit); | ||
527 | input_set_abs_params(ts->input, ABS_X, ts->pdata->abs_min_x, ts->pdata->abs_max_x, 0, 0); | ||
528 | input_set_abs_params(ts->input, ABS_Y, ts->pdata->abs_min_y, ts->pdata->abs_max_y, 0, 0); | ||
529 | } | ||
530 | else { | ||
531 | /* multi touch */ | ||
532 | input_set_abs_params(ts->input, ABS_MT_POSITION_X, ts->pdata->abs_min_x, ts->pdata->abs_max_x, 0, 0); | ||
533 | input_set_abs_params(ts->input, ABS_MT_POSITION_Y, ts->pdata->abs_min_y, ts->pdata->abs_max_y, 0, 0); | ||
534 | |||
535 | if(ts->pdata->area_max) | ||
536 | input_set_abs_params(ts->input, ABS_MT_TOUCH_MAJOR, ts->pdata->area_min, ts->pdata->area_max, 0, 0); | ||
537 | |||
538 | if(ts->pdata->press_max) | ||
539 | input_set_abs_params(ts->input, ABS_MT_PRESSURE, ts->pdata->press_min, ts->pdata->press_max, 0, 0); | ||
540 | } | ||
541 | |||
542 | if(ts->pdata->id_max) { | ||
543 | input_set_abs_params(ts->input, ABS_MT_TRACKING_ID, ts->pdata->id_min, ts->pdata->id_max, 0, 0); | ||
544 | input_mt_init_slots(ts->input, ts->pdata->max_fingers); | ||
545 | } | ||
546 | |||
547 | if ((rc = input_register_device(ts->input))) { | ||
548 | dev_err(dev, "(%s) input register fail!\n", ts->input->name); | ||
549 | goto err_free_input_mem; | ||
550 | } | ||
551 | |||
552 | if(ts->irq) { | ||
553 | |||
554 | switch(ts->pdata->irq_mode) { | ||
555 | default : | ||
556 | case IRQ_MODE_THREAD: | ||
557 | if((rc = request_threaded_irq(ts->irq, NULL, ts->pdata->irq_func, ts->pdata->irq_flags, ts->pdata->name, ts))) { | ||
558 | dev_err(dev, "irq %d request fail!\n", ts->irq); | ||
559 | goto err_free_input_mem; | ||
560 | } | ||
561 | break; | ||
562 | case IRQ_MODE_NORMAL: | ||
563 | INIT_WORK(&ts->work, touch_work_q); | ||
564 | if((ts->work_queue = create_singlethread_workqueue("work_queue")) == NULL) goto err_free_input_mem; | ||
565 | |||
566 | if((rc = request_irq(ts->irq, ts->pdata->irq_func, ts->pdata->irq_flags, ts->pdata->name, ts))) { | ||
567 | printk("irq %d request fail!\n", ts->irq); | ||
568 | goto err_free_input_mem; | ||
569 | } | ||
570 | break; | ||
571 | case IRQ_MODE_POLLING: | ||
572 | printk("Error IRQ_MODE POLLING!! but defined irq_gpio\n"); | ||
573 | break; | ||
574 | } | ||
575 | |||
576 | disable_irq_nosync(ts->irq); | ||
577 | } | ||
578 | |||
579 | ts->disabled = true; | ||
580 | |||
581 | #if defined(CONFIG_HAS_EARLYSUSPEND) | ||
582 | if(ts->pdata->suspend) ts->power.suspend = ts->pdata->suspend; | ||
583 | if(ts->pdata->resume) ts->power.resume = ts->pdata->resume; | ||
584 | |||
585 | ts->power.level = EARLY_SUSPEND_LEVEL_DISABLE_FB-1; | ||
586 | |||
587 | //if, is in USER_SLEEP status and no active auto expiring wake lock | ||
588 | //if (has_wake_lock(WAKE_LOCK_SUSPEND) == 0 && get_suspend_state() == PM_SUSPEND_ON) | ||
589 | register_early_suspend(&ts->power); | ||
590 | #endif | ||
591 | |||
592 | if((rc = touch_sysfs_create(dev)) < 0) goto err_free_irq; | ||
593 | |||
594 | if(ts->pdata->probe) { | ||
595 | if((rc = ts->pdata->probe(ts)) < 0) goto err_free_all; | ||
596 | } | ||
597 | |||
598 | touch_info_display(ts); | ||
599 | |||
600 | return 0; | ||
601 | |||
602 | err_free_all: | ||
603 | touch_sysfs_remove(dev); | ||
604 | err_free_irq: | ||
605 | free_irq(ts->irq, ts); | ||
606 | input_unregister_device(ts->input); | ||
607 | err_free_input_mem: | ||
608 | input_free_device(ts->input); | ||
609 | ts->input = NULL; | ||
610 | err_free_mem: | ||
611 | kfree(ts->finger); ts->finger = NULL; | ||
612 | kfree(ts); ts = NULL; | ||
613 | return rc; | ||
614 | } | ||
615 | |||
616 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
617 | // | ||
618 | // Power Management function | ||
619 | // | ||
620 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
621 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
622 | #ifdef CONFIG_HAS_EARLYSUSPEND | ||
623 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
624 | static void touch_suspend (struct early_suspend *h) | ||
625 | { | ||
626 | struct touch *ts = container_of(h, struct touch, power); | ||
627 | |||
628 | printk("%s\n", __func__); | ||
629 | |||
630 | ts->pdata->disable(ts); | ||
631 | } | ||
632 | |||
633 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
634 | static void touch_resume (struct early_suspend *h) | ||
635 | { | ||
636 | struct touch *ts = container_of(h, struct touch, power); | ||
637 | |||
638 | printk("%s\n", __func__); | ||
639 | |||
640 | ts->pdata->enable(ts); | ||
641 | } | ||
642 | |||
643 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
644 | #endif | ||
645 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
646 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
647 | int touch_remove (struct device *dev) | ||
648 | { | ||
649 | struct touch *ts = dev_get_drvdata(dev); | ||
650 | |||
651 | if(ts->irq) free_irq(ts->irq, ts); | ||
652 | |||
653 | if(ts->pdata->reset_gpio) gpio_free(ts->pdata->reset_gpio); | ||
654 | |||
655 | touch_sysfs_remove(dev); | ||
656 | |||
657 | input_unregister_device(ts->input); | ||
658 | |||
659 | dev_set_drvdata(dev, NULL); | ||
660 | |||
661 | kfree(ts); | ||
662 | |||
663 | return 0; | ||
664 | } | ||
665 | |||
666 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
667 | MODULE_AUTHOR("HardKernel Co., Ltd."); | ||
668 | MODULE_LICENSE("GPL"); | ||
669 | MODULE_DESCRIPTION("Touchscreen Driver"); | ||
670 | |||
671 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
672 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
diff --git a/drivers/input/touchscreen/touch.h b/drivers/input/touchscreen/touch.h new file mode 100644 index 00000000000..691d6098ab9 --- /dev/null +++ b/drivers/input/touchscreen/touch.h | |||
@@ -0,0 +1,25 @@ | |||
1 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
2 | // | ||
3 | // | ||
4 | // | ||
5 | // I2C Touchscreen driver | ||
6 | // 2012.01.17 | ||
7 | // | ||
8 | // | ||
9 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
10 | #ifndef _TOUCH_H_ | ||
11 | #define _TOUCH_H_ | ||
12 | |||
13 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
14 | // extern function define | ||
15 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
16 | extern void touch_hw_reset (struct touch *ts); | ||
17 | extern int touch_info_display (struct touch *ts); | ||
18 | extern int touch_probe (struct i2c_client *client); | ||
19 | extern int touch_remove (struct device *dev); | ||
20 | |||
21 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
22 | #endif /* _TOUCH_H_ */ | ||
23 | |||
24 | //[*]--------------------------------------------------------------------------------------------------[*] | ||
25 | //[*]--------------------------------------------------------------------------------------------------[*] | ||