Skip to content

Commit

Permalink
Input: tegra-kbc - support for defining row/columns based on SoC
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Laxman Dewangan authored and Dmitry Torokhov committed Mar 31, 2013
1 parent da5bce1 commit e10af9e
Showing 1 changed file with 62 additions and 18 deletions.
80 changes: 62 additions & 18 deletions drivers/input/keyboard/tegra-kbc.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,18 +27,19 @@
#include <linux/io.h>
#include <linux/interrupt.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/clk.h>
#include <linux/slab.h>
#include <linux/input/matrix_keypad.h>
#include <linux/clk/tegra.h>
#include <linux/err.h>

#define KBC_MAX_GPIO 24
#define KBC_MAX_KPENT 8

#define KBC_MAX_ROW 16
#define KBC_MAX_COL 8
#define KBC_MAX_KEY (KBC_MAX_ROW * KBC_MAX_COL)
/* Maximum row/column supported by Tegra KBC yet is 16x8 */
#define KBC_MAX_GPIO 24
/* Maximum keys supported by Tegra KBC yet is 16 x 8*/
#define KBC_MAX_KEY (16 * 8)

#define KBC_MAX_DEBOUNCE_CNT 0x3ffu

Expand Down Expand Up @@ -81,6 +82,12 @@ enum tegra_pin_type {
PIN_CFG_ROW,
};

/* Tegra KBC hw support */
struct tegra_kbc_hw_support {
int max_rows;
int max_columns;
};

