aboutsummaryrefslogtreecommitdiff
path: root/drivers/input/keyboard/pxa27x_keypad.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/input/keyboard/pxa27x_keypad.c')
-rw-r--r--drivers/input/keyboard/pxa27x_keypad.c407
1 files changed, 339 insertions, 68 deletions
diff --git a/drivers/input/keyboard/pxa27x_keypad.c b/drivers/input/keyboard/pxa27x_keypad.c
index 4b0ec35259a..a15063bea70 100644
--- a/drivers/input/keyboard/pxa27x_keypad.c
+++ b/drivers/input/keyboard/pxa27x_keypad.c
@@ -18,7 +18,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/input.h>
#include <linux/device.h>
@@ -27,12 +26,13 @@
#include <linux/err.h>
#include <linux/input/matrix_keypad.h>
#include <linux/slab.h>
+#include <linux/of.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include <mach/hardware.h>
-#include <plat/pxa27x_keypad.h>
+#include <linux/platform_data/keypad-pxa27x.h>
/*
* Keypad Controller registers
*/
@@ -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;
@@ -111,6 +111,8 @@ struct pxa27x_keypad {
unsigned short keycodes[MAX_KEYPAD_KEYS];
int rotary_rel_code[2];
+ unsigned int row_shift;
+
/* state row bits of each column scan */
uint32_t matrix_key_state[MAX_MATRIX_KEY_COLS];
uint32_t direct_key_state;
@@ -118,25 +120,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 +409,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];
@@ -236,7 +469,8 @@ scan:
if ((bits_changed & (1 << row)) == 0)
continue;
- code = MATRIX_SCAN_CODE(row, col, MATRIX_ROW_SHIFT);
+ code = MATRIX_SCAN_CODE(row, col, keypad->row_shift);
+
input_event(input_dev, EV_MSC, MSC_SCAN, code);
input_report_key(input_dev, keypad->keycodes[code],
new_state[col] & (1 << row));
@@ -284,7 +518,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 +534,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;
@@ -311,7 +545,15 @@ static void pxa27x_keypad_scan_direct(struct pxa27x_keypad *keypad)
if (pdata->enable_rotary0 || pdata->enable_rotary1)
pxa27x_keypad_scan_rotary(keypad);
- new_state = KPDK_DK(kpdk) & keypad->direct_key_mask;
+ /*
+ * The KPDR_DK only output the key pin level, so it relates to board,
+ * and low level may be active.
+ */
+ if (pdata->direct_key_low_active)
+ new_state = ~KPDK_DK(kpdk) & keypad->direct_key_mask;
+ else
+ new_state = KPDK_DK(kpdk) & keypad->direct_key_mask;
+
bits_changed = keypad->direct_key_state ^ new_state;
if (bits_changed == 0)
@@ -332,7 +574,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)();
@@ -356,10 +598,13 @@ 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;
+ /* clear pending interrupt bit */
+ keypad_readl(KPC);
+
/* enable matrix keys with automatic scan */
if (pdata->matrix_key_rows && pdata->matrix_key_cols) {
kpc |= KPC_ASACT | KPC_MIE | KPC_ME | KPC_MS_ALL;
@@ -383,7 +628,14 @@ static void pxa27x_keypad_config(struct pxa27x_keypad *keypad)
if (pdata->direct_key_num > direct_key_num)
direct_key_num = pdata->direct_key_num;
- keypad->direct_key_mask = ((2 << direct_key_num) - 1) & ~mask;
+ /*
+ * Direct keys usage may not start from KP_DKIN0, check the platfrom
+ * mask data to config the specific.
+ */
+ if (pdata->direct_key_mask)
+ keypad->direct_key_mask = pdata->direct_key_mask;
+ else
+ keypad->direct_key_mask = ((1 << direct_key_num) - 1) & ~mask;
/* enable direct key */
if (direct_key_num)
@@ -399,7 +651,7 @@ static int pxa27x_keypad_open(struct input_dev *dev)
struct pxa27x_keypad *keypad = input_get_drvdata(dev);
/* Enable unit clock */
- clk_enable(keypad->clk);
+ clk_prepare_enable(keypad->clk);
pxa27x_keypad_config(keypad);
return 0;
@@ -410,19 +662,23 @@ static void pxa27x_keypad_close(struct input_dev *dev)
struct pxa27x_keypad *keypad = input_get_drvdata(dev);
/* Disable clock unit */
- clk_disable(keypad->clk);
+ 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);
struct pxa27x_keypad *keypad = platform_get_drvdata(pdev);
- clk_disable(keypad->clk);
-
+ /*
+ * If the keypad is used a wake up source, clock can not be disabled.
+ * Or it can not detect the key pressing.
+ */
if (device_may_wakeup(&pdev->dev))
enable_irq_wake(keypad->irq);
+ else
+ clk_disable_unprepare(keypad->clk);
return 0;
}
@@ -433,40 +689,45 @@ static int pxa27x_keypad_resume(struct device *dev)
struct pxa27x_keypad *keypad = platform_get_drvdata(pdev);
struct input_dev *input_dev = keypad->input_dev;
- if (device_may_wakeup(&pdev->dev))
+ /*
+ * If the keypad is used as wake up source, the clock is not turned
+ * off. So do not need configure it again.
+ */
+ if (device_may_wakeup(&pdev->dev)) {
disable_irq_wake(keypad->irq);
+ } else {
+ mutex_lock(&input_dev->mutex);
- mutex_lock(&input_dev->mutex);
+ if (input_dev->users) {
+ /* Enable unit clock */
+ clk_prepare_enable(keypad->clk);
+ pxa27x_keypad_config(keypad);
+ }
- if (input_dev->users) {
- /* Enable unit clock */
- clk_enable(keypad->clk);
- pxa27x_keypad_config(keypad);
+ mutex_unlock(&input_dev->mutex);
}
- mutex_unlock(&input_dev->mutex);
-
return 0;
}
-
-static const struct dev_pm_ops pxa27x_keypad_pm_ops = {
- .suspend = pxa27x_keypad_suspend,
- .resume = pxa27x_keypad_resume,
-};
#endif
-static int __devinit pxa27x_keypad_probe(struct platform_device *pdev)
+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) {
@@ -528,14 +789,30 @@ static int __devinit 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);
+ /*
+ * Data that we get from DT resides in dynamically
+ * allocated memory so we need to update our pdata
+ * pointer.
+ */
+ pdata = keypad->pdata;
+ }
+ if (error) {
+ dev_err(&pdev->dev, "failed to build keycode\n");
+ goto failed_put_clk;
+ }
+
+ keypad->row_shift = get_count_order(pdata->matrix_key_cols);
if ((pdata->enable_rotary0 && keypad->rotary_rel_code[0] != -1) ||
(pdata->enable_rotary1 && keypad->rotary_rel_code[1] != -1)) {
input_dev->evbit[0] |= BIT_MASK(EV_REL);
}
- error = request_irq(irq, pxa27x_keypad_irq_handler, IRQF_DISABLED,
+ error = request_irq(irq, pxa27x_keypad_irq_handler, 0,
pdev->name, keypad);
if (error) {
dev_err(&pdev->dev, "failed to request IRQ\n");
@@ -555,7 +832,7 @@ static int __devinit 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:
@@ -568,12 +845,12 @@ failed_free:
return error;
}
-static int __devexit pxa27x_keypad_remove(struct platform_device *pdev)
+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);
@@ -582,7 +859,6 @@ static int __devexit 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;
@@ -591,30 +867,25 @@ static int __devexit 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 = __devexit_p(pxa27x_keypad_remove),
+ .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
},
};
-
-static int __init pxa27x_keypad_init(void)
-{
- return platform_driver_register(&pxa27x_keypad_driver);
-}
-
-static void __exit pxa27x_keypad_exit(void)
-{
- platform_driver_unregister(&pxa27x_keypad_driver);
-}
-
-module_init(pxa27x_keypad_init);
-module_exit(pxa27x_keypad_exit);
+module_platform_driver(pxa27x_keypad_driver);
MODULE_DESCRIPTION("PXA27x Keypad Controller Driver");
MODULE_LICENSE("GPL");