diff options
| author | Laxman Dewangan <ldewangan@nvidia.com> | 2013-03-31 03:41:12 -0400 |
|---|---|---|
| committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2013-03-31 03:48:29 -0400 |
| commit | e10af9e79a97ac5d305ec1be94338e8d3fd7aaa4 (patch) | |
| tree | 097a883b2be59488f84d4415ba5cfd86ac221ef8 /drivers | |
| parent | da5bce199fa9209c462259125f9a0144adf6885c (diff) | |
Input: tegra-kbc - support for defining row/columns based on SoC
NVIDIA's Tegra20 and Tegra30 supports the 16x8 keyboard matrix and T114
support the 11x8 Key matrix.
Add support for defining the maximum row/columns based on SoC through
proper compatibility.
Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com>
Reviewed-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/input/keyboard/tegra-kbc.c | 80 |
1 files changed, 62 insertions, 18 deletions
diff --git a/drivers/input/keyboard/tegra-kbc.c b/drivers/input/keyboard/tegra-kbc.c index 68b2b65024d6..b46142f78ef2 100644 --- a/drivers/input/keyboard/tegra-kbc.c +++ b/drivers/input/keyboard/tegra-kbc.c | |||
| @@ -27,18 +27,19 @@ | |||
| 27 | #include <linux/io.h> | 27 | #include <linux/io.h> |
| 28 | #include <linux/interrupt.h> | 28 | #include <linux/interrupt.h> |
| 29 | #include <linux/of.h> | 29 | #include <linux/of.h> |
| 30 | #include <linux/of_device.h> | ||
| 30 | #include <linux/clk.h> | 31 | #include <linux/clk.h> |
| 31 | #include <linux/slab.h> | 32 | #include <linux/slab.h> |
| 32 | #include <linux/input/matrix_keypad.h> | 33 | #include <linux/input/matrix_keypad.h> |
| 33 | #include <linux/clk/tegra.h> | 34 | #include <linux/clk/tegra.h> |
| 34 | #include <linux/err.h> | 35 | #include <linux/err.h> |
| 35 | 36 | ||
| 36 | #define KBC_MAX_GPIO 24 | ||
| 37 | #define KBC_MAX_KPENT 8 | 37 | #define KBC_MAX_KPENT 8 |
| 38 | 38 | ||
| 39 | #define KBC_MAX_ROW 16 | 39 | /* Maximum row/column supported by Tegra KBC yet is 16x8 */ |
| 40 | #define KBC_MAX_COL 8 | 40 | #define KBC_MAX_GPIO 24 |
| 41 | #define KBC_MAX_KEY (KBC_MAX_ROW * KBC_MAX_COL) | 41 | /* Maximum keys supported by Tegra KBC yet is 16 x 8*/ |
| 42 | #define KBC_MAX_KEY (16 * 8) | ||
| 42 | 43 | ||
| 43 | #define KBC_MAX_DEBOUNCE_CNT 0x3ffu | 44 | #define KBC_MAX_DEBOUNCE_CNT 0x3ffu |
| 44 | 45 | ||
| @@ -81,6 +82,12 @@ enum tegra_pin_type { | |||
| 81 | PIN_CFG_ROW, | 82 | PIN_CFG_ROW, |
| 82 | }; | 83 | }; |
| 83 | 84 | ||
| 85 | /* Tegra KBC hw support */ | ||
| 86 | struct tegra_kbc_hw_support { | ||
| 87 | int max_rows; | ||
| 88 | int max_columns; | ||
| 89 | }; | ||
| 90 | |||
| 84 | struct tegra_kbc_pin_cfg { | 91 | struct tegra_kbc_pin_cfg { |
| 85 | enum tegra_pin_type type; | 92 | enum tegra_pin_type type; |
| 86 | unsigned char num; | 93 | unsigned char num; |
| @@ -109,6 +116,9 @@ struct tegra_kbc { | |||
| 109 | u32 wakeup_key; | 116 | u32 wakeup_key; |
| 110 | struct timer_list timer; | 117 | struct timer_list timer; |
| 111 | struct clk *clk; | 118 | struct clk *clk; |
| 119 | const struct tegra_kbc_hw_support *hw_support; | ||
| 120 | int max_keys; | ||
| 121 | int num_rows_and_columns; | ||
| 112 | }; | 122 | }; |
| 113 | 123 | ||
| 114 | static void tegra_kbc_report_released_keys(struct input_dev *input, | 124 | static void tegra_kbc_report_released_keys(struct input_dev *input, |
| @@ -205,11 +215,11 @@ static void tegra_kbc_report_keys(struct tegra_kbc *kbc) | |||
| 205 | 215 | ||
| 206 | /* | 216 | /* |
| 207 | * If the platform uses Fn keymaps, translate keys on a Fn keypress. | 217 | * If the platform uses Fn keymaps, translate keys on a Fn keypress. |
| 208 | * Function keycodes are KBC_MAX_KEY apart from the plain keycodes. | 218 | * Function keycodes are max_keys apart from the plain keycodes. |
| 209 | */ | 219 | */ |
| 210 | if (fn_keypress) { | 220 | if (fn_keypress) { |
| 211 | for (i = 0; i < num_down; i++) { | 221 | for (i = 0; i < num_down; i++) { |
| 212 | scancodes[i] += KBC_MAX_KEY; | 222 | scancodes[i] += kbc->max_keys; |
| 213 | keycodes[i] = kbc->keycode[scancodes[i]]; | 223 | keycodes[i] = kbc->keycode[scancodes[i]]; |
| 214 | } | 224 | } |
| 215 | } | 225 | } |
| @@ -316,7 +326,7 @@ static void tegra_kbc_setup_wakekeys(struct tegra_kbc *kbc, bool filter) | |||
| 316 | /* Either mask all keys or none. */ | 326 | /* Either mask all keys or none. */ |
| 317 | rst_val = (filter && !kbc->wakeup) ? ~0 : 0; | 327 | rst_val = (filter && !kbc->wakeup) ? ~0 : 0; |
| 318 | 328 | ||
| 319 | for (i = 0; i < KBC_MAX_ROW; i++) | 329 | for (i = 0; i < kbc->hw_support->max_rows; i++) |
| 320 | writel(rst_val, kbc->mmio + KBC_ROW0_MASK_0 + i * 4); | 330 | writel(rst_val, kbc->mmio + KBC_ROW0_MASK_0 + i * 4); |
| 321 | } | 331 | } |
| 322 | 332 | ||
| @@ -453,7 +463,7 @@ static bool tegra_kbc_check_pin_cfg(const struct tegra_kbc *kbc, | |||
| 453 | 463 | ||
| 454 | switch (pin_cfg->type) { | 464 | switch (pin_cfg->type) { |
| 455 | case PIN_CFG_ROW: | 465 | case PIN_CFG_ROW: |
| 456 | if (pin_cfg->num >= KBC_MAX_ROW) { | 466 | if (pin_cfg->num >= kbc->hw_support->max_rows) { |
| 457 | dev_err(kbc->dev, | 467 | dev_err(kbc->dev, |
| 458 | "pin_cfg[%d]: invalid row number %d\n", | 468 | "pin_cfg[%d]: invalid row number %d\n", |
| 459 | i, pin_cfg->num); | 469 | i, pin_cfg->num); |
| @@ -463,7 +473,7 @@ static bool tegra_kbc_check_pin_cfg(const struct tegra_kbc *kbc, | |||
| 463 | break; | 473 | break; |
| 464 | 474 | ||
| 465 | case PIN_CFG_COL: | 475 | case PIN_CFG_COL: |
| 466 | if (pin_cfg->num >= KBC_MAX_COL) { | 476 | if (pin_cfg->num >= kbc->hw_support->max_columns) { |
| 467 | dev_err(kbc->dev, | 477 | dev_err(kbc->dev, |
| 468 | "pin_cfg[%d]: invalid column number %d\n", | 478 | "pin_cfg[%d]: invalid column number %d\n", |
| 469 | i, pin_cfg->num); | 479 | i, pin_cfg->num); |
| @@ -521,6 +531,18 @@ static int tegra_kbc_parse_dt(struct tegra_kbc *kbc) | |||
| 521 | } | 531 | } |
| 522 | num_cols = proplen / sizeof(u32); | 532 | num_cols = proplen / sizeof(u32); |
| 523 | 533 | ||
| 534 | if (num_rows > kbc->hw_support->max_rows) { | ||
| 535 | dev_err(kbc->dev, | ||
| 536 | "Number of rows is more than supported by hardware\n"); | ||
| 537 | return -EINVAL; | ||
| 538 | } | ||
| 539 | |||
| 540 | if (num_cols > kbc->hw_support->max_columns) { | ||
| 541 | dev_err(kbc->dev, | ||
| 542 | "Number of cols is more than supported by hardware\n"); | ||
| 543 | return -EINVAL; | ||
| 544 | } | ||
| 545 | |||
| 524 | if (!of_get_property(np, "linux,keymap", &proplen)) { | 546 | if (!of_get_property(np, "linux,keymap", &proplen)) { |
| 525 | dev_err(kbc->dev, "property linux,keymap not found\n"); | 547 | dev_err(kbc->dev, "property linux,keymap not found\n"); |
| 526 | return -ENOENT; | 548 | return -ENOENT; |
| @@ -533,7 +555,7 @@ static int tegra_kbc_parse_dt(struct tegra_kbc *kbc) | |||
| 533 | } | 555 | } |
| 534 | 556 | ||
| 535 | /* Set all pins as non-configured */ | 557 | /* Set all pins as non-configured */ |
| 536 | for (i = 0; i < KBC_MAX_GPIO; i++) | 558 | for (i = 0; i < kbc->num_rows_and_columns; i++) |
| 537 | kbc->pin_cfg[i].type = PIN_CFG_IGNORE; | 559 | kbc->pin_cfg[i].type = PIN_CFG_IGNORE; |
| 538 | 560 | ||
| 539 | ret = of_property_read_u32_array(np, "nvidia,kbc-row-pins", | 561 | ret = of_property_read_u32_array(np, "nvidia,kbc-row-pins", |
| @@ -563,6 +585,24 @@ static int tegra_kbc_parse_dt(struct tegra_kbc *kbc) | |||
| 563 | return 0; | 585 | return 0; |
| 564 | } | 586 | } |
| 565 | 587 | ||
| 588 | static const struct tegra_kbc_hw_support tegra20_kbc_hw_support = { | ||
| 589 | .max_rows = 16, | ||
| 590 | .max_columns = 8, | ||
| 591 | }; | ||
| 592 | |||
| 593 | static const struct tegra_kbc_hw_support tegra11_kbc_hw_support = { | ||
| 594 | .max_rows = 11, | ||
| 595 | .max_columns = 8, | ||
| 596 | }; | ||
| 597 | |||
| 598 | static const struct of_device_id tegra_kbc_of_match[] = { | ||
| 599 | { .compatible = "nvidia,tegra114-kbc", .data = &tegra11_kbc_hw_support}, | ||
| 600 | { .compatible = "nvidia,tegra30-kbc", .data = &tegra20_kbc_hw_support}, | ||
| 601 | { .compatible = "nvidia,tegra20-kbc", .data = &tegra20_kbc_hw_support}, | ||
| 602 | { }, | ||
| 603 | }; | ||
| 604 | MODULE_DEVICE_TABLE(of, tegra_kbc_of_match); | ||
| 605 | |||
| 566 | static int tegra_kbc_probe(struct platform_device *pdev) | 606 | static int tegra_kbc_probe(struct platform_device *pdev) |
| 567 | { | 607 | { |
| 568 | struct tegra_kbc *kbc; | 608 | struct tegra_kbc *kbc; |
| @@ -571,7 +611,10 @@ static int tegra_kbc_probe(struct platform_device *pdev) | |||
| 571 | int num_rows = 0; | 611 | int num_rows = 0; |
| 572 | unsigned int debounce_cnt; | 612 | unsigned int debounce_cnt; |
| 573 | unsigned int scan_time_rows; | 613 | unsigned int scan_time_rows; |
| 574 | unsigned int keymap_rows = KBC_MAX_KEY; | 614 | unsigned int keymap_rows; |
| 615 | const struct of_device_id *match; | ||
| 616 | |||
| 617 | match = of_match_device(of_match_ptr(tegra_kbc_of_match), &pdev->dev); | ||
| 575 | 618 | ||
| 576 | kbc = devm_kzalloc(&pdev->dev, sizeof(*kbc), GFP_KERNEL); | 619 | kbc = devm_kzalloc(&pdev->dev, sizeof(*kbc), GFP_KERNEL); |
| 577 | if (!kbc) { | 620 | if (!kbc) { |
| @@ -580,6 +623,12 @@ static int tegra_kbc_probe(struct platform_device *pdev) | |||
| 580 | } | 623 | } |
| 581 | 624 | ||
| 582 | kbc->dev = &pdev->dev; | 625 | kbc->dev = &pdev->dev; |
| 626 | kbc->hw_support = match->data; | ||
| 627 | kbc->max_keys = kbc->hw_support->max_rows * | ||
| 628 | kbc->hw_support->max_columns; | ||
| 629 | kbc->num_rows_and_columns = kbc->hw_support->max_rows + | ||
| 630 | kbc->hw_support->max_columns; | ||
| 631 | keymap_rows = kbc->max_keys; | ||
| 583 | spin_lock_init(&kbc->lock); | 632 | spin_lock_init(&kbc->lock); |
| 584 | 633 | ||
| 585 | err = tegra_kbc_parse_dt(kbc); | 634 | err = tegra_kbc_parse_dt(kbc); |
| @@ -640,7 +689,8 @@ static int tegra_kbc_probe(struct platform_device *pdev) | |||
| 640 | keymap_rows *= 2; | 689 | keymap_rows *= 2; |
| 641 | 690 | ||
| 642 | err = matrix_keypad_build_keymap(kbc->keymap_data, NULL, | 691 | err = matrix_keypad_build_keymap(kbc->keymap_data, NULL, |
| 643 | keymap_rows, KBC_MAX_COL, | 692 | keymap_rows, |
| 693 | kbc->hw_support->max_columns, | ||
| 644 | kbc->keycode, kbc->idev); | 694 | kbc->keycode, kbc->idev); |
| 645 | if (err) { | 695 | if (err) { |
| 646 | dev_err(&pdev->dev, "failed to setup keymap\n"); | 696 | dev_err(&pdev->dev, "failed to setup keymap\n"); |
| @@ -766,12 +816,6 @@ static int tegra_kbc_resume(struct device *dev) | |||
| 766 | 816 | ||
| 767 | static SIMPLE_DEV_PM_OPS(tegra_kbc_pm_ops, tegra_kbc_suspend, tegra_kbc_resume); | 817 | static SIMPLE_DEV_PM_OPS(tegra_kbc_pm_ops, tegra_kbc_suspend, tegra_kbc_resume); |
| 768 | 818 | ||
| 769 | static const struct of_device_id tegra_kbc_of_match[] = { | ||
| 770 | { .compatible = "nvidia,tegra20-kbc", }, | ||
| 771 | { }, | ||
| 772 | }; | ||
| 773 | MODULE_DEVICE_TABLE(of, tegra_kbc_of_match); | ||
| 774 | |||
| 775 | static struct platform_driver tegra_kbc_driver = { | 819 | static struct platform_driver tegra_kbc_driver = { |
| 776 | .probe = tegra_kbc_probe, | 820 | .probe = tegra_kbc_probe, |
| 777 | .driver = { | 821 | .driver = { |
