diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-06-20 10:17:02 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-06-20 10:17:02 -0700 |
commit | 93db6294958f62643a917e44d1abc85440e600cf (patch) | |
tree | 33de2c41b0f70d209d64487d1a2bba6d673015ef /drivers | |
parent | 43813f399c72aa22e01a680559c1cb5274bf2140 (diff) | |
parent | eef3e4cab72eaf5345e3c73b2975c194a714f6cd (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input: (35 commits)
Input: add driver for Synaptics I2C touchpad
Input: synaptics - add support for reporting x/y resolution
Input: ALPS - handle touchpoints buttons correctly
Input: gpio-keys - change timer to workqueue
Input: ads7846 - pin change interrupt support
Input: add support for touchscreen on W90P910 ARM platform
Input: appletouch - improve finger detection
Input: wacom - clear Intuos4 wheel data when finger leaves proximity
Input: ucb1400 - move static function from header into core
Input: add driver for EETI touchpanels
Input: ads7846 - more detailed model name in sysfs
Input: ads7846 - support swapping x and y axes
Input: ati_remote2 - use non-atomic bitops
Input: introduce lm8323 keypad driver
Input: psmouse - ESD workaround fix for OLPC XO touchpad
Input: tsc2007 - make sure platform provides get_pendown_state()
Input: uinput - flush all pending ff effects before destroying device
Input: simplify name handling for certain input handles
Input: serio - do not use deprecated dev.power.power_state
Input: wacom - add support for Intuos4 tablets
...
Diffstat (limited to 'drivers')
42 files changed, 4142 insertions, 219 deletions
diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c index de26a978fbd..737be953cc5 100644 --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c @@ -1123,8 +1123,6 @@ static int emulate_raw(struct vc_data *vc, unsigned int keycode, #define HW_RAW(dev) 0 -#warning "Cannot generate rawmode keyboard for your architecture yet." - static int emulate_raw(struct vc_data *vc, unsigned int keycode, unsigned char up_flag) { if (keycode > 127) diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index 7a7a026ba71..114efd8dc8f 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -25,7 +25,6 @@ struct evdev { int exist; int open; int minor; - char name[16]; struct input_handle handle; wait_queue_head_t wait; struct evdev_client *grab; @@ -609,7 +608,8 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd, p, compat_mode); if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0))) - return str_to_user(dev->name, _IOC_SIZE(cmd), p); + return str_to_user(dev_name(&evdev->dev), + _IOC_SIZE(cmd), p); if (_IOC_NR(cmd) == _IOC_NR(EVIOCGPHYS(0))) return str_to_user(dev->phys, _IOC_SIZE(cmd), p); @@ -626,8 +626,11 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd, abs.maximum = dev->absmax[t]; abs.fuzz = dev->absfuzz[t]; abs.flat = dev->absflat[t]; + abs.resolution = dev->absres[t]; - if (copy_to_user(p, &abs, sizeof(struct input_absinfo))) + if (copy_to_user(p, &abs, min_t(size_t, + _IOC_SIZE(cmd), + sizeof(struct input_absinfo)))) return -EFAULT; return 0; @@ -654,8 +657,9 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd, t = _IOC_NR(cmd) & ABS_MAX; - if (copy_from_user(&abs, p, - sizeof(struct input_absinfo))) + if (copy_from_user(&abs, p, min_t(size_t, + _IOC_SIZE(cmd), + sizeof(struct input_absinfo)))) return -EFAULT; /* @@ -670,6 +674,8 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd, dev->absmax[t] = abs.maximum; dev->absfuzz[t] = abs.fuzz; dev->absflat[t] = abs.flat; + dev->absres[t] = _IOC_SIZE(cmd) < sizeof(struct input_absinfo) ? + 0 : abs.resolution; spin_unlock_irq(&dev->event_lock); @@ -807,16 +813,15 @@ static int evdev_connect(struct input_handler *handler, struct input_dev *dev, mutex_init(&evdev->mutex); init_waitqueue_head(&evdev->wait); - snprintf(evdev->name, sizeof(evdev->name), "event%d", minor); + dev_set_name(&evdev->dev, "event%d", minor); evdev->exist = 1; evdev->minor = minor; evdev->handle.dev = input_get_device(dev); - evdev->handle.name = evdev->name; + evdev->handle.name = dev_name(&evdev->dev); evdev->handle.handler = handler; evdev->handle.private = evdev; - dev_set_name(&evdev->dev, evdev->name); evdev->dev.devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor); evdev->dev.class = &input_class; evdev->dev.parent = &dev->dev; diff --git a/drivers/input/gameport/fm801-gp.c b/drivers/input/gameport/fm801-gp.c index 1dec00e20db..8a1810f88b9 100644 --- a/drivers/input/gameport/fm801-gp.c +++ b/drivers/input/gameport/fm801-gp.c @@ -167,5 +167,6 @@ module_exit(fm801_gp_exit); MODULE_DEVICE_TABLE(pci, fm801_gp_id_table); +MODULE_DESCRIPTION("FM801 gameport driver"); MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>"); MODULE_LICENSE("GPL"); diff --git a/drivers/input/gameport/gameport.c b/drivers/input/gameport/gameport.c index 2d175b5928f..ac11be08585 100644 --- a/drivers/input/gameport/gameport.c +++ b/drivers/input/gameport/gameport.c @@ -30,16 +30,6 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); MODULE_DESCRIPTION("Generic gameport layer"); MODULE_LICENSE("GPL"); -EXPORT_SYMBOL(__gameport_register_port); -EXPORT_SYMBOL(gameport_unregister_port); -EXPORT_SYMBOL(__gameport_register_driver); -EXPORT_SYMBOL(gameport_unregister_driver); -EXPORT_SYMBOL(gameport_open); -EXPORT_SYMBOL(gameport_close); -EXPORT_SYMBOL(gameport_set_phys); -EXPORT_SYMBOL(gameport_start_polling); -EXPORT_SYMBOL(gameport_stop_polling); - /* * gameport_mutex protects entire gameport subsystem and is taken * every time gameport port or driver registrered or unregistered. @@ -162,6 +152,7 @@ void gameport_start_polling(struct gameport *gameport) spin_unlock(&gameport->timer_lock); } +EXPORT_SYMBOL(gameport_start_polling); void gameport_stop_polling(struct gameport *gameport) { @@ -172,6 +163,7 @@ void gameport_stop_polling(struct gameport *gameport) spin_unlock(&gameport->timer_lock); } +EXPORT_SYMBOL(gameport_stop_polling); static void gameport_run_poll_handler(unsigned long d) { @@ -516,6 +508,7 @@ void gameport_set_phys(struct gameport *gameport, const char *fmt, ...) vsnprintf(gameport->phys, sizeof(gameport->phys), fmt, args); va_end(args); } +EXPORT_SYMBOL(gameport_set_phys); /* * Prepare gameport port for registration. @@ -658,6 +651,7 @@ void __gameport_register_port(struct gameport *gameport, struct module *owner) gameport_init_port(gameport); gameport_queue_event(gameport, owner, GAMEPORT_REGISTER_PORT); } +EXPORT_SYMBOL(__gameport_register_port); /* * Synchronously unregisters gameport port. @@ -669,6 +663,7 @@ void gameport_unregister_port(struct gameport *gameport) gameport_destroy_port(gameport); mutex_unlock(&gameport_mutex); } +EXPORT_SYMBOL(gameport_unregister_port); /* @@ -728,7 +723,7 @@ int __gameport_register_driver(struct gameport_driver *drv, struct module *owner * Temporarily disable automatic binding because probing * takes long time and we are better off doing it in kgameportd */ - drv->ignore = 1; + drv->ignore = true; error = driver_register(&drv->driver); if (error) { @@ -741,7 +736,7 @@ int __gameport_register_driver(struct gameport_driver *drv, struct module *owner /* * Reset ignore flag and let kgameportd bind the driver to free ports */ - drv->ignore = 0; + drv->ignore = false; error = gameport_queue_event(drv, NULL, GAMEPORT_ATTACH_DRIVER); if (error) { driver_unregister(&drv->driver); @@ -750,6 +745,7 @@ int __gameport_register_driver(struct gameport_driver *drv, struct module *owner return 0; } +EXPORT_SYMBOL(__gameport_register_driver); void gameport_unregister_driver(struct gameport_driver *drv) { @@ -757,7 +753,7 @@ void gameport_unregister_driver(struct gameport_driver *drv) mutex_lock(&gameport_mutex); - drv->ignore = 1; /* so gameport_find_driver ignores it */ + drv->ignore = true; /* so gameport_find_driver ignores it */ gameport_remove_pending_events(drv); start_over: @@ -774,6 +770,7 @@ start_over: mutex_unlock(&gameport_mutex); } +EXPORT_SYMBOL(gameport_unregister_driver); static int gameport_bus_match(struct device *dev, struct device_driver *drv) { @@ -812,6 +809,7 @@ int gameport_open(struct gameport *gameport, struct gameport_driver *drv, int mo gameport_set_drv(gameport, drv); return 0; } +EXPORT_SYMBOL(gameport_open); void gameport_close(struct gameport *gameport) { @@ -822,6 +820,7 @@ void gameport_close(struct gameport *gameport) if (gameport->close) gameport->close(gameport); } +EXPORT_SYMBOL(gameport_close); static int __init gameport_init(void) { diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c index 012a5e75399..0e12f89276a 100644 --- a/drivers/input/joydev.c +++ b/drivers/input/joydev.c @@ -39,7 +39,6 @@ struct joydev { int exist; int open; int minor; - char name[16]; struct input_handle handle; wait_queue_head_t wait; struct list_head client_list; @@ -537,12 +536,14 @@ static int joydev_ioctl_common(struct joydev *joydev, default: if ((cmd & ~IOCSIZE_MASK) == JSIOCGNAME(0)) { int len; - if (!dev->name) + const char *name = dev_name(&dev->dev); + + if (!name) return 0; - len = strlen(dev->name) + 1; + len = strlen(name) + 1; if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); - if (copy_to_user(argp, dev->name, len)) + if (copy_to_user(argp, name, len)) return -EFAULT; return len; } @@ -742,13 +743,13 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev, mutex_init(&joydev->mutex); init_waitqueue_head(&joydev->wait); - snprintf(joydev->name, sizeof(joydev->name), "js%d", minor); + dev_set_name(&joydev->dev, "js%d", minor); joydev->exist = 1; joydev->minor = minor; joydev->exist = 1; joydev->handle.dev = input_get_device(dev); - joydev->handle.name = joydev->name; + joydev->handle.name = dev_name(&joydev->dev); joydev->handle.handler = handler; joydev->handle.private = joydev; @@ -797,7 +798,6 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev, } } - dev_set_name(&joydev->dev, joydev->name); joydev->dev.devt = MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor); joydev->dev.class = &input_class; joydev->dev.parent = &dev->dev; diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index ea2638b4198..9d8f796c674 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -250,6 +250,17 @@ config KEYBOARD_HP7XX To compile this driver as a module, choose M here: the module will be called jornada720_kbd. +config KEYBOARD_LM8323 + tristate "LM8323 keypad chip" + depends on I2C + depends on LEDS_CLASS + help + If you say yes here you get support for the National Semiconductor + LM8323 keypad controller. + + To compile this driver as a module, choose M here: the + module will be called lm8323. + config KEYBOARD_OMAP tristate "TI OMAP keypad support" depends on (ARCH_OMAP1 || ARCH_OMAP2) @@ -332,4 +343,14 @@ config KEYBOARD_SH_KEYSC To compile this driver as a module, choose M here: the module will be called sh_keysc. + +config KEYBOARD_EP93XX + tristate "EP93xx Matrix Keypad support" + depends on ARCH_EP93XX + help + Say Y here to enable the matrix keypad on the Cirrus EP93XX. + + To compile this driver as a module, choose M here: the + module will be called ep93xx_keypad. + endif diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile index 36351e1190f..156b647a259 100644 --- a/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile @@ -18,6 +18,7 @@ obj-$(CONFIG_KEYBOARD_SPITZ) += spitzkbd.o obj-$(CONFIG_KEYBOARD_TOSA) += tosakbd.o obj-$(CONFIG_KEYBOARD_HIL) += hil_kbd.o obj-$(CONFIG_KEYBOARD_HIL_OLD) += hilkbd.o +obj-$(CONFIG_KEYBOARD_LM8323) += lm8323.o obj-$(CONFIG_KEYBOARD_OMAP) += omap-keypad.o obj-$(CONFIG_KEYBOARD_PXA27x) += pxa27x_keypad.o obj-$(CONFIG_KEYBOARD_PXA930_ROTARY) += pxa930_rotary.o @@ -28,3 +29,4 @@ obj-$(CONFIG_KEYBOARD_HP7XX) += jornada720_kbd.o obj-$(CONFIG_KEYBOARD_MAPLE) += maple_keyb.o obj-$(CONFIG_KEYBOARD_BFIN) += bf54x-keys.o obj-$(CONFIG_KEYBOARD_SH_KEYSC) += sh_keysc.o +obj-$(CONFIG_KEYBOARD_EP93XX) += ep93xx_keypad.o diff --git a/drivers/input/keyboard/ep93xx_keypad.c b/drivers/input/keyboard/ep93xx_keypad.c new file mode 100644 index 00000000000..181d30e3018 --- /dev/null +++ b/drivers/input/keyboard/ep93xx_keypad.c @@ -0,0 +1,470 @@ +/* + * Driver for the Cirrus EP93xx matrix keypad controller. + * + * Copyright (c) 2008 H Hartley Sweeten <hsweeten@visionengravers.com> + * + * Based on the pxa27x matrix keypad controller by Rodolfo Giometti. + * + * 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. + * + * NOTE: + * + * The 3-key reset is triggered by pressing the 3 keys in + * Row 0, Columns 2, 4, and 7 at the same time. This action can + * be disabled by setting the EP93XX_KEYPAD_DISABLE_3_KEY flag. + * + * Normal operation for the matrix does not autorepeat the key press. + * This action can be enabled by setting the EP93XX_KEYPAD_AUTOREPEAT + * flag. + */ + +#include <linux/platform_device.h> +#include <linux/interrupt.h> +#include <linux/input.h> +#include <linux/clk.h> + +#include <mach/hardware.h> +#include <mach/gpio.h> +#include <mach/ep93xx_keypad.h> + +/* + * Keypad Interface Register offsets + */ +#define KEY_INIT 0x00 /* Key Scan Initialization register */ +#define KEY_DIAG 0x04 /* Key Scan Diagnostic register */ +#define KEY_REG 0x08 /* Key Value Capture register */ + +/* Key Scan Initialization Register bit defines */ +#define KEY_INIT_DBNC_MASK (0x00ff0000) +#define KEY_INIT_DBNC_SHIFT (16) +#define KEY_INIT_DIS3KY (1<<15) +#define KEY_INIT_DIAG (1<<14) +#define KEY_INIT_BACK (1<<13) +#define KEY_INIT_T2 (1<<12) +#define KEY_INIT_PRSCL_MASK (0x000003ff) +#define KEY_INIT_PRSCL_SHIFT (0) + +/* Key Scan Diagnostic Register bit defines */ +#define KEY_DIAG_MASK (0x0000003f) +#define KEY_DIAG_SHIFT (0) + +/* Key Value Capture Register bit defines */ +#define KEY_REG_K (1<<15) +#define KEY_REG_INT (1<<14) +#define KEY_REG_2KEYS (1<<13) +#define KEY_REG_1KEY (1<<12) +#define KEY_REG_KEY2_MASK (0x00000fc0) +#define KEY_REG_KEY2_SHIFT (6) +#define KEY_REG_KEY1_MASK (0x0000003f) +#define KEY_REG_KEY1_SHIFT (0) + +#define keypad_readl(off) __raw_readl(keypad->mmio_base + (off)) +#define keypad_writel(v, off) __raw_writel((v), keypad->mmio_base + (off)) + +#define MAX_MATRIX_KEY_NUM (MAX_MATRIX_KEY_ROWS * MAX_MATRIX_KEY_COLS) + +struct ep93xx_keypad { + struct ep93xx_keypad_platform_data *pdata; + + struct clk *clk; + struct input_dev *input_dev; + void __iomem *mmio_base; + + int irq; + int enabled; + + int key1; + int key2; + + unsigned int matrix_keycodes[MAX_MATRIX_KEY_NUM]; +}; + +static void ep93xx_keypad_build_keycode(struct ep93xx_keypad *keypad) +{ + struct ep93xx_keypad_platform_data *pdata = keypad->pdata; + struct input_dev *input_dev = keypad->input_dev; + int i; + + for (i = 0; i < pdata->matrix_key_map_size; i++) { + unsigned int key = pdata->matrix_key_map[i]; + int row = (key >> 28) & 0xf; + int col = (key >> 24) & 0xf; + int code = key & 0xffffff; + + keypad->matrix_keycodes[(row << 3) + col] = code; + __set_bit(code, input_dev->keybit); + } +} + +static irqreturn_t ep93xx_keypad_irq_handler(int irq, void *dev_id) +{ + struct ep93xx_keypad *keypad = dev_id; + struct input_dev *input_dev = keypad->input_dev; + unsigned int status = keypad_readl(KEY_REG); + int keycode, key1, key2; + + keycode = (status & KEY_REG_KEY1_MASK) >> KEY_REG_KEY1_SHIFT; + key1 = keypad->matrix_keycodes[keycode]; + + keycode = (status & KEY_REG_KEY2_MASK) >> KEY_REG_KEY2_SHIFT; + key2 = keypad->matrix_keycodes[keycode]; + + if (status & KEY_REG_2KEYS) { + if (keypad->key1 && key1 != keypad->key1 && key2 != keypad->key1) + input_report_key(input_dev, keypad->key1, 0); + + if (keypad->key2 && key1 != keypad->key2 && key2 != keypad->key2) + input_report_key(input_dev, keypad->key2, 0); + + input_report_key(input_dev, key1, 1); + input_report_key(input_dev, key2, 1); + + keypad->key1 = key1; + keypad->key2 = key2; + + } else if (status & KEY_REG_1KEY) { + if (keypad->key1 && key1 != keypad->key1) + input_report_key(input_dev, keypad->key1, 0); + + if (keypad->key2 && key1 != keypad->key2) + input_report_key(input_dev, keypad->key2, 0); + + input_report_key(input_dev, key1, 1); + + keypad->key1 = key1; + keypad->key2 = 0; + + } else { + input_report_key(input_dev, keypad->key1, 0); + input_report_key(input_dev, keypad->key2, 0); + + keypad->key1 = keypad->key2 = 0; + } + input_sync(input_dev); + + return IRQ_HANDLED; +} + +static void ep93xx_keypad_config(struct ep93xx_keypad *keypad) +{ + struct ep93xx_keypad_platform_data *pdata = keypad->pdata; + unsigned int val = 0; + + clk_set_rate(keypad->clk, pdata->flags & EP93XX_KEYPAD_KDIV); + + if (pdata->flags & EP93XX_KEYPAD_DISABLE_3_KEY) + val |= KEY_INIT_DIS3KY; + if (pdata->flags & EP93XX_KEYPAD_DIAG_MODE) + val |= KEY_INIT_DIAG; + if (pdata->flags & EP93XX_KEYPAD_BACK_DRIVE) + val |= KEY_INIT_BACK; + if (pdata->flags & EP93XX_KEYPAD_TEST_MODE) + val |= KEY_INIT_T2; + + val |= ((pdata->debounce << KEY_INIT_DBNC_SHIFT) & KEY_INIT_DBNC_MASK); + + val |= ((pdata->prescale << KEY_INIT_PRSCL_SHIFT) & KEY_INIT_PRSCL_MASK); + + keypad_writel(val, KEY_INIT); +} + +static int ep93xx_keypad_open(struct input_dev *pdev) +{ + struct ep93xx_keypad *keypad = input_get_drvdata(pdev); + + if (!keypad->enabled) { + ep93xx_keypad_config(keypad); + clk_enable(keypad->clk); + keypad->enabled = 1; + } + + return 0; +} + +static void ep93xx_keypad_close(struct input_dev *pdev) +{ + struct ep93xx_keypad *keypad = input_get_drvdata(pdev); + + if (keypad->enabled) { + clk_disable(keypad->clk); + keypad->enabled = 0; + } +} + + +#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) +{ + struct ep93xx_keypad *keypad = platform_get_drvdata(pdev); + struct input_dev *input_dev = keypad->input_dev; + + mutex_lock(&input_dev->mutex); + + if (keypad->enabled) { + clk_disable(keypad->clk); + keypad->enabled = 0; + } + + mutex_unlock(&input_dev->mutex); + + if (device_may_wakeup(&pdev->dev)) + enable_irq_wake(keypad->irq); + + return 0; +} + +static int ep93xx_keypad_resume(struct platform_device *pdev) +{ + struct ep93xx_keypad *keypad = platform_get_drvdata(pdev); + struct input_dev *input_dev = keypad->input_dev; + + if (device_may_wakeup(&pdev->dev)) + disable_irq_wake(keypad->irq); + + mutex_lock(&input_dev->mutex); + + if (input_dev->users) { + if (!keypad->enabled) { + ep93xx_keypad_config(keypad); + clk_enable(keypad->clk); + keypad->enabled = 1; + } + } + + mutex_unlock(&input_dev->mutex); + + return 0; +} +#else /* !CONFIG_PM */ +#define ep93xx_keypad_suspend NULL +#define ep93xx_keypad_resume NULL +#endif /* !CONFIG_PM */ + +static int __devinit ep93xx_keypad_probe(struct platform_device *pdev) +{ + struct ep93xx_keypad *keypad; + struct ep93xx_keypad_platform_data *pdata = pdev->dev.platform_data; + struct input_dev *input_dev; + struct resource *res; + int irq, err, i, gpio; + + if (!pdata || + !pdata->matrix_key_rows || + pdata->matrix_key_rows > MAX_MATRIX_KEY_ROWS || + !pdata->matrix_key_cols || + pdata->matrix_key_cols > MAX_MATRIX_KEY_COLS) { + dev_err(&pdev->dev, "invalid or missing platform data\n"); + return -EINVAL; + } + + keypad = kzalloc(sizeof(struct ep93xx_keypad), GFP_KERNEL); + if (!keypad) { + dev_err(&pdev->dev, "failed to allocate driver data\n"); + return -ENOMEM; + } + + keypad->pdata = pdata; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "failed to get keypad irq\n"); + err = -ENXIO; + goto failed_free; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "failed to get I/O memory\n"); + err = -ENXIO; + goto failed_free; + } + + 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 failed_free; + } + + 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"); + err = -ENXIO; + goto failed_free_mem; + } + + /* Request the needed GPIO's */ + gpio = EP93XX_GPIO_LINE_ROW0; + for (i = 0; i < keypad->pdata->matrix_key_rows; i++, gpio++) { + err = gpio_request(gpio, pdev->name); + if (err) { + dev_err(&pdev->dev, "failed to request gpio-%d\n", + gpio); + goto failed_free_rows; + } + } + + gpio = EP93XX_GPIO_LINE_COL0; + for (i = 0; i < keypad->pdata->matrix_key_cols; i++, gpio++) { + err = gpio_request(gpio, pdev->name); + if (err) { + dev_err(&pdev->dev, "failed to request gpio-%d\n", + gpio); + goto failed_free_cols; + } + } + + keypad->clk = clk_get(&pdev->dev, "key_clk"); + if (IS_ERR(keypad->clk)) { + dev_err(&pdev->dev, "failed to get keypad clock\n"); + err = PTR_ERR(keypad->clk); + goto failed_free_io; + } + + /* Create and register the input driver */ + input_dev = input_allocate_device(); + if (!input_dev) { + dev_err(&pdev->dev, "failed to allocate input device\n"); + err = -ENOMEM; + goto failed_put_clk; + } + + keypad->input_dev = input_dev; + + input_dev->name = pdev->name; + input_dev->id.bustype = BUS_HOST; + input_dev->open = ep93xx_keypad_open; + input_dev->close = ep93xx_keypad_close; + input_dev->dev.parent = &pdev->dev; + input_dev->keycode = keypad->matrix_keycodes; + input_dev->keycodesize = sizeof(keypad->matrix_keycodes[0]); + input_dev->keycodemax = ARRAY_SIZE(keypad->matrix_keycodes); + + input_set_drvdata(input_dev, keypad); + + input_dev->evbit[0] = BIT_MASK(EV_KEY); + if (keypad->pdata->flags & EP93XX_KEYPAD_AUTOREPEAT) + input_dev->evbit[0] |= BIT_MASK(EV_REP); + + ep93xx_keypad_build_keycode(keypad); + platform_set_drvdata(pdev, keypad); + + err = request_irq(irq, ep93xx_keypad_irq_handler, IRQF_DISABLED, + pdev->name, keypad); + if (err) { + dev_err(&pdev->dev, "failed to request IRQ\n"); + goto failed_free_dev; + } + + keypad->irq = irq; + + /* Register the input device */ + err = input_register_device(input_dev); + if (err) { + dev_err(&pdev->dev, "failed to register input device\n"); + goto failed_free_irq; + } + + device_init_wakeup(&pdev->dev, 1); + + return 0; + +failed_free_irq: + free_irq(irq, pdev); + platform_set_drvdata(pdev, NULL); +failed_free_dev: + input_free_device(input_dev); +failed_put_clk: + clk_put(keypad->clk |