diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-07-04 15:35:08 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-07-04 15:35:08 -0700 |
commit | f5b63ac0f77ecab46796ba5d368ea5dd51834e6e (patch) | |
tree | 66788b3327afa62aa7f8fe05951945a2ee1e9e4e /drivers/input/keyboard | |
parent | 98f486f18d16e2214728d101ed8b6a12dce75539 (diff) | |
parent | 57961e3ba72f4a8a1aa52e978020ecc2ca03a79f (diff) | |
download | linux-f5b63ac0f77ecab46796ba5d368ea5dd51834e6e.tar.gz linux-f5b63ac0f77ecab46796ba5d368ea5dd51834e6e.tar.bz2 linux-f5b63ac0f77ecab46796ba5d368ea5dd51834e6e.zip |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
Pull input updates from Dmitry Torokhov:
"First round of updates for the input subsystem.
You will get a new touchsreen driver for Cypress 4th generation
devices, a driver for a special controller implementing PS/2 protocol
in OLPC devices, and a driver for power key for SiRFprimaII PWRC.
HID and bcm5497 now support for the 2013 MacBook Air.
EVIOCGKEY and the rest of evdev ioctls now flush events of matching
type from the client's event queue so that clients can be sure any
events received after issuing EVIOCG* ioctl are new events.
And a host of cleanups and improvements in other drivers"
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input: (87 commits)
Input: cyttsp4 - kfree xfer_buf on error path in probe()
Input: tps6507x-ts - select INPUT_POLLDEV
Input: bcm5974 - add support for the 2013 MacBook Air
HID: apple: Add support for the 2013 Macbook Air
Input: cyttsp4 - leak on error path in probe()
Input: cyttsp4 - silence NULL dereference warning
Input: cyttsp4 - silence shift wrap warning
Input: tps6507x-ts - convert to polled input device infrastructure
ARM: davinci: da850-evm: remove vref from touchscreen platform data
Input: cyttsp4 - SPI driver for Cypress TMA4XX touchscreen devices
Input: cyttsp4 - I2C driver for Cypress TMA4XX touchscreen devices
Input: cyttsp4 - add core driver for Cypress TMA4XX touchscreen devices
Input: cyttsp - I2C driver split into two modules
Input: add OLPC AP-SP driver
Input: nspire-keypad - remove redundant dev_err call in nspire_keypad_probe()
Input: tps6507x-ts - remove vref from platform data
Input: tps6507x-ts - use bool for booleans
Input: tps6507x-ts - remove bogus unreachable code
Input: samsung-keypad - let device core setup the default pin configuration
Input: wacom_i2c - implement hovering capability
...
Diffstat (limited to 'drivers/input/keyboard')
23 files changed, 580 insertions, 122 deletions
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index 7ac9c9818d55..269d4c3658cb 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 0c43e8cf8d0e..a699b6172303 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 ba0b36f7daea..096d6067ae1f 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 20b9fa91fb9e..fc88fb48d70d 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 829753702b62..d15977a8361e 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 9857e8fd0987..47206bdba411 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 b29ca651a395..440ce32462ba 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 21147164874d..cd5ed9e22168 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 74e75a6e8deb..a2a034c25f0b 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 5ceef636df2f..b0ad457ca9d8 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 71d77192ac1e..90ff73ace424 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 000000000000..e0a1339e40e6 --- /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 + 0xc); + + /* 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 1b289092f4e3..f4aa53a1fd69 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 7ac5f174c6f7..7b9b44158ad1 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 74339e139d43..2c9f19ac35ea 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 5330d8fbf6c0..134c3b404a54 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 bcad95be73aa..248cdcf95296 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 22e357b51024..ac43a486c775 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 fdb9eb2df380..fe0e498d2479 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 cb1e8f614631..7111124b5362 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 ee1635011292..5f7b427dd7ed 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 04f84fd57173..d2d178c84ea7 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 ee163bee8cce..7b039162a3f8 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; |