diff options
| author | Sourav Poddar <sourav.poddar@ti.com> | 2012-07-13 03:10:47 -0400 |
|---|---|---|
| committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2012-07-18 02:16:07 -0400 |
| commit | 13987435cc28eab6e562e878e71b521e7ef5c860 (patch) | |
| tree | 92283f54561ec3c7499a736efbbb97499594f447 | |
| parent | 8a90c034ae0d4282e2aeb9cf8311dc90c855d815 (diff) | |
Input: omap4-keypad - add device tree support
Add device tree support for omap4 keypad driver and update the
Documentation with omap4 keypad device tree binding information.
Tested on omap4430 sdp.
Signed-off-by: Sourav Poddar <sourav.poddar@ti.com>
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
| -rw-r--r-- | Documentation/devicetree/bindings/input/omap-keypad.txt | 31 | ||||
| -rw-r--r-- | drivers/input/keyboard/omap4-keypad.c | 127 |
2 files changed, 118 insertions, 40 deletions
diff --git a/Documentation/devicetree/bindings/input/omap-keypad.txt b/Documentation/devicetree/bindings/input/omap-keypad.txt new file mode 100644 index 000000000000..f2fa5e10493d --- /dev/null +++ b/Documentation/devicetree/bindings/input/omap-keypad.txt | |||
| @@ -0,0 +1,31 @@ | |||
| 1 | * TI's Keypad Controller device tree bindings | ||
| 2 | |||
| 3 | TI's Keypad controller is used to interface a SoC with a matrix-type | ||
| 4 | keypad device. The keypad controller supports multiple row and column lines. | ||
| 5 | A key can be placed at each intersection of a unique row and a unique column. | ||
| 6 | The keypad controller can sense a key-press and key-release and report the | ||
| 7 | event using a interrupt to the cpu. | ||
| 8 | |||
| 9 | Required SoC Specific Properties: | ||
| 10 | - compatible: should be one of the following | ||
| 11 | - "ti,omap4-keypad": For controllers compatible with omap4 keypad | ||
| 12 | controller. | ||
| 13 | |||
| 14 | Required Board Specific Properties, in addition to those specified by | ||
| 15 | the shared matrix-keyboard bindings: | ||
| 16 | - keypad,num-rows: Number of row lines connected to the keypad | ||
| 17 | controller. | ||
| 18 | |||
| 19 | - keypad,num-columns: Number of column lines connected to the | ||
| 20 | keypad controller. | ||
| 21 | |||
| 22 | Optional Properties specific to linux: | ||
| 23 | - linux,keypad-no-autorepeat: do no enable autorepeat feature. | ||
| 24 | |||
| 25 | Example: | ||
| 26 | keypad@4ae1c000{ | ||
| 27 | compatible = "ti,omap4-keypad"; | ||
| 28 | keypad,num-rows = <2>; | ||
| 29 | keypad,num-columns = <8>; | ||
| 30 | linux,keypad-no-autorepeat; | ||
| 31 | }; | ||
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); |
