summary refs log tree commit diff
path: root/drivers/input
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2010-08-04 10:41:52 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2010-08-04 10:41:52 -0700
commitfe445c6e2cb62a566e1a89f8798de11459975710 (patch)
treedb1f2c0c19f488992fb5b9371476b4e7701c49a0 /drivers/input
parentf63b759c44b0561c76a67894c734157df3313b42 (diff)
parentd01d0756f75e7a5b4b43764ad45b83c4340f11d6 (diff)
downloadlinux-fe445c6e2cb62a566e1a89f8798de11459975710.tar.gz
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: (57 commits)
  Input: adp5588-keypad - fix NULL dereference in adp5588_gpio_add()
  Input: cy8ctmg110 - capacitive touchscreen support
  Input: keyboard - also match braille-only keyboards
  Input: adp5588-keys - export unused GPIO pins
  Input: xpad - add product ID for Hori Fighting Stick EX2
  Input: adxl34x - fix leak and use after free
  Input: samsung-keypad - Add samsung keypad driver
  Input: i8042 - reset keyboard controller wehen resuming from S2R
  Input: synaptics - set min/max for finger width
  Input: synaptics - only report width on hardware that supports it
  Input: evdev - signal that device is writable in evdev_poll()
  Input: mousedev - signal that device is writable in mousedev_poll()
  Input: change input handlers to use bool when possible
  Input: document the MT event slot protocol
  Input: introduce MT event slots
  Input: usbtouchscreen - implement reset_resume
  Input: usbtouchscreen - implement runtime power management
  Input: usbtouchscreen - implement basic suspend/resume
  Input: Add ATMEL QT602240 touchscreen driver
  Input: fix signedness warning in input_set_keycode()
  ...
Diffstat (limited to 'drivers/input')
-rw-r--r--drivers/input/evdev.c54
-rw-r--r--drivers/input/input.c182
-rw-r--r--drivers/input/joydev.c7
-rw-r--r--drivers/input/joystick/xpad.c108
-rw-r--r--drivers/input/keyboard/Kconfig21
-rw-r--r--drivers/input/keyboard/Makefile2
-rw-r--r--drivers/input/keyboard/adp5588-keys.c351
-rw-r--r--drivers/input/keyboard/gpio_keys.c19
-rw-r--r--drivers/input/keyboard/lm8323.c12
-rw-r--r--drivers/input/keyboard/matrix_keypad.c108
-rw-r--r--drivers/input/keyboard/mcs_touchkey.c239
-rw-r--r--drivers/input/keyboard/samsung-keypad.c491
-rw-r--r--drivers/input/misc/Kconfig48
-rw-r--r--drivers/input/misc/Makefile4
-rw-r--r--drivers/input/misc/adxl34x-i2c.c163
-rw-r--r--drivers/input/misc/adxl34x-spi.c145
-rw-r--r--drivers/input/misc/adxl34x.c915
-rw-r--r--drivers/input/misc/adxl34x.h30
-rw-r--r--drivers/input/misc/atlas_btns.c38
-rw-r--r--drivers/input/misc/pwm-beeper.c199
-rw-r--r--drivers/input/misc/twl4030-pwrbutton.c12
-rw-r--r--drivers/input/misc/wistron_btns.c4
-rw-r--r--drivers/input/mouse/bcm5974.c23
-rw-r--r--drivers/input/mouse/synaptics.c8
-rw-r--r--drivers/input/mousedev.c15
-rw-r--r--drivers/input/serio/i8042-ppcio.h75
-rw-r--r--drivers/input/serio/i8042.c65
-rw-r--r--drivers/input/tablet/wacom_wac.c44
-rw-r--r--drivers/input/tablet/wacom_wac.h1
-rw-r--r--drivers/input/touchscreen/Kconfig67
-rw-r--r--drivers/input/touchscreen/Makefile6
-rw-r--r--drivers/input/touchscreen/ad7879-i2c.c143
-rw-r--r--drivers/input/touchscreen/ad7879-spi.c198
-rw-r--r--drivers/input/touchscreen/ad7879.c625
-rw-r--r--drivers/input/touchscreen/ad7879.h30
-rw-r--r--drivers/input/touchscreen/ads7846.c206
-rw-r--r--drivers/input/touchscreen/cy8ctmg110_ts.c363
-rw-r--r--drivers/input/touchscreen/mcs5000_ts.c6
-rw-r--r--drivers/input/touchscreen/qt602240_ts.c1401
-rw-r--r--drivers/input/touchscreen/tps6507x-ts.c3
-rw-r--r--drivers/input/touchscreen/usbtouchscreen.c215
41 files changed, 5761 insertions, 885 deletions
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index 2ee6c7a68bdc..054edf346e0b 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -10,7 +10,8 @@
 
 #define EVDEV_MINOR_BASE	64
 #define EVDEV_MINORS		32
-#define EVDEV_BUFFER_SIZE	64
+#define EVDEV_MIN_BUFFER_SIZE	64U
+#define EVDEV_BUF_PACKETS	8
 
 #include <linux/poll.h>
 #include <linux/sched.h>
@@ -23,7 +24,6 @@
 #include "input-compat.h"
 
 struct evdev {
-	int exist;
 	int open;
 	int minor;
 	struct input_handle handle;
@@ -33,16 +33,18 @@ struct evdev {
 	spinlock_t client_lock; /* protects client_list */
 	struct mutex mutex;
 	struct device dev;
+	bool exist;
 };
 
 struct evdev_client {
-	struct input_event buffer[EVDEV_BUFFER_SIZE];
 	int head;
 	int tail;
 	spinlock_t buffer_lock; /* protects access to buffer, head and tail */
 	struct fasync_struct *fasync;
 	struct evdev *evdev;
 	struct list_head node;
+	int bufsize;
+	struct input_event buffer[];
 };
 
 static struct evdev *evdev_table[EVDEV_MINORS];
@@ -52,11 +54,15 @@ static void evdev_pass_event(struct evdev_client *client,
 			     struct input_event *event)
 {
 	/*
-	 * Interrupts are disabled, just acquire the lock
+	 * Interrupts are disabled, just acquire the lock.
+	 * Make sure we don't leave with the client buffer
+	 * "empty" by having client->head == client->tail.
 	 */
 	spin_lock(&client->buffer_lock);
-	client->buffer[client->head++] = *event;
-	client->head &= EVDEV_BUFFER_SIZE - 1;
+	do {
+		client->buffer[client->head++] = *event;
+		client->head &= client->bufsize - 1;
+	} while (client->head == client->tail);
 	spin_unlock(&client->buffer_lock);
 
 	if (event->type == EV_SYN)
@@ -242,11 +248,21 @@ static int evdev_release(struct inode *inode, struct file *file)
 	return 0;
 }
 
+static unsigned int evdev_compute_buffer_size(struct input_dev *dev)
+{
+	unsigned int n_events =
+		max(dev->hint_events_per_packet * EVDEV_BUF_PACKETS,
+		    EVDEV_MIN_BUFFER_SIZE);
+
+	return roundup_pow_of_two(n_events);
+}
+
 static int evdev_open(struct inode *inode, struct file *file)
 {
 	struct evdev *evdev;
 	struct evdev_client *client;
 	int i = iminor(inode) - EVDEV_MINOR_BASE;
+	unsigned int bufsize;
 	int error;
 
 	if (i >= EVDEV_MINORS)
@@ -263,12 +279,17 @@ static int evdev_open(struct inode *inode, struct file *file)
 	if (!evdev)
 		return -ENODEV;
 
-	client = kzalloc(sizeof(struct evdev_client), GFP_KERNEL);
+	bufsize = evdev_compute_buffer_size(evdev->handle.dev);
+
+	client = kzalloc(sizeof(struct evdev_client) +
+				bufsize * sizeof(struct input_event),
+			 GFP_KERNEL);
 	if (!client) {
 		error = -ENOMEM;
 		goto err_put_evdev;
 	}
 
+	client->bufsize = bufsize;
 	spin_lock_init(&client->buffer_lock);
 	client->evdev = evdev;
 	evdev_attach_client(evdev, client);
@@ -334,7 +355,7 @@ static int evdev_fetch_next_event(struct evdev_client *client,
 	have_event = client->head != client->tail;
 	if (have_event) {
 		*event = client->buffer[client->tail++];
-		client->tail &= EVDEV_BUFFER_SIZE - 1;
+		client->tail &= client->bufsize - 1;
 	}
 
 	spin_unlock_irq(&client->buffer_lock);
@@ -382,10 +403,15 @@ static unsigned int evdev_poll(struct file *file, poll_table *wait)
 {
 	struct evdev_client *client = file->private_data;
 	struct evdev *evdev = client->evdev;
+	unsigned int mask;
 
 	poll_wait(file, &evdev->wait, wait);
-	return ((client->head == client->tail) ? 0 : (POLLIN | POLLRDNORM)) |
-		(evdev->exist ? 0 : (POLLHUP | POLLERR));
+
+	mask = evdev->exist ? POLLOUT | POLLWRNORM : POLLHUP | POLLERR;
+	if (client->head != client->tail)
+		mask |= POLLIN | POLLRDNORM;
+
+	return mask;
 }
 
 #ifdef CONFIG_COMPAT
@@ -665,6 +691,10 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,
 								  sizeof(struct input_absinfo))))
 					return -EFAULT;
 
+				/* We can't change number of reserved MT slots */
+				if (t == ABS_MT_SLOT)
+					return -EINVAL;
+
 				/*
 				 * Take event lock to ensure that we are not
 				 * changing device parameters in the middle
@@ -768,7 +798,7 @@ static void evdev_remove_chrdev(struct evdev *evdev)
 static void evdev_mark_dead(struct evdev *evdev)
 {
 	mutex_lock(&evdev->mutex);
-	evdev->exist = 0;
+	evdev->exist = false;
 	mutex_unlock(&evdev->mutex);
 }
 
@@ -817,7 +847,7 @@ static int evdev_connect(struct input_handler *handler, struct input_dev *dev,
 	init_waitqueue_head(&evdev->wait);
 
 	dev_set_name(&evdev->dev, "event%d", minor);
-	evdev->exist = 1;
+	evdev->exist = true;
 	evdev->minor = minor;
 
 	evdev->handle.dev = input_get_device(dev);
diff --git a/drivers/input/input.c b/drivers/input/input.c
index 9c79bd56b51a..e1243b4b32a5 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -33,25 +33,6 @@ MODULE_LICENSE("GPL");
 
 #define INPUT_DEVICES	256
 
-/*
- * EV_ABS events which should not be cached are listed here.
- */
-static unsigned int input_abs_bypass_init_data[] __initdata = {
-	ABS_MT_TOUCH_MAJOR,
-	ABS_MT_TOUCH_MINOR,
-	ABS_MT_WIDTH_MAJOR,
-	ABS_MT_WIDTH_MINOR,
-	ABS_MT_ORIENTATION,
-	ABS_MT_POSITION_X,
-	ABS_MT_POSITION_Y,
-	ABS_MT_TOOL_TYPE,
-	ABS_MT_BLOB_ID,
-	ABS_MT_TRACKING_ID,
-	ABS_MT_PRESSURE,
-	0
-};
-static unsigned long input_abs_bypass[BITS_TO_LONGS(ABS_CNT)];
-
 static LIST_HEAD(input_dev_list);
 static LIST_HEAD(input_handler_list);
 
@@ -181,6 +162,56 @@ static void input_stop_autorepeat(struct input_dev *dev)
 #define INPUT_PASS_TO_DEVICE	2
 #define INPUT_PASS_TO_ALL	(INPUT_PASS_TO_HANDLERS | INPUT_PASS_TO_DEVICE)
 
