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
  ...
diff --git a/Documentation/input/input.txt b/Documentation/input/input.txt
index 686ee99..b93c084 100644
--- a/Documentation/input/input.txt
+++ b/Documentation/input/input.txt
@@ -278,7 +278,7 @@
 };
 
   'time' is the timestamp, it returns the time at which the event happened.
-Type is for example EV_REL for relative moment, REL_KEY for a keypress or
+Type is for example EV_REL for relative moment, EV_KEY for a keypress or
 release. More types are defined in include/linux/input.h.
 
   'code' is event code, for example REL_X or KEY_BACKSPACE, again a complete
diff --git a/Documentation/input/rotary-encoder.txt b/Documentation/input/rotary-encoder.txt
index 435102a..3a6aec4 100644
--- a/Documentation/input/rotary-encoder.txt
+++ b/Documentation/input/rotary-encoder.txt
@@ -67,7 +67,12 @@
 struct rotary_encoder_platform_data is declared in
 include/linux/rotary-encoder.h and needs to be filled with the number of
 steps the encoder has and can carry information about externally inverted
-signals (because of used invertig buffer or other reasons).
+signals (because of an inverting buffer or other reasons). The encoder
+can be set up to deliver input information as either an absolute or relative
+axes. For relative axes the input event returns +/-1 for each step. For
+absolute axes the position of the encoder can either roll over between zero
+and the number of steps or will clamp at the maximum and zero depending on
+the configuration.
 
 Because GPIO to IRQ mapping is platform specific, this information must
 be given in seperately to the driver. See the example below.
@@ -85,6 +90,8 @@
 static struct rotary_encoder_platform_data my_rotary_encoder_info = {
 	.steps		= 24,
 	.axis		= ABS_X,
+	.relative_axis	= false,
+	.rollover	= false,
 	.gpio_a		= GPIO_ROTARY_A,
 	.gpio_b		= GPIO_ROTARY_B,
 	.inverted_a	= 0,
diff --git a/arch/arm/mach-ep93xx/include/mach/ep93xx_keypad.h b/arch/arm/mach-ep93xx/include/mach/ep93xx_keypad.h
new file mode 100644
index 0000000..83f31cd
--- /dev/null
+++ b/arch/arm/mach-ep93xx/include/mach/ep93xx_keypad.h
@@ -0,0 +1,42 @@
+/*
+ * arch/arm/mach-ep93xx/include/mach/ep93xx_keypad.h
+ */
+
+#ifndef __ASM_ARCH_EP93XX_KEYPAD_H
+#define __ASM_ARCH_EP93XX_KEYPAD_H
+
+#define MAX_MATRIX_KEY_ROWS		(8)
+#define MAX_MATRIX_KEY_COLS		(8)
+
+/* flags for the ep93xx_keypad driver */
+#define EP93XX_KEYPAD_DISABLE_3_KEY	(1<<0)	/* disable 3-key reset */
+#define EP93XX_KEYPAD_DIAG_MODE		(1<<1)	/* diagnostic mode */
+#define EP93XX_KEYPAD_BACK_DRIVE	(1<<2)	/* back driving mode */
+#define EP93XX_KEYPAD_TEST_MODE		(1<<3)	/* scan only column 0 */
+#define EP93XX_KEYPAD_KDIV		(1<<4)	/* 1/4 clock or 1/16 clock */
+#define EP93XX_KEYPAD_AUTOREPEAT	(1<<5)	/* enable key autorepeat */
+
+/**
+ * struct ep93xx_keypad_platform_data - platform specific device structure
+ * @matrix_key_rows:		number of rows in the keypad matrix
+ * @matrix_key_cols:		number of columns in the keypad matrix
+ * @matrix_key_map:		array of keycodes defining the keypad matrix
+ * @matrix_key_map_size:	ARRAY_SIZE(matrix_key_map)
+ * @debounce:			debounce start count; terminal count is 0xff
+ * @prescale:			row/column counter pre-scaler load value
+ * @flags:			see above
+ */
+struct ep93xx_keypad_platform_data {
+	unsigned int	matrix_key_rows;
+	unsigned int	matrix_key_cols;
+	unsigned int	*matrix_key_map;
+	int		matrix_key_map_size;
+	unsigned int	debounce;
+	unsigned int	prescale;
+	unsigned int	flags;
+};
+
+/* macro for creating the matrix_key_map table */
+#define KEY(row, col, val)	(((row) << 28) | ((col) << 24) | (val))
+
+#endif	/* __ASM_ARCH_EP93XX_KEYPAD_H */
diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c
index de26a97..737be95 100644
--- a/drivers/char/keyboard.c
+++ b/drivers/char/keyboard.c
@@ -1123,8 +1123,6 @@
 
 #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 7a7a026..114efd8 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -25,7 +25,6 @@
 	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 @@
 						    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 @@
 				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 @@
 
 				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 @@
 				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 @@
 	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 1dec00e..8a1810f 100644
--- a/drivers/input/gameport/fm801-gp.c
+++ b/drivers/input/gameport/fm801-gp.c
@@ -167,5 +167,6 @@
 
 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 2d175b5..ac11be0 100644
--- a/drivers/input/gameport/gameport.c
+++ b/drivers/input/gameport/gameport.c
@@ -30,16 +30,6 @@
 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 @@
 
 	spin_unlock(&gameport->timer_lock);
 }
+EXPORT_SYMBOL(gameport_start_polling);
 
 void gameport_stop_polling(struct gameport *gameport)
 {
@@ -172,6 +163,7 @@
 
 	spin_unlock(&gameport->timer_lock);
 }
+EXPORT_SYMBOL(gameport_stop_polling);
 
 static void gameport_run_poll_handler(unsigned long d)
 {
@@ -516,6 +508,7 @@
 	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 @@
 	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 @@
 	gameport_destroy_port(gameport);
 	mutex_unlock(&gameport_mutex);
 }
