summaryrefslogtreecommitdiffstats
path: root/drivers/input/keyboard
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/input/keyboard')
-rw-r--r--drivers/input/keyboard/Kconfig11
-rw-r--r--drivers/input/keyboard/Makefile1
-rw-r--r--drivers/input/keyboard/amikbd.c1
-rw-r--r--drivers/input/keyboard/bf54x-keys.c2
-rw-r--r--drivers/input/keyboard/davinci_keyscan.c2
-rw-r--r--drivers/input/keyboard/ep93xx_keypad.c7
-rw-r--r--drivers/input/keyboard/gpio_keys.c1
-rw-r--r--drivers/input/keyboard/gpio_keys_polled.c2
-rw-r--r--drivers/input/keyboard/jornada680_kbd.c2
-rw-r--r--drivers/input/keyboard/jornada720_kbd.c2
-rw-r--r--drivers/input/keyboard/matrix_keypad.c2
-rw-r--r--drivers/input/keyboard/nspire-keypad.c283
-rw-r--r--drivers/input/keyboard/omap4-keypad.c2
-rw-r--r--drivers/input/keyboard/opencores-kbd.c2
-rw-r--r--drivers/input/keyboard/pmic8xxx-keypad.c2
-rw-r--r--drivers/input/keyboard/pxa27x_keypad.c312
-rw-r--r--drivers/input/keyboard/pxa930_rotary.c1
-rw-r--r--drivers/input/keyboard/samsung-keypad.c54
-rw-r--r--drivers/input/keyboard/sh_keysc.c2
-rw-r--r--drivers/input/keyboard/spear-keyboard.c1
-rw-r--r--drivers/input/keyboard/tnetv107x-keypad.c2
-rw-r--r--drivers/input/keyboard/twl4030_keypad.c3
-rw-r--r--drivers/input/keyboard/w90p910_keypad.c5
23 files changed, 580 insertions, 122 deletions
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index 7ac9c9818d5..269d4c3658c 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -418,6 +418,16 @@ config KEYBOARD_NOMADIK
To compile this driver as a module, choose M here: the
module will be called nmk-ske-keypad.
+config KEYBOARD_NSPIRE
+ tristate "TI-NSPIRE built-in keyboard"
+ depends on ARCH_NSPIRE && OF
+ select INPUT_MATRIXKMAP
+ help
+ Say Y here if you want to use the built-in keypad on TI-NSPIRE.
+
+ To compile this driver as a module, choose M here: the
+ module will be called nspire-keypad.
+
config KEYBOARD_TEGRA
tristate "NVIDIA Tegra internal matrix keyboard controller support"
depends on ARCH_TEGRA && OF
@@ -442,6 +452,7 @@ config KEYBOARD_OPENCORES
config KEYBOARD_PXA27x
tristate "PXA27x/PXA3xx keypad support"
depends on PXA27x || PXA3xx || ARCH_MMP
+ select INPUT_MATRIXKMAP
help
Enable support for PXA27x/PXA3xx keypad controller.
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
index 0c43e8cf8d0..a699b617230 100644
--- a/drivers/input/keyboard/Makefile
+++ b/drivers/input/keyboard/Makefile
@@ -36,6 +36,7 @@ obj-$(CONFIG_KEYBOARD_MCS) += mcs_touchkey.o
obj-$(CONFIG_KEYBOARD_MPR121) += mpr121_touchkey.o
obj-$(CONFIG_KEYBOARD_NEWTON) += newtonkbd.o
obj-$(CONFIG_KEYBOARD_NOMADIK) += nomadik-ske-keypad.o
+obj-$(CONFIG_KEYBOARD_NSPIRE) += nspire-keypad.o
obj-$(CONFIG_KEYBOARD_OMAP) += omap-keypad.o
obj-$(CONFIG_KEYBOARD_OMAP4) += omap4-keypad.o
obj-$(CONFIG_KEYBOARD_OPENCORES) += opencores-kbd.o
diff --git a/drivers/input/keyboard/amikbd.c b/drivers/input/keyboard/amikbd.c
index ba0b36f7dae..096d6067ae1 100644
--- a/drivers/input/keyboard/amikbd.c
+++ b/drivers/input/keyboard/amikbd.c
@@ -246,7 +246,6 @@ static int __exit amikbd_remove(struct platform_device *pdev)
{
struct input_dev *dev = platform_get_drvdata(pdev);
- platform_set_drvdata(pdev, NULL);
free_irq(IRQ_AMIGA_CIAA_SP, dev);
input_unregister_device(dev);
return 0;
diff --git a/drivers/input/keyboard/bf54x-keys.c b/drivers/input/keyboard/bf54x-keys.c
index 20b9fa91fb9..fc88fb48d70 100644
--- a/drivers/input/keyboard/bf54x-keys.c
+++ b/drivers/input/keyboard/bf54x-keys.c
@@ -326,7 +326,6 @@ out0:
kfree(bf54x_kpad->keycode);
out:
kfree(bf54x_kpad);
- platform_set_drvdata(pdev, NULL);
return error;
}
@@ -346,7 +345,6 @@ static int bfin_kpad_remove(struct platform_device *pdev)
kfree(bf54x_kpad->keycode);
kfree(bf54x_kpad);
- platform_set_drvdata(pdev, NULL);
return 0;
}
diff --git a/drivers/input/keyboard/davinci_keyscan.c b/drivers/input/keyboard/davinci_keyscan.c
index 829753702b6..d15977a8361 100644
--- a/drivers/input/keyboard/davinci_keyscan.c
+++ b/drivers/input/keyboard/davinci_keyscan.c
@@ -314,8 +314,6 @@ static int davinci_ks_remove(struct platform_device *pdev)
iounmap(davinci_ks->base);
release_mem_region(davinci_ks->pbase, davinci_ks->base_size);
- platform_set_drvdata(pdev, NULL);
-
kfree(davinci_ks);
return 0;
diff --git a/drivers/input/keyboard/ep93xx_keypad.c b/drivers/input/keyboard/ep93xx_keypad.c
index 9857e8fd098..47206bdba41 100644
--- a/drivers/input/keyboard/ep93xx_keypad.c
+++ b/drivers/input/keyboard/ep93xx_keypad.c
@@ -329,8 +329,7 @@ static int ep93xx_keypad_probe(struct platform_device *pdev)
return 0;
failed_free_irq:
- free_irq(keypad->irq, pdev);
- platform_set_drvdata(pdev, NULL);
+ free_irq(keypad->irq, keypad);
failed_free_dev:
input_free_device(input_dev);
failed_put_clk:
@@ -351,9 +350,7 @@ static int ep93xx_keypad_remove(struct platform_device *pdev)
struct ep93xx_keypad *keypad = platform_get_drvdata(pdev);
struct resource *res;
- free_irq(keypad->irq, pdev);
-
- platform_set_drvdata(pdev, NULL);
+ free_irq(keypad->irq, keypad);
if (keypad->enabled)
clk_disable(keypad->clk);
diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c
index b29ca651a39..440ce32462b 100644
--- a/drivers/input/keyboard/gpio_keys.c
+++ b/drivers/input/keyboard/gpio_keys.c
@@ -767,7 +767,6 @@ static int gpio_keys_probe(struct platform_device *pdev)
while (--i >= 0)
gpio_remove_key(&ddata->data[i]);
- platform_set_drvdata(pdev, NULL);
fail1:
input_free_device(input);
kfree(ddata);
diff --git a/drivers/input/keyboard/gpio_keys_polled.c b/drivers/input/keyboard/gpio_keys_polled.c
index 21147164874..cd5ed9e2216 100644
--- a/drivers/input/keyboard/gpio_keys_polled.c
+++ b/drivers/input/keyboard/gpio_keys_polled.c
@@ -324,7 +324,6 @@ err_free_gpio:
err_free_bdev:
kfree(bdev);
- platform_set_drvdata(pdev, NULL);
err_free_pdata:
/* If we have no platform_data, we allocated pdata dynamically. */
@@ -355,7 +354,6 @@ static int gpio_keys_polled_remove(struct platform_device *pdev)
kfree(pdata);
kfree(bdev);
- platform_set_drvdata(pdev, NULL);
return 0;
}
diff --git a/drivers/input/keyboard/jornada680_kbd.c b/drivers/input/keyboard/jornada680_kbd.c
index 74e75a6e8de..a2a034c25f0 100644
--- a/drivers/input/keyboard/jornada680_kbd.c
+++ b/drivers/input/keyboard/jornada680_kbd.c
@@ -233,7 +233,6 @@ static int jornada680kbd_probe(struct platform_device *pdev)
failed:
printk(KERN_ERR "Jornadakbd: failed to register driver, error: %d\n",
error);
- platform_set_drvdata(pdev, NULL);
input_free_polled_device(poll_dev);
kfree(jornadakbd);
return error;
@@ -244,7 +243,6 @@ static int jornada680kbd_remove(struct platform_device *pdev)
{
struct jornadakbd *jornadakbd = platform_get_drvdata(pdev);
- platform_set_drvdata(pdev, NULL);
input_unregister_polled_device(jornadakbd->poll_dev);
input_free_polled_device(jornadakbd->poll_dev);
kfree(jornadakbd);
diff --git a/drivers/input/keyboard/jornada720_kbd.c b/drivers/input/keyboard/jornada720_kbd.c
index 5ceef636df2..b0ad457ca9d 100644
--- a/drivers/input/keyboard/jornada720_kbd.c
+++ b/drivers/input/keyboard/jornada720_kbd.c
@@ -146,7 +146,6 @@ static int jornada720_kbd_probe(struct platform_device *pdev)
fail2: /* IRQ, DEVICE, MEMORY */
free_irq(IRQ_GPIO0, pdev);
fail1: /* DEVICE, MEMORY */
- platform_set_drvdata(pdev, NULL);
input_free_device(input_dev);
kfree(jornadakbd);
return err;
@@ -157,7 +156,6 @@ static int jornada720_kbd_remove(struct platform_device *pdev)
struct jornadakbd *jornadakbd = platform_get_drvdata(pdev);
free_irq(IRQ_GPIO0, pdev);
- platform_set_drvdata(pdev, NULL);
input_unregister_device(jornadakbd->input);
kfree(jornadakbd);
diff --git a/drivers/input/keyboard/matrix_keypad.c b/drivers/input/keyboard/matrix_keypad.c
index 71d77192ac1..90ff73ace42 100644
--- a/drivers/input/keyboard/matrix_keypad.c
+++ b/drivers/input/keyboard/matrix_keypad.c
@@ -549,8 +549,6 @@ static int matrix_keypad_remove(struct platform_device *pdev)
input_unregister_device(keypad->input_dev);
kfree(keypad);
- platform_set_drvdata(pdev, NULL);
-
return 0;
}
diff --git a/drivers/input/keyboard/nspire-keypad.c b/drivers/input/keyboard/nspire-keypad.c
new file mode 100644
index 00000000000..20d872d6f60
--- /dev/null
+++ b/drivers/input/keyboard/nspire-keypad.c
@@ -0,0 +1,283 @@
+/*
+ * Copyright (C) 2013 Daniel Tang <tangrs@tangrs.id.au>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/input/matrix_keypad.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/of.h>
+
+#define KEYPAD_SCAN_MODE 0x00
+#define KEYPAD_CNTL 0x04
+#define KEYPAD_INT 0x08
+#define KEYPAD_INTMSK 0x0C
+
+#define KEYPAD_DATA 0x10
+#define KEYPAD_GPIO 0x30
+
+#define KEYPAD_UNKNOWN_INT 0x40
+#define KEYPAD_UNKNOWN_INT_STS 0x44
+
+#define KEYPAD_BITMASK_COLS 11
+#define KEYPAD_BITMASK_ROWS 8
+
+struct nspire_keypad {
+ void __iomem *reg_base;
+ u32 int_mask;
+
+ struct input_dev *input;
+ struct clk *clk;
+
+ struct matrix_keymap_data *keymap;
+ int row_shift;
+
+ /* Maximum delay estimated assuming 33MHz APB */
+ u32 scan_interval; /* In microseconds (~2000us max) */
+ u32 row_delay; /* In microseconds (~500us max) */
+
+ u16 state[KEYPAD_BITMASK_ROWS];
+
+ bool active_low;
+};
+
+static irqreturn_t nspire_keypad_irq(int irq, void *dev_id)
+{
+ struct nspire_keypad *keypad = dev_id;
+ struct input_dev *input = keypad->input;
+ unsigned short *keymap = input->keycode;
+ unsigned int code;
+ int row, col;
+ u32 int_sts;
+ u16 state[8];
+ u16 bits, changed;
+
+ int_sts = readl(keypad->reg_base + KEYPAD_INT) & keypad->int_mask;
+ if (!int_sts)
+ return IRQ_NONE;
+
+ memcpy_fromio(state, keypad->reg_base + KEYPAD_DATA, sizeof(state));
+
+ for (row = 0; row < KEYPAD_BITMASK_ROWS; row++) {
+ bits = state[row];
+ if (keypad->active_low)
+ bits = ~bits;
+
+ changed = bits ^ keypad->state[row];
+ if (!changed)
+ continue;
+
+ keypad->state[row] = bits;
+
+ for (col = 0; col < KEYPAD_BITMASK_COLS; col++) {
+ if (!(changed & (1U << col)))
+ continue;
+
+ code = MATRIX_SCAN_CODE(row, col, keypad->row_shift);
+ input_event(input, EV_MSC, MSC_SCAN, code);
+ input_report_key(input, keymap[code],
+ bits & (1U << col));
+ }
+ }
+
+ input_sync(input);
+
+ writel(0x3, keypad->reg_base + KEYPAD_INT);
+
+ return IRQ_HANDLED;
+}
+
+static int nspire_keypad_chip_init(struct nspire_keypad *keypad)
+{
+ unsigned long val = 0, cycles_per_us, delay_cycles, row_delay_cycles;
+
+ cycles_per_us = (clk_get_rate(keypad->clk) / 1000000);
+ if (cycles_per_us == 0)
+ cycles_per_us = 1;
+
+ delay_cycles = cycles_per_us * keypad->scan_interval;
+ WARN_ON(delay_cycles >= (1 << 16)); /* Overflow */
+ delay_cycles &= 0xffff;
+
+ row_delay_cycles = cycles_per_us * keypad->row_delay;
+ WARN_ON(row_delay_cycles >= (1 << 14)); /* Overflow */
+ row_delay_cycles &= 0x3fff;
+
+ val |= 3 << 0; /* Set scan mode to 3 (continuous scan) */
+ val |= row_delay_cycles << 2; /* Delay between scanning each row */
+ val |= delay_cycles << 16; /* Delay between scans */
+ writel(val, keypad->reg_base + KEYPAD_SCAN_MODE);
+
+ val = (KEYPAD_BITMASK_ROWS & 0xff) | (KEYPAD_BITMASK_COLS & 0xff)<<8;
+ writel(val, keypad->reg_base + KEYPAD_CNTL);
+
+ /* Enable interrupts */
+ keypad->int_mask = 1 << 1;
+ writel(keypad->int_mask, keypad->reg_base + KEYPAD_INTMSK);
+
+ /* Disable GPIO interrupts to prevent hanging on touchpad */
+ /* Possibly used to detect touchpad events */
+ writel(0, keypad->reg_base + KEYPAD_UNKNOWN_INT);
+ /* Acknowledge existing interrupts */
+ writel(~0, keypad->reg_base + KEYPAD_UNKNOWN_INT_STS);
+
+ return 0;
+}
+
+static int nspire_keypad_open(struct input_dev *input)
+{
+ struct nspire_keypad *keypad = input_get_drvdata(input);
+ int error;
+
+ error = clk_prepare_enable(keypad->clk);
+ if (error)
+ return error;
+
+ error = nspire_keypad_chip_init(keypad);
+ if (error)
+ return error;
+
+ return 0;
+}
+
+static void nspire_keypad_close(struct input_dev *input)
+{
+ struct nspire_keypad *keypad = input_get_drvdata(input);
+
+ clk_disable_unprepare(keypad->clk);
+}
+
+static int nspire_keypad_probe(struct platform_device *pdev)
+{
+ const struct device_node *of_node = pdev->dev.of_node;
+ struct nspire_keypad *keypad;
+ struct input_dev *input;
+ struct resource *res;
+ int irq;
+ int error;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "failed to get keypad irq\n");
+ return -EINVAL;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "missing platform resources\n");
+ return -EINVAL;
+ }
+
+ keypad = devm_kzalloc(&pdev->dev, sizeof(struct nspire_keypad),
+ GFP_KERNEL);
+ if (!keypad) {
+ dev_err(&pdev->dev, "failed to allocate keypad memory\n");
+ return -ENOMEM;
+ }
+
+ keypad->row_shift = get_count_order(KEYPAD_BITMASK_COLS);
+
+ error = of_property_read_u32(of_node, "scan-interval",
+ &keypad->scan_interval);
+ if (error) {
+ dev_err(&pdev->dev, "failed to get scan-interval\n");
+ return error;
+ }
+
+ error = of_property_read_u32(of_node, "row-delay",
+ &keypad->row_delay);
+ if (error) {
+ dev_err(&pdev->dev, "failed to get row-delay\n");
+ return error;
+ }
+
+ keypad->active_low = of_property_read_bool(of_node, "active-low");
+
+ keypad->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(keypad->clk)) {
+ dev_err(&pdev->dev, "unable to get clock\n");
+ return PTR_ERR(keypad->clk);
+ }
+
+ keypad->reg_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(keypad->reg_base))
+ return PTR_ERR(keypad->reg_base);
+
+ keypad->input = input = devm_input_allocate_device(&pdev->dev);
+ if (!input) {
+ dev_err(&pdev->dev, "failed to allocate input device\n");
+ return -ENOMEM;
+ }
+
+ input_set_drvdata(input, keypad);
+
+ input->id.bustype = BUS_HOST;
+ input->name = "nspire-keypad";
+ input->open = nspire_keypad_open;
+ input->close = nspire_keypad_close;
+
+ __set_bit(EV_KEY, input->evbit);
+ __set_bit(EV_REP, input->evbit);
+ input_set_capability(input, EV_MSC, MSC_SCAN);
+
+ error = matrix_keypad_build_keymap(NULL, NULL,
+ KEYPAD_BITMASK_ROWS,
+ KEYPAD_BITMASK_COLS,
+ NULL, input);
+ if (error) {
+ dev_err(&pdev->dev, "building keymap failed\n");
+ return error;
+ }
+
+ error = devm_request_irq(&pdev->dev, irq, nspire_keypad_irq, 0,
+ "nspire_keypad", keypad);
+ if (error) {
+ dev_err(&pdev->dev, "allocate irq %d failed\n", irq);
+ return error;
+ }
+
+ error = input_register_device(input);
+ if (error) {
+ dev_err(&pdev->dev,
+ "unable to register input device: %d\n", error);
+ return error;
+ }
+
+ platform_set_drvdata(pdev, keypad);
+
+ dev_dbg(&pdev->dev,
+ "TI-NSPIRE keypad at %pR (scan_interval=%uus, row_delay=%uus%s)\n",
+ res, keypad->row_delay, keypad->scan_interval,
+ keypad->active_low ? ", active_low" : "");
+
+ return 0;
+}
+
+static const struct of_device_id nspire_keypad_dt_match[] = {
+ { .compatible = "ti,nspire-keypad" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, nspire_keypad_dt_match);
+
+static struct platform_driver nspire_keypad_driver = {
+ .driver = {
+ .name = "nspire-keypad",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(nspire_keypad_dt_match),
+ },
+ .probe = nspire_keypad_probe,
+};
+
+module_platform_driver(nspire_keypad_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("TI-NSPIRE Keypad Driver");
diff --git a/drivers/input/keyboard/omap4-keypad.c b/drivers/input/keyboard/omap4-keypad.c
index 1b289092f4e..f4aa53a1fd6 100644
--- a/drivers/input/keyboard/omap4-keypad.c
+++ b/drivers/input/keyboard/omap4-keypad.c
@@ -419,8 +419,6 @@ static int omap4_keypad_remove(struct platform_device *pdev)
kfree(keypad_data->keymap);
kfree(keypad_data);
- platform_set_drvdata(pdev, NULL);
-
return 0;
}
diff --git a/drivers/input/keyboard/opencores-kbd.c b/drivers/input/keyboard/opencores-kbd.c
index 7ac5f174c6f..7b9b44158ad 100644
--- a/drivers/input/keyboard/opencores-kbd.c
+++ b/drivers/input/keyboard/opencores-kbd.c
@@ -151,8 +151,6 @@ static int opencores_kbd_remove(struct platform_device *pdev)
input_unregister_device(opencores_kbd->input);
kfree(opencores_kbd);
- platform_set_drvdata(pdev, NULL);
-
return 0;
}
diff --git a/drivers/input/keyboard/pmic8xxx-keypad.c b/drivers/input/keyboard/pmic8xxx-keypad.c
index 74339e139d4..2c9f19ac35e 100644
--- a/drivers/input/keyboard/pmic8xxx-keypad.c
+++ b/drivers/input/keyboard/pmic8xxx-keypad.c
@@ -707,7 +707,6 @@ err_gpio_config:
err_get_irq:
input_free_device(kp->input);
err_alloc_device:
- platform_set_drvdata(pdev, NULL);
kfree(kp);
return rc;
}
@@ -722,7 +721,6 @@ static int pmic8xxx_kp_remove(struct platform_device *pdev)
input_unregister_device(kp->input);
kfree(kp);
- platform_set_drvdata(pdev, NULL);
return 0;
}
diff --git a/drivers/input/keyboard/pxa27x_keypad.c b/drivers/input/keyboard/pxa27x_keypad.c
index 5330d8fbf6c..134c3b404a5 100644
--- a/drivers/input/keyboard/pxa27x_keypad.c
+++ b/drivers/input/keyboard/pxa27x_keypad.c
@@ -100,7 +100,7 @@
#define MAX_KEYPAD_KEYS (MAX_MATRIX_KEY_NUM + MAX_DIRECT_KEY_NUM)
struct pxa27x_keypad {
- struct pxa27x_keypad_platform_data *pdata;
+ const struct pxa27x_keypad_platform_data *pdata;
struct clk *clk;
struct input_dev *input_dev;
@@ -118,25 +118,254 @@ struct pxa27x_keypad {
unsigned int direct_key_mask;
};
-static void pxa27x_keypad_build_keycode(struct pxa27x_keypad *keypad)
+#ifdef CONFIG_OF
+static int pxa27x_keypad_matrix_key_parse_dt(struct pxa27x_keypad *keypad,
+ struct pxa27x_keypad_platform_data *pdata)
{
- struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
struct input_dev *input_dev = keypad->input_dev;
- unsigned short keycode;
+ struct device *dev = input_dev->dev.parent;
+ u32 rows, cols;
+ int error;
+
+ error = matrix_keypad_parse_of_params(dev, &rows, &cols);
+ if (error)
+ return error;
+
+ if (rows > MAX_MATRIX_KEY_ROWS || cols > MAX_MATRIX_KEY_COLS) {
+ dev_err(dev, "rows or cols exceeds maximum value\n");
+ return -EINVAL;
+ }
+
+ pdata->matrix_key_rows = rows;
+ pdata->matrix_key_cols = cols;
+
+ error = matrix_keypad_build_keymap(NULL, NULL,
+ pdata->matrix_key_rows,
+ pdata->matrix_key_cols,
+ keypad->keycodes, input_dev);
+ if (error)
+ return error;
+
+ return 0;
+}
+
+static int pxa27x_keypad_direct_key_parse_dt(struct pxa27x_keypad *keypad,
+ struct pxa27x_keypad_platform_data *pdata)
+{
+ struct input_dev *input_dev = keypad->input_dev;
+ struct device *dev = input_dev->dev.parent;
+ struct device_node *np = dev->of_node;
+ const __be16 *prop;
+ unsigned short code;
+ unsigned int proplen, size;
int i;
+ int error;
- for (i = 0; i < pdata->matrix_key_map_size; i++) {
- unsigned int key = pdata->matrix_key_map[i];
- unsigned int row = KEY_ROW(key);
- unsigned int col = KEY_COL(key);
- unsigned int scancode = MATRIX_SCAN_CODE(row, col,
- MATRIX_ROW_SHIFT);
+ error = of_property_read_u32(np, "marvell,direct-key-count",
+ &pdata->direct_key_num);
+ if (error) {
+ /*
+ * If do not have marvel,direct-key-count defined,
+ * it means direct key is not supported.
+ */
+ return error == -EINVAL ? 0 : error;
+ }
- keycode = KEY_VAL(key);
- keypad->keycodes[scancode] = keycode;
- __set_bit(keycode, input_dev->keybit);
+ error = of_property_read_u32(np, "marvell,direct-key-mask",
+ &pdata->direct_key_mask);
+ if (error) {
+ if (error != -EINVAL)
+ return error;
+
+ /*
+ * If marvell,direct-key-mask is not defined, driver will use
+ * default value. Default value is set when configure the keypad.
+ */
+ pdata->direct_key_mask = 0;
+ }
+
+ pdata->direct_key_low_active = of_property_read_bool(np,
+ "marvell,direct-key-low-active");
+
+ prop = of_get_property(np, "marvell,direct-key-map", &proplen);
+ if (!prop)
+ return -EINVAL;
+
+ if (proplen % sizeof(u16))
+ return -EINVAL;
+
+ size = proplen / sizeof(u16);
+
+ /* Only MAX_DIRECT_KEY_NUM is accepted.*/
+ if (size > MAX_DIRECT_KEY_NUM)
+ return -EINVAL;
+
+ for (i = 0; i < size; i++) {
+ code = be16_to_cpup(prop + i);
+ keypad->keycodes[MAX_MATRIX_KEY_NUM + i] = code;
+ __set_bit(code, input_dev->keybit);
+ }
+
+ return 0;
+}
+
+static int pxa27x_keypad_rotary_parse_dt(struct pxa27x_keypad *keypad,
+ struct pxa27x_keypad_platform_data *pdata)
+{
+ const __be32 *prop;
+ int i, relkey_ret;
+ unsigned int code, proplen;
+ const char *rotaryname[2] = {
+ "marvell,rotary0", "marvell,rotary1"};
+ const char relkeyname[] = {"marvell,rotary-rel-key"};
+ struct input_dev *input_dev = keypad->input_dev;
+ struct device *dev = input_dev->dev.parent;
+ struct device_node *np = dev->of_node;
+
+ relkey_ret = of_property_read_u32(np, relkeyname, &code);
+ /* if can read correct rotary key-code, we do not need this. */
+ if (relkey_ret == 0) {
+ unsigned short relcode;
+
+ /* rotary0 taks lower half, rotary1 taks upper half. */
+ relcode = code & 0xffff;
+ pdata->rotary0_rel_code = (code & 0xffff);
+ __set_bit(relcode, input_dev->relbit);
+
+ relcode = code >> 16;
+ pdata->rotary1_rel_code = relcode;
+ __set_bit(relcode, input_dev->relbit);
+ }
+
+ for (i = 0; i < 2; i++) {
+ prop = of_get_property(np, rotaryname[i], &proplen);
+ /*
+ * If the prop is not set, it means keypad does not need
+ * initialize the rotaryX.
+ */
+ if (!prop)
+ continue;
+
+ code = be32_to_cpup(prop);
+ /*
+ * Not all up/down key code are valid.
+ * Now we depends on direct-rel-code.
+ */
+ if ((!(code & 0xffff) || !(code >> 16)) && relkey_ret) {
+ return relkey_ret;
+ } else {
+ unsigned int n = MAX_MATRIX_KEY_NUM + (i << 1);
+ unsigned short keycode;
+
+ keycode = code & 0xffff;
+ keypad->keycodes[n] = keycode;
+ __set_bit(keycode, input_dev->keybit);
+
+ keycode = code >> 16;
+ keypad->keycodes[n + 1] = keycode;
+ __set_bit(keycode, input_dev->keybit);
+
+ if (i == 0)
+ pdata->rotary0_rel_code = -1;
+ else
+ pdata->rotary1_rel_code = -1;
+ }
+ if (i == 0)
+ pdata->enable_rotary0 = 1;
+ else
+ pdata->enable_rotary1 = 1;
+ }
+
+ keypad->rotary_rel_code[0] = pdata->rotary0_rel_code;
+ keypad->rotary_rel_code[1] = pdata->rotary1_rel_code;
+
+ return 0;
+}
+
+static int pxa27x_keypad_build_keycode_from_dt(struct pxa27x_keypad *keypad)
+{
+ struct input_dev *input_dev = keypad->input_dev;
+ struct device *dev = input_dev->dev.parent;
+ struct device_node *np = dev->of_node;
+ struct pxa27x_keypad_platform_data *pdata;
+ int error;
+
+ pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata) {
+ dev_err(dev, "failed to allocate memory for pdata\n");
+ return -ENOMEM;
+ }
+
+ error = pxa27x_keypad_matrix_key_parse_dt(keypad, pdata);
+ if (error) {
+ dev_err(dev, "failed to parse matrix key\n");
+ return error;
+ }
+
+ error = pxa27x_keypad_direct_key_parse_dt(keypad, pdata);
+ if (error) {
+ dev_err(dev, "failed to parse direct key\n");
+ return error;
+ }
+
+ error = pxa27x_keypad_rotary_parse_dt(keypad, pdata);
+ if (error) {
+ dev_err(dev, "failed to parse rotary key\n");
+ return error;
+ }
+
+ error = of_property_read_u32(np, "marvell,debounce-interval",
+ &pdata->debounce_interval);
+ if (error) {
+ dev_err(dev, "failed to parse debpunce-interval\n");
+ return error;
}
+ /*
+ * The keycodes may not only includes matrix key but also the direct
+ * key or rotary key.
+ */
+ input_dev->keycodemax = ARRAY_SIZE(keypad->keycodes);
+
+ keypad->pdata = pdata;
+ return 0;
+}
+
+#else
+
+static int pxa27x_keypad_build_keycode_from_dt(struct pxa27x_keypad *keypad)
+{
+ dev_info(keypad->input_dev->dev.parent, "missing platform data\n");
+
+ return -EINVAL;
+}
+
+#endif
+
+static int pxa27x_keypad_build_keycode(struct pxa27x_keypad *keypad)
+{
+ const struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
+ struct input_dev *input_dev = keypad->input_dev;
+ const struct matrix_keymap_data *keymap_data =
+ pdata ? pdata->matrix_keymap_data : NULL;
+ unsigned short keycode;
+ int i;
+ int error;
+
+ error = matrix_keypad_build_keymap(keymap_data, NULL,
+ pdata->matrix_key_rows,
+ pdata->matrix_key_cols,
+ keypad->keycodes, input_dev);
+ if (error)
+ return error;
+
+ /*
+ * The keycodes may not only include matrix keys but also the direct
+ * or rotary keys.
+ */
+ input_dev->keycodemax = ARRAY_SIZE(keypad->keycodes);
+
+ /* For direct keys. */
for (i = 0; i < pdata->direct_key_num; i++) {
keycode = pdata->direct_key_map[i];
keypad->keycodes[MAX_MATRIX_KEY_NUM + i] = keycode;
@@ -178,11 +407,13 @@ static void pxa27x_keypad_build_keycode(struct pxa27x_keypad *keypad)
}
__clear_bit(KEY_RESERVED, input_dev->keybit);
+
+ return 0;
}
static void pxa27x_keypad_scan_matrix(struct pxa27x_keypad *keypad)
{
- struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
+ const struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
struct input_dev *input_dev = keypad->input_dev;
int row, col, num_keys_pressed = 0;
uint32_t new_state[MAX_MATRIX_KEY_COLS];
@@ -284,7 +515,7 @@ static void report_rotary_event(struct pxa27x_keypad *keypad, int r, int delta)
static void pxa27x_keypad_scan_rotary(struct pxa27x_keypad *keypad)
{
- struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
+ const struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
uint32_t kprec;
/* read and reset to default count value */
@@ -300,7 +531,7 @@ static void pxa27x_keypad_scan_rotary(struct pxa27x_keypad *keypad)
static void pxa27x_keypad_scan_direct(struct pxa27x_keypad *keypad)
{
- struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
+ const struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
struct input_dev *input_dev = keypad->input_dev;
unsigned int new_state;
uint32_t kpdk, bits_changed;
@@ -340,7 +571,7 @@ static void pxa27x_keypad_scan_direct(struct pxa27x_keypad *keypad)
static void clear_wakeup_event(struct pxa27x_keypad *keypad)
{
- struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
+ const struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
if (pdata->clear_wakeup_event)
(pdata->clear_wakeup_event)();
@@ -364,7 +595,7 @@ static irqreturn_t pxa27x_keypad_irq_handler(int irq, void *dev_id)
static void pxa27x_keypad_config(struct pxa27x_keypad *keypad)
{
- struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
+ const struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
unsigned int mask = 0, direct_key_num = 0;
unsigned long kpc = 0;
@@ -431,7 +662,7 @@ static void pxa27x_keypad_close(struct input_dev *dev)
clk_disable_unprepare(keypad->clk);
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int pxa27x_keypad_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
@@ -475,25 +706,25 @@ static int pxa27x_keypad_resume(struct device *dev)
return 0;
}
-
-static const struct dev_pm_ops pxa27x_keypad_pm_ops = {
- .suspend = pxa27x_keypad_suspend,
- .resume = pxa27x_keypad_resume,
-};
#endif
+static SIMPLE_DEV_PM_OPS(pxa27x_keypad_pm_ops,
+ pxa27x_keypad_suspend, pxa27x_keypad_resume);
+
+
static int pxa27x_keypad_probe(struct platform_device *pdev)
{
- struct pxa27x_keypad_platform_data *pdata = pdev->dev.platform_data;
+ const struct pxa27x_keypad_platform_data *pdata =
+ dev_get_platdata(&pdev->dev);
+ struct device_node *np = pdev->dev.of_node;
struct pxa27x_keypad *keypad;
struct input_dev *input_dev;
struct resource *res;
int irq, error;
- if (pdata == NULL) {
- dev_err(&pdev->dev, "no platform data defined\n");
+ /* Driver need build keycode from device tree or pdata */
+ if (!np && !pdata)
return -EINVAL;
- }
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
@@ -555,7 +786,14 @@ static int pxa27x_keypad_probe(struct platform_device *pdev)
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
input_set_capability(input_dev, EV_MSC, MSC_SCAN);
- pxa27x_keypad_build_keycode(keypad);
+ if (pdata)
+ error = pxa27x_keypad_build_keycode(keypad);
+ else
+ error = pxa27x_keypad_build_keycode_from_dt(keypad);
+ if (error) {
+ dev_err(&pdev->dev, "failed to build keycode\n");
+ goto failed_put_clk;
+ }
if ((pdata->enable_rotary0 && keypad->rotary_rel_code[0] != -1) ||
(pdata->enable_rotary1 && keypad->rotary_rel_code[1] != -1)) {
@@ -582,7 +820,7 @@ static int pxa27x_keypad_probe(struct platform_device *pdev)
return 0;
failed_free_irq:
- free_irq(irq, pdev);
+ free_irq(irq, keypad);
failed_put_clk:
clk_put(keypad->clk);
failed_free_io:
@@ -600,7 +838,7 @@ static int pxa27x_keypad_remove(struct platform_device *pdev)
struct pxa27x_keypad *keypad = platform_get_drvdata(pdev);
struct resource *res;
- free_irq(keypad->irq, pdev);
+ free_irq(keypad->irq, keypad);
clk_put(keypad->clk);
input_unregister_device(keypad->input_dev);
@@ -609,7 +847,6 @@ static int pxa27x_keypad_remove(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
release_mem_region(res->start, resource_size(res));
- platform_set_drvdata(pdev, NULL);
kfree(keypad);
return 0;
@@ -618,15 +855,22 @@ static int pxa27x_keypad_remove(struct platform_device *pdev)
/* work with hotplug and coldplug */
MODULE_ALIAS("platform:pxa27x-keypad");
+#ifdef CONFIG_OF
+static const struct of_device_id pxa27x_keypad_dt_match[] = {
+ { .compatible = "marvell,pxa27x-keypad" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, pxa27x_keypad_dt_match);
+#endif
+
static struct platform_driver pxa27x_keypad_driver = {
.probe = pxa27x_keypad_probe,
.remove = pxa27x_keypad_remove,
.driver = {
.name = "pxa27x-keypad",
+ .of_match_table = of_match_ptr(pxa27x_keypad_dt_match),
.owner = THIS_MODULE,
-#ifdef CONFIG_PM
.pm = &pxa27x_keypad_pm_ops,
-#endif
},
};
module_platform_driver(pxa27x_keypad_driver);
diff --git a/drivers/input/keyboard/pxa930_rotary.c b/drivers/input/keyboard/pxa930_rotary.c
index bcad95be73a..248cdcf9529 100644
--- a/drivers/input/keyboard/pxa930_rotary.c
+++ b/drivers/input/keyboard/pxa930_rotary.c
@@ -181,7 +181,6 @@ static int pxa930_rotary_remove(struct platform_device *pdev)
free_irq(platform_get_irq(pdev, 0), r);
input_unregister_device(r->input_dev);
iounmap(r->mmio_base);
- platform_set_drvdata(pdev, NULL);
kfree(r);
return 0;
diff --git a/drivers/input/keyboard/samsung-keypad.c b/drivers/input/keyboard/samsung-keypad.c
index 22e357b5102..ac43a486c77 100644
--- a/drivers/input/keyboard/samsung-keypad.c
+++ b/drivers/input/keyboard/samsung-keypad.c
@@ -24,7 +24,6 @@
#include <linux/pm_runtime.h>
#include <linux/slab.h>
#include <linux/of.h>
-#include <linux/of_gpio.h>
#include <linux/sched.h>
#include <linux/input/samsung-keypad.h>
@@ -79,10 +78,6 @@ struct samsung_keypad {
unsigned int rows;
unsigned int cols;
unsigned int row_state[SAMSUNG_MAX_COLS];
-#ifdef CONFIG_OF
- int row_gpios[SAMSUNG_MAX_ROWS];
- int col_gpios[SAMSUNG_MAX_COLS];
-#endif
unsigned short keycodes[];
};
@@ -304,45 +299,6 @@ static struct samsung_keypad_platdata *samsung_keypad_parse_dt(
return pdata;
}
-
-static void samsung_keypad_parse_dt_gpio(struct device *dev,
- struct samsung_keypad *keypad)
-{
- struct device_node *np = dev->of_node;
- int gpio, error, row, col;
-
- for (row = 0; row < keypad->rows; row++) {
- gpio = of_get_named_gpio(np, "row-gpios", row);
- keypad->row_gpios[row] = gpio;
- if (!gpio_is_valid(gpio)) {
- dev_err(dev, "keypad row[%d]: invalid gpio %d\n",
- row, gpio);
- continue;
- }
-
- error = devm_gpio_request(dev, gpio, "keypad-row");
- if (error)
- dev_err(dev,
- "keypad row[%d] gpio request failed: %d\n",
- row, error);
- }
-
- for (col = 0; col < keypad->cols; col++) {
- gpio = of_get_named_gpio(np, "col-gpios", col);
- keypad->col_gpios[col] = gpio;
- if (!gpio_is_valid(gpio)) {
- dev_err(dev, "keypad column[%d]: invalid gpio %d\n",
- col, gpio);
- continue;
- }
-
- error = devm_gpio_request(dev, gpio, "keypad-col");
- if (error)
- dev_err(dev,
- "keypad column[%d] gpio request failed: %d\n",
- col, error);
- }
-}
#else
static
struct samsung_keypad_platdata *samsung_keypad_parse_dt(struct device *dev)
@@ -424,15 +380,11 @@ static int samsung_keypad_probe(struct platform_device *pdev)
keypad->stopped = true;
init_waitqueue_head(&keypad->wait);
- if (pdev->dev.of_node) {
-#ifdef CONFIG_OF
- samsung_keypad_parse_dt_gpio(&pdev->dev, keypad);
+ if (pdev->dev.of_node)
keypad->type = of_device_is_compatible(pdev->dev.of_node,
"samsung,s5pv210-keypad");
-#endif
- } else {
+ else
keypad->type = platform_get_device_id(pdev)->driver_data;
- }
input_dev->name = pdev->name;
input_dev->id.bustype = BUS_HOST;
@@ -487,7 +439,6 @@ static int samsung_keypad_probe(struct platform_device *pdev)
err_disable_runtime_pm:
pm_runtime_disable(&pdev->dev);
device_init_wakeup(&pdev->dev, 0);
- platform_set_drvdata(pdev, NULL);
err_unprepare_clk:
clk_unprepare(keypad->clk);
return error;
@@ -499,7 +450,6 @@ static int samsung_keypad_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
device_init_wakeup(&pdev->dev, 0);
- platform_set_drvdata(pdev, NULL);
input_unregister_device(keypad->input_dev);
diff --git a/drivers/input/keyboard/sh_keysc.c b/drivers/input/keyboard/sh_keysc.c
index fdb9eb2df38..fe0e498d247 100644
--- a/drivers/input/keyboard/sh_keysc.c
+++ b/drivers/input/keyboard/sh_keysc.c
@@ -266,7 +266,6 @@ static int sh_keysc_probe(struct platform_device *pdev)
err2:
iounmap(priv->iomem_base);
err1:
- platform_set_drvdata(pdev, NULL);
kfree(priv);
err0:
return error;
@@ -285,7 +284,6 @@ static int sh_keysc_remove(struct platform_device *pdev)
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
- platform_set_drvdata(pdev, NULL);
kfree(priv);
return 0;
diff --git a/drivers/input/keyboard/spear-keyboard.c b/drivers/input/keyboard/spear-keyboard.c
index cb1e8f61463..7111124b536 100644
--- a/drivers/input/keyboard/spear-keyboard.c
+++ b/drivers/input/keyboard/spear-keyboard.c
@@ -290,7 +290,6 @@ static int spear_kbd_remove(struct platform_device *pdev)
clk_unprepare(kbd->clk);
device_init_wakeup(&pdev->dev, 0);
- platform_set_drvdata(pdev, NULL);
return 0;
}
diff --git a/drivers/input/keyboard/tnetv107x-keypad.c b/drivers/input/keyboard/tnetv107x-keypad.c
index ee163501129..5f7b427dd7e 100644
--- a/drivers/input/keyboard/tnetv107x-keypad.c
+++ b/drivers/input/keyboard/tnetv107x-keypad.c
@@ -296,7 +296,6 @@ error_clk:
error_map:
release_mem_region(kp->res->start, resource_size(kp->res));
error_res:
- platform_set_drvdata(pdev, NULL);
kfree(kp);
return error;
}
@@ -311,7 +310,6 @@ static int keypad_remove(struct platform_device *pdev)
clk_put(kp->clk);
iounmap(kp->regs);
release_mem_region(kp->res->start, resource_size(kp->res));
- platform_set_drvdata(pdev, NULL);
kfree(kp);
return 0;
diff --git a/drivers/input/keyboard/twl4030_keypad.c b/drivers/input/keyboard/twl4030_keypad.c
index 04f84fd5717..d2d178c84ea 100644
--- a/drivers/input/keyboard/twl4030_keypad.c
+++ b/drivers/input/keyboard/twl4030_keypad.c
@@ -422,7 +422,7 @@ static int twl4030_kp_probe(struct platform_device *pdev)
err3:
/* mask all events - we don't care about the result */
(void) twl4030_kpwrite_u8(kp, 0xff, KEYP_IMR1);
- free_irq(kp->irq, NULL);
+ free_irq(kp->irq, kp);
err2:
input_unregister_device(input);
input = NULL;
@@ -438,7 +438,6 @@ static int twl4030_kp_remove(struct platform_device *pdev)
free_irq(kp->irq, kp);
input_unregister_device(kp->input);
- platform_set_drvdata(pdev, NULL);
kfree(kp);
return 0;
diff --git a/drivers/input/keyboard/w90p910_keypad.c b/drivers/input/keyboard/w90p910_keypad.c
index ee163bee8cc..7b039162a3f 100644
--- a/drivers/input/keyboard/w90p910_keypad.c
+++ b/drivers/input/keyboard/w90p910_keypad.c
@@ -221,7 +221,7 @@ static int w90p910_keypad_probe(struct platform_device *pdev)
return 0;
failed_free_irq:
- free_irq(irq, pdev);
+ free_irq(irq, keypad);
failed_put_clk:
clk_put(keypad->clk);
failed_free_io:
@@ -239,7 +239,7 @@ static int w90p910_keypad_remove(struct platform_device *pdev)
struct w90p910_keypad *keypad = platform_get_drvdata(pdev);
struct resource *res;
- free_irq(keypad->irq, pdev);
+ free_irq(keypad->irq, keypad);
clk_put(keypad->clk);
@@ -249,7 +249,6 @@ static int w90p910_keypad_remove(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
release_mem_region(res->start, resource_size(res));
- platform_set_drvdata(pdev, NULL);
kfree(keypad);
return 0;