diff options
author | Sebastian Reichel <sre@debian.org> | 2014-01-04 03:41:03 -0500 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2014-01-04 03:47:37 -0500 |
commit | 7abf38d6d13c9e3e3b9e4d7d8d7a68a353279d11 (patch) | |
tree | 08fe799cadec0e31bee634624f36a0b47812ecff /drivers/input/keyboard/twl4030_keypad.c | |
parent | f048dd1725c85356517c90f7ecf6bdd9f47d4bf3 (diff) |
Input: twl4030-keypad - add device tree support
Add device tree support for twl4030 keypad driver.
Tested on Nokia N900.
Signed-off-by: Sebastian Reichel <sre@debian.org>
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Diffstat (limited to 'drivers/input/keyboard/twl4030_keypad.c')
-rw-r--r-- | drivers/input/keyboard/twl4030_keypad.c | 67 |
1 files changed, 50 insertions, 17 deletions
diff --git a/drivers/input/keyboard/twl4030_keypad.c b/drivers/input/keyboard/twl4030_keypad.c index 8bc2879b4c87..f663c1953bad 100644 --- a/drivers/input/keyboard/twl4030_keypad.c +++ b/drivers/input/keyboard/twl4030_keypad.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <linux/platform_device.h> | 33 | #include <linux/platform_device.h> |
34 | #include <linux/i2c/twl.h> | 34 | #include <linux/i2c/twl.h> |
35 | #include <linux/slab.h> | 35 | #include <linux/slab.h> |
36 | #include <linux/of.h> | ||
36 | 37 | ||
37 | /* | 38 | /* |
38 | * The TWL4030 family chips include a keypad controller that supports | 39 | * The TWL4030 family chips include a keypad controller that supports |
@@ -60,6 +61,7 @@ | |||
60 | struct twl4030_keypad { | 61 | struct twl4030_keypad { |
61 | unsigned short keymap[TWL4030_KEYMAP_SIZE]; | 62 | unsigned short keymap[TWL4030_KEYMAP_SIZE]; |
62 | u16 kp_state[TWL4030_MAX_ROWS]; | 63 | u16 kp_state[TWL4030_MAX_ROWS]; |
64 | bool autorepeat; | ||
63 | unsigned n_rows; | 65 | unsigned n_rows; |
64 | unsigned n_cols; | 66 | unsigned n_cols; |
65 | unsigned irq; | 67 | unsigned irq; |
@@ -331,20 +333,12 @@ static int twl4030_kp_program(struct twl4030_keypad *kp) | |||
331 | static int twl4030_kp_probe(struct platform_device *pdev) | 333 | static int twl4030_kp_probe(struct platform_device *pdev) |
332 | { | 334 | { |
333 | struct twl4030_keypad_data *pdata = dev_get_platdata(&pdev->dev); | 335 | struct twl4030_keypad_data *pdata = dev_get_platdata(&pdev->dev); |
334 | const struct matrix_keymap_data *keymap_data; | 336 | const struct matrix_keymap_data *keymap_data = NULL; |
335 | struct twl4030_keypad *kp; | 337 | struct twl4030_keypad *kp; |
336 | struct input_dev *input; | 338 | struct input_dev *input; |
337 | u8 reg; | 339 | u8 reg; |
338 | int error; | 340 | int error; |
339 | 341 | ||
340 | if (!pdata || !pdata->rows || !pdata->cols || !pdata->keymap_data || | ||
341 | pdata->rows > TWL4030_MAX_ROWS || pdata->cols > TWL4030_MAX_COLS) { | ||
342 | dev_err(&pdev->dev, "Invalid platform_data\n"); | ||
343 | return -EINVAL; | ||
344 | } | ||
345 | |||
346 | keymap_data = pdata->keymap_data; | ||
347 | |||
348 | kp = kzalloc(sizeof(*kp), GFP_KERNEL); | 342 | kp = kzalloc(sizeof(*kp), GFP_KERNEL); |
349 | input = input_allocate_device(); | 343 | input = input_allocate_device(); |
350 | if (!kp || !input) { | 344 | if (!kp || !input) { |
@@ -352,13 +346,9 @@ static int twl4030_kp_probe(struct platform_device *pdev) | |||
352 | goto err1; | 346 | goto err1; |
353 | } | 347 | } |
354 | 348 | ||
355 | /* Get the debug Device */ | 349 | /* get the debug device */ |
356 | kp->dbg_dev = &pdev->dev; | 350 | kp->dbg_dev = &pdev->dev; |
357 | kp->input = input; | 351 | kp->input = input; |
358 | |||
359 | kp->n_rows = pdata->rows; | ||
360 | kp->n_cols = pdata->cols; | ||
361 | kp->irq = platform_get_irq(pdev, 0); | ||
362 | 352 | ||
363 | /* setup input device */ | 353 | /* setup input device */ |
364 | input->name = "TWL4030 Keypad"; | 354 | input->name = "TWL4030 Keypad"; |
@@ -370,6 +360,40 @@ static int twl4030_kp_probe(struct platform_device *pdev) | |||
370 | input->id.product = 0x0001; | 360 | input->id.product = 0x0001; |
371 | input->id.version = 0x0003; | 361 | input->id.version = 0x0003; |
372 | 362 | ||
363 | if (pdata) { | ||
364 | if (!pdata->rows || !pdata->cols || !pdata->keymap_data) { | ||
365 | dev_err(&pdev->dev, "Missing platform_data\n"); | ||
366 | error = -EINVAL; | ||
367 | goto err1; | ||
368 | } | ||
369 | |||
370 | kp->n_rows = pdata->rows; | ||
371 | kp->n_cols = pdata->cols; | ||
372 | kp->autorepeat = pdata->rep; | ||
373 | keymap_data = pdata->keymap_data; | ||
374 | } else { | ||
375 | error = matrix_keypad_parse_of_params(&pdev->dev, &kp->n_rows, | ||
376 | &kp->n_cols); | ||
377 | if (error) | ||
378 | goto err1; | ||
379 | |||
380 | kp->autorepeat = true; | ||
381 | } | ||
382 | |||
383 | if (kp->n_rows > TWL4030_MAX_ROWS || kp->n_cols > TWL4030_MAX_COLS) { | ||
384 | dev_err(&pdev->dev, | ||
385 | "Invalid rows/cols amount specified in platform/devicetree data\n"); | ||
386 | error = -EINVAL; | ||
387 | goto err1; | ||
388 | } | ||
389 | |||
390 | kp->irq = platform_get_irq(pdev, 0); | ||
391 | if (!kp->irq) { | ||
392 | dev_err(&pdev->dev, "no keyboard irq assigned\n"); | ||
393 | error = -EINVAL; | ||
394 | goto err1; | ||
395 | } | ||
396 | |||
373 | error = matrix_keypad_build_keymap(keymap_data, NULL, | 397 | error = matrix_keypad_build_keymap(keymap_data, NULL, |
374 | TWL4030_MAX_ROWS, | 398 | TWL4030_MAX_ROWS, |
375 | 1 << TWL4030_ROW_SHIFT, | 399 | 1 << TWL4030_ROW_SHIFT, |
@@ -381,7 +405,7 @@ static int twl4030_kp_probe(struct platform_device *pdev) | |||
381 | 405 | ||
382 | input_set_capability(input, EV_MSC, MSC_SCAN); | 406 | input_set_capability(input, EV_MSC, MSC_SCAN); |
383 | /* Enable auto repeat feature of Linux input subsystem */ | 407 | /* Enable auto repeat feature of Linux input subsystem */ |
384 | if (pdata->rep) | 408 | if (kp->autorepeat) |
385 | __set_bit(EV_REP, input->evbit); | 409 | __set_bit(EV_REP, input->evbit); |
386 | 410 | ||
387 | error = input_register_device(input); | 411 | error = input_register_device(input); |
@@ -443,6 +467,14 @@ static int twl4030_kp_remove(struct platform_device *pdev) | |||
443 | return 0; | 467 | return 0; |
444 | } | 468 | } |
445 | 469 | ||
470 | #ifdef CONFIG_OF | ||
471 | static const struct of_device_id twl4030_keypad_dt_match_table[] = { | ||
472 | { .compatible = "ti,twl4030-keypad" }, | ||
473 | {}, | ||
474 | }; | ||
475 | MODULE_DEVICE_TABLE(of, twl4030_keypad_dt_match_table); | ||
476 | #endif | ||
477 | |||
446 | /* | 478 | /* |
447 | * NOTE: twl4030 are multi-function devices connected via I2C. | 479 | * NOTE: twl4030 are multi-function devices connected via I2C. |
448 | * So this device is a child of an I2C parent, thus it needs to | 480 | * So this device is a child of an I2C parent, thus it needs to |
@@ -455,6 +487,7 @@ static struct platform_driver twl4030_kp_driver = { | |||
455 | .driver = { | 487 | .driver = { |
456 | .name = "twl4030_keypad", | 488 | .name = "twl4030_keypad", |
457 | .owner = THIS_MODULE, | 489 | .owner = THIS_MODULE, |
490 | .of_match_table = of_match_ptr(twl4030_keypad_dt_match_table), | ||
458 | }, | 491 | }, |
459 | }; | 492 | }; |
460 | module_platform_driver(twl4030_kp_driver); | 493 | module_platform_driver(twl4030_kp_driver); |