+EXPORT_SYMBOL(gameport_unregister_port);
 
 
 /*
@@ -728,7 +723,7 @@
 	 * 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 @@
 	/*
 	 * 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 @@
 
 	return 0;
 }
+EXPORT_SYMBOL(__gameport_register_driver);
 
 void gameport_unregister_driver(struct gameport_driver *drv)
 {
@@ -757,7 +753,7 @@
 
 	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 @@
 
 	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 @@
 	gameport_set_drv(gameport, drv);
 	return 0;
 }
+EXPORT_SYMBOL(gameport_open);
 
 void gameport_close(struct gameport *gameport)
 {
@@ -822,6 +820,7 @@
 	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 012a5e7..0e12f89 100644
--- a/drivers/input/joydev.c
+++ b/drivers/input/joydev.c
@@ -39,7 +39,6 @@
 	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 @@
 	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 @@
 	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 @@
 		}
 	}
 
-	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 ea2638b..9d8f796 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -250,6 +250,17 @@
 	  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 @@
 
 	  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 36351e1..156b647 100644
--- a/drivers/input/keyboard/Makefile
+++ b/drivers/input/keyboard/Makefile
@@ -18,6 +18,7 @@
 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_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 0000000..181d30e
--- /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);
+failed_free_io:
+	i = keypad->pdata->matrix_key_cols - 1;
+	gpio = EP93XX_GPIO_LINE_COL0 + i;
+failed_free_cols:
+	for ( ; i >= 0; i--, gpio--)
+		gpio_free(gpio);
+	i = keypad->pdata->matrix_key_rows - 1;
+	gpio = EP93XX_GPIO_LINE_ROW0 + i;
+failed_free_rows:
+	for ( ; i >= 0; i--, gpio--)
+		gpio_free(gpio);
+	iounmap(keypad->mmio_base);
+failed_free_mem:
+	release_mem_region(res->start, resource_size(res));
+failed_free:
+	kfree(keypad);
+	return err;
+}
+
+static int __devexit ep93xx_keypad_remove(struct platform_device *pdev)
+{
+	struct ep93xx_keypad *keypad = platform_get_drvdata(pdev);
+	struct resource *res;
+	int i, gpio;
+
+	free_irq(keypad->irq, pdev);
+
+	platform_set_drvdata(pdev, NULL);
+
+	if (keypad->enabled)
+		clk_disable(keypad->clk);
+	clk_put(keypad->clk);
+
+	input_unregister_device(keypad->input_dev);
+
+	i = keypad->pdata->matrix_key_cols - 1;
+	gpio = EP93XX_GPIO_LINE_COL0 + i;
+	for ( ; i >= 0; i--, gpio--)
+		gpio_free(gpio);
+
+	i = keypad->pdata->matrix_key_rows - 1;
+	gpio = EP93XX_GPIO_LINE_ROW0 + i;
+	for ( ; i >= 0; i--, gpio--)
+		gpio_free(gpio);
+
+	iounmap(keypad->mmio_base);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	release_mem_region(res->start, resource_size(res));
+
+	kfree(keypad);
+
+	return 0;
+}
+
+static struct platform_driver ep93xx_keypad_driver = {
+	.driver		= {
+		.name	= "ep93xx-keypad",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= ep93xx_keypad_probe,
+	.remove		= __devexit_p(ep93xx_keypad_remove),
+	.suspend	= ep93xx_keypad_suspend,
+	.resume		= ep93xx_keypad_resume,
+};
+
+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_LICENSE("GPL");
+MODULE_AUTHOR("H Hartley Sweeten <hsweeten@visionengravers.com>");
+MODULE_DESCRIPTION("EP93xx Matrix Keypad Controller");
+MODULE_ALIAS("platform:ep93xx-keypad");
diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c
index ad67d76..2157cd7 100644
--- a/drivers/input/keyboard/gpio_keys.c
+++ b/drivers/input/keyboard/gpio_keys.c
@@ -22,13 +22,14 @@
 #include <linux/platform_device.h>
 #include <linux/input.h>
 #include <linux/gpio_keys.h>
+#include <linux/workqueue.h>
 
 #include <asm/gpio.h>
 
 struct gpio_button_data {
 	struct gpio_keys_button *button;
 	struct input_dev *input;
-	struct timer_list timer;
+	struct delayed_work work;
 };
 
 struct gpio_keys_drvdata {
@@ -36,8 +37,10 @@
 	struct gpio_button_data data[0];
 };
 
-static void gpio_keys_report_event(struct gpio_button_data *bdata)
+static void gpio_keys_report_event(struct work_struct *work)
 {
+	struct gpio_button_data *bdata =
+		container_of(work, struct gpio_button_data, work.work);
 	struct gpio_keys_button *button = bdata->button;
 	struct input_dev *input = bdata->input;
 	unsigned int type = button->type ?: EV_KEY;
@@ -47,25 +50,17 @@
 	input_sync(input);
 }
 
-static void gpio_check_button(unsigned long _data)
-{
-	struct gpio_button_data *data = (struct gpio_button_data *)_data;
-
-	gpio_keys_report_event(data);
-}
-
 static irqreturn_t gpio_keys_isr(int irq, void *dev_id)
 {
 	struct gpio_button_data *bdata = dev_id;
 	struct gpio_keys_button *button = bdata->button;
+	unsigned long delay;
 
 	BUG_ON(irq != gpio_to_irq(button->gpio));
 
-	if (button->debounce_interval)
-		mod_timer(&bdata->timer,
-			jiffies + msecs_to_jiffies(button->debounce_interval));
-	else
-		gpio_keys_report_event(bdata);
+	delay = button->debounce_interval ?
+			msecs_to_jiffies(button->debounce_interval) : 0;
+	schedule_delayed_work(&bdata->work, delay);
 
 	return IRQ_HANDLED;
 }
@@ -112,8 +107,7 @@
 
 		bdata->input = input;
 		bdata->button = button;
-		setup_timer(&bdata->timer,
-			    gpio_check_button, (unsigned long)bdata);
+		INIT_DELAYED_WORK(&bdata->work, gpio_keys_report_event);
 
 		error = gpio_request(button->gpio, button->desc ?: "gpio_keys");
 		if (error < 0) {
@@ -142,8 +136,7 @@
 		}
 
 		error = request_irq(irq, gpio_keys_isr,
-				    IRQF_SAMPLE_RANDOM | IRQF_TRIGGER_RISING |
-					IRQF_TRIGGER_FALLING,
+				    IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
 				    button->desc ? button->desc : "gpio_keys",
 				    bdata);
 		if (error) {
@@ -173,8 +166,7 @@
  fail2:
 	while (--i >= 0) {
 		free_irq(gpio_to_irq(pdata->buttons[i].gpio), &ddata->data[i]);
-		if (pdata->buttons[i].debounce_interval)
-			del_timer_sync(&ddata->data[i].timer);
+		cancel_delayed_work_sync(&ddata->data[i].work);
 		gpio_free(pdata->buttons[i].gpio);
 	}
 
@@ -198,8 +190,7 @@
 	for (i = 0; i < pdata->nbuttons; i++) {
 		int irq = gpio_to_irq(pdata->buttons[i].gpio);
 		free_irq(irq, &ddata->data[i]);
-		if (pdata->buttons[i].debounce_interval)
-			del_timer_sync(&ddata->data[i].timer);
+		cancel_delayed_work_sync(&ddata->data[i].work);
 		gpio_free(pdata->buttons[i].gpio);
 	}
 
diff --git a/drivers/input/keyboard/lm8323.c b/drivers/input/keyboard/lm8323.c
new file mode 100644
index 0000000..574eda2
--- /dev/null
+++ b/drivers/input/keyboard/lm8323.c
@@ -0,0 +1,878 @@
+/*
+ * drivers/i2c/chips/lm8323.c
+ *
+ * Copyright (C) 2007-2009 Nokia Corporation
+ *
+ * Written by Daniel Stone <daniel.stone@nokia.com>
+ *            Timo O. Karjalainen <timo.o.karjalainen@nokia.com>
+ *
+ * Updated by Felipe Balbi <felipe.balbi@nokia.com>
+ *
+ * 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 of the License only).
+ *
+ * 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 02111-1307 USA
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/leds.h>
+#include <linux/i2c/lm8323.h>
+
+/* Commands to send to the chip. */
+#define LM8323_CMD_READ_ID		0x80 /* Read chip ID. */
+#define LM8323_CMD_WRITE_CFG		0x81 /* Set configuration item. */
+#define LM8323_CMD_READ_INT		0x82 /* Get interrupt status. */
+#define LM8323_CMD_RESET		0x83 /* Reset, same as external one */
+#define LM8323_CMD_WRITE_PORT_SEL	0x85 /* Set GPIO in/out. */
+#define LM8323_CMD_WRITE_PORT_STATE	0x86 /* Set GPIO pullup. */
+#define LM8323_CMD_READ_PORT_SEL	0x87 /* Get GPIO in/out. */
+#define LM8323_CMD_READ_PORT_STATE	0x88 /* Get GPIO pullup. */
+#define LM8323_CMD_READ_FIFO		0x89 /* Read byte from FIFO. */
+#define LM8323_CMD_RPT_READ_FIFO	0x8a /* Read FIFO (no increment). */
+#define LM8323_CMD_SET_ACTIVE		0x8b /* Set active time. */
+#define LM8323_CMD_READ_ERR		0x8c /* Get error status. */
+#define LM8323_CMD_READ_ROTATOR		0x8e /* Read rotator status. */
+#define LM8323_CMD_SET_DEBOUNCE		0x8f /* Set debouncing time. */
+#define LM8323_CMD_SET_KEY_SIZE		0x90 /* Set keypad size. */
+#define LM8323_CMD_READ_KEY_SIZE	0x91 /* Get keypad size. */
+#define LM8323_CMD_READ_CFG		0x92 /* Get configuration item. */
+#define LM8323_CMD_WRITE_CLOCK		0x93 /* Set clock config. */
+#define LM8323_CMD_READ_CLOCK		0x94 /* Get clock config. */
+#define LM8323_CMD_PWM_WRITE		0x95 /* Write PWM script. */
+#define LM8323_CMD_START_PWM		0x96 /* Start PWM engine. */
+#define LM8323_CMD_STOP_PWM		0x97 /* Stop PWM engine. */
+
+/* Interrupt status. */
+#define INT_KEYPAD			0x01 /* Key event. */
+#define INT_ROTATOR			0x02 /* Rotator event. */
+#define INT_ERROR			0x08 /* Error: use CMD_READ_ERR. */
+#define INT_NOINIT			0x10 /* Lost configuration. */
+#define INT_PWM1			0x20 /* PWM1 stopped. */
+#define INT_PWM2			0x40 /* PWM2 stopped. */
+#define INT_PWM3			0x80 /* PWM3 stopped. */
+
+/* Errors (signalled by INT_ERROR, read with CMD_READ_ERR). */
+#define ERR_BADPAR			0x01 /* Bad parameter. */
+#define ERR_CMDUNK			0x02 /* Unknown command. */
+#define ERR_KEYOVR			0x04 /* Too many keys pressed. */
+#define ERR_FIFOOVER			0x40 /* FIFO overflow. */
+
+/* Configuration keys (CMD_{WRITE,READ}_CFG). */
+#define CFG_MUX1SEL			0x01 /* Select MUX1_OUT input. */
+#define CFG_MUX1EN			0x02 /* Enable MUX1_OUT. */
+#define CFG_MUX2SEL			0x04 /* Select MUX2_OUT input. */
+#define CFG_MUX2EN			0x08 /* Enable MUX2_OUT. */
+#define CFG_PSIZE			0x20 /* Package size (must be 0). */
+#define CFG_ROTEN			0x40 /* Enable rotator. */
+
+/* Clock settings (CMD_{WRITE,READ}_CLOCK). */
+#define CLK_RCPWM_INTERNAL		0x00
+#define CLK_RCPWM_EXTERNAL		0x03
+#define CLK_SLOWCLKEN			0x08 /* Enable 32.768kHz clock. */
+#define CLK_SLOWCLKOUT			0x40 /* Enable slow pulse output. */
+
+/* The possible addresses corresponding to CONFIG1 and CONFIG2 pin wirings. */
+#define LM8323_I2C_ADDR00		(0x84 >> 1)	/* 1000 010x */
+#define LM8323_I2C_ADDR01		(0x86 >> 1)	/* 1000 011x */
+#define LM8323_I2C_ADDR10		(0x88 >> 1)	/* 1000 100x */
+#define LM8323_I2C_ADDR11		(0x8A >> 1)	/* 1000 101x */
+
+/* Key event fifo length */
+#define LM8323_FIFO_LEN			15
+
+/* Commands for PWM engine; feed in with PWM_WRITE. */
+/* Load ramp counter from duty cycle field (range 0 - 0xff). */
+#define PWM_SET(v)			(0x4000 | ((v) & 0xff))
+/* Go to start of script. */
+#define PWM_GOTOSTART			0x0000
+/*
+ * Stop engine (generates interrupt).  If reset is 1, clear the program
+ * counter, else leave it.
+ */
+#define PWM_END(reset)			(0xc000 | (!!(reset) << 11))
+/*
+ * Ramp.  If s is 1, divide clock by 512, else divide clock by 16.
+ * Take t clock scales (up to 63) per step, for n steps (up to 126).
+ * If u is set, ramp up, else ramp down.
+ */
+#define PWM_RAMP(s, t, n, u)		((!!(s) << 14) | ((t) & 0x3f) << 8 | \
+					 ((n) & 0x7f) | ((u) ? 0 : 0x80))
+/*
+ * Loop (i.e. jump back to pos) for a given number of iterations (up to 63).
+ * If cnt is zero, execute until PWM_END is encountered.
+ */
+#define PWM_LOOP(cnt, pos)		(0xa000 | (((cnt) & 0x3f) << 7) | \
+					 ((pos) & 0x3f))
+/*
+ * Wait for trigger.  Argument is a mask of channels, shifted by the channel
+ * number, e.g. 0xa for channels 3 and 1.  Note that channels are numbered
+ * from 1, not 0.
+ */
+#define PWM_WAIT_TRIG(chans)		(0xe000 | (((chans) & 0x7) << 6))
+/* Send trigger.  Argument is same as PWM_WAIT_TRIG. */
+#define PWM_SEND_TRIG(chans)		(0xe000 | ((chans) & 0x7))
+
+struct lm8323_pwm {
+	int			id;
+	int			fade_time;
+	int			brightness;
+	int			desired_brightness;
+	bool			enabled;
+	bool			running;
+	/* pwm lock */
+	struct mutex		lock;
+	struct work_struct	work;
+	struct led_classdev	cdev;
+	struct lm8323_chip	*chip;
+};
+
+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;
+	unsigned		keys_down;
+	char			phys[32];
+	unsigned short		keymap[LM8323_KEYMAP_SIZE];
+	int			size_x;
+	int			size_y;
+	int			debounce_time;
+	int			active_time;
+	struct lm8323_pwm	pwm[LM8323_NUM_PWMS];
+};
+
+#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)
+
+#define LM8323_MAX_DATA 8
+
+/*
+ * To write, we just access the chip's address in write mode, and dump the
+ * command and data out on the bus.  The command byte and data are taken as
+ * sequential u8s out of varargs, to a maximum of LM8323_MAX_DATA.
+ */
+static int lm8323_write(struct lm8323_chip *lm, int len, ...)
+{
+	int ret, i;
+	va_list ap;
+	u8 data[LM8323_MAX_DATA];
+
+	va_start(ap, len);
+
+	if (unlikely(len > LM8323_MAX_DATA)) {
+		dev_err(&lm->client->dev, "tried to send %d bytes\n", len);
+		va_end(ap);
+		return 0;
+	}
+
+	for (i = 0; i < len; i++)
+		data[i] = va_arg(ap, int);
+
+	va_end(ap);
+
+	/*
+	 * If the host is asleep while we send the data, we can get a NACK
+	 * back while it wakes up, so try again, once.
+	 */
+	ret = i2c_master_send(lm->client, data, len);
+	if (unlikely(ret == -EREMOTEIO))
+		ret = i2c_master_send(lm->client, data, len);
+	if (unlikely(ret != len))
+		dev_err(&lm->client->dev, "sent %d bytes of %d total\n",
+			len, ret);
+
+	return ret;
+}
+
+/*
+ * To read, we first send the command byte to the chip and end the transaction,
+ * then access the chip in read mode, at which point it will send the data.
+ */
+static int lm8323_read(struct lm8323_chip *lm, u8 cmd, u8 *buf, int len)
+{
+	int ret;
+
+	/*
+	 * If the host is asleep while we send the byte, we can get a NACK
+	 * back while it wakes up, so try again, once.
+	 */
+	ret = i2c_master_send(lm->client, &cmd, 1);
+	if (unlikely(ret == -EREMOTEIO))
+		ret = i2c_master_send(lm->client, &cmd, 1);
+	if (unlikely(ret != 1)) {
+		dev_err(&lm->client->dev, "sending read cmd 0x%02x failed\n",
+			cmd);
+		return 0;
+	}
+
+	ret = i2c_master_recv(lm->client, buf, len);
+	if (unlikely(ret != len))
+		dev_err(&lm->client->dev, "wanted %d bytes, got %d\n",
+			len, ret);
+
+	return ret;
+}
+
+/*
+ * Set the chip active time (idle time before it enters halt).
+ */
+static void lm8323_set_active_time(struct lm8323_chip *lm, int time)
+{
+	lm8323_write(lm, 2, LM8323_CMD_SET_ACTIVE, time >> 2);
+}
+
+/*
+ * The signals are AT-style: the low 7 bits are the keycode, and the top
+ * bit indicates the state (1 for down, 0 for up).
+ */
+static inline u8 lm8323_whichkey(u8 event)
+{
+	return event & 0x7f;
+}
+
+static inline int lm8323_ispress(u8 event)
+{
+	return (event & 0x80) ? 1 : 0;
+}
+
+static void process_keys(struct lm8323_chip *lm)
+{
+	u8 event;
+	u8 key_fifo[LM8323_FIFO_LEN + 1];
+	int old_keys_down = lm->keys_down;
+	int ret;
+	int i = 0;
+
+	/*
+	 * Read all key events from the FIFO at once. Next READ_FIFO clears the
+	 * FIFO even if we didn't read all events previously.
+	 */
+	ret = lm8323_read(lm, LM8323_CMD_READ_FIFO, key_fifo, LM8323_FIFO_LEN);
+
+	if (ret < 0) {
+		dev_err(&lm->client->dev, "Failed reading fifo \n");
+		return;
+	}
+	key_fifo[ret] = 0;
+
+	while ((event = key_fifo[i++])) {
+		u8 key = lm8323_whichkey(event);
+		int isdown = lm8323_ispress(event);
+		unsigned short keycode = lm->keymap[key];
+
+		dev_vdbg(&lm->client->dev, "key 0x%02x %s\n",
+			 key, isdown ? "down" : "up");
+
+		if (lm->kp_enabled) {
+			input_event(lm->idev, EV_MSC, MSC_SCAN, key);
+			input_report_key(lm->idev, keycode, isdown);
+			input_sync(lm->idev);
+		}
+
+		if (isdown)
+			lm->keys_down++;
+		else
+			lm->keys_down--;
+	}
+
+	/*
+	 * Errata: We need to ensure that the chip never enters halt mode
+	 * during a keypress, so set active time to 0.  When it's released,
+	 * we can enter halt again, so set the active time back to normal.
+	 */
+	if (!old_keys_down && lm->keys_down)
+		lm8323_set_active_time(lm, 0);
+	if (old_keys_down && !lm->keys_down)
+		lm8323_set_active_time(lm, lm->active_time);
+}
+
+static void lm8323_process_error(struct lm8323_chip *lm)
+{
+	u8 error;
+
+	if (lm8323_read(lm, LM8323_CMD_READ_ERR, &error, 1) == 1) {
+		if (error & ERR_FIFOOVER)
+			dev_vdbg(&lm->client->dev, "fifo overflow!\n");
+		if (error & ERR_KEYOVR)
+			dev_vdbg(&lm->client->dev,
+					"more than two keys pressed\n");
+		if (error & ERR_CMDUNK)
+			dev_vdbg(&lm->client->dev,
+					"unknown command submitted\n");
+		if (error & ERR_BADPAR)
+			dev_vdbg(&lm->client->dev, "bad command parameter\n");
+	}
+}
+
+static void lm8323_reset(struct lm8323_chip *lm)
+{
+	/* The docs say we must pass 0xAA as the data byte. */
+	lm8323_write(lm, 2, LM8323_CMD_RESET, 0xAA);
+}
+
+static int lm8323_configure(struct lm8323_chip *lm)
+{
+	int keysize = (lm->size_x << 4) | lm->size_y;
+	int clock = (CLK_SLOWCLKEN | CLK_RCPWM_EXTERNAL);
+	int debounce = lm->debounce_time >> 2;
+	int active = lm->active_time >> 2;
+
+	/*
+	 * Active time must be greater than the debounce time: if it's
+	 * a close-run thing, give ourselves a 12ms buffer.
+	 */
+	if (debounce >= active)
+		active = debounce + 3;
+
+	lm8323_write(lm, 2, LM8323_CMD_WRITE_CFG, 0);
+	lm8323_write(lm, 2, LM8323_CMD_WRITE_CLOCK, clock);
+	lm8323_write(lm, 2, LM8323_CMD_SET_KEY_SIZE, keysize);
+	lm8323_set_active_time(lm, lm->active_time);
+	lm8323_write(lm, 2, LM8323_CMD_SET_DEBOUNCE, debounce);
+	lm8323_write(lm, 3, LM8323_CMD_WRITE_PORT_STATE, 0xff, 0xff);
+	lm8323_write(lm, 3, LM8323_CMD_WRITE_PORT_SEL, 0, 0);
+
+	/*
+	 * Not much we can do about errors at this point, so just hope
+	 * for the best.
+	 */
+
+	return 0;
+}
+
+static void pwm_done(struct lm8323_pwm *pwm)
+{
+	mutex_lock(&pwm->lock);
+	pwm->running = false;
+	if (pwm->desired_brightness != pwm->brightness)
+		schedule_work(&pwm->work);
+	mutex_unlock(&pwm->lock);
+}
+
+/*
+ * Bottom half: handle the interrupt by posting key events, or dealing with
+ * errors appropriately.
+ */
+static void lm8323_work(struct work_struct *work)
+{
+	struct lm8323_chip *lm = work_to_lm8323(work);
+	u8 ints;
+	int i;
+
+	mutex_lock(&lm->lock);
+
+	while ((lm8323_read(lm, LM8323_CMD_READ_INT, &ints, 1) == 1) && ints) {
+		if (likely(ints & INT_KEYPAD))
+			process_keys(lm);
+		if (ints & INT_ROTATOR) {
+			/* We don't currently support the rotator. */
+			dev_vdbg(&lm->client->dev, "rotator fired\n");
+		}
+		if (ints & INT_ERROR) {
+			dev_vdbg(&lm->client->dev, "error!\n");
+			lm8323_process_error(lm);
+		}
+		if (ints & INT_NOINIT) {
+			dev_err(&lm->client->dev, "chip lost config; "
+						  "reinitialising\n");
+			lm8323_configure(lm);
+		}
+		for (i = 0; i < LM8323_NUM_PWMS; i++) {
+			if (ints & (1 << (INT_PWM1 + i))) {
+				dev_vdbg(&lm->client->dev,
+					 "pwm%d engine completed\n", i);
+				pwm_done(&lm->pwm[i]);
+			}
+		}
+	}
+
+	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;
+}
+
+/*
+ * Read the chip ID.
+ */
+static int lm8323_read_id(struct lm8323_chip *lm, u8 *buf)
+{
+	int bytes;
+
+	bytes = lm8323_read(lm, LM8323_CMD_READ_ID, buf, 2);
+	if (unlikely(bytes != 2))
+		return -EIO;
+
+	return 0;
+}
+
+static void lm8323_write_pwm_one(struct lm8323_pwm *pwm, int pos, u16 cmd)
+{
+	lm8323_write(pwm->chip, 4, LM8323_CMD_PWM_WRITE, (pos << 2) | pwm->id,
+		     (cmd & 0xff00) >> 8, cmd & 0x00ff);
+}
+
+/*
+ * Write a script into a given PWM engine, concluding with PWM_END.
+ * If 'kill' is nonzero, the engine will be shut down at the end
+ * of the script, producing a zero output. Otherwise the engine
+ * will be kept running at the final PWM level indefinitely.
+ */
+static void lm8323_write_pwm(struct lm8323_pwm *pwm, int kill,
+			     int len, const u16 *cmds)
+{
+	int i;
+
+	for (i = 0; i < len; i++)
+		lm8323_write_pwm_one(pwm, i, cmds[i]);
+
+	lm8323_write_pwm_one(pwm, i++, PWM_END(kill));
+	lm8323_write(pwm->chip, 2, LM8323_CMD_START_PWM, pwm->id);
+	pwm->running = true;
+}
+
+static void lm8323_pwm_work(struct work_struct *work)
+{
+	struct lm8323_pwm *pwm = work_to_pwm(work);
+	int div512, perstep, steps, hz, up, kill;
+	u16 pwm_cmds[3];
+	int num_cmds = 0;
+
+	mutex_lock(&pwm->lock);
+
+	/*
+	 * Do nothing if we're already at the requested level,
+	 * or previous setting is not yet complete. In the latter
+	 * case we will be called again when the previous PWM script
+	 * finishes.
+	 */
+	if (pwm->running || pwm->desired_brightness == pwm->brightness)
+		goto out;
+
+	kill = (pwm->desired_brightness == 0);
+	up = (pwm->desired_brightness > pwm->brightness);
+	steps = abs(pwm->desired_brightness - pwm->brightness);
+
+	/*
+	 * Convert time (in ms) into a divisor (512 or 16 on a refclk of
+	 * 32768Hz), and number of ticks per step.
+	 */
+	if ((pwm->fade_time / steps) > (32768 / 512)) {
+		div512 = 1;
+		hz = 32768 / 512;
+	} else {
+		div512 = 0;
+		hz = 32768 / 16;
+	}
+
+	perstep = (hz * pwm->fade_time) / (steps * 1000);
+
+	if (perstep == 0)
+		perstep = 1;
+	else if (perstep > 63)
+		perstep = 63;
+
+	while (steps) {
+		int s;
+
+		s = min(126, steps);
+		pwm_cmds[num_cmds++] = PWM_RAMP(div512, perstep, s, up);
+		steps -= s;
+	}
+
+	lm8323_write_pwm(pwm, kill, num_cmds, pwm_cmds);
+	pwm->brightness = pwm->desired_brightness;
+
+ out:
+	mutex_unlock(&pwm->lock);
+}
+
+static void lm8323_pwm_set_brightness(struct led_classdev *led_cdev,
+				      enum led_brightness brightness)
+{
+	struct lm8323_pwm *pwm = cdev_to_pwm(led_cdev);
+	struct lm8323_chip *lm = pwm->chip;
+
+	mutex_lock(&pwm->lock);
+	pwm->desired_brightness = brightness;
+	mutex_unlock(&pwm->lock);
+
+	if (in_interrupt()) {
+		schedule_work(&pwm->work);
+	} else {
+		/*
+		 * Schedule PWM work as usual unless we are going into suspend
+		 */
+		mutex_lock(&lm->lock);
+		if (likely(!lm->pm_suspend))
+			schedule_work(&pwm->work);
+		else
+			lm8323_pwm_work(&pwm->work);
+		mutex_unlock(&lm->lock);
+	}
+}
+
+static ssize_t lm8323_pwm_show_time(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
+	struct lm8323_pwm *pwm = cdev_to_pwm(led_cdev);
+
+	return sprintf(buf, "%d\n", pwm->fade_time);
+}
+
+static ssize_t lm8323_pwm_store_time(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t len)
+{
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
+	struct lm8323_pwm *pwm = cdev_to_pwm(led_cdev);
+	int ret;
+	unsigned long time;
+
+	ret = strict_strtoul(buf, 10, &time);
+	/* Numbers only, please. */
+	if (ret)
+		return -EINVAL;
+
+	pwm->fade_time = time;
+
+	return strlen(buf);
+}
+static DEVICE_ATTR(time, 0644, lm8323_pwm_show_time, lm8323_pwm_store_time);
+
+static int init_pwm(struct lm8323_chip *lm, int id, struct device *dev,
+		    const char *name)
+{
+	struct lm8323_pwm *pwm;
+
+	BUG_ON(id > 3);
+
+	pwm = &lm->pwm[id - 1];
+
+	pwm->id = id;
+	pwm->fade_time = 0;
+	pwm->brightness = 0;
+	pwm->desired_brightness = 0;
+	pwm->running = false;
+	pwm->enabled = false;
+	INIT_WORK(&pwm->work, lm8323_pwm_work);
+	mutex_init(&pwm->lock);
+	pwm->chip = lm;
+
+	if (name) {
+		pwm->cdev.name = name;
+		pwm->cdev.brightness_set = lm8323_pwm_set_brightness;
+		if (led_classdev_register(dev, &pwm->cdev) < 0) {
+			dev_err(dev, "couldn't register PWM %d\n", id);
+			return -1;
+		}
+		if (device_create_file(pwm->cdev.dev,
+					&dev_attr_time) < 0) {
+			dev_err(dev, "couldn't register time attribute\n");
+			led_classdev_unregister(&pwm->cdev);
+			return -1;
+		}
+		pwm->enabled = true;
+	}
+
+	return 0;
+}
+
+static struct i2c_driver lm8323_i2c_driver;
+
+static ssize_t lm8323_show_disable(struct device *dev,
+				   struct device_attribute *attr, char *buf)
+{
+	struct lm8323_chip *lm = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%u\n", !lm->kp_enabled);
+}
+
+static ssize_t lm8323_set_disable(struct device *dev,
+				  struct device_attribute *attr,
+				  const char *buf, size_t count)
+{
+	struct lm8323_chip *lm = dev_get_drvdata(dev);
+	int ret;
+	unsigned long i;
+
+	ret = strict_strtoul(buf, 10, &i);
+
+	mutex_lock(&lm->lock);
+	lm->kp_enabled = !i;
+	mutex_unlock(&lm->lock);
+
+	return count;
+}
+static DEVICE_ATTR(disable_kp, 0644, lm8323_show_disable, lm8323_set_disable);
+
+static int __devinit lm8323_probe(struct i2c_client *client,
+				  const struct i2c_device_id *id)
+{
+	struct lm8323_platform_data *pdata = client->dev.platform_data;
+	struct input_dev *idev;
+	struct lm8323_chip *lm;
+	int i, err;
+	unsigned long tmo;
+	u8 data[2];
+
+	if (!pdata || !pdata->size_x || !pdata->size_y) {
+		dev_err(&client->dev, "missing platform_data\n");
+		return -EINVAL;
+	}
+
+	if (pdata->size_x > 8) {
+		dev_err(&client->dev, "invalid x size %d specified\n",
+			pdata->size_x);
+		return -EINVAL;
+	}
+
+	if (pdata->size_y > 12) {
+		dev_err(&client->dev, "invalid y size %d specified\n",
+			pdata->size_y);
+		return -EINVAL;
+	}
+
+	lm = kzalloc(sizeof *lm, GFP_KERNEL);
+	idev = input_allocate_device();
+	if (!lm || !idev) {
+		err = -ENOMEM;
+		goto fail1;
+	}
+
+	i2c_set_clientdata(client, lm);
+
+	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;
+	dev_vdbg(&client->dev, "Keypad size: %d x %d\n",
+		 lm->size_x, lm->size_y);
+
+	lm->debounce_time = pdata->debounce_time;
+	lm->active_time = pdata->active_time;
+
+	lm8323_reset(lm);
+
+	/* Nothing's set up to service the IRQ yet, so just spin for max.
+	 * 100ms until we can configure. */
+	tmo = jiffies + msecs_to_jiffies(100);
+	while (lm8323_read(lm, LM8323_CMD_READ_INT, data, 1) == 1) {
+		if (data[0] & INT_NOINIT)
+			break;
+
+		if (time_after(jiffies, tmo)) {
+			dev_err(&client->dev,
+				"timeout waiting for initialisation\n");
+			break;
+		}
+
+		msleep(1);
+	}
+
+	lm8323_configure(lm);
+
+	/* If a true probe check the device */
+	if (lm8323_read_id(lm, data) != 0) {
+		dev_err(&client->dev, "device not found\n");
+		err = -ENODEV;
+		goto fail1;
+	}
+
+	for (i = 0; i < LM8323_NUM_PWMS; i++) {
+		err = init_pwm(lm, i + 1, &client->dev, pdata->pwm_names[i]);
+		if (err < 0)
+			goto fail2;
+	}
+
+	lm->kp_enabled = true;
+	err = device_create_file(&client->dev, &dev_attr_disable_kp);
+	if (err < 0)
+		goto fail2;
+
+	idev->name = pdata->name ? : "LM8323 keypad";
+	snprintf(lm->phys, sizeof(lm->phys),
+		 "%s/input-kp", dev_name(&client->dev));
+	idev->phys = lm->phys;
+
+	idev->evbit[0] = BIT(EV_KEY) | BIT(EV_MSC);
+	__set_bit(MSC_SCAN, idev->mscbit);
+	for (i = 0; i < LM8323_KEYMAP_SIZE; i++) {
+		__set_bit(pdata->keymap[i], idev->keybit);
+		lm->keymap[i] = pdata->keymap[i];
+	}
+	__clear_bit(KEY_RESERVED, idev->keybit);
+
+	if (pdata->repeat)
+		__set_bit(EV_REP, idev->evbit);
+
+	err = input_register_device(idev);
+	if (err) {
+		dev_dbg(&client->dev, "error registering input device\n");
+		goto fail3;
+	}
+
+	err = request_irq(client->irq, lm8323_irq,
+			  IRQF_TRIGGER_FALLING | IRQF_DISABLED,
+			  "lm8323", lm);
+	if (err) {
+		dev_err(&client->dev, "could not get IRQ %d\n", client->irq);
+		goto fail4;
+	}
+
+	device_init_wakeup(&client->dev, 1);
+	enable_irq_wake(client->irq);
+
+	return 0;
+
+fail4:
+	input_unregister_device(idev);
+	idev = NULL;
+fail3:
+	device_remove_file(&client->dev, &dev_attr_disable_kp);
+fail2:
+	while (--i >= 0)
+		if (lm->pwm[i].enabled)
+			led_classdev_unregister(&lm->pwm[i].cdev);
+fail1:
+	input_free_device(idev);
+	kfree(lm);
+	return err;
+}
+
+static int __devexit 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)
+			led_classdev_unregister(&lm->pwm[i].cdev);
+
+	kfree(lm);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+/*
+ * We don't need to explicitly suspend the chip, as it already switches off
+ * when there's no activity.
+ */
+static int lm8323_suspend(struct i2c_client *client, pm_message_t mesg)
+{
+	struct lm8323_chip *lm = i2c_get_clientdata(client);
+	int i;
+
+	set_irq_wake(client->irq, 0);
+	disable_irq(client->irq);
+
+	mutex_lock(&lm->lock);
+	lm->pm_suspend = true;
+	mutex_unlock(&lm->lock);
+
+	for (i = 0; i < 3; i++)
+		if (lm->pwm[i].enabled)
+			led_classdev_suspend(&lm->pwm[i].cdev);
+
+	return 0;
+}
+
+static int lm8323_resume(struct i2c_client *client)
+{
+	struct lm8323_chip *lm = i2c_get_clientdata(client);
+	int i;
+
+	mutex_lock(&lm->lock);
+	lm->pm_suspend = false;
+	mutex_unlock(&lm->lock);
+
+	for (i = 0; i < 3; i++)
+		if (lm->pwm[i].enabled)
+			led_classdev_resume(&lm->pwm[i].cdev);
+
+	enable_irq(client->irq);
+	set_irq_wake(client->irq, 1);
+
+	return 0;
+}
+#else
+#define lm8323_suspend	NULL
+#define lm8323_resume	NULL
+#endif
+
+static const struct i2c_device_id lm8323_id[] = {
+	{ "lm8323", 0 },
+	{ }
+};
+
+static struct i2c_driver lm8323_i2c_driver = {
+	.driver = {
+		.name	= "lm8323",
+	},
+	.probe		= lm8323_probe,
+	.remove		= __devexit_p(lm8323_remove),
+	.suspend	= lm8323_suspend,
+	.resume		= lm8323_resume,
+	.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_AUTHOR("Timo O. Karjalainen <timo.o.karjalainen@nokia.com>");
+MODULE_AUTHOR("Daniel Stone");
+MODULE_AUTHOR("Felipe Balbi <felipe.balbi@nokia.com>");
+MODULE_DESCRIPTION("LM8323 keypad driver");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index 06f46fc..1acfa3a 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -193,6 +193,16 @@
 	  To compile this driver as a module, choose M here: the module will be
 	  called cm109.
 
+config INPUT_TWL4030_PWRBUTTON
+	tristate "TWL4030 Power button Driver"
+	depends on TWL4030_CORE
+	help
+	  Say Y here if you want to enable power key reporting via the
+	  TWL4030 family of chips.
+
+	  To compile this driver as a module, choose M here. The module will
+	  be called twl4030_pwrbutton.
+
 config INPUT_UINPUT
 	tristate "User level driver support"
 	help
@@ -250,4 +260,13 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called rb532_button.
 
+config INPUT_DM355EVM
+	tristate "TI DaVinci DM355 EVM Keypad and IR Remote"
+	depends on MFD_DM355EVM_MSP
+	help
+	  Supports the pushbuttons and IR remote used with
+	  the DM355 EVM board.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called dm355evm_keys.
 endif
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index eb3f407..0d979fd 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -10,6 +10,7 @@
 obj-$(CONFIG_INPUT_ATLAS_BTNS)		+= atlas_btns.o
 obj-$(CONFIG_INPUT_CM109)		+= cm109.o
 obj-$(CONFIG_INPUT_COBALT_BTNS)		+= cobalt_btns.o
+obj-$(CONFIG_INPUT_DM355EVM)		+= dm355evm_keys.o
 obj-$(CONFIG_HP_SDC_RTC)		+= hp_sdc_rtc.o
 obj-$(CONFIG_INPUT_IXP4XX_BEEPER)	+= ixp4xx-beeper.o
 obj-$(CONFIG_INPUT_KEYSPAN_REMOTE)	+= keyspan_remote.o
@@ -21,6 +22,7 @@
 obj-$(CONFIG_INPUT_GPIO_ROTARY_ENCODER)	+= rotary_encoder.o
 obj-$(CONFIG_INPUT_SGI_BTNS)		+= sgi_btns.o
 obj-$(CONFIG_INPUT_SPARCSPKR)		+= sparcspkr.o
+obj-$(CONFIG_INPUT_TWL4030_PWRBUTTON)	+= twl4030-pwrbutton.o
 obj-$(CONFIG_INPUT_UINPUT)		+= uinput.o
 obj-$(CONFIG_INPUT_WISTRON_BTNS)	+= wistron_btns.o
 obj-$(CONFIG_INPUT_YEALINK)		+= yealink.o
diff --git a/drivers/input/misc/ati_remote2.c b/drivers/input/misc/ati_remote2.c
index 922c051..0501f0e 100644
--- a/drivers/input/misc/ati_remote2.c
+++ b/drivers/input/misc/ati_remote2.c
@@ -509,7 +509,7 @@
 
 	old_keycode = ar2->keycode[mode][index];
 	ar2->keycode[mode][index] = keycode;
-	set_bit(keycode, idev->keybit);
+	__set_bit(keycode, idev->keybit);
 
 	for (mode = 0; mode < ATI_REMOTE2_MODES; mode++) {
 		for (index = 0; index < ARRAY_SIZE(ati_remote2_key_table); index++) {
@@ -518,7 +518,7 @@
 		}
 	}
 
-	clear_bit(old_keycode, idev->keybit);
+	__clear_bit(old_keycode, idev->keybit);
 
 	return 0;
 }
@@ -543,7 +543,7 @@
 	for (mode = 0; mode < ATI_REMOTE2_MODES; mode++) {
 		for (index = 0; index < ARRAY_SIZE(ati_remote2_key_table); index++) {
 			ar2->keycode[mode][index] = ati_remote2_key_table[index].keycode;
-			set_bit(ar2->keycode[mode][index], idev->keybit);
+			__set_bit(ar2->keycode[mode][index], idev->keybit);
 		}
 	}
 
@@ -554,11 +554,11 @@
 	ar2->keycode[ATI_REMOTE2_AUX3][index] = KEY_PROG3;
 	ar2->keycode[ATI_REMOTE2_AUX4][index] = KEY_PROG4;
 	ar2->keycode[ATI_REMOTE2_PC][index] = KEY_PC;
-	set_bit(KEY_PROG1, idev->keybit);
-	set_bit(KEY_PROG2, idev->keybit);
-	set_bit(KEY_PROG3, idev->keybit);
-	set_bit(KEY_PROG4, idev->keybit);
-	set_bit(KEY_PC, idev->keybit);
+	__set_bit(KEY_PROG1, idev->keybit);
+	__set_bit(KEY_PROG2, idev->keybit);
+	__set_bit(KEY_PROG3, idev->keybit);
+	__set_bit(KEY_PROG4, idev->keybit);
+	__set_bit(KEY_PC, idev->keybit);
 
 	idev->rep[REP_DELAY]  = 250;
 	idev->rep[REP_PERIOD] = 33;