struct tegra_kbc_pin_cfg {
enum tegra_pin_type type;
unsigned char num;
Expand Down Expand Up @@ -109,6 +116,9 @@ struct tegra_kbc {
u32 wakeup_key;
struct timer_list timer;
struct clk *clk;
const struct tegra_kbc_hw_support *hw_support;
int max_keys;
int num_rows_and_columns;
};

static void tegra_kbc_report_released_keys(struct input_dev *input,
Expand Down Expand Up @@ -205,11 +215,11 @@ static void tegra_kbc_report_keys(struct tegra_kbc *kbc)

/*
* If the platform uses Fn keymaps, translate keys on a Fn keypress.
* Function keycodes are KBC_MAX_KEY apart from the plain keycodes.
* Function keycodes are max_keys apart from the plain keycodes.
*/
if (fn_keypress) {
for (i = 0; i < num_down; i++) {
scancodes[i] += KBC_MAX_KEY;
scancodes[i] += kbc->max_keys;
keycodes[i] = kbc->keycode[scancodes[i]];
}
}
Expand Down Expand Up @@ -316,7 +326,7 @@ static void tegra_kbc_setup_wakekeys(struct tegra_kbc *kbc, bool filter)
/* Either mask all keys or none. */
rst_val = (filter && !kbc->wakeup) ? ~0 : 0;

for (i = 0; i < KBC_MAX_ROW; i++)
for (i = 0; i < kbc->hw_support->max_rows; i++)
writel(rst_val, kbc->mmio + KBC_ROW0_MASK_0 + i * 4);
}

Expand Down Expand Up @@ -453,7 +463,7 @@ static bool tegra_kbc_check_pin_cfg(const struct tegra_kbc *kbc,

switch (pin_cfg->type) {
case PIN_CFG_ROW:
if (pin_cfg->num >= KBC_MAX_ROW) {
if (pin_cfg->num >= kbc->hw_support->max_rows) {
dev_err(kbc->dev,
"pin_cfg[%d]: invalid row number %d\n",
i, pin_cfg->num);
Expand All @@ -463,7 +473,7 @@ static bool tegra_kbc_check_pin_cfg(const struct tegra_kbc *kbc,
break;

case PIN_CFG_COL:
if (pin_cfg->num >= KBC_MAX_COL) {
if (pin_cfg->num >= kbc->hw_support->max_columns) {
dev_err(kbc->dev,
"pin_cfg[%d]: invalid column number %d\n",
i, pin_cfg->num);
Expand Down Expand Up @@ -521,6 +531,18 @@ static int tegra_kbc_parse_dt(struct tegra_kbc *kbc)
}
num_cols = proplen / sizeof(u32);

if (num_rows > kbc->hw_support->max_rows) {
dev_err(kbc->dev,
"Number of rows is more than supported by hardware\n");
return -EINVAL;
}

if (num_cols > kbc->hw_support->max_columns) {
dev_err(kbc->dev,
"Number of cols is more than supported by hardware\n");
return -EINVAL;
}

if (!of_get_property(np, "linux,keymap", &proplen)) {
dev_err(kbc->dev, "property linux,keymap not found\n");
return -ENOENT;
Expand All @@ -533,7 +555,7 @@ static int tegra_kbc_parse_dt(struct tegra_kbc *kbc)
}

/* Set all pins as non-configured */
for (i = 0; i < KBC_MAX_GPIO; i++)
for (i = 0; i < kbc->num_rows_and_columns; i++)
kbc->pin_cfg[i].type = PIN_CFG_IGNORE;

ret = of_property_read_u32_array(np, "nvidia,kbc-row-pins",
Expand Down Expand Up @@ -563,6 +585,24 @@ static int tegra_kbc_parse_dt(struct tegra_kbc *kbc)
return 0;
}

static const struct tegra_kbc_hw_support tegra20_kbc_hw_support = {
.max_rows = 16,
.max_columns = 8,
};

static const struct tegra_kbc_hw_support tegra11_kbc_hw_support = {
.max_rows = 11,
.max_columns = 8,
};

static const struct of_device_id tegra_kbc_of_match[] = {
{ .compatible = "nvidia,tegra114-kbc", .data = &tegra11_kbc_hw_support},
{ .compatible = "nvidia,tegra30-kbc", .data = &tegra20_kbc_hw_support},
{ .compatible = "nvidia,tegra20-kbc", .data = &tegra20_kbc_hw_support},
{ },
};
MODULE_DEVICE_TABLE(of, tegra_kbc_of_match);

static int tegra_kbc_probe(struct platform_device *pdev)
{
struct tegra_kbc *kbc;
Expand All @@ -571,7 +611,10 @@ static int tegra_kbc_probe(struct platform_device *pdev)
int num_rows = 0;
unsigned int debounce_cnt;
unsigned int scan_time_rows;
unsigned int keymap_rows = KBC_MAX_KEY;
unsigned int keymap_rows;
const struct of_device_id *match;

match = of_match_device(of_match_ptr(tegra_kbc_of_match), &pdev->dev);

kbc = devm_kzalloc(&pdev->dev, sizeof(*kbc), GFP_KERNEL);
if (!kbc) {
Expand All @@ -580,6 +623,12 @@ static int tegra_kbc_probe(struct platform_device *pdev)
}

kbc->dev = &pdev->dev;
kbc->hw_support = match->data;
kbc->max_keys = kbc->hw_support->max_rows *
kbc->hw_support->max_columns;
kbc->num_rows_and_columns = kbc->hw_support->max_rows +
kbc->hw_support->max_columns;
keymap_rows = kbc->max_keys;
spin_lock_init(&kbc->lock);

err = tegra_kbc_parse_dt(kbc);
Expand Down Expand Up @@ -640,7 +689,8 @@ static int tegra_kbc_probe(struct platform_device *pdev)
keymap_rows *= 2;

err = matrix_keypad_build_keymap(kbc->keymap_data, NULL,
keymap_rows, KBC_MAX_COL,
keymap_rows,
kbc->hw_support->max_columns,
kbc->keycode, kbc->idev);
if (err) {
dev_err(&pdev->dev, "failed to setup keymap\n");
Expand Down Expand Up @@ -766,12 +816,6 @@ static int tegra_kbc_resume(struct device *dev)

static SIMPLE_DEV_PM_OPS(tegra_kbc_pm_ops, tegra_kbc_suspend, tegra_kbc_resume);

static const struct of_device_id tegra_kbc_of_match[] = {
{ .compatible = "nvidia,tegra20-kbc", },
{ },
};
MODULE_DEVICE_TABLE(of, tegra_kbc_of_match);

static struct platform_driver tegra_kbc_driver = {
.probe = tegra_kbc_probe,
.driver = {
Expand Down

0 comments on commit e10af9e

Please sign in to comment.