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 | |
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>
-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 = { |