diff --git a/drivers/input/misc/dm355evm_keys.c b/drivers/input/misc/dm355evm_keys.c
new file mode 100644
index 0000000..a63315c
--- /dev/null
+++ b/drivers/input/misc/dm355evm_keys.c
@@ -0,0 +1,329 @@
+/*
+ * dm355evm_keys.c - support buttons and IR remote on DM355 EVM board
+ *
+ * Copyright (c) 2008 by David Brownell
+ *
+ * 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/kernel.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+
+#include <linux/i2c/dm355evm_msp.h>
+
+
+/*
+ * The MSP430 firmware on the DM355 EVM monitors on-board pushbuttons
+ * and an IR receptor used for the remote control.  When any key is
+ * pressed, or its autorepeat kicks in, an event is sent.  This driver
+ * read those events from the small (32 event) queue and reports them.
+ *
+ * Because we communicate with the MSP430 using I2C, and all I2C calls
+ * in Linux sleep, we need to cons up a kind of threaded IRQ handler
+ * using a work_struct.  The IRQ is active low, but we use it through
+ * the GPIO controller so we can trigger on falling edges.
+ *
+ * Note that physically there can only be one of these devices.
+ *
+ * This driver was tested with firmware revision A4.
+ */
+struct dm355evm_keys {
+	struct work_struct	work;
+	struct input_dev	*input;
+	struct device		*dev;
+	int			irq;
+};
+
+static irqreturn_t dm355evm_keys_irq(int irq, void *_keys)
+{
+	struct dm355evm_keys	*keys = _keys;
+
+	schedule_work(&keys->work);
+	return IRQ_HANDLED;
+}
+
+/* These initial keycodes can be remapped by dm355evm_setkeycode(). */
+static struct {
+	u16	event;
+	u16	keycode;
+} dm355evm_keys[] = {
+
+	/*
+	 * Pushbuttons on the EVM board ... note that the labels for these
+	 * are SW10/SW11/etc on the PC board.  The left/right orientation
+	 * comes only from the firmware's documentation, and presumes the
+	 * power connector is immediately in front of you and the IR sensor
+	 * is to the right.  (That is, rotate the board counter-clockwise
+	 * by 90 degrees from the SW10/etc and "DM355 EVM" labels.)
+	 */
+	{ 0x00d8, KEY_OK, },		/* SW12 */
+	{ 0x00b8, KEY_UP, },		/* SW13 */
+	{ 0x00e8, KEY_DOWN, },		/* SW11 */
+	{ 0x0078, KEY_LEFT, },		/* SW14 */
+	{ 0x00f0, KEY_RIGHT, },		/* SW10 */
+
+	/*
+	 * IR buttons ... codes assigned to match the universal remote
+	 * provided with the EVM (Philips PM4S) using DVD code 0020.
+	 *
+	 * These event codes match firmware documentation, but other
+	 * remote controls could easily send more RC5-encoded events.
+	 * The PM4S manual was used in several cases to help select
+	 * a keycode reflecting the intended usage.
+	 *
+	 * RC5 codes are 14 bits, with two start bits (0x3 prefix)
+	 * and a toggle bit (masked out below).
+	 */
+	{ 0x300c, KEY_POWER, },		/* NOTE: docs omit this */
+	{ 0x3000, KEY_NUMERIC_0, },
+	{ 0x3001, KEY_NUMERIC_1, },
+	{ 0x3002, KEY_NUMERIC_2, },
+	{ 0x3003, KEY_NUMERIC_3, },
+	{ 0x3004, KEY_NUMERIC_4, },
+	{ 0x3005, KEY_NUMERIC_5, },
+	{ 0x3006, KEY_NUMERIC_6, },
+	{ 0x3007, KEY_NUMERIC_7, },
+	{ 0x3008, KEY_NUMERIC_8, },
+	{ 0x3009, KEY_NUMERIC_9, },
+	{ 0x3022, KEY_ENTER, },
+	{ 0x30ec, KEY_MODE, },		/* "tv/vcr/..." */
+	{ 0x300f, KEY_SELECT, },	/* "info" */
+	{ 0x3020, KEY_CHANNELUP, },	/* "up" */
+	{ 0x302e, KEY_MENU, },		/* "in/out" */
+	{ 0x3011, KEY_VOLUMEDOWN, },	/* "left" */
+	{ 0x300d, KEY_MUTE, },		/* "ok" */
+	{ 0x3010, KEY_VOLUMEUP, },	/* "right" */
+	{ 0x301e, KEY_SUBTITLE, },	/* "cc" */
+	{ 0x3021, KEY_CHANNELDOWN, },	/* "down" */
+	{ 0x3022, KEY_PREVIOUS, },
+	{ 0x3026, KEY_SLEEP, },
+	{ 0x3172, KEY_REWIND, },	/* NOTE: docs wrongly say 0x30ca */
+	{ 0x3175, KEY_PLAY, },
+	{ 0x3174, KEY_FASTFORWARD, },
+	{ 0x3177, KEY_RECORD, },
+	{ 0x3176, KEY_STOP, },
+	{ 0x3169, KEY_PAUSE, },
+};
+
+static void dm355evm_keys_work(struct work_struct *work)
+{
+	struct dm355evm_keys	*keys;
+	int			status;
+
+	keys = container_of(work, struct dm355evm_keys, work);
+
+	/* For simplicity we ignore INPUT_COUNT and just read
+	 * events until we get the "queue empty" indicator.
+	 * Reading INPUT_LOW decrements the count.
+	 */
+	for (;;) {
+		static u16	last_event;
+		u16		event;
+		int		keycode;
+		int		i;
+
+		status = dm355evm_msp_read(DM355EVM_MSP_INPUT_HIGH);
+		if (status < 0) {
+			dev_dbg(keys->dev, "input high err %d\n",
+					status);
+			break;
+		}
+		event = status << 8;
+
+		status = dm355evm_msp_read(DM355EVM_MSP_INPUT_LOW);
+		if (status < 0) {
+			dev_dbg(keys->dev, "input low err %d\n",
+					status);
+			break;
+		}
+		event |= status;
+		if (event == 0xdead)
+			break;
+
+		/* Press and release a button:  two events, same code.
+		 * Press and hold (autorepeat), then release: N events
+		 * (N > 2), same code.  For RC5 buttons the toggle bits
+		 * distinguish (for example) "1-autorepeat" from "1 1";
+		 * but PCB buttons don't support that bit.
+		 *
+		 * So we must synthesize release events.  We do that by
+		 * mapping events to a press/release event pair; then
+		 * to avoid adding extra events, skip the second event
+		 * of each pair.
+		 */
+		if (event == last_event) {
+			last_event = 0;
+			continue;
+		}
+		last_event = event;
+
+		/* ignore the RC5 toggle bit */
+		event &= ~0x0800;
+
+		/* find the key, or leave it as unknown */
+		keycode = KEY_UNKNOWN;
+		for (i = 0; i < ARRAY_SIZE(dm355evm_keys); i++) {
+			if (dm355evm_keys[i].event != event)
+				continue;
+			keycode = dm355evm_keys[i].keycode;
+			break;
+		}
+		dev_dbg(keys->dev,
+			"input event 0x%04x--> keycode %d\n",
+			event, keycode);
+
+		/* report press + release */
+		input_report_key(keys->input, keycode, 1);
+		input_sync(keys->input);
+		input_report_key(keys->input, keycode, 0);
+		input_sync(keys->input);
+	}
+}
+
+static int dm355evm_setkeycode(struct input_dev *dev, int index, int keycode)
+{
+	u16		old_keycode;
+	unsigned	i;
+
+	if (((unsigned)index) >= ARRAY_SIZE(dm355evm_keys))
+		return -EINVAL;
+
+	old_keycode = dm355evm_keys[index].keycode;
+	dm355evm_keys[index].keycode = keycode;
+	set_bit(keycode, dev->keybit);
+
+	for (i = 0; i < ARRAY_SIZE(dm355evm_keys); i++) {
+		if (dm355evm_keys[index].keycode == old_keycode)
+			goto done;
+	}
+	clear_bit(old_keycode, dev->keybit);
+done:
+	return 0;
+}
+
+static int dm355evm_getkeycode(struct input_dev *dev, int index, int *keycode)
+{
+	if (((unsigned)index) >= ARRAY_SIZE(dm355evm_keys))
+		return -EINVAL;
+
+	return dm355evm_keys[index].keycode;
+}
+
+/*----------------------------------------------------------------------*/
+
+static int __devinit dm355evm_keys_probe(struct platform_device *pdev)
+{
+	struct dm355evm_keys	*keys;
+	struct input_dev	*input;
+	int			status;
+	int			i;
+
+	/* allocate instance struct and input dev */
+	keys = kzalloc(sizeof *keys, GFP_KERNEL);
+	input = input_allocate_device();
+	if (!keys || !input) {
+		status = -ENOMEM;
+		goto fail1;
+	}
+
+	keys->dev = &pdev->dev;
+	keys->input = input;
+	INIT_WORK(&keys->work, dm355evm_keys_work);
+
+	/* set up "threaded IRQ handler" */
+	status = platform_get_irq(pdev, 0);
+	if (status < 0)
+		goto fail1;
+	keys->irq = status;
+
+	input_set_drvdata(input, keys);
+
+	input->name = "DM355 EVM Controls";
+	input->phys = "dm355evm/input0";
+	input->dev.parent = &pdev->dev;
+
+	input->id.bustype = BUS_I2C;
+	input->id.product = 0x0355;
+	input->id.version = dm355evm_msp_read(DM355EVM_MSP_FIRMREV);
+
+	input->evbit[0] = BIT(EV_KEY);
+	for (i = 0; i < ARRAY_SIZE(dm355evm_keys); i++)
+		__set_bit(dm355evm_keys[i].keycode, input->keybit);
+
+	input->setkeycode = dm355evm_setkeycode;
+	input->getkeycode = dm355evm_getkeycode;
+
+	/* REVISIT:  flush the event queue? */
+
+	status = request_irq(keys->irq, dm355evm_keys_irq,
+			     IRQF_TRIGGER_FALLING,
+			     dev_name(&pdev->dev), keys);
+	if (status < 0)
+		goto fail1;
+
+	/* register */
+	status = input_register_device(input);
+	if (status < 0)
+		goto fail2;
+
+	platform_set_drvdata(pdev, keys);
+
+	return 0;
+
+fail2:
+	free_irq(keys->irq, keys);
+fail1:
+	input_free_device(input);
+	kfree(keys);
+	dev_err(&pdev->dev, "can't register, err %d\n", status);
+
+	return status;
+}
+
+static int __devexit dm355evm_keys_remove(struct platform_device *pdev)
+{
+	struct dm355evm_keys	*keys = platform_get_drvdata(pdev);
+
+	free_irq(keys->irq, keys);
+	input_unregister_device(keys->input);
+	kfree(keys);
+
+	return 0;
+}
+
+/* REVISIT:  add suspend/resume when DaVinci supports it.  The IRQ should
+ * be able to wake up the system.  When device_may_wakeup(&pdev->dev), call
+ * enable_irq_wake() on suspend, and disable_irq_wake() on resume.
+ */
+
+/*
+ * I2C is used to talk to the MSP430, but this platform device is
+ * exposed by an MFD driver that manages I2C communications.
+ */
+static struct platform_driver dm355evm_keys_driver = {
+	.probe		= dm355evm_keys_probe,
+	.remove		= __devexit_p(dm355evm_keys_remove),
+	.driver		= {
+		.owner	= THIS_MODULE,
+		.name	= "dm355evm_keys",
+	},
+};
+
+static int __init dm355evm_keys_init(void)
+{
+	return platform_driver_register(&dm355evm_keys_driver);
+}
+module_init(dm355evm_keys_init);
+
+static void __exit dm355evm_keys_exit(void)
+{
+	platform_driver_unregister(&dm355evm_keys_driver);
+}
+module_exit(dm355evm_keys_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/misc/rotary_encoder.c b/drivers/input/misc/rotary_encoder.c
index 5bb3ab5..c806fbf 100644
--- a/drivers/input/misc/rotary_encoder.c
+++ b/drivers/input/misc/rotary_encoder.c
@@ -26,13 +26,17 @@
 #define DRV_NAME "rotary-encoder"
 
 struct rotary_encoder {
-	unsigned int irq_a;
-	unsigned int irq_b;
-	unsigned int pos;
-	unsigned int armed;
-	unsigned int dir;
 	struct input_dev *input;
 	struct rotary_encoder_platform_data *pdata;
+
+	unsigned int axis;
+	unsigned int pos;
+
+	unsigned int irq_a;
+	unsigned int irq_b;
+
+	bool armed;
+	unsigned char dir;	/* 0 - clockwise, 1 - CCW */
 };
 
 static irqreturn_t rotary_encoder_irq(int irq, void *dev_id)
@@ -53,21 +57,32 @@
 		if (!encoder->armed)
 			break;
 
-		if (encoder->dir) {
-			/* turning counter-clockwise */
-			encoder->pos += pdata->steps;
-			encoder->pos--;
-			encoder->pos %= pdata->steps;
+		if (pdata->relative_axis) {
+			input_report_rel(encoder->input, pdata->axis,
+					 encoder->dir ? -1 : 1);
 		} else {
-			/* turning clockwise */
-			encoder->pos++;
-			encoder->pos %= pdata->steps;
-		}
+			unsigned int pos = encoder->pos;
 
-		input_report_abs(encoder->input, pdata->axis, encoder->pos);
+			if (encoder->dir) {
+				/* turning counter-clockwise */
+				if (pdata->rollover)
+					pos += pdata->steps;
+				if (pos)
+					pos--;
+			} else {
+				/* turning clockwise */
+				if (pdata->rollover || pos < pdata->steps)
+					pos++;
+			}
+			if (pdata->rollover)
+				pos %= pdata->steps;
+			encoder->pos = pos;
+			input_report_abs(encoder->input, pdata->axis,
+					 encoder->pos);
+		}
 		input_sync(encoder->input);
 
-		encoder->armed = 0;
+		encoder->armed = false;
 		break;
 
 	case 0x1:
@@ -77,7 +92,7 @@
 		break;
 
 	case 0x3:
-		encoder->armed = 1;
+		encoder->armed = true;
 		break;
 	}
 
@@ -113,9 +128,15 @@
 	input->name = pdev->name;
 	input->id.bustype = BUS_HOST;
 	input->dev.parent = &pdev->dev;
