diff options
Diffstat (limited to 'drivers/input/keyboard/omap4-keypad.c')
-rw-r--r-- | drivers/input/keyboard/omap4-keypad.c | 127 |
1 files changed, 87 insertions, 40 deletions
diff --git a/drivers/input/keyboard/omap4-keypad.c b/drivers/input/keyboard/omap4-keypad.c index aed5f6999ce2..c05f98c41410 100644 --- a/drivers/input/keyboard/omap4-keypad.c +++ b/drivers/input/keyboard/omap4-keypad.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <linux/platform_device.h> | 27 | #include <linux/platform_device.h> |
28 | #include <linux/errno.h> | 28 | #include <linux/errno.h> |
29 | #include <linux/io.h> | 29 | #include <linux/io.h> |
30 | #include <linux/of.h> | ||
30 | #include <linux/input.h> | 31 | #include <linux/input.h> |
31 | #include <linux/slab.h> | 32 | #include <linux/slab.h> |
32 | #include <linux/pm_runtime.h> | 33 | #include <linux/pm_runtime.h> |
@@ -84,8 +85,9 @@ struct omap4_keypad { | |||
84 | u32 reg_offset; | 85 | u32 reg_offset; |
85 | u32 irqreg_offset; | 86 | u32 irqreg_offset; |
86 | unsigned int row_shift; | 87 | unsigned int row_shift; |
88 | bool no_autorepeat; | ||
87 | unsigned char key_state[8]; | 89 | unsigned char key_state[8]; |
88 | unsigned short keymap[]; | 90 | unsigned short *keymap; |
89 | }; | 91 | }; |
90 | 92 | ||
91 | static int kbd_readl(struct omap4_keypad *keypad_data, u32 offset) | 93 | static int kbd_readl(struct omap4_keypad *keypad_data, u32 offset) |
@@ -208,25 +210,51 @@ static void omap4_keypad_close(struct input_dev *input) | |||
208 | pm_runtime_put_sync(input->dev.parent); | 210 | pm_runtime_put_sync(input->dev.parent); |
209 | } | 211 | } |
210 | 212 | ||
213 | #ifdef CONFIG_OF | ||
214 | static int __devinit omap4_keypad_parse_dt(struct device *dev, | ||
215 | struct omap4_keypad *keypad_data) | ||
216 | { | ||
217 | struct device_node *np = dev->of_node; | ||
218 | |||
219 | if (!np) { | ||
220 | dev_err(dev, "missing DT data"); | ||
221 | return -EINVAL; | ||
222 | } | ||
223 | |||
224 | of_property_read_u32(np, "keypad,num-rows", &keypad_data->rows); | ||
225 | of_property_read_u32(np, "keypad,num-columns", &keypad_data->cols); | ||
226 | if (!keypad_data->rows || !keypad_data->cols) { | ||
227 | dev_err(dev, "number of keypad rows/columns not specified\n"); | ||
228 | return -EINVAL; | ||
229 | } | ||
230 | |||
231 | if (of_get_property(np, "linux,input-no-autorepeat", NULL)) | ||
232 | keypad_data->no_autorepeat = true; | ||
233 | |||
234 | return 0; | ||
235 | } | ||
236 | #else | ||
237 | static inline int omap4_keypad_parse_dt(struct device *dev, | ||
238 | struct omap4_keypad *keypad_data) | ||
239 | { | ||
240 | return -ENOSYS; | ||
241 | } | ||
242 | #endif | ||
243 | |||
211 | static int __devinit omap4_keypad_probe(struct platform_device *pdev) | 244 | static int __devinit omap4_keypad_probe(struct platform_device *pdev) |
212 | { | 245 | { |
213 | const struct omap4_keypad_platform_data *pdata; | 246 | const struct omap4_keypad_platform_data *pdata = |
247 | dev_get_platdata(&pdev->dev); | ||
248 | const struct matrix_keymap_data *keymap_data = | ||
249 | pdata ? pdata->keymap_data : NULL; | ||
214 | struct omap4_keypad *keypad_data; | 250 | struct omap4_keypad *keypad_data; |
215 | struct input_dev *input_dev; | 251 | struct input_dev *input_dev; |
216 | struct resource *res; | 252 | struct resource *res; |
217 | resource_size_t size; | 253 | unsigned int max_keys; |
218 | unsigned int row_shift, max_keys; | ||
219 | int rev; | 254 | int rev; |
220 | int irq; | 255 | int irq; |
221 | int error; | 256 | int error; |
222 | 257 | ||
223 | /* platform data */ | ||
224 | pdata = pdev->dev.platform_data; | ||
225 | if (!pdata) { | ||
226 | dev_err(&pdev->dev, "no platform data defined\n"); | ||
227 | return -EINVAL; | ||
228 | } | ||
229 | |||
230 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 258 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
231 | if (!res) { | 259 | if (!res) { |
232 | dev_err(&pdev->dev, "no base address specified\n"); | 260 | dev_err(&pdev->dev, "no base address specified\n"); |
@@ -239,25 +267,24 @@ static int __devinit omap4_keypad_probe(struct platform_device *pdev) | |||
239 | return -EINVAL; | 267 | return -EINVAL; |
240 | } | 268 | } |
241 | 269 | ||
242 | if (!pdata->keymap_data) { | 270 | keypad_data = kzalloc(sizeof(struct omap4_keypad), GFP_KERNEL); |
243 | dev_err(&pdev->dev, "no keymap data defined\n"); | ||
244 | return -EINVAL; | ||
245 | } | ||
246 | |||
247 | row_shift = get_count_order(pdata->cols); | ||
248 | max_keys = pdata->rows << row_shift; | ||
249 | |||
250 | keypad_data = kzalloc(sizeof(struct omap4_keypad) + | ||
251 | max_keys * sizeof(keypad_data->keymap[0]), | ||
252 | GFP_KERNEL); | ||
253 | if (!keypad_data) { | 271 | if (!keypad_data) { |
254 | dev_err(&pdev->dev, "keypad_data memory allocation failed\n"); | 272 | dev_err(&pdev->dev, "keypad_data memory allocation failed\n"); |
255 | return -ENOMEM; | 273 | return -ENOMEM; |
256 | } | 274 | } |
257 | 275 | ||
258 | size = resource_size(res); | 276 | keypad_data->irq = irq; |
277 | |||
278 | if (pdata) { | ||
279 | keypad_data->rows = pdata->rows; | ||
280 | keypad_data->cols = pdata->cols; | ||
281 | } else { | ||
282 | error = omap4_keypad_parse_dt(&pdev->dev, keypad_data); | ||
283 | if (error) | ||
284 | return error; | ||
285 | } | ||
259 | 286 | ||
260 | res = request_mem_region(res->start, size, pdev->name); | 287 | res = request_mem_region(res->start, resource_size(res), pdev->name); |
261 | if (!res) { | 288 | if (!res) { |
262 | dev_err(&pdev->dev, "can't request mem region\n"); | 289 | dev_err(&pdev->dev, "can't request mem region\n"); |
263 | error = -EBUSY; | 290 | error = -EBUSY; |
@@ -271,15 +298,11 @@ static int __devinit omap4_keypad_probe(struct platform_device *pdev) | |||
271 | goto err_release_mem; | 298 | goto err_release_mem; |
272 | } | 299 | } |
273 | 300 | ||
274 | keypad_data->irq = irq; | ||
275 | keypad_data->row_shift = row_shift; | ||
276 | keypad_data->rows = pdata->rows; | ||
277 | keypad_data->cols = pdata->cols; | ||
278 | 301 | ||
279 | /* | 302 | /* |
280 | * Enable clocks for the keypad module so that we can read | 303 | * Enable clocks for the keypad module so that we can read |
281 | * revision register. | 304 | * revision register. |
282 | */ | 305 | */ |
283 | pm_runtime_enable(&pdev->dev); | 306 | pm_runtime_enable(&pdev->dev); |
284 | error = pm_runtime_get_sync(&pdev->dev); | 307 | error = pm_runtime_get_sync(&pdev->dev); |
285 | if (error) { | 308 | if (error) { |
@@ -322,19 +345,30 @@ static int __devinit omap4_keypad_probe(struct platform_device *pdev) | |||
322 | input_dev->open = omap4_keypad_open; | 345 | input_dev->open = omap4_keypad_open; |
323 | input_dev->close = omap4_keypad_close; | 346 | input_dev->close = omap4_keypad_close; |
324 | 347 | ||
325 | error = matrix_keypad_build_keymap(pdata->keymap_data, NULL, | 348 | input_set_capability(input_dev, EV_MSC, MSC_SCAN); |
326 | pdata->rows, pdata->cols, | 349 | if (!keypad_data->no_autorepeat) |
350 | __set_bit(EV_REP, input_dev->evbit); | ||
351 | |||
352 | input_set_drvdata(input_dev, keypad_data); | ||
353 | |||
354 | keypad_data->row_shift = get_count_order(keypad_data->cols); | ||
355 | max_keys = keypad_data->rows << keypad_data->row_shift; | ||
356 | keypad_data->keymap = kzalloc(max_keys * sizeof(keypad_data->keymap[0]), | ||
357 | GFP_KERNEL); | ||
358 | if (!keypad_data->keymap) { | ||
359 | dev_err(&pdev->dev, "Not enough memory for keymap\n"); | ||
360 | error = -ENOMEM; | ||
361 | goto err_free_input; | ||
362 | } | ||
363 | |||
364 | error = matrix_keypad_build_keymap(keymap_data, NULL, | ||
365 | keypad_data->rows, keypad_data->cols, | ||
327 | keypad_data->keymap, input_dev); | 366 | keypad_data->keymap, input_dev); |
328 | if (error) { | 367 | if (error) { |
329 | dev_err(&pdev->dev, "failed to build keymap\n"); | 368 | dev_err(&pdev->dev, "failed to build keymap\n"); |
330 | goto err_free_input; | 369 | goto err_free_keymap; |
331 | } | 370 | } |
332 | 371 | ||
333 | __set_bit(EV_REP, input_dev->evbit); | ||
334 | input_set_capability(input_dev, EV_MSC, MSC_SCAN); | ||
335 | |||
336 | input_set_drvdata(input_dev, keypad_data); | ||
337 | |||
338 | error = request_irq(keypad_data->irq, omap4_keypad_interrupt, | 372 | error = request_irq(keypad_data->irq, omap4_keypad_interrupt, |
339 | IRQF_TRIGGER_RISING, | 373 | IRQF_TRIGGER_RISING, |
340 | "omap4-keypad", keypad_data); | 374 | "omap4-keypad", keypad_data); |
@@ -357,6 +391,8 @@ static int __devinit omap4_keypad_probe(struct platform_device *pdev) | |||
357 | err_pm_disable: | 391 | err_pm_disable: |
358 | pm_runtime_disable(&pdev->dev); | 392 | pm_runtime_disable(&pdev->dev); |
359 | free_irq(keypad_data->irq, keypad_data); | 393 | free_irq(keypad_data->irq, keypad_data); |
394 | err_free_keymap: | ||
395 | kfree(keypad_data->keymap); | ||
360 | err_free_input: | 396 | err_free_input: |
361 | input_free_device(input_dev); | 397 | input_free_device(input_dev); |
362 | err_pm_put_sync: | 398 | err_pm_put_sync: |
@@ -364,7 +400,7 @@ err_pm_put_sync: | |||
364 | err_unmap: | 400 | err_unmap: |
365 | iounmap(keypad_data->base); | 401 | iounmap(keypad_data->base); |
366 | err_release_mem: | 402 | err_release_mem: |
367 | release_mem_region(res->start, size); | 403 | release_mem_region(res->start, resource_size(res)); |
368 | err_free_keypad: | 404 | err_free_keypad: |
369 | kfree(keypad_data); | 405 | kfree(keypad_data); |
370 | return error; | 406 | return error; |
@@ -386,18 +422,29 @@ static int __devexit omap4_keypad_remove(struct platform_device *pdev) | |||
386 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 422 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
387 | release_mem_region(res->start, resource_size(res)); | 423 | release_mem_region(res->start, resource_size(res)); |
388 | 424 | ||
425 | kfree(keypad_data->keymap); | ||
389 | kfree(keypad_data); | 426 | kfree(keypad_data); |
427 | |||
390 | platform_set_drvdata(pdev, NULL); | 428 | platform_set_drvdata(pdev, NULL); |
391 | 429 | ||
392 | return 0; | 430 | return 0; |
393 | } | 431 | } |
394 | 432 | ||
433 | #ifdef CONFIG_OF | ||
434 | static const struct of_device_id omap_keypad_dt_match[] = { | ||
435 | { .compatible = "ti,omap4-keypad" }, | ||
436 | {}, | ||
437 | }; | ||
438 | MODULE_DEVICE_TABLE(of, omap_keypad_dt_match); | ||
439 | #endif | ||
440 | |||
395 | static struct platform_driver omap4_keypad_driver = { | 441 | static struct platform_driver omap4_keypad_driver = { |
396 | .probe = omap4_keypad_probe, | 442 | .probe = omap4_keypad_probe, |
397 | .remove = __devexit_p(omap4_keypad_remove), | 443 | .remove = __devexit_p(omap4_keypad_remove), |
398 | .driver = { | 444 | .driver = { |
399 | .name = "omap4-keypad", | 445 | .name = "omap4-keypad", |
400 | .owner = THIS_MODULE, | 446 | .owner = THIS_MODULE, |
447 | .of_match_table = of_match_ptr(omap_keypad_dt_match), | ||
401 | }, | 448 | }, |
402 | }; | 449 | }; |
403 | module_platform_driver(omap4_keypad_driver); | 450 | module_platform_driver(omap4_keypad_driver); |