+static int input_handle_abs_event(struct input_dev *dev,
+				  unsigned int code, int *pval)
+{
+	bool is_mt_event;
+	int *pold;
+
+	if (code == ABS_MT_SLOT) {
+		/*
+		 * "Stage" the event; we'll flush it later, when we
+		 * get actiual touch data.
+		 */
+		if (*pval >= 0 && *pval < dev->mtsize)
+			dev->slot = *pval;
+
+		return INPUT_IGNORE_EVENT;
+	}
+
+	is_mt_event = code >= ABS_MT_FIRST && code <= ABS_MT_LAST;
+
+	if (!is_mt_event) {
+		pold = &dev->abs[code];
+	} else if (dev->mt) {
+		struct input_mt_slot *mtslot = &dev->mt[dev->slot];
+		pold = &mtslot->abs[code - ABS_MT_FIRST];
+	} else {
+		/*
+		 * Bypass filtering for multitouch events when
+		 * not employing slots.
+		 */
+		pold = NULL;
+	}
+
+	if (pold) {
+		*pval = input_defuzz_abs_event(*pval, *pold,
+						dev->absfuzz[code]);
+		if (*pold == *pval)
+			return INPUT_IGNORE_EVENT;
+
+		*pold = *pval;
+	}
+
+	/* Flush pending "slot" event */
+	if (is_mt_event && dev->slot != dev->abs[ABS_MT_SLOT]) {
+		dev->abs[ABS_MT_SLOT] = dev->slot;
+		input_pass_event(dev, EV_ABS, ABS_MT_SLOT, dev->slot);
+	}
+
+	return INPUT_PASS_TO_HANDLERS;
+}
+
 static void input_handle_event(struct input_dev *dev,
 			       unsigned int type, unsigned int code, int value)
 {
@@ -196,12 +227,12 @@ static void input_handle_event(struct input_dev *dev,
 
 		case SYN_REPORT:
 			if (!dev->sync) {
-				dev->sync = 1;
+				dev->sync = true;
 				disposition = INPUT_PASS_TO_HANDLERS;
 			}
 			break;
 		case SYN_MT_REPORT:
-			dev->sync = 0;
+			dev->sync = false;
 			disposition = INPUT_PASS_TO_HANDLERS;
 			break;
 		}
@@ -233,21 +264,9 @@ static void input_handle_event(struct input_dev *dev,
 		break;
 
 	case EV_ABS:
-		if (is_event_supported(code, dev->absbit, ABS_MAX)) {
-
-			if (test_bit(code, input_abs_bypass)) {
-				disposition = INPUT_PASS_TO_HANDLERS;
-				break;
-			}
+		if (is_event_supported(code, dev->absbit, ABS_MAX))
+			disposition = input_handle_abs_event(dev, code, &value);
 
-			value = input_defuzz_abs_event(value,
-					dev->abs[code], dev->absfuzz[code]);
-
-			if (dev->abs[code] != value) {
-				dev->abs[code] = value;
-				disposition = INPUT_PASS_TO_HANDLERS;
-			}
-		}
 		break;
 
 	case EV_REL:
@@ -298,7 +317,7 @@ static void input_handle_event(struct input_dev *dev,
 	}
 
 	if (disposition != INPUT_IGNORE_EVENT && type != EV_SYN)
-		dev->sync = 0;
+		dev->sync = false;
 
 	if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event)
 		dev->event(dev, type, code, value);
@@ -528,12 +547,30 @@ void input_close_device(struct input_handle *handle)
 EXPORT_SYMBOL(input_close_device);
 
 /*
+ * Simulate keyup events for all keys that are marked as pressed.
+ * The function must be called with dev->event_lock held.
+ */
+static void input_dev_release_keys(struct input_dev *dev)
+{
+	int code;
+
+	if (is_event_supported(EV_KEY, dev->evbit, EV_MAX)) {
+		for (code = 0; code <= KEY_MAX; code++) {
+			if (is_event_supported(code, dev->keybit, KEY_MAX) &&
+			    __test_and_clear_bit(code, dev->key)) {
+				input_pass_event(dev, EV_KEY, code, 0);
+			}
+		}
+		input_pass_event(dev, EV_SYN, SYN_REPORT, 1);
+	}
+}
+
+/*
  * Prepare device for unregistering
  */
 static void input_disconnect_device(struct input_dev *dev)
 {
 	struct input_handle *handle;
-	int code;
 
 	/*
 	 * Mark device as going away. Note that we take dev->mutex here
@@ -552,15 +589,7 @@ static void input_disconnect_device(struct input_dev *dev)
 	 * generate events even after we done here but they will not
 	 * reach any handlers.
 	 */
-	if (is_event_supported(EV_KEY, dev->evbit, EV_MAX)) {
-		for (code = 0; code <= KEY_MAX; code++) {
-			if (is_event_supported(code, dev->keybit, KEY_MAX) &&
-			    __test_and_clear_bit(code, dev->key)) {
-				input_pass_event(dev, EV_KEY, code, 0);
-			}
-		}
-		input_pass_event(dev, EV_SYN, SYN_REPORT, 1);
-	}
+	input_dev_release_keys(dev);
 
 	list_for_each_entry(handle, &dev->h_list, d_node)
 		handle->open = 0;
@@ -684,7 +713,7 @@ int input_set_keycode(struct input_dev *dev,
 		      unsigned int scancode, unsigned int keycode)
 {
 	unsigned long flags;
-	int old_keycode;
+	unsigned int old_keycode;
 	int retval;
 
 	if (keycode > KEY_MAX)
@@ -1278,6 +1307,7 @@ static void input_dev_release(struct device *device)
 	struct input_dev *dev = to_input_dev(device);
 
 	input_ff_destroy(dev);
+	input_mt_destroy_slots(dev);
 	kfree(dev);
 
 	module_put(THIS_MODULE);
@@ -1433,6 +1463,15 @@ static int input_dev_resume(struct device *dev)
 
 	mutex_lock(&input_dev->mutex);
 	input_dev_reset(input_dev, true);
+
+	/*
+	 * Keys that have been pressed at suspend time are unlikely
+	 * to be still pressed when we resume.
+	 */
+	spin_lock_irq(&input_dev->event_lock);
+	input_dev_release_keys(input_dev);
+	spin_unlock_irq(&input_dev->event_lock);
+
 	mutex_unlock(&input_dev->mutex);
 
 	return 0;
@@ -1518,6 +1557,45 @@ void input_free_device(struct input_dev *dev)
 EXPORT_SYMBOL(input_free_device);
 
 /**
+ * input_mt_create_slots() - create MT input slots
+ * @dev: input device supporting MT events and finger tracking
+ * @num_slots: number of slots used by the device
+ *
+ * This function allocates all necessary memory for MT slot handling
+ * in the input device, and adds ABS_MT_SLOT to the device capabilities.
+ */
+int input_mt_create_slots(struct input_dev *dev, unsigned int num_slots)
+{
+	if (!num_slots)
+		return 0;
+
+	dev->mt = kcalloc(num_slots, sizeof(struct input_mt_slot), GFP_KERNEL);
+	if (!dev->mt)
+		return -ENOMEM;
+
+	dev->mtsize = num_slots;
+	input_set_abs_params(dev, ABS_MT_SLOT, 0, num_slots - 1, 0, 0);
+
+	return 0;
+}
+EXPORT_SYMBOL(input_mt_create_slots);
+
+/**
+ * input_mt_destroy_slots() - frees the MT slots of the input device
+ * @dev: input device with allocated MT slots
+ *
+ * This function is only needed in error path as the input core will
+ * automatically free the MT slots when the device is destroyed.
+ */
+void input_mt_destroy_slots(struct input_dev *dev)
+{
+	kfree(dev->mt);
+	dev->mt = NULL;
+	dev->mtsize = 0;
+}
+EXPORT_SYMBOL(input_mt_destroy_slots);
+
+/**
  * input_set_capability - mark device as capable of a certain event
  * @dev: device that is capable of emitting or accepting event
  * @type: type of the event (EV_KEY, EV_REL, etc...)
@@ -1926,20 +2004,10 @@ static const struct file_operations input_fops = {
 	.open = input_open_file,
 };
 
-static void __init input_init_abs_bypass(void)
-{
-	const unsigned int *p;
-
-	for (p = input_abs_bypass_init_data; *p; p++)
-		input_abs_bypass[BIT_WORD(*p)] |= BIT_MASK(*p);
-}
-
 static int __init input_init(void)
 {
 	int err;
 
-	input_init_abs_bypass();
-
 	err = class_register(&input_class);
 	if (err) {
 		printk(KERN_ERR "input: unable to register input_dev class\n");
diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c
index 34157bb97ed6..63834585c283 100644
--- a/drivers/input/joydev.c
+++ b/drivers/input/joydev.c
@@ -37,7 +37,6 @@ MODULE_LICENSE("GPL");
 #define JOYDEV_BUFFER_SIZE	64
 
 struct joydev {
-	int exist;
 	int open;
 	int minor;
 	struct input_handle handle;
@@ -46,6 +45,7 @@ struct joydev {
 	spinlock_t client_lock; /* protects client_list */
 	struct mutex mutex;
 	struct device dev;
+	bool exist;
 
 	struct js_corr corr[ABS_CNT];
 	struct JS_DATA_SAVE_TYPE glue;
@@ -760,7 +760,7 @@ static void joydev_remove_chrdev(struct joydev *joydev)
 static void joydev_mark_dead(struct joydev *joydev)
 {
 	mutex_lock(&joydev->mutex);
-	joydev->exist = 0;
+	joydev->exist = false;
 	mutex_unlock(&joydev->mutex);
 }
 
@@ -817,10 +817,9 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev,
 	init_waitqueue_head(&joydev->wait);
 
 	dev_set_name(&joydev->dev, "js%d", minor);
-	joydev->exist = 1;
+	joydev->exist = true;
 	joydev->minor = minor;
 
-	joydev->exist = 1;
 	joydev->handle.dev = input_get_device(dev);
 	joydev->handle.name = dev_name(&joydev->dev);
 	joydev->handle.handler = handler;
diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c
index c1087ce4cef9..269a846f3694 100644
--- a/drivers/input/joystick/xpad.c
+++ b/drivers/input/joystick/xpad.c
@@ -9,6 +9,7 @@
  *               2005 Dominic Cerquetti <binary1230@yahoo.com>
  *               2006 Adam Buchbinder <adam.buchbinder@gmail.com>
  *               2007 Jan Kratochvil <honza@jikos.cz>
+ *               2010 Christoph Fritz <chf.fritz@googlemail.com>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
@@ -88,6 +89,9 @@
    but we map them to axes when possible to simplify things */
 #define MAP_DPAD_TO_BUTTONS		(1 << 0)
 #define MAP_TRIGGERS_TO_BUTTONS		(1 << 1)
+#define MAP_STICKS_TO_NULL		(1 << 2)
+#define DANCEPAD_MAP_CONFIG	(MAP_DPAD_TO_BUTTONS |			\
+				MAP_TRIGGERS_TO_BUTTONS | MAP_STICKS_TO_NULL)
 
 #define XTYPE_XBOX        0
 #define XTYPE_XBOX360     1
@@ -102,6 +106,10 @@ static int triggers_to_buttons;
 module_param(triggers_to_buttons, bool, S_IRUGO);
 MODULE_PARM_DESC(triggers_to_buttons, "Map triggers to buttons rather than axes for unknown pads");
 
+static int sticks_to_null;
+module_param(sticks_to_null, bool, S_IRUGO);
+MODULE_PARM_DESC(sticks_to_null, "Do not map sticks at all for unknown pads");
+
 static const struct xpad_device {
 	u16 idVendor;
 	u16 idProduct;
@@ -114,7 +122,7 @@ static const struct xpad_device {
 	{ 0x045e, 0x0285, "Microsoft X-Box pad (Japan)", 0, XTYPE_XBOX },
 	{ 0x045e, 0x0287, "Microsoft Xbox Controller S", 0, XTYPE_XBOX },
 	{ 0x045e, 0x0719, "Xbox 360 Wireless Receiver", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W },
-	{ 0x0c12, 0x8809, "RedOctane Xbox Dance Pad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
+	{ 0x0c12, 0x8809, "RedOctane Xbox Dance Pad", DANCEPAD_MAP_CONFIG, XTYPE_XBOX },
 	{ 0x044f, 0x0f07, "Thrustmaster, Inc. Controller", 0, XTYPE_XBOX },
 	{ 0x046d, 0xc242, "Logitech Chillstream Controller", 0, XTYPE_XBOX360 },
 	{ 0x046d, 0xca84, "Logitech Xbox Cordless Controller", 0, XTYPE_XBOX },
@@ -151,6 +159,7 @@ static const struct xpad_device {
 	{ 0x045e, 0x028e, "Microsoft X-Box 360 pad", 0, XTYPE_XBOX360 },
 	{ 0x1bad, 0x0003, "Harmonix Rock Band Drumkit", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 },
 	{ 0x0f0d, 0x0016, "Hori Real Arcade Pro.EX", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
+	{ 0x0f0d, 0x000d, "Hori Fighting Stick EX2", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
 	{ 0xffff, 0xffff, "Chinese-made Xbox Controller", 0, XTYPE_XBOX },
 	{ 0x0000, 0x0000, "Generic X-Box pad", 0, XTYPE_UNKNOWN }
 };
@@ -158,7 +167,7 @@ static const struct xpad_device {
 /* buttons shared with xbox and xbox360 */
 static const signed short xpad_common_btn[] = {
 	BTN_A, BTN_B, BTN_X, BTN_Y,			/* "analog" buttons */
-	BTN_START, BTN_BACK, BTN_THUMBL, BTN_THUMBR,	/* start/back/sticks */
+	BTN_START, BTN_SELECT, BTN_THUMBL, BTN_THUMBR,	/* start/back/sticks */
 	-1						/* terminating entry */
 };
 
@@ -168,10 +177,10 @@ static const signed short xpad_btn[] = {
 	-1			/* terminating entry */
 };
 
-/* used when dpad is mapped to nuttons */
+/* used when dpad is mapped to buttons */
 static const signed short xpad_btn_pad[] = {
-	BTN_LEFT, BTN_RIGHT,		/* d-pad left, right */
-	BTN_0, BTN_1,			/* d-pad up, down (XXX names??) */
+	BTN_TRIGGER_HAPPY1, BTN_TRIGGER_HAPPY2,		/* d-pad left, right */
+	BTN_TRIGGER_HAPPY3, BTN_TRIGGER_HAPPY4,		/* d-pad up, down */
 	-1				/* terminating entry */
 };
 
@@ -279,17 +288,19 @@ static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *d
 {
 	struct input_dev *dev = xpad->dev;
 
-	/* left stick */
-	input_report_abs(dev, ABS_X,
-			 (__s16) le16_to_cpup((__le16 *)(data + 12)));
-	input_report_abs(dev, ABS_Y,
-			 ~(__s16) le16_to_cpup((__le16 *)(data + 14)));
-
-	/* right stick */
-	input_report_abs(dev, ABS_RX,
-			 (__s16) le16_to_cpup((__le16 *)(data + 16)));
-	input_report_abs(dev, ABS_RY,
-			 ~(__s16) le16_to_cpup((__le16 *)(data + 18)));
+	if (!(xpad->mapping & MAP_STICKS_TO_NULL)) {
+		/* left stick */
+		input_report_abs(dev, ABS_X,
+				 (__s16) le16_to_cpup((__le16 *)(data + 12)));
+		input_report_abs(dev, ABS_Y,
+				 ~(__s16) le16_to_cpup((__le16 *)(data + 14)));
+
+		/* right stick */
+		input_report_abs(dev, ABS_RX,
+				 (__s16) le16_to_cpup((__le16 *)(data + 16)));
+		input_report_abs(dev, ABS_RY,
+				 ~(__s16) le16_to_cpup((__le16 *)(data + 18)));
+	}
 
 	/* triggers left/right */
 	if (xpad->mapping & MAP_TRIGGERS_TO_BUTTONS) {
@@ -302,10 +313,11 @@ static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *d
 
 	/* digital pad */
 	if (xpad->mapping & MAP_DPAD_TO_BUTTONS) {
-		input_report_key(dev, BTN_LEFT,  data[2] & 0x04);
-		input_report_key(dev, BTN_RIGHT, data[2] & 0x08);
-		input_report_key(dev, BTN_0,     data[2] & 0x01); /* up */
-		input_report_key(dev, BTN_1,     data[2] & 0x02); /* down */
+		/* dpad as buttons (left, right, up, down) */
+		input_report_key(dev, BTN_TRIGGER_HAPPY1, data[2] & 0x04);
+		input_report_key(dev, BTN_TRIGGER_HAPPY2, data[2] & 0x08);
+		input_report_key(dev, BTN_TRIGGER_HAPPY3, data[2] & 0x01);
+		input_report_key(dev, BTN_TRIGGER_HAPPY4, data[2] & 0x02);
 	} else {
 		input_report_abs(dev, ABS_HAT0X,
 				 !!(data[2] & 0x08) - !!(data[2] & 0x04));
@@ -315,7 +327,7 @@ static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *d
 
 	/* start/back buttons and stick press left/right */
 	input_report_key(dev, BTN_START,  data[2] & 0x10);
-	input_report_key(dev, BTN_BACK,   data[2] & 0x20);
+	input_report_key(dev, BTN_SELECT, data[2] & 0x20);
 	input_report_key(dev, BTN_THUMBL, data[2] & 0x40);
 	input_report_key(dev, BTN_THUMBR, data[2] & 0x80);
 
@@ -349,11 +361,11 @@ static void xpad360_process_packet(struct usb_xpad *xpad,
 
 	/* digital pad */
 	if (xpad->mapping & MAP_DPAD_TO_BUTTONS) {
-		/* dpad as buttons (right, left, down, up) */
-		input_report_key(dev, BTN_LEFT, data[2] & 0x04);
-		input_report_key(dev, BTN_RIGHT, data[2] & 0x08);
-		input_report_key(dev, BTN_0, data[2] & 0x01);	/* up */
-		input_report_key(dev, BTN_1, data[2] & 0x02);	/* down */
+		/* dpad as buttons (left, right, up, down) */
+		input_report_key(dev, BTN_TRIGGER_HAPPY1, data[2] & 0x04);
+		input_report_key(dev, BTN_TRIGGER_HAPPY2, data[2] & 0x08);
+		input_report_key(dev, BTN_TRIGGER_HAPPY3, data[2] & 0x01);
+		input_report_key(dev, BTN_TRIGGER_HAPPY4, data[2] & 0x02);
 	} else {
 		input_report_abs(dev, ABS_HAT0X,
 				 !!(data[2] & 0x08) - !!(data[2] & 0x04));
@@ -363,7 +375,7 @@ static void xpad360_process_packet(struct usb_xpad *xpad,
 
 	/* start/back buttons */
 	input_report_key(dev, BTN_START,  data[2] & 0x10);
-	input_report_key(dev, BTN_BACK,   data[2] & 0x20);
+	input_report_key(dev, BTN_SELECT, data[2] & 0x20);
 
 	/* stick press left/right */
 	input_report_key(dev, BTN_THUMBL, data[2] & 0x40);
@@ -378,17 +390,19 @@ static void xpad360_process_packet(struct usb_xpad *xpad,
 	input_report_key(dev, BTN_TR,	data[3] & 0x02);
 	input_report_key(dev, BTN_MODE,	data[3] & 0x04);
 
-	/* left stick */
-	input_report_abs(dev, ABS_X,
-			 (__s16) le16_to_cpup((__le16 *)(data + 6)));
-	input_report_abs(dev, ABS_Y,
-			 ~(__s16) le16_to_cpup((__le16 *)(data + 8)));
-
-	/* right stick */
-	input_report_abs(dev, ABS_RX,
-			 (__s16) le16_to_cpup((__le16 *)(data + 10)));
-	input_report_abs(dev, ABS_RY,
-			 ~(__s16) le16_to_cpup((__le16 *)(data + 12)));
+	if (!(xpad->mapping & MAP_STICKS_TO_NULL)) {
+		/* left stick */
+		input_report_abs(dev, ABS_X,
+				 (__s16) le16_to_cpup((__le16 *)(data + 6)));
+		input_report_abs(dev, ABS_Y,
+				 ~(__s16) le16_to_cpup((__le16 *)(data + 8)));
+
+		/* right stick */
+		input_report_abs(dev, ABS_RX,
+				 (__s16) le16_to_cpup((__le16 *)(data + 10)));
+		input_report_abs(dev, ABS_RY,
+				 ~(__s16) le16_to_cpup((__le16 *)(data + 12)));
+	}
 
 	/* triggers left/right */
 	if (xpad->mapping & MAP_TRIGGERS_TO_BUTTONS) {
@@ -814,6 +828,8 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
 			xpad->mapping |= MAP_DPAD_TO_BUTTONS;
 		if (triggers_to_buttons)
 			xpad->mapping |= MAP_TRIGGERS_TO_BUTTONS;
+		if (sticks_to_null)
+			xpad->mapping |= MAP_STICKS_TO_NULL;
 	}
 
 	xpad->dev = input_dev;
@@ -830,16 +846,20 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
 	input_dev->open = xpad_open;
 	input_dev->close = xpad_close;
 
-	input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+	input_dev->evbit[0] = BIT_MASK(EV_KEY);
+
+	if (!(xpad->mapping & MAP_STICKS_TO_NULL)) {
+		input_dev->evbit[0] |= BIT_MASK(EV_ABS);
+		/* set up axes */
+		for (i = 0; xpad_abs[i] >= 0; i++)
+			xpad_set_up_abs(input_dev, xpad_abs[i]);
+	}
 
-	/* set up standard buttons and axes */
+	/* set up standard buttons */
 	for (i = 0; xpad_common_btn[i] >= 0; i++)
 		__set_bit(xpad_common_btn[i], input_dev->keybit);
 
-	for (i = 0; xpad_abs[i] >= 0; i++)
-		xpad_set_up_abs(input_dev, xpad_abs[i]);
-
-	/* Now set up model-specific ones */
+	/* set up model-specific ones */
 	if (xpad->xtype == XTYPE_XBOX360 || xpad->xtype == XTYPE_XBOX360W) {
 		for (i = 0; xpad360_btn[i] >= 0; i++)
 			__set_bit(xpad360_btn[i], input_dev->keybit);
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index 1ba25145b333..b171f63fe4d7 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -297,6 +297,18 @@ config KEYBOARD_MAX7359
 	  To compile this driver as a module, choose M here: the
 	  module will be called max7359_keypad.
 
+config KEYBOARD_MCS
+	tristate "MELFAS MCS Touchkey"
+	depends on I2C
+	help
+	  Say Y here if you have the MELFAS MCS5000/5080 touchkey controller
+	  chip in your system.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called mcs_touchkey.
+
 config KEYBOARD_IMX
 	tristate "IMX keypad support"
 	depends on ARCH_MXC
@@ -342,6 +354,15 @@ config KEYBOARD_PXA930_ROTARY
 	  To compile this driver as a module, choose M here: the
 	  module will be called pxa930_rotary.
 
+config KEYBOARD_SAMSUNG
+	tristate "Samsung keypad support"
+	depends on SAMSUNG_DEV_KEYPAD
+	help
+	  Say Y here if you want to use the Samsung keypad.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called samsung-keypad.
+
 config KEYBOARD_STOWAWAY
 	tristate "Stowaway keyboard"
 	select SERIO
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
index 4596d0c6f922..1a66d5f1ca8b 100644
--- a/drivers/input/keyboard/Makefile
+++ b/drivers/input/keyboard/Makefile
@@ -26,12 +26,14 @@ obj-$(CONFIG_KEYBOARD_LOCOMO)		+= locomokbd.o
 obj-$(CONFIG_KEYBOARD_MAPLE)		+= maple_keyb.o
 obj-$(CONFIG_KEYBOARD_MATRIX)		+= matrix_keypad.o
 obj-$(CONFIG_KEYBOARD_MAX7359)		+= max7359_keypad.o
+obj-$(CONFIG_KEYBOARD_MCS)		+= mcs_touchkey.o
 obj-$(CONFIG_KEYBOARD_NEWTON)		+= newtonkbd.o
 obj-$(CONFIG_KEYBOARD_OMAP)		+= omap-keypad.o
 obj-$(CONFIG_KEYBOARD_OPENCORES)	+= opencores-kbd.o
 obj-$(CONFIG_KEYBOARD_PXA27x)		+= pxa27x_keypad.o
 obj-$(CONFIG_KEYBOARD_PXA930_ROTARY)	+= pxa930_rotary.o
 obj-$(CONFIG_KEYBOARD_QT2160)		+= qt2160.o
+obj-$(CONFIG_KEYBOARD_SAMSUNG)		+= samsung-keypad.o
 obj-$(CONFIG_KEYBOARD_SH_KEYSC)		+= sh_keysc.o
 obj-$(CONFIG_KEYBOARD_STOWAWAY)		+= stowaway.o
 obj-$(CONFIG_KEYBOARD_SUNKBD)		+= sunkbd.o
diff --git a/drivers/input/keyboard/adp5588-keys.c b/drivers/input/keyboard/adp5588-keys.c
index 744600eff222..d6918cb966c0 100644
--- a/drivers/input/keyboard/adp5588-keys.c
+++ b/drivers/input/keyboard/adp5588-keys.c
@@ -19,6 +19,7 @@
 #include <linux/platform_device.h>
 #include <linux/input.h>
 #include <linux/i2c.h>
+#include <linux/gpio.h>
 #include <linux/slab.h>
 
 #include <linux/i2c/adp5588.h>
@@ -54,6 +55,10 @@
 
 #define KEYP_MAX_EVENT		10
 
+#define MAXGPIO			18
+#define ADP_BANK(offs)		((offs) >> 3)
+#define ADP_BIT(offs)		(1u << ((offs) & 0x7))
+
 /*
  * Early pre 4.0 Silicon required to delay readout by at least 25ms,
  * since the Event Counter Register updated 25ms after the interrupt
@@ -67,6 +72,16 @@ struct adp5588_kpad {
 	struct delayed_work work;
 	unsigned long delay;
 	unsigned short keycode[ADP5588_KEYMAPSIZE];
+	const struct adp5588_gpi_map *gpimap;
+	unsigned short gpimapsize;
+#ifdef CONFIG_GPIOLIB
+	unsigned char gpiomap[MAXGPIO];
+	bool export_gpio;
+	struct gpio_chip gc;
+	struct mutex gpio_lock;	/* Protect cached dir, dat_out */
+	u8 dat_out[3];
+	u8 dir[3];
+#endif
 };
 
 static int adp5588_read(struct i2c_client *client, u8 reg)
@@ -84,12 +99,222 @@ static int adp5588_write(struct i2c_client *client, u8 reg, u8 val)
 	return i2c_smbus_write_byte_data(client, reg, val);
 }
 
+#ifdef CONFIG_GPIOLIB
+static int adp5588_gpio_get_value(struct gpio_chip *chip, unsigned off)
+{
+	struct adp5588_kpad *kpad = container_of(chip, struct adp5588_kpad, gc);
+	unsigned int bank = ADP_BANK(kpad->gpiomap[off]);
+	unsigned int bit = ADP_BIT(kpad->gpiomap[off]);
+
+	return !!(adp5588_read(kpad->client, GPIO_DAT_STAT1 + bank) & bit);
+}
+
+static void adp5588_gpio_set_value(struct gpio_chip *chip,
+				   unsigned off, int val)
+{
+	struct adp5588_kpad *kpad = container_of(chip, struct adp5588_kpad, gc);
+	unsigned int bank = ADP_BANK(kpad->gpiomap[off]);
+	unsigned int bit = ADP_BIT(kpad->gpiomap[off]);
+
+	mutex_lock(&kpad->gpio_lock);
+
+	if (val)
+		kpad->dat_out[bank] |= bit;
+	else
+		kpad->dat_out[bank] &= ~bit;
+
+	adp5588_write(kpad->client, GPIO_DAT_OUT1 + bank,
+			   kpad->dat_out[bank]);
+
+	mutex_unlock(&kpad->gpio_lock);
+}
+
+static int adp5588_gpio_direction_input(struct gpio_chip *chip, unsigned off)
+{
+	struct adp5588_kpad *kpad = container_of(chip, struct adp5588_kpad, gc);
+	unsigned int bank = ADP_BANK(kpad->gpiomap[off]);
+	unsigned int bit = ADP_BIT(kpad->gpiomap[off]);
+	int ret;
+
+	mutex_lock(&kpad->gpio_lock);
+
+	kpad->dir[bank] &= ~bit;
+	ret = adp5588_write(kpad->client, GPIO_DIR1 + bank, kpad->dir[bank]);
+
+	mutex_unlock(&kpad->gpio_lock);
+
+	return ret;
+}
+
+static int adp5588_gpio_direction_output(struct gpio_chip *chip,
+					 unsigned off, int val)
+{
+	struct adp5588_kpad *kpad = container_of(chip, struct adp5588_kpad, gc);
+	unsigned int bank = ADP_BANK(kpad->gpiomap[off]);
+	unsigned int bit = ADP_BIT(kpad->gpiomap[off]);
+	int ret;
+
+	mutex_lock(&kpad->gpio_lock);
+
+	kpad->dir[bank] |= bit;
+
+	if (val)
+		kpad->dat_out[bank] |= bit;
+	else
+		kpad->dat_out[bank] &= ~bit;
+
+	ret = adp5588_write(kpad->client, GPIO_DAT_OUT1 + bank,
+				 kpad->dat_out[bank]);
+	ret |= adp5588_write(kpad->client, GPIO_DIR1 + bank,
+				 kpad->dir[bank]);
+
+	mutex_unlock(&kpad->gpio_lock);
+
+	return ret;
+}
+
+static int __devinit adp5588_build_gpiomap(struct adp5588_kpad *kpad,
+				const struct adp5588_kpad_platform_data *pdata)
+{
+	bool pin_used[MAXGPIO];
+	int n_unused = 0;
+	int i;
+
+	memset(pin_used, 0, sizeof(pin_used));
+
+	for (i = 0; i < pdata->rows; i++)
+		pin_used[i] = true;
+
+	for (i = 0; i < pdata->cols; i++)
+		pin_used[i + GPI_PIN_COL_BASE - GPI_PIN_BASE] = true;
+
+	for (i = 0; i < kpad->gpimapsize; i++)
+		pin_used[kpad->gpimap[i].pin - GPI_PIN_BASE] = true;
+
+	for (i = 0; i < MAXGPIO; i++)
+		if (!pin_used[i])
+			kpad->gpiomap[n_unused++] = i;
+
+	return n_unused;
+}
+
+static int __devinit adp5588_gpio_add(struct adp5588_kpad *kpad)
+{
+	struct device *dev = &kpad->client->dev;
+	const struct adp5588_kpad_platform_data *pdata = dev->platform_data;
+	const struct adp5588_gpio_platform_data *gpio_data = pdata->gpio_data;
+	int i, error;
+
+	if (!gpio_data)
+		return 0;
+
+	kpad->gc.ngpio = adp5588_build_gpiomap(kpad, pdata);
+	if (kpad->gc.ngpio == 0) {
+		dev_info(dev, "No unused gpios left to export\n");
+		return 0;
+	}
+
+	kpad->export_gpio = true;
+
+	kpad->gc.direction_input = adp5588_gpio_direction_input;
+	kpad->gc.direction_output = adp5588_gpio_direction_output;
+	kpad->gc.get = adp5588_gpio_get_value;
+	kpad->gc.set = adp5588_gpio_set_value;
+	kpad->gc.can_sleep = 1;
+
+	kpad->gc.base = gpio_data->gpio_start;
+	kpad->gc.label = kpad->client->name;
+	kpad->gc.owner = THIS_MODULE;
+
+	mutex_init(&kpad->gpio_lock);
+
+	error = gpiochip_add(&kpad->gc);
+	if (error) {
+		dev_err(dev, "gpiochip_add failed, err: %d\n", error);
+		return error;
+	}
+
+	for (i = 0; i <= ADP_BANK(MAXGPIO); i++) {
+		kpad->dat_out[i] = adp5588_read(kpad->client,
+						GPIO_DAT_OUT1 + i);
+		kpad->dir[i] = adp5588_read(kpad->client, GPIO_DIR1 + i);
+	}
+
+	if (gpio_data->setup) {
+		error = gpio_data->setup(kpad->client,
+					 kpad->gc.base, kpad->gc.ngpio,
+					 gpio_data->context);
+		if (error)
+			dev_warn(dev, "setup failed, %d\n", error);
+	}
+
+	return 0;
+}
+
+static void __devexit adp5588_gpio_remove(struct adp5588_kpad *kpad)
+{
+	struct device *dev = &kpad->client->dev;
+	const struct adp5588_kpad_platform_data *pdata = dev->platform_data;
+	const struct adp5588_gpio_platform_data *gpio_data = pdata->gpio_data;
+	int error;
+
+	if (!kpad->export_gpio)
+		return;
+
+	if (gpio_data->teardown) {
+		error = gpio_data->teardown(kpad->client,
+					    kpad->gc.base, kpad->gc.ngpio,
+					    gpio_data->context);
+		if (error)
+			dev_warn(dev, "teardown failed %d\n", error);
+	}
+
+	error = gpiochip_remove(&kpad->gc);
+	if (error)
+		dev_warn(dev, "gpiochip_remove failed %d\n", error);
+}
+#else
+static inline int adp5588_gpio_add(struct adp5588_kpad *kpad)
+{
+	return 0;
+}
+
+static inline void adp5588_gpio_remove(struct adp5588_kpad *kpad)
+{
+}
+#endif
+
+static void adp5588_report_events(struct adp5588_kpad *kpad, int ev_cnt)
+{
+	int i, j;
+
+	for (i = 0; i < ev_cnt; i++) {
+		int key = adp5588_read(kpad->client, Key_EVENTA + i);
+		int key_val = key & KEY_EV_MASK;
+
+		if (key_val >= GPI_PIN_BASE && key_val <= GPI_PIN_END) {
+			for (j = 0; j < kpad->gpimapsize; j++) {
+				if (key_val == kpad->gpimap[j].pin) {
+					input_report_switch(kpad->input,
+							kpad->gpimap[j].sw_evt,
+							key & KEY_EV_PRESSED);
+					break;
+				}
+			}
+		} else {
+			input_report_key(kpad->input,
+					 kpad->keycode[key_val - 1],
+					 key & KEY_EV_PRESSED);
+		}
+	}
+}
+
 static void adp5588_work(struct work_struct *work)
 {
 	struct adp5588_kpad *kpad = container_of(work,
 						struct adp5588_kpad, work.work);
 	struct i2c_client *client = kpad->client;
-	int i, key, status, ev_cnt;
+	int status, ev_cnt;
 
 	status = adp5588_read(client, INT_STAT);
 
@@ -99,12 +324,7 @@ static void adp5588_work(struct work_struct *work)
 	if (status & KE_INT) {
 		ev_cnt = adp5588_read(client, KEY_LCK_EC_STAT) & KEC;
 		if (ev_cnt) {
-			for (i = 0; i < ev_cnt; i++) {
-				key = adp5588_read(client, Key_EVENTA + i);
-				input_report_key(kpad->input,
-					kpad->keycode[(key & KEY_EV_MASK) - 1],
-					key & KEY_EV_PRESSED);
-			}
+			adp5588_report_events(kpad, ev_cnt);
 			input_sync(kpad->input);
 		}
 	}
@@ -128,8 +348,10 @@ static irqreturn_t adp5588_irq(int irq, void *handle)
 
 static int __devinit adp5588_setup(struct i2c_client *client)
 {
-	struct adp5588_kpad_platform_data *pdata = client->dev.platform_data;
+	const struct adp5588_kpad_platform_data *pdata = client->dev.platform_data;
+	const struct adp5588_gpio_platform_data *gpio_data = pdata->gpio_data;
 	int i, ret;
+	unsigned char evt_mode1 = 0, evt_mode2 = 0, evt_mode3 = 0;
 
 	ret = adp5588_write(client, KP_GPIO1, KP_SEL(pdata->rows));
 	ret |= adp5588_write(client, KP_GPIO2, KP_SEL(pdata->cols) & 0xFF);
@@ -144,6 +366,32 @@ static int __devinit adp5588_setup(struct i2c_client *client)
 	for (i = 0; i < KEYP_MAX_EVENT; i++)
 		ret |= adp5588_read(client, Key_EVENTA);
 
+	for (i = 0; i < pdata->gpimapsize; i++) {
+		unsigned short pin = pdata->gpimap[i].pin;
+
+		if (pin <= GPI_PIN_ROW_END) {
+			evt_mode1 |= (1 << (pin - GPI_PIN_ROW_BASE));
+		} else {
+			evt_mode2 |= ((1 << (pin - GPI_PIN_COL_BASE)) & 0xFF);
+			evt_mode3 |= ((1 << (pin - GPI_PIN_COL_BASE)) >> 8);
+		}
+	}
+
+	if (pdata->gpimapsize) {
+		ret |= adp5588_write(client, GPI_EM1, evt_mode1);
+		ret |= adp5588_write(client, GPI_EM2, evt_mode2);
+		ret |= adp5588_write(client, GPI_EM3, evt_mode3);
+	}
+
+	if (gpio_data) {
+		for (i = 0; i <= ADP_BANK(MAXGPIO); i++) {
+			int pull_mask = gpio_data->pullup_dis_mask;
+
+			ret |= adp5588_write(client, GPIO_PULL1 + i,
+				(pull_mask >> (8 * i)) & 0xFF);
+		}
+	}
+
 	ret |= adp5588_write(client, INT_STAT, CMP2_INT | CMP1_INT |
 					OVR_FLOW_INT | K_LCK_INT |
 					GPI_INT | KE_INT); /* Status is W1C */
@@ -158,11 +406,49 @@ static int __devinit adp5588_setup(struct i2c_client *client)
 	return 0;
 }
 
+static void __devinit adp5588_report_switch_state(struct adp5588_kpad *kpad)
+{
+	int gpi_stat1 = adp5588_read(kpad->client, GPIO_DAT_STAT1);
+	int gpi_stat2 = adp5588_read(kpad->client, GPIO_DAT_STAT2);
+	int gpi_stat3 = adp5588_read(kpad->client, GPIO_DAT_STAT3);
+	int gpi_stat_tmp, pin_loc;
+	int i;
+
+	for (i = 0; i < kpad->gpimapsize; i++) {
+		unsigned short pin = kpad->gpimap[i].pin;
+
+		if (pin <= GPI_PIN_ROW_END) {
+			gpi_stat_tmp = gpi_stat1;
+			pin_loc = pin - GPI_PIN_ROW_BASE;
+		} else if ((pin - GPI_PIN_COL_BASE) < 8) {
+			gpi_stat_tmp = gpi_stat2;
+			pin_loc = pin - GPI_PIN_COL_BASE;
+		} else {
+			gpi_stat_tmp = gpi_stat3;
+			pin_loc = pin - GPI_PIN_COL_BASE - 8;
+		}
+
+		if (gpi_stat_tmp < 0) {
+			dev_err(&kpad->client->dev,
+				"Can't read GPIO_DAT_STAT switch %d default to OFF\n",
+				pin);
+			gpi_stat_tmp = 0;
+		}
+
+		input_report_switch(kpad->input,
+				    kpad->gpimap[i].sw_evt,
+				    !(gpi_stat_tmp & (1 << pin_loc)));
+	}
+
+	input_sync(kpad->input);
+}
+
+
 static int __devinit adp5588_probe(struct i2c_client *client,
 					const struct i2c_device_id *id)
 {
 	struct adp5588_kpad *kpad;
-	struct adp5588_kpad_platform_data *pdata = client->dev.platform_data;
+	const struct adp5588_kpad_platform_data *pdata = client->dev.platform_data;
 	struct input_dev *input;
 	unsigned int revid;
 	int ret, i;
@@ -189,6 +475,37 @@ static int __devinit adp5588_probe(struct i2c_client *client,
 		return -EINVAL;
 	}
 
+	if (!pdata->gpimap && pdata->gpimapsize) {
+		dev_err(&client->dev, "invalid gpimap from pdata\n");
+		return -EINVAL;
+	}
+
+	if (pdata->gpimapsize > ADP5588_GPIMAPSIZE_MAX) {
+		dev_err(&client->dev, "invalid gpimapsize\n");
+		return -EINVAL;
+	}
+
+	for (i = 0; i < pdata->gpimapsize; i++) {
+		unsigned short pin = pdata->gpimap[i].pin;
+
+		if (pin < GPI_PIN_BASE || pin > GPI_PIN_END) {
+			dev_err(&client->dev, "invalid gpi pin data\n");
+			return -EINVAL;
+		}
+
+		if (pin <= GPI_PIN_ROW_END) {
+			if (pin - GPI_PIN_ROW_BASE + 1 <= pdata->rows) {
+				dev_err(&client->dev, "invalid gpi row data\n");
+				return -EINVAL;
+			}
+		} else {
+			if (pin - GPI_PIN_COL_BASE + 1 <= pdata->cols) {
+				dev_err(&client->dev, "invalid gpi col data\n");
+				return -EINVAL;
+			}
+		}
+	}
+
 	if (!client->irq) {
 		dev_err(&client->dev, "no IRQ?\n");
 		return -EINVAL;
@@ -233,6 +550,9 @@ static int __devinit adp5588_probe(struct i2c_client *client,
 	memcpy(kpad->keycode, pdata->keymap,
 		pdata->keymapsize * input->keycodesize);
 
+	kpad->gpimap = pdata->gpimap;
+	kpad->gpimapsize = pdata->gpimapsize;
+
 	/* setup input device */
 	__set_bit(EV_KEY, input->evbit);
 
@@ -243,6 +563,11 @@ static int __devinit adp5588_probe(struct i2c_client *client,
 		__set_bit(kpad->keycode[i] & KEY_MAX, input->keybit);
 	__clear_bit(KEY_RESERVED, input->keybit);
 
+	if (kpad->gpimapsize)
+		__set_bit(EV_SW, input->evbit);
+	for (i = 0; i < kpad->gpimapsize; i++)
+		__set_bit(kpad->gpimap[i].sw_evt, input->swbit);
+
 	error = input_register_device(input);
 	if (error) {
 		dev_err(&client->dev, "unable to register input device\n");
@@ -261,6 +586,13 @@ static int __devinit adp5588_probe(struct i2c_client *client,
 	if (error)
 		goto err_free_irq;
 
+	if (kpad->gpimapsize)
+		adp5588_report_switch_state(kpad);
+
+	error = adp5588_gpio_add(kpad);
+	if (error)
+		goto err_free_irq;
+
 	device_init_wakeup(&client->dev, 1);
 	i2c_set_clientdata(client, kpad);
 
@@ -287,6 +619,7 @@ static int __devexit adp5588_remove(struct i2c_client *client)
 	free_irq(client->irq, kpad);
 	cancel_delayed_work_sync(&kpad->work);
 	input_unregister_device(kpad->input);
+	adp5588_gpio_remove(kpad);
 	kfree(kpad);
 
 	return 0;
diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c
index b8213fd13c3f..a9fd147f2ba7 100644
--- a/drivers/input/keyboard/gpio_keys.c
+++ b/drivers/input/keyboard/gpio_keys.c
@@ -31,6 +31,7 @@ struct gpio_button_data {
 	struct input_dev *input;
 	struct timer_list timer;
 	struct work_struct work;
+	int timer_debounce;	/* in msecs */
 	bool disabled;
 };
 
@@ -109,7 +110,7 @@ static void gpio_keys_disable_button(struct gpio_button_data *bdata)
 		 * Disable IRQ and possible debouncing timer.
 		 */
 		disable_irq(gpio_to_irq(bdata->button->gpio));
-		if (bdata->button->debounce_interval)
+		if (bdata->timer_debounce)
 			del_timer_sync(&bdata->timer);
 
 		bdata->disabled = true;
@@ -347,9 +348,9 @@ static irqreturn_t gpio_keys_isr(int irq, void *dev_id)
 
 	BUG_ON(irq != gpio_to_irq(button->gpio));
 
-	if (button->debounce_interval)
+	if (bdata->timer_debounce)
 		mod_timer(&bdata->timer,
-			jiffies + msecs_to_jiffies(button->debounce_interval));
+			jiffies + msecs_to_jiffies(bdata->timer_debounce));
 	else
 		schedule_work(&bdata->work);
 
@@ -383,6 +384,14 @@ static int __devinit gpio_keys_setup_key(struct platform_device *pdev,
 		goto fail3;
 	}
 
+	if (button->debounce_interval) {
+		error = gpio_set_debounce(button->gpio,
+					  button->debounce_interval * 1000);
+		/* use timer if gpiolib doesn't provide debounce */
+		if (error < 0)
+			bdata->timer_debounce = button->debounce_interval;
+	}
+
 	irq = gpio_to_irq(button->gpio);
 	if (irq < 0) {
 		error = irq;
@@ -498,7 +507,7 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
  fail2:
 	while (--i >= 0) {
 		free_irq(gpio_to_irq(pdata->buttons[i].gpio), &ddata->data[i]);
-		if (pdata->buttons[i].debounce_interval)
+		if (ddata->data[i].timer_debounce)
 			del_timer_sync(&ddata->data[i].timer);
 		cancel_work_sync(&ddata->data[i].work);
 		gpio_free(pdata->buttons[i].gpio);
@@ -526,7 +535,7 @@ static int __devexit gpio_keys_remove(struct platform_device *pdev)
 	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)
+		if (ddata->data[i].timer_debounce)
 			del_timer_sync(&ddata->data[i].timer);
 		cancel_work_sync(&ddata->data[i].work);
 		gpio_free(pdata->buttons[i].gpio);
diff --git a/drivers/input/keyboard/lm8323.c b/drivers/input/keyboard/lm8323.c
index 40b032f0e32c..f7c2a166576b 100644
--- a/drivers/input/keyboard/lm8323.c
+++ b/drivers/input/keyboard/lm8323.c
@@ -642,6 +642,7 @@ static int __devinit lm8323_probe(struct i2c_client *client,
 	struct lm8323_platform_data *pdata = client->dev.platform_data;
 	struct input_dev *idev;
 	struct lm8323_chip *lm;
+	int pwm;
 	int i, err;
 	unsigned long tmo;
 	u8 data[2];
@@ -710,8 +711,9 @@ static int __devinit lm8323_probe(struct i2c_client *client,
 		goto fail1;
 	}
 
-	for (i = 0; i < LM8323_NUM_PWMS; i++) {
-		err = init_pwm(lm, i + 1, &client->dev, pdata->pwm_names[i]);
+	for (pwm = 0; pwm < LM8323_NUM_PWMS; pwm++) {
+		err = init_pwm(lm, pwm + 1, &client->dev,
+			       pdata->pwm_names[pwm]);
 		if (err < 0)
 			goto fail2;
 	}
@@ -764,9 +766,9 @@ fail4:
 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);
+	while (--pwm >= 0)
+		if (lm->pwm[pwm].enabled)
+			led_classdev_unregister(&lm->pwm[pwm].cdev);
 fail1:
 	input_free_device(idev);
 	kfree(lm);
diff --git a/drivers/input/keyboard/matrix_keypad.c b/drivers/input/keyboard/matrix_keypad.c
index b443e088fd3c..b02e4268e18f 100644
--- a/drivers/input/keyboard/matrix_keypad.c
+++ b/drivers/input/keyboard/matrix_keypad.c
@@ -37,6 +37,7 @@ struct matrix_keypad {
 	spinlock_t lock;
 	bool scan_pending;
 	bool stopped;
+	bool gpio_all_disabled;
 };
 
 /*
@@ -87,8 +88,12 @@ static void enable_row_irqs(struct matrix_keypad *keypad)
 	const struct matrix_keypad_platform_data *pdata = keypad->pdata;
 	int i;
 
-	for (i = 0; i < pdata->num_row_gpios; i++)
-		enable_irq(gpio_to_irq(pdata->row_gpios[i]));
+	if (pdata->clustered_irq > 0)
+		enable_irq(pdata->clustered_irq);
+	else {
+		for (i = 0; i < pdata->num_row_gpios; i++)
+			enable_irq(gpio_to_irq(pdata->row_gpios[i]));
+	}
 }
 
 static void disable_row_irqs(struct matrix_keypad *keypad)
@@ -96,8 +101,12 @@ static void disable_row_irqs(struct matrix_keypad *keypad)
 	const struct matrix_keypad_platform_data *pdata = keypad->pdata;
 	int i;
 
-	for (i = 0; i < pdata->num_row_gpios; i++)
-		disable_irq_nosync(gpio_to_irq(pdata->row_gpios[i]));
+	if (pdata->clustered_irq > 0)
+		disable_irq_nosync(pdata->clustered_irq);
+	else {
+		for (i = 0; i < pdata->num_row_gpios; i++)
+			disable_irq_nosync(gpio_to_irq(pdata->row_gpios[i]));
+	}
 }
 
 /*
@@ -216,45 +225,69 @@ static void matrix_keypad_stop(struct input_dev *dev)
 }
 
 #ifdef CONFIG_PM
-static int matrix_keypad_suspend(struct device *dev)
+static void matrix_keypad_enable_wakeup(struct matrix_keypad *keypad)
 {
-	struct platform_device *pdev = to_platform_device(dev);
-	struct matrix_keypad *keypad = platform_get_drvdata(pdev);
 	const struct matrix_keypad_platform_data *pdata = keypad->pdata;
+	unsigned int gpio;
 	int i;
 
-	matrix_keypad_stop(keypad->input_dev);
+	if (pdata->clustered_irq > 0) {
+		if (enable_irq_wake(pdata->clustered_irq) == 0)
+			keypad->gpio_all_disabled = true;
+	} else {
 
-	if (device_may_wakeup(&pdev->dev)) {
 		for (i = 0; i < pdata->num_row_gpios; i++) {
 			if (!test_bit(i, keypad->disabled_gpios)) {
-				unsigned int gpio = pdata->row_gpios[i];
+				gpio = pdata->row_gpios[i];
 
 				if (enable_irq_wake(gpio_to_irq(gpio)) == 0)
 					__set_bit(i, keypad->disabled_gpios);
 			}
 		}
 	}
-
-	return 0;
 }
 
-static int matrix_keypad_resume(struct device *dev)
+static void matrix_keypad_disable_wakeup(struct matrix_keypad *keypad)
 {
-	struct platform_device *pdev = to_platform_device(dev);
-	struct matrix_keypad *keypad = platform_get_drvdata(pdev);
 	const struct matrix_keypad_platform_data *pdata = keypad->pdata;
+	unsigned int gpio;
 	int i;
 
-	if (device_may_wakeup(&pdev->dev)) {
+	if (pdata->clustered_irq > 0) {
+		if (keypad->gpio_all_disabled) {
+			disable_irq_wake(pdata->clustered_irq);
+			keypad->gpio_all_disabled = false;
+		}
+	} else {
 		for (i = 0; i < pdata->num_row_gpios; i++) {
 			if (test_and_clear_bit(i, keypad->disabled_gpios)) {
-				unsigned int gpio = pdata->row_gpios[i];
-
+				gpio = pdata->row_gpios[i];
 				disable_irq_wake(gpio_to_irq(gpio));
 			}
 		}
 	}
+}
+
+static int matrix_keypad_suspend(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct matrix_keypad *keypad = platform_get_drvdata(pdev);
+
+	matrix_keypad_stop(keypad->input_dev);
+
+	if (device_may_wakeup(&pdev->dev))
+		matrix_keypad_enable_wakeup(keypad);
+
+	return 0;
+}
+
+static int matrix_keypad_resume(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct matrix_keypad *keypad = platform_get_drvdata(pdev);
+
+	if (device_may_wakeup(&pdev->dev))
+		matrix_keypad_disable_wakeup(keypad);
 
 	matrix_keypad_start(keypad->input_dev);
 
@@ -296,17 +329,31 @@ static int __devinit init_matrix_gpio(struct platform_device *pdev,
 		gpio_direction_input(pdata->row_gpios[i]);
 	}
 
-	for (i = 0; i < pdata->num_row_gpios; i++) {
-		err = request_irq(gpio_to_irq(pdata->row_gpios[i]),
+	if (pdata->clustered_irq > 0) {
+		err = request_irq(pdata->clustered_irq,
 				matrix_keypad_interrupt,
-				IRQF_DISABLED |
-				IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+				pdata->clustered_irq_flags,
 				"matrix-keypad", keypad);
 		if (err) {
 			dev_err(&pdev->dev,
-				"Unable to acquire interrupt for GPIO line %i\n",
-				pdata->row_gpios[i]);
-			goto err_free_irqs;
+				"Unable to acquire clustered interrupt\n");
+			goto err_free_rows;
+		}
+	} else {
+		for (i = 0; i < pdata->num_row_gpios; i++) {
+			err = request_irq(gpio_to_irq(pdata->row_gpios[i]),
+					matrix_keypad_interrupt,
+					IRQF_DISABLED |
+					IRQF_TRIGGER_RISING |
+					IRQF_TRIGGER_FALLING,
+					"matrix-keypad", keypad);
+			if (err) {
+				dev_err(&pdev->dev,
+					"Unable to acquire interrupt "
+					"for GPIO line %i\n",
+					pdata->row_gpios[i]);
+				goto err_free_irqs;
+			}
 		}
 	}
 
@@ -418,11 +465,16 @@ static int __devexit matrix_keypad_remove(struct platform_device *pdev)
 
 	device_init_wakeup(&pdev->dev, 0);
 
-	for (i = 0; i < pdata->num_row_gpios; i++) {
-		free_irq(gpio_to_irq(pdata->row_gpios[i]), keypad);
-		gpio_free(pdata->row_gpios[i]);
+	if (pdata->clustered_irq > 0) {
+		free_irq(pdata->clustered_irq, keypad);
+	} else {
+		for (i = 0; i < pdata->num_row_gpios; i++)
+			free_irq(gpio_to_irq(pdata->row_gpios[i]), keypad);
 	}
 
+	for (i = 0; i < pdata->num_row_gpios; i++)
+		gpio_free(pdata->row_gpios[i]);
+
 	for (i = 0; i < pdata->num_col_gpios; i++)
 		gpio_free(pdata->col_gpios[i]);
 
diff --git a/drivers/input/keyboard/mcs_touchkey.c b/drivers/input/keyboard/mcs_touchkey.c
new file mode 100644
index 000000000000..63b849d7e90b
--- /dev/null
+++ b/drivers/input/keyboard/mcs_touchkey.c
@@ -0,0 +1,239 @@
+/*
+ * mcs_touchkey.c - Touchkey driver for MELFAS MCS5000/5080 controller
+ *
+ * Copyright (C) 2010 Samsung Electronics Co.Ltd
+ * Author: HeungJun Kim <riverful.kim@samsung.com>
+ * Author: Joonyoung Shim <jy0922.shim@samsung.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;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/i2c/mcs.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+#include <linux/irq.h>
+#include <linux/slab.h>
+
+/* MCS5000 Touchkey */
+#define MCS5000_TOUCHKEY_STATUS		0x04
+#define MCS5000_TOUCHKEY_STATUS_PRESS	7
+#define MCS5000_TOUCHKEY_FW		0x0a
+#define MCS5000_TOUCHKEY_BASE_VAL	0x61
+
+/* MCS5080 Touchkey */
+#define MCS5080_TOUCHKEY_STATUS		0x00
+#define MCS5080_TOUCHKEY_STATUS_PRESS	3
+#define MCS5080_TOUCHKEY_FW		0x01
+#define MCS5080_TOUCHKEY_BASE_VAL	0x1
+
+enum mcs_touchkey_type {
+	MCS5000_TOUCHKEY,
+	MCS5080_TOUCHKEY,
+};
+
+struct mcs_touchkey_chip {
+	unsigned int status_reg;
+	unsigned int pressbit;
+	unsigned int press_invert;
+	unsigned int baseval;
+};
+
+struct mcs_touchkey_data {
+	struct i2c_client *client;
+	struct input_dev *input_dev;
+	struct mcs_touchkey_chip chip;
+	unsigned int key_code;
+	unsigned int key_val;
+	unsigned short keycodes[];
+};
+
+static irqreturn_t mcs_touchkey_interrupt(int irq, void *dev_id)
+{
+	struct mcs_touchkey_data *data = dev_id;
+	struct mcs_touchkey_chip *chip = &data->chip;
+	struct i2c_client *client = data->client;
+	struct input_dev *input = data->input_dev;
+	unsigned int key_val;
+	unsigned int pressed;
+	int val;
+
+	val = i2c_smbus_read_byte_data(client, chip->status_reg);
+	if (val < 0) {
+		dev_err(&client->dev, "i2c read error [%d]\n", val);
+		goto out;
+	}
+
+	pressed = (val & (1 << chip->pressbit)) >> chip->pressbit;
+	if (chip->press_invert)
+		pressed ^= chip->press_invert;
+
+	/* key_val is 0 when released, so we should use key_val of press. */
+	if (pressed) {
+		key_val = val & (0xff >> (8 - chip->pressbit));
+		if (!key_val)
+			goto out;
+		key_val -= chip->baseval;
+		data->key_code = data->keycodes[key_val];
+		data->key_val = key_val;
+	}
+
+	input_event(input, EV_MSC, MSC_SCAN, data->key_val);
+	input_report_key(input, data->key_code, pressed);
+	input_sync(input);
+
+	dev_dbg(&client->dev, "key %d %d %s\n", data->key_val, data->key_code,
+		pressed ? "pressed" : "released");
+
+ out:
+	return IRQ_HANDLED;
+}
+
+static int __devinit mcs_touchkey_probe(struct i2c_client *client,
+		const struct i2c_device_id *id)
+{
+	const struct mcs_platform_data *pdata;
+	struct mcs_touchkey_data *data;
+	struct input_dev *input_dev;
+	unsigned int fw_reg;
+	int fw_ver;
+	int error;
+	int i;
+
+	pdata = client->dev.platform_data;
+	if (!pdata) {
+		dev_err(&client->dev, "no platform data defined\n");
+		return -EINVAL;
+	}
+
+	data = kzalloc(sizeof(struct mcs_touchkey_data) +
+			sizeof(data->keycodes[0]) * (pdata->key_maxval + 1),
+			GFP_KERNEL);
+	input_dev = input_allocate_device();
+	if (!data || !input_dev) {
+		dev_err(&client->dev, "Failed to allocate memory\n");
+		error = -ENOMEM;
+		goto err_free_mem;
+	}
+
+	data->client = client;
+	data->input_dev = input_dev;
+
+	if (id->driver_data == MCS5000_TOUCHKEY) {
+		data->chip.status_reg = MCS5000_TOUCHKEY_STATUS;
+		data->chip.pressbit = MCS5000_TOUCHKEY_STATUS_PRESS;
+		data->chip.baseval = MCS5000_TOUCHKEY_BASE_VAL;
+		fw_reg = MCS5000_TOUCHKEY_FW;
+	} else {
+		data->chip.status_reg = MCS5080_TOUCHKEY_STATUS;
+		data->chip.pressbit = MCS5080_TOUCHKEY_STATUS_PRESS;
+		data->chip.press_invert = 1;
+		data->chip.baseval = MCS5080_TOUCHKEY_BASE_VAL;
+		fw_reg = MCS5080_TOUCHKEY_FW;
+	}
+
+	fw_ver = i2c_smbus_read_byte_data(client, fw_reg);
+	if (fw_ver < 0) {
+		error = fw_ver;
+		dev_err(&client->dev, "i2c read error[%d]\n", error);
+		goto err_free_mem;
+	}
+	dev_info(&client->dev, "Firmware version: %d\n", fw_ver);
+
+	input_dev->name = "MELPAS MCS Touchkey";
+	input_dev->id.bustype = BUS_I2C;
+	input_dev->dev.parent = &client->dev;
+	input_dev->evbit[0] = BIT_MASK(EV_KEY);
+	if (!pdata->no_autorepeat)
+		input_dev->evbit[0] |= BIT_MASK(EV_REP);
+	input_dev->keycode = data->keycodes;
+	input_dev->keycodesize = sizeof(data->keycodes[0]);
+	input_dev->keycodemax = pdata->key_maxval + 1;
+
+	for (i = 0; i < pdata->keymap_size; i++) {
+		unsigned int val = MCS_KEY_VAL(pdata->keymap[i]);
+		unsigned int code = MCS_KEY_CODE(pdata->keymap[i]);
+
+		data->keycodes[val] = code;
+		__set_bit(code, input_dev->keybit);
+	}
+
+	input_set_capability(input_dev, EV_MSC, MSC_SCAN);
+	input_set_drvdata(input_dev, data);
+
+	if (pdata->cfg_pin)
+		pdata->cfg_pin();
+
+	error = request_threaded_irq(client->irq, NULL, mcs_touchkey_interrupt,
+			IRQF_TRIGGER_FALLING, client->dev.driver->name, data);
+	if (error) {
+		dev_err(&client->dev, "Failed to register interrupt\n");
+		goto err_free_mem;
+	}
+
+	error = input_register_device(input_dev);
+	if (error)
+		goto err_free_irq;
+
+	i2c_set_clientdata(client, data);
+	return 0;
+
+err_free_irq:
+	free_irq(client->irq, data);
+err_free_mem:
+	input_free_device(input_dev);
+	kfree(data);
+	return error;
+}
+
+static int __devexit mcs_touchkey_remove(struct i2c_client *client)
+{
+	struct mcs_touchkey_data *data = i2c_get_clientdata(client);
+
+	free_irq(client->irq, data);
+	input_unregister_device(data->input_dev);
+	kfree(data);
+
+	return 0;
+}
+
+static const struct i2c_device_id mcs_touchkey_id[] = {
+	{ "mcs5000_touchkey", MCS5000_TOUCHKEY },
+	{ "mcs5080_touchkey", MCS5080_TOUCHKEY },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, mcs_touchkey_id);
+
+static struct i2c_driver mcs_touchkey_driver = {
+	.driver = {
+		.name	= "mcs_touchkey",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= mcs_touchkey_probe,
+	.remove		= __devexit_p(mcs_touchkey_remove),
+	.id_table	= mcs_touchkey_id,
+};
+
+static int __init mcs_touchkey_init(void)
+{
+	return i2c_add_driver(&mcs_touchkey_driver);
+}
+
+static void __exit mcs_touchkey_exit(void)
+{
+	i2c_del_driver(&mcs_touchkey_driver);
+}
+
+module_init(mcs_touchkey_init);
+module_exit(mcs_touchkey_exit);
+
+/* Module information */
+MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
+MODULE_AUTHOR("HeungJun Kim <riverful.kim@samsung.com>");
+MODULE_DESCRIPTION("Touchkey driver for MELFAS MCS5000/5080 controller");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/keyboard/samsung-keypad.c b/drivers/input/keyboard/samsung-keypad.c
new file mode 100644
index 000000000000..f689f49e3109
--- /dev/null
+++ b/drivers/input/keyboard/samsung-keypad.c
@@ -0,0 +1,491 @@
+/*
+ * Samsung keypad driver
+ *
+ * Copyright (C) 2010 Samsung Electronics Co.Ltd
+ * Author: Joonyoung Shim <jy0922.shim@samsung.com>
+ * Author: Donghwa Lee <dh09.lee@samsung.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;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <plat/keypad.h>
+
+#define SAMSUNG_KEYIFCON			0x00
+#define SAMSUNG_KEYIFSTSCLR			0x04
+#define SAMSUNG_KEYIFCOL			0x08
+#define SAMSUNG_KEYIFROW			0x0c
+#define SAMSUNG_KEYIFFC				0x10
+
+/* SAMSUNG_KEYIFCON */
+#define SAMSUNG_KEYIFCON_INT_F_EN		(1 << 0)
+#define SAMSUNG_KEYIFCON_INT_R_EN		(1 << 1)
+#define SAMSUNG_KEYIFCON_DF_EN			(1 << 2)
+#define SAMSUNG_KEYIFCON_FC_EN			(1 << 3)
+#define SAMSUNG_KEYIFCON_WAKEUPEN		(1 << 4)
+
+/* SAMSUNG_KEYIFSTSCLR */
+#define SAMSUNG_KEYIFSTSCLR_P_INT_MASK		(0xff << 0)
+#define SAMSUNG_KEYIFSTSCLR_R_INT_MASK		(0xff << 8)
+#define SAMSUNG_KEYIFSTSCLR_R_INT_OFFSET	8
+#define S5PV210_KEYIFSTSCLR_P_INT_MASK		(0x3fff << 0)
+#define S5PV210_KEYIFSTSCLR_R_INT_MASK		(0x3fff << 16)
+#define S5PV210_KEYIFSTSCLR_R_INT_OFFSET	16
+
+/* SAMSUNG_KEYIFCOL */
+#define SAMSUNG_KEYIFCOL_MASK			(0xff << 0)
+#define S5PV210_KEYIFCOLEN_MASK			(0xff << 8)
+
+/* SAMSUNG_KEYIFROW */
+#define SAMSUNG_KEYIFROW_MASK			(0xff << 0)
+#define S5PV210_KEYIFROW_MASK			(0x3fff << 0)
+
+/* SAMSUNG_KEYIFFC */
+#define SAMSUNG_KEYIFFC_MASK			(0x3ff << 0)
+
+enum samsung_keypad_type {
+	KEYPAD_TYPE_SAMSUNG,
+	KEYPAD_TYPE_S5PV210,
+};
+
+struct samsung_keypad {
+	struct input_dev *input_dev;
+	struct clk *clk;
+	void __iomem *base;
+	wait_queue_head_t wait;
+	bool stopped;
+	int irq;
+	unsigned int row_shift;
+	unsigned int rows;
+	unsigned int cols;
+	unsigned int row_state[SAMSUNG_MAX_COLS];
+	unsigned short keycodes[];
+};
+
+static int samsung_keypad_is_s5pv210(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	enum samsung_keypad_type type =
+		platform_get_device_id(pdev)->driver_data;
+
+	return type == KEYPAD_TYPE_S5PV210;
+}
+
+static void samsung_keypad_scan(struct samsung_keypad *keypad,
+				unsigned int *row_state)
+{
+	struct device *dev = keypad->input_dev->dev.parent;
+	unsigned int col;
+	unsigned int val;
+
+	for (col = 0; col < keypad->cols; col++) {
+		if (samsung_keypad_is_s5pv210(dev)) {
+			val = S5PV210_KEYIFCOLEN_MASK;
+			val &= ~(1 << col) << 8;
+		} else {
+			val = SAMSUNG_KEYIFCOL_MASK;
+			val &= ~(1 << col);
+		}
+
+		writel(val, keypad->base + SAMSUNG_KEYIFCOL);
+		mdelay(1);
+
+		val = readl(keypad->base + SAMSUNG_KEYIFROW);
+		row_state[col] = ~val & ((1 << keypad->rows) - 1);
+	}
+
+	/* KEYIFCOL reg clear */
+	writel(0, keypad->base + SAMSUNG_KEYIFCOL);
+}
+
+static bool samsung_keypad_report(struct samsung_keypad *keypad,
+				  unsigned int *row_state)
+{
+	struct input_dev *input_dev = keypad->input_dev;
+	unsigned int changed;
+	unsigned int pressed;
+	unsigned int key_down = 0;
+	unsigned int val;
+	unsigned int col, row;
+
+	for (col = 0; col < keypad->cols; col++) {
+		changed = row_state[col] ^ keypad->row_state[col];
+		key_down |= row_state[col];
+		if (!changed)
+			continue;
+
+		for (row = 0; row < keypad->rows; row++) {
+			if (!(changed & (1 << row)))
+				continue;
+
+			pressed = row_state[col] & (1 << row);
+
+			dev_dbg(&keypad->input_dev->dev,
+				"key %s, row: %d, col: %d\n",
+				pressed ? "pressed" : "released", row, col);
+
+			val = MATRIX_SCAN_CODE(row, col, keypad->row_shift);
+
+			input_event(input_dev, EV_MSC, MSC_SCAN, val);
+			input_report_key(input_dev,
+					keypad->keycodes[val], pressed);
+		}
+		input_sync(keypad->input_dev);
+	}
+
+	memcpy(keypad->row_state, row_state, sizeof(keypad->row_state));
+
+	return key_down;
+}
+
+static irqreturn_t samsung_keypad_irq(int irq, void *dev_id)
+{
+	struct samsung_keypad *keypad = dev_id;
+	unsigned int row_state[SAMSUNG_MAX_COLS];
+	unsigned int val;
+	bool key_down;
+
+	do {
+		val = readl(keypad->base + SAMSUNG_KEYIFSTSCLR);
+		/* Clear interrupt. */
+		writel(~0x0, keypad->base + SAMSUNG_KEYIFSTSCLR);
+
+		samsung_keypad_scan(keypad, row_state);
+
+		key_down = samsung_keypad_report(keypad, row_state);
+		if (key_down)
+			wait_event_timeout(keypad->wait, keypad->stopped,
+					   msecs_to_jiffies(50));
+
+	} while (key_down && !keypad->stopped);
+
+	return IRQ_HANDLED;
+}
+
+static void samsung_keypad_start(struct samsung_keypad *keypad)
+{
+	unsigned int val;
+
+	/* Tell IRQ thread that it may poll the device. */
+	keypad->stopped = false;
+
+	clk_enable(keypad->clk);
+
+	/* Enable interrupt bits. */
+	val = readl(keypad->base + SAMSUNG_KEYIFCON);
+	val |= SAMSUNG_KEYIFCON_INT_F_EN | SAMSUNG_KEYIFCON_INT_R_EN;
+	writel(val, keypad->base + SAMSUNG_KEYIFCON);
+
+	/* KEYIFCOL reg clear. */
+	writel(0, keypad->base + SAMSUNG_KEYIFCOL);
+}
+
+static void samsung_keypad_stop(struct samsung_keypad *keypad)
+{
+	unsigned int val;
+
+	/* Signal IRQ thread to stop polling and disable the handler. */
+	keypad->stopped = true;
+	wake_up(&keypad->wait);
+	disable_irq(keypad->irq);
+
+	/* Clear interrupt. */
+	writel(~0x0, keypad->base + SAMSUNG_KEYIFSTSCLR);
+
+	/* Disable interrupt bits. */
+	val = readl(keypad->base + SAMSUNG_KEYIFCON);
+	val &= ~(SAMSUNG_KEYIFCON_INT_F_EN | SAMSUNG_KEYIFCON_INT_R_EN);
+	writel(val, keypad->base + SAMSUNG_KEYIFCON);
+
+	clk_disable(keypad->clk);
+
+	/*
+	 * Now that chip should not generate interrupts we can safely
+	 * re-enable the handler.
+	 */
+	enable_irq(keypad->irq);
+}
+
+static int samsung_keypad_open(struct input_dev *input_dev)
+{
+	struct samsung_keypad *keypad = input_get_drvdata(input_dev);
+
+	samsung_keypad_start(keypad);
+
+	return 0;
+}
+
+static void samsung_keypad_close(struct input_dev *input_dev)
+{
+	struct samsung_keypad *keypad = input_get_drvdata(input_dev);
+
+	samsung_keypad_stop(keypad);
+}
+
+static int __devinit samsung_keypad_probe(struct platform_device *pdev)
+{
+	const struct samsung_keypad_platdata *pdata;
+	const struct matrix_keymap_data *keymap_data;
+	struct samsung_keypad *keypad;
+	struct resource *res;
+	struct input_dev *input_dev;
+	unsigned int row_shift;
+	unsigned int keymap_size;
+	int error;
+
+	pdata = pdev->dev.platform_data;
+	if (!pdata) {
+		dev_err(&pdev->dev, "no platform data defined\n");
+		return -EINVAL;
+	}
+
+	keymap_data = pdata->keymap_data;
+	if (!keymap_data) {
+		dev_err(&pdev->dev, "no keymap data defined\n");
+		return -EINVAL;
+	}
+
+	if (!pdata->rows || pdata->rows > SAMSUNG_MAX_ROWS)
+		return -EINVAL;
+
+	if (!pdata->cols || pdata->cols > SAMSUNG_MAX_COLS)
+		return -EINVAL;
+
+	/* initialize the gpio */
+	if (pdata->cfg_gpio)
+		pdata->cfg_gpio(pdata->rows, pdata->cols);
+
+	row_shift = get_count_order(pdata->cols);
+	keymap_size = (pdata->rows << row_shift) * sizeof(keypad->keycodes[0]);
+
+	keypad = kzalloc(sizeof(*keypad) + keymap_size, GFP_KERNEL);
+	input_dev = input_allocate_device();
+	if (!keypad || !input_dev) {
+		error = -ENOMEM;
+		goto err_free_mem;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		error = -ENODEV;
+		goto err_free_mem;
+	}
+
+	keypad->base = ioremap(res->start, resource_size(res));
+	if (!keypad->base) {
+		error = -EBUSY;
+		goto err_free_mem;
+	}
+
+	keypad->clk = clk_get(&pdev->dev, "keypad");
+	if (IS_ERR(keypad->clk)) {
+		dev_err(&pdev->dev, "failed to get keypad clk\n");
+		error = PTR_ERR(keypad->clk);
+		goto err_unmap_base;
+	}
+
+	keypad->input_dev = input_dev;
+	keypad->row_shift = row_shift;
+	keypad->rows = pdata->rows;
+	keypad->cols = pdata->cols;
+	init_waitqueue_head(&keypad->wait);
+
+	input_dev->name = pdev->name;
+	input_dev->id.bustype = BUS_HOST;
+	input_dev->dev.parent = &pdev->dev;
+	input_set_drvdata(input_dev, keypad);
+
+	input_dev->open = samsung_keypad_open;
+	input_dev->close = samsung_keypad_close;
+
+	input_dev->evbit[0] = BIT_MASK(EV_KEY);
+	if (!pdata->no_autorepeat)
+		input_dev->evbit[0] |= BIT_MASK(EV_REP);
+
+	input_set_capability(input_dev, EV_MSC, MSC_SCAN);
+
+	input_dev->keycode = keypad->keycodes;
+	input_dev->keycodesize = sizeof(keypad->keycodes[0]);
+	input_dev->keycodemax = pdata->rows << row_shift;
+
+	matrix_keypad_build_keymap(keymap_data, row_shift,
+			input_dev->keycode, input_dev->keybit);
+
+	keypad->irq = platform_get_irq(pdev, 0);
+	if (keypad->irq < 0) {
+		error = keypad->irq;
+		goto err_put_clk;
+	}
+
+	error = request_threaded_irq(keypad->irq, NULL, samsung_keypad_irq,
+			IRQF_ONESHOT, dev_name(&pdev->dev), keypad);
+	if (error) {
+		dev_err(&pdev->dev, "failed to register keypad interrupt\n");
+		goto err_put_clk;
+	}
+
+	error = input_register_device(keypad->input_dev);
+	if (error)
+		goto err_free_irq;
+
+	device_init_wakeup(&pdev->dev, pdata->wakeup);
+	platform_set_drvdata(pdev, keypad);
+	return 0;
+
+err_free_irq:
+	free_irq(keypad->irq, keypad);
+err_put_clk:
+	clk_put(keypad->clk);
+err_unmap_base:
+	iounmap(keypad->base);
+err_free_mem:
+	input_free_device(input_dev);
+	kfree(keypad);
+
+	return error;
+}
+
+static int __devexit samsung_keypad_remove(struct platform_device *pdev)
+{
+	struct samsung_keypad *keypad = platform_get_drvdata(pdev);
+
+	device_init_wakeup(&pdev->dev, 0);
+	platform_set_drvdata(pdev, NULL);
+
+	input_unregister_device(keypad->input_dev);
+
+	/*
+	 * It is safe to free IRQ after unregistering device because
+	 * samsung_keypad_close will shut off interrupts.
+	 */
+	free_irq(keypad->irq, keypad);
+
+	clk_put(keypad->clk);
+
+	iounmap(keypad->base);
+	kfree(keypad);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static void samsung_keypad_toggle_wakeup(struct samsung_keypad *keypad,
+					 bool enable)
+{
+	struct device *dev = keypad->input_dev->dev.parent;
+	unsigned int val;
+
+	clk_enable(keypad->clk);
+
+	val = readl(keypad->base + SAMSUNG_KEYIFCON);
+	if (enable) {
+		val |= SAMSUNG_KEYIFCON_WAKEUPEN;
+		if (device_may_wakeup(dev))
+			enable_irq_wake(keypad->irq);
+	} else {
+		val &= ~SAMSUNG_KEYIFCON_WAKEUPEN;
+		if (device_may_wakeup(dev))
+			disable_irq_wake(keypad->irq);
+	}
+	writel(val, keypad->base + SAMSUNG_KEYIFCON);
+
+	clk_disable(keypad->clk);
+}
+
+static int samsung_keypad_suspend(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct samsung_keypad *keypad = platform_get_drvdata(pdev);
+	struct input_dev *input_dev = keypad->input_dev;
+
+	mutex_lock(&input_dev->mutex);
+
+	if (input_dev->users)
+		samsung_keypad_stop(keypad);
+
+	samsung_keypad_toggle_wakeup(keypad, true);
+
+	mutex_unlock(&input_dev->mutex);
+
+	return 0;
+}
+
+static int samsung_keypad_resume(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct samsung_keypad *keypad = platform_get_drvdata(pdev);
+	struct input_dev *input_dev = keypad->input_dev;
+
+	mutex_lock(&input_dev->mutex);
+
+	samsung_keypad_toggle_wakeup(keypad, false);
+
+	if (input_dev->users)
+		samsung_keypad_start(keypad);
+
+	mutex_unlock(&input_dev->mutex);
+
+	return 0;
+}
+
+static const struct dev_pm_ops samsung_keypad_pm_ops = {
+	.suspend	= samsung_keypad_suspend,
+	.resume		= samsung_keypad_resume,
+};
+#endif
+
+static struct platform_device_id samsung_keypad_driver_ids[] = {
+	{
+		.name		= "samsung-keypad",
+		.driver_data	= KEYPAD_TYPE_SAMSUNG,
+	}, {
+		.name		= "s5pv210-keypad",
+		.driver_data	= KEYPAD_TYPE_S5PV210,
+	},
+	{ },
+};
+MODULE_DEVICE_TABLE(platform, samsung_keypad_driver_ids);
+
+static struct platform_driver samsung_keypad_driver = {
+	.probe		= samsung_keypad_probe,
+	.remove		= __devexit_p(samsung_keypad_remove),
+	.driver		= {
+		.name	= "samsung-keypad",
+		.owner	= THIS_MODULE,
+#ifdef CONFIG_PM
+		.pm	= &samsung_keypad_pm_ops,
+#endif
+	},
+	.id_table	= samsung_keypad_driver_ids,
+};
+
+static int __init samsung_keypad_init(void)
+{
+	return platform_driver_register(&samsung_keypad_driver);
+}
+module_init(samsung_keypad_init);
+
+static void __exit samsung_keypad_exit(void)
+{
+	platform_driver_unregister(&samsung_keypad_driver);
+}
+module_exit(samsung_keypad_exit);
+
+MODULE_DESCRIPTION("Samsung keypad driver");
+MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
+MODULE_AUTHOR("Donghwa Lee <dh09.lee@samsung.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:samsung-keypad");
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index c44b9eafc556..b49e23379723 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -327,6 +327,17 @@ config INPUT_PCF8574
 	  To compile this driver as a module, choose M here: the
 	  module will be called pcf8574_keypad.
 
+config INPUT_PWM_BEEPER
+	tristate "PWM beeper support"
+	depends on HAVE_PWM
+	help
+	  Say Y here to get support for PWM based beeper devices.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the module will be
+	  called pwm-beeper.
+
 config INPUT_GPIO_ROTARY_ENCODER
 	tristate "Rotary encoders connected to GPIO pins"
 	depends on GPIOLIB && GENERIC_GPIO
@@ -390,4 +401,41 @@ config INPUT_PCAP
 	  To compile this driver as a module, choose M here: the
 	  module will be called pcap_keys.
 
+config INPUT_ADXL34X
+	tristate "Analog Devices ADXL34x Three-Axis Digital Accelerometer"
+	default n
+	help
+	  Say Y here if you have a Accelerometer interface using the
+	  ADXL345/6 controller, and your board-specific initialization
+	  code includes that in its table of devices.
+
+	  This driver can use either I2C or SPI communication to the
+	  ADXL345/6 controller.  Select the appropriate method for
+	  your system.
+
+	  If unsure, say N (but it's safe to say "Y").
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called adxl34x.
+
+config INPUT_ADXL34X_I2C
+	tristate "support I2C bus connection"
+	depends on INPUT_ADXL34X && I2C
+	default y
+	help
+	  Say Y here if you have ADXL345/6 hooked to an I2C bus.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called adxl34x-i2c.
+
+config INPUT_ADXL34X_SPI
+	tristate "support SPI bus connection"
+	depends on INPUT_ADXL34X && SPI
+	default y
+	help
+	  Say Y here if you have ADXL345/6 hooked to a SPI bus.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called adxl34x-spi.
+
 endif
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index 71fe57d8023f..19ccca78fa76 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -8,6 +8,9 @@ obj-$(CONFIG_INPUT_88PM860X_ONKEY)	+= 88pm860x_onkey.o
 obj-$(CONFIG_INPUT_AD714X)		+= ad714x.o
 obj-$(CONFIG_INPUT_AD714X_I2C)		+= ad714x-i2c.o
 obj-$(CONFIG_INPUT_AD714X_SPI)		+= ad714x-spi.o
+obj-$(CONFIG_INPUT_ADXL34X)		+= adxl34x.o
+obj-$(CONFIG_INPUT_ADXL34X_I2C)		+= adxl34x-i2c.o
+obj-$(CONFIG_INPUT_ADXL34X_SPI)		+= adxl34x-spi.o
 obj-$(CONFIG_INPUT_APANEL)		+= apanel.o
 obj-$(CONFIG_INPUT_ATI_REMOTE)		+= ati_remote.o
 obj-$(CONFIG_INPUT_ATI_REMOTE2)		+= ati_remote2.o
@@ -26,6 +29,7 @@ obj-$(CONFIG_INPUT_PCF50633_PMU)	+= pcf50633-input.o
 obj-$(CONFIG_INPUT_PCF8574)		+= pcf8574_keypad.o
 obj-$(CONFIG_INPUT_PCSPKR)		+= pcspkr.o
 obj-$(CONFIG_INPUT_POWERMATE)		+= powermate.o
+obj-$(CONFIG_INPUT_PWM_BEEPER)		+= pwm-beeper.o
 obj-$(CONFIG_INPUT_RB532_BUTTON)	+= rb532_button.o
 obj-$(CONFIG_INPUT_GPIO_ROTARY_ENCODER)	+= rotary_encoder.o
 obj-$(CONFIG_INPUT_SGI_BTNS)		+= sgi_btns.o
diff --git a/drivers/input/misc/adxl34x-i2c.c b/drivers/input/misc/adxl34x-i2c.c
new file mode 100644
index 000000000000..0779724af7e7
--- /dev/null
+++ b/drivers/input/misc/adxl34x-i2c.c
@@ -0,0 +1,163 @@
+/*
+ * ADLX345/346 Three-Axis Digital Accelerometers (I2C Interface)
+ *
+ * Enter bugs at http://blackfin.uclinux.org/
+ *
+ * Copyright (C) 2009 Michael Hennerich, Analog Devices Inc.
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/input.h>	/* BUS_I2C */
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include "adxl34x.h"
+
+static int adxl34x_smbus_read(struct device *dev, unsigned char reg)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+
+	return i2c_smbus_read_byte_data(client, reg);
+}
+
+static int adxl34x_smbus_write(struct device *dev,
+			       unsigned char reg, unsigned char val)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+
+	return i2c_smbus_write_byte_data(client, reg, val);
+}
+
+static int adxl34x_smbus_read_block(struct device *dev,
+				    unsigned char reg, int count,
+				    void *buf)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+
+	return i2c_smbus_read_i2c_block_data(client, reg, count, buf);
+}
+
+static int adxl34x_i2c_read_block(struct device *dev,
+				  unsigned char reg, int count,
+				  void *buf)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	int ret;
+
+	ret = i2c_master_send(client, &reg, 1);
+	if (ret < 0)
+		return ret;
+
+	ret = i2c_master_recv(client, buf, count);
+	if (ret < 0)
+		return ret;
+
+	if (ret != count)
+		return -EIO;
+
+	return 0;
+}
+
+static const struct adxl34x_bus_ops adxl34x_smbus_bops = {
+	.bustype	= BUS_I2C,
+	.write		= adxl34x_smbus_write,
+	.read		= adxl34x_smbus_read,
+	.read_block	= adxl34x_smbus_read_block,
+};
+
+static const struct adxl34x_bus_ops adxl34x_i2c_bops = {
+	.bustype	= BUS_I2C,
+	.write		= adxl34x_smbus_write,
+	.read		= adxl34x_smbus_read,
+	.read_block	= adxl34x_i2c_read_block,
+};
+
+static int __devinit adxl34x_i2c_probe(struct i2c_client *client,
+				       const struct i2c_device_id *id)
+{
+	struct adxl34x *ac;
+	int error;
+
+	error = i2c_check_functionality(client->adapter,
+			I2C_FUNC_SMBUS_BYTE_DATA);
+	if (!error) {
+		dev_err(&client->dev, "SMBUS Byte Data not Supported\n");
+		return -EIO;
+	}
+
+	ac = adxl34x_probe(&client->dev, client->irq, false,
+			   i2c_check_functionality(client->adapter,
+						   I2C_FUNC_SMBUS_READ_I2C_BLOCK) ?
+				&adxl34x_smbus_bops : &adxl34x_i2c_bops);
+	if (IS_ERR(ac))
+		return PTR_ERR(ac);
+
+	i2c_set_clientdata(client, ac);
+
+	return 0;
+}
+
+static int __devexit adxl34x_i2c_remove(struct i2c_client *client)
+{
+	struct adxl34x *ac = i2c_get_clientdata(client);
+
+	return adxl34x_remove(ac);
+}
+
+#ifdef CONFIG_PM
+static int adxl34x_i2c_suspend(struct i2c_client *client, pm_message_t message)
+{
+	struct adxl34x *ac = i2c_get_clientdata(client);
+
+	adxl34x_suspend(ac);
+
+	return 0;
+}
+
+static int adxl34x_i2c_resume(struct i2c_client *client)
+{
+	struct adxl34x *ac = i2c_get_clientdata(client);
+
+	adxl34x_resume(ac);
+
+	return 0;
+}
+#else
+# define adxl34x_i2c_suspend NULL
+# define adxl34x_i2c_resume  NULL
+#endif
+
+static const struct i2c_device_id adxl34x_id[] = {
+	{ "adxl34x", 0 },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(i2c, adxl34x_id);
+
+static struct i2c_driver adxl34x_driver = {
+	.driver = {
+		.name = "adxl34x",
+		.owner = THIS_MODULE,
+	},
+	.probe    = adxl34x_i2c_probe,
+	.remove   = __devexit_p(adxl34x_i2c_remove),
+	.suspend  = adxl34x_i2c_suspend,
+	.resume   = adxl34x_i2c_resume,
+	.id_table = adxl34x_id,
+};
+
+static int __init adxl34x_i2c_init(void)
+{
+	return i2c_add_driver(&adxl34x_driver);
+}
+module_init(adxl34x_i2c_init);
+
+static void __exit adxl34x_i2c_exit(void)
+{
+	i2c_del_driver(&adxl34x_driver);
+}
+module_exit(adxl34x_i2c_exit);
+
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("ADXL345/346 Three-Axis Digital Accelerometer I2C Bus Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/misc/adxl34x-spi.c b/drivers/input/misc/adxl34x-spi.c
new file mode 100644
index 000000000000..782de9e89828
--- /dev/null
+++ b/drivers/input/misc/adxl34x-spi.c
@@ -0,0 +1,145 @@
+/*
+ * ADLX345/346 Three-Axis Digital Accelerometers (SPI Interface)
+ *
+ * Enter bugs at http://blackfin.uclinux.org/
+ *
+ * Copyright (C) 2009 Michael Hennerich, Analog Devices Inc.
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/input.h>	/* BUS_SPI */
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+#include <linux/types.h>
+#include "adxl34x.h"
+
+#define MAX_SPI_FREQ_HZ		5000000
+#define MAX_FREQ_NO_FIFODELAY	1500000
+#define ADXL34X_CMD_MULTB	(1 << 6)
+#define ADXL34X_CMD_READ	(1 << 7)
+#define ADXL34X_WRITECMD(reg)	(reg & 0x3F)
+#define ADXL34X_READCMD(reg)	(ADXL34X_CMD_READ | (reg & 0x3F))
+#define ADXL34X_READMB_CMD(reg) (ADXL34X_CMD_READ | ADXL34X_CMD_MULTB \
+					| (reg & 0x3F))
+
+static int adxl34x_spi_read(struct device *dev, unsigned char reg)
+{
+	struct spi_device *spi = to_spi_device(dev);
+	unsigned char cmd;
+
+	cmd = ADXL34X_READCMD(reg);
+
+	return spi_w8r8(spi, cmd);
+}
+
+static int adxl34x_spi_write(struct device *dev,
+			     unsigned char reg, unsigned char val)
+{
+	struct spi_device *spi = to_spi_device(dev);
+	unsigned char buf[2];
+
+	buf[0] = ADXL34X_WRITECMD(reg);
+	buf[1] = val;
+
+	return spi_write(spi, buf, sizeof(buf));
+}
+
+static int adxl34x_spi_read_block(struct device *dev,
+				  unsigned char reg, int count,
+				  void *buf)
+{
+	struct spi_device *spi = to_spi_device(dev);
+	ssize_t status;
+
+	reg = ADXL34X_READMB_CMD(reg);
+	status = spi_write_then_read(spi, &reg, 1, buf, count);
+
+	return (status < 0) ? status : 0;
+}
+
+static const struct adxl34x_bus_ops adx134x_spi_bops = {
+	.bustype	= BUS_SPI,
+	.write		= adxl34x_spi_write,
+	.read		= adxl34x_spi_read,
+	.read_block	= adxl34x_spi_read_block,
+};
+
+static int __devinit adxl34x_spi_probe(struct spi_device *spi)
+{
+	struct adxl34x *ac;
+
+	/* don't exceed max specified SPI CLK frequency */
+	if (spi->max_speed_hz > MAX_SPI_FREQ_HZ) {
+		dev_err(&spi->dev, "SPI CLK %d Hz too fast\n", spi->max_speed_hz);
+		return -EINVAL;
+	}
+
+	ac = adxl34x_probe(&spi->dev, spi->irq,
+			   spi->max_speed_hz > MAX_FREQ_NO_FIFODELAY,
+			   &adx134x_spi_bops);
+
+	if (IS_ERR(ac))
+		return PTR_ERR(ac);
+
+	spi_set_drvdata(spi, ac);
+
+	return 0;
+}
+
+static int __devexit adxl34x_spi_remove(struct spi_device *spi)
+{
+	struct adxl34x *ac = dev_get_drvdata(&spi->dev);
+
+	return adxl34x_remove(ac);
+}
+
+#ifdef CONFIG_PM
+static int adxl34x_spi_suspend(struct spi_device *spi, pm_message_t message)
+{
+	struct adxl34x *ac = dev_get_drvdata(&spi->dev);
+
+	adxl34x_suspend(ac);
+
+	return 0;
+}
+
+static int adxl34x_spi_resume(struct spi_device *spi)
+{
+	struct adxl34x *ac = dev_get_drvdata(&spi->dev);
+
+	adxl34x_resume(ac);
+
+	return 0;
+}
+#else
+# define adxl34x_spi_suspend NULL
+# define adxl34x_spi_resume  NULL
+#endif
+
+static struct spi_driver adxl34x_driver = {
+	.driver = {
+		.name = "adxl34x",
+		.bus = &spi_bus_type,
+		.owner = THIS_MODULE,
+	},
+	.probe   = adxl34x_spi_probe,
+	.remove  = __devexit_p(adxl34x_spi_remove),
+	.suspend = adxl34x_spi_suspend,
+	.resume  = adxl34x_spi_resume,
+};
+
+static int __init adxl34x_spi_init(void)
+{
+	return spi_register_driver(&adxl34x_driver);
+}
+module_init(adxl34x_spi_init);
+
+static void __exit adxl34x_spi_exit(void)
+{
+	spi_unregister_driver(&adxl34x_driver);
+}
+module_exit(adxl34x_spi_exit);
+
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("ADXL345/346 Three-Axis Digital Accelerometer SPI Bus Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/misc/adxl34x.c b/drivers/input/misc/adxl34x.c
new file mode 100644
index 000000000000..e2ca01708080
--- /dev/null
+++ b/drivers/input/misc/adxl34x.c
@@ -0,0 +1,915 @@
+/*
+ * ADXL345/346 Three-Axis Digital Accelerometers
+ *
+ * Enter bugs at http://blackfin.uclinux.org/
+ *
+ * Copyright (C) 2009 Michael Hennerich, Analog Devices Inc.
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <linux/input/adxl34x.h>
+
+#include "adxl34x.h"
+
+/* ADXL345/6 Register Map */
+#define DEVID		0x00	/* R   Device ID */
+#define THRESH_TAP	0x1D	/* R/W Tap threshold */
+#define OFSX		0x1E	/* R/W X-axis offset */
+#define OFSY		0x1F	/* R/W Y-axis offset */
+#define OFSZ		0x20	/* R/W Z-axis offset */
+#define DUR		0x21	/* R/W Tap duration */
+#define LATENT		0x22	/* R/W Tap latency */
+#define WINDOW		0x23	/* R/W Tap window */
+#define THRESH_ACT	0x24	/* R/W Activity threshold */
+#define THRESH_INACT	0x25	/* R/W Inactivity threshold */
+#define TIME_INACT	0x26	/* R/W Inactivity time */
+#define ACT_INACT_CTL	0x27	/* R/W Axis enable control for activity and */
+				/* inactivity detection */
+#define THRESH_FF	0x28	/* R/W Free-fall threshold */
+#define TIME_FF		0x29	/* R/W Free-fall time */
+#define TAP_AXES	0x2A	/* R/W Axis control for tap/double tap */
+#define ACT_TAP_STATUS	0x2B	/* R   Source of tap/double tap */
+#define BW_RATE		0x2C	/* R/W Data rate and power mode control */
+#define POWER_CTL	0x2D	/* R/W Power saving features control */
+#define INT_ENABLE	0x2E	/* R/W Interrupt enable control */
+#define INT_MAP		0x2F	/* R/W Interrupt mapping control */
+#define INT_SOURCE	0x30	/* R   Source of interrupts */
+#define DATA_FORMAT	0x31	/* R/W Data format control */
+#define DATAX0		0x32	/* R   X-Axis Data 0 */
+#define DATAX1		0x33	/* R   X-Axis Data 1 */
+#define DATAY0		0x34	/* R   Y-Axis Data 0 */
+#define DATAY1		0x35	/* R   Y-Axis Data 1 */
+#define DATAZ0		0x36	/* R   Z-Axis Data 0 */
+#define DATAZ1		0x37	/* R   Z-Axis Data 1 */
+#define FIFO_CTL	0x38	/* R/W FIFO control */
+#define FIFO_STATUS	0x39	/* R   FIFO status */
+#define TAP_SIGN	0x3A	/* R   Sign and source for tap/double tap */
+/* Orientation ADXL346 only */
+#define ORIENT_CONF	0x3B	/* R/W Orientation configuration */
+#define ORIENT		0x3C	/* R   Orientation status */
+
+/* DEVIDs */
+#define ID_ADXL345	0xE5
+#define ID_ADXL346	0xE6
+
+/* INT_ENABLE/INT_MAP/INT_SOURCE Bits */
+#define DATA_READY	(1 << 7)
+#define SINGLE_TAP	(1 << 6)
+#define DOUBLE_TAP	(1 << 5)
+#define ACTIVITY	(1 << 4)
+#define INACTIVITY	(1 << 3)
+#define FREE_FALL	(1 << 2)
+#define WATERMARK	(1 << 1)
+#define OVERRUN		(1 << 0)
+
+/* ACT_INACT_CONTROL Bits */
+#define ACT_ACDC	(1 << 7)
+#define ACT_X_EN	(1 << 6)
+#define ACT_Y_EN	(1 << 5)
+#define ACT_Z_EN	(1 << 4)
+#define INACT_ACDC	(1 << 3)
+#define INACT_X_EN	(1 << 2)
+#define INACT_Y_EN	(1 << 1)
+#define INACT_Z_EN	(1 << 0)
+
+/* TAP_AXES Bits */
+#define SUPPRESS	(1 << 3)
+#define TAP_X_EN	(1 << 2)
+#define TAP_Y_EN	(1 << 1)
+#define TAP_Z_EN	(1 << 0)
+
+/* ACT_TAP_STATUS Bits */
+#define ACT_X_SRC	(1 << 6)
+#define ACT_Y_SRC	(1 << 5)
+#define ACT_Z_SRC	(1 << 4)
+#define ASLEEP		(1 << 3)
+#define TAP_X_SRC	(1 << 2)
+#define TAP_Y_SRC	(1 << 1)
+#define TAP_Z_SRC	(1 << 0)
+
+/* BW_RATE Bits */
+#define LOW_POWER	(1 << 4)
+#define RATE(x)		((x) & 0xF)
+
+/* POWER_CTL Bits */
+#define PCTL_LINK	(1 << 5)
+#define PCTL_AUTO_SLEEP (1 << 4)
+#define PCTL_MEASURE	(1 << 3)
+#define PCTL_SLEEP	(1 << 2)
+#define PCTL_WAKEUP(x)	((x) & 0x3)
+
+/* DATA_FORMAT Bits */
+#define SELF_TEST	(1 << 7)
+#define SPI		(1 << 6)
+#define INT_INVERT	(1 << 5)
+#define FULL_RES	(1 << 3)
+#define JUSTIFY		(1 << 2)
+#define RANGE(x)	((x) & 0x3)
+#define RANGE_PM_2g	0
+#define RANGE_PM_4g	1
+#define RANGE_PM_8g	2
+#define RANGE_PM_16g	3
+
+/*
+ * Maximum value our axis may get in full res mode for the input device
+ * (signed 13 bits)
+ */
+#define ADXL_FULLRES_MAX_VAL 4096
+
+/*
+ * Maximum value our axis may get in fixed res mode for the input device
+ * (signed 10 bits)
+ */
+#define ADXL_FIXEDRES_MAX_VAL 512
+
+/* FIFO_CTL Bits */
+#define FIFO_MODE(x)	(((x) & 0x3) << 6)
+#define FIFO_BYPASS	0
+#define FIFO_FIFO	1
+#define FIFO_STREAM	2
+#define FIFO_TRIGGER	3
+#define TRIGGER		(1 << 5)
+#define SAMPLES(x)	((x) & 0x1F)
+
+/* FIFO_STATUS Bits */
+#define FIFO_TRIG	(1 << 7)
+#define ENTRIES(x)	((x) & 0x3F)
+
+/* TAP_SIGN Bits ADXL346 only */
+#define XSIGN		(1 << 6)
+#define YSIGN		(1 << 5)
+#define ZSIGN		(1 << 4)
+#define XTAP		(1 << 3)
+#define YTAP		(1 << 2)
+#define ZTAP		(1 << 1)
+
+/* ORIENT_CONF ADXL346 only */
+#define ORIENT_DEADZONE(x)	(((x) & 0x7) << 4)
+#define ORIENT_DIVISOR(x)	((x) & 0x7)
+
+/* ORIENT ADXL346 only */
+#define ADXL346_2D_VALID		(1 << 6)
+#define ADXL346_2D_ORIENT(x)		(((x) & 0x3) >> 4)
+#define ADXL346_3D_VALID		(1 << 3)
+#define ADXL346_3D_ORIENT(x)		((x) & 0x7)
+#define ADXL346_2D_PORTRAIT_POS		0	/* +X */
+#define ADXL346_2D_PORTRAIT_NEG		1	/* -X */
+#define ADXL346_2D_LANDSCAPE_POS	2	/* +Y */
+#define ADXL346_2D_LANDSCAPE_NEG	3	/* -Y */
+
+#define ADXL346_3D_FRONT		3	/* +X */
+#define ADXL346_3D_BACK			4	/* -X */
+#define ADXL346_3D_RIGHT		2	/* +Y */
+#define ADXL346_3D_LEFT			5	/* -Y */
+#define ADXL346_3D_TOP			1	/* +Z */
+#define ADXL346_3D_BOTTOM		6	/* -Z */
+
+#undef ADXL_DEBUG
+
+#define ADXL_X_AXIS			0
+#define ADXL_Y_AXIS			1
+#define ADXL_Z_AXIS			2
+
+#define AC_READ(ac, reg)	((ac)->bops->read((ac)->dev, reg))
+#define AC_WRITE(ac, reg, val)	((ac)->bops->write((ac)->dev, reg, val))
+
+struct axis_triple {
+	int x;
+	int y;
+	int z;
+};
+
+struct adxl34x {
+	struct device *dev;
+	struct input_dev *input;
+	struct mutex mutex;	/* reentrant protection for struct */
+	struct adxl34x_platform_data pdata;
+	struct axis_triple swcal;
+	struct axis_triple hwcal;
+	struct axis_triple saved;
+	char phys[32];
+	unsigned orient2d_saved;
+	unsigned orient3d_saved;
+	bool disabled;	/* P: mutex */
+	bool opened;	/* P: mutex */
+	bool suspended;	/* P: mutex */
+	bool fifo_delay;
+	int irq;
+	unsigned model;
+	unsigned int_mask;
+
+	const struct adxl34x_bus_ops *bops;
+};
+
+static const struct adxl34x_platform_data adxl34x_default_init = {
+	.tap_threshold = 35,
+	.tap_duration = 3,
+	.tap_latency = 20,
+	.tap_window = 20,
+	.tap_axis_control = ADXL_TAP_X_EN | ADXL_TAP_Y_EN | ADXL_TAP_Z_EN,
+	.act_axis_control = 0xFF,
+	.activity_threshold = 6,
+	.inactivity_threshold = 4,
+	.inactivity_time = 3,
+	.free_fall_threshold = 8,
+	.free_fall_time = 0x20,
+	.data_rate = 8,
+	.data_range = ADXL_FULL_RES,
+
+	.ev_type = EV_ABS,
+	.ev_code_x = ABS_X,	/* EV_REL */
+	.ev_code_y = ABS_Y,	/* EV_REL */
+	.ev_code_z = ABS_Z,	/* EV_REL */
+
+	.ev_code_tap = {BTN_TOUCH, BTN_TOUCH, BTN_TOUCH}, /* EV_KEY {x,y,z} */
+	.power_mode = ADXL_AUTO_SLEEP | ADXL_LINK,
+	.fifo_mode = FIFO_STREAM,
+	.watermark = 0,
+};
+
+static void adxl34x_get_triple(struct adxl34x *ac, struct axis_triple *axis)
+{
+	short buf[3];
+
+	ac->bops->read_block(ac->dev, DATAX0, DATAZ1 - DATAX0 + 1, buf);
+
+	mutex_lock(&ac->mutex);
+	ac->saved.x = (s16) le16_to_cpu(buf[0]);
+	axis->x = ac->saved.x;
+
+	ac->saved.y = (s16) le16_to_cpu(buf[1]);
+	axis->y = ac->saved.y;
+
+	ac->saved.z = (s16) le16_to_cpu(buf[2]);
+	axis->z = ac->saved.z;
+	mutex_unlock(&ac->mutex);
+}
+
+static void adxl34x_service_ev_fifo(struct adxl34x *ac)
+{
+	struct adxl34x_platform_data *pdata = &ac->pdata;
+	struct axis_triple axis;
+
+	adxl34x_get_triple(ac, &axis);
+
+	input_event(ac->input, pdata->ev_type, pdata->ev_code_x,
+		    axis.x - ac->swcal.x);
+	input_event(ac->input, pdata->ev_type, pdata->ev_code_y,
+		    axis.y - ac->swcal.y);
+	input_event(ac->input, pdata->ev_type, pdata->ev_code_z,
+		    axis.z - ac->swcal.z);
+}
+
+static void adxl34x_report_key_single(struct input_dev *input, int key)
+{
+	input_report_key(input, key, true);
+	input_sync(input);
+	input_report_key(input, key, false);
+}
+
+static void adxl34x_send_key_events(struct adxl34x *ac,
+		struct adxl34x_platform_data *pdata, int status, int press)
+{
+	int i;
+
+	for (i = ADXL_X_AXIS; i <= ADXL_Z_AXIS; i++) {
+		if (status & (1 << (ADXL_Z_AXIS - i)))
+			input_report_key(ac->input,
+					 pdata->ev_code_tap[i], press);
+	}
+}
+
+static void adxl34x_do_tap(struct adxl34x *ac,
+		struct adxl34x_platform_data *pdata, int status)
+{
+	adxl34x_send_key_events(ac, pdata, status, true);
+	input_sync(ac->input);
+	adxl34x_send_key_events(ac, pdata, status, false);
+}
+
+static irqreturn_t adxl34x_irq(int irq, void *handle)
+{
+	struct adxl34x *ac = handle;
+	struct adxl34x_platform_data *pdata = &ac->pdata;
+	int int_stat, tap_stat, samples, orient, orient_code;
+
+	/*
+	 * ACT_TAP_STATUS should be read before clearing the interrupt
+	 * Avoid reading ACT_TAP_STATUS in case TAP detection is disabled
+	 */
+
+	if (pdata->tap_axis_control & (TAP_X_EN | TAP_Y_EN | TAP_Z_EN))
+		tap_stat = AC_READ(ac, ACT_TAP_STATUS);
+	else
+		tap_stat = 0;
+
+	int_stat = AC_READ(ac, INT_SOURCE);
+
+	if (int_stat & FREE_FALL)
+		adxl34x_report_key_single(ac->input, pdata->ev_code_ff);
+
+	if (int_stat & OVERRUN)
+		dev_dbg(ac->dev, "OVERRUN\n");
+
+	if (int_stat & (SINGLE_TAP | DOUBLE_TAP)) {
+		adxl34x_do_tap(ac, pdata, tap_stat);
+
+		if (int_stat & DOUBLE_TAP)
+			adxl34x_do_tap(ac, pdata, tap_stat);
+	}
+
+	if (pdata->ev_code_act_inactivity) {
+		if (int_stat & ACTIVITY)
+			input_report_key(ac->input,
+					 pdata->ev_code_act_inactivity, 1);
+		if (int_stat & INACTIVITY)
+			input_report_key(ac->input,
+					 pdata->ev_code_act_inactivity, 0);
+	}
+
+	/*
+	 * ORIENTATION SENSING ADXL346 only
+	 */
+	if (pdata->orientation_enable) {
+		orient = AC_READ(ac, ORIENT);
+		if ((pdata->orientation_enable & ADXL_EN_ORIENTATION_2D) &&
+		    (orient & ADXL346_2D_VALID)) {
+
+			orient_code = ADXL346_2D_ORIENT(orient);
+			/* Report orientation only when it changes */
+			if (ac->orient2d_saved != orient_code) {
+				ac->orient2d_saved = orient_code;
+				adxl34x_report_key_single(ac->input,
+					pdata->ev_codes_orient_2d[orient_code]);
+			}
+		}
+
+		if ((pdata->orientation_enable & ADXL_EN_ORIENTATION_3D) &&
+		    (orient & ADXL346_3D_VALID)) {
+
+			orient_code = ADXL346_3D_ORIENT(orient) - 1;
+			/* Report orientation only when it changes */
+			if (ac->orient3d_saved != orient_code) {
+				ac->orient3d_saved = orient_code;
+				adxl34x_report_key_single(ac->input,
+					pdata->ev_codes_orient_3d[orient_code]);
+			}
+		}
+	}
+
+	if (int_stat & (DATA_READY | WATERMARK)) {
+
+		if (pdata->fifo_mode)
+			samples = ENTRIES(AC_READ(ac, FIFO_STATUS)) + 1;
+		else
+			samples = 1;
+
+		for (; samples > 0; samples--) {
+			adxl34x_service_ev_fifo(ac);
+			/*
+			 * To ensure that the FIFO has
+			 * completely popped, there must be at least 5 us between
+			 * the end of reading the data registers, signified by the
+			 * transition to register 0x38 from 0x37 or the CS pin
+			 * going high, and the start of new reads of the FIFO or
+			 * reading the FIFO_STATUS register. For SPI operation at
+			 * 1.5 MHz or lower, the register addressing portion of the
+			 * transmission is sufficient delay to ensure the FIFO has
+			 * completely popped. It is necessary for SPI operation
+			 * greater than 1.5 MHz to de-assert the CS pin to ensure a
+			 * total of 5 us, which is at most 3.4 us at 5 MHz
+			 * operation.
+			 */
+			if (ac->fifo_delay && (samples > 1))
+				udelay(3);
+		}
+	}
+
+	input_sync(ac->input);
+
+	return IRQ_HANDLED;
+}
+
+static void __adxl34x_disable(struct adxl34x *ac)
+{
+	/*
+	 * A '0' places the ADXL34x into standby mode
+	 * with minimum power consumption.
+	 */
+	AC_WRITE(ac, POWER_CTL, 0);
+}
+
+static void __adxl34x_enable(struct adxl34x *ac)
+{
+	AC_WRITE(ac, POWER_CTL, ac->pdata.power_mode | PCTL_MEASURE);
+}
+
+void adxl34x_suspend(struct adxl34x *ac)
+{
+	mutex_lock(&ac->mutex);
+
+	if (!ac->suspended && !ac->disabled && ac->opened)
+		__adxl34x_disable(ac);
+
+	ac->suspended = true;
+
+	mutex_unlock(&ac->mutex);
+}
+EXPORT_SYMBOL_GPL(adxl34x_suspend);
+
+void adxl34x_resume(struct adxl34x *ac)
+{
+	mutex_lock(&ac->mutex);
+
+	if (ac->suspended && !ac->disabled && ac->opened)
+		__adxl34x_enable(ac);
+
+	ac->suspended = false;
+
+	mutex_unlock(&ac->mutex);
+}
+EXPORT_SYMBOL_GPL(adxl34x_resume);
+
+static ssize_t adxl34x_disable_show(struct device *dev,
+				    struct device_attribute *attr, char *buf)
+{
+	struct adxl34x *ac = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%u\n", ac->disabled);
+}
+
+static ssize_t adxl34x_disable_store(struct device *dev,
+				     struct device_attribute *attr,
+				     const char *buf, size_t count)
+{
+	struct adxl34x *ac = dev_get_drvdata(dev);
+	unsigned long val;
+	int error;
+
+	error = strict_strtoul(buf, 10, &val);
+	if (error)
+		return error;
+
+	mutex_lock(&ac->mutex);
+
+	if (!ac->suspended && ac->opened) {
+		if (val) {
+			if (!ac->disabled)
+				__adxl34x_disable(ac);
+		} else {
+			if (ac->disabled)
+				__adxl34x_enable(ac);
+		}
+	}
+
+	ac->disabled = !!val;
+
+	mutex_unlock(&ac->mutex);
+
+	return count;
+}
+
+static DEVICE_ATTR(disable, 0664, adxl34x_disable_show, adxl34x_disable_store);
+
+static ssize_t adxl34x_calibrate_show(struct device *dev,
+				      struct device_attribute *attr, char *buf)
+{
+	struct adxl34x *ac = dev_get_drvdata(dev);
+	ssize_t count;
+
+	mutex_lock(&ac->mutex);
+	count = sprintf(buf, "%d,%d,%d\n",
+			ac->hwcal.x * 4 + ac->swcal.x,
+			ac->hwcal.y * 4 + ac->swcal.y,
+			ac->hwcal.z * 4 + ac->swcal.z);
+	mutex_unlock(&ac->mutex);
+
+	return count;
+}
+
+static ssize_t adxl34x_calibrate_store(struct device *dev,
+				       struct device_attribute *attr,
+				       const char *buf, size_t count)
+{
+	struct adxl34x *ac = dev_get_drvdata(dev);
+
+	/*
+	 * Hardware offset calibration has a resolution of 15.6 mg/LSB.
+	 * We use HW calibration and handle the remaining bits in SW. (4mg/LSB)
+	 */
+
+	mutex_lock(&ac->mutex);
+	ac->hwcal.x -= (ac->saved.x / 4);
+	ac->swcal.x = ac->saved.x % 4;
+
+	ac->hwcal.y -= (ac->saved.y / 4);
+	ac->swcal.y = ac->saved.y % 4;
+
+	ac->hwcal.z -= (ac->saved.z / 4);
+	ac->swcal.z = ac->saved.z % 4;
+
+	AC_WRITE(ac, OFSX, (s8) ac->hwcal.x);
+	AC_WRITE(ac, OFSY, (s8) ac->hwcal.y);
+	AC_WRITE(ac, OFSZ, (s8) ac->hwcal.z);
+	mutex_unlock(&ac->mutex);
+
+	return count;
+}
+
+static DEVICE_ATTR(calibrate, 0664,
+		   adxl34x_calibrate_show, adxl34x_calibrate_store);
+
+static ssize_t adxl34x_rate_show(struct device *dev,
+				 struct device_attribute *attr, char *buf)
+{
+	struct adxl34x *ac = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%u\n", RATE(ac->pdata.data_rate));
+}
+
+static ssize_t adxl34x_rate_store(struct device *dev,
+				  struct device_attribute *attr,
+				  const char *buf, size_t count)
+{
+	struct adxl34x *ac = dev_get_drvdata(dev);
+	unsigned long val;
+	int error;
+
+	error = strict_strtoul(buf, 10, &val);
+	if (error)
+		return error;
+
+	mutex_lock(&ac->mutex);
+
+	ac->pdata.data_rate = RATE(val);
+	AC_WRITE(ac, BW_RATE,
+		 ac->pdata.data_rate |
+			(ac->pdata.low_power_mode ? LOW_POWER : 0));
+
+	mutex_unlock(&ac->mutex);
+
+	return count;
+}
+
+static DEVICE_ATTR(rate, 0664, adxl34x_rate_show, adxl34x_rate_store);
+
+static ssize_t adxl34x_autosleep_show(struct device *dev,
+				 struct device_attribute *attr, char *buf)
+{
+	struct adxl34x *ac = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%u\n",
+		ac->pdata.power_mode & (PCTL_AUTO_SLEEP | PCTL_LINK) ? 1 : 0);
+}
+
+static ssize_t adxl34x_autosleep_store(struct device *dev,
+				  struct device_attribute *attr,
+				  const char *buf, size_t count)
+{
+	struct adxl34x *ac = dev_get_drvdata(dev);
+	unsigned long val;
+	int error;
+
+	error = strict_strtoul(buf, 10, &val);
+	if (error)
+		return error;
+
+	mutex_lock(&ac->mutex);
+
+	if (val)
+		ac->pdata.power_mode |= (PCTL_AUTO_SLEEP | PCTL_LINK);
+	else
+		ac->pdata.power_mode &= ~(PCTL_AUTO_SLEEP | PCTL_LINK);
+
+	if (!ac->disabled && !ac->suspended && ac->opened)
+		AC_WRITE(ac, POWER_CTL, ac->pdata.power_mode | PCTL_MEASURE);
+
+	mutex_unlock(&ac->mutex);
+
+	return count;
+}
+
+static DEVICE_ATTR(autosleep, 0664,
+		   adxl34x_autosleep_show, adxl34x_autosleep_store);
+
+static ssize_t adxl34x_position_show(struct device *dev,
+				 struct device_attribute *attr, char *buf)
+{
+	struct adxl34x *ac = dev_get_drvdata(dev);
+	ssize_t count;
+
+	mutex_lock(&ac->mutex);
+	count = sprintf(buf, "(%d, %d, %d)\n",
+			ac->saved.x, ac->saved.y, ac->saved.z);
+	mutex_unlock(&ac->mutex);
+
+	return count;
+}
+
+static DEVICE_ATTR(position, S_IRUGO, adxl34x_position_show, NULL);
+
+#ifdef ADXL_DEBUG
+static ssize_t adxl34x_write_store(struct device *dev,
+				   struct device_attribute *attr,
+				   const char *buf, size_t count)
+{
+	struct adxl34x *ac = dev_get_drvdata(dev);
+	unsigned long val;
+	int error;
+
+	/*
+	 * This allows basic ADXL register write access for debug purposes.
+	 */
+	error = strict_strtoul(buf, 16, &val);
+	if (error)
+		return error;
+
+	mutex_lock(&ac->mutex);
+	AC_WRITE(ac, val >> 8, val & 0xFF);
+	mutex_unlock(&ac->mutex);
+
+	return count;
+}
+
+static DEVICE_ATTR(write, 0664, NULL, adxl34x_write_store);
+#endif
+
+static struct attribute *adxl34x_attributes[] = {
+	&dev_attr_disable.attr,
+	&dev_attr_calibrate.attr,
+	&dev_attr_rate.attr,
+	&dev_attr_autosleep.attr,
+	&dev_attr_position.attr,
+#ifdef ADXL_DEBUG
+	&dev_attr_write.attr,
+#endif
+	NULL
+};
+
+static const struct attribute_group adxl34x_attr_group = {
+	.attrs = adxl34x_attributes,
+};
+
+static int adxl34x_input_open(struct input_dev *input)
+{
+	struct adxl34x *ac = input_get_drvdata(input);
+
+	mutex_lock(&ac->mutex);
+
+	if (!ac->suspended && !ac->disabled)
+		__adxl34x_enable(ac);
+
+	ac->opened = true;
+
+	mutex_unlock(&ac->mutex);
+
+	return 0;
+}
+
+static void adxl34x_input_close(struct input_dev *input)
+{
+	struct adxl34x *ac = input_get_drvdata(input);
+
+	mutex_lock(&ac->mutex);
+
+	if (!ac->suspended && !ac->disabled)
+		__adxl34x_disable(ac);
+
+	ac->opened = false;
+
+	mutex_unlock(&ac->mutex);
+}
+
+struct adxl34x *adxl34x_probe(struct device *dev, int irq,
+			      bool fifo_delay_default,
+			      const struct adxl34x_bus_ops *bops)
+{
+	struct adxl34x *ac;
+	struct input_dev *input_dev;
+	const struct adxl34x_platform_data *pdata;
+	int err, range, i;
+	unsigned char revid;
+
+	if (!irq) {
+		dev_err(dev, "no IRQ?\n");
+		err = -ENODEV;
+		goto err_out;
+	}
+
+	ac = kzalloc(sizeof(*ac), GFP_KERNEL);
+	input_dev = input_allocate_device();
+	if (!ac || !input_dev) {
+		err = -ENOMEM;
+		goto err_free_mem;
+	}
+
+	ac->fifo_delay = fifo_delay_default;
+
+	pdata = dev->platform_data;
+	if (!pdata) {
+		dev_dbg(dev,
+			"No platfrom data: Using default initialization\n");
+		pdata = &adxl34x_default_init;
+	}
+
+	ac->pdata = *pdata;
+	pdata = &ac->pdata;
+
+	ac->input = input_dev;
+	ac->disabled = true;
+	ac->dev = dev;
+	ac->irq = irq;
+	ac->bops = bops;
+
+	mutex_init(&ac->mutex);
+
+	input_dev->name = "ADXL34x accelerometer";
+	revid = ac->bops->read(dev, DEVID);
+
+	switch (revid) {
+	case ID_ADXL345:
+		ac->model = 345;
+		break;
+	case ID_ADXL346:
+		ac->model = 346;
+		break;
+	default:
+		dev_err(dev, "Failed to probe %s\n", input_dev->name);
+		err = -ENODEV;
+		goto err_free_mem;
+	}
+
+	snprintf(ac->phys, sizeof(ac->phys), "%s/input0", dev_name(dev));
+
+	input_dev->phys = ac->phys;
+	input_dev->dev.parent = dev;
+	input_dev->id.product = ac->model;
+	input_dev->id.bustype = bops->bustype;
+	input_dev->open = adxl34x_input_open;
+	input_dev->close = adxl34x_input_close;
+
+	input_set_drvdata(input_dev, ac);
+
+	__set_bit(ac->pdata.ev_type, input_dev->evbit);
+
+	if (ac->pdata.ev_type == EV_REL) {
+		__set_bit(REL_X, input_dev->relbit);
+		__set_bit(REL_Y, input_dev->relbit);
+		__set_bit(REL_Z, input_dev->relbit);
+	} else {
+		/* EV_ABS */
+		__set_bit(ABS_X, input_dev->absbit);
+		__set_bit(ABS_Y, input_dev->absbit);
+		__set_bit(ABS_Z, input_dev->absbit);
+
+		if (pdata->data_range & FULL_RES)
+			range = ADXL_FULLRES_MAX_VAL;	/* Signed 13-bit */
+		else
+			range = ADXL_FIXEDRES_MAX_VAL;	/* Signed 10-bit */
+
+		input_set_abs_params(input_dev, ABS_X, -range, range, 3, 3);
+		input_set_abs_params(input_dev, ABS_Y, -range, range, 3, 3);
+		input_set_abs_params(input_dev, ABS_Z, -range, range, 3, 3);
+	}
+
+	__set_bit(EV_KEY, input_dev->evbit);
+	__set_bit(pdata->ev_code_tap[ADXL_X_AXIS], input_dev->keybit);
+	__set_bit(pdata->ev_code_tap[ADXL_Y_AXIS], input_dev->keybit);
+	__set_bit(pdata->ev_code_tap[ADXL_Z_AXIS], input_dev->keybit);
+
+	if (pdata->ev_code_ff) {
+		ac->int_mask = FREE_FALL;
+		__set_bit(pdata->ev_code_ff, input_dev->keybit);
+	}
+
+	if (pdata->ev_code_act_inactivity)
+		__set_bit(pdata->ev_code_act_inactivity, input_dev->keybit);
+
+	ac->int_mask |= ACTIVITY | INACTIVITY;
+
+	if (pdata->watermark) {
+		ac->int_mask |= WATERMARK;
+		if (!FIFO_MODE(pdata->fifo_mode))
+			ac->pdata.fifo_mode |= FIFO_STREAM;
+	} else {
+		ac->int_mask |= DATA_READY;
+	}
+
+	if (pdata->tap_axis_control & (TAP_X_EN | TAP_Y_EN | TAP_Z_EN))
+		ac->int_mask |= SINGLE_TAP | DOUBLE_TAP;
+
+	if (FIFO_MODE(pdata->fifo_mode) == FIFO_BYPASS)
+		ac->fifo_delay = false;
+
+	ac->bops->write(dev, POWER_CTL, 0);
+
+	err = request_threaded_irq(ac->irq, NULL, adxl34x_irq,
+				   IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
+				   dev_name(dev), ac);
+	if (err) {
+		dev_err(dev, "irq %d busy?\n", ac->irq);
+		goto err_free_mem;
+	}
+
+	err = sysfs_create_group(&dev->kobj, &adxl34x_attr_group);
+	if (err)
+		goto err_free_irq;
+
+	err = input_register_device(input_dev);
+	if (err)
+		goto err_remove_attr;
+
+	AC_WRITE(ac, THRESH_TAP, pdata->tap_threshold);
+	AC_WRITE(ac, OFSX, pdata->x_axis_offset);
+	ac->hwcal.x = pdata->x_axis_offset;
+	AC_WRITE(ac, OFSY, pdata->y_axis_offset);
+	ac->hwcal.y = pdata->y_axis_offset;
+	AC_WRITE(ac, OFSZ, pdata->z_axis_offset);
+	ac->hwcal.z = pdata->z_axis_offset;
+	AC_WRITE(ac, THRESH_TAP, pdata->tap_threshold);
+	AC_WRITE(ac, DUR, pdata->tap_duration);
+	AC_WRITE(ac, LATENT, pdata->tap_latency);
+	AC_WRITE(ac, WINDOW, pdata->tap_window);
+	AC_WRITE(ac, THRESH_ACT, pdata->activity_threshold);
+	AC_WRITE(ac, THRESH_INACT, pdata->inactivity_threshold);
+	AC_WRITE(ac, TIME_INACT, pdata->inactivity_time);
+	AC_WRITE(ac, THRESH_FF, pdata->free_fall_threshold);
+	AC_WRITE(ac, TIME_FF, pdata->free_fall_time);
+	AC_WRITE(ac, TAP_AXES, pdata->tap_axis_control);
+	AC_WRITE(ac, ACT_INACT_CTL, pdata->act_axis_control);
+	AC_WRITE(ac, BW_RATE, RATE(ac->pdata.data_rate) |
+		 (pdata->low_power_mode ? LOW_POWER : 0));
+	AC_WRITE(ac, DATA_FORMAT, pdata->data_range);
+	AC_WRITE(ac, FIFO_CTL, FIFO_MODE(pdata->fifo_mode) |
+			SAMPLES(pdata->watermark));
+
+	if (pdata->use_int2) {
+		/* Map all INTs to INT2 */
+		AC_WRITE(ac, INT_MAP, ac->int_mask | OVERRUN);
+	} else {
+		/* Map all INTs to INT1 */
+		AC_WRITE(ac, INT_MAP, 0);
+	}
+
+	if (ac->model == 346 && ac->pdata.orientation_enable) {
+		AC_WRITE(ac, ORIENT_CONF,
+			ORIENT_DEADZONE(ac->pdata.deadzone_angle) |
+			ORIENT_DIVISOR(ac->pdata.divisor_length));
+
+		ac->orient2d_saved = 1234;
+		ac->orient3d_saved = 1234;
+
+		if (pdata->orientation_enable & ADXL_EN_ORIENTATION_3D)
+			for (i = 0; i < ARRAY_SIZE(pdata->ev_codes_orient_3d); i++)
+				__set_bit(pdata->ev_codes_orient_3d[i],
+					  input_dev->keybit);
+
+		if (pdata->orientation_enable & ADXL_EN_ORIENTATION_2D)
+			for (i = 0; i < ARRAY_SIZE(pdata->ev_codes_orient_2d); i++)
+				__set_bit(pdata->ev_codes_orient_2d[i],
+					  input_dev->keybit);
+	} else {
+		ac->pdata.orientation_enable = 0;
+	}
+
+	AC_WRITE(ac, INT_ENABLE, ac->int_mask | OVERRUN);
+
+	ac->pdata.power_mode &= (PCTL_AUTO_SLEEP | PCTL_LINK);
+
+	return ac;
+
+ err_remove_attr:
+	sysfs_remove_group(&dev->kobj, &adxl34x_attr_group);
+ err_free_irq:
+	free_irq(ac->irq, ac);
+ err_free_mem:
+	input_free_device(input_dev);
+	kfree(ac);
+ err_out:
+	return ERR_PTR(err);
+}
+EXPORT_SYMBOL_GPL(adxl34x_probe);
+
+int adxl34x_remove(struct adxl34x *ac)
+{
+	sysfs_remove_group(&ac->dev->kobj, &adxl34x_attr_group);
+	free_irq(ac->irq, ac);
+	input_unregister_device(ac->input);
+	dev_dbg(ac->dev, "unregistered accelerometer\n");
+	kfree(ac);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(adxl34x_remove);
+
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("ADXL345/346 Three-Axis Digital Accelerometer Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/misc/adxl34x.h b/drivers/input/misc/adxl34x.h
new file mode 100644
index 000000000000..bbbc80fda164
--- /dev/null
+++ b/drivers/input/misc/adxl34x.h
@@ -0,0 +1,30 @@
+/*
+ * ADXL345/346 Three-Axis Digital Accelerometers (I2C/SPI Interface)
+ *
+ * Enter bugs at http://blackfin.uclinux.org/
+ *
+ * Copyright (C) 2009 Michael Hennerich, Analog Devices Inc.
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef _ADXL34X_H_
+#define _ADXL34X_H_
+
+struct device;
+struct adxl34x;
+
+struct adxl34x_bus_ops {
+	u16 bustype;
+	int (*read)(struct device *, unsigned char);
+	int (*read_block)(struct device *, unsigned char, int, void *);
+	int (*write)(struct device *, unsigned char, unsigned char);
+};
+
+void adxl34x_suspend(struct adxl34x *ac);
+void adxl34x_resume(struct adxl34x *ac);
+struct adxl34x *adxl34x_probe(struct device *dev, int irq,
+			      bool fifo_delay_default,
+			      const struct adxl34x_bus_ops *bops);
+int adxl34x_remove(struct adxl34x *ac);
+
+#endif
diff --git a/drivers/input/misc/atlas_btns.c b/drivers/input/misc/atlas_btns.c
index dfaa9a045ed8..601f7372f9c4 100644
--- a/drivers/input/misc/atlas_btns.c
+++ b/drivers/input/misc/atlas_btns.c
@@ -21,6 +21,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/init.h>
@@ -60,12 +62,11 @@ static acpi_status acpi_atlas_button_handler(u32 function,
 		input_report_key(input_dev, atlas_keymap[code], key_down);
 		input_sync(input_dev);
 
-		status = 0;
+		status = AE_OK;
 	} else {
-		printk(KERN_WARNING "atlas: shrugged on unexpected function"
-			":function=%x,address=%lx,value=%x\n",
+		pr_warn("shrugged on unexpected function: function=%x,address=%lx,value=%x\n",
 			function, (unsigned long)address, (u32)*value);
-		status = -EINVAL;
+		status = AE_BAD_PARAMETER;
 	}
 
 	return status;
@@ -79,7 +80,7 @@ static int atlas_acpi_button_add(struct acpi_device *device)
 
 	input_dev = input_allocate_device();
 	if (!input_dev) {
-		printk(KERN_ERR "atlas: unable to allocate input device\n");
+		pr_err("unable to allocate input device\n");
 		return -ENOMEM;
 	}
 
@@ -102,7 +103,7 @@ static int atlas_acpi_button_add(struct acpi_device *device)
 
 	err = input_register_device(input_dev);
 	if (err) {
-		printk(KERN_ERR "atlas: couldn't register input device\n");
+		pr_err("couldn't register input device\n");
 		input_free_device(input_dev);
 		return err;
 	}
@@ -112,12 +113,12 @@ static int atlas_acpi_button_add(struct acpi_device *device)
 				0x81, &acpi_atlas_button_handler,
 				&acpi_atlas_button_setup, device);
 	if (ACPI_FAILURE(status)) {
-		printk(KERN_ERR "Atlas: Error installing addr spc handler\n");
+		pr_err("error installing addr spc handler\n");
 		input_unregister_device(input_dev);
-		status = -EINVAL;
+		err = -EINVAL;
 	}
 
-	return status;
+	return err;
 }
 
 static int atlas_acpi_button_remove(struct acpi_device *device, int type)
@@ -126,14 +127,12 @@ static int atlas_acpi_button_remove(struct acpi_device *device, int type)
 
 	status = acpi_remove_address_space_handler(device->handle,
 				0x81, &acpi_atlas_button_handler);
-	if (ACPI_FAILURE(status)) {
-		printk(KERN_ERR "Atlas: Error removing addr spc handler\n");
-		status = -EINVAL;
-	}
+	if (ACPI_FAILURE(status))
+		pr_err("error removing addr spc handler\n");
 
 	input_unregister_device(input_dev);
 
-	return status;
+	return 0;
 }
 
 static const struct acpi_device_id atlas_device_ids[] = {
@@ -145,6 +144,7 @@ MODULE_DEVICE_TABLE(acpi, atlas_device_ids);
 static struct acpi_driver atlas_acpi_driver = {
 	.name	= ACPI_ATLAS_NAME,
 	.class	= ACPI_ATLAS_CLASS,
+	.owner	= THIS_MODULE,
 	.ids	= atlas_device_ids,
 	.ops	= {
 		.add	= atlas_acpi_button_add,
@@ -154,18 +154,10 @@ static struct acpi_driver atlas_acpi_driver = {
 
 static int __init atlas_acpi_init(void)
 {
-	int result;
-
 	if (acpi_disabled)
 		return -ENODEV;
 
-	result = acpi_bus_register_driver(&atlas_acpi_driver);
-	if (result < 0) {
-		printk(KERN_ERR "Atlas ACPI: Unable to register driver\n");
-		return -ENODEV;
-	}
-
-	return 0;
+	return acpi_bus_register_driver(&atlas_acpi_driver);
 }
 
 static void __exit atlas_acpi_exit(void)
diff --git a/drivers/input/misc/pwm-beeper.c b/drivers/input/misc/pwm-beeper.c
new file mode 100644
index 000000000000..57c294f07198
--- /dev/null
+++ b/drivers/input/misc/pwm-beeper.c
@@ -0,0 +1,199 @@
+/*
+ *  Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
+ *  PWM beeper 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;  either version 2 of the License, or (at your
+ *  option) any later version.
+ *
+ *  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.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/pwm.h>
+#include <linux/slab.h>
+
+struct pwm_beeper {
+	struct input_dev *input;
+	struct pwm_device *pwm;
+	unsigned long period;
+};
+
+#define HZ_TO_NANOSECONDS(x) (1000000000UL/(x))
+
+static int pwm_beeper_event(struct input_dev *input,
+			    unsigned int type, unsigned int code, int value)
+{
+	int ret = 0;
+	struct pwm_beeper *beeper = input_get_drvdata(input);
+	unsigned long period;
+
+	if (type != EV_SND || value < 0)
+		return -EINVAL;
+
+	switch (code) {
+	case SND_BELL:
+		value = value ? 1000 : 0;
+		break;
+	case SND_TONE:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (value == 0) {
+		pwm_config(beeper->pwm, 0, 0);
+		pwm_disable(beeper->pwm);
+	} else {
+		period = HZ_TO_NANOSECONDS(value);
+		ret = pwm_config(beeper->pwm, period / 2, period);
+		if (ret)
+			return ret;
+		ret = pwm_enable(beeper->pwm);
+		if (ret)
+			return ret;
+		beeper->period = period;
+	}
+
+	return 0;
+}
+
+static int __devinit pwm_beeper_probe(struct platform_device *pdev)
+{
+	unsigned long pwm_id = (unsigned long)pdev->dev.platform_data;
+	struct pwm_beeper *beeper;
+	int error;
+
+	beeper = kzalloc(sizeof(*beeper), GFP_KERNEL);
+	if (!beeper)
+		return -ENOMEM;
+
+	beeper->pwm = pwm_request(pwm_id, "pwm beeper");
+
+	if (IS_ERR(beeper->pwm)) {
+		error = PTR_ERR(beeper->pwm);
+		dev_err(&pdev->dev, "Failed to request pwm device: %d\n", error);
+		goto err_free;
+	}
+
+	beeper->input = input_allocate_device();
+	if (!beeper->input) {
+		dev_err(&pdev->dev, "Failed to allocate input device\n");
+		error = -ENOMEM;
+		goto err_pwm_free;
+	}
+	beeper->input->dev.parent = &pdev->dev;
+
+	beeper->input->name = "pwm-beeper";
+	beeper->input->phys = "pwm/input0";
+	beeper->input->id.bustype = BUS_HOST;
+	beeper->input->id.vendor = 0x001f;
+	beeper->input->id.product = 0x0001;
+	beeper->input->id.version = 0x0100;
+
+	beeper->input->evbit[0] = BIT(EV_SND);
+	beeper->input->sndbit[0] = BIT(SND_TONE) | BIT(SND_BELL);
+
+	beeper->input->event = pwm_beeper_event;
+
+	input_set_drvdata(beeper->input, beeper);
+
+	error = input_register_device(beeper->input);
+	if (error) {
+		dev_err(&pdev->dev, "Failed to register input device: %d\n", error);
+		goto err_input_free;
+	}
+
+	platform_set_drvdata(pdev, beeper);
+
+	return 0;
+
+err_input_free:
+	input_free_device(beeper->input);
+err_pwm_free:
+	pwm_free(beeper->pwm);
+err_free:
+	kfree(beeper);
+
+	return error;
+}
+
+static int __devexit pwm_beeper_remove(struct platform_device *pdev)
+{
+	struct pwm_beeper *beeper = platform_get_drvdata(pdev);
+
+	platform_set_drvdata(pdev, NULL);
+	input_unregister_device(beeper->input);
+
+	pwm_disable(beeper->pwm);
+	pwm_free(beeper->pwm);
+
+	kfree(beeper);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int pwm_beeper_suspend(struct device *dev)
+{
+	struct pwm_beeper *beeper = dev_get_drvdata(dev);
+
+	if (beeper->period)
+		pwm_disable(beeper->pwm);
+
+	return 0;
+}
+
+static int pwm_beeper_resume(struct device *dev)
+{
+	struct pwm_beeper *beeper = dev_get_drvdata(dev);
+
+	if (beeper->period) {
+		pwm_config(beeper->pwm, beeper->period / 2, beeper->period);
+		pwm_enable(beeper->pwm);
+	}
+
+	return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(pwm_beeper_pm_ops,
+			 pwm_beeper_suspend, pwm_beeper_resume);
+
+#define PWM_BEEPER_PM_OPS (&pwm_beeper_pm_ops)
+#else
+#define PWM_BEEPER_PM_OPS NULL
+#endif
+
+static struct platform_driver pwm_beeper_driver = {
+	.probe	= pwm_beeper_probe,
+	.remove = __devexit_p(pwm_beeper_remove),
+	.driver = {
+		.name	= "pwm-beeper",
+		.owner	= THIS_MODULE,
+		.pm	= PWM_BEEPER_PM_OPS,
+	},
+};
+
+static int __init pwm_beeper_init(void)
+{
+	return platform_driver_register(&pwm_beeper_driver);
+}
+module_init(pwm_beeper_init);
+
+static void __exit pwm_beeper_exit(void)
+{
+	platform_driver_unregister(&pwm_beeper_driver);
+}
+module_exit(pwm_beeper_exit);
+
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_DESCRIPTION("PWM beeper driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pwm-beeper");
diff --git a/drivers/input/misc/twl4030-pwrbutton.c b/drivers/input/misc/twl4030-pwrbutton.c
index e9069b87fde2..f16972bddca4 100644
--- a/drivers/input/misc/twl4030-pwrbutton.c
+++ b/drivers/input/misc/twl4030-pwrbutton.c
@@ -52,7 +52,7 @@ static irqreturn_t powerbutton_irq(int irq, void *_pwr)
 	return IRQ_HANDLED;
 }
 
-static int __devinit twl4030_pwrbutton_probe(struct platform_device *pdev)
+static int __init twl4030_pwrbutton_probe(struct platform_device *pdev)
 {
 	struct input_dev *pwr;
 	int irq = platform_get_irq(pdev, 0);
@@ -95,7 +95,7 @@ free_input_dev:
 	return err;
 }
 
-static int __devexit twl4030_pwrbutton_remove(struct platform_device *pdev)
+static int __exit twl4030_pwrbutton_remove(struct platform_device *pdev)
 {
 	struct input_dev *pwr = platform_get_drvdata(pdev);
 	int irq = platform_get_irq(pdev, 0);
@@ -106,9 +106,8 @@ static int __devexit twl4030_pwrbutton_remove(struct platform_device *pdev)
 	return 0;
 }
 
-struct platform_driver twl4030_pwrbutton_driver = {
-	.probe		= twl4030_pwrbutton_probe,
-	.remove		= __devexit_p(twl4030_pwrbutton_remove),
+static struct platform_driver twl4030_pwrbutton_driver = {
+	.remove		= __exit_p(twl4030_pwrbutton_remove),
 	.driver		= {
 		.name	= "twl4030_pwrbutton",
 		.owner	= THIS_MODULE,
@@ -117,7 +116,8 @@ struct platform_driver twl4030_pwrbutton_driver = {
 
 static int __init twl4030_pwrbutton_init(void)
 {
-	return platform_driver_register(&twl4030_pwrbutton_driver);
+	return platform_driver_probe(&twl4030_pwrbutton_driver,
+			twl4030_pwrbutton_probe);
 }
 module_init(twl4030_pwrbutton_init);
 
diff --git a/drivers/input/misc/wistron_btns.c b/drivers/input/misc/wistron_btns.c
index 4dac8b79fcd4..12501de0c5cd 100644
--- a/drivers/input/misc/wistron_btns.c
+++ b/drivers/input/misc/wistron_btns.c
@@ -1347,7 +1347,7 @@ static int __init wb_module_init(void)
 
 	err = map_bios();
 	if (err)
-		return err;
+		goto err_free_keymap;
 
 	err = platform_driver_register(&wistron_driver);
 	if (err)
@@ -1371,6 +1371,8 @@ static int __init wb_module_init(void)
 	platform_driver_unregister(&wistron_driver);
  err_unmap_bios:
 	unmap_bios();
+ err_free_keymap:
+	kfree(keymap);
 
 	return err;
 }
diff --git a/drivers/input/mouse/bcm5974.c b/drivers/input/mouse/bcm5974.c
index 6dedded27222..ea67c49146a3 100644
--- a/drivers/input/mouse/bcm5974.c
+++ b/drivers/input/mouse/bcm5974.c
@@ -312,6 +312,8 @@ static void setup_events_to_report(struct input_dev *input_dev,
 	__set_bit(BTN_TOOL_TRIPLETAP, input_dev->keybit);
 	__set_bit(BTN_TOOL_QUADTAP, input_dev->keybit);
 	__set_bit(BTN_LEFT, input_dev->keybit);
+
+	input_set_events_per_packet(input_dev, 60);
 }
 
 /* report button data as logical button state */
@@ -580,23 +582,30 @@ exit:
  */
 static int bcm5974_start_traffic(struct bcm5974 *dev)
 {
-	if (bcm5974_wellspring_mode(dev, true)) {
+	int error;
+
+	error = bcm5974_wellspring_mode(dev, true);
+	if (error) {
 		dprintk(1, "bcm5974: mode switch failed\n");
-		goto error;
+		goto err_out;
 	}
 
-	if (usb_submit_urb(dev->bt_urb, GFP_KERNEL))
-		goto error;
+	error = usb_submit_urb(dev->bt_urb, GFP_KERNEL);
+	if (error)
+		goto err_reset_mode;
 
-	if (usb_submit_urb(dev->tp_urb, GFP_KERNEL))
+	error = usb_submit_urb(dev->tp_urb, GFP_KERNEL);
+	if (error)
 		goto err_kill_bt;
 
 	return 0;
 
 err_kill_bt:
 	usb_kill_urb(dev->bt_urb);
-error:
-	return -EIO;
+err_reset_mode:
+	bcm5974_wellspring_mode(dev, false);
+err_out:
+	return error;
 }
 
 static void bcm5974_pause_traffic(struct bcm5974 *dev)
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
index 705589dc9ac5..8c324403b9f2 100644
--- a/drivers/input/mouse/synaptics.c
+++ b/drivers/input/mouse/synaptics.c
@@ -502,7 +502,9 @@ static void synaptics_process_packet(struct psmouse *psmouse)
 	}
 	input_report_abs(dev, ABS_PRESSURE, hw.z);
 
-	input_report_abs(dev, ABS_TOOL_WIDTH, finger_width);
+	if (SYN_CAP_PALMDETECT(priv->capabilities))
+		input_report_abs(dev, ABS_TOOL_WIDTH, finger_width);
+
 	input_report_key(dev, BTN_TOOL_FINGER, num_fingers == 1);
 	input_report_key(dev, BTN_LEFT, hw.left);
 	input_report_key(dev, BTN_RIGHT, hw.right);
@@ -602,7 +604,9 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv)
 	input_set_abs_params(dev, ABS_Y,
 			     YMIN_NOMINAL, priv->y_max ?: YMAX_NOMINAL, 0, 0);
 	input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0);
-	__set_bit(ABS_TOOL_WIDTH, dev->absbit);
+
+	if (SYN_CAP_PALMDETECT(priv->capabilities))
+		input_set_abs_params(dev, ABS_TOOL_WIDTH, 0, 15, 0, 0);
 
 	__set_bit(EV_KEY, dev->evbit);
 	__set_bit(BTN_TOUCH, dev->keybit);
diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c
index f34b22bce4ff..d8f68f77007b 100644
--- a/drivers/input/mousedev.c
+++ b/drivers/input/mousedev.c
@@ -57,7 +57,6 @@ struct mousedev_hw_data {
 };
 
 struct mousedev {
-	int exist;
 	int open;
 	int minor;
 	struct input_handle handle;
@@ -66,6 +65,7 @@ struct mousedev {
 	spinlock_t client_lock; /* protects client_list */
 	struct mutex mutex;
 	struct device dev;
+	bool exist;
 
 	struct list_head mixdev_node;
 	int mixdev_open;
@@ -765,10 +765,15 @@ static unsigned int mousedev_poll(struct file *file, poll_table *wait)
 {
 	struct mousedev_client *client = file->private_data;
 	struct mousedev *mousedev = client->mousedev;
+	unsigned int mask;
 
 	poll_wait(file, &mousedev->wait, wait);
-	return ((client->ready || client->buffer) ? (POLLIN | POLLRDNORM) : 0) |
-		(mousedev->exist ? 0 : (POLLHUP | POLLERR));
+
+	mask = mousedev->exist ? POLLOUT | POLLWRNORM : POLLHUP | POLLERR;
+	if (client->ready || client->buffer)
+		mask |= POLLIN | POLLRDNORM;
+
+	return mask;
 }
 
 static const struct file_operations mousedev_fops = {
@@ -802,7 +807,7 @@ static void mousedev_remove_chrdev(struct mousedev *mousedev)
 static void mousedev_mark_dead(struct mousedev *mousedev)
 {
 	mutex_lock(&mousedev->mutex);
-	mousedev->exist = 0;
+	mousedev->exist = false;
 	mutex_unlock(&mousedev->mutex);
 }
 
@@ -862,7 +867,7 @@ static struct mousedev *mousedev_create(struct input_dev *dev,
 		dev_set_name(&mousedev->dev, "mouse%d", minor);
 
 	mousedev->minor = minor;
-	mousedev->exist = 1;
+	mousedev->exist = true;
 	mousedev->handle.dev = input_get_device(dev);
 	mousedev->handle.name = dev_name(&mousedev->dev);
 	mousedev->handle.handler = handler;
diff --git a/drivers/input/serio/i8042-ppcio.h b/drivers/input/serio/i8042-ppcio.h
index 2906e1b60c04..f708c75d16f1 100644
--- a/drivers/input/serio/i8042-ppcio.h
+++ b/drivers/input/serio/i8042-ppcio.h
@@ -52,81 +52,6 @@ static inline void i8042_platform_exit(void)
 {
 }
 
-#elif defined(CONFIG_SPRUCE)
-
-#define I8042_KBD_IRQ 22
-#define I8042_AUX_IRQ 21
-
-#define I8042_KBD_PHYS_DESC "spruceps2/serio0"
-#define I8042_AUX_PHYS_DESC "spruceps2/serio1"
-#define I8042_MUX_PHYS_DESC "spruceps2/serio%d"
-
-#define I8042_COMMAND_REG 0xff810000
-#define I8042_DATA_REG 0xff810001
-
-static inline int i8042_read_data(void)
-{
-	unsigned long kbd_data;
-
-	__raw_writel(0x00000088, 0xff500008);
-	eieio();
-
-	__raw_writel(0x03000000, 0xff50000c);
-	eieio();
-
-	asm volatile("lis     7,0xff88        \n\
-		      lswi    6,7,0x8         \n\
-		      mr      %0,6"
-	              : "=r" (kbd_data) :: "6", "7");
-
-	__raw_writel(0x00000000, 0xff50000c);
-	eieio();
-
-	return (unsigned char)(kbd_data >> 24);
-}
-
-static inline int i8042_read_status(void)
-{
-	unsigned long kbd_status;
-
-	__raw_writel(0x00000088, 0xff500008);
-	eieio();
-
-	__raw_writel(0x03000000, 0xff50000c);
-	eieio();
-
-	asm volatile("lis     7,0xff88        \n\
-		      ori     7,7,0x8         \n\
-		      lswi    6,7,0x8         \n\
-		      mr      %0,6"
-		      : "=r" (kbd_status) :: "6", "7");
-
-	__raw_writel(0x00000000, 0xff50000c);
-	eieio();
-
-	return (unsigned char)(kbd_status >> 24);
-}
-
-static inline void i8042_write_data(int val)
-{
-	*((unsigned char *)0xff810000) = (char)val;
-}
-
-static inline void i8042_write_command(int val)
-{
-	*((unsigned char *)0xff810001) = (char)val;
-}
-
-static inline int i8042_platform_init(void)
-{
-	i8042_reset = 1;
-	return 0;
-}
-
-static inline void i8042_platform_exit(void)
-{
-}
-
 #else
 
 #include "i8042-io.h"
diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c
index 6440a8f55686..258b98b9d7c2 100644
--- a/drivers/input/serio/i8042.c
+++ b/drivers/input/serio/i8042.c
@@ -861,9 +861,6 @@ static int i8042_controller_selftest(void)
 	unsigned char param;
 	int i = 0;
 
-	if (!i8042_reset)
-		return 0;
-
 	/*
 	 * We try this 5 times; on some really fragile systems this does not
 	 * take the first time...
@@ -1020,7 +1017,8 @@ static void i8042_controller_reset(void)
  * Reset the controller if requested.
  */
 
-	i8042_controller_selftest();
+	if (i8042_reset)
+		i8042_controller_selftest();
 
 /*
  * Restore the original control register setting.
@@ -1094,23 +1092,11 @@ static void i8042_dritek_enable(void)
 #ifdef CONFIG_PM
 
 /*
- * Here we try to restore the original BIOS settings to avoid
- * upsetting it.
- */
-
-static int i8042_pm_reset(struct device *dev)
-{
-	i8042_controller_reset();
-
-	return 0;
-}
-
-/*
  * Here we try to reset everything back to a state we had
  * before suspending.
  */
 
-static int i8042_pm_restore(struct device *dev)
+static int i8042_controller_resume(bool force_reset)
 {
 	int error;
 
@@ -1118,9 +1104,11 @@ static int i8042_pm_restore(struct device *dev)
 	if (error)
 		return error;
 
-	error = i8042_controller_selftest();
-	if (error)
-		return error;
+	if (i8042_reset || force_reset) {
+		error = i8042_controller_selftest();
+		if (error)
+			return error;
+	}
 
 /*
  * Restore original CTR value and disable all ports
@@ -1162,6 +1150,28 @@ static int i8042_pm_restore(struct device *dev)
 	return 0;
 }
 
+/*
+ * Here we try to restore the original BIOS settings to avoid
+ * upsetting it.
+ */
+
+static int i8042_pm_reset(struct device *dev)
+{
+	i8042_controller_reset();
+
+	return 0;
+}
+
+static int i8042_pm_resume(struct device *dev)
+{
+	/*
+	 * On resume from S2R we always try to reset the controller
+	 * to bring it in a sane state. (In case of S2D we expect
+	 * BIOS to reset the controller for us.)
+	 */
+	return i8042_controller_resume(true);
+}
+
 static int i8042_pm_thaw(struct device *dev)
 {
 	i8042_interrupt(0, NULL);
@@ -1169,9 +1179,14 @@ static int i8042_pm_thaw(struct device *dev)
 	return 0;
 }
 
+static int i8042_pm_restore(struct device *dev)
+{
+	return i8042_controller_resume(false);
+}
+
 static const struct dev_pm_ops i8042_pm_ops = {
 	.suspend	= i8042_pm_reset,
-	.resume		= i8042_pm_restore,
+	.resume		= i8042_pm_resume,
 	.thaw		= i8042_pm_thaw,
 	.poweroff	= i8042_pm_reset,
 	.restore	= i8042_pm_restore,
@@ -1389,9 +1404,11 @@ static int __init i8042_probe(struct platform_device *dev)
 
 	i8042_platform_device = dev;
 
-	error = i8042_controller_selftest();
-	if (error)
-		return error;
+	if (i8042_reset) {
+		error = i8042_controller_selftest();
+		if (error)
+			return error;
+	}
 
 	error = i8042_controller_init();
 	if (error)
diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c
index 415f6306105d..ce0b4608dad9 100644
--- a/drivers/input/tablet/wacom_wac.c
+++ b/drivers/input/tablet/wacom_wac.c
@@ -158,6 +158,39 @@ static int wacom_ptu_irq(struct wacom_wac *wacom)
 	return 1;
 }
 
+static int wacom_dtu_irq(struct wacom_wac *wacom)
+{
+	struct wacom_features *features = &wacom->features;
+	char *data = wacom->data;
+	struct input_dev *input = wacom->input;
+	int prox = data[1] & 0x20, pressure;
+
+	dbg("wacom_dtu_irq: received report #%d", data[0]);
+
+	if (prox) {
+		/* Going into proximity select tool */
+		wacom->tool[0] = (data[1] & 0x0c) ? BTN_TOOL_RUBBER : BTN_TOOL_PEN;
+		if (wacom->tool[0] == BTN_TOOL_PEN)
+			wacom->id[0] = STYLUS_DEVICE_ID;
+		else
+			wacom->id[0] = ERASER_DEVICE_ID;
+	}
+	input_report_key(input, BTN_STYLUS, data[1] & 0x02);
+	input_report_key(input, BTN_STYLUS2, data[1] & 0x10);
+	input_report_abs(input, ABS_X, le16_to_cpup((__le16 *)&data[2]));
+	input_report_abs(input, ABS_Y, le16_to_cpup((__le16 *)&data[4]));
+	pressure = ((data[7] & 0x01) << 8) | data[6];
+	if (pressure < 0)
+		pressure = features->pressure_max + pressure + 1;
+	input_report_abs(input, ABS_PRESSURE, pressure);
+	input_report_key(input, BTN_TOUCH, data[1] & 0x05);
+	if (!prox) /* out-prox */
+		wacom->id[0] = 0;
+	input_report_key(input, wacom->tool[0], prox);
+	input_report_abs(input, ABS_MISC, wacom->id[0]);
+	return 1;
+}
+
 static int wacom_graphire_irq(struct wacom_wac *wacom)
 {
 	struct wacom_features *features = &wacom->features;
@@ -845,6 +878,10 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)
 		sync = wacom_ptu_irq(wacom_wac);
 		break;
 
+	case DTU:
+		sync = wacom_dtu_irq(wacom_wac);
+		break;
+
 	case INTUOS:
 	case INTUOS3S:
 	case INTUOS3:
@@ -1030,6 +1067,7 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
 
 	case PL:
 	case PTU:
+	case DTU:
 		__set_bit(BTN_TOOL_PEN, input_dev->keybit);
 		__set_bit(BTN_STYLUS, input_dev->keybit);
 		__set_bit(BTN_STYLUS2, input_dev->keybit);
@@ -1155,6 +1193,10 @@ static const struct wacom_features wacom_features_0xC6 =
 	{ "Wacom Cintiq 12WX",    WACOM_PKGLEN_INTUOS,    53020, 33440, 1023, 63, WACOM_BEE };
 static const struct wacom_features wacom_features_0xC7 =
 	{ "Wacom DTU1931",        WACOM_PKGLEN_GRAPHIRE,  37832, 30305,  511,  0, PL };
+static const struct wacom_features wacom_features_0xCE =
+	{ "Wacom DTU2231",        WACOM_PKGLEN_GRAPHIRE,  47864, 27011,  511,  0, DTU };
+static const struct wacom_features wacom_features_0xF0 =
+	{ "Wacom DTU1631",        WACOM_PKGLEN_GRAPHIRE,  34623, 19553,  511,  0, DTU };
 static const struct wacom_features wacom_features_0xCC =
 	{ "Wacom Cintiq 21UX2",   WACOM_PKGLEN_INTUOS,    87200, 65600, 2047, 63, WACOM_21UX2 };
 static const struct wacom_features wacom_features_0x90 =
@@ -1234,6 +1276,8 @@ const struct usb_device_id wacom_ids[] = {
 	{ USB_DEVICE_WACOM(0xC5) },
 	{ USB_DEVICE_WACOM(0xC6) },
 	{ USB_DEVICE_WACOM(0xC7) },
+	{ USB_DEVICE_WACOM(0xCE) },
+	{ USB_DEVICE_WACOM(0xF0) },
 	{ USB_DEVICE_WACOM(0xCC) },
 	{ USB_DEVICE_WACOM(0x90) },
 	{ USB_DEVICE_WACOM(0x93) },
diff --git a/drivers/input/tablet/wacom_wac.h b/drivers/input/tablet/wacom_wac.h
index 854b92092dfc..99e1a54cd305 100644
--- a/drivers/input/tablet/wacom_wac.h
+++ b/drivers/input/tablet/wacom_wac.h
@@ -43,6 +43,7 @@ enum {
 	WACOM_G4,
 	PTU,
 	PL,
+	DTU,
 	INTUOS,
 	INTUOS3S,
 	INTUOS3,
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 3b9d5e2105d7..61f35184f76c 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -55,37 +55,36 @@ config TOUCHSCREEN_AD7877
 	  To compile this driver as a module, choose M here: the
 	  module will be called ad7877.
 
-config TOUCHSCREEN_AD7879_I2C
-	tristate "AD7879 based touchscreens: AD7879-1 I2C Interface"
-	depends on I2C
-	select TOUCHSCREEN_AD7879
+config TOUCHSCREEN_AD7879
+	tristate "Analog Devices AD7879-1/AD7889-1 touchscreen interface"
 	help
-	  Say Y here if you have a touchscreen interface using the
-	  AD7879-1/AD7889-1 controller, and your board-specific
-	  initialization code includes that in its table of I2C devices.
+	  Say Y here if you want to support a touchscreen interface using
+	  the AD7879-1/AD7889-1 controller.
 
-	  If unsure, say N (but it's safe to say "Y").
+	  You should select a bus connection too.
 
 	  To compile this driver as a module, choose M here: the
 	  module will be called ad7879.
 
+config TOUCHSCREEN_AD7879_I2C
+	tristate "support I2C bus connection"
+	depends on TOUCHSCREEN_AD7879 && I2C
+	help
+	  Say Y here if you have AD7879-1/AD7889-1 hooked to an I2C bus.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ad7879-i2c.
+
 config TOUCHSCREEN_AD7879_SPI
-	tristate "AD7879 based touchscreens: AD7879 SPI Interface"
-	depends on SPI_MASTER && TOUCHSCREEN_AD7879_I2C = n
-	select TOUCHSCREEN_AD7879
+	tristate "support SPI bus connection"
+	depends on TOUCHSCREEN_AD7879 && SPI_MASTER
 	help
-	  Say Y here if you have a touchscreen interface using the
-	  AD7879/AD7889 controller, and your board-specific initialization
-	  code includes that in its table of SPI devices.
+	  Say Y here if you have AD7879-1/AD7889-1 hooked to a SPI bus.
 
 	  If unsure, say N (but it's safe to say "Y").
 
 	  To compile this driver as a module, choose M here: the
-	  module will be called ad7879.
-
-config TOUCHSCREEN_AD7879
-	tristate
-	default n
+	  module will be called ad7879-spi.
 
 config TOUCHSCREEN_BITSY
 	tristate "Compaq iPAQ H3600 (Bitsy) touchscreen"
@@ -99,6 +98,20 @@ config TOUCHSCREEN_BITSY
 	  To compile this driver as a module, choose M here: the
 	  module will be called h3600_ts_input.
 
+config TOUCHSCREEN_CY8CTMG110
+	tristate "cy8ctmg110 touchscreen"
+	depends on I2C
+	depends on GPIOLIB
+
+	help
+	  Say Y here if you have a cy8ctmg110 capacitive touchscreen on
+	  an AAVA device.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called cy8ctmg110_ts.
+
 config TOUCHSCREEN_DA9034
 	tristate "Touchscreen support for Dialog Semiconductor DA9034"
 	depends on PMIC_DA903X
@@ -292,6 +305,18 @@ config TOUCHSCREEN_PENMOUNT
 	  To compile this driver as a module, choose M here: the
 	  module will be called penmount.
 
+config TOUCHSCREEN_QT602240
+	tristate "QT602240 I2C Touchscreen"
+	depends on I2C
+	help
+	  Say Y here if you have the AT42QT602240/ATMXT224 I2C touchscreen
+	  connected to your system.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called qt602240_ts.
+
 config TOUCHSCREEN_MIGOR
 	tristate "Renesas MIGO-R touchscreen"
 	depends on SH_MIGOR && I2C
@@ -540,9 +565,9 @@ config TOUCHSCREEN_USB_ZYTRONIC
 	bool "Zytronic controller" if EMBEDDED
 	depends on TOUCHSCREEN_USB_COMPOSITE
 
-config TOUCHSCREEN_USB_ETT_TC5UH
+config TOUCHSCREEN_USB_ETT_TC45USB
 	default y
-	bool "ET&T TC5UH touchscreen controler support" if EMBEDDED
+	bool "ET&T USB series TC4UM/TC5UH touchscreen controler support" if EMBEDDED
 	depends on TOUCHSCREEN_USB_COMPOSITE
 
 config TOUCHSCREEN_USB_NEXIO
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 497964a7a214..bd6f30b4ff70 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -9,9 +9,13 @@ wm97xx-ts-y := wm97xx-core.o
 obj-$(CONFIG_TOUCHSCREEN_88PM860X)	+= 88pm860x-ts.o
 obj-$(CONFIG_TOUCHSCREEN_AD7877)	+= ad7877.o
 obj-$(CONFIG_TOUCHSCREEN_AD7879)	+= ad7879.o
+obj-$(CONFIG_TOUCHSCREEN_AD7879_I2C)	+= ad7879-i2c.o
+obj-$(CONFIG_TOUCHSCREEN_AD7879_SPI)	+= ad7879-spi.o
 obj-$(CONFIG_TOUCHSCREEN_ADS7846)	+= ads7846.o
 obj-$(CONFIG_TOUCHSCREEN_ATMEL_TSADCC)	+= atmel_tsadcc.o
 obj-$(CONFIG_TOUCHSCREEN_BITSY)		+= h3600_ts_input.o
+obj-$(CONFIG_TOUCHSCREEN_CY8CTMG110)	+= cy8ctmg110_ts.o
+obj-$(CONFIG_TOUCHSCREEN_DA9034)	+= da9034-ts.o
 obj-$(CONFIG_TOUCHSCREEN_DYNAPRO)	+= dynapro.o
 obj-$(CONFIG_TOUCHSCREEN_HAMPSHIRE)	+= hampshire.o
 obj-$(CONFIG_TOUCHSCREEN_GUNZE)		+= gunze.o
@@ -30,6 +34,7 @@ obj-$(CONFIG_TOUCHSCREEN_HTCPEN)	+= htcpen.o
 obj-$(CONFIG_TOUCHSCREEN_USB_COMPOSITE)	+= usbtouchscreen.o
 obj-$(CONFIG_TOUCHSCREEN_PCAP)		+= pcap_ts.o
 obj-$(CONFIG_TOUCHSCREEN_PENMOUNT)	+= penmount.o
+obj-$(CONFIG_TOUCHSCREEN_QT602240)	+= qt602240_ts.o
 obj-$(CONFIG_TOUCHSCREEN_S3C2410)	+= s3c2410_ts.o
 obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213)	+= touchit213.o
 obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT)	+= touchright.o
@@ -38,7 +43,6 @@ obj-$(CONFIG_TOUCHSCREEN_TSC2007)	+= tsc2007.o
 obj-$(CONFIG_TOUCHSCREEN_UCB1400)	+= ucb1400_ts.o
 obj-$(CONFIG_TOUCHSCREEN_WACOM_W8001)	+= wacom_w8001.o
 obj-$(CONFIG_TOUCHSCREEN_WM97XX)	+= wm97xx-ts.o
-obj-$(CONFIG_TOUCHSCREEN_DA9034)	+= da9034-ts.o
 wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9705)	+= wm9705.o
 wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9712)	+= wm9712.o
 wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9713)	+= wm9713.o
diff --git a/drivers/input/touchscreen/ad7879-i2c.c b/drivers/input/touchscreen/ad7879-i2c.c
new file mode 100644
index 000000000000..d82a38ee9a3e
--- /dev/null
+++ b/drivers/input/touchscreen/ad7879-i2c.c
@@ -0,0 +1,143 @@
+/*
+ * AD7879-1/AD7889-1 touchscreen (I2C bus)
+ *
+ * Copyright (C) 2008-2010 Michael Hennerich, Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/input.h>	/* BUS_I2C */
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/types.h>
+
+#include "ad7879.h"
+
+#define AD7879_DEVID		0x79	/* AD7879-1/AD7889-1 */
+
+#ifdef CONFIG_PM
+static int ad7879_i2c_suspend(struct i2c_client *client, pm_message_t message)
+{
+	struct ad7879 *ts = i2c_get_clientdata(client);
+
+	ad7879_suspend(ts);
+
+	return 0;
+}
+
+static int ad7879_i2c_resume(struct i2c_client *client)
+{
+	struct ad7879 *ts = i2c_get_clientdata(client);
+
+	ad7879_resume(ts);
+
+	return 0;
+}
+#else
+# define ad7879_i2c_suspend NULL
+# define ad7879_i2c_resume  NULL
+#endif
+
+/* All registers are word-sized.
+ * AD7879 uses a high-byte first convention.
+ */
+static int ad7879_i2c_read(struct device *dev, u8 reg)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+
+	return swab16(i2c_smbus_read_word_data(client, reg));
+}
+
+static int ad7879_i2c_multi_read(struct device *dev,
+				 u8 first_reg, u8 count, u16 *buf)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	u8 idx;
+
+	i2c_smbus_read_i2c_block_data(client, first_reg, count * 2, (u8 *)buf);
+
+	for (idx = 0; idx < count; ++idx)
+		buf[idx] = swab16(buf[idx]);
+
+	return 0;
+}
+
+static int ad7879_i2c_write(struct device *dev, u8 reg, u16 val)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+
+	return i2c_smbus_write_word_data(client, reg, swab16(val));
+}
+
+static const struct ad7879_bus_ops ad7879_i2c_bus_ops = {
+	.bustype	= BUS_I2C,
+	.read		= ad7879_i2c_read,
+	.multi_read	= ad7879_i2c_multi_read,
+	.write		= ad7879_i2c_write,
+};
+
+static int __devinit ad7879_i2c_probe(struct i2c_client *client,
+				      const struct i2c_device_id *id)
+{
+	struct ad7879 *ts;
+
+	if (!i2c_check_functionality(client->adapter,
+				     I2C_FUNC_SMBUS_WORD_DATA)) {
+		dev_err(&client->dev, "SMBUS Word Data not Supported\n");
+		return -EIO;
+	}
+
+	ts = ad7879_probe(&client->dev, AD7879_DEVID, client->irq,
+			  &ad7879_i2c_bus_ops);
+	if (IS_ERR(ts))
+		return PTR_ERR(ts);
+
+	i2c_set_clientdata(client, ts);
+
+	return 0;
+}
+
+static int __devexit ad7879_i2c_remove(struct i2c_client *client)
+{
+	struct ad7879 *ts = i2c_get_clientdata(client);
+
+	ad7879_remove(ts);
+
+	return 0;
+}
+
+static const struct i2c_device_id ad7879_id[] = {
+	{ "ad7879", 0 },
+	{ "ad7889", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, ad7879_id);
+
+static struct i2c_driver ad7879_i2c_driver = {
+	.driver = {
+		.name	= "ad7879",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= ad7879_i2c_probe,
+	.remove		= __devexit_p(ad7879_i2c_remove),
+	.suspend	= ad7879_i2c_suspend,
+	.resume		= ad7879_i2c_resume,
+	.id_table	= ad7879_id,
+};
+
+static int __init ad7879_i2c_init(void)
+{
+	return i2c_add_driver(&ad7879_i2c_driver);
+}
+module_init(ad7879_i2c_init);
+
+static void __exit ad7879_i2c_exit(void)
+{
+	i2c_del_driver(&ad7879_i2c_driver);
+}
+module_exit(ad7879_i2c_exit);
+
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("AD7879(-1) touchscreen I2C bus driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("i2c:ad7879");
diff --git a/drivers/input/touchscreen/ad7879-spi.c b/drivers/input/touchscreen/ad7879-spi.c
new file mode 100644
index 000000000000..59c6e68c4325
--- /dev/null
+++ b/drivers/input/touchscreen/ad7879-spi.c
@@ -0,0 +1,198 @@
+/*
+ * AD7879/AD7889 touchscreen (SPI bus)
+ *
+ * Copyright (C) 2008-2010 Michael Hennerich, Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/input.h>	/* BUS_SPI */
+#include <linux/spi/spi.h>
+
+#include "ad7879.h"
+
+#define AD7879_DEVID		0x7A	/* AD7879/AD7889 */
+
+#define MAX_SPI_FREQ_HZ      5000000
+#define AD7879_CMD_MAGIC     0xE000
+#define AD7879_CMD_READ      (1 << 10)
+#define AD7879_CMD(reg)      (AD7879_CMD_MAGIC | ((reg) & 0xF))
+#define AD7879_WRITECMD(reg) (AD7879_CMD(reg))
+#define AD7879_READCMD(reg)  (AD7879_CMD(reg) | AD7879_CMD_READ)
+
+#ifdef CONFIG_PM
+static int ad7879_spi_suspend(struct spi_device *spi, pm_message_t message)
+{
+	struct ad7879 *ts = spi_get_drvdata(spi);
+
+	ad7879_suspend(ts);
+
+	return 0;
+}
+
+static int ad7879_spi_resume(struct spi_device *spi)
+{
+	struct ad7879 *ts = spi_get_drvdata(spi);
+
+	ad7879_resume(ts);
+
+	return 0;
+}
+#else
+# define ad7879_spi_suspend NULL
+# define ad7879_spi_resume  NULL
+#endif
+
+/*
+ * ad7879_read/write are only used for initial setup and for sysfs controls.
+ * The main traffic is done in ad7879_collect().
+ */
+
+static int ad7879_spi_xfer(struct spi_device *spi,
+			   u16 cmd, u8 count, u16 *tx_buf, u16 *rx_buf)
+{
+	struct spi_message msg;
+	struct spi_transfer *xfers;
+	void *spi_data;
+	u16 *command;
+	u16 *_rx_buf = _rx_buf; /* shut gcc up */
+	u8 idx;
+	int ret;
+
+	xfers = spi_data = kzalloc(sizeof(*xfers) * (count + 2), GFP_KERNEL);
+	if (!spi_data)
+		return -ENOMEM;
+
+	spi_message_init(&msg);
+
+	command = spi_data;
+	command[0] = cmd;
+	if (count == 1) {
+		/* ad7879_spi_{read,write} gave us buf on stack */
+		command[1] = *tx_buf;
+		tx_buf = &command[1];
+		_rx_buf = rx_buf;
+		rx_buf = &command[2];
+	}
+
+	++xfers;
+	xfers[0].tx_buf = command;
+	xfers[0].len = 2;
+	spi_message_add_tail(&xfers[0], &msg);
+	++xfers;
+
+	for (idx = 0; idx < count; ++idx) {
+		if (rx_buf)
+			xfers[idx].rx_buf = &rx_buf[idx];
+		if (tx_buf)
+			xfers[idx].tx_buf = &tx_buf[idx];
+		xfers[idx].len = 2;
+		spi_message_add_tail(&xfers[idx], &msg);
+	}
+
+	ret = spi_sync(spi, &msg);
+
+	if (count == 1)
+		_rx_buf[0] = command[2];
+
+	kfree(spi_data);
+
+	return ret;
+}
+
+static int ad7879_spi_multi_read(struct device *dev,
+				 u8 first_reg, u8 count, u16 *buf)
+{
+	struct spi_device *spi = to_spi_device(dev);
+
+	return ad7879_spi_xfer(spi, AD7879_READCMD(first_reg), count, NULL, buf);
+}
+
+static int ad7879_spi_read(struct device *dev, u8 reg)
+{
+	struct spi_device *spi = to_spi_device(dev);
+	u16 ret, dummy;
+
+	return ad7879_spi_xfer(spi, AD7879_READCMD(reg), 1, &dummy, &ret) ? : ret;
+}
+
+static int ad7879_spi_write(struct device *dev, u8 reg, u16 val)
+{
+	struct spi_device *spi = to_spi_device(dev);
+	u16 dummy;
+
+	return ad7879_spi_xfer(spi, AD7879_WRITECMD(reg), 1, &val, &dummy);
+}
+
+static const struct ad7879_bus_ops ad7879_spi_bus_ops = {
+	.bustype	= BUS_SPI,
+	.read		= ad7879_spi_read,
+	.multi_read	= ad7879_spi_multi_read,
+	.write		= ad7879_spi_write,
+};
+
+static int __devinit ad7879_spi_probe(struct spi_device *spi)
+{
+	struct ad7879 *ts;
+	int err;
+
+	/* don't exceed max specified SPI CLK frequency */
+	if (spi->max_speed_hz > MAX_SPI_FREQ_HZ) {
+		dev_err(&spi->dev, "SPI CLK %d Hz?\n", spi->max_speed_hz);
+		return -EINVAL;
+	}
+
+	spi->bits_per_word = 16;
+	err = spi_setup(spi);
+	if (err) {
+	        dev_dbg(&spi->dev, "spi master doesn't support 16 bits/word\n");
+	        return err;
+	}
+
+	ts = ad7879_probe(&spi->dev, AD7879_DEVID, spi->irq, &ad7879_spi_bus_ops);
+	if (IS_ERR(ts))
+		return PTR_ERR(ts);
+
+	spi_set_drvdata(spi, ts);
+
+	return 0;
+}
+
+static int __devexit ad7879_spi_remove(struct spi_device *spi)
+{
+	struct ad7879 *ts = spi_get_drvdata(spi);
+
+	ad7879_remove(ts);
+	spi_set_drvdata(spi, NULL);
+
+	return 0;
+}
+
+static struct spi_driver ad7879_spi_driver = {
+	.driver = {
+		.name	= "ad7879",
+		.bus	= &spi_bus_type,
+		.owner	= THIS_MODULE,
+	},
+	.probe		= ad7879_spi_probe,
+	.remove		= __devexit_p(ad7879_spi_remove),
+	.suspend	= ad7879_spi_suspend,
+	.resume		= ad7879_spi_resume,
+};
+
+static int __init ad7879_spi_init(void)
+{
+	return spi_register_driver(&ad7879_spi_driver);
+}
+module_init(ad7879_spi_init);
+
+static void __exit ad7879_spi_exit(void)
+{
+	spi_unregister_driver(&ad7879_spi_driver);
+}
+module_exit(ad7879_spi_exit);
+
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("AD7879(-1) touchscreen SPI bus driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("spi:ad7879");
diff --git a/drivers/input/touchscreen/ad7879.c b/drivers/input/touchscreen/ad7879.c
index 4b32fb4704cd..ba6f0bd1e762 100644
--- a/drivers/input/touchscreen/ad7879.c
+++ b/drivers/input/touchscreen/ad7879.c
@@ -1,25 +1,9 @@
 /*
- * Copyright (C) 2008-2009 Michael Hennerich, Analog Devices Inc.
+ * AD7879/AD7889 based touchscreen and GPIO driver
  *
- * Description:	AD7879/AD7889 based touchscreen, and GPIO driver
- *		(I2C/SPI Interface)
+ * Copyright (C) 2008-2010 Michael Hennerich, Analog Devices Inc.
  *
- * Bugs:        Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ * Licensed under the GPL-2 or later.
  *
  * History:
  * Copyright (c) 2005 David Brownell
@@ -44,12 +28,12 @@
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/slab.h>
-#include <linux/workqueue.h>
 #include <linux/spi/spi.h>
 #include <linux/i2c.h>
 #include <linux/gpio.h>
 
 #include <linux/spi/ad7879.h>
+#include "ad7879.h"
 
 #define AD7879_REG_ZEROS		0
 #define AD7879_REG_CTRL1		1
@@ -120,30 +104,19 @@ enum {
 #define	MAX_12BIT			((1<<12)-1)
 #define	TS_PEN_UP_TIMEOUT		msecs_to_jiffies(50)
 
-#if defined(CONFIG_TOUCHSCREEN_AD7879_SPI) || defined(CONFIG_TOUCHSCREEN_AD7879_SPI_MODULE)
-#define AD7879_DEVID		0x7A
-typedef struct spi_device	bus_device;
-#elif defined(CONFIG_TOUCHSCREEN_AD7879_I2C) || defined(CONFIG_TOUCHSCREEN_AD7879_I2C_MODULE)
-#define AD7879_DEVID		0x79
-typedef struct i2c_client	bus_device;
-#endif
-
 struct ad7879 {
-	bus_device		*bus;
+	const struct ad7879_bus_ops *bops;
+
+	struct device		*dev;
 	struct input_dev	*input;
-	struct work_struct	work;
 	struct timer_list	timer;
 #ifdef CONFIG_GPIOLIB
 	struct gpio_chip	gc;
-#endif
 	struct mutex		mutex;
-	unsigned		disabled:1;	/* P: mutex */
-
-#if defined(CONFIG_TOUCHSCREEN_AD7879_SPI) || defined(CONFIG_TOUCHSCREEN_AD7879_SPI_MODULE)
-	struct spi_message	msg;
-	struct spi_transfer	xfer[AD7879_NR_SENSE + 1];
-	u16			cmd;
 #endif
+	unsigned int		irq;
+	bool			disabled;	/* P: input->mutex */
+	bool			suspended;	/* P: input->mutex */
 	u16			conversion_data[AD7879_NR_SENSE];
 	char			phys[32];
 	u8			first_conversion_delay;
@@ -158,11 +131,22 @@ struct ad7879 {
 	u16			cmd_crtl3;
 };
 
-static int ad7879_read(bus_device *, u8);
-static int ad7879_write(bus_device *, u8, u16);
-static void ad7879_collect(struct ad7879 *);
+static int ad7879_read(struct ad7879 *ts, u8 reg)
+{
+	return ts->bops->read(ts->dev, reg);
+}
+
+static int ad7879_multi_read(struct ad7879 *ts, u8 first_reg, u8 count, u16 *buf)
+{
+	return ts->bops->multi_read(ts->dev, first_reg, count, buf);
+}
 
-static void ad7879_report(struct ad7879 *ts)
+static int ad7879_write(struct ad7879 *ts, u8 reg, u16 val)
+{
+	return ts->bops->write(ts->dev, reg, val);
+}
+
+static int ad7879_report(struct ad7879 *ts)
 {
 	struct input_dev *input_dev = ts->input;
 	unsigned Rt;
@@ -175,12 +159,14 @@ static void ad7879_report(struct ad7879 *ts)
 
 	/*
 	 * The samples processed here are already preprocessed by the AD7879.
-	 * The preprocessing function consists of a median and an averaging filter.
-	 * The combination of these two techniques provides a robust solution,
-	 * discarding the spurious noise in the signal and keeping only the data of interest.
-	 * The size of both filters is programmable. (dev.platform_data, see linux/spi/ad7879.h)
-	 * Other user-programmable conversion controls include variable acquisition time,
-	 * and first conversion delay. Up to 16 averages can be taken per conversion.
+	 * The preprocessing function consists of a median and an averaging
+	 * filter.  The combination of these two techniques provides a robust
+	 * solution, discarding the spurious noise in the signal and keeping
+	 * only the data of interest.  The size of both filters is
+	 * programmable. (dev.platform_data, see linux/spi/ad7879.h) Other
+	 * user-programmable conversion controls include variable acquisition
+	 * time, and first conversion delay. Up to 16 averages can be taken
+	 * per conversion.
 	 */
 
 	if (likely(x && z1)) {
@@ -189,21 +175,17 @@ static void ad7879_report(struct ad7879 *ts)
 		Rt /= z1;
 		Rt = (Rt + 2047) >> 12;
 
+		if (!timer_pending(&ts->timer))
+			input_report_key(input_dev, BTN_TOUCH, 1);
+
 		input_report_abs(input_dev, ABS_X, x);
 		input_report_abs(input_dev, ABS_Y, y);
 		input_report_abs(input_dev, ABS_PRESSURE, Rt);
 		input_sync(input_dev);
+		return 0;
 	}
-}
-
-static void ad7879_work(struct work_struct *work)
-{
-	struct ad7879 *ts = container_of(work, struct ad7879, work);
 
-	/* use keventd context to read the result registers */
-	ad7879_collect(ts);
-	ad7879_report(ts);
-	mod_timer(&ts->timer, jiffies + TS_PEN_UP_TIMEOUT);
+	return -EINVAL;
 }
 
 static void ad7879_ts_event_release(struct ad7879 *ts)
@@ -211,6 +193,7 @@ static void ad7879_ts_event_release(struct ad7879 *ts)
 	struct input_dev *input_dev = ts->input;
 
 	input_report_abs(input_dev, ABS_PRESSURE, 0);
+	input_report_key(input_dev, BTN_TOUCH, 0);
 	input_sync(input_dev);
 }
 
@@ -225,56 +208,98 @@ static irqreturn_t ad7879_irq(int irq, void *handle)
 {
 	struct ad7879 *ts = handle;
 
-	/* The repeated conversion sequencer controlled by TMR kicked off too fast.
-	 * We ignore the last and process the sample sequence currently in the queue.
-	 * It can't be older than 9.4ms
-	 */
+	ad7879_multi_read(ts, AD7879_REG_XPLUS, AD7879_NR_SENSE, ts->conversion_data);
 
-	if (!work_pending(&ts->work))
-		schedule_work(&ts->work);
+	if (!ad7879_report(ts))
+		mod_timer(&ts->timer, jiffies + TS_PEN_UP_TIMEOUT);
 
 	return IRQ_HANDLED;
 }
 
-static void ad7879_setup(struct ad7879 *ts)
+static void __ad7879_enable(struct ad7879 *ts)
 {
-	ad7879_write(ts->bus, AD7879_REG_CTRL2, ts->cmd_crtl2);
-	ad7879_write(ts->bus, AD7879_REG_CTRL3, ts->cmd_crtl3);
-	ad7879_write(ts->bus, AD7879_REG_CTRL1, ts->cmd_crtl1);
+	ad7879_write(ts, AD7879_REG_CTRL2, ts->cmd_crtl2);
+	ad7879_write(ts, AD7879_REG_CTRL3, ts->cmd_crtl3);
+	ad7879_write(ts, AD7879_REG_CTRL1, ts->cmd_crtl1);
+
+	enable_irq(ts->irq);
 }
 
-static void ad7879_disable(struct ad7879 *ts)
+static void __ad7879_disable(struct ad7879 *ts)
 {
-	mutex_lock(&ts->mutex);
+	disable_irq(ts->irq);
+
+	if (del_timer_sync(&ts->timer))
+		ad7879_ts_event_release(ts);
+
+	ad7879_write(ts, AD7879_REG_CTRL2, AD7879_PM(AD7879_PM_SHUTDOWN));
+}
 
-	if (!ts->disabled) {
 
-		ts->disabled = 1;
-		disable_irq(ts->bus->irq);
+static int ad7879_open(struct input_dev *input)
+{
+	struct ad7879 *ts = input_get_drvdata(input);
 
-		cancel_work_sync(&ts->work);
+	/* protected by input->mutex */
+	if (!ts->disabled && !ts->suspended)
+		__ad7879_enable(ts);
 
-		if (del_timer_sync(&ts->timer))
-			ad7879_ts_event_release(ts);
+	return 0;
+}
 
-		ad7879_write(ts->bus, AD7879_REG_CTRL2,
-			     AD7879_PM(AD7879_PM_SHUTDOWN));
-	}
+static void ad7879_close(struct input_dev* input)
+{
+	struct ad7879 *ts = input_get_drvdata(input);
 
-	mutex_unlock(&ts->mutex);
+	/* protected by input->mutex */
+	if (!ts->disabled && !ts->suspended)
+		__ad7879_disable(ts);
 }
 
-static void ad7879_enable(struct ad7879 *ts)
+void ad7879_suspend(struct ad7879 *ts)
 {
-	mutex_lock(&ts->mutex);
+	mutex_lock(&ts->input->mutex);
+
+	if (!ts->suspended && !ts->disabled && ts->input->users)
+		__ad7879_disable(ts);
+
+	ts->suspended = true;
 
-	if (ts->disabled) {
-		ad7879_setup(ts);
-		ts->disabled = 0;
-		enable_irq(ts->bus->irq);
+	mutex_unlock(&ts->input->mutex);
+}
+EXPORT_SYMBOL(ad7879_suspend);
+
+void ad7879_resume(struct ad7879 *ts)
+{
+	mutex_lock(&ts->input->mutex);
+
+	if (ts->suspended && !ts->disabled && ts->input->users)
+		__ad7879_enable(ts);
+
+	ts->suspended = false;
+
+	mutex_unlock(&ts->input->mutex);
+}
+EXPORT_SYMBOL(ad7879_resume);
+
+static void ad7879_toggle(struct ad7879 *ts, bool disable)
+{
+	mutex_lock(&ts->input->mutex);
+
+	if (!ts->suspended && ts->input->users != 0) {
+
+		if (disable) {
+			if (ts->disabled)
+				__ad7879_enable(ts);
+		} else {
+			if (!ts->disabled)
+				__ad7879_disable(ts);
+		}
 	}
 
-	mutex_unlock(&ts->mutex);
+	ts->disabled = disable;
+
+	mutex_unlock(&ts->input->mutex);
 }
 
 static ssize_t ad7879_disable_show(struct device *dev,
@@ -297,10 +322,7 @@ static ssize_t ad7879_disable_store(struct device *dev,
 	if (error)
 		return error;
 
-	if (val)
-		ad7879_disable(ts);
-	else
-		ad7879_enable(ts);
+	ad7879_toggle(ts, val);
 
 	return count;
 }
@@ -325,7 +347,7 @@ static int ad7879_gpio_direction_input(struct gpio_chip *chip,
 
 	mutex_lock(&ts->mutex);
 	ts->cmd_crtl2 |= AD7879_GPIO_EN | AD7879_GPIODIR | AD7879_GPIOPOL;
-	err = ad7879_write(ts->bus, AD7879_REG_CTRL2, ts->cmd_crtl2);
+	err = ad7879_write(ts, AD7879_REG_CTRL2, ts->cmd_crtl2);
 	mutex_unlock(&ts->mutex);
 
 	return err;
@@ -345,7 +367,7 @@ static int ad7879_gpio_direction_output(struct gpio_chip *chip,
 	else
 		ts->cmd_crtl2 &= ~AD7879_GPIO_DATA;
 
-	err = ad7879_write(ts->bus, AD7879_REG_CTRL2, ts->cmd_crtl2);
+	err = ad7879_write(ts, AD7879_REG_CTRL2, ts->cmd_crtl2);
 	mutex_unlock(&ts->mutex);
 
 	return err;
@@ -357,7 +379,7 @@ static int ad7879_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
 	u16 val;
 
 	mutex_lock(&ts->mutex);
-	val = ad7879_read(ts->bus, AD7879_REG_CTRL2);
+	val = ad7879_read(ts, AD7879_REG_CTRL2);
 	mutex_unlock(&ts->mutex);
 
 	return !!(val & AD7879_GPIO_DATA);
@@ -374,16 +396,17 @@ static void ad7879_gpio_set_value(struct gpio_chip *chip,
 	else
 		ts->cmd_crtl2 &= ~AD7879_GPIO_DATA;
 
-	ad7879_write(ts->bus, AD7879_REG_CTRL2, ts->cmd_crtl2);
+	ad7879_write(ts, AD7879_REG_CTRL2, ts->cmd_crtl2);
 	mutex_unlock(&ts->mutex);
 }
 
-static int __devinit ad7879_gpio_add(struct device *dev)
+static int ad7879_gpio_add(struct ad7879 *ts,
+			   const struct ad7879_platform_data *pdata)
 {
-	struct ad7879 *ts = dev_get_drvdata(dev);
-	struct ad7879_platform_data *pdata = dev->platform_data;
 	int ret = 0;
 
+	mutex_init(&ts->mutex);
+
 	if (pdata->gpio_export) {
 		ts->gc.direction_input = ad7879_gpio_direction_input;
 		ts->gc.direction_output = ad7879_gpio_direction_output;
@@ -394,72 +417,75 @@ static int __devinit ad7879_gpio_add(struct device *dev)
 		ts->gc.ngpio = 1;
 		ts->gc.label = "AD7879-GPIO";
 		ts->gc.owner = THIS_MODULE;
-		ts->gc.dev = dev;
+		ts->gc.dev = ts->dev;
 
 		ret = gpiochip_add(&ts->gc);
 		if (ret)
-			dev_err(dev, "failed to register gpio %d\n",
+			dev_err(ts->dev, "failed to register gpio %d\n",
 				ts->gc.base);
 	}
 
 	return ret;
 }
 
-/*
- * We mark ad7879_gpio_remove inline so there is a chance the code
- * gets discarded when not needed. We can't do __devinit/__devexit
- * markup since it is used in both probe and remove methods.
- */
-static inline void ad7879_gpio_remove(struct device *dev)
+static void ad7879_gpio_remove(struct ad7879 *ts)
 {
-	struct ad7879 *ts = dev_get_drvdata(dev);
-	struct ad7879_platform_data *pdata = dev->platform_data;
+	const struct ad7879_platform_data *pdata = ts->dev->platform_data;
 	int ret;
 
 	if (pdata->gpio_export) {
 		ret = gpiochip_remove(&ts->gc);
 		if (ret)
-			dev_err(dev, "failed to remove gpio %d\n",
+			dev_err(ts->dev, "failed to remove gpio %d\n",
 				ts->gc.base);
 	}
 }
 #else
-static inline int ad7879_gpio_add(struct device *dev)
+static inline int ad7879_gpio_add(struct ad7879 *ts,
+				  const struct ad7879_platform_data *pdata)
 {
 	return 0;
 }
 
-static inline void ad7879_gpio_remove(struct device *dev)
+static inline void ad7879_gpio_remove(struct ad7879 *ts)
 {
 }
 #endif
 
-static int __devinit ad7879_construct(bus_device *bus, struct ad7879 *ts)
+struct ad7879 *ad7879_probe(struct device *dev, u8 devid, unsigned int irq,
+			    const struct ad7879_bus_ops *bops)
 {
+	struct ad7879_platform_data *pdata = dev->platform_data;
+	struct ad7879 *ts;
 	struct input_dev *input_dev;
-	struct ad7879_platform_data *pdata = bus->dev.platform_data;
 	int err;
 	u16 revid;
 
-	if (!bus->irq) {
-		dev_err(&bus->dev, "no IRQ?\n");
-		return -ENODEV;
+	if (!irq) {
+		dev_err(dev, "no IRQ?\n");
+		err = -EINVAL;
+		goto err_out;
 	}
 
 	if (!pdata) {
-		dev_err(&bus->dev, "no platform data?\n");
-		return -ENODEV;
+		dev_err(dev, "no platform data?\n");
+		err = -EINVAL;
+		goto err_out;
 	}
 
+	ts = kzalloc(sizeof(*ts), GFP_KERNEL);
 	input_dev = input_allocate_device();
-	if (!input_dev)
-		return -ENOMEM;
+	if (!ts || !input_dev) {
+		err = -ENOMEM;
+		goto err_free_mem;
+	}
 
+	ts->bops = bops;
+	ts->dev = dev;
 	ts->input = input_dev;
+	ts->irq = irq;
 
 	setup_timer(&ts->timer, ad7879_timer, (unsigned long) ts);
-	INIT_WORK(&ts->work, ad7879_work);
-	mutex_init(&ts->mutex);
 
 	ts->x_plate_ohms = pdata->x_plate_ohms ? : 400;
 	ts->pressure_max = pdata->pressure_max ? : ~0;
@@ -470,17 +496,26 @@ static int __devinit ad7879_construct(bus_device *bus, struct ad7879 *ts)
 	ts->pen_down_acc_interval = pdata->pen_down_acc_interval;
 	ts->median = pdata->median;
 
-	snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(&bus->dev));
+	snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(dev));
 
 	input_dev->name = "AD7879 Touchscreen";
 	input_dev->phys = ts->phys;
-	input_dev->dev.parent = &bus->dev;
+	input_dev->dev.parent = dev;
+	input_dev->id.bustype = bops->bustype;
+
+	input_dev->open = ad7879_open;
+	input_dev->close = ad7879_close;
+
+	input_set_drvdata(input_dev, ts);
 
 	__set_bit(EV_ABS, input_dev->evbit);
 	__set_bit(ABS_X, input_dev->absbit);
 	__set_bit(ABS_Y, input_dev->absbit);
 	__set_bit(ABS_PRESSURE, input_dev->absbit);
 
+	__set_bit(EV_KEY, input_dev->evbit);
+	__set_bit(BTN_TOUCH, input_dev->keybit);
+
 	input_set_abs_params(input_dev, ABS_X,
 			pdata->x_min ? : 0,
 			pdata->x_max ? : MAX_12BIT,
@@ -492,17 +527,18 @@ static int __devinit ad7879_construct(bus_device *bus, struct ad7879 *ts)
 	input_set_abs_params(input_dev, ABS_PRESSURE,
 			pdata->pressure_min, pdata->pressure_max, 0, 0);
 
-	err = ad7879_write(bus, AD7879_REG_CTRL2, AD7879_RESET);
-
+	err = ad7879_write(ts, AD7879_REG_CTRL2, AD7879_RESET);
 	if (err < 0) {
-		dev_err(&bus->dev, "Failed to write %s\n", input_dev->name);
+		dev_err(dev, "Failed to write %s\n", input_dev->name);
 		goto err_free_mem;
 	}
 
-	revid = ad7879_read(bus, AD7879_REG_REVID);
-
-	if ((revid & 0xFF) != AD7879_DEVID) {
-		dev_err(&bus->dev, "Failed to probe %s\n", input_dev->name);
+	revid = ad7879_read(ts, AD7879_REG_REVID);
+	input_dev->id.product = (revid & 0xff);
+	input_dev->id.version = revid >> 8;
+	if (input_dev->id.product != devid) {
+		dev_err(dev, "Failed to probe %s (%x vs %x)\n",
+			input_dev->name, devid, revid);
 		err = -ENODEV;
 		goto err_free_mem;
 	}
@@ -524,21 +560,21 @@ static int __devinit ad7879_construct(bus_device *bus, struct ad7879 *ts)
 			AD7879_ACQ(ts->acquisition_time) |
 			AD7879_TMR(ts->pen_down_acc_interval);
 
-	ad7879_setup(ts);
-
-	err = request_irq(bus->irq, ad7879_irq,
-			  IRQF_TRIGGER_FALLING, bus->dev.driver->name, ts);
-
+	err = request_threaded_irq(ts->irq, NULL, ad7879_irq,
+				   IRQF_TRIGGER_FALLING,
+				   dev_name(dev), ts);
 	if (err) {
-		dev_err(&bus->dev, "irq %d busy?\n", bus->irq);
+		dev_err(dev, "irq %d busy?\n", ts->irq);
 		goto err_free_mem;
 	}
 
-	err = sysfs_create_group(&bus->dev.kobj, &ad7879_attr_group);
+	__ad7879_disable(ts);
+
+	err = sysfs_create_group(&dev->kobj, &ad7879_attr_group);
 	if (err)
 		goto err_free_irq;
 
-	err = ad7879_gpio_add(&bus->dev);
+	err = ad7879_gpio_add(ts, pdata);
 	if (err)
 		goto err_remove_attr;
 
@@ -546,321 +582,32 @@ static int __devinit ad7879_construct(bus_device *bus, struct ad7879 *ts)
 	if (err)
 		goto err_remove_gpio;
 
-	dev_info(&bus->dev, "Rev.%d touchscreen, irq %d\n",
-		 revid >> 8, bus->irq);
-
-	return 0;
+	return ts;
 
 err_remove_gpio:
-	ad7879_gpio_remove(&bus->dev);
+	ad7879_gpio_remove(ts);
 err_remove_attr:
-	sysfs_remove_group(&bus->dev.kobj, &ad7879_attr_group);
+	sysfs_remove_group(&dev->kobj, &ad7879_attr_group);
 err_free_irq:
-	free_irq(bus->irq, ts);
+	free_irq(ts->irq, ts);
 err_free_mem:
 	input_free_device(input_dev);
-
-	return err;
-}
-
-static int __devexit ad7879_destroy(bus_device *bus, struct ad7879 *ts)
-{
-	ad7879_gpio_remove(&bus->dev);
-	ad7879_disable(ts);
-	sysfs_remove_group(&ts->bus->dev.kobj, &ad7879_attr_group);
-	free_irq(ts->bus->irq, ts);
-	input_unregister_device(ts->input);
-	dev_dbg(&bus->dev, "unregistered touchscreen\n");
-
-	return 0;
-}
-
-#ifdef CONFIG_PM
-static int ad7879_suspend(bus_device *bus, pm_message_t message)
-{
-	struct ad7879 *ts = dev_get_drvdata(&bus->dev);
-
-	ad7879_disable(ts);
-
-	return 0;
-}
-
-static int ad7879_resume(bus_device *bus)
-{
-	struct ad7879 *ts = dev_get_drvdata(&bus->dev);
-
-	ad7879_enable(ts);
-
-	return 0;
-}
-#else
-#define ad7879_suspend NULL
-#define ad7879_resume  NULL
-#endif
-
-#if defined(CONFIG_TOUCHSCREEN_AD7879_SPI) || defined(CONFIG_TOUCHSCREEN_AD7879_SPI_MODULE)
-#define MAX_SPI_FREQ_HZ		5000000
-#define AD7879_CMD_MAGIC	0xE000
-#define AD7879_CMD_READ		(1 << 10)
-#define AD7879_WRITECMD(reg)	(AD7879_CMD_MAGIC | (reg & 0xF))
-#define AD7879_READCMD(reg)	(AD7879_CMD_MAGIC | AD7879_CMD_READ | (reg & 0xF))
-
-struct ser_req {
-	u16			command;
-	u16			data;
-	struct spi_message	msg;
-	struct spi_transfer	xfer[2];
-};
-
-/*
- * ad7879_read/write are only used for initial setup and for sysfs controls.
- * The main traffic is done in ad7879_collect().
- */
-
-static int ad7879_read(struct spi_device *spi, u8 reg)
-{
-	struct ser_req *req;
-	int status, ret;
-
-	req = kzalloc(sizeof *req, GFP_KERNEL);
-	if (!req)
-		return -ENOMEM;
-
-	spi_message_init(&req->msg);
-
-	req->command = (u16) AD7879_READCMD(reg);
-	req->xfer[0].tx_buf = &req->command;
-	req->xfer[0].len = 2;
-
-	req->xfer[1].rx_buf = &req->data;
-	req->xfer[1].len = 2;
-
-	spi_message_add_tail(&req->xfer[0], &req->msg);
-	spi_message_add_tail(&req->xfer[1], &req->msg);
-
-	status = spi_sync(spi, &req->msg);
-	ret = status ? : req->data;
-
-	kfree(req);
-
-	return ret;
-}
-
-static int ad7879_write(struct spi_device *spi, u8 reg, u16 val)
-{
-	struct ser_req *req;
-	int status;
-
-	req = kzalloc(sizeof *req, GFP_KERNEL);
-	if (!req)
-		return -ENOMEM;
-
-	spi_message_init(&req->msg);
-
-	req->command = (u16) AD7879_WRITECMD(reg);
-	req->xfer[0].tx_buf = &req->command;
-	req->xfer[0].len = 2;
-
-	req->data = val;
-	req->xfer[1].tx_buf = &req->data;
-	req->xfer[1].len = 2;
-
-	spi_message_add_tail(&req->xfer[0], &req->msg);
-	spi_message_add_tail(&req->xfer[1], &req->msg);
-
-	status = spi_sync(spi, &req->msg);
-
-	kfree(req);
-
-	return status;
-}
-
-static void ad7879_collect(struct ad7879 *ts)
-{
-	int status = spi_sync(ts->bus, &ts->msg);
-
-	if (status)
-		dev_err(&ts->bus->dev, "spi_sync --> %d\n", status);
-}
-
-static void ad7879_setup_ts_def_msg(struct ad7879 *ts)
-{
-	struct spi_message *m;
-	int i;
-
-	ts->cmd = (u16) AD7879_READCMD(AD7879_REG_XPLUS);
-
-	m = &ts->msg;
-	spi_message_init(m);
-	ts->xfer[0].tx_buf = &ts->cmd;
-	ts->xfer[0].len = 2;
-
-	spi_message_add_tail(&ts->xfer[0], m);
-
-	for (i = 0; i < AD7879_NR_SENSE; i++) {
-		ts->xfer[i + 1].rx_buf = &ts->conversion_data[i];
-		ts->xfer[i + 1].len = 2;
-		spi_message_add_tail(&ts->xfer[i + 1], m);
-	}
-}
-
-static int __devinit ad7879_probe(struct spi_device *spi)
-{
-	struct ad7879 *ts;
-	int error;
-
-	/* don't exceed max specified SPI CLK frequency */
-	if (spi->max_speed_hz > MAX_SPI_FREQ_HZ) {
-		dev_err(&spi->dev, "SPI CLK %d Hz?\n", spi->max_speed_hz);
-		return -EINVAL;
-	}
-
-	ts = kzalloc(sizeof(struct ad7879), GFP_KERNEL);
-	if (!ts)
-		return -ENOMEM;
-
-	dev_set_drvdata(&spi->dev, ts);
-	ts->bus = spi;
-
-	ad7879_setup_ts_def_msg(ts);
-
-	error = ad7879_construct(spi, ts);
-	if (error) {
-		dev_set_drvdata(&spi->dev, NULL);
-		kfree(ts);
-	}
-
-	return error;
-}
-
-static int __devexit ad7879_remove(struct spi_device *spi)
-{
-	struct ad7879 *ts = dev_get_drvdata(&spi->dev);
-
-	ad7879_destroy(spi, ts);
-	dev_set_drvdata(&spi->dev, NULL);
 	kfree(ts);
-
-	return 0;
+err_out:
+	return ERR_PTR(err);
 }
+EXPORT_SYMBOL(ad7879_probe);
 
-static struct spi_driver ad7879_driver = {
-	.driver = {
-		.name	= "ad7879",
-		.bus	= &spi_bus_type,
-		.owner	= THIS_MODULE,
-	},
-	.probe		= ad7879_probe,
-	.remove		= __devexit_p(ad7879_remove),
-	.suspend	= ad7879_suspend,
-	.resume		= ad7879_resume,
-};
-
-static int __init ad7879_init(void)
-{
-	return spi_register_driver(&ad7879_driver);
-}
-module_init(ad7879_init);
-
-static void __exit ad7879_exit(void)
-{
-	spi_unregister_driver(&ad7879_driver);
-}
-module_exit(ad7879_exit);
-
-#elif defined(CONFIG_TOUCHSCREEN_AD7879_I2C) || defined(CONFIG_TOUCHSCREEN_AD7879_I2C_MODULE)
-
-/* All registers are word-sized.
- * AD7879 uses a high-byte first convention.
- */
-static int ad7879_read(struct i2c_client *client, u8 reg)
+void ad7879_remove(struct ad7879 *ts)
 {
-	return swab16(i2c_smbus_read_word_data(client, reg));
-}
-
-static int ad7879_write(struct i2c_client *client, u8 reg, u16 val)
-{
-	return i2c_smbus_write_word_data(client, reg, swab16(val));
-}
-
-static void ad7879_collect(struct ad7879 *ts)
-{
-	int i;
-
-	for (i = 0; i < AD7879_NR_SENSE; i++)
-		ts->conversion_data[i] = ad7879_read(ts->bus,
-						     AD7879_REG_XPLUS + i);
-}
-
-static int __devinit ad7879_probe(struct i2c_client *client,
-					const struct i2c_device_id *id)
-{
-	struct ad7879 *ts;
-	int error;
-
-	if (!i2c_check_functionality(client->adapter,
-					I2C_FUNC_SMBUS_WORD_DATA)) {
-		dev_err(&client->dev, "SMBUS Word Data not Supported\n");
-		return -EIO;
-	}
-
-	ts = kzalloc(sizeof(struct ad7879), GFP_KERNEL);
-	if (!ts)
-		return -ENOMEM;
-
-	i2c_set_clientdata(client, ts);
-	ts->bus = client;
-
-	error = ad7879_construct(client, ts);
-	if (error)
-		kfree(ts);
-
-	return error;
-}
-
-static int __devexit ad7879_remove(struct i2c_client *client)
-{
-	struct ad7879 *ts = dev_get_drvdata(&client->dev);
-
-	ad7879_destroy(client, ts);
+	ad7879_gpio_remove(ts);
+	sysfs_remove_group(&ts->dev->kobj, &ad7879_attr_group);
+	free_irq(ts->irq, ts);
+	input_unregister_device(ts->input);
 	kfree(ts);
-
-	return 0;
-}
-
-static const struct i2c_device_id ad7879_id[] = {
-	{ "ad7879", 0 },
-	{ "ad7889", 0 },
-	{ }
-};
-MODULE_DEVICE_TABLE(i2c, ad7879_id);
-
-static struct i2c_driver ad7879_driver = {
-	.driver = {
-		.name	= "ad7879",
-		.owner	= THIS_MODULE,
-	},
-	.probe		= ad7879_probe,
-	.remove		= __devexit_p(ad7879_remove),
-	.suspend	= ad7879_suspend,
-	.resume		= ad7879_resume,
-	.id_table	= ad7879_id,
-};
-
-static int __init ad7879_init(void)
-{
-	return i2c_add_driver(&ad7879_driver);
-}
-module_init(ad7879_init);
-
-static void __exit ad7879_exit(void)
-{
-	i2c_del_driver(&ad7879_driver);
 }
-module_exit(ad7879_exit);
-#endif
+EXPORT_SYMBOL(ad7879_remove);
 
 MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
 MODULE_DESCRIPTION("AD7879(-1) touchscreen Driver");
 MODULE_LICENSE("GPL");
-MODULE_ALIAS("spi:ad7879");
diff --git a/drivers/input/touchscreen/ad7879.h b/drivers/input/touchscreen/ad7879.h
new file mode 100644
index 000000000000..6b45a27236c7
--- /dev/null
+++ b/drivers/input/touchscreen/ad7879.h
@@ -0,0 +1,30 @@
+/*
+ * AD7879/AD7889 touchscreen (bus interfaces)
+ *
+ * Copyright (C) 2008-2010 Michael Hennerich, Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef _AD7879_H_
+#define _AD7879_H_
+
+#include <linux/types.h>
+
+struct ad7879;
+struct device;
+
+struct ad7879_bus_ops {
+	u16 bustype;
+	int (*read)(struct device *dev, u8 reg);
+	int (*multi_read)(struct device *dev, u8 first_reg, u8 count, u16 *buf);
+	int (*write)(struct device *dev, u8 reg, u16 val);
+};
+
+void ad7879_suspend(struct ad7879 *);
+void ad7879_resume(struct ad7879 *);
+struct ad7879 *ad7879_probe(struct device *dev, u8 devid, unsigned irq,
+			    const struct ad7879_bus_ops *bops);
+void ad7879_remove(struct ad7879 *);
+
+#endif
diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c
index a9fdf55c0238..16031933a8f6 100644
--- a/drivers/input/touchscreen/ads7846.c
+++ b/drivers/input/touchscreen/ads7846.c
@@ -68,6 +68,8 @@ struct ts_event {
 	u16	y;
 	u16	z1, z2;
 	int	ignore;
+	u8	x_buf[3];
+	u8	y_buf[3];
 };
 
 /*
@@ -79,6 +81,8 @@ struct ads7846_packet {
 	u8			read_x, read_y, read_z1, read_z2, pwrdown;
 	u16			dummy;		/* for the pwrdown read */
 	struct ts_event		tc;
+	/* for ads7845 with mpc5121 psc spi we use 3-byte buffers */
+	u8			read_x_cmd[3], read_y_cmd[3], pwrdown_cmd[3];
 };
 
 struct ads7846 {
@@ -207,6 +211,14 @@ struct ser_req {
 	struct spi_transfer	xfer[6];
 };
 
+struct ads7845_ser_req {
+	u8			command[3];
+	u8			pwrdown[3];
+	u8			sample[3];
+	struct spi_message	msg;
+	struct spi_transfer	xfer[2];
+};
+
 static void ads7846_enable(struct ads7846 *ts);
 static void ads7846_disable(struct ads7846 *ts);
 
@@ -287,6 +299,41 @@ static int ads7846_read12_ser(struct device *dev, unsigned command)
 	return status;
 }
 
+static int ads7845_read12_ser(struct device *dev, unsigned command)
+{
+	struct spi_device	*spi = to_spi_device(dev);
+	struct ads7846		*ts = dev_get_drvdata(dev);
+	struct ads7845_ser_req	*req = kzalloc(sizeof *req, GFP_KERNEL);
+	int			status;
+
+	if (!req)
+		return -ENOMEM;
+
+	spi_message_init(&req->msg);
+
+	req->command[0] = (u8) command;
+	req->xfer[0].tx_buf = req->command;
+	req->xfer[0].rx_buf = req->sample;
+	req->xfer[0].len = 3;
+	spi_message_add_tail(&req->xfer[0], &req->msg);
+
+	ts->irq_disabled = 1;
+	disable_irq(spi->irq);
+	status = spi_sync(spi, &req->msg);
+	ts->irq_disabled = 0;
+	enable_irq(spi->irq);
+
+	if (status == 0) {
+		/* BE12 value, then padding */
+		status = be16_to_cpu(*((u16 *)&req->sample[1]));
+		status = status >> 3;
+		status &= 0x0fff;
+	}
+
+	kfree(req);
+	return status;
+}
+
 #if defined(CONFIG_HWMON) || defined(CONFIG_HWMON_MODULE)
 
 #define SHOW(name, var, adjust) static ssize_t \
@@ -540,10 +587,17 @@ static void ads7846_rx(void *ads)
 	/* ads7846_rx_val() did in-place conversion (including byteswap) from
 	 * on-the-wire format as part of debouncing to get stable readings.
 	 */
-	x = packet->tc.x;
-	y = packet->tc.y;
-	z1 = packet->tc.z1;
-	z2 = packet->tc.z2;
+	if (ts->model == 7845) {
+		x = *(u16 *)packet->tc.x_buf;
+		y = *(u16 *)packet->tc.y_buf;
+		z1 = 0;
+		z2 = 0;
+	} else {
+		x = packet->tc.x;
+		y = packet->tc.y;
+		z1 = packet->tc.z1;
+		z2 = packet->tc.z2;
+	}
 
 	/* range filtering */
 	if (x == MAX_12BIT)
@@ -551,6 +605,12 @@ static void ads7846_rx(void *ads)
 
 	if (ts->model == 7843) {
 		Rt = ts->pressure_max / 2;
+	} else if (ts->model == 7845) {
+		if (get_pendown_state(ts))
+			Rt = ts->pressure_max / 2;
+		else
+			Rt = 0;
+		dev_vdbg(&ts->spi->dev, "x/y: %d/%d, PD %d\n", x, y, Rt);
 	} else if (likely(x && z1)) {
 		/* compute touch pressure resistance using equation #2 */
 		Rt = z2;
@@ -671,10 +731,14 @@ static void ads7846_rx_val(void *ads)
 	m = &ts->msg[ts->msg_idx];
 	t = list_entry(m->transfers.prev, struct spi_transfer, transfer_list);
 
-	/* adjust:  on-wire is a must-ignore bit, a BE12 value, then padding;
-	 * built from two 8 bit values written msb-first.
-	 */
-	val = be16_to_cpup((__be16 *)t->rx_buf) >> 3;
+	if (ts->model == 7845) {
+		val = be16_to_cpup((__be16 *)&(((char*)t->rx_buf)[1])) >> 3;
+	} else {
+		/* adjust:  on-wire is a must-ignore bit, a BE12 value, then
+		 * padding; built from two 8 bit values written msb-first.
+		 */
+		val = be16_to_cpup((__be16 *)t->rx_buf) >> 3;
+	}
 
 	action = ts->filter(ts->filter_data, ts->msg_idx, &val);
 	switch (action) {
@@ -878,14 +942,15 @@ static int __devinit setup_pendown(struct spi_device *spi, struct ads7846 *ts)
 
 static int __devinit ads7846_probe(struct spi_device *spi)
 {
-	struct ads7846			*ts;
-	struct ads7846_packet		*packet;
-	struct input_dev		*input_dev;
-	struct ads7846_platform_data	*pdata = spi->dev.platform_data;
-	struct spi_message		*m;
-	struct spi_transfer		*x;
-	int				vref;
-	int				err;
+	struct ads7846 *ts;
+	struct ads7846_packet *packet;
+	struct input_dev *input_dev;
+	const struct ads7846_platform_data *pdata = spi->dev.platform_data;
+	struct spi_message *m;
+	struct spi_transfer *x;
+	unsigned long irq_flags;
+	int vref;
+	int err;
 
 	if (!spi->irq) {
 		dev_dbg(&spi->dev, "no IRQ?\n");
@@ -1008,16 +1073,26 @@ static int __devinit ads7846_probe(struct spi_device *spi)
 
 	spi_message_init(m);
 
-	/* y- still on; turn on only y+ (and ADC) */
-	packet->read_y = READ_Y(vref);
-	x->tx_buf = &packet->read_y;
-	x->len = 1;
-	spi_message_add_tail(x, m);
+	if (ts->model == 7845) {
+		packet->read_y_cmd[0] = READ_Y(vref);
+		packet->read_y_cmd[1] = 0;
+		packet->read_y_cmd[2] = 0;
+		x->tx_buf = &packet->read_y_cmd[0];
+		x->rx_buf = &packet->tc.y_buf[0];
+		x->len = 3;
+		spi_message_add_tail(x, m);
+	} else {
+		/* y- still on; turn on only y+ (and ADC) */
+		packet->read_y = READ_Y(vref);
+		x->tx_buf = &packet->read_y;
+		x->len = 1;
+		spi_message_add_tail(x, m);
 
-	x++;
-	x->rx_buf = &packet->tc.y;
-	x->len = 2;
-	spi_message_add_tail(x, m);
+		x++;
+		x->rx_buf = &packet->tc.y;
+		x->len = 2;
+		spi_message_add_tail(x, m);
+	}
 
 	/* the first sample after switching drivers can be low quality;
 	 * optionally discard it, using a second one after the signals
@@ -1043,17 +1118,28 @@ static int __devinit ads7846_probe(struct spi_device *spi)
 	m++;
 	spi_message_init(m);
 
-	/* turn y- off, x+ on, then leave in lowpower */
-	x++;
-	packet->read_x = READ_X(vref);
-	x->tx_buf = &packet->read_x;
-	x->len = 1;
-	spi_message_add_tail(x, m);
+	if (ts->model == 7845) {
+		x++;
+		packet->read_x_cmd[0] = READ_X(vref);
+		packet->read_x_cmd[1] = 0;
+		packet->read_x_cmd[2] = 0;
+		x->tx_buf = &packet->read_x_cmd[0];
+		x->rx_buf = &packet->tc.x_buf[0];
+		x->len = 3;
+		spi_message_add_tail(x, m);
+	} else {
+		/* turn y- off, x+ on, then leave in lowpower */
+		x++;
+		packet->read_x = READ_X(vref);
+		x->tx_buf = &packet->read_x;
+		x->len = 1;
+		spi_message_add_tail(x, m);
 
-	x++;
-	x->rx_buf = &packet->tc.x;
-	x->len = 2;
-	spi_message_add_tail(x, m);
+		x++;
+		x->rx_buf = &packet->tc.x;
+		x->len = 2;
+		spi_message_add_tail(x, m);
+	}
 
 	/* ... maybe discard first sample ... */
 	if (pdata->settle_delay_usecs) {
@@ -1144,15 +1230,25 @@ static int __devinit ads7846_probe(struct spi_device *spi)
 	m++;
 	spi_message_init(m);
 
-	x++;
-	packet->pwrdown = PWRDOWN;
-	x->tx_buf = &packet->pwrdown;
-	x->len = 1;
-	spi_message_add_tail(x, m);
+	if (ts->model == 7845) {
+		x++;
+		packet->pwrdown_cmd[0] = PWRDOWN;
+		packet->pwrdown_cmd[1] = 0;
+		packet->pwrdown_cmd[2] = 0;
+		x->tx_buf = &packet->pwrdown_cmd[0];
+		x->len = 3;
+	} else {
+		x++;
+		packet->pwrdown = PWRDOWN;
+		x->tx_buf = &packet->pwrdown;
+		x->len = 1;
+		spi_message_add_tail(x, m);
+
+		x++;
+		x->rx_buf = &packet->dummy;
+		x->len = 2;
+	}
 
-	x++;
-	x->rx_buf = &packet->dummy;
-	x->len = 2;
 	CS_CHANGE(*x);
 	spi_message_add_tail(x, m);
 
@@ -1174,17 +1270,22 @@ static int __devinit ads7846_probe(struct spi_device *spi)
 		goto err_put_regulator;
 	}
 
-	if (request_irq(spi->irq, ads7846_irq, IRQF_TRIGGER_FALLING,
-			spi->dev.driver->name, ts)) {
+	irq_flags = pdata->irq_flags ? : IRQF_TRIGGER_FALLING;
+
+	err = request_irq(spi->irq, ads7846_irq, irq_flags,
+			  spi->dev.driver->name, ts);
+
+	if (err && !pdata->irq_flags) {
 		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_disable_regulator;
-		}
+	}
+
+	if (err) {
+		dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq);
+		goto err_disable_regulator;
 	}
 
 	err = ads784x_hwmon_register(spi, ts);
@@ -1196,8 +1297,11 @@ static int __devinit ads7846_probe(struct spi_device *spi)
 	/* take a first sample, leaving nPENIRQ active and vREF off; avoid
 	 * the touchscreen, in case it's not connected.
 	 */
-	(void) ads7846_read12_ser(&spi->dev,
-			  READ_12BIT_SER(vaux) | ADS_PD10_ALL_ON);
+	if (ts->model == 7845)
+		ads7845_read12_ser(&spi->dev, PWRDOWN);
+	else
+		(void) ads7846_read12_ser(&spi->dev,
+				READ_12BIT_SER(vaux) | ADS_PD10_ALL_ON);
 
 	err = sysfs_create_group(&spi->dev.kobj, &ads784x_attr_group);
 	if (err)
diff --git a/drivers/input/touchscreen/cy8ctmg110_ts.c b/drivers/input/touchscreen/cy8ctmg110_ts.c
new file mode 100644
index 000000000000..4eb7df0b7f87
--- /dev/null
+++ b/drivers/input/touchscreen/cy8ctmg110_ts.c
@@ -0,0 +1,363 @@
+/*
+ * Driver for cypress touch screen controller
+ *
+ * Copyright (c) 2009 Aava Mobile
+ *
+ * Some cleanups by Alan Cox <alan@linux.intel.com>
+ *
+ * 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.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/input.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/input/cy8ctmg110_pdata.h>
+
+#define CY8CTMG110_DRIVER_NAME      "cy8ctmg110"
+
+/* Touch coordinates */
+#define CY8CTMG110_X_MIN		0
+#define CY8CTMG110_Y_MIN		0
+#define CY8CTMG110_X_MAX		759
+#define CY8CTMG110_Y_MAX		465
+
+
+/* cy8ctmg110 register definitions */
+#define CY8CTMG110_TOUCH_WAKEUP_TIME	0
+#define CY8CTMG110_TOUCH_SLEEP_TIME	2
+#define CY8CTMG110_TOUCH_X1		3
+#define CY8CTMG110_TOUCH_Y1		5
+#define CY8CTMG110_TOUCH_X2		7
+#define CY8CTMG110_TOUCH_Y2		9
+#define CY8CTMG110_FINGERS		11
+#define CY8CTMG110_GESTURE		12
+#define CY8CTMG110_REG_MAX		13
+
+
+/*
+ * The touch driver structure.
+ */
+struct cy8ctmg110 {
+	struct input_dev *input;
+	char phys[32];
+	struct i2c_client *client;
+	int reset_pin;
+	int irq_pin;
+};
+
+/*
+ * cy8ctmg110_power is the routine that is called when touch hardware
+ * will powered off or on.
+ */
+static void cy8ctmg110_power(struct cy8ctmg110 *ts, bool poweron)
+{
+	if (ts->reset_pin)
+		gpio_direction_output(ts->reset_pin, 1 - poweron);
+}
+
+static int cy8ctmg110_write_regs(struct cy8ctmg110 *tsc, unsigned char reg,
+		unsigned char len, unsigned char *value)
+{
+	struct i2c_client *client = tsc->client;
+	unsigned int ret;
+	unsigned char i2c_data[6];
+
+	BUG_ON(len > 5);
+
+	i2c_data[0] = reg;
+	memcpy(i2c_data + 1, value, len);
+
+	ret = i2c_master_send(client, i2c_data, len + 1);
+	if (ret != 1) {
+		dev_err(&client->dev, "i2c write data cmd failed\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int cy8ctmg110_read_regs(struct cy8ctmg110 *tsc,
+		unsigned char *data, unsigned char len, unsigned char cmd)
+{
+	struct i2c_client *client = tsc->client;
+	unsigned int ret;
+	struct i2c_msg msg[2] = {
+		/* first write slave position to i2c devices */
+		{ client->addr, 0, 1, &cmd },
+		/* Second read data from position */
+		{ client->addr, I2C_M_RD, len, data }
+	};
+
+	ret = i2c_transfer(client->adapter, msg, 2);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int cy8ctmg110_touch_pos(struct cy8ctmg110 *tsc)
+{
+	struct input_dev *input = tsc->input;
+	unsigned char reg_p[CY8CTMG110_REG_MAX];
+	int x, y;
+
+	memset(reg_p, 0, CY8CTMG110_REG_MAX);
+
+	/* Reading coordinates */
+	if (cy8ctmg110_read_regs(tsc, reg_p, 9, CY8CTMG110_TOUCH_X1) != 0)
+		return -EIO;
+
+	y = reg_p[2] << 8 | reg_p[3];
+	x = reg_p[0] << 8 | reg_p[1];
+
+	/* Number of touch */
+	if (reg_p[8] == 0) {
+		input_report_key(input, BTN_TOUCH, 0);
+	} else  {
+		input_report_key(input, BTN_TOUCH, 1);
+		input_report_abs(input, ABS_X, x);
+		input_report_abs(input, ABS_Y, y);
+	}
+
+	input_sync(input);
+
+	return 0;
+}
+
+static int cy8ctmg110_set_sleepmode(struct cy8ctmg110 *ts, bool sleep)
+{
+	unsigned char reg_p[3];
+
+	if (sleep) {
+		reg_p[0] = 0x00;
+		reg_p[1] = 0xff;
+		reg_p[2] = 5;
+	} else {
+		reg_p[0] = 0x10;
+		reg_p[1] = 0xff;
+		reg_p[2] = 0;
+	}
+
+	return cy8ctmg110_write_regs(ts, CY8CTMG110_TOUCH_WAKEUP_TIME, 3, reg_p);
+}
+
+static irqreturn_t cy8ctmg110_irq_thread(int irq, void *dev_id)
+{
+	struct cy8ctmg110 *tsc = dev_id;
+
+	cy8ctmg110_touch_pos(tsc);
+
+	return IRQ_HANDLED;
+}
+
+static int __devinit cy8ctmg110_probe(struct i2c_client *client,
+					const struct i2c_device_id *id)
+{
+	const struct cy8ctmg110_pdata *pdata = client->dev.platform_data;
+	struct cy8ctmg110 *ts;
+	struct input_dev *input_dev;
+	int err;
+
+	/* No pdata no way forward */
+	if (pdata == NULL) {
+		dev_err(&client->dev, "no pdata\n");
+		return -ENODEV;
+	}
+
+	if (!i2c_check_functionality(client->adapter,
+					I2C_FUNC_SMBUS_READ_WORD_DATA))
+		return -EIO;
+
+	ts = kzalloc(sizeof(struct cy8ctmg110), GFP_KERNEL);
+	input_dev = input_allocate_device();
+	if (!ts || !input_dev) {
+		err = -ENOMEM;
+		goto err_free_mem;
+	}
+
+	ts->client = client;
+	ts->input = input_dev;
+
+	snprintf(ts->phys, sizeof(ts->phys),
+		 "%s/input0", dev_name(&client->dev));
+
+	input_dev->name = CY8CTMG110_DRIVER_NAME " Touchscreen";
+	input_dev->phys = ts->phys;
+	input_dev->id.bustype = BUS_I2C;
+	input_dev->dev.parent = &client->dev;
+
+	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,
+			CY8CTMG110_X_MIN, CY8CTMG110_X_MAX, 0, 0);
+	input_set_abs_params(input_dev, ABS_Y,
+			CY8CTMG110_Y_MIN, CY8CTMG110_Y_MAX, 0, 0);
+
+	if (ts->reset_pin) {
+		err = gpio_request(ts->reset_pin, NULL);
+		if (err) {
+			dev_err(&client->dev,
+				"Unable to request GPIO pin %d.\n",
+				ts->reset_pin);
+			goto err_free_mem;
+		}
+	}
+
+	cy8ctmg110_power(ts, true);
+	cy8ctmg110_set_sleepmode(ts, false);
+
+	err = gpio_request(ts->irq_pin, "touch_irq_key");
+	if (err < 0) {
+		dev_err(&client->dev,
+			"Failed to request GPIO %d, error %d\n",
+			ts->irq_pin, err);
+		goto err_shutoff_device;
+	}
+
+	err = gpio_direction_input(ts->irq_pin);
+	if (err < 0) {
+		dev_err(&client->dev,
+			"Failed to configure input direction for GPIO %d, error %d\n",
+			ts->irq_pin, err);
+		goto err_free_irq_gpio;
+	}
+
+	client->irq = gpio_to_irq(ts->irq_pin);
+	if (client->irq < 0) {
+		err = client->irq;
+		dev_err(&client->dev,
+			"Unable to get irq number for GPIO %d, error %d\n",
+			ts->irq_pin, err);
+		goto err_free_irq_gpio;
+	}
+
+	err = request_threaded_irq(client->irq, NULL, cy8ctmg110_irq_thread,
+				   IRQF_TRIGGER_RISING, "touch_reset_key", ts);
+	if (err < 0) {
+		dev_err(&client->dev,
+			"irq %d busy? error %d\n", client->irq, err);
+		goto err_free_irq_gpio;
+	}
+
+	err = input_register_device(input_dev);
+	if (err)
+		goto err_free_irq;
+
+	i2c_set_clientdata(client, ts);
+	device_init_wakeup(&client->dev, 1);
+	return 0;
+
+err_free_irq:
+	free_irq(client->irq, ts);
+err_free_irq_gpio:
+	gpio_free(ts->irq_pin);
+err_shutoff_device:
+	cy8ctmg110_set_sleepmode(ts, true);
+	cy8ctmg110_power(ts, false);
+	if (ts->reset_pin)
+		gpio_free(ts->reset_pin);
+err_free_mem:
+	input_free_device(input_dev);
+	kfree(ts);
+	return err;
+}
+
+#ifdef CONFIG_PM
+static int cy8ctmg110_suspend(struct i2c_client *client, pm_message_t mesg)
+{
+	struct cy8ctmg110 *ts = i2c_get_clientdata(client);
+
+	if (device_may_wakeup(&client->dev))
+		enable_irq_wake(client->irq);
+	else {
+		cy8ctmg110_set_sleepmode(ts, true);
+		cy8ctmg110_power(ts, false);
+	}
+	return 0;
+}
+
+static int cy8ctmg110_resume(struct i2c_client *client)
+{
+	struct cy8ctmg110 *ts = i2c_get_clientdata(client);
+
+	if (device_may_wakeup(&client->dev))
+		disable_irq_wake(client->irq);
+	else {
+		cy8ctmg110_power(ts, true);
+		cy8ctmg110_set_sleepmode(ts, false);
+	}
+	return 0;
+}
+#endif
+
+static int __devexit cy8ctmg110_remove(struct i2c_client *client)
+{
+	struct cy8ctmg110 *ts = i2c_get_clientdata(client);
+
+	cy8ctmg110_set_sleepmode(ts, true);
+	cy8ctmg110_power(ts, false);
+
+	free_irq(client->irq, ts);
+	input_unregister_device(ts->input);
+	gpio_free(ts->irq_pin);
+	if (ts->reset_pin)
+		gpio_free(ts->reset_pin);
+	kfree(ts);
+
+	return 0;
+}
+
+static struct i2c_device_id cy8ctmg110_idtable[] = {
+	{ CY8CTMG110_DRIVER_NAME, 1 },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(i2c, cy8ctmg110_idtable);
+
+static struct i2c_driver cy8ctmg110_driver = {
+	.driver		= {
+		.owner	= THIS_MODULE,
+		.name	= CY8CTMG110_DRIVER_NAME,
+	},
+	.id_table	= cy8ctmg110_idtable,
+	.probe		= cy8ctmg110_probe,
+	.remove		= __devexit_p(cy8ctmg110_remove),
+#ifdef CONFIG_PM
+	.suspend	= cy8ctmg110_suspend,
+	.resume		= cy8ctmg110_resume,
+#endif
+};
+
+static int __init cy8ctmg110_init(void)
+{
+	return i2c_add_driver(&cy8ctmg110_driver);
+}
+
+static void __exit cy8ctmg110_exit(void)
+{
+	i2c_del_driver(&cy8ctmg110_driver);
+}
+
+module_init(cy8ctmg110_init);
+module_exit(cy8ctmg110_exit);
+
+MODULE_AUTHOR("Samuli Konttila <samuli.konttila@aavamobile.com>");
+MODULE_DESCRIPTION("cy8ctmg110 TouchScreen Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/input/touchscreen/mcs5000_ts.c b/drivers/input/touchscreen/mcs5000_ts.c
index 1fb0c2f06a44..6ee9940aaf5b 100644
--- a/drivers/input/touchscreen/mcs5000_ts.c
+++ b/drivers/input/touchscreen/mcs5000_ts.c
@@ -16,7 +16,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/i2c.h>
-#include <linux/i2c/mcs5000_ts.h>
+#include <linux/i2c/mcs.h>
 #include <linux/interrupt.h>
 #include <linux/input.h>
 #include <linux/irq.h>
@@ -105,7 +105,7 @@ enum mcs5000_ts_read_offset {
 struct mcs5000_ts_data {
 	struct i2c_client *client;
 	struct input_dev *input_dev;
-	const struct mcs5000_ts_platform_data *platform_data;
+	const struct mcs_platform_data *platform_data;
 };
 
 static irqreturn_t mcs5000_ts_interrupt(int irq, void *dev_id)
@@ -164,7 +164,7 @@ static irqreturn_t mcs5000_ts_interrupt(int irq, void *dev_id)
 
 static void mcs5000_ts_phys_init(struct mcs5000_ts_data *data)
 {
-	const struct mcs5000_ts_platform_data *platform_data =
+	const struct mcs_platform_data *platform_data =
 		data->platform_data;
 	struct i2c_client *client = data->client;
 
diff --git a/drivers/input/touchscreen/qt602240_ts.c b/drivers/input/touchscreen/qt602240_ts.c
new file mode 100644
index 000000000000..66b26ad3032a
--- /dev/null
+++ b/drivers/input/touchscreen/qt602240_ts.c
@@ -0,0 +1,1401 @@
+/*
+ * AT42QT602240/ATMXT224 Touchscreen driver
+ *
+ * Copyright (C) 2010 Samsung Electronics Co.Ltd
+ * Author: Joonyoung Shim <jy0922.shim@samsung.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;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/firmware.h>
+#include <linux/i2c.h>
+#include <linux/i2c/qt602240_ts.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+
+/* Version */
+#define QT602240_VER_20			20
+#define QT602240_VER_21			21
+#define QT602240_VER_22			22
+
+/* Slave addresses */
+#define QT602240_APP_LOW		0x4a
+#define QT602240_APP_HIGH		0x4b
+#define QT602240_BOOT_LOW		0x24
+#define QT602240_BOOT_HIGH		0x25
+
+/* Firmware */
+#define QT602240_FW_NAME		"qt602240.fw"
+
+/* Registers */
+#define QT602240_FAMILY_ID		0x00
+#define QT602240_VARIANT_ID		0x01
+#define QT602240_VERSION		0x02
+#define QT602240_BUILD			0x03
+#define QT602240_MATRIX_X_SIZE		0x04
+#define QT602240_MATRIX_Y_SIZE		0x05
+#define QT602240_OBJECT_NUM		0x06
+#define QT602240_OBJECT_START		0x07
+
+#define QT602240_OBJECT_SIZE		6
+
+/* Object types */
+#define QT602240_DEBUG_DIAGNOSTIC	37
+#define QT602240_GEN_MESSAGE		5
+#define QT602240_GEN_COMMAND		6
+#define QT602240_GEN_POWER		7
+#define QT602240_GEN_ACQUIRE		8
+#define QT602240_TOUCH_MULTI		9
+#define QT602240_TOUCH_KEYARRAY		15
+#define QT602240_TOUCH_PROXIMITY	23
+#define QT602240_PROCI_GRIPFACE		20
+#define QT602240_PROCG_NOISE		22
+#define QT602240_PROCI_ONETOUCH		24
+#define QT602240_PROCI_TWOTOUCH		27
+#define QT602240_SPT_COMMSCONFIG	18	/* firmware ver 21 over */
+#define QT602240_SPT_GPIOPWM		19
+#define QT602240_SPT_SELFTEST		25
+#define QT602240_SPT_CTECONFIG		28
+#define QT602240_SPT_USERDATA		38	/* firmware ver 21 over */
+
+/* QT602240_GEN_COMMAND field */
+#define QT602240_COMMAND_RESET		0
+#define QT602240_COMMAND_BACKUPNV	1
+#define QT602240_COMMAND_CALIBRATE	2
+#define QT602240_COMMAND_REPORTALL	3
+#define QT602240_COMMAND_DIAGNOSTIC	5
+
+/* QT602240_GEN_POWER field */
+#define QT602240_POWER_IDLEACQINT	0
+#define QT602240_POWER_ACTVACQINT	1
+#define QT602240_POWER_ACTV2IDLETO	2
+
+/* QT602240_GEN_ACQUIRE field */
+#define QT602240_ACQUIRE_CHRGTIME	0
+#define QT602240_ACQUIRE_TCHDRIFT	2
+#define QT602240_ACQUIRE_DRIFTST	3
+#define QT602240_ACQUIRE_TCHAUTOCAL	4
+#define QT602240_ACQUIRE_SYNC		5
+#define QT602240_ACQUIRE_ATCHCALST	6
+#define QT602240_ACQUIRE_ATCHCALSTHR	7
+
+/* QT602240_TOUCH_MULTI field */
+#define QT602240_TOUCH_CTRL		0
+#define QT602240_TOUCH_XORIGIN		1
+#define QT602240_TOUCH_YORIGIN		2
+#define QT602240_TOUCH_XSIZE		3
+#define QT602240_TOUCH_YSIZE		4
+#define QT602240_TOUCH_BLEN		6
+#define QT602240_TOUCH_TCHTHR		7
+#define QT602240_TOUCH_TCHDI		8
+#define QT602240_TOUCH_ORIENT		9
+#define QT602240_TOUCH_MOVHYSTI		11
+#define QT602240_TOUCH_MOVHYSTN		12
+#define QT602240_TOUCH_NUMTOUCH		14
+#define QT602240_TOUCH_MRGHYST		15
+#define QT602240_TOUCH_MRGTHR		16
+#define QT602240_TOUCH_AMPHYST		17
+#define QT602240_TOUCH_XRANGE_LSB	18
+#define QT602240_TOUCH_XRANGE_MSB	19
+#define QT602240_TOUCH_YRANGE_LSB	20
+#define QT602240_TOUCH_YRANGE_MSB	21
+#define QT602240_TOUCH_XLOCLIP		22
+#define QT602240_TOUCH_XHICLIP		23
+#define QT602240_TOUCH_YLOCLIP		24
+#define QT602240_TOUCH_YHICLIP		25
+#define QT602240_TOUCH_XEDGECTRL	26
+#define QT602240_TOUCH_XEDGEDIST	27
+#define QT602240_TOUCH_YEDGECTRL	28
+#define QT602240_TOUCH_YEDGEDIST	29
+#define QT602240_TOUCH_JUMPLIMIT	30	/* firmware ver 22 over */
+
+/* QT602240_PROCI_GRIPFACE field */
+#define QT602240_GRIPFACE_CTRL		0
+#define QT602240_GRIPFACE_XLOGRIP	1
+#define QT602240_GRIPFACE_XHIGRIP	2
+#define QT602240_GRIPFACE_YLOGRIP	3
+#define QT602240_GRIPFACE_YHIGRIP	4
+#define QT602240_GRIPFACE_MAXTCHS	5
+#define QT602240_GRIPFACE_SZTHR1	7
+#define QT602240_GRIPFACE_SZTHR2	8
+#define QT602240_GRIPFACE_SHPTHR1	9
+#define QT602240_GRIPFACE_SHPTHR2	10
+#define QT602240_GRIPFACE_SUPEXTTO	11
+
+/* QT602240_PROCI_NOISE field */
+#define QT602240_NOISE_CTRL		0
+#define QT602240_NOISE_OUTFLEN		1
+#define QT602240_NOISE_GCAFUL_LSB	3
+#define QT602240_NOISE_GCAFUL_MSB	4
+#define QT602240_NOISE_GCAFLL_LSB	5
+#define QT602240_NOISE_GCAFLL_MSB	6
+#define QT602240_NOISE_ACTVGCAFVALID	7
+#define QT602240_NOISE_NOISETHR		8
+#define QT602240_NOISE_FREQHOPSCALE	10
+#define QT602240_NOISE_FREQ0		11
+#define QT602240_NOISE_FREQ1		12
+#define QT602240_NOISE_FREQ2		13
+#define QT602240_NOISE_FREQ3		14
+#define QT602240_NOISE_FREQ4		15
+#define QT602240_NOISE_IDLEGCAFVALID	16
+
+/* QT602240_SPT_COMMSCONFIG */
+#define QT602240_COMMS_CTRL		0
+#define QT602240_COMMS_CMD		1
+
+/* QT602240_SPT_CTECONFIG field */
+#define QT602240_CTE_CTRL		0
+#define QT602240_CTE_CMD		1
+#define QT602240_CTE_MODE		2
+#define QT602240_CTE_IDLEGCAFDEPTH	3
+#define QT602240_CTE_ACTVGCAFDEPTH	4
+#define QT602240_CTE_VOLTAGE		5	/* firmware ver 21 over */
+
+#define QT602240_VOLTAGE_DEFAULT	2700000
+#define QT602240_VOLTAGE_STEP		10000
+
+/* Define for QT602240_GEN_COMMAND */
+#define QT602240_BOOT_VALUE		0xa5
+#define QT602240_BACKUP_VALUE		0x55
+#define QT602240_BACKUP_TIME		25	/* msec */
+#define QT602240_RESET_TIME		65	/* msec */
+
+#define QT602240_FWRESET_TIME		175	/* msec */
+
+/* Command to unlock bootloader */
+#define QT602240_UNLOCK_CMD_MSB		0xaa
+#define QT602240_UNLOCK_CMD_LSB		0xdc
+
+/* Bootloader mode status */
+#define QT602240_WAITING_BOOTLOAD_CMD	0xc0	/* valid 7 6 bit only */
+#define QT602240_WAITING_FRAME_DATA	0x80	/* valid 7 6 bit only */
+#define QT602240_FRAME_CRC_CHECK	0x02
+#define QT602240_FRAME_CRC_FAIL		0x03
+#define QT602240_FRAME_CRC_PASS		0x04
+#define QT602240_APP_CRC_FAIL		0x40	/* valid 7 8 bit only */
+#define QT602240_BOOT_STATUS_MASK	0x3f
+
+/* Touch status */
+#define QT602240_SUPPRESS		(1 << 1)
+#define QT602240_AMP			(1 << 2)
+#define QT602240_VECTOR			(1 << 3)
+#define QT602240_MOVE			(1 << 4)
+#define QT602240_RELEASE		(1 << 5)
+#define QT602240_PRESS			(1 << 6)
+#define QT602240_DETECT			(1 << 7)
+
+/* Touchscreen absolute values */
+#define QT602240_MAX_XC			0x3ff
+#define QT602240_MAX_YC			0x3ff
+#define QT602240_MAX_AREA		0xff
+
+#define QT602240_MAX_FINGER		10
+
+/* Initial register values recommended from chip vendor */
+static const u8 init_vals_ver_20[] = {
+	/* QT602240_GEN_COMMAND(6) */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	/* QT602240_GEN_POWER(7) */
+	0x20, 0xff, 0x32,
+	/* QT602240_GEN_ACQUIRE(8) */
+	0x08, 0x05, 0x05, 0x00, 0x00, 0x00, 0x05, 0x14,
+	/* QT602240_TOUCH_MULTI(9) */
+	0x00, 0x00, 0x00, 0x11, 0x0a, 0x00, 0x00, 0x00, 0x02, 0x00,
+	0x00, 0x01, 0x01, 0x0e, 0x0a, 0x0a, 0x0a, 0x0a, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x64,
+	/* QT602240_TOUCH_KEYARRAY(15) */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00,
+	/* QT602240_SPT_GPIOPWM(19) */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00,
+	/* QT602240_PROCI_GRIPFACE(20) */
+	0x00, 0x64, 0x64, 0x64, 0x64, 0x00, 0x00, 0x1e, 0x14, 0x04,
+	0x1e, 0x00,
+	/* QT602240_PROCG_NOISE(22) */
+	0x05, 0x00, 0x00, 0x19, 0x00, 0xe7, 0xff, 0x04, 0x32, 0x00,
+	0x01, 0x0a, 0x0f, 0x14, 0x00, 0x00, 0xe8,
+	/* QT602240_TOUCH_PROXIMITY(23) */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00,
+	/* QT602240_PROCI_ONETOUCH(24) */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	/* QT602240_SPT_SELFTEST(25) */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	/* QT602240_PROCI_TWOTOUCH(27) */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	/* QT602240_SPT_CTECONFIG(28) */
+	0x00, 0x00, 0x00, 0x04, 0x08,
+};
+
+static const u8 init_vals_ver_21[] = {
+	/* QT602240_GEN_COMMAND(6) */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	/* QT602240_GEN_POWER(7) */
+	0x20, 0xff, 0x32,
+	/* QT602240_GEN_ACQUIRE(8) */
+	0x0a, 0x00, 0x05, 0x00, 0x00, 0x00, 0x09, 0x23,
+	/* QT602240_TOUCH_MULTI(9) */
+	0x00, 0x00, 0x00, 0x13, 0x0b, 0x00, 0x00, 0x00, 0x02, 0x00,
+	0x00, 0x01, 0x01, 0x0e, 0x0a, 0x0a, 0x0a, 0x0a, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	/* QT602240_TOUCH_KEYARRAY(15) */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00,
+	/* QT602240_SPT_GPIOPWM(19) */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	/* QT602240_PROCI_GRIPFACE(20) */
+	0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x28, 0x04,
+	0x0f, 0x0a,
+	/* QT602240_PROCG_NOISE(22) */
+	0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x23, 0x00,
+	0x00, 0x05, 0x0f, 0x19, 0x23, 0x2d, 0x03,
+	/* QT602240_TOUCH_PROXIMITY(23) */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00,
+	/* QT602240_PROCI_ONETOUCH(24) */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	/* QT602240_SPT_SELFTEST(25) */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	/* QT602240_PROCI_TWOTOUCH(27) */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	/* QT602240_SPT_CTECONFIG(28) */
+	0x00, 0x00, 0x00, 0x08, 0x10, 0x00,
+};
+
+static const u8 init_vals_ver_22[] = {
+	/* QT602240_GEN_COMMAND(6) */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	/* QT602240_GEN_POWER(7) */
+	0x20, 0xff, 0x32,
+	/* QT602240_GEN_ACQUIRE(8) */
+	0x0a, 0x00, 0x05, 0x00, 0x00, 0x00, 0x09, 0x23,
+	/* QT602240_TOUCH_MULTI(9) */
+	0x00, 0x00, 0x00, 0x13, 0x0b, 0x00, 0x00, 0x00, 0x02, 0x00,
+	0x00, 0x01, 0x01, 0x0e, 0x0a, 0x0a, 0x0a, 0x0a, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00,
+	/* QT602240_TOUCH_KEYARRAY(15) */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00,
+	/* QT602240_SPT_GPIOPWM(19) */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	/* QT602240_PROCI_GRIPFACE(20) */
+	0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x28, 0x04,
+	0x0f, 0x0a,
+	/* QT602240_PROCG_NOISE(22) */
+	0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x23, 0x00,
+	0x00, 0x05, 0x0f, 0x19, 0x23, 0x2d, 0x03,
+	/* QT602240_TOUCH_PROXIMITY(23) */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00,
+	/* QT602240_PROCI_ONETOUCH(24) */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	/* QT602240_SPT_SELFTEST(25) */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	/* QT602240_PROCI_TWOTOUCH(27) */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	/* QT602240_SPT_CTECONFIG(28) */
+	0x00, 0x00, 0x00, 0x08, 0x10, 0x00,
+};
+
+struct qt602240_info {
+	u8 family_id;
+	u8 variant_id;
+	u8 version;
+	u8 build;
+	u8 matrix_xsize;
+	u8 matrix_ysize;
+	u8 object_num;
+};
+
+struct qt602240_object {
+	u8 type;
+	u16 start_address;
+	u8 size;
+	u8 instances;
+	u8 num_report_ids;
+
+	/* to map object and message */
+	u8 max_reportid;
+};
+
+struct qt602240_message {
+	u8 reportid;
+	u8 message[7];
+	u8 checksum;
+};
+
+struct qt602240_finger {
+	int status;
+	int x;
+	int y;
+	int area;
+};
+
+/* Each client has this additional data */
+struct qt602240_data {
+	struct i2c_client *client;
+	struct input_dev *input_dev;
+	const struct qt602240_platform_data *pdata;
+	struct qt602240_object *object_table;
+	struct qt602240_info info;
+	struct qt602240_finger finger[QT602240_MAX_FINGER];
+	unsigned int irq;
+};
+
+static bool qt602240_object_readable(unsigned int type)
+{
+	switch (type) {
+	case QT602240_GEN_MESSAGE:
+	case QT602240_GEN_COMMAND:
+	case QT602240_GEN_POWER:
+	case QT602240_GEN_ACQUIRE:
+	case QT602240_TOUCH_MULTI:
+	case QT602240_TOUCH_KEYARRAY:
+	case QT602240_TOUCH_PROXIMITY:
+	case QT602240_PROCI_GRIPFACE:
+	case QT602240_PROCG_NOISE:
+	case QT602240_PROCI_ONETOUCH:
+	case QT602240_PROCI_TWOTOUCH:
+	case QT602240_SPT_COMMSCONFIG:
+	case QT602240_SPT_GPIOPWM:
+	case QT602240_SPT_SELFTEST:
+	case QT602240_SPT_CTECONFIG:
+	case QT602240_SPT_USERDATA:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool qt602240_object_writable(unsigned int type)
+{
+	switch (type) {
+	case QT602240_GEN_COMMAND:
+	case QT602240_GEN_POWER:
+	case QT602240_GEN_ACQUIRE:
+	case QT602240_TOUCH_MULTI:
+	case QT602240_TOUCH_KEYARRAY:
+	case QT602240_TOUCH_PROXIMITY:
+	case QT602240_PROCI_GRIPFACE:
+	case QT602240_PROCG_NOISE:
+	case QT602240_PROCI_ONETOUCH:
+	case QT602240_PROCI_TWOTOUCH:
+	case QT602240_SPT_GPIOPWM:
+	case QT602240_SPT_SELFTEST:
+	case QT602240_SPT_CTECONFIG:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static void qt602240_dump_message(struct device *dev,
+				  struct qt602240_message *message)
+{
+	dev_dbg(dev, "reportid:\t0x%x\n", message->reportid);
+	dev_dbg(dev, "message1:\t0x%x\n", message->message[0]);
+	dev_dbg(dev, "message2:\t0x%x\n", message->message[1]);
+	dev_dbg(dev, "message3:\t0x%x\n", message->message[2]);
+	dev_dbg(dev, "message4:\t0x%x\n", message->message[3]);
+	dev_dbg(dev, "message5:\t0x%x\n", message->message[4]);
+	dev_dbg(dev, "message6:\t0x%x\n", message->message[5]);
+	dev_dbg(dev, "message7:\t0x%x\n", message->message[6]);
+	dev_dbg(dev, "checksum:\t0x%x\n", message->checksum);
+}
+
+static int qt602240_check_bootloader(struct i2c_client *client,
+				     unsigned int state)
+{
+	u8 val;
+
+recheck:
+	if (i2c_master_recv(client, &val, 1) != 1) {
+		dev_err(&client->dev, "%s: i2c recv failed\n", __func__);
+		return -EIO;
+	}
+
+	switch (state) {
+	case QT602240_WAITING_BOOTLOAD_CMD:
+	case QT602240_WAITING_FRAME_DATA:
+		val &= ~QT602240_BOOT_STATUS_MASK;
+		break;
+	case QT602240_FRAME_CRC_PASS:
+		if (val == QT602240_FRAME_CRC_CHECK)
+			goto recheck;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (val != state) {
+		dev_err(&client->dev, "Unvalid bootloader mode state\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int qt602240_unlock_bootloader(struct i2c_client *client)
+{
+	u8 buf[2];
+
+	buf[0] = QT602240_UNLOCK_CMD_LSB;
+	buf[1] = QT602240_UNLOCK_CMD_MSB;
+
+	if (i2c_master_send(client, buf, 2) != 2) {
+		dev_err(&client->dev, "%s: i2c send failed\n", __func__);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int qt602240_fw_write(struct i2c_client *client,
+			     const u8 *data, unsigned int frame_size)
+{
+	if (i2c_master_send(client, data, frame_size) != frame_size) {
+		dev_err(&client->dev, "%s: i2c send failed\n", __func__);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int __qt602240_read_reg(struct i2c_client *client,
+			       u16 reg, u16 len, void *val)
+{
+	struct i2c_msg xfer[2];
+	u8 buf[2];
+
+	buf[0] = reg & 0xff;
+	buf[1] = (reg >> 8) & 0xff;
+
+	/* Write register */
+	xfer[0].addr = client->addr;
+	xfer[0].flags = 0;
+	xfer[0].len = 2;
+	xfer[0].buf = buf;
+
+	/* Read data */
+	xfer[1].addr = client->addr;
+	xfer[1].flags = I2C_M_RD;
+	xfer[1].len = len;
+	xfer[1].buf = val;
+
+	if (i2c_transfer(client->adapter, xfer, 2) != 2) {
+		dev_err(&client->dev, "%s: i2c transfer failed\n", __func__);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int qt602240_read_reg(struct i2c_client *client, u16 reg, u8 *val)
+{
+	return __qt602240_read_reg(client, reg, 1, val);
+}
+
+static int qt602240_write_reg(struct i2c_client *client, u16 reg, u8 val)
+{
+	u8 buf[3];
+
+	buf[0] = reg & 0xff;
+	buf[1] = (reg >> 8) & 0xff;
+	buf[2] = val;
+
+	if (i2c_master_send(client, buf, 3) != 3) {
+		dev_err(&client->dev, "%s: i2c send failed\n", __func__);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int qt602240_read_object_table(struct i2c_client *client,
+				      u16 reg, u8 *object_buf)
+{
+	return __qt602240_read_reg(client, reg, QT602240_OBJECT_SIZE,
+				   object_buf);
+}
+
+static struct qt602240_object *
+qt602240_get_object(struct qt602240_data *data, u8 type)
+{
+	struct qt602240_object *object;
+	int i;
+
+	for (i = 0; i < data->info.object_num; i++) {
+		object = data->object_table + i;
+		if (object->type == type)
+			return object;
+	}
+
+	dev_err(&data->client->dev, "Invalid object type\n");
+	return NULL;
+}
+
+static int qt602240_read_message(struct qt602240_data *data,
+				 struct qt602240_message *message)
+{
+	struct qt602240_object *object;
+	u16 reg;
+
+	object = qt602240_get_object(data, QT602240_GEN_MESSAGE);
+	if (!object)
+		return -EINVAL;
+
+	reg = object->start_address;
+	return __qt602240_read_reg(data->client, reg,
+			sizeof(struct qt602240_message), message);
+}
+
+static int qt602240_read_object(struct qt602240_data *data,
+				u8 type, u8 offset, u8 *val)
+{
+	struct qt602240_object *object;
+	u16 reg;
+
+	object = qt602240_get_object(data, type);
+	if (!object)
+		return -EINVAL;
+
+	reg = object->start_address;
+	return __qt602240_read_reg(data->client, reg + offset, 1, val);
+}
+
+static int qt602240_write_object(struct qt602240_data *data,
+				 u8 type, u8 offset, u8 val)
+{
+	struct qt602240_object *object;
+	u16 reg;
+
+	object = qt602240_get_object(data, type);
+	if (!object)
+		return -EINVAL;
+
+	reg = object->start_address;
+	return qt602240_write_reg(data->client, reg + offset, val);
+}
+
+static void qt602240_input_report(struct qt602240_data *data, int single_id)
+{
+	struct qt602240_finger *finger = data->finger;
+	struct input_dev *input_dev = data->input_dev;
+	int status = finger[single_id].status;
+	int finger_num = 0;
+	int id;
+
+	for (id = 0; id < QT602240_MAX_FINGER; id++) {
+		if (!finger[id].status)
+			continue;
+
+		input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR,
+				finger[id].status != QT602240_RELEASE ?
+				finger[id].area : 0);
+		input_report_abs(input_dev, ABS_MT_POSITION_X,
+				finger[id].x);
+		input_report_abs(input_dev, ABS_MT_POSITION_Y,
+				finger[id].y);
+		input_mt_sync(input_dev);
+
+		if (finger[id].status == QT602240_RELEASE)
+			finger[id].status = 0;
+		else
+			finger_num++;
+	}
+
+	input_report_key(input_dev, BTN_TOUCH, finger_num > 0);
+
+	if (status != QT602240_RELEASE) {
+		input_report_abs(input_dev, ABS_X, finger[single_id].x);
+		input_report_abs(input_dev, ABS_Y, finger[single_id].y);
+	}
+
+	input_sync(input_dev);
+}
+
+static void qt602240_input_touchevent(struct qt602240_data *data,
+				      struct qt602240_message *message, int id)
+{
+	struct qt602240_finger *finger = data->finger;
+	struct device *dev = &data->client->dev;
+	u8 status = message->message[0];
+	int x;
+	int y;
+	int area;
+
+	/* Check the touch is present on the screen */
+	if (!(status & QT602240_DETECT)) {
+		if (status & QT602240_RELEASE) {
+			dev_dbg(dev, "[%d] released\n", id);
+
+			finger[id].status = QT602240_RELEASE;
+			qt602240_input_report(data, id);
+		}
+		return;
+	}
+
+	/* Check only AMP detection */
+	if (!(status & (QT602240_PRESS | QT602240_MOVE)))
+		return;
+
+	x = (message->message[1] << 2) | ((message->message[3] & ~0x3f) >> 6);
+	y = (message->message[2] << 2) | ((message->message[3] & ~0xf3) >> 2);
+	area = message->message[4];
+
+	dev_dbg(dev, "[%d] %s x: %d, y: %d, area: %d\n", id,
+		status & QT602240_MOVE ? "moved" : "pressed",
+		x, y, area);
+
+	finger[id].status = status & QT602240_MOVE ?
+				QT602240_MOVE : QT602240_PRESS;
+	finger[id].x = x;
+	finger[id].y = y;
+	finger[id].area = area;
+
+	qt602240_input_report(data, id);
+}
+
+static irqreturn_t qt602240_interrupt(int irq, void *dev_id)
+{
+	struct qt602240_data *data = dev_id;
+	struct qt602240_message message;
+	struct qt602240_object *object;
+	struct device *dev = &data->client->dev;
+	int id;
+	u8 reportid;
+	u8 max_reportid;
+	u8 min_reportid;
+
+	do {
+		if (qt602240_read_message(data, &message)) {
+			dev_err(dev, "Failed to read message\n");
+			goto end;
+		}
+
+		reportid = message.reportid;
+
+		/* whether reportid is thing of QT602240_TOUCH_MULTI */
+		object = qt602240_get_object(data, QT602240_TOUCH_MULTI);
+		if (!object)
+			goto end;
+
+		max_reportid = object->max_reportid;
+		min_reportid = max_reportid - object->num_report_ids + 1;
+		id = reportid - min_reportid;
+
+		if (reportid >= min_reportid && reportid <= max_reportid)
+			qt602240_input_touchevent(data, &message, id);
+		else
+			qt602240_dump_message(dev, &message);
+	} while (reportid != 0xff);
+
+end:
+	return IRQ_HANDLED;
+}
+
+static int qt602240_check_reg_init(struct qt602240_data *data)
+{
+	struct qt602240_object *object;
+	struct device *dev = &data->client->dev;
+	int index = 0;
+	int i, j;
+	u8 version = data->info.version;
+	u8 *init_vals;
+
+	switch (version) {
+	case QT602240_VER_20:
+		init_vals = (u8 *)init_vals_ver_20;
+		break;
+	case QT602240_VER_21:
+		init_vals = (u8 *)init_vals_ver_21;
+		break;
+	case QT602240_VER_22:
+		init_vals = (u8 *)init_vals_ver_22;
+		break;
+	default:
+		dev_err(dev, "Firmware version %d doesn't support\n", version);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < data->info.object_num; i++) {
+		object = data->object_table + i;
+
+		if (!qt602240_object_writable(object->type))
+			continue;
+
+		for (j = 0; j < object->size + 1; j++)
+			qt602240_write_object(data, object->type, j,
+					init_vals[index + j]);
+
+		index += object->size + 1;
+	}
+
+	return 0;
+}
+
+static int qt602240_check_matrix_size(struct qt602240_data *data)
+{
+	const struct qt602240_platform_data *pdata = data->pdata;
+	struct device *dev = &data->client->dev;
+	int mode = -1;
+	int error;
+	u8 val;
+
+	dev_dbg(dev, "Number of X lines: %d\n", pdata->x_line);
+	dev_dbg(dev, "Number of Y lines: %d\n", pdata->y_line);
+
+	switch (pdata->x_line) {
+	case 0 ... 15:
+		if (pdata->y_line <= 14)
+			mode = 0;
+		break;
+	case 16:
+		if (pdata->y_line <= 12)
+			mode = 1;
+		if (pdata->y_line == 13 || pdata->y_line == 14)
+			mode = 0;
+		break;
+	case 17:
+		if (pdata->y_line <= 11)
+			mode = 2;
+		if (pdata->y_line == 12 || pdata->y_line == 13)
+			mode = 1;
+		break;
+	case 18:
+		if (pdata->y_line <= 10)
+			mode = 3;
+		if (pdata->y_line == 11 || pdata->y_line == 12)
+			mode = 2;
+		break;
+	case 19:
+		if (pdata->y_line <= 9)
+			mode = 4;
+		if (pdata->y_line == 10 || pdata->y_line == 11)
+			mode = 3;
+		break;
+	case 20:
+		mode = 4;
+	}
+
+	if (mode < 0) {
+		dev_err(dev, "Invalid X/Y lines\n");
+		return -EINVAL;
+	}
+
+	error = qt602240_read_object(data, QT602240_SPT_CTECONFIG,
+				QT602240_CTE_MODE, &val);
+	if (error)
+		return error;
+
+	if (mode == val)
+		return 0;
+
+	/* Change the CTE configuration */
+	qt602240_write_object(data, QT602240_SPT_CTECONFIG,
+			QT602240_CTE_CTRL, 1);
+	qt602240_write_object(data, QT602240_SPT_CTECONFIG,
+			QT602240_CTE_MODE, mode);
+	qt602240_write_object(data, QT602240_SPT_CTECONFIG,
+			QT602240_CTE_CTRL, 0);
+
+	return 0;
+}
+
+static int qt602240_make_highchg(struct qt602240_data *data)
+{
+	struct device *dev = &data->client->dev;
+	int count = 10;
+	int error;
+	u8 val;
+
+	/* Read dummy message to make high CHG pin */
+	do {
+		error = qt602240_read_object(data, QT602240_GEN_MESSAGE, 0, &val);
+		if (error)
+			return error;
+	} while ((val != 0xff) && --count);
+
+	if (!count) {
+		dev_err(dev, "CHG pin isn't cleared\n");
+		return -EBUSY;
+	}
+
+	return 0;
+}
+
+static void qt602240_handle_pdata(struct qt602240_data *data)
+{
+	const struct qt602240_platform_data *pdata = data->pdata;
+	u8 voltage;
+
+	/* Set touchscreen lines */
+	qt602240_write_object(data, QT602240_TOUCH_MULTI, QT602240_TOUCH_XSIZE,
+			pdata->x_line);
+	qt602240_write_object(data, QT602240_TOUCH_MULTI, QT602240_TOUCH_YSIZE,
+			pdata->y_line);
+
+	/* Set touchscreen orient */
+	qt602240_write_object(data, QT602240_TOUCH_MULTI, QT602240_TOUCH_ORIENT,
+			pdata->orient);
+
+	/* Set touchscreen burst length */
+	qt602240_write_object(data, QT602240_TOUCH_MULTI,
+			QT602240_TOUCH_BLEN, pdata->blen);
+
+	/* Set touchscreen threshold */
+	qt602240_write_object(data, QT602240_TOUCH_MULTI,
+			QT602240_TOUCH_TCHTHR, pdata->threshold);
+
+	/* Set touchscreen resolution */
+	qt602240_write_object(data, QT602240_TOUCH_MULTI,
+			QT602240_TOUCH_XRANGE_LSB, (pdata->x_size - 1) & 0xff);
+	qt602240_write_object(data, QT602240_TOUCH_MULTI,
+			QT602240_TOUCH_XRANGE_MSB, (pdata->x_size - 1) >> 8);
+	qt602240_write_object(data, QT602240_TOUCH_MULTI,
+			QT602240_TOUCH_YRANGE_LSB, (pdata->y_size - 1) & 0xff);
+	qt602240_write_object(data, QT602240_TOUCH_MULTI,
+			QT602240_TOUCH_YRANGE_MSB, (pdata->y_size - 1) >> 8);
+
+	/* Set touchscreen voltage */
+	if (data->info.version >= QT602240_VER_21 && pdata->voltage) {
+		if (pdata->voltage < QT602240_VOLTAGE_DEFAULT) {
+			voltage = (QT602240_VOLTAGE_DEFAULT - pdata->voltage) /
+				QT602240_VOLTAGE_STEP;
+			voltage = 0xff - voltage + 1;
+		} else
+			voltage = (pdata->voltage - QT602240_VOLTAGE_DEFAULT) /
+				QT602240_VOLTAGE_STEP;
+
+		qt602240_write_object(data, QT602240_SPT_CTECONFIG,
+				QT602240_CTE_VOLTAGE, voltage);
+	}
+}
+
+static int qt602240_get_info(struct qt602240_data *data)
+{
+	struct i2c_client *client = data->client;
+	struct qt602240_info *info = &data->info;
+	int error;
+	u8 val;
+
+	error = qt602240_read_reg(client, QT602240_FAMILY_ID, &val);
+	if (error)
+		return error;
+	info->family_id = val;
+
+	error = qt602240_read_reg(client, QT602240_VARIANT_ID, &val);
+	if (error)
+		return error;
+	info->variant_id = val;
+
+	error = qt602240_read_reg(client, QT602240_VERSION, &val);
+	if (error)
+		return error;
+	info->version = val;
+
+	error = qt602240_read_reg(client, QT602240_BUILD, &val);
+	if (error)
+		return error;
+	info->build = val;
+
+	error = qt602240_read_reg(client, QT602240_OBJECT_NUM, &val);
+	if (error)
+		return error;
+	info->object_num = val;
+
+	return 0;
+}
+
+static int qt602240_get_object_table(struct qt602240_data *data)
+{
+	int error;
+	int i;
+	u16 reg;
+	u8 reportid = 0;
+	u8 buf[QT602240_OBJECT_SIZE];
+
+	for (i = 0; i < data->info.object_num; i++) {
+		struct qt602240_object *object = data->object_table + i;
+
+		reg = QT602240_OBJECT_START + QT602240_OBJECT_SIZE * i;
+		error = qt602240_read_object_table(data->client, reg, buf);
+		if (error)
+			return error;
+
+		object->type = buf[0];
+		object->start_address = (buf[2] << 8) | buf[1];
+		object->size = buf[3];
+		object->instances = buf[4];
+		object->num_report_ids = buf[5];
+
+		if (object->num_report_ids) {
+			reportid += object->num_report_ids *
+					(object->instances + 1);
+			object->max_reportid = reportid;
+		}
+	}
+
+	return 0;
+}
+
+static int qt602240_initialize(struct qt602240_data *data)
+{
+	struct i2c_client *client = data->client;
+	struct qt602240_info *info = &data->info;
+	int error;
+	u8 val;
+
+	error = qt602240_get_info(data);
+	if (error)
+		return error;
+
+	data->object_table = kcalloc(info->object_num,
+				     sizeof(struct qt602240_data),
+				     GFP_KERNEL);
+	if (!data->object_table) {
+		dev_err(&client->dev, "Failed to allocate memory\n");
+		return -ENOMEM;
+	}
+
+	/* Get object table information */
+	error = qt602240_get_object_table(data);
+	if (error)
+		return error;
+
+	/* Check register init values */
+	error = qt602240_check_reg_init(data);
+	if (error)
+		return error;
+
+	/* Check X/Y matrix size */
+	error = qt602240_check_matrix_size(data);
+	if (error)
+		return error;
+
+	error = qt602240_make_highchg(data);
+	if (error)
+		return error;
+
+	qt602240_handle_pdata(data);
+
+	/* Backup to memory */
+	qt602240_write_object(data, QT602240_GEN_COMMAND,
+			QT602240_COMMAND_BACKUPNV,
+			QT602240_BACKUP_VALUE);
+	msleep(QT602240_BACKUP_TIME);
+
+	/* Soft reset */
+	qt602240_write_object(data, QT602240_GEN_COMMAND,
+			QT602240_COMMAND_RESET, 1);
+	msleep(QT602240_RESET_TIME);
+
+	/* Update matrix size at info struct */
+	error = qt602240_read_reg(client, QT602240_MATRIX_X_SIZE, &val);
+	if (error)
+		return error;
+	info->matrix_xsize = val;
+
+	error = qt602240_read_reg(client, QT602240_MATRIX_Y_SIZE, &val);
+	if (error)
+		return error;
+	info->matrix_ysize = val;
+
+	dev_info(&client->dev,
+			"Family ID: %d Variant ID: %d Version: %d Build: %d\n",
+			info->family_id, info->variant_id, info->version,
+			info->build);
+
+	dev_info(&client->dev,
+			"Matrix X Size: %d Matrix Y Size: %d Object Num: %d\n",
+			info->matrix_xsize, info->matrix_ysize,
+			info->object_num);
+
+	return 0;
+}
+
+static ssize_t qt602240_object_show(struct device *dev,
+				    struct device_attribute *attr, char *buf)
+{
+	struct qt602240_data *data = dev_get_drvdata(dev);
+	struct qt602240_object *object;
+	int count = 0;
+	int i, j;
+	int error;
+	u8 val;
+
+	for (i = 0; i < data->info.object_num; i++) {
+		object = data->object_table + i;
+
+		count += sprintf(buf + count,
+				"Object Table Element %d(Type %d)\n",
+				i + 1, object->type);
+
+		if (!qt602240_object_readable(object->type)) {
+			count += sprintf(buf + count, "\n");
+			continue;
+		}
+
+		for (j = 0; j < object->size + 1; j++) {
+			error = qt602240_read_object(data,
+						object->type, j, &val);
+			if (error)
+				return error;
+
+			count += sprintf(buf + count,
+					"  Byte %d: 0x%x (%d)\n", j, val, val);
+		}
+
+		count += sprintf(buf + count, "\n");
+	}
+
+	return count;
+}
+
+static int qt602240_load_fw(struct device *dev, const char *fn)
+{
+	struct qt602240_data *data = dev_get_drvdata(dev);
+	struct i2c_client *client = data->client;
+	const struct firmware *fw = NULL;
+	unsigned int frame_size;
+	unsigned int pos = 0;
+	int ret;
+
+	ret = request_firmware(&fw, fn, dev);
+	if (ret) {
+		dev_err(dev, "Unable to open firmware %s\n", fn);
+		return ret;
+	}
+
+	/* Change to the bootloader mode */
+	qt602240_write_object(data, QT602240_GEN_COMMAND,
+			QT602240_COMMAND_RESET, QT602240_BOOT_VALUE);
+	msleep(QT602240_RESET_TIME);
+
+	/* Change to slave address of bootloader */
+	if (client->addr == QT602240_APP_LOW)
+		client->addr = QT602240_BOOT_LOW;
+	else
+		client->addr = QT602240_BOOT_HIGH;
+
+	ret = qt602240_check_bootloader(client, QT602240_WAITING_BOOTLOAD_CMD);
+	if (ret)
+		goto out;
+
+	/* Unlock bootloader */
+	qt602240_unlock_bootloader(client);
+
+	while (pos < fw->size) {
+		ret = qt602240_check_bootloader(client,
+						QT602240_WAITING_FRAME_DATA);
+		if (ret)
+			goto out;
+
+		frame_size = ((*(fw->data + pos) << 8) | *(fw->data + pos + 1));
+
+		/* We should add 2 at frame size as the the firmware data is not
+		 * included the CRC bytes.
+		 */
+		frame_size += 2;
+
+		/* Write one frame to device */
+		qt602240_fw_write(client, fw->data + pos, frame_size);
+
+		ret = qt602240_check_bootloader(client,
+						QT602240_FRAME_CRC_PASS);
+		if (ret)
+			goto out;
+
+		pos += frame_size;
+
+		dev_dbg(dev, "Updated %d bytes / %zd bytes\n", pos, fw->size);
+	}
+
+out:
+	release_firmware(fw);
+
+	/* Change to slave address of application */
+	if (client->addr == QT602240_BOOT_LOW)
+		client->addr = QT602240_APP_LOW;
+	else
+		client->addr = QT602240_APP_HIGH;
+
+	return ret;
+}
+
+static ssize_t qt602240_update_fw_store(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf, size_t count)
+{
+	struct qt602240_data *data = dev_get_drvdata(dev);
+	unsigned int version;
+	int error;
+
+	if (sscanf(buf, "%u", &version) != 1) {
+		dev_err(dev, "Invalid values\n");
+		return -EINVAL;
+	}
+
+	if (data->info.version < QT602240_VER_21 || version < QT602240_VER_21) {
+		dev_err(dev, "FW update supported starting with version 21\n");
+		return -EINVAL;
+	}
+
+	disable_irq(data->irq);
+
+	error = qt602240_load_fw(dev, QT602240_FW_NAME);
+	if (error) {
+		dev_err(dev, "The firmware update failed(%d)\n", error);
+		count = error;
+	} else {
+		dev_dbg(dev, "The firmware update succeeded\n");
+
+		/* Wait for reset */
+		msleep(QT602240_FWRESET_TIME);
+
+		kfree(data->object_table);
+		data->object_table = NULL;
+
+		qt602240_initialize(data);
+	}
+
+	enable_irq(data->irq);
+
+	return count;
+}
+
+static DEVICE_ATTR(object, 0444, qt602240_object_show, NULL);
+static DEVICE_ATTR(update_fw, 0664, NULL, qt602240_update_fw_store);
+
+static struct attribute *qt602240_attrs[] = {
+	&dev_attr_object.attr,
+	&dev_attr_update_fw.attr,
+	NULL
+};
+
+static const struct attribute_group qt602240_attr_group = {
+	.attrs = qt602240_attrs,
+};
+
+static void qt602240_start(struct qt602240_data *data)
+{
+	/* Touch enable */
+	qt602240_write_object(data,
+			QT602240_TOUCH_MULTI, QT602240_TOUCH_CTRL, 0x83);
+}
+
+static void qt602240_stop(struct qt602240_data *data)
+{
+	/* Touch disable */
+	qt602240_write_object(data,
+			QT602240_TOUCH_MULTI, QT602240_TOUCH_CTRL, 0);
+}
+
+static int qt602240_input_open(struct input_dev *dev)
+{
+	struct qt602240_data *data = input_get_drvdata(dev);
+
+	qt602240_start(data);
+
+	return 0;
+}
+
+static void qt602240_input_close(struct input_dev *dev)
+{
+	struct qt602240_data *data = input_get_drvdata(dev);
+
+	qt602240_stop(data);
+}
+
+static int __devinit qt602240_probe(struct i2c_client *client,
+		const struct i2c_device_id *id)
+{
+	struct qt602240_data *data;
+	struct input_dev *input_dev;
+	int error;
+
+	if (!client->dev.platform_data)
+		return -EINVAL;
+
+	data = kzalloc(sizeof(struct qt602240_data), GFP_KERNEL);
+	input_dev = input_allocate_device();
+	if (!data || !input_dev) {
+		dev_err(&client->dev, "Failed to allocate memory\n");
+		error = -ENOMEM;
+		goto err_free_mem;
+	}
+
+	input_dev->name = "AT42QT602240/ATMXT224 Touchscreen";
+	input_dev->id.bustype = BUS_I2C;
+	input_dev->dev.parent = &client->dev;
+	input_dev->open = qt602240_input_open;
+	input_dev->close = qt602240_input_close;
+
+	__set_bit(EV_ABS, input_dev->evbit);
+	__set_bit(EV_KEY, input_dev->evbit);
+	__set_bit(BTN_TOUCH, input_dev->keybit);
+
+	/* For single touch */
+	input_set_abs_params(input_dev, ABS_X,
+			     0, QT602240_MAX_XC, 0, 0);
+	input_set_abs_params(input_dev, ABS_Y,
+			     0, QT602240_MAX_YC, 0, 0);
+
+	/* For multi touch */
+	input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR,
+			     0, QT602240_MAX_AREA, 0, 0);
+	input_set_abs_params(input_dev, ABS_MT_POSITION_X,
+			     0, QT602240_MAX_XC, 0, 0);
+	input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
+			     0, QT602240_MAX_YC, 0, 0);
+
+	input_set_drvdata(input_dev, data);
+
+	data->client = client;
+	data->input_dev = input_dev;
+	data->pdata = client->dev.platform_data;
+	data->irq = client->irq;
+
+	i2c_set_clientdata(client, data);
+
+	error = qt602240_initialize(data);
+	if (error)
+		goto err_free_object;
+
+	error = request_threaded_irq(client->irq, NULL, qt602240_interrupt,
+			IRQF_TRIGGER_FALLING, client->dev.driver->name, data);
+	if (error) {
+		dev_err(&client->dev, "Failed to register interrupt\n");
+		goto err_free_object;
+	}
+
+	error = input_register_device(input_dev);
+	if (error)
+		goto err_free_irq;
+
+	error = sysfs_create_group(&client->dev.kobj, &qt602240_attr_group);
+	if (error)
+		goto err_unregister_device;
+
+	return 0;
+
+err_unregister_device:
+	input_unregister_device(input_dev);
+	input_dev = NULL;
+err_free_irq:
+	free_irq(client->irq, data);
+err_free_object:
+	kfree(data->object_table);
+err_free_mem:
+	input_free_device(input_dev);
+	kfree(data);
+	return error;
+}
+
+static int __devexit qt602240_remove(struct i2c_client *client)
+{
+	struct qt602240_data *data = i2c_get_clientdata(client);
+
+	sysfs_remove_group(&client->dev.kobj, &qt602240_attr_group);
+	free_irq(data->irq, data);
+	input_unregister_device(data->input_dev);
+	kfree(data->object_table);
+	kfree(data);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int qt602240_suspend(struct i2c_client *client, pm_message_t mesg)
+{
+	struct qt602240_data *data = i2c_get_clientdata(client);
+	struct input_dev *input_dev = data->input_dev;
+
+	mutex_lock(&input_dev->mutex);
+
+	if (input_dev->users)
+		qt602240_stop(data);
+
+	mutex_unlock(&input_dev->mutex);
+
+	return 0;
+}
+
+static int qt602240_resume(struct i2c_client *client)
+{
+	struct qt602240_data *data = i2c_get_clientdata(client);
+	struct input_dev *input_dev = data->input_dev;
+
+	/* Soft reset */
+	qt602240_write_object(data, QT602240_GEN_COMMAND,
+			QT602240_COMMAND_RESET, 1);
+
+	msleep(QT602240_RESET_TIME);
+
+	mutex_lock(&input_dev->mutex);
+
+	if (input_dev->users)
+		qt602240_start(data);
+
+	mutex_unlock(&input_dev->mutex);
+
+	return 0;
+}
+#else
+#define qt602240_suspend	NULL
+#define qt602240_resume		NULL
+#endif
+
+static const struct i2c_device_id qt602240_id[] = {
+	{ "qt602240_ts", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, qt602240_id);
+
+static struct i2c_driver qt602240_driver = {
+	.driver = {
+		.name	= "qt602240_ts",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= qt602240_probe,
+	.remove		= __devexit_p(qt602240_remove),
+	.suspend	= qt602240_suspend,
+	.resume		= qt602240_resume,
+	.id_table	= qt602240_id,
+};
+
+static int __init qt602240_init(void)
+{
+	return i2c_add_driver(&qt602240_driver);
+}
+
+static void __exit qt602240_exit(void)
+{
+	i2c_del_driver(&qt602240_driver);
+}
+
+module_init(qt602240_init);
+module_exit(qt602240_exit);
+
+/* Module information */
+MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
+MODULE_DESCRIPTION("AT42QT602240/ATMXT224 Touchscreen driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/tps6507x-ts.c b/drivers/input/touchscreen/tps6507x-ts.c
index 5b70a1419b4d..a644d18c04dc 100644
--- a/drivers/input/touchscreen/tps6507x-ts.c
+++ b/drivers/input/touchscreen/tps6507x-ts.c
@@ -355,9 +355,6 @@ static int __devexit tps6507x_ts_remove(struct platform_device *pdev)
 	struct tps6507x_ts *tsc = tps6507x_dev->ts;
 	struct input_dev *input_dev = tsc->input_dev;
 
-	if (!tsc)
-		return 0;
-
 	cancel_delayed_work_sync(&tsc->work);
 	destroy_workqueue(tsc->wq);
 
diff --git a/drivers/input/touchscreen/usbtouchscreen.c b/drivers/input/touchscreen/usbtouchscreen.c
index 567d57215c28..f45f80f6d336 100644
--- a/drivers/input/touchscreen/usbtouchscreen.c
+++ b/drivers/input/touchscreen/usbtouchscreen.c
@@ -95,6 +95,7 @@ struct usbtouch_device_info {
 	int  (*get_pkt_len) (unsigned char *pkt, int len);
 
 	int  (*read_data)   (struct usbtouch_usb *usbtouch, unsigned char *pkt);
+	int  (*alloc)       (struct usbtouch_usb *usbtouch);
 	int  (*init)        (struct usbtouch_usb *usbtouch);
 	void (*exit)	    (struct usbtouch_usb *usbtouch);
 };
@@ -135,7 +136,7 @@ enum {
 	DEVTYPE_JASTEC,
 	DEVTYPE_E2I,
 	DEVTYPE_ZYTRONIC,
-	DEVTYPE_TC5UH,
+	DEVTYPE_TC45USB,
 	DEVTYPE_NEXIO,
 };
 
@@ -222,8 +223,11 @@ static const struct usb_device_id usbtouch_devices[] = {
 	{USB_DEVICE(0x14c8, 0x0003), .driver_info = DEVTYPE_ZYTRONIC},
 #endif
 
-#ifdef CONFIG_TOUCHSCREEN_USB_ETT_TC5UH
-	{USB_DEVICE(0x0664, 0x0309), .driver_info = DEVTYPE_TC5UH},
+#ifdef CONFIG_TOUCHSCREEN_USB_ETT_TC45USB
+	/* TC5UH */
+	{USB_DEVICE(0x0664, 0x0309), .driver_info = DEVTYPE_TC45USB},
+	/* TC4UM */
+	{USB_DEVICE(0x0664, 0x0306), .driver_info = DEVTYPE_TC45USB},
 #endif
 
 #ifdef CONFIG_TOUCHSCREEN_USB_NEXIO
@@ -507,7 +511,7 @@ static int dmc_tsc10_init(struct usbtouch_usb *usbtouch)
 	int ret = -ENOMEM;
 	unsigned char *buf;
 
-	buf = kmalloc(2, GFP_KERNEL);
+	buf = kmalloc(2, GFP_NOIO);
 	if (!buf)
 		goto err_nobuf;
 	/* reset */
@@ -574,10 +578,10 @@ static int irtouch_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
 #endif
 
 /*****************************************************************************
- * ET&T TC5UH part
+ * ET&T TC5UH/TC4UM part
  */
-#ifdef CONFIG_TOUCHSCREEN_USB_ETT_TC5UH
-static int tc5uh_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
+#ifdef CONFIG_TOUCHSCREEN_USB_ETT_TC45USB
+static int tc45usb_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
 {
 	dev->x = ((pkt[2] & 0x0F) << 8) | pkt[1];
 	dev->y = ((pkt[4] & 0x0F) << 8) | pkt[3];
@@ -732,11 +736,43 @@ static void nexio_ack_complete(struct urb *urb)
 {
 }
 
+static int nexio_alloc(struct usbtouch_usb *usbtouch)
+{
+	struct nexio_priv *priv;
+	int ret = -ENOMEM;
+
+	usbtouch->priv = kmalloc(sizeof(struct nexio_priv), GFP_KERNEL);
+	if (!usbtouch->priv)
+		goto out_buf;
+
+	priv = usbtouch->priv;
+
+	priv->ack_buf = kmemdup(nexio_ack_pkt, sizeof(nexio_ack_pkt),
+				GFP_KERNEL);
+	if (!priv->ack_buf)
+		goto err_priv;
+
+	priv->ack = usb_alloc_urb(0, GFP_KERNEL);
+	if (!priv->ack) {
+		dbg("%s - usb_alloc_urb failed: usbtouch->ack", __func__);
+		goto err_ack_buf;
+	}
+
+	return 0;
+
+err_ack_buf:
+	kfree(priv->ack_buf);
+err_priv:
+	kfree(priv);
+out_buf:
+	return ret;
+}
+
 static int nexio_init(struct usbtouch_usb *usbtouch)
 {
 	struct usb_device *dev = interface_to_usbdev(usbtouch->interface);
 	struct usb_host_interface *interface = usbtouch->interface->cur_altsetting;
-	struct nexio_priv *priv;
+	struct nexio_priv *priv = usbtouch->priv;
 	int ret = -ENOMEM;
 	int actual_len, i;
 	unsigned char *buf;
@@ -755,7 +791,7 @@ static int nexio_init(struct usbtouch_usb *usbtouch)
 	if (!input_ep || !output_ep)
 		return -ENXIO;
 
-	buf = kmalloc(NEXIO_BUFSIZE, GFP_KERNEL);
+	buf = kmalloc(NEXIO_BUFSIZE, GFP_NOIO);
 	if (!buf)
 		goto out_buf;
 
@@ -787,11 +823,11 @@ static int nexio_init(struct usbtouch_usb *usbtouch)
 		switch (buf[0]) {
 		case 0x83:	/* firmware version */
 			if (!firmware_ver)
-				firmware_ver = kstrdup(&buf[2], GFP_KERNEL);
+				firmware_ver = kstrdup(&buf[2], GFP_NOIO);
 			break;
 		case 0x84:	/* device name */
 			if (!device_name)
-				device_name = kstrdup(&buf[2], GFP_KERNEL);
+				device_name = kstrdup(&buf[2], GFP_NOIO);
 			break;
 		}
 	}
@@ -802,36 +838,11 @@ static int nexio_init(struct usbtouch_usb *usbtouch)
 	kfree(firmware_ver);
 	kfree(device_name);
 
-	/* prepare ACK URB */
-	ret = -ENOMEM;
-
-	usbtouch->priv = kmalloc(sizeof(struct nexio_priv), GFP_KERNEL);
-	if (!usbtouch->priv)
-		goto out_buf;
-
-	priv = usbtouch->priv;
-
-	priv->ack_buf = kmemdup(nexio_ack_pkt, sizeof(nexio_ack_pkt),
-				GFP_KERNEL);
-	if (!priv->ack_buf)
-		goto err_priv;
-
-	priv->ack = usb_alloc_urb(0, GFP_KERNEL);
-	if (!priv->ack) {
-		dbg("%s - usb_alloc_urb failed: usbtouch->ack", __func__);
-		goto err_ack_buf;
-	}
-
 	usb_fill_bulk_urb(priv->ack, dev, usb_sndbulkpipe(dev, output_ep),
 			  priv->ack_buf, sizeof(nexio_ack_pkt),
 			  nexio_ack_complete, usbtouch);
 	ret = 0;
-	goto out_buf;
 
-err_ack_buf:
-	kfree(priv->ack_buf);
-err_priv:
-	kfree(priv);
 out_buf:
 	kfree(buf);
 	return ret;
@@ -849,29 +860,32 @@ static void nexio_exit(struct usbtouch_usb *usbtouch)
 
 static int nexio_read_data(struct usbtouch_usb *usbtouch, unsigned char *pkt)
 {
-	int x, y, begin_x, begin_y, end_x, end_y, w, h, ret;
 	struct nexio_touch_packet *packet = (void *) pkt;
 	struct nexio_priv *priv = usbtouch->priv;
+	unsigned int data_len = be16_to_cpu(packet->data_len);
+	unsigned int x_len = be16_to_cpu(packet->x_len);
+	unsigned int y_len = be16_to_cpu(packet->y_len);
+	int x, y, begin_x, begin_y, end_x, end_y, w, h, ret;
 
 	/* got touch data? */
 	if ((pkt[0] & 0xe0) != 0xe0)
 		return 0;
 
-	if (be16_to_cpu(packet->data_len) > 0xff)
-		packet->data_len = cpu_to_be16(be16_to_cpu(packet->data_len) - 0x100);
-	if (be16_to_cpu(packet->x_len) > 0xff)
-		packet->x_len = cpu_to_be16(be16_to_cpu(packet->x_len) - 0x80);
+	if (data_len > 0xff)
+		data_len -= 0x100;
+	if (x_len > 0xff)
+		x_len -= 0x80;
 
 	/* send ACK */
 	ret = usb_submit_urb(priv->ack, GFP_ATOMIC);
 
 	if (!usbtouch->type->max_xc) {
-		usbtouch->type->max_xc = 2 * be16_to_cpu(packet->x_len);
-		input_set_abs_params(usbtouch->input, ABS_X, 0,
-				     2 * be16_to_cpu(packet->x_len), 0, 0);
-		usbtouch->type->max_yc = 2 * be16_to_cpu(packet->y_len);
-		input_set_abs_params(usbtouch->input, ABS_Y, 0,
-				     2 * be16_to_cpu(packet->y_len), 0, 0);
+		usbtouch->type->max_xc = 2 * x_len;
+		input_set_abs_params(usbtouch->input, ABS_X,
+				     0, usbtouch->type->max_xc, 0, 0);
+		usbtouch->type->max_yc = 2 * y_len;
+		input_set_abs_params(usbtouch->input, ABS_Y,
+				     0, usbtouch->type->max_yc, 0, 0);
 	}
 	/*
 	 * The device reports state of IR sensors on X and Y axes.
@@ -881,22 +895,21 @@ static int nexio_read_data(struct usbtouch_usb *usbtouch, unsigned char *pkt)
 	 * it's disabled (and untested) here as there's no X driver for that.
 	 */
 	begin_x = end_x = begin_y = end_y = -1;
-	for (x = 0; x < be16_to_cpu(packet->x_len); x++) {
+	for (x = 0; x < x_len; x++) {
 		if (begin_x == -1 && packet->data[x] > NEXIO_THRESHOLD) {
 			begin_x = x;
 			continue;
 		}
 		if (end_x == -1 && begin_x != -1 && packet->data[x] < NEXIO_THRESHOLD) {
 			end_x = x - 1;
-			for (y = be16_to_cpu(packet->x_len);
-			     y < be16_to_cpu(packet->data_len); y++) {
+			for (y = x_len; y < data_len; y++) {
 				if (begin_y == -1 && packet->data[y] > NEXIO_THRESHOLD) {
-					begin_y = y - be16_to_cpu(packet->x_len);
+					begin_y = y - x_len;
 					continue;
 				}
 				if (end_y == -1 &&
 				    begin_y != -1 && packet->data[y] < NEXIO_THRESHOLD) {
-					end_y = y - 1 - be16_to_cpu(packet->x_len);
+					end_y = y - 1 - x_len;
 					w = end_x - begin_x;
 					h = end_y - begin_y;
 #if 0
@@ -1104,14 +1117,14 @@ static struct usbtouch_device_info usbtouch_dev_info[] = {
 	},
 #endif
 
-#ifdef CONFIG_TOUCHSCREEN_USB_ETT_TC5UH
-	[DEVTYPE_TC5UH] = {
+#ifdef CONFIG_TOUCHSCREEN_USB_ETT_TC45USB
+	[DEVTYPE_TC45USB] = {
 		.min_xc		= 0x0,
 		.max_xc		= 0x0fff,
 		.min_yc		= 0x0,
 		.max_yc		= 0x0fff,
 		.rept_size	= 5,
-		.read_data	= tc5uh_read_data,
+		.read_data	= tc45usb_read_data,
 	},
 #endif
 
@@ -1120,6 +1133,7 @@ static struct usbtouch_device_info usbtouch_dev_info[] = {
 		.rept_size	= 1024,
 		.irq_always	= true,
 		.read_data	= nexio_read_data,
+		.alloc		= nexio_alloc,
 		.init		= nexio_init,
 		.exit		= nexio_exit,
 	},
@@ -1263,6 +1277,7 @@ static void usbtouch_irq(struct urb *urb)
 	usbtouch->type->process_pkt(usbtouch, usbtouch->data, urb->actual_length);
 
 exit:
+	usb_mark_last_busy(interface_to_usbdev(usbtouch->interface));
 	retval = usb_submit_urb(urb, GFP_ATOMIC);
 	if (retval)
 		err("%s - usb_submit_urb failed with result: %d",
@@ -1272,25 +1287,89 @@ exit:
 static int usbtouch_open(struct input_dev *input)
 {
 	struct usbtouch_usb *usbtouch = input_get_drvdata(input);
+	int r;
 
 	usbtouch->irq->dev = interface_to_usbdev(usbtouch->interface);
 
+	r = usb_autopm_get_interface(usbtouch->interface) ? -EIO : 0;
+	if (r < 0)
+		goto out;
+
 	if (!usbtouch->type->irq_always) {
-		if (usb_submit_urb(usbtouch->irq, GFP_KERNEL))
-		  return -EIO;
+		if (usb_submit_urb(usbtouch->irq, GFP_KERNEL)) {
+			r = -EIO;
+			goto out_put;
+		}
 	}
 
-	return 0;
+	usbtouch->interface->needs_remote_wakeup = 1;
+out_put:
+	usb_autopm_put_interface(usbtouch->interface);
+out:
+	return r;
 }
 
 static void usbtouch_close(struct input_dev *input)
 {
 	struct usbtouch_usb *usbtouch = input_get_drvdata(input);
+	int r;
 
 	if (!usbtouch->type->irq_always)
 		usb_kill_urb(usbtouch->irq);
+	r = usb_autopm_get_interface(usbtouch->interface);
+	usbtouch->interface->needs_remote_wakeup = 0;
+	if (!r)
+		usb_autopm_put_interface(usbtouch->interface);
 }
 
+static int usbtouch_suspend
+(struct usb_interface *intf, pm_message_t message)
+{
+	struct usbtouch_usb *usbtouch = usb_get_intfdata(intf);
+
+	usb_kill_urb(usbtouch->irq);
+
+	return 0;
+}
+
+static int usbtouch_resume(struct usb_interface *intf)
+{
+	struct usbtouch_usb *usbtouch = usb_get_intfdata(intf);
+	struct input_dev *input = usbtouch->input;
+	int result = 0;
+
+	mutex_lock(&input->mutex);
+	if (input->users || usbtouch->type->irq_always)
+		result = usb_submit_urb(usbtouch->irq, GFP_NOIO);
+	mutex_unlock(&input->mutex);
+
+	return result;
+}
+
+static int usbtouch_reset_resume(struct usb_interface *intf)
+{
+	struct usbtouch_usb *usbtouch = usb_get_intfdata(intf);
+	struct input_dev *input = usbtouch->input;
+	int err = 0;
+
+	/* reinit the device */
+	if (usbtouch->type->init) {
+		err = usbtouch->type->init(usbtouch);
+		if (err) {
+			dbg("%s - type->init() failed, err: %d",
+			    __func__, err);
+			return err;
+		}
+	}
+
+	/* restart IO if needed */
+	mutex_lock(&input->mutex);
+	if (input->users)
+		err = usb_submit_urb(usbtouch->irq, GFP_NOIO);
+	mutex_unlock(&input->mutex);
+
+	return err;
+}
 
 static void usbtouch_free_buffers(struct usb_device *udev,
 				  struct usbtouch_usb *usbtouch)
@@ -1411,12 +1490,21 @@ static int usbtouch_probe(struct usb_interface *intf,
 	usbtouch->irq->transfer_dma = usbtouch->data_dma;
 	usbtouch->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
 
-	/* device specific init */
+	/* device specific allocations */
+	if (type->alloc) {
+		err = type->alloc(usbtouch);
+		if (err) {
+			dbg("%s - type->alloc() failed, err: %d", __func__, err);
+			goto out_free_urb;
+		}
+	}
+
+	/* device specific initialisation*/
 	if (type->init) {
 		err = type->init(usbtouch);
 		if (err) {
 			dbg("%s - type->init() failed, err: %d", __func__, err);
-			goto out_free_urb;
+			goto out_do_exit;
 		}
 	}
 
@@ -1429,8 +1517,11 @@ static int usbtouch_probe(struct usb_interface *intf,
 	usb_set_intfdata(intf, usbtouch);
 
 	if (usbtouch->type->irq_always) {
+		/* this can't fail */
+		usb_autopm_get_interface(intf);
 		err = usb_submit_urb(usbtouch->irq, GFP_KERNEL);
 		if (err) {
+			usb_autopm_put_interface(intf);
 			err("%s - usb_submit_urb failed with result: %d",
 			    __func__, err);
 			goto out_unregister_input;
@@ -1481,7 +1572,11 @@ static struct usb_driver usbtouch_driver = {
 	.name		= "usbtouchscreen",
 	.probe		= usbtouch_probe,
 	.disconnect	= usbtouch_disconnect,
+	.suspend	= usbtouch_suspend,
+	.resume		= usbtouch_resume,
+	.reset_resume	= usbtouch_reset_resume,
 	.id_table	= usbtouch_devices,
+	.supports_autosuspend = 1,
 };
 
 static int __init usbtouch_init(void)