-	input->evbit[0] = BIT_MASK(EV_ABS);
-	input_set_abs_params(encoder->input,
-			     pdata->axis, 0, pdata->steps, 0, 1);
+
+	if (pdata->relative_axis) {
+		input->evbit[0] = BIT_MASK(EV_REL);
+		input->relbit[0] = BIT_MASK(pdata->axis);
+	} else {
+		input->evbit[0] = BIT_MASK(EV_ABS);
+		input_set_abs_params(encoder->input,
+				     pdata->axis, 0, pdata->steps, 0, 1);
+	}
 
 	err = input_register_device(input);
 	if (err) {
diff --git a/drivers/input/misc/twl4030-pwrbutton.c b/drivers/input/misc/twl4030-pwrbutton.c
new file mode 100644
index 0000000..f5fc997
--- /dev/null
+++ b/drivers/input/misc/twl4030-pwrbutton.c
@@ -0,0 +1,145 @@
+/**
+ * twl4030-pwrbutton.c - TWL4030 Power Button Input Driver
+ *
+ * Copyright (C) 2008-2009 Nokia Corporation
+ *
+ * Written by Peter De Schrijver <peter.de-schrijver@nokia.com>
+ * Several fixes by Felipe Balbi <felipe.balbi@nokia.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file "COPYING" in the main directory of this
+ * archive for more details.
+ *
+ * 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  02111-1307  USA
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/i2c/twl4030.h>
+
+#define PWR_PWRON_IRQ (1 << 0)
+
+#define STS_HW_CONDITIONS 0xf
+
+static irqreturn_t powerbutton_irq(int irq, void *_pwr)
+{
+	struct input_dev *pwr = _pwr;
+	int err;
+	u8 value;
+
+#ifdef CONFIG_LOCKDEP
+	/* WORKAROUND for lockdep forcing IRQF_DISABLED on us, which
+	 * we don't want and can't tolerate since this is a threaded
+	 * IRQ and can sleep due to the i2c reads it has to issue.
+	 * Although it might be friendlier not to borrow this thread
+	 * context...
+	 */
+	local_irq_enable();
+#endif
+
+	err = twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &value,
+				  STS_HW_CONDITIONS);
+	if (!err)  {
+		input_report_key(pwr, KEY_POWER, value & PWR_PWRON_IRQ);
+		input_sync(pwr);
+	} else {
+		dev_err(pwr->dev.parent, "twl4030: i2c error %d while reading"
+			" TWL4030 PM_MASTER STS_HW_CONDITIONS register\n", err);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int __devinit twl4030_pwrbutton_probe(struct platform_device *pdev)
+{
+	struct input_dev *pwr;
+	int irq = platform_get_irq(pdev, 0);
+	int err;
+
+	pwr = input_allocate_device();
+	if (!pwr) {
+		dev_dbg(&pdev->dev, "Can't allocate power button\n");
+		return -ENOMEM;
+	}
+
+	pwr->evbit[0] = BIT_MASK(EV_KEY);
+	pwr->keybit[BIT_WORD(KEY_POWER)] = BIT_MASK(KEY_POWER);
+	pwr->name = "twl4030_pwrbutton";
+	pwr->phys = "twl4030_pwrbutton/input0";
+	pwr->dev.parent = &pdev->dev;
+
+	err = request_irq(irq, powerbutton_irq,
+			IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
+			"twl4030_pwrbutton", pwr);
+	if (err < 0) {
+		dev_dbg(&pdev->dev, "Can't get IRQ for pwrbutton: %d\n", err);
+		goto free_input_dev;
+	}
+
+	err = input_register_device(pwr);
+	if (err) {
+		dev_dbg(&pdev->dev, "Can't register power button: %d\n", err);
+		goto free_irq;
+	}
+
+	platform_set_drvdata(pdev, pwr);
+
+	return 0;
+
+free_irq:
+	free_irq(irq, NULL);
+free_input_dev:
+	input_free_device(pwr);
+	return err;
+}
+
+static int __devexit twl4030_pwrbutton_remove(struct platform_device *pdev)
+{
+	struct input_dev *pwr = platform_get_drvdata(pdev);
+	int irq = platform_get_irq(pdev, 0);
+
+	free_irq(irq, pwr);
+	input_unregister_device(pwr);
+
+	return 0;
+}
+
+struct platform_driver twl4030_pwrbutton_driver = {
+	.probe		= twl4030_pwrbutton_probe,
+	.remove		= __devexit_p(twl4030_pwrbutton_remove),
+	.driver		= {
+		.name	= "twl4030_pwrbutton",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init twl4030_pwrbutton_init(void)
+{
+	return platform_driver_register(&twl4030_pwrbutton_driver);
+}
+module_init(twl4030_pwrbutton_init);
+
+static void __exit twl4030_pwrbutton_exit(void)
+{
+	platform_driver_unregister(&twl4030_pwrbutton_driver);
+}
+module_exit(twl4030_pwrbutton_exit);
+
+MODULE_ALIAS("platform:twl4030_pwrbutton");
+MODULE_DESCRIPTION("Triton2 Power Button");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Peter De Schrijver <peter.de-schrijver@nokia.com>");
+MODULE_AUTHOR("Felipe Balbi <felipe.balbi@nokia.com>");
+
diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c
index 46b7cae..c5a49ab 100644
--- a/drivers/input/misc/uinput.c
+++ b/drivers/input/misc/uinput.c
@@ -54,27 +54,28 @@
 	return 0;
 }
 
+/* Atomically allocate an ID for the given request. Returns 0 on success. */
 static int uinput_request_alloc_id(struct uinput_device *udev, struct uinput_request *request)
 {
-	/* Atomically allocate an ID for the given request. Returns 0 on success. */
 	int id;
 	int err = -1;
 
 	spin_lock(&udev->requests_lock);
 
-	for (id = 0; id < UINPUT_NUM_REQUESTS; id++)
+	for (id = 0; id < UINPUT_NUM_REQUESTS; id++) {
 		if (!udev->requests[id]) {
 			request->id = id;
 			udev->requests[id] = request;
 			err = 0;
 			break;
 		}
+	}
 
 	spin_unlock(&udev->requests_lock);
 	return err;
 }
 
-static struct uinput_request* uinput_request_find(struct uinput_device *udev, int id)
+static struct uinput_request *uinput_request_find(struct uinput_device *udev, int id)
 {
 	/* Find an input request, by ID. Returns NULL if the ID isn't valid. */
 	if (id >= UINPUT_NUM_REQUESTS || id < 0)
@@ -99,14 +100,51 @@
 	complete(&request->done);
 }
 
-static int uinput_request_submit(struct input_dev *dev, struct uinput_request *request)
+static int uinput_request_submit(struct uinput_device *udev, struct uinput_request *request)
 {
-	/* Tell our userspace app about this new request by queueing an input event */
-	uinput_dev_event(dev, EV_UINPUT, request->code, request->id);
+	int retval;
 
-	/* Wait for the request to complete */
-	wait_for_completion(&request->done);
-	return request->retval;
+	retval = uinput_request_reserve_slot(udev, request);
+	if (retval)
+		return retval;
+
+	retval = mutex_lock_interruptible(&udev->mutex);
+	if (retval)
+		return retval;
+
+	if (udev->state != UIST_CREATED) {
+		retval = -ENODEV;
+		goto out;
+	}
+
+	/* Tell our userspace app about this new request by queueing an input event */
+	uinput_dev_event(udev->dev, EV_UINPUT, request->code, request->id);
+
+ out:
+	mutex_unlock(&udev->mutex);
+	return retval;
+}
+
+/*
+ * Fail all ouitstanding requests so handlers don't wait for the userspace
+ * to finish processing them.
+ */
+static void uinput_flush_requests(struct uinput_device *udev)
+{
+	struct uinput_request *request;
+	int i;
+
+	spin_lock(&udev->requests_lock);
+
+	for (i = 0; i < UINPUT_NUM_REQUESTS; i++) {
+		request = udev->requests[i];
+		if (request) {
+			request->retval = -ENODEV;
+			uinput_request_done(udev, request);
+		}
+	}
+
+	spin_unlock(&udev->requests_lock);
 }
 
 static void uinput_dev_set_gain(struct input_dev *dev, u16 gain)
@@ -126,6 +164,7 @@
 
 static int uinput_dev_upload_effect(struct input_dev *dev, struct ff_effect *effect, struct ff_effect *old)
 {
+	struct uinput_device *udev = input_get_drvdata(dev);
 	struct uinput_request request;
 	int retval;
 
@@ -146,15 +185,18 @@
 	request.u.upload.effect = effect;
 	request.u.upload.old = old;
 
-	retval = uinput_request_reserve_slot(input_get_drvdata(dev), &request);
-	if (!retval)
-		retval = uinput_request_submit(dev, &request);
+	retval = uinput_request_submit(udev, &request);
+	if (!retval) {
+		wait_for_completion(&request.done);
+		retval = request.retval;
+	}
 
 	return retval;
 }
 
 static int uinput_dev_erase_effect(struct input_dev *dev, int effect_id)
 {
+	struct uinput_device *udev = input_get_drvdata(dev);
 	struct uinput_request request;
 	int retval;
 
@@ -166,9 +208,11 @@
 	request.code = UI_FF_ERASE;
 	request.u.effect_id = effect_id;
 
-	retval = uinput_request_reserve_slot(input_get_drvdata(dev), &request);
-	if (!retval)
-		retval = uinput_request_submit(dev, &request);
+	retval = uinput_request_submit(udev, &request);
+	if (!retval) {
+		wait_for_completion(&request.done);
+		retval = request.retval;
+	}
 
 	return retval;
 }
@@ -176,20 +220,24 @@
 static void uinput_destroy_device(struct uinput_device *udev)
 {
 	const char *name, *phys;
+	struct input_dev *dev = udev->dev;
+	enum uinput_state old_state = udev->state;
 
-	if (udev->dev) {
-		name = udev->dev->name;
-		phys = udev->dev->phys;
-		if (udev->state == UIST_CREATED)
-			input_unregister_device(udev->dev);
-		else
-			input_free_device(udev->dev);
+	udev->state = UIST_NEW_DEVICE;
+
+	if (dev) {
+		name = dev->name;
+		phys = dev->phys;
+		if (old_state == UIST_CREATED) {
+			uinput_flush_requests(udev);
+			input_unregister_device(dev);
+		} else {
+			input_free_device(dev);
+		}
 		kfree(name);
 		kfree(phys);
 		udev->dev = NULL;
 	}
-
-	udev->state = UIST_NEW_DEVICE;
 }
 
 static int uinput_create_device(struct uinput_device *udev)
diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig
index c66cc3d..8a2c5b1 100644
--- a/drivers/input/mouse/Kconfig
+++ b/drivers/input/mouse/Kconfig
@@ -303,4 +303,22 @@
 	  To compile this driver as a module choose M here: the module will be
 	  called maplemouse.
 
+config MOUSE_SYNAPTICS_I2C
+	tristate "Synaptics I2C Touchpad support"
+	depends on I2C
+	help
+	  This driver supports Synaptics I2C touchpad controller on eXeda
+	  mobile device.
+	  The device will not work the synaptics X11 driver because
+	  (i) it  reports only relative coordinates and has no capabilities
+	  to report absolute coordinates
+	  (ii) the eXeda device itself uses Xfbdev as X Server and it does
+	  not allow using xf86-input-* drivers.
+
+	  Say y here if you have eXeda device and want to use a Synaptics
+	  I2C Touchpad.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called synaptics_i2c.
+
 endif
diff --git a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile
index 4721894..010f265 100644
--- a/drivers/input/mouse/Makefile
+++ b/drivers/input/mouse/Makefile
@@ -18,6 +18,7 @@
 obj-$(CONFIG_MOUSE_PXA930_TRKBALL)	+= pxa930_trkball.o
 obj-$(CONFIG_MOUSE_RISCPC)		+= rpcmouse.o
 obj-$(CONFIG_MOUSE_SERIAL)		+= sermouse.o
+obj-$(CONFIG_MOUSE_SYNAPTICS_I2C)	+= synaptics_i2c.o
 obj-$(CONFIG_MOUSE_VSXXXAA)		+= vsxxxaa.o
 
 psmouse-objs := psmouse-base.o synaptics.o
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
index daecc75..5547e24 100644
--- a/drivers/input/mouse/alps.c
+++ b/drivers/input/mouse/alps.c
@@ -38,25 +38,25 @@
 
 static const struct alps_model_info alps_model_data[] = {
 	{ { 0x32, 0x02, 0x14 },	0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* Toshiba Salellite Pro M10 */
-	{ { 0x33, 0x02, 0x0a },	0x88, 0xf8, ALPS_OLDPROTO },		/* UMAX-530T */
+	{ { 0x33, 0x02, 0x0a },	0x88, 0xf8, ALPS_OLDPROTO },		  /* UMAX-530T */
 	{ { 0x53, 0x02, 0x0a },	0xf8, 0xf8, 0 },
 	{ { 0x53, 0x02, 0x14 },	0xf8, 0xf8, 0 },
-	{ { 0x60, 0x03, 0xc8 }, 0xf8, 0xf8, 0 },			/* HP ze1115 */
+	{ { 0x60, 0x03, 0xc8 }, 0xf8, 0xf8, 0 },			  /* HP ze1115 */
 	{ { 0x63, 0x02, 0x0a },	0xf8, 0xf8, 0 },
 	{ { 0x63, 0x02, 0x14 },	0xf8, 0xf8, 0 },
-	{ { 0x63, 0x02, 0x28 },	0xf8, 0xf8, ALPS_FW_BK_2 },		/* Fujitsu Siemens S6010 */
-	{ { 0x63, 0x02, 0x3c },	0x8f, 0x8f, ALPS_WHEEL },		/* Toshiba Satellite S2400-103 */
-	{ { 0x63, 0x02, 0x50 },	0xef, 0xef, ALPS_FW_BK_1 },		/* NEC Versa L320 */
+	{ { 0x63, 0x02, 0x28 },	0xf8, 0xf8, ALPS_FW_BK_2 },		  /* Fujitsu Siemens S6010 */
+	{ { 0x63, 0x02, 0x3c },	0x8f, 0x8f, ALPS_WHEEL },		  /* Toshiba Satellite S2400-103 */
+	{ { 0x63, 0x02, 0x50 },	0xef, 0xef, ALPS_FW_BK_1 },		  /* NEC Versa L320 */
 	{ { 0x63, 0x02, 0x64 },	0xf8, 0xf8, 0 },
-	{ { 0x63, 0x03, 0xc8 }, 0xf8, 0xf8, ALPS_PASS },		/* Dell Latitude D800 */
-	{ { 0x73, 0x00, 0x0a },	0xf8, 0xf8, ALPS_DUALPOINT },		/* ThinkPad R61 8918-5QG */
+	{ { 0x63, 0x03, 0xc8 }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D800 */
+	{ { 0x73, 0x00, 0x0a },	0xf8, 0xf8, ALPS_DUALPOINT },		  /* ThinkPad R61 8918-5QG */
 	{ { 0x73, 0x02, 0x0a },	0xf8, 0xf8, 0 },
-	{ { 0x73, 0x02, 0x14 },	0xf8, 0xf8, ALPS_FW_BK_2 },		/* Ahtec Laptop */
+	{ { 0x73, 0x02, 0x14 },	0xf8, 0xf8, ALPS_FW_BK_2 },		  /* Ahtec Laptop */
 	{ { 0x20, 0x02, 0x0e },	0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* XXX */
 	{ { 0x22, 0x02, 0x0a },	0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT },
 	{ { 0x22, 0x02, 0x14 }, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D600 */
 	{ { 0x62, 0x02, 0x14 }, 0xcf, 0xcf, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude E6500 */
-	{ { 0x73, 0x02, 0x50 }, 0xcf, 0xcf, ALPS_FW_BK_1 } /* Dell Vostro 1400 */
+	{ { 0x73, 0x02, 0x50 }, 0xcf, 0xcf, ALPS_FW_BK_1 },		  /* Dell Vostro 1400 */
 };
 
 /*
@@ -132,18 +132,23 @@
 	ges = packet[2] & 1;
 	fin = packet[2] & 2;
 
-	input_report_key(dev, BTN_LEFT, left);
-	input_report_key(dev, BTN_RIGHT, right);
-	input_report_key(dev, BTN_MIDDLE, middle);
-
 	if ((priv->i->flags & ALPS_DUALPOINT) && z == 127) {
 		input_report_rel(dev2, REL_X,  (x > 383 ? (x - 768) : x));
 		input_report_rel(dev2, REL_Y, -(y > 255 ? (y - 512) : y));
+
+		input_report_key(dev2, BTN_LEFT, left);
+		input_report_key(dev2, BTN_RIGHT, right);
+		input_report_key(dev2, BTN_MIDDLE, middle);
+
 		input_sync(dev);
 		input_sync(dev2);
 		return;
 	}
 
+	input_report_key(dev, BTN_LEFT, left);
+	input_report_key(dev, BTN_RIGHT, right);
+	input_report_key(dev, BTN_MIDDLE, middle);
+
 	/* Convert hardware tap to a reasonable Z value */
 	if (ges && !fin) z = 40;
 
diff --git a/drivers/input/mouse/appletouch.c b/drivers/input/mouse/appletouch.c
index e0140fd..908b5b4 100644
--- a/drivers/input/mouse/appletouch.c
+++ b/drivers/input/mouse/appletouch.c
@@ -361,7 +361,7 @@
 		    (!is_increasing && xy_sensors[i - 1] < xy_sensors[i])) {
 			(*fingers)++;
 			is_increasing = 1;
-		} else if (i > 0 && xy_sensors[i - 1] >= xy_sensors[i]) {
+		} else if (i > 0 && (xy_sensors[i - 1] - xy_sensors[i] > threshold)) {
 			is_increasing = 0;
 		}
 
diff --git a/drivers/input/mouse/lifebook.c b/drivers/input/mouse/lifebook.c
index 15ac320..dcd4236 100644
--- a/drivers/input/mouse/lifebook.c
+++ b/drivers/input/mouse/lifebook.c
@@ -159,21 +159,22 @@
 		if (!dev2)
 			printk(KERN_WARNING "lifebook.c: got relative packet "
 				"but no relative device set up\n");
-	} else if (lifebook_use_6byte_proto) {
-		input_report_abs(dev1, ABS_X,
-				 ((packet[1] & 0x3f) << 6) | (packet[2] & 0x3f));
-		input_report_abs(dev1, ABS_Y,
-				 4096 - (((packet[4] & 0x3f) << 6) | (packet[5] & 0x3f)));
 	} else {
-		input_report_abs(dev1, ABS_X,
-				 (packet[1] | ((packet[0] & 0x30) << 4)));
-		input_report_abs(dev1, ABS_Y,
-				 1024 - (packet[2] | ((packet[0] & 0xC0) << 2)));
+		if (lifebook_use_6byte_proto) {
+			input_report_abs(dev1, ABS_X,
+				((packet[1] & 0x3f) << 6) | (packet[2] & 0x3f));
+			input_report_abs(dev1, ABS_Y,
+				4096 - (((packet[4] & 0x3f) << 6) | (packet[5] & 0x3f)));
+		} else {
+			input_report_abs(dev1, ABS_X,
+				(packet[1] | ((packet[0] & 0x30) << 4)));
+			input_report_abs(dev1, ABS_Y,
+				1024 - (packet[2] | ((packet[0] & 0xC0) << 2)));
+		}
+		input_report_key(dev1, BTN_TOUCH, packet[0] & 0x04);
+		input_sync(dev1);
 	}
 
-	input_report_key(dev1, BTN_TOUCH, packet[0] & 0x04);
-	input_sync(dev1);
-
 	if (dev2) {
 		if (relative_packet) {
 			input_report_rel(dev2, REL_X,
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
index f8f86de..b407b35 100644
--- a/drivers/input/mouse/psmouse-base.c
+++ b/drivers/input/mouse/psmouse-base.c
@@ -327,7 +327,9 @@
 			goto out;
 		}
 
-		if (psmouse->packet[1] == PSMOUSE_RET_ID) {
+		if (psmouse->packet[1] == PSMOUSE_RET_ID ||
+		    (psmouse->type == PSMOUSE_HGPK &&
+		     psmouse->packet[1] == PSMOUSE_RET_BAT)) {
 			__psmouse_set_state(psmouse, PSMOUSE_IGNORE);
 			serio_reconnect(serio);
 			goto out;
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
index f3e4f7b..19984bf 100644
--- a/drivers/input/mouse/synaptics.c
+++ b/drivers/input/mouse/synaptics.c
@@ -180,6 +180,29 @@
 	return -1;
 }
 
+/*
+ * Read touchpad resolution
+ * Resolution is left zero if touchpad does not support the query
+ */
+static int synaptics_resolution(struct psmouse *psmouse)
+{
+	struct synaptics_data *priv = psmouse->private;
+	unsigned char res[3];
+
+	if (SYN_ID_MAJOR(priv->identity) < 4)
+		return 0;
+
+	if (synaptics_send_cmd(psmouse, SYN_QUE_RESOLUTION, res))
+		return 0;
+
+	if ((res[0] != 0) && (res[1] & 0x80) && (res[2] != 0)) {
+		priv->x_res = res[0]; /* x resolution in units/mm */
+		priv->y_res = res[2]; /* y resolution in units/mm */
+	}
+
+	return 0;
+}
+
 static int synaptics_query_hardware(struct psmouse *psmouse)
 {
 	if (synaptics_identify(psmouse))
@@ -188,6 +211,8 @@
 		return -1;
 	if (synaptics_capability(psmouse))
 		return -1;
+	if (synaptics_resolution(psmouse))
+		return -1;
 
 	return 0;
 }
@@ -563,6 +588,9 @@
 	clear_bit(EV_REL, dev->evbit);
 	clear_bit(REL_X, dev->relbit);
 	clear_bit(REL_Y, dev->relbit);
+
+	dev->absres[ABS_X] = priv->x_res;
+	dev->absres[ABS_Y] = priv->y_res;
 }
 
 static void synaptics_disconnect(struct psmouse *psmouse)
diff --git a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h
index 02aa4cf..3023821 100644
--- a/drivers/input/mouse/synaptics.h
+++ b/drivers/input/mouse/synaptics.h
@@ -97,6 +97,8 @@
 	unsigned long int capabilities;		/* Capabilities */
 	unsigned long int ext_cap;		/* Extended Capabilities */
 	unsigned long int identity;		/* Identification */
+	int x_res;				/* X resolution in units/mm */
+	int y_res;				/* Y resolution in units/mm */
 
 	unsigned char pkt_type;			/* packet type - old, new, etc */
 	unsigned char mode;			/* current mode byte */
diff --git a/drivers/input/mouse/synaptics_i2c.c b/drivers/input/mouse/synaptics_i2c.c
new file mode 100644
index 0000000..eac9fdd
--- /dev/null
+++ b/drivers/input/mouse/synaptics_i2c.c
@@ -0,0 +1,676 @@
+/*
+ * Synaptics touchpad with I2C interface
+ *
+ * Copyright (C) 2009 Compulab, Ltd.
+ * Mike Rapoport <mike@compulab.co.il>
+ * Igor Grinberg <grinberg@compulab.co.il>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive for
+ * more details.
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+#include <linux/delay.h>
+#include <linux/workqueue.h>
+
+#define DRIVER_NAME		"synaptics_i2c"
+/* maximum product id is 15 characters */
+#define PRODUCT_ID_LENGTH	15
+#define REGISTER_LENGTH		8
+
+/*
+ * after soft reset, we should wait for 1 ms
+ * before the device becomes operational
+ */
+#define SOFT_RESET_DELAY_MS	3
+/* and after hard reset, we should wait for max 500ms */
+#define HARD_RESET_DELAY_MS	500
+
+/* Registers by SMBus address */
+#define PAGE_SEL_REG		0xff
+#define DEVICE_STATUS_REG	0x09
+
+/* Registers by RMI address */
+#define DEV_CONTROL_REG		0x0000
+#define INTERRUPT_EN_REG	0x0001
+#define ERR_STAT_REG		0x0002
+#define INT_REQ_STAT_REG	0x0003
+#define DEV_COMMAND_REG		0x0004
+
+#define RMI_PROT_VER_REG	0x0200
+#define MANUFACT_ID_REG		0x0201
+#define PHYS_INT_VER_REG	0x0202
+#define PROD_PROPERTY_REG	0x0203
+#define INFO_QUERY_REG0		0x0204
+#define INFO_QUERY_REG1		(INFO_QUERY_REG0 + 1)
+#define INFO_QUERY_REG2		(INFO_QUERY_REG0 + 2)
+#define INFO_QUERY_REG3		(INFO_QUERY_REG0 + 3)
+
+#define PRODUCT_ID_REG0		0x0210
+#define PRODUCT_ID_REG1		(PRODUCT_ID_REG0 + 1)
+#define PRODUCT_ID_REG2		(PRODUCT_ID_REG0 + 2)
+#define PRODUCT_ID_REG3		(PRODUCT_ID_REG0 + 3)
+#define PRODUCT_ID_REG4		(PRODUCT_ID_REG0 + 4)
+#define PRODUCT_ID_REG5		(PRODUCT_ID_REG0 + 5)
+#define PRODUCT_ID_REG6		(PRODUCT_ID_REG0 + 6)
+#define PRODUCT_ID_REG7		(PRODUCT_ID_REG0 + 7)
+#define PRODUCT_ID_REG8		(PRODUCT_ID_REG0 + 8)
+#define PRODUCT_ID_REG9		(PRODUCT_ID_REG0 + 9)
+#define PRODUCT_ID_REG10	(PRODUCT_ID_REG0 + 10)
+#define PRODUCT_ID_REG11	(PRODUCT_ID_REG0 + 11)
+#define PRODUCT_ID_REG12	(PRODUCT_ID_REG0 + 12)
+#define PRODUCT_ID_REG13	(PRODUCT_ID_REG0 + 13)
+#define PRODUCT_ID_REG14	(PRODUCT_ID_REG0 + 14)
+#define PRODUCT_ID_REG15	(PRODUCT_ID_REG0 + 15)
+
+#define DATA_REG0		0x0400
+#define ABS_PRESSURE_REG	0x0401
+#define ABS_MSB_X_REG		0x0402
+#define ABS_LSB_X_REG		(ABS_MSB_X_REG + 1)
+#define ABS_MSB_Y_REG		0x0404
+#define ABS_LSB_Y_REG		(ABS_MSB_Y_REG + 1)
+#define REL_X_REG		0x0406
+#define REL_Y_REG		0x0407
+
+#define DEV_QUERY_REG0		0x1000
+#define DEV_QUERY_REG1		(DEV_QUERY_REG0 + 1)
+#define DEV_QUERY_REG2		(DEV_QUERY_REG0 + 2)
+#define DEV_QUERY_REG3		(DEV_QUERY_REG0 + 3)
+#define DEV_QUERY_REG4		(DEV_QUERY_REG0 + 4)
+#define DEV_QUERY_REG5		(DEV_QUERY_REG0 + 5)
+#define DEV_QUERY_REG6		(DEV_QUERY_REG0 + 6)
+#define DEV_QUERY_REG7		(DEV_QUERY_REG0 + 7)
+#define DEV_QUERY_REG8		(DEV_QUERY_REG0 + 8)
+
+#define GENERAL_2D_CONTROL_REG	0x1041
+#define SENSOR_SENSITIVITY_REG	0x1044
+#define SENS_MAX_POS_MSB_REG	0x1046
+#define SENS_MAX_POS_LSB_REG	(SENS_MAX_POS_UPPER_REG + 1)
+
+/* Register bits */
+/* Device Control Register Bits */
+#define REPORT_RATE_1ST_BIT	6
+
+/* Interrupt Enable Register Bits (INTERRUPT_EN_REG) */
+#define F10_ABS_INT_ENA		0
+#define F10_REL_INT_ENA		1
+#define F20_INT_ENA		2
+
+/* Interrupt Request Register Bits (INT_REQ_STAT_REG | DEVICE_STATUS_REG) */
+#define F10_ABS_INT_REQ		0
+#define F10_REL_INT_REQ		1
+#define F20_INT_REQ		2
+/* Device Status Register Bits (DEVICE_STATUS_REG) */
+#define STAT_CONFIGURED		6
+#define STAT_ERROR		7
+
+/* Device Command Register Bits (DEV_COMMAND_REG) */
+#define RESET_COMMAND		0x01
+#define REZERO_COMMAND		0x02
+
+/* Data Register 0 Bits (DATA_REG0) */
+#define GESTURE			3
+
+/* Device Query Registers Bits */
+/* DEV_QUERY_REG3 */
+#define HAS_PALM_DETECT		1
+#define HAS_MULTI_FING		2
+#define HAS_SCROLLER		4
+#define HAS_2D_SCROLL		5
+
+/* General 2D Control Register Bits (GENERAL_2D_CONTROL_REG) */
+#define NO_DECELERATION		1
+#define REDUCE_REPORTING	3
+#define NO_FILTER		5
+
+/* Function Masks */
+/* Device Control Register Masks (DEV_CONTROL_REG) */
+#define REPORT_RATE_MSK		0xc0
+#define SLEEP_MODE_MSK		0x07
+
+/* Device Sleep Modes */
+#define FULL_AWAKE		0x0
+#define NORMAL_OP		0x1
+#define LOW_PWR_OP		0x2
+#define VERY_LOW_PWR_OP		0x3
+#define SENS_SLEEP		0x4
+#define SLEEP_MOD		0x5
+#define DEEP_SLEEP		0x6
+#define HIBERNATE		0x7
+
+/* Interrupt Register Mask */
+/* (INT_REQ_STAT_REG | DEVICE_STATUS_REG | INTERRUPT_EN_REG) */
+#define INT_ENA_REQ_MSK		0x07
+#define INT_ENA_ABS_MSK		0x01
+#define INT_ENA_REL_MSK		0x02
+#define INT_ENA_F20_MSK		0x04
+
+/* Device Status Register Masks (DEVICE_STATUS_REG) */
+#define CONFIGURED_MSK		0x40
+#define ERROR_MSK		0x80
+
+/* Data Register 0 Masks */
+#define FINGER_WIDTH_MSK	0xf0
+#define GESTURE_MSK		0x08
+#define SENSOR_STATUS_MSK	0x07
+
+/*
+ * MSB Position Register Masks
+ * ABS_MSB_X_REG | ABS_MSB_Y_REG | SENS_MAX_POS_MSB_REG |
+ * DEV_QUERY_REG3 | DEV_QUERY_REG5
+ */
+#define MSB_POSITION_MSK	0x1f
+
+/* Device Query Registers Masks */
+
+/* DEV_QUERY_REG2 */
+#define NUM_EXTRA_POS_MSK	0x07
+
+/* When in IRQ mode read the device every THREAD_IRQ_SLEEP_SECS */
+#define THREAD_IRQ_SLEEP_SECS	2
+#define THREAD_IRQ_SLEEP_MSECS	(THREAD_IRQ_SLEEP_SECS * MSEC_PER_SEC)
+
+/*
+ * When in Polling mode and no data received for NO_DATA_THRES msecs
+ * reduce the polling rate to NO_DATA_SLEEP_MSECS
+ */
+#define NO_DATA_THRES		(MSEC_PER_SEC)
+#define NO_DATA_SLEEP_MSECS	(MSEC_PER_SEC / 4)
+
+/* Control touchpad's No Deceleration option */
+static int no_decel = 1;
+module_param(no_decel, bool, 0644);
+MODULE_PARM_DESC(no_decel, "No Deceleration. Default = 1 (on)");
+
+/* Control touchpad's Reduced Reporting option */
+static int reduce_report;
+module_param(reduce_report, bool, 0644);
+MODULE_PARM_DESC(reduce_report, "Reduced Reporting. Default = 0 (off)");
+
+/* Control touchpad's No Filter option */
+static int no_filter;
+module_param(no_filter, bool, 0644);
+MODULE_PARM_DESC(no_filter, "No Filter. Default = 0 (off)");
+
+/*
+ * touchpad Attention line is Active Low and Open Drain,
+ * therefore should be connected to pulled up line
+ * and the irq configuration should be set to Falling Edge Trigger
+ */
+/* Control IRQ / Polling option */
+static int polling_req;
+module_param(polling_req, bool, 0444);
+MODULE_PARM_DESC(polling_req, "Request Polling. Default = 0 (use irq)");
+
+/* Control Polling Rate */
+static int scan_rate = 80;
+module_param(scan_rate, int, 0644);
+MODULE_PARM_DESC(scan_rate, "Polling rate in times/sec. Default = 80");
+
+/* The main device structure */
+struct synaptics_i2c {
+	struct i2c_client	*client;
+	struct input_dev	*input;
+	struct delayed_work	dwork;
+	int			no_data_count;
+	int			no_decel_param;
+	int			reduce_report_param;
+	int			no_filter_param;
+	int			scan_rate_param;
+	int			scan_ms;
+};
+
+static inline void set_scan_rate(struct synaptics_i2c *touch, int scan_rate)
+{
+	touch->scan_ms = MSEC_PER_SEC / scan_rate;
+	touch->scan_rate_param = scan_rate;
+}
+
+/*
+ * Driver's initial design makes no race condition possible on i2c bus,
+ * so there is no need in any locking.
+ * Keep it in mind, while playing with the code.
+ */
+static s32 synaptics_i2c_reg_get(struct i2c_client *client, u16 reg)
+{
+	int ret;
+
+	ret = i2c_smbus_write_byte_data(client, PAGE_SEL_REG, reg >> 8);
+	if (ret == 0)
+		ret = i2c_smbus_read_byte_data(client, reg & 0xff);
+
+	return ret;
+}
+
+static s32 synaptics_i2c_reg_set(struct i2c_client *client, u16 reg, u8 val)
+{
+	int ret;
+
+	ret = i2c_smbus_write_byte_data(client, PAGE_SEL_REG, reg >> 8);
+	if (ret == 0)
+		ret = i2c_smbus_write_byte_data(client, reg & 0xff, val);
+
+	return ret;
+}
+
+static s32 synaptics_i2c_word_get(struct i2c_client *client, u16 reg)
+{
+	int ret;
+
+	ret = i2c_smbus_write_byte_data(client, PAGE_SEL_REG, reg >> 8);
+	if (ret == 0)
+		ret = i2c_smbus_read_word_data(client, reg & 0xff);
+
+	return ret;
+}
+
+static int synaptics_i2c_config(struct i2c_client *client)
+{
+	int ret, control;
+	u8 int_en;
+
+	/* set Report Rate to Device Highest (>=80) and Sleep to normal */
+	ret = synaptics_i2c_reg_set(client, DEV_CONTROL_REG, 0xc1);
+	if (ret)
+		return ret;
+
+	/* set Interrupt Disable to Func20 / Enable to Func10) */
+	int_en = (polling_req) ? 0 : INT_ENA_ABS_MSK | INT_ENA_REL_MSK;
+	ret = synaptics_i2c_reg_set(client, INTERRUPT_EN_REG, int_en);
+	if (ret)
+		return ret;
+
+	control = synaptics_i2c_reg_get(client, GENERAL_2D_CONTROL_REG);
+	/* No Deceleration */
+	control |= no_decel ? 1 << NO_DECELERATION : 0;
+	/* Reduced Reporting */
+	control |= reduce_report ? 1 << REDUCE_REPORTING : 0;
+	/* No Filter */
+	control |= no_filter ? 1 << NO_FILTER : 0;
+	ret = synaptics_i2c_reg_set(client, GENERAL_2D_CONTROL_REG, control);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int synaptics_i2c_reset_config(struct i2c_client *client)
+{
+	int ret;
+
+	/* Reset the Touchpad */
+	ret = synaptics_i2c_reg_set(client, DEV_COMMAND_REG, RESET_COMMAND);
+	if (ret) {
+		dev_err(&client->dev, "Unable to reset device\n");
+	} else {
+		msleep(SOFT_RESET_DELAY_MS);
+		ret = synaptics_i2c_config(client);
+		if (ret)
+			dev_err(&client->dev, "Unable to config device\n");
+	}
+
+	return ret;
+}
+
+static int synaptics_i2c_check_error(struct i2c_client *client)
+{
+	int status, ret = 0;
+
+	status = i2c_smbus_read_byte_data(client, DEVICE_STATUS_REG) &
+		(CONFIGURED_MSK | ERROR_MSK);
+
+	if (status != CONFIGURED_MSK)
+		ret = synaptics_i2c_reset_config(client);
+
+	return ret;
+}
+
+static bool synaptics_i2c_get_input(struct synaptics_i2c *touch)
+{
+	struct input_dev *input = touch->input;
+	int xy_delta, gesture;
+	s32 data;
+	s8 x_delta, y_delta;
+
+	/* Deal with spontanious resets and errors */
+	if (synaptics_i2c_check_error(touch->client))
+		return 0;
+
+	/* Get Gesture Bit */
+	data = synaptics_i2c_reg_get(touch->client, DATA_REG0);
+	gesture = (data >> GESTURE) & 0x1;
+
+	/*
+	 * Get Relative axes. we have to get them in one shot,
+	 * so we get 2 bytes starting from REL_X_REG.
+	 */
+	xy_delta = synaptics_i2c_word_get(touch->client, REL_X_REG) & 0xffff;
+
+	/* Separate X from Y */
+	x_delta = xy_delta & 0xff;
+	y_delta = (xy_delta >> REGISTER_LENGTH) & 0xff;
+
+	/* Report the button event */
+	input_report_key(input, BTN_LEFT, gesture);
+
+	/* Report the deltas */
+	input_report_rel(input, REL_X, x_delta);
+	input_report_rel(input, REL_Y, -y_delta);
+	input_sync(input);
+
+	return xy_delta || gesture;
+}
+
+static irqreturn_t synaptics_i2c_irq(int irq, void *dev_id)
+{
+	struct synaptics_i2c *touch = dev_id;
+
+	/*
+	 * We want to have the work run immediately but it might have
+	 * already been scheduled with a delay, that's why we have to
+	 * cancel it first.
+	 */
+	cancel_delayed_work(&touch->dwork);
+	schedule_delayed_work(&touch->dwork, 0);
+
+	return IRQ_HANDLED;
+}
+
+static void synaptics_i2c_check_params(struct synaptics_i2c *touch)
+{
+	bool reset = false;
+
+	if (scan_rate != touch->scan_rate_param)
+		set_scan_rate(touch, scan_rate);
+
+	if (no_decel != touch->no_decel_param) {
+		touch->no_decel_param = no_decel;
+		reset = true;
+	}
+
+	if (no_filter != touch->no_filter_param) {
+		touch->no_filter_param = no_filter;
+		reset = true;
+	}
+
+	if (reduce_report != touch->reduce_report_param) {
+		touch->reduce_report_param = reduce_report;
+		reset = true;
+	}
+
+	if (reset)
+		synaptics_i2c_reset_config(touch->client);
+}
+
+/* Control the Device polling rate / Work Handler sleep time */
+unsigned long synaptics_i2c_adjust_delay(struct synaptics_i2c *touch,
+					 bool have_data)
+{
+	unsigned long delay, nodata_count_thres;
+
+	if (polling_req) {
+		delay = touch->scan_ms;
+		if (have_data) {
+			touch->no_data_count = 0;
+		} else {
+			nodata_count_thres = NO_DATA_THRES / touch->scan_ms;
+			if (touch->no_data_count < nodata_count_thres)
+				touch->no_data_count++;
+			else
+				delay = NO_DATA_SLEEP_MSECS;
+		}
+		return msecs_to_jiffies(delay);
+	} else {
+		delay = msecs_to_jiffies(THREAD_IRQ_SLEEP_MSECS);
+		return round_jiffies_relative(delay);
+	}
+}
+
+/* Work Handler */
+static void synaptics_i2c_work_handler(struct work_struct *work)
+{
+	bool have_data;
+	struct synaptics_i2c *touch =
+			container_of(work, struct synaptics_i2c, dwork.work);
+	unsigned long delay;
+
+	synaptics_i2c_check_params(touch);
+
+	have_data = synaptics_i2c_get_input(touch);
+	delay = synaptics_i2c_adjust_delay(touch, have_data);
+
+	/*
+	 * While interrupt driven, there is no real need to poll the device.
+	 * But touchpads are very sensitive, so there could be errors
+	 * related to physical environment and the attention line isn't
+	 * neccesarily asserted. In such case we can lose the touchpad.
+	 * We poll the device once in THREAD_IRQ_SLEEP_SECS and
+	 * if error is detected, we try to reset and reconfigure the touchpad.
+	 */
+	schedule_delayed_work(&touch->dwork, delay);
+}
+
+static int synaptics_i2c_open(struct input_dev *input)
+{
+	struct synaptics_i2c *touch = input_get_drvdata(input);
+	int ret;
+
+	ret = synaptics_i2c_reset_config(touch->client);
+	if (ret)
+		return ret;
+
+	if (polling_req)
+		schedule_delayed_work(&touch->dwork,
+				       msecs_to_jiffies(NO_DATA_SLEEP_MSECS));
+
+	return 0;
+}
+
+static void synaptics_i2c_close(struct input_dev *input)
+{
+	struct synaptics_i2c *touch = input_get_drvdata(input);
+
+	if (!polling_req)
+		synaptics_i2c_reg_set(touch->client, INTERRUPT_EN_REG, 0);
+
+	cancel_delayed_work_sync(&touch->dwork);
+
+	/* Save some power */
+	synaptics_i2c_reg_set(touch->client, DEV_CONTROL_REG, DEEP_SLEEP);
+}
+
+static void synaptics_i2c_set_input_params(struct synaptics_i2c *touch)
+{
+	struct input_dev *input = touch->input;
+
+	input->name = touch->client->name;
+	input->phys = touch->client->adapter->name;
+	input->id.bustype = BUS_I2C;
+	input->id.version = synaptics_i2c_word_get(touch->client,
+						   INFO_QUERY_REG0);
+	input->dev.parent = &touch->client->dev;
+	input->open = synaptics_i2c_open;
+	input->close = synaptics_i2c_close;
+	input_set_drvdata(input, touch);
+
+	/* Register the device as mouse */
+	__set_bit(EV_REL, input->evbit);
+	__set_bit(REL_X, input->relbit);
+	__set_bit(REL_Y, input->relbit);
+
+	/* Register device's buttons and keys */
+	__set_bit(EV_KEY, input->evbit);
+	__set_bit(BTN_LEFT, input->keybit);
+}
+
+struct synaptics_i2c *synaptics_i2c_touch_create(struct i2c_client *client)
+{
+	struct synaptics_i2c *touch;
+
+	touch = kzalloc(sizeof(struct synaptics_i2c), GFP_KERNEL);
+	if (!touch)
+		return NULL;
+
+	touch->client = client;
+	touch->no_decel_param = no_decel;
+	touch->scan_rate_param = scan_rate;
+	set_scan_rate(touch, scan_rate);
+	INIT_DELAYED_WORK(&touch->dwork, synaptics_i2c_work_handler);
+
+	return touch;
+}
+
+static int __devinit synaptics_i2c_probe(struct i2c_client *client,
+			       const struct i2c_device_id *dev_id)
+{
+	int ret;
+	struct synaptics_i2c *touch;
+
+	touch = synaptics_i2c_touch_create(client);
+	if (!touch)
+		return -ENOMEM;
+
+	i2c_set_clientdata(client, touch);
+
+	ret = synaptics_i2c_reset_config(client);
+	if (ret)
+		goto err_mem_free;
+
+	if (client->irq < 1)
+		polling_req = 1;
+
+	touch->input = input_allocate_device();
+	if (!touch->input) {
+		ret = -ENOMEM;
+		goto err_mem_free;
+	}
+
+	synaptics_i2c_set_input_params(touch);
+
+	if (!polling_req) {
+		dev_dbg(&touch->client->dev,
+			 "Requesting IRQ: %d\n", touch->client->irq);
+
+		ret = request_irq(touch->client->irq, synaptics_i2c_irq,
+				  IRQF_DISABLED|IRQ_TYPE_EDGE_FALLING,
+				  DRIVER_NAME, touch);
+		if (ret) {
+			dev_warn(&touch->client->dev,
+				  "IRQ request failed: %d, "
+				  "falling back to polling\n", ret);
+			polling_req = 1;
+			synaptics_i2c_reg_set(touch->client,
+					      INTERRUPT_EN_REG, 0);
+		}
+	}
+
+	if (polling_req)
+		dev_dbg(&touch->client->dev,
+			 "Using polling at rate: %d times/sec\n", scan_rate);
+
+	/* Register the device in input subsystem */
+	ret = input_register_device(touch->input);
+	if (ret) {
+		dev_err(&client->dev,
+			 "Input device register failed: %d\n", ret);
+		goto err_input_free;
+	}
+	return 0;
+
+err_input_free:
+	input_free_device(touch->input);
+err_mem_free:
+	i2c_set_clientdata(client, NULL);
+	kfree(touch);
+
+	return ret;
+}
+
+static int __devexit synaptics_i2c_remove(struct i2c_client *client)
+{
+	struct synaptics_i2c *touch = i2c_get_clientdata(client);
+
+	if (!polling_req)
+		free_irq(touch->client->irq, touch);
+
+	input_unregister_device(touch->input);
+	i2c_set_clientdata(client, NULL);
+	kfree(touch);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int synaptics_i2c_suspend(struct i2c_client *client, pm_message_t mesg)
+{
+	struct synaptics_i2c *touch = i2c_get_clientdata(client);
+
+	cancel_delayed_work_sync(&touch->dwork);
+
+	/* Save some power */
+	synaptics_i2c_reg_set(touch->client, DEV_CONTROL_REG, DEEP_SLEEP);
+
+	return 0;
+}
+
+static int synaptics_i2c_resume(struct i2c_client *client)
+{
+	int ret;
+	struct synaptics_i2c *touch = i2c_get_clientdata(client);
+
+	ret = synaptics_i2c_reset_config(client);
+	if (ret)
+		return ret;
+
+	schedule_delayed_work(&touch->dwork,
+			       msecs_to_jiffies(NO_DATA_SLEEP_MSECS));
+
+	return 0;
+}
+#else
+#define synaptics_i2c_suspend	NULL
+#define synaptics_i2c_resume	NULL
+#endif
+
+static const struct i2c_device_id synaptics_i2c_id_table[] = {
+	{ "synaptics_i2c", 0 },
+	{ },
+};
+MODULE_DEVICE_TABLE(i2c, synaptics_i2c_id_table);
+
+static struct i2c_driver synaptics_i2c_driver = {
+	.driver = {
+		.name	= DRIVER_NAME,
+		.owner	= THIS_MODULE,
+	},
+
+	.probe		= synaptics_i2c_probe,
+	.remove		= __devexit_p(synaptics_i2c_remove),
+
+	.suspend	= synaptics_i2c_suspend,
+	.resume		= synaptics_i2c_resume,
+	.id_table	= synaptics_i2c_id_table,
+};
+
+static int __init synaptics_i2c_init(void)
+{
+	return i2c_add_driver(&synaptics_i2c_driver);
+}
+
+static void __exit synaptics_i2c_exit(void)
+{
+	i2c_del_driver(&synaptics_i2c_driver);
+}
+
+module_init(synaptics_i2c_init);
+module_exit(synaptics_i2c_exit);
+
+MODULE_DESCRIPTION("Synaptics I2C touchpad driver");
+MODULE_AUTHOR("Mike Rapoport, Igor Grinberg, Compulab");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c
index 17fd6d4..966b886 100644
--- a/drivers/input/mousedev.c
+++ b/drivers/input/mousedev.c
@@ -60,7 +60,6 @@
 	int exist;
 	int open;
 	int minor;
-	char name[16];
 	struct input_handle handle;
 	wait_queue_head_t wait;
 	struct list_head client_list;
@@ -863,19 +862,17 @@
 	init_waitqueue_head(&mousedev->wait);
 
 	if (minor == MOUSEDEV_MIX)
-		strlcpy(mousedev->name, "mice", sizeof(mousedev->name));
+		dev_set_name(&mousedev->dev, "mice");
 	else
-		snprintf(mousedev->name, sizeof(mousedev->name),
-			 "mouse%d", minor);
+		dev_set_name(&mousedev->dev, "mouse%d", minor);
 
 	mousedev->minor = minor;
 	mousedev->exist = 1;
 	mousedev->handle.dev = input_get_device(dev);
-	mousedev->handle.name = mousedev->name;
+	mousedev->handle.name = dev_name(&mousedev->dev);
 	mousedev->handle.handler = handler;
 	mousedev->handle.private = mousedev;
 
-	dev_set_name(&mousedev->dev, mousedev->name);
 	mousedev->dev.class = &input_class;
 	if (dev)
 		mousedev->dev.parent = &dev->dev;
diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c
index 3cffb70..f919bf5 100644
--- a/drivers/input/serio/i8042.c
+++ b/drivers/input/serio/i8042.c
@@ -10,6 +10,7 @@
  * the Free Software Foundation.
  */
 
+#include <linux/types.h>
 #include <linux/delay.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
@@ -921,6 +922,9 @@
 #endif
 
 #ifdef CONFIG_PM
+
+static bool i8042_suspended;
+
 /*
  * Here we try to restore the original BIOS settings. We only want to
  * do that once, when we really suspend, not when we taking memory
@@ -930,11 +934,9 @@
 
 static int i8042_suspend(struct platform_device *dev, pm_message_t state)
 {
-	if (dev->dev.power.power_state.event != state.event) {
-		if (state.event == PM_EVENT_SUSPEND)
-			i8042_controller_reset();
-
-		dev->dev.power.power_state = state;
+	if (!i8042_suspended && state.event == PM_EVENT_SUSPEND) {
+		i8042_controller_reset();
+		i8042_suspended = true;
 	}
 
 	return 0;
@@ -952,7 +954,7 @@
 /*
  * Do not bother with restoring state if we haven't suspened yet
  */
-	if (dev->dev.power.power_state.event == PM_EVENT_ON)
+	if (!i8042_suspended)
 		return 0;
 
 	error = i8042_controller_check();
@@ -998,10 +1000,9 @@
 	if (i8042_ports[I8042_KBD_PORT_NO].serio)
 		i8042_enable_kbd_port();
 
+	i8042_suspended = false;
 	i8042_interrupt(0, NULL);
 
-	dev->dev.power.power_state = PMSG_ON;
-
 	return 0;
 }
 #endif /* CONFIG_PM */
diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c
index bc03325..fb17573 100644
--- a/drivers/input/serio/serio.c
+++ b/drivers/input/serio/serio.c
@@ -41,17 +41,6 @@
 MODULE_DESCRIPTION("Serio abstraction core");
 MODULE_LICENSE("GPL");
 
-EXPORT_SYMBOL(serio_interrupt);
-EXPORT_SYMBOL(__serio_register_port);
-EXPORT_SYMBOL(serio_unregister_port);
-EXPORT_SYMBOL(serio_unregister_child_port);
-EXPORT_SYMBOL(__serio_register_driver);
-EXPORT_SYMBOL(serio_unregister_driver);
-EXPORT_SYMBOL(serio_open);
-EXPORT_SYMBOL(serio_close);
-EXPORT_SYMBOL(serio_rescan);
-EXPORT_SYMBOL(serio_reconnect);
-
 /*
  * serio_mutex protects entire serio subsystem and is taken every time
  * serio port or driver registrered or unregistered.
@@ -506,9 +495,9 @@
 
 	retval = count;
 	if (!strncmp(buf, "manual", count)) {
-		serio->manual_bind = 1;
+		serio->manual_bind = true;
 	} else if (!strncmp(buf, "auto", count)) {
-		serio->manual_bind = 0;
+		serio->manual_bind = false;
 	} else {
 		retval = -EINVAL;
 	}
@@ -581,7 +570,7 @@
 			"serio: device_add() failed for %s (%s), error: %d\n",
 			serio->phys, serio->name, error);
 	else {
-		serio->registered = 1;
+		serio->registered = true;
 		error = sysfs_create_group(&serio->dev.kobj, &serio_id_attr_group);
 		if (error)
 			printk(KERN_ERR
@@ -617,7 +606,7 @@
 	if (serio->registered) {
 		sysfs_remove_group(&serio->dev.kobj, &serio_id_attr_group);
 		device_del(&serio->dev);
-		serio->registered = 0;
+		serio->registered = false;
 	}
 
 	list_del_init(&serio->node);
@@ -692,11 +681,13 @@
 {
 	serio_queue_event(serio, NULL, SERIO_RESCAN_PORT);
 }
+EXPORT_SYMBOL(serio_rescan);
 
 void serio_reconnect(struct serio *serio)
 {
 	serio_queue_event(serio, NULL, SERIO_RECONNECT_CHAIN);
 }
+EXPORT_SYMBOL(serio_reconnect);
 
 /*
  * Submits register request to kseriod for subsequent execution.
@@ -707,6 +698,7 @@
 	serio_init_port(serio);
 	serio_queue_event(serio, owner, SERIO_REGISTER_PORT);
 }
+EXPORT_SYMBOL(__serio_register_port);
 
 /*
  * Synchronously unregisters serio port.
@@ -718,6 +710,7 @@
 	serio_destroy_port(serio);
 	mutex_unlock(&serio_mutex);
 }
+EXPORT_SYMBOL(serio_unregister_port);
 
 /*
  * Safely unregisters child port if one is present.
@@ -731,6 +724,7 @@
 	}
 	mutex_unlock(&serio_mutex);
 }
+EXPORT_SYMBOL(serio_unregister_child_port);
 
 
 /*
@@ -756,9 +750,9 @@
 
 	retval = count;
 	if (!strncmp(buf, "manual", count)) {
-		serio_drv->manual_bind = 1;
+		serio_drv->manual_bind = true;
 	} else if (!strncmp(buf, "auto", count)) {
-		serio_drv->manual_bind = 0;
+		serio_drv->manual_bind = false;
 	} else {
 		retval = -EINVAL;
 	}
@@ -818,7 +812,7 @@
 
 int __serio_register_driver(struct serio_driver *drv, struct module *owner, const char *mod_name)
 {
-	int manual_bind = drv->manual_bind;
+	bool manual_bind = drv->manual_bind;
 	int error;
 
 	drv->driver.bus = &serio_bus;
@@ -829,7 +823,7 @@
 	 * Temporarily disable automatic binding because probing
 	 * takes long time and we are better off doing it in kseriod
 	 */
-	drv->manual_bind = 1;
+	drv->manual_bind = true;
 
 	error = driver_register(&drv->driver);
 	if (error) {
@@ -844,7 +838,7 @@
 	 * driver to free ports
 	 */
 	if (!manual_bind) {
-		drv->manual_bind = 0;
+		drv->manual_bind = false;
 		error = serio_queue_event(drv, NULL, SERIO_ATTACH_DRIVER);
 		if (error) {
 			driver_unregister(&drv->driver);
@@ -854,6 +848,7 @@
 
 	return 0;
 }
+EXPORT_SYMBOL(__serio_register_driver);
 
 void serio_unregister_driver(struct serio_driver *drv)
 {
@@ -861,7 +856,7 @@
 
 	mutex_lock(&serio_mutex);
 
-	drv->manual_bind = 1;	/* so serio_find_driver ignores it */
+	drv->manual_bind = true;	/* so serio_find_driver ignores it */
 	serio_remove_pending_events(drv);
 
 start_over:
@@ -877,6 +872,7 @@
 	driver_unregister(&drv->driver);
 	mutex_unlock(&serio_mutex);
 }
+EXPORT_SYMBOL(serio_unregister_driver);
 
 static void serio_set_drv(struct serio *serio, struct serio_driver *drv)
 {
@@ -937,11 +933,11 @@
 #ifdef CONFIG_PM
 static int serio_suspend(struct device *dev, pm_message_t state)
 {
-	if (dev->power.power_state.event != state.event) {
-		if (state.event == PM_EVENT_SUSPEND)
-			serio_cleanup(to_serio_port(dev));
+	struct serio *serio = to_serio_port(dev);
 
-		dev->power.power_state = state;
+	if (!serio->suspended && state.event == PM_EVENT_SUSPEND) {
+		serio_cleanup(serio);
+		serio->suspended = true;
 	}
 
 	return 0;
@@ -949,14 +945,15 @@
 
 static int serio_resume(struct device *dev)
 {
+	struct serio *serio = to_serio_port(dev);
+
 	/*
 	 * Driver reconnect can take a while, so better let kseriod
 	 * deal with it.
 	 */
-	if (dev->power.power_state.event != PM_EVENT_ON) {
-		dev->power.power_state = PMSG_ON;
-		serio_queue_event(to_serio_port(dev), NULL,
-				  SERIO_RECONNECT_PORT);
+	if (serio->suspended) {
+		serio->suspended = false;
+		serio_queue_event(serio, NULL, SERIO_RECONNECT_PORT);
 	}
 
 	return 0;
@@ -974,6 +971,7 @@
 	}
 	return 0;
 }
+EXPORT_SYMBOL(serio_open);
 
 /* called from serio_driver->connect/disconnect methods under serio_mutex */
 void serio_close(struct serio *serio)
@@ -983,6 +981,7 @@
 
 	serio_set_drv(serio, NULL);
 }
+EXPORT_SYMBOL(serio_close);
 
 irqreturn_t serio_interrupt(struct serio *serio,
 		unsigned char data, unsigned int dfl)
@@ -1003,6 +1002,7 @@
 
 	return ret;
 }
+EXPORT_SYMBOL(serio_interrupt);
 
 static struct bus_type serio_bus = {
 	.name		= "serio",
diff --git a/drivers/input/tablet/gtco.c b/drivers/input/tablet/gtco.c
index 2e18a1c..3d32d3f 100644
--- a/drivers/input/tablet/gtco.c
+++ b/drivers/input/tablet/gtco.c
@@ -1050,4 +1050,5 @@
 module_init(gtco_init);
 module_exit(gtco_exit);
 
+MODULE_DESCRIPTION("GTCO digitizer USB driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/input/tablet/wacom.h b/drivers/input/tablet/wacom.h
index 9710bfd..9114ae1 100644
--- a/drivers/input/tablet/wacom.h
+++ b/drivers/input/tablet/wacom.h
@@ -68,6 +68,7 @@
  *      v1.48 (pc) - Added support for Bamboo1, BambooFun, and Cintiq 12WX
  *      v1.49 (pc) - Added support for USB Tablet PC (0x90, 0x93, and 0x9A)
  *      v1.50 (pc) - Fixed a TabletPC touch bug in 2.6.28
+ *      v1.51 (pc) - Added support for Intuos4
  */
 
 /*
@@ -88,7 +89,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v1.50"
+#define DRIVER_VERSION "v1.51"
 #define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@ucw.cz>"
 #define DRIVER_DESC "USB Wacom Graphire and Wacom Intuos tablet driver"
 #define DRIVER_LICENSE "GPL"
@@ -128,6 +129,8 @@
 extern void input_dev_i3s(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
 extern void input_dev_i3(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
 extern void input_dev_i(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
+extern void input_dev_i4s(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
+extern void input_dev_i4(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
 extern void input_dev_pl(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
 extern void input_dev_pt(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
 extern void input_dev_mo(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
diff --git a/drivers/input/tablet/wacom_sys.c b/drivers/input/tablet/wacom_sys.c
index b8624f2..a9d5031 100644
--- a/drivers/input/tablet/wacom_sys.c
+++ b/drivers/input/tablet/wacom_sys.c
@@ -229,6 +229,19 @@
 	input_set_abs_params(input_dev, ABS_RY, 0, 4096, 0, 0);
 }
 
+void input_dev_i4s(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
+{
+	input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_FINGER);
+	input_dev->keybit[BIT_WORD(BTN_MISC)] |= BIT_MASK(BTN_0) | BIT_MASK(BTN_1) | BIT_MASK(BTN_2) | BIT_MASK(BTN_3);
+	input_dev->keybit[BIT_WORD(BTN_MISC)] |= BIT_MASK(BTN_4) | BIT_MASK(BTN_5) | BIT_MASK(BTN_6);
+	input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
+}
+
+void input_dev_i4(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
+{
+	input_dev->keybit[BIT_WORD(BTN_MISC)] |= BIT_MASK(BTN_7) | BIT_MASK(BTN_8);
+}
+
 void input_dev_bee(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
 {
 	input_dev->keybit[BIT_WORD(BTN_MISC)] |= BIT_MASK(BTN_8) | BIT_MASK(BTN_9);
diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c
index 2638811..38bf863 100644
--- a/drivers/input/tablet/wacom_wac.c
+++ b/drivers/input/tablet/wacom_wac.c
@@ -283,10 +283,11 @@
 static int wacom_intuos_inout(struct wacom_wac *wacom, void *wcombo)
 {
 	unsigned char *data = wacom->data;
-	int idx;
+	int idx = 0;
 
 	/* tool number */
-	idx = data[1] & 0x01;
+	if (wacom->features->type == INTUOS)
+		idx = data[1] & 0x01;
 
 	/* Enter report */
 	if ((data[1] & 0xfc) == 0xc0) {
@@ -299,6 +300,7 @@
 		switch (wacom->id[idx]) {
 			case 0x812: /* Inking pen */
 			case 0x801: /* Intuos3 Inking pen */
+			case 0x20802: /* Intuos4 Classic Pen */
 			case 0x012:
 				wacom->tool[idx] = BTN_TOOL_PENCIL;
 				break;
@@ -308,6 +310,9 @@
 			case 0x823: /* Intuos3 Grip Pen */
 			case 0x813: /* Intuos3 Classic Pen */
 			case 0x885: /* Intuos3 Marker Pen */
+			case 0x802: /* Intuos4 Grip Pen Eraser */
+			case 0x804: /* Intuos4 Marker Pen */
+			case 0x40802: /* Intuos4 Classic Pen */
 			case 0x022:
 				wacom->tool[idx] = BTN_TOOL_PEN;
 				break;
@@ -319,10 +324,12 @@
 		        case 0x09c:
 			case 0x094:
 			case 0x017: /* Intuos3 2D Mouse */
+			case 0x806: /* Intuos4 Mouse */
 				wacom->tool[idx] = BTN_TOOL_MOUSE;
 				break;
 			case 0x096: /* Lens cursor */
 			case 0x097: /* Intuos3 Lens cursor */
+			case 0x006: /* Intuos4 Lens cursor */
 				wacom->tool[idx] = BTN_TOOL_LENS;
 				break;
 			case 0x82a: /* Eraser */
@@ -333,12 +340,17 @@
 			case 0x82b: /* Intuos3 Grip Pen Eraser */
 			case 0x81b: /* Intuos3 Classic Pen Eraser */
 			case 0x91b: /* Intuos3 Airbrush Eraser */
+			case 0x80c: /* Intuos4 Marker Pen Eraser */
+			case 0x80a: /* Intuos4 Grip Pen Eraser */
+			case 0x4080a: /* Intuos4 Classic Pen Eraser */
+			case 0x90a: /* Intuos4 Airbrush Eraser */
 				wacom->tool[idx] = BTN_TOOL_RUBBER;
 				break;
 			case 0xd12:
 			case 0x912:
 			case 0x112:
 			case 0x913: /* Intuos3 Airbrush */
+			case 0x902: /* Intuos4 Airbrush */
 				wacom->tool[idx] = BTN_TOOL_AIRBRUSH;
 				break;
 			default: /* Unknown tool */
@@ -349,9 +361,15 @@
 
 	/* Exit report */
 	if ((data[1] & 0xfe) == 0x80) {
+		/*
+		 * Reset all states otherwise we lose the initial states
+		 * when in-prox next time
+		 */
 		wacom_report_abs(wcombo, ABS_X, 0);
 		wacom_report_abs(wcombo, ABS_Y, 0);
 		wacom_report_abs(wcombo, ABS_DISTANCE, 0);
+		wacom_report_abs(wcombo, ABS_TILT_X, 0);
+		wacom_report_abs(wcombo, ABS_TILT_Y, 0);
 		if (wacom->tool[idx] >= BTN_TOOL_MOUSE) {
 			wacom_report_key(wcombo, BTN_LEFT, 0);
 			wacom_report_key(wcombo, BTN_MIDDLE, 0);
@@ -362,8 +380,6 @@
 			wacom_report_abs(wcombo, ABS_RZ, 0);
 		} else {
 			wacom_report_abs(wcombo, ABS_PRESSURE, 0);
-			wacom_report_abs(wcombo, ABS_TILT_X, 0);
-			wacom_report_abs(wcombo, ABS_TILT_Y, 0);
 			wacom_report_key(wcombo, BTN_STYLUS, 0);
 			wacom_report_key(wcombo, BTN_STYLUS2, 0);
 			wacom_report_key(wcombo, BTN_TOUCH, 0);
@@ -372,6 +388,7 @@
 		wacom_report_key(wcombo, wacom->tool[idx], 0);
 		wacom_report_abs(wcombo, ABS_MISC, 0); /* reset tool id */
 		wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, wacom->serial[idx]);
+		wacom->id[idx] = 0;
 		return 2;
 	}
 	return 0;
@@ -385,6 +402,8 @@
 	/* general pen packet */
 	if ((data[1] & 0xb8) == 0xa0) {
 		t = (data[6] << 2) | ((data[7] >> 6) & 3);
+		if (wacom->features->type >= INTUOS4S && wacom->features->type <= INTUOS4L)
+			t = (t << 1) | (data[1] & 1);
 		wacom_report_abs(wcombo, ABS_PRESSURE, t);
 		wacom_report_abs(wcombo, ABS_TILT_X,
 				((data[7] << 1) & 0x7e) | (data[8] >> 7));
@@ -409,7 +428,7 @@
 {
 	unsigned char *data = wacom->data;
 	unsigned int t;
-	int idx, result;
+	int idx = 0, result;
 
 	if (data[0] != 2 && data[0] != 5 && data[0] != 6 && data[0] != 12) {
 		dbg("wacom_intuos_irq: received unknown report #%d", data[0]);
@@ -417,7 +436,8 @@
 	}
 
 	/* tool number */
-	idx = data[1] & 0x01;
+	if (wacom->features->type == INTUOS)
+		idx = data[1] & 0x01;
 
 	/* pad packets. Works as a second tool and is always in prox */
 	if (data[0] == 12) {
@@ -425,25 +445,54 @@
 		if (wacom->tool[1] != BTN_TOOL_FINGER)
 			wacom->tool[1] = BTN_TOOL_FINGER;
 
-		wacom_report_key(wcombo, BTN_0, (data[5] & 0x01));
-		wacom_report_key(wcombo, BTN_1, (data[5] & 0x02));
-		wacom_report_key(wcombo, BTN_2, (data[5] & 0x04));
-		wacom_report_key(wcombo, BTN_3, (data[5] & 0x08));
-		wacom_report_key(wcombo, BTN_4, (data[6] & 0x01));
-		wacom_report_key(wcombo, BTN_5, (data[6] & 0x02));
-		wacom_report_key(wcombo, BTN_6, (data[6] & 0x04));
-		wacom_report_key(wcombo, BTN_7, (data[6] & 0x08));
-		wacom_report_key(wcombo, BTN_8, (data[5] & 0x10));
-		wacom_report_key(wcombo, BTN_9, (data[6] & 0x10));
-		wacom_report_abs(wcombo, ABS_RX, ((data[1] & 0x1f) << 8) | data[2]);
-		wacom_report_abs(wcombo, ABS_RY, ((data[3] & 0x1f) << 8) | data[4]);
+		if (wacom->features->type >= INTUOS4S && wacom->features->type <= INTUOS4L) {
+			wacom_report_key(wcombo, BTN_0, (data[2] & 0x01));
+			wacom_report_key(wcombo, BTN_1, (data[3] & 0x01));
+			wacom_report_key(wcombo, BTN_2, (data[3] & 0x02));
+			wacom_report_key(wcombo, BTN_3, (data[3] & 0x04));
+			wacom_report_key(wcombo, BTN_4, (data[3] & 0x08));
+			wacom_report_key(wcombo, BTN_5, (data[3] & 0x10));
+			wacom_report_key(wcombo, BTN_6, (data[3] & 0x20));
+			if (data[1] & 0x80) {
+				wacom_report_abs(wcombo, ABS_WHEEL, (data[1] & 0x7f));
+			} else {
+				/* Out of proximity, clear wheel value. */
+				wacom_report_abs(wcombo, ABS_WHEEL, 0);
+			}
+			if (wacom->features->type != INTUOS4S) {
+				wacom_report_key(wcombo, BTN_7, (data[3] & 0x40));
+				wacom_report_key(wcombo, BTN_8, (data[3] & 0x80));
+			}
+			if (data[1] | (data[2] & 0x01) | data[3]) {
+				wacom_report_key(wcombo, wacom->tool[1], 1);
+				wacom_report_abs(wcombo, ABS_MISC, PAD_DEVICE_ID);
+			} else {
+				wacom_report_key(wcombo, wacom->tool[1], 0);
+				wacom_report_abs(wcombo, ABS_MISC, 0);
+			}
+		} else {
+			wacom_report_key(wcombo, BTN_0, (data[5] & 0x01));
+			wacom_report_key(wcombo, BTN_1, (data[5] & 0x02));
+			wacom_report_key(wcombo, BTN_2, (data[5] & 0x04));
+			wacom_report_key(wcombo, BTN_3, (data[5] & 0x08));
+			wacom_report_key(wcombo, BTN_4, (data[6] & 0x01));
+			wacom_report_key(wcombo, BTN_5, (data[6] & 0x02));
+			wacom_report_key(wcombo, BTN_6, (data[6] & 0x04));
+			wacom_report_key(wcombo, BTN_7, (data[6] & 0x08));
+			wacom_report_key(wcombo, BTN_8, (data[5] & 0x10));
+			wacom_report_key(wcombo, BTN_9, (data[6] & 0x10));
+			wacom_report_abs(wcombo, ABS_RX, ((data[1] & 0x1f) << 8) | data[2]);
+			wacom_report_abs(wcombo, ABS_RY, ((data[3] & 0x1f) << 8) | data[4]);
 
-		if ((data[5] & 0x1f) | (data[6] & 0x1f) | (data[1] & 0x1f) |
-			data[2] | (data[3] & 0x1f) | data[4])
-			wacom_report_key(wcombo, wacom->tool[1], 1);
-		else
-			wacom_report_key(wcombo, wacom->tool[1], 0);
-		wacom_report_abs(wcombo, ABS_MISC, PAD_DEVICE_ID);
+			if ((data[5] & 0x1f) | (data[6] & 0x1f) | (data[1] & 0x1f) |
+				data[2] | (data[3] & 0x1f) | data[4]) {
+				wacom_report_key(wcombo, wacom->tool[1], 1);
+				wacom_report_abs(wcombo, ABS_MISC, PAD_DEVICE_ID);
+			} else {
+				wacom_report_key(wcombo, wacom->tool[1], 0);
+				wacom_report_abs(wcombo, ABS_MISC, 0);
+			}
+		}
 		wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, 0xffffffff);
                 return 1;
 	}
@@ -453,10 +502,16 @@
 	if (result)
                 return result-1;
 
-	/* Only large I3 and I1 & I2 support Lense Cursor */
+	/* don't proceed if we don't know the ID */
+	if (!wacom->id[idx])
+		return 0;
+
+	/* Only large Intuos support Lense Cursor */
 	if ((wacom->tool[idx] == BTN_TOOL_LENS)
 			&& ((wacom->features->type == INTUOS3)
-			|| (wacom->features->type == INTUOS3S)))
+			|| (wacom->features->type == INTUOS3S)
+			|| (wacom->features->type == INTUOS4)
+			|| (wacom->features->type == INTUOS4S)))
 		return 0;
 
 	/* Cintiq doesn't send data when RDY bit isn't set */
@@ -476,8 +531,8 @@
 	/* process general packets */
 	wacom_intuos_general(wacom, wcombo);
 
-	/* 4D mouse, 2D mouse, marker pen rotation, or Lens cursor packets */
-	if ((data[1] & 0xbc) == 0xa8 || (data[1] & 0xbe) == 0xb0) {
+	/* 4D mouse, 2D mouse, marker pen rotation, tilt mouse, or Lens cursor packets */
+	if ((data[1] & 0xbc) == 0xa8 || (data[1] & 0xbe) == 0xb0 || (data[1] & 0xbc) == 0xac) {
 
 		if (data[1] & 0x02) {
 			/* Rotation packet */
@@ -506,20 +561,36 @@
 			wacom_report_abs(wcombo, ABS_THROTTLE, (data[8] & 0x08) ? -t : t);
 
 		} else if (wacom->tool[idx] == BTN_TOOL_MOUSE) {
-			/* 2D mouse packet */
-			wacom_report_key(wcombo, BTN_LEFT,   data[8] & 0x04);
-			wacom_report_key(wcombo, BTN_MIDDLE, data[8] & 0x08);
-			wacom_report_key(wcombo, BTN_RIGHT,  data[8] & 0x10);
-			wacom_report_rel(wcombo, REL_WHEEL, (data[8] & 0x01)
+			/* I4 mouse */
+			if (wacom->features->type >= INTUOS4S && wacom->features->type <= INTUOS4L) {
+				wacom_report_key(wcombo, BTN_LEFT,   data[6] & 0x01);
+				wacom_report_key(wcombo, BTN_MIDDLE, data[6] & 0x02);
+				wacom_report_key(wcombo, BTN_RIGHT,  data[6] & 0x04);
+				wacom_report_rel(wcombo, REL_WHEEL, ((data[7] & 0x80) >> 7)
+						 - ((data[7] & 0x40) >> 6));
+				wacom_report_key(wcombo, BTN_SIDE,   data[6] & 0x08);
+				wacom_report_key(wcombo, BTN_EXTRA,  data[6] & 0x10);
+
+				wacom_report_abs(wcombo, ABS_TILT_X,
+					((data[7] << 1) & 0x7e) | (data[8] >> 7));
+				wacom_report_abs(wcombo, ABS_TILT_Y, data[8] & 0x7f);
+			} else {
+				/* 2D mouse packet */
+				wacom_report_key(wcombo, BTN_LEFT,   data[8] & 0x04);
+				wacom_report_key(wcombo, BTN_MIDDLE, data[8] & 0x08);
+				wacom_report_key(wcombo, BTN_RIGHT,  data[8] & 0x10);
+				wacom_report_rel(wcombo, REL_WHEEL, (data[8] & 0x01)
 						 - ((data[8] & 0x02) >> 1));
 
-			/* I3 2D mouse side buttons */
-			if (wacom->features->type >= INTUOS3S && wacom->features->type <= INTUOS3L) {
-				wacom_report_key(wcombo, BTN_SIDE,   data[8] & 0x40);
-				wacom_report_key(wcombo, BTN_EXTRA,  data[8] & 0x20);
+				/* I3 2D mouse side buttons */
+				if (wacom->features->type >= INTUOS3S && wacom->features->type <= INTUOS3L) {
+					wacom_report_key(wcombo, BTN_SIDE,   data[8] & 0x40);
+					wacom_report_key(wcombo, BTN_EXTRA,  data[8] & 0x20);
+				}
 			}
-
-		} else if (wacom->features->type < INTUOS3S || wacom->features->type == INTUOS3L) {
+		} else if ((wacom->features->type < INTUOS3S || wacom->features->type == INTUOS3L ||
+				wacom->features->type == INTUOS4L) &&
+			   wacom->tool[idx] == BTN_TOOL_LENS) {
 			/* Lens cursor packets */
 			wacom_report_key(wcombo, BTN_LEFT,   data[8] & 0x01);
 			wacom_report_key(wcombo, BTN_MIDDLE, data[8] & 0x02);
@@ -581,6 +652,7 @@
 			}
 		} else if (touchOut || !prox) { /* force touch out-prox */
 			wacom_report_abs(wcombo, ABS_MISC, TOUCH_DEVICE_ID);
+			wacom_report_key(wcombo, wacom->tool[1], 0);
 			wacom_report_key(wcombo, BTN_TOUCH, 0);
 			touchOut = 0;
 			touchInProx = 1;
@@ -669,6 +741,9 @@
 		case INTUOS3S:
 		case INTUOS3:
 		case INTUOS3L:
+		case INTUOS4S:
+		case INTUOS4:
+		case INTUOS4L:
 		case CINTIQ:
 		case WACOM_BEE:
 			return wacom_intuos_irq(wacom_wac, wcombo);
@@ -706,6 +781,14 @@
 		case INTUOS:
 			input_dev_i(input_dev, wacom_wac);
 			break;
+		case INTUOS4:
+		case INTUOS4L:
+			input_dev_i4(input_dev, wacom_wac);
+			/* fall through */
+		case INTUOS4S:
+			input_dev_i4s(input_dev, wacom_wac);
+			input_dev_i(input_dev, wacom_wac);
+			break;
 		case PL:
 		case PTU:
 		case TABLETPC:
@@ -766,6 +849,10 @@
 	{ "Wacom Intuos3 12x19", 10, 97536, 60960, 1023, 63, INTUOS3L },
 	{ "Wacom Intuos3 6x11",  10, 54204, 31750, 1023, 63, INTUOS3 },
 	{ "Wacom Intuos3 4x6",   10, 31496, 19685, 1023, 63, INTUOS3S },
+	{ "Wacom Intuos4 4x6",   10, 31496, 19685, 2047, 63, INTUOS4S },
+	{ "Wacom Intuos4 6x9",   10, 44704, 27940, 2047, 63, INTUOS4 },
+	{ "Wacom Intuos4 8x13",  10, 65024, 40640, 2047, 63, INTUOS4L },
+	{ "Wacom Intuos4 12x19", 10, 97536, 60960, 2047, 63, INTUOS4L },
 	{ "Wacom Cintiq 21UX",   10, 87200, 65600, 1023, 63, CINTIQ },
 	{ "Wacom Cintiq 20WSX",  10, 86680, 54180, 1023, 63, WACOM_BEE },
 	{ "Wacom Cintiq 12WX",   10, 53020, 33440, 1023, 63, WACOM_BEE },
@@ -825,6 +912,10 @@
 	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB4) },
 	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB5) },
 	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB7) },
+	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB8) },
+	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB9) },
+	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0xBA) },
+	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0xBB) },
 	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x3F) },
 	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0xC5) },
 	{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0xC6) },
