diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-08-04 13:41:52 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-08-04 13:41:52 -0400 |
commit | fe445c6e2cb62a566e1a89f8798de11459975710 (patch) | |
tree | db1f2c0c19f488992fb5b9371476b4e7701c49a0 /drivers/input/keyboard | |
parent | f63b759c44b0561c76a67894c734157df3313b42 (diff) | |
parent | d01d0756f75e7a5b4b43764ad45b83c4340f11d6 (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input: (57 commits)
Input: adp5588-keypad - fix NULL dereference in adp5588_gpio_add()
Input: cy8ctmg110 - capacitive touchscreen support
Input: keyboard - also match braille-only keyboards
Input: adp5588-keys - export unused GPIO pins
Input: xpad - add product ID for Hori Fighting Stick EX2
Input: adxl34x - fix leak and use after free
Input: samsung-keypad - Add samsung keypad driver
Input: i8042 - reset keyboard controller wehen resuming from S2R
Input: synaptics - set min/max for finger width
Input: synaptics - only report width on hardware that supports it
Input: evdev - signal that device is writable in evdev_poll()
Input: mousedev - signal that device is writable in mousedev_poll()
Input: change input handlers to use bool when possible
Input: document the MT event slot protocol
Input: introduce MT event slots
Input: usbtouchscreen - implement reset_resume
Input: usbtouchscreen - implement runtime power management
Input: usbtouchscreen - implement basic suspend/resume
Input: Add ATMEL QT602240 touchscreen driver
Input: fix signedness warning in input_set_keycode()
...
Diffstat (limited to 'drivers/input/keyboard')
-rw-r--r-- | drivers/input/keyboard/Kconfig | 21 | ||||
-rw-r--r-- | drivers/input/keyboard/Makefile | 2 | ||||
-rw-r--r-- | drivers/input/keyboard/adp5588-keys.c | 351 | ||||
-rw-r--r-- | drivers/input/keyboard/gpio_keys.c | 19 | ||||
-rw-r--r-- | drivers/input/keyboard/lm8323.c | 12 | ||||
-rw-r--r-- | drivers/input/keyboard/matrix_keypad.c | 108 | ||||
-rw-r--r-- | drivers/input/keyboard/mcs_touchkey.c | 239 | ||||
-rw-r--r-- | drivers/input/keyboard/samsung-keypad.c | 491 |
8 files changed, 1196 insertions, 47 deletions
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index 1ba25145b333..b171f63fe4d7 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig | |||
@@ -297,6 +297,18 @@ config KEYBOARD_MAX7359 | |||
297 | To compile this driver as a module, choose M here: the | 297 | To compile this driver as a module, choose M here: the |
298 | module will be called max7359_keypad. | 298 | module will be called max7359_keypad. |
299 | 299 | ||
300 | config KEYBOARD_MCS | ||
301 | tristate "MELFAS MCS Touchkey" | ||
302 | depends on I2C | ||
303 | help | ||
304 | Say Y here if you have the MELFAS MCS5000/5080 touchkey controller | ||
305 | chip in your system. | ||
306 | |||
307 | If unsure, say N. | ||
308 | |||
309 | To compile this driver as a module, choose M here: the | ||
310 | module will be called mcs_touchkey. | ||
311 | |||
300 | config KEYBOARD_IMX | 312 | config KEYBOARD_IMX |
301 | tristate "IMX keypad support" | 313 | tristate "IMX keypad support" |
302 | depends on ARCH_MXC | 314 | depends on ARCH_MXC |
@@ -342,6 +354,15 @@ config KEYBOARD_PXA930_ROTARY | |||
342 | To compile this driver as a module, choose M here: the | 354 | To compile this driver as a module, choose M here: the |
343 | module will be called pxa930_rotary. | 355 | module will be called pxa930_rotary. |
344 | 356 | ||
357 | config KEYBOARD_SAMSUNG | ||
358 | tristate "Samsung keypad support" | ||
359 | depends on SAMSUNG_DEV_KEYPAD | ||
360 | help | ||
361 | Say Y here if you want to use the Samsung keypad. | ||
362 | |||
363 | To compile this driver as a module, choose M here: the | ||
364 | module will be called samsung-keypad. | ||
365 | |||
345 | config KEYBOARD_STOWAWAY | 366 | config KEYBOARD_STOWAWAY |
346 | tristate "Stowaway keyboard" | 367 | tristate "Stowaway keyboard" |
347 | select SERIO | 368 | select SERIO |
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile index 4596d0c6f922..1a66d5f1ca8b 100644 --- a/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile | |||
@@ -26,12 +26,14 @@ obj-$(CONFIG_KEYBOARD_LOCOMO) += locomokbd.o | |||
26 | obj-$(CONFIG_KEYBOARD_MAPLE) += maple_keyb.o | 26 | obj-$(CONFIG_KEYBOARD_MAPLE) += maple_keyb.o |
27 | obj-$(CONFIG_KEYBOARD_MATRIX) += matrix_keypad.o | 27 | obj-$(CONFIG_KEYBOARD_MATRIX) += matrix_keypad.o |
28 | obj-$(CONFIG_KEYBOARD_MAX7359) += max7359_keypad.o | 28 | obj-$(CONFIG_KEYBOARD_MAX7359) += max7359_keypad.o |
29 | obj-$(CONFIG_KEYBOARD_MCS) += mcs_touchkey.o | ||
29 | obj-$(CONFIG_KEYBOARD_NEWTON) += newtonkbd.o | 30 | obj-$(CONFIG_KEYBOARD_NEWTON) += newtonkbd.o |
30 | obj-$(CONFIG_KEYBOARD_OMAP) += omap-keypad.o | 31 | obj-$(CONFIG_KEYBOARD_OMAP) += omap-keypad.o |
31 | obj-$(CONFIG_KEYBOARD_OPENCORES) += opencores-kbd.o | 32 | obj-$(CONFIG_KEYBOARD_OPENCORES) += opencores-kbd.o |
32 | obj-$(CONFIG_KEYBOARD_PXA27x) += pxa27x_keypad.o | 33 | obj-$(CONFIG_KEYBOARD_PXA27x) += pxa27x_keypad.o |
33 | obj-$(CONFIG_KEYBOARD_PXA930_ROTARY) += pxa930_rotary.o | 34 | obj-$(CONFIG_KEYBOARD_PXA930_ROTARY) += pxa930_rotary.o |
34 | obj-$(CONFIG_KEYBOARD_QT2160) += qt2160.o | 35 | obj-$(CONFIG_KEYBOARD_QT2160) += qt2160.o |
36 | obj-$(CONFIG_KEYBOARD_SAMSUNG) += samsung-keypad.o | ||
35 | obj-$(CONFIG_KEYBOARD_SH_KEYSC) += sh_keysc.o | 37 | obj-$(CONFIG_KEYBOARD_SH_KEYSC) += sh_keysc.o |
36 | obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o | 38 | obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o |
37 | obj-$(CONFIG_KEYBOARD_SUNKBD) += sunkbd.o | 39 | obj-$(CONFIG_KEYBOARD_SUNKBD) += sunkbd.o |
diff --git a/drivers/input/keyboard/adp5588-keys.c b/drivers/input/keyboard/adp5588-keys.c index 744600eff222..d6918cb966c0 100644 --- a/drivers/input/keyboard/adp5588-keys.c +++ b/drivers/input/keyboard/adp5588-keys.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/platform_device.h> | 19 | #include <linux/platform_device.h> |
20 | #include <linux/input.h> | 20 | #include <linux/input.h> |
21 | #include <linux/i2c.h> | 21 | #include <linux/i2c.h> |
22 | #include <linux/gpio.h> | ||
22 | #include <linux/slab.h> | 23 | #include <linux/slab.h> |
23 | 24 | ||
24 | #include <linux/i2c/adp5588.h> | 25 | #include <linux/i2c/adp5588.h> |
@@ -54,6 +55,10 @@ | |||
54 | 55 | ||
55 | #define KEYP_MAX_EVENT 10 | 56 | #define KEYP_MAX_EVENT 10 |
56 | 57 | ||
58 | #define MAXGPIO 18 | ||
59 | #define ADP_BANK(offs) ((offs) >> 3) | ||
60 | #define ADP_BIT(offs) (1u << ((offs) & 0x7)) | ||
61 | |||
57 | /* | 62 | /* |
58 | * Early pre 4.0 Silicon required to delay readout by at least 25ms, | 63 | * Early pre 4.0 Silicon required to delay readout by at least 25ms, |
59 | * since the Event Counter Register updated 25ms after the interrupt | 64 | * since the Event Counter Register updated 25ms after the interrupt |
@@ -67,6 +72,16 @@ struct adp5588_kpad { | |||
67 | struct delayed_work work; | 72 | struct delayed_work work; |
68 | unsigned long delay; | 73 | unsigned long delay; |
69 | unsigned short keycode[ADP5588_KEYMAPSIZE]; | 74 | unsigned short keycode[ADP5588_KEYMAPSIZE]; |
75 | const struct adp5588_gpi_map *gpimap; | ||
76 | unsigned short gpimapsize; | ||
77 | #ifdef CONFIG_GPIOLIB | ||
78 | unsigned char gpiomap[MAXGPIO]; | ||
79 | bool export_gpio; | ||
80 | struct gpio_chip gc; | ||
81 | struct mutex gpio_lock; /* Protect cached dir, dat_out */ | ||
82 | u8 dat_out[3]; | ||
83 | u8 dir[3]; | ||
84 | #endif | ||
70 | }; | 85 | }; |
71 | 86 | ||
72 | static int adp5588_read(struct i2c_client *client, u8 reg) | 87 | static int adp5588_read(struct i2c_client *client, u8 reg) |
@@ -84,12 +99,222 @@ static int adp5588_write(struct i2c_client *client, u8 reg, u8 val) | |||
84 | return i2c_smbus_write_byte_data(client, reg, val); | 99 | return i2c_smbus_write_byte_data(client, reg, val); |
85 | } | 100 | } |
86 | 101 | ||
102 | #ifdef CONFIG_GPIOLIB | ||
103 | static int adp5588_gpio_get_value(struct gpio_chip *chip, unsigned off) | ||
104 | { | ||
105 | struct adp5588_kpad *kpad = container_of(chip, struct adp5588_kpad, gc); | ||
106 | unsigned int bank = ADP_BANK(kpad->gpiomap[off]); | ||
107 | unsigned int bit = ADP_BIT(kpad->gpiomap[off]); | ||
108 | |||
109 | return !!(adp5588_read(kpad->client, GPIO_DAT_STAT1 + bank) & bit); | ||
110 | } | ||
111 | |||
112 | static void adp5588_gpio_set_value(struct gpio_chip *chip, | ||
113 | unsigned off, int val) | ||
114 | { | ||
115 | struct adp5588_kpad *kpad = container_of(chip, struct adp5588_kpad, gc); | ||
116 | unsigned int bank = ADP_BANK(kpad->gpiomap[off]); | ||
117 | unsigned int bit = ADP_BIT(kpad->gpiomap[off]); | ||
118 | |||
119 | mutex_lock(&kpad->gpio_lock); | ||
120 | |||
121 | if (val) | ||
122 | kpad->dat_out[bank] |= bit; | ||
123 | else | ||
124 | kpad->dat_out[bank] &= ~bit; | ||
125 | |||
126 | adp5588_write(kpad->client, GPIO_DAT_OUT1 + bank, | ||
127 | kpad->dat_out[bank]); | ||
128 | |||
129 | mutex_unlock(&kpad->gpio_lock); | ||
130 | } | ||
131 | |||
132 | static int adp5588_gpio_direction_input(struct gpio_chip *chip, unsigned off) | ||
133 | { | ||
134 | struct adp5588_kpad *kpad = container_of(chip, struct adp5588_kpad, gc); | ||
135 | unsigned int bank = ADP_BANK(kpad->gpiomap[off]); | ||
136 | unsigned int bit = ADP_BIT(kpad->gpiomap[off]); | ||
137 | int ret; | ||
138 | |||
139 | mutex_lock(&kpad->gpio_lock); | ||
140 | |||
141 | kpad->dir[bank] &= ~bit; | ||
142 | ret = adp5588_write(kpad->client, GPIO_DIR1 + bank, kpad->dir[bank]); | ||
143 | |||
144 | mutex_unlock(&kpad->gpio_lock); | ||
145 | |||
146 | return ret; | ||
147 | } | ||
148 | |||
149 | static int adp5588_gpio_direction_output(struct gpio_chip *chip, | ||
150 | unsigned off, int val) | ||
151 | { | ||
152 | struct adp5588_kpad *kpad = container_of(chip, struct adp5588_kpad, gc); | ||
153 | unsigned int bank = ADP_BANK(kpad->gpiomap[off]); | ||
154 | unsigned int bit = ADP_BIT(kpad->gpiomap[off]); | ||
155 | int ret; | ||
156 | |||
157 | mutex_lock(&kpad->gpio_lock); | ||
158 | |||
159 | kpad->dir[bank] |= bit; | ||
160 | |||
161 | if (val) | ||
162 | kpad->dat_out[bank] |= bit; | ||
163 | else | ||
164 | kpad->dat_out[bank] &= ~bit; | ||
165 | |||
166 | ret = adp5588_write(kpad->client, GPIO_DAT_OUT1 + bank, | ||
167 | kpad->dat_out[bank]); | ||
168 | ret |= adp5588_write(kpad->client, GPIO_DIR1 + bank, | ||
169 | kpad->dir[bank]); | ||
170 | |||
171 | mutex_unlock(&kpad->gpio_lock); | ||
172 | |||
173 | return ret; | ||
174 | } | ||
175 | |||
176 | static int __devinit adp5588_build_gpiomap(struct adp5588_kpad *kpad, | ||
177 | const struct adp5588_kpad_platform_data *pdata) | ||
178 | { | ||
179 | bool pin_used[MAXGPIO]; | ||
180 | int n_unused = 0; | ||
181 | int i; | ||
182 | |||
183 | memset(pin_used, 0, sizeof(pin_used)); | ||
184 | |||
185 | for (i = 0; i < pdata->rows; i++) | ||
186 | pin_used[i] = true; | ||
187 | |||
188 | for (i = 0; i < pdata->cols; i++) | ||
189 | pin_used[i + GPI_PIN_COL_BASE - GPI_PIN_BASE] = true; | ||
190 | |||
191 | for (i = 0; i < kpad->gpimapsize; i++) | ||
192 | pin_used[kpad->gpimap[i].pin - GPI_PIN_BASE] = true; | ||
193 | |||
194 | for (i = 0; i < MAXGPIO; i++) | ||
195 | if (!pin_used[i]) | ||
196 | kpad->gpiomap[n_unused++] = i; | ||
197 | |||
198 | return n_unused; | ||
199 | } | ||
200 | |||
201 | static int __devinit adp5588_gpio_add(struct adp5588_kpad *kpad) | ||
202 | { | ||
203 | struct device *dev = &kpad->client->dev; | ||
204 | const struct adp5588_kpad_platform_data *pdata = dev->platform_data; | ||
205 | const struct adp5588_gpio_platform_data *gpio_data = pdata->gpio_data; | ||
206 | int i, error; | ||
207 | |||
208 | if (!gpio_data) | ||
209 | return 0; | ||
210 | |||
211 | kpad->gc.ngpio = adp5588_build_gpiomap(kpad, pdata); | ||
212 | if (kpad->gc.ngpio == 0) { | ||
213 | dev_info(dev, "No unused gpios left to export\n"); | ||
214 | return 0; | ||
215 | } | ||
216 | |||
217 | kpad->export_gpio = true; | ||
218 | |||
219 | kpad->gc.direction_input = adp5588_gpio_direction_input; | ||
220 | kpad->gc.direction_output = adp5588_gpio_direction_output; | ||
221 | kpad->gc.get = adp5588_gpio_get_value; | ||
222 | kpad->gc.set = adp5588_gpio_set_value; | ||
223 | kpad->gc.can_sleep = 1; | ||
224 | |||
225 | kpad->gc.base = gpio_data->gpio_start; | ||
226 | kpad->gc.label = kpad->client->name; | ||
227 | kpad->gc.owner = THIS_MODULE; | ||
228 | |||
229 | mutex_init(&kpad->gpio_lock); | ||
230 | |||
231 | error = gpiochip_add(&kpad->gc); | ||
232 | if (error) { | ||
233 | dev_err(dev, "gpiochip_add failed, err: %d\n", error); | ||
234 | return error; | ||
235 | } | ||
236 | |||
237 | for (i = 0; i <= ADP_BANK(MAXGPIO); i++) { | ||
238 | kpad->dat_out[i] = adp5588_read(kpad->client, | ||
239 | GPIO_DAT_OUT1 + i); | ||
240 | kpad->dir[i] = adp5588_read(kpad->client, GPIO_DIR1 + i); | ||
241 | } | ||
242 | |||
243 | if (gpio_data->setup) { | ||
244 | error = gpio_data->setup(kpad->client, | ||
245 | kpad->gc.base, kpad->gc.ngpio, | ||
246 | gpio_data->context); | ||
247 | if (error) | ||
248 | dev_warn(dev, "setup failed, %d\n", error); | ||
249 | } | ||
250 | |||
251 | return 0; | ||
252 | } | ||
253 | |||
254 | static void __devexit adp5588_gpio_remove(struct adp5588_kpad *kpad) | ||
255 | { | ||
256 | struct device *dev = &kpad->client->dev; | ||
257 | const struct adp5588_kpad_platform_data *pdata = dev->platform_data; | ||
258 | const struct adp5588_gpio_platform_data *gpio_data = pdata->gpio_data; | ||
259 | int error; | ||
260 | |||
261 | if (!kpad->export_gpio) | ||
262 | return; | ||
263 | |||
264 | if (gpio_data->teardown) { | ||
265 | error = gpio_data->teardown(kpad->client, | ||
266 | kpad->gc.base, kpad->gc.ngpio, | ||
267 | gpio_data->context); | ||
268 | if (error) | ||
269 | dev_warn(dev, "teardown failed %d\n", error); | ||
270 | } | ||
271 | |||
272 | error = gpiochip_remove(&kpad->gc); | ||
273 | if (error) | ||
274 | dev_warn(dev, "gpiochip_remove failed %d\n", error); | ||
275 | } | ||
276 | #else | ||
277 | static inline int adp5588_gpio_add(struct adp5588_kpad *kpad) | ||
278 | { | ||
279 | return 0; | ||
280 | } | ||
281 | |||
282 | static inline void adp5588_gpio_remove(struct adp5588_kpad *kpad) | ||
283 | { | ||
284 | } | ||
285 | #endif | ||
286 | |||
287 | static void adp5588_report_events(struct adp5588_kpad *kpad, int ev_cnt) | ||
288 | { | ||
289 | int i, j; | ||
290 | |||
291 | for (i = 0; i < ev_cnt; i++) { | ||
292 | int key = adp5588_read(kpad->client, Key_EVENTA + i); | ||
293 | int key_val = key & KEY_EV_MASK; | ||
294 | |||
295 | if (key_val >= GPI_PIN_BASE && key_val <= GPI_PIN_END) { | ||
296 | for (j = 0; j < kpad->gpimapsize; j++) { | ||
297 | if (key_val == kpad->gpimap[j].pin) { | ||
298 | input_report_switch(kpad->input, | ||
299 | kpad->gpimap[j].sw_evt, | ||
300 | key & KEY_EV_PRESSED); | ||
301 | break; | ||
302 | } | ||
303 | } | ||
304 | } else { | ||
305 | input_report_key(kpad->input, | ||
306 | kpad->keycode[key_val - 1], | ||
307 | key & KEY_EV_PRESSED); | ||
308 | } | ||
309 | } | ||
310 | } | ||
311 | |||
87 | static void adp5588_work(struct work_struct *work) | 312 | static void adp5588_work(struct work_struct *work) |
88 | { | 313 | { |
89 | struct adp5588_kpad *kpad = container_of(work, | 314 | struct adp5588_kpad *kpad = container_of(work, |
90 | struct adp5588_kpad, work.work); | 315 | struct adp5588_kpad, work.work); |
91 | struct i2c_client *client = kpad->client; | 316 | struct i2c_client *client = kpad->client; |
92 | int i, key, status, ev_cnt; | 317 | int status, ev_cnt; |
93 | 318 | ||
94 | status = adp5588_read(client, INT_STAT); | 319 | status = adp5588_read(client, INT_STAT); |
95 | 320 | ||
@@ -99,12 +324,7 @@ static void adp5588_work(struct work_struct *work) | |||
99 | if (status & KE_INT) { | 324 | if (status & KE_INT) { |
100 | ev_cnt = adp5588_read(client, KEY_LCK_EC_STAT) & KEC; | 325 | ev_cnt = adp5588_read(client, KEY_LCK_EC_STAT) & KEC; |
101 | if (ev_cnt) { | 326 | if (ev_cnt) { |
102 | for (i = 0; i < ev_cnt; i++) { | 327 | adp5588_report_events(kpad, ev_cnt); |
103 | key = adp5588_read(client, Key_EVENTA + i); | ||
104 | input_report_key(kpad->input, | ||
105 | kpad->keycode[(key & KEY_EV_MASK) - 1], | ||
106 | key & KEY_EV_PRESSED); | ||
107 | } | ||
108 | input_sync(kpad->input); | 328 | input_sync(kpad->input); |
109 | } | 329 | } |
110 | } | 330 | } |
@@ -128,8 +348,10 @@ static irqreturn_t adp5588_irq(int irq, void *handle) | |||
128 | 348 | ||
129 | static int __devinit adp5588_setup(struct i2c_client *client) | 349 | static int __devinit adp5588_setup(struct i2c_client *client) |
130 | { | 350 | { |
131 | struct adp5588_kpad_platform_data *pdata = client->dev.platform_data; | 351 | const struct adp5588_kpad_platform_data *pdata = client->dev.platform_data; |
352 | const struct adp5588_gpio_platform_data *gpio_data = pdata->gpio_data; | ||
132 | int i, ret; | 353 | int i, ret; |
354 | unsigned char evt_mode1 = 0, evt_mode2 = 0, evt_mode3 = 0; | ||
133 | 355 | ||
134 | ret = adp5588_write(client, KP_GPIO1, KP_SEL(pdata->rows)); | 356 | ret = adp5588_write(client, KP_GPIO1, KP_SEL(pdata->rows)); |
135 | ret |= adp5588_write(client, KP_GPIO2, KP_SEL(pdata->cols) & 0xFF); | 357 | ret |= adp5588_write(client, KP_GPIO2, KP_SEL(pdata->cols) & 0xFF); |
@@ -144,6 +366,32 @@ static int __devinit adp5588_setup(struct i2c_client *client) | |||
144 | for (i = 0; i < KEYP_MAX_EVENT; i++) | 366 | for (i = 0; i < KEYP_MAX_EVENT; i++) |
145 | ret |= adp5588_read(client, Key_EVENTA); | 367 | ret |= adp5588_read(client, Key_EVENTA); |
146 | 368 | ||
369 | for (i = 0; i < pdata->gpimapsize; i++) { | ||
370 | unsigned short pin = pdata->gpimap[i].pin; | ||
371 | |||
372 | if (pin <= GPI_PIN_ROW_END) { | ||
373 | evt_mode1 |= (1 << (pin - GPI_PIN_ROW_BASE)); | ||
374 | } else { | ||
375 | evt_mode2 |= ((1 << (pin - GPI_PIN_COL_BASE)) & 0xFF); | ||
376 | evt_mode3 |= ((1 << (pin - GPI_PIN_COL_BASE)) >> 8); | ||
377 | } | ||
378 | } | ||
379 | |||
380 | if (pdata->gpimapsize) { | ||
381 | ret |= adp5588_write(client, GPI_EM1, evt_mode1); | ||
382 | ret |= adp5588_write(client, GPI_EM2, evt_mode2); | ||
383 | ret |= adp5588_write(client, GPI_EM3, evt_mode3); | ||
384 | } | ||
385 | |||
386 | if (gpio_data) { | ||
387 | for (i = 0; i <= ADP_BANK(MAXGPIO); i++) { | ||
388 | int pull_mask = gpio_data->pullup_dis_mask; | ||
389 | |||
390 | ret |= adp5588_write(client, GPIO_PULL1 + i, | ||
391 | (pull_mask >> (8 * i)) & 0xFF); | ||
392 | } | ||
393 | } | ||
394 | |||
147 | ret |= adp5588_write(client, INT_STAT, CMP2_INT | CMP1_INT | | 395 | ret |= adp5588_write(client, INT_STAT, CMP2_INT | CMP1_INT | |
148 | OVR_FLOW_INT | K_LCK_INT | | 396 | OVR_FLOW_INT | K_LCK_INT | |
149 | GPI_INT | KE_INT); /* Status is W1C */ | 397 | GPI_INT | KE_INT); /* Status is W1C */ |
@@ -158,11 +406,49 @@ static int __devinit adp5588_setup(struct i2c_client *client) | |||
158 | return 0; | 406 | return 0; |
159 | } | 407 | } |
160 | 408 | ||
409 | static void __devinit adp5588_report_switch_state(struct adp5588_kpad *kpad) | ||
410 | { | ||
411 | int gpi_stat1 = adp5588_read(kpad->client, GPIO_DAT_STAT1); | ||
412 | int gpi_stat2 = adp5588_read(kpad->client, GPIO_DAT_STAT2); | ||
413 | int gpi_stat3 = adp5588_read(kpad->client, GPIO_DAT_STAT3); | ||
414 | int gpi_stat_tmp, pin_loc; | ||
415 | int i; | ||
416 | |||
417 | for (i = 0; i < kpad->gpimapsize; i++) { | ||
418 | unsigned short pin = kpad->gpimap[i].pin; | ||
419 | |||
420 | if (pin <= GPI_PIN_ROW_END) { | ||
421 | gpi_stat_tmp = gpi_stat1; | ||
422 | pin_loc = pin - GPI_PIN_ROW_BASE; | ||
423 | } else if ((pin - GPI_PIN_COL_BASE) < 8) { | ||
424 | gpi_stat_tmp = gpi_stat2; | ||
425 | pin_loc = pin - GPI_PIN_COL_BASE; | ||
426 | } else { | ||
427 | gpi_stat_tmp = gpi_stat3; | ||
428 | pin_loc = pin - GPI_PIN_COL_BASE - 8; | ||
429 | } | ||
430 | |||
431 | if (gpi_stat_tmp < 0) { | ||
432 | dev_err(&kpad->client->dev, | ||
433 | "Can't read GPIO_DAT_STAT switch %d default to OFF\n", | ||
434 | pin); | ||
435 | gpi_stat_tmp = 0; | ||
436 | } | ||
437 | |||
438 | input_report_switch(kpad->input, | ||
439 | kpad->gpimap[i].sw_evt, | ||
440 | !(gpi_stat_tmp & (1 << pin_loc))); | ||
441 | } | ||
442 | |||
443 | input_sync(kpad->input); | ||
444 | } | ||
445 | |||
446 | |||
161 | static int __devinit adp5588_probe(struct i2c_client *client, | 447 | static int __devinit adp5588_probe(struct i2c_client *client, |
162 | const struct i2c_device_id *id) | 448 | const struct i2c_device_id *id) |
163 | { | 449 | { |
164 | struct adp5588_kpad *kpad; | 450 | struct adp5588_kpad *kpad; |
165 | struct adp5588_kpad_platform_data *pdata = client->dev.platform_data; | 451 | const struct adp5588_kpad_platform_data *pdata = client->dev.platform_data; |
166 | struct input_dev *input; | 452 | struct input_dev *input; |
167 | unsigned int revid; | 453 | unsigned int revid; |
168 | int ret, i; | 454 | int ret, i; |
@@ -189,6 +475,37 @@ static int __devinit adp5588_probe(struct i2c_client *client, | |||
189 | return -EINVAL; | 475 | return -EINVAL; |
190 | } | 476 | } |
191 | 477 | ||
478 | if (!pdata->gpimap && pdata->gpimapsize) { | ||
479 | dev_err(&client->dev, "invalid gpimap from pdata\n"); | ||
480 | return -EINVAL; | ||
481 | } | ||
482 | |||
483 | if (pdata->gpimapsize > ADP5588_GPIMAPSIZE_MAX) { | ||
484 | dev_err(&client->dev, "invalid gpimapsize\n"); | ||
485 | return -EINVAL; | ||
486 | } | ||
487 | |||
488 | for (i = 0; i < pdata->gpimapsize; i++) { | ||
489 | unsigned short pin = pdata->gpimap[i].pin; | ||
490 | |||
491 | if (pin < GPI_PIN_BASE || pin > GPI_PIN_END) { | ||
492 | dev_err(&client->dev, "invalid gpi pin data\n"); | ||
493 | return -EINVAL; | ||
494 | } | ||
495 | |||
496 | if (pin <= GPI_PIN_ROW_END) { | ||
497 | if (pin - GPI_PIN_ROW_BASE + 1 <= pdata->rows) { | ||
498 | dev_err(&client->dev, "invalid gpi row data\n"); | ||
499 | return -EINVAL; | ||
500 | } | ||
501 | } else { | ||
502 | if (pin - GPI_PIN_COL_BASE + 1 <= pdata->cols) { | ||
503 | dev_err(&client->dev, "invalid gpi col data\n"); | ||
504 | return -EINVAL; | ||
505 | } | ||
506 | } | ||
507 | } | ||
508 | |||
192 | if (!client->irq) { | 509 | if (!client->irq) { |
193 | dev_err(&client->dev, "no IRQ?\n"); | 510 | dev_err(&client->dev, "no IRQ?\n"); |
194 | return -EINVAL; | 511 | return -EINVAL; |
@@ -233,6 +550,9 @@ static int __devinit adp5588_probe(struct i2c_client *client, | |||
233 | memcpy(kpad->keycode, pdata->keymap, | 550 | memcpy(kpad->keycode, pdata->keymap, |
234 | pdata->keymapsize * input->keycodesize); | 551 | pdata->keymapsize * input->keycodesize); |
235 | 552 | ||
553 | kpad->gpimap = pdata->gpimap; | ||
554 | kpad->gpimapsize = pdata->gpimapsize; | ||
555 | |||
236 | /* setup input device */ | 556 | /* setup input device */ |
237 | __set_bit(EV_KEY, input->evbit); | 557 | __set_bit(EV_KEY, input->evbit); |
238 | 558 | ||
@@ -243,6 +563,11 @@ static int __devinit adp5588_probe(struct i2c_client *client, | |||
243 | __set_bit(kpad->keycode[i] & KEY_MAX, input->keybit); | 563 | __set_bit(kpad->keycode[i] & KEY_MAX, input->keybit); |
244 | __clear_bit(KEY_RESERVED, input->keybit); | 564 | __clear_bit(KEY_RESERVED, input->keybit); |
245 | 565 | ||
566 | if (kpad->gpimapsize) | ||
567 | __set_bit(EV_SW, input->evbit); | ||
568 | for (i = 0; i < kpad->gpimapsize; i++) | ||
569 | __set_bit(kpad->gpimap[i].sw_evt, input->swbit); | ||
570 | |||
246 | error = input_register_device(input); | 571 | error = input_register_device(input); |
247 | if (error) { | 572 | if (error) { |
248 | dev_err(&client->dev, "unable to register input device\n"); | 573 | dev_err(&client->dev, "unable to register input device\n"); |
@@ -261,6 +586,13 @@ static int __devinit adp5588_probe(struct i2c_client *client, | |||
261 | if (error) | 586 | if (error) |
262 | goto err_free_irq; | 587 | goto err_free_irq; |
263 | 588 | ||
589 | if (kpad->gpimapsize) | ||
590 | adp5588_report_switch_state(kpad); | ||
591 | |||
592 | error = adp5588_gpio_add(kpad); | ||
593 | if (error) | ||
594 | goto err_free_irq; | ||
595 | |||
264 | device_init_wakeup(&client->dev, 1); | 596 | device_init_wakeup(&client->dev, 1); |
265 | i2c_set_clientdata(client, kpad); | 597 | i2c_set_clientdata(client, kpad); |
266 | 598 | ||
@@ -287,6 +619,7 @@ static int __devexit adp5588_remove(struct i2c_client *client) | |||
287 | free_irq(client->irq, kpad); | 619 | free_irq(client->irq, kpad); |
288 | cancel_delayed_work_sync(&kpad->work); | 620 | cancel_delayed_work_sync(&kpad->work); |
289 | input_unregister_device(kpad->input); | 621 | input_unregister_device(kpad->input); |
622 | adp5588_gpio_remove(kpad); | ||
290 | kfree(kpad); | 623 | kfree(kpad); |
291 | 624 | ||
292 | return 0; | 625 | return 0; |
diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index b8213fd13c3f..a9fd147f2ba7 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c | |||
@@ -31,6 +31,7 @@ struct gpio_button_data { | |||
31 | struct input_dev *input; | 31 | struct input_dev *input; |
32 | struct timer_list timer; | 32 | struct timer_list timer; |
33 | struct work_struct work; | 33 | struct work_struct work; |
34 | int timer_debounce; /* in msecs */ | ||
34 | bool disabled; | 35 | bool disabled; |
35 | }; | 36 | }; |
36 | 37 | ||
@@ -109,7 +110,7 @@ static void gpio_keys_disable_button(struct gpio_button_data *bdata) | |||
109 | * Disable IRQ and possible debouncing timer. | 110 | * Disable IRQ and possible debouncing timer. |
110 | */ | 111 | */ |
111 | disable_irq(gpio_to_irq(bdata->button->gpio)); | 112 | disable_irq(gpio_to_irq(bdata->button->gpio)); |
112 | if (bdata->button->debounce_interval) | 113 | if (bdata->timer_debounce) |
113 | del_timer_sync(&bdata->timer); | 114 | del_timer_sync(&bdata->timer); |
114 | 115 | ||
115 | bdata->disabled = true; | 116 | bdata->disabled = true; |
@@ -347,9 +348,9 @@ static irqreturn_t gpio_keys_isr(int irq, void *dev_id) | |||
347 | 348 | ||
348 | BUG_ON(irq != gpio_to_irq(button->gpio)); | 349 | BUG_ON(irq != gpio_to_irq(button->gpio)); |
349 | 350 | ||
350 | if (button->debounce_interval) | 351 | if (bdata->timer_debounce) |
351 | mod_timer(&bdata->timer, | 352 | mod_timer(&bdata->timer, |
352 | jiffies + msecs_to_jiffies(button->debounce_interval)); | 353 | jiffies + msecs_to_jiffies(bdata->timer_debounce)); |
353 | else | 354 | else |
354 | schedule_work(&bdata->work); | 355 | schedule_work(&bdata->work); |
355 | 356 | ||
@@ -383,6 +384,14 @@ static int __devinit gpio_keys_setup_key(struct platform_device *pdev, | |||
383 | goto fail3; | 384 | goto fail3; |
384 | } | 385 | } |
385 | 386 | ||
387 | if (button->debounce_interval) { | ||
388 | error = gpio_set_debounce(button->gpio, | ||
389 | button->debounce_interval * 1000); | ||
390 | /* use timer if gpiolib doesn't provide debounce */ | ||
391 | if (error < 0) | ||
392 | bdata->timer_debounce = button->debounce_interval; | ||
393 | } | ||
394 | |||
386 | irq = gpio_to_irq(button->gpio); | 395 | irq = gpio_to_irq(button->gpio); |
387 | if (irq < 0) { | 396 | if (irq < 0) { |
388 | error = irq; | 397 | error = irq; |
@@ -498,7 +507,7 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev) | |||
498 | fail2: | 507 | fail2: |
499 | while (--i >= 0) { | 508 | while (--i >= 0) { |
500 | free_irq(gpio_to_irq(pdata->buttons[i].gpio), &ddata->data[i]); | 509 | free_irq(gpio_to_irq(pdata->buttons[i].gpio), &ddata->data[i]); |
501 | if (pdata->buttons[i].debounce_interval) | 510 | if (ddata->data[i].timer_debounce) |
502 | del_timer_sync(&ddata->data[i].timer); | 511 | del_timer_sync(&ddata->data[i].timer); |
503 | cancel_work_sync(&ddata->data[i].work); | 512 | cancel_work_sync(&ddata->data[i].work); |
504 | gpio_free(pdata->buttons[i].gpio); | 513 | gpio_free(pdata->buttons[i].gpio); |
@@ -526,7 +535,7 @@ static int __devexit gpio_keys_remove(struct platform_device *pdev) | |||
526 | for (i = 0; i < pdata->nbuttons; i++) { | 535 | for (i = 0; i < pdata->nbuttons; i++) { |
527 | int irq = gpio_to_irq(pdata->buttons[i].gpio); | 536 | int irq = gpio_to_irq(pdata->buttons[i].gpio); |
528 | free_irq(irq, &ddata->data[i]); | 537 | free_irq(irq, &ddata->data[i]); |
529 | if (pdata->buttons[i].debounce_interval) | 538 | if (ddata->data[i].timer_debounce) |
530 | del_timer_sync(&ddata->data[i].timer); | 539 | del_timer_sync(&ddata->data[i].timer); |
531 | cancel_work_sync(&ddata->data[i].work); | 540 | cancel_work_sync(&ddata->data[i].work); |
532 | gpio_free(pdata->buttons[i].gpio); | 541 | gpio_free(pdata->buttons[i].gpio); |
diff --git a/drivers/input/keyboard/lm8323.c b/drivers/input/keyboard/lm8323.c index 40b032f0e32c..f7c2a166576b 100644 --- a/drivers/input/keyboard/lm8323.c +++ b/drivers/input/keyboard/lm8323.c | |||
@@ -642,6 +642,7 @@ static int __devinit lm8323_probe(struct i2c_client *client, | |||
642 | struct lm8323_platform_data *pdata = client->dev.platform_data; | 642 | struct lm8323_platform_data *pdata = client->dev.platform_data; |
643 | struct input_dev *idev; | 643 | struct input_dev *idev; |
644 | struct lm8323_chip *lm; | 644 | struct lm8323_chip *lm; |
645 | int pwm; | ||
645 | int i, err; | 646 | int i, err; |
646 | unsigned long tmo; | 647 | unsigned long tmo; |
647 | u8 data[2]; | 648 | u8 data[2]; |
@@ -710,8 +711,9 @@ static int __devinit lm8323_probe(struct i2c_client *client, | |||
710 | goto fail1; | 711 | goto fail1; |
711 | } | 712 | } |
712 | 713 | ||
713 | for (i = 0; i < LM8323_NUM_PWMS; i++) { | 714 | for (pwm = 0; pwm < LM8323_NUM_PWMS; pwm++) { |
714 | err = init_pwm(lm, i + 1, &client->dev, pdata->pwm_names[i]); | 715 | err = init_pwm(lm, pwm + 1, &client->dev, |
716 | pdata->pwm_names[pwm]); | ||
715 | if (err < 0) | 717 | if (err < 0) |
716 | goto fail2; | 718 | goto fail2; |
717 | } | 719 | } |
@@ -764,9 +766,9 @@ fail4: | |||
764 | fail3: | 766 | fail3: |
765 | device_remove_file(&client->dev, &dev_attr_disable_kp); | 767 | device_remove_file(&client->dev, &dev_attr_disable_kp); |
766 | fail2: | 768 | fail2: |
767 | while (--i >= 0) | 769 | while (--pwm >= 0) |
768 | if (lm->pwm[i].enabled) | 770 | if (lm->pwm[pwm].enabled) |
769 | led_classdev_unregister(&lm->pwm[i].cdev); | 771 | led_classdev_unregister(&lm->pwm[pwm].cdev); |
770 | fail1: | 772 | fail1: |
771 | input_free_device(idev); | 773 | input_free_device(idev); |
772 | kfree(lm); | 774 | kfree(lm); |
diff --git a/drivers/input/keyboard/matrix_keypad.c b/drivers/input/keyboard/matrix_keypad.c index b443e088fd3c..b02e4268e18f 100644 --- a/drivers/input/keyboard/matrix_keypad.c +++ b/drivers/input/keyboard/matrix_keypad.c | |||
@@ -37,6 +37,7 @@ struct matrix_keypad { | |||
37 | spinlock_t lock; | 37 | spinlock_t lock; |
38 | bool scan_pending; | 38 | bool scan_pending; |
39 | bool stopped; | 39 | bool stopped; |
40 | bool gpio_all_disabled; | ||
40 | }; | 41 | }; |
41 | 42 | ||
42 | /* | 43 | /* |
@@ -87,8 +88,12 @@ static void enable_row_irqs(struct matrix_keypad *keypad) | |||
87 | const struct matrix_keypad_platform_data *pdata = keypad->pdata; | 88 | const struct matrix_keypad_platform_data *pdata = keypad->pdata; |
88 | int i; | 89 | int i; |
89 | 90 | ||
90 | for (i = 0; i < pdata->num_row_gpios; i++) | 91 | if (pdata->clustered_irq > 0) |
91 | enable_irq(gpio_to_irq(pdata->row_gpios[i])); | 92 | enable_irq(pdata->clustered_irq); |
93 | else { | ||
94 | for (i = 0; i < pdata->num_row_gpios; i++) | ||
95 | enable_irq(gpio_to_irq(pdata->row_gpios[i])); | ||
96 | } | ||
92 | } | 97 | } |
93 | 98 | ||
94 | static void disable_row_irqs(struct matrix_keypad *keypad) | 99 | static void disable_row_irqs(struct matrix_keypad *keypad) |
@@ -96,8 +101,12 @@ static void disable_row_irqs(struct matrix_keypad *keypad) | |||
96 | const struct matrix_keypad_platform_data *pdata = keypad->pdata; | 101 | const struct matrix_keypad_platform_data *pdata = keypad->pdata; |
97 | int i; | 102 | int i; |
98 | 103 | ||
99 | for (i = 0; i < pdata->num_row_gpios; i++) | 104 | if (pdata->clustered_irq > 0) |
100 | disable_irq_nosync(gpio_to_irq(pdata->row_gpios[i])); | 105 | disable_irq_nosync(pdata->clustered_irq); |
106 | else { | ||
107 | for (i = 0; i < pdata->num_row_gpios; i++) | ||
108 | disable_irq_nosync(gpio_to_irq(pdata->row_gpios[i])); | ||
109 | } | ||
101 | } | 110 | } |
102 | 111 | ||
103 | /* | 112 | /* |
@@ -216,45 +225,69 @@ static void matrix_keypad_stop(struct input_dev *dev) | |||
216 | } | 225 | } |
217 | 226 | ||
218 | #ifdef CONFIG_PM | 227 | #ifdef CONFIG_PM |
219 | static int matrix_keypad_suspend(struct device *dev) | 228 | static void matrix_keypad_enable_wakeup(struct matrix_keypad *keypad) |
220 | { | 229 | { |
221 | struct platform_device *pdev = to_platform_device(dev); | ||
222 | struct matrix_keypad *keypad = platform_get_drvdata(pdev); | ||
223 | const struct matrix_keypad_platform_data *pdata = keypad->pdata; | 230 | const struct matrix_keypad_platform_data *pdata = keypad->pdata; |
231 | unsigned int gpio; | ||
224 | int i; | 232 | int i; |
225 | 233 | ||
226 | matrix_keypad_stop(keypad->input_dev); | 234 | if (pdata->clustered_irq > 0) { |
235 | if (enable_irq_wake(pdata->clustered_irq) == 0) | ||
236 | keypad->gpio_all_disabled = true; | ||
237 | } else { | ||
227 | 238 | ||
228 | if (device_may_wakeup(&pdev->dev)) { | ||
229 | for (i = 0; i < pdata->num_row_gpios; i++) { | 239 | for (i = 0; i < pdata->num_row_gpios; i++) { |
230 | if (!test_bit(i, keypad->disabled_gpios)) { | 240 | if (!test_bit(i, keypad->disabled_gpios)) { |
231 | unsigned int gpio = pdata->row_gpios[i]; | 241 | gpio = pdata->row_gpios[i]; |
232 | 242 | ||
233 | if (enable_irq_wake(gpio_to_irq(gpio)) == 0) | 243 | if (enable_irq_wake(gpio_to_irq(gpio)) == 0) |
234 | __set_bit(i, keypad->disabled_gpios); | 244 | __set_bit(i, keypad->disabled_gpios); |
235 | } | 245 | } |
236 | } | 246 | } |
237 | } | 247 | } |
238 | |||
239 | return 0; | ||
240 | } | 248 | } |
241 | 249 | ||
242 | static int matrix_keypad_resume(struct device *dev) | 250 | static void matrix_keypad_disable_wakeup(struct matrix_keypad *keypad) |
243 | { | 251 | { |
244 | struct platform_device *pdev = to_platform_device(dev); | ||
245 | struct matrix_keypad *keypad = platform_get_drvdata(pdev); | ||
246 | const struct matrix_keypad_platform_data *pdata = keypad->pdata; | 252 | const struct matrix_keypad_platform_data *pdata = keypad->pdata; |
253 | unsigned int gpio; | ||
247 | int i; | 254 | int i; |
248 | 255 | ||
249 | if (device_may_wakeup(&pdev->dev)) { | 256 | if (pdata->clustered_irq > 0) { |
257 | if (keypad->gpio_all_disabled) { | ||
258 | disable_irq_wake(pdata->clustered_irq); | ||
259 | keypad->gpio_all_disabled = false; | ||
260 | } | ||
261 | } else { | ||
250 | for (i = 0; i < pdata->num_row_gpios; i++) { | 262 | for (i = 0; i < pdata->num_row_gpios; i++) { |
251 | if (test_and_clear_bit(i, keypad->disabled_gpios)) { | 263 | if (test_and_clear_bit(i, keypad->disabled_gpios)) { |
252 | unsigned int gpio = pdata->row_gpios[i]; | 264 | gpio = pdata->row_gpios[i]; |
253 | |||
254 | disable_irq_wake(gpio_to_irq(gpio)); | 265 | disable_irq_wake(gpio_to_irq(gpio)); |
255 | } | 266 | } |
256 | } | 267 | } |
257 | } | 268 | } |
269 | } | ||
270 | |||
271 | static int matrix_keypad_suspend(struct device *dev) | ||
272 | { | ||
273 | struct platform_device *pdev = to_platform_device(dev); | ||
274 | struct matrix_keypad *keypad = platform_get_drvdata(pdev); | ||
275 | |||
276 | matrix_keypad_stop(keypad->input_dev); | ||
277 | |||
278 | if (device_may_wakeup(&pdev->dev)) | ||
279 | matrix_keypad_enable_wakeup(keypad); | ||
280 | |||
281 | return 0; | ||
282 | } | ||
283 | |||
284 | static int matrix_keypad_resume(struct device *dev) | ||
285 | { | ||
286 | struct platform_device *pdev = to_platform_device(dev); | ||
287 | struct matrix_keypad *keypad = platform_get_drvdata(pdev); | ||
288 | |||
289 | if (device_may_wakeup(&pdev->dev)) | ||
290 | matrix_keypad_disable_wakeup(keypad); | ||
258 | 291 | ||
259 | matrix_keypad_start(keypad->input_dev); | 292 | matrix_keypad_start(keypad->input_dev); |
260 | 293 | ||
@@ -296,17 +329,31 @@ static int __devinit init_matrix_gpio(struct platform_device *pdev, | |||
296 | gpio_direction_input(pdata->row_gpios[i]); | 329 | gpio_direction_input(pdata->row_gpios[i]); |
297 | } | 330 | } |
298 | 331 | ||
299 | for (i = 0; i < pdata->num_row_gpios; i++) { | 332 | if (pdata->clustered_irq > 0) { |
300 | err = request_irq(gpio_to_irq(pdata->row_gpios[i]), | 333 | err = request_irq(pdata->clustered_irq, |
301 | matrix_keypad_interrupt, | 334 | matrix_keypad_interrupt, |
302 | IRQF_DISABLED | | 335 | pdata->clustered_irq_flags, |
303 | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, | ||
304 | "matrix-keypad", keypad); | 336 | "matrix-keypad", keypad); |
305 | if (err) { | 337 | if (err) { |
306 | dev_err(&pdev->dev, | 338 | dev_err(&pdev->dev, |
307 | "Unable to acquire interrupt for GPIO line %i\n", | 339 | "Unable to acquire clustered interrupt\n"); |
308 | pdata->row_gpios[i]); | 340 | goto err_free_rows; |
309 | goto err_free_irqs; | 341 | } |
342 | } else { | ||
343 | for (i = 0; i < pdata->num_row_gpios; i++) { | ||
344 | err = request_irq(gpio_to_irq(pdata->row_gpios[i]), | ||
345 | matrix_keypad_interrupt, | ||
346 | IRQF_DISABLED | | ||
347 | IRQF_TRIGGER_RISING | | ||
348 | IRQF_TRIGGER_FALLING, | ||
349 | "matrix-keypad", keypad); | ||
350 | if (err) { | ||
351 | dev_err(&pdev->dev, | ||
352 | "Unable to acquire interrupt " | ||
353 | "for GPIO line %i\n", | ||
354 | pdata->row_gpios[i]); | ||
355 | goto err_free_irqs; | ||
356 | } | ||
310 | } | 357 | } |
311 | } | 358 | } |
312 | 359 | ||
@@ -418,11 +465,16 @@ static int __devexit matrix_keypad_remove(struct platform_device *pdev) | |||
418 | 465 | ||
419 | device_init_wakeup(&pdev->dev, 0); | 466 | device_init_wakeup(&pdev->dev, 0); |
420 | 467 | ||
421 | for (i = 0; i < pdata->num_row_gpios; i++) { | 468 | if (pdata->clustered_irq > 0) { |
422 | free_irq(gpio_to_irq(pdata->row_gpios[i]), keypad); | 469 | free_irq(pdata->clustered_irq, keypad); |
423 | gpio_free(pdata->row_gpios[i]); | 470 | } else { |
471 | for (i = 0; i < pdata->num_row_gpios; i++) | ||
472 | free_irq(gpio_to_irq(pdata->row_gpios[i]), keypad); | ||
424 | } | 473 | } |
425 | 474 | ||
475 | for (i = 0; i < pdata->num_row_gpios; i++) | ||
476 | gpio_free(pdata->row_gpios[i]); | ||
477 | |||
426 | for (i = 0; i < pdata->num_col_gpios; i++) | 478 | for (i = 0; i < pdata->num_col_gpios; i++) |
427 | gpio_free(pdata->col_gpios[i]); | 479 | gpio_free(pdata->col_gpios[i]); |
428 | 480 | ||
diff --git a/drivers/input/keyboard/mcs_touchkey.c b/drivers/input/keyboard/mcs_touchkey.c new file mode 100644 index 000000000000..63b849d7e90b --- /dev/null +++ b/drivers/input/keyboard/mcs_touchkey.c | |||
@@ -0,0 +1,239 @@ | |||
1 | /* | ||
2 | * mcs_touchkey.c - Touchkey driver for MELFAS MCS5000/5080 controller | ||
3 | * | ||
4 | * Copyright (C) 2010 Samsung Electronics Co.Ltd | ||
5 | * Author: HeungJun Kim <riverful.kim@samsung.com> | ||
6 | * Author: Joonyoung Shim <jy0922.shim@samsung.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the | ||
10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
11 | * option) any later version. | ||
12 | */ | ||
13 | |||
14 | #include <linux/module.h> | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/i2c.h> | ||
17 | #include <linux/i2c/mcs.h> | ||
18 | #include <linux/interrupt.h> | ||
19 | #include <linux/input.h> | ||
20 | #include <linux/irq.h> | ||
21 | #include <linux/slab.h> | ||
22 | |||
23 | /* MCS5000 Touchkey */ | ||
24 | #define MCS5000_TOUCHKEY_STATUS 0x04 | ||
25 | #define MCS5000_TOUCHKEY_STATUS_PRESS 7 | ||
26 | #define MCS5000_TOUCHKEY_FW 0x0a | ||
27 | #define MCS5000_TOUCHKEY_BASE_VAL 0x61 | ||
28 | |||
29 | /* MCS5080 Touchkey */ | ||
30 | #define MCS5080_TOUCHKEY_STATUS 0x00 | ||
31 | #define MCS5080_TOUCHKEY_STATUS_PRESS 3 | ||
32 | #define MCS5080_TOUCHKEY_FW 0x01 | ||
33 | #define MCS5080_TOUCHKEY_BASE_VAL 0x1 | ||
34 | |||
35 | enum mcs_touchkey_type { | ||
36 | MCS5000_TOUCHKEY, | ||
37 | MCS5080_TOUCHKEY, | ||
38 | }; | ||
39 | |||
40 | struct mcs_touchkey_chip { | ||
41 | unsigned int status_reg; | ||
42 | unsigned int pressbit; | ||
43 | unsigned int press_invert; | ||
44 | unsigned int baseval; | ||
45 | }; | ||
46 | |||
47 | struct mcs_touchkey_data { | ||
48 | struct i2c_client *client; | ||
49 | struct input_dev *input_dev; | ||
50 | struct mcs_touchkey_chip chip; | ||
51 | unsigned int key_code; | ||
52 | unsigned int key_val; | ||
53 | unsigned short keycodes[]; | ||
54 | }; | ||
55 | |||
56 | static irqreturn_t mcs_touchkey_interrupt(int irq, void *dev_id) | ||
57 | { | ||
58 | struct mcs_touchkey_data *data = dev_id; | ||
59 | struct mcs_touchkey_chip *chip = &data->chip; | ||
60 | struct i2c_client *client = data->client; | ||
61 | struct input_dev *input = data->input_dev; | ||
62 | unsigned int key_val; | ||
63 | unsigned int pressed; | ||
64 | int val; | ||
65 | |||
66 | val = i2c_smbus_read_byte_data(client, chip->status_reg); | ||
67 | if (val < 0) { | ||
68 | dev_err(&client->dev, "i2c read error [%d]\n", val); | ||
69 | goto out; | ||
70 | } | ||
71 | |||
72 | pressed = (val & (1 << chip->pressbit)) >> chip->pressbit; | ||
73 | if (chip->press_invert) | ||
74 | pressed ^= chip->press_invert; | ||
75 | |||
76 | /* key_val is 0 when released, so we should use key_val of press. */ | ||
77 | if (pressed) { | ||
78 | key_val = val & (0xff >> (8 - chip->pressbit)); | ||
79 | if (!key_val) | ||
80 | goto out; | ||
81 | key_val -= chip->baseval; | ||
82 | data->key_code = data->keycodes[key_val]; | ||
83 | data->key_val = key_val; | ||
84 | } | ||
85 | |||
86 | input_event(input, EV_MSC, MSC_SCAN, data->key_val); | ||
87 | input_report_key(input, data->key_code, pressed); | ||
88 | input_sync(input); | ||
89 | |||
90 | dev_dbg(&client->dev, "key %d %d %s\n", data->key_val, data->key_code, | ||
91 | pressed ? "pressed" : "released"); | ||
92 | |||
93 | out: | ||
94 | return IRQ_HANDLED; | ||
95 | } | ||
96 | |||
97 | static int __devinit mcs_touchkey_probe(struct i2c_client *client, | ||
98 | const struct i2c_device_id *id) | ||
99 | { | ||
100 | const struct mcs_platform_data *pdata; | ||
101 | struct mcs_touchkey_data *data; | ||
102 | struct input_dev *input_dev; | ||
103 | unsigned int fw_reg; | ||
104 | int fw_ver; | ||
105 | int error; | ||
106 | int i; | ||
107 | |||
108 | pdata = client->dev.platform_data; | ||
109 | if (!pdata) { | ||
110 | dev_err(&client->dev, "no platform data defined\n"); | ||
111 | return -EINVAL; | ||
112 | } | ||
113 | |||
114 | data = kzalloc(sizeof(struct mcs_touchkey_data) + | ||
115 | sizeof(data->keycodes[0]) * (pdata->key_maxval + 1), | ||
116 | GFP_KERNEL); | ||
117 | input_dev = input_allocate_device(); | ||
118 | if (!data || !input_dev) { | ||
119 | dev_err(&client->dev, "Failed to allocate memory\n"); | ||
120 | error = -ENOMEM; | ||
121 | goto err_free_mem; | ||
122 | } | ||
123 | |||
124 | data->client = client; | ||
125 | data->input_dev = input_dev; | ||
126 | |||
127 | if (id->driver_data == MCS5000_TOUCHKEY) { | ||
128 | data->chip.status_reg = MCS5000_TOUCHKEY_STATUS; | ||
129 | data->chip.pressbit = MCS5000_TOUCHKEY_STATUS_PRESS; | ||
130 | data->chip.baseval = MCS5000_TOUCHKEY_BASE_VAL; | ||
131 | fw_reg = MCS5000_TOUCHKEY_FW; | ||
132 | } else { | ||
133 | data->chip.status_reg = MCS5080_TOUCHKEY_STATUS; | ||
134 | data->chip.pressbit = MCS5080_TOUCHKEY_STATUS_PRESS; | ||
135 | data->chip.press_invert = 1; | ||
136 | data->chip.baseval = MCS5080_TOUCHKEY_BASE_VAL; | ||
137 | fw_reg = MCS5080_TOUCHKEY_FW; | ||
138 | } | ||
139 | |||
140 | fw_ver = i2c_smbus_read_byte_data(client, fw_reg); | ||
141 | if (fw_ver < 0) { | ||
142 | error = fw_ver; | ||
143 | dev_err(&client->dev, "i2c read error[%d]\n", error); | ||
144 | goto err_free_mem; | ||
145 | } | ||
146 | dev_info(&client->dev, "Firmware version: %d\n", fw_ver); | ||
147 | |||
148 | input_dev->name = "MELPAS MCS Touchkey"; | ||
149 | input_dev->id.bustype = BUS_I2C; | ||
150 | input_dev->dev.parent = &client->dev; | ||
151 | input_dev->evbit[0] = BIT_MASK(EV_KEY); | ||
152 | if (!pdata->no_autorepeat) | ||
153 | input_dev->evbit[0] |= BIT_MASK(EV_REP); | ||
154 | input_dev->keycode = data->keycodes; | ||
155 | input_dev->keycodesize = sizeof(data->keycodes[0]); | ||
156 | input_dev->keycodemax = pdata->key_maxval + 1; | ||
157 | |||
158 | for (i = 0; i < pdata->keymap_size; i++) { | ||
159 | unsigned int val = MCS_KEY_VAL(pdata->keymap[i]); | ||
160 | unsigned int code = MCS_KEY_CODE(pdata->keymap[i]); | ||
161 | |||
162 | data->keycodes[val] = code; | ||
163 | __set_bit(code, input_dev->keybit); | ||
164 | } | ||
165 | |||
166 | input_set_capability(input_dev, EV_MSC, MSC_SCAN); | ||
167 | input_set_drvdata(input_dev, data); | ||
168 | |||
169 | if (pdata->cfg_pin) | ||
170 | pdata->cfg_pin(); | ||
171 | |||
172 | error = request_threaded_irq(client->irq, NULL, mcs_touchkey_interrupt, | ||
173 | IRQF_TRIGGER_FALLING, client->dev.driver->name, data); | ||
174 | if (error) { | ||
175 | dev_err(&client->dev, "Failed to register interrupt\n"); | ||
176 | goto err_free_mem; | ||
177 | } | ||
178 | |||
179 | error = input_register_device(input_dev); | ||
180 | if (error) | ||
181 | goto err_free_irq; | ||
182 | |||
183 | i2c_set_clientdata(client, data); | ||
184 | return 0; | ||
185 | |||
186 | err_free_irq: | ||
187 | free_irq(client->irq, data); | ||
188 | err_free_mem: | ||
189 | input_free_device(input_dev); | ||
190 | kfree(data); | ||
191 | return error; | ||
192 | } | ||
193 | |||
194 | static int __devexit mcs_touchkey_remove(struct i2c_client *client) | ||
195 | { | ||
196 | struct mcs_touchkey_data *data = i2c_get_clientdata(client); | ||
197 | |||
198 | free_irq(client->irq, data); | ||
199 | input_unregister_device(data->input_dev); | ||
200 | kfree(data); | ||
201 | |||
202 | return 0; | ||
203 | } | ||
204 | |||
205 | static const struct i2c_device_id mcs_touchkey_id[] = { | ||
206 | { "mcs5000_touchkey", MCS5000_TOUCHKEY }, | ||
207 | { "mcs5080_touchkey", MCS5080_TOUCHKEY }, | ||
208 | { } | ||
209 | }; | ||
210 | MODULE_DEVICE_TABLE(i2c, mcs_touchkey_id); | ||
211 | |||
212 | static struct i2c_driver mcs_touchkey_driver = { | ||
213 | .driver = { | ||
214 | .name = "mcs_touchkey", | ||
215 | .owner = THIS_MODULE, | ||
216 | }, | ||
217 | .probe = mcs_touchkey_probe, | ||
218 | .remove = __devexit_p(mcs_touchkey_remove), | ||
219 | .id_table = mcs_touchkey_id, | ||
220 | }; | ||
221 | |||
222 | static int __init mcs_touchkey_init(void) | ||
223 | { | ||
224 | return i2c_add_driver(&mcs_touchkey_driver); | ||
225 | } | ||
226 | |||
227 | static void __exit mcs_touchkey_exit(void) | ||
228 | { | ||
229 | i2c_del_driver(&mcs_touchkey_driver); | ||
230 | } | ||
231 | |||
232 | module_init(mcs_touchkey_init); | ||
233 | module_exit(mcs_touchkey_exit); | ||
234 | |||
235 | /* Module information */ | ||
236 | MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>"); | ||
237 | MODULE_AUTHOR("HeungJun Kim <riverful.kim@samsung.com>"); | ||
238 | MODULE_DESCRIPTION("Touchkey driver for MELFAS MCS5000/5080 controller"); | ||
239 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/input/keyboard/samsung-keypad.c b/drivers/input/keyboard/samsung-keypad.c new file mode 100644 index 000000000000..f689f49e3109 --- /dev/null +++ b/drivers/input/keyboard/samsung-keypad.c | |||
@@ -0,0 +1,491 @@ | |||
1 | /* | ||
2 | * Samsung keypad driver | ||
3 | * | ||
4 | * Copyright (C) 2010 Samsung Electronics Co.Ltd | ||
5 | * Author: Joonyoung Shim <jy0922.shim@samsung.com> | ||
6 | * Author: Donghwa Lee <dh09.lee@samsung.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the | ||
10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
11 | * option) any later version. | ||
12 | */ | ||
13 | |||
14 | #include <linux/clk.h> | ||
15 | #include <linux/delay.h> | ||
16 | #include <linux/err.h> | ||
17 | #include <linux/init.h> | ||
18 | #include <linux/input.h> | ||
19 | #include <linux/interrupt.h> | ||
20 | #include <linux/io.h> | ||
21 | #include <linux/module.h> | ||
22 | #include <linux/platform_device.h> | ||
23 | #include <linux/slab.h> | ||
24 | #include <linux/sched.h> | ||
25 | #include <plat/keypad.h> | ||
26 | |||
27 | #define SAMSUNG_KEYIFCON 0x00 | ||
28 | #define SAMSUNG_KEYIFSTSCLR 0x04 | ||
29 | #define SAMSUNG_KEYIFCOL 0x08 | ||
30 | #define SAMSUNG_KEYIFROW 0x0c | ||
31 | #define SAMSUNG_KEYIFFC 0x10 | ||
32 | |||
33 | /* SAMSUNG_KEYIFCON */ | ||
34 | #define SAMSUNG_KEYIFCON_INT_F_EN (1 << 0) | ||
35 | #define SAMSUNG_KEYIFCON_INT_R_EN (1 << 1) | ||
36 | #define SAMSUNG_KEYIFCON_DF_EN (1 << 2) | ||
37 | #define SAMSUNG_KEYIFCON_FC_EN (1 << 3) | ||
38 | #define SAMSUNG_KEYIFCON_WAKEUPEN (1 << 4) | ||
39 | |||
40 | /* SAMSUNG_KEYIFSTSCLR */ | ||
41 | #define SAMSUNG_KEYIFSTSCLR_P_INT_MASK (0xff << 0) | ||
42 | #define SAMSUNG_KEYIFSTSCLR_R_INT_MASK (0xff << 8) | ||
43 | #define SAMSUNG_KEYIFSTSCLR_R_INT_OFFSET 8 | ||
44 | #define S5PV210_KEYIFSTSCLR_P_INT_MASK (0x3fff << 0) | ||
45 | #define S5PV210_KEYIFSTSCLR_R_INT_MASK (0x3fff << 16) | ||
46 | #define S5PV210_KEYIFSTSCLR_R_INT_OFFSET 16 | ||
47 | |||
48 | /* SAMSUNG_KEYIFCOL */ | ||
49 | #define SAMSUNG_KEYIFCOL_MASK (0xff << 0) | ||
50 | #define S5PV210_KEYIFCOLEN_MASK (0xff << 8) | ||
51 | |||
52 | /* SAMSUNG_KEYIFROW */ | ||
53 | #define SAMSUNG_KEYIFROW_MASK (0xff << 0) | ||
54 | #define S5PV210_KEYIFROW_MASK (0x3fff << 0) | ||
55 | |||
56 | /* SAMSUNG_KEYIFFC */ | ||
57 | #define SAMSUNG_KEYIFFC_MASK (0x3ff << 0) | ||
58 | |||
59 | enum samsung_keypad_type { | ||
60 | KEYPAD_TYPE_SAMSUNG, | ||
61 | KEYPAD_TYPE_S5PV210, | ||
62 | }; | ||
63 | |||
64 | struct samsung_keypad { | ||
65 | struct input_dev *input_dev; | ||
66 | struct clk *clk; | ||
67 | void __iomem *base; | ||
68 | wait_queue_head_t wait; | ||
69 | bool stopped; | ||
70 | int irq; | ||
71 | unsigned int row_shift; | ||
72 | unsigned int rows; | ||
73 | unsigned int cols; | ||
74 | unsigned int row_state[SAMSUNG_MAX_COLS]; | ||
75 | unsigned short keycodes[]; | ||
76 | }; | ||
77 | |||
78 | static int samsung_keypad_is_s5pv210(struct device *dev) | ||
79 | { | ||
80 | struct platform_device *pdev = to_platform_device(dev); | ||
81 | enum samsung_keypad_type type = | ||
82 | platform_get_device_id(pdev)->driver_data; | ||
83 | |||
84 | return type == KEYPAD_TYPE_S5PV210; | ||
85 | } | ||
86 | |||
87 | static void samsung_keypad_scan(struct samsung_keypad *keypad, | ||
88 | unsigned int *row_state) | ||
89 | { | ||
90 | struct device *dev = keypad->input_dev->dev.parent; | ||
91 | unsigned int col; | ||
92 | unsigned int val; | ||
93 | |||
94 | for (col = 0; col < keypad->cols; col++) { | ||
95 | if (samsung_keypad_is_s5pv210(dev)) { | ||
96 | val = S5PV210_KEYIFCOLEN_MASK; | ||
97 | val &= ~(1 << col) << 8; | ||
98 | } else { | ||
99 | val = SAMSUNG_KEYIFCOL_MASK; | ||
100 | val &= ~(1 << col); | ||
101 | } | ||
102 | |||
103 | writel(val, keypad->base + SAMSUNG_KEYIFCOL); | ||
104 | mdelay(1); | ||
105 | |||
106 | val = readl(keypad->base + SAMSUNG_KEYIFROW); | ||
107 | row_state[col] = ~val & ((1 << keypad->rows) - 1); | ||
108 | } | ||
109 | |||
110 | /* KEYIFCOL reg clear */ | ||
111 | writel(0, keypad->base + SAMSUNG_KEYIFCOL); | ||
112 | } | ||
113 | |||
114 | static bool samsung_keypad_report(struct samsung_keypad *keypad, | ||
115 | unsigned int *row_state) | ||
116 | { | ||
117 | struct input_dev *input_dev = keypad->input_dev; | ||
118 | unsigned int changed; | ||
119 | unsigned int pressed; | ||
120 | unsigned int key_down = 0; | ||
121 | unsigned int val; | ||
122 | unsigned int col, row; | ||
123 | |||
124 | for (col = 0; col < keypad->cols; col++) { | ||
125 | changed = row_state[col] ^ keypad->row_state[col]; | ||
126 | key_down |= row_state[col]; | ||
127 | if (!changed) | ||
128 | continue; | ||
129 | |||
130 | for (row = 0; row < keypad->rows; row++) { | ||
131 | if (!(changed & (1 << row))) | ||
132 | continue; | ||
133 | |||
134 | pressed = row_state[col] & (1 << row); | ||
135 | |||
136 | dev_dbg(&keypad->input_dev->dev, | ||
137 | "key %s, row: %d, col: %d\n", | ||
138 | pressed ? "pressed" : "released", row, col); | ||
139 | |||
140 | val = MATRIX_SCAN_CODE(row, col, keypad->row_shift); | ||
141 | |||
142 | input_event(input_dev, EV_MSC, MSC_SCAN, val); | ||
143 | input_report_key(input_dev, | ||
144 | keypad->keycodes[val], pressed); | ||
145 | } | ||
146 | input_sync(keypad->input_dev); | ||
147 | } | ||
148 | |||
149 | memcpy(keypad->row_state, row_state, sizeof(keypad->row_state)); | ||
150 | |||
151 | return key_down; | ||
152 | } | ||
153 | |||
154 | static irqreturn_t samsung_keypad_irq(int irq, void *dev_id) | ||
155 | { | ||
156 | struct samsung_keypad *keypad = dev_id; | ||
157 | unsigned int row_state[SAMSUNG_MAX_COLS]; | ||
158 | unsigned int val; | ||
159 | bool key_down; | ||
160 | |||
161 | do { | ||
162 | val = readl(keypad->base + SAMSUNG_KEYIFSTSCLR); | ||
163 | /* Clear interrupt. */ | ||
164 | writel(~0x0, keypad->base + SAMSUNG_KEYIFSTSCLR); | ||
165 | |||
166 | samsung_keypad_scan(keypad, row_state); | ||
167 | |||
168 | key_down = samsung_keypad_report(keypad, row_state); | ||
169 | if (key_down) | ||
170 | wait_event_timeout(keypad->wait, keypad->stopped, | ||
171 | msecs_to_jiffies(50)); | ||
172 | |||
173 | } while (key_down && !keypad->stopped); | ||
174 | |||
175 | return IRQ_HANDLED; | ||
176 | } | ||
177 | |||
178 | static void samsung_keypad_start(struct samsung_keypad *keypad) | ||
179 | { | ||
180 | unsigned int val; | ||
181 | |||
182 | /* Tell IRQ thread that it may poll the device. */ | ||
183 | keypad->stopped = false; | ||
184 | |||
185 | clk_enable(keypad->clk); | ||
186 | |||
187 | /* Enable interrupt bits. */ | ||
188 | val = readl(keypad->base + SAMSUNG_KEYIFCON); | ||
189 | val |= SAMSUNG_KEYIFCON_INT_F_EN | SAMSUNG_KEYIFCON_INT_R_EN; | ||
190 | writel(val, keypad->base + SAMSUNG_KEYIFCON); | ||
191 | |||
192 | /* KEYIFCOL reg clear. */ | ||
193 | writel(0, keypad->base + SAMSUNG_KEYIFCOL); | ||
194 | } | ||
195 | |||
196 | static void samsung_keypad_stop(struct samsung_keypad *keypad) | ||
197 | { | ||
198 | unsigned int val; | ||
199 | |||
200 | /* Signal IRQ thread to stop polling and disable the handler. */ | ||
201 | keypad->stopped = true; | ||
202 | wake_up(&keypad->wait); | ||
203 | disable_irq(keypad->irq); | ||
204 | |||
205 | /* Clear interrupt. */ | ||
206 | writel(~0x0, keypad->base + SAMSUNG_KEYIFSTSCLR); | ||
207 | |||
208 | /* Disable interrupt bits. */ | ||
209 | val = readl(keypad->base + SAMSUNG_KEYIFCON); | ||
210 | val &= ~(SAMSUNG_KEYIFCON_INT_F_EN | SAMSUNG_KEYIFCON_INT_R_EN); | ||
211 | writel(val, keypad->base + SAMSUNG_KEYIFCON); | ||
212 | |||
213 | clk_disable(keypad->clk); | ||
214 | |||
215 | /* | ||
216 | * Now that chip should not generate interrupts we can safely | ||
217 | * re-enable the handler. | ||
218 | */ | ||
219 | enable_irq(keypad->irq); | ||
220 | } | ||
221 | |||
222 | static int samsung_keypad_open(struct input_dev *input_dev) | ||
223 | { | ||
224 | struct samsung_keypad *keypad = input_get_drvdata(input_dev); | ||
225 | |||
226 | samsung_keypad_start(keypad); | ||
227 | |||
228 | return 0; | ||
229 | } | ||
230 | |||
231 | static void samsung_keypad_close(struct input_dev *input_dev) | ||
232 | { | ||
233 | struct samsung_keypad *keypad = input_get_drvdata(input_dev); | ||
234 | |||
235 | samsung_keypad_stop(keypad); | ||
236 | } | ||
237 | |||
238 | static int __devinit samsung_keypad_probe(struct platform_device *pdev) | ||
239 | { | ||
240 | const struct samsung_keypad_platdata *pdata; | ||
241 | const struct matrix_keymap_data *keymap_data; | ||
242 | struct samsung_keypad *keypad; | ||
243 | struct resource *res; | ||
244 | struct input_dev *input_dev; | ||
245 | unsigned int row_shift; | ||
246 | unsigned int keymap_size; | ||
247 | int error; | ||
248 | |||
249 | pdata = pdev->dev.platform_data; | ||
250 | if (!pdata) { | ||
251 | dev_err(&pdev->dev, "no platform data defined\n"); | ||
252 | return -EINVAL; | ||
253 | } | ||
254 | |||
255 | keymap_data = pdata->keymap_data; | ||
256 | if (!keymap_data) { | ||
257 | dev_err(&pdev->dev, "no keymap data defined\n"); | ||
258 | return -EINVAL; | ||
259 | } | ||
260 | |||
261 | if (!pdata->rows || pdata->rows > SAMSUNG_MAX_ROWS) | ||
262 | return -EINVAL; | ||
263 | |||
264 | if (!pdata->cols || pdata->cols > SAMSUNG_MAX_COLS) | ||
265 | return -EINVAL; | ||
266 | |||
267 | /* initialize the gpio */ | ||
268 | if (pdata->cfg_gpio) | ||
269 | pdata->cfg_gpio(pdata->rows, pdata->cols); | ||
270 | |||
271 | row_shift = get_count_order(pdata->cols); | ||
272 | keymap_size = (pdata->rows << row_shift) * sizeof(keypad->keycodes[0]); | ||
273 | |||
274 | keypad = kzalloc(sizeof(*keypad) + keymap_size, GFP_KERNEL); | ||
275 | input_dev = input_allocate_device(); | ||
276 | if (!keypad || !input_dev) { | ||
277 | error = -ENOMEM; | ||
278 | goto err_free_mem; | ||
279 | } | ||
280 | |||
281 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
282 | if (!res) { | ||
283 | error = -ENODEV; | ||
284 | goto err_free_mem; | ||
285 | } | ||
286 | |||
287 | keypad->base = ioremap(res->start, resource_size(res)); | ||
288 | if (!keypad->base) { | ||
289 | error = -EBUSY; | ||
290 | goto err_free_mem; | ||
291 | } | ||
292 | |||
293 | keypad->clk = clk_get(&pdev->dev, "keypad"); | ||
294 | if (IS_ERR(keypad->clk)) { | ||
295 | dev_err(&pdev->dev, "failed to get keypad clk\n"); | ||
296 | error = PTR_ERR(keypad->clk); | ||
297 | goto err_unmap_base; | ||
298 | } | ||
299 | |||
300 | keypad->input_dev = input_dev; | ||
301 | keypad->row_shift = row_shift; | ||
302 | keypad->rows = pdata->rows; | ||
303 | keypad->cols = pdata->cols; | ||
304 | init_waitqueue_head(&keypad->wait); | ||
305 | |||
306 | input_dev->name = pdev->name; | ||
307 | input_dev->id.bustype = BUS_HOST; | ||
308 | input_dev->dev.parent = &pdev->dev; | ||
309 | input_set_drvdata(input_dev, keypad); | ||
310 | |||
311 | input_dev->open = samsung_keypad_open; | ||
312 | input_dev->close = samsung_keypad_close; | ||
313 | |||
314 | input_dev->evbit[0] = BIT_MASK(EV_KEY); | ||
315 | if (!pdata->no_autorepeat) | ||
316 | input_dev->evbit[0] |= BIT_MASK(EV_REP); | ||
317 | |||
318 | input_set_capability(input_dev, EV_MSC, MSC_SCAN); | ||
319 | |||
320 | input_dev->keycode = keypad->keycodes; | ||
321 | input_dev->keycodesize = sizeof(keypad->keycodes[0]); | ||
322 | input_dev->keycodemax = pdata->rows << row_shift; | ||
323 | |||
324 | matrix_keypad_build_keymap(keymap_data, row_shift, | ||
325 | input_dev->keycode, input_dev->keybit); | ||
326 | |||
327 | keypad->irq = platform_get_irq(pdev, 0); | ||
328 | if (keypad->irq < 0) { | ||
329 | error = keypad->irq; | ||
330 | goto err_put_clk; | ||
331 | } | ||
332 | |||
333 | error = request_threaded_irq(keypad->irq, NULL, samsung_keypad_irq, | ||
334 | IRQF_ONESHOT, dev_name(&pdev->dev), keypad); | ||
335 | if (error) { | ||
336 | dev_err(&pdev->dev, "failed to register keypad interrupt\n"); | ||
337 | goto err_put_clk; | ||
338 | } | ||
339 | |||
340 | error = input_register_device(keypad->input_dev); | ||
341 | if (error) | ||
342 | goto err_free_irq; | ||
343 | |||
344 | device_init_wakeup(&pdev->dev, pdata->wakeup); | ||
345 | platform_set_drvdata(pdev, keypad); | ||
346 | return 0; | ||
347 | |||
348 | err_free_irq: | ||
349 | free_irq(keypad->irq, keypad); | ||
350 | err_put_clk: | ||
351 | clk_put(keypad->clk); | ||
352 | err_unmap_base: | ||
353 | iounmap(keypad->base); | ||
354 | err_free_mem: | ||
355 | input_free_device(input_dev); | ||
356 | kfree(keypad); | ||
357 | |||
358 | return error; | ||
359 | } | ||
360 | |||
361 | static int __devexit samsung_keypad_remove(struct platform_device *pdev) | ||
362 | { | ||
363 | struct samsung_keypad *keypad = platform_get_drvdata(pdev); | ||
364 | |||
365 | device_init_wakeup(&pdev->dev, 0); | ||
366 | platform_set_drvdata(pdev, NULL); | ||
367 | |||
368 | input_unregister_device(keypad->input_dev); | ||
369 | |||
370 | /* | ||
371 | * It is safe to free IRQ after unregistering device because | ||
372 | * samsung_keypad_close will shut off interrupts. | ||
373 | */ | ||
374 | free_irq(keypad->irq, keypad); | ||
375 | |||
376 | clk_put(keypad->clk); | ||
377 | |||
378 | iounmap(keypad->base); | ||
379 | kfree(keypad); | ||
380 | |||
381 | return 0; | ||
382 | } | ||
383 | |||
384 | #ifdef CONFIG_PM | ||
385 | static void samsung_keypad_toggle_wakeup(struct samsung_keypad *keypad, | ||
386 | bool enable) | ||
387 | { | ||
388 | struct device *dev = keypad->input_dev->dev.parent; | ||
389 | unsigned int val; | ||
390 | |||
391 | clk_enable(keypad->clk); | ||
392 | |||
393 | val = readl(keypad->base + SAMSUNG_KEYIFCON); | ||
394 | if (enable) { | ||
395 | val |= SAMSUNG_KEYIFCON_WAKEUPEN; | ||
396 | if (device_may_wakeup(dev)) | ||
397 | enable_irq_wake(keypad->irq); | ||
398 | } else { | ||
399 | val &= ~SAMSUNG_KEYIFCON_WAKEUPEN; | ||
400 | if (device_may_wakeup(dev)) | ||
401 | disable_irq_wake(keypad->irq); | ||
402 | } | ||
403 | writel(val, keypad->base + SAMSUNG_KEYIFCON); | ||
404 | |||
405 | clk_disable(keypad->clk); | ||
406 | } | ||
407 | |||
408 | static int samsung_keypad_suspend(struct device *dev) | ||
409 | { | ||
410 | struct platform_device *pdev = to_platform_device(dev); | ||
411 | struct samsung_keypad *keypad = platform_get_drvdata(pdev); | ||
412 | struct input_dev *input_dev = keypad->input_dev; | ||
413 | |||
414 | mutex_lock(&input_dev->mutex); | ||
415 | |||
416 | if (input_dev->users) | ||
417 | samsung_keypad_stop(keypad); | ||
418 | |||
419 | samsung_keypad_toggle_wakeup(keypad, true); | ||
420 | |||
421 | mutex_unlock(&input_dev->mutex); | ||
422 | |||
423 | return 0; | ||
424 | } | ||
425 | |||
426 | static int samsung_keypad_resume(struct device *dev) | ||
427 | { | ||
428 | struct platform_device *pdev = to_platform_device(dev); | ||
429 | struct samsung_keypad *keypad = platform_get_drvdata(pdev); | ||
430 | struct input_dev *input_dev = keypad->input_dev; | ||
431 | |||
432 | mutex_lock(&input_dev->mutex); | ||
433 | |||
434 | samsung_keypad_toggle_wakeup(keypad, false); | ||
435 | |||
436 | if (input_dev->users) | ||
437 | samsung_keypad_start(keypad); | ||
438 | |||
439 | mutex_unlock(&input_dev->mutex); | ||
440 | |||
441 | return 0; | ||
442 | } | ||
443 | |||
444 | static const struct dev_pm_ops samsung_keypad_pm_ops = { | ||
445 | .suspend = samsung_keypad_suspend, | ||
446 | .resume = samsung_keypad_resume, | ||
447 | }; | ||
448 | #endif | ||
449 | |||
450 | static struct platform_device_id samsung_keypad_driver_ids[] = { | ||
451 | { | ||
452 | .name = "samsung-keypad", | ||
453 | .driver_data = KEYPAD_TYPE_SAMSUNG, | ||
454 | }, { | ||
455 | .name = "s5pv210-keypad", | ||
456 | .driver_data = KEYPAD_TYPE_S5PV210, | ||
457 | }, | ||
458 | { }, | ||
459 | }; | ||
460 | MODULE_DEVICE_TABLE(platform, samsung_keypad_driver_ids); | ||
461 | |||
462 | static struct platform_driver samsung_keypad_driver = { | ||
463 | .probe = samsung_keypad_probe, | ||
464 | .remove = __devexit_p(samsung_keypad_remove), | ||
465 | .driver = { | ||
466 | .name = "samsung-keypad", | ||
467 | .owner = THIS_MODULE, | ||
468 | #ifdef CONFIG_PM | ||
469 | .pm = &samsung_keypad_pm_ops, | ||
470 | #endif | ||
471 | }, | ||
472 | .id_table = samsung_keypad_driver_ids, | ||
473 | }; | ||
474 | |||
475 | static int __init samsung_keypad_init(void) | ||
476 | { | ||
477 | return platform_driver_register(&samsung_keypad_driver); | ||
478 | } | ||
479 | module_init(samsung_keypad_init); | ||
480 | |||
481 | static void __exit samsung_keypad_exit(void) | ||
482 | { | ||
483 | platform_driver_unregister(&samsung_keypad_driver); | ||
484 | } | ||
485 | module_exit(samsung_keypad_exit); | ||
486 | |||
487 | MODULE_DESCRIPTION("Samsung keypad driver"); | ||
488 | MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>"); | ||
489 | MODULE_AUTHOR("Donghwa Lee <dh09.lee@samsung.com>"); | ||
490 | MODULE_LICENSE("GPL"); | ||
491 | MODULE_ALIAS("platform:samsung-keypad"); | ||