diff options
Diffstat (limited to 'drivers/input/keyboard')
55 files changed, 6136 insertions, 2951 deletions
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index b4dee9d5a05..f7e79b48134 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -2,7 +2,7 @@ # Input core configuration # menuconfig INPUT_KEYBOARD - bool "Keyboards" if EXPERT || !X86 + bool "Keyboards" default y help Say Y here, and a list of supported keyboards will be displayed. @@ -33,10 +33,10 @@ config KEYBOARD_ADP5588 module will be called adp5588-keys. config KEYBOARD_ADP5589 - tristate "ADP5589 I2C QWERTY Keypad and IO Expander" + tristate "ADP5585/ADP5589 I2C QWERTY Keypad and IO Expander" depends on I2C help - Say Y here if you want to use a ADP5589 attached to your + Say Y here if you want to use a ADP5585/ADP5589 attached to your system I2C bus. To compile this driver as a module, choose M here: the @@ -67,11 +67,11 @@ config KEYBOARD_ATARI module will be called atakbd. config KEYBOARD_ATKBD - tristate "AT keyboard" if EXPERT || !X86 + tristate "AT keyboard" default y select SERIO select SERIO_LIBPS2 - select SERIO_I8042 if X86 + select SERIO_I8042 if ARCH_MIGHT_HAVE_PC_SERIO select SERIO_GSCPS2 if GSC help Say Y here if you want to use a standard AT or PS/2 keyboard. Usually @@ -134,7 +134,7 @@ config KEYBOARD_QT1070 config KEYBOARD_QT2160 tristate "Atmel AT42QT2160 Touch Sensor Chip" - depends on I2C && EXPERIMENTAL + depends on I2C help If you say yes here you get support for Atmel AT42QT2160 Touch Sensor chip as a keyboard input. @@ -151,6 +151,18 @@ config KEYBOARD_BFIN To compile this driver as a module, choose M here: the module will be called bf54x-keys. +config KEYBOARD_CLPS711X + tristate "CLPS711X Keypad support" + depends on OF_GPIO && (ARCH_CLPS711X || COMPILE_TEST) + select INPUT_MATRIXKMAP + select INPUT_POLLDEV + help + Say Y here to enable the matrix keypad on the Cirrus Logic + CLPS711X CPUs. + + To compile this driver as a module, choose M here: the + module will be called clps711x-keypad. + config KEYBOARD_LKKBD tristate "DECstation/VAXstation LK201/LK401 keyboard" select SERIO @@ -166,6 +178,7 @@ config KEYBOARD_LKKBD config KEYBOARD_EP93XX tristate "EP93xx Matrix Keypad support" depends on ARCH_EP93XX + select INPUT_MATRIXKMAP help Say Y here to enable the matrix keypad on the Cirrus EP93XX. @@ -174,7 +187,7 @@ config KEYBOARD_EP93XX config KEYBOARD_GPIO tristate "GPIO Buttons" - depends on GENERIC_GPIO + depends on GPIOLIB help This driver implements support for buttons connected to GPIO pins of various CPUs (and some other chips). @@ -189,7 +202,7 @@ config KEYBOARD_GPIO config KEYBOARD_GPIO_POLLED tristate "Polled GPIO buttons" - depends on GENERIC_GPIO + depends on GPIOLIB select INPUT_POLLDEV help This driver implements support for buttons connected @@ -221,9 +234,27 @@ config KEYBOARD_TCA6416 To compile this driver as a module, choose M here: the module will be called tca6416_keypad. +config KEYBOARD_TCA8418 + tristate "TCA8418 Keypad Support" + depends on I2C + select INPUT_MATRIXKMAP + help + This driver implements basic keypad functionality + for keys connected through TCA8418 keypad decoder. + + Say Y here if your device has keys connected to + TCA8418 keypad decoder. + + If enabled the complete TCA8418 device will be managed through + this driver. + + To compile this driver as a module, choose M here: the + module will be called tca8418_keypad. + config KEYBOARD_MATRIX tristate "GPIO driven matrix keypad support" - depends on GENERIC_GPIO + depends on GPIOLIB + select INPUT_MATRIXKMAP help Enable support for GPIO driven matrix keypad. @@ -293,6 +324,17 @@ config KEYBOARD_LM8323 To compile this driver as a module, choose M here: the module will be called lm8323. +config KEYBOARD_LM8333 + tristate "LM8333 keypad chip" + depends on I2C + select INPUT_MATRIXKMAP + help + If you say yes here you get support for the National Semiconductor + LM8333 keypad controller. + + To compile this driver as a module, choose M here: the + module will be called lm8333. + config KEYBOARD_LOCOMO tristate "LoCoMo Keyboard Support" depends on SHARP_LOCOMO @@ -302,6 +344,17 @@ config KEYBOARD_LOCOMO To compile this driver as a module, choose M here: the module will be called locomokbd. +config KEYBOARD_LPC32XX + tristate "LPC32XX matrix key scanner support" + depends on ARCH_LPC32XX && OF + select INPUT_MATRIXKMAP + help + Say Y here if you want to use NXP LPC32XX SoC key scanner interface, + connected to a key matrix. + + To compile this driver as a module, choose M here: the + module will be called lpc32xx-keys. + config KEYBOARD_MAPLE tristate "Maple bus keyboard" depends on SH_DREAMCAST && MAPLE @@ -350,6 +403,7 @@ config KEYBOARD_MPR121 config KEYBOARD_IMX tristate "IMX keypad support" depends on ARCH_MXC + select INPUT_MATRIXKMAP help Enable support for IMX keypad port. @@ -367,7 +421,8 @@ config KEYBOARD_NEWTON config KEYBOARD_NOMADIK tristate "ST-Ericsson Nomadik SKE keyboard" - depends on PLAT_NOMADIK + depends on (ARCH_NOMADIK || ARCH_U8500) + select INPUT_MATRIXKMAP help Say Y here if you want to use a keypad provided on the SKE controller used on the Ux500 and Nomadik platforms @@ -375,9 +430,20 @@ 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 + depends on ARCH_TEGRA && OF + select INPUT_MATRIXKMAP help Say Y here if you want to use a matrix keyboard connected directly to the internal keyboard controller on Tegra SoCs. @@ -387,6 +453,7 @@ config KEYBOARD_TEGRA config KEYBOARD_OPENCORES tristate "OpenCores Keyboard Controller" + depends on HAS_IOMEM help Say Y here if you want to use the OpenCores Keyboard Controller http://www.opencores.org/project,keyboardcontroller @@ -397,6 +464,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. @@ -415,6 +483,7 @@ config KEYBOARD_PXA930_ROTARY config KEYBOARD_PMIC8XXX tristate "Qualcomm PMIC8XXX keypad support" depends on MFD_PM8XXX + select INPUT_MATRIXKMAP help Say Y here if you want to enable the driver for the PMIC8XXX keypad provided as a reference design from Qualcomm. This is intended @@ -425,13 +494,25 @@ config KEYBOARD_PMIC8XXX config KEYBOARD_SAMSUNG tristate "Samsung keypad support" - depends on SAMSUNG_DEV_KEYPAD + depends on HAVE_CLK + select INPUT_MATRIXKMAP help - Say Y here if you want to use the Samsung keypad. + Say Y here if you want to use the keypad on your Samsung mobile + device. To compile this driver as a module, choose M here: the module will be called samsung-keypad. +config KEYBOARD_GOLDFISH_EVENTS + depends on GOLDFISH + tristate "Generic Input Event device for Goldfish" + help + Say Y here to get an input event device for the Goldfish virtual + device emulator. + + To compile this driver as a module, choose M here: the + module will be called goldfish-events. + config KEYBOARD_STOWAWAY tristate "Stowaway keyboard" select SERIO @@ -443,6 +524,17 @@ config KEYBOARD_STOWAWAY To compile this driver as a module, choose M here: the module will be called stowaway. +config KEYBOARD_ST_KEYSCAN + tristate "STMicroelectronics keyscan support" + depends on ARCH_STI || COMPILE_TEST + select INPUT_MATRIXKMAP + help + Say Y here if you want to use a keypad attached to the keyscan block + on some STMicroelectronics SoC devices. + + To compile this driver as a module, choose M here: the + module will be called st-keyscan. + config KEYBOARD_SUNKBD tristate "Sun Type 4 and Type 5 keyboard" select SERIO @@ -456,7 +548,7 @@ config KEYBOARD_SUNKBD config KEYBOARD_SH_KEYSC tristate "SuperH KEYSC keypad support" - depends on SUPERH || ARCH_SHMOBILE + depends on SUPERH || ARCH_SHMOBILE || COMPILE_TEST help Say Y here if you want to use a keypad attached to the KEYSC block on SuperH processors such as sh7722 and sh7343. @@ -467,6 +559,7 @@ config KEYBOARD_SH_KEYSC config KEYBOARD_STMPE tristate "STMPE keypad support" depends on MFD_STMPE + select INPUT_MATRIXKMAP help Say Y here if you want to use the keypad controller on STMPE I/O expanders. @@ -486,7 +579,8 @@ config KEYBOARD_DAVINCI config KEYBOARD_OMAP tristate "TI OMAP keypad support" - depends on (ARCH_OMAP1 || ARCH_OMAP2) + depends on ARCH_OMAP1 + select INPUT_MATRIXKMAP help Say Y here if you want to use the OMAP keypad. @@ -494,10 +588,11 @@ config KEYBOARD_OMAP module will be called omap-keypad. config KEYBOARD_OMAP4 - tristate "TI OMAP4 keypad support" - depends on ARCH_OMAP4 + tristate "TI OMAP4+ keypad support" + depends on OF || ARCH_OMAP2PLUS + select INPUT_MATRIXKMAP help - Say Y here if you want to use the OMAP4 keypad. + Say Y here if you want to use the OMAP4+ keypad. To compile this driver as a module, choose M here: the module will be called omap4-keypad. @@ -505,6 +600,7 @@ config KEYBOARD_OMAP4 config KEYBOARD_SPEAR tristate "ST SPEAR keyboard support" depends on PLAT_SPEAR + select INPUT_MATRIXKMAP help Say Y here if you want to use the SPEAR keyboard. @@ -514,6 +610,7 @@ config KEYBOARD_SPEAR config KEYBOARD_TC3589X tristate "TC3589X Keypad support" depends on MFD_TC3589X + select INPUT_MATRIXKMAP help Say Y here if you want to use the keypad controller on TC35892/3 I/O expander. @@ -521,18 +618,10 @@ config KEYBOARD_TC3589X To compile this driver as a module, choose M here: the module will be called tc3589x-keypad. -config KEYBOARD_TNETV107X - tristate "TI TNETV107X keypad support" - depends on ARCH_DAVINCI_TNETV107X - help - Say Y here if you want to use the TNETV107X keypad. - - To compile this driver as a module, choose M here: the - module will be called tnetv107x-keypad. - config KEYBOARD_TWL4030 tristate "TI TWL4030/TWL5030/TPS659x0 keypad support" depends on TWL4030_CORE + select INPUT_MATRIXKMAP help Say Y here if your board use the keypad controller on TWL4030 family chips. It's safe to say enable this @@ -556,6 +645,7 @@ config KEYBOARD_XTKBD config KEYBOARD_W90P910 tristate "W90P910 Matrix Keypad support" depends on ARCH_W90X900 + select INPUT_MATRIXKMAP help Say Y here to enable the matrix keypad on evaluation board based on W90P910. @@ -563,4 +653,16 @@ config KEYBOARD_W90P910 To compile this driver as a module, choose M here: the module will be called w90p910_keypad. +config KEYBOARD_CROS_EC + tristate "ChromeOS EC keyboard" + select INPUT_MATRIXKMAP + depends on MFD_CROS_EC + help + Say Y here to enable the matrix keyboard used by ChromeOS devices + and implemented on the ChromeOS EC. You must enable one bus option + (MFD_CROS_EC_I2C or MFD_CROS_EC_SPI) to use this. + + To compile this driver as a module, choose M here: the + module will be called cros_ec_keyb. + endif diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile index ddde0fd476f..7504ae19049 100644 --- a/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile @@ -11,11 +11,15 @@ obj-$(CONFIG_KEYBOARD_AMIGA) += amikbd.o obj-$(CONFIG_KEYBOARD_ATARI) += atakbd.o obj-$(CONFIG_KEYBOARD_ATKBD) += atkbd.o obj-$(CONFIG_KEYBOARD_BFIN) += bf54x-keys.o +obj-$(CONFIG_KEYBOARD_CLPS711X) += clps711x-keypad.o +obj-$(CONFIG_KEYBOARD_CROS_EC) += cros_ec_keyb.o obj-$(CONFIG_KEYBOARD_DAVINCI) += davinci_keyscan.o obj-$(CONFIG_KEYBOARD_EP93XX) += ep93xx_keypad.o +obj-$(CONFIG_KEYBOARD_GOLDFISH_EVENTS) += goldfish_events.o obj-$(CONFIG_KEYBOARD_GPIO) += gpio_keys.o obj-$(CONFIG_KEYBOARD_GPIO_POLLED) += gpio_keys_polled.o obj-$(CONFIG_KEYBOARD_TCA6416) += tca6416-keypad.o +obj-$(CONFIG_KEYBOARD_TCA8418) += tca8418_keypad.o obj-$(CONFIG_KEYBOARD_HIL) += hil_kbd.o obj-$(CONFIG_KEYBOARD_HIL_OLD) += hilkbd.o obj-$(CONFIG_KEYBOARD_IMX) += imx_keypad.o @@ -23,7 +27,9 @@ obj-$(CONFIG_KEYBOARD_HP6XX) += jornada680_kbd.o obj-$(CONFIG_KEYBOARD_HP7XX) += jornada720_kbd.o obj-$(CONFIG_KEYBOARD_LKKBD) += lkkbd.o obj-$(CONFIG_KEYBOARD_LM8323) += lm8323.o +obj-$(CONFIG_KEYBOARD_LM8333) += lm8333.o obj-$(CONFIG_KEYBOARD_LOCOMO) += locomokbd.o +obj-$(CONFIG_KEYBOARD_LPC32XX) += lpc32xx-keys.o obj-$(CONFIG_KEYBOARD_MAPLE) += maple_keyb.o obj-$(CONFIG_KEYBOARD_MATRIX) += matrix_keypad.o obj-$(CONFIG_KEYBOARD_MAX7359) += max7359_keypad.o @@ -31,6 +37,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 @@ -44,10 +51,10 @@ obj-$(CONFIG_KEYBOARD_SH_KEYSC) += sh_keysc.o obj-$(CONFIG_KEYBOARD_SPEAR) += spear-keyboard.o obj-$(CONFIG_KEYBOARD_STMPE) += stmpe-keypad.o obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o +obj-$(CONFIG_KEYBOARD_ST_KEYSCAN) += st-keyscan.o obj-$(CONFIG_KEYBOARD_SUNKBD) += sunkbd.o obj-$(CONFIG_KEYBOARD_TC3589X) += tc3589x-keypad.o obj-$(CONFIG_KEYBOARD_TEGRA) += tegra-kbc.o -obj-$(CONFIG_KEYBOARD_TNETV107X) += tnetv107x-keypad.o obj-$(CONFIG_KEYBOARD_TWL4030) += twl4030_keypad.o obj-$(CONFIG_KEYBOARD_XTKBD) += xtkbd.o obj-$(CONFIG_KEYBOARD_W90P910) += w90p910_keypad.o diff --git a/drivers/input/keyboard/adp5520-keys.c b/drivers/input/keyboard/adp5520-keys.c index 3db8006dac3..7f4a8b58efc 100644 --- a/drivers/input/keyboard/adp5520-keys.c +++ b/drivers/input/keyboard/adp5520-keys.c @@ -8,11 +8,11 @@ #include <linux/module.h> #include <linux/kernel.h> -#include <linux/init.h> #include <linux/platform_device.h> #include <linux/input.h> #include <linux/mfd/adp5520.h> #include <linux/slab.h> +#include <linux/device.h> struct adp5520_keys { struct input_dev *input; @@ -69,9 +69,9 @@ static int adp5520_keys_notifier(struct notifier_block *nb, return 0; } -static int __devinit adp5520_keys_probe(struct platform_device *pdev) +static int adp5520_keys_probe(struct platform_device *pdev) { - struct adp5520_keys_platform_data *pdata = pdev->dev.platform_data; + struct adp5520_keys_platform_data *pdata = dev_get_platdata(&pdev->dev); struct input_dev *input; struct adp5520_keys *dev; int ret, i; @@ -82,7 +82,7 @@ static int __devinit adp5520_keys_probe(struct platform_device *pdev) return -EINVAL; } - if (pdata == NULL) { + if (!pdata) { dev_err(&pdev->dev, "missing platform data\n"); return -EINVAL; } @@ -90,17 +90,15 @@ static int __devinit adp5520_keys_probe(struct platform_device *pdev) if (!(pdata->rows_en_mask && pdata->cols_en_mask)) return -EINVAL; - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (dev == NULL) { + dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); + if (!dev) { dev_err(&pdev->dev, "failed to alloc memory\n"); return -ENOMEM; } - input = input_allocate_device(); - if (!input) { - ret = -ENOMEM; - goto err; - } + input = devm_input_allocate_device(&pdev->dev); + if (!input) + return -ENOMEM; dev->master = pdev->dev.parent; dev->input = input; @@ -136,7 +134,7 @@ static int __devinit adp5520_keys_probe(struct platform_device *pdev) ret = input_register_device(input); if (ret) { dev_err(&pdev->dev, "unable to register input device\n"); - goto err; + return ret; } en_mask = pdata->rows_en_mask | pdata->cols_en_mask; @@ -158,8 +156,7 @@ static int __devinit adp5520_keys_probe(struct platform_device *pdev) if (ret) { dev_err(&pdev->dev, "failed to write\n"); - ret = -EIO; - goto err1; + return -EIO; } dev->notifier.notifier_call = adp5520_keys_notifier; @@ -167,30 +164,20 @@ static int __devinit adp5520_keys_probe(struct platform_device *pdev) ADP5520_KP_IEN | ADP5520_KR_IEN); if (ret) { dev_err(&pdev->dev, "failed to register notifier\n"); - goto err1; + return ret; } platform_set_drvdata(pdev, dev); return 0; - -err1: - input_unregister_device(input); - input = NULL; -err: - input_free_device(input); - kfree(dev); - return ret; } -static int __devexit adp5520_keys_remove(struct platform_device *pdev) +static int adp5520_keys_remove(struct platform_device *pdev) { struct adp5520_keys *dev = platform_get_drvdata(pdev); adp5520_unregister_notifier(dev->master, &dev->notifier, ADP5520_KP_IEN | ADP5520_KR_IEN); - input_unregister_device(dev->input); - kfree(dev); return 0; } @@ -200,20 +187,9 @@ static struct platform_driver adp5520_keys_driver = { .owner = THIS_MODULE, }, .probe = adp5520_keys_probe, - .remove = __devexit_p(adp5520_keys_remove), + .remove = adp5520_keys_remove, }; - -static int __init adp5520_keys_init(void) -{ - return platform_driver_register(&adp5520_keys_driver); -} -module_init(adp5520_keys_init); - -static void __exit adp5520_keys_exit(void) -{ - platform_driver_unregister(&adp5520_keys_driver); -} -module_exit(adp5520_keys_exit); +module_platform_driver(adp5520_keys_driver); MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); MODULE_DESCRIPTION("Keys ADP5520 Driver"); diff --git a/drivers/input/keyboard/adp5588-keys.c b/drivers/input/keyboard/adp5588-keys.c index af45d275f68..5ef7fcf0e25 100644 --- a/drivers/input/keyboard/adp5588-keys.c +++ b/drivers/input/keyboard/adp5588-keys.c @@ -9,8 +9,6 @@ */ #include <linux/module.h> -#include <linux/version.h> -#include <linux/init.h> #include <linux/interrupt.h> #include <linux/irq.h> #include <linux/workqueue.h> @@ -78,8 +76,18 @@ static int adp5588_gpio_get_value(struct gpio_chip *chip, unsigned off) struct adp5588_kpad *kpad = container_of(chip, struct adp5588_kpad, gc); unsigned int bank = ADP5588_BANK(kpad->gpiomap[off]); unsigned int bit = ADP5588_BIT(kpad->gpiomap[off]); + int val; - return !!(adp5588_read(kpad->client, GPIO_DAT_STAT1 + bank) & bit); + mutex_lock(&kpad->gpio_lock); + + if (kpad->dir[bank] & bit) + val = kpad->dat_out[bank]; + else + val = adp5588_read(kpad->client, GPIO_DAT_STAT1 + bank); + + mutex_unlock(&kpad->gpio_lock); + + return !!(val & bit); } static void adp5588_gpio_set_value(struct gpio_chip *chip, @@ -146,7 +154,7 @@ static int adp5588_gpio_direction_output(struct gpio_chip *chip, return ret; } -static int __devinit adp5588_build_gpiomap(struct adp5588_kpad *kpad, +static int adp5588_build_gpiomap(struct adp5588_kpad *kpad, const struct adp5588_kpad_platform_data *pdata) { bool pin_used[ADP5588_MAXGPIO]; @@ -171,10 +179,10 @@ static int __devinit adp5588_build_gpiomap(struct adp5588_kpad *kpad, return n_unused; } -static int __devinit adp5588_gpio_add(struct adp5588_kpad *kpad) +static int adp5588_gpio_add(struct adp5588_kpad *kpad) { struct device *dev = &kpad->client->dev; - const struct adp5588_kpad_platform_data *pdata = dev->platform_data; + const struct adp5588_kpad_platform_data *pdata = dev_get_platdata(dev); const struct adp5588_gpio_platform_data *gpio_data = pdata->gpio_data; int i, error; @@ -198,6 +206,7 @@ static int __devinit adp5588_gpio_add(struct adp5588_kpad *kpad) kpad->gc.base = gpio_data->gpio_start; kpad->gc.label = kpad->client->name; kpad->gc.owner = THIS_MODULE; + kpad->gc.names = gpio_data->names; mutex_init(&kpad->gpio_lock); @@ -224,10 +233,10 @@ static int __devinit adp5588_gpio_add(struct adp5588_kpad *kpad) return 0; } -static void __devexit adp5588_gpio_remove(struct adp5588_kpad *kpad) +static void adp5588_gpio_remove(struct adp5588_kpad *kpad) { struct device *dev = &kpad->client->dev; - const struct adp5588_kpad_platform_data *pdata = dev->platform_data; + const struct adp5588_kpad_platform_data *pdata = dev_get_platdata(dev); const struct adp5588_gpio_platform_data *gpio_data = pdata->gpio_data; int error; @@ -319,9 +328,10 @@ static irqreturn_t adp5588_irq(int irq, void *handle) return IRQ_HANDLED; } -static int __devinit adp5588_setup(struct i2c_client *client) +static int adp5588_setup(struct i2c_client *client) { - const struct adp5588_kpad_platform_data *pdata = client->dev.platform_data; + const struct adp5588_kpad_platform_data *pdata = + dev_get_platdata(&client->dev); const struct adp5588_gpio_platform_data *gpio_data = pdata->gpio_data; int i, ret; unsigned char evt_mode1 = 0, evt_mode2 = 0, evt_mode3 = 0; @@ -382,7 +392,7 @@ static int __devinit adp5588_setup(struct i2c_client *client) return 0; } -static void __devinit adp5588_report_switch_state(struct adp5588_kpad *kpad) +static void adp5588_report_switch_state(struct adp5588_kpad *kpad) { int gpi_stat1 = adp5588_read(kpad->client, GPIO_DAT_STAT1); int gpi_stat2 = adp5588_read(kpad->client, GPIO_DAT_STAT2); @@ -420,11 +430,12 @@ static void __devinit adp5588_report_switch_state(struct adp5588_kpad *kpad) } -static int __devinit adp5588_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int adp5588_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct adp5588_kpad *kpad; - const struct adp5588_kpad_platform_data *pdata = client->dev.platform_data; + const struct adp5588_kpad_platform_data *pdata = + dev_get_platdata(&client->dev); struct input_dev *input; unsigned int revid; int ret, i; @@ -536,7 +547,8 @@ static int __devinit adp5588_probe(struct i2c_client *client, __set_bit(EV_REP, input->evbit); for (i = 0; i < input->keycodemax; i++) - __set_bit(kpad->keycode[i] & KEY_MAX, input->keybit); + if (kpad->keycode[i] <= KEY_MAX) + __set_bit(kpad->keycode[i], input->keybit); __clear_bit(KEY_RESERVED, input->keybit); if (kpad->gpimapsize) @@ -551,7 +563,7 @@ static int __devinit adp5588_probe(struct i2c_client *client, } error = request_irq(client->irq, adp5588_irq, - IRQF_TRIGGER_FALLING | IRQF_DISABLED, + IRQF_TRIGGER_FALLING, client->dev.driver->name, kpad); if (error) { dev_err(&client->dev, "irq %d busy?\n", client->irq); @@ -587,7 +599,7 @@ static int __devinit adp5588_probe(struct i2c_client *client, return error; } -static int __devexit adp5588_remove(struct i2c_client *client) +static int adp5588_remove(struct i2c_client *client) { struct adp5588_kpad *kpad = i2c_get_clientdata(client); @@ -650,23 +662,12 @@ static struct i2c_driver adp5588_driver = { #endif }, .probe = adp5588_probe, - .remove = __devexit_p(adp5588_remove), + .remove = adp5588_remove, .id_table = adp5588_id, }; -static int __init adp5588_init(void) -{ - return i2c_add_driver(&adp5588_driver); -} -module_init(adp5588_init); - -static void __exit adp5588_exit(void) -{ - i2c_del_driver(&adp5588_driver); -} -module_exit(adp5588_exit); +module_i2c_driver(adp5588_driver); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); MODULE_DESCRIPTION("ADP5588/87 Keypad driver"); -MODULE_ALIAS("platform:adp5588-keys"); diff --git a/drivers/input/keyboard/adp5589-keys.c b/drivers/input/keyboard/adp5589-keys.c index 631598663aa..6329549bf6a 100644 --- a/drivers/input/keyboard/adp5589-keys.c +++ b/drivers/input/keyboard/adp5589-keys.c @@ -1,5 +1,5 @@ /* - * Description: keypad driver for ADP5589 + * Description: keypad driver for ADP5589, ADP5585 * I2C QWERTY Keypad and IO Expander * Bugs: Enter bugs at http://blackfin.uclinux.org/ * @@ -8,8 +8,6 @@ */ #include <linux/module.h> -#include <linux/version.h> -#include <linux/init.h> #include <linux/interrupt.h> #include <linux/irq.h> #include <linux/workqueue.h> @@ -23,35 +21,165 @@ #include <linux/input/adp5589.h> +/* ADP5589/ADP5585 Common Registers */ +#define ADP5589_5_ID 0x00 +#define ADP5589_5_INT_STATUS 0x01 +#define ADP5589_5_STATUS 0x02 +#define ADP5589_5_FIFO_1 0x03 +#define ADP5589_5_FIFO_2 0x04 +#define ADP5589_5_FIFO_3 0x05 +#define ADP5589_5_FIFO_4 0x06 +#define ADP5589_5_FIFO_5 0x07 +#define ADP5589_5_FIFO_6 0x08 +#define ADP5589_5_FIFO_7 0x09 +#define ADP5589_5_FIFO_8 0x0A +#define ADP5589_5_FIFO_9 0x0B +#define ADP5589_5_FIFO_10 0x0C +#define ADP5589_5_FIFO_11 0x0D +#define ADP5589_5_FIFO_12 0x0E +#define ADP5589_5_FIFO_13 0x0F +#define ADP5589_5_FIFO_14 0x10 +#define ADP5589_5_FIFO_15 0x11 +#define ADP5589_5_FIFO_16 0x12 +#define ADP5589_5_GPI_INT_STAT_A 0x13 +#define ADP5589_5_GPI_INT_STAT_B 0x14 + +/* ADP5589 Registers */ +#define ADP5589_GPI_INT_STAT_C 0x15 +#define ADP5589_GPI_STATUS_A 0x16 +#define ADP5589_GPI_STATUS_B 0x17 +#define ADP5589_GPI_STATUS_C 0x18 +#define ADP5589_RPULL_CONFIG_A 0x19 +#define ADP5589_RPULL_CONFIG_B 0x1A +#define ADP5589_RPULL_CONFIG_C 0x1B +#define ADP5589_RPULL_CONFIG_D 0x1C +#define ADP5589_RPULL_CONFIG_E 0x1D +#define ADP5589_GPI_INT_LEVEL_A 0x1E +#define ADP5589_GPI_INT_LEVEL_B 0x1F +#define ADP5589_GPI_INT_LEVEL_C 0x20 +#define ADP5589_GPI_EVENT_EN_A 0x21 +#define ADP5589_GPI_EVENT_EN_B 0x22 +#define ADP5589_GPI_EVENT_EN_C 0x23 +#define ADP5589_GPI_INTERRUPT_EN_A 0x24 +#define ADP5589_GPI_INTERRUPT_EN_B 0x25 +#define ADP5589_GPI_INTERRUPT_EN_C 0x26 +#define ADP5589_DEBOUNCE_DIS_A 0x27 +#define ADP5589_DEBOUNCE_DIS_B 0x28 +#define ADP5589_DEBOUNCE_DIS_C 0x29 +#define ADP5589_GPO_DATA_OUT_A 0x2A +#define ADP5589_GPO_DATA_OUT_B 0x2B +#define ADP5589_GPO_DATA_OUT_C 0x2C +#define ADP5589_GPO_OUT_MODE_A 0x2D +#define ADP5589_GPO_OUT_MODE_B 0x2E +#define ADP5589_GPO_OUT_MODE_C 0x2F +#define ADP5589_GPIO_DIRECTION_A 0x30 +#define ADP5589_GPIO_DIRECTION_B 0x31 +#define ADP5589_GPIO_DIRECTION_C 0x32 +#define ADP5589_UNLOCK1 0x33 +#define ADP5589_UNLOCK2 0x34 +#define ADP5589_EXT_LOCK_EVENT 0x35 +#define ADP5589_UNLOCK_TIMERS 0x36 +#define ADP5589_LOCK_CFG 0x37 +#define ADP5589_RESET1_EVENT_A 0x38 +#define ADP5589_RESET1_EVENT_B 0x39 +#define ADP5589_RESET1_EVENT_C 0x3A +#define ADP5589_RESET2_EVENT_A 0x3B +#define ADP5589_RESET2_EVENT_B 0x3C +#define ADP5589_RESET_CFG 0x3D +#define ADP5589_PWM_OFFT_LOW 0x3E +#define ADP5589_PWM_OFFT_HIGH 0x3F +#define ADP5589_PWM_ONT_LOW 0x40 +#define ADP5589_PWM_ONT_HIGH 0x41 +#define ADP5589_PWM_CFG 0x42 +#define ADP5589_CLOCK_DIV_CFG 0x43 +#define ADP5589_LOGIC_1_CFG 0x44 +#define ADP5589_LOGIC_2_CFG 0x45 +#define ADP5589_LOGIC_FF_CFG 0x46 +#define ADP5589_LOGIC_INT_EVENT_EN 0x47 +#define ADP5589_POLL_PTIME_CFG 0x48 +#define ADP5589_PIN_CONFIG_A 0x49 +#define ADP5589_PIN_CONFIG_B 0x4A +#define ADP5589_PIN_CONFIG_C 0x4B +#define ADP5589_PIN_CONFIG_D 0x4C +#define ADP5589_GENERAL_CFG 0x4D +#define ADP5589_INT_EN 0x4E + +/* ADP5585 Registers */ +#define ADP5585_GPI_STATUS_A 0x15 +#define ADP5585_GPI_STATUS_B 0x16 +#define ADP5585_RPULL_CONFIG_A 0x17 +#define ADP5585_RPULL_CONFIG_B 0x18 +#define ADP5585_RPULL_CONFIG_C 0x19 +#define ADP5585_RPULL_CONFIG_D 0x1A +#define ADP5585_GPI_INT_LEVEL_A 0x1B +#define ADP5585_GPI_INT_LEVEL_B 0x1C +#define ADP5585_GPI_EVENT_EN_A 0x1D +#define ADP5585_GPI_EVENT_EN_B 0x1E +#define ADP5585_GPI_INTERRUPT_EN_A 0x1F +#define ADP5585_GPI_INTERRUPT_EN_B 0x20 +#define ADP5585_DEBOUNCE_DIS_A 0x21 +#define ADP5585_DEBOUNCE_DIS_B 0x22 +#define ADP5585_GPO_DATA_OUT_A 0x23 +#define ADP5585_GPO_DATA_OUT_B 0x24 +#define ADP5585_GPO_OUT_MODE_A 0x25 +#define ADP5585_GPO_OUT_MODE_B 0x26 +#define ADP5585_GPIO_DIRECTION_A 0x27 +#define ADP5585_GPIO_DIRECTION_B 0x28 +#define ADP5585_RESET1_EVENT_A 0x29 +#define ADP5585_RESET1_EVENT_B 0x2A +#define ADP5585_RESET1_EVENT_C 0x2B +#define ADP5585_RESET2_EVENT_A 0x2C +#define ADP5585_RESET2_EVENT_B 0x2D +#define ADP5585_RESET_CFG 0x2E +#define ADP5585_PWM_OFFT_LOW 0x2F +#define ADP5585_PWM_OFFT_HIGH 0x30 +#define ADP5585_PWM_ONT_LOW 0x31 +#define ADP5585_PWM_ONT_HIGH 0x32 +#define ADP5585_PWM_CFG 0x33 +#define ADP5585_LOGIC_CFG 0x34 +#define ADP5585_LOGIC_FF_CFG 0x35 +#define ADP5585_LOGIC_INT_EVENT_EN 0x36 +#define ADP5585_POLL_PTIME_CFG 0x37 +#define ADP5585_PIN_CONFIG_A 0x38 +#define ADP5585_PIN_CONFIG_B 0x39 +#define ADP5585_PIN_CONFIG_D 0x3A +#define ADP5585_GENERAL_CFG 0x3B +#define ADP5585_INT_EN 0x3C + +/* ID Register */ +#define ADP5589_5_DEVICE_ID_MASK 0xF +#define ADP5589_5_MAN_ID_MASK 0xF +#define ADP5589_5_MAN_ID_SHIFT 4 +#define ADP5589_5_MAN_ID 0x02 + /* GENERAL_CFG Register */ #define OSC_EN (1 << 7) #define CORE_CLK(x) (((x) & 0x3) << 5) -#define LCK_TRK_LOGIC (1 << 4) -#define LCK_TRK_GPI (1 << 3) +#define LCK_TRK_LOGIC (1 << 4) /* ADP5589 only */ +#define LCK_TRK_GPI (1 << 3) /* ADP5589 only */ #define INT_CFG (1 << 1) #define RST_CFG (1 << 0) /* INT_EN Register */ -#define LOGIC2_IEN (1 << 5) +#define LOGIC2_IEN (1 << 5) /* ADP5589 only */ #define LOGIC1_IEN (1 << 4) -#define LOCK_IEN (1 << 3) +#define LOCK_IEN (1 << 3) /* ADP5589 only */ #define OVRFLOW_IEN (1 << 2) #define GPI_IEN (1 << 1) #define EVENT_IEN (1 << 0) /* Interrupt Status Register */ -#define LOGIC2_INT (1 << 5) +#define LOGIC2_INT (1 << 5) /* ADP5589 only */ #define LOGIC1_INT (1 << 4) -#define LOCK_INT (1 << 3) +#define LOCK_INT (1 << 3) /* ADP5589 only */ #define OVRFLOW_INT (1 << 2) #define GPI_INT (1 << 1) #define EVENT_INT (1 << 0) /* STATUS Register */ - -#define LOGIC2_STAT (1 << 7) +#define LOGIC2_STAT (1 << 7) /* ADP5589 only */ #define LOGIC1_STAT (1 << 6) -#define LOCK_STAT (1 << 5) +#define LOCK_STAT (1 << 5) /* ADP5589 only */ #define KEC 0xF /* PIN_CONFIG_D Register */ @@ -62,27 +190,54 @@ #define LOCK_EN (1 << 0) #define PTIME_MASK 0x3 -#define LTIME_MASK 0x3 +#define LTIME_MASK 0x3 /* ADP5589 only */ /* Key Event Register xy */ #define KEY_EV_PRESSED (1 << 7) #define KEY_EV_MASK (0x7F) #define KEYP_MAX_EVENT 16 +#define ADP5589_MAXGPIO 19 +#define ADP5585_MAXGPIO 11 /* 10 on the ADP5585-01, 11 on ADP5585-02 */ -#define MAXGPIO 19 -#define ADP_BANK(offs) ((offs) >> 3) -#define ADP_BIT(offs) (1u << ((offs) & 0x7)) +enum { + ADP5589, + ADP5585_01, + ADP5585_02 +}; + +struct adp_constants { + u8 maxgpio; + u8 keymapsize; + u8 gpi_pin_row_base; + u8 gpi_pin_row_end; + u8 gpi_pin_col_base; + u8 gpi_pin_base; + u8 gpi_pin_end; + u8 gpimapsize_max; + u8 max_row_num; + u8 max_col_num; + u8 row_mask; + u8 col_mask; + u8 col_shift; + u8 c4_extend_cfg; + u8 (*bank) (u8 offset); + u8 (*bit) (u8 offset); + u8 (*reg) (u8 reg); +}; struct adp5589_kpad { struct i2c_client *client; struct input_dev *input; + const struct adp_constants *var; unsigned short keycode[ADP5589_KEYMAPSIZE]; const struct adp5589_gpi_map *gpimap; unsigned short gpimapsize; unsigned extend_cfg; + bool is_adp5585; + bool adp5585_support_row5; #ifdef CONFIG_GPIOLIB - unsigned char gpiomap[MAXGPIO]; + unsigned char gpiomap[ADP5589_MAXGPIO]; bool export_gpio; struct gpio_chip gc; struct mutex gpio_lock; /* Protect cached dir, dat_out */ @@ -91,6 +246,129 @@ struct adp5589_kpad { #endif }; +/* + * ADP5589 / ADP5585 derivative / variant handling + */ + + +/* ADP5589 */ + +static unsigned char adp5589_bank(unsigned char offset) +{ + return offset >> 3; +} + +static unsigned char adp5589_bit(unsigned char offset) +{ + return 1u << (offset & 0x7); +} + +static unsigned char adp5589_reg(unsigned char reg) +{ + return reg; +} + +static const struct adp_constants const_adp5589 = { + .maxgpio = ADP5589_MAXGPIO, + .keymapsize = ADP5589_KEYMAPSIZE, + .gpi_pin_row_base = ADP5589_GPI_PIN_ROW_BASE, + .gpi_pin_row_end = ADP5589_GPI_PIN_ROW_END, + .gpi_pin_col_base = ADP5589_GPI_PIN_COL_BASE, + .gpi_pin_base = ADP5589_GPI_PIN_BASE, + .gpi_pin_end = ADP5589_GPI_PIN_END, + .gpimapsize_max = ADP5589_GPIMAPSIZE_MAX, + .c4_extend_cfg = 12, + .max_row_num = ADP5589_MAX_ROW_NUM, + .max_col_num = ADP5589_MAX_COL_NUM, + .row_mask = ADP5589_ROW_MASK, + .col_mask = ADP5589_COL_MASK, + .col_shift = ADP5589_COL_SHIFT, + .bank = adp5589_bank, + .bit = adp5589_bit, + .reg = adp5589_reg, +}; + +/* ADP5585 */ + +static unsigned char adp5585_bank(unsigned char offset) +{ + return offset > ADP5585_MAX_ROW_NUM; +} + +static unsigned char adp5585_bit(unsigned char offset) +{ + return (offset > ADP5585_MAX_ROW_NUM) ? + 1u << (offset - ADP5585_COL_SHIFT) : 1u << offset; +} + +static const unsigned char adp5585_reg_lut[] = { + [ADP5589_GPI_STATUS_A] = ADP5585_GPI_STATUS_A, + [ADP5589_GPI_STATUS_B] = ADP5585_GPI_STATUS_B, + [ADP5589_RPULL_CONFIG_A] = ADP5585_RPULL_CONFIG_A, + [ADP5589_RPULL_CONFIG_B] = ADP5585_RPULL_CONFIG_B, + [ADP5589_RPULL_CONFIG_C] = ADP5585_RPULL_CONFIG_C, + [ADP5589_RPULL_CONFIG_D] = ADP5585_RPULL_CONFIG_D, + [ADP5589_GPI_INT_LEVEL_A] = ADP5585_GPI_INT_LEVEL_A, + [ADP5589_GPI_INT_LEVEL_B] = ADP5585_GPI_INT_LEVEL_B, + [ADP5589_GPI_EVENT_EN_A] = ADP5585_GPI_EVENT_EN_A, + [ADP5589_GPI_EVENT_EN_B] = ADP5585_GPI_EVENT_EN_B, + [ADP5589_GPI_INTERRUPT_EN_A] = ADP5585_GPI_INTERRUPT_EN_A, + [ADP5589_GPI_INTERRUPT_EN_B] = ADP5585_GPI_INTERRUPT_EN_B, + [ADP5589_DEBOUNCE_DIS_A] = ADP5585_DEBOUNCE_DIS_A, + [ADP5589_DEBOUNCE_DIS_B] = ADP5585_DEBOUNCE_DIS_B, + [ADP5589_GPO_DATA_OUT_A] = ADP5585_GPO_DATA_OUT_A, + [ADP5589_GPO_DATA_OUT_B] = ADP5585_GPO_DATA_OUT_B, + [ADP5589_GPO_OUT_MODE_A] = ADP5585_GPO_OUT_MODE_A, + [ADP5589_GPO_OUT_MODE_B] = ADP5585_GPO_OUT_MODE_B, + [ADP5589_GPIO_DIRECTION_A] = ADP5585_GPIO_DIRECTION_A, + [ADP5589_GPIO_DIRECTION_B] = ADP5585_GPIO_DIRECTION_B, + [ADP5589_RESET1_EVENT_A] = ADP5585_RESET1_EVENT_A, + [ADP5589_RESET1_EVENT_B] = ADP5585_RESET1_EVENT_B, + [ADP5589_RESET1_EVENT_C] = ADP5585_RESET1_EVENT_C, + [ADP5589_RESET2_EVENT_A] = ADP5585_RESET2_EVENT_A, + [ADP5589_RESET2_EVENT_B] = ADP5585_RESET2_EVENT_B, + [ADP5589_RESET_CFG] = ADP5585_RESET_CFG, + [ADP5589_PWM_OFFT_LOW] = ADP5585_PWM_OFFT_LOW, + [ADP5589_PWM_OFFT_HIGH] = ADP5585_PWM_OFFT_HIGH, + [ADP5589_PWM_ONT_LOW] = ADP5585_PWM_ONT_LOW, + [ADP5589_PWM_ONT_HIGH] = ADP5585_PWM_ONT_HIGH, + [ADP5589_PWM_CFG] = ADP5585_PWM_CFG, + [ADP5589_LOGIC_1_CFG] = ADP5585_LOGIC_CFG, + [ADP5589_LOGIC_FF_CFG] = ADP5585_LOGIC_FF_CFG, + [ADP5589_LOGIC_INT_EVENT_EN] = ADP5585_LOGIC_INT_EVENT_EN, + [ADP5589_POLL_PTIME_CFG] = ADP5585_POLL_PTIME_CFG, + [ADP5589_PIN_CONFIG_A] = ADP5585_PIN_CONFIG_A, + [ADP5589_PIN_CONFIG_B] = ADP5585_PIN_CONFIG_B, + [ADP5589_PIN_CONFIG_D] = ADP5585_PIN_CONFIG_D, + [ADP5589_GENERAL_CFG] = ADP5585_GENERAL_CFG, + [ADP5589_INT_EN] = ADP5585_INT_EN, +}; + +static unsigned char adp5585_reg(unsigned char reg) +{ + return adp5585_reg_lut[reg]; +} + +static const struct adp_constants const_adp5585 = { + .maxgpio = ADP5585_MAXGPIO, + .keymapsize = ADP5585_KEYMAPSIZE, + .gpi_pin_row_base = ADP5585_GPI_PIN_ROW_BASE, + .gpi_pin_row_end = ADP5585_GPI_PIN_ROW_END, + .gpi_pin_col_base = ADP5585_GPI_PIN_COL_BASE, + .gpi_pin_base = ADP5585_GPI_PIN_BASE, + .gpi_pin_end = ADP5585_GPI_PIN_END, + .gpimapsize_max = ADP5585_GPIMAPSIZE_MAX, + .c4_extend_cfg = 10, + .max_row_num = ADP5585_MAX_ROW_NUM, + .max_col_num = ADP5585_MAX_COL_NUM, + .row_mask = ADP5585_ROW_MASK, + .col_mask = ADP5585_COL_MASK, + .col_shift = ADP5585_COL_SHIFT, + .bank = adp5585_bank, + .bit = adp5585_bit, + .reg = adp5585_reg, +}; + static int adp5589_read(struct i2c_client *client, u8 reg) { int ret = i2c_smbus_read_byte_data(client, reg); @@ -110,19 +388,20 @@ static int adp5589_write(struct i2c_client *client, u8 reg, u8 val) static int adp5589_gpio_get_value(struct gpio_chip *chip, unsigned off) { struct adp5589_kpad *kpad = container_of(chip, struct adp5589_kpad, gc); - unsigned int bank = ADP_BANK(kpad->gpiomap[off]); - unsigned int bit = ADP_BIT(kpad->gpiomap[off]); + unsigned int bank = kpad->var->bank(kpad->gpiomap[off]); + unsigned int bit = kpad->var->bit(kpad->gpiomap[off]); - return !!(adp5589_read(kpad->client, ADP5589_GPI_STATUS_A + bank) & - bit); + return !!(adp5589_read(kpad->client, + kpad->var->reg(ADP5589_GPI_STATUS_A) + bank) & + bit); } static void adp5589_gpio_set_value(struct gpio_chip *chip, unsigned off, int val) { struct adp5589_kpad *kpad = container_of(chip, struct adp5589_kpad, gc); - unsigned int bank = ADP_BANK(kpad->gpiomap[off]); - unsigned int bit = ADP_BIT(kpad->gpiomap[off]); + unsigned int bank = kpad->var->bank(kpad->gpiomap[off]); + unsigned int bit = kpad->var->bit(kpad->gpiomap[off]); mutex_lock(&kpad->gpio_lock); @@ -131,8 +410,8 @@ static void adp5589_gpio_set_value(struct gpio_chip *chip, else kpad->dat_out[bank] &= ~bit; - adp5589_write(kpad->client, ADP5589_GPO_DATA_OUT_A + bank, - kpad->dat_out[bank]); + adp5589_write(kpad->client, kpad->var->reg(ADP5589_GPO_DATA_OUT_A) + + bank, kpad->dat_out[bank]); mutex_unlock(&kpad->gpio_lock); } @@ -140,14 +419,15 @@ static void adp5589_gpio_set_value(struct gpio_chip *chip, static int adp5589_gpio_direction_input(struct gpio_chip *chip, unsigned off) { struct adp5589_kpad *kpad = container_of(chip, struct adp5589_kpad, gc); - unsigned int bank = ADP_BANK(kpad->gpiomap[off]); - unsigned int bit = ADP_BIT(kpad->gpiomap[off]); + unsigned int bank = kpad->var->bank(kpad->gpiomap[off]); + unsigned int bit = kpad->var->bit(kpad->gpiomap[off]); int ret; mutex_lock(&kpad->gpio_lock); kpad->dir[bank] &= ~bit; - ret = adp5589_write(kpad->client, ADP5589_GPIO_DIRECTION_A + bank, + ret = adp5589_write(kpad->client, + kpad->var->reg(ADP5589_GPIO_DIRECTION_A) + bank, kpad->dir[bank]); mutex_unlock(&kpad->gpio_lock); @@ -159,8 +439,8 @@ static int adp5589_gpio_direction_output(struct gpio_chip *chip, unsigned off, int val) { struct adp5589_kpad *kpad = container_of(chip, struct adp5589_kpad, gc); - unsigned int bank = ADP_BANK(kpad->gpiomap[off]); - unsigned int bit = ADP_BIT(kpad->gpiomap[off]); + unsigned int bank = kpad->var->bank(kpad->gpiomap[off]); + unsigned int bit = kpad->var->bit(kpad->gpiomap[off]); int ret; mutex_lock(&kpad->gpio_lock); @@ -172,9 +452,10 @@ static int adp5589_gpio_direction_output(struct gpio_chip *chip, else kpad->dat_out[bank] &= ~bit; - ret = adp5589_write(kpad->client, ADP5589_GPO_DATA_OUT_A + bank, - kpad->dat_out[bank]); - ret |= adp5589_write(kpad->client, ADP5589_GPIO_DIRECTION_A + bank, + ret = adp5589_write(kpad->client, kpad->var->reg(ADP5589_GPO_DATA_OUT_A) + + bank, kpad->dat_out[bank]); + ret |= adp5589_write(kpad->client, + kpad->var->reg(ADP5589_GPIO_DIRECTION_A) + bank, kpad->dir[bank]); mutex_unlock(&kpad->gpio_lock); @@ -182,39 +463,42 @@ static int adp5589_gpio_direction_output(struct gpio_chip *chip, return ret; } -static int __devinit adp5589_build_gpiomap(struct adp5589_kpad *kpad, +static int adp5589_build_gpiomap(struct adp5589_kpad *kpad, const struct adp5589_kpad_platform_data *pdata) { - bool pin_used[MAXGPIO]; + bool pin_used[ADP5589_MAXGPIO]; int n_unused = 0; int i; memset(pin_used, false, sizeof(pin_used)); - for (i = 0; i < MAXGPIO; i++) + for (i = 0; i < kpad->var->maxgpio; i++) if (pdata->keypad_en_mask & (1 << i)) pin_used[i] = true; for (i = 0; i < kpad->gpimapsize; i++) - pin_used[kpad->gpimap[i].pin - ADP5589_GPI_PIN_BASE] = true; + pin_used[kpad->gpimap[i].pin - kpad->var->gpi_pin_base] = true; if (kpad->extend_cfg & R4_EXTEND_CFG) pin_used[4] = true; if (kpad->extend_cfg & C4_EXTEND_CFG) - pin_used[12] = true; + pin_used[kpad->var->c4_extend_cfg] = true; + + if (!kpad->adp5585_support_row5) + pin_used[5] = true; - for (i = 0; i < MAXGPIO; i++) + for (i = 0; i < kpad->var->maxgpio; i++) if (!pin_used[i]) kpad->gpiomap[n_unused++] = i; return n_unused; } -static int __devinit adp5589_gpio_add(struct adp5589_kpad *kpad) +static int adp5589_gpio_add(struct adp5589_kpad *kpad) { struct device *dev = &kpad->client->dev; - const struct adp5589_kpad_platform_data *pdata = dev->platform_data; + const struct adp5589_kpad_platform_data *pdata = dev_get_platdata(dev); const struct adp5589_gpio_platform_data *gpio_data = pdata->gpio_data; int i, error; @@ -247,11 +531,11 @@ static int __devinit adp5589_gpio_add(struct adp5589_kpad *kpad) return error; } - for (i = 0; i <= ADP_BANK(MAXGPIO); i++) { - kpad->dat_out[i] = adp5589_read(kpad->client, - ADP5589_GPO_DATA_OUT_A + i); - kpad->dir[i] = adp5589_read(kpad->client, - ADP5589_GPIO_DIRECTION_A + i); + for (i = 0; i <= kpad->var->bank(kpad->var->maxgpio); i++) { + kpad->dat_out[i] = adp5589_read(kpad->client, kpad->var->reg( + ADP5589_GPO_DATA_OUT_A) + i); + kpad->dir[i] = adp5589_read(kpad->client, kpad->var->reg( + ADP5589_GPIO_DIRECTION_A) + i); } if (gpio_data->setup) { @@ -265,10 +549,10 @@ static int __devinit adp5589_gpio_add(struct adp5589_kpad *kpad) return 0; } -static void __devexit adp5589_gpio_remove(struct adp5589_kpad *kpad) +static void adp5589_gpio_remove(struct adp5589_kpad *kpad) { struct device *dev = &kpad->client->dev; - const struct adp5589_kpad_platform_data *pdata = dev->platform_data; + const struct adp5589_kpad_platform_data *pdata = dev_get_platdata(dev); const struct adp5589_gpio_platform_data *gpio_data = pdata->gpio_data; int error; @@ -318,11 +602,11 @@ static void adp5589_report_events(struct adp5589_kpad *kpad, int ev_cnt) int i; for (i = 0; i < ev_cnt; i++) { - int key = adp5589_read(kpad->client, ADP5589_FIFO_1 + i); + int key = adp5589_read(kpad->client, ADP5589_5_FIFO_1 + i); int key_val = key & KEY_EV_MASK; - if (key_val >= ADP5589_GPI_PIN_BASE && - key_val <= ADP5589_GPI_PIN_END) { + if (key_val >= kpad->var->gpi_pin_base && + key_val <= kpad->var->gpi_pin_end) { adp5589_report_switches(kpad, key, key_val); } else { input_report_key(kpad->input, @@ -338,29 +622,29 @@ static irqreturn_t adp5589_irq(int irq, void *handle) struct i2c_client *client = kpad->client; int status, ev_cnt; - status = adp5589_read(client, ADP5589_INT_STATUS); + status = adp5589_read(client, ADP5589_5_INT_STATUS); if (status & OVRFLOW_INT) /* Unlikely and should never happen */ dev_err(&client->dev, "Event Overflow Error\n"); if (status & EVENT_INT) { - ev_cnt = adp5589_read(client, ADP5589_STATUS) & KEC; + ev_cnt = adp5589_read(client, ADP5589_5_STATUS) & KEC; if (ev_cnt) { adp5589_report_events(kpad, ev_cnt); input_sync(kpad->input); } } - adp5589_write(client, ADP5589_INT_STATUS, status); /* Status is W1C */ + adp5589_write(client, ADP5589_5_INT_STATUS, status); /* Status is W1C */ return IRQ_HANDLED; } -static int __devinit adp5589_get_evcode(struct adp5589_kpad *kpad, unsigned short key) +static int adp5589_get_evcode(struct adp5589_kpad *kpad, unsigned short key) { int i; - for (i = 0; i < ADP5589_KEYMAPSIZE; i++) + for (i = 0; i < kpad->var->keymapsize; i++) if (key == kpad->keycode[i]) return (i + 1) | KEY_EV_PRESSED; @@ -369,23 +653,27 @@ static int __devinit adp5589_get_evcode(struct adp5589_kpad *kpad, unsigned shor return -EINVAL; } -static int __devinit adp5589_setup(struct adp5589_kpad *kpad) +static int adp5589_setup(struct adp5589_kpad *kpad) { struct i2c_client *client = kpad->client; const struct adp5589_kpad_platform_data *pdata = - client->dev.platform_data; - int i, ret; + dev_get_platdata(&client->dev); + u8 (*reg) (u8) = kpad->var->reg; unsigned char evt_mode1 = 0, evt_mode2 = 0, evt_mode3 = 0; unsigned char pull_mask = 0; + int i, ret; - ret = adp5589_write(client, ADP5589_PIN_CONFIG_A, - pdata->keypad_en_mask & 0xFF); - ret |= adp5589_write(client, ADP5589_PIN_CONFIG_B, - (pdata->keypad_en_mask >> 8) & 0xFF); - ret |= adp5589_write(client, ADP5589_PIN_CONFIG_C, - (pdata->keypad_en_mask >> 16) & 0xFF); + ret = adp5589_write(client, reg(ADP5589_PIN_CONFIG_A), + pdata->keypad_en_mask & kpad->var->row_mask); + ret |= adp5589_write(client, reg(ADP5589_PIN_CONFIG_B), + (pdata->keypad_en_mask >> kpad->var->col_shift) & + kpad->var->col_mask); - if (pdata->en_keylock) { + if (!kpad->is_adp5585) + ret |= adp5589_write(client, ADP5589_PIN_CONFIG_C, + (pdata->keypad_en_mask >> 16) & 0xFF); + + if (!kpad->is_adp5585 && pdata->en_keylock) { ret |= adp5589_write(client, ADP5589_UNLOCK1, pdata->unlock_key1); ret |= adp5589_write(client, ADP5589_UNLOCK2, @@ -396,96 +684,130 @@ static int __devinit adp5589_setup(struct adp5589_kpad *kpad) } for (i = 0; i < KEYP_MAX_EVENT; i++) - ret |= adp5589_read(client, ADP5589_FIFO_1 + i); + ret |= adp5589_read(client, ADP5589_5_FIFO_1 + i); for (i = 0; i < pdata->gpimapsize; i++) { unsigned short pin = pdata->gpimap[i].pin; - if (pin <= ADP5589_GPI_PIN_ROW_END) { - evt_mode1 |= (1 << (pin - ADP5589_GPI_PIN_ROW_BASE)); + if (pin <= kpad->var->gpi_pin_row_end) { + evt_mode1 |= (1 << (pin - kpad->var->gpi_pin_row_base)); } else { evt_mode2 |= - ((1 << (pin - ADP5589_GPI_PIN_COL_BASE)) & 0xFF); - evt_mode3 |= - ((1 << (pin - ADP5589_GPI_PIN_COL_BASE)) >> 8); + ((1 << (pin - kpad->var->gpi_pin_col_base)) & 0xFF); + if (!kpad->is_adp5585) + evt_mode3 |= ((1 << (pin - + kpad->var->gpi_pin_col_base)) >> 8); } } if (pdata->gpimapsize) { - ret |= adp5589_write(client, ADP5589_GPI_EVENT_EN_A, evt_mode1); - ret |= adp5589_write(client, ADP5589_GPI_EVENT_EN_B, evt_mode2); - ret |= adp5589_write(client, ADP5589_GPI_EVENT_EN_C, evt_mode3); + ret |= adp5589_write(client, reg(ADP5589_GPI_EVENT_EN_A), + evt_mode1); + ret |= adp5589_write(client, reg(ADP5589_GPI_EVENT_EN_B), + evt_mode2); + if (!kpad->is_adp5585) + ret |= adp5589_write(client, + reg(ADP5589_GPI_EVENT_EN_C), + evt_mode3); } if (pdata->pull_dis_mask & pdata->pullup_en_100k & - pdata->pullup_en_300k & pdata->pulldown_en_300k) + pdata->pullup_en_300k & pdata->pulldown_en_300k) dev_warn(&client->dev, "Conflicting pull resistor config\n"); - for (i = 0; i < MAXGPIO; i++) { - unsigned val = 0; + for (i = 0; i <= kpad->var->max_row_num; i++) { + unsigned val = 0, bit = (1 << i); + if (pdata->pullup_en_300k & bit) + val = 0; + else if (pdata->pulldown_en_300k & bit) + val = 1; + else if (pdata->pullup_en_100k & bit) + val = 2; + else if (pdata->pull_dis_mask & bit) + val = 3; + + pull_mask |= val << (2 * (i & 0x3)); - if (pdata->pullup_en_300k & (1 << i)) + if (i == 3 || i == kpad->var->max_row_num) { + ret |= adp5589_write(client, reg(ADP5585_RPULL_CONFIG_A) + + (i >> 2), pull_mask); + pull_mask = 0; + } + } + + for (i = 0; i <= kpad->var->max_col_num; i++) { + unsigned val = 0, bit = 1 << (i + kpad->var->col_shift); + if (pdata->pullup_en_300k & bit) val = 0; - else if (pdata->pulldown_en_300k & (1 << i)) + else if (pdata->pulldown_en_300k & bit) val = 1; - else if (pdata->pullup_en_100k & (1 << i)) + else if (pdata->pullup_en_100k & bit) val = 2; - else if (pdata->pull_dis_mask & (1 << i)) + else if (pdata->pull_dis_mask & bit) val = 3; pull_mask |= val << (2 * (i & 0x3)); - if ((i & 0x3) == 0x3 || i == MAXGPIO - 1) { + if (i == 3 || i == kpad->var->max_col_num) { ret |= adp5589_write(client, - ADP5589_RPULL_CONFIG_A + (i >> 2), - pull_mask); + reg(ADP5585_RPULL_CONFIG_C) + + (i >> 2), pull_mask); pull_mask = 0; } } if (pdata->reset1_key_1 && pdata->reset1_key_2 && pdata->reset1_key_3) { - ret |= adp5589_write(client, ADP5589_RESET1_EVENT_A, + ret |= adp5589_write(client, reg(ADP5589_RESET1_EVENT_A), adp5589_get_evcode(kpad, pdata->reset1_key_1)); - ret |= adp5589_write(client, ADP5589_RESET1_EVENT_B, + ret |= adp5589_write(client, reg(ADP5589_RESET1_EVENT_B), adp5589_get_evcode(kpad, pdata->reset1_key_2)); - ret |= adp5589_write(client, ADP5589_RESET1_EVENT_C, + ret |= adp5589_write(client, reg(ADP5589_RESET1_EVENT_C), adp5589_get_evcode(kpad, pdata->reset1_key_3)); kpad->extend_cfg |= R4_EXTEND_CFG; } if (pdata->reset2_key_1 && pdata->reset2_key_2) { - ret |= adp5589_write(client, ADP5589_RESET2_EVENT_A, + ret |= adp5589_write(client, reg(ADP5589_RESET2_EVENT_A), adp5589_get_evcode(kpad, pdata->reset2_key_1)); - ret |= adp5589_write(client, ADP5589_RESET2_EVENT_B, + ret |= adp5589_write(client, reg(ADP5589_RESET2_EVENT_B), adp5589_get_evcode(kpad, pdata->reset2_key_2)); kpad->extend_cfg |= C4_EXTEND_CFG; } if (kpad->extend_cfg) { - ret |= adp5589_write(client, ADP5589_RESET_CFG, + ret |= adp5589_write(client, reg(ADP5589_RESET_CFG), pdata->reset_cfg); - ret |= adp5589_write(client, ADP5589_PIN_CONFIG_D, + ret |= adp5589_write(client, reg(ADP5589_PIN_CONFIG_D), kpad->extend_cfg); } - for (i = 0; i <= ADP_BANK(MAXGPIO); i++) - ret |= adp5589_write(client, ADP5589_DEBOUNCE_DIS_A + i, - pdata->debounce_dis_mask >> (i * 8)); + ret |= adp5589_write(client, reg(ADP5589_DEBOUNCE_DIS_A), + pdata->debounce_dis_mask & kpad->var->row_mask); + + ret |= adp5589_write(client, reg(ADP5589_DEBOUNCE_DIS_B), + (pdata->debounce_dis_mask >> kpad->var->col_shift) + & kpad->var->col_mask); - ret |= adp5589_write(client, ADP5589_POLL_PTIME_CFG, + if (!kpad->is_adp5585) + ret |= adp5589_write(client, reg(ADP5589_DEBOUNCE_DIS_C), + (pdata->debounce_dis_mask >> 16) & 0xFF); + + ret |= adp5589_write(client, reg(ADP5589_POLL_PTIME_CFG), pdata->scan_cycle_time & PTIME_MASK); - ret |= adp5589_write(client, ADP5589_INT_STATUS, LOGIC2_INT | - LOGIC1_INT | OVRFLOW_INT | LOCK_INT | + ret |= adp5589_write(client, ADP5589_5_INT_STATUS, + (kpad->is_adp5585 ? 0 : LOGIC2_INT) | + LOGIC1_INT | OVRFLOW_INT | + (kpad->is_adp5585 ? 0 : LOCK_INT) | GPI_INT | EVENT_INT); /* Status is W1C */ - ret |= adp5589_write(client, ADP5589_GENERAL_CFG, + ret |= adp5589_write(client, reg(ADP5589_GENERAL_CFG), INT_CFG | OSC_EN | CORE_CLK(3)); - ret |= adp5589_write(client, ADP5589_INT_EN, + ret |= adp5589_write(client, reg(ADP5589_INT_EN), OVRFLOW_IEN | GPI_IEN | EVENT_IEN); if (ret < 0) { @@ -496,32 +818,35 @@ static int __devinit adp5589_setup(struct adp5589_kpad *kpad) return 0; } -static void __devinit adp5589_report_switch_state(struct adp5589_kpad *kpad) +static void adp5589_report_switch_state(struct adp5589_kpad *kpad) { - int gpi_stat1 = adp5589_read(kpad->client, ADP5589_GPI_STATUS_A); - int gpi_stat2 = adp5589_read(kpad->client, ADP5589_GPI_STATUS_B); - int gpi_stat3 = adp5589_read(kpad->client, ADP5589_GPI_STATUS_C); int gpi_stat_tmp, pin_loc; int i; + int gpi_stat1 = adp5589_read(kpad->client, + kpad->var->reg(ADP5589_GPI_STATUS_A)); + int gpi_stat2 = adp5589_read(kpad->client, + kpad->var->reg(ADP5589_GPI_STATUS_B)); + int gpi_stat3 = !kpad->is_adp5585 ? + adp5589_read(kpad->client, ADP5589_GPI_STATUS_C) : 0; for (i = 0; i < kpad->gpimapsize; i++) { unsigned short pin = kpad->gpimap[i].pin; - if (pin <= ADP5589_GPI_PIN_ROW_END) { + if (pin <= kpad->var->gpi_pin_row_end) { gpi_stat_tmp = gpi_stat1; - pin_loc = pin - ADP5589_GPI_PIN_ROW_BASE; - } else if ((pin - ADP5589_GPI_PIN_COL_BASE) < 8) { + pin_loc = pin - kpad->var->gpi_pin_row_base; + } else if ((pin - kpad->var->gpi_pin_col_base) < 8) { gpi_stat_tmp = gpi_stat2; - pin_loc = pin - ADP5589_GPI_PIN_COL_BASE; + pin_loc = pin - kpad->var->gpi_pin_col_base; } else { gpi_stat_tmp = gpi_stat3; - pin_loc = pin - ADP5589_GPI_PIN_COL_BASE - 8; + pin_loc = pin - kpad->var->gpi_pin_col_base - 8; } if (gpi_stat_tmp < 0) { dev_err(&kpad->client->dev, - "Can't read GPIO_DAT_STAT switch" - " %d default to OFF\n", pin); + "Can't read GPIO_DAT_STAT switch %d, default to OFF\n", + pin); gpi_stat_tmp = 0; } @@ -533,11 +858,12 @@ static void __devinit adp5589_report_switch_state(struct adp5589_kpad *kpad) input_sync(kpad->input); } -static int __devinit adp5589_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int adp5589_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct adp5589_kpad *kpad; - const struct adp5589_kpad_platform_data *pdata; + const struct adp5589_kpad_platform_data *pdata = + dev_get_platdata(&client->dev); struct input_dev *input; unsigned int revid; int ret, i; @@ -549,56 +875,79 @@ static int __devinit adp5589_probe(struct i2c_client *client, return -EIO; } - pdata = client->dev.platform_data; if (!pdata) { dev_err(&client->dev, "no platform data?\n"); return -EINVAL; } - if (!((pdata->keypad_en_mask & 0xFF) && - (pdata->keypad_en_mask >> 8)) || !pdata->keymap) { + kpad = kzalloc(sizeof(*kpad), GFP_KERNEL); + if (!kpad) + return -ENOMEM; + + switch (id->driver_data) { + case ADP5585_02: + kpad->adp5585_support_row5 = true; + case ADP5585_01: + kpad->is_adp5585 = true; + kpad->var = &const_adp5585; + break; + case ADP5589: + kpad->var = &const_adp5589; + break; + } + + if (!((pdata->keypad_en_mask & kpad->var->row_mask) && + (pdata->keypad_en_mask >> kpad->var->col_shift)) || + !pdata->keymap) { dev_err(&client->dev, "no rows, cols or keymap from pdata\n"); - return -EINVAL; + error = -EINVAL; + goto err_free_mem; } - if (pdata->keymapsize != ADP5589_KEYMAPSIZE) { + if (pdata->keymapsize != kpad->var->keymapsize) { dev_err(&client->dev, "invalid keymapsize\n"); - return -EINVAL; + error = -EINVAL; + goto err_free_mem; } if (!pdata->gpimap && pdata->gpimapsize) { dev_err(&client->dev, "invalid gpimap from pdata\n"); - return -EINVAL; + error = -EINVAL; + goto err_free_mem; } - if (pdata->gpimapsize > ADP5589_GPIMAPSIZE_MAX) { + if (pdata->gpimapsize > kpad->var->gpimapsize_max) { dev_err(&client->dev, "invalid gpimapsize\n"); - return -EINVAL; + error = -EINVAL; + goto err_free_mem; } for (i = 0; i < pdata->gpimapsize; i++) { unsigned short pin = pdata->gpimap[i].pin; - if (pin < ADP5589_GPI_PIN_BASE || pin > ADP5589_GPI_PIN_END) { + if (pin < kpad->var->gpi_pin_base || + pin > kpad->var->gpi_pin_end) { dev_err(&client->dev, "invalid gpi pin data\n"); - return -EINVAL; + error = -EINVAL; + goto err_free_mem; } - if ((1 << (pin - ADP5589_GPI_PIN_ROW_BASE)) & + if ((1 << (pin - kpad->var->gpi_pin_row_base)) & pdata->keypad_en_mask) { dev_err(&client->dev, "invalid gpi row/col data\n"); - return -EINVAL; + error = -EINVAL; + goto err_free_mem; } } if (!client->irq) { dev_err(&client->dev, "no IRQ?\n"); - return -EINVAL; + error = -EINVAL; + goto err_free_mem; } - kpad = kzalloc(sizeof(*kpad), GFP_KERNEL); input = input_allocate_device(); - if (!kpad || !input) { + if (!input) { error = -ENOMEM; goto err_free_mem; } @@ -606,13 +955,13 @@ static int __devinit adp5589_probe(struct i2c_client *client, kpad->client = client; kpad->input = input; - ret = adp5589_read(client, ADP5589_ID); + ret = adp5589_read(client, ADP5589_5_ID); if (ret < 0) { error = ret; - goto err_free_mem; + goto err_free_input; } - revid = (u8) ret & ADP5589_DEVICE_ID_MASK; + revid = (u8) ret & ADP5589_5_DEVICE_ID_MASK; input->name = client->name; input->phys = "adp5589-keys/input0"; @@ -642,7 +991,8 @@ static int __devinit adp5589_probe(struct i2c_client *client, __set_bit(EV_REP, input->evbit); for (i = 0; i < input->keycodemax; i++) - __set_bit(kpad->keycode[i] & KEY_MAX, input->keybit); + if (kpad->keycode[i] <= KEY_MAX) + __set_bit(kpad->keycode[i], input->keybit); __clear_bit(KEY_RESERVED, input->keybit); if (kpad->gpimapsize) @@ -653,7 +1003,7 @@ static int __devinit adp5589_probe(struct i2c_client *client, error = input_register_device(input); if (error) { dev_err(&client->dev, "unable to register input device\n"); - goto err_free_mem; + goto err_free_input; } error = request_threaded_irq(client->irq, NULL, adp5589_irq, @@ -686,18 +1036,19 @@ err_free_irq: err_unreg_dev: input_unregister_device(input); input = NULL; -err_free_mem: +err_free_input: input_free_device(input); +err_free_mem: kfree(kpad); return error; } -static int __devexit adp5589_remove(struct i2c_client *client) +static int adp5589_remove(struct i2c_client *client) { struct adp5589_kpad *kpad = i2c_get_clientdata(client); - adp5589_write(client, ADP5589_GENERAL_CFG, 0); + adp5589_write(client, kpad->var->reg(ADP5589_GENERAL_CFG), 0); free_irq(client->irq, kpad); input_unregister_device(kpad->input); adp5589_gpio_remove(kpad); @@ -737,7 +1088,9 @@ static int adp5589_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(adp5589_dev_pm_ops, adp5589_suspend, adp5589_resume); static const struct i2c_device_id adp5589_id[] = { - {"adp5589-keys", 0}, + {"adp5589-keys", ADP5589}, + {"adp5585-keys", ADP5585_01}, + {"adp5585-02-keys", ADP5585_02}, /* Adds ROW5 to ADP5585 */ {} }; @@ -750,22 +1103,12 @@ static struct i2c_driver adp5589_driver = { .pm = &adp5589_dev_pm_ops, }, .probe = adp5589_probe, - .remove = __devexit_p(adp5589_remove), + .remove = adp5589_remove, .id_table = adp5589_id, }; -static int __init adp5589_init(void) -{ - return i2c_add_driver(&adp5589_driver); -} -module_init(adp5589_init); - -static void __exit adp5589_exit(void) -{ - i2c_del_driver(&adp5589_driver); -} -module_exit(adp5589_exit); +module_i2c_driver(adp5589_driver); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); -MODULE_DESCRIPTION("ADP5589 Keypad driver"); +MODULE_DESCRIPTION("ADP5589/ADP5585 Keypad driver"); diff --git a/drivers/input/keyboard/amikbd.c b/drivers/input/keyboard/amikbd.c index 79172af164f..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; @@ -260,18 +259,6 @@ static struct platform_driver amikbd_driver = { }, }; -static int __init amikbd_init(void) -{ - return platform_driver_probe(&amikbd_driver, amikbd_probe); -} - -module_init(amikbd_init); - -static void __exit amikbd_exit(void) -{ - platform_driver_unregister(&amikbd_driver); -} - -module_exit(amikbd_exit); +module_platform_driver_probe(amikbd_driver, amikbd_probe); MODULE_ALIAS("platform:amiga-keyboard"); diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c index 11478eb2c27..2dd1d0dd4f7 100644 --- a/drivers/input/keyboard/atkbd.c +++ b/drivers/input/keyboard/atkbd.c @@ -243,6 +243,12 @@ static void (*atkbd_platform_fixup)(struct atkbd *, const void *data); static void *atkbd_platform_fixup_data; static unsigned int (*atkbd_platform_scancode_fixup)(struct atkbd *, unsigned int); +/* + * Certain keyboards to not like ATKBD_CMD_RESET_DIS and stop responding + * to many commands until full reset (ATKBD_CMD_RESET_BAT) is performed. + */ +static bool atkbd_skip_deactivate; + static ssize_t atkbd_attr_show_helper(struct device *dev, char *buf, ssize_t (*handler)(struct atkbd *, char *)); static ssize_t atkbd_attr_set_helper(struct device *dev, const char *buf, size_t count, @@ -433,7 +439,7 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, if (printk_ratelimit()) dev_warn(&serio->dev, "Spurious %s on %s. " - "Some program might be trying access hardware directly.\n", + "Some program might be trying to access hardware directly.\n", data == ATKBD_RET_ACK ? "ACK" : "NAK", serio->phys); goto out; case ATKBD_RET_ERR: @@ -676,6 +682,39 @@ static inline void atkbd_disable(struct atkbd *atkbd) serio_continue_rx(atkbd->ps2dev.serio); } +static int atkbd_activate(struct atkbd *atkbd) +{ + struct ps2dev *ps2dev = &atkbd->ps2dev; + +/* + * Enable the keyboard to receive keystrokes. + */ + + if (ps2_command(ps2dev, NULL, ATKBD_CMD_ENABLE)) { + dev_err(&ps2dev->serio->dev, + "Failed to enable keyboard on %s\n", + ps2dev->serio->phys); + return -1; + } + + return 0; +} + +/* + * atkbd_deactivate() resets and disables the keyboard from sending + * keystrokes. + */ + +static void atkbd_deactivate(struct atkbd *atkbd) +{ + struct ps2dev *ps2dev = &atkbd->ps2dev; + + if (ps2_command(ps2dev, NULL, ATKBD_CMD_RESET_DIS)) + dev_err(&ps2dev->serio->dev, + "Failed to deactivate keyboard on %s\n", + ps2dev->serio->phys); +} + /* * atkbd_probe() probes for an AT keyboard on a serio port. */ @@ -726,11 +765,18 @@ static int atkbd_probe(struct atkbd *atkbd) if (atkbd->id == 0xaca1 && atkbd->translated) { dev_err(&ps2dev->serio->dev, - "NCD terminal keyboards are only supported on non-translating controlelrs. " + "NCD terminal keyboards are only supported on non-translating controllers. " "Use i8042.direct=1 to disable translation.\n"); return -1; } +/* + * Make sure nothing is coming from the keyboard and disturbs our + * internal state. + */ + if (!atkbd_skip_deactivate) + atkbd_deactivate(atkbd); + return 0; } @@ -825,24 +871,6 @@ static int atkbd_reset_state(struct atkbd *atkbd) return 0; } -static int atkbd_activate(struct atkbd *atkbd) -{ - struct ps2dev *ps2dev = &atkbd->ps2dev; - -/* - * Enable the keyboard to receive keystrokes. - */ - - if (ps2_command(ps2dev, NULL, ATKBD_CMD_ENABLE)) { - dev_err(&ps2dev->serio->dev, - "Failed to enable keyboard on %s\n", - ps2dev->serio->phys); - return -1; - } - - return 0; -} - /* * atkbd_cleanup() restores the keyboard state so that BIOS is happy after a * reboot. @@ -1150,7 +1178,6 @@ static int atkbd_connect(struct serio *serio, struct serio_driver *drv) atkbd->set = atkbd_select_set(atkbd, atkbd_set, atkbd_extra); atkbd_reset_state(atkbd); - atkbd_activate(atkbd); } else { atkbd->set = 2; @@ -1165,6 +1192,8 @@ static int atkbd_connect(struct serio *serio, struct serio_driver *drv) goto fail3; atkbd_enable(atkbd); + if (serio->write) + atkbd_activate(atkbd); err = input_register_device(atkbd->dev); if (err) @@ -1208,8 +1237,6 @@ static int atkbd_reconnect(struct serio *serio) if (atkbd->set != atkbd_select_set(atkbd, atkbd->set, atkbd->extra)) goto out; - atkbd_activate(atkbd); - /* * Restore LED state and repeat rate. While input core * will do this for us at resume time reconnect may happen @@ -1223,7 +1250,17 @@ static int atkbd_reconnect(struct serio *serio) } + /* + * Reset our state machine in case reconnect happened in the middle + * of multi-byte scancode. + */ + atkbd->xl_bit = 0; + atkbd->emul = 0; + atkbd_enable(atkbd); + if (atkbd->write) + atkbd_activate(atkbd); + retval = 0; out: @@ -1305,7 +1342,7 @@ static ssize_t atkbd_show_extra(struct atkbd *atkbd, char *buf) static ssize_t atkbd_set_extra(struct atkbd *atkbd, const char *buf, size_t count) { struct input_dev *old_dev, *new_dev; - unsigned long value; + unsigned int value; int err; bool old_extra; unsigned char old_set; @@ -1313,7 +1350,11 @@ static ssize_t atkbd_set_extra(struct atkbd *atkbd, const char *buf, size_t coun if (!atkbd->write) return -EIO; - if (strict_strtoul(buf, 10, &value) || value > 1) + err = kstrtouint(buf, 10, &value); + if (err) + return err; + + if (value > 1) return -EINVAL; if (atkbd->extra != value) { @@ -1389,11 +1430,15 @@ static ssize_t atkbd_show_scroll(struct atkbd *atkbd, char *buf) static ssize_t atkbd_set_scroll(struct atkbd *atkbd, const char *buf, size_t count) { struct input_dev *old_dev, *new_dev; - unsigned long value; + unsigned int value; int err; bool old_scroll; - if (strict_strtoul(buf, 10, &value) || value > 1) + err = kstrtouint(buf, 10, &value); + if (err) + return err; + + if (value > 1) return -EINVAL; if (atkbd->scroll != value) { @@ -1433,7 +1478,7 @@ static ssize_t atkbd_show_set(struct atkbd *atkbd, char *buf) static ssize_t atkbd_set_set(struct atkbd *atkbd, const char *buf, size_t count) { struct input_dev *old_dev, *new_dev; - unsigned long value; + unsigned int value; int err; unsigned char old_set; bool old_extra; @@ -1441,7 +1486,11 @@ static ssize_t atkbd_set_set(struct atkbd *atkbd, const char *buf, size_t count) if (!atkbd->write) return -EIO; - if (strict_strtoul(buf, 10, &value) || (value != 2 && value != 3)) + err = kstrtouint(buf, 10, &value); + if (err) + return err; + + if (value != 2 && value != 3) return -EINVAL; if (atkbd->set != value) { @@ -1484,14 +1533,18 @@ static ssize_t atkbd_show_softrepeat(struct atkbd *atkbd, char *buf) static ssize_t atkbd_set_softrepeat(struct atkbd *atkbd, const char *buf, size_t count) { struct input_dev *old_dev, *new_dev; - unsigned long value; + unsigned int value; int err; bool old_softrepeat, old_softraw; if (!atkbd->write) return -EIO; - if (strict_strtoul(buf, 10, &value) || value > 1) + err = kstrtouint(buf, 10, &value); + if (err) + return err; + + if (value > 1) return -EINVAL; if (atkbd->softrepeat != value) { @@ -1534,11 +1587,15 @@ static ssize_t atkbd_show_softraw(struct atkbd *atkbd, char *buf) static ssize_t atkbd_set_softraw(struct atkbd *atkbd, const char *buf, size_t count) { struct input_dev *old_dev, *new_dev; - unsigned long value; + unsigned int value; int err; bool old_softraw; - if (strict_strtoul(buf, 10, &value) || value > 1) + err = kstrtouint(buf, 10, &value); + if (err) + return err; + + if (value > 1) return -EINVAL; if (atkbd->softraw != value) { @@ -1578,14 +1635,20 @@ static int __init atkbd_setup_forced_release(const struct dmi_system_id *id) atkbd_platform_fixup = atkbd_apply_forced_release_keylist; atkbd_platform_fixup_data = id->driver_data; - return 0; + return 1; } static int __init atkbd_setup_scancode_fixup(const struct dmi_system_id *id) { atkbd_platform_scancode_fixup = id->driver_data; - return 0; + return 1; +} + +static int __init atkbd_deactivate_fixup(const struct dmi_system_id *id) +{ + atkbd_skip_deactivate = true; + return 1; } static const struct dmi_system_id atkbd_dmi_quirk_table[] __initconst = { @@ -1725,6 +1788,20 @@ static const struct dmi_system_id atkbd_dmi_quirk_table[] __initconst = { .callback = atkbd_setup_scancode_fixup, .driver_data = atkbd_oqo_01plus_scancode_fixup, }, + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LG Electronics"), + DMI_MATCH(DMI_PRODUCT_NAME, "LW25-B7HV"), + }, + .callback = atkbd_deactivate_fixup, + }, + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LG Electronics"), + DMI_MATCH(DMI_PRODUCT_NAME, "P1-J273B"), + }, + .callback = atkbd_deactivate_fixup, + }, { } }; diff --git a/drivers/input/keyboard/bf54x-keys.c b/drivers/input/keyboard/bf54x-keys.c index 7d989603f87..e6d46c5994d 100644 --- a/drivers/input/keyboard/bf54x-keys.c +++ b/drivers/input/keyboard/bf54x-keys.c @@ -30,7 +30,6 @@ #include <linux/module.h> -#include <linux/init.h> #include <linux/fs.h> #include <linux/interrupt.h> #include <linux/irq.h> @@ -177,10 +176,10 @@ static irqreturn_t bfin_kpad_isr(int irq, void *dev_id) return IRQ_HANDLED; } -static int __devinit bfin_kpad_probe(struct platform_device *pdev) +static int bfin_kpad_probe(struct platform_device *pdev) { struct bf54x_kpad *bf54x_kpad; - struct bfin_kpad_platform_data *pdata = pdev->dev.platform_data; + struct bfin_kpad_platform_data *pdata = dev_get_platdata(&pdev->dev); struct input_dev *input; int i, error; @@ -289,7 +288,8 @@ static int __devinit bfin_kpad_probe(struct platform_device *pdev) __set_bit(EV_REP, input->evbit); for (i = 0; i < input->keycodemax; i++) - __set_bit(bf54x_kpad->keycode[i] & KEY_MAX, input->keybit); + if (bf54x_kpad->keycode[i] <= KEY_MAX) + __set_bit(bf54x_kpad->keycode[i], input->keybit); __clear_bit(KEY_RESERVED, input->keybit); error = input_register_device(input); @@ -326,14 +326,13 @@ out0: kfree(bf54x_kpad->keycode); out: kfree(bf54x_kpad); - platform_set_drvdata(pdev, NULL); return error; } -static int __devexit bfin_kpad_remove(struct platform_device *pdev) +static int bfin_kpad_remove(struct platform_device *pdev) { - struct bfin_kpad_platform_data *pdata = pdev->dev.platform_data; + struct bfin_kpad_platform_data *pdata = dev_get_platdata(&pdev->dev); struct bf54x_kpad *bf54x_kpad = platform_get_drvdata(pdev); del_timer_sync(&bf54x_kpad->timer); @@ -346,7 +345,6 @@ static int __devexit bfin_kpad_remove(struct platform_device *pdev) kfree(bf54x_kpad->keycode); kfree(bf54x_kpad); - platform_set_drvdata(pdev, NULL); return 0; } @@ -384,29 +382,17 @@ static int bfin_kpad_resume(struct platform_device *pdev) # define bfin_kpad_resume NULL #endif -struct platform_driver bfin_kpad_device_driver = { +static struct platform_driver bfin_kpad_device_driver = { .driver = { .name = DRV_NAME, .owner = THIS_MODULE, }, .probe = bfin_kpad_probe, - .remove = __devexit_p(bfin_kpad_remove), + .remove = bfin_kpad_remove, .suspend = bfin_kpad_suspend, .resume = bfin_kpad_resume, }; - -static int __init bfin_kpad_init(void) -{ - return platform_driver_register(&bfin_kpad_device_driver); -} - -static void __exit bfin_kpad_exit(void) -{ - platform_driver_unregister(&bfin_kpad_device_driver); -} - -module_init(bfin_kpad_init); -module_exit(bfin_kpad_exit); +module_platform_driver(bfin_kpad_device_driver); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); diff --git a/drivers/input/keyboard/clps711x-keypad.c b/drivers/input/keyboard/clps711x-keypad.c new file mode 100644 index 00000000000..552b65c6e6b --- /dev/null +++ b/drivers/input/keyboard/clps711x-keypad.c @@ -0,0 +1,207 @@ +/* + * Cirrus Logic CLPS711X Keypad driver + * + * Copyright (C) 2014 Alexander Shiyan <shc_work@mail.ru> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include <linux/input.h> +#include <linux/input-polldev.h> +#include <linux/module.h> +#include <linux/of_gpio.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/sched.h> +#include <linux/input/matrix_keypad.h> +#include <linux/mfd/syscon.h> +#include <linux/mfd/syscon/clps711x.h> + +#define CLPS711X_KEYPAD_COL_COUNT 8 + +struct clps711x_gpio_data { + struct gpio_desc *desc; + DECLARE_BITMAP(last_state, CLPS711X_KEYPAD_COL_COUNT); +}; + +struct clps711x_keypad_data { + struct regmap *syscon; + int row_count; + unsigned int row_shift; + struct clps711x_gpio_data *gpio_data; +}; + +static void clps711x_keypad_poll(struct input_polled_dev *dev) +{ + const unsigned short *keycodes = dev->input->keycode; + struct clps711x_keypad_data *priv = dev->private; + bool sync = false; + int col, row; + + for (col = 0; col < CLPS711X_KEYPAD_COL_COUNT; col++) { + /* Assert column */ + regmap_update_bits(priv->syscon, SYSCON_OFFSET, + SYSCON1_KBDSCAN_MASK, + SYSCON1_KBDSCAN(8 + col)); + + /* Scan rows */ + for (row = 0; row < priv->row_count; row++) { + struct clps711x_gpio_data *data = &priv->gpio_data[row]; + bool state, state1; + + /* Read twice for protection against fluctuations */ + do { + state = gpiod_get_value_cansleep(data->desc); + cond_resched(); + state1 = gpiod_get_value_cansleep(data->desc); + } while (state != state1); + + if (test_bit(col, data->last_state) != state) { + int code = MATRIX_SCAN_CODE(row, col, + priv->row_shift); + + if (state) { + set_bit(col, data->last_state); + input_event(dev->input, EV_MSC, + MSC_SCAN, code); + } else { + clear_bit(col, data->last_state); + } + + if (keycodes[code]) + input_report_key(dev->input, + keycodes[code], state); + sync = true; + } + } + + /* Set all columns to low */ + regmap_update_bits(priv->syscon, SYSCON_OFFSET, + SYSCON1_KBDSCAN_MASK, SYSCON1_KBDSCAN(1)); + } + + if (sync) + input_sync(dev->input); +} + +static int clps711x_keypad_probe(struct platform_device *pdev) +{ + struct clps711x_keypad_data *priv; + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct input_polled_dev *poll_dev; + u32 poll_interval; + int i, err; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->syscon = + syscon_regmap_lookup_by_compatible("cirrus,clps711x-syscon1"); + if (IS_ERR(priv->syscon)) + return PTR_ERR(priv->syscon); + + priv->row_count = of_gpio_named_count(np, "row-gpios"); + if (priv->row_count < 1) + return -EINVAL; + + priv->gpio_data = devm_kzalloc(dev, + sizeof(*priv->gpio_data) * priv->row_count, + GFP_KERNEL); + if (!priv->gpio_data) + return -ENOMEM; + + priv->row_shift = get_count_order(CLPS711X_KEYPAD_COL_COUNT); + + for (i = 0; i < priv->row_count; i++) { + struct clps711x_gpio_data *data = &priv->gpio_data[i]; + + data->desc = devm_gpiod_get_index(dev, "row", i); + if (!data->desc) + return -EINVAL; + + if (IS_ERR(data->desc)) + return PTR_ERR(data->desc); + + gpiod_direction_input(data->desc); + } + + err = of_property_read_u32(np, "poll-interval", &poll_interval); + if (err) + return err; + + poll_dev = input_allocate_polled_device(); + if (!poll_dev) + return -ENOMEM; + + poll_dev->private = priv; + poll_dev->poll = clps711x_keypad_poll; + poll_dev->poll_interval = poll_interval; + poll_dev->input->name = pdev->name; + poll_dev->input->dev.parent = dev; + poll_dev->input->id.bustype = BUS_HOST; + poll_dev->input->id.vendor = 0x0001; + poll_dev->input->id.product = 0x0001; + poll_dev->input->id.version = 0x0100; + + err = matrix_keypad_build_keymap(NULL, NULL, priv->row_count, + CLPS711X_KEYPAD_COL_COUNT, + NULL, poll_dev->input); + if (err) + goto out_err; + + input_set_capability(poll_dev->input, EV_MSC, MSC_SCAN); + if (of_property_read_bool(np, "autorepeat")) + __set_bit(EV_REP, poll_dev->input->evbit); + + platform_set_drvdata(pdev, poll_dev); + + /* Set all columns to low */ + regmap_update_bits(priv->syscon, SYSCON_OFFSET, SYSCON1_KBDSCAN_MASK, + SYSCON1_KBDSCAN(1)); + + err = input_register_polled_device(poll_dev); + if (err) + goto out_err; + + return 0; + +out_err: + input_free_polled_device(poll_dev); + return err; +} + +static int clps711x_keypad_remove(struct platform_device *pdev) +{ + struct input_polled_dev *poll_dev = platform_get_drvdata(pdev); + + input_unregister_polled_device(poll_dev); + input_free_polled_device(poll_dev); + + return 0; +} + +static const struct of_device_id clps711x_keypad_of_match[] = { + { .compatible = "cirrus,clps711x-keypad", }, + { } +}; +MODULE_DEVICE_TABLE(of, clps711x_keypad_of_match); + +static struct platform_driver clps711x_keypad_driver = { + .driver = { + .name = "clps711x-keypad", + .owner = THIS_MODULE, + .of_match_table = clps711x_keypad_of_match, + }, + .probe = clps711x_keypad_probe, + .remove = clps711x_keypad_remove, +}; +module_platform_driver(clps711x_keypad_driver); + +MODULE_AUTHOR("Alexander Shiyan <shc_work@mail.ru>"); +MODULE_DESCRIPTION("Cirrus Logic CLPS711X Keypad driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/keyboard/cros_ec_keyb.c b/drivers/input/keyboard/cros_ec_keyb.c new file mode 100644 index 00000000000..408379669d3 --- /dev/null +++ b/drivers/input/keyboard/cros_ec_keyb.c @@ -0,0 +1,341 @@ +/* + * ChromeOS EC keyboard driver + * + * Copyright (C) 2012 Google, Inc + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * This driver uses the Chrome OS EC byte-level message-based protocol for + * communicating the keyboard state (which keys are pressed) from a keyboard EC + * to the AP over some bus (such as i2c, lpc, spi). The EC does debouncing, + * but everything else (including deghosting) is done here. The main + * motivation for this is to keep the EC firmware as simple as possible, since + * it cannot be easily upgraded and EC flash/IRAM space is relatively + * expensive. + */ + +#include <linux/module.h> +#include <linux/i2c.h> +#include <linux/input.h> +#include <linux/kernel.h> +#include <linux/notifier.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/input/matrix_keypad.h> +#include <linux/mfd/cros_ec.h> +#include <linux/mfd/cros_ec_commands.h> + +/* + * @rows: Number of rows in the keypad + * @cols: Number of columns in the keypad + * @row_shift: log2 or number of rows, rounded up + * @keymap_data: Matrix keymap data used to convert to keyscan values + * @ghost_filter: true to enable the matrix key-ghosting filter + * @old_kb_state: bitmap of keys pressed last scan + * @dev: Device pointer + * @idev: Input device + * @ec: Top level ChromeOS device to use to talk to EC + * @event_notifier: interrupt event notifier for transport devices + */ +struct cros_ec_keyb { + unsigned int rows; + unsigned int cols; + int row_shift; + const struct matrix_keymap_data *keymap_data; + bool ghost_filter; + uint8_t *old_kb_state; + + struct device *dev; + struct input_dev *idev; + struct cros_ec_device *ec; + struct notifier_block notifier; +}; + + +static bool cros_ec_keyb_row_has_ghosting(struct cros_ec_keyb *ckdev, + uint8_t *buf, int row) +{ + int pressed_in_row = 0; + int row_has_teeth = 0; + int col, mask; + + mask = 1 << row; + for (col = 0; col < ckdev->cols; col++) { + if (buf[col] & mask) { + pressed_in_row++; + row_has_teeth |= buf[col] & ~mask; + if (pressed_in_row > 1 && row_has_teeth) { + /* ghosting */ + dev_dbg(ckdev->dev, + "ghost found at: r%d c%d, pressed %d, teeth 0x%x\n", + row, col, pressed_in_row, + row_has_teeth); + return true; + } + } + } + + return false; +} + +/* + * Returns true when there is at least one combination of pressed keys that + * results in ghosting. + */ +static bool cros_ec_keyb_has_ghosting(struct cros_ec_keyb *ckdev, uint8_t *buf) +{ + int row; + + /* + * Ghosting happens if for any pressed key X there are other keys + * pressed both in the same row and column of X as, for instance, + * in the following diagram: + * + * . . Y . g . + * . . . . . . + * . . . . . . + * . . X . Z . + * + * In this case only X, Y, and Z are pressed, but g appears to be + * pressed too (see Wikipedia). + * + * We can detect ghosting in a single pass (*) over the keyboard state + * by maintaining two arrays. pressed_in_row counts how many pressed + * keys we have found in a row. row_has_teeth is true if any of the + * pressed keys for this row has other pressed keys in its column. If + * at any point of the scan we find that a row has multiple pressed + * keys, and at least one of them is at the intersection with a column + * with multiple pressed keys, we're sure there is ghosting. + * Conversely, if there is ghosting, we will detect such situation for + * at least one key during the pass. + * + * (*) This looks linear in the number of keys, but it's not. We can + * cheat because the number of rows is small. + */ + for (row = 0; row < ckdev->rows; row++) + if (cros_ec_keyb_row_has_ghosting(ckdev, buf, row)) + return true; + + return false; +} + +/* + * Compares the new keyboard state to the old one and produces key + * press/release events accordingly. The keyboard state is 13 bytes (one byte + * per column) + */ +static void cros_ec_keyb_process(struct cros_ec_keyb *ckdev, + uint8_t *kb_state, int len) +{ + struct input_dev *idev = ckdev->idev; + int col, row; + int new_state; + int old_state; + int num_cols; + + num_cols = len; + + if (ckdev->ghost_filter && cros_ec_keyb_has_ghosting(ckdev, kb_state)) { + /* + * Simple-minded solution: ignore this state. The obvious + * improvement is to only ignore changes to keys involved in + * the ghosting, but process the other changes. + */ + dev_dbg(ckdev->dev, "ghosting found\n"); + return; + } + + for (col = 0; col < ckdev->cols; col++) { + for (row = 0; row < ckdev->rows; row++) { + int pos = MATRIX_SCAN_CODE(row, col, ckdev->row_shift); + const unsigned short *keycodes = idev->keycode; + + new_state = kb_state[col] & (1 << row); + old_state = ckdev->old_kb_state[col] & (1 << row); + if (new_state != old_state) { + dev_dbg(ckdev->dev, + "changed: [r%d c%d]: byte %02x\n", + row, col, new_state); + + input_report_key(idev, keycodes[pos], + new_state); + } + } + ckdev->old_kb_state[col] = kb_state[col]; + } + input_sync(ckdev->idev); +} + +static int cros_ec_keyb_open(struct input_dev *dev) +{ + struct cros_ec_keyb *ckdev = input_get_drvdata(dev); + + return blocking_notifier_chain_register(&ckdev->ec->event_notifier, + &ckdev->notifier); +} + +static void cros_ec_keyb_close(struct input_dev *dev) +{ + struct cros_ec_keyb *ckdev = input_get_drvdata(dev); + + blocking_notifier_chain_unregister(&ckdev->ec->event_notifier, + &ckdev->notifier); +} + +static int cros_ec_keyb_get_state(struct cros_ec_keyb *ckdev, uint8_t *kb_state) +{ + return ckdev->ec->command_recv(ckdev->ec, EC_CMD_MKBP_STATE, + kb_state, ckdev->cols); +} + +static int cros_ec_keyb_work(struct notifier_block *nb, + unsigned long state, void *_notify) +{ + int ret; + struct cros_ec_keyb *ckdev = container_of(nb, struct cros_ec_keyb, + notifier); + uint8_t kb_state[ckdev->cols]; + + ret = cros_ec_keyb_get_state(ckdev, kb_state); + if (ret >= 0) + cros_ec_keyb_process(ckdev, kb_state, ret); + + return NOTIFY_DONE; +} + +static int cros_ec_keyb_probe(struct platform_device *pdev) +{ + struct cros_ec_device *ec = dev_get_drvdata(pdev->dev.parent); + struct device *dev = ec->dev; + struct cros_ec_keyb *ckdev; + struct input_dev *idev; + struct device_node *np; + int err; + + np = pdev->dev.of_node; + if (!np) + return -ENODEV; + + ckdev = devm_kzalloc(&pdev->dev, sizeof(*ckdev), GFP_KERNEL); + if (!ckdev) + return -ENOMEM; + err = matrix_keypad_parse_of_params(&pdev->dev, &ckdev->rows, + &ckdev->cols); + if (err) + return err; + ckdev->old_kb_state = devm_kzalloc(&pdev->dev, ckdev->cols, GFP_KERNEL); + if (!ckdev->old_kb_state) + return -ENOMEM; + + idev = devm_input_allocate_device(&pdev->dev); + if (!idev) + return -ENOMEM; + + ckdev->ec = ec; + ckdev->notifier.notifier_call = cros_ec_keyb_work; + ckdev->dev = dev; + dev_set_drvdata(&pdev->dev, ckdev); + + idev->name = ec->ec_name; + idev->phys = ec->phys_name; + __set_bit(EV_REP, idev->evbit); + + idev->id.bustype = BUS_VIRTUAL; + idev->id.version = 1; + idev->id.product = 0; + idev->dev.parent = &pdev->dev; + idev->open = cros_ec_keyb_open; + idev->close = cros_ec_keyb_close; + + ckdev->ghost_filter = of_property_read_bool(np, + "google,needs-ghost-filter"); + + err = matrix_keypad_build_keymap(NULL, NULL, ckdev->rows, ckdev->cols, + NULL, idev); + if (err) { + dev_err(dev, "cannot build key matrix\n"); + return err; + } + + ckdev->row_shift = get_count_order(ckdev->cols); + + input_set_capability(idev, EV_MSC, MSC_SCAN); + input_set_drvdata(idev, ckdev); + ckdev->idev = idev; + err = input_register_device(ckdev->idev); + if (err) { + dev_err(dev, "cannot register input device\n"); + return err; + } + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +/* Clear any keys in the buffer */ +static void cros_ec_keyb_clear_keyboard(struct cros_ec_keyb *ckdev) +{ + uint8_t old_state[ckdev->cols]; + uint8_t new_state[ckdev->cols]; + unsigned long duration; + int i, ret; + + /* + * Keep reading until we see that the scan state does not change. + * That indicates that we are done. + * + * Assume that the EC keyscan buffer is at most 32 deep. + */ + duration = jiffies; + ret = cros_ec_keyb_get_state(ckdev, new_state); + for (i = 1; !ret && i < 32; i++) { + memcpy(old_state, new_state, sizeof(old_state)); + ret = cros_ec_keyb_get_state(ckdev, new_state); + if (0 == memcmp(old_state, new_state, sizeof(old_state))) + break; + } + duration = jiffies - duration; + dev_info(ckdev->dev, "Discarded %d keyscan(s) in %dus\n", i, + jiffies_to_usecs(duration)); +} + +static int cros_ec_keyb_resume(struct device *dev) +{ + struct cros_ec_keyb *ckdev = dev_get_drvdata(dev); + + /* + * When the EC is not a wake source, then it could not have caused the + * resume, so we clear the EC's key scan buffer. If the EC was a + * wake source (e.g. the lid is open and the user might press a key to + * wake) then the key scan buffer should be preserved. + */ + if (ckdev->ec->was_wake_device) + cros_ec_keyb_clear_keyboard(ckdev); + + return 0; +} + +#endif + +static SIMPLE_DEV_PM_OPS(cros_ec_keyb_pm_ops, NULL, cros_ec_keyb_resume); + +static struct platform_driver cros_ec_keyb_driver = { + .probe = cros_ec_keyb_probe, + .driver = { + .name = "cros-ec-keyb", + .pm = &cros_ec_keyb_pm_ops, + }, +}; + +module_platform_driver(cros_ec_keyb_driver); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("ChromeOS EC keyboard driver"); +MODULE_ALIAS("platform:cros-ec-keyb"); diff --git a/drivers/input/keyboard/davinci_keyscan.c b/drivers/input/keyboard/davinci_keyscan.c index cd89d17162a..1559dc1cf95 100644 --- a/drivers/input/keyboard/davinci_keyscan.c +++ b/drivers/input/keyboard/davinci_keyscan.c @@ -36,7 +36,7 @@ #include <mach/hardware.h> #include <mach/irqs.h> -#include <mach/keyscan.h> +#include <linux/platform_data/keyscan-davinci.h> /* Key scan registers */ #define DAVINCI_KEYSCAN_KEYCTRL 0x0000 @@ -172,7 +172,7 @@ static int __init davinci_ks_probe(struct platform_device *pdev) struct input_dev *key_dev; struct resource *res, *mem; struct device *dev = &pdev->dev; - struct davinci_ks_platform_data *pdata = pdev->dev.platform_data; + struct davinci_ks_platform_data *pdata = dev_get_platdata(&pdev->dev); int error, i; if (pdata->device_enable) { @@ -271,7 +271,7 @@ static int __init davinci_ks_probe(struct platform_device *pdev) } error = request_irq(davinci_ks->irq, davinci_ks_interrupt, - IRQF_DISABLED, pdev->name, davinci_ks); + 0, pdev->name, davinci_ks); if (error < 0) { dev_err(dev, "unable to register davinci key scan interrupt\n"); goto fail5; @@ -303,7 +303,7 @@ fail1: return error; } -static int __devexit davinci_ks_remove(struct platform_device *pdev) +static int davinci_ks_remove(struct platform_device *pdev) { struct davinci_ks *davinci_ks = platform_get_drvdata(pdev); @@ -314,8 +314,6 @@ static int __devexit 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; @@ -326,20 +324,10 @@ static struct platform_driver davinci_ks_driver = { .name = "davinci_keyscan", .owner = THIS_MODULE, }, - .remove = __devexit_p(davinci_ks_remove), + .remove = davinci_ks_remove, }; -static int __init davinci_ks_init(void) -{ - return platform_driver_probe(&davinci_ks_driver, davinci_ks_probe); -} -module_init(davinci_ks_init); - -static void __exit davinci_ks_exit(void) -{ - platform_driver_unregister(&davinci_ks_driver); -} -module_exit(davinci_ks_exit); +module_platform_driver_probe(davinci_ks_driver, davinci_ks_probe); MODULE_AUTHOR("Miguel Aguilar"); MODULE_DESCRIPTION("Texas Instruments DaVinci Key Scan Driver"); diff --git a/drivers/input/keyboard/ep93xx_keypad.c b/drivers/input/keyboard/ep93xx_keypad.c index c8242dd190d..e59876212b8 100644 --- a/drivers/input/keyboard/ep93xx_keypad.c +++ b/drivers/input/keyboard/ep93xx_keypad.c @@ -20,6 +20,7 @@ * flag. */ +#include <linux/module.h> #include <linux/platform_device.h> #include <linux/interrupt.h> #include <linux/clk.h> @@ -28,7 +29,7 @@ #include <linux/slab.h> #include <mach/hardware.h> -#include <mach/ep93xx_keypad.h> +#include <linux/platform_data/keypad-ep93xx.h> /* * Keypad Interface Register offsets @@ -181,16 +182,10 @@ static void ep93xx_keypad_close(struct input_dev *pdev) } -#ifdef CONFIG_PM -/* - * NOTE: I don't know if this is correct, or will work on the ep93xx. - * - * None of the existing ep93xx drivers have power management support. - * But, this is basically what the pxa27x_keypad driver does. - */ -static int ep93xx_keypad_suspend(struct platform_device *pdev, - pm_message_t state) +#ifdef CONFIG_PM_SLEEP +static int ep93xx_keypad_suspend(struct device *dev) { + struct platform_device *pdev = to_platform_device(dev); struct ep93xx_keypad *keypad = platform_get_drvdata(pdev); struct input_dev *input_dev = keypad->input_dev; @@ -209,8 +204,9 @@ static int ep93xx_keypad_suspend(struct platform_device *pdev, return 0; } -static int ep93xx_keypad_resume(struct platform_device *pdev) +static int ep93xx_keypad_resume(struct device *dev) { + struct platform_device *pdev = to_platform_device(dev); struct ep93xx_keypad *keypad = platform_get_drvdata(pdev); struct input_dev *input_dev = keypad->input_dev; @@ -231,12 +227,12 @@ static int ep93xx_keypad_resume(struct platform_device *pdev) return 0; } -#else /* !CONFIG_PM */ -#define ep93xx_keypad_suspend NULL -#define ep93xx_keypad_resume NULL -#endif /* !CONFIG_PM */ +#endif -static int __devinit ep93xx_keypad_probe(struct platform_device *pdev) +static SIMPLE_DEV_PM_OPS(ep93xx_keypad_pm_ops, + ep93xx_keypad_suspend, ep93xx_keypad_resume); + +static int ep93xx_keypad_probe(struct platform_device *pdev) { struct ep93xx_keypad *keypad; const struct matrix_keymap_data *keymap_data; @@ -248,7 +244,7 @@ static int __devinit ep93xx_keypad_probe(struct platform_device *pdev) if (!keypad) return -ENOMEM; - keypad->pdata = pdev->dev.platform_data; + keypad->pdata = dev_get_platdata(&pdev->dev); if (!keypad->pdata) { err = -EINVAL; goto failed_free; @@ -307,22 +303,19 @@ static int __devinit ep93xx_keypad_probe(struct platform_device *pdev) input_dev->open = ep93xx_keypad_open; input_dev->close = ep93xx_keypad_close; input_dev->dev.parent = &pdev->dev; - input_dev->keycode = keypad->keycodes; - input_dev->keycodesize = sizeof(keypad->keycodes[0]); - input_dev->keycodemax = ARRAY_SIZE(keypad->keycodes); - input_set_drvdata(input_dev, keypad); + err = matrix_keypad_build_keymap(keymap_data, NULL, + EP93XX_MATRIX_ROWS, EP93XX_MATRIX_COLS, + keypad->keycodes, input_dev); + if (err) + goto failed_free_dev; - input_dev->evbit[0] = BIT_MASK(EV_KEY); if (keypad->pdata->flags & EP93XX_KEYPAD_AUTOREPEAT) - input_dev->evbit[0] |= BIT_MASK(EV_REP); - - matrix_keypad_build_keymap(keymap_data, 3, - input_dev->keycode, input_dev->keybit); - platform_set_drvdata(pdev, keypad); + __set_bit(EV_REP, input_dev->evbit); + input_set_drvdata(input_dev, keypad); err = request_irq(keypad->irq, ep93xx_keypad_irq_handler, - IRQF_DISABLED, pdev->name, keypad); + 0, pdev->name, keypad); if (err) goto failed_free_dev; @@ -330,13 +323,13 @@ static int __devinit ep93xx_keypad_probe(struct platform_device *pdev) if (err) goto failed_free_irq; + platform_set_drvdata(pdev, keypad); device_init_wakeup(&pdev->dev, 1); 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: @@ -352,14 +345,12 @@ failed_free: return err; } -static int __devexit ep93xx_keypad_remove(struct platform_device *pdev) +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); @@ -383,25 +374,12 @@ static struct platform_driver ep93xx_keypad_driver = { .driver = { .name = "ep93xx-keypad", .owner = THIS_MODULE, + .pm = &ep93xx_keypad_pm_ops, }, .probe = ep93xx_keypad_probe, - .remove = __devexit_p(ep93xx_keypad_remove), - .suspend = ep93xx_keypad_suspend, - .resume = ep93xx_keypad_resume, + .remove = ep93xx_keypad_remove, }; - -static int __init ep93xx_keypad_init(void) -{ - return platform_driver_register(&ep93xx_keypad_driver); -} - -static void __exit ep93xx_keypad_exit(void) -{ - platform_driver_unregister(&ep93xx_keypad_driver); -} - -module_init(ep93xx_keypad_init); -module_exit(ep93xx_keypad_exit); +module_platform_driver(ep93xx_keypad_driver); MODULE_LICENSE("GPL"); MODULE_AUTHOR("H Hartley Sweeten <hsweeten@visionengravers.com>"); diff --git a/drivers/input/keyboard/goldfish_events.c b/drivers/input/keyboard/goldfish_events.c new file mode 100644 index 00000000000..69e85476337 --- /dev/null +++ b/drivers/input/keyboard/goldfish_events.c @@ -0,0 +1,193 @@ +/* + * Copyright (C) 2007 Google, Inc. + * Copyright (C) 2012 Intel, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <linux/module.h> +#include <linux/interrupt.h> +#include <linux/types.h> +#include <linux/input.h> +#include <linux/kernel.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/irq.h> +#include <linux/io.h> + +enum { + REG_READ = 0x00, + REG_SET_PAGE = 0x00, + REG_LEN = 0x04, + REG_DATA = 0x08, + + PAGE_NAME = 0x00000, + PAGE_EVBITS = 0x10000, + PAGE_ABSDATA = 0x20000 | EV_ABS, +}; + +struct event_dev { + struct input_dev *input; + int irq; + void __iomem *addr; + char name[0]; +}; + +static irqreturn_t events_interrupt(int irq, void *dev_id) +{ + struct event_dev *edev = dev_id; + unsigned type, code, value; + + type = __raw_readl(edev->addr + REG_READ); + code = __raw_readl(edev->addr + REG_READ); + value = __raw_readl(edev->addr + REG_READ); + + input_event(edev->input, type, code, value); + input_sync(edev->input); + return IRQ_HANDLED; +} + +static void events_import_bits(struct event_dev *edev, + unsigned long bits[], unsigned type, size_t count) +{ + void __iomem *addr = edev->addr; + int i, j; + size_t size; + uint8_t val; + + __raw_writel(PAGE_EVBITS | type, addr + REG_SET_PAGE); + + size = __raw_readl(addr + REG_LEN) * 8; + if (size < count) + count = size; + + addr += REG_DATA; + for (i = 0; i < count; i += 8) { + val = __raw_readb(addr++); + for (j = 0; j < 8; j++) + if (val & 1 << j) + set_bit(i + j, bits); + } +} + +static void events_import_abs_params(struct event_dev *edev) +{ + struct input_dev *input_dev = edev->input; + void __iomem *addr = edev->addr; + u32 val[4]; + int count; + int i, j; + + __raw_writel(PAGE_ABSDATA, addr + REG_SET_PAGE); + + count = __raw_readl(addr + REG_LEN) / sizeof(val); + if (count > ABS_MAX) + count = ABS_MAX; + + for (i = 0; i < count; i++) { + if (!test_bit(i, input_dev->absbit)) + continue; + + for (j = 0; j < ARRAY_SIZE(val); j++) { + int offset = (i * ARRAY_SIZE(val) + j) * sizeof(u32); + val[j] = __raw_readl(edev->addr + REG_DATA + offset); + } + + input_set_abs_params(input_dev, i, + val[0], val[1], val[2], val[3]); + } +} + +static int events_probe(struct platform_device *pdev) +{ + struct input_dev *input_dev; + struct event_dev *edev; + struct resource *res; + unsigned keymapnamelen; + void __iomem *addr; + int irq; + int i; + int error; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return -EINVAL; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -EINVAL; + + addr = devm_ioremap(&pdev->dev, res->start, 4096); + if (!addr) + return -ENOMEM; + + __raw_writel(PAGE_NAME, addr + REG_SET_PAGE); + keymapnamelen = __raw_readl(addr + REG_LEN); + + edev = devm_kzalloc(&pdev->dev, + sizeof(struct event_dev) + keymapnamelen + 1, + GFP_KERNEL); + if (!edev) + return -ENOMEM; + + input_dev = devm_input_allocate_device(&pdev->dev); + if (!input_dev) + return -ENOMEM; + + edev->input = input_dev; + edev->addr = addr; + edev->irq = irq; + + for (i = 0; i < keymapnamelen; i++) + edev->name[i] = __raw_readb(edev->addr + REG_DATA + i); + + pr_debug("events_probe() keymap=%s\n", edev->name); + + input_dev->name = edev->name; + input_dev->id.bustype = BUS_HOST; + + events_import_bits(edev, input_dev->evbit, EV_SYN, EV_MAX); + events_import_bits(edev, input_dev->keybit, EV_KEY, KEY_MAX); + events_import_bits(edev, input_dev->relbit, EV_REL, REL_MAX); + events_import_bits(edev, input_dev->absbit, EV_ABS, ABS_MAX); + events_import_bits(edev, input_dev->mscbit, EV_MSC, MSC_MAX); + events_import_bits(edev, input_dev->ledbit, EV_LED, LED_MAX); + events_import_bits(edev, input_dev->sndbit, EV_SND, SND_MAX); + events_import_bits(edev, input_dev->ffbit, EV_FF, FF_MAX); + events_import_bits(edev, input_dev->swbit, EV_SW, SW_MAX); + + events_import_abs_params(edev); + + error = devm_request_irq(&pdev->dev, edev->irq, events_interrupt, 0, + "goldfish-events-keypad", edev); + if (error) + return error; + + error = input_register_device(input_dev); + if (error) + return error; + + return 0; +} + +static struct platform_driver events_driver = { + .probe = events_probe, + .driver = { + .owner = THIS_MODULE, + .name = "goldfish_events", + }, +}; + +module_platform_driver(events_driver); + +MODULE_AUTHOR("Brian Swetland"); +MODULE_DESCRIPTION("Goldfish Event Device"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index 6e6145b9a4c..8c98e97f8e4 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -2,6 +2,7 @@ * Driver for keys on GPIO lines capable of generating interrupts. * * Copyright 2005 Phil Blundell + * Copyright 2010, 2011 David Jander <david@protonic.nl> * * 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 @@ -25,22 +26,27 @@ #include <linux/gpio_keys.h> #include <linux/workqueue.h> #include <linux/gpio.h> +#include <linux/of.h> +#include <linux/of_platform.h> +#include <linux/of_gpio.h> +#include <linux/spinlock.h> struct gpio_button_data { - struct gpio_keys_button *button; + const struct gpio_keys_button *button; struct input_dev *input; struct timer_list timer; struct work_struct work; - int timer_debounce; /* in msecs */ + unsigned int timer_debounce; /* in msecs */ + unsigned int irq; + spinlock_t lock; bool disabled; + bool key_pressed; }; struct gpio_keys_drvdata { + const struct gpio_keys_platform_data *pdata; struct input_dev *input; struct mutex disable_lock; - unsigned int n_buttons; - int (*enable)(struct device *dev); - void (*disable)(struct device *dev); struct gpio_button_data data[0]; }; @@ -111,7 +117,7 @@ static void gpio_keys_disable_button(struct gpio_button_data *bdata) /* * Disable IRQ and possible debouncing timer. */ - disable_irq(gpio_to_irq(bdata->button->gpio)); + disable_irq(bdata->irq); if (bdata->timer_debounce) del_timer_sync(&bdata->timer); @@ -132,7 +138,7 @@ static void gpio_keys_disable_button(struct gpio_button_data *bdata) static void gpio_keys_enable_button(struct gpio_button_data *bdata) { if (bdata->disabled) { - enable_irq(gpio_to_irq(bdata->button->gpio)); + enable_irq(bdata->irq); bdata->disabled = false; } } @@ -164,7 +170,7 @@ static ssize_t gpio_keys_attr_show_helper(struct gpio_keys_drvdata *ddata, if (!bits) return -ENOMEM; - for (i = 0; i < ddata->n_buttons; i++) { + for (i = 0; i < ddata->pdata->nbuttons; i++) { struct gpio_button_data *bdata = &ddata->data[i]; if (bdata->button->type != type) @@ -192,7 +198,7 @@ static ssize_t gpio_keys_attr_show_helper(struct gpio_keys_drvdata *ddata, * @type: button type (%EV_KEY, %EV_SW) * * This function parses stringified bitmap from @buf and disables/enables - * GPIO buttons accordinly. Returns 0 on success and negative error + * GPIO buttons accordingly. Returns 0 on success and negative error * on failure. */ static ssize_t gpio_keys_attr_store_helper(struct gpio_keys_drvdata *ddata, @@ -212,7 +218,7 @@ static ssize_t gpio_keys_attr_store_helper(struct gpio_keys_drvdata *ddata, goto out; /* First validate */ - for (i = 0; i < ddata->n_buttons; i++) { + for (i = 0; i < ddata->pdata->nbuttons; i++) { struct gpio_button_data *bdata = &ddata->data[i]; if (bdata->button->type != type) @@ -227,7 +233,7 @@ static ssize_t gpio_keys_attr_store_helper(struct gpio_keys_drvdata *ddata, mutex_lock(&ddata->disable_lock); - for (i = 0; i < ddata->n_buttons; i++) { + for (i = 0; i < ddata->pdata->nbuttons; i++) { struct gpio_button_data *bdata = &ddata->data[i]; if (bdata->button->type != type) @@ -317,9 +323,9 @@ static struct attribute_group gpio_keys_attr_group = { .attrs = gpio_keys_attrs, }; -static void gpio_keys_report_event(struct gpio_button_data *bdata) +static void gpio_keys_gpio_report_event(struct gpio_button_data *bdata) { - struct gpio_keys_button *button = bdata->button; + const struct gpio_keys_button *button = bdata->button; struct input_dev *input = bdata->input; unsigned int type = button->type ?: EV_KEY; int state = (gpio_get_value_cansleep(button->gpio) ? 1 : 0) ^ button->active_low; @@ -333,28 +339,32 @@ static void gpio_keys_report_event(struct gpio_button_data *bdata) input_sync(input); } -static void gpio_keys_work_func(struct work_struct *work) +static void gpio_keys_gpio_work_func(struct work_struct *work) { struct gpio_button_data *bdata = container_of(work, struct gpio_button_data, work); - gpio_keys_report_event(bdata); + gpio_keys_gpio_report_event(bdata); + + if (bdata->button->wakeup) + pm_relax(bdata->input->dev.parent); } -static void gpio_keys_timer(unsigned long _data) +static void gpio_keys_gpio_timer(unsigned long _data) { - struct gpio_button_data *data = (struct gpio_button_data *)_data; + struct gpio_button_data *bdata = (struct gpio_button_data *)_data; - schedule_work(&data->work); + schedule_work(&bdata->work); } -static irqreturn_t gpio_keys_isr(int irq, void *dev_id) +static irqreturn_t gpio_keys_gpio_isr(int irq, void *dev_id) { struct gpio_button_data *bdata = dev_id; - struct gpio_keys_button *button = bdata->button; - BUG_ON(irq != gpio_to_irq(button->gpio)); + BUG_ON(irq != bdata->irq); + if (bdata->button->wakeup) + pm_stay_awake(bdata->input->dev.parent); if (bdata->timer_debounce) mod_timer(&bdata->timer, jiffies + msecs_to_jiffies(bdata->timer_debounce)); @@ -364,50 +374,152 @@ static irqreturn_t gpio_keys_isr(int irq, void *dev_id) return IRQ_HANDLED; } -static int __devinit gpio_keys_setup_key(struct platform_device *pdev, - struct gpio_button_data *bdata, - struct gpio_keys_button *button) +static void gpio_keys_irq_timer(unsigned long _data) +{ + struct gpio_button_data *bdata = (struct gpio_button_data *)_data; + struct input_dev *input = bdata->input; + unsigned long flags; + + spin_lock_irqsave(&bdata->lock, flags); + if (bdata->key_pressed) { + input_event(input, EV_KEY, bdata->button->code, 0); + input_sync(input); + bdata->key_pressed = false; + } + spin_unlock_irqrestore(&bdata->lock, flags); +} + +static irqreturn_t gpio_keys_irq_isr(int irq, void *dev_id) +{ + struct gpio_button_data *bdata = dev_id; + const struct gpio_keys_button *button = bdata->button; + struct input_dev *input = bdata->input; + unsigned long flags; + + BUG_ON(irq != bdata->irq); + + spin_lock_irqsave(&bdata->lock, flags); + + if (!bdata->key_pressed) { + if (bdata->button->wakeup) + pm_wakeup_event(bdata->input->dev.parent, 0); + + input_event(input, EV_KEY, button->code, 1); + input_sync(input); + + if (!bdata->timer_debounce) { + input_event(input, EV_KEY, button->code, 0); + input_sync(input); + goto out; + } + + bdata->key_pressed = true; + } + + if (bdata->timer_debounce) + mod_timer(&bdata->timer, + jiffies + msecs_to_jiffies(bdata->timer_debounce)); +out: + spin_unlock_irqrestore(&bdata->lock, flags); + return IRQ_HANDLED; +} + +static void gpio_keys_quiesce_key(void *data) +{ + struct gpio_button_data *bdata = data; + + if (bdata->timer_debounce) + del_timer_sync(&bdata->timer); + + cancel_work_sync(&bdata->work); +} + +static int gpio_keys_setup_key(struct platform_device *pdev, + struct input_dev *input, + struct gpio_button_data *bdata, + const struct gpio_keys_button *button) { const char *desc = button->desc ? button->desc : "gpio_keys"; struct device *dev = &pdev->dev; + irq_handler_t isr; unsigned long irqflags; - int irq, error; + int irq; + int error; - setup_timer(&bdata->timer, gpio_keys_timer, (unsigned long)bdata); - INIT_WORK(&bdata->work, gpio_keys_work_func); + bdata->input = input; + bdata->button = button; + spin_lock_init(&bdata->lock); - error = gpio_request(button->gpio, desc); - if (error < 0) { - dev_err(dev, "failed to request GPIO %d, error %d\n", - button->gpio, error); - goto fail2; - } + if (gpio_is_valid(button->gpio)) { - error = gpio_direction_input(button->gpio); - if (error < 0) { - dev_err(dev, "failed to configure" - " direction for GPIO %d, error %d\n", - button->gpio, error); - goto fail3; - } + error = devm_gpio_request_one(&pdev->dev, button->gpio, + GPIOF_IN, desc); + if (error < 0) { + dev_err(dev, "Failed to request GPIO %d, error %d\n", + button->gpio, error); + return error; + } + + if (button->debounce_interval) { + error = gpio_set_debounce(button->gpio, + button->debounce_interval * 1000); + /* use timer if gpiolib doesn't provide debounce */ + if (error < 0) + bdata->timer_debounce = + button->debounce_interval; + } + + irq = gpio_to_irq(button->gpio); + if (irq < 0) { + error = irq; + dev_err(dev, + "Unable to get irq number for GPIO %d, error %d\n", + button->gpio, error); + return error; + } + bdata->irq = irq; + + INIT_WORK(&bdata->work, gpio_keys_gpio_work_func); + setup_timer(&bdata->timer, + gpio_keys_gpio_timer, (unsigned long)bdata); + + isr = gpio_keys_gpio_isr; + irqflags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING; + + } else { + if (!button->irq) { + dev_err(dev, "No IRQ specified\n"); + return -EINVAL; + } + bdata->irq = button->irq; + + if (button->type && button->type != EV_KEY) { + dev_err(dev, "Only EV_KEY allowed for IRQ buttons.\n"); + return -EINVAL; + } + + bdata->timer_debounce = button->debounce_interval; + setup_timer(&bdata->timer, + gpio_keys_irq_timer, (unsigned long)bdata); - if (button->debounce_interval) { - error = gpio_set_debounce(button->gpio, - button->debounce_interval * 1000); - /* use timer if gpiolib doesn't provide debounce */ - if (error < 0) - bdata->timer_debounce = button->debounce_interval; + isr = gpio_keys_irq_isr; + irqflags = 0; } - irq = gpio_to_irq(button->gpio); - if (irq < 0) { - error = irq; - dev_err(dev, "Unable to get irq number for GPIO %d, error %d\n", - button->gpio, error); - goto fail3; + input_set_capability(input, button->type ?: EV_KEY, button->code); + + /* + * Install custom action to cancel debounce timer and + * workqueue item. + */ + error = devm_add_action(&pdev->dev, gpio_keys_quiesce_key, bdata); + if (error) { + dev_err(&pdev->dev, + "failed to register quiesce action, error: %d\n", + error); + return error; } - irqflags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING; /* * If platform has specified that the button can be disabled, * we don't want it to share the interrupt line. @@ -415,59 +527,192 @@ static int __devinit gpio_keys_setup_key(struct platform_device *pdev, if (!button->can_disable) irqflags |= IRQF_SHARED; - error = request_any_context_irq(irq, gpio_keys_isr, irqflags, desc, bdata); + error = devm_request_any_context_irq(&pdev->dev, bdata->irq, + isr, irqflags, desc, bdata); if (error < 0) { dev_err(dev, "Unable to claim irq %d; error %d\n", - irq, error); - goto fail3; + bdata->irq, error); + return error; } return 0; +} -fail3: - gpio_free(button->gpio); -fail2: - return error; +static void gpio_keys_report_state(struct gpio_keys_drvdata *ddata) +{ + struct input_dev *input = ddata->input; + int i; + + for (i = 0; i < ddata->pdata->nbuttons; i++) { + struct gpio_button_data *bdata = &ddata->data[i]; + if (gpio_is_valid(bdata->button->gpio)) + gpio_keys_gpio_report_event(bdata); + } + input_sync(input); } static int gpio_keys_open(struct input_dev *input) { struct gpio_keys_drvdata *ddata = input_get_drvdata(input); + const struct gpio_keys_platform_data *pdata = ddata->pdata; + int error; + + if (pdata->enable) { + error = pdata->enable(input->dev.parent); + if (error) + return error; + } + + /* Report current state of buttons that are connected to GPIOs */ + gpio_keys_report_state(ddata); - return ddata->enable ? ddata->enable(input->dev.parent) : 0; + return 0; } static void gpio_keys_close(struct input_dev *input) { struct gpio_keys_drvdata *ddata = input_get_drvdata(input); + const struct gpio_keys_platform_data *pdata = ddata->pdata; + + if (pdata->disable) + pdata->disable(input->dev.parent); +} + +/* + * Handlers for alternative sources of platform_data + */ + +#ifdef CONFIG_OF +/* + * Translate OpenFirmware node properties into platform_data + */ +static struct gpio_keys_platform_data * +gpio_keys_get_devtree_pdata(struct device *dev) +{ + struct device_node *node, *pp; + struct gpio_keys_platform_data *pdata; + struct gpio_keys_button *button; + int error; + int nbuttons; + int i; + + node = dev->of_node; + if (!node) + return ERR_PTR(-ENODEV); + + nbuttons = of_get_child_count(node); + if (nbuttons == 0) + return ERR_PTR(-ENODEV); + + pdata = devm_kzalloc(dev, + sizeof(*pdata) + nbuttons * sizeof(*button), + GFP_KERNEL); + if (!pdata) + return ERR_PTR(-ENOMEM); + + pdata->buttons = (struct gpio_keys_button *)(pdata + 1); + pdata->nbuttons = nbuttons; + + pdata->rep = !!of_get_property(node, "autorepeat", NULL); + + i = 0; + for_each_child_of_node(node, pp) { + int gpio; + enum of_gpio_flags flags; + + if (!of_find_property(pp, "gpios", NULL)) { + pdata->nbuttons--; + dev_warn(dev, "Found button without gpios\n"); + continue; + } + + gpio = of_get_gpio_flags(pp, 0, &flags); + if (gpio < 0) { + error = gpio; + if (error != -EPROBE_DEFER) + dev_err(dev, + "Failed to get gpio flags, error: %d\n", + error); + return ERR_PTR(error); + } - if (ddata->disable) - ddata->disable(input->dev.parent); + button = &pdata->buttons[i++]; + + button->gpio = gpio; + button->active_low = flags & OF_GPIO_ACTIVE_LOW; + + if (of_property_read_u32(pp, "linux,code", &button->code)) { + dev_err(dev, "Button without keycode: 0x%x\n", + button->gpio); + return ERR_PTR(-EINVAL); + } + + button->desc = of_get_property(pp, "label", NULL); + + if (of_property_read_u32(pp, "linux,input-type", &button->type)) + button->type = EV_KEY; + + button->wakeup = !!of_get_property(pp, "gpio-key,wakeup", NULL); + + if (of_property_read_u32(pp, "debounce-interval", + &button->debounce_interval)) + button->debounce_interval = 5; + } + + if (pdata->nbuttons == 0) + return ERR_PTR(-EINVAL); + + return pdata; } -static int __devinit gpio_keys_probe(struct platform_device *pdev) +static const struct of_device_id gpio_keys_of_match[] = { + { .compatible = "gpio-keys", }, + { }, +}; +MODULE_DEVICE_TABLE(of, gpio_keys_of_match); + +#else + +static inline struct gpio_keys_platform_data * +gpio_keys_get_devtree_pdata(struct device *dev) +{ + return ERR_PTR(-ENODEV); +} + +#endif + +static int gpio_keys_probe(struct platform_device *pdev) { - struct gpio_keys_platform_data *pdata = pdev->dev.platform_data; - struct gpio_keys_drvdata *ddata; struct device *dev = &pdev->dev; + const struct gpio_keys_platform_data *pdata = dev_get_platdata(dev); + struct gpio_keys_drvdata *ddata; struct input_dev *input; + size_t size; int i, error; int wakeup = 0; - ddata = kzalloc(sizeof(struct gpio_keys_drvdata) + - pdata->nbuttons * sizeof(struct gpio_button_data), - GFP_KERNEL); - input = input_allocate_device(); - if (!ddata || !input) { + if (!pdata) { + pdata = gpio_keys_get_devtree_pdata(dev); + if (IS_ERR(pdata)) + return PTR_ERR(pdata); + } + + size = sizeof(struct gpio_keys_drvdata) + + pdata->nbuttons * sizeof(struct gpio_button_data); + ddata = devm_kzalloc(dev, size, GFP_KERNEL); + if (!ddata) { dev_err(dev, "failed to allocate state\n"); - error = -ENOMEM; - goto fail1; + return -ENOMEM; } + input = devm_input_allocate_device(dev); + if (!input) { + dev_err(dev, "failed to allocate input device\n"); + return -ENOMEM; + } + + ddata->pdata = pdata; ddata->input = input; - ddata->n_buttons = pdata->nbuttons; - ddata->enable = pdata->enable; - ddata->disable = pdata->disable; mutex_init(&ddata->disable_lock); platform_set_drvdata(pdev, ddata); @@ -489,106 +734,67 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev) __set_bit(EV_REP, input->evbit); for (i = 0; i < pdata->nbuttons; i++) { - struct gpio_keys_button *button = &pdata->buttons[i]; + const struct gpio_keys_button *button = &pdata->buttons[i]; struct gpio_button_data *bdata = &ddata->data[i]; - unsigned int type = button->type ?: EV_KEY; - - bdata->input = input; - bdata->button = button; - error = gpio_keys_setup_key(pdev, bdata, button); + error = gpio_keys_setup_key(pdev, input, bdata, button); if (error) - goto fail2; + return error; if (button->wakeup) wakeup = 1; - - input_set_capability(input, type, button->code); } error = sysfs_create_group(&pdev->dev.kobj, &gpio_keys_attr_group); if (error) { dev_err(dev, "Unable to export keys/switches, error: %d\n", error); - goto fail2; + return error; } error = input_register_device(input); if (error) { dev_err(dev, "Unable to register input device, error: %d\n", error); - goto fail3; + goto err_remove_group; } - /* get current state of buttons */ - for (i = 0; i < pdata->nbuttons; i++) - gpio_keys_report_event(&ddata->data[i]); - input_sync(input); - device_init_wakeup(&pdev->dev, wakeup); return 0; - fail3: +err_remove_group: sysfs_remove_group(&pdev->dev.kobj, &gpio_keys_attr_group); - fail2: - while (--i >= 0) { - free_irq(gpio_to_irq(pdata->buttons[i].gpio), &ddata->data[i]); - if (ddata->data[i].timer_debounce) - del_timer_sync(&ddata->data[i].timer); - cancel_work_sync(&ddata->data[i].work); - gpio_free(pdata->buttons[i].gpio); - } - - platform_set_drvdata(pdev, NULL); - fail1: - input_free_device(input); - kfree(ddata); - return error; } -static int __devexit gpio_keys_remove(struct platform_device *pdev) +static int gpio_keys_remove(struct platform_device *pdev) { - struct gpio_keys_platform_data *pdata = pdev->dev.platform_data; - struct gpio_keys_drvdata *ddata = platform_get_drvdata(pdev); - struct input_dev *input = ddata->input; - int i; - sysfs_remove_group(&pdev->dev.kobj, &gpio_keys_attr_group); device_init_wakeup(&pdev->dev, 0); - for (i = 0; i < pdata->nbuttons; i++) { - int irq = gpio_to_irq(pdata->buttons[i].gpio); - free_irq(irq, &ddata->data[i]); - if (ddata->data[i].timer_debounce) - del_timer_sync(&ddata->data[i].timer); - cancel_work_sync(&ddata->data[i].work); - gpio_free(pdata->buttons[i].gpio); - } - - input_unregister_device(input); - return 0; } - -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP static int gpio_keys_suspend(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct gpio_keys_platform_data *pdata = pdev->dev.platform_data; + struct gpio_keys_drvdata *ddata = dev_get_drvdata(dev); + struct input_dev *input = ddata->input; int i; - if (device_may_wakeup(&pdev->dev)) { - for (i = 0; i < pdata->nbuttons; i++) { - struct gpio_keys_button *button = &pdata->buttons[i]; - if (button->wakeup) { - int irq = gpio_to_irq(button->gpio); - enable_irq_wake(irq); - } + if (device_may_wakeup(dev)) { + for (i = 0; i < ddata->pdata->nbuttons; i++) { + struct gpio_button_data *bdata = &ddata->data[i]; + if (bdata->button->wakeup) + enable_irq_wake(bdata->irq); } + } else { + mutex_lock(&input->mutex); + if (input->users) + gpio_keys_close(input); + mutex_unlock(&input->mutex); } return 0; @@ -596,41 +802,42 @@ static int gpio_keys_suspend(struct device *dev) static int gpio_keys_resume(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct gpio_keys_drvdata *ddata = platform_get_drvdata(pdev); - struct gpio_keys_platform_data *pdata = pdev->dev.platform_data; + struct gpio_keys_drvdata *ddata = dev_get_drvdata(dev); + struct input_dev *input = ddata->input; + int error = 0; int i; - for (i = 0; i < pdata->nbuttons; i++) { - - struct gpio_keys_button *button = &pdata->buttons[i]; - if (button->wakeup && device_may_wakeup(&pdev->dev)) { - int irq = gpio_to_irq(button->gpio); - disable_irq_wake(irq); + if (device_may_wakeup(dev)) { + for (i = 0; i < ddata->pdata->nbuttons; i++) { + struct gpio_button_data *bdata = &ddata->data[i]; + if (bdata->button->wakeup) + disable_irq_wake(bdata->irq); } - - gpio_keys_report_event(&ddata->data[i]); + } else { + mutex_lock(&input->mutex); + if (input->users) + error = gpio_keys_open(input); + mutex_unlock(&input->mutex); } - input_sync(ddata->input); + if (error) + return error; + + gpio_keys_report_state(ddata); return 0; } - -static const struct dev_pm_ops gpio_keys_pm_ops = { - .suspend = gpio_keys_suspend, - .resume = gpio_keys_resume, -}; #endif +static SIMPLE_DEV_PM_OPS(gpio_keys_pm_ops, gpio_keys_suspend, gpio_keys_resume); + static struct platform_driver gpio_keys_device_driver = { .probe = gpio_keys_probe, - .remove = __devexit_p(gpio_keys_remove), + .remove = gpio_keys_remove, .driver = { .name = "gpio-keys", .owner = THIS_MODULE, -#ifdef CONFIG_PM .pm = &gpio_keys_pm_ops, -#endif + .of_match_table = of_match_ptr(gpio_keys_of_match), } }; @@ -644,10 +851,10 @@ static void __exit gpio_keys_exit(void) platform_driver_unregister(&gpio_keys_device_driver); } -module_init(gpio_keys_init); +late_initcall(gpio_keys_init); module_exit(gpio_keys_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Phil Blundell <pb@handhelds.org>"); -MODULE_DESCRIPTION("Keyboard driver for CPU GPIOs"); +MODULE_DESCRIPTION("Keyboard driver for GPIOs"); MODULE_ALIAS("platform:gpio-keys"); diff --git a/drivers/input/keyboard/gpio_keys_polled.c b/drivers/input/keyboard/gpio_keys_polled.c index 4c17aff2065..432d36395f3 100644 --- a/drivers/input/keyboard/gpio_keys_polled.c +++ b/drivers/input/keyboard/gpio_keys_polled.c @@ -17,7 +17,6 @@ #include <linux/kernel.h> #include <linux/module.h> -#include <linux/init.h> #include <linux/slab.h> #include <linux/input.h> #include <linux/input-polldev.h> @@ -25,6 +24,9 @@ #include <linux/platform_device.h> #include <linux/gpio.h> #include <linux/gpio_keys.h> +#include <linux/of.h> +#include <linux/of_platform.h> +#include <linux/of_gpio.h> #define DRV_NAME "gpio-keys-polled" @@ -38,7 +40,7 @@ struct gpio_keys_button_data { struct gpio_keys_polled_dev { struct input_polled_dev *poll_dev; struct device *dev; - struct gpio_keys_platform_data *pdata; + const struct gpio_keys_platform_data *pdata; struct gpio_keys_button_data data[0]; }; @@ -67,11 +69,11 @@ static void gpio_keys_polled_check_state(struct input_dev *input, static void gpio_keys_polled_poll(struct input_polled_dev *dev) { struct gpio_keys_polled_dev *bdev = dev->private; - struct gpio_keys_platform_data *pdata = bdev->pdata; + const struct gpio_keys_platform_data *pdata = bdev->pdata; struct input_dev *input = dev->input; int i; - for (i = 0; i < bdev->pdata->nbuttons; i++) { + for (i = 0; i < pdata->nbuttons; i++) { struct gpio_keys_button_data *bdata = &bdev->data[i]; if (bdata->count < bdata->threshold) @@ -85,7 +87,7 @@ static void gpio_keys_polled_poll(struct input_polled_dev *dev) static void gpio_keys_polled_open(struct input_polled_dev *dev) { struct gpio_keys_polled_dev *bdev = dev->private; - struct gpio_keys_platform_data *pdata = bdev->pdata; + const struct gpio_keys_platform_data *pdata = bdev->pdata; if (pdata->enable) pdata->enable(bdev->dev); @@ -94,38 +96,144 @@ static void gpio_keys_polled_open(struct input_polled_dev *dev) static void gpio_keys_polled_close(struct input_polled_dev *dev) { struct gpio_keys_polled_dev *bdev = dev->private; - struct gpio_keys_platform_data *pdata = bdev->pdata; + const struct gpio_keys_platform_data *pdata = bdev->pdata; if (pdata->disable) pdata->disable(bdev->dev); } -static int __devinit gpio_keys_polled_probe(struct platform_device *pdev) +#ifdef CONFIG_OF +static struct gpio_keys_platform_data *gpio_keys_polled_get_devtree_pdata(struct device *dev) +{ + struct device_node *node, *pp; + struct gpio_keys_platform_data *pdata; + struct gpio_keys_button *button; + int error; + int nbuttons; + int i; + + node = dev->of_node; + if (!node) + return NULL; + + nbuttons = of_get_child_count(node); + if (nbuttons == 0) + return NULL; + + pdata = devm_kzalloc(dev, sizeof(*pdata) + nbuttons * sizeof(*button), + GFP_KERNEL); + if (!pdata) + return ERR_PTR(-ENOMEM); + + pdata->buttons = (struct gpio_keys_button *)(pdata + 1); + pdata->nbuttons = nbuttons; + + pdata->rep = !!of_get_property(node, "autorepeat", NULL); + of_property_read_u32(node, "poll-interval", &pdata->poll_interval); + + i = 0; + for_each_child_of_node(node, pp) { + int gpio; + enum of_gpio_flags flags; + + if (!of_find_property(pp, "gpios", NULL)) { + pdata->nbuttons--; + dev_warn(dev, "Found button without gpios\n"); + continue; + } + + gpio = of_get_gpio_flags(pp, 0, &flags); + if (gpio < 0) { + error = gpio; + if (error != -EPROBE_DEFER) + dev_err(dev, + "Failed to get gpio flags, error: %d\n", + error); + return ERR_PTR(error); + } + + button = &pdata->buttons[i++]; + + button->gpio = gpio; + button->active_low = flags & OF_GPIO_ACTIVE_LOW; + + if (of_property_read_u32(pp, "linux,code", &button->code)) { + dev_err(dev, "Button without keycode: 0x%x\n", + button->gpio); + return ERR_PTR(-EINVAL); + } + + button->desc = of_get_property(pp, "label", NULL); + + if (of_property_read_u32(pp, "linux,input-type", &button->type)) + button->type = EV_KEY; + + button->wakeup = !!of_get_property(pp, "gpio-key,wakeup", NULL); + + if (of_property_read_u32(pp, "debounce-interval", + &button->debounce_interval)) + button->debounce_interval = 5; + } + + if (pdata->nbuttons == 0) + return ERR_PTR(-EINVAL); + + return pdata; +} + +static const struct of_device_id gpio_keys_polled_of_match[] = { + { .compatible = "gpio-keys-polled", }, + { }, +}; +MODULE_DEVICE_TABLE(of, gpio_keys_polled_of_match); + +#else + +static inline struct gpio_keys_platform_data * +gpio_keys_polled_get_devtree_pdata(struct device *dev) +{ + return NULL; +} +#endif + +static int gpio_keys_polled_probe(struct platform_device *pdev) { - struct gpio_keys_platform_data *pdata = pdev->dev.platform_data; struct device *dev = &pdev->dev; + const struct gpio_keys_platform_data *pdata = dev_get_platdata(dev); struct gpio_keys_polled_dev *bdev; struct input_polled_dev *poll_dev; struct input_dev *input; + size_t size; int error; int i; - if (!pdata || !pdata->poll_interval) + if (!pdata) { + pdata = gpio_keys_polled_get_devtree_pdata(dev); + if (IS_ERR(pdata)) + return PTR_ERR(pdata); + if (!pdata) { + dev_err(dev, "missing platform data\n"); + return -EINVAL; + } + } + + if (!pdata->poll_interval) { + dev_err(dev, "missing poll_interval value\n"); return -EINVAL; + } - bdev = kzalloc(sizeof(struct gpio_keys_polled_dev) + - pdata->nbuttons * sizeof(struct gpio_keys_button_data), - GFP_KERNEL); + size = sizeof(struct gpio_keys_polled_dev) + + pdata->nbuttons * sizeof(struct gpio_keys_button_data); + bdev = devm_kzalloc(&pdev->dev, size, GFP_KERNEL); if (!bdev) { dev_err(dev, "no memory for private data\n"); return -ENOMEM; } - poll_dev = input_allocate_polled_device(); + poll_dev = devm_input_allocate_polled_device(&pdev->dev); if (!poll_dev) { dev_err(dev, "no memory for polled device\n"); - error = -ENOMEM; - goto err_free_bdev; + return -ENOMEM; } poll_dev->private = bdev; @@ -136,16 +244,18 @@ static int __devinit gpio_keys_polled_probe(struct platform_device *pdev) input = poll_dev->input; - input->evbit[0] = BIT(EV_KEY); input->name = pdev->name; input->phys = DRV_NAME"/input0"; - input->dev.parent = &pdev->dev; input->id.bustype = BUS_HOST; input->id.vendor = 0x0001; input->id.product = 0x0001; input->id.version = 0x0100; + __set_bit(EV_KEY, input->evbit); + if (pdata->rep) + __set_bit(EV_REP, input->evbit); + for (i = 0; i < pdata->nbuttons; i++) { struct gpio_keys_button *button = &pdata->buttons[i]; struct gpio_keys_button_data *bdata = &bdev->data[i]; @@ -154,24 +264,15 @@ static int __devinit gpio_keys_polled_probe(struct platform_device *pdev) if (button->wakeup) { dev_err(dev, DRV_NAME " does not support wakeup\n"); - error = -EINVAL; - goto err_free_gpio; + return -EINVAL; } - error = gpio_request(gpio, - button->desc ? button->desc : DRV_NAME); + error = devm_gpio_request_one(&pdev->dev, gpio, GPIOF_IN, + button->desc ? : DRV_NAME); if (error) { dev_err(dev, "unable to claim gpio %u, err=%d\n", gpio, error); - goto err_free_gpio; - } - - error = gpio_direction_input(gpio); - if (error) { - dev_err(dev, - "unable to set direction on gpio %u, err=%d\n", - gpio, error); - goto err_free_gpio; + return error; } bdata->can_sleep = gpio_cansleep(gpio); @@ -191,69 +292,26 @@ static int __devinit gpio_keys_polled_probe(struct platform_device *pdev) if (error) { dev_err(dev, "unable to register polled device, err=%d\n", error); - goto err_free_gpio; + return error; } /* report initial state of the buttons */ for (i = 0; i < pdata->nbuttons; i++) gpio_keys_polled_check_state(input, &pdata->buttons[i], - &bdev->data[i]); - - return 0; - -err_free_gpio: - while (--i >= 0) - gpio_free(pdata->buttons[i].gpio); - - input_free_polled_device(poll_dev); - -err_free_bdev: - kfree(bdev); - - platform_set_drvdata(pdev, NULL); - return error; -} - -static int __devexit gpio_keys_polled_remove(struct platform_device *pdev) -{ - struct gpio_keys_polled_dev *bdev = platform_get_drvdata(pdev); - struct gpio_keys_platform_data *pdata = bdev->pdata; - int i; - - input_unregister_polled_device(bdev->poll_dev); - - for (i = 0; i < pdata->nbuttons; i++) - gpio_free(pdata->buttons[i].gpio); - - input_free_polled_device(bdev->poll_dev); - - kfree(bdev); - platform_set_drvdata(pdev, NULL); + &bdev->data[i]); return 0; } static struct platform_driver gpio_keys_polled_driver = { .probe = gpio_keys_polled_probe, - .remove = __devexit_p(gpio_keys_polled_remove), .driver = { .name = DRV_NAME, .owner = THIS_MODULE, + .of_match_table = of_match_ptr(gpio_keys_polled_of_match), }, }; - -static int __init gpio_keys_polled_init(void) -{ - return platform_driver_register(&gpio_keys_polled_driver); -} - -static void __exit gpio_keys_polled_exit(void) -{ - platform_driver_unregister(&gpio_keys_polled_driver); -} - -module_init(gpio_keys_polled_init); -module_exit(gpio_keys_polled_exit); +module_platform_driver(gpio_keys_polled_driver); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>"); diff --git a/drivers/input/keyboard/hil_kbd.c b/drivers/input/keyboard/hil_kbd.c index fed31e0947a..610a8af795a 100644 --- a/drivers/input/keyboard/hil_kbd.c +++ b/drivers/input/keyboard/hil_kbd.c @@ -36,7 +36,6 @@ #include <linux/serio.h> #include <linux/kernel.h> #include <linux/module.h> -#include <linux/init.h> #include <linux/completion.h> #include <linux/slab.h> #include <linux/pci_ids.h> @@ -583,15 +582,4 @@ static struct serio_driver hil_serio_drv = { .interrupt = hil_dev_interrupt }; -static int __init hil_dev_init(void) -{ - return serio_register_driver(&hil_serio_drv); -} - -static void __exit hil_dev_exit(void) -{ - serio_unregister_driver(&hil_serio_drv); -} - -module_init(hil_dev_init); -module_exit(hil_dev_exit); +module_serio_driver(hil_serio_drv); diff --git a/drivers/input/keyboard/hilkbd.c b/drivers/input/keyboard/hilkbd.c index 5f72440b50c..198dc07a1be 100644 --- a/drivers/input/keyboard/hilkbd.c +++ b/drivers/input/keyboard/hilkbd.c @@ -200,7 +200,7 @@ static void hil_do(unsigned char cmd, unsigned char *data, unsigned int len) /* initialize HIL */ -static int __devinit hil_keyb_init(void) +static int hil_keyb_init(void) { unsigned char c; unsigned int i, kbid; @@ -286,7 +286,7 @@ err1: return err; } -static void __devexit hil_keyb_exit(void) +static void hil_keyb_exit(void) { if (HIL_IRQ) free_irq(HIL_IRQ, hil_dev.dev_id); @@ -299,7 +299,7 @@ static void __devexit hil_keyb_exit(void) } #if defined(CONFIG_PARISC) -static int __devinit hil_probe_chip(struct parisc_device *dev) +static int hil_probe_chip(struct parisc_device *dev) { /* Only allow one HIL keyboard */ if (hil_dev.dev) @@ -320,7 +320,7 @@ static int __devinit hil_probe_chip(struct parisc_device *dev) return hil_keyb_init(); } -static int __devexit hil_remove_chip(struct parisc_device *dev) +static int hil_remove_chip(struct parisc_device *dev) { hil_keyb_exit(); @@ -341,7 +341,7 @@ static struct parisc_driver hil_driver = { .name = "hil", .id_table = hil_tbl, .probe = hil_probe_chip, - .remove = __devexit_p(hil_remove_chip), + .remove = hil_remove_chip, }; static int __init hil_init(void) diff --git a/drivers/input/keyboard/imx_keypad.c b/drivers/input/keyboard/imx_keypad.c index d92c15c39e6..8280cb16260 100644 --- a/drivers/input/keyboard/imx_keypad.c +++ b/drivers/input/keyboard/imx_keypad.c @@ -13,13 +13,13 @@ #include <linux/delay.h> #include <linux/device.h> #include <linux/err.h> -#include <linux/init.h> #include <linux/input/matrix_keypad.h> #include <linux/interrupt.h> #include <linux/io.h> #include <linux/jiffies.h> #include <linux/kernel.h> #include <linux/module.h> +#include <linux/of.h> #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/timer.h> @@ -358,10 +358,12 @@ static void imx_keypad_inhibit(struct imx_keypad *keypad) /* Inhibit KDI and KRI interrupts. */ reg_val = readw(keypad->mmio_base + KPSR); reg_val &= ~(KBD_STAT_KRIE | KBD_STAT_KDIE); + reg_val |= KBD_STAT_KPKR | KBD_STAT_KPKD; writew(reg_val, keypad->mmio_base + KPSR); /* Colums as open drain and disable all rows */ - writew(0xff00, keypad->mmio_base + KPCR); + reg_val = (keypad->cols_en_mask & 0xff) << 8; + writew(reg_val, keypad->mmio_base + KPCR); } static void imx_keypad_close(struct input_dev *dev) @@ -378,20 +380,24 @@ static void imx_keypad_close(struct input_dev *dev) imx_keypad_inhibit(keypad); /* Disable clock unit */ - clk_disable(keypad->clk); + clk_disable_unprepare(keypad->clk); } static int imx_keypad_open(struct input_dev *dev) { struct imx_keypad *keypad = input_get_drvdata(dev); + int error; dev_dbg(&dev->dev, ">%s\n", __func__); + /* Enable the kpp clock */ + error = clk_prepare_enable(keypad->clk); + if (error) + return error; + /* We became active from now */ keypad->enabled = true; - /* Enable the kpp clock */ - clk_enable(keypad->clk); imx_keypad_config(keypad); /* Sanity control, not all the rows must be actived now. */ @@ -408,15 +414,24 @@ open_err: return -EIO; } -static int __devinit imx_keypad_probe(struct platform_device *pdev) +#ifdef CONFIG_OF +static const struct of_device_id imx_keypad_of_match[] = { + { .compatible = "fsl,imx21-kpp", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, imx_keypad_of_match); +#endif + +static int imx_keypad_probe(struct platform_device *pdev) { - const struct matrix_keymap_data *keymap_data = pdev->dev.platform_data; + const struct matrix_keymap_data *keymap_data = + dev_get_platdata(&pdev->dev); struct imx_keypad *keypad; struct input_dev *input_dev; struct resource *res; - int irq, error, i; + int irq, error, i, row, col; - if (keymap_data == NULL) { + if (!keymap_data && !pdev->dev.of_node) { dev_err(&pdev->dev, "no keymap defined\n"); return -EINVAL; } @@ -424,33 +439,20 @@ static int __devinit imx_keypad_probe(struct platform_device *pdev) irq = platform_get_irq(pdev, 0); if (irq < 0) { dev_err(&pdev->dev, "no irq defined in platform data\n"); - return -EINVAL; - } - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (res == NULL) { - dev_err(&pdev->dev, "no I/O memory defined in platform data\n"); - return -EINVAL; - } - - res = request_mem_region(res->start, resource_size(res), pdev->name); - if (res == NULL) { - dev_err(&pdev->dev, "failed to request I/O memory\n"); - return -EBUSY; + return irq; } - input_dev = input_allocate_device(); + input_dev = devm_input_allocate_device(&pdev->dev); if (!input_dev) { dev_err(&pdev->dev, "failed to allocate the input device\n"); - error = -ENOMEM; - goto failed_rel_mem; + return -ENOMEM; } - keypad = kzalloc(sizeof(struct imx_keypad), GFP_KERNEL); + keypad = devm_kzalloc(&pdev->dev, sizeof(struct imx_keypad), + GFP_KERNEL); if (!keypad) { dev_err(&pdev->dev, "not enough memory for driver data\n"); - error = -ENOMEM; - goto failed_free_input; + return -ENOMEM; } keypad->input_dev = input_dev; @@ -460,134 +462,133 @@ static int __devinit imx_keypad_probe(struct platform_device *pdev) setup_timer(&keypad->check_matrix_timer, imx_keypad_check_for_events, (unsigned long) keypad); - keypad->mmio_base = ioremap(res->start, resource_size(res)); - if (keypad->mmio_base == NULL) { - dev_err(&pdev->dev, "failed to remap I/O memory\n"); - error = -ENOMEM; - goto failed_free_priv; - } + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + keypad->mmio_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(keypad->mmio_base)) + return PTR_ERR(keypad->mmio_base); - keypad->clk = clk_get(&pdev->dev, "kpp"); + keypad->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(keypad->clk)) { dev_err(&pdev->dev, "failed to get keypad clock\n"); - error = PTR_ERR(keypad->clk); - goto failed_unmap; + return PTR_ERR(keypad->clk); } - /* Search for rows and cols enabled */ - for (i = 0; i < keymap_data->keymap_size; i++) { - keypad->rows_en_mask |= 1 << KEY_ROW(keymap_data->keymap[i]); - keypad->cols_en_mask |= 1 << KEY_COL(keymap_data->keymap[i]); - } - - if (keypad->rows_en_mask > ((1 << MAX_MATRIX_KEY_ROWS) - 1) || - keypad->cols_en_mask > ((1 << MAX_MATRIX_KEY_COLS) - 1)) { - dev_err(&pdev->dev, - "invalid key data (too many rows or colums)\n"); - error = -EINVAL; - goto failed_clock_put; - } - dev_dbg(&pdev->dev, "enabled rows mask: %x\n", keypad->rows_en_mask); - dev_dbg(&pdev->dev, "enabled cols mask: %x\n", keypad->cols_en_mask); - /* Init the Input device */ input_dev->name = pdev->name; input_dev->id.bustype = BUS_HOST; input_dev->dev.parent = &pdev->dev; input_dev->open = imx_keypad_open; input_dev->close = imx_keypad_close; - input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP); - input_dev->keycode = keypad->keycodes; - input_dev->keycodesize = sizeof(keypad->keycodes[0]); - input_dev->keycodemax = ARRAY_SIZE(keypad->keycodes); - matrix_keypad_build_keymap(keymap_data, MATRIX_ROW_SHIFT, - keypad->keycodes, input_dev->keybit); + error = matrix_keypad_build_keymap(keymap_data, NULL, + MAX_MATRIX_KEY_ROWS, + MAX_MATRIX_KEY_COLS, + keypad->keycodes, input_dev); + if (error) { + dev_err(&pdev->dev, "failed to build keymap\n"); + return error; + } + /* Search for rows and cols enabled */ + for (row = 0; row < MAX_MATRIX_KEY_ROWS; row++) { + for (col = 0; col < MAX_MATRIX_KEY_COLS; col++) { + i = MATRIX_SCAN_CODE(row, col, MATRIX_ROW_SHIFT); + if (keypad->keycodes[i] != KEY_RESERVED) { + keypad->rows_en_mask |= 1 << row; + keypad->cols_en_mask |= 1 << col; + } + } + } + dev_dbg(&pdev->dev, "enabled rows mask: %x\n", keypad->rows_en_mask); + dev_dbg(&pdev->dev, "enabled cols mask: %x\n", keypad->cols_en_mask); + + __set_bit(EV_REP, input_dev->evbit); input_set_capability(input_dev, EV_MSC, MSC_SCAN); input_set_drvdata(input_dev, keypad); /* Ensure that the keypad will stay dormant until opened */ + clk_prepare_enable(keypad->clk); imx_keypad_inhibit(keypad); + clk_disable_unprepare(keypad->clk); - error = request_irq(irq, imx_keypad_irq_handler, IRQF_DISABLED, + error = devm_request_irq(&pdev->dev, irq, imx_keypad_irq_handler, 0, pdev->name, keypad); if (error) { dev_err(&pdev->dev, "failed to request IRQ\n"); - goto failed_clock_put; + return error; } /* Register the input device */ error = input_register_device(input_dev); if (error) { dev_err(&pdev->dev, "failed to register input device\n"); - goto failed_free_irq; + return error; } platform_set_drvdata(pdev, keypad); device_init_wakeup(&pdev->dev, 1); return 0; - -failed_free_irq: - free_irq(irq, pdev); -failed_clock_put: - clk_put(keypad->clk); -failed_unmap: - iounmap(keypad->mmio_base); -failed_free_priv: - kfree(keypad); -failed_free_input: - input_free_device(input_dev); -failed_rel_mem: - release_mem_region(res->start, resource_size(res)); - return error; } -static int __devexit imx_keypad_remove(struct platform_device *pdev) +#ifdef CONFIG_PM_SLEEP +static int imx_kbd_suspend(struct device *dev) { - struct imx_keypad *keypad = platform_get_drvdata(pdev); - struct resource *res; + struct platform_device *pdev = to_platform_device(dev); + struct imx_keypad *kbd = platform_get_drvdata(pdev); + struct input_dev *input_dev = kbd->input_dev; - dev_dbg(&pdev->dev, ">%s\n", __func__); + /* imx kbd can wake up system even clock is disabled */ + mutex_lock(&input_dev->mutex); - platform_set_drvdata(pdev, NULL); + if (input_dev->users) + clk_disable_unprepare(kbd->clk); - input_unregister_device(keypad->input_dev); + mutex_unlock(&input_dev->mutex); - free_irq(keypad->irq, keypad); - clk_put(keypad->clk); + if (device_may_wakeup(&pdev->dev)) + enable_irq_wake(kbd->irq); - iounmap(keypad->mmio_base); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(res->start, resource_size(res)); + return 0; +} - kfree(keypad); +static int imx_kbd_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct imx_keypad *kbd = platform_get_drvdata(pdev); + struct input_dev *input_dev = kbd->input_dev; + int ret = 0; - return 0; + if (device_may_wakeup(&pdev->dev)) + disable_irq_wake(kbd->irq); + + mutex_lock(&input_dev->mutex); + + if (input_dev->users) { + ret = clk_prepare_enable(kbd->clk); + if (ret) + goto err_clk; + } + +err_clk: + mutex_unlock(&input_dev->mutex); + + return ret; } +#endif + +static SIMPLE_DEV_PM_OPS(imx_kbd_pm_ops, imx_kbd_suspend, imx_kbd_resume); static struct platform_driver imx_keypad_driver = { .driver = { .name = "imx-keypad", .owner = THIS_MODULE, + .pm = &imx_kbd_pm_ops, + .of_match_table = of_match_ptr(imx_keypad_of_match), }, .probe = imx_keypad_probe, - .remove = __devexit_p(imx_keypad_remove), }; - -static int __init imx_keypad_init(void) -{ - return platform_driver_register(&imx_keypad_driver); -} - -static void __exit imx_keypad_exit(void) -{ - platform_driver_unregister(&imx_keypad_driver); -} - -module_init(imx_keypad_init); -module_exit(imx_keypad_exit); +module_platform_driver(imx_keypad_driver); MODULE_AUTHOR("Alberto Panizzo <maramaopercheseimorto@gmail.com>"); MODULE_DESCRIPTION("IMX Keypad Port Driver"); diff --git a/drivers/input/keyboard/jornada680_kbd.c b/drivers/input/keyboard/jornada680_kbd.c index 7197c569874..0ba4428da24 100644 --- a/drivers/input/keyboard/jornada680_kbd.c +++ b/drivers/input/keyboard/jornada680_kbd.c @@ -16,7 +16,7 @@ * published by the Free Software Foundation. */ -#include <linux/init.h> +#include <linux/device.h> #include <linux/input.h> #include <linux/input-polldev.h> #include <linux/interrupt.h> @@ -179,21 +179,22 @@ static void jornadakbd680_poll(struct input_polled_dev *dev) memcpy(jornadakbd->old_scan, jornadakbd->new_scan, JORNADA_SCAN_SIZE); } -static int __devinit jornada680kbd_probe(struct platform_device *pdev) +static int jornada680kbd_probe(struct platform_device *pdev) { struct jornadakbd *jornadakbd; struct input_polled_dev *poll_dev; struct input_dev *input_dev; int i, error; - jornadakbd = kzalloc(sizeof(struct jornadakbd), GFP_KERNEL); + jornadakbd = devm_kzalloc(&pdev->dev, sizeof(struct jornadakbd), + GFP_KERNEL); if (!jornadakbd) return -ENOMEM; - poll_dev = input_allocate_polled_device(); + poll_dev = devm_input_allocate_polled_device(&pdev->dev); if (!poll_dev) { - error = -ENOMEM; - goto failed; + dev_err(&pdev->dev, "failed to allocate polled input device\n"); + return -ENOMEM; } platform_set_drvdata(pdev, jornadakbd); @@ -225,29 +226,10 @@ static int __devinit jornada680kbd_probe(struct platform_device *pdev) input_set_capability(input_dev, EV_MSC, MSC_SCAN); error = input_register_polled_device(jornadakbd->poll_dev); - if (error) - goto failed; - - return 0; - - 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; - -} - -static int __devexit 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); + if (error) { + dev_err(&pdev->dev, "failed to register polled input device\n"); + return error; + } return 0; } @@ -258,21 +240,8 @@ static struct platform_driver jornada680kbd_driver = { .owner = THIS_MODULE, }, .probe = jornada680kbd_probe, - .remove = __devexit_p(jornada680kbd_remove), }; - -static int __init jornada680kbd_init(void) -{ - return platform_driver_register(&jornada680kbd_driver); -} - -static void __exit jornada680kbd_exit(void) -{ - platform_driver_unregister(&jornada680kbd_driver); -} - -module_init(jornada680kbd_init); -module_exit(jornada680kbd_exit); +module_platform_driver(jornada680kbd_driver); MODULE_AUTHOR("Kristoffer Ericson <kristoffer.ericson@gmail.com>"); MODULE_DESCRIPTION("HP Jornada 620/660/680/690 Keyboard Driver"); diff --git a/drivers/input/keyboard/jornada720_kbd.c b/drivers/input/keyboard/jornada720_kbd.c index 2cd3e1d56ea..cd729d485e9 100644 --- a/drivers/input/keyboard/jornada720_kbd.c +++ b/drivers/input/keyboard/jornada720_kbd.c @@ -18,7 +18,6 @@ #include <linux/device.h> #include <linux/errno.h> #include <linux/interrupt.h> -#include <linux/init.h> #include <linux/input.h> #include <linux/kernel.h> #include <linux/module.h> @@ -27,6 +26,7 @@ #include <mach/jornada720.h> #include <mach/hardware.h> +#include <mach/irqs.h> MODULE_AUTHOR("Kristoffer Ericson <Kristoffer.Ericson@gmail.com>"); MODULE_DESCRIPTION("HP Jornada 710/720/728 keyboard driver"); @@ -93,7 +93,7 @@ static irqreturn_t jornada720_kbd_interrupt(int irq, void *dev_id) return IRQ_HANDLED; }; -static int __devinit jornada720_kbd_probe(struct platform_device *pdev) +static int jornada720_kbd_probe(struct platform_device *pdev) { struct jornadakbd *jornadakbd; struct input_dev *input_dev; @@ -129,7 +129,7 @@ static int __devinit jornada720_kbd_probe(struct platform_device *pdev) err = request_irq(IRQ_GPIO0, jornada720_kbd_interrupt, - IRQF_DISABLED | IRQF_TRIGGER_FALLING, + IRQF_TRIGGER_FALLING, "jornadakbd", pdev); if (err) { printk(KERN_INFO "jornadakbd720_kbd: Unable to grab IRQ\n"); @@ -145,18 +145,16 @@ static int __devinit 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; }; -static int __devexit jornada720_kbd_remove(struct platform_device *pdev) +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); @@ -172,18 +170,6 @@ static struct platform_driver jornada720_kbd_driver = { .owner = THIS_MODULE, }, .probe = jornada720_kbd_probe, - .remove = __devexit_p(jornada720_kbd_remove), + .remove = jornada720_kbd_remove, }; - -static int __init jornada720_kbd_init(void) -{ - return platform_driver_register(&jornada720_kbd_driver); -} - -static void __exit jornada720_kbd_exit(void) -{ - platform_driver_unregister(&jornada720_kbd_driver); -} - -module_init(jornada720_kbd_init); -module_exit(jornada720_kbd_exit); +module_platform_driver(jornada720_kbd_driver); diff --git a/drivers/input/keyboard/lkkbd.c b/drivers/input/keyboard/lkkbd.c index fa9bb6d235e..9fcd9f1d5dc 100644 --- a/drivers/input/keyboard/lkkbd.c +++ b/drivers/input/keyboard/lkkbd.c @@ -65,7 +65,6 @@ #include <linux/slab.h> #include <linux/module.h> #include <linux/interrupt.h> -#include <linux/init.h> #include <linux/input.h> #include <linux/serio.h> #include <linux/workqueue.h> @@ -731,19 +730,4 @@ static struct serio_driver lkkbd_drv = { .interrupt = lkkbd_interrupt, }; -/* - * The functions for insering/removing us as a module. - */ -static int __init lkkbd_init(void) -{ - return serio_register_driver(&lkkbd_drv); -} - -static void __exit lkkbd_exit(void) -{ - serio_unregister_driver(&lkkbd_drv); -} - -module_init(lkkbd_init); -module_exit(lkkbd_exit); - +module_serio_driver(lkkbd_drv); diff --git a/drivers/input/keyboard/lm8323.c b/drivers/input/keyboard/lm8323.c index 71f744a8e68..0b42118cbf8 100644 --- a/drivers/input/keyboard/lm8323.c +++ b/drivers/input/keyboard/lm8323.c @@ -146,7 +146,6 @@ struct lm8323_chip { /* device lock */ struct mutex lock; struct i2c_client *client; - struct work_struct work; struct input_dev *idev; bool kp_enabled; bool pm_suspend; @@ -162,7 +161,6 @@ struct lm8323_chip { #define client_to_lm8323(c) container_of(c, struct lm8323_chip, client) #define dev_to_lm8323(d) container_of(d, struct lm8323_chip, client->dev) -#define work_to_lm8323(w) container_of(w, struct lm8323_chip, work) #define cdev_to_pwm(c) container_of(c, struct lm8323_pwm, cdev) #define work_to_pwm(w) container_of(w, struct lm8323_pwm, work) @@ -375,9 +373,9 @@ static void pwm_done(struct lm8323_pwm *pwm) * Bottom half: handle the interrupt by posting key events, or dealing with * errors appropriately. */ -static void lm8323_work(struct work_struct *work) +static irqreturn_t lm8323_irq(int irq, void *_lm) { - struct lm8323_chip *lm = work_to_lm8323(work); + struct lm8323_chip *lm = _lm; u8 ints; int i; @@ -400,7 +398,7 @@ static void lm8323_work(struct work_struct *work) lm8323_configure(lm); } for (i = 0; i < LM8323_NUM_PWMS; i++) { - if (ints & (1 << (INT_PWM1 + i))) { + if (ints & (INT_PWM1 << i)) { dev_vdbg(&lm->client->dev, "pwm%d engine completed\n", i); pwm_done(&lm->pwm[i]); @@ -409,16 +407,6 @@ static void lm8323_work(struct work_struct *work) } mutex_unlock(&lm->lock); -} - -/* - * We cannot use I2C in interrupt context, so we just schedule work. - */ -static irqreturn_t lm8323_irq(int irq, void *data) -{ - struct lm8323_chip *lm = data; - - schedule_work(&lm->work); return IRQ_HANDLED; } @@ -557,13 +545,12 @@ static ssize_t lm8323_pwm_store_time(struct device *dev, { struct led_classdev *led_cdev = dev_get_drvdata(dev); struct lm8323_pwm *pwm = cdev_to_pwm(led_cdev); - int ret; - unsigned long time; + int ret, time; - ret = strict_strtoul(buf, 10, &time); + ret = kstrtoint(buf, 10, &time); /* Numbers only, please. */ if (ret) - return -EINVAL; + return ret; pwm->fade_time = time; @@ -625,9 +612,9 @@ static ssize_t lm8323_set_disable(struct device *dev, { struct lm8323_chip *lm = dev_get_drvdata(dev); int ret; - unsigned long i; + unsigned int i; - ret = strict_strtoul(buf, 10, &i); + ret = kstrtouint(buf, 10, &i); mutex_lock(&lm->lock); lm->kp_enabled = !i; @@ -637,10 +624,10 @@ static ssize_t lm8323_set_disable(struct device *dev, } static DEVICE_ATTR(disable_kp, 0644, lm8323_show_disable, lm8323_set_disable); -static int __devinit lm8323_probe(struct i2c_client *client, +static int lm8323_probe(struct i2c_client *client, const struct i2c_device_id *id) { - struct lm8323_platform_data *pdata = client->dev.platform_data; + struct lm8323_platform_data *pdata = dev_get_platdata(&client->dev); struct input_dev *idev; struct lm8323_chip *lm; int pwm; @@ -675,7 +662,6 @@ static int __devinit lm8323_probe(struct i2c_client *client, lm->client = client; lm->idev = idev; mutex_init(&lm->lock); - INIT_WORK(&lm->work, lm8323_work); lm->size_x = pdata->size_x; lm->size_y = pdata->size_y; @@ -746,9 +732,8 @@ static int __devinit lm8323_probe(struct i2c_client *client, goto fail3; } - err = request_irq(client->irq, lm8323_irq, - IRQF_TRIGGER_FALLING | IRQF_DISABLED, - "lm8323", lm); + err = request_threaded_irq(client->irq, NULL, lm8323_irq, + IRQF_TRIGGER_LOW|IRQF_ONESHOT, "lm8323", lm); if (err) { dev_err(&client->dev, "could not get IRQ %d\n", client->irq); goto fail4; @@ -768,37 +753,41 @@ fail3: device_remove_file(&client->dev, &dev_attr_disable_kp); fail2: while (--pwm >= 0) - if (lm->pwm[pwm].enabled) + if (lm->pwm[pwm].enabled) { + device_remove_file(lm->pwm[pwm].cdev.dev, + &dev_attr_time); led_classdev_unregister(&lm->pwm[pwm].cdev); + } fail1: input_free_device(idev); kfree(lm); return err; } -static int __devexit lm8323_remove(struct i2c_client *client) +static int lm8323_remove(struct i2c_client *client) { struct lm8323_chip *lm = i2c_get_clientdata(client); int i; disable_irq_wake(client->irq); free_irq(client->irq, lm); - cancel_work_sync(&lm->work); input_unregister_device(lm->idev); device_remove_file(&lm->client->dev, &dev_attr_disable_kp); for (i = 0; i < 3; i++) - if (lm->pwm[i].enabled) + if (lm->pwm[i].enabled) { + device_remove_file(lm->pwm[i].cdev.dev, &dev_attr_time); led_classdev_unregister(&lm->pwm[i].cdev); + } kfree(lm); return 0; } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP /* * We don't need to explicitly suspend the chip, as it already switches off * when there's no activity. @@ -857,22 +846,12 @@ static struct i2c_driver lm8323_i2c_driver = { .pm = &lm8323_pm_ops, }, .probe = lm8323_probe, - .remove = __devexit_p(lm8323_remove), + .remove = lm8323_remove, .id_table = lm8323_id, }; MODULE_DEVICE_TABLE(i2c, lm8323_id); -static int __init lm8323_init(void) -{ - return i2c_add_driver(&lm8323_i2c_driver); -} -module_init(lm8323_init); - -static void __exit lm8323_exit(void) -{ - i2c_del_driver(&lm8323_i2c_driver); -} -module_exit(lm8323_exit); +module_i2c_driver(lm8323_i2c_driver); MODULE_AUTHOR("Timo O. Karjalainen <timo.o.karjalainen@nokia.com>"); MODULE_AUTHOR("Daniel Stone"); diff --git a/drivers/input/keyboard/lm8333.c b/drivers/input/keyboard/lm8333.c new file mode 100644 index 00000000000..9081cbef11e --- /dev/null +++ b/drivers/input/keyboard/lm8333.c @@ -0,0 +1,236 @@ +/* + * LM8333 keypad driver + * Copyright (C) 2012 Wolfram Sang, Pengutronix <w.sang@pengutronix.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License. + */ + +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/irq.h> +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/input/matrix_keypad.h> +#include <linux/input/lm8333.h> + +#define LM8333_FIFO_READ 0x20 +#define LM8333_DEBOUNCE 0x22 +#define LM8333_READ_INT 0xD0 +#define LM8333_ACTIVE 0xE4 +#define LM8333_READ_ERROR 0xF0 + +#define LM8333_KEYPAD_IRQ (1 << 0) +#define LM8333_ERROR_IRQ (1 << 3) + +#define LM8333_ERROR_KEYOVR 0x04 +#define LM8333_ERROR_FIFOOVR 0x40 + +#define LM8333_FIFO_TRANSFER_SIZE 16 + +#define LM8333_NUM_ROWS 8 +#define LM8333_NUM_COLS 16 +#define LM8333_ROW_SHIFT 4 + +struct lm8333 { + struct i2c_client *client; + struct input_dev *input; + unsigned short keycodes[LM8333_NUM_ROWS << LM8333_ROW_SHIFT]; +}; + +/* The accessors try twice because the first access may be needed for wakeup */ +#define LM8333_READ_RETRIES 2 + +int lm8333_read8(struct lm8333 *lm8333, u8 cmd) +{ + int retries = 0, ret; + + do { + ret = i2c_smbus_read_byte_data(lm8333->client, cmd); + } while (ret < 0 && retries++ < LM8333_READ_RETRIES); + + return ret; +} + +int lm8333_write8(struct lm8333 *lm8333, u8 cmd, u8 val) +{ + int retries = 0, ret; + + do { + ret = i2c_smbus_write_byte_data(lm8333->client, cmd, val); + } while (ret < 0 && retries++ < LM8333_READ_RETRIES); + + return ret; +} + +int lm8333_read_block(struct lm8333 *lm8333, u8 cmd, u8 len, u8 *buf) +{ + int retries = 0, ret; + + do { + ret = i2c_smbus_read_i2c_block_data(lm8333->client, + cmd, len, buf); + } while (ret < 0 && retries++ < LM8333_READ_RETRIES); + + return ret; +} + +static void lm8333_key_handler(struct lm8333 *lm8333) +{ + struct input_dev *input = lm8333->input; + u8 keys[LM8333_FIFO_TRANSFER_SIZE]; + u8 code, pressed; + int i, ret; + + ret = lm8333_read_block(lm8333, LM8333_FIFO_READ, + LM8333_FIFO_TRANSFER_SIZE, keys); + if (ret != LM8333_FIFO_TRANSFER_SIZE) { + dev_err(&lm8333->client->dev, + "Error %d while reading FIFO\n", ret); + return; + } + + for (i = 0; i < LM8333_FIFO_TRANSFER_SIZE && keys[i]; i++) { + pressed = keys[i] & 0x80; + code = keys[i] & 0x7f; + + input_event(input, EV_MSC, MSC_SCAN, code); + input_report_key(input, lm8333->keycodes[code], pressed); + } + + input_sync(input); +} + +static irqreturn_t lm8333_irq_thread(int irq, void *data) +{ + struct lm8333 *lm8333 = data; + u8 status = lm8333_read8(lm8333, LM8333_READ_INT); + + if (!status) + return IRQ_NONE; + + if (status & LM8333_ERROR_IRQ) { + u8 err = lm8333_read8(lm8333, LM8333_READ_ERROR); + + if (err & (LM8333_ERROR_KEYOVR | LM8333_ERROR_FIFOOVR)) { + u8 dummy[LM8333_FIFO_TRANSFER_SIZE]; + + lm8333_read_block(lm8333, LM8333_FIFO_READ, + LM8333_FIFO_TRANSFER_SIZE, dummy); + } + dev_err(&lm8333->client->dev, "Got error %02x\n", err); + } + + if (status & LM8333_KEYPAD_IRQ) + lm8333_key_handler(lm8333); + + return IRQ_HANDLED; +} + +static int lm8333_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + const struct lm8333_platform_data *pdata = + dev_get_platdata(&client->dev); + struct lm8333 *lm8333; + struct input_dev *input; + int err, active_time; + + if (!pdata) + return -EINVAL; + + active_time = pdata->active_time ?: 500; + if (active_time / 3 <= pdata->debounce_time / 3) { + dev_err(&client->dev, "Active time not big enough!\n"); + return -EINVAL; + } + + lm8333 = kzalloc(sizeof(*lm8333), GFP_KERNEL); + input = input_allocate_device(); + if (!lm8333 || !input) { + err = -ENOMEM; + goto free_mem; + } + + lm8333->client = client; + lm8333->input = input; + + input->name = client->name; + input->dev.parent = &client->dev; + input->id.bustype = BUS_I2C; + + input_set_capability(input, EV_MSC, MSC_SCAN); + + err = matrix_keypad_build_keymap(pdata->matrix_data, NULL, + LM8333_NUM_ROWS, LM8333_NUM_COLS, + lm8333->keycodes, input); + if (err) + goto free_mem; + + if (pdata->debounce_time) { + err = lm8333_write8(lm8333, LM8333_DEBOUNCE, + pdata->debounce_time / 3); + if (err) + dev_warn(&client->dev, "Unable to set debounce time\n"); + } + + if (pdata->active_time) { + err = lm8333_write8(lm8333, LM8333_ACTIVE, + pdata->active_time / 3); + if (err) + dev_warn(&client->dev, "Unable to set active time\n"); + } + + err = request_threaded_irq(client->irq, NULL, lm8333_irq_thread, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + "lm8333", lm8333); + if (err) + goto free_mem; + + err = input_register_device(input); + if (err) + goto free_irq; + + i2c_set_clientdata(client, lm8333); + return 0; + + free_irq: + free_irq(client->irq, lm8333); + free_mem: + input_free_device(input); + kfree(lm8333); + return err; +} + +static int lm8333_remove(struct i2c_client *client) +{ + struct lm8333 *lm8333 = i2c_get_clientdata(client); + + free_irq(client->irq, lm8333); + input_unregister_device(lm8333->input); + kfree(lm8333); + + return 0; +} + +static const struct i2c_device_id lm8333_id[] = { + { "lm8333", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, lm8333_id); + +static struct i2c_driver lm8333_driver = { + .driver = { + .name = "lm8333", + .owner = THIS_MODULE, + }, + .probe = lm8333_probe, + .remove = lm8333_remove, + .id_table = lm8333_id, +}; +module_i2c_driver(lm8333_driver); + +MODULE_AUTHOR("Wolfram Sang <w.sang@pengutronix.de>"); +MODULE_DESCRIPTION("LM8333 keyboard driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/input/keyboard/locomokbd.c b/drivers/input/keyboard/locomokbd.c index b1ab29861e1..c94d610b9d7 100644 --- a/drivers/input/keyboard/locomokbd.c +++ b/drivers/input/keyboard/locomokbd.c @@ -46,7 +46,7 @@ MODULE_LICENSE("GPL"); #define KEY_CENTER KEY_F15 static const unsigned char -locomokbd_keycode[LOCOMOKBD_NUMKEYS] __devinitconst = { +locomokbd_keycode[LOCOMOKBD_NUMKEYS] = { 0, KEY_ESC, KEY_ACTIVITY, 0, 0, 0, 0, 0, 0, 0, /* 0 - 9 */ 0, 0, 0, 0, 0, 0, 0, KEY_MENU, KEY_HOME, KEY_CONTACT, /* 10 - 19 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 20 - 29 */ @@ -236,7 +236,7 @@ static void locomokbd_close(struct input_dev *dev) locomo_writel(r, locomokbd->base + LOCOMO_KIC); } -static int __devinit locomokbd_probe(struct locomo_dev *dev) +static int locomokbd_probe(struct locomo_dev *dev) { struct locomokbd *locomokbd; struct input_dev *input_dev; @@ -321,7 +321,7 @@ static int __devinit locomokbd_probe(struct locomo_dev *dev) return err; } -static int __devexit locomokbd_remove(struct locomo_dev *dev) +static int locomokbd_remove(struct locomo_dev *dev) { struct locomokbd *locomokbd = locomo_get_drvdata(dev); @@ -345,7 +345,7 @@ static struct locomo_driver keyboard_driver = { }, .devid = LOCOMO_DEVID_KEYBOARD, .probe = locomokbd_probe, - .remove = __devexit_p(locomokbd_remove), + .remove = locomokbd_remove, }; static int __init locomokbd_init(void) diff --git a/drivers/input/keyboard/lpc32xx-keys.c b/drivers/input/keyboard/lpc32xx-keys.c new file mode 100644 index 00000000000..8b1b01361ec --- /dev/null +++ b/drivers/input/keyboard/lpc32xx-keys.c @@ -0,0 +1,395 @@ +/* + * NXP LPC32xx SoC Key Scan Interface + * + * Authors: + * Kevin Wells <kevin.wells@nxp.com> + * Roland Stigge <stigge@antcom.de> + * + * Copyright (C) 2010 NXP Semiconductors + * Copyright (C) 2012 Roland Stigge + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * + * This controller supports square key matrices from 1x1 up to 8x8 + */ + +#include <linux/module.h> +#include <linux/interrupt.h> +#include <linux/slab.h> +#include <linux/irq.h> +#include <linux/pm.h> +#include <linux/platform_device.h> +#include <linux/input.h> +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/input/matrix_keypad.h> + +#define DRV_NAME "lpc32xx_keys" + +/* + * Key scanner register offsets + */ +#define LPC32XX_KS_DEB(x) ((x) + 0x00) +#define LPC32XX_KS_STATE_COND(x) ((x) + 0x04) +#define LPC32XX_KS_IRQ(x) ((x) + 0x08) +#define LPC32XX_KS_SCAN_CTL(x) ((x) + 0x0C) +#define LPC32XX_KS_FAST_TST(x) ((x) + 0x10) +#define LPC32XX_KS_MATRIX_DIM(x) ((x) + 0x14) /* 1..8 */ +#define LPC32XX_KS_DATA(x, y) ((x) + 0x40 + ((y) << 2)) + +#define LPC32XX_KSCAN_DEB_NUM_DEB_PASS(n) ((n) & 0xFF) + +#define LPC32XX_KSCAN_SCOND_IN_IDLE 0x0 +#define LPC32XX_KSCAN_SCOND_IN_SCANONCE 0x1 +#define LPC32XX_KSCAN_SCOND_IN_IRQGEN 0x2 +#define LPC32XX_KSCAN_SCOND_IN_SCAN_MATRIX 0x3 + +#define LPC32XX_KSCAN_IRQ_PENDING_CLR 0x1 + +#define LPC32XX_KSCAN_SCTRL_SCAN_DELAY(n) ((n) & 0xFF) + +#define LPC32XX_KSCAN_FTST_FORCESCANONCE 0x1 +#define LPC32XX_KSCAN_FTST_USE32K_CLK 0x2 + +#define LPC32XX_KSCAN_MSEL_SELECT(n) ((n) & 0xF) + +struct lpc32xx_kscan_drv { + struct input_dev *input; + struct clk *clk; + struct resource *iores; + void __iomem *kscan_base; + unsigned int irq; + + u32 matrix_sz; /* Size of matrix in XxY, ie. 3 = 3x3 */ + u32 deb_clks; /* Debounce clocks (based on 32KHz clock) */ + u32 scan_delay; /* Scan delay (based on 32KHz clock) */ + + unsigned short *keymap; /* Pointer to key map for the scan matrix */ + unsigned int row_shift; + + u8 lastkeystates[8]; +}; + +static void lpc32xx_mod_states(struct lpc32xx_kscan_drv *kscandat, int col) +{ + struct input_dev *input = kscandat->input; + unsigned row, changed, scancode, keycode; + u8 key; + + key = readl(LPC32XX_KS_DATA(kscandat->kscan_base, col)); + changed = key ^ kscandat->lastkeystates[col]; + kscandat->lastkeystates[col] = key; + + for (row = 0; changed; row++, changed >>= 1) { + if (changed & 1) { + /* Key state changed, signal an event */ + scancode = MATRIX_SCAN_CODE(row, col, + kscandat->row_shift); + keycode = kscandat->keymap[scancode]; + input_event(input, EV_MSC, MSC_SCAN, scancode); + input_report_key(input, keycode, key & (1 << row)); + } + } +} + +static irqreturn_t lpc32xx_kscan_irq(int irq, void *dev_id) +{ + struct lpc32xx_kscan_drv *kscandat = dev_id; + int i; + + for (i = 0; i < kscandat->matrix_sz; i++) + lpc32xx_mod_states(kscandat, i); + + writel(1, LPC32XX_KS_IRQ(kscandat->kscan_base)); + + input_sync(kscandat->input); + + return IRQ_HANDLED; +} + +static int lpc32xx_kscan_open(struct input_dev *dev) +{ + struct lpc32xx_kscan_drv *kscandat = input_get_drvdata(dev); + int error; + + error = clk_prepare_enable(kscandat->clk); + if (error) + return error; + + writel(1, LPC32XX_KS_IRQ(kscandat->kscan_base)); + + return 0; +} + +static void lpc32xx_kscan_close(struct input_dev *dev) +{ + struct lpc32xx_kscan_drv *kscandat = input_get_drvdata(dev); + + writel(1, LPC32XX_KS_IRQ(kscandat->kscan_base)); + clk_disable_unprepare(kscandat->clk); +} + +static int lpc32xx_parse_dt(struct device *dev, + struct lpc32xx_kscan_drv *kscandat) +{ + struct device_node *np = dev->of_node; + u32 rows = 0, columns = 0; + int err; + + err = matrix_keypad_parse_of_params(dev, &rows, &columns); + if (err) + return err; + if (rows != columns) { + dev_err(dev, "rows and columns must be equal!\n"); + return -EINVAL; + } + + kscandat->matrix_sz = rows; + kscandat->row_shift = get_count_order(columns); + + of_property_read_u32(np, "nxp,debounce-delay-ms", &kscandat->deb_clks); + of_property_read_u32(np, "nxp,scan-delay-ms", &kscandat->scan_delay); + if (!kscandat->deb_clks || !kscandat->scan_delay) { + dev_err(dev, "debounce or scan delay not specified\n"); + return -EINVAL; + } + + return 0; +} + +static int lpc32xx_kscan_probe(struct platform_device *pdev) +{ + struct lpc32xx_kscan_drv *kscandat; + struct input_dev *input; + struct resource *res; + size_t keymap_size; + int error; + int irq; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "failed to get platform I/O memory\n"); + return -EINVAL; + } + + irq = platform_get_irq(pdev, 0); + if (irq < 0 || irq >= NR_IRQS) { + dev_err(&pdev->dev, "failed to get platform irq\n"); + return -EINVAL; + } + + kscandat = kzalloc(sizeof(struct lpc32xx_kscan_drv), GFP_KERNEL); + if (!kscandat) { + dev_err(&pdev->dev, "failed to allocate memory\n"); + return -ENOMEM; + } + + error = lpc32xx_parse_dt(&pdev->dev, kscandat); + if (error) { + dev_err(&pdev->dev, "failed to parse device tree\n"); + goto err_free_mem; + } + + keymap_size = sizeof(kscandat->keymap[0]) * + (kscandat->matrix_sz << kscandat->row_shift); + kscandat->keymap = kzalloc(keymap_size, GFP_KERNEL); + if (!kscandat->keymap) { + dev_err(&pdev->dev, "could not allocate memory for keymap\n"); + error = -ENOMEM; + goto err_free_mem; + } + + kscandat->input = input = input_allocate_device(); + if (!input) { + dev_err(&pdev->dev, "failed to allocate input device\n"); + error = -ENOMEM; + goto err_free_keymap; + } + + /* Setup key input */ + input->name = pdev->name; + input->phys = "lpc32xx/input0"; + input->id.vendor = 0x0001; + input->id.product = 0x0001; + input->id.version = 0x0100; + input->open = lpc32xx_kscan_open; + input->close = lpc32xx_kscan_close; + input->dev.parent = &pdev->dev; + + input_set_capability(input, EV_MSC, MSC_SCAN); + + error = matrix_keypad_build_keymap(NULL, NULL, + kscandat->matrix_sz, + kscandat->matrix_sz, + kscandat->keymap, kscandat->input); + if (error) { + dev_err(&pdev->dev, "failed to build keymap\n"); + goto err_free_input; + } + + input_set_drvdata(kscandat->input, kscandat); + + kscandat->iores = request_mem_region(res->start, resource_size(res), + pdev->name); + if (!kscandat->iores) { + dev_err(&pdev->dev, "failed to request I/O memory\n"); + error = -EBUSY; + goto err_free_input; + } + + kscandat->kscan_base = ioremap(kscandat->iores->start, + resource_size(kscandat->iores)); + if (!kscandat->kscan_base) { + dev_err(&pdev->dev, "failed to remap I/O memory\n"); + error = -EBUSY; + goto err_release_memregion; + } + + /* Get the key scanner clock */ + kscandat->clk = clk_get(&pdev->dev, NULL); + if (IS_ERR(kscandat->clk)) { + dev_err(&pdev->dev, "failed to get clock\n"); + error = PTR_ERR(kscandat->clk); + goto err_unmap; + } + + /* Configure the key scanner */ + error = clk_prepare_enable(kscandat->clk); + if (error) + goto err_clk_put; + + writel(kscandat->deb_clks, LPC32XX_KS_DEB(kscandat->kscan_base)); + writel(kscandat->scan_delay, LPC32XX_KS_SCAN_CTL(kscandat->kscan_base)); + writel(LPC32XX_KSCAN_FTST_USE32K_CLK, + LPC32XX_KS_FAST_TST(kscandat->kscan_base)); + writel(kscandat->matrix_sz, + LPC32XX_KS_MATRIX_DIM(kscandat->kscan_base)); + writel(1, LPC32XX_KS_IRQ(kscandat->kscan_base)); + clk_disable_unprepare(kscandat->clk); + + error = request_irq(irq, lpc32xx_kscan_irq, 0, pdev->name, kscandat); + if (error) { + dev_err(&pdev->dev, "failed to request irq\n"); + goto err_clk_put; + } + + error = input_register_device(kscandat->input); + if (error) { + dev_err(&pdev->dev, "failed to register input device\n"); + goto err_free_irq; + } + + platform_set_drvdata(pdev, kscandat); + return 0; + +err_free_irq: + free_irq(irq, kscandat); +err_clk_put: + clk_put(kscandat->clk); +err_unmap: + iounmap(kscandat->kscan_base); +err_release_memregion: + release_mem_region(kscandat->iores->start, + resource_size(kscandat->iores)); +err_free_input: + input_free_device(kscandat->input); +err_free_keymap: + kfree(kscandat->keymap); +err_free_mem: + kfree(kscandat); + + return error; +} + +static int lpc32xx_kscan_remove(struct platform_device *pdev) +{ + struct lpc32xx_kscan_drv *kscandat = platform_get_drvdata(pdev); + + free_irq(platform_get_irq(pdev, 0), kscandat); + clk_put(kscandat->clk); + iounmap(kscandat->kscan_base); + release_mem_region(kscandat->iores->start, + resource_size(kscandat->iores)); + input_unregister_device(kscandat->input); + kfree(kscandat->keymap); + kfree(kscandat); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int lpc32xx_kscan_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct lpc32xx_kscan_drv *kscandat = platform_get_drvdata(pdev); + struct input_dev *input = kscandat->input; + + mutex_lock(&input->mutex); + + if (input->users) { + /* Clear IRQ and disable clock */ + writel(1, LPC32XX_KS_IRQ(kscandat->kscan_base)); + clk_disable_unprepare(kscandat->clk); + } + + mutex_unlock(&input->mutex); + return 0; +} + +static int lpc32xx_kscan_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct lpc32xx_kscan_drv *kscandat = platform_get_drvdata(pdev); + struct input_dev *input = kscandat->input; + int retval = 0; + + mutex_lock(&input->mutex); + + if (input->users) { + /* Enable clock and clear IRQ */ + retval = clk_prepare_enable(kscandat->clk); + if (retval == 0) + writel(1, LPC32XX_KS_IRQ(kscandat->kscan_base)); + } + + mutex_unlock(&input->mutex); + return retval; +} +#endif + +static SIMPLE_DEV_PM_OPS(lpc32xx_kscan_pm_ops, lpc32xx_kscan_suspend, + lpc32xx_kscan_resume); + +static const struct of_device_id lpc32xx_kscan_match[] = { + { .compatible = "nxp,lpc3220-key" }, + {}, +}; +MODULE_DEVICE_TABLE(of, lpc32xx_kscan_match); + +static struct platform_driver lpc32xx_kscan_driver = { + .probe = lpc32xx_kscan_probe, + .remove = lpc32xx_kscan_remove, + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + .pm = &lpc32xx_kscan_pm_ops, + .of_match_table = lpc32xx_kscan_match, + } +}; + +module_platform_driver(lpc32xx_kscan_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Kevin Wells <kevin.wells@nxp.com>"); +MODULE_AUTHOR("Roland Stigge <stigge@antcom.de>"); +MODULE_DESCRIPTION("Key scanner driver for LPC32XX devices"); diff --git a/drivers/input/keyboard/matrix_keypad.c b/drivers/input/keyboard/matrix_keypad.c index b02e4268e18..8d2e19e81e1 100644 --- a/drivers/input/keyboard/matrix_keypad.c +++ b/drivers/input/keyboard/matrix_keypad.c @@ -14,7 +14,6 @@ #include <linux/types.h> #include <linux/delay.h> #include <linux/platform_device.h> -#include <linux/init.h> #include <linux/input.h> #include <linux/irq.h> #include <linux/interrupt.h> @@ -23,11 +22,13 @@ #include <linux/gpio.h> #include <linux/input/matrix_keypad.h> #include <linux/slab.h> +#include <linux/of.h> +#include <linux/of_gpio.h> +#include <linux/of_platform.h> struct matrix_keypad { const struct matrix_keypad_platform_data *pdata; struct input_dev *input_dev; - unsigned short *keycodes; unsigned int row_shift; DECLARE_BITMAP(disabled_gpios, MATRIX_MAX_ROWS); @@ -117,6 +118,7 @@ static void matrix_keypad_scan(struct work_struct *work) struct matrix_keypad *keypad = container_of(work, struct matrix_keypad, work.work); struct input_dev *input_dev = keypad->input_dev; + const unsigned short *keycodes = input_dev->keycode; const struct matrix_keypad_platform_data *pdata = keypad->pdata; uint32_t new_state[MATRIX_MAX_COLS]; int row, col, code; @@ -152,7 +154,7 @@ static void matrix_keypad_scan(struct work_struct *work) 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], + keycodes[code], new_state[col] & (1 << row)); } } @@ -224,7 +226,7 @@ static void matrix_keypad_stop(struct input_dev *dev) disable_row_irqs(keypad); } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP static void matrix_keypad_enable_wakeup(struct matrix_keypad *keypad) { const struct matrix_keypad_platform_data *pdata = keypad->pdata; @@ -293,16 +295,16 @@ static int matrix_keypad_resume(struct device *dev) return 0; } - -static const SIMPLE_DEV_PM_OPS(matrix_keypad_pm_ops, - matrix_keypad_suspend, matrix_keypad_resume); #endif -static int __devinit init_matrix_gpio(struct platform_device *pdev, - struct matrix_keypad *keypad) +static SIMPLE_DEV_PM_OPS(matrix_keypad_pm_ops, + matrix_keypad_suspend, matrix_keypad_resume); + +static int matrix_keypad_init_gpio(struct platform_device *pdev, + struct matrix_keypad *keypad) { const struct matrix_keypad_platform_data *pdata = keypad->pdata; - int i, err = -EINVAL; + int i, err; /* initialized strobe lines as outputs, activated */ for (i = 0; i < pdata->num_col_gpios; i++) { @@ -343,14 +345,12 @@ static int __devinit init_matrix_gpio(struct platform_device *pdev, for (i = 0; i < pdata->num_row_gpios; i++) { err = request_irq(gpio_to_irq(pdata->row_gpios[i]), matrix_keypad_interrupt, - IRQF_DISABLED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "matrix-keypad", keypad); if (err) { dev_err(&pdev->dev, - "Unable to acquire interrupt " - "for GPIO line %i\n", + "Unable to acquire interrupt for GPIO line %i\n", pdata->row_gpios[i]); goto err_free_irqs; } @@ -376,44 +376,123 @@ err_free_cols: return err; } -static int __devinit matrix_keypad_probe(struct platform_device *pdev) +static void matrix_keypad_free_gpio(struct matrix_keypad *keypad) +{ + const struct matrix_keypad_platform_data *pdata = keypad->pdata; + int i; + + if (pdata->clustered_irq > 0) { + free_irq(pdata->clustered_irq, keypad); + } else { + for (i = 0; i < pdata->num_row_gpios; i++) + free_irq(gpio_to_irq(pdata->row_gpios[i]), keypad); + } + + for (i = 0; i < pdata->num_row_gpios; i++) + gpio_free(pdata->row_gpios[i]); + + for (i = 0; i < pdata->num_col_gpios; i++) + gpio_free(pdata->col_gpios[i]); +} + +#ifdef CONFIG_OF +static struct matrix_keypad_platform_data * +matrix_keypad_parse_dt(struct device *dev) +{ + struct matrix_keypad_platform_data *pdata; + struct device_node *np = dev->of_node; + unsigned int *gpios; + int i, nrow, ncol; + + if (!np) { + dev_err(dev, "device lacks DT data\n"); + return ERR_PTR(-ENODEV); + } + + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) { + dev_err(dev, "could not allocate memory for platform data\n"); + return ERR_PTR(-ENOMEM); + } + + pdata->num_row_gpios = nrow = of_gpio_named_count(np, "row-gpios"); + pdata->num_col_gpios = ncol = of_gpio_named_count(np, "col-gpios"); + if (nrow <= 0 || ncol <= 0) { + dev_err(dev, "number of keypad rows/columns not specified\n"); + return ERR_PTR(-EINVAL); + } + + if (of_get_property(np, "linux,no-autorepeat", NULL)) + pdata->no_autorepeat = true; + if (of_get_property(np, "linux,wakeup", NULL)) + pdata->wakeup = true; + if (of_get_property(np, "gpio-activelow", NULL)) + pdata->active_low = true; + + of_property_read_u32(np, "debounce-delay-ms", &pdata->debounce_ms); + of_property_read_u32(np, "col-scan-delay-us", + &pdata->col_scan_delay_us); + + gpios = devm_kzalloc(dev, + sizeof(unsigned int) * + (pdata->num_row_gpios + pdata->num_col_gpios), + GFP_KERNEL); + if (!gpios) { + dev_err(dev, "could not allocate memory for gpios\n"); + return ERR_PTR(-ENOMEM); + } + + for (i = 0; i < pdata->num_row_gpios; i++) + gpios[i] = of_get_named_gpio(np, "row-gpios", i); + + for (i = 0; i < pdata->num_col_gpios; i++) + gpios[pdata->num_row_gpios + i] = + of_get_named_gpio(np, "col-gpios", i); + + pdata->row_gpios = gpios; + pdata->col_gpios = &gpios[pdata->num_row_gpios]; + + return pdata; +} +#else +static inline struct matrix_keypad_platform_data * +matrix_keypad_parse_dt(struct device *dev) +{ + dev_err(dev, "no platform data defined\n"); + + return ERR_PTR(-EINVAL); +} +#endif + +static int matrix_keypad_probe(struct platform_device *pdev) { const struct matrix_keypad_platform_data *pdata; - const struct matrix_keymap_data *keymap_data; struct matrix_keypad *keypad; struct input_dev *input_dev; - unsigned short *keycodes; - unsigned int row_shift; int err; - pdata = pdev->dev.platform_data; + pdata = dev_get_platdata(&pdev->dev); if (!pdata) { - dev_err(&pdev->dev, "no platform data defined\n"); - return -EINVAL; - } - - keymap_data = pdata->keymap_data; - if (!keymap_data) { + pdata = matrix_keypad_parse_dt(&pdev->dev); + if (IS_ERR(pdata)) { + dev_err(&pdev->dev, "no platform data defined\n"); + return PTR_ERR(pdata); + } + } else if (!pdata->keymap_data) { dev_err(&pdev->dev, "no keymap data defined\n"); return -EINVAL; } - row_shift = get_count_order(pdata->num_col_gpios); - keypad = kzalloc(sizeof(struct matrix_keypad), GFP_KERNEL); - keycodes = kzalloc((pdata->num_row_gpios << row_shift) * - sizeof(*keycodes), - GFP_KERNEL); input_dev = input_allocate_device(); - if (!keypad || !keycodes || !input_dev) { + if (!keypad || !input_dev) { err = -ENOMEM; goto err_free_mem; } keypad->input_dev = input_dev; keypad->pdata = pdata; - keypad->keycodes = keycodes; - keypad->row_shift = row_shift; + keypad->row_shift = get_count_order(pdata->num_col_gpios); keypad->stopped = true; INIT_DELAYED_WORK(&keypad->work, matrix_keypad_scan); spin_lock_init(&keypad->lock); @@ -421,95 +500,76 @@ static int __devinit matrix_keypad_probe(struct platform_device *pdev) input_dev->name = pdev->name; input_dev->id.bustype = BUS_HOST; input_dev->dev.parent = &pdev->dev; - input_dev->evbit[0] = BIT_MASK(EV_KEY); - if (!pdata->no_autorepeat) - input_dev->evbit[0] |= BIT_MASK(EV_REP); input_dev->open = matrix_keypad_start; input_dev->close = matrix_keypad_stop; - input_dev->keycode = keycodes; - input_dev->keycodesize = sizeof(*keycodes); - input_dev->keycodemax = pdata->num_row_gpios << row_shift; - - matrix_keypad_build_keymap(keymap_data, row_shift, - input_dev->keycode, input_dev->keybit); + err = matrix_keypad_build_keymap(pdata->keymap_data, NULL, + pdata->num_row_gpios, + pdata->num_col_gpios, + NULL, input_dev); + if (err) { + dev_err(&pdev->dev, "failed to build keymap\n"); + goto err_free_mem; + } + if (!pdata->no_autorepeat) + __set_bit(EV_REP, input_dev->evbit); input_set_capability(input_dev, EV_MSC, MSC_SCAN); input_set_drvdata(input_dev, keypad); - err = init_matrix_gpio(pdev, keypad); + err = matrix_keypad_init_gpio(pdev, keypad); if (err) goto err_free_mem; err = input_register_device(keypad->input_dev); if (err) - goto err_free_mem; + goto err_free_gpio; device_init_wakeup(&pdev->dev, pdata->wakeup); platform_set_drvdata(pdev, keypad); return 0; +err_free_gpio: + matrix_keypad_free_gpio(keypad); err_free_mem: input_free_device(input_dev); - kfree(keycodes); kfree(keypad); return err; } -static int __devexit matrix_keypad_remove(struct platform_device *pdev) +static int matrix_keypad_remove(struct platform_device *pdev) { struct matrix_keypad *keypad = platform_get_drvdata(pdev); - const struct matrix_keypad_platform_data *pdata = keypad->pdata; - int i; device_init_wakeup(&pdev->dev, 0); - if (pdata->clustered_irq > 0) { - free_irq(pdata->clustered_irq, keypad); - } else { - for (i = 0; i < pdata->num_row_gpios; i++) - free_irq(gpio_to_irq(pdata->row_gpios[i]), keypad); - } - - for (i = 0; i < pdata->num_row_gpios; i++) - gpio_free(pdata->row_gpios[i]); - - for (i = 0; i < pdata->num_col_gpios; i++) - gpio_free(pdata->col_gpios[i]); - + matrix_keypad_free_gpio(keypad); input_unregister_device(keypad->input_dev); - platform_set_drvdata(pdev, NULL); - kfree(keypad->keycodes); kfree(keypad); return 0; } +#ifdef CONFIG_OF +static const struct of_device_id matrix_keypad_dt_match[] = { + { .compatible = "gpio-matrix-keypad" }, + { } +}; +MODULE_DEVICE_TABLE(of, matrix_keypad_dt_match); +#endif + static struct platform_driver matrix_keypad_driver = { .probe = matrix_keypad_probe, - .remove = __devexit_p(matrix_keypad_remove), + .remove = matrix_keypad_remove, .driver = { .name = "matrix-keypad", .owner = THIS_MODULE, -#ifdef CONFIG_PM .pm = &matrix_keypad_pm_ops, -#endif + .of_match_table = of_match_ptr(matrix_keypad_dt_match), }, }; - -static int __init matrix_keypad_init(void) -{ - return platform_driver_register(&matrix_keypad_driver); -} - -static void __exit matrix_keypad_exit(void) -{ - platform_driver_unregister(&matrix_keypad_driver); -} - -module_init(matrix_keypad_init); -module_exit(matrix_keypad_exit); +module_platform_driver(matrix_keypad_driver); MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>"); MODULE_DESCRIPTION("GPIO Driven Matrix Keypad Driver"); diff --git a/drivers/input/keyboard/max7359_keypad.c b/drivers/input/keyboard/max7359_keypad.c index 5afe35ad24d..430b5453972 100644 --- a/drivers/input/keyboard/max7359_keypad.c +++ b/drivers/input/keyboard/max7359_keypad.c @@ -179,10 +179,11 @@ static void max7359_initialize(struct i2c_client *client) max7359_fall_deepsleep(client); } -static int __devinit max7359_probe(struct i2c_client *client, +static int max7359_probe(struct i2c_client *client, const struct i2c_device_id *id) { - const struct matrix_keymap_data *keymap_data = client->dev.platform_data; + const struct matrix_keymap_data *keymap_data = + dev_get_platdata(&client->dev); struct max7359_keypad *keypad; struct input_dev *input_dev; int ret; @@ -260,7 +261,7 @@ failed_free_mem: return error; } -static int __devexit max7359_remove(struct i2c_client *client) +static int max7359_remove(struct i2c_client *client) { struct max7359_keypad *keypad = i2c_get_clientdata(client); @@ -271,7 +272,7 @@ static int __devexit max7359_remove(struct i2c_client *client) return 0; } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP static int max7359_suspend(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); @@ -312,21 +313,11 @@ static struct i2c_driver max7359_i2c_driver = { .pm = &max7359_pm, }, .probe = max7359_probe, - .remove = __devexit_p(max7359_remove), + .remove = max7359_remove, .id_table = max7359_ids, }; -static int __init max7359_init(void) -{ - return i2c_add_driver(&max7359_i2c_driver); -} -module_init(max7359_init); - -static void __exit max7359_exit(void) -{ - i2c_del_driver(&max7359_i2c_driver); -} -module_exit(max7359_exit); +module_i2c_driver(max7359_i2c_driver); MODULE_AUTHOR("Kim Kyuwon <q1.kim@samsung.com>"); MODULE_DESCRIPTION("MAX7359 Key Switch Controller Driver"); diff --git a/drivers/input/keyboard/mcs_touchkey.c b/drivers/input/keyboard/mcs_touchkey.c index af1aab324a4..375b05ca8e2 100644 --- a/drivers/input/keyboard/mcs_touchkey.c +++ b/drivers/input/keyboard/mcs_touchkey.c @@ -12,7 +12,6 @@ */ #include <linux/module.h> -#include <linux/init.h> #include <linux/i2c.h> #include <linux/i2c/mcs.h> #include <linux/interrupt.h> @@ -97,7 +96,7 @@ static irqreturn_t mcs_touchkey_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static int __devinit mcs_touchkey_probe(struct i2c_client *client, +static int mcs_touchkey_probe(struct i2c_client *client, const struct i2c_device_id *id) { const struct mcs_platform_data *pdata; @@ -108,7 +107,7 @@ static int __devinit mcs_touchkey_probe(struct i2c_client *client, int error; int i; - pdata = client->dev.platform_data; + pdata = dev_get_platdata(&client->dev); if (!pdata) { dev_err(&client->dev, "no platform data defined\n"); return -EINVAL; @@ -148,7 +147,7 @@ static int __devinit mcs_touchkey_probe(struct i2c_client *client, } dev_info(&client->dev, "Firmware version: %d\n", fw_ver); - input_dev->name = "MELPAS MCS Touchkey"; + input_dev->name = "MELFAS MCS Touchkey"; input_dev->id.bustype = BUS_I2C; input_dev->dev.parent = &client->dev; input_dev->evbit[0] = BIT_MASK(EV_KEY); @@ -178,7 +177,8 @@ static int __devinit mcs_touchkey_probe(struct i2c_client *client, } error = request_threaded_irq(client->irq, NULL, mcs_touchkey_interrupt, - IRQF_TRIGGER_FALLING, client->dev.driver->name, data); + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + client->dev.driver->name, data); if (error) { dev_err(&client->dev, "Failed to register interrupt\n"); goto err_free_mem; @@ -199,7 +199,7 @@ err_free_mem: return error; } -static int __devexit mcs_touchkey_remove(struct i2c_client *client) +static int mcs_touchkey_remove(struct i2c_client *client) { struct mcs_touchkey_data *data = i2c_get_clientdata(client); @@ -269,23 +269,12 @@ static struct i2c_driver mcs_touchkey_driver = { .pm = &mcs_touchkey_pm_ops, }, .probe = mcs_touchkey_probe, - .remove = __devexit_p(mcs_touchkey_remove), + .remove = mcs_touchkey_remove, .shutdown = mcs_touchkey_shutdown, .id_table = mcs_touchkey_id, }; -static int __init mcs_touchkey_init(void) -{ - return i2c_add_driver(&mcs_touchkey_driver); -} - -static void __exit mcs_touchkey_exit(void) -{ - i2c_del_driver(&mcs_touchkey_driver); -} - -module_init(mcs_touchkey_init); -module_exit(mcs_touchkey_exit); +module_i2c_driver(mcs_touchkey_driver); /* Module information */ MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>"); diff --git a/drivers/input/keyboard/mpr121_touchkey.c b/drivers/input/keyboard/mpr121_touchkey.c index 0a9e8119488..009c82256e8 100644 --- a/drivers/input/keyboard/mpr121_touchkey.c +++ b/drivers/input/keyboard/mpr121_touchkey.c @@ -13,7 +13,6 @@ */ #include <linux/module.h> -#include <linux/init.h> #include <linux/input.h> #include <linux/i2c.h> #include <linux/slab.h> @@ -43,14 +42,15 @@ * enabled capacitance sensing inputs and its run/suspend mode. */ #define ELECTRODE_CONF_ADDR 0x5e +#define ELECTRODE_CONF_QUICK_CHARGE 0x80 #define AUTO_CONFIG_CTRL_ADDR 0x7b #define AUTO_CONFIG_USL_ADDR 0x7d #define AUTO_CONFIG_LSL_ADDR 0x7e #define AUTO_CONFIG_TL_ADDR 0x7f /* Threshold of touch/release trigger */ -#define TOUCH_THRESHOLD 0x0f -#define RELEASE_THRESHOLD 0x0a +#define TOUCH_THRESHOLD 0x08 +#define RELEASE_THRESHOLD 0x05 /* Masks for touch and release triggers */ #define TOUCH_STATUS_MASK 0xfff /* MPR121 has 12 keys */ @@ -70,7 +70,7 @@ struct mpr121_init_register { u8 val; }; -static const struct mpr121_init_register init_reg_table[] __devinitconst = { +static const struct mpr121_init_register init_reg_table[] = { { MHD_RISING_ADDR, 0x1 }, { NHD_RISING_ADDR, 0x1 }, { MHD_FALLING_ADDR, 0x1 }, @@ -122,12 +122,12 @@ out: return IRQ_HANDLED; } -static int __devinit mpr121_phys_init(const struct mpr121_platform_data *pdata, +static int mpr121_phys_init(const struct mpr121_platform_data *pdata, struct mpr121_touchkey *mpr121, struct i2c_client *client) { const struct mpr121_init_register *reg; - unsigned char usl, lsl, tl; + unsigned char usl, lsl, tl, eleconf; int i, t, vdd, ret; /* Set up touch/release threshold for ele0-ele11 */ @@ -163,8 +163,15 @@ static int __devinit mpr121_phys_init(const struct mpr121_platform_data *pdata, ret = i2c_smbus_write_byte_data(client, AUTO_CONFIG_USL_ADDR, usl); ret |= i2c_smbus_write_byte_data(client, AUTO_CONFIG_LSL_ADDR, lsl); ret |= i2c_smbus_write_byte_data(client, AUTO_CONFIG_TL_ADDR, tl); + + /* + * Quick charge bit will let the capacitive charge to ready + * state quickly, or the buttons may not function after system + * boot. + */ + eleconf = mpr121->keycount | ELECTRODE_CONF_QUICK_CHARGE; ret |= i2c_smbus_write_byte_data(client, ELECTRODE_CONF_ADDR, - mpr121->keycount); + eleconf); if (ret != 0) goto err_i2c_write; @@ -177,10 +184,11 @@ err_i2c_write: return ret; } -static int __devinit mpr_touchkey_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int mpr_touchkey_probe(struct i2c_client *client, + const struct i2c_device_id *id) { - const struct mpr121_platform_data *pdata = client->dev.platform_data; + const struct mpr121_platform_data *pdata = + dev_get_platdata(&client->dev); struct mpr121_touchkey *mpr121; struct input_dev *input_dev; int error; @@ -240,7 +248,7 @@ static int __devinit mpr_touchkey_probe(struct i2c_client *client, error = request_threaded_irq(client->irq, NULL, mpr_touchkey_interrupt, - IRQF_TRIGGER_FALLING, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, client->dev.driver->name, mpr121); if (error) { dev_err(&client->dev, "Failed to register interrupt\n"); @@ -264,7 +272,7 @@ err_free_mem: return error; } -static int __devexit mpr_touchkey_remove(struct i2c_client *client) +static int mpr_touchkey_remove(struct i2c_client *client) { struct mpr121_touchkey *mpr121 = i2c_get_clientdata(client); @@ -319,20 +327,10 @@ static struct i2c_driver mpr_touchkey_driver = { }, .id_table = mpr121_id, .probe = mpr_touchkey_probe, - .remove = __devexit_p(mpr_touchkey_remove), + .remove = mpr_touchkey_remove, }; -static int __init mpr_touchkey_init(void) -{ - return i2c_add_driver(&mpr_touchkey_driver); -} -module_init(mpr_touchkey_init); - -static void __exit mpr_touchkey_exit(void) -{ - i2c_del_driver(&mpr_touchkey_driver); -} -module_exit(mpr_touchkey_exit); +module_i2c_driver(mpr_touchkey_driver); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Zhang Jiejing <jiejing.zhang@freescale.com>"); diff --git a/drivers/input/keyboard/newtonkbd.c b/drivers/input/keyboard/newtonkbd.c index 48d1cab0aa1..20f04437799 100644 --- a/drivers/input/keyboard/newtonkbd.c +++ b/drivers/input/keyboard/newtonkbd.c @@ -29,7 +29,6 @@ #include <linux/slab.h> #include <linux/module.h> #include <linux/input.h> -#include <linux/init.h> #include <linux/serio.h> #define DRIVER_DESC "Newton keyboard driver" @@ -166,15 +165,4 @@ static struct serio_driver nkbd_drv = { .disconnect = nkbd_disconnect, }; -static int __init nkbd_init(void) -{ - return serio_register_driver(&nkbd_drv); -} - -static void __exit nkbd_exit(void) -{ - serio_unregister_driver(&nkbd_drv); -} - -module_init(nkbd_init); -module_exit(nkbd_exit); +module_serio_driver(nkbd_drv); diff --git a/drivers/input/keyboard/nomadik-ske-keypad.c b/drivers/input/keyboard/nomadik-ske-keypad.c index 6e0f2309136..63332e2f862 100644 --- a/drivers/input/keyboard/nomadik-ske-keypad.c +++ b/drivers/input/keyboard/nomadik-ske-keypad.c @@ -18,8 +18,9 @@ #include <linux/input.h> #include <linux/slab.h> #include <linux/clk.h> +#include <linux/module.h> -#include <plat/ske.h> +#include <linux/platform_data/keypad-nomadik-ske.h> /* SKE_CR bits */ #define SKE_KPMLT (0x1 << 6) @@ -38,7 +39,8 @@ #define SKE_KPRISA (0x1 << 2) #define SKE_KEYPAD_ROW_SHIFT 3 -#define SKE_KPD_KEYMAP_SIZE (8 * 8) +#define SKE_KPD_NUM_ROWS 8 +#define SKE_KPD_NUM_COLS 8 /* keypad auto scan registers */ #define SKE_ASR0 0x20 @@ -47,6 +49,7 @@ #define SKE_ASR3 0x2C #define SKE_NUM_ASRX_REGISTERS (4) +#define KEY_PRESSED_DELAY 10 /** * struct ske_keypad - data structure used by keypad driver @@ -62,8 +65,9 @@ struct ske_keypad { void __iomem *reg_base; struct input_dev *input; const struct ske_keypad_platform_data *board; - unsigned short keymap[SKE_KPD_KEYMAP_SIZE]; + unsigned short keymap[SKE_KPD_NUM_ROWS * SKE_KPD_NUM_COLS]; struct clk *clk; + struct clk *pclk; spinlock_t ske_keypad_lock; }; @@ -87,10 +91,10 @@ static void ske_keypad_set_bits(struct ske_keypad *keypad, u16 addr, * * Enable Multi key press detection, auto scan mode */ -static int __devinit ske_keypad_chip_init(struct ske_keypad *keypad) +static int __init ske_keypad_chip_init(struct ske_keypad *keypad) { u32 value; - int timeout = 50; + int timeout = keypad->board->debounce_ms; /* check SKE_RIS to be 0 */ while ((readl(keypad->reg_base + SKE_RIS) != 0x00000000) && timeout--) @@ -133,12 +137,37 @@ static int __devinit ske_keypad_chip_init(struct ske_keypad *keypad) return 0; } -static void ske_keypad_read_data(struct ske_keypad *keypad) +static void ske_keypad_report(struct ske_keypad *keypad, u8 status, int col) { + int row = 0, code, pos; struct input_dev *input = keypad->input; - u16 status; - int col = 0, row = 0, code; - int ske_asr, ske_ris, key_pressed, i; + u32 ske_ris; + int key_pressed; + int num_of_rows; + + /* find out the row */ + num_of_rows = hweight8(status); + do { + pos = __ffs(status); + row = pos; + status &= ~(1 << pos); + + code = MATRIX_SCAN_CODE(row, col, SKE_KEYPAD_ROW_SHIFT); + ske_ris = readl(keypad->reg_base + SKE_RIS); + key_pressed = ske_ris & SKE_KPRISA; + + input_event(input, EV_MSC, MSC_SCAN, code); + input_report_key(input, keypad->keymap[code], key_pressed); + input_sync(input); + num_of_rows--; + } while (num_of_rows); +} + +static void ske_keypad_read_data(struct ske_keypad *keypad) +{ + u8 status; + int col = 0; + int ske_asr, i; /* * Read the auto scan registers @@ -152,44 +181,38 @@ static void ske_keypad_read_data(struct ske_keypad *keypad) if (!ske_asr) continue; - /* now that ASRx is zero, find out the column x and row y*/ - if (ske_asr & 0xff) { + /* now that ASRx is zero, find out the coloumn x and row y */ + status = ske_asr & 0xff; + if (status) { col = i * 2; - status = ske_asr & 0xff; - } else { + ske_keypad_report(keypad, status, col); + } + status = (ske_asr & 0xff00) >> 8; + if (status) { col = (i * 2) + 1; - status = (ske_asr & 0xff00) >> 8; + ske_keypad_report(keypad, status, col); } - - /* find out the row */ - row = __ffs(status); - - code = MATRIX_SCAN_CODE(row, col, SKE_KEYPAD_ROW_SHIFT); - ske_ris = readl(keypad->reg_base + SKE_RIS); - key_pressed = ske_ris & SKE_KPRISA; - - input_event(input, EV_MSC, MSC_SCAN, code); - input_report_key(input, keypad->keymap[code], key_pressed); - input_sync(input); } } static irqreturn_t ske_keypad_irq(int irq, void *dev_id) { struct ske_keypad *keypad = dev_id; - int retries = 20; + int timeout = keypad->board->debounce_ms; /* disable auto scan interrupt; mask the interrupt generated */ ske_keypad_set_bits(keypad, SKE_IMSC, ~SKE_KPIMA, 0x0); ske_keypad_set_bits(keypad, SKE_ICR, 0x0, SKE_KPICA); - while ((readl(keypad->reg_base + SKE_CR) & SKE_KPASON) && --retries) - msleep(5); + while ((readl(keypad->reg_base + SKE_CR) & SKE_KPASON) && --timeout) + cpu_relax(); - if (retries) { - /* SKEx registers are stable and can be read */ - ske_keypad_read_data(keypad); - } + /* SKEx registers are stable and can be read */ + ske_keypad_read_data(keypad); + + /* wait until raw interrupt is clear */ + while ((readl(keypad->reg_base + SKE_RIS)) && --timeout) + msleep(KEY_PRESSED_DELAY); /* enable auto scan interrupts */ ske_keypad_set_bits(keypad, SKE_IMSC, 0x0, SKE_KPIMA); @@ -197,9 +220,10 @@ static irqreturn_t ske_keypad_irq(int irq, void *dev_id) return IRQ_HANDLED; } -static int __devinit ske_keypad_probe(struct platform_device *pdev) +static int __init ske_keypad_probe(struct platform_device *pdev) { - const struct ske_keypad_platform_data *plat = pdev->dev.platform_data; + const struct ske_keypad_platform_data *plat = + dev_get_platdata(&pdev->dev); struct ske_keypad *keypad; struct input_dev *input; struct resource *res; @@ -249,31 +273,48 @@ static int __devinit ske_keypad_probe(struct platform_device *pdev) goto err_free_mem_region; } + keypad->pclk = clk_get(&pdev->dev, "apb_pclk"); + if (IS_ERR(keypad->pclk)) { + dev_err(&pdev->dev, "failed to get pclk\n"); + error = PTR_ERR(keypad->pclk); + goto err_iounmap; + } + keypad->clk = clk_get(&pdev->dev, NULL); if (IS_ERR(keypad->clk)) { dev_err(&pdev->dev, "failed to get clk\n"); error = PTR_ERR(keypad->clk); - goto err_iounmap; + goto err_pclk; } input->id.bustype = BUS_HOST; input->name = "ux500-ske-keypad"; input->dev.parent = &pdev->dev; - input->keycode = keypad->keymap; - input->keycodesize = sizeof(keypad->keymap[0]); - input->keycodemax = ARRAY_SIZE(keypad->keymap); + error = matrix_keypad_build_keymap(plat->keymap_data, NULL, + SKE_KPD_NUM_ROWS, SKE_KPD_NUM_COLS, + keypad->keymap, input); + if (error) { + dev_err(&pdev->dev, "Failed to build keymap\n"); + goto err_clk; + } input_set_capability(input, EV_MSC, MSC_SCAN); - - __set_bit(EV_KEY, input->evbit); if (!plat->no_autorepeat) __set_bit(EV_REP, input->evbit); - matrix_keypad_build_keymap(plat->keymap_data, SKE_KEYPAD_ROW_SHIFT, - input->keycode, input->keybit); + error = clk_prepare_enable(keypad->pclk); + if (error) { + dev_err(&pdev->dev, "Failed to prepare/enable pclk\n"); + goto err_clk; + } + + error = clk_prepare_enable(keypad->clk); + if (error) { + dev_err(&pdev->dev, "Failed to prepare/enable clk\n"); + goto err_pclk_disable; + } - clk_enable(keypad->clk); /* go through board initialization helpers */ if (keypad->board->init) @@ -309,8 +350,13 @@ static int __devinit ske_keypad_probe(struct platform_device *pdev) err_free_irq: free_irq(keypad->irq, keypad); err_clk_disable: - clk_disable(keypad->clk); + clk_disable_unprepare(keypad->clk); +err_pclk_disable: + clk_disable_unprepare(keypad->pclk); +err_clk: clk_put(keypad->clk); +err_pclk: + clk_put(keypad->pclk); err_iounmap: iounmap(keypad->reg_base); err_free_mem_region: @@ -321,7 +367,7 @@ err_free_mem: return error; } -static int __devexit ske_keypad_remove(struct platform_device *pdev) +static int ske_keypad_remove(struct platform_device *pdev) { struct ske_keypad *keypad = platform_get_drvdata(pdev); struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -330,7 +376,7 @@ static int __devexit ske_keypad_remove(struct platform_device *pdev) input_unregister_device(keypad->input); - clk_disable(keypad->clk); + clk_disable_unprepare(keypad->clk); clk_put(keypad->clk); if (keypad->board->exit) @@ -343,7 +389,7 @@ static int __devexit ske_keypad_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP static int ske_keypad_suspend(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); @@ -371,36 +417,21 @@ static int ske_keypad_resume(struct device *dev) return 0; } - -static const struct dev_pm_ops ske_keypad_dev_pm_ops = { - .suspend = ske_keypad_suspend, - .resume = ske_keypad_resume, -}; #endif -struct platform_driver ske_keypad_driver = { +static SIMPLE_DEV_PM_OPS(ske_keypad_dev_pm_ops, + ske_keypad_suspend, ske_keypad_resume); + +static struct platform_driver ske_keypad_driver = { .driver = { .name = "nmk-ske-keypad", .owner = THIS_MODULE, -#ifdef CONFIG_PM .pm = &ske_keypad_dev_pm_ops, -#endif }, - .probe = ske_keypad_probe, - .remove = __devexit_p(ske_keypad_remove), + .remove = ske_keypad_remove, }; -static int __init ske_keypad_init(void) -{ - return platform_driver_probe(&ske_keypad_driver, ske_keypad_probe); -} -module_init(ske_keypad_init); - -static void __exit ske_keypad_exit(void) -{ - platform_driver_unregister(&ske_keypad_driver); -} -module_exit(ske_keypad_exit); +module_platform_driver_probe(ske_keypad_driver, ske_keypad_probe); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Naveen Kumar <naveen.gaddipati@stericsson.com> / Sundar Iyer <sundar.iyer@stericsson.com>"); diff --git a/drivers/input/keyboard/nspire-keypad.c b/drivers/input/keyboard/nspire-keypad.c new file mode 100644 index 00000000000..b31064981e9 --- /dev/null +++ b/drivers/input/keyboard/nspire-keypad.c @@ -0,0 +1,280 @@ +/* + * 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) { + clk_disable_unprepare(keypad->clk); + 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; + } + + 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); + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + 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 = 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/omap-keypad.c b/drivers/input/keyboard/omap-keypad.c index f23a743817d..b1acc9852eb 100644 --- a/drivers/input/keyboard/omap-keypad.c +++ b/drivers/input/keyboard/omap-keypad.c @@ -25,7 +25,6 @@ */ #include <linux/module.h> -#include <linux/init.h> #include <linux/interrupt.h> #include <linux/types.h> #include <linux/input.h> @@ -35,13 +34,9 @@ #include <linux/mutex.h> #include <linux/errno.h> #include <linux/slab.h> -#include <mach/gpio.h> -#include <plat/keypad.h> -#include <plat/menelaus.h> -#include <asm/irq.h> -#include <mach/hardware.h> -#include <asm/io.h> -#include <plat/mux.h> +#include <linux/gpio.h> +#include <linux/platform_data/gpio-omap.h> +#include <linux/platform_data/keypad-omap.h> #undef NEW_BOARD_LEARNING_MODE @@ -61,6 +56,7 @@ struct omap_kp { unsigned int cols; unsigned long delay; unsigned int debounce; + unsigned short keymap[]; }; static DECLARE_TASKLET_DISABLED(kp_tasklet, omap_kp_tasklet, 0); @@ -95,28 +91,8 @@ static u8 get_row_gpio_val(struct omap_kp *omap_kp) static irqreturn_t omap_kp_interrupt(int irq, void *dev_id) { - struct omap_kp *omap_kp = dev_id; - /* disable keyboard interrupt and schedule for handling */ - if (cpu_is_omap24xx()) { - int i; - - for (i = 0; i < omap_kp->rows; i++) { - int gpio_irq = gpio_to_irq(row_gpios[i]); - /* - * The interrupt which we're currently handling should - * be disabled _nosync() to avoid deadlocks waiting - * for this handler to complete. All others should - * be disabled the regular way for SMP safety. - */ - if (gpio_irq == irq) - disable_irq_nosync(gpio_irq); - else - disable_irq(gpio_irq); - } - } else - /* disable keyboard interrupt and schedule for handling */ - omap_writew(1, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT); + omap_writew(1, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT); tasklet_schedule(&kp_tasklet); @@ -132,33 +108,22 @@ static void omap_kp_scan_keypad(struct omap_kp *omap_kp, unsigned char *state) { int col = 0; - /* read the keypad status */ - if (cpu_is_omap24xx()) { - /* read the keypad status */ - for (col = 0; col < omap_kp->cols; col++) { - set_col_gpio_val(omap_kp, ~(1 << col)); - state[col] = ~(get_row_gpio_val(omap_kp)) & 0xff; - } - set_col_gpio_val(omap_kp, 0); - - } else { - /* disable keyboard interrupt and schedule for handling */ - omap_writew(1, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT); + /* disable keyboard interrupt and schedule for handling */ + omap_writew(1, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT); - /* read the keypad status */ - omap_writew(0xff, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBC); - for (col = 0; col < omap_kp->cols; col++) { - omap_writew(~(1 << col) & 0xff, - OMAP1_MPUIO_BASE + OMAP_MPUIO_KBC); + /* read the keypad status */ + omap_writew(0xff, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBC); + for (col = 0; col < omap_kp->cols; col++) { + omap_writew(~(1 << col) & 0xff, + OMAP1_MPUIO_BASE + OMAP_MPUIO_KBC); - udelay(omap_kp->delay); + udelay(omap_kp->delay); - state[col] = ~omap_readw(OMAP1_MPUIO_BASE + - OMAP_MPUIO_KBR_LATCH) & 0xff; - } - omap_writew(0x00, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBC); - udelay(2); + state[col] = ~omap_readw(OMAP1_MPUIO_BASE + + OMAP_MPUIO_KBR_LATCH) & 0xff; } + omap_writew(0x00, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBC); + udelay(2); } static void omap_kp_tasklet(unsigned long data) @@ -209,10 +174,11 @@ static void omap_kp_tasklet(unsigned long data) #endif } } + input_sync(omap_kp_data->input); memcpy(keypad_state, new_state, sizeof(keypad_state)); if (key_down) { - int delay = HZ / 20; + int delay = HZ / 20; /* some key is pressed - keep irq disabled and use timer * to poll the keypad */ if (spurious) @@ -220,14 +186,8 @@ static void omap_kp_tasklet(unsigned long data) mod_timer(&omap_kp_data->timer, jiffies + delay); } else { /* enable interrupts */ - if (cpu_is_omap24xx()) { - int i; - for (i = 0; i < omap_kp_data->rows; i++) - enable_irq(gpio_to_irq(row_gpios[i])); - } else { - omap_writew(0, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT); - kp_cur_group = -1; - } + omap_writew(0, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT); + kp_cur_group = -1; } } @@ -240,6 +200,7 @@ static ssize_t omap_kp_enable_show(struct device *dev, static ssize_t omap_kp_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { + struct omap_kp *omap_kp = dev_get_drvdata(dev); int state; if (sscanf(buf, "%u", &state) != 1) @@ -251,9 +212,9 @@ static ssize_t omap_kp_enable_store(struct device *dev, struct device_attribute mutex_lock(&kp_enable_mutex); if (state != kp_enable) { if (state) - enable_irq(INT_KEYBOARD); + enable_irq(omap_kp->irq); else - disable_irq(INT_KEYBOARD); + disable_irq(omap_kp->irq); kp_enable = state; } mutex_unlock(&kp_enable_mutex); @@ -282,12 +243,12 @@ static int omap_kp_resume(struct platform_device *dev) #define omap_kp_resume NULL #endif -static int __devinit omap_kp_probe(struct platform_device *pdev) +static int omap_kp_probe(struct platform_device *pdev) { struct omap_kp *omap_kp; struct input_dev *input_dev; - struct omap_kp_platform_data *pdata = pdev->dev.platform_data; - int i, col_idx, row_idx, irq_idx, ret; + struct omap_kp_platform_data *pdata = dev_get_platdata(&pdev->dev); + int i, col_idx, row_idx, ret; unsigned int row_shift, keycodemax; if (!pdata->rows || !pdata->cols || !pdata->keymap_data) { @@ -312,15 +273,7 @@ static int __devinit omap_kp_probe(struct platform_device *pdev) omap_kp->input = input_dev; /* Disable the interrupt for the MPUIO keyboard */ - if (!cpu_is_omap24xx()) - omap_writew(1, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT); - - input_dev->keycode = &omap_kp[1]; - input_dev->keycodesize = sizeof(unsigned short); - input_dev->keycodemax = keycodemax; - - if (pdata->rep) - __set_bit(EV_REP, input_dev->evbit); + omap_writew(1, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT); if (pdata->delay) omap_kp->delay = pdata->delay; @@ -333,31 +286,8 @@ static int __devinit omap_kp_probe(struct platform_device *pdev) omap_kp->rows = pdata->rows; omap_kp->cols = pdata->cols; - if (cpu_is_omap24xx()) { - /* Cols: outputs */ - for (col_idx = 0; col_idx < omap_kp->cols; col_idx++) { - if (gpio_request(col_gpios[col_idx], "omap_kp_col") < 0) { - printk(KERN_ERR "Failed to request" - "GPIO%d for keypad\n", - col_gpios[col_idx]); - goto err1; - } - gpio_direction_output(col_gpios[col_idx], 0); - } - /* Rows: inputs */ - for (row_idx = 0; row_idx < omap_kp->rows; row_idx++) { - if (gpio_request(row_gpios[row_idx], "omap_kp_row") < 0) { - printk(KERN_ERR "Failed to request" - "GPIO%d for keypad\n", - row_gpios[row_idx]); - goto err2; - } - gpio_direction_input(row_gpios[row_idx]); - } - } else { - col_idx = 0; - row_idx = 0; - } + col_idx = 0; + row_idx = 0; setup_timer(&omap_kp->timer, omap_kp_timer, (unsigned long)omap_kp); @@ -370,9 +300,6 @@ static int __devinit omap_kp_probe(struct platform_device *pdev) goto err2; /* setup input device */ - __set_bit(EV_KEY, input_dev->evbit); - matrix_keypad_build_keymap(pdata->keymap_data, row_shift, - input_dev->keycode, input_dev->keybit); input_dev->name = "omap-keypad"; input_dev->phys = "omap-keypad/input0"; input_dev->dev.parent = &pdev->dev; @@ -382,6 +309,15 @@ static int __devinit omap_kp_probe(struct platform_device *pdev) input_dev->id.product = 0x0001; input_dev->id.version = 0x0100; + if (pdata->rep) + __set_bit(EV_REP, input_dev->evbit); + + ret = matrix_keypad_build_keymap(pdata->keymap_data, NULL, + pdata->rows, pdata->cols, + omap_kp->keymap, input_dev); + if (ret < 0) + goto err3; + ret = input_register_device(omap_kp->input); if (ret < 0) { printk(KERN_ERR "Unable to register omap-keypad input device\n"); @@ -393,37 +329,25 @@ static int __devinit omap_kp_probe(struct platform_device *pdev) /* scan current status and enable interrupt */ omap_kp_scan_keypad(omap_kp, keypad_state); - if (!cpu_is_omap24xx()) { - omap_kp->irq = platform_get_irq(pdev, 0); - if (omap_kp->irq >= 0) { - if (request_irq(omap_kp->irq, omap_kp_interrupt, 0, - "omap-keypad", omap_kp) < 0) - goto err4; - } - omap_writew(0, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT); - } else { - for (irq_idx = 0; irq_idx < omap_kp->rows; irq_idx++) { - if (request_irq(gpio_to_irq(row_gpios[irq_idx]), - omap_kp_interrupt, - IRQF_TRIGGER_FALLING, - "omap-keypad", omap_kp) < 0) - goto err5; - } + omap_kp->irq = platform_get_irq(pdev, 0); + if (omap_kp->irq >= 0) { + if (request_irq(omap_kp->irq, omap_kp_interrupt, 0, + "omap-keypad", omap_kp) < 0) + goto err4; } + omap_writew(0, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT); + return 0; -err5: - for (i = irq_idx - 1; i >=0; i--) - free_irq(row_gpios[i], omap_kp); + err4: input_unregister_device(omap_kp->input); input_dev = NULL; err3: device_remove_file(&pdev->dev, &dev_attr_enable); err2: - for (i = row_idx - 1; i >=0; i--) + for (i = row_idx - 1; i >= 0; i--) gpio_free(row_gpios[i]); -err1: - for (i = col_idx - 1; i >=0; i--) + for (i = col_idx - 1; i >= 0; i--) gpio_free(col_gpios[i]); kfree(omap_kp); @@ -432,24 +356,14 @@ err1: return -EINVAL; } -static int __devexit omap_kp_remove(struct platform_device *pdev) +static int omap_kp_remove(struct platform_device *pdev) { struct omap_kp *omap_kp = platform_get_drvdata(pdev); /* disable keypad interrupt handling */ tasklet_disable(&kp_tasklet); - if (cpu_is_omap24xx()) { - int i; - for (i = 0; i < omap_kp->cols; i++) - gpio_free(col_gpios[i]); - for (i = 0; i < omap_kp->rows; i++) { - gpio_free(row_gpios[i]); - free_irq(gpio_to_irq(row_gpios[i]), omap_kp); - } - } else { - omap_writew(1, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT); - free_irq(omap_kp->irq, omap_kp); - } + omap_writew(1, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT); + free_irq(omap_kp->irq, omap_kp); del_timer_sync(&omap_kp->timer); tasklet_kill(&kp_tasklet); @@ -464,7 +378,7 @@ static int __devexit omap_kp_remove(struct platform_device *pdev) static struct platform_driver omap_kp_driver = { .probe = omap_kp_probe, - .remove = __devexit_p(omap_kp_remove), + .remove = omap_kp_remove, .suspend = omap_kp_suspend, .resume = omap_kp_resume, .driver = { @@ -472,20 +386,7 @@ static struct platform_driver omap_kp_driver = { .owner = THIS_MODULE, }, }; - -static int __init omap_kp_init(void) -{ - printk(KERN_INFO "OMAP Keypad Driver\n"); - return platform_driver_register(&omap_kp_driver); -} - -static void __exit omap_kp_exit(void) -{ - platform_driver_unregister(&omap_kp_driver); -} - -module_init(omap_kp_init); -module_exit(omap_kp_exit); +module_platform_driver(omap_kp_driver); MODULE_AUTHOR("Timo Teräs"); MODULE_DESCRIPTION("OMAP Keypad Driver"); diff --git a/drivers/input/keyboard/omap4-keypad.c b/drivers/input/keyboard/omap4-keypad.c index c51a3c4a7fe..024b7bdffe5 100644 --- a/drivers/input/keyboard/omap4-keypad.c +++ b/drivers/input/keyboard/omap4-keypad.c @@ -22,17 +22,16 @@ */ #include <linux/module.h> -#include <linux/init.h> #include <linux/interrupt.h> #include <linux/platform_device.h> #include <linux/errno.h> #include <linux/io.h> +#include <linux/of.h> #include <linux/input.h> +#include <linux/input/matrix_keypad.h> #include <linux/slab.h> #include <linux/pm_runtime.h> -#include <plat/omap4-keypad.h> - /* OMAP4 registers */ #define OMAP4_KBD_REVISION 0x00 #define OMAP4_KBD_SYSCONFIG 0x10 @@ -52,37 +51,82 @@ #define OMAP4_KBD_FULLCODE63_32 0x48 /* OMAP4 bit definitions */ -#define OMAP4_DEF_IRQENABLE_EVENTEN (1 << 0) -#define OMAP4_DEF_IRQENABLE_LONGKEY (1 << 1) -#define OMAP4_DEF_IRQENABLE_TIMEOUTEN (1 << 2) -#define OMAP4_DEF_WUP_EVENT_ENA (1 << 0) -#define OMAP4_DEF_WUP_LONG_KEY_ENA (1 << 1) -#define OMAP4_DEF_CTRL_NOSOFTMODE (1 << 1) -#define OMAP4_DEF_CTRLPTVVALUE (1 << 2) -#define OMAP4_DEF_CTRLPTV (1 << 1) +#define OMAP4_DEF_IRQENABLE_EVENTEN BIT(0) +#define OMAP4_DEF_IRQENABLE_LONGKEY BIT(1) +#define OMAP4_DEF_WUP_EVENT_ENA BIT(0) +#define OMAP4_DEF_WUP_LONG_KEY_ENA BIT(1) +#define OMAP4_DEF_CTRL_NOSOFTMODE BIT(1) +#define OMAP4_DEF_CTRL_PTV_SHIFT 2 /* OMAP4 values */ -#define OMAP4_VAL_IRQDISABLE 0x00 -#define OMAP4_VAL_DEBOUNCINGTIME 0x07 -#define OMAP4_VAL_FUNCTIONALCFG 0x1E +#define OMAP4_VAL_IRQDISABLE 0x0 +#define OMAP4_VAL_DEBOUNCINGTIME 0x7 +#define OMAP4_VAL_PVT 0x7 -#define OMAP4_MASK_IRQSTATUSDISABLE 0xFFFF +enum { + KBD_REVISION_OMAP4 = 0, + KBD_REVISION_OMAP5, +}; struct omap4_keypad { struct input_dev *input; void __iomem *base; - int irq; + bool irq_wake_enabled; + unsigned int irq; unsigned int rows; unsigned int cols; + u32 reg_offset; + u32 irqreg_offset; unsigned int row_shift; + bool no_autorepeat; unsigned char key_state[8]; - unsigned short keymap[]; + unsigned short *keymap; }; -/* Interrupt handler */ -static irqreturn_t omap4_keypad_interrupt(int irq, void *dev_id) +static int kbd_readl(struct omap4_keypad *keypad_data, u32 offset) +{ + return __raw_readl(keypad_data->base + + keypad_data->reg_offset + offset); +} + +static void kbd_writel(struct omap4_keypad *keypad_data, u32 offset, u32 value) +{ + __raw_writel(value, + keypad_data->base + keypad_data->reg_offset + offset); +} + +static int kbd_read_irqreg(struct omap4_keypad *keypad_data, u32 offset) +{ + return __raw_readl(keypad_data->base + + keypad_data->irqreg_offset + offset); +} + +static void kbd_write_irqreg(struct omap4_keypad *keypad_data, + u32 offset, u32 value) +{ + __raw_writel(value, + keypad_data->base + keypad_data->irqreg_offset + offset); +} + + +/* Interrupt handlers */ +static irqreturn_t omap4_keypad_irq_handler(int irq, void *dev_id) +{ + struct omap4_keypad *keypad_data = dev_id; + + if (kbd_read_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS)) { + /* Disable interrupts */ + kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQENABLE, + OMAP4_VAL_IRQDISABLE); + return IRQ_WAKE_THREAD; + } + + return IRQ_NONE; +} + +static irqreturn_t omap4_keypad_irq_thread_fn(int irq, void *dev_id) { struct omap4_keypad *keypad_data = dev_id; struct input_dev *input_dev = keypad_data->input; @@ -90,13 +134,8 @@ static irqreturn_t omap4_keypad_interrupt(int irq, void *dev_id) unsigned int col, row, code, changed; u32 *new_state = (u32 *) key_state; - /* Disable interrupts */ - __raw_writel(OMAP4_VAL_IRQDISABLE, - keypad_data->base + OMAP4_KBD_IRQENABLE); - - *new_state = __raw_readl(keypad_data->base + OMAP4_KBD_FULLCODE31_0); - *(new_state + 1) = __raw_readl(keypad_data->base - + OMAP4_KBD_FULLCODE63_32); + *new_state = kbd_readl(keypad_data, OMAP4_KBD_FULLCODE31_0); + *(new_state + 1) = kbd_readl(keypad_data, OMAP4_KBD_FULLCODE63_32); for (row = 0; row < keypad_data->rows; row++) { changed = key_state[row] ^ keypad_data->key_state[row]; @@ -121,12 +160,13 @@ static irqreturn_t omap4_keypad_interrupt(int irq, void *dev_id) sizeof(keypad_data->key_state)); /* clear pending interrupts */ - __raw_writel(__raw_readl(keypad_data->base + OMAP4_KBD_IRQSTATUS), - keypad_data->base + OMAP4_KBD_IRQSTATUS); + kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS, + kbd_read_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS)); /* enable interrupts */ - __raw_writel(OMAP4_DEF_IRQENABLE_EVENTEN | OMAP4_DEF_IRQENABLE_LONGKEY, - keypad_data->base + OMAP4_KBD_IRQENABLE); + kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQENABLE, + OMAP4_DEF_IRQENABLE_EVENTEN | + OMAP4_DEF_IRQENABLE_LONGKEY); return IRQ_HANDLED; } @@ -139,16 +179,19 @@ static int omap4_keypad_open(struct input_dev *input) disable_irq(keypad_data->irq); - __raw_writel(OMAP4_VAL_FUNCTIONALCFG, - keypad_data->base + OMAP4_KBD_CTRL); - __raw_writel(OMAP4_VAL_DEBOUNCINGTIME, - keypad_data->base + OMAP4_KBD_DEBOUNCINGTIME); - __raw_writel(OMAP4_VAL_IRQDISABLE, - keypad_data->base + OMAP4_KBD_IRQSTATUS); - __raw_writel(OMAP4_DEF_IRQENABLE_EVENTEN | OMAP4_DEF_IRQENABLE_LONGKEY, - keypad_data->base + OMAP4_KBD_IRQENABLE); - __raw_writel(OMAP4_DEF_WUP_EVENT_ENA | OMAP4_DEF_WUP_LONG_KEY_ENA, - keypad_data->base + OMAP4_KBD_WAKEUPENABLE); + kbd_writel(keypad_data, OMAP4_KBD_CTRL, + OMAP4_DEF_CTRL_NOSOFTMODE | + (OMAP4_VAL_PVT << OMAP4_DEF_CTRL_PTV_SHIFT)); + kbd_writel(keypad_data, OMAP4_KBD_DEBOUNCINGTIME, + OMAP4_VAL_DEBOUNCINGTIME); + /* clear pending interrupts */ + kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS, + kbd_read_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS)); + kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQENABLE, + OMAP4_DEF_IRQENABLE_EVENTEN | + OMAP4_DEF_IRQENABLE_LONGKEY); + kbd_writel(keypad_data, OMAP4_KBD_WAKEUPENABLE, + OMAP4_DEF_WUP_EVENT_ENA | OMAP4_DEF_WUP_LONG_KEY_ENA); enable_irq(keypad_data->irq); @@ -162,36 +205,45 @@ static void omap4_keypad_close(struct input_dev *input) disable_irq(keypad_data->irq); /* Disable interrupts */ - __raw_writel(OMAP4_VAL_IRQDISABLE, - keypad_data->base + OMAP4_KBD_IRQENABLE); + kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQENABLE, + OMAP4_VAL_IRQDISABLE); /* clear pending interrupts */ - __raw_writel(__raw_readl(keypad_data->base + OMAP4_KBD_IRQSTATUS), - keypad_data->base + OMAP4_KBD_IRQSTATUS); + kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS, + kbd_read_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS)); enable_irq(keypad_data->irq); pm_runtime_put_sync(input->dev.parent); } -static int __devinit omap4_keypad_probe(struct platform_device *pdev) +static int omap4_keypad_parse_dt(struct device *dev, + struct omap4_keypad *keypad_data) +{ + struct device_node *np = dev->of_node; + int err; + + err = matrix_keypad_parse_of_params(dev, &keypad_data->rows, + &keypad_data->cols); + if (err) + return err; + + if (of_get_property(np, "linux,input-no-autorepeat", NULL)) + keypad_data->no_autorepeat = true; + + return 0; +} + +static int omap4_keypad_probe(struct platform_device *pdev) { - const struct omap4_keypad_platform_data *pdata; struct omap4_keypad *keypad_data; struct input_dev *input_dev; struct resource *res; - resource_size_t size; - unsigned int row_shift, max_keys; + unsigned int max_keys; + int rev; int irq; int error; - /* platform data */ - pdata = pdev->dev.platform_data; - if (!pdata) { - dev_err(&pdev->dev, "no platform data defined\n"); - return -EINVAL; - } - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(&pdev->dev, "no base address specified\n"); @@ -204,25 +256,19 @@ static int __devinit omap4_keypad_probe(struct platform_device *pdev) return -EINVAL; } - if (!pdata->keymap_data) { - dev_err(&pdev->dev, "no keymap data defined\n"); - return -EINVAL; - } - - row_shift = get_count_order(pdata->cols); - max_keys = pdata->rows << row_shift; - - keypad_data = kzalloc(sizeof(struct omap4_keypad) + - max_keys * sizeof(keypad_data->keymap[0]), - GFP_KERNEL); + keypad_data = kzalloc(sizeof(struct omap4_keypad), GFP_KERNEL); if (!keypad_data) { dev_err(&pdev->dev, "keypad_data memory allocation failed\n"); return -ENOMEM; } - size = resource_size(res); + keypad_data->irq = irq; + + error = omap4_keypad_parse_dt(&pdev->dev, keypad_data); + if (error) + return error; - res = request_mem_region(res->start, size, pdev->name); + res = request_mem_region(res->start, resource_size(res), pdev->name); if (!res) { dev_err(&pdev->dev, "can't request mem region\n"); error = -EBUSY; @@ -236,16 +282,41 @@ static int __devinit omap4_keypad_probe(struct platform_device *pdev) goto err_release_mem; } - keypad_data->irq = irq; - keypad_data->row_shift = row_shift; - keypad_data->rows = pdata->rows; - keypad_data->cols = pdata->cols; + + /* + * Enable clocks for the keypad module so that we can read + * revision register. + */ + pm_runtime_enable(&pdev->dev); + error = pm_runtime_get_sync(&pdev->dev); + if (error) { + dev_err(&pdev->dev, "pm_runtime_get_sync() failed\n"); + goto err_unmap; + } + rev = __raw_readl(keypad_data->base + OMAP4_KBD_REVISION); + rev &= 0x03 << 30; + rev >>= 30; + switch (rev) { + case KBD_REVISION_OMAP4: + keypad_data->reg_offset = 0x00; + keypad_data->irqreg_offset = 0x00; + break; + case KBD_REVISION_OMAP5: + keypad_data->reg_offset = 0x10; + keypad_data->irqreg_offset = 0x0c; + break; + default: + dev_err(&pdev->dev, + "Keypad reports unsupported revision %d", rev); + error = -EINVAL; + goto err_pm_put_sync; + } /* input device allocation */ keypad_data->input = input_dev = input_allocate_device(); if (!input_dev) { error = -ENOMEM; - goto err_unmap; + goto err_pm_put_sync; } input_dev->name = pdev->name; @@ -258,29 +329,40 @@ static int __devinit omap4_keypad_probe(struct platform_device *pdev) input_dev->open = omap4_keypad_open; input_dev->close = omap4_keypad_close; - input_dev->keycode = keypad_data->keymap; - input_dev->keycodesize = sizeof(keypad_data->keymap[0]); - input_dev->keycodemax = max_keys; - - __set_bit(EV_KEY, input_dev->evbit); - __set_bit(EV_REP, input_dev->evbit); - input_set_capability(input_dev, EV_MSC, MSC_SCAN); + if (!keypad_data->no_autorepeat) + __set_bit(EV_REP, input_dev->evbit); input_set_drvdata(input_dev, keypad_data); - matrix_keypad_build_keymap(pdata->keymap_data, row_shift, - input_dev->keycode, input_dev->keybit); + keypad_data->row_shift = get_count_order(keypad_data->cols); + max_keys = keypad_data->rows << keypad_data->row_shift; + keypad_data->keymap = kzalloc(max_keys * sizeof(keypad_data->keymap[0]), + GFP_KERNEL); + if (!keypad_data->keymap) { + dev_err(&pdev->dev, "Not enough memory for keymap\n"); + error = -ENOMEM; + goto err_free_input; + } + + error = matrix_keypad_build_keymap(NULL, NULL, + keypad_data->rows, keypad_data->cols, + keypad_data->keymap, input_dev); + if (error) { + dev_err(&pdev->dev, "failed to build keymap\n"); + goto err_free_keymap; + } - error = request_irq(keypad_data->irq, omap4_keypad_interrupt, - IRQF_TRIGGER_RISING, - "omap4-keypad", keypad_data); + error = request_threaded_irq(keypad_data->irq, omap4_keypad_irq_handler, + omap4_keypad_irq_thread_fn, 0, + "omap4-keypad", keypad_data); if (error) { dev_err(&pdev->dev, "failed to register interrupt\n"); goto err_free_input; } - pm_runtime_enable(&pdev->dev); + device_init_wakeup(&pdev->dev, true); + pm_runtime_put_sync(&pdev->dev); error = input_register_device(keypad_data->input); if (error < 0) { @@ -293,19 +375,24 @@ static int __devinit omap4_keypad_probe(struct platform_device *pdev) err_pm_disable: pm_runtime_disable(&pdev->dev); + device_init_wakeup(&pdev->dev, false); free_irq(keypad_data->irq, keypad_data); +err_free_keymap: + kfree(keypad_data->keymap); err_free_input: input_free_device(input_dev); +err_pm_put_sync: + pm_runtime_put_sync(&pdev->dev); err_unmap: iounmap(keypad_data->base); err_release_mem: - release_mem_region(res->start, size); + release_mem_region(res->start, resource_size(res)); err_free_keypad: kfree(keypad_data); return error; } -static int __devexit omap4_keypad_remove(struct platform_device *pdev) +static int omap4_keypad_remove(struct platform_device *pdev) { struct omap4_keypad *keypad_data = platform_get_drvdata(pdev); struct resource *res; @@ -314,6 +401,8 @@ static int __devexit omap4_keypad_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); + device_init_wakeup(&pdev->dev, false); + input_unregister_device(keypad_data->input); iounmap(keypad_data->base); @@ -321,32 +410,62 @@ static int __devexit omap4_keypad_remove(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); release_mem_region(res->start, resource_size(res)); + kfree(keypad_data->keymap); kfree(keypad_data); - platform_set_drvdata(pdev, NULL); return 0; } -static struct platform_driver omap4_keypad_driver = { - .probe = omap4_keypad_probe, - .remove = __devexit_p(omap4_keypad_remove), - .driver = { - .name = "omap4-keypad", - .owner = THIS_MODULE, - }, +static const struct of_device_id omap_keypad_dt_match[] = { + { .compatible = "ti,omap4-keypad" }, + {}, }; +MODULE_DEVICE_TABLE(of, omap_keypad_dt_match); -static int __init omap4_keypad_init(void) +#ifdef CONFIG_PM_SLEEP +static int omap4_keypad_suspend(struct device *dev) { - return platform_driver_register(&omap4_keypad_driver); + struct platform_device *pdev = to_platform_device(dev); + struct omap4_keypad *keypad_data = platform_get_drvdata(pdev); + int error; + + if (device_may_wakeup(&pdev->dev)) { + error = enable_irq_wake(keypad_data->irq); + if (!error) + keypad_data->irq_wake_enabled = true; + } + + return 0; } -module_init(omap4_keypad_init); -static void __exit omap4_keypad_exit(void) +static int omap4_keypad_resume(struct device *dev) { - platform_driver_unregister(&omap4_keypad_driver); + struct platform_device *pdev = to_platform_device(dev); + struct omap4_keypad *keypad_data = platform_get_drvdata(pdev); + + if (device_may_wakeup(&pdev->dev) && keypad_data->irq_wake_enabled) { + disable_irq_wake(keypad_data->irq); + keypad_data->irq_wake_enabled = false; + } + + return 0; } -module_exit(omap4_keypad_exit); +#endif + +static SIMPLE_DEV_PM_OPS(omap4_keypad_pm_ops, + omap4_keypad_suspend, omap4_keypad_resume); + +static struct platform_driver omap4_keypad_driver = { + .probe = omap4_keypad_probe, + .remove = omap4_keypad_remove, + .driver = { + .name = "omap4-keypad", + .owner = THIS_MODULE, + .pm = &omap4_keypad_pm_ops, + .of_match_table = omap_keypad_dt_match, + }, +}; +module_platform_driver(omap4_keypad_driver); MODULE_AUTHOR("Texas Instruments"); MODULE_DESCRIPTION("OMAP4 Keypad Driver"); diff --git a/drivers/input/keyboard/opencores-kbd.c b/drivers/input/keyboard/opencores-kbd.c index 1f1a5563f60..7b9b44158ad 100644 --- a/drivers/input/keyboard/opencores-kbd.c +++ b/drivers/input/keyboard/opencores-kbd.c @@ -37,7 +37,7 @@ static irqreturn_t opencores_kbd_isr(int irq, void *dev_id) return IRQ_HANDLED; } -static int __devinit opencores_kbd_probe(struct platform_device *pdev) +static int opencores_kbd_probe(struct platform_device *pdev) { struct input_dev *input; struct opencores_kbd *opencores_kbd; @@ -139,7 +139,7 @@ static int __devinit opencores_kbd_probe(struct platform_device *pdev) return error; } -static int __devexit opencores_kbd_remove(struct platform_device *pdev) +static int opencores_kbd_remove(struct platform_device *pdev) { struct opencores_kbd *opencores_kbd = platform_get_drvdata(pdev); @@ -151,30 +151,17 @@ static int __devexit opencores_kbd_remove(struct platform_device *pdev) input_unregister_device(opencores_kbd->input); kfree(opencores_kbd); - platform_set_drvdata(pdev, NULL); - return 0; } static struct platform_driver opencores_kbd_device_driver = { .probe = opencores_kbd_probe, - .remove = __devexit_p(opencores_kbd_remove), + .remove = opencores_kbd_remove, .driver = { .name = "opencores-kbd", }, }; - -static int __init opencores_kbd_init(void) -{ - return platform_driver_register(&opencores_kbd_device_driver); -} -module_init(opencores_kbd_init); - -static void __exit opencores_kbd_exit(void) -{ - platform_driver_unregister(&opencores_kbd_device_driver); -} -module_exit(opencores_kbd_exit); +module_platform_driver(opencores_kbd_device_driver); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Javier Herrero <jherrero@hvsistemas.es>"); diff --git a/drivers/input/keyboard/pmic8xxx-keypad.c b/drivers/input/keyboard/pmic8xxx-keypad.c index 40b02ae96f8..80c6b0ef3fc 100644 --- a/drivers/input/keyboard/pmic8xxx-keypad.c +++ b/drivers/input/keyboard/pmic8xxx-keypad.c @@ -19,10 +19,9 @@ #include <linux/bitops.h> #include <linux/delay.h> #include <linux/mutex.h> - -#include <linux/mfd/pm8xxx/core.h> -#include <linux/mfd/pm8xxx/gpio.h> -#include <linux/input/pmic8xxx-keypad.h> +#include <linux/regmap.h> +#include <linux/of.h> +#include <linux/input/matrix_keypad.h> #define PM8XXX_MAX_ROWS 18 #define PM8XXX_MAX_COLS 8 @@ -85,8 +84,10 @@ /** * struct pmic8xxx_kp - internal keypad data structure - * @pdata - keypad platform data pointer + * @num_cols - number of columns of keypad + * @num_rows - number of row of keypad * @input - input device pointer for keypad + * @regmap - regmap handle * @key_sense_irq - key press/release irq number * @key_stuck_irq - key stuck notification irq number * @keycodes - array to hold the key codes @@ -96,8 +97,10 @@ * @ctrl_reg - control register value */ struct pmic8xxx_kp { - const struct pm8xxx_keypad_platform_data *pdata; + unsigned int num_rows; + unsigned int num_cols; struct input_dev *input; + struct regmap *regmap; int key_sense_irq; int key_stuck_irq; @@ -110,40 +113,13 @@ struct pmic8xxx_kp { u8 ctrl_reg; }; -static int pmic8xxx_kp_write_u8(struct pmic8xxx_kp *kp, - u8 data, u16 reg) -{ - int rc; - - rc = pm8xxx_writeb(kp->dev->parent, reg, data); - return rc; -} - -static int pmic8xxx_kp_read(struct pmic8xxx_kp *kp, - u8 *data, u16 reg, unsigned num_bytes) -{ - int rc; - - rc = pm8xxx_read_buf(kp->dev->parent, reg, data, num_bytes); - return rc; -} - -static int pmic8xxx_kp_read_u8(struct pmic8xxx_kp *kp, - u8 *data, u16 reg) -{ - int rc; - - rc = pmic8xxx_kp_read(kp, data, reg, 1); - return rc; -} - static u8 pmic8xxx_col_state(struct pmic8xxx_kp *kp, u8 col) { /* all keys pressed on that particular row? */ if (col == 0x00) - return 1 << kp->pdata->num_cols; + return 1 << kp->num_cols; else - return col & ((1 << kp->pdata->num_cols) - 1); + return col & ((1 << kp->num_cols) - 1); } /* @@ -161,9 +137,9 @@ static u8 pmic8xxx_col_state(struct pmic8xxx_kp *kp, u8 col) static int pmic8xxx_chk_sync_read(struct pmic8xxx_kp *kp) { int rc; - u8 scan_val; + unsigned int scan_val; - rc = pmic8xxx_kp_read_u8(kp, &scan_val, KEYP_SCAN); + rc = regmap_read(kp->regmap, KEYP_SCAN, &scan_val); if (rc < 0) { dev_err(kp->dev, "Error reading KEYP_SCAN reg, rc=%d\n", rc); return rc; @@ -171,7 +147,7 @@ static int pmic8xxx_chk_sync_read(struct pmic8xxx_kp *kp) scan_val |= 0x1; - rc = pmic8xxx_kp_write_u8(kp, scan_val, KEYP_SCAN); + rc = regmap_write(kp->regmap, KEYP_SCAN, scan_val); if (rc < 0) { dev_err(kp->dev, "Error writing KEYP_SCAN reg, rc=%d\n", rc); return rc; @@ -187,31 +163,29 @@ static int pmic8xxx_kp_read_data(struct pmic8xxx_kp *kp, u16 *state, u16 data_reg, int read_rows) { int rc, row; - u8 new_data[PM8XXX_MAX_ROWS]; + unsigned int val; - rc = pmic8xxx_kp_read(kp, new_data, data_reg, read_rows); - if (rc) - return rc; - - for (row = 0; row < kp->pdata->num_rows; row++) { - dev_dbg(kp->dev, "new_data[%d] = %d\n", row, - new_data[row]); - state[row] = pmic8xxx_col_state(kp, new_data[row]); + for (row = 0; row < read_rows; row++) { + rc = regmap_read(kp->regmap, data_reg, &val); + if (rc) + return rc; + dev_dbg(kp->dev, "%d = %d\n", row, val); + state[row] = pmic8xxx_col_state(kp, val); } - return rc; + return 0; } static int pmic8xxx_kp_read_matrix(struct pmic8xxx_kp *kp, u16 *new_state, u16 *old_state) { int rc, read_rows; - u8 scan_val; + unsigned int scan_val; - if (kp->pdata->num_rows < PM8XXX_MIN_ROWS) + if (kp->num_rows < PM8XXX_MIN_ROWS) read_rows = PM8XXX_MIN_ROWS; else - read_rows = kp->pdata->num_rows; + read_rows = kp->num_rows; pmic8xxx_chk_sync_read(kp); @@ -236,14 +210,14 @@ static int pmic8xxx_kp_read_matrix(struct pmic8xxx_kp *kp, u16 *new_state, /* 4 * 32KHz clocks */ udelay((4 * DIV_ROUND_UP(USEC_PER_SEC, KEYP_CLOCK_FREQ)) + 1); - rc = pmic8xxx_kp_read_u8(kp, &scan_val, KEYP_SCAN); + rc = regmap_read(kp->regmap, KEYP_SCAN, &scan_val); if (rc < 0) { dev_err(kp->dev, "Error reading KEYP_SCAN reg, rc=%d\n", rc); return rc; } scan_val &= 0xFE; - rc = pmic8xxx_kp_write_u8(kp, scan_val, KEYP_SCAN); + rc = regmap_write(kp->regmap, KEYP_SCAN, scan_val); if (rc < 0) dev_err(kp->dev, "Error writing KEYP_SCAN reg, rc=%d\n", rc); @@ -255,13 +229,13 @@ static void __pmic8xxx_kp_scan_matrix(struct pmic8xxx_kp *kp, u16 *new_state, { int row, col, code; - for (row = 0; row < kp->pdata->num_rows; row++) { + for (row = 0; row < kp->num_rows; row++) { int bits_changed = new_state[row] ^ old_state[row]; if (!bits_changed) continue; - for (col = 0; col < kp->pdata->num_cols; col++) { + for (col = 0; col < kp->num_cols; col++) { if (!(bits_changed & (1 << col))) continue; @@ -287,9 +261,9 @@ static bool pmic8xxx_detect_ghost_keys(struct pmic8xxx_kp *kp, u16 *new_state) u16 check, row_state; check = 0; - for (row = 0; row < kp->pdata->num_rows; row++) { + for (row = 0; row < kp->num_rows; row++) { row_state = (~new_state[row]) & - ((1 << kp->pdata->num_cols) - 1); + ((1 << kp->num_cols) - 1); if (hweight16(row_state) > 1) { if (found_first == -1) @@ -379,10 +353,10 @@ static irqreturn_t pmic8xxx_kp_stuck_irq(int irq, void *data) static irqreturn_t pmic8xxx_kp_irq(int irq, void *data) { struct pmic8xxx_kp *kp = data; - u8 ctrl_val, events; + unsigned int ctrl_val, events; int rc; - rc = pmic8xxx_kp_read(kp, &ctrl_val, KEYP_CTRL, 1); + rc = regmap_read(kp->regmap, KEYP_CTRL, &ctrl_val); if (rc < 0) { dev_err(kp->dev, "failed to read keyp_ctrl register\n"); return IRQ_HANDLED; @@ -397,8 +371,13 @@ static irqreturn_t pmic8xxx_kp_irq(int irq, void *data) return IRQ_HANDLED; } -static int __devinit pmic8xxx_kpd_init(struct pmic8xxx_kp *kp) +static int pmic8xxx_kpd_init(struct pmic8xxx_kp *kp, + struct platform_device *pdev) { + const struct device_node *of_node = pdev->dev.of_node; + unsigned int scan_delay_ms; + unsigned int row_hold_ns; + unsigned int debounce_ms; int bits, rc, cycles; u8 scan_val = 0, ctrl_val = 0; static const u8 row_bits[] = { @@ -406,40 +385,69 @@ static int __devinit pmic8xxx_kpd_init(struct pmic8xxx_kp *kp) }; /* Find column bits */ - if (kp->pdata->num_cols < KEYP_CTRL_SCAN_COLS_MIN) + if (kp->num_cols < KEYP_CTRL_SCAN_COLS_MIN) bits = 0; else - bits = kp->pdata->num_cols - KEYP_CTRL_SCAN_COLS_MIN; + bits = kp->num_cols - KEYP_CTRL_SCAN_COLS_MIN; ctrl_val = (bits & KEYP_CTRL_SCAN_COLS_BITS) << KEYP_CTRL_SCAN_COLS_SHIFT; /* Find row bits */ - if (kp->pdata->num_rows < KEYP_CTRL_SCAN_ROWS_MIN) + if (kp->num_rows < KEYP_CTRL_SCAN_ROWS_MIN) bits = 0; else - bits = row_bits[kp->pdata->num_rows - KEYP_CTRL_SCAN_ROWS_MIN]; + bits = row_bits[kp->num_rows - KEYP_CTRL_SCAN_ROWS_MIN]; ctrl_val |= (bits << KEYP_CTRL_SCAN_ROWS_SHIFT); - rc = pmic8xxx_kp_write_u8(kp, ctrl_val, KEYP_CTRL); + rc = regmap_write(kp->regmap, KEYP_CTRL, ctrl_val); if (rc < 0) { dev_err(kp->dev, "Error writing KEYP_CTRL reg, rc=%d\n", rc); return rc; } - bits = (kp->pdata->debounce_ms / 5) - 1; + if (of_property_read_u32(of_node, "scan-delay", &scan_delay_ms)) + scan_delay_ms = MIN_SCAN_DELAY; + + if (scan_delay_ms > MAX_SCAN_DELAY || scan_delay_ms < MIN_SCAN_DELAY || + !is_power_of_2(scan_delay_ms)) { + dev_err(&pdev->dev, "invalid keypad scan time supplied\n"); + return -EINVAL; + } + + if (of_property_read_u32(of_node, "row-hold", &row_hold_ns)) + row_hold_ns = MIN_ROW_HOLD_DELAY; + + if (row_hold_ns > MAX_ROW_HOLD_DELAY || + row_hold_ns < MIN_ROW_HOLD_DELAY || + ((row_hold_ns % MIN_ROW_HOLD_DELAY) != 0)) { + dev_err(&pdev->dev, "invalid keypad row hold time supplied\n"); + return -EINVAL; + } + + if (of_property_read_u32(of_node, "debounce", &debounce_ms)) + debounce_ms = MIN_DEBOUNCE_TIME; + + if (((debounce_ms % 5) != 0) || + debounce_ms > MAX_DEBOUNCE_TIME || + debounce_ms < MIN_DEBOUNCE_TIME) { + dev_err(&pdev->dev, "invalid debounce time supplied\n"); + return -EINVAL; + } + + bits = (debounce_ms / 5) - 1; scan_val |= (bits << KEYP_SCAN_DBOUNCE_SHIFT); - bits = fls(kp->pdata->scan_delay_ms) - 1; + bits = fls(scan_delay_ms) - 1; scan_val |= (bits << KEYP_SCAN_PAUSE_SHIFT); /* Row hold time is a multiple of 32KHz cycles. */ - cycles = (kp->pdata->row_hold_ns * KEYP_CLOCK_FREQ) / NSEC_PER_SEC; + cycles = (row_hold_ns * KEYP_CLOCK_FREQ) / NSEC_PER_SEC; scan_val |= (cycles << KEYP_SCAN_ROW_HOLD_SHIFT); - rc = pmic8xxx_kp_write_u8(kp, scan_val, KEYP_SCAN); + rc = regmap_write(kp->regmap, KEYP_SCAN, scan_val); if (rc) dev_err(kp->dev, "Error writing KEYP_SCAN reg, rc=%d\n", rc); @@ -447,34 +455,13 @@ static int __devinit pmic8xxx_kpd_init(struct pmic8xxx_kp *kp) } -static int __devinit pmic8xxx_kp_config_gpio(int gpio_start, int num_gpios, - struct pmic8xxx_kp *kp, struct pm_gpio *gpio_config) -{ - int rc, i; - - if (gpio_start < 0 || num_gpios < 0) - return -EINVAL; - - for (i = 0; i < num_gpios; i++) { - rc = pm8xxx_gpio_config(gpio_start + i, gpio_config); - if (rc) { - dev_err(kp->dev, "%s: FAIL pm8xxx_gpio_config():" - "for PM GPIO [%d] rc=%d.\n", - __func__, gpio_start + i, rc); - return rc; - } - } - - return 0; -} - static int pmic8xxx_kp_enable(struct pmic8xxx_kp *kp) { int rc; kp->ctrl_reg |= KEYP_CTRL_KEYP_EN; - rc = pmic8xxx_kp_write_u8(kp, kp->ctrl_reg, KEYP_CTRL); + rc = regmap_write(kp->regmap, KEYP_CTRL, kp->ctrl_reg); if (rc < 0) dev_err(kp->dev, "Error writing KEYP_CTRL reg, rc=%d\n", rc); @@ -487,7 +474,7 @@ static int pmic8xxx_kp_disable(struct pmic8xxx_kp *kp) kp->ctrl_reg &= ~KEYP_CTRL_KEYP_EN; - rc = pmic8xxx_kp_write_u8(kp, kp->ctrl_reg, KEYP_CTRL); + rc = regmap_write(kp->regmap, KEYP_CTRL, kp->ctrl_reg); if (rc < 0) return rc; @@ -518,172 +505,117 @@ static void pmic8xxx_kp_close(struct input_dev *dev) * - set irq edge type. * - enable the keypad controller. */ -static int __devinit pmic8xxx_kp_probe(struct platform_device *pdev) +static int pmic8xxx_kp_probe(struct platform_device *pdev) { - const struct pm8xxx_keypad_platform_data *pdata = mfd_get_data(pdev); - const struct matrix_keymap_data *keymap_data; + unsigned int rows, cols; + bool repeat; + bool wakeup; struct pmic8xxx_kp *kp; int rc; - u8 ctrl_val; - - struct pm_gpio kypd_drv = { - .direction = PM_GPIO_DIR_OUT, - .output_buffer = PM_GPIO_OUT_BUF_OPEN_DRAIN, - .output_value = 0, - .pull = PM_GPIO_PULL_NO, - .vin_sel = PM_GPIO_VIN_S3, - .out_strength = PM_GPIO_STRENGTH_LOW, - .function = PM_GPIO_FUNC_1, - .inv_int_pol = 1, - }; - - struct pm_gpio kypd_sns = { - .direction = PM_GPIO_DIR_IN, - .pull = PM_GPIO_PULL_UP_31P5, - .vin_sel = PM_GPIO_VIN_S3, - .out_strength = PM_GPIO_STRENGTH_NO, - .function = PM_GPIO_FUNC_NORMAL, - .inv_int_pol = 1, - }; + unsigned int ctrl_val; + rc = matrix_keypad_parse_of_params(&pdev->dev, &rows, &cols); + if (rc) + return rc; - if (!pdata || !pdata->num_cols || !pdata->num_rows || - pdata->num_cols > PM8XXX_MAX_COLS || - pdata->num_rows > PM8XXX_MAX_ROWS || - pdata->num_cols < PM8XXX_MIN_COLS) { + if (cols > PM8XXX_MAX_COLS || rows > PM8XXX_MAX_ROWS || + cols < PM8XXX_MIN_COLS) { dev_err(&pdev->dev, "invalid platform data\n"); return -EINVAL; } - if (!pdata->scan_delay_ms || - pdata->scan_delay_ms > MAX_SCAN_DELAY || - pdata->scan_delay_ms < MIN_SCAN_DELAY || - !is_power_of_2(pdata->scan_delay_ms)) { - dev_err(&pdev->dev, "invalid keypad scan time supplied\n"); - return -EINVAL; - } - - if (!pdata->row_hold_ns || - pdata->row_hold_ns > MAX_ROW_HOLD_DELAY || - pdata->row_hold_ns < MIN_ROW_HOLD_DELAY || - ((pdata->row_hold_ns % MIN_ROW_HOLD_DELAY) != 0)) { - dev_err(&pdev->dev, "invalid keypad row hold time supplied\n"); - return -EINVAL; - } - - if (!pdata->debounce_ms || - ((pdata->debounce_ms % 5) != 0) || - pdata->debounce_ms > MAX_DEBOUNCE_TIME || - pdata->debounce_ms < MIN_DEBOUNCE_TIME) { - dev_err(&pdev->dev, "invalid debounce time supplied\n"); - return -EINVAL; - } + repeat = !of_property_read_bool(pdev->dev.of_node, + "linux,input-no-autorepeat"); + wakeup = of_property_read_bool(pdev->dev.of_node, + "linux,keypad-wakeup"); - keymap_data = pdata->keymap_data; - if (!keymap_data) { - dev_err(&pdev->dev, "no keymap data supplied\n"); - return -EINVAL; - } - - kp = kzalloc(sizeof(*kp), GFP_KERNEL); + kp = devm_kzalloc(&pdev->dev, sizeof(*kp), GFP_KERNEL); if (!kp) return -ENOMEM; + kp->regmap = dev_get_regmap(pdev->dev.parent, NULL); + if (!kp->regmap) + return -ENODEV; + platform_set_drvdata(pdev, kp); - kp->pdata = pdata; + kp->num_rows = rows; + kp->num_cols = cols; kp->dev = &pdev->dev; - kp->input = input_allocate_device(); + kp->input = devm_input_allocate_device(&pdev->dev); if (!kp->input) { dev_err(&pdev->dev, "unable to allocate input device\n"); - rc = -ENOMEM; - goto err_alloc_device; + return -ENOMEM; } kp->key_sense_irq = platform_get_irq(pdev, 0); if (kp->key_sense_irq < 0) { dev_err(&pdev->dev, "unable to get keypad sense irq\n"); - rc = -ENXIO; - goto err_get_irq; + return kp->key_sense_irq; } kp->key_stuck_irq = platform_get_irq(pdev, 1); if (kp->key_stuck_irq < 0) { dev_err(&pdev->dev, "unable to get keypad stuck irq\n"); - rc = -ENXIO; - goto err_get_irq; + return kp->key_stuck_irq; } - kp->input->name = pdata->input_name ? : "PMIC8XXX keypad"; - kp->input->phys = pdata->input_phys_device ? : "pmic8xxx_keypad/input0"; - - kp->input->dev.parent = &pdev->dev; + kp->input->name = "PMIC8XXX keypad"; + kp->input->phys = "pmic8xxx_keypad/input0"; kp->input->id.bustype = BUS_I2C; kp->input->id.version = 0x0001; kp->input->id.product = 0x0001; kp->input->id.vendor = 0x0001; - kp->input->evbit[0] = BIT_MASK(EV_KEY); - - if (pdata->rep) - __set_bit(EV_REP, kp->input->evbit); - - kp->input->keycode = kp->keycodes; - kp->input->keycodemax = PM8XXX_MATRIX_MAX_SIZE; - kp->input->keycodesize = sizeof(kp->keycodes); kp->input->open = pmic8xxx_kp_open; kp->input->close = pmic8xxx_kp_close; - matrix_keypad_build_keymap(keymap_data, PM8XXX_ROW_SHIFT, - kp->input->keycode, kp->input->keybit); + rc = matrix_keypad_build_keymap(NULL, NULL, + PM8XXX_MAX_ROWS, PM8XXX_MAX_COLS, + kp->keycodes, kp->input); + if (rc) { + dev_err(&pdev->dev, "failed to build keymap\n"); + return rc; + } + if (repeat) + __set_bit(EV_REP, kp->input->evbit); input_set_capability(kp->input, EV_MSC, MSC_SCAN); + input_set_drvdata(kp->input, kp); /* initialize keypad state */ memset(kp->keystate, 0xff, sizeof(kp->keystate)); memset(kp->stuckstate, 0xff, sizeof(kp->stuckstate)); - rc = pmic8xxx_kpd_init(kp); + rc = pmic8xxx_kpd_init(kp, pdev); if (rc < 0) { dev_err(&pdev->dev, "unable to initialize keypad controller\n"); - goto err_get_irq; - } - - rc = pmic8xxx_kp_config_gpio(pdata->cols_gpio_start, - pdata->num_cols, kp, &kypd_sns); - if (rc < 0) { - dev_err(&pdev->dev, "unable to configure keypad sense lines\n"); - goto err_gpio_config; - } - - rc = pmic8xxx_kp_config_gpio(pdata->rows_gpio_start, - pdata->num_rows, kp, &kypd_drv); - if (rc < 0) { - dev_err(&pdev->dev, "unable to configure keypad drive lines\n"); - goto err_gpio_config; + return rc; } - rc = request_any_context_irq(kp->key_sense_irq, pmic8xxx_kp_irq, - IRQF_TRIGGER_RISING, "pmic-keypad", kp); + rc = devm_request_any_context_irq(&pdev->dev, kp->key_sense_irq, + pmic8xxx_kp_irq, IRQF_TRIGGER_RISING, "pmic-keypad", + kp); if (rc < 0) { dev_err(&pdev->dev, "failed to request keypad sense irq\n"); - goto err_get_irq; + return rc; } - rc = request_any_context_irq(kp->key_stuck_irq, pmic8xxx_kp_stuck_irq, - IRQF_TRIGGER_RISING, "pmic-keypad-stuck", kp); + rc = devm_request_any_context_irq(&pdev->dev, kp->key_stuck_irq, + pmic8xxx_kp_stuck_irq, IRQF_TRIGGER_RISING, + "pmic-keypad-stuck", kp); if (rc < 0) { dev_err(&pdev->dev, "failed to request keypad stuck irq\n"); - goto err_req_stuck_irq; + return rc; } - rc = pmic8xxx_kp_read_u8(kp, &ctrl_val, KEYP_CTRL); + rc = regmap_read(kp->regmap, KEYP_CTRL, &ctrl_val); if (rc < 0) { dev_err(&pdev->dev, "failed to read KEYP_CTRL register\n"); - goto err_pmic_reg_read; + return rc; } kp->ctrl_reg = ctrl_val; @@ -691,37 +623,11 @@ static int __devinit pmic8xxx_kp_probe(struct platform_device *pdev) rc = input_register_device(kp->input); if (rc < 0) { dev_err(&pdev->dev, "unable to register keypad input device\n"); - goto err_pmic_reg_read; + return rc; } - device_init_wakeup(&pdev->dev, pdata->wakeup); - - return 0; - -err_pmic_reg_read: - free_irq(kp->key_stuck_irq, NULL); -err_req_stuck_irq: - free_irq(kp->key_sense_irq, NULL); -err_gpio_config: -err_get_irq: - input_free_device(kp->input); -err_alloc_device: - platform_set_drvdata(pdev, NULL); - kfree(kp); - return rc; -} - -static int __devexit pmic8xxx_kp_remove(struct platform_device *pdev) -{ - struct pmic8xxx_kp *kp = platform_get_drvdata(pdev); + device_init_wakeup(&pdev->dev, wakeup); - device_init_wakeup(&pdev->dev, 0); - free_irq(kp->key_stuck_irq, NULL); - free_irq(kp->key_sense_irq, NULL); - input_unregister_device(kp->input); - kfree(kp); - - platform_set_drvdata(pdev, NULL); return 0; } @@ -770,27 +676,23 @@ static int pmic8xxx_kp_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(pm8xxx_kp_pm_ops, pmic8xxx_kp_suspend, pmic8xxx_kp_resume); +static const struct of_device_id pm8xxx_match_table[] = { + { .compatible = "qcom,pm8058-keypad" }, + { .compatible = "qcom,pm8921-keypad" }, + { } +}; +MODULE_DEVICE_TABLE(of, pm8xxx_match_table); + static struct platform_driver pmic8xxx_kp_driver = { .probe = pmic8xxx_kp_probe, - .remove = __devexit_p(pmic8xxx_kp_remove), .driver = { - .name = PM8XXX_KEYPAD_DEV_NAME, + .name = "pm8xxx-keypad", .owner = THIS_MODULE, .pm = &pm8xxx_kp_pm_ops, + .of_match_table = pm8xxx_match_table, }, }; - -static int __init pmic8xxx_kp_init(void) -{ - return platform_driver_register(&pmic8xxx_kp_driver); -} -module_init(pmic8xxx_kp_init); - -static void __exit pmic8xxx_kp_exit(void) -{ - platform_driver_unregister(&pmic8xxx_kp_driver); -} -module_exit(pmic8xxx_kp_exit); +module_platform_driver(pmic8xxx_kp_driver); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("PMIC8XXX keypad driver"); 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"); diff --git a/drivers/input/keyboard/pxa930_rotary.c b/drivers/input/keyboard/pxa930_rotary.c index b7123a44b6e..374ca0246c8 100644 --- a/drivers/input/keyboard/pxa930_rotary.c +++ b/drivers/input/keyboard/pxa930_rotary.c @@ -8,14 +8,13 @@ #include <linux/kernel.h> #include <linux/module.h> -#include <linux/init.h> #include <linux/interrupt.h> #include <linux/input.h> #include <linux/platform_device.h> #include <linux/io.h> #include <linux/slab.h> -#include <mach/pxa930_rotary.h> +#include <linux/platform_data/keyboard-pxa930_rotary.h> #define SBCR (0x04) #define ERCR (0x0c) @@ -82,9 +81,10 @@ static void pxa930_rotary_close(struct input_dev *dev) clear_sbcr(r); } -static int __devinit pxa930_rotary_probe(struct platform_device *pdev) +static int pxa930_rotary_probe(struct platform_device *pdev) { - struct pxa930_rotary_platform_data *pdata = pdev->dev.platform_data; + struct pxa930_rotary_platform_data *pdata = + dev_get_platdata(&pdev->dev); struct pxa930_rotary *r; struct input_dev *input_dev; struct resource *res; @@ -148,7 +148,7 @@ static int __devinit pxa930_rotary_probe(struct platform_device *pdev) r->input_dev = input_dev; input_set_drvdata(input_dev, r); - err = request_irq(irq, rotary_irq, IRQF_DISABLED, + err = request_irq(irq, rotary_irq, 0, "enhanced rotary", r); if (err) { dev_err(&pdev->dev, "failed to request IRQ\n"); @@ -174,14 +174,13 @@ failed_free: return err; } -static int __devexit pxa930_rotary_remove(struct platform_device *pdev) +static int pxa930_rotary_remove(struct platform_device *pdev) { struct pxa930_rotary *r = platform_get_drvdata(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; @@ -193,20 +192,9 @@ static struct platform_driver pxa930_rotary_driver = { .owner = THIS_MODULE, }, .probe = pxa930_rotary_probe, - .remove = __devexit_p(pxa930_rotary_remove), + .remove = pxa930_rotary_remove, }; - -static int __init pxa930_rotary_init(void) -{ - return platform_driver_register(&pxa930_rotary_driver); -} -module_init(pxa930_rotary_init); - -static void __exit pxa930_rotary_exit(void) -{ - platform_driver_unregister(&pxa930_rotary_driver); -} -module_exit(pxa930_rotary_exit); +module_platform_driver(pxa930_rotary_driver); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Driver for PXA93x Enhanced Rotary Controller"); diff --git a/drivers/input/keyboard/qt1070.c b/drivers/input/keyboard/qt1070.c index ca7b89196ab..52cd6e88acd 100644 --- a/drivers/input/keyboard/qt1070.c +++ b/drivers/input/keyboard/qt1070.c @@ -25,7 +25,6 @@ */ #include <linux/kernel.h> #include <linux/module.h> -#include <linux/init.h> #include <linux/i2c.h> #include <linux/input.h> #include <linux/slab.h> @@ -91,7 +90,7 @@ static int qt1070_write(struct i2c_client *client, u8 reg, u8 data) return ret; } -static bool __devinit qt1070_identify(struct i2c_client *client) +static bool qt1070_identify(struct i2c_client *client) { int id, ver; @@ -140,7 +139,7 @@ static irqreturn_t qt1070_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static int __devinit qt1070_probe(struct i2c_client *client, +static int qt1070_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct qt1070_data *data; @@ -201,7 +200,8 @@ static int __devinit qt1070_probe(struct i2c_client *client, msleep(QT1070_RESET_TIME); err = request_threaded_irq(client->irq, NULL, qt1070_interrupt, - IRQF_TRIGGER_NONE, client->dev.driver->name, data); + IRQF_TRIGGER_NONE | IRQF_ONESHOT, + client->dev.driver->name, data); if (err) { dev_err(&client->dev, "fail to request irq\n"); goto err_free_mem; @@ -229,7 +229,7 @@ err_free_mem: return err; } -static int __devexit qt1070_remove(struct i2c_client *client) +static int qt1070_remove(struct i2c_client *client) { struct qt1070_data *data = i2c_get_clientdata(client); @@ -239,11 +239,35 @@ static int __devexit qt1070_remove(struct i2c_client *client) input_unregister_device(data->input); kfree(data); - i2c_set_clientdata(client, NULL); + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int qt1070_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct qt1070_data *data = i2c_get_clientdata(client); + + if (device_may_wakeup(dev)) + enable_irq_wake(data->irq); return 0; } +static int qt1070_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct qt1070_data *data = i2c_get_clientdata(client); + + if (device_may_wakeup(dev)) + disable_irq_wake(data->irq); + + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(qt1070_pm_ops, qt1070_suspend, qt1070_resume); + static const struct i2c_device_id qt1070_id[] = { { "qt1070", 0 }, { }, @@ -254,23 +278,14 @@ static struct i2c_driver qt1070_driver = { .driver = { .name = "qt1070", .owner = THIS_MODULE, + .pm = &qt1070_pm_ops, }, .id_table = qt1070_id, .probe = qt1070_probe, - .remove = __devexit_p(qt1070_remove), + .remove = qt1070_remove, }; -static int __init qt1070_init(void) -{ - return i2c_add_driver(&qt1070_driver); -} -module_init(qt1070_init); - -static void __exit qt1070_exit(void) -{ - i2c_del_driver(&qt1070_driver); -} -module_exit(qt1070_exit); +module_i2c_driver(qt1070_driver); MODULE_AUTHOR("Bo Shen <voice.shen@atmel.com>"); MODULE_DESCRIPTION("Driver for AT42QT1070 QTouch sensor"); diff --git a/drivers/input/keyboard/qt2160.c b/drivers/input/keyboard/qt2160.c index fac695157e8..819b22897c1 100644 --- a/drivers/input/keyboard/qt2160.c +++ b/drivers/input/keyboard/qt2160.c @@ -19,7 +19,7 @@ */ #include <linux/kernel.h> -#include <linux/init.h> +#include <linux/leds.h> #include <linux/module.h> #include <linux/slab.h> #include <linux/jiffies.h> @@ -39,6 +39,11 @@ #define QT2160_CMD_GPIOS 6 #define QT2160_CMD_SUBVER 7 #define QT2160_CMD_CALIBRATE 10 +#define QT2160_CMD_DRIVE_X 70 +#define QT2160_CMD_PWMEN_X 74 +#define QT2160_CMD_PWM_DUTY 76 + +#define QT2160_NUM_LEDS_X 8 #define QT2160_CYCLE_INTERVAL (2*HZ) @@ -49,6 +54,17 @@ static unsigned char qt2160_key2code[] = { KEY_C, KEY_D, KEY_E, KEY_F, }; +#ifdef CONFIG_LEDS_CLASS +struct qt2160_led { + struct qt2160_data *qt2160; + struct led_classdev cdev; + struct work_struct work; + char name[32]; + int id; + enum led_brightness new_brightness; +}; +#endif + struct qt2160_data { struct i2c_client *client; struct input_dev *input; @@ -56,8 +72,61 @@ struct qt2160_data { spinlock_t lock; /* Protects canceling/rescheduling of dwork */ unsigned short keycodes[ARRAY_SIZE(qt2160_key2code)]; u16 key_matrix; +#ifdef CONFIG_LEDS_CLASS + struct qt2160_led leds[QT2160_NUM_LEDS_X]; + struct mutex led_lock; +#endif }; +static int qt2160_read(struct i2c_client *client, u8 reg); +static int qt2160_write(struct i2c_client *client, u8 reg, u8 data); + +#ifdef CONFIG_LEDS_CLASS + +static void qt2160_led_work(struct work_struct *work) +{ + struct qt2160_led *led = container_of(work, struct qt2160_led, work); + struct qt2160_data *qt2160 = led->qt2160; + struct i2c_client *client = qt2160->client; + int value = led->new_brightness; + u32 drive, pwmen; + + mutex_lock(&qt2160->led_lock); + + drive = qt2160_read(client, QT2160_CMD_DRIVE_X); + pwmen = qt2160_read(client, QT2160_CMD_PWMEN_X); + if (value != LED_OFF) { + drive |= (1 << led->id); + pwmen |= (1 << led->id); + + } else { + drive &= ~(1 << led->id); + pwmen &= ~(1 << led->id); + } + qt2160_write(client, QT2160_CMD_DRIVE_X, drive); + qt2160_write(client, QT2160_CMD_PWMEN_X, pwmen); + + /* + * Changing this register will change the brightness + * of every LED in the qt2160. It's a HW limitation. + */ + if (value != LED_OFF) + qt2160_write(client, QT2160_CMD_PWM_DUTY, value); + + mutex_unlock(&qt2160->led_lock); +} + +static void qt2160_led_set(struct led_classdev *cdev, + enum led_brightness value) +{ + struct qt2160_led *led = container_of(cdev, struct qt2160_led, cdev); + + led->new_brightness = value; + schedule_work(&led->work); +} + +#endif /* CONFIG_LEDS_CLASS */ + static int qt2160_read_block(struct i2c_client *client, u8 inireg, u8 *buffer, unsigned int count) { @@ -156,8 +225,7 @@ static irqreturn_t qt2160_irq(int irq, void *_qt2160) spin_lock_irqsave(&qt2160->lock, flags); - __cancel_delayed_work(&qt2160->dwork); - schedule_delayed_work(&qt2160->dwork, 0); + mod_delayed_work(system_wq, &qt2160->dwork, 0); spin_unlock_irqrestore(&qt2160->lock, flags); @@ -184,7 +252,7 @@ static void qt2160_worker(struct work_struct *work) qt2160_schedule_read(qt2160); } -static int __devinit qt2160_read(struct i2c_client *client, u8 reg) +static int qt2160_read(struct i2c_client *client, u8 reg) { int ret; @@ -205,29 +273,77 @@ static int __devinit qt2160_read(struct i2c_client *client, u8 reg) return ret; } -static int __devinit qt2160_write(struct i2c_client *client, u8 reg, u8 data) +static int qt2160_write(struct i2c_client *client, u8 reg, u8 data) { - int error; + int ret; - error = i2c_smbus_write_byte(client, reg); - if (error) { + ret = i2c_smbus_write_byte_data(client, reg, data); + if (ret < 0) dev_err(&client->dev, - "couldn't send request. Returned %d\n", error); - return error; + "couldn't write data. Returned %d\n", ret); + + return ret; +} + +#ifdef CONFIG_LEDS_CLASS + +static int qt2160_register_leds(struct qt2160_data *qt2160) +{ + struct i2c_client *client = qt2160->client; + int ret; + int i; + + mutex_init(&qt2160->led_lock); + + for (i = 0; i < QT2160_NUM_LEDS_X; i++) { + struct qt2160_led *led = &qt2160->leds[i]; + + snprintf(led->name, sizeof(led->name), "qt2160:x%d", i); + led->cdev.name = led->name; + led->cdev.brightness_set = qt2160_led_set; + led->cdev.brightness = LED_OFF; + led->id = i; + led->qt2160 = qt2160; + + INIT_WORK(&led->work, qt2160_led_work); + + ret = led_classdev_register(&client->dev, &led->cdev); + if (ret < 0) + return ret; } - error = i2c_smbus_write_byte(client, data); - if (error) { - dev_err(&client->dev, - "couldn't write data. Returned %d\n", error); - return error; + /* Tur off LEDs */ + qt2160_write(client, QT2160_CMD_DRIVE_X, 0); + qt2160_write(client, QT2160_CMD_PWMEN_X, 0); + qt2160_write(client, QT2160_CMD_PWM_DUTY, 0); + + return 0; +} + +static void qt2160_unregister_leds(struct qt2160_data *qt2160) +{ + int i; + + for (i = 0; i < QT2160_NUM_LEDS_X; i++) { + led_classdev_unregister(&qt2160->leds[i].cdev); + cancel_work_sync(&qt2160->leds[i].work); } +} - return error; +#else + +static inline int qt2160_register_leds(struct qt2160_data *qt2160) +{ + return 0; } +static inline void qt2160_unregister_leds(struct qt2160_data *qt2160) +{ +} -static bool __devinit qt2160_identify(struct i2c_client *client) +#endif + +static bool qt2160_identify(struct i2c_client *client) { int id, ver, rev; @@ -258,8 +374,8 @@ static bool __devinit qt2160_identify(struct i2c_client *client) return true; } -static int __devinit qt2160_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int qt2160_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct qt2160_data *qt2160; struct input_dev *input; @@ -324,11 +440,17 @@ static int __devinit qt2160_probe(struct i2c_client *client, } } + error = qt2160_register_leds(qt2160); + if (error) { + dev_err(&client->dev, "Failed to register leds\n"); + goto err_free_irq; + } + error = input_register_device(qt2160->input); if (error) { dev_err(&client->dev, "Failed to register input device\n"); - goto err_free_irq; + goto err_unregister_leds; } i2c_set_clientdata(client, qt2160); @@ -336,6 +458,8 @@ static int __devinit qt2160_probe(struct i2c_client *client, return 0; +err_unregister_leds: + qt2160_unregister_leds(qt2160); err_free_irq: if (client->irq) free_irq(client->irq, qt2160); @@ -345,10 +469,12 @@ err_free_mem: return error; } -static int __devexit qt2160_remove(struct i2c_client *client) +static int qt2160_remove(struct i2c_client *client) { struct qt2160_data *qt2160 = i2c_get_clientdata(client); + qt2160_unregister_leds(qt2160); + /* Release IRQ so no queue will be scheduled */ if (client->irq) free_irq(client->irq, qt2160); @@ -376,20 +502,10 @@ static struct i2c_driver qt2160_driver = { .id_table = qt2160_idtable, .probe = qt2160_probe, - .remove = __devexit_p(qt2160_remove), + .remove = qt2160_remove, }; -static int __init qt2160_init(void) -{ - return i2c_add_driver(&qt2160_driver); -} -module_init(qt2160_init); - -static void __exit qt2160_cleanup(void) -{ - i2c_del_driver(&qt2160_driver); -} -module_exit(qt2160_cleanup); +module_i2c_driver(qt2160_driver); MODULE_AUTHOR("Raphael Derosso Pereira <raphaelpereira@gmail.com>"); MODULE_DESCRIPTION("Driver for AT42QT2160 Touch Sensor"); diff --git a/drivers/input/keyboard/samsung-keypad.c b/drivers/input/keyboard/samsung-keypad.c index f689f49e310..5e80fbf7b5e 100644 --- a/drivers/input/keyboard/samsung-keypad.c +++ b/drivers/input/keyboard/samsung-keypad.c @@ -14,15 +14,17 @@ #include <linux/clk.h> #include <linux/delay.h> #include <linux/err.h> -#include <linux/init.h> #include <linux/input.h> #include <linux/interrupt.h> #include <linux/io.h> #include <linux/module.h> #include <linux/platform_device.h> +#include <linux/pm.h> +#include <linux/pm_runtime.h> #include <linux/slab.h> +#include <linux/of.h> #include <linux/sched.h> -#include <plat/keypad.h> +#include <linux/input/samsung-keypad.h> #define SAMSUNG_KEYIFCON 0x00 #define SAMSUNG_KEYIFSTSCLR 0x04 @@ -63,11 +65,14 @@ enum samsung_keypad_type { struct samsung_keypad { struct input_dev *input_dev; + struct platform_device *pdev; struct clk *clk; void __iomem *base; wait_queue_head_t wait; bool stopped; + bool wake_enabled; int irq; + enum samsung_keypad_type type; unsigned int row_shift; unsigned int rows; unsigned int cols; @@ -75,24 +80,14 @@ struct samsung_keypad { unsigned short keycodes[]; }; -static int samsung_keypad_is_s5pv210(struct device *dev) -{ - struct platform_device *pdev = to_platform_device(dev); - enum samsung_keypad_type type = - platform_get_device_id(pdev)->driver_data; - - return type == KEYPAD_TYPE_S5PV210; -} - static void samsung_keypad_scan(struct samsung_keypad *keypad, unsigned int *row_state) { - struct device *dev = keypad->input_dev->dev.parent; unsigned int col; unsigned int val; for (col = 0; col < keypad->cols; col++) { - if (samsung_keypad_is_s5pv210(dev)) { + if (keypad->type == KEYPAD_TYPE_S5PV210) { val = S5PV210_KEYIFCOLEN_MASK; val &= ~(1 << col) << 8; } else { @@ -158,6 +153,8 @@ static irqreturn_t samsung_keypad_irq(int irq, void *dev_id) unsigned int val; bool key_down; + pm_runtime_get_sync(&keypad->pdev->dev); + do { val = readl(keypad->base + SAMSUNG_KEYIFSTSCLR); /* Clear interrupt. */ @@ -172,6 +169,8 @@ static irqreturn_t samsung_keypad_irq(int irq, void *dev_id) } while (key_down && !keypad->stopped); + pm_runtime_put(&keypad->pdev->dev); + return IRQ_HANDLED; } @@ -179,6 +178,8 @@ static void samsung_keypad_start(struct samsung_keypad *keypad) { unsigned int val; + pm_runtime_get_sync(&keypad->pdev->dev); + /* Tell IRQ thread that it may poll the device. */ keypad->stopped = false; @@ -191,12 +192,16 @@ static void samsung_keypad_start(struct samsung_keypad *keypad) /* KEYIFCOL reg clear. */ writel(0, keypad->base + SAMSUNG_KEYIFCOL); + + pm_runtime_put(&keypad->pdev->dev); } static void samsung_keypad_stop(struct samsung_keypad *keypad) { unsigned int val; + pm_runtime_get_sync(&keypad->pdev->dev); + /* Signal IRQ thread to stop polling and disable the handler. */ keypad->stopped = true; wake_up(&keypad->wait); @@ -217,6 +222,8 @@ static void samsung_keypad_stop(struct samsung_keypad *keypad) * re-enable the handler. */ enable_irq(keypad->irq); + + pm_runtime_put(&keypad->pdev->dev); } static int samsung_keypad_open(struct input_dev *input_dev) @@ -235,7 +242,79 @@ static void samsung_keypad_close(struct input_dev *input_dev) samsung_keypad_stop(keypad); } -static int __devinit samsung_keypad_probe(struct platform_device *pdev) +#ifdef CONFIG_OF +static struct samsung_keypad_platdata * +samsung_keypad_parse_dt(struct device *dev) +{ + struct samsung_keypad_platdata *pdata; + struct matrix_keymap_data *keymap_data; + uint32_t *keymap, num_rows = 0, num_cols = 0; + struct device_node *np = dev->of_node, *key_np; + unsigned int key_count; + + if (!np) { + dev_err(dev, "missing device tree data\n"); + return ERR_PTR(-EINVAL); + } + + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) { + dev_err(dev, "could not allocate memory for platform data\n"); + return ERR_PTR(-ENOMEM); + } + + of_property_read_u32(np, "samsung,keypad-num-rows", &num_rows); + of_property_read_u32(np, "samsung,keypad-num-columns", &num_cols); + if (!num_rows || !num_cols) { + dev_err(dev, "number of keypad rows/columns not specified\n"); + return ERR_PTR(-EINVAL); + } + pdata->rows = num_rows; + pdata->cols = num_cols; + + keymap_data = devm_kzalloc(dev, sizeof(*keymap_data), GFP_KERNEL); + if (!keymap_data) { + dev_err(dev, "could not allocate memory for keymap data\n"); + return ERR_PTR(-ENOMEM); + } + pdata->keymap_data = keymap_data; + + key_count = of_get_child_count(np); + keymap_data->keymap_size = key_count; + keymap = devm_kzalloc(dev, sizeof(uint32_t) * key_count, GFP_KERNEL); + if (!keymap) { + dev_err(dev, "could not allocate memory for keymap\n"); + return ERR_PTR(-ENOMEM); + } + keymap_data->keymap = keymap; + + for_each_child_of_node(np, key_np) { + u32 row, col, key_code; + of_property_read_u32(key_np, "keypad,row", &row); + of_property_read_u32(key_np, "keypad,column", &col); + of_property_read_u32(key_np, "linux,code", &key_code); + *keymap++ = KEY(row, col, key_code); + } + + if (of_get_property(np, "linux,input-no-autorepeat", NULL)) + pdata->no_autorepeat = true; + + if (of_get_property(np, "linux,input-wakeup", NULL)) + pdata->wakeup = true; + + return pdata; +} +#else +static struct samsung_keypad_platdata * +samsung_keypad_parse_dt(struct device *dev) +{ + dev_err(dev, "no platform data defined\n"); + + return ERR_PTR(-EINVAL); +} +#endif + +static int samsung_keypad_probe(struct platform_device *pdev) { const struct samsung_keypad_platdata *pdata; const struct matrix_keymap_data *keymap_data; @@ -246,10 +325,11 @@ static int __devinit samsung_keypad_probe(struct platform_device *pdev) unsigned int keymap_size; int error; - pdata = pdev->dev.platform_data; + pdata = dev_get_platdata(&pdev->dev); if (!pdata) { - dev_err(&pdev->dev, "no platform data defined\n"); - return -EINVAL; + pdata = samsung_keypad_parse_dt(&pdev->dev); + if (IS_ERR(pdata)) + return PTR_ERR(pdata); } keymap_data = pdata->keymap_data; @@ -271,121 +351,169 @@ static int __devinit samsung_keypad_probe(struct platform_device *pdev) row_shift = get_count_order(pdata->cols); keymap_size = (pdata->rows << row_shift) * sizeof(keypad->keycodes[0]); - keypad = kzalloc(sizeof(*keypad) + keymap_size, GFP_KERNEL); - input_dev = input_allocate_device(); - if (!keypad || !input_dev) { - error = -ENOMEM; - goto err_free_mem; - } + keypad = devm_kzalloc(&pdev->dev, sizeof(*keypad) + keymap_size, + GFP_KERNEL); + input_dev = devm_input_allocate_device(&pdev->dev); + if (!keypad || !input_dev) + return -ENOMEM; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - error = -ENODEV; - goto err_free_mem; - } + if (!res) + return -ENODEV; - keypad->base = ioremap(res->start, resource_size(res)); - if (!keypad->base) { - error = -EBUSY; - goto err_free_mem; - } + keypad->base = devm_ioremap(&pdev->dev, res->start, resource_size(res)); + if (!keypad->base) + return -EBUSY; - keypad->clk = clk_get(&pdev->dev, "keypad"); + keypad->clk = devm_clk_get(&pdev->dev, "keypad"); if (IS_ERR(keypad->clk)) { dev_err(&pdev->dev, "failed to get keypad clk\n"); - error = PTR_ERR(keypad->clk); - goto err_unmap_base; + return PTR_ERR(keypad->clk); + } + + error = clk_prepare(keypad->clk); + if (error) { + dev_err(&pdev->dev, "keypad clock prepare failed\n"); + return error; } keypad->input_dev = input_dev; + keypad->pdev = pdev; keypad->row_shift = row_shift; keypad->rows = pdata->rows; keypad->cols = pdata->cols; + keypad->stopped = true; init_waitqueue_head(&keypad->wait); + if (pdev->dev.of_node) + keypad->type = of_device_is_compatible(pdev->dev.of_node, + "samsung,s5pv210-keypad"); + else + keypad->type = platform_get_device_id(pdev)->driver_data; + input_dev->name = pdev->name; input_dev->id.bustype = BUS_HOST; input_dev->dev.parent = &pdev->dev; - input_set_drvdata(input_dev, keypad); input_dev->open = samsung_keypad_open; input_dev->close = samsung_keypad_close; - input_dev->evbit[0] = BIT_MASK(EV_KEY); - if (!pdata->no_autorepeat) - input_dev->evbit[0] |= BIT_MASK(EV_REP); + error = matrix_keypad_build_keymap(keymap_data, NULL, + pdata->rows, pdata->cols, + keypad->keycodes, input_dev); + if (error) { + dev_err(&pdev->dev, "failed to build keymap\n"); + goto err_unprepare_clk; + } input_set_capability(input_dev, EV_MSC, MSC_SCAN); + if (!pdata->no_autorepeat) + __set_bit(EV_REP, input_dev->evbit); - input_dev->keycode = keypad->keycodes; - input_dev->keycodesize = sizeof(keypad->keycodes[0]); - input_dev->keycodemax = pdata->rows << row_shift; - - matrix_keypad_build_keymap(keymap_data, row_shift, - input_dev->keycode, input_dev->keybit); + input_set_drvdata(input_dev, keypad); keypad->irq = platform_get_irq(pdev, 0); if (keypad->irq < 0) { error = keypad->irq; - goto err_put_clk; + goto err_unprepare_clk; } - error = request_threaded_irq(keypad->irq, NULL, samsung_keypad_irq, - IRQF_ONESHOT, dev_name(&pdev->dev), keypad); + error = devm_request_threaded_irq(&pdev->dev, keypad->irq, NULL, + samsung_keypad_irq, IRQF_ONESHOT, + dev_name(&pdev->dev), keypad); if (error) { dev_err(&pdev->dev, "failed to register keypad interrupt\n"); - goto err_put_clk; + goto err_unprepare_clk; } + device_init_wakeup(&pdev->dev, pdata->wakeup); + platform_set_drvdata(pdev, keypad); + pm_runtime_enable(&pdev->dev); + error = input_register_device(keypad->input_dev); if (error) - goto err_free_irq; + goto err_disable_runtime_pm; - device_init_wakeup(&pdev->dev, pdata->wakeup); - platform_set_drvdata(pdev, keypad); + if (pdev->dev.of_node) { + devm_kfree(&pdev->dev, (void *)pdata->keymap_data->keymap); + devm_kfree(&pdev->dev, (void *)pdata->keymap_data); + devm_kfree(&pdev->dev, (void *)pdata); + } return 0; -err_free_irq: - free_irq(keypad->irq, keypad); -err_put_clk: - clk_put(keypad->clk); -err_unmap_base: - iounmap(keypad->base); -err_free_mem: - input_free_device(input_dev); - kfree(keypad); - +err_disable_runtime_pm: + pm_runtime_disable(&pdev->dev); + device_init_wakeup(&pdev->dev, 0); +err_unprepare_clk: + clk_unprepare(keypad->clk); return error; } -static int __devexit samsung_keypad_remove(struct platform_device *pdev) +static int samsung_keypad_remove(struct platform_device *pdev) { struct samsung_keypad *keypad = platform_get_drvdata(pdev); + pm_runtime_disable(&pdev->dev); device_init_wakeup(&pdev->dev, 0); - platform_set_drvdata(pdev, NULL); input_unregister_device(keypad->input_dev); - /* - * It is safe to free IRQ after unregistering device because - * samsung_keypad_close will shut off interrupts. - */ - free_irq(keypad->irq, keypad); + clk_unprepare(keypad->clk); - clk_put(keypad->clk); + return 0; +} - iounmap(keypad->base); - kfree(keypad); +#ifdef CONFIG_PM_RUNTIME +static int samsung_keypad_runtime_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct samsung_keypad *keypad = platform_get_drvdata(pdev); + unsigned int val; + int error; + + if (keypad->stopped) + return 0; + + /* This may fail on some SoCs due to lack of controller support */ + error = enable_irq_wake(keypad->irq); + if (!error) + keypad->wake_enabled = true; + + val = readl(keypad->base + SAMSUNG_KEYIFCON); + val |= SAMSUNG_KEYIFCON_WAKEUPEN; + writel(val, keypad->base + SAMSUNG_KEYIFCON); + + clk_disable(keypad->clk); return 0; } -#ifdef CONFIG_PM +static int samsung_keypad_runtime_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct samsung_keypad *keypad = platform_get_drvdata(pdev); + unsigned int val; + + if (keypad->stopped) + return 0; + + clk_enable(keypad->clk); + + val = readl(keypad->base + SAMSUNG_KEYIFCON); + val &= ~SAMSUNG_KEYIFCON_WAKEUPEN; + writel(val, keypad->base + SAMSUNG_KEYIFCON); + + if (keypad->wake_enabled) + disable_irq_wake(keypad->irq); + + return 0; +} +#endif + +#ifdef CONFIG_PM_SLEEP static void samsung_keypad_toggle_wakeup(struct samsung_keypad *keypad, bool enable) { - struct device *dev = keypad->input_dev->dev.parent; unsigned int val; clk_enable(keypad->clk); @@ -393,11 +521,11 @@ static void samsung_keypad_toggle_wakeup(struct samsung_keypad *keypad, val = readl(keypad->base + SAMSUNG_KEYIFCON); if (enable) { val |= SAMSUNG_KEYIFCON_WAKEUPEN; - if (device_may_wakeup(dev)) + if (device_may_wakeup(&keypad->pdev->dev)) enable_irq_wake(keypad->irq); } else { val &= ~SAMSUNG_KEYIFCON_WAKEUPEN; - if (device_may_wakeup(dev)) + if (device_may_wakeup(&keypad->pdev->dev)) disable_irq_wake(keypad->irq); } writel(val, keypad->base + SAMSUNG_KEYIFCON); @@ -440,11 +568,21 @@ static int samsung_keypad_resume(struct device *dev) return 0; } +#endif static const struct dev_pm_ops samsung_keypad_pm_ops = { - .suspend = samsung_keypad_suspend, - .resume = samsung_keypad_resume, + SET_SYSTEM_SLEEP_PM_OPS(samsung_keypad_suspend, samsung_keypad_resume) + SET_RUNTIME_PM_OPS(samsung_keypad_runtime_suspend, + samsung_keypad_runtime_resume, NULL) }; + +#ifdef CONFIG_OF +static const struct of_device_id samsung_keypad_dt_match[] = { + { .compatible = "samsung,s3c6410-keypad" }, + { .compatible = "samsung,s5pv210-keypad" }, + {}, +}; +MODULE_DEVICE_TABLE(of, samsung_keypad_dt_match); #endif static struct platform_device_id samsung_keypad_driver_ids[] = { @@ -461,31 +599,18 @@ MODULE_DEVICE_TABLE(platform, samsung_keypad_driver_ids); static struct platform_driver samsung_keypad_driver = { .probe = samsung_keypad_probe, - .remove = __devexit_p(samsung_keypad_remove), + .remove = samsung_keypad_remove, .driver = { .name = "samsung-keypad", .owner = THIS_MODULE, -#ifdef CONFIG_PM + .of_match_table = of_match_ptr(samsung_keypad_dt_match), .pm = &samsung_keypad_pm_ops, -#endif }, .id_table = samsung_keypad_driver_ids, }; - -static int __init samsung_keypad_init(void) -{ - return platform_driver_register(&samsung_keypad_driver); -} -module_init(samsung_keypad_init); - -static void __exit samsung_keypad_exit(void) -{ - platform_driver_unregister(&samsung_keypad_driver); -} -module_exit(samsung_keypad_exit); +module_platform_driver(samsung_keypad_driver); MODULE_DESCRIPTION("Samsung keypad driver"); MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>"); MODULE_AUTHOR("Donghwa Lee <dh09.lee@samsung.com>"); MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:samsung-keypad"); diff --git a/drivers/input/keyboard/sh_keysc.c b/drivers/input/keyboard/sh_keysc.c index 834cf98e7ef..7abf03b4cc9 100644 --- a/drivers/input/keyboard/sh_keysc.c +++ b/drivers/input/keyboard/sh_keysc.c @@ -12,7 +12,6 @@ #include <linux/kernel.h> #include <linux/module.h> -#include <linux/init.h> #include <linux/interrupt.h> #include <linux/irq.h> #include <linux/delay.h> @@ -32,7 +31,7 @@ static const struct { [SH_KEYSC_MODE_3] = { 2, 4, 7 }, [SH_KEYSC_MODE_4] = { 3, 6, 6 }, [SH_KEYSC_MODE_5] = { 4, 6, 7 }, - [SH_KEYSC_MODE_6] = { 5, 7, 7 }, + [SH_KEYSC_MODE_6] = { 5, 8, 8 }, }; struct sh_keysc_priv { @@ -162,7 +161,7 @@ static irqreturn_t sh_keysc_isr(int irq, void *dev_id) return IRQ_HANDLED; } -static int __devinit sh_keysc_probe(struct platform_device *pdev) +static int sh_keysc_probe(struct platform_device *pdev) { struct sh_keysc_priv *priv; struct sh_keysc_info *pdata; @@ -171,7 +170,7 @@ static int __devinit sh_keysc_probe(struct platform_device *pdev) int i; int irq, error; - if (!pdev->dev.platform_data) { + if (!dev_get_platdata(&pdev->dev)) { dev_err(&pdev->dev, "no platform data defined\n"); error = -EINVAL; goto err0; @@ -198,7 +197,7 @@ static int __devinit sh_keysc_probe(struct platform_device *pdev) } platform_set_drvdata(pdev, priv); - memcpy(&priv->pdata, pdev->dev.platform_data, sizeof(priv->pdata)); + memcpy(&priv->pdata, dev_get_platdata(&pdev->dev), sizeof(priv->pdata)); pdata = &priv->pdata; priv->iomem_base = ioremap_nocache(res->start, resource_size(res)); @@ -266,13 +265,12 @@ static int __devinit sh_keysc_probe(struct platform_device *pdev) err2: iounmap(priv->iomem_base); err1: - platform_set_drvdata(pdev, NULL); kfree(priv); err0: return error; } -static int __devexit sh_keysc_remove(struct platform_device *pdev) +static int sh_keysc_remove(struct platform_device *pdev) { struct sh_keysc_priv *priv = platform_get_drvdata(pdev); @@ -285,13 +283,12 @@ static int __devexit 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; } -#if CONFIG_PM_SLEEP +#ifdef CONFIG_PM_SLEEP static int sh_keysc_suspend(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); @@ -331,25 +328,13 @@ static SIMPLE_DEV_PM_OPS(sh_keysc_dev_pm_ops, static struct platform_driver sh_keysc_device_driver = { .probe = sh_keysc_probe, - .remove = __devexit_p(sh_keysc_remove), + .remove = sh_keysc_remove, .driver = { .name = "sh_keysc", .pm = &sh_keysc_dev_pm_ops, } }; - -static int __init sh_keysc_init(void) -{ - return platform_driver_register(&sh_keysc_device_driver); -} - -static void __exit sh_keysc_exit(void) -{ - platform_driver_unregister(&sh_keysc_device_driver); -} - -module_init(sh_keysc_init); -module_exit(sh_keysc_exit); +module_platform_driver(sh_keysc_device_driver); MODULE_AUTHOR("Magnus Damm"); MODULE_DESCRIPTION("SuperH KEYSC Keypad Driver"); diff --git a/drivers/input/keyboard/spear-keyboard.c b/drivers/input/keyboard/spear-keyboard.c index d712dffd215..258af10e581 100644 --- a/drivers/input/keyboard/spear-keyboard.c +++ b/drivers/input/keyboard/spear-keyboard.c @@ -12,53 +12,58 @@ #include <linux/clk.h> #include <linux/errno.h> -#include <linux/init.h> #include <linux/interrupt.h> #include <linux/input.h> #include <linux/io.h> #include <linux/irq.h> #include <linux/kernel.h> #include <linux/module.h> +#include <linux/of.h> #include <linux/platform_device.h> #include <linux/pm_wakeup.h> #include <linux/slab.h> #include <linux/types.h> -#include <plat/keyboard.h> +#include <linux/platform_data/keyboard-spear.h> /* Keyboard Registers */ -#define MODE_REG 0x00 /* 16 bit reg */ -#define STATUS_REG 0x0C /* 2 bit reg */ -#define DATA_REG 0x10 /* 8 bit reg */ +#define MODE_CTL_REG 0x00 +#define STATUS_REG 0x0C +#define DATA_REG 0x10 #define INTR_MASK 0x54 /* Register Values */ -/* - * pclk freq mask = (APB FEQ -1)= 82 MHZ.Programme bit 15-9 in mode - * control register as 1010010(82MHZ) - */ -#define PCLK_FREQ_MSK 0xA400 /* 82 MHz */ -#define START_SCAN 0x0100 -#define SCAN_RATE_10 0x0000 -#define SCAN_RATE_20 0x0004 -#define SCAN_RATE_40 0x0008 -#define SCAN_RATE_80 0x000C -#define MODE_KEYBOARD 0x0002 -#define DATA_AVAIL 0x2 - -#define KEY_MASK 0xFF000000 -#define KEY_VALUE 0x00FFFFFF -#define ROW_MASK 0xF0 -#define COLUMN_MASK 0x0F -#define ROW_SHIFT 4 +#define NUM_ROWS 16 +#define NUM_COLS 16 +#define MODE_CTL_PCLK_FREQ_SHIFT 9 +#define MODE_CTL_PCLK_FREQ_MSK 0x7F + +#define MODE_CTL_KEYBOARD (0x2 << 0) +#define MODE_CTL_SCAN_RATE_10 (0x0 << 2) +#define MODE_CTL_SCAN_RATE_20 (0x1 << 2) +#define MODE_CTL_SCAN_RATE_40 (0x2 << 2) +#define MODE_CTL_SCAN_RATE_80 (0x3 << 2) +#define MODE_CTL_KEYNUM_SHIFT 6 +#define MODE_CTL_START_SCAN (0x1 << 8) + +#define STATUS_DATA_AVAIL (0x1 << 1) + +#define DATA_ROW_MASK 0xF0 +#define DATA_COLUMN_MASK 0x0F + +#define ROW_SHIFT 4 struct spear_kbd { struct input_dev *input; - struct resource *res; void __iomem *io_base; struct clk *clk; unsigned int irq; + unsigned int mode; + unsigned int suspended_rate; unsigned short last_key; - unsigned short keycodes[256]; + unsigned short keycodes[NUM_ROWS * NUM_COLS]; + bool rep; + bool irq_wake_enabled; + u32 mode_ctl_reg; }; static irqreturn_t spear_kbd_interrupt(int irq, void *dev_id) @@ -66,10 +71,10 @@ static irqreturn_t spear_kbd_interrupt(int irq, void *dev_id) struct spear_kbd *kbd = dev_id; struct input_dev *input = kbd->input; unsigned int key; - u8 sts, val; + u32 sts, val; - sts = readb(kbd->io_base + STATUS_REG); - if (!(sts & DATA_AVAIL)) + sts = readl_relaxed(kbd->io_base + STATUS_REG); + if (!(sts & STATUS_DATA_AVAIL)) return IRQ_NONE; if (kbd->last_key != KEY_RESERVED) { @@ -78,7 +83,8 @@ static irqreturn_t spear_kbd_interrupt(int irq, void *dev_id) } /* following reads active (row, col) pair */ - val = readb(kbd->io_base + DATA_REG); + val = readl_relaxed(kbd->io_base + DATA_REG) & + (DATA_ROW_MASK | DATA_COLUMN_MASK); key = kbd->keycodes[val]; input_event(input, EV_MSC, MSC_SCAN, val); @@ -88,7 +94,7 @@ static irqreturn_t spear_kbd_interrupt(int irq, void *dev_id) kbd->last_key = key; /* clear interrupt */ - writeb(0, kbd->io_base + STATUS_REG); + writel_relaxed(0, kbd->io_base + STATUS_REG); return IRQ_HANDLED; } @@ -97,7 +103,7 @@ static int spear_kbd_open(struct input_dev *dev) { struct spear_kbd *kbd = input_get_drvdata(dev); int error; - u16 val; + u32 val; kbd->last_key = KEY_RESERVED; @@ -105,15 +111,20 @@ static int spear_kbd_open(struct input_dev *dev) if (error) return error; + /* keyboard rate to be programmed is input clock (in MHz) - 1 */ + val = clk_get_rate(kbd->clk) / 1000000 - 1; + val = (val & MODE_CTL_PCLK_FREQ_MSK) << MODE_CTL_PCLK_FREQ_SHIFT; + /* program keyboard */ - val = SCAN_RATE_80 | MODE_KEYBOARD | PCLK_FREQ_MSK; - writew(val, kbd->io_base + MODE_REG); - writeb(1, kbd->io_base + STATUS_REG); + val = MODE_CTL_SCAN_RATE_80 | MODE_CTL_KEYBOARD | val | + (kbd->mode << MODE_CTL_KEYNUM_SHIFT); + writel_relaxed(val, kbd->io_base + MODE_CTL_REG); + writel_relaxed(1, kbd->io_base + STATUS_REG); /* start key scan */ - val = readw(kbd->io_base + MODE_REG); - val |= START_SCAN; - writew(val, kbd->io_base + MODE_REG); + val = readl_relaxed(kbd->io_base + MODE_CTL_REG); + val |= MODE_CTL_START_SCAN; + writel_relaxed(val, kbd->io_base + MODE_CTL_REG); return 0; } @@ -121,85 +132,106 @@ static int spear_kbd_open(struct input_dev *dev) static void spear_kbd_close(struct input_dev *dev) { struct spear_kbd *kbd = input_get_drvdata(dev); - u16 val; + u32 val; /* stop key scan */ - val = readw(kbd->io_base + MODE_REG); - val &= ~START_SCAN; - writew(val, kbd->io_base + MODE_REG); + val = readl_relaxed(kbd->io_base + MODE_CTL_REG); + val &= ~MODE_CTL_START_SCAN; + writel_relaxed(val, kbd->io_base + MODE_CTL_REG); clk_disable(kbd->clk); kbd->last_key = KEY_RESERVED; } -static int __devinit spear_kbd_probe(struct platform_device *pdev) +#ifdef CONFIG_OF +static int spear_kbd_parse_dt(struct platform_device *pdev, + struct spear_kbd *kbd) { - const struct kbd_platform_data *pdata = pdev->dev.platform_data; - const struct matrix_keymap_data *keymap; - struct spear_kbd *kbd; - struct input_dev *input_dev; - struct resource *res; - int irq; + struct device_node *np = pdev->dev.of_node; int error; + u32 val, suspended_rate; - if (!pdata) { - dev_err(&pdev->dev, "Invalid platform data\n"); + if (!np) { + dev_err(&pdev->dev, "Missing DT data\n"); return -EINVAL; } - keymap = pdata->keymap; - if (!keymap) { - dev_err(&pdev->dev, "no keymap defined\n"); - return -EINVAL; - } + if (of_property_read_bool(np, "autorepeat")) + kbd->rep = true; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "no keyboard resource defined\n"); - return -EBUSY; + if (of_property_read_u32(np, "suspended_rate", &suspended_rate)) + kbd->suspended_rate = suspended_rate; + + error = of_property_read_u32(np, "st,mode", &val); + if (error) { + dev_err(&pdev->dev, "DT: Invalid or missing mode\n"); + return error; } + kbd->mode = val; + return 0; +} +#else +static inline int spear_kbd_parse_dt(struct platform_device *pdev, + struct spear_kbd *kbd) +{ + return -ENOSYS; +} +#endif + +static int spear_kbd_probe(struct platform_device *pdev) +{ + struct kbd_platform_data *pdata = dev_get_platdata(&pdev->dev); + const struct matrix_keymap_data *keymap = pdata ? pdata->keymap : NULL; + struct spear_kbd *kbd; + struct input_dev *input_dev; + struct resource *res; + int irq; + int error; + irq = platform_get_irq(pdev, 0); if (irq < 0) { dev_err(&pdev->dev, "not able to get irq for the device\n"); return irq; } - kbd = kzalloc(sizeof(*kbd), GFP_KERNEL); - input_dev = input_allocate_device(); - if (!kbd || !input_dev) { - dev_err(&pdev->dev, "out of memory\n"); - error = -ENOMEM; - goto err_free_mem; + kbd = devm_kzalloc(&pdev->dev, sizeof(*kbd), GFP_KERNEL); + if (!kbd) { + dev_err(&pdev->dev, "not enough memory for driver data\n"); + return -ENOMEM; + } + + input_dev = devm_input_allocate_device(&pdev->dev); + if (!input_dev) { + dev_err(&pdev->dev, "unable to allocate input device\n"); + return -ENOMEM; } kbd->input = input_dev; kbd->irq = irq; - kbd->res = request_mem_region(res->start, resource_size(res), - pdev->name); - if (!kbd->res) { - dev_err(&pdev->dev, "keyboard region already claimed\n"); - error = -EBUSY; - goto err_free_mem; - } - kbd->io_base = ioremap(res->start, resource_size(res)); - if (!kbd->io_base) { - dev_err(&pdev->dev, "ioremap failed for kbd_region\n"); - error = -ENOMEM; - goto err_release_mem_region; + if (!pdata) { + error = spear_kbd_parse_dt(pdev, kbd); + if (error) + return error; + } else { + kbd->mode = pdata->mode; + kbd->rep = pdata->rep; + kbd->suspended_rate = pdata->suspended_rate; } - kbd->clk = clk_get(&pdev->dev, NULL); - if (IS_ERR(kbd->clk)) { - error = PTR_ERR(kbd->clk); - goto err_iounmap; - } + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + kbd->io_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(kbd->io_base)) + return PTR_ERR(kbd->io_base); + + kbd->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(kbd->clk)) + return PTR_ERR(kbd->clk); input_dev->name = "Spear Keyboard"; input_dev->phys = "keyboard/input0"; - input_dev->dev.parent = &pdev->dev; input_dev->id.bustype = BUS_HOST; input_dev->id.vendor = 0x0001; input_dev->id.product = 0x0001; @@ -207,65 +239,51 @@ static int __devinit spear_kbd_probe(struct platform_device *pdev) input_dev->open = spear_kbd_open; input_dev->close = spear_kbd_close; - __set_bit(EV_KEY, input_dev->evbit); - if (pdata->rep) + error = matrix_keypad_build_keymap(keymap, NULL, NUM_ROWS, NUM_COLS, + kbd->keycodes, input_dev); + if (error) { + dev_err(&pdev->dev, "Failed to build keymap\n"); + return error; + } + + if (kbd->rep) __set_bit(EV_REP, input_dev->evbit); input_set_capability(input_dev, EV_MSC, MSC_SCAN); - input_dev->keycode = kbd->keycodes; - input_dev->keycodesize = sizeof(kbd->keycodes[0]); - input_dev->keycodemax = ARRAY_SIZE(kbd->keycodes); - - matrix_keypad_build_keymap(keymap, ROW_SHIFT, - input_dev->keycode, input_dev->keybit); - input_set_drvdata(input_dev, kbd); - error = request_irq(irq, spear_kbd_interrupt, 0, "keyboard", kbd); + error = devm_request_irq(&pdev->dev, irq, spear_kbd_interrupt, 0, + "keyboard", kbd); if (error) { - dev_err(&pdev->dev, "request_irq fail\n"); - goto err_put_clk; + dev_err(&pdev->dev, "request_irq failed\n"); + return error; } + error = clk_prepare(kbd->clk); + if (error) + return error; + error = input_register_device(input_dev); if (error) { dev_err(&pdev->dev, "Unable to register keyboard device\n"); - goto err_free_irq; + clk_unprepare(kbd->clk); + return error; } device_init_wakeup(&pdev->dev, 1); platform_set_drvdata(pdev, kbd); return 0; - -err_free_irq: - free_irq(kbd->irq, kbd); -err_put_clk: - clk_put(kbd->clk); -err_iounmap: - iounmap(kbd->io_base); -err_release_mem_region: - release_mem_region(res->start, resource_size(res)); -err_free_mem: - input_free_device(input_dev); - kfree(kbd); - - return error; } -static int __devexit spear_kbd_remove(struct platform_device *pdev) +static int spear_kbd_remove(struct platform_device *pdev) { struct spear_kbd *kbd = platform_get_drvdata(pdev); - free_irq(kbd->irq, kbd); input_unregister_device(kbd->input); - clk_put(kbd->clk); - iounmap(kbd->io_base); - release_mem_region(kbd->res->start, resource_size(kbd->res)); - kfree(kbd); + clk_unprepare(kbd->clk); - device_init_wakeup(&pdev->dev, 1); - platform_set_drvdata(pdev, NULL); + device_init_wakeup(&pdev->dev, 0); return 0; } @@ -276,14 +294,48 @@ static int spear_kbd_suspend(struct device *dev) struct platform_device *pdev = to_platform_device(dev); struct spear_kbd *kbd = platform_get_drvdata(pdev); struct input_dev *input_dev = kbd->input; + unsigned int rate = 0, mode_ctl_reg, val; mutex_lock(&input_dev->mutex); + /* explicitly enable clock as we may program device */ + clk_enable(kbd->clk); + + mode_ctl_reg = readl_relaxed(kbd->io_base + MODE_CTL_REG); + + if (device_may_wakeup(&pdev->dev)) { + if (!enable_irq_wake(kbd->irq)) + kbd->irq_wake_enabled = true; + + /* + * reprogram the keyboard operating frequency as on some + * platform it may change during system suspended + */ + if (kbd->suspended_rate) + rate = kbd->suspended_rate / 1000000 - 1; + else + rate = clk_get_rate(kbd->clk) / 1000000 - 1; + + val = mode_ctl_reg & + ~(MODE_CTL_PCLK_FREQ_MSK << MODE_CTL_PCLK_FREQ_SHIFT); + val |= (rate & MODE_CTL_PCLK_FREQ_MSK) + << MODE_CTL_PCLK_FREQ_SHIFT; + writel_relaxed(val, kbd->io_base + MODE_CTL_REG); + + } else { + if (input_dev->users) { + writel_relaxed(mode_ctl_reg & ~MODE_CTL_START_SCAN, + kbd->io_base + MODE_CTL_REG); + clk_disable(kbd->clk); + } + } + + /* store current configuration */ if (input_dev->users) - clk_enable(kbd->clk); + kbd->mode_ctl_reg = mode_ctl_reg; - if (device_may_wakeup(&pdev->dev)) - enable_irq_wake(kbd->irq); + /* restore previous clk state */ + clk_disable(kbd->clk); mutex_unlock(&input_dev->mutex); @@ -298,46 +350,47 @@ static int spear_kbd_resume(struct device *dev) mutex_lock(&input_dev->mutex); - if (device_may_wakeup(&pdev->dev)) - disable_irq_wake(kbd->irq); + if (device_may_wakeup(&pdev->dev)) { + if (kbd->irq_wake_enabled) { + kbd->irq_wake_enabled = false; + disable_irq_wake(kbd->irq); + } + } else { + if (input_dev->users) + clk_enable(kbd->clk); + } + /* restore current configuration */ if (input_dev->users) - clk_enable(kbd->clk); + writel_relaxed(kbd->mode_ctl_reg, kbd->io_base + MODE_CTL_REG); mutex_unlock(&input_dev->mutex); return 0; } +#endif + +static SIMPLE_DEV_PM_OPS(spear_kbd_pm_ops, spear_kbd_suspend, spear_kbd_resume); -static const struct dev_pm_ops spear_kbd_pm_ops = { - .suspend = spear_kbd_suspend, - .resume = spear_kbd_resume, +#ifdef CONFIG_OF +static const struct of_device_id spear_kbd_id_table[] = { + { .compatible = "st,spear300-kbd" }, + {} }; +MODULE_DEVICE_TABLE(of, spear_kbd_id_table); #endif static struct platform_driver spear_kbd_driver = { .probe = spear_kbd_probe, - .remove = __devexit_p(spear_kbd_remove), + .remove = spear_kbd_remove, .driver = { .name = "keyboard", .owner = THIS_MODULE, -#ifdef CONFIG_PM .pm = &spear_kbd_pm_ops, -#endif + .of_match_table = of_match_ptr(spear_kbd_id_table), }, }; - -static int __init spear_kbd_init(void) -{ - return platform_driver_register(&spear_kbd_driver); -} -module_init(spear_kbd_init); - -static void __exit spear_kbd_exit(void) -{ - platform_driver_unregister(&spear_kbd_driver); -} -module_exit(spear_kbd_exit); +module_platform_driver(spear_kbd_driver); MODULE_AUTHOR("Rajeev Kumar"); MODULE_DESCRIPTION("SPEAr Keyboard Driver"); diff --git a/drivers/input/keyboard/st-keyscan.c b/drivers/input/keyboard/st-keyscan.c new file mode 100644 index 00000000000..de7be4f03d9 --- /dev/null +++ b/drivers/input/keyboard/st-keyscan.c @@ -0,0 +1,276 @@ +/* + * STMicroelectronics Key Scanning driver + * + * Copyright (c) 2014 STMicroelectonics Ltd. + * Author: Stuart Menefy <stuart.menefy@st.com> + * + * Based on sh_keysc.c, copyright 2008 Magnus Damm + * + * 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/module.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/input/matrix_keypad.h> + +#define ST_KEYSCAN_MAXKEYS 16 + +#define KEYSCAN_CONFIG_OFF 0x0 +#define KEYSCAN_CONFIG_ENABLE 0x1 +#define KEYSCAN_DEBOUNCE_TIME_OFF 0x4 +#define KEYSCAN_MATRIX_STATE_OFF 0x8 +#define KEYSCAN_MATRIX_DIM_OFF 0xc +#define KEYSCAN_MATRIX_DIM_X_SHIFT 0x0 +#define KEYSCAN_MATRIX_DIM_Y_SHIFT 0x2 + +struct st_keyscan { + void __iomem *base; + int irq; + struct clk *clk; + struct input_dev *input_dev; + unsigned long last_state; + unsigned int n_rows; + unsigned int n_cols; + unsigned int debounce_us; +}; + +static irqreturn_t keyscan_isr(int irq, void *dev_id) +{ + struct st_keyscan *keypad = dev_id; + unsigned short *keycode = keypad->input_dev->keycode; + unsigned long state, change; + int bit_nr; + + state = readl(keypad->base + KEYSCAN_MATRIX_STATE_OFF) & 0xffff; + change = keypad->last_state ^ state; + keypad->last_state = state; + + for_each_set_bit(bit_nr, &change, BITS_PER_LONG) + input_report_key(keypad->input_dev, + keycode[bit_nr], state & BIT(bit_nr)); + + input_sync(keypad->input_dev); + + return IRQ_HANDLED; +} + +static int keyscan_start(struct st_keyscan *keypad) +{ + int error; + + error = clk_enable(keypad->clk); + if (error) + return error; + + writel(keypad->debounce_us * (clk_get_rate(keypad->clk) / 1000000), + keypad->base + KEYSCAN_DEBOUNCE_TIME_OFF); + + writel(((keypad->n_cols - 1) << KEYSCAN_MATRIX_DIM_X_SHIFT) | + ((keypad->n_rows - 1) << KEYSCAN_MATRIX_DIM_Y_SHIFT), + keypad->base + KEYSCAN_MATRIX_DIM_OFF); + + writel(KEYSCAN_CONFIG_ENABLE, keypad->base + KEYSCAN_CONFIG_OFF); + + return 0; +} + +static void keyscan_stop(struct st_keyscan *keypad) +{ + writel(0, keypad->base + KEYSCAN_CONFIG_OFF); + + clk_disable(keypad->clk); +} + +static int keyscan_open(struct input_dev *dev) +{ + struct st_keyscan *keypad = input_get_drvdata(dev); + + return keyscan_start(keypad); +} + +static void keyscan_close(struct input_dev *dev) +{ + struct st_keyscan *keypad = input_get_drvdata(dev); + + keyscan_stop(keypad); +} + +static int keypad_matrix_key_parse_dt(struct st_keyscan *keypad_data) +{ + struct device *dev = keypad_data->input_dev->dev.parent; + struct device_node *np = dev->of_node; + int error; + + error = matrix_keypad_parse_of_params(dev, &keypad_data->n_rows, + &keypad_data->n_cols); + if (error) { + dev_err(dev, "failed to parse keypad params\n"); + return error; + } + + of_property_read_u32(np, "st,debounce-us", &keypad_data->debounce_us); + + dev_dbg(dev, "n_rows=%d n_col=%d debounce=%d\n", + keypad_data->n_rows, keypad_data->n_cols, + keypad_data->debounce_us); + + return 0; +} + +static int keyscan_probe(struct platform_device *pdev) +{ + struct st_keyscan *keypad_data; + struct input_dev *input_dev; + struct resource *res; + int error; + + if (!pdev->dev.of_node) { + dev_err(&pdev->dev, "no DT data present\n"); + return -EINVAL; + } + + keypad_data = devm_kzalloc(&pdev->dev, sizeof(*keypad_data), + GFP_KERNEL); + if (!keypad_data) + return -ENOMEM; + + input_dev = devm_input_allocate_device(&pdev->dev); + if (!input_dev) { + dev_err(&pdev->dev, "failed to allocate the input device\n"); + return -ENOMEM; + } + + input_dev->name = pdev->name; + input_dev->phys = "keyscan-keys/input0"; + input_dev->dev.parent = &pdev->dev; + input_dev->open = keyscan_open; + input_dev->close = keyscan_close; + + input_dev->id.bustype = BUS_HOST; + + error = keypad_matrix_key_parse_dt(keypad_data); + if (error) + return error; + + error = matrix_keypad_build_keymap(NULL, NULL, + keypad_data->n_rows, + keypad_data->n_cols, + NULL, input_dev); + if (error) { + dev_err(&pdev->dev, "failed to build keymap\n"); + return error; + } + + input_set_drvdata(input_dev, keypad_data); + + keypad_data->input_dev = input_dev; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + keypad_data->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(keypad_data->base)) + return PTR_ERR(keypad_data->base); + + keypad_data->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(keypad_data->clk)) { + dev_err(&pdev->dev, "cannot get clock\n"); + return PTR_ERR(keypad_data->clk); + } + + error = clk_enable(keypad_data->clk); + if (error) { + dev_err(&pdev->dev, "failed to enable clock\n"); + return error; + } + + keyscan_stop(keypad_data); + + keypad_data->irq = platform_get_irq(pdev, 0); + if (keypad_data->irq < 0) { + dev_err(&pdev->dev, "no IRQ specified\n"); + return -EINVAL; + } + + error = devm_request_irq(&pdev->dev, keypad_data->irq, keyscan_isr, 0, + pdev->name, keypad_data); + if (error) { + dev_err(&pdev->dev, "failed to request IRQ\n"); + return error; + } + + error = input_register_device(input_dev); + if (error) { + dev_err(&pdev->dev, "failed to register input device\n"); + return error; + } + + platform_set_drvdata(pdev, keypad_data); + + device_set_wakeup_capable(&pdev->dev, 1); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int keyscan_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct st_keyscan *keypad = platform_get_drvdata(pdev); + struct input_dev *input = keypad->input_dev; + + mutex_lock(&input->mutex); + + if (device_may_wakeup(dev)) + enable_irq_wake(keypad->irq); + else if (input->users) + keyscan_stop(keypad); + + mutex_unlock(&input->mutex); + return 0; +} + +static int keyscan_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct st_keyscan *keypad = platform_get_drvdata(pdev); + struct input_dev *input = keypad->input_dev; + int retval = 0; + + mutex_lock(&input->mutex); + + if (device_may_wakeup(dev)) + disable_irq_wake(keypad->irq); + else if (input->users) + retval = keyscan_start(keypad); + + mutex_unlock(&input->mutex); + return retval; +} +#endif + +static SIMPLE_DEV_PM_OPS(keyscan_dev_pm_ops, keyscan_suspend, keyscan_resume); + +static const struct of_device_id keyscan_of_match[] = { + { .compatible = "st,sti-keyscan" }, + { }, +}; +MODULE_DEVICE_TABLE(of, keyscan_of_match); + +static struct platform_driver keyscan_device_driver = { + .probe = keyscan_probe, + .driver = { + .name = "st-keyscan", + .pm = &keyscan_dev_pm_ops, + .of_match_table = of_match_ptr(keyscan_of_match), + } +}; + +module_platform_driver(keyscan_device_driver); + +MODULE_AUTHOR("Stuart Menefy <stuart.menefy@st.com>"); +MODULE_DESCRIPTION("STMicroelectronics keyscan device driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/keyboard/stmpe-keypad.c b/drivers/input/keyboard/stmpe-keypad.c index ab7610ca10e..c6727dda68f 100644 --- a/drivers/input/keyboard/stmpe-keypad.c +++ b/drivers/input/keyboard/stmpe-keypad.c @@ -6,7 +6,6 @@ */ #include <linux/module.h> -#include <linux/init.h> #include <linux/slab.h> #include <linux/input.h> #include <linux/interrupt.h> @@ -166,7 +165,7 @@ static irqreturn_t stmpe_keypad_irq(int irq, void *dev) return IRQ_HANDLED; } -static int __devinit stmpe_keypad_altfunc_init(struct stmpe_keypad *keypad) +static int stmpe_keypad_altfunc_init(struct stmpe_keypad *keypad) { const struct stmpe_keypad_variant *variant = keypad->variant; unsigned int col_gpios = variant->col_gpios; @@ -207,7 +206,7 @@ static int __devinit stmpe_keypad_altfunc_init(struct stmpe_keypad *keypad) return stmpe_set_altfunc(stmpe, pins, STMPE_BLOCK_KEYPAD); } -static int __devinit stmpe_keypad_chip_init(struct stmpe_keypad *keypad) +static int stmpe_keypad_chip_init(struct stmpe_keypad *keypad) { const struct stmpe_keypad_platform_data *plat = keypad->plat; const struct stmpe_keypad_variant *variant = keypad->variant; @@ -257,107 +256,131 @@ static int __devinit stmpe_keypad_chip_init(struct stmpe_keypad *keypad) (plat->debounce_ms << 1)); } -static int __devinit stmpe_keypad_probe(struct platform_device *pdev) +static void stmpe_keypad_fill_used_pins(struct stmpe_keypad *keypad) { - struct stmpe *stmpe = dev_get_drvdata(pdev->dev.parent); + int row, col; + + for (row = 0; row < STMPE_KEYPAD_MAX_ROWS; row++) { + for (col = 0; col < STMPE_KEYPAD_MAX_COLS; col++) { + int code = MATRIX_SCAN_CODE(row, col, + STMPE_KEYPAD_ROW_SHIFT); + if (keypad->keymap[code] != KEY_RESERVED) { + keypad->rows |= 1 << row; + keypad->cols |= 1 << col; + } + } + } +} + +#ifdef CONFIG_OF +static const struct stmpe_keypad_platform_data * +stmpe_keypad_of_probe(struct device *dev) +{ + struct device_node *np = dev->of_node; struct stmpe_keypad_platform_data *plat; + + if (!np) + return ERR_PTR(-ENODEV); + + plat = devm_kzalloc(dev, sizeof(*plat), GFP_KERNEL); + if (!plat) + return ERR_PTR(-ENOMEM); + + of_property_read_u32(np, "debounce-interval", &plat->debounce_ms); + of_property_read_u32(np, "st,scan-count", &plat->scan_count); + + plat->no_autorepeat = of_property_read_bool(np, "st,no-autorepeat"); + + return plat; +} +#else +static inline const struct stmpe_keypad_platform_data * +stmpe_keypad_of_probe(struct device *dev) +{ + return ERR_PTR(-EINVAL); +} +#endif + +static int stmpe_keypad_probe(struct platform_device *pdev) +{ + struct stmpe *stmpe = dev_get_drvdata(pdev->dev.parent); + const struct stmpe_keypad_platform_data *plat; struct stmpe_keypad *keypad; struct input_dev *input; - int ret; + int error; int irq; - int i; plat = stmpe->pdata->keypad; - if (!plat) - return -ENODEV; + if (!plat) { + plat = stmpe_keypad_of_probe(&pdev->dev); + if (IS_ERR(plat)) + return PTR_ERR(plat); + } irq = platform_get_irq(pdev, 0); if (irq < 0) return irq; - keypad = kzalloc(sizeof(struct stmpe_keypad), GFP_KERNEL); + keypad = devm_kzalloc(&pdev->dev, sizeof(struct stmpe_keypad), + GFP_KERNEL); if (!keypad) return -ENOMEM; - input = input_allocate_device(); - if (!input) { - ret = -ENOMEM; - goto out_freekeypad; - } + input = devm_input_allocate_device(&pdev->dev); + if (!input) + return -ENOMEM; input->name = "STMPE keypad"; input->id.bustype = BUS_I2C; input->dev.parent = &pdev->dev; - input_set_capability(input, EV_MSC, MSC_SCAN); + error = matrix_keypad_build_keymap(plat->keymap_data, NULL, + STMPE_KEYPAD_MAX_ROWS, + STMPE_KEYPAD_MAX_COLS, + keypad->keymap, input); + if (error) + return error; - __set_bit(EV_KEY, input->evbit); + input_set_capability(input, EV_MSC, MSC_SCAN); if (!plat->no_autorepeat) __set_bit(EV_REP, input->evbit); - input->keycode = keypad->keymap; - input->keycodesize = sizeof(keypad->keymap[0]); - input->keycodemax = ARRAY_SIZE(keypad->keymap); - - matrix_keypad_build_keymap(plat->keymap_data, STMPE_KEYPAD_ROW_SHIFT, - input->keycode, input->keybit); - - for (i = 0; i < plat->keymap_data->keymap_size; i++) { - unsigned int key = plat->keymap_data->keymap[i]; - - keypad->cols |= 1 << KEY_COL(key); - keypad->rows |= 1 << KEY_ROW(key); - } + stmpe_keypad_fill_used_pins(keypad); keypad->stmpe = stmpe; keypad->plat = plat; keypad->input = input; keypad->variant = &stmpe_keypad_variants[stmpe->partnum]; - ret = stmpe_keypad_chip_init(keypad); - if (ret < 0) - goto out_freeinput; + error = stmpe_keypad_chip_init(keypad); + if (error < 0) + return error; - ret = input_register_device(input); - if (ret) { - dev_err(&pdev->dev, - "unable to register input device: %d\n", ret); - goto out_freeinput; + error = devm_request_threaded_irq(&pdev->dev, irq, + NULL, stmpe_keypad_irq, + IRQF_ONESHOT, "stmpe-keypad", keypad); + if (error) { + dev_err(&pdev->dev, "unable to get irq: %d\n", error); + return error; } - ret = request_threaded_irq(irq, NULL, stmpe_keypad_irq, IRQF_ONESHOT, - "stmpe-keypad", keypad); - if (ret) { - dev_err(&pdev->dev, "unable to get irq: %d\n", ret); - goto out_unregisterinput; + 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); return 0; - -out_unregisterinput: - input_unregister_device(input); - input = NULL; -out_freeinput: - input_free_device(input); -out_freekeypad: - kfree(keypad); - return ret; } -static int __devexit stmpe_keypad_remove(struct platform_device *pdev) +static int stmpe_keypad_remove(struct platform_device *pdev) { struct stmpe_keypad *keypad = platform_get_drvdata(pdev); - struct stmpe *stmpe = keypad->stmpe; - int irq = platform_get_irq(pdev, 0); - stmpe_disable(stmpe, STMPE_BLOCK_KEYPAD); - - free_irq(irq, keypad); - input_unregister_device(keypad->input); - platform_set_drvdata(pdev, NULL); - kfree(keypad); + stmpe_disable(keypad->stmpe, STMPE_BLOCK_KEYPAD); return 0; } @@ -366,20 +389,9 @@ static struct platform_driver stmpe_keypad_driver = { .driver.name = "stmpe-keypad", .driver.owner = THIS_MODULE, .probe = stmpe_keypad_probe, - .remove = __devexit_p(stmpe_keypad_remove), + .remove = stmpe_keypad_remove, }; - -static int __init stmpe_keypad_init(void) -{ - return platform_driver_register(&stmpe_keypad_driver); -} -module_init(stmpe_keypad_init); - -static void __exit stmpe_keypad_exit(void) -{ - platform_driver_unregister(&stmpe_keypad_driver); -} -module_exit(stmpe_keypad_exit); +module_platform_driver(stmpe_keypad_driver); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("STMPExxxx keypad driver"); diff --git a/drivers/input/keyboard/stowaway.c b/drivers/input/keyboard/stowaway.c index 7437219370b..a6e0d565e30 100644 --- a/drivers/input/keyboard/stowaway.c +++ b/drivers/input/keyboard/stowaway.c @@ -32,7 +32,6 @@ #include <linux/slab.h> #include <linux/module.h> #include <linux/input.h> -#include <linux/init.h> #include <linux/serio.h> #define DRIVER_DESC "Stowaway keyboard driver" @@ -170,15 +169,4 @@ static struct serio_driver skbd_drv = { .disconnect = skbd_disconnect, }; -static int __init skbd_init(void) -{ - return serio_register_driver(&skbd_drv); -} - -static void __exit skbd_exit(void) -{ - serio_unregister_driver(&skbd_drv); -} - -module_init(skbd_init); -module_exit(skbd_exit); +module_serio_driver(skbd_drv); diff --git a/drivers/input/keyboard/sunkbd.c b/drivers/input/keyboard/sunkbd.c index a99a04b03ee..dc6bb9d5b4f 100644 --- a/drivers/input/keyboard/sunkbd.c +++ b/drivers/input/keyboard/sunkbd.c @@ -31,7 +31,6 @@ #include <linux/slab.h> #include <linux/module.h> #include <linux/interrupt.h> -#include <linux/init.h> #include <linux/input.h> #include <linux/serio.h> #include <linux/workqueue.h> @@ -369,19 +368,4 @@ static struct serio_driver sunkbd_drv = { .disconnect = sunkbd_disconnect, }; -/* - * The functions for insering/removing us as a module. - */ - -static int __init sunkbd_init(void) -{ - return serio_register_driver(&sunkbd_drv); -} - -static void __exit sunkbd_exit(void) -{ - serio_unregister_driver(&sunkbd_drv); -} - -module_init(sunkbd_init); -module_exit(sunkbd_exit); +module_serio_driver(sunkbd_drv); diff --git a/drivers/input/keyboard/tc3589x-keypad.c b/drivers/input/keyboard/tc3589x-keypad.c index 99122f59e98..ad7abae6907 100644 --- a/drivers/input/keyboard/tc3589x-keypad.c +++ b/drivers/input/keyboard/tc3589x-keypad.c @@ -10,7 +10,6 @@ */ #include <linux/module.h> -#include <linux/init.h> #include <linux/interrupt.h> #include <linux/input.h> #include <linux/platform_device.h> @@ -70,15 +69,15 @@ #define TC3589x_EVT_INT_CLR 0x2 #define TC3589x_KBD_INT_CLR 0x1 -#define TC3589x_KBD_KEYMAP_SIZE 64 - /** * struct tc_keypad - data structure used by keypad driver + * @tc3589x: pointer to tc35893 * @input: pointer to input device object * @board: keypad platform device * @krow: number of rows - * @kcol: number of coloumns + * @kcol: number of columns * @keymap: matrix scan code table for keycodes + * @keypad_stopped: holds keypad status */ struct tc_keypad { struct tc3589x *tc3589x; @@ -86,29 +85,23 @@ struct tc_keypad { const struct tc3589x_keypad_platform_data *board; unsigned int krow; unsigned int kcol; - unsigned short keymap[TC3589x_KBD_KEYMAP_SIZE]; + unsigned short *keymap; bool keypad_stopped; }; -static int __devinit tc3589x_keypad_init_key_hardware(struct tc_keypad *keypad) +static int tc3589x_keypad_init_key_hardware(struct tc_keypad *keypad) { int ret; struct tc3589x *tc3589x = keypad->tc3589x; - u8 settle_time = keypad->board->settle_time; - u8 dbounce_period = keypad->board->debounce_period; - u8 rows = keypad->board->krow & 0xf; /* mask out the nibble */ - u8 column = keypad->board->kcol & 0xf; /* mask out the nibble */ - - /* validate platform configurations */ - if (keypad->board->kcol > TC3589x_MAX_KPCOL || - keypad->board->krow > TC3589x_MAX_KPROW || - keypad->board->debounce_period > TC3589x_MAX_DEBOUNCE_SETTLE || - keypad->board->settle_time > TC3589x_MAX_DEBOUNCE_SETTLE) + const struct tc3589x_keypad_platform_data *board = keypad->board; + + /* validate platform configuration */ + if (board->kcol > TC3589x_MAX_KPCOL || board->krow > TC3589x_MAX_KPROW) return -EINVAL; /* configure KBDSIZE 4 LSbits for cols and 4 MSbits for rows */ ret = tc3589x_reg_write(tc3589x, TC3589x_KBDSIZE, - (rows << KP_ROW_SHIFT) | column); + (board->krow << KP_ROW_SHIFT) | board->kcol); if (ret < 0) return ret; @@ -122,12 +115,14 @@ static int __devinit tc3589x_keypad_init_key_hardware(struct tc_keypad *keypad) return ret; /* Configure settle time */ - ret = tc3589x_reg_write(tc3589x, TC3589x_KBDSETTLE_REG, settle_time); + ret = tc3589x_reg_write(tc3589x, TC3589x_KBDSETTLE_REG, + board->settle_time); if (ret < 0) return ret; /* Configure debounce time */ - ret = tc3589x_reg_write(tc3589x, TC3589x_KBDBOUNCE, dbounce_period); + ret = tc3589x_reg_write(tc3589x, TC3589x_KBDBOUNCE, + board->debounce_period); if (ret < 0) return ret; @@ -301,7 +296,66 @@ static void tc3589x_keypad_close(struct input_dev *input) tc3589x_keypad_disable(keypad); } -static int __devinit tc3589x_keypad_probe(struct platform_device *pdev) +#ifdef CONFIG_OF +static const struct tc3589x_keypad_platform_data * +tc3589x_keypad_of_probe(struct device *dev) +{ + struct device_node *np = dev->of_node; + struct tc3589x_keypad_platform_data *plat; + u32 cols, rows; + u32 debounce_ms; + int proplen; + + if (!np) + return ERR_PTR(-ENODEV); + + plat = devm_kzalloc(dev, sizeof(*plat), GFP_KERNEL); + if (!plat) + return ERR_PTR(-ENOMEM); + + of_property_read_u32(np, "keypad,num-columns", &cols); + of_property_read_u32(np, "keypad,num-rows", &rows); + plat->kcol = (u8) cols; + plat->krow = (u8) rows; + if (!plat->krow || !plat->kcol || + plat->krow > TC_KPD_ROWS || plat->kcol > TC_KPD_COLUMNS) { + dev_err(dev, + "keypad columns/rows not properly specified (%ux%u)\n", + plat->kcol, plat->krow); + return ERR_PTR(-EINVAL); + } + + if (!of_get_property(np, "linux,keymap", &proplen)) { + dev_err(dev, "property linux,keymap not found\n"); + return ERR_PTR(-ENOENT); + } + + plat->no_autorepeat = of_property_read_bool(np, "linux,no-autorepeat"); + plat->enable_wakeup = of_property_read_bool(np, "linux,wakeup"); + + /* The custom delay format is ms/16 */ + of_property_read_u32(np, "debounce-delay-ms", &debounce_ms); + if (debounce_ms) + plat->debounce_period = debounce_ms * 16; + else + plat->debounce_period = TC_KPD_DEBOUNCE_PERIOD; + + plat->settle_time = TC_KPD_SETTLE_TIME; + /* FIXME: should be property of the IRQ resource? */ + plat->irqtype = IRQF_TRIGGER_FALLING; + + return plat; +} +#else +static inline const struct tc3589x_keypad_platform_data * +tc3589x_keypad_of_probe(struct device *dev) +{ + return ERR_PTR(-ENODEV); +} +#endif + + +static int tc3589x_keypad_probe(struct platform_device *pdev) { struct tc3589x *tc3589x = dev_get_drvdata(pdev->dev.parent); struct tc_keypad *keypad; @@ -311,8 +365,11 @@ static int __devinit tc3589x_keypad_probe(struct platform_device *pdev) plat = tc3589x->pdata->keypad; if (!plat) { - dev_err(&pdev->dev, "invalid keypad platform data\n"); - return -EINVAL; + plat = tc3589x_keypad_of_probe(&pdev->dev); + if (IS_ERR(plat)) { + dev_err(&pdev->dev, "invalid keypad platform data\n"); + return PTR_ERR(plat); + } } irq = platform_get_irq(pdev, 0); @@ -335,23 +392,24 @@ static int __devinit tc3589x_keypad_probe(struct platform_device *pdev) input->name = pdev->name; input->dev.parent = &pdev->dev; - input->keycode = keypad->keymap; - input->keycodesize = sizeof(keypad->keymap[0]); - input->keycodemax = ARRAY_SIZE(keypad->keymap); - input->open = tc3589x_keypad_open; input->close = tc3589x_keypad_close; - input_set_drvdata(input, keypad); + error = matrix_keypad_build_keymap(plat->keymap_data, NULL, + TC3589x_MAX_KPROW, TC3589x_MAX_KPCOL, + NULL, input); + if (error) { + dev_err(&pdev->dev, "Failed to build keymap\n"); + goto err_free_mem; + } - input_set_capability(input, EV_MSC, MSC_SCAN); + keypad->keymap = input->keycode; - __set_bit(EV_KEY, input->evbit); + input_set_capability(input, EV_MSC, MSC_SCAN); if (!plat->no_autorepeat) __set_bit(EV_REP, input->evbit); - matrix_keypad_build_keymap(plat->keymap_data, 0x3, - input->keycode, input->keybit); + input_set_drvdata(input, keypad); error = request_threaded_irq(irq, NULL, tc3589x_keypad_irq, plat->irqtype, @@ -385,7 +443,7 @@ err_free_mem: return error; } -static int __devexit tc3589x_keypad_remove(struct platform_device *pdev) +static int tc3589x_keypad_remove(struct platform_device *pdev) { struct tc_keypad *keypad = platform_get_drvdata(pdev); int irq = platform_get_irq(pdev, 0); @@ -451,20 +509,9 @@ static struct platform_driver tc3589x_keypad_driver = { .pm = &tc3589x_keypad_dev_pm_ops, }, .probe = tc3589x_keypad_probe, - .remove = __devexit_p(tc3589x_keypad_remove), + .remove = tc3589x_keypad_remove, }; - -static int __init tc3589x_keypad_init(void) -{ - return platform_driver_register(&tc3589x_keypad_driver); -} -module_init(tc3589x_keypad_init); - -static void __exit tc3589x_keypad_exit(void) -{ - return platform_driver_unregister(&tc3589x_keypad_driver); -} -module_exit(tc3589x_keypad_exit); +module_platform_driver(tc3589x_keypad_driver); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Jayeeta Banerjee/Sundar Iyer"); diff --git a/drivers/input/keyboard/tca6416-keypad.c b/drivers/input/keyboard/tca6416-keypad.c index 3afea3f8971..dc983ab6c0a 100644 --- a/drivers/input/keyboard/tca6416-keypad.c +++ b/drivers/input/keyboard/tca6416-keypad.c @@ -166,7 +166,7 @@ static void tca6416_keys_close(struct input_dev *dev) disable_irq(chip->irqnum); } -static int __devinit tca6416_setup_registers(struct tca6416_keypad_chip *chip) +static int tca6416_setup_registers(struct tca6416_keypad_chip *chip) { int error; @@ -197,7 +197,7 @@ static int __devinit tca6416_setup_registers(struct tca6416_keypad_chip *chip) return 0; } -static int __devinit tca6416_keypad_probe(struct i2c_client *client, +static int tca6416_keypad_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct tca6416_keys_platform_data *pdata; @@ -213,7 +213,7 @@ static int __devinit tca6416_keypad_probe(struct i2c_client *client, return -ENODEV; } - pdata = client->dev.platform_data; + pdata = dev_get_platdata(&client->dev); if (!pdata) { dev_dbg(&client->dev, "no platform data\n"); return -EINVAL; @@ -278,7 +278,8 @@ static int __devinit tca6416_keypad_probe(struct i2c_client *client, error = request_threaded_irq(chip->irqnum, NULL, tca6416_keys_isr, - IRQF_TRIGGER_FALLING, + IRQF_TRIGGER_FALLING | + IRQF_ONESHOT, "tca6416-keypad", chip); if (error) { dev_dbg(&client->dev, @@ -312,7 +313,7 @@ fail1: return error; } -static int __devexit tca6416_keypad_remove(struct i2c_client *client) +static int tca6416_keypad_remove(struct i2c_client *client) { struct tca6416_keypad_chip *chip = i2c_get_clientdata(client); @@ -360,7 +361,7 @@ static struct i2c_driver tca6416_keypad_driver = { .pm = &tca6416_keypad_dev_pm_ops, }, .probe = tca6416_keypad_probe, - .remove = __devexit_p(tca6416_keypad_remove), + .remove = tca6416_keypad_remove, .id_table = tca6416_id, }; diff --git a/drivers/input/keyboard/tca8418_keypad.c b/drivers/input/keyboard/tca8418_keypad.c new file mode 100644 index 00000000000..4e491c1762c --- /dev/null +++ b/drivers/input/keyboard/tca8418_keypad.c @@ -0,0 +1,428 @@ +/* + * Driver for TCA8418 I2C keyboard + * + * Copyright (C) 2011 Fuel7, Inc. All rights reserved. + * + * Author: Kyle Manna <kyle.manna@fuel7.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License v2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 021110-1307, USA. + * + * If you can't comply with GPLv2, alternative licensing terms may be + * arranged. Please contact Fuel7, Inc. (http://fuel7.com/) for proprietary + * alternative licensing inquiries. + */ + +#include <linux/types.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/interrupt.h> +#include <linux/workqueue.h> +#include <linux/gpio.h> +#include <linux/i2c.h> +#include <linux/input.h> +#include <linux/input/tca8418_keypad.h> +#include <linux/of.h> + +/* TCA8418 hardware limits */ +#define TCA8418_MAX_ROWS 8 +#define TCA8418_MAX_COLS 10 + +/* TCA8418 register offsets */ +#define REG_CFG 0x01 +#define REG_INT_STAT 0x02 +#define REG_KEY_LCK_EC 0x03 +#define REG_KEY_EVENT_A 0x04 +#define REG_KEY_EVENT_B 0x05 +#define REG_KEY_EVENT_C 0x06 +#define REG_KEY_EVENT_D 0x07 +#define REG_KEY_EVENT_E 0x08 +#define REG_KEY_EVENT_F 0x09 +#define REG_KEY_EVENT_G 0x0A +#define REG_KEY_EVENT_H 0x0B +#define REG_KEY_EVENT_I 0x0C +#define REG_KEY_EVENT_J 0x0D +#define REG_KP_LCK_TIMER 0x0E +#define REG_UNLOCK1 0x0F +#define REG_UNLOCK2 0x10 +#define REG_GPIO_INT_STAT1 0x11 +#define REG_GPIO_INT_STAT2 0x12 +#define REG_GPIO_INT_STAT3 0x13 +#define REG_GPIO_DAT_STAT1 0x14 +#define REG_GPIO_DAT_STAT2 0x15 +#define REG_GPIO_DAT_STAT3 0x16 +#define REG_GPIO_DAT_OUT1 0x17 +#define REG_GPIO_DAT_OUT2 0x18 +#define REG_GPIO_DAT_OUT3 0x19 +#define REG_GPIO_INT_EN1 0x1A +#define REG_GPIO_INT_EN2 0x1B +#define REG_GPIO_INT_EN3 0x1C +#define REG_KP_GPIO1 0x1D +#define REG_KP_GPIO2 0x1E +#define REG_KP_GPIO3 0x1F +#define REG_GPI_EM1 0x20 +#define REG_GPI_EM2 0x21 +#define REG_GPI_EM3 0x22 +#define REG_GPIO_DIR1 0x23 +#define REG_GPIO_DIR2 0x24 +#define REG_GPIO_DIR3 0x25 +#define REG_GPIO_INT_LVL1 0x26 +#define REG_GPIO_INT_LVL2 0x27 +#define REG_GPIO_INT_LVL3 0x28 +#define REG_DEBOUNCE_DIS1 0x29 +#define REG_DEBOUNCE_DIS2 0x2A +#define REG_DEBOUNCE_DIS3 0x2B +#define REG_GPIO_PULL1 0x2C +#define REG_GPIO_PULL2 0x2D +#define REG_GPIO_PULL3 0x2E + +/* TCA8418 bit definitions */ +#define CFG_AI BIT(7) +#define CFG_GPI_E_CFG BIT(6) +#define CFG_OVR_FLOW_M BIT(5) +#define CFG_INT_CFG BIT(4) +#define CFG_OVR_FLOW_IEN BIT(3) +#define CFG_K_LCK_IEN BIT(2) +#define CFG_GPI_IEN BIT(1) +#define CFG_KE_IEN BIT(0) + +#define INT_STAT_CAD_INT BIT(4) +#define INT_STAT_OVR_FLOW_INT BIT(3) +#define INT_STAT_K_LCK_INT BIT(2) +#define INT_STAT_GPI_INT BIT(1) +#define INT_STAT_K_INT BIT(0) + +/* TCA8418 register masks */ +#define KEY_LCK_EC_KEC 0x7 +#define KEY_EVENT_CODE 0x7f +#define KEY_EVENT_VALUE 0x80 + +struct tca8418_keypad { + struct i2c_client *client; + struct input_dev *input; + + unsigned int row_shift; +}; + +/* + * Write a byte to the TCA8418 + */ +static int tca8418_write_byte(struct tca8418_keypad *keypad_data, + int reg, u8 val) +{ + int error; + + error = i2c_smbus_write_byte_data(keypad_data->client, reg, val); + if (error < 0) { + dev_err(&keypad_data->client->dev, + "%s failed, reg: %d, val: %d, error: %d\n", + __func__, reg, val, error); + return error; + } + + return 0; +} + +/* + * Read a byte from the TCA8418 + */ +static int tca8418_read_byte(struct tca8418_keypad *keypad_data, + int reg, u8 *val) +{ + int error; + + error = i2c_smbus_read_byte_data(keypad_data->client, reg); + if (error < 0) { + dev_err(&keypad_data->client->dev, + "%s failed, reg: %d, error: %d\n", + __func__, reg, error); + return error; + } + + *val = (u8)error; + + return 0; +} + +static void tca8418_read_keypad(struct tca8418_keypad *keypad_data) +{ + struct input_dev *input = keypad_data->input; + unsigned short *keymap = input->keycode; + int error, col, row; + u8 reg, state, code; + + /* Initial read of the key event FIFO */ + error = tca8418_read_byte(keypad_data, REG_KEY_EVENT_A, ®); + + /* Assume that key code 0 signifies empty FIFO */ + while (error >= 0 && reg > 0) { + state = reg & KEY_EVENT_VALUE; + code = reg & KEY_EVENT_CODE; + + row = code / TCA8418_MAX_COLS; + col = code % TCA8418_MAX_COLS; + + row = (col) ? row : row - 1; + col = (col) ? col - 1 : TCA8418_MAX_COLS - 1; + + code = MATRIX_SCAN_CODE(row, col, keypad_data->row_shift); + input_event(input, EV_MSC, MSC_SCAN, code); + input_report_key(input, keymap[code], state); + + /* Read for next loop */ + error = tca8418_read_byte(keypad_data, REG_KEY_EVENT_A, ®); + } + + if (error < 0) + dev_err(&keypad_data->client->dev, + "unable to read REG_KEY_EVENT_A\n"); + + input_sync(input); +} + +/* + * Threaded IRQ handler and this can (and will) sleep. + */ +static irqreturn_t tca8418_irq_handler(int irq, void *dev_id) +{ + struct tca8418_keypad *keypad_data = dev_id; + u8 reg; + int error; + + error = tca8418_read_byte(keypad_data, REG_INT_STAT, ®); + if (error) { + dev_err(&keypad_data->client->dev, + "unable to read REG_INT_STAT\n"); + return IRQ_NONE; + } + + if (!reg) + return IRQ_NONE; + + if (reg & INT_STAT_OVR_FLOW_INT) + dev_warn(&keypad_data->client->dev, "overflow occurred\n"); + + if (reg & INT_STAT_K_INT) + tca8418_read_keypad(keypad_data); + + /* Clear all interrupts, even IRQs we didn't check (GPI, CAD, LCK) */ + reg = 0xff; + error = tca8418_write_byte(keypad_data, REG_INT_STAT, reg); + if (error) + dev_err(&keypad_data->client->dev, + "unable to clear REG_INT_STAT\n"); + + return IRQ_HANDLED; +} + +/* + * Configure the TCA8418 for keypad operation + */ +static int tca8418_configure(struct tca8418_keypad *keypad_data, + u32 rows, u32 cols) +{ + int reg, error; + + /* Write config register, if this fails assume device not present */ + error = tca8418_write_byte(keypad_data, REG_CFG, + CFG_INT_CFG | CFG_OVR_FLOW_IEN | CFG_KE_IEN); + if (error < 0) + return -ENODEV; + + + /* Assemble a mask for row and column registers */ + reg = ~(~0 << rows); + reg += (~(~0 << cols)) << 8; + + /* Set registers to keypad mode */ + error |= tca8418_write_byte(keypad_data, REG_KP_GPIO1, reg); + error |= tca8418_write_byte(keypad_data, REG_KP_GPIO2, reg >> 8); + error |= tca8418_write_byte(keypad_data, REG_KP_GPIO3, reg >> 16); + + /* Enable column debouncing */ + error |= tca8418_write_byte(keypad_data, REG_DEBOUNCE_DIS1, reg); + error |= tca8418_write_byte(keypad_data, REG_DEBOUNCE_DIS2, reg >> 8); + error |= tca8418_write_byte(keypad_data, REG_DEBOUNCE_DIS3, reg >> 16); + + return error; +} + +static int tca8418_keypad_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct device *dev = &client->dev; + const struct tca8418_keypad_platform_data *pdata = + dev_get_platdata(dev); + struct tca8418_keypad *keypad_data; + struct input_dev *input; + const struct matrix_keymap_data *keymap_data = NULL; + u32 rows = 0, cols = 0; + bool rep = false; + bool irq_is_gpio = false; + int irq; + int error, row_shift, max_keys; + + /* Copy the platform data */ + if (pdata) { + if (!pdata->keymap_data) { + dev_err(dev, "no keymap data defined\n"); + return -EINVAL; + } + keymap_data = pdata->keymap_data; + rows = pdata->rows; + cols = pdata->cols; + rep = pdata->rep; + irq_is_gpio = pdata->irq_is_gpio; + } else { + struct device_node *np = dev->of_node; + int err; + + err = matrix_keypad_parse_of_params(dev, &rows, &cols); + if (err) + return err; + rep = of_property_read_bool(np, "keypad,autorepeat"); + } + + if (!rows || rows > TCA8418_MAX_ROWS) { + dev_err(dev, "invalid rows\n"); + return -EINVAL; + } + + if (!cols || cols > TCA8418_MAX_COLS) { + dev_err(dev, "invalid columns\n"); + return -EINVAL; + } + + /* Check i2c driver capabilities */ + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE)) { + dev_err(dev, "%s adapter not supported\n", + dev_driver_string(&client->adapter->dev)); + return -ENODEV; + } + + row_shift = get_count_order(cols); + max_keys = rows << row_shift; + + /* Allocate memory for keypad_data and input device */ + keypad_data = devm_kzalloc(dev, sizeof(*keypad_data), GFP_KERNEL); + if (!keypad_data) + return -ENOMEM; + + keypad_data->client = client; + keypad_data->row_shift = row_shift; + + /* Initialize the chip or fail if chip isn't present */ + error = tca8418_configure(keypad_data, rows, cols); + if (error < 0) + return error; + + /* Configure input device */ + input = devm_input_allocate_device(dev); + if (!input) + return -ENOMEM; + + keypad_data->input = input; + + input->name = client->name; + input->id.bustype = BUS_I2C; + input->id.vendor = 0x0001; + input->id.product = 0x001; + input->id.version = 0x0001; + + error = matrix_keypad_build_keymap(keymap_data, NULL, rows, cols, + NULL, input); + if (error) { + dev_err(dev, "Failed to build keymap\n"); + return error; + } + + if (rep) + __set_bit(EV_REP, input->evbit); + input_set_capability(input, EV_MSC, MSC_SCAN); + + input_set_drvdata(input, keypad_data); + + irq = client->irq; + if (irq_is_gpio) + irq = gpio_to_irq(irq); + + error = devm_request_threaded_irq(dev, irq, NULL, tca8418_irq_handler, + IRQF_TRIGGER_FALLING | + IRQF_SHARED | + IRQF_ONESHOT, + client->name, keypad_data); + if (error) { + dev_err(dev, "Unable to claim irq %d; error %d\n", + client->irq, error); + return error; + } + + error = input_register_device(input); + if (error) { + dev_err(dev, "Unable to register input device, error: %d\n", + error); + return error; + } + + return 0; +} + +static const struct i2c_device_id tca8418_id[] = { + { TCA8418_NAME, 8418, }, + { } +}; +MODULE_DEVICE_TABLE(i2c, tca8418_id); + +#ifdef CONFIG_OF +static const struct of_device_id tca8418_dt_ids[] = { + { .compatible = "ti,tca8418", }, + { } +}; +MODULE_DEVICE_TABLE(of, tca8418_dt_ids); + +/* + * The device tree based i2c loader looks for + * "i2c:" + second_component_of(property("compatible")) + * and therefore we need an alias to be found. + */ +MODULE_ALIAS("i2c:tca8418"); +#endif + +static struct i2c_driver tca8418_keypad_driver = { + .driver = { + .name = TCA8418_NAME, + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(tca8418_dt_ids), + }, + .probe = tca8418_keypad_probe, + .id_table = tca8418_id, +}; + +static int __init tca8418_keypad_init(void) +{ + return i2c_add_driver(&tca8418_keypad_driver); +} +subsys_initcall(tca8418_keypad_init); + +static void __exit tca8418_keypad_exit(void) +{ + i2c_del_driver(&tca8418_keypad_driver); +} +module_exit(tca8418_keypad_exit); + +MODULE_AUTHOR("Kyle Manna <kyle.manna@fuel7.com>"); +MODULE_DESCRIPTION("Keypad driver for TCA8418"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/keyboard/tegra-kbc.c b/drivers/input/keyboard/tegra-kbc.c index 2b3b73ec668..9757a58bc89 100644 --- a/drivers/input/keyboard/tegra-kbc.c +++ b/drivers/input/keyboard/tegra-kbc.c @@ -19,16 +19,27 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#include <linux/kernel.h> #include <linux/module.h> #include <linux/input.h> #include <linux/platform_device.h> #include <linux/delay.h> #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 <mach/clk.h> -#include <mach/kbc.h> +#include <linux/input/matrix_keypad.h> +#include <linux/reset.h> +#include <linux/err.h> + +#define KBC_MAX_KPENT 8 + +/* 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 @@ -37,7 +48,7 @@ #define KBC_ROW_SCAN_DLY 5 /* KBC uses a 32KHz clock so a cycle = 1/32Khz */ -#define KBC_CYCLE_USEC 32 +#define KBC_CYCLE_MS 32 /* KBC Registers */ @@ -46,14 +57,17 @@ #define KBC_FIFO_TH_CNT_SHIFT(cnt) (cnt << 14) #define KBC_DEBOUNCE_CNT_SHIFT(cnt) (cnt << 4) #define KBC_CONTROL_FIFO_CNT_INT_EN (1 << 3) +#define KBC_CONTROL_KEYPRESS_INT_EN (1 << 1) #define KBC_CONTROL_KBC_EN (1 << 0) /* KBC Interrupt Register */ #define KBC_INT_0 0x4 #define KBC_INT_FIFO_CNT_INT_STATUS (1 << 2) +#define KBC_INT_KEYPRESS_INT_STATUS (1 << 0) #define KBC_ROW_CFG0_0 0x8 #define KBC_COL_CFG0_0 0x18 +#define KBC_TO_CNT_0 0x24 #define KBC_INIT_DLY_0 0x28 #define KBC_RPT_DLY_0 0x2c #define KBC_KP_ENT0_0 0x30 @@ -62,161 +76,50 @@ #define KBC_ROW_SHIFT 3 +enum tegra_pin_type { + PIN_CFG_IGNORE, + PIN_CFG_COL, + 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; +}; + struct tegra_kbc { + struct device *dev; + unsigned int debounce_cnt; + unsigned int repeat_cnt; + struct tegra_kbc_pin_cfg pin_cfg[KBC_MAX_GPIO]; + const struct matrix_keymap_data *keymap_data; + bool wakeup; void __iomem *mmio; struct input_dev *idev; - unsigned int irq; + int irq; spinlock_t lock; unsigned int repoll_dly; unsigned long cp_dly_jiffies; + unsigned int cp_to_wkup_dly; bool use_fn_map; bool use_ghost_filter; - const struct tegra_kbc_platform_data *pdata; + bool keypress_caused_wake; unsigned short keycode[KBC_MAX_KEY * 2]; unsigned short current_keys[KBC_MAX_KPENT]; unsigned int num_pressed_keys; + u32 wakeup_key; struct timer_list timer; struct clk *clk; -}; - -static const u32 tegra_kbc_default_keymap[] = { - KEY(0, 2, KEY_W), - KEY(0, 3, KEY_S), - KEY(0, 4, KEY_A), - KEY(0, 5, KEY_Z), - KEY(0, 7, KEY_FN), - - KEY(1, 7, KEY_LEFTMETA), - - KEY(2, 6, KEY_RIGHTALT), - KEY(2, 7, KEY_LEFTALT), - - KEY(3, 0, KEY_5), - KEY(3, 1, KEY_4), - KEY(3, 2, KEY_R), - KEY(3, 3, KEY_E), - KEY(3, 4, KEY_F), - KEY(3, 5, KEY_D), - KEY(3, 6, KEY_X), - - KEY(4, 0, KEY_7), - KEY(4, 1, KEY_6), - KEY(4, 2, KEY_T), - KEY(4, 3, KEY_H), - KEY(4, 4, KEY_G), - KEY(4, 5, KEY_V), - KEY(4, 6, KEY_C), - KEY(4, 7, KEY_SPACE), - - KEY(5, 0, KEY_9), - KEY(5, 1, KEY_8), - KEY(5, 2, KEY_U), - KEY(5, 3, KEY_Y), - KEY(5, 4, KEY_J), - KEY(5, 5, KEY_N), - KEY(5, 6, KEY_B), - KEY(5, 7, KEY_BACKSLASH), - - KEY(6, 0, KEY_MINUS), - KEY(6, 1, KEY_0), - KEY(6, 2, KEY_O), - KEY(6, 3, KEY_I), - KEY(6, 4, KEY_L), - KEY(6, 5, KEY_K), - KEY(6, 6, KEY_COMMA), - KEY(6, 7, KEY_M), - - KEY(7, 1, KEY_EQUAL), - KEY(7, 2, KEY_RIGHTBRACE), - KEY(7, 3, KEY_ENTER), - KEY(7, 7, KEY_MENU), - - KEY(8, 4, KEY_RIGHTSHIFT), - KEY(8, 5, KEY_LEFTSHIFT), - - KEY(9, 5, KEY_RIGHTCTRL), - KEY(9, 7, KEY_LEFTCTRL), - - KEY(11, 0, KEY_LEFTBRACE), - KEY(11, 1, KEY_P), - KEY(11, 2, KEY_APOSTROPHE), - KEY(11, 3, KEY_SEMICOLON), - KEY(11, 4, KEY_SLASH), - KEY(11, 5, KEY_DOT), - - KEY(12, 0, KEY_F10), - KEY(12, 1, KEY_F9), - KEY(12, 2, KEY_BACKSPACE), - KEY(12, 3, KEY_3), - KEY(12, 4, KEY_2), - KEY(12, 5, KEY_UP), - KEY(12, 6, KEY_PRINT), - KEY(12, 7, KEY_PAUSE), - - KEY(13, 0, KEY_INSERT), - KEY(13, 1, KEY_DELETE), - KEY(13, 3, KEY_PAGEUP), - KEY(13, 4, KEY_PAGEDOWN), - KEY(13, 5, KEY_RIGHT), - KEY(13, 6, KEY_DOWN), - KEY(13, 7, KEY_LEFT), - - KEY(14, 0, KEY_F11), - KEY(14, 1, KEY_F12), - KEY(14, 2, KEY_F8), - KEY(14, 3, KEY_Q), - KEY(14, 4, KEY_F4), - KEY(14, 5, KEY_F3), - KEY(14, 6, KEY_1), - KEY(14, 7, KEY_F7), - - KEY(15, 0, KEY_ESC), - KEY(15, 1, KEY_GRAVE), - KEY(15, 2, KEY_F5), - KEY(15, 3, KEY_TAB), - KEY(15, 4, KEY_F1), - KEY(15, 5, KEY_F2), - KEY(15, 6, KEY_CAPSLOCK), - KEY(15, 7, KEY_F6), - - /* Software Handled Function Keys */ - KEY(20, 0, KEY_KP7), - - KEY(21, 0, KEY_KP9), - KEY(21, 1, KEY_KP8), - KEY(21, 2, KEY_KP4), - KEY(21, 4, KEY_KP1), - - KEY(22, 1, KEY_KPSLASH), - KEY(22, 2, KEY_KP6), - KEY(22, 3, KEY_KP5), - KEY(22, 4, KEY_KP3), - KEY(22, 5, KEY_KP2), - KEY(22, 7, KEY_KP0), - - KEY(27, 1, KEY_KPASTERISK), - KEY(27, 3, KEY_KPMINUS), - KEY(27, 4, KEY_KPPLUS), - KEY(27, 5, KEY_KPDOT), - - KEY(28, 5, KEY_VOLUMEUP), - - KEY(29, 3, KEY_HOME), - KEY(29, 4, KEY_END), - KEY(29, 5, KEY_BRIGHTNESSDOWN), - KEY(29, 6, KEY_VOLUMEDOWN), - KEY(29, 7, KEY_BRIGHTNESSUP), - - KEY(30, 0, KEY_NUMLOCK), - KEY(30, 1, KEY_SCROLLLOCK), - KEY(30, 2, KEY_MUTE), - - KEY(31, 4, KEY_HELP), -}; - -static const struct matrix_keymap_data tegra_kbc_default_keymap_data = { - .keymap = tegra_kbc_default_keymap, - .keymap_size = ARRAY_SIZE(tegra_kbc_default_keymap), + struct reset_control *rst; + 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, @@ -257,12 +160,10 @@ static void tegra_kbc_report_keys(struct tegra_kbc *kbc) u32 val = 0; unsigned int i; unsigned int num_down = 0; - unsigned long flags; bool fn_keypress = false; bool key_in_same_row = false; bool key_in_same_col = false; - spin_lock_irqsave(&kbc->lock, flags); for (i = 0; i < KBC_MAX_KPENT; i++) { if ((i % 4) == 0) val = readl(kbc->mmio + KBC_KP_ENT0_0 + i); @@ -291,7 +192,7 @@ static void tegra_kbc_report_keys(struct tegra_kbc *kbc) * any 2 of the 3 keys share a row, and any 2 of them share a column. * If so ignore the key presses for this iteration. */ - if ((kbc->use_ghost_filter) && (num_down >= 3)) { + if (kbc->use_ghost_filter && num_down >= 3) { for (i = 0; i < num_down; i++) { unsigned int j; u8 curr_col = scancodes[i] & 0x07; @@ -315,17 +216,15 @@ 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]]; } } - spin_unlock_irqrestore(&kbc->lock, flags); - /* Ignore the key presses for this iteration? */ if (key_in_same_col && key_in_same_row) return; @@ -340,6 +239,18 @@ static void tegra_kbc_report_keys(struct tegra_kbc *kbc) kbc->num_pressed_keys = num_down; } +static void tegra_kbc_set_fifo_interrupt(struct tegra_kbc *kbc, bool enable) +{ + u32 val; + + val = readl(kbc->mmio + KBC_CONTROL_0); + if (enable) + val |= KBC_CONTROL_FIFO_CNT_INT_EN; + else + val &= ~KBC_CONTROL_FIFO_CNT_INT_EN; + writel(val, kbc->mmio + KBC_CONTROL_0); +} + static void tegra_kbc_keypress_timer(unsigned long data) { struct tegra_kbc *kbc = (struct tegra_kbc *)data; @@ -347,6 +258,8 @@ static void tegra_kbc_keypress_timer(unsigned long data) u32 val; unsigned int i; + spin_lock_irqsave(&kbc->lock, flags); + val = (readl(kbc->mmio + KBC_INT_0) >> 4) & 0xf; if (val) { unsigned long dly; @@ -368,26 +281,19 @@ static void tegra_kbc_keypress_timer(unsigned long data) kbc->num_pressed_keys = 0; /* All keys are released so enable the keypress interrupt */ - spin_lock_irqsave(&kbc->lock, flags); - val = readl(kbc->mmio + KBC_CONTROL_0); - val |= KBC_CONTROL_FIFO_CNT_INT_EN; - writel(val, kbc->mmio + KBC_CONTROL_0); - spin_unlock_irqrestore(&kbc->lock, flags); + tegra_kbc_set_fifo_interrupt(kbc, true); } + + spin_unlock_irqrestore(&kbc->lock, flags); } static irqreturn_t tegra_kbc_isr(int irq, void *args) { struct tegra_kbc *kbc = args; - u32 val, ctl; + unsigned long flags; + u32 val; - /* - * Until all keys are released, defer further processing to - * the polling loop in tegra_kbc_keypress_timer - */ - ctl = readl(kbc->mmio + KBC_CONTROL_0); - ctl &= ~KBC_CONTROL_FIFO_CNT_INT_EN; - writel(ctl, kbc->mmio + KBC_CONTROL_0); + spin_lock_irqsave(&kbc->lock, flags); /* * Quickly bail out & reenable interrupts if the fifo threshold @@ -398,34 +304,35 @@ static irqreturn_t tegra_kbc_isr(int irq, void *args) if (val & KBC_INT_FIFO_CNT_INT_STATUS) { /* - * Schedule timer to run when hardware is in continuous - * polling mode. + * Until all keys are released, defer further processing to + * the polling loop in tegra_kbc_keypress_timer. */ + tegra_kbc_set_fifo_interrupt(kbc, false); mod_timer(&kbc->timer, jiffies + kbc->cp_dly_jiffies); - } else { - ctl |= KBC_CONTROL_FIFO_CNT_INT_EN; - writel(ctl, kbc->mmio + KBC_CONTROL_0); + } else if (val & KBC_INT_KEYPRESS_INT_STATUS) { + /* We can be here only through system resume path */ + kbc->keypress_caused_wake = true; } + spin_unlock_irqrestore(&kbc->lock, flags); + return IRQ_HANDLED; } static void tegra_kbc_setup_wakekeys(struct tegra_kbc *kbc, bool filter) { - const struct tegra_kbc_platform_data *pdata = kbc->pdata; int i; unsigned int rst_val; /* Either mask all keys or none. */ - rst_val = (filter && !pdata->wakeup) ? ~0 : 0; + 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); } static void tegra_kbc_config_pins(struct tegra_kbc *kbc) { - const struct tegra_kbc_platform_data *pdata = kbc->pdata; int i; for (i = 0; i < KBC_MAX_GPIO; i++) { @@ -441,10 +348,18 @@ static void tegra_kbc_config_pins(struct tegra_kbc *kbc) row_cfg &= ~r_mask; col_cfg &= ~c_mask; - if (pdata->pin_cfg[i].is_row) - row_cfg |= ((pdata->pin_cfg[i].num << 1) | 1) << r_shft; - else - col_cfg |= ((pdata->pin_cfg[i].num << 1) | 1) << c_shft; + switch (kbc->pin_cfg[i].type) { + case PIN_CFG_ROW: + row_cfg |= ((kbc->pin_cfg[i].num << 1) | 1) << r_shft; + break; + + case PIN_CFG_COL: + col_cfg |= ((kbc->pin_cfg[i].num << 1) | 1) << c_shft; + break; + + case PIN_CFG_IGNORE: + break; + } writel(row_cfg, kbc->mmio + r_offs); writel(col_cfg, kbc->mmio + c_offs); @@ -453,26 +368,24 @@ static void tegra_kbc_config_pins(struct tegra_kbc *kbc) static int tegra_kbc_start(struct tegra_kbc *kbc) { - const struct tegra_kbc_platform_data *pdata = kbc->pdata; - unsigned long flags; unsigned int debounce_cnt; u32 val = 0; - clk_enable(kbc->clk); + clk_prepare_enable(kbc->clk); /* Reset the KBC controller to clear all previous status.*/ - tegra_periph_reset_assert(kbc->clk); + reset_control_assert(kbc->rst); udelay(100); - tegra_periph_reset_deassert(kbc->clk); + reset_control_assert(kbc->rst); udelay(100); tegra_kbc_config_pins(kbc); tegra_kbc_setup_wakekeys(kbc, false); - writel(pdata->repeat_cnt, kbc->mmio + KBC_RPT_DLY_0); + writel(kbc->repeat_cnt, kbc->mmio + KBC_RPT_DLY_0); /* Keyboard debounce count is maximum of 12 bits. */ - debounce_cnt = min(pdata->debounce_cnt, KBC_MAX_DEBOUNCE_CNT); + debounce_cnt = min(kbc->debounce_cnt, KBC_MAX_DEBOUNCE_CNT); val = KBC_DEBOUNCE_CNT_SHIFT(debounce_cnt); val |= KBC_FIFO_TH_CNT_SHIFT(1); /* set fifo interrupt threshold to 1 */ val |= KBC_CONTROL_FIFO_CNT_INT_EN; /* interrupt on FIFO threshold */ @@ -492,7 +405,6 @@ static int tegra_kbc_start(struct tegra_kbc *kbc) * Atomically clear out any remaining entries in the key FIFO * and enable keyboard interrupts. */ - spin_lock_irqsave(&kbc->lock, flags); while (1) { val = readl(kbc->mmio + KBC_INT_0); val >>= 4; @@ -503,7 +415,6 @@ static int tegra_kbc_start(struct tegra_kbc *kbc) val = readl(kbc->mmio + KBC_KP_ENT1_0); } writel(0x7, kbc->mmio + KBC_INT_0); - spin_unlock_irqrestore(&kbc->lock, flags); enable_irq(kbc->irq); @@ -524,7 +435,7 @@ static void tegra_kbc_stop(struct tegra_kbc *kbc) disable_irq(kbc->irq); del_timer_sync(&kbc->timer); - clk_disable(kbc->clk); + clk_disable_unprepare(kbc->clk); } static int tegra_kbc_open(struct input_dev *dev) @@ -541,101 +452,222 @@ static void tegra_kbc_close(struct input_dev *dev) return tegra_kbc_stop(kbc); } -static bool __devinit -tegra_kbc_check_pin_cfg(const struct tegra_kbc_platform_data *pdata, - struct device *dev, unsigned int *num_rows) +static bool tegra_kbc_check_pin_cfg(const struct tegra_kbc *kbc, + unsigned int *num_rows) { int i; *num_rows = 0; for (i = 0; i < KBC_MAX_GPIO; i++) { - const struct tegra_kbc_pin_cfg *pin_cfg = &pdata->pin_cfg[i]; + const struct tegra_kbc_pin_cfg *pin_cfg = &kbc->pin_cfg[i]; - if (pin_cfg->is_row) { - if (pin_cfg->num >= KBC_MAX_ROW) { - dev_err(dev, + switch (pin_cfg->type) { + case PIN_CFG_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); return false; } (*num_rows)++; - } else { - if (pin_cfg->num >= KBC_MAX_COL) { - dev_err(dev, + break; + + case PIN_CFG_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); return false; } + break; + + case PIN_CFG_IGNORE: + break; + + default: + dev_err(kbc->dev, + "pin_cfg[%d]: invalid entry type %d\n", + pin_cfg->type, pin_cfg->num); + return false; } } return true; } -static int __devinit tegra_kbc_probe(struct platform_device *pdev) +static int tegra_kbc_parse_dt(struct tegra_kbc *kbc) +{ + struct device_node *np = kbc->dev->of_node; + u32 prop; + int i; + u32 num_rows = 0; + u32 num_cols = 0; + u32 cols_cfg[KBC_MAX_GPIO]; + u32 rows_cfg[KBC_MAX_GPIO]; + int proplen; + int ret; + + if (!of_property_read_u32(np, "nvidia,debounce-delay-ms", &prop)) + kbc->debounce_cnt = prop; + + if (!of_property_read_u32(np, "nvidia,repeat-delay-ms", &prop)) + kbc->repeat_cnt = prop; + + if (of_find_property(np, "nvidia,needs-ghost-filter", NULL)) + kbc->use_ghost_filter = true; + + if (of_find_property(np, "nvidia,wakeup-source", NULL)) + kbc->wakeup = true; + + if (!of_get_property(np, "nvidia,kbc-row-pins", &proplen)) { + dev_err(kbc->dev, "property nvidia,kbc-row-pins not found\n"); + return -ENOENT; + } + num_rows = proplen / sizeof(u32); + + if (!of_get_property(np, "nvidia,kbc-col-pins", &proplen)) { + dev_err(kbc->dev, "property nvidia,kbc-col-pins not found\n"); + return -ENOENT; + } + 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; + } + + if (!num_rows || !num_cols || ((num_rows + num_cols) > KBC_MAX_GPIO)) { + dev_err(kbc->dev, + "keypad rows/columns not porperly specified\n"); + return -EINVAL; + } + + /* Set all pins as non-configured */ + 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", + rows_cfg, num_rows); + if (ret < 0) { + dev_err(kbc->dev, "Rows configurations are not proper\n"); + return -EINVAL; + } + + ret = of_property_read_u32_array(np, "nvidia,kbc-col-pins", + cols_cfg, num_cols); + if (ret < 0) { + dev_err(kbc->dev, "Cols configurations are not proper\n"); + return -EINVAL; + } + + for (i = 0; i < num_rows; i++) { + kbc->pin_cfg[rows_cfg[i]].type = PIN_CFG_ROW; + kbc->pin_cfg[rows_cfg[i]].num = i; + } + + for (i = 0; i < num_cols; i++) { + kbc->pin_cfg[cols_cfg[i]].type = PIN_CFG_COL; + kbc->pin_cfg[cols_cfg[i]].num = i; + } + + 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) { - const struct tegra_kbc_platform_data *pdata = pdev->dev.platform_data; - const struct matrix_keymap_data *keymap_data; struct tegra_kbc *kbc; - struct input_dev *input_dev; struct resource *res; - int irq; int err; int num_rows = 0; unsigned int debounce_cnt; unsigned int scan_time_rows; + unsigned int keymap_rows; + const struct of_device_id *match; - if (!pdata) - return -EINVAL; - - if (!tegra_kbc_check_pin_cfg(pdata, &pdev->dev, &num_rows)) - return -EINVAL; + match = of_match_device(tegra_kbc_of_match, &pdev->dev); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "failed to get I/O memory\n"); - return -ENXIO; + kbc = devm_kzalloc(&pdev->dev, sizeof(*kbc), GFP_KERNEL); + if (!kbc) { + dev_err(&pdev->dev, "failed to alloc memory for kbc\n"); + return -ENOMEM; } - irq = platform_get_irq(pdev, 0); - if (irq < 0) { + 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); + if (err) + return err; + + if (!tegra_kbc_check_pin_cfg(kbc, &num_rows)) + return -EINVAL; + + kbc->irq = platform_get_irq(pdev, 0); + if (kbc->irq < 0) { dev_err(&pdev->dev, "failed to get keyboard IRQ\n"); return -ENXIO; } - kbc = kzalloc(sizeof(*kbc), GFP_KERNEL); - input_dev = input_allocate_device(); - if (!kbc || !input_dev) { - err = -ENOMEM; - goto err_free_mem; + kbc->idev = devm_input_allocate_device(&pdev->dev); + if (!kbc->idev) { + dev_err(&pdev->dev, "failed to allocate input device\n"); + return -ENOMEM; } - kbc->pdata = pdata; - kbc->idev = input_dev; - kbc->irq = irq; - spin_lock_init(&kbc->lock); setup_timer(&kbc->timer, tegra_kbc_keypress_timer, (unsigned long)kbc); - res = request_mem_region(res->start, resource_size(res), pdev->name); - if (!res) { - dev_err(&pdev->dev, "failed to request I/O memory\n"); - err = -EBUSY; - goto err_free_mem; - } - - kbc->mmio = ioremap(res->start, resource_size(res)); - if (!kbc->mmio) { - dev_err(&pdev->dev, "failed to remap I/O memory\n"); - err = -ENXIO; - goto err_free_mem_region; - } + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + kbc->mmio = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(kbc->mmio)) + return PTR_ERR(kbc->mmio); - kbc->clk = clk_get(&pdev->dev, NULL); + kbc->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(kbc->clk)) { dev_err(&pdev->dev, "failed to get keyboard clock\n"); - err = PTR_ERR(kbc->clk); - goto err_iounmap; + return PTR_ERR(kbc->clk); + } + + kbc->rst = devm_reset_control_get(&pdev->dev, "kbc"); + if (IS_ERR(kbc->rst)) { + dev_err(&pdev->dev, "failed to get keyboard reset\n"); + return PTR_ERR(kbc->rst); } /* @@ -644,39 +676,39 @@ static int __devinit tegra_kbc_probe(struct platform_device *pdev) * the rows. There is an additional delay before the row scanning * starts. The repoll delay is computed in milliseconds. */ - debounce_cnt = min(pdata->debounce_cnt, KBC_MAX_DEBOUNCE_CNT); + debounce_cnt = min(kbc->debounce_cnt, KBC_MAX_DEBOUNCE_CNT); scan_time_rows = (KBC_ROW_SCAN_TIME + debounce_cnt) * num_rows; - kbc->repoll_dly = KBC_ROW_SCAN_DLY + scan_time_rows + pdata->repeat_cnt; - kbc->repoll_dly = ((kbc->repoll_dly * KBC_CYCLE_USEC) + 999) / 1000; - - input_dev->name = pdev->name; - input_dev->id.bustype = BUS_HOST; - input_dev->dev.parent = &pdev->dev; - input_dev->open = tegra_kbc_open; - input_dev->close = tegra_kbc_close; - - input_set_drvdata(input_dev, kbc); - - input_dev->evbit[0] = BIT_MASK(EV_KEY); - input_set_capability(input_dev, EV_MSC, MSC_SCAN); - - input_dev->keycode = kbc->keycode; - input_dev->keycodesize = sizeof(kbc->keycode[0]); - input_dev->keycodemax = KBC_MAX_KEY; - if (pdata->use_fn_map) - input_dev->keycodemax *= 2; - - kbc->use_fn_map = pdata->use_fn_map; - kbc->use_ghost_filter = pdata->use_ghost_filter; - keymap_data = pdata->keymap_data ?: &tegra_kbc_default_keymap_data; - matrix_keypad_build_keymap(keymap_data, KBC_ROW_SHIFT, - input_dev->keycode, input_dev->keybit); - - err = request_irq(kbc->irq, tegra_kbc_isr, IRQF_TRIGGER_HIGH, - pdev->name, kbc); + kbc->repoll_dly = KBC_ROW_SCAN_DLY + scan_time_rows + kbc->repeat_cnt; + kbc->repoll_dly = DIV_ROUND_UP(kbc->repoll_dly, KBC_CYCLE_MS); + + kbc->idev->name = pdev->name; + kbc->idev->id.bustype = BUS_HOST; + kbc->idev->dev.parent = &pdev->dev; + kbc->idev->open = tegra_kbc_open; + kbc->idev->close = tegra_kbc_close; + + if (kbc->keymap_data && kbc->use_fn_map) + keymap_rows *= 2; + + err = matrix_keypad_build_keymap(kbc->keymap_data, NULL, + keymap_rows, + kbc->hw_support->max_columns, + kbc->keycode, kbc->idev); + if (err) { + dev_err(&pdev->dev, "failed to setup keymap\n"); + return err; + } + + __set_bit(EV_REP, kbc->idev->evbit); + input_set_capability(kbc->idev, EV_MSC, MSC_SCAN); + + input_set_drvdata(kbc->idev, kbc); + + err = devm_request_irq(&pdev->dev, kbc->irq, tegra_kbc_isr, + IRQF_NO_SUSPEND | IRQF_TRIGGER_HIGH, pdev->name, kbc); if (err) { dev_err(&pdev->dev, "failed to request keyboard IRQ\n"); - goto err_put_clk; + return err; } disable_irq(kbc->irq); @@ -684,67 +716,61 @@ static int __devinit tegra_kbc_probe(struct platform_device *pdev) err = input_register_device(kbc->idev); if (err) { dev_err(&pdev->dev, "failed to register input device\n"); - goto err_free_irq; + return err; } platform_set_drvdata(pdev, kbc); - device_init_wakeup(&pdev->dev, pdata->wakeup); + device_init_wakeup(&pdev->dev, kbc->wakeup); return 0; - -err_free_irq: - free_irq(kbc->irq, pdev); -err_put_clk: - clk_put(kbc->clk); -err_iounmap: - iounmap(kbc->mmio); -err_free_mem_region: - release_mem_region(res->start, resource_size(res)); -err_free_mem: - input_free_device(kbc->idev); - kfree(kbc); - - return err; } -static int __devexit tegra_kbc_remove(struct platform_device *pdev) +#ifdef CONFIG_PM_SLEEP +static void tegra_kbc_set_keypress_interrupt(struct tegra_kbc *kbc, bool enable) { - struct tegra_kbc *kbc = platform_get_drvdata(pdev); - struct resource *res; - - free_irq(kbc->irq, pdev); - clk_put(kbc->clk); - - input_unregister_device(kbc->idev); - iounmap(kbc->mmio); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(res->start, resource_size(res)); - - kfree(kbc); - - platform_set_drvdata(pdev, NULL); + u32 val; - return 0; + val = readl(kbc->mmio + KBC_CONTROL_0); + if (enable) + val |= KBC_CONTROL_KEYPRESS_INT_EN; + else + val &= ~KBC_CONTROL_KEYPRESS_INT_EN; + writel(val, kbc->mmio + KBC_CONTROL_0); } -#ifdef CONFIG_PM_SLEEP static int tegra_kbc_suspend(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct tegra_kbc *kbc = platform_get_drvdata(pdev); + mutex_lock(&kbc->idev->mutex); if (device_may_wakeup(&pdev->dev)) { - tegra_kbc_setup_wakekeys(kbc, true); - enable_irq_wake(kbc->irq); + disable_irq(kbc->irq); + del_timer_sync(&kbc->timer); + tegra_kbc_set_fifo_interrupt(kbc, false); + /* Forcefully clear the interrupt status */ writel(0x7, kbc->mmio + KBC_INT_0); + /* + * Store the previous resident time of continuous polling mode. + * Force the keyboard into interrupt mode. + */ + kbc->cp_to_wkup_dly = readl(kbc->mmio + KBC_TO_CNT_0); + writel(0, kbc->mmio + KBC_TO_CNT_0); + + tegra_kbc_setup_wakekeys(kbc, true); msleep(30); + + kbc->keypress_caused_wake = false; + /* Enable keypress interrupt before going into suspend. */ + tegra_kbc_set_keypress_interrupt(kbc, true); + enable_irq(kbc->irq); + enable_irq_wake(kbc->irq); } else { - mutex_lock(&kbc->idev->mutex); if (kbc->idev->users) tegra_kbc_stop(kbc); - mutex_unlock(&kbc->idev->mutex); } + mutex_unlock(&kbc->idev->mutex); return 0; } @@ -755,15 +781,36 @@ static int tegra_kbc_resume(struct device *dev) struct tegra_kbc *kbc = platform_get_drvdata(pdev); int err = 0; + mutex_lock(&kbc->idev->mutex); if (device_may_wakeup(&pdev->dev)) { disable_irq_wake(kbc->irq); tegra_kbc_setup_wakekeys(kbc, false); + /* We will use fifo interrupts for key detection. */ + tegra_kbc_set_keypress_interrupt(kbc, false); + + /* Restore the resident time of continuous polling mode. */ + writel(kbc->cp_to_wkup_dly, kbc->mmio + KBC_TO_CNT_0); + + tegra_kbc_set_fifo_interrupt(kbc, true); + + if (kbc->keypress_caused_wake && kbc->wakeup_key) { + /* + * We can't report events directly from the ISR + * because timekeeping is stopped when processing + * wakeup request and we get a nasty warning when + * we try to call do_gettimeofday() in evdev + * handler. + */ + input_report_key(kbc->idev, kbc->wakeup_key, 1); + input_sync(kbc->idev); + input_report_key(kbc->idev, kbc->wakeup_key, 0); + input_sync(kbc->idev); + } } else { - mutex_lock(&kbc->idev->mutex); if (kbc->idev->users) err = tegra_kbc_start(kbc); - mutex_unlock(&kbc->idev->mutex); } + mutex_unlock(&kbc->idev->mutex); return err; } @@ -773,25 +820,14 @@ static SIMPLE_DEV_PM_OPS(tegra_kbc_pm_ops, tegra_kbc_suspend, tegra_kbc_resume); static struct platform_driver tegra_kbc_driver = { .probe = tegra_kbc_probe, - .remove = __devexit_p(tegra_kbc_remove), .driver = { .name = "tegra-kbc", .owner = THIS_MODULE, .pm = &tegra_kbc_pm_ops, + .of_match_table = tegra_kbc_of_match, }, }; - -static void __exit tegra_kbc_exit(void) -{ - platform_driver_unregister(&tegra_kbc_driver); -} -module_exit(tegra_kbc_exit); - -static int __init tegra_kbc_init(void) -{ - return platform_driver_register(&tegra_kbc_driver); -} -module_init(tegra_kbc_init); +module_platform_driver(tegra_kbc_driver); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Rakesh Iyer <riyer@nvidia.com>"); diff --git a/drivers/input/keyboard/tnetv107x-keypad.c b/drivers/input/keyboard/tnetv107x-keypad.c deleted file mode 100644 index c8f097a15d8..00000000000 --- a/drivers/input/keyboard/tnetv107x-keypad.c +++ /dev/null @@ -1,341 +0,0 @@ -/* - * Texas Instruments TNETV107X Keypad Driver - * - * Copyright (C) 2010 Texas Instruments - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include <linux/kernel.h> -#include <linux/err.h> -#include <linux/errno.h> -#include <linux/input.h> -#include <linux/platform_device.h> -#include <linux/interrupt.h> -#include <linux/slab.h> -#include <linux/delay.h> -#include <linux/io.h> -#include <linux/clk.h> -#include <linux/input/matrix_keypad.h> - -#define BITS(x) (BIT(x) - 1) - -#define KEYPAD_ROWS 9 -#define KEYPAD_COLS 9 - -#define DEBOUNCE_MIN 0x400ul -#define DEBOUNCE_MAX 0x3ffffffful - -struct keypad_regs { - u32 rev; - u32 mode; - u32 mask; - u32 pol; - u32 dclock; - u32 rclock; - u32 stable_cnt; - u32 in_en; - u32 out; - u32 out_en; - u32 in; - u32 lock; - u32 pres[3]; -}; - -#define keypad_read(kp, reg) __raw_readl(&(kp)->regs->reg) -#define keypad_write(kp, reg, val) __raw_writel(val, &(kp)->regs->reg) - -struct keypad_data { - struct input_dev *input_dev; - struct resource *res; - struct keypad_regs __iomem *regs; - struct clk *clk; - struct device *dev; - spinlock_t lock; - u32 irq_press; - u32 irq_release; - int rows, cols, row_shift; - int debounce_ms, active_low; - u32 prev_keys[3]; - unsigned short keycodes[]; -}; - -static irqreturn_t keypad_irq(int irq, void *data) -{ - struct keypad_data *kp = data; - int i, bit, val, row, col, code; - unsigned long flags; - u32 curr_keys[3]; - u32 change; - - spin_lock_irqsave(&kp->lock, flags); - - memset(curr_keys, 0, sizeof(curr_keys)); - if (irq == kp->irq_press) - for (i = 0; i < 3; i++) - curr_keys[i] = keypad_read(kp, pres[i]); - - for (i = 0; i < 3; i++) { - change = curr_keys[i] ^ kp->prev_keys[i]; - - while (change) { - bit = fls(change) - 1; - change ^= BIT(bit); - val = curr_keys[i] & BIT(bit); - bit += i * 32; - row = bit / KEYPAD_COLS; - col = bit % KEYPAD_COLS; - - code = MATRIX_SCAN_CODE(row, col, kp->row_shift); - input_event(kp->input_dev, EV_MSC, MSC_SCAN, code); - input_report_key(kp->input_dev, kp->keycodes[code], - val); - } - } - input_sync(kp->input_dev); - memcpy(kp->prev_keys, curr_keys, sizeof(curr_keys)); - - if (irq == kp->irq_press) - keypad_write(kp, lock, 0); /* Allow hardware updates */ - - spin_unlock_irqrestore(&kp->lock, flags); - - return IRQ_HANDLED; -} - -static int keypad_start(struct input_dev *dev) -{ - struct keypad_data *kp = input_get_drvdata(dev); - unsigned long mask, debounce, clk_rate_khz; - unsigned long flags; - - clk_enable(kp->clk); - clk_rate_khz = clk_get_rate(kp->clk) / 1000; - - spin_lock_irqsave(&kp->lock, flags); - - /* Initialize device registers */ - keypad_write(kp, mode, 0); - - mask = BITS(kp->rows) << KEYPAD_COLS; - mask |= BITS(kp->cols); - keypad_write(kp, mask, ~mask); - - keypad_write(kp, pol, kp->active_low ? 0 : 0x3ffff); - keypad_write(kp, stable_cnt, 3); - - debounce = kp->debounce_ms * clk_rate_khz; - debounce = clamp(debounce, DEBOUNCE_MIN, DEBOUNCE_MAX); - keypad_write(kp, dclock, debounce); - keypad_write(kp, rclock, 4 * debounce); - - keypad_write(kp, in_en, 1); - - spin_unlock_irqrestore(&kp->lock, flags); - - return 0; -} - -static void keypad_stop(struct input_dev *dev) -{ - struct keypad_data *kp = input_get_drvdata(dev); - - synchronize_irq(kp->irq_press); - synchronize_irq(kp->irq_release); - clk_disable(kp->clk); -} - -static int __devinit keypad_probe(struct platform_device *pdev) -{ - const struct matrix_keypad_platform_data *pdata; - const struct matrix_keymap_data *keymap_data; - struct device *dev = &pdev->dev; - struct keypad_data *kp; - int error = 0, sz, row_shift; - u32 rev = 0; - - pdata = pdev->dev.platform_data; - if (!pdata) { - dev_err(dev, "cannot find device data\n"); - return -EINVAL; - } - - keymap_data = pdata->keymap_data; - if (!keymap_data) { - dev_err(dev, "cannot find keymap data\n"); - return -EINVAL; - } - - row_shift = get_count_order(pdata->num_col_gpios); - sz = offsetof(struct keypad_data, keycodes); - sz += (pdata->num_row_gpios << row_shift) * sizeof(kp->keycodes[0]); - kp = kzalloc(sz, GFP_KERNEL); - if (!kp) { - dev_err(dev, "cannot allocate device info\n"); - return -ENOMEM; - } - - kp->dev = dev; - kp->rows = pdata->num_row_gpios; - kp->cols = pdata->num_col_gpios; - kp->row_shift = row_shift; - platform_set_drvdata(pdev, kp); - spin_lock_init(&kp->lock); - - kp->irq_press = platform_get_irq_byname(pdev, "press"); - kp->irq_release = platform_get_irq_byname(pdev, "release"); - if (kp->irq_press < 0 || kp->irq_release < 0) { - dev_err(dev, "cannot determine device interrupts\n"); - error = -ENODEV; - goto error_res; - } - - kp->res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!kp->res) { - dev_err(dev, "cannot determine register area\n"); - error = -ENODEV; - goto error_res; - } - - if (!request_mem_region(kp->res->start, resource_size(kp->res), - pdev->name)) { - dev_err(dev, "cannot claim register memory\n"); - kp->res = NULL; - error = -EINVAL; - goto error_res; - } - - kp->regs = ioremap(kp->res->start, resource_size(kp->res)); - if (!kp->regs) { - dev_err(dev, "cannot map register memory\n"); - error = -ENOMEM; - goto error_map; - } - - kp->clk = clk_get(dev, NULL); - if (IS_ERR(kp->clk)) { - dev_err(dev, "cannot claim device clock\n"); - error = PTR_ERR(kp->clk); - goto error_clk; - } - - error = request_threaded_irq(kp->irq_press, NULL, keypad_irq, 0, - dev_name(dev), kp); - if (error < 0) { - dev_err(kp->dev, "Could not allocate keypad press key irq\n"); - goto error_irq_press; - } - - error = request_threaded_irq(kp->irq_release, NULL, keypad_irq, 0, - dev_name(dev), kp); - if (error < 0) { - dev_err(kp->dev, "Could not allocate keypad release key irq\n"); - goto error_irq_release; - } - - kp->input_dev = input_allocate_device(); - if (!kp->input_dev) { - dev_err(dev, "cannot allocate input device\n"); - error = -ENOMEM; - goto error_input; - } - input_set_drvdata(kp->input_dev, kp); - - kp->input_dev->name = pdev->name; - kp->input_dev->dev.parent = &pdev->dev; - kp->input_dev->open = keypad_start; - kp->input_dev->close = keypad_stop; - kp->input_dev->evbit[0] = BIT_MASK(EV_KEY); - if (!pdata->no_autorepeat) - kp->input_dev->evbit[0] |= BIT_MASK(EV_REP); - - clk_enable(kp->clk); - rev = keypad_read(kp, rev); - kp->input_dev->id.bustype = BUS_HOST; - kp->input_dev->id.product = ((rev >> 8) & 0x07); - kp->input_dev->id.version = ((rev >> 16) & 0xfff); - clk_disable(kp->clk); - - kp->input_dev->keycode = kp->keycodes; - kp->input_dev->keycodesize = sizeof(kp->keycodes[0]); - kp->input_dev->keycodemax = kp->rows << kp->row_shift; - - matrix_keypad_build_keymap(keymap_data, kp->row_shift, kp->keycodes, - kp->input_dev->keybit); - - input_set_capability(kp->input_dev, EV_MSC, MSC_SCAN); - - error = input_register_device(kp->input_dev); - if (error < 0) { - dev_err(dev, "Could not register input device\n"); - goto error_reg; - } - - return 0; - - -error_reg: - input_free_device(kp->input_dev); -error_input: - free_irq(kp->irq_release, kp); -error_irq_release: - free_irq(kp->irq_press, kp); -error_irq_press: - clk_put(kp->clk); -error_clk: - iounmap(kp->regs); -error_map: - release_mem_region(kp->res->start, resource_size(kp->res)); -error_res: - platform_set_drvdata(pdev, NULL); - kfree(kp); - return error; -} - -static int __devexit keypad_remove(struct platform_device *pdev) -{ - struct keypad_data *kp = platform_get_drvdata(pdev); - - free_irq(kp->irq_press, kp); - free_irq(kp->irq_release, kp); - input_unregister_device(kp->input_dev); - 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; -} - -static struct platform_driver keypad_driver = { - .probe = keypad_probe, - .remove = __devexit_p(keypad_remove), - .driver.name = "tnetv107x-keypad", - .driver.owner = THIS_MODULE, -}; - -static int __init keypad_init(void) -{ - return platform_driver_register(&keypad_driver); -} - -static void __exit keypad_exit(void) -{ - platform_driver_unregister(&keypad_driver); -} - -module_init(keypad_init); -module_exit(keypad_exit); - -MODULE_AUTHOR("Cyril Chemparathy"); -MODULE_DESCRIPTION("TNETV107X Keypad Driver"); -MODULE_ALIAS("platform: tnetv107x-keypad"); -MODULE_LICENSE("GPL"); diff --git a/drivers/input/keyboard/twl4030_keypad.c b/drivers/input/keyboard/twl4030_keypad.c index a26922cf0e8..c5a11700a1b 100644 --- a/drivers/input/keyboard/twl4030_keypad.c +++ b/drivers/input/keyboard/twl4030_keypad.c @@ -27,13 +27,12 @@ #include <linux/kernel.h> #include <linux/module.h> -#include <linux/init.h> #include <linux/interrupt.h> #include <linux/input.h> #include <linux/platform_device.h> #include <linux/i2c/twl.h> #include <linux/slab.h> - +#include <linux/of.h> /* * The TWL4030 family chips include a keypad controller that supports @@ -61,6 +60,7 @@ struct twl4030_keypad { unsigned short keymap[TWL4030_KEYMAP_SIZE]; u16 kp_state[TWL4030_MAX_ROWS]; + bool autorepeat; unsigned n_rows; unsigned n_cols; unsigned irq; @@ -272,7 +272,7 @@ static irqreturn_t do_kp_irq(int irq, void *_kp) return IRQ_HANDLED; } -static int __devinit twl4030_kp_program(struct twl4030_keypad *kp) +static int twl4030_kp_program(struct twl4030_keypad *kp) { u8 reg; int i; @@ -302,7 +302,7 @@ static int __devinit twl4030_kp_program(struct twl4030_keypad *kp) if (twl4030_kpwrite_u8(kp, i, KEYP_DEB) < 0) return -EIO; - /* Set timeout period to 100 ms */ + /* Set timeout period to 200 ms */ i = KEYP_PERIOD_US(200000, PTV_PRESCALER); if (twl4030_kpwrite_u8(kp, (i & 0xFF), KEYP_TIMEOUT_L) < 0) return -EIO; @@ -329,73 +329,91 @@ static int __devinit twl4030_kp_program(struct twl4030_keypad *kp) * Registers keypad device with input subsystem * and configures TWL4030 keypad registers */ -static int __devinit twl4030_kp_probe(struct platform_device *pdev) +static int twl4030_kp_probe(struct platform_device *pdev) { - struct twl4030_keypad_data *pdata = pdev->dev.platform_data; - const struct matrix_keymap_data *keymap_data; + struct twl4030_keypad_data *pdata = dev_get_platdata(&pdev->dev); + const struct matrix_keymap_data *keymap_data = NULL; struct twl4030_keypad *kp; struct input_dev *input; u8 reg; int error; - if (!pdata || !pdata->rows || !pdata->cols || !pdata->keymap_data || - pdata->rows > TWL4030_MAX_ROWS || pdata->cols > TWL4030_MAX_COLS) { - dev_err(&pdev->dev, "Invalid platform_data\n"); - return -EINVAL; - } - - keymap_data = pdata->keymap_data; + kp = devm_kzalloc(&pdev->dev, sizeof(*kp), GFP_KERNEL); + if (!kp) + return -ENOMEM; - kp = kzalloc(sizeof(*kp), GFP_KERNEL); - input = input_allocate_device(); - if (!kp || !input) { - error = -ENOMEM; - goto err1; - } + input = devm_input_allocate_device(&pdev->dev); + if (!input) + return -ENOMEM; - /* Get the debug Device */ - kp->dbg_dev = &pdev->dev; - kp->input = input; - - kp->n_rows = pdata->rows; - kp->n_cols = pdata->cols; - kp->irq = platform_get_irq(pdev, 0); + /* get the debug device */ + kp->dbg_dev = &pdev->dev; + kp->input = input; /* setup input device */ - __set_bit(EV_KEY, input->evbit); - - /* Enable auto repeat feature of Linux input subsystem */ - if (pdata->rep) - __set_bit(EV_REP, input->evbit); - - input_set_capability(input, EV_MSC, MSC_SCAN); - input->name = "TWL4030 Keypad"; input->phys = "twl4030_keypad/input0"; - input->dev.parent = &pdev->dev; input->id.bustype = BUS_HOST; input->id.vendor = 0x0001; input->id.product = 0x0001; input->id.version = 0x0003; - input->keycode = kp->keymap; - input->keycodesize = sizeof(kp->keymap[0]); - input->keycodemax = ARRAY_SIZE(kp->keymap); + if (pdata) { + if (!pdata->rows || !pdata->cols || !pdata->keymap_data) { + dev_err(&pdev->dev, "Missing platform_data\n"); + return -EINVAL; + } + + kp->n_rows = pdata->rows; + kp->n_cols = pdata->cols; + kp->autorepeat = pdata->rep; + keymap_data = pdata->keymap_data; + } else { + error = matrix_keypad_parse_of_params(&pdev->dev, &kp->n_rows, + &kp->n_cols); + if (error) + return error; + + kp->autorepeat = true; + } + + if (kp->n_rows > TWL4030_MAX_ROWS || kp->n_cols > TWL4030_MAX_COLS) { + dev_err(&pdev->dev, + "Invalid rows/cols amount specified in platform/devicetree data\n"); + return -EINVAL; + } + + kp->irq = platform_get_irq(pdev, 0); + if (!kp->irq) { + dev_err(&pdev->dev, "no keyboard irq assigned\n"); + return -EINVAL; + } + + error = matrix_keypad_build_keymap(keymap_data, NULL, + TWL4030_MAX_ROWS, + 1 << TWL4030_ROW_SHIFT, + kp->keymap, input); + if (error) { + dev_err(kp->dbg_dev, "Failed to build keymap\n"); + return error; + } - matrix_keypad_build_keymap(keymap_data, TWL4030_ROW_SHIFT, - input->keycode, input->keybit); + input_set_capability(input, EV_MSC, MSC_SCAN); + /* Enable auto repeat feature of Linux input subsystem */ + if (kp->autorepeat) + __set_bit(EV_REP, input->evbit); error = input_register_device(input); if (error) { dev_err(kp->dbg_dev, "Unable to register twl4030 keypad device\n"); - goto err1; + return error; } error = twl4030_kp_program(kp); if (error) - goto err2; + return error; /* * This ISR will always execute in kernel thread context because of @@ -403,48 +421,33 @@ static int __devinit twl4030_kp_probe(struct platform_device *pdev) * * NOTE: we assume this host is wired to TWL4040 INT1, not INT2 ... */ - error = request_threaded_irq(kp->irq, NULL, do_kp_irq, - 0, pdev->name, kp); + error = devm_request_threaded_irq(&pdev->dev, kp->irq, NULL, do_kp_irq, + 0, pdev->name, kp); if (error) { - dev_info(kp->dbg_dev, "request_irq failed for irq no=%d\n", - kp->irq); - goto err2; + dev_info(kp->dbg_dev, "request_irq failed for irq no=%d: %d\n", + kp->irq, error); + return error; } /* Enable KP and TO interrupts now. */ reg = (u8) ~(KEYP_IMR1_KP | KEYP_IMR1_TO); if (twl4030_kpwrite_u8(kp, reg, KEYP_IMR1)) { - error = -EIO; - goto err3; + /* mask all events - we don't care about the result */ + (void) twl4030_kpwrite_u8(kp, 0xff, KEYP_IMR1); + return -EIO; } platform_set_drvdata(pdev, kp); return 0; - -err3: - /* mask all events - we don't care about the result */ - (void) twl4030_kpwrite_u8(kp, 0xff, KEYP_IMR1); - free_irq(kp->irq, NULL); -err2: - input_unregister_device(input); - input = NULL; -err1: - input_free_device(input); - kfree(kp); - return error; } -static int __devexit twl4030_kp_remove(struct platform_device *pdev) -{ - struct twl4030_keypad *kp = platform_get_drvdata(pdev); - - free_irq(kp->irq, kp); - input_unregister_device(kp->input); - platform_set_drvdata(pdev, NULL); - kfree(kp); - - return 0; -} +#ifdef CONFIG_OF +static const struct of_device_id twl4030_keypad_dt_match_table[] = { + { .compatible = "ti,twl4030-keypad" }, + {}, +}; +MODULE_DEVICE_TABLE(of, twl4030_keypad_dt_match_table); +#endif /* * NOTE: twl4030 are multi-function devices connected via I2C. @@ -454,27 +457,15 @@ static int __devexit twl4030_kp_remove(struct platform_device *pdev) static struct platform_driver twl4030_kp_driver = { .probe = twl4030_kp_probe, - .remove = __devexit_p(twl4030_kp_remove), .driver = { .name = "twl4030_keypad", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(twl4030_keypad_dt_match_table), }, }; - -static int __init twl4030_kp_init(void) -{ - return platform_driver_register(&twl4030_kp_driver); -} -module_init(twl4030_kp_init); - -static void __exit twl4030_kp_exit(void) -{ - platform_driver_unregister(&twl4030_kp_driver); -} -module_exit(twl4030_kp_exit); +module_platform_driver(twl4030_kp_driver); MODULE_AUTHOR("Texas Instruments"); MODULE_DESCRIPTION("TWL4030 Keypad Driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:twl4030_keypad"); - diff --git a/drivers/input/keyboard/w90p910_keypad.c b/drivers/input/keyboard/w90p910_keypad.c index ee2bf6bcf29..e8b9d94daae 100644 --- a/drivers/input/keyboard/w90p910_keypad.c +++ b/drivers/input/keyboard/w90p910_keypad.c @@ -11,7 +11,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> @@ -21,7 +20,7 @@ #include <linux/io.h> #include <linux/slab.h> -#include <mach/w90p910_keypad.h> +#include <linux/platform_data/keypad-w90p910.h> /* Keypad Interface Control Registers */ #define KPI_CONF 0x00 @@ -42,7 +41,8 @@ #define KGET_RAW(n) (((n) & KEY0R) >> 3) #define KGET_COLUMN(n) ((n) & KEY0C) -#define W90P910_MAX_KEY_NUM (8 * 8) +#define W90P910_NUM_ROWS 8 +#define W90P910_NUM_COLS 8 #define W90P910_ROW_SHIFT 3 struct w90p910_keypad { @@ -51,7 +51,7 @@ struct w90p910_keypad { struct input_dev *input_dev; void __iomem *mmio_base; int irq; - unsigned short keymap[W90P910_MAX_KEY_NUM]; + unsigned short keymap[W90P910_NUM_ROWS * W90P910_NUM_COLS]; }; static void w90p910_keypad_scan_matrix(struct w90p910_keypad *keypad, @@ -117,10 +117,10 @@ static void w90p910_keypad_close(struct input_dev *dev) clk_disable(keypad->clk); } -static int __devinit w90p910_keypad_probe(struct platform_device *pdev) +static int w90p910_keypad_probe(struct platform_device *pdev) { const struct w90p910_keypad_platform_data *pdata = - pdev->dev.platform_data; + dev_get_platdata(&pdev->dev); const struct matrix_keymap_data *keymap_data; struct w90p910_keypad *keypad; struct input_dev *input_dev; @@ -190,25 +190,25 @@ static int __devinit w90p910_keypad_probe(struct platform_device *pdev) input_dev->close = w90p910_keypad_close; input_dev->dev.parent = &pdev->dev; - input_dev->keycode = keypad->keymap; - input_dev->keycodesize = sizeof(keypad->keymap[0]); - input_dev->keycodemax = ARRAY_SIZE(keypad->keymap); - - input_set_drvdata(input_dev, keypad); - - input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP); - input_set_capability(input_dev, EV_MSC, MSC_SCAN); - - matrix_keypad_build_keymap(keymap_data, W90P910_ROW_SHIFT, - input_dev->keycode, input_dev->keybit); + error = matrix_keypad_build_keymap(keymap_data, NULL, + W90P910_NUM_ROWS, W90P910_NUM_COLS, + keypad->keymap, input_dev); + if (error) { + dev_err(&pdev->dev, "failed to build keymap\n"); + goto failed_put_clk; + } error = request_irq(keypad->irq, w90p910_keypad_irq_handler, - IRQF_DISABLED, pdev->name, keypad); + 0, pdev->name, keypad); if (error) { dev_err(&pdev->dev, "failed to request IRQ\n"); goto failed_put_clk; } + __set_bit(EV_REP, input_dev->evbit); + input_set_capability(input_dev, EV_MSC, MSC_SCAN); + input_set_drvdata(input_dev, keypad); + /* Register the input device */ error = input_register_device(input_dev); if (error) { @@ -220,7 +220,7 @@ static int __devinit 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: @@ -233,12 +233,12 @@ failed_free: return error; } -static int __devexit w90p910_keypad_remove(struct platform_device *pdev) +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); @@ -248,7 +248,6 @@ static int __devexit 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; @@ -256,25 +255,13 @@ static int __devexit w90p910_keypad_remove(struct platform_device *pdev) static struct platform_driver w90p910_keypad_driver = { .probe = w90p910_keypad_probe, - .remove = __devexit_p(w90p910_keypad_remove), + .remove = w90p910_keypad_remove, .driver = { .name = "nuc900-kpi", .owner = THIS_MODULE, }, }; - -static int __init w90p910_keypad_init(void) -{ - return platform_driver_register(&w90p910_keypad_driver); -} - -static void __exit w90p910_keypad_exit(void) -{ - platform_driver_unregister(&w90p910_keypad_driver); -} - -module_init(w90p910_keypad_init); -module_exit(w90p910_keypad_exit); +module_platform_driver(w90p910_keypad_driver); MODULE_AUTHOR("Wan ZongShun <mcuos.com@gmail.com>"); MODULE_DESCRIPTION("w90p910 keypad driver"); diff --git a/drivers/input/keyboard/xtkbd.c b/drivers/input/keyboard/xtkbd.c index 37b01d777a4..7c2325bd740 100644 --- a/drivers/input/keyboard/xtkbd.c +++ b/drivers/input/keyboard/xtkbd.c @@ -29,7 +29,6 @@ #include <linux/slab.h> #include <linux/module.h> #include <linux/input.h> -#include <linux/init.h> #include <linux/serio.h> #define DRIVER_DESC "XT keyboard driver" @@ -169,15 +168,4 @@ static struct serio_driver xtkbd_drv = { .disconnect = xtkbd_disconnect, }; -static int __init xtkbd_init(void) -{ - return serio_register_driver(&xtkbd_drv); -} - -static void __exit xtkbd_exit(void) -{ - serio_unregister_driver(&xtkbd_drv); -} - -module_init(xtkbd_init); -module_exit(xtkbd_exit); +module_serio_driver(xtkbd_drv); |