diff --git a/drivers/input/tablet/wacom_wac.h b/drivers/input/tablet/wacom_wac.h
index f9c8b69..c10235a 100644
--- a/drivers/input/tablet/wacom_wac.h
+++ b/drivers/input/tablet/wacom_wac.h
@@ -25,6 +25,9 @@
 	INTUOS3S,
 	INTUOS3,
 	INTUOS3L,
+	INTUOS4S,
+	INTUOS4,
+	INTUOS4L,
 	CINTIQ,
 	WACOM_BEE,
 	WACOM_MO,
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index b01fd61d..72e2712 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -111,6 +111,15 @@
 	  Say Y here to enable the support for the touchscreen found
 	  on Dialog Semiconductor DA9034 PMIC.
 
+config TOUCHSCREEN_EETI
+	tristate "EETI touchscreen panel support"
+	depends on I2C
+	help
+	  Say Y here to enable support for I2C connected EETI touch panels.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called eeti_ts.
+
 config TOUCHSCREEN_FUJITSU
 	tristate "Fujitsu serial touchscreen"
 	select SERIO
@@ -341,6 +350,21 @@
 	  Say Y here to enable support for the Wolfson Microelectronics
 	  WM9713 touchscreen controller.
 
+config TOUCHSCREEN_WM97XX_ATMEL
+	tristate "WM97xx Atmel accelerated touch"
+	depends on TOUCHSCREEN_WM97XX && (AVR32 || ARCH_AT91)
+	help
+	  Say Y here for support for streaming mode with WM97xx touchscreens
+	  on Atmel AT91 or AVR32 systems with an AC97C module.
+
+	  Be aware that this will use channel B in the controller for
+	  streaming data, this must not conflict with other AC97C drivers.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the module will
+	  be called atmel-wm97xx.
+
 config TOUCHSCREEN_WM97XX_MAINSTONE
 	tristate "WM97xx Mainstone accelerated touch"
 	depends on TOUCHSCREEN_WM97XX && ARCH_PXA
@@ -466,4 +490,12 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called tsc2007.
 
+config TOUCHSCREEN_W90X900
+	tristate "W90P910 touchscreen driver"
+	help
+	  Say Y here if you have a W90P910 based touchscreen.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called w90p910_ts.
+
 endif
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 6700f7b..3e1c5e0 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -13,6 +13,7 @@
 obj-$(CONFIG_TOUCHSCREEN_BITSY)		+= h3600_ts_input.o
 obj-$(CONFIG_TOUCHSCREEN_CORGI)		+= corgi_ts.o
 obj-$(CONFIG_TOUCHSCREEN_GUNZE)		+= gunze.o
+obj-$(CONFIG_TOUCHSCREEN_EETI)		+= eeti_ts.o
 obj-$(CONFIG_TOUCHSCREEN_ELO)		+= elo.o
 obj-$(CONFIG_TOUCHSCREEN_FUJITSU)	+= fujitsu_ts.o
 obj-$(CONFIG_TOUCHSCREEN_INEXIO)	+= inexio.o
@@ -35,5 +36,7 @@
 wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9705)	+= wm9705.o
 wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9712)	+= wm9712.o
 wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9713)	+= wm9713.o
+obj-$(CONFIG_TOUCHSCREEN_WM97XX_ATMEL)	+= atmel-wm97xx.o
 obj-$(CONFIG_TOUCHSCREEN_WM97XX_MAINSTONE)	+= mainstone-wm97xx.o
 obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE)	+= zylonite-wm97xx.o
+obj-$(CONFIG_TOUCHSCREEN_W90X900)	+= w90p910_ts.o
diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c
index 2b01e56..ba9d38c 100644
--- a/drivers/input/touchscreen/ads7846.c
+++ b/drivers/input/touchscreen/ads7846.c
@@ -83,6 +83,7 @@
 struct ads7846 {
 	struct input_dev	*input;
 	char			phys[32];
+	char			name[32];
 
 	struct spi_device	*spi;
 
@@ -97,6 +98,8 @@
 	u16			x_plate_ohms;
 	u16			pressure_max;
 
+	bool			swap_xy;
+
 	struct ads7846_packet	*packet;
 
 	struct spi_transfer	xfer[18];
@@ -599,6 +602,10 @@
 			dev_dbg(&ts->spi->dev, "DOWN\n");
 #endif
 		}
+
+		if (ts->swap_xy)
+			swap(x, y);
+
 		input_report_abs(input, ABS_X, x);
 		input_report_abs(input, ABS_Y, y);
 		input_report_abs(input, ABS_PRESSURE, Rt);
@@ -917,6 +924,7 @@
 	ts->spi = spi;
 	ts->input = input_dev;
 	ts->vref_mv = pdata->vref_mv;
+	ts->swap_xy = pdata->swap_xy;
 
 	hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
 	ts->timer.function = ads7846_timer;
@@ -958,8 +966,9 @@
 	ts->wait_for_sync = pdata->wait_for_sync ? : null_wait_for_sync;
 
 	snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(&spi->dev));
+	snprintf(ts->name, sizeof(ts->name), "ADS%d Touchscreen", ts->model);
 
-	input_dev->name = "ADS784x Touchscreen";
+	input_dev->name = ts->name;
 	input_dev->phys = ts->phys;
 	input_dev->dev.parent = &spi->dev;
 
@@ -1141,9 +1150,15 @@
 
 	if (request_irq(spi->irq, ads7846_irq, IRQF_TRIGGER_FALLING,
 			spi->dev.driver->name, ts)) {
-		dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq);
-		err = -EBUSY;
-		goto err_free_gpio;
+		dev_info(&spi->dev,
+			"trying pin change workaround on irq %d\n", spi->irq);
+		err = request_irq(spi->irq, ads7846_irq,
+				  IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
+				  spi->dev.driver->name, ts);
+		if (err) {
+			dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq);
+			goto err_free_gpio;
+		}
 	}
 
 	err = ads784x_hwmon_register(spi, ts);
diff --git a/drivers/input/touchscreen/atmel-wm97xx.c b/drivers/input/touchscreen/atmel-wm97xx.c
new file mode 100644
index 0000000..35377f5
--- /dev/null
+++ b/drivers/input/touchscreen/atmel-wm97xx.c
@@ -0,0 +1,446 @@
+/*
+ * Atmel AT91 and AVR32 continuous touch screen driver for Wolfson WM97xx AC97
+ * codecs.
+ *
+ * Copyright (C) 2008 - 2009 Atmel Corporation
+ *
+ * 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/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/wm97xx.h>
+#include <linux/timer.h>
+#include <linux/gpio.h>
+#include <linux/io.h>
+
+#define AC97C_ICA		0x10
+#define AC97C_CBRHR		0x30
+#define AC97C_CBSR		0x38
+#define AC97C_CBMR		0x3c
+#define AC97C_IER		0x54
+#define AC97C_IDR		0x58
+
+#define AC97C_RXRDY		(1 << 4)
+#define AC97C_OVRUN		(1 << 5)
+
+#define AC97C_CMR_SIZE_20	(0 << 16)
+#define AC97C_CMR_SIZE_18	(1 << 16)
+#define AC97C_CMR_SIZE_16	(2 << 16)
+#define AC97C_CMR_SIZE_10	(3 << 16)
+#define AC97C_CMR_CEM_LITTLE	(1 << 18)
+#define AC97C_CMR_CEM_BIG	(0 << 18)
+#define AC97C_CMR_CENA		(1 << 21)
+
+#define AC97C_INT_CBEVT		(1 << 4)
+
+#define AC97C_SR_CAEVT		(1 << 3)
+
+#define AC97C_CH_MASK(slot)						\
+	(0x7 << (3 * (slot - 3)))
+#define AC97C_CH_ASSIGN(slot, channel)					\
+	(AC97C_CHANNEL_##channel << (3 * (slot - 3)))
+#define AC97C_CHANNEL_NONE	0x0
+#define AC97C_CHANNEL_B		0x2
+
+#define ac97c_writel(chip, reg, val)			\
+	__raw_writel((val), (chip)->regs + AC97C_##reg)
+#define ac97c_readl(chip, reg)				\
+	__raw_readl((chip)->regs + AC97C_##reg)
+
+#ifdef CONFIG_CPU_AT32AP700X
+#define ATMEL_WM97XX_AC97C_IOMEM	(0xfff02800)
+#define ATMEL_WM97XX_AC97C_IRQ		(29)
+#define ATMEL_WM97XX_GPIO_DEFAULT	(32+16) /* Pin 16 on port B. */
+#else
+#error Unkown CPU, this driver only supports AT32AP700X CPUs.
+#endif
+
+struct continuous {
+	u16 id;    /* codec id */
+	u8 code;   /* continuous code */
+	u8 reads;  /* number of coord reads per read cycle */
+	u32 speed; /* number of coords per second */
+};
+
+#define WM_READS(sp) ((sp / HZ) + 1)
+
+static const struct continuous cinfo[] = {
+	{WM9705_ID2, 0, WM_READS(94), 94},
+	{WM9705_ID2, 1, WM_READS(188), 188},
+	{WM9705_ID2, 2, WM_READS(375), 375},
+	{WM9705_ID2, 3, WM_READS(750), 750},
+	{WM9712_ID2, 0, WM_READS(94), 94},
+	{WM9712_ID2, 1, WM_READS(188), 188},
+	{WM9712_ID2, 2, WM_READS(375), 375},
+	{WM9712_ID2, 3, WM_READS(750), 750},
+	{WM9713_ID2, 0, WM_READS(94), 94},
+	{WM9713_ID2, 1, WM_READS(120), 120},
+	{WM9713_ID2, 2, WM_READS(154), 154},
+	{WM9713_ID2, 3, WM_READS(188), 188},
+};
+
+/* Continuous speed index. */
+static int sp_idx;
+
+/*
+ * Pen sampling frequency (Hz) in continuous mode.
+ */
+static int cont_rate = 188;
+module_param(cont_rate, int, 0);
+MODULE_PARM_DESC(cont_rate, "Sampling rate in continuous mode (Hz)");
+
+/*
+ * Pen down detection.
+ *
+ * This driver can either poll or use an interrupt to indicate a pen down
+ * event. If the irq request fails then it will fall back to polling mode.
+ */
+static int pen_int = 1;
+module_param(pen_int, int, 0);
+MODULE_PARM_DESC(pen_int, "Pen down detection (1 = interrupt, 0 = polling)");
+
+/*
+ * Pressure readback.
+ *
+ * Set to 1 to read back pen down pressure.
+ */
+static int pressure;
+module_param(pressure, int, 0);
+MODULE_PARM_DESC(pressure, "Pressure readback (1 = pressure, 0 = no pressure)");
+
+/*
+ * AC97 touch data slot.
+ *
+ * Touch screen readback data ac97 slot.
+ */
+static int ac97_touch_slot = 5;
+module_param(ac97_touch_slot, int, 0);
+MODULE_PARM_DESC(ac97_touch_slot, "Touch screen data slot AC97 number");
+
+/*
+ * GPIO line number.
+ *
+ * Set to GPIO number where the signal from the WM97xx device is hooked up.
+ */
+static int atmel_gpio_line = ATMEL_WM97XX_GPIO_DEFAULT;
+module_param(atmel_gpio_line, int, 0);
+MODULE_PARM_DESC(atmel_gpio_line, "GPIO line number connected to WM97xx");
+
+struct atmel_wm97xx {
+	struct wm97xx		*wm;
+	struct timer_list	pen_timer;
+	void __iomem		*regs;
+	unsigned long		ac97c_irq;
+	unsigned long		gpio_pen;
+	unsigned long		gpio_irq;
+	unsigned short		x;
+	unsigned short		y;
+};
+
+static irqreturn_t atmel_wm97xx_channel_b_interrupt(int irq, void *dev_id)
+{
+	struct atmel_wm97xx *atmel_wm97xx = dev_id;
+	struct wm97xx *wm = atmel_wm97xx->wm;
+	int status = ac97c_readl(atmel_wm97xx, CBSR);
+	irqreturn_t retval = IRQ_NONE;
+
+	if (status & AC97C_OVRUN) {
+		dev_dbg(&wm->touch_dev->dev, "AC97C overrun\n");
+		ac97c_readl(atmel_wm97xx, CBRHR);
+		retval = IRQ_HANDLED;
+	} else if (status & AC97C_RXRDY) {
+		u16 data;
+		u16 value;
+		u16 source;
+		u16 pen_down;
+
+		data = ac97c_readl(atmel_wm97xx, CBRHR);
+		value = data & 0x0fff;
+		source = data & WM97XX_ADCSRC_MASK;
+		pen_down = (data & WM97XX_PEN_DOWN) >> 8;
+
+		if (source == WM97XX_ADCSEL_X)
+			atmel_wm97xx->x = value;
+		if (source == WM97XX_ADCSEL_Y)
+			atmel_wm97xx->y = value;
+
+		if (!pressure && source == WM97XX_ADCSEL_Y) {
+			input_report_abs(wm->input_dev, ABS_X, atmel_wm97xx->x);
+			input_report_abs(wm->input_dev, ABS_Y, atmel_wm97xx->y);
+			input_report_key(wm->input_dev, BTN_TOUCH, pen_down);
+			input_sync(wm->input_dev);
+		} else if (pressure && source == WM97XX_ADCSEL_PRES) {
+			input_report_abs(wm->input_dev, ABS_X, atmel_wm97xx->x);
+			input_report_abs(wm->input_dev, ABS_Y, atmel_wm97xx->y);
+			input_report_abs(wm->input_dev, ABS_PRESSURE, value);
+			input_report_key(wm->input_dev, BTN_TOUCH, value);
+			input_sync(wm->input_dev);
+		}
+
+		retval = IRQ_HANDLED;
+	}
+
+	return retval;
+}
+
+static void atmel_wm97xx_acc_pen_up(struct wm97xx *wm)
+{
+	struct atmel_wm97xx *atmel_wm97xx = platform_get_drvdata(wm->touch_dev);
+	struct input_dev *input_dev = wm->input_dev;
+	int pen_down = gpio_get_value(atmel_wm97xx->gpio_pen);
+
+	if (pen_down != 0) {
+		mod_timer(&atmel_wm97xx->pen_timer,
+			  jiffies + msecs_to_jiffies(1));
+	} else {
+		if (pressure)
+			input_report_abs(input_dev, ABS_PRESSURE, 0);
+		input_report_key(input_dev, BTN_TOUCH, 0);
+		input_sync(input_dev);
+	}
+}
+
+static void atmel_wm97xx_pen_timer(unsigned long data)
+{
+	atmel_wm97xx_acc_pen_up((struct wm97xx *)data);
+}
+
+static int atmel_wm97xx_acc_startup(struct wm97xx *wm)
+{
+	struct atmel_wm97xx *atmel_wm97xx = platform_get_drvdata(wm->touch_dev);
+	int idx = 0;
+
+	if (wm->ac97 == NULL)
+		return -ENODEV;
+
+	for (idx = 0; idx < ARRAY_SIZE(cinfo); idx++) {
+		if (wm->id != cinfo[idx].id)
+			continue;
+
+		sp_idx = idx;
+
+		if (cont_rate <= cinfo[idx].speed)
+			break;
+	}
+
+	wm->acc_rate = cinfo[sp_idx].code;
+	wm->acc_slot = ac97_touch_slot;
+	dev_info(&wm->touch_dev->dev, "atmel accelerated touchscreen driver, "
+			"%d samples/sec\n", cinfo[sp_idx].speed);
+
+	if (pen_int) {
+		unsigned long reg;
+
+		wm->pen_irq = atmel_wm97xx->gpio_irq;
+
+		switch (wm->id) {
+		case WM9712_ID2: /* Fall through. */
+		case WM9713_ID2:
+			/*
+			 * Use GPIO 13 (PEN_DOWN) to assert GPIO line 3
+			 * (PENDOWN).
+			 */
+			wm97xx_config_gpio(wm, WM97XX_GPIO_13, WM97XX_GPIO_IN,
+					WM97XX_GPIO_POL_HIGH,
+					WM97XX_GPIO_STICKY,
+					WM97XX_GPIO_WAKE);
+			wm97xx_config_gpio(wm, WM97XX_GPIO_3, WM97XX_GPIO_OUT,
+					WM97XX_GPIO_POL_HIGH,
+					WM97XX_GPIO_NOTSTICKY,
+					WM97XX_GPIO_NOWAKE);
+		case WM9705_ID2: /* Fall through. */
+			/*
+			 * Enable touch data slot in AC97 controller channel B.
+			 */
+			reg = ac97c_readl(atmel_wm97xx, ICA);
+			reg &= ~AC97C_CH_MASK(wm->acc_slot);
+			reg |= AC97C_CH_ASSIGN(wm->acc_slot, B);
+			ac97c_writel(atmel_wm97xx, ICA, reg);
+
+			/*
+			 * Enable channel and interrupt for RXRDY and OVERRUN.
+			 */
+			ac97c_writel(atmel_wm97xx, CBMR, AC97C_CMR_CENA
+					| AC97C_CMR_CEM_BIG
+					| AC97C_CMR_SIZE_16
+					| AC97C_OVRUN
+					| AC97C_RXRDY);
+			/* Dummy read to empty RXRHR. */
+			ac97c_readl(atmel_wm97xx, CBRHR);
+			/*
+			 * Enable interrupt for channel B in the AC97
+			 * controller.
+			 */
+			ac97c_writel(atmel_wm97xx, IER, AC97C_INT_CBEVT);
+			break;
+		default:
+			dev_err(&wm->touch_dev->dev, "pen down irq not "
+					"supported on this device\n");
+			pen_int = 0;
+			break;
+		}
+	}
+
+	return 0;
+}
+
+static void atmel_wm97xx_acc_shutdown(struct wm97xx *wm)
+{
+	if (pen_int) {
+		struct atmel_wm97xx *atmel_wm97xx =
+			platform_get_drvdata(wm->touch_dev);
+		unsigned long ica;
+
+		switch (wm->id & 0xffff) {
+		case WM9705_ID2: /* Fall through. */
+		case WM9712_ID2: /* Fall through. */
+		case WM9713_ID2:
+			/* Disable slot and turn off channel B interrupts. */
+			ica = ac97c_readl(atmel_wm97xx, ICA);
+			ica &= ~AC97C_CH_MASK(wm->acc_slot);
+			ac97c_writel(atmel_wm97xx, ICA, ica);
+			ac97c_writel(atmel_wm97xx, IDR, AC97C_INT_CBEVT);
+			ac97c_writel(atmel_wm97xx, CBMR, 0);
+			wm->pen_irq = 0;
+			break;
+		default:
+			dev_err(&wm->touch_dev->dev, "unknown codec\n");
+			break;
+		}
+	}
+}
+
+static void atmel_wm97xx_irq_enable(struct wm97xx *wm, int enable)
+{
+	/* Intentionally left empty. */
+}
+
+static struct wm97xx_mach_ops atmel_mach_ops = {
+	.acc_enabled	= 1,
+	.acc_pen_up	= atmel_wm97xx_acc_pen_up,
+	.acc_startup	= atmel_wm97xx_acc_startup,
+	.acc_shutdown	= atmel_wm97xx_acc_shutdown,
+	.irq_enable	= atmel_wm97xx_irq_enable,
+	.irq_gpio	= WM97XX_GPIO_3,
+};
+
+static int __init atmel_wm97xx_probe(struct platform_device *pdev)
+{
+	struct wm97xx *wm = platform_get_drvdata(pdev);
+	struct atmel_wm97xx *atmel_wm97xx;
+	int ret;
+
+	atmel_wm97xx = kzalloc(sizeof(struct atmel_wm97xx), GFP_KERNEL);
+	if (!atmel_wm97xx) {
+		dev_dbg(&pdev->dev, "out of memory\n");
+		return -ENOMEM;
+	}
+
+	atmel_wm97xx->wm	= wm;
+	atmel_wm97xx->regs	= (void *)ATMEL_WM97XX_AC97C_IOMEM;
+	atmel_wm97xx->ac97c_irq	= ATMEL_WM97XX_AC97C_IRQ;
+	atmel_wm97xx->gpio_pen	= atmel_gpio_line;
+	atmel_wm97xx->gpio_irq	= gpio_to_irq(atmel_wm97xx->gpio_pen);
+
+	setup_timer(&atmel_wm97xx->pen_timer, atmel_wm97xx_pen_timer,
+			(unsigned long)wm);
+
+	ret = request_irq(atmel_wm97xx->ac97c_irq,
+			  atmel_wm97xx_channel_b_interrupt,
+			  IRQF_SHARED, "atmel-wm97xx-ch-b", atmel_wm97xx);
+	if (ret) {
+		dev_dbg(&pdev->dev, "could not request ac97c irq\n");
+		goto err;
+	}
+
+	platform_set_drvdata(pdev, atmel_wm97xx);
+
+	ret = wm97xx_register_mach_ops(wm, &atmel_mach_ops);
+	if (ret)
+		goto err_irq;
+
+	return ret;
+
+err_irq:
+	free_irq(atmel_wm97xx->ac97c_irq, atmel_wm97xx);
+err:
+	platform_set_drvdata(pdev, NULL);
+	kfree(atmel_wm97xx);
+	return ret;
+}
+
+static int __exit atmel_wm97xx_remove(struct platform_device *pdev)
+{
+	struct atmel_wm97xx *atmel_wm97xx = platform_get_drvdata(pdev);
+	struct wm97xx *wm = atmel_wm97xx->wm;
+
+	ac97c_writel(atmel_wm97xx, IDR, AC97C_INT_CBEVT);
+	free_irq(atmel_wm97xx->ac97c_irq, atmel_wm97xx);
+	del_timer_sync(&atmel_wm97xx->pen_timer);
+	wm97xx_unregister_mach_ops(wm);
+	platform_set_drvdata(pdev, NULL);
+	kfree(atmel_wm97xx);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int atmel_wm97xx_suspend(struct platform_device *pdev, pm_message_t msg)
+{
+	struct atmel_wm97xx *atmel_wm97xx = platform_get_drvdata(pdev);
+
+	ac97c_writel(atmel_wm97xx, IDR, AC97C_INT_CBEVT);
+	disable_irq(atmel_wm97xx->gpio_irq);
+	del_timer_sync(&atmel_wm97xx->pen_timer);
+
+	return 0;
+}
+
+static int atmel_wm97xx_resume(struct platform_device *pdev)
+{
+	struct atmel_wm97xx *atmel_wm97xx = platform_get_drvdata(pdev);
+	struct wm97xx *wm = atmel_wm97xx->wm;
+
+	if (wm->input_dev->users) {
+		enable_irq(atmel_wm97xx->gpio_irq);
+		ac97c_writel(atmel_wm97xx, IER, AC97C_INT_CBEVT);
+	}
+
+	return 0;
+}
+#else
+#define atmel_wm97xx_suspend	NULL
+#define atmel_wm97xx_resume	NULL
+#endif
+
+static struct platform_driver atmel_wm97xx_driver = {
+	.remove		= __exit_p(atmel_wm97xx_remove),
+	.driver		= {
+		.name = "wm97xx-touch",
+	},
+	.suspend	= atmel_wm97xx_suspend,
+	.resume		= atmel_wm97xx_resume,
+};
+
+static int __init atmel_wm97xx_init(void)
+{
+	return platform_driver_probe(&atmel_wm97xx_driver, atmel_wm97xx_probe);
+}
+module_init(atmel_wm97xx_init);
+
+static void __exit atmel_wm97xx_exit(void)
+{
+	platform_driver_unregister(&atmel_wm97xx_driver);
+}
+module_exit(atmel_wm97xx_exit);
+
+MODULE_AUTHOR("Hans-Christian Egtvedt <hans-christian.egtvedt@atmel.com>");
+MODULE_DESCRIPTION("wm97xx continuous touch driver for Atmel AT91 and AVR32");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/eeti_ts.c b/drivers/input/touchscreen/eeti_ts.c
new file mode 100644
index 0000000..3ab9222
--- /dev/null
+++ b/drivers/input/touchscreen/eeti_ts.c
@@ -0,0 +1,286 @@
+/*
+ * Touch Screen driver for EETI's I2C connected touch screen panels
+ *   Copyright (c) 2009 Daniel Mack <daniel@caiaq.de>
+ *
+ * See EETI's software guide for the protocol specification:
+ *   http://home.eeti.com.tw/web20/eg/guide.htm
+ *
+ * Based on migor_ts.c
+ *   Copyright (c) 2008 Magnus Damm
+ *   Copyright (c) 2007 Ujjwal Pande <ujjwal@kenati.com>
+ *
+ * This file 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 file 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 library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/timer.h>
+#include <linux/gpio.h>
+
+static int flip_x;
+module_param(flip_x, bool, 0644);
+MODULE_PARM_DESC(flip_x, "flip x coordinate");
+
+static int flip_y;
+module_param(flip_y, bool, 0644);
+MODULE_PARM_DESC(flip_y, "flip y coordinate");
+
+struct eeti_ts_priv {
+	struct i2c_client *client;
+	struct input_dev *input;
+	struct work_struct work;
+	struct mutex mutex;
+	int irq;
+};
+
+#define EETI_TS_BITDEPTH	(11)
+#define EETI_MAXVAL		((1 << (EETI_TS_BITDEPTH + 1)) - 1)
+
+#define REPORT_BIT_PRESSED	(1 << 0)
+#define REPORT_BIT_AD0		(1 << 1)
+#define REPORT_BIT_AD1		(1 << 2)
+#define REPORT_BIT_HAS_PRESSURE	(1 << 6)
+#define REPORT_RES_BITS(v)	(((v) >> 1) + EETI_TS_BITDEPTH)
+
+static void eeti_ts_read(struct work_struct *work)
+{
+	char buf[6];
+	unsigned int x, y, res, pressed, to = 100;
+	struct eeti_ts_priv *priv =
+		container_of(work, struct eeti_ts_priv, work);
+
+	mutex_lock(&priv->mutex);
+
+	while (!gpio_get_value(irq_to_gpio(priv->irq)) && --to)
+		i2c_master_recv(priv->client, buf, sizeof(buf));
+
+	if (!to) {
+		dev_err(&priv->client->dev,
+			"unable to clear IRQ - line stuck?\n");
+		goto out;
+	}
+
+	/* drop non-report packets */
+	if (!(buf[0] & 0x80))
+		goto out;
+
+	pressed = buf[0] & REPORT_BIT_PRESSED;
+	res = REPORT_RES_BITS(buf[0] & (REPORT_BIT_AD0 | REPORT_BIT_AD1));
+	x = buf[2] | (buf[1] << 8);
+	y = buf[4] | (buf[3] << 8);
+
+	/* fix the range to 11 bits */
+	x >>= res - EETI_TS_BITDEPTH;
+	y >>= res - EETI_TS_BITDEPTH;
+
+	if (flip_x)
+		x = EETI_MAXVAL - x;
+
+	if (flip_y)
+		y = EETI_MAXVAL - y;
+
+	if (buf[0] & REPORT_BIT_HAS_PRESSURE)
+		input_report_abs(priv->input, ABS_PRESSURE, buf[5]);
+
+	input_report_abs(priv->input, ABS_X, x);
+	input_report_abs(priv->input, ABS_Y, y);
+	input_report_key(priv->input, BTN_TOUCH, !!pressed);
+	input_sync(priv->input);
+
+out:
+	mutex_unlock(&priv->mutex);
+}
+
+static irqreturn_t eeti_ts_isr(int irq, void *dev_id)
+{
+	struct eeti_ts_priv *priv = dev_id;
+
+	 /* postpone I2C transactions as we are atomic */
+	schedule_work(&priv->work);
+
+	return IRQ_HANDLED;
+}
+
+static int eeti_ts_open(struct input_dev *dev)
+{
+	struct eeti_ts_priv *priv = input_get_drvdata(dev);
+
+	enable_irq(priv->irq);
+
+	/* Read the events once to arm the IRQ */
+	eeti_ts_read(&priv->work);
+
+	return 0;
+}
+
+static void eeti_ts_close(struct input_dev *dev)
+{
+	struct eeti_ts_priv *priv = input_get_drvdata(dev);
+
+	disable_irq(priv->irq);
+	cancel_work_sync(&priv->work);
+}
+
+static int __devinit eeti_ts_probe(struct i2c_client *client,
+				   const struct i2c_device_id *idp)
+{
+	struct eeti_ts_priv *priv;
+	struct input_dev *input;
+	int err = -ENOMEM;
+
+	/* In contrast to what's described in the datasheet, there seems
+	 * to be no way of probing the presence of that device using I2C
+	 * commands. So we need to blindly believe it is there, and wait
+	 * for interrupts to occur. */
+
+	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+	if (!priv) {
+		dev_err(&client->dev, "failed to allocate driver data\n");
+		goto err0;
+	}
+
+	mutex_init(&priv->mutex);
+	input = input_allocate_device();
+
+	if (!input) {
+		dev_err(&client->dev, "Failed to allocate input device.\n");
+		goto err1;
+	}
+
+	input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+	input->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+
+	input_set_abs_params(input, ABS_X, 0, EETI_MAXVAL, 0, 0);
+	input_set_abs_params(input, ABS_Y, 0, EETI_MAXVAL, 0, 0);
+	input_set_abs_params(input, ABS_PRESSURE, 0, 0xff, 0, 0);
+
+	input->name = client->name;
+	input->id.bustype = BUS_I2C;
+	input->dev.parent = &client->dev;
+	input->open = eeti_ts_open;
+	input->close = eeti_ts_close;
+
+	priv->client = client;
+	priv->input = input;
+	priv->irq = client->irq;
+
+	INIT_WORK(&priv->work, eeti_ts_read);
+	i2c_set_clientdata(client, priv);
+	input_set_drvdata(input, priv);
+
+	err = input_register_device(input);
+	if (err)
+		goto err1;
+
+	err = request_irq(priv->irq, eeti_ts_isr, IRQF_TRIGGER_FALLING,
+			  client->name, priv);
+	if (err) {
+		dev_err(&client->dev, "Unable to request touchscreen IRQ.\n");
+		goto err2;
+	}
+
+	/* Disable the irq for now. It will be enabled once the input device
+	 * is opened. */
+	disable_irq(priv->irq);
+
+	device_init_wakeup(&client->dev, 0);
+	return 0;
+
+err2:
+	input_unregister_device(input);
+	input = NULL; /* so we dont try to free it below */
+err1:
+	input_free_device(input);
+	i2c_set_clientdata(client, NULL);
+	kfree(priv);
+err0:
+	return err;
+}
+
+static int __devexit eeti_ts_remove(struct i2c_client *client)
+{
+	struct eeti_ts_priv *priv = i2c_get_clientdata(client);
+
+	free_irq(priv->irq, priv);
+	input_unregister_device(priv->input);
+	i2c_set_clientdata(client, NULL);
+	kfree(priv);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int eeti_ts_suspend(struct i2c_client *client, pm_message_t mesg)
+{
+	struct eeti_ts_priv *priv = i2c_get_clientdata(client);
+
+	if (device_may_wakeup(&client->dev))
+		enable_irq_wake(priv->irq);
+
+	return 0;
+}
+
+static int eeti_ts_resume(struct i2c_client *client)
+{
+	struct eeti_ts_priv *priv = i2c_get_clientdata(client);
+
+	if (device_may_wakeup(&client->dev))
+		disable_irq_wake(priv->irq);
+
+	return 0;
+}
+#else
+#define eeti_ts_suspend NULL
+#define eeti_ts_resume NULL
+#endif
+
+static const struct i2c_device_id eeti_ts_id[] = {
+	{ "eeti_ts", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, eeti_ts_id);
+
+static struct i2c_driver eeti_ts_driver = {
+	.driver = {
+		.name = "eeti_ts",
+	},
+	.probe = eeti_ts_probe,
+	.remove = __devexit_p(eeti_ts_remove),
+	.suspend = eeti_ts_suspend,
+	.resume = eeti_ts_resume,
+	.id_table = eeti_ts_id,
+};
+
+static int __init eeti_ts_init(void)
+{
+	return i2c_add_driver(&eeti_ts_driver);
+}
+
+static void __exit eeti_ts_exit(void)
+{
+	i2c_del_driver(&eeti_ts_driver);
+}
+
+MODULE_DESCRIPTION("EETI Touchscreen driver");
+MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>");
+MODULE_LICENSE("GPL");
+
+module_init(eeti_ts_init);
+module_exit(eeti_ts_exit);
+
diff --git a/drivers/input/touchscreen/tsc2007.c b/drivers/input/touchscreen/tsc2007.c
index 948e167..880f58c 100644
--- a/drivers/input/touchscreen/tsc2007.c
+++ b/drivers/input/touchscreen/tsc2007.c
@@ -257,7 +257,7 @@
 	struct input_dev *input_dev;
 	int err;
 
-	if (!pdata) {
+	if (!pdata || !pdata->get_pendown_state) {
 		dev_err(&client->dev, "platform data is required!\n");
 		return -EINVAL;
 	}
diff --git a/drivers/input/touchscreen/w90p910_ts.c b/drivers/input/touchscreen/w90p910_ts.c
new file mode 100644
index 0000000..6071f58
--- /dev/null
+++ b/drivers/input/touchscreen/w90p910_ts.c
@@ -0,0 +1,350 @@
+/*
+ * Copyright (c) 2008 Nuvoton technology corporation.
+ *
+ * Wan ZongShun <mcuos.com@gmail.com>
+ *
+ * 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 of the License.
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+
+/* ADC controller bit defines */
+#define ADC_DELAY	0xf00
+#define ADC_DOWN	0x01
+#define ADC_TSC_Y	(0x01 << 8)
+#define ADC_TSC_X	(0x00 << 8)
+#define TSC_FOURWIRE	(~(0x03 << 1))
+#define ADC_CLK_EN	(0x01 << 28)	/* ADC clock enable */
+#define ADC_READ_CON	(0x01 << 12)
+#define ADC_CONV	(0x01 << 13)
+#define ADC_SEMIAUTO	(0x01 << 14)
+#define ADC_WAITTRIG	(0x03 << 14)
+#define ADC_RST1	(0x01 << 16)
+#define ADC_RST0	(0x00 << 16)
+#define ADC_EN		(0x01 << 17)
+#define ADC_INT		(0x01 << 18)
+#define WT_INT		(0x01 << 20)
+#define ADC_INT_EN	(0x01 << 21)
+#define LVD_INT_EN	(0x01 << 22)
+#define WT_INT_EN	(0x01 << 23)
+#define ADC_DIV		(0x04 << 1)	/* div = 6 */
+
+enum ts_state {
+	TS_WAIT_NEW_PACKET,	/* We are waiting next touch report */
+	TS_WAIT_X_COORD,	/* We are waiting for ADC to report X coord */
+	TS_WAIT_Y_COORD,	/* We are waiting for ADC to report Y coord */
+	TS_IDLE,		/* Input device is closed, don't do anything */
+};
+
+struct w90p910_ts {
+	struct input_dev *input;
+	struct timer_list timer;
+	int irq_num;
+	void __iomem *clocken;
+	void __iomem *ts_reg;
+	spinlock_t lock;
+	enum ts_state state;
+};
+
+static void w90p910_report_event(struct w90p910_ts *w90p910_ts, bool down)
+{
+	struct input_dev *dev = w90p910_ts->input;
+
+	if (down) {
+		input_report_abs(dev, ABS_X,
+				 __raw_readl(w90p910_ts->ts_reg + 0x0c));
+		input_report_abs(dev, ABS_Y,
+				 __raw_readl(w90p910_ts->ts_reg + 0x10));
+	}
+
+	input_report_key(dev, BTN_TOUCH, down);
+	input_sync(dev);
+}
+
+static void w90p910_prepare_x_reading(struct w90p910_ts *w90p910_ts)
+{
+	unsigned long ctlreg;
+
+	__raw_writel(ADC_TSC_X, w90p910_ts->ts_reg + 0x04);
+	ctlreg = __raw_readl(w90p910_ts->ts_reg);
+	ctlreg &= ~(ADC_WAITTRIG | WT_INT | WT_INT_EN);
+	ctlreg |= ADC_SEMIAUTO | ADC_INT_EN | ADC_CONV;
+	__raw_writel(ctlreg, w90p910_ts->ts_reg);
+
+	w90p910_ts->state = TS_WAIT_X_COORD;
+}
+
+static void w90p910_prepare_y_reading(struct w90p910_ts *w90p910_ts)
+{
+	unsigned long ctlreg;
+
+	__raw_writel(ADC_TSC_Y, w90p910_ts->ts_reg + 0x04);
+	ctlreg = __raw_readl(w90p910_ts->ts_reg);
+	ctlreg &= ~(ADC_WAITTRIG | ADC_INT | WT_INT_EN);
+	ctlreg |= ADC_SEMIAUTO | ADC_INT_EN | ADC_CONV;
+	__raw_writel(ctlreg, w90p910_ts->ts_reg);
+
+	w90p910_ts->state = TS_WAIT_Y_COORD;
+}
+
+static void w90p910_prepare_next_packet(struct w90p910_ts *w90p910_ts)
+{
+	unsigned long ctlreg;
+
+	ctlreg = __raw_readl(w90p910_ts->ts_reg);
+	ctlreg &= ~(ADC_INT | ADC_INT_EN | ADC_SEMIAUTO | ADC_CONV);
+	ctlreg |= ADC_WAITTRIG | WT_INT_EN;
+	__raw_writel(ctlreg, w90p910_ts->ts_reg);
+
+	w90p910_ts->state = TS_WAIT_NEW_PACKET;
+}
+
+static irqreturn_t w90p910_ts_interrupt(int irq, void *dev_id)
+{
+	struct w90p910_ts *w90p910_ts = dev_id;
+	unsigned long flags;
+
+	spin_lock_irqsave(&w90p910_ts->lock, flags);
+
+	switch (w90p910_ts->state) {
+	case TS_WAIT_NEW_PACKET:
+		/*
+		 * The controller only generates interrupts when pen
+		 * is down.
+		 */
+		del_timer(&w90p910_ts->timer);
+		w90p910_prepare_x_reading(w90p910_ts);
+		break;
+
+
+	case TS_WAIT_X_COORD:
+		w90p910_prepare_y_reading(w90p910_ts);
+		break;
+
+	case TS_WAIT_Y_COORD:
+		w90p910_report_event(w90p910_ts, true);
+		w90p910_prepare_next_packet(w90p910_ts);
+		mod_timer(&w90p910_ts->timer, jiffies + msecs_to_jiffies(100));
+		break;
+
+	case TS_IDLE:
+		break;
+	}
+
+	spin_unlock_irqrestore(&w90p910_ts->lock, flags);
+
+	return IRQ_HANDLED;
+}
+
+static void w90p910_check_pen_up(unsigned long data)
+{
+	struct w90p910_ts *w90p910_ts = (struct w90p910_ts *) data;
+	unsigned long flags;
+
+	spin_lock_irqsave(&w90p910_ts->lock, flags);
+
+	if (w90p910_ts->state == TS_WAIT_NEW_PACKET &&
+	    !(__raw_readl(w90p910_ts->ts_reg + 0x04) & ADC_DOWN)) {
+
+		w90p910_report_event(w90p910_ts, false);
+	}
+
+	spin_unlock_irqrestore(&w90p910_ts->lock, flags);
+}
+
+static int w90p910_open(struct input_dev *dev)
+{
+	struct w90p910_ts *w90p910_ts = input_get_drvdata(dev);
+	unsigned long val;
+
+	/* enable the ADC clock */
+	val = __raw_readl(w90p910_ts->clocken);
+	__raw_writel(val | ADC_CLK_EN, w90p910_ts->clocken);
+
+	__raw_writel(ADC_RST1, w90p910_ts->ts_reg);
+	msleep(1);
+	__raw_writel(ADC_RST0, w90p910_ts->ts_reg);
+	msleep(1);
+
+	/* set delay and screen type */
+	val = __raw_readl(w90p910_ts->ts_reg + 0x04);
+	__raw_writel(val & TSC_FOURWIRE, w90p910_ts->ts_reg + 0x04);
+	__raw_writel(ADC_DELAY, w90p910_ts->ts_reg + 0x08);
+
+	w90p910_ts->state = TS_WAIT_NEW_PACKET;
+	wmb();
+
+	/* set trigger mode */
+	val = __raw_readl(w90p910_ts->ts_reg);
+	val |= ADC_WAITTRIG | ADC_DIV | ADC_EN | WT_INT_EN;
+	__raw_writel(val, w90p910_ts->ts_reg);
+
+	return 0;
+}
+
+static void w90p910_close(struct input_dev *dev)
+{
+	struct w90p910_ts *w90p910_ts = input_get_drvdata(dev);
+	unsigned long val;
+
+	/* disable trigger mode */
+
+	spin_lock_irq(&w90p910_ts->lock);
+
+	w90p910_ts->state = TS_IDLE;
+
+	val = __raw_readl(w90p910_ts->ts_reg);
+	val &= ~(ADC_WAITTRIG | ADC_DIV | ADC_EN | WT_INT_EN | ADC_INT_EN);
+	__raw_writel(val, w90p910_ts->ts_reg);
+
+	spin_unlock_irq(&w90p910_ts->lock);
+
+	/* Now that interrupts are shut off we can safely delete timer */
+	del_timer_sync(&w90p910_ts->timer);
+
+	/* stop the ADC clock */
+	val = __raw_readl(w90p910_ts->clocken);
+	__raw_writel(val & ~ADC_CLK_EN, w90p910_ts->clocken);
+}
+
+static int __devinit w90x900ts_probe(struct platform_device *pdev)
+{
+	struct w90p910_ts *w90p910_ts;
+	struct input_dev *input_dev;
+	struct resource *res;
+	int err;
+
+	w90p910_ts = kzalloc(sizeof(struct w90p910_ts), GFP_KERNEL);
+	input_dev = input_allocate_device();
+	if (!w90p910_ts || !input_dev) {
+		err = -ENOMEM;
+		goto fail1;
+	}
+
+	w90p910_ts->input = input_dev;
+	w90p910_ts->state = TS_IDLE;
+	spin_lock_init(&w90p910_ts->lock);
+	setup_timer(&w90p910_ts->timer, w90p910_check_pen_up,
+		    (unsigned long)&w90p910_ts);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		err = -ENXIO;
+		goto fail1;
+	}
+
+	if (!request_mem_region(res->start, res->end - res->start + 1,
+				pdev->name)) {
+		err = -EBUSY;
+		goto fail1;
+	}
+
+	w90p910_ts->ts_reg = ioremap(res->start, res->end - res->start + 1);
+	if (!w90p910_ts->ts_reg) {
+		err = -ENOMEM;
+		goto fail2;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	if (!res) {
+		err = -ENXIO;
+		goto fail3;
+	}
+
+	w90p910_ts->clocken = (void __iomem *)res->start;
+
+	input_dev->name = "W90P910 TouchScreen";
+	input_dev->phys = "w90p910ts/event0";
+	input_dev->id.bustype = BUS_HOST;
+	input_dev->id.vendor  = 0x0005;
+	input_dev->id.product = 0x0001;
+	input_dev->id.version = 0x0100;
+	input_dev->dev.parent = &pdev->dev;
+	input_dev->open = w90p910_open;
+	input_dev->close = w90p910_close;
+
+	input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+	input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+
+	input_set_abs_params(input_dev, ABS_X, 0, 0x400, 0, 0);
+	input_set_abs_params(input_dev, ABS_Y, 0, 0x400, 0, 0);
+
+	input_set_drvdata(input_dev, w90p910_ts);
+
+	w90p910_ts->irq_num = platform_get_irq(pdev, 0);
+	if (request_irq(w90p910_ts->irq_num, w90p910_ts_interrupt,
+			IRQF_DISABLED, "w90p910ts", w90p910_ts)) {
+		err = -EBUSY;
+		goto fail3;
+	}
+
+	err = input_register_device(w90p910_ts->input);
+	if (err)
+		goto fail4;
+
+	platform_set_drvdata(pdev, w90p910_ts);
+
+	return 0;
+
+fail4:	free_irq(w90p910_ts->irq_num, w90p910_ts);
+fail3:	iounmap(w90p910_ts->ts_reg);
+fail2:	release_mem_region(res->start, res->end - res->start + 1);
+fail1:	input_free_device(input_dev);
+	kfree(w90p910_ts);
+	return err;
+}
+
+static int __devexit w90x900ts_remove(struct platform_device *pdev)
+{
+	struct w90p910_ts *w90p910_ts = platform_get_drvdata(pdev);
+	struct resource *res;
+
+	free_irq(w90p910_ts->irq_num, w90p910_ts);
+	del_timer_sync(&w90p910_ts->timer);
+	iounmap(w90p910_ts->ts_reg);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	release_mem_region(res->start, res->end - res->start + 1);
+
+	input_unregister_device(w90p910_ts->input);
+	kfree(w90p910_ts);
+
+	platform_set_drvdata(pdev, NULL);
+
+	return 0;
+}
+
+static struct platform_driver w90x900ts_driver = {
+	.probe		= w90x900ts_probe,
+	.remove		= __devexit_p(w90x900ts_remove),
+	.driver		= {
+		.name	= "w90x900-ts",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init w90x900ts_init(void)
+{
+	return platform_driver_register(&w90x900ts_driver);
+}
+
+static void __exit w90x900ts_exit(void)
+{
+	platform_driver_unregister(&w90x900ts_driver);
+}
+
+module_init(w90x900ts_init);
+module_exit(w90x900ts_exit);
+
+MODULE_AUTHOR("Wan ZongShun <mcuos.com@gmail.com>");
+MODULE_DESCRIPTION("w90p910 touch screen driver!");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:w90p910-ts");
diff --git a/drivers/mfd/ucb1400_core.c b/drivers/mfd/ucb1400_core.c
index 178159e..78c2135 100644
--- a/drivers/mfd/ucb1400_core.c
+++ b/drivers/mfd/ucb1400_core.c
@@ -23,6 +23,26 @@
 #include <linux/module.h>
 #include <linux/ucb1400.h>
 
+unsigned int ucb1400_adc_read(struct snd_ac97 *ac97, u16 adc_channel,
+		int adcsync)
+{
+	unsigned int val;
+
+	if (adcsync)
+		adc_channel |= UCB_ADC_SYNC_ENA;
+
+	ucb1400_reg_write(ac97, UCB_ADC_CR, UCB_ADC_ENA | adc_channel);
+	ucb1400_reg_write(ac97, UCB_ADC_CR, UCB_ADC_ENA | adc_channel |
+			UCB_ADC_START);
+
+	while (!((val = ucb1400_reg_read(ac97, UCB_ADC_DATA))
+				& UCB_ADC_DAT_VALID))
+		schedule_timeout_uninterruptible(1);
+
+	return val & UCB_ADC_DAT_MASK;
+}
+EXPORT_SYMBOL_GPL(ucb1400_adc_read);
+
 static int ucb1400_core_probe(struct device *dev)
 {
 	int err;
diff --git a/include/linux/gameport.h b/include/linux/gameport.h
index 0cd825f..1bc0854 100644
--- a/include/linux/gameport.h
+++ b/include/linux/gameport.h
@@ -11,6 +11,7 @@
 
 #ifdef __KERNEL__
 #include <asm/io.h>
+#include <linux/types.h>
 #include <linux/list.h>
 #include <linux/mutex.h>
 #include <linux/device.h>
@@ -62,7 +63,7 @@
 
 	struct device_driver driver;
 
-	unsigned int ignore;
+	bool ignore;
 };
 #define to_gameport_driver(d)	container_of(d, struct gameport_driver, driver)
 
diff --git a/include/linux/i2c/lm8323.h b/include/linux/i2c/lm8323.h
new file mode 100644
index 0000000..478d668
--- /dev/null
+++ b/include/linux/i2c/lm8323.h
@@ -0,0 +1,46 @@
+/*
+ * lm8323.h - Configuration for LM8323 keypad driver.
+ *
+ * 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 of the License only).
+ *
+ * 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 02111-1307 USA
+ */
+
+#ifndef __LINUX_LM8323_H
+#define __LINUX_LM8323_H
+
+#include <linux/types.h>
+
+/*
+ * Largest keycode that the chip can send, plus one,
+ * so keys can be mapped directly at the index of the
+ * LM8323 keycode instead of subtracting one.
+ */
+#define LM8323_KEYMAP_SIZE	(0x7f + 1)
+
+#define LM8323_NUM_PWMS		3
+
+struct lm8323_platform_data {
+	int debounce_time; /* Time to watch for key bouncing, in ms. */
+	int active_time; /* Idle time until sleep, in ms. */
+
+	int size_x;
+	int size_y;
+	bool repeat;
+	const unsigned short *keymap;
+
+	const char *pwm_names[LM8323_NUM_PWMS];
+
+	const char *name; /* Device name. */
+};
+
+#endif /* __LINUX_LM8323_H */
diff --git a/include/linux/input.h b/include/linux/input.h
index 6fed4f6..8b3bc3e 100644
--- a/include/linux/input.h
+++ b/include/linux/input.h
@@ -53,6 +53,7 @@
 	__s32 maximum;
 	__s32 fuzz;
 	__s32 flat;
+	__s32 resolution;
 };
 
 #define EVIOCGVERSION		_IOR('E', 0x01, int)			/* get driver version */
@@ -1109,6 +1110,7 @@
 	int absmin[ABS_MAX + 1];
 	int absfuzz[ABS_MAX + 1];
 	int absflat[ABS_MAX + 1];
+	int absres[ABS_MAX + 1];
 
 	int (*open)(struct input_dev *dev);
 	void (*close)(struct input_dev *dev);
diff --git a/include/linux/rotary_encoder.h b/include/linux/rotary_encoder.h
index 12d63a3..215278b 100644
--- a/include/linux/rotary_encoder.h
+++ b/include/linux/rotary_encoder.h
@@ -8,6 +8,8 @@
 	unsigned int gpio_b;
 	unsigned int inverted_a;
 	unsigned int inverted_b;
+	bool relative_axis;
+	bool rollover;
 };
 
 #endif /* __ROTARY_ENCODER_H__ */
diff --git a/include/linux/serio.h b/include/linux/serio.h
index e0417e4..126d24c 100644
--- a/include/linux/serio.h
+++ b/include/linux/serio.h
@@ -15,6 +15,7 @@
 
 #ifdef __KERNEL__
 
+#include <linux/types.h>
 #include <linux/interrupt.h>
 #include <linux/list.h>
 #include <linux/spinlock.h>
@@ -28,7 +29,10 @@
 	char name[32];
 	char phys[32];
 
-	unsigned int manual_bind;
+	bool manual_bind;
+	bool registered;	/* port has been fully registered with driver core */
+	bool suspended;		/* port is suspended */
+
 
 	struct serio_device_id id;
 
@@ -47,7 +51,6 @@
 	struct mutex drv_mutex;		/* protects serio->drv so attributes can pin driver */
 
 	struct device dev;
-	unsigned int registered;	/* port has been fully registered with driver core */
 
 	struct list_head node;
 };
@@ -58,7 +61,7 @@
 	char *description;
 
 	struct serio_device_id *id_table;
-	unsigned int manual_bind;
+	bool manual_bind;
 
 	void (*write_wakeup)(struct serio *);
 	irqreturn_t (*interrupt)(struct serio *, unsigned char, unsigned int);
diff --git a/include/linux/spi/ads7846.h b/include/linux/spi/ads7846.h
index 2ea2032..51948eb 100644
--- a/include/linux/spi/ads7846.h
+++ b/include/linux/spi/ads7846.h
@@ -17,6 +17,7 @@
 	u16	vref_mv;		/* external vref value, milliVolts */
 	bool	keep_vref_on;		/* set to keep vref on for differential
 					 * measurements as well */
+	bool	swap_xy;		/* swap x and y axes */
 
 	/* Settling time of the analog signals; a function of Vcc and the
 	 * capacitance on the X/Y drivers.  If set to non-zero, two samples
diff --git a/include/linux/ucb1400.h b/include/linux/ucb1400.h
index 970473b..ed889f4 100644
--- a/include/linux/ucb1400.h
+++ b/include/linux/ucb1400.h
@@ -134,28 +134,13 @@
 	ucb1400_reg_write(ac97, UCB_ADC_CR, UCB_ADC_ENA);
 }
 
-static unsigned int ucb1400_adc_read(struct snd_ac97 *ac97, u16 adc_channel,
-					int adcsync)
-{
-	unsigned int val;
-
-	if (adcsync)
-		adc_channel |= UCB_ADC_SYNC_ENA;
-
-	ucb1400_reg_write(ac97, UCB_ADC_CR, UCB_ADC_ENA | adc_channel);
-	ucb1400_reg_write(ac97, UCB_ADC_CR, UCB_ADC_ENA | adc_channel |
-				UCB_ADC_START);
-
-	while (!((val = ucb1400_reg_read(ac97, UCB_ADC_DATA))
-			& UCB_ADC_DAT_VALID))
-		schedule_timeout_uninterruptible(1);
-
-	return val & UCB_ADC_DAT_MASK;
-}
-
 static inline void ucb1400_adc_disable(struct snd_ac97 *ac97)
 {
 	ucb1400_reg_write(ac97, UCB_ADC_CR, 0);
 }
 
+
+unsigned int ucb1400_adc_read(struct snd_ac97 *ac97, u16 adc_channel,
+			      int adcsync);
+
 #endif