Initial Contribution

msm-2.6.38: tag AU_LINUX_ANDROID_GINGERBREAD.02.03.04.00.142

Signed-off-by: Bryan Huntsman <bryanh@codeaurora.org>
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index ce28bf6..9acebc0 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -321,6 +321,18 @@
 	help
 	  Say Y here if you want to support gpio based keys, wheels etc...
 
+config INPUT_ISA1200_FF_MEMLESS
+	tristate "ISA1200 haptic ff-memless support"
+	depends on I2C
+	select INPUT_FF_MEMLESS
+	help
+	  ISA1200 is a high performance enhanced haptic chip.
+	  Say Y here if you want to support ISA1200 connected via I2C,
+	  and select N if you are unsure.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called isa1200-ff-memless.
+
 config HP_SDC_RTC
 	tristate "HP SDC Real Time Clock"
 	depends on (GSC || HP300) && SERIO
@@ -505,4 +517,43 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called xen-kbdfront.
 
+config PMIC8058_PWRKEY
+        tristate "PMIC8058 power key support"
+        default n
+        depends on PMIC8058
+        help
+          Say Y here if you want support for the PMIC8058 power key.
+
+          To compile this driver as a module, choose M here: the
+          module will be called pmic8058-pwrkey.
+
+config PMIC8058_OTHC
+        tristate "Qualcomm PMIC8058 OTHC support"
+        default n
+        depends on PMIC8058
+        help
+          Say Y here if you want support PMIC8058 OTHC.
+
+          To compile this driver as a module, choose M here: the
+          module will be called pmic8058-othc.
+
+config INPUT_PMIC8058_VIBRA_MEMLESS
+	tristate "Qualcomm PM8058 vibrator support (ff-memless)"
+	depends on PMIC8058 && INPUT_FF_MEMLESS
+	default n
+	help
+	  This option enables device driver support for the vibrator
+	  on Qualcomm PM8058 chip. This driver supports ff-memless interface
+	  from input framework.
+
+	  To compile this driver as module, choose M here: the
+	  module will be called pmic8058-vib-memless.
+
+config BOSCH_BMA150
+        tristate "SMB380/BMA150 acceleration sensor support"
+        depends on I2C=y
+        help
+          If you say yes here you get support for Bosch Sensortec's
+          acceleration sensors SMB380/BMA150.
+
 endif
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index 014d45f..770eb96 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -33,6 +33,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_PMIC8XXX_PWRKEY)	+= pmic8xxx-pwrkey.o
 obj-$(CONFIG_INPUT_POWERMATE)		+= powermate.o
 obj-$(CONFIG_INPUT_PWM_BEEPER)		+= pwm-beeper.o
 obj-$(CONFIG_INPUT_PMIC8XXX_PWRKEY)	+= pmic8xxx-pwrkey.o
@@ -48,4 +49,8 @@
 obj-$(CONFIG_INPUT_WM831X_ON)		+= wm831x-on.o
 obj-$(CONFIG_INPUT_XEN_KBDDEV_FRONTEND)	+= xen-kbdfront.o
 obj-$(CONFIG_INPUT_YEALINK)		+= yealink.o
+obj-$(CONFIG_PMIC8058_PWRKEY)           += pmic8058-pwrkey.o
+obj-$(CONFIG_PMIC8058_OTHC)             += pmic8058-othc.o
+obj-$(CONFIG_INPUT_PMIC8058_VIBRA_MEMLESS) += pmic8058-vib-memless.o
+obj-$(CONFIG_BOSCH_BMA150)              += bma150.o
 
diff --git a/drivers/input/misc/bma150.c b/drivers/input/misc/bma150.c
new file mode 100644
index 0000000..8911c0b
--- /dev/null
+++ b/drivers/input/misc/bma150.c
@@ -0,0 +1,791 @@
+/*  Date: 2011/3/7 11:00:00
+ *  Revision: 2.11
+ */
+
+/*
+ * This software program is licensed subject to the GNU General Public License
+ * (GPL).Version 2,June 1991, available at http://www.fsf.org/copyleft/gpl.html
+
+ * (C) Copyright 2011 Bosch Sensortec GmbH
+ * All Rights Reserved
+ */
+
+
+/* file BMA150.c
+   brief This file contains all function implementations for the BMA150 in linux
+
+*/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+#include <linux/workqueue.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/bma150.h>
+
+#define SENSOR_NAME			"bma150"
+#define GRAVITY_EARTH		9806550
+#define ABSMIN_2G			(-GRAVITY_EARTH * 2)
+#define ABSMAX_2G			(GRAVITY_EARTH * 2)
+#define BMA150_MAX_DELAY	200
+#define BMA150_CHIP_ID		2
+#define BMA150_RANGE_SET	0
+#define BMA150_BW_SET		4
+
+
+
+#define BMA150_CHIP_ID_REG		0x00
+#define BMA150_X_AXIS_LSB_REG	0x02
+#define BMA150_X_AXIS_MSB_REG	0x03
+#define BMA150_Y_AXIS_LSB_REG	0x04
+#define BMA150_Y_AXIS_MSB_REG	0x05
+#define BMA150_Z_AXIS_LSB_REG	0x06
+#define BMA150_Z_AXIS_MSB_REG	0x07
+#define BMA150_STATUS_REG		0x09
+#define BMA150_CTRL_REG			0x0a
+#define BMA150_CONF1_REG		0x0b
+
+#define BMA150_CUSTOMER1_REG	0x12
+#define BMA150_CUSTOMER2_REG	0x13
+#define BMA150_RANGE_BWIDTH_REG	0x14
+#define BMA150_CONF2_REG		0x15
+
+#define BMA150_OFFS_GAIN_X_REG	0x16
+#define BMA150_OFFS_GAIN_Y_REG	0x17
+#define BMA150_OFFS_GAIN_Z_REG	0x18
+#define BMA150_OFFS_GAIN_T_REG	0x19
+#define BMA150_OFFSET_X_REG		0x1a
+#define BMA150_OFFSET_Y_REG		0x1b
+#define BMA150_OFFSET_Z_REG		0x1c
+#define BMA150_OFFSET_T_REG		0x1d
+
+#define BMA150_CHIP_ID__POS		0
+#define BMA150_CHIP_ID__MSK		0x07
+#define BMA150_CHIP_ID__LEN		3
+#define BMA150_CHIP_ID__REG		BMA150_CHIP_ID_REG
+
+/* DATA REGISTERS */
+
+#define BMA150_NEW_DATA_X__POS		0
+#define BMA150_NEW_DATA_X__LEN		1
+#define BMA150_NEW_DATA_X__MSK		0x01
+#define BMA150_NEW_DATA_X__REG		BMA150_X_AXIS_LSB_REG
+
+#define BMA150_ACC_X_LSB__POS		6
+#define BMA150_ACC_X_LSB__LEN		2
+#define BMA150_ACC_X_LSB__MSK		0xC0
+#define BMA150_ACC_X_LSB__REG		BMA150_X_AXIS_LSB_REG
+
+#define BMA150_ACC_X_MSB__POS		0
+#define BMA150_ACC_X_MSB__LEN		8
+#define BMA150_ACC_X_MSB__MSK		0xFF
+#define BMA150_ACC_X_MSB__REG		BMA150_X_AXIS_MSB_REG
+
+#define BMA150_ACC_Y_LSB__POS		6
+#define BMA150_ACC_Y_LSB__LEN		2
+#define BMA150_ACC_Y_LSB__MSK		0xC0
+#define BMA150_ACC_Y_LSB__REG		BMA150_Y_AXIS_LSB_REG
+
+#define BMA150_ACC_Y_MSB__POS		0
+#define BMA150_ACC_Y_MSB__LEN		8
+#define BMA150_ACC_Y_MSB__MSK		0xFF
+#define BMA150_ACC_Y_MSB__REG		BMA150_Y_AXIS_MSB_REG
+
+#define BMA150_ACC_Z_LSB__POS		6
+#define BMA150_ACC_Z_LSB__LEN		2
+#define BMA150_ACC_Z_LSB__MSK		0xC0
+#define BMA150_ACC_Z_LSB__REG		BMA150_Z_AXIS_LSB_REG
+
+#define BMA150_ACC_Z_MSB__POS		0
+#define BMA150_ACC_Z_MSB__LEN		8
+#define BMA150_ACC_Z_MSB__MSK		0xFF
+#define BMA150_ACC_Z_MSB__REG		BMA150_Z_AXIS_MSB_REG
+
+/* CONTROL BITS */
+
+#define BMA150_SLEEP__POS			0
+#define BMA150_SLEEP__LEN			1
+#define BMA150_SLEEP__MSK			0x01
+#define BMA150_SLEEP__REG			BMA150_CTRL_REG
+
+#define BMA150_SOFT_RESET__POS		1
+#define BMA150_SOFT_RESET__LEN		1
+#define BMA150_SOFT_RESET__MSK		0x02
+#define BMA150_SOFT_RESET__REG		BMA150_CTRL_REG
+
+#define BMA150_EE_W__POS			4
+#define BMA150_EE_W__LEN			1
+#define BMA150_EE_W__MSK			0x10
+#define BMA150_EE_W__REG			BMA150_CTRL_REG
+
+#define BMA150_UPDATE_IMAGE__POS	5
+#define BMA150_UPDATE_IMAGE__LEN	1
+#define BMA150_UPDATE_IMAGE__MSK	0x20
+#define BMA150_UPDATE_IMAGE__REG	BMA150_CTRL_REG
+
+#define BMA150_RESET_INT__POS		6
+#define BMA150_RESET_INT__LEN		1
+#define BMA150_RESET_INT__MSK		0x40
+#define BMA150_RESET_INT__REG		BMA150_CTRL_REG
+
+/* BANDWIDTH dependend definitions */
+
+#define BMA150_BANDWIDTH__POS				0
+#define BMA150_BANDWIDTH__LEN				3
+#define BMA150_BANDWIDTH__MSK				0x07
+#define BMA150_BANDWIDTH__REG				BMA150_RANGE_BWIDTH_REG
+
+/* RANGE */
+
+#define BMA150_RANGE__POS				3
+#define BMA150_RANGE__LEN				2
+#define BMA150_RANGE__MSK				0x18
+#define BMA150_RANGE__REG				BMA150_RANGE_BWIDTH_REG
+
+/* WAKE UP */
+
+#define BMA150_WAKE_UP__POS			0
+#define BMA150_WAKE_UP__LEN			1
+#define BMA150_WAKE_UP__MSK			0x01
+#define BMA150_WAKE_UP__REG			BMA150_CONF2_REG
+
+#define BMA150_WAKE_UP_PAUSE__POS		1
+#define BMA150_WAKE_UP_PAUSE__LEN		2
+#define BMA150_WAKE_UP_PAUSE__MSK		0x06
+#define BMA150_WAKE_UP_PAUSE__REG		BMA150_CONF2_REG
+
+#define BMA150_GET_BITSLICE(regvar, bitname)\
+	((regvar & bitname##__MSK) >> bitname##__POS)
+
+
+#define BMA150_SET_BITSLICE(regvar, bitname, val)\
+	((regvar & ~bitname##__MSK) | ((val<<bitname##__POS)&bitname##__MSK))
+
+/* range and bandwidth */
+
+#define BMA150_RANGE_2G			0
+#define BMA150_RANGE_4G			1
+#define BMA150_RANGE_8G			2
+
+#define BMA150_BW_25HZ		0
+#define BMA150_BW_50HZ		1
+#define BMA150_BW_100HZ		2
+#define BMA150_BW_190HZ		3
+#define BMA150_BW_375HZ		4
+#define BMA150_BW_750HZ		5
+#define BMA150_BW_1500HZ	6
+
+/* mode settings */
+
+#define BMA150_MODE_NORMAL      0
+#define BMA150_MODE_SLEEP       2
+#define BMA150_MODE_WAKE_UP     3
+
+struct bma150acc{
+	s16	x,
+		y,
+		z;
+} ;
+
+struct bma150_data {
+	struct i2c_client *bma150_client;
+	struct bma150_platform_data *platform_data;
+	int IRQ;
+	atomic_t delay;
+	unsigned char mode;
+	struct input_dev *input;
+	struct bma150acc value;
+	struct mutex value_mutex;
+	struct mutex mode_mutex;
+	struct delayed_work work;
+	struct work_struct irq_work;
+};
+
+static int bma150_smbus_read_byte(struct i2c_client *client,
+		unsigned char reg_addr, unsigned char *data)
+{
+	s32 dummy;
+	dummy = i2c_smbus_read_byte_data(client, reg_addr);
+	if (dummy < 0)
+		return -EPERM;
+	*data = dummy & 0x000000ff;
+
+	return 0;
+}
+
+static int bma150_smbus_write_byte(struct i2c_client *client,
+		unsigned char reg_addr, unsigned char *data)
+{
+	s32 dummy;
+	dummy = i2c_smbus_write_byte_data(client, reg_addr, *data);
+	if (dummy < 0)
+		return -EPERM;
+	return 0;
+}
+
+static int bma150_smbus_read_byte_block(struct i2c_client *client,
+		unsigned char reg_addr, unsigned char *data, unsigned char len)
+{
+	s32 dummy;
+	dummy = i2c_smbus_read_i2c_block_data(client, reg_addr, len, data);
+	if (dummy < 0)
+		return -EPERM;
+	return 0;
+}
+
+static int bma150_set_mode(struct i2c_client *client, unsigned char Mode)
+{
+	int comres = 0;
+	unsigned char data1 = 0, data2 = 0;
+	struct bma150_data *bma150 = i2c_get_clientdata(client);
+
+	if (client == NULL) {
+		comres = -1;
+	} else{
+		if (Mode < 4 && Mode != 1) {
+
+			comres = bma150_smbus_read_byte(client,
+						BMA150_WAKE_UP__REG, &data1);
+			data1 = BMA150_SET_BITSLICE(data1,
+						BMA150_WAKE_UP, Mode);
+			comres += bma150_smbus_read_byte(client,
+						BMA150_SLEEP__REG, &data2);
+			data2 = BMA150_SET_BITSLICE(data2,
+						BMA150_SLEEP, (Mode>>1));
+			comres += bma150_smbus_write_byte(client,
+						BMA150_WAKE_UP__REG, &data1);
+			comres += bma150_smbus_write_byte(client,
+						BMA150_SLEEP__REG, &data2);
+			mutex_lock(&bma150->mode_mutex);
+			bma150->mode = (unsigned char) Mode;
+			mutex_unlock(&bma150->mode_mutex);
+
+		} else{
+			comres = -1;
+		}
+	}
+
+	return comres;
+}
+
+
+static int bma150_set_range(struct i2c_client *client, unsigned char Range)
+{
+	int comres = 0;
+	unsigned char data = 0;
+
+	if (client == NULL) {
+		comres = -1;
+	} else{
+		if (Range < 3) {
+
+			comres = bma150_smbus_read_byte(client,
+						BMA150_RANGE__REG, &data);
+			data = BMA150_SET_BITSLICE(data, BMA150_RANGE, Range);
+			comres += bma150_smbus_write_byte(client,
+						BMA150_RANGE__REG, &data);
+
+		} else{
+			comres = -1;
+		}
+	}
+
+	return comres;
+}
+
+static int bma150_get_range(struct i2c_client *client, unsigned char *Range)
+{
+	int comres = 0;
+	unsigned char data;
+
+	if (client == NULL) {
+		comres = -1;
+	} else{
+		comres = bma150_smbus_read_byte(client,
+						BMA150_RANGE__REG, &data);
+
+		*Range = BMA150_GET_BITSLICE(data, BMA150_RANGE);
+
+	}
+
+	return comres;
+}
+
+
+
+static int bma150_set_bandwidth(struct i2c_client *client, unsigned char BW)
+{
+	int comres = 0;
+	unsigned char data = 0;
+
+	if (client == NULL) {
+		comres = -1;
+	} else{
+		if (BW < 8) {
+			comres = bma150_smbus_read_byte(client,
+						BMA150_BANDWIDTH__REG, &data);
+			data = BMA150_SET_BITSLICE(data, BMA150_BANDWIDTH, BW);
+			comres += bma150_smbus_write_byte(client,
+						BMA150_BANDWIDTH__REG, &data);
+
+		} else{
+			comres = -1;
+		}
+	}
+
+	return comres;
+}
+
+static int bma150_get_bandwidth(struct i2c_client *client, unsigned char *BW)
+{
+	int comres = 0;
+	unsigned char data;
+
+	if (client == NULL) {
+		comres = -1;
+	} else{
+
+
+		comres = bma150_smbus_read_byte(client,
+						BMA150_BANDWIDTH__REG, &data);
+
+		*BW = BMA150_GET_BITSLICE(data, BMA150_BANDWIDTH);
+
+
+	}
+
+	return comres;
+}
+
+static int bma150_read_accel_xyz(struct i2c_client *client,
+		struct bma150acc *acc)
+{
+	int comres;
+	unsigned char data[6];
+	if (client == NULL) {
+		comres = -1;
+	} else{
+
+
+		comres = bma150_smbus_read_byte_block(client,
+					BMA150_ACC_X_LSB__REG, &data[0], 6);
+
+		acc->x = BMA150_GET_BITSLICE(data[0], BMA150_ACC_X_LSB) |
+			(BMA150_GET_BITSLICE(data[1], BMA150_ACC_X_MSB)<<
+							BMA150_ACC_X_LSB__LEN);
+		acc->x = acc->x << (sizeof(short)*8-(BMA150_ACC_X_LSB__LEN+
+							BMA150_ACC_X_MSB__LEN));
+		acc->x = acc->x >> (sizeof(short)*8-(BMA150_ACC_X_LSB__LEN+
+							BMA150_ACC_X_MSB__LEN));
+
+		acc->y = BMA150_GET_BITSLICE(data[2], BMA150_ACC_Y_LSB) |
+			(BMA150_GET_BITSLICE(data[3], BMA150_ACC_Y_MSB)<<
+							BMA150_ACC_Y_LSB__LEN);
+		acc->y = acc->y << (sizeof(short)*8-(BMA150_ACC_Y_LSB__LEN +
+							BMA150_ACC_Y_MSB__LEN));
+		acc->y = acc->y >> (sizeof(short)*8-(BMA150_ACC_Y_LSB__LEN +
+							BMA150_ACC_Y_MSB__LEN));
+
+
+		acc->z = BMA150_GET_BITSLICE(data[4], BMA150_ACC_Z_LSB);
+		acc->z |= (BMA150_GET_BITSLICE(data[5], BMA150_ACC_Z_MSB)<<
+							BMA150_ACC_Z_LSB__LEN);
+		acc->z = acc->z << (sizeof(short)*8-(BMA150_ACC_Z_LSB__LEN+
+							BMA150_ACC_Z_MSB__LEN));
+		acc->z = acc->z >> (sizeof(short)*8-(BMA150_ACC_Z_LSB__LEN+
+							BMA150_ACC_Z_MSB__LEN));
+
+	}
+
+	return comres;
+}
+
+static void bma150_work_func(struct work_struct *work)
+{
+	struct bma150_data *bma150 = container_of((struct delayed_work *)work,
+			struct bma150_data, work);
+	static struct bma150acc acc;
+	unsigned long delay = msecs_to_jiffies(atomic_read(&bma150->delay));
+
+
+
+	bma150_read_accel_xyz(bma150->bma150_client, &acc);
+	input_report_abs(bma150->input, ABS_X, acc.x);
+	input_report_abs(bma150->input, ABS_Y, acc.y);
+	input_report_abs(bma150->input, ABS_Z, acc.z);
+	input_sync(bma150->input);
+	mutex_lock(&bma150->value_mutex);
+	bma150->value = acc;
+	mutex_unlock(&bma150->value_mutex);
+	schedule_delayed_work(&bma150->work, delay);
+}
+
+static ssize_t bma150_mode_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	unsigned char data;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct bma150_data *bma150 = i2c_get_clientdata(client);
+
+	mutex_lock(&bma150->mode_mutex);
+	data = bma150->mode;
+	mutex_unlock(&bma150->mode_mutex);
+
+	return sprintf(buf, "%d\n", data);
+}
+
+static ssize_t bma150_mode_store(struct device *dev,
+		struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	unsigned long data;
+	int error;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct bma150_data *bma150 = i2c_get_clientdata(client);
+
+	error = strict_strtoul(buf, 10, &data);
+	if (error)
+		return error;
+	if (bma150_set_mode(bma150->bma150_client, (unsigned char) data) < 0)
+		return -EINVAL;
+
+
+	return count;
+}
+static ssize_t bma150_range_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	unsigned char data;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct bma150_data *bma150 = i2c_get_clientdata(client);
+
+	if (bma150_get_range(bma150->bma150_client, &data) < 0)
+		return sprintf(buf, "Read error\n");
+
+	return sprintf(buf, "%d\n", data);
+}
+
+static ssize_t bma150_range_store(struct device *dev,
+		struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	unsigned long data;
+	int error;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct bma150_data *bma150 = i2c_get_clientdata(client);
+
+	error = strict_strtoul(buf, 10, &data);
+	if (error)
+		return error;
+	if (bma150_set_range(bma150->bma150_client, (unsigned char) data) < 0)
+		return -EINVAL;
+
+	return count;
+}
+
+static ssize_t bma150_bandwidth_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	unsigned char data;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct bma150_data *bma150 = i2c_get_clientdata(client);
+
+	if (bma150_get_bandwidth(bma150->bma150_client, &data) < 0)
+		return sprintf(buf, "Read error\n");
+
+	return sprintf(buf, "%d\n", data);
+
+}
+
+static ssize_t bma150_bandwidth_store(struct device *dev,
+		struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	unsigned long data;
+	int error;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct bma150_data *bma150 = i2c_get_clientdata(client);
+
+	error = strict_strtoul(buf, 10, &data);
+	if (error)
+		return error;
+	if (bma150_set_bandwidth(bma150->bma150_client,
+				(unsigned char) data) < 0)
+		return -EINVAL;
+
+	return count;
+}
+
+static ssize_t bma150_value_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct input_dev *input = to_input_dev(dev);
+	struct bma150_data *bma150 = input_get_drvdata(input);
+	struct bma150acc acc_value;
+
+	mutex_lock(&bma150->value_mutex);
+	acc_value = bma150->value;
+	mutex_unlock(&bma150->value_mutex);
+
+	return sprintf(buf, "%d %d %d\n", acc_value.x, acc_value.y,
+			acc_value.z);
+}
+
+
+
+static ssize_t bma150_delay_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct bma150_data *bma150 = i2c_get_clientdata(client);
+
+	return sprintf(buf, "%d\n", atomic_read(&bma150->delay));
+
+}
+
+static ssize_t bma150_delay_store(struct device *dev,
+		struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	unsigned long data;
+	int error;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct bma150_data *bma150 = i2c_get_clientdata(client);
+
+	error = strict_strtoul(buf, 10, &data);
+	if (error)
+		return error;
+	if (data > BMA150_MAX_DELAY)
+		data = BMA150_MAX_DELAY;
+	atomic_set(&bma150->delay, (unsigned int) data);
+
+	return count;
+}
+
+static DEVICE_ATTR(range, S_IRUGO|S_IWUSR|S_IWGRP,
+		bma150_range_show, bma150_range_store);
+static DEVICE_ATTR(bandwidth, S_IRUGO|S_IWUSR|S_IWGRP,
+		bma150_bandwidth_show, bma150_bandwidth_store);
+static DEVICE_ATTR(mode, S_IRUGO|S_IWUSR|S_IWGRP,
+		bma150_mode_show, bma150_mode_store);
+static DEVICE_ATTR(value, S_IRUGO|S_IWUSR|S_IWGRP,
+		bma150_value_show, NULL);
+static DEVICE_ATTR(delay, S_IRUGO|S_IWUSR|S_IWGRP|S_IWOTH,
+		bma150_delay_show, bma150_delay_store);
+
+static struct attribute *bma150_attributes[] = {
+	&dev_attr_range.attr,
+	&dev_attr_bandwidth.attr,
+	&dev_attr_mode.attr,
+	&dev_attr_value.attr,
+	&dev_attr_delay.attr,
+	NULL
+};
+
+static struct attribute_group bma150_attribute_group = {
+	.attrs = bma150_attributes
+};
+
+static int bma150_detect(struct i2c_client *client,
+			  struct i2c_board_info *info)
+{
+	struct i2c_adapter *adapter = client->adapter;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_I2C))
+		return -ENODEV;
+
+	strlcpy(info->type, SENSOR_NAME, I2C_NAME_SIZE);
+
+	return 0;
+}
+
+static int bma150_input_init(struct bma150_data *bma150)
+{
+	struct input_dev *dev;
+	int err;
+
+	dev = input_allocate_device();
+	if (!dev)
+		return -ENOMEM;
+	dev->name = SENSOR_NAME;
+	dev->id.bustype = BUS_I2C;
+
+	input_set_capability(dev, EV_ABS, ABS_MISC);
+	input_set_abs_params(dev, ABS_X, ABSMIN_2G, ABSMAX_2G, 0, 0);
+	input_set_abs_params(dev, ABS_Y, ABSMIN_2G, ABSMAX_2G, 0, 0);
+	input_set_abs_params(dev, ABS_Z, ABSMIN_2G, ABSMAX_2G, 0, 0);
+	input_set_drvdata(dev, bma150);
+
+	err = input_register_device(dev);
+	if (err < 0) {
+		input_free_device(dev);
+		return err;
+	}
+	bma150->input = dev;
+
+	return 0;
+}
+
+static void bma150_input_delete(struct bma150_data *bma150)
+{
+	struct input_dev *dev = bma150->input;
+
+	input_unregister_device(dev);
+	input_free_device(dev);
+}
+
+static int bma150_probe(struct i2c_client *client,
+		const struct i2c_device_id *id)
+{
+	int err = 0;
+	int tempvalue;
+	struct bma150_data *data;
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		printk(KERN_INFO "i2c_check_functionality error\n");
+		goto exit;
+	}
+	data = kzalloc(sizeof(struct bma150_data), GFP_KERNEL);
+	if (!data) {
+		err = -ENOMEM;
+		goto exit;
+	}
+
+	i2c_set_clientdata(client, data);
+	data->platform_data = client->dev.platform_data;
+
+	if (data->platform_data->power_on)
+		data->platform_data->power_on();
+	else
+		printk(KERN_ERR "power_on function not defined!!\n");
+
+	tempvalue = 0;
+	tempvalue = i2c_smbus_read_word_data(client, BMA150_CHIP_ID_REG);
+
+	if ((tempvalue&0x00FF) == BMA150_CHIP_ID) {
+		printk(KERN_INFO "Bosch Sensortec Device detected!\n" \
+				"BMA150 registered I2C driver!\n");
+	} else{
+		printk(KERN_INFO "Bosch Sensortec Device not found" \
+			"i2c error %d\n", tempvalue);
+		err = -1;
+		goto kfree_exit;
+	}
+	i2c_set_clientdata(client, data);
+	data->bma150_client = client;
+	mutex_init(&data->value_mutex);
+	mutex_init(&data->mode_mutex);
+	bma150_set_bandwidth(client, BMA150_BW_SET);
+	bma150_set_range(client, BMA150_RANGE_SET);
+
+
+	INIT_DELAYED_WORK(&data->work, bma150_work_func);
+	atomic_set(&data->delay, BMA150_MAX_DELAY);
+	err = bma150_input_init(data);
+	if (err < 0)
+		goto kfree_exit;
+
+	err = sysfs_create_group(&data->input->dev.kobj,
+			&bma150_attribute_group);
+	if (err < 0)
+		goto error_sysfs;
+
+	schedule_delayed_work(&data->work,
+			msecs_to_jiffies(atomic_read(&data->delay)));
+
+	return 0;
+
+error_sysfs:
+	bma150_input_delete(data);
+
+kfree_exit:
+	kfree(data);
+exit:
+	return err;
+}
+
+static int bma150_suspend(struct i2c_client *client, pm_message_t mesg)
+{
+	struct bma150_data *data = i2c_get_clientdata(client);
+
+	cancel_delayed_work_sync(&data->work);
+
+	bma150_set_mode(client, BMA150_MODE_SLEEP);
+
+	if ((data->platform_data) && (data->platform_data->power_off))
+		data->platform_data->power_off();
+
+	return 0;
+}
+
+static int bma150_resume(struct i2c_client *client)
+{
+	struct bma150_data *data = i2c_get_clientdata(client);
+
+	if ((data->platform_data) && (data->platform_data->power_on))
+		data->platform_data->power_on();
+
+	bma150_set_mode(client, BMA150_MODE_NORMAL);
+
+	schedule_delayed_work(&data->work,
+		msecs_to_jiffies(atomic_read(&data->delay)));
+
+	return 0;
+}
+
+static int bma150_remove(struct i2c_client *client)
+{
+	struct bma150_data *data = i2c_get_clientdata(client);
+
+	if (data->platform_data->power_off)
+		data->platform_data->power_off();
+	else
+		printk(KERN_ERR "power_off function not defined!!\n");
+
+	sysfs_remove_group(&data->input->dev.kobj, &bma150_attribute_group);
+	bma150_input_delete(data);
+	free_irq(data->IRQ, data);
+	kfree(data);
+
+	return 0;
+}
+
+static const struct i2c_device_id bma150_id[] = {
+	{ SENSOR_NAME, 0 },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(i2c, bma150_id);
+
+static struct i2c_driver bma150_driver = {
+	.driver = {
+		.owner	= THIS_MODULE,
+		.name	= SENSOR_NAME,
+	},
+	.class          = I2C_CLASS_HWMON,
+	.id_table	= bma150_id,
+	.probe		= bma150_probe,
+	.remove		= bma150_remove,
+	.detect		= bma150_detect,
+	.suspend    = bma150_suspend,
+	.resume     = bma150_resume,
+};
+
+static int __init BMA150_init(void)
+{
+	return i2c_add_driver(&bma150_driver);
+}
+
+static void __exit BMA150_exit(void)
+{
+	i2c_del_driver(&bma150_driver);
+}
+
+MODULE_DESCRIPTION("BMA150 driver");
+
+module_init(BMA150_init);
+module_exit(BMA150_exit);
+
diff --git a/drivers/input/misc/gpio_matrix.c b/drivers/input/misc/gpio_matrix.c
index eaa9e89..56e91fd 100644
--- a/drivers/input/misc/gpio_matrix.c
+++ b/drivers/input/misc/gpio_matrix.c
@@ -181,12 +181,14 @@
 			gpio_set_value(gpio, polarity);
 		else
 			gpio_direction_output(gpio, polarity);
-		hrtimer_start(timer, mi->settle_time, HRTIMER_MODE_REL);
+		hrtimer_start(timer, timespec_to_ktime(mi->settle_time),
+			HRTIMER_MODE_REL);
 		return HRTIMER_NORESTART;
 	}
 	if (gpio_keypad_flags & GPIOKPF_DEBOUNCE) {
 		if (kp->key_state_changed) {
-			hrtimer_start(&kp->timer, mi->debounce_delay,
+			hrtimer_start(&kp->timer,
+				timespec_to_ktime(mi->debounce_delay),
 				      HRTIMER_MODE_REL);
 			return HRTIMER_NORESTART;
 		}
@@ -202,7 +204,8 @@
 		report_sync(kp);
 	}
 	if (!kp->use_irq || kp->some_keys_pressed) {
-		hrtimer_start(timer, mi->poll_time, HRTIMER_MODE_REL);
+		hrtimer_start(timer, timespec_to_ktime(mi->poll_time),
+			HRTIMER_MODE_REL);
 		return HRTIMER_NORESTART;
 	}
 
diff --git a/drivers/input/misc/isa1200-ff-memless.c b/drivers/input/misc/isa1200-ff-memless.c
new file mode 100644
index 0000000..f4e2c35
--- /dev/null
+++ b/drivers/input/misc/isa1200-ff-memless.c
@@ -0,0 +1,449 @@
+/*
+ * Copyright (C) 2009 Samsung Electronics
+ * Kyungmin Park <kyungmin.park@samsung.com>
+ *
+ * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only 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.
+ *
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/workqueue.h>
+#include <linux/delay.h>
+#include <linux/pwm.h>
+#include <linux/input.h>
+#include <linux/slab.h>
+#include <linux/pm.h>
+#include <linux/i2c/isa1200.h>
+
+#define ISA1200_HCTRL0			0x30
+#define HCTRL0_MODE_CTRL_BIT		(3)
+#define HCTRL0_OVERDRIVE_HIGH_BIT	(5)
+#define HCTRL0_OVERDRIVE_EN_BIT		(6)
+#define HCTRL0_HAP_EN			(7)
+#define HCTRL0_RESET			0x01
+#define HCTRL1_RESET			0x4B
+
+#define ISA1200_HCTRL1			0x31
+#define HCTRL1_SMART_ENABLE_BIT		(3)
+#define HCTRL1_ERM_BIT			(5)
+#define HCTRL1_EXT_CLK_ENABLE_BIT	(7)
+
+#define ISA1200_HCTRL5			0x35
+#define HCTRL5_VIB_STRT			0xD5
+#define HCTRL5_VIB_STOP			0x6B
+
+#define DIVIDER_128			(128)
+#define DIVIDER_1024			(1024)
+#define DIVIDE_SHIFTER_128		(7)
+
+#define FREQ_22400			(22400)
+#define FREQ_172600			(172600)
+
+#define POR_DELAY_USEC			250
+
+struct isa1200_chip {
+	const struct isa1200_platform_data *pdata;
+	struct i2c_client *client;
+	struct input_dev *input_device;
+	struct pwm_device *pwm;
+	unsigned int period_ns;
+	unsigned int state;
+	struct work_struct work;
+};
+
+static void isa1200_vib_set(struct isa1200_chip *haptic, int enable)
+{
+	int rc;
+
+	if (enable) {
+		if (haptic->pdata->mode_ctrl == PWM_INPUT_MODE) {
+			int period_us = haptic->period_ns / NSEC_PER_USEC;
+			rc = pwm_config(haptic->pwm,
+				(period_us * haptic->pdata->duty) / 100,
+				period_us);
+			if (rc < 0)
+				pr_err("pwm_config fail\n");
+			rc = pwm_enable(haptic->pwm);
+			if (rc < 0)
+				pr_err("pwm_enable fail\n");
+		} else if (haptic->pdata->mode_ctrl == PWM_GEN_MODE) {
+			rc = i2c_smbus_write_byte_data(haptic->client,
+						ISA1200_HCTRL5,
+						HCTRL5_VIB_STRT);
+			if (rc < 0)
+				pr_err("start vibration fail\n");
+		}
+	} else {
+		if (haptic->pdata->mode_ctrl == PWM_INPUT_MODE)
+			pwm_disable(haptic->pwm);
+		else if (haptic->pdata->mode_ctrl == PWM_GEN_MODE) {
+			rc = i2c_smbus_write_byte_data(haptic->client,
+						ISA1200_HCTRL5,
+						HCTRL5_VIB_STOP);
+			if (rc < 0)
+				pr_err("stop vibration fail\n");
+		}
+	}
+}
+
+static int isa1200_setup(struct i2c_client *client)
+{
+	struct isa1200_chip *haptic = i2c_get_clientdata(client);
+	int value, temp, rc;
+
+	gpio_set_value_cansleep(haptic->pdata->hap_en_gpio, 0);
+	udelay(POR_DELAY_USEC);
+	gpio_set_value_cansleep(haptic->pdata->hap_en_gpio, 1);
+
+	value =	(haptic->pdata->smart_en << HCTRL1_SMART_ENABLE_BIT) |
+		(haptic->pdata->is_erm << HCTRL1_ERM_BIT) |
+		(haptic->pdata->ext_clk_en << HCTRL1_EXT_CLK_ENABLE_BIT);
+
+	rc = i2c_smbus_write_byte_data(client, ISA1200_HCTRL1, value);
+	if (rc < 0) {
+		pr_err("i2c write failure\n");
+		return rc;
+	}
+
+	if (haptic->pdata->mode_ctrl == PWM_GEN_MODE) {
+		temp = haptic->pdata->pwm_fd.pwm_div;
+		if (temp < DIVIDER_128 || temp > DIVIDER_1024 ||
+					temp % DIVIDER_128) {
+			pr_err("Invalid divider\n");
+			rc = -EINVAL;
+			goto reset_hctrl1;
+		}
+		value = ((temp >> DIVIDE_SHIFTER_128) - 1);
+	} else if (haptic->pdata->mode_ctrl == PWM_INPUT_MODE) {
+		temp = haptic->pdata->pwm_fd.pwm_freq;
+		if (temp < FREQ_22400 || temp > FREQ_172600 ||
+					temp % FREQ_22400) {
+			pr_err("Invalid frequency\n");
+			rc = -EINVAL;
+			goto reset_hctrl1;
+		}
+		value = ((temp / FREQ_22400) - 1);
+		haptic->period_ns = NSEC_PER_SEC / temp;
+	}
+	value |= (haptic->pdata->mode_ctrl << HCTRL0_MODE_CTRL_BIT) |
+		(haptic->pdata->overdrive_high << HCTRL0_OVERDRIVE_HIGH_BIT) |
+		(haptic->pdata->overdrive_en << HCTRL0_OVERDRIVE_EN_BIT) |
+		(haptic->pdata->chip_en << HCTRL0_HAP_EN);
+
+	rc = i2c_smbus_write_byte_data(client, ISA1200_HCTRL0, value);
+	if (rc < 0) {
+		pr_err("i2c write failure\n");
+		goto reset_hctrl1;
+	}
+
+	return 0;
+
+reset_hctrl1:
+	i2c_smbus_write_byte_data(client, ISA1200_HCTRL1,
+				HCTRL1_RESET);
+	return rc;
+}
+
+static void isa1200_worker(struct work_struct *work)
+{
+	struct isa1200_chip *haptic;
+
+	haptic = container_of(work, struct isa1200_chip, work);
+	isa1200_vib_set(haptic, !!haptic->state);
+}
+
+static int isa1200_play_effect(struct input_dev *dev, void *data,
+				struct ff_effect *effect)
+{
+	struct isa1200_chip *haptic = input_get_drvdata(dev);
+
+	/* support basic vibration */
+	haptic->state = effect->u.rumble.strong_magnitude >> 8;
+	if (!haptic->state)
+		haptic->state = effect->u.rumble.weak_magnitude >> 9;
+
+	schedule_work(&haptic->work);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int isa1200_suspend(struct device *dev)
+{
+	struct isa1200_chip *haptic = dev_get_drvdata(dev);
+	int rc;
+
+	cancel_work_sync(&haptic->work);
+	/* turn-off current vibration */
+	isa1200_vib_set(haptic, 0);
+
+	if (haptic->pdata->power_on) {
+		rc = haptic->pdata->power_on(0);
+		if (rc) {
+			pr_err("power-down failed\n");
+			return rc;
+		}
+	}
+
+	return 0;
+}
+
+static int isa1200_resume(struct device *dev)
+{
+	struct isa1200_chip *haptic = dev_get_drvdata(dev);
+	int rc;
+
+	if (haptic->pdata->power_on) {
+		rc = haptic->pdata->power_on(1);
+		if (rc) {
+			pr_err("power-up failed\n");
+			return rc;
+		}
+	}
+
+	isa1200_setup(haptic->client);
+	return 0;
+}
+#else
+#define isa1200_suspend		NULL
+#define isa1200_resume		NULL
+#endif
+
+static int isa1200_open(struct input_dev *dev)
+{
+	struct isa1200_chip *haptic = input_get_drvdata(dev);
+	int rc;
+
+	/* device setup */
+	if (haptic->pdata->dev_setup) {
+		rc = haptic->pdata->dev_setup(true);
+		if (rc < 0) {
+			pr_err("setup failed!\n");
+			return rc;
+		}
+	}
+
+	/* power on */
+	if (haptic->pdata->power_on) {
+		rc = haptic->pdata->power_on(true);
+		if (rc < 0) {
+			pr_err("power failed\n");
+			goto err_setup;
+		}
+	}
+
+	/* request gpio */
+	rc = gpio_is_valid(haptic->pdata->hap_en_gpio);
+	if (rc) {
+		rc = gpio_request(haptic->pdata->hap_en_gpio, "haptic_gpio");
+		if (rc) {
+			pr_err("gpio %d request failed\n",
+					haptic->pdata->hap_en_gpio);
+			goto err_power_on;
+		}
+	} else {
+		pr_err("Invalid gpio %d\n",
+					haptic->pdata->hap_en_gpio);
+		goto err_power_on;
+	}
+
+	rc = gpio_direction_output(haptic->pdata->hap_en_gpio, 0);
+	if (rc) {
+		pr_err("gpio %d set direction failed\n",
+					haptic->pdata->hap_en_gpio);
+		goto err_gpio_free;
+	}
+
+	/* setup registers */
+	rc = isa1200_setup(haptic->client);
+	if (rc < 0) {
+		pr_err("setup fail %d\n", rc);
+		goto err_gpio_free;
+	}
+
+	if (haptic->pdata->mode_ctrl == PWM_INPUT_MODE) {
+		haptic->pwm = pwm_request(haptic->pdata->pwm_ch_id,
+				haptic->client->driver->id_table->name);
+		if (IS_ERR(haptic->pwm)) {
+			pr_err("pwm request failed\n");
+			rc = PTR_ERR(haptic->pwm);
+			goto err_reset_hctrl0;
+		}
+	}
+
+	/* init workqeueue */
+	INIT_WORK(&haptic->work, isa1200_worker);
+	return 0;
+
+err_reset_hctrl0:
+	i2c_smbus_write_byte_data(haptic->client, ISA1200_HCTRL0,
+					HCTRL0_RESET);
+err_gpio_free:
+	gpio_free(haptic->pdata->hap_en_gpio);
+err_power_on:
+	if (haptic->pdata->power_on)
+		haptic->pdata->power_on(0);
+err_setup:
+	if (haptic->pdata->dev_setup)
+		haptic->pdata->dev_setup(false);
+
+	return rc;
+}
+
+static void isa1200_close(struct input_dev *dev)
+{
+	struct isa1200_chip *haptic = input_get_drvdata(dev);
+
+	/* turn-off current vibration */
+	isa1200_vib_set(haptic, 0);
+
+	if (haptic->pdata->mode_ctrl == PWM_INPUT_MODE)
+		pwm_free(haptic->pwm);
+
+	gpio_free(haptic->pdata->hap_en_gpio);
+
+	/* reset hardware registers */
+	i2c_smbus_write_byte_data(haptic->client, ISA1200_HCTRL0,
+				HCTRL0_RESET);
+	i2c_smbus_write_byte_data(haptic->client, ISA1200_HCTRL1,
+				HCTRL1_RESET);
+
+	if (haptic->pdata->dev_setup)
+		haptic->pdata->dev_setup(false);
+
+	/* power-off the chip */
+	if (haptic->pdata->power_on)
+		haptic->pdata->power_on(0);
+}
+
+static int __devinit isa1200_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	struct isa1200_chip *haptic;
+	int rc;
+
+	if (!i2c_check_functionality(client->adapter,
+			I2C_FUNC_SMBUS_BYTE_DATA)) {
+		pr_err("i2c is not supported\n");
+		return -EIO;
+	}
+
+	if (!client->dev.platform_data) {
+		pr_err("pdata is not avaiable\n");
+		return -EINVAL;
+	}
+
+	haptic = kzalloc(sizeof(struct isa1200_chip), GFP_KERNEL);
+	if (!haptic) {
+		pr_err("no memory\n");
+		return -ENOMEM;
+	}
+
+	haptic->pdata = client->dev.platform_data;
+	haptic->client = client;
+
+	i2c_set_clientdata(client, haptic);
+
+	haptic->input_device = input_allocate_device();
+	if (!haptic->input_device) {
+		pr_err("input device alloc failed\n");
+		rc = -ENOMEM;
+		goto err_mem_alloc;
+	}
+
+	input_set_drvdata(haptic->input_device, haptic);
+	haptic->input_device->name = haptic->pdata->name ? :
+					"isa1200-ff-memless";
+
+	haptic->input_device->dev.parent = &client->dev;
+
+	input_set_capability(haptic->input_device, EV_FF, FF_RUMBLE);
+
+	haptic->input_device->open = isa1200_open;
+	haptic->input_device->close = isa1200_close;
+
+	rc = input_ff_create_memless(haptic->input_device, NULL,
+					isa1200_play_effect);
+	if (rc < 0) {
+		pr_err("unable to register with ff\n");
+		goto err_free_dev;
+	}
+
+	rc = input_register_device(haptic->input_device);
+	if (rc < 0) {
+		pr_err("unable to register input device\n");
+		goto err_ff_destroy;
+	}
+
+	return 0;
+
+err_ff_destroy:
+	input_ff_destroy(haptic->input_device);
+err_free_dev:
+	input_free_device(haptic->input_device);
+err_mem_alloc:
+	kfree(haptic);
+	return rc;
+}
+
+static int __devexit isa1200_remove(struct i2c_client *client)
+{
+	struct isa1200_chip *haptic = i2c_get_clientdata(client);
+
+	input_unregister_device(haptic->input_device);
+	kfree(haptic);
+
+	return 0;
+}
+
+static const struct i2c_device_id isa1200_id_table[] = {
+	{"isa1200_1", 0},
+	{ },
+};
+MODULE_DEVICE_TABLE(i2c, isa1200_id_table);
+
+static const struct dev_pm_ops isa1200_pm_ops = {
+	.suspend = isa1200_suspend,
+	.resume = isa1200_resume,
+};
+
+static struct i2c_driver isa1200_driver = {
+	.driver = {
+		.name = "isa1200-ff-memless",
+		.owner = THIS_MODULE,
+		.pm = &isa1200_pm_ops,
+	},
+	.probe = isa1200_probe,
+	.remove = __devexit_p(isa1200_remove),
+	.id_table = isa1200_id_table,
+};
+
+static int __init isa1200_init(void)
+{
+	return i2c_add_driver(&isa1200_driver);
+}
+module_init(isa1200_init);
+
+static void __exit isa1200_exit(void)
+{
+	i2c_del_driver(&isa1200_driver);
+}
+module_exit(isa1200_exit);
+
+MODULE_DESCRIPTION("isa1200 based vibrator chip driver");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Kyungmin Park <kyungmin.park@samsung.com>");
diff --git a/drivers/input/misc/pmic8058-othc.c b/drivers/input/misc/pmic8058-othc.c
new file mode 100644
index 0000000..c6be119
--- /dev/null
+++ b/drivers/input/misc/pmic8058-othc.c
@@ -0,0 +1,1199 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only 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.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/switch.h>
+#include <linux/pm.h>
+#include <linux/slab.h>
+#include <linux/pm_runtime.h>
+#include <linux/hrtimer.h>
+#include <linux/delay.h>
+#include <linux/regulator/consumer.h>
+
+#include <linux/mfd/pmic8058.h>
+#include <linux/pmic8058-othc.h>
+#include <linux/msm_adc.h>
+
+#define PM8058_OTHC_LOW_CURR_MASK	0xF0
+#define PM8058_OTHC_HIGH_CURR_MASK	0x0F
+#define PM8058_OTHC_EN_SIG_MASK		0x3F
+#define PM8058_OTHC_HYST_PREDIV_MASK	0xC7
+#define PM8058_OTHC_CLK_PREDIV_MASK	0xF8
+#define PM8058_OTHC_HYST_CLK_MASK	0x0F
+#define PM8058_OTHC_PERIOD_CLK_MASK	0xF0
+
+#define PM8058_OTHC_LOW_CURR_SHIFT	0x4
+#define PM8058_OTHC_EN_SIG_SHIFT	0x6
+#define PM8058_OTHC_HYST_PREDIV_SHIFT	0x3
+#define PM8058_OTHC_HYST_CLK_SHIFT	0x4
+
+#define OTHC_GPIO_MAX_LEN		25
+
+struct pm8058_othc {
+	bool othc_sw_state;
+	bool switch_reject;
+	bool othc_support_n_switch;
+	bool accessory_support;
+	bool accessories_adc_support;
+	int othc_base;
+	int othc_irq_sw;
+	int othc_irq_ir;
+	int othc_ir_state;
+	int num_accessories;
+	int curr_accessory_code;
+	int curr_accessory;
+	int video_out_gpio;
+	u32 sw_key_code;
+	u32 accessories_adc_channel;
+	int ir_gpio;
+	unsigned long switch_debounce_ms;
+	unsigned long detection_delay_ms;
+	void *adc_handle;
+	void *accessory_adc_handle;
+	spinlock_t lock;
+	struct regulator *othc_vreg;
+	struct input_dev *othc_ipd;
+	struct switch_dev othc_sdev;
+	struct pmic8058_othc_config_pdata *othc_pdata;
+	struct othc_accessory_info *accessory_info;
+	struct hrtimer timer;
+	struct othc_n_switch_config *switch_config;
+	struct pm8058_chip *pm_chip;
+	struct work_struct switch_work;
+	struct delayed_work detect_work;
+	struct delayed_work hs_work;
+};
+
+static struct pm8058_othc *config[OTHC_MICBIAS_MAX];
+
+static void hs_worker(struct work_struct *work)
+{
+	int rc;
+	struct pm8058_othc *dd =
+		container_of(work, struct pm8058_othc, hs_work.work);
+
+	rc = gpio_get_value_cansleep(dd->ir_gpio);
+	if (rc < 0) {
+		pr_err("Unable to read IR GPIO\n");
+		enable_irq(dd->othc_irq_ir);
+		return;
+	}
+
+	dd->othc_ir_state = !rc;
+	schedule_delayed_work(&dd->detect_work,
+				msecs_to_jiffies(dd->detection_delay_ms));
+}
+
+static irqreturn_t ir_gpio_irq(int irq, void *dev_id)
+{
+	unsigned long flags;
+	struct pm8058_othc *dd = dev_id;
+
+	spin_lock_irqsave(&dd->lock, flags);
+	/* Enable the switch reject flag */
+	dd->switch_reject = true;
+	spin_unlock_irqrestore(&dd->lock, flags);
+
+	/* Start the HR timer if one is not active */
+	if (hrtimer_active(&dd->timer))
+		hrtimer_cancel(&dd->timer);
+
+	hrtimer_start(&dd->timer,
+		ktime_set((dd->switch_debounce_ms / 1000),
+		(dd->switch_debounce_ms % 1000) * 1000000), HRTIMER_MODE_REL);
+
+	/* disable irq, this gets enabled in the workqueue */
+	disable_irq_nosync(dd->othc_irq_ir);
+	schedule_delayed_work(&dd->hs_work, 0);
+
+	return IRQ_HANDLED;
+}
+/*
+ * The API pm8058_micbias_enable() allows to configure
+ * the MIC_BIAS. Only the lines which are not used for
+ * headset detection can be configured using this API.
+ * The API returns an error code if it fails to configure
+ * the specified MIC_BIAS line, else it returns 0.
+ */
+int pm8058_micbias_enable(enum othc_micbias micbias,
+		enum othc_micbias_enable enable)
+{
+	int rc;
+	u8 reg;
+	struct pm8058_othc *dd = config[micbias];
+
+	if (dd == NULL) {
+		pr_err("MIC_BIAS not registered, cannot enable\n");
+		return -ENODEV;
+	}
+
+	if (dd->othc_pdata->micbias_capability != OTHC_MICBIAS) {
+		pr_err("MIC_BIAS enable capability not supported\n");
+		return -EINVAL;
+	}
+
+	rc = pm8058_read(dd->pm_chip, dd->othc_base + 1, &reg, 1);
+	if (rc < 0) {
+		pr_err("PM8058 read failed\n");
+		return rc;
+	}
+
+	reg &= PM8058_OTHC_EN_SIG_MASK;
+	reg |= (enable << PM8058_OTHC_EN_SIG_SHIFT);
+
+	rc = pm8058_write(dd->pm_chip, dd->othc_base + 1, &reg, 1);
+	if (rc < 0) {
+		pr_err("PM8058 write failed\n");
+		return rc;
+	}
+
+	return rc;
+}
+EXPORT_SYMBOL(pm8058_micbias_enable);
+
+int pm8058_othc_svideo_enable(enum othc_micbias micbias, bool enable)
+{
+	struct pm8058_othc *dd = config[micbias];
+
+	if (dd == NULL) {
+		pr_err("MIC_BIAS not registered, cannot enable\n");
+		return -ENODEV;
+	}
+
+	if (dd->othc_pdata->micbias_capability != OTHC_MICBIAS_HSED) {
+		pr_err("MIC_BIAS enable capability not supported\n");
+		return -EINVAL;
+	}
+
+	if (dd->accessories_adc_support) {
+		/* GPIO state for MIC_IN = 0, SVIDEO = 1 */
+		gpio_set_value_cansleep(dd->video_out_gpio, !!enable);
+		if (enable) {
+			pr_debug("Enable the video path\n");
+			switch_set_state(&dd->othc_sdev, dd->curr_accessory);
+			input_report_switch(dd->othc_ipd,
+						dd->curr_accessory_code, 1);
+			input_sync(dd->othc_ipd);
+		} else {
+			pr_debug("Disable the video path\n");
+			switch_set_state(&dd->othc_sdev, 0);
+			input_report_switch(dd->othc_ipd,
+					dd->curr_accessory_code, 0);
+			input_sync(dd->othc_ipd);
+		}
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(pm8058_othc_svideo_enable);
+
+#ifdef CONFIG_PM
+static int pm8058_othc_suspend(struct device *dev)
+{
+	int rc = 0;
+	struct pm8058_othc *dd = dev_get_drvdata(dev);
+
+	if (dd->othc_pdata->micbias_capability == OTHC_MICBIAS_HSED) {
+		if (device_may_wakeup(dev)) {
+			enable_irq_wake(dd->othc_irq_sw);
+			enable_irq_wake(dd->othc_irq_ir);
+		}
+	}
+
+	if (!device_may_wakeup(dev)) {
+		rc = regulator_disable(dd->othc_vreg);
+		if (rc)
+			pr_err("othc micbais power off failed\n");
+	}
+
+	return rc;
+}
+
+static int pm8058_othc_resume(struct device *dev)
+{
+	int rc = 0;
+	struct pm8058_othc *dd = dev_get_drvdata(dev);
+
+	if (dd->othc_pdata->micbias_capability == OTHC_MICBIAS_HSED) {
+		if (device_may_wakeup(dev)) {
+			disable_irq_wake(dd->othc_irq_sw);
+			disable_irq_wake(dd->othc_irq_ir);
+		}
+	}
+
+	if (!device_may_wakeup(dev)) {
+		rc = regulator_enable(dd->othc_vreg);
+		if (rc)
+			pr_err("othc micbais power on failed\n");
+	}
+
+	return rc;
+}
+
+static struct dev_pm_ops pm8058_othc_pm_ops = {
+	.suspend = pm8058_othc_suspend,
+	.resume = pm8058_othc_resume,
+};
+#endif
+
+static int __devexit pm8058_othc_remove(struct platform_device *pd)
+{
+	struct pm8058_othc *dd = platform_get_drvdata(pd);
+
+	pm_runtime_set_suspended(&pd->dev);
+	pm_runtime_disable(&pd->dev);
+
+	if (dd->othc_pdata->micbias_capability == OTHC_MICBIAS_HSED) {
+		device_init_wakeup(&pd->dev, 0);
+		if (dd->othc_support_n_switch == true) {
+			adc_channel_close(dd->adc_handle);
+			cancel_work_sync(&dd->switch_work);
+		}
+
+		if (dd->accessory_support == true) {
+			int i;
+			for (i = 0; i < dd->num_accessories; i++) {
+				if (dd->accessory_info[i].detect_flags &
+							OTHC_GPIO_DETECT)
+					gpio_free(dd->accessory_info[i].gpio);
+			}
+		}
+		cancel_delayed_work_sync(&dd->detect_work);
+		cancel_delayed_work_sync(&dd->hs_work);
+		free_irq(dd->othc_irq_sw, dd);
+		free_irq(dd->othc_irq_ir, dd);
+		if (dd->ir_gpio != -1)
+			gpio_free(dd->ir_gpio);
+		input_unregister_device(dd->othc_ipd);
+	}
+	regulator_disable(dd->othc_vreg);
+	regulator_put(dd->othc_vreg);
+
+	kfree(dd);
+
+	return 0;
+}
+
+static enum hrtimer_restart pm8058_othc_timer(struct hrtimer *timer)
+{
+	unsigned long flags;
+	struct pm8058_othc *dd = container_of(timer,
+					struct pm8058_othc, timer);
+
+	spin_lock_irqsave(&dd->lock, flags);
+	dd->switch_reject = false;
+	spin_unlock_irqrestore(&dd->lock, flags);
+
+	return HRTIMER_NORESTART;
+}
+
+static void othc_report_switch(struct pm8058_othc *dd, u32 res)
+{
+	u8 i;
+	struct othc_switch_info *sw_info = dd->switch_config->switch_info;
+
+	for (i = 0; i < dd->switch_config->num_keys; i++) {
+		if (res >= sw_info[i].min_adc_threshold &&
+				res <= sw_info[i].max_adc_threshold) {
+			dd->othc_sw_state = true;
+			dd->sw_key_code = sw_info[i].key_code;
+			input_report_key(dd->othc_ipd, sw_info[i].key_code, 1);
+			input_sync(dd->othc_ipd);
+			return;
+		}
+	}
+
+	/*
+	 * If the switch is not present in a specified ADC range
+	 * report a default switch press.
+	 */
+	if (dd->switch_config->default_sw_en) {
+		dd->othc_sw_state = true;
+		dd->sw_key_code =
+			sw_info[dd->switch_config->default_sw_idx].key_code;
+		input_report_key(dd->othc_ipd, dd->sw_key_code, 1);
+		input_sync(dd->othc_ipd);
+	}
+}
+
+static void switch_work_f(struct work_struct *work)
+{
+	int rc, i;
+	u32 res = 0;
+	struct adc_chan_result adc_result;
+	struct pm8058_othc *dd =
+		container_of(work, struct pm8058_othc, switch_work);
+	DECLARE_COMPLETION_ONSTACK(adc_wait);
+	u8 num_adc_samples = dd->switch_config->num_adc_samples;
+
+	/* sleep for settling time */
+	msleep(dd->switch_config->voltage_settling_time_ms);
+
+	for (i = 0; i < num_adc_samples; i++) {
+		rc = adc_channel_request_conv(dd->adc_handle, &adc_wait);
+		if (rc) {
+			pr_err("adc_channel_request_conv failed\n");
+			goto bail_out;
+		}
+		rc = wait_for_completion_interruptible(&adc_wait);
+		if (rc) {
+			pr_err("wait_for_completion_interruptible failed\n");
+			goto bail_out;
+		}
+		rc = adc_channel_read_result(dd->adc_handle, &adc_result);
+		if (rc) {
+			pr_err("adc_channel_read_result failed\n");
+			goto bail_out;
+		}
+		res += adc_result.physical;
+	}
+bail_out:
+	if (i == num_adc_samples && num_adc_samples != 0) {
+		res /= num_adc_samples;
+		othc_report_switch(dd, res);
+	} else
+		pr_err("Insufficient ADC samples\n");
+
+	enable_irq(dd->othc_irq_sw);
+}
+
+static int accessory_adc_detect(struct pm8058_othc *dd, int accessory)
+{
+	int rc;
+	u32 res;
+	struct adc_chan_result accessory_adc_result;
+	DECLARE_COMPLETION_ONSTACK(accessory_adc_wait);
+
+	rc = adc_channel_request_conv(dd->accessory_adc_handle,
+						&accessory_adc_wait);
+	if (rc) {
+		pr_err("adc_channel_request_conv failed\n");
+		goto adc_failed;
+	}
+	rc = wait_for_completion_interruptible(&accessory_adc_wait);
+	if (rc) {
+		pr_err("wait_for_completion_interruptible failed\n");
+		goto adc_failed;
+	}
+	rc = adc_channel_read_result(dd->accessory_adc_handle,
+						&accessory_adc_result);
+	if (rc) {
+		pr_err("adc_channel_read_result failed\n");
+		goto adc_failed;
+	}
+
+	res = accessory_adc_result.physical;
+
+	if (res >= dd->accessory_info[accessory].adc_thres.min_threshold &&
+		res <= dd->accessory_info[accessory].adc_thres.max_threshold) {
+		pr_debug("Accessory on ADC detected!, ADC Value = %u\n", res);
+		return 1;
+	}
+
+adc_failed:
+	return 0;
+}
+
+
+static int pm8058_accessory_report(struct pm8058_othc *dd, int status)
+{
+	int i, rc, detected = 0;
+	u8 micbias_status, switch_status;
+
+	if (dd->accessory_support == false) {
+		/* Report default headset */
+		switch_set_state(&dd->othc_sdev, !!status);
+		input_report_switch(dd->othc_ipd, SW_HEADPHONE_INSERT,
+							!!status);
+		input_sync(dd->othc_ipd);
+		return 0;
+	}
+
+	/* For accessory */
+	if (dd->accessory_support == true && status == 0) {
+		/* Report removal of the accessory. */
+
+		/*
+		 * If the current accessory is video cable, reject the removal
+		 * interrupt.
+		 */
+		pr_info("Accessory [%d] removed\n", dd->curr_accessory);
+		if (dd->curr_accessory == OTHC_SVIDEO_OUT)
+			return 0;
+
+		switch_set_state(&dd->othc_sdev, 0);
+		input_report_switch(dd->othc_ipd, dd->curr_accessory_code, 0);
+		input_sync(dd->othc_ipd);
+		return 0;
+	}
+
+	if (dd->ir_gpio < 0) {
+		/* Check the MIC_BIAS status */
+		rc = pm8058_irq_get_rt_status(dd->pm_chip, dd->othc_irq_ir);
+		if (rc < 0) {
+			pr_err("Unable to read IR status from PMIC\n");
+			goto fail_ir_accessory;
+		}
+		micbias_status = !!rc;
+	} else {
+		rc = gpio_get_value_cansleep(dd->ir_gpio);
+		if (rc < 0) {
+			pr_err("Unable to read IR status from GPIO\n");
+			goto fail_ir_accessory;
+		}
+		micbias_status = !rc;
+	}
+
+	/* Check the switch status */
+	rc = pm8058_irq_get_rt_status(dd->pm_chip, dd->othc_irq_sw);
+	if (rc < 0) {
+		pr_err("Unable to read SWITCH status\n");
+		goto fail_ir_accessory;
+	}
+	switch_status = !!rc;
+
+	/* Loop through to check which accessory is connected */
+	for (i = 0; i < dd->num_accessories; i++) {
+		detected = 0;
+		if (dd->accessory_info[i].enabled == false)
+			continue;
+
+		if (dd->accessory_info[i].detect_flags & OTHC_MICBIAS_DETECT) {
+			if (micbias_status)
+				detected = 1;
+			else
+				continue;
+		}
+		if (dd->accessory_info[i].detect_flags & OTHC_SWITCH_DETECT) {
+			if (switch_status)
+				detected = 1;
+			else
+				continue;
+		}
+		if (dd->accessory_info[i].detect_flags & OTHC_GPIO_DETECT) {
+			rc = gpio_get_value_cansleep(
+						dd->accessory_info[i].gpio);
+			if (rc < 0)
+				continue;
+
+			if (rc ^ dd->accessory_info[i].active_low)
+				detected = 1;
+			else
+				continue;
+		}
+		if (dd->accessory_info[i].detect_flags & OTHC_ADC_DETECT)
+			detected = accessory_adc_detect(dd, i);
+
+		if (detected)
+			break;
+	}
+
+	if (detected) {
+		dd->curr_accessory = dd->accessory_info[i].accessory;
+		dd->curr_accessory_code = dd->accessory_info[i].key_code;
+
+		/* if Video out cable detected enable the video path*/
+		if (dd->curr_accessory == OTHC_SVIDEO_OUT) {
+			pm8058_othc_svideo_enable(
+					dd->othc_pdata->micbias_select, true);
+
+		} else {
+			switch_set_state(&dd->othc_sdev, dd->curr_accessory);
+			input_report_switch(dd->othc_ipd,
+						dd->curr_accessory_code, 1);
+			input_sync(dd->othc_ipd);
+		}
+		pr_info("Accessory [%d] inserted\n", dd->curr_accessory);
+	} else
+		pr_info("Unable to detect accessory. False interrupt!\n");
+
+	return 0;
+
+fail_ir_accessory:
+	return rc;
+}
+
+static void detect_work_f(struct work_struct *work)
+{
+	int rc;
+	struct pm8058_othc *dd =
+		container_of(work, struct pm8058_othc, detect_work.work);
+
+	if (dd->othc_ir_state) {
+		/* inserted */
+		rc = pm8058_accessory_report(dd, 1);
+		if (rc)
+			pr_err("Accessory could not be detected\n");
+	} else {
+		/* removed */
+		rc = pm8058_accessory_report(dd, 0);
+		if (rc)
+			pr_err("Accessory could not be detected\n");
+		/* Clear existing switch state */
+		dd->othc_sw_state = false;
+	}
+	enable_irq(dd->othc_irq_ir);
+}
+
+/*
+ * The pm8058_no_sw detects the switch press and release operation.
+ * The odd number call is press and even number call is release.
+ * The current state of the button is maintained in othc_sw_state variable.
+ * This isr gets called only for NO type headsets.
+ */
+static irqreturn_t pm8058_no_sw(int irq, void *dev_id)
+{
+	int level;
+	struct pm8058_othc *dd = dev_id;
+	unsigned long flags;
+
+	/* Check if headset has been inserted, else return */
+	if (!dd->othc_ir_state)
+		return IRQ_HANDLED;
+
+	spin_lock_irqsave(&dd->lock, flags);
+	if (dd->switch_reject == true) {
+		pr_debug("Rejected switch interrupt\n");
+		spin_unlock_irqrestore(&dd->lock, flags);
+		return IRQ_HANDLED;
+	}
+	spin_unlock_irqrestore(&dd->lock, flags);
+
+	level = pm8058_irq_get_rt_status(dd->pm_chip, dd->othc_irq_sw);
+	if (level < 0) {
+		pr_err("Unable to read IRQ status register\n");
+		return IRQ_HANDLED;
+	}
+
+	if (dd->othc_support_n_switch == true) {
+		if (level == 0) {
+			dd->othc_sw_state = false;
+			input_report_key(dd->othc_ipd, dd->sw_key_code, 0);
+			input_sync(dd->othc_ipd);
+		} else {
+			disable_irq_nosync(dd->othc_irq_sw);
+			schedule_work(&dd->switch_work);
+		}
+		return IRQ_HANDLED;
+	}
+	/*
+	 * It is necessary to check the software state and the hardware state
+	 * to make sure that the residual interrupt after the debounce time does
+	 * not disturb the software state machine.
+	 */
+	if (level == 1 && dd->othc_sw_state == false) {
+		/*  Switch has been pressed */
+		dd->othc_sw_state = true;
+		input_report_key(dd->othc_ipd, KEY_MEDIA, 1);
+	} else if (level == 0 && dd->othc_sw_state == true) {
+		/* Switch has been released */
+		dd->othc_sw_state = false;
+		input_report_key(dd->othc_ipd, KEY_MEDIA, 0);
+	}
+	input_sync(dd->othc_ipd);
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * The pm8058_nc_ir detects insert / remove of the headset (for NO),
+ * The current state of the headset is maintained in othc_ir_state variable.
+ * Due to a hardware bug, false switch interrupts are seen during headset
+ * insert. This is handled in the software by rejecting the switch interrupts
+ * for a small period of time after the headset has been inserted.
+ */
+static irqreturn_t pm8058_nc_ir(int irq, void *dev_id)
+{
+	unsigned long flags, rc;
+	struct pm8058_othc *dd = dev_id;
+
+	spin_lock_irqsave(&dd->lock, flags);
+	/* Enable the switch reject flag */
+	dd->switch_reject = true;
+	spin_unlock_irqrestore(&dd->lock, flags);
+
+	/* Start the HR timer if one is not active */
+	if (hrtimer_active(&dd->timer))
+		hrtimer_cancel(&dd->timer);
+
+	hrtimer_start(&dd->timer,
+		ktime_set((dd->switch_debounce_ms / 1000),
+		(dd->switch_debounce_ms % 1000) * 1000000), HRTIMER_MODE_REL);
+
+	/* disable irq, this gets enabled in the workqueue */
+	disable_irq_nosync(dd->othc_irq_ir);
+
+	/* Check the MIC_BIAS status, to check if inserted or removed */
+	rc = pm8058_irq_get_rt_status(dd->pm_chip, dd->othc_irq_ir);
+	if (rc < 0) {
+		pr_err("Unable to read IR status\n");
+		goto fail_ir;
+	}
+
+	dd->othc_ir_state = rc;
+	schedule_delayed_work(&dd->detect_work,
+				msecs_to_jiffies(dd->detection_delay_ms));
+
+fail_ir:
+	return IRQ_HANDLED;
+}
+
+static int pm8058_configure_micbias(struct pm8058_othc *dd)
+{
+	int rc;
+	u8 reg, value;
+	u32 value1;
+	u16 base_addr = dd->othc_base;
+	struct hsed_bias_config *hsed_config =
+			dd->othc_pdata->hsed_config->hsed_bias_config;
+
+	/* Intialize the OTHC module */
+	/* Control Register 1*/
+	rc = pm8058_read(dd->pm_chip, base_addr, &reg, 1);
+	if (rc < 0) {
+		pr_err("PM8058 read failed\n");
+		return rc;
+	}
+
+	/* set iDAC high current threshold */
+	value = (hsed_config->othc_highcurr_thresh_uA / 100) - 2;
+	reg =  (reg & PM8058_OTHC_HIGH_CURR_MASK) | value;
+
+	rc = pm8058_write(dd->pm_chip, base_addr, &reg, 1);
+	if (rc < 0) {
+		pr_err("PM8058 read failed\n");
+		return rc;
+	}
+
+	/* Control register 2*/
+	rc = pm8058_read(dd->pm_chip, base_addr + 1, &reg, 1);
+	if (rc < 0) {
+		pr_err("PM8058 read failed\n");
+		return rc;
+	}
+
+	value = dd->othc_pdata->micbias_enable;
+	reg &= PM8058_OTHC_EN_SIG_MASK;
+	reg |= (value << PM8058_OTHC_EN_SIG_SHIFT);
+
+	value = 0;
+	value1 = (hsed_config->othc_hyst_prediv_us << 10) / USEC_PER_SEC;
+	while (value1 != 0) {
+		value1 = value1 >> 1;
+		value++;
+	}
+	if (value > 7) {
+		pr_err("Invalid input argument - othc_hyst_prediv_us\n");
+		return -EINVAL;
+	}
+	reg &= PM8058_OTHC_HYST_PREDIV_MASK;
+	reg |= (value << PM8058_OTHC_HYST_PREDIV_SHIFT);
+
+	value = 0;
+	value1 = (hsed_config->othc_period_clkdiv_us << 10) / USEC_PER_SEC;
+	while (value1 != 1) {
+		value1 = value1 >> 1;
+		value++;
+	}
+	if (value > 8) {
+		pr_err("Invalid input argument - othc_period_clkdiv_us\n");
+		return -EINVAL;
+	}
+	reg = (reg &  PM8058_OTHC_CLK_PREDIV_MASK) | (value - 1);
+
+	rc = pm8058_write(dd->pm_chip, base_addr + 1, &reg, 1);
+	if (rc < 0) {
+		pr_err("PM8058 read failed\n");
+		return rc;
+	}
+
+	/* Control register 3 */
+	rc = pm8058_read(dd->pm_chip, base_addr + 2 , &reg, 1);
+	if (rc < 0) {
+		pr_err("PM8058 read failed\n");
+		return rc;
+	}
+
+	value = hsed_config->othc_hyst_clk_us /
+					hsed_config->othc_hyst_prediv_us;
+	if (value > 15) {
+		pr_err("Invalid input argument - othc_hyst_prediv_us\n");
+		return -EINVAL;
+	}
+	reg &= PM8058_OTHC_HYST_CLK_MASK;
+	reg |= value << PM8058_OTHC_HYST_CLK_SHIFT;
+
+	value = hsed_config->othc_period_clk_us /
+					hsed_config->othc_period_clkdiv_us;
+	if (value > 15) {
+		pr_err("Invalid input argument - othc_hyst_prediv_us\n");
+		return -EINVAL;
+	}
+	reg = (reg & PM8058_OTHC_PERIOD_CLK_MASK) | value;
+
+	rc = pm8058_write(dd->pm_chip, base_addr + 2, &reg, 1);
+	if (rc < 0) {
+		pr_err("PM8058 read failed\n");
+		return rc;
+	}
+
+	return 0;
+}
+
+static ssize_t othc_headset_print_name(struct switch_dev *sdev, char *buf)
+{
+	switch (switch_get_state(sdev)) {
+	case OTHC_NO_DEVICE:
+		return sprintf(buf, "No Device\n");
+	case OTHC_HEADSET:
+	case OTHC_HEADPHONE:
+	case OTHC_MICROPHONE:
+	case OTHC_ANC_HEADSET:
+	case OTHC_ANC_HEADPHONE:
+	case OTHC_ANC_MICROPHONE:
+		return sprintf(buf, "Headset\n");
+	}
+	return -EINVAL;
+}
+
+static int pm8058_configure_switch(struct pm8058_othc *dd)
+{
+	int rc, i;
+
+	if (dd->othc_support_n_switch == true) {
+		/* n-switch support */
+		rc = adc_channel_open(dd->switch_config->adc_channel,
+							&dd->adc_handle);
+		if (rc) {
+			pr_err("Unable to open ADC channel\n");
+			return -ENODEV;
+		}
+
+		for (i = 0; i < dd->switch_config->num_keys; i++) {
+			input_set_capability(dd->othc_ipd, EV_KEY,
+				dd->switch_config->switch_info[i].key_code);
+		}
+	} else /* Only single switch supported */
+		input_set_capability(dd->othc_ipd, EV_KEY, KEY_MEDIA);
+
+	return 0;
+}
+
+static int
+pm8058_configure_accessory(struct pm8058_othc *dd)
+{
+	int i, rc;
+	char name[OTHC_GPIO_MAX_LEN];
+
+	/*
+	 * Not bailing out if the gpio_* configure calls fail. This is required
+	 * as multiple accessories are detected by the same gpio.
+	 */
+	for (i = 0; i < dd->num_accessories; i++) {
+		if (dd->accessory_info[i].enabled == false)
+			continue;
+		if (dd->accessory_info[i].detect_flags & OTHC_GPIO_DETECT) {
+			snprintf(name, OTHC_GPIO_MAX_LEN, "%s%d",
+							"othc_acc_gpio_", i);
+			rc = gpio_request(dd->accessory_info[i].gpio, name);
+			if (rc) {
+				pr_debug("Unable to request GPIO [%d]\n",
+						dd->accessory_info[i].gpio);
+				continue;
+			}
+			rc = gpio_direction_input(dd->accessory_info[i].gpio);
+			if (rc) {
+				pr_debug("Unable to set-direction GPIO [%d]\n",
+						dd->accessory_info[i].gpio);
+				gpio_free(dd->accessory_info[i].gpio);
+				continue;
+			}
+		}
+		input_set_capability(dd->othc_ipd, EV_SW,
+					dd->accessory_info[i].key_code);
+	}
+
+	if (dd->accessories_adc_support) {
+		/*
+		 * Check if 3 switch is supported. If both are using the same
+		 * ADC channel, the same handle can be used.
+		 */
+		if (dd->othc_support_n_switch) {
+			if (dd->adc_handle != NULL &&
+				(dd->accessories_adc_channel ==
+				 dd->switch_config->adc_channel))
+				dd->accessory_adc_handle = dd->adc_handle;
+		} else {
+			rc = adc_channel_open(dd->accessories_adc_channel,
+						&dd->accessory_adc_handle);
+			if (rc) {
+				pr_err("Unable to open ADC channel\n");
+				rc = -ENODEV;
+				goto accessory_adc_fail;
+			}
+		}
+		if (dd->video_out_gpio != 0) {
+			rc = gpio_request(dd->video_out_gpio, "vout_enable");
+			if (rc < 0) {
+				pr_err("request VOUT gpio failed (%d)\n", rc);
+				goto accessory_adc_fail;
+			}
+			rc = gpio_direction_output(dd->video_out_gpio, 0);
+			if (rc < 0) {
+				pr_err("direction_out failed (%d)\n", rc);
+				goto accessory_adc_fail;
+			}
+		}
+
+	}
+
+	return 0;
+
+accessory_adc_fail:
+	for (i = 0; i < dd->num_accessories; i++) {
+		if (dd->accessory_info[i].enabled == false)
+			continue;
+		gpio_free(dd->accessory_info[i].gpio);
+	}
+	return rc;
+}
+
+static int
+othc_configure_hsed(struct pm8058_othc *dd, struct platform_device *pd)
+{
+	int rc;
+	struct input_dev *ipd;
+	struct pmic8058_othc_config_pdata *pdata = pd->dev.platform_data;
+	struct othc_hsed_config *hsed_config = pdata->hsed_config;
+
+	dd->othc_sdev.name = "h2w";
+	dd->othc_sdev.print_name = othc_headset_print_name;
+
+	rc = switch_dev_register(&dd->othc_sdev);
+	if (rc) {
+		pr_err("Unable to register switch device\n");
+		return rc;
+	}
+
+	ipd = input_allocate_device();
+	if (ipd == NULL) {
+		pr_err("Unable to allocate memory\n");
+		rc = -ENOMEM;
+		goto fail_input_alloc;
+	}
+
+	/* Get the IRQ for Headset Insert-remove and Switch-press */
+	dd->othc_irq_sw = platform_get_irq(pd, 0);
+	dd->othc_irq_ir = platform_get_irq(pd, 1);
+	if (dd->othc_irq_ir < 0 || dd->othc_irq_sw < 0) {
+		pr_err("othc resource:IRQs absent\n");
+		rc = -ENXIO;
+		goto fail_micbias_config;
+	}
+
+	if (pdata->hsed_name != NULL)
+		ipd->name = pdata->hsed_name;
+	else
+		ipd->name = "pmic8058_othc";
+
+	ipd->phys = "pmic8058_othc/input0";
+	ipd->dev.parent = &pd->dev;
+
+	dd->othc_ipd = ipd;
+	dd->ir_gpio = hsed_config->ir_gpio;
+	dd->othc_sw_state = false;
+	dd->switch_debounce_ms = hsed_config->switch_debounce_ms;
+	dd->othc_support_n_switch = hsed_config->othc_support_n_switch;
+	dd->accessory_support = pdata->hsed_config->accessories_support;
+	dd->detection_delay_ms = pdata->hsed_config->detection_delay_ms;
+
+	if (dd->othc_support_n_switch == true)
+		dd->switch_config = hsed_config->switch_config;
+
+	if (dd->accessory_support == true) {
+		dd->accessory_info = pdata->hsed_config->accessories;
+		dd->num_accessories = pdata->hsed_config->othc_num_accessories;
+		dd->accessories_adc_support =
+				pdata->hsed_config->accessories_adc_support;
+		dd->accessories_adc_channel =
+				pdata->hsed_config->accessories_adc_channel;
+		dd->video_out_gpio = pdata->hsed_config->video_out_gpio;
+	}
+
+	/* Configure the MIC_BIAS line for headset detection */
+	rc = pm8058_configure_micbias(dd);
+	if (rc < 0)
+		goto fail_micbias_config;
+
+	/* Configure for the switch events */
+	rc = pm8058_configure_switch(dd);
+	if (rc < 0)
+		goto fail_micbias_config;
+
+	/* Configure the accessory */
+	if (dd->accessory_support == true) {
+		rc = pm8058_configure_accessory(dd);
+		if (rc < 0)
+			goto fail_micbias_config;
+	}
+
+	input_set_drvdata(ipd, dd);
+	spin_lock_init(&dd->lock);
+
+	rc = input_register_device(ipd);
+	if (rc) {
+		pr_err("Unable to register OTHC device\n");
+		goto fail_micbias_config;
+	}
+
+	hrtimer_init(&dd->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+	dd->timer.function = pm8058_othc_timer;
+
+	/* Request the HEADSET IR interrupt */
+	if (dd->ir_gpio < 0) {
+		rc = request_threaded_irq(dd->othc_irq_ir, NULL, pm8058_nc_ir,
+		IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_DISABLED,
+					"pm8058_othc_ir", dd);
+		if (rc < 0) {
+			pr_err("Unable to request pm8058_othc_ir IRQ\n");
+			goto fail_ir_irq;
+		}
+	} else {
+		rc = gpio_request(dd->ir_gpio, "othc_ir_gpio");
+		if (rc) {
+			pr_err("Unable to request IR GPIO\n");
+			goto fail_ir_gpio_req;
+		}
+		rc = gpio_direction_input(dd->ir_gpio);
+		if (rc) {
+			pr_err("GPIO %d set_direction failed\n", dd->ir_gpio);
+			goto fail_ir_irq;
+		}
+		dd->othc_irq_ir = gpio_to_irq(dd->ir_gpio);
+		rc = request_any_context_irq(dd->othc_irq_ir, ir_gpio_irq,
+		IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
+				"othc_gpio_ir_irq", dd);
+		if (rc < 0) {
+			pr_err("could not request hs irq err=%d\n", rc);
+			goto fail_ir_irq;
+		}
+	}
+	/* Request the  SWITCH press/release interrupt */
+	rc = request_threaded_irq(dd->othc_irq_sw, NULL, pm8058_no_sw,
+	IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_DISABLED,
+			"pm8058_othc_sw", dd);
+	if (rc < 0) {
+		pr_err("Unable to request pm8058_othc_sw IRQ\n");
+		goto fail_sw_irq;
+	}
+
+	/* Check if the accessory is already inserted during boot up */
+	if (dd->ir_gpio < 0) {
+		rc = pm8058_irq_get_rt_status(dd->pm_chip, dd->othc_irq_ir);
+		if (rc < 0) {
+			pr_err("Unable to get accessory status at boot\n");
+			goto fail_ir_status;
+		}
+	} else {
+		rc = gpio_get_value_cansleep(dd->ir_gpio);
+		if (rc < 0) {
+			pr_err("Unable to get accessory status at boot\n");
+			goto fail_ir_status;
+		}
+		rc = !rc;
+	}
+	if (rc) {
+		pr_debug("Accessory inserted during boot up\n");
+		/* process the data and report the inserted accessory */
+		rc = pm8058_accessory_report(dd, 1);
+		if (rc)
+			pr_debug("Unabele to detect accessory at boot up\n");
+	}
+
+	device_init_wakeup(&pd->dev,
+			hsed_config->hsed_bias_config->othc_wakeup);
+
+	INIT_DELAYED_WORK(&dd->detect_work, detect_work_f);
+
+	INIT_DELAYED_WORK(&dd->hs_work, hs_worker);
+
+	if (dd->othc_support_n_switch == true)
+		INIT_WORK(&dd->switch_work, switch_work_f);
+
+
+	return 0;
+
+fail_ir_status:
+	free_irq(dd->othc_irq_sw, dd);
+fail_sw_irq:
+	free_irq(dd->othc_irq_ir, dd);
+fail_ir_irq:
+	if (dd->ir_gpio != -1)
+		gpio_free(dd->ir_gpio);
+fail_ir_gpio_req:
+	input_unregister_device(ipd);
+	dd->othc_ipd = NULL;
+fail_micbias_config:
+	input_free_device(ipd);
+fail_input_alloc:
+	switch_dev_unregister(&dd->othc_sdev);
+	return rc;
+}
+
+static int __devinit pm8058_othc_probe(struct platform_device *pd)
+{
+	int rc;
+	struct pm8058_othc *dd;
+	struct pm8058_chip *chip;
+	struct resource *res;
+	struct pmic8058_othc_config_pdata *pdata = pd->dev.platform_data;
+
+	chip = dev_get_drvdata(pd->dev.parent);
+	if (chip == NULL) {
+		pr_err("Invalid driver information\n");
+		return  -EINVAL;
+	}
+
+	/* Check PMIC8058 version. A0 version is not supported */
+	if (pm8058_rev(chip) == PM_8058_REV_1p0) {
+		pr_err("PMIC8058 version not supported\n");
+		return -ENODEV;
+	}
+
+	if (pdata == NULL) {
+		pr_err("Platform data not present\n");
+		return -EINVAL;
+	}
+
+	dd = kzalloc(sizeof(*dd), GFP_KERNEL);
+	if (dd == NULL) {
+		pr_err("Unable to allocate memory\n");
+		return -ENOMEM;
+	}
+
+	/* Enable runtime PM ops, start in ACTIVE mode */
+	rc = pm_runtime_set_active(&pd->dev);
+	if (rc < 0)
+		dev_dbg(&pd->dev, "unable to set runtime pm state\n");
+	pm_runtime_enable(&pd->dev);
+
+	res = platform_get_resource_byname(pd, IORESOURCE_IO, "othc_base");
+	if (res == NULL) {
+		pr_err("othc resource:Base address absent\n");
+		rc = -ENXIO;
+		goto fail_get_res;
+	}
+
+	dd->othc_pdata = pdata;
+	dd->pm_chip = chip;
+	dd->othc_base = res->start;
+	if (pdata->micbias_regulator == NULL) {
+		pr_err("OTHC regulator not specified\n");
+		goto fail_get_res;
+	}
+
+	dd->othc_vreg = regulator_get(NULL,
+				pdata->micbias_regulator->regulator);
+	if (IS_ERR(dd->othc_vreg)) {
+		pr_err("regulator get failed\n");
+		rc = PTR_ERR(dd->othc_vreg);
+		goto fail_get_res;
+	}
+
+	rc = regulator_set_voltage(dd->othc_vreg,
+				pdata->micbias_regulator->min_uV,
+				pdata->micbias_regulator->max_uV);
+	if (rc) {
+		pr_err("othc regulator set voltage failed\n");
+		goto fail_reg_enable;
+	}
+
+	rc = regulator_enable(dd->othc_vreg);
+	if (rc) {
+		pr_err("othc regulator enable failed\n");
+		goto fail_reg_enable;
+	}
+
+	platform_set_drvdata(pd, dd);
+
+	if (pdata->micbias_capability == OTHC_MICBIAS_HSED) {
+		/* HSED to be supported on this MICBIAS line */
+		if (pdata->hsed_config != NULL) {
+			rc = othc_configure_hsed(dd, pd);
+			if (rc < 0)
+				goto fail_othc_hsed;
+		} else {
+			pr_err("HSED config data not present\n");
+			rc = -EINVAL;
+			goto fail_othc_hsed;
+		}
+	}
+
+	/* Store the local driver data structure */
+	if (dd->othc_pdata->micbias_select < OTHC_MICBIAS_MAX)
+		config[dd->othc_pdata->micbias_select] = dd;
+
+	pr_debug("Device %s:%d successfully registered\n",
+			pd->name, pd->id);
+	return 0;
+
+fail_othc_hsed:
+	regulator_disable(dd->othc_vreg);
+fail_reg_enable:
+	regulator_put(dd->othc_vreg);
+fail_get_res:
+	pm_runtime_set_suspended(&pd->dev);
+	pm_runtime_disable(&pd->dev);
+
+	kfree(dd);
+	return rc;
+}
+
+static struct platform_driver pm8058_othc_driver = {
+	.driver = {
+		.name = "pm8058-othc",
+		.owner = THIS_MODULE,
+#ifdef CONFIG_PM
+		.pm = &pm8058_othc_pm_ops,
+#endif
+	},
+	.probe = pm8058_othc_probe,
+	.remove = __devexit_p(pm8058_othc_remove),
+};
+
+static int __init pm8058_othc_init(void)
+{
+	return platform_driver_register(&pm8058_othc_driver);
+}
+
+static void __exit pm8058_othc_exit(void)
+{
+	platform_driver_unregister(&pm8058_othc_driver);
+}
+/*
+ * Move to late_initcall, to make sure that the ADC driver registration is
+ * completed before we open a ADC channel.
+ */
+late_initcall(pm8058_othc_init);
+module_exit(pm8058_othc_exit);
+
+MODULE_ALIAS("platform:pmic8058_othc");
+MODULE_DESCRIPTION("PMIC 8058 OTHC");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/input/misc/pmic8058-pwrkey.c b/drivers/input/misc/pmic8058-pwrkey.c
new file mode 100644
index 0000000..a981013
--- /dev/null
+++ b/drivers/input/misc/pmic8058-pwrkey.c
@@ -0,0 +1,375 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only 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.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/pmic8058.h>
+#include <linux/pmic8058-pwrkey.h>
+#include <linux/log2.h>
+#include <linux/spinlock.h>
+#include <linux/hrtimer.h>
+#include <linux/pm.h>
+#include <linux/slab.h>
+#include <linux/pm_runtime.h>
+
+#define PON_CNTL_1	0x1C
+#define PON_CNTL_PULL_UP BIT(7)
+#define PON_CNTL_TRIG_DELAY_MASK (0x7)
+
+struct pmic8058_pwrkey {
+	struct input_dev *pwr;
+	int key_press_irq;
+	int key_release_irq;
+	struct pm8058_chip	*pm_chip;
+	struct hrtimer timer;
+	bool key_pressed;
+	bool pressed_first;
+	struct pmic8058_pwrkey_pdata *pdata;
+	spinlock_t lock;
+};
+
+static enum hrtimer_restart pmic8058_pwrkey_timer(struct hrtimer *timer)
+{
+	unsigned long flags;
+	struct pmic8058_pwrkey *pwrkey = container_of(timer,
+						struct pmic8058_pwrkey,	timer);
+
+	spin_lock_irqsave(&pwrkey->lock, flags);
+	pwrkey->key_pressed = true;
+
+	input_report_key(pwrkey->pwr, KEY_POWER, 1);
+	input_sync(pwrkey->pwr);
+	spin_unlock_irqrestore(&pwrkey->lock, flags);
+
+	return HRTIMER_NORESTART;
+}
+
+static irqreturn_t pwrkey_press_irq(int irq, void *_pwrkey)
+{
+	struct pmic8058_pwrkey *pwrkey = _pwrkey;
+	struct pmic8058_pwrkey_pdata *pdata = pwrkey->pdata;
+	unsigned long flags;
+
+	spin_lock_irqsave(&pwrkey->lock, flags);
+	if (pwrkey->pressed_first) {
+		/*
+		 * If pressed_first flag is set already then release interrupt
+		 * has occured first. Events are handled in the release IRQ so
+		 * return.
+		 */
+		pwrkey->pressed_first = false;
+		spin_unlock_irqrestore(&pwrkey->lock, flags);
+		return IRQ_HANDLED;
+	} else {
+		pwrkey->pressed_first = true;
+		/*no pwrkey time duration, means no end key simulation*/
+		if (!pwrkey->pdata->pwrkey_time_ms) {
+			input_report_key(pwrkey->pwr, KEY_POWER, 1);
+			input_sync(pwrkey->pwr);
+			spin_unlock_irqrestore(&pwrkey->lock, flags);
+			return IRQ_HANDLED;
+		}
+
+		input_report_key(pwrkey->pwr, KEY_END, 1);
+		input_sync(pwrkey->pwr);
+
+		hrtimer_start(&pwrkey->timer,
+				ktime_set(pdata->pwrkey_time_ms / 1000,
+				(pdata->pwrkey_time_ms % 1000) * 1000000),
+				HRTIMER_MODE_REL);
+	}
+	spin_unlock_irqrestore(&pwrkey->lock, flags);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t pwrkey_release_irq(int irq, void *_pwrkey)
+{
+	struct pmic8058_pwrkey *pwrkey = _pwrkey;
+	unsigned long flags;
+
+	spin_lock_irqsave(&pwrkey->lock, flags);
+	if (pwrkey->pressed_first) {
+		pwrkey->pressed_first = false;
+		/* no pwrkey time, means no delay in pwr key reporting */
+		if (!pwrkey->pdata->pwrkey_time_ms) {
+			input_report_key(pwrkey->pwr, KEY_POWER, 0);
+			input_sync(pwrkey->pwr);
+			spin_unlock_irqrestore(&pwrkey->lock, flags);
+			return IRQ_HANDLED;
+		}
+
+		hrtimer_cancel(&pwrkey->timer);
+
+		if (pwrkey->key_pressed) {
+			pwrkey->key_pressed = false;
+			input_report_key(pwrkey->pwr, KEY_POWER, 0);
+			input_sync(pwrkey->pwr);
+		}
+
+		input_report_key(pwrkey->pwr, KEY_END, 0);
+		input_sync(pwrkey->pwr);
+	} else {
+		/*
+		 * Set this flag true so that in the subsequent interrupt of
+		 * press we can know release interrupt came first
+		 */
+		pwrkey->pressed_first = true;
+		/* no pwrkey time, means no delay in pwr key reporting */
+		if (!pwrkey->pdata->pwrkey_time_ms) {
+			input_report_key(pwrkey->pwr, KEY_POWER, 1);
+			input_sync(pwrkey->pwr);
+			input_report_key(pwrkey->pwr, KEY_POWER, 0);
+			input_sync(pwrkey->pwr);
+			spin_unlock_irqrestore(&pwrkey->lock, flags);
+			return IRQ_HANDLED;
+		}
+		input_report_key(pwrkey->pwr, KEY_END, 1);
+		input_sync(pwrkey->pwr);
+		input_report_key(pwrkey->pwr, KEY_END, 0);
+		input_sync(pwrkey->pwr);
+	}
+	spin_unlock_irqrestore(&pwrkey->lock, flags);
+
+	return IRQ_HANDLED;
+}
+
+#ifdef CONFIG_PM
+static int pmic8058_pwrkey_suspend(struct device *dev)
+{
+	struct pmic8058_pwrkey *pwrkey = dev_get_drvdata(dev);
+
+	if (device_may_wakeup(dev)) {
+		enable_irq_wake(pwrkey->key_press_irq);
+		enable_irq_wake(pwrkey->key_release_irq);
+	}
+
+	return 0;
+}
+
+static int pmic8058_pwrkey_resume(struct device *dev)
+{
+	struct pmic8058_pwrkey *pwrkey = dev_get_drvdata(dev);
+
+	if (device_may_wakeup(dev)) {
+		disable_irq_wake(pwrkey->key_press_irq);
+		disable_irq_wake(pwrkey->key_release_irq);
+	}
+
+	return 0;
+}
+
+static struct dev_pm_ops pm8058_pwr_key_pm_ops = {
+	.suspend	= pmic8058_pwrkey_suspend,
+	.resume		= pmic8058_pwrkey_resume,
+};
+#endif
+
+static int __devinit pmic8058_pwrkey_probe(struct platform_device *pdev)
+{
+	struct input_dev *pwr;
+	int key_release_irq = platform_get_irq(pdev, 0);
+	int key_press_irq = platform_get_irq(pdev, 1);
+	int err;
+	unsigned int delay;
+	u8 pon_cntl;
+	struct pmic8058_pwrkey *pwrkey;
+	struct pmic8058_pwrkey_pdata *pdata = pdev->dev.platform_data;
+	struct pm8058_chip	*pm_chip;
+
+	pm_chip = dev_get_drvdata(pdev->dev.parent);
+	if (pm_chip == NULL) {
+		dev_err(&pdev->dev, "no parent data passed in\n");
+		return -EFAULT;
+	}
+
+	if (!pdata) {
+		dev_err(&pdev->dev, "power key platform data not supplied\n");
+		return -EINVAL;
+	}
+
+	if (pdata->kpd_trigger_delay_us > 62500) {
+		dev_err(&pdev->dev, "invalid pwr key trigger delay\n");
+		return -EINVAL;
+	}
+
+	if (pdata->pwrkey_time_ms &&
+	     (pdata->pwrkey_time_ms < 500 || pdata->pwrkey_time_ms > 1000)) {
+		dev_err(&pdev->dev, "invalid pwr key time supplied\n");
+		return -EINVAL;
+	}
+
+	pwrkey = kzalloc(sizeof(*pwrkey), GFP_KERNEL);
+	if (!pwrkey)
+		return -ENOMEM;
+
+	pwrkey->pm_chip = pm_chip;
+	pwrkey->pdata   = pdata;
+	pwrkey->pressed_first = false;
+	/* Enable runtime PM ops, start in ACTIVE mode */
+	err = pm_runtime_set_active(&pdev->dev);
+	if (err < 0)
+		dev_dbg(&pdev->dev, "unable to set runtime pm state\n");
+	pm_runtime_enable(&pdev->dev);
+
+	pwr = input_allocate_device();
+	if (!pwr) {
+		dev_dbg(&pdev->dev, "Can't allocate power button\n");
+		err = -ENOMEM;
+		goto free_pwrkey;
+	}
+
+	input_set_capability(pwr, EV_KEY, KEY_POWER);
+	input_set_capability(pwr, EV_KEY, KEY_END);
+
+	pwr->name = "pmic8058_pwrkey";
+	pwr->phys = "pmic8058_pwrkey/input0";
+	pwr->dev.parent = &pdev->dev;
+
+	delay = (pdata->kpd_trigger_delay_us << 10) / USEC_PER_SEC;
+	delay = 1 + ilog2(delay);
+
+	err = pm8058_read(pwrkey->pm_chip, PON_CNTL_1, &pon_cntl, 1);
+	if (err < 0) {
+		dev_err(&pdev->dev, "failed reading PON_CNTL_1 err=%d\n", err);
+		goto free_input_dev;
+	}
+
+
+	pon_cntl &= ~PON_CNTL_TRIG_DELAY_MASK;
+	pon_cntl |= (delay & PON_CNTL_TRIG_DELAY_MASK);
+	pon_cntl |= (pdata->pull_up ? PON_CNTL_PULL_UP : ~PON_CNTL_PULL_UP);
+	err = pm8058_write(pwrkey->pm_chip, PON_CNTL_1, &pon_cntl, 1);
+	if (err < 0) {
+		dev_err(&pdev->dev, "failed writing PON_CNTL_1 err=%d\n", err);
+		goto free_input_dev;
+	}
+
+	hrtimer_init(&pwrkey->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+	pwrkey->timer.function = pmic8058_pwrkey_timer;
+
+	spin_lock_init(&pwrkey->lock);
+
+	err = input_register_device(pwr);
+	if (err) {
+		dev_dbg(&pdev->dev, "Can't register power key: %d\n", err);
+		goto free_input_dev;
+	}
+
+	pwrkey->key_press_irq = key_press_irq;
+	pwrkey->key_release_irq = key_release_irq;
+	pwrkey->pwr = pwr;
+
+	platform_set_drvdata(pdev, pwrkey);
+
+	/* Check if power-key is pressed at boot up */
+	err = pm8058_irq_get_rt_status(pwrkey->pm_chip, key_press_irq);
+	if (err < 0) {
+		dev_err(&pdev->dev, "Key-press status at boot failed rc=%d\n",
+									err);
+		goto unreg_input_dev;
+	}
+	if (err) {
+		if (!pwrkey->pdata->pwrkey_time_ms)
+			input_report_key(pwrkey->pwr, KEY_POWER, 1);
+		else
+			input_report_key(pwrkey->pwr, KEY_END, 1);
+		input_sync(pwrkey->pwr);
+		pwrkey->pressed_first = true;
+	}
+
+	err = request_threaded_irq(key_press_irq, NULL, pwrkey_press_irq,
+			 IRQF_TRIGGER_RISING, "pmic8058_pwrkey_press", pwrkey);
+	if (err < 0) {
+		dev_dbg(&pdev->dev, "Can't get %d IRQ for pwrkey: %d\n",
+				 key_press_irq, err);
+		goto unreg_input_dev;
+	}
+
+	err = request_threaded_irq(key_release_irq, NULL, pwrkey_release_irq,
+			 IRQF_TRIGGER_RISING, "pmic8058_pwrkey_release",
+				 pwrkey);
+	if (err < 0) {
+		dev_dbg(&pdev->dev, "Can't get %d IRQ for pwrkey: %d\n",
+				 key_release_irq, err);
+
+		goto free_press_irq;
+	}
+
+	device_init_wakeup(&pdev->dev, pdata->wakeup);
+
+	return 0;
+
+free_press_irq:
+	free_irq(key_press_irq, NULL);
+unreg_input_dev:
+	input_unregister_device(pwr);
+	pwr = NULL;
+free_input_dev:
+	input_free_device(pwr);
+free_pwrkey:
+	pm_runtime_set_suspended(&pdev->dev);
+	pm_runtime_disable(&pdev->dev);
+	kfree(pwrkey);
+	return err;
+}
+
+static int __devexit pmic8058_pwrkey_remove(struct platform_device *pdev)
+{
+	struct pmic8058_pwrkey *pwrkey = platform_get_drvdata(pdev);
+	int key_release_irq = platform_get_irq(pdev, 0);
+	int key_press_irq = platform_get_irq(pdev, 1);
+
+	pm_runtime_set_suspended(&pdev->dev);
+	pm_runtime_disable(&pdev->dev);
+	device_init_wakeup(&pdev->dev, 0);
+
+	free_irq(key_press_irq, pwrkey);
+	free_irq(key_release_irq, pwrkey);
+	input_unregister_device(pwrkey->pwr);
+	kfree(pwrkey);
+
+	return 0;
+}
+
+static struct platform_driver pmic8058_pwrkey_driver = {
+	.probe		= pmic8058_pwrkey_probe,
+	.remove		= __devexit_p(pmic8058_pwrkey_remove),
+	.driver		= {
+		.name	= "pm8058-pwrkey",
+		.owner	= THIS_MODULE,
+#ifdef CONFIG_PM
+		.pm	= &pm8058_pwr_key_pm_ops,
+#endif
+	},
+};
+
+static int __init pmic8058_pwrkey_init(void)
+{
+	return platform_driver_register(&pmic8058_pwrkey_driver);
+}
+module_init(pmic8058_pwrkey_init);
+
+static void __exit pmic8058_pwrkey_exit(void)
+{
+	platform_driver_unregister(&pmic8058_pwrkey_driver);
+}
+module_exit(pmic8058_pwrkey_exit);
+
+MODULE_ALIAS("platform:pmic8058_pwrkey");
+MODULE_DESCRIPTION("PMIC8058 Power Key");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/input/misc/pmic8058-vib-memless.c b/drivers/input/misc/pmic8058-vib-memless.c
new file mode 100644
index 0000000..ba05400
--- /dev/null
+++ b/drivers/input/misc/pmic8058-vib-memless.c
@@ -0,0 +1,282 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only 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.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/pmic8058-vibrator.h>
+#include <linux/mfd/pmic8058.h>
+#include <linux/pm.h>
+#include <linux/input.h>
+#include <linux/slab.h>
+
+#define VIB_DRV			0x4A
+
+#define VIB_DRV_SEL_MASK	0xf8
+#define VIB_DRV_SEL_SHIFT	0x03
+#define VIB_DRV_EN_MANUAL_MASK	0xfc
+
+#define VIB_MAX_LEVEL_mV	(3100)
+#define VIB_MIN_LEVEL_mV	(1200)
+#define VIB_MAX_LEVELS		(VIB_MAX_LEVEL_mV - VIB_MIN_LEVEL_mV)
+
+#define MAX_FF_SPEED		0xff
+
+struct pmic8058_vib {
+	struct input_dev *info;
+	spinlock_t lock;
+	struct work_struct work;
+
+	bool enabled;
+	int speed;
+	struct device *dev;
+	struct pmic8058_vibrator_pdata *pdata;
+	int state;
+	int level;
+	u8  reg_vib_drv;
+
+	struct pm8058_chip	*pm_chip;
+};
+
+/* REVISIT: just for debugging, will be removed in final working version */
+static void __dump_vib_regs(struct pmic8058_vib *vib, char *msg)
+{
+	u8 temp;
+
+	dev_dbg(vib->dev, "%s\n", msg);
+
+	pm8058_read(vib->pm_chip, VIB_DRV, &temp, 1);
+	dev_dbg(vib->dev, "VIB_DRV - %X\n", temp);
+}
+
+static int pmic8058_vib_read_u8(struct pmic8058_vib *vib,
+				 u8 *data, u16 reg)
+{
+	int rc;
+
+	rc = pm8058_read(vib->pm_chip, reg, data, 1);
+	if (rc < 0)
+		dev_warn(vib->dev, "Error reading pmic8058: %X - ret %X\n",
+				reg, rc);
+
+	return rc;
+}
+
+static int pmic8058_vib_write_u8(struct pmic8058_vib *vib,
+				 u8 data, u16 reg)
+{
+	int rc;
+
+	rc = pm8058_write(vib->pm_chip, reg, &data, 1);
+	if (rc < 0)
+		dev_warn(vib->dev, "Error writing pmic8058: %X - ret %X\n",
+				reg, rc);
+	return rc;
+}
+
+static int pmic8058_vib_set(struct pmic8058_vib *vib, int on)
+{
+	int rc;
+	u8 val;
+
+	if (on) {
+		val = vib->reg_vib_drv;
+		val |= ((vib->level << VIB_DRV_SEL_SHIFT) & VIB_DRV_SEL_MASK);
+		rc = pmic8058_vib_write_u8(vib, val, VIB_DRV);
+		if (rc < 0)
+			return rc;
+		vib->reg_vib_drv = val;
+		vib->enabled = 1;
+
+	} else {
+		val = vib->reg_vib_drv;
+		val &= ~VIB_DRV_SEL_MASK;
+		rc = pmic8058_vib_write_u8(vib, val, VIB_DRV);
+		if (rc < 0)
+			return rc;
+		vib->reg_vib_drv = val;
+		vib->enabled = 0;
+	}
+	__dump_vib_regs(vib, "vib_set_end");
+
+	return rc;
+}
+
+static void pmic8058_work_handler(struct work_struct *work)
+{
+	u8 val;
+	int rc;
+	struct pmic8058_vib *info;
+
+	info  = container_of(work, struct pmic8058_vib, work);
+
+	rc = pmic8058_vib_read_u8(info, &val, VIB_DRV);
+	if (rc < 0)
+		return;
+
+	/*
+	 * Vibrator support voltage ranges from 1.2 to 3.1V, so
+	 * scale the FF speed to these range.
+	 */
+	if (info->speed) {
+		info->state = 1;
+		info->level = ((VIB_MAX_LEVELS * info->speed) / MAX_FF_SPEED) +
+						VIB_MIN_LEVEL_mV;
+		info->level /= 100;
+	} else {
+		info->state = 0;
+		info->level = VIB_MIN_LEVEL_mV / 100;
+	}
+	pmic8058_vib_set(info, info->state);
+}
+
+static int pmic8058_vib_play_effect(struct input_dev *dev, void *data,
+		      struct ff_effect *effect)
+{
+	struct pmic8058_vib *info = input_get_drvdata(dev);
+
+	info->speed = effect->u.rumble.strong_magnitude >> 8;
+	if (!info->speed)
+		info->speed = effect->u.rumble.weak_magnitude >> 9;
+	schedule_work(&info->work);
+	return 0;
+}
+
+static int __devinit pmic8058_vib_probe(struct platform_device *pdev)
+
+{
+	struct pmic8058_vibrator_pdata *pdata = pdev->dev.platform_data;
+	struct pmic8058_vib *vib;
+	u8 val;
+	int rc;
+
+	struct pm8058_chip	*pm_chip;
+
+	pm_chip = dev_get_drvdata(pdev->parent.dev);
+	if (pm_chip == NULL) {
+		dev_err(&pdev->dev, "no parent data passed in\n");
+		return -EFAULT;
+	}
+
+	if (!pdata)
+		return -EINVAL;
+
+	if (pdata->level_mV < VIB_MIN_LEVEL_mV ||
+			 pdata->level_mV > VIB_MAX_LEVEL_mV)
+		return -EINVAL;
+
+	vib = kzalloc(sizeof(*vib), GFP_KERNEL);
+	if (!vib)
+		return -ENOMEM;
+
+	vib->pm_chip	= pm_chip;
+	vib->enabled	= 0;
+	vib->pdata	= pdata;
+	vib->level	= pdata->level_mV / 100;
+	vib->dev	= &pdev->dev;
+
+	spin_lock_init(&vib->lock);
+	INIT_WORK(&vib->work, pmic8058_work_handler);
+
+	vib->info = input_allocate_device();
+
+	if (vib->info == NULL) {
+		dev_err(&pdev->dev, "couldn't allocate input device\n");
+		return -ENOMEM;
+	}
+
+	input_set_drvdata(vib->info, vib);
+
+	vib->info->name = "pmic8058:vibrator";
+	vib->info->id.version = 1;
+	vib->info->dev.parent = pdev->dev.parent;
+
+	__set_bit(FF_RUMBLE, vib->info->ffbit);
+	__dump_vib_regs(vib, "boot_vib_default");
+
+	/* operate in manual mode */
+	rc = pmic8058_vib_read_u8(vib, &val, VIB_DRV);
+	if (rc < 0)
+		goto err_read_vib;
+	val &= ~VIB_DRV_EN_MANUAL_MASK;
+	rc = pmic8058_vib_write_u8(vib, val, VIB_DRV);
+	if (rc < 0)
+		goto err_read_vib;
+
+	vib->reg_vib_drv = val;
+
+	rc = input_ff_create_memless(vib->info, NULL, pmic8058_vib_play_effect);
+	if (rc < 0) {
+		dev_dbg(&pdev->dev, "couldn't register vibrator to FF\n");
+		goto create_memless_err;
+	}
+
+	platform_set_drvdata(pdev, vib);
+
+	rc = input_register_device(vib->info);
+	if (rc < 0) {
+		dev_dbg(&pdev->dev, "couldn't register input device\n");
+		goto reg_err;
+	}
+
+	return 0;
+
+reg_err:
+	input_ff_destroy(vib->info);
+create_memless_err:
+	input_free_device(vib->info);
+err_read_vib:
+	kfree(vib);
+	return rc;
+}
+
+static int __devexit pmic8058_vib_remove(struct platform_device *pdev)
+{
+	struct pmic8058_vib *vib = platform_get_drvdata(pdev);
+
+	cancel_work_sync(&vib->work);
+	if (vib->enabled)
+		pmic8058_vib_set(vib, 0);
+
+	input_unregister_device(vib->info);
+	kfree(vib);
+
+	return 0;
+}
+
+static struct platform_driver pmic8058_vib_driver = {
+	.probe		= pmic8058_vib_probe,
+	.remove		= __devexit_p(pmic8058_vib_remove),
+	.driver		= {
+		.name	= "pm8058-vib",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init pmic8058_vib_init(void)
+{
+	return platform_driver_register(&pmic8058_vib_driver);
+}
+module_init(pmic8058_vib_init);
+
+static void __exit pmic8058_vib_exit(void)
+{
+	platform_driver_unregister(&pmic8058_vib_driver);
+}
+module_exit(pmic8058_vib_exit);
+
+MODULE_ALIAS("platform:pmic8058_vib");
+MODULE_DESCRIPTION("PMIC8058 vibrator driver memless framework");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/input/misc/pmic8xxx-pwrkey.c b/drivers/input/misc/pmic8xxx-pwrkey.c
index b3cfb9c..02838e3 100644
--- a/drivers/input/misc/pmic8xxx-pwrkey.c
+++ b/drivers/input/misc/pmic8xxx-pwrkey.c
@@ -30,10 +30,12 @@
 /**
  * struct pmic8xxx_pwrkey - pmic8xxx pwrkey information
  * @key_press_irq: key press irq number
+ * @pdata: platform data
  */
 struct pmic8xxx_pwrkey {
 	struct input_dev *pwr;
 	int key_press_irq;
+	const struct pm8xxx_pwrkey_platform_data *pdata;
 };
 
 static irqreturn_t pwrkey_press_irq(int irq, void *_pwrkey)
@@ -107,6 +109,8 @@
 	if (!pwrkey)
 		return -ENOMEM;
 
+	pwrkey->pdata = pdata;
+
 	pwr = input_allocate_device();
 	if (!pwr) {
 		dev_dbg(&pdev->dev, "Can't allocate power button\n");
@@ -153,7 +157,7 @@
 
 	platform_set_drvdata(pdev, pwrkey);
 
-	err = request_irq(key_press_irq, pwrkey_press_irq,
+	err = request_threaded_irq(key_press_irq, NULL, pwrkey_press_irq,
 		IRQF_TRIGGER_RISING, "pmic8xxx_pwrkey_press", pwrkey);
 	if (err < 0) {
 		dev_dbg(&pdev->dev, "Can't get %d IRQ for pwrkey: %d\n",
@@ -161,7 +165,7 @@
 		goto unreg_input_dev;
 	}
 
-	err = request_irq(key_release_irq, pwrkey_release_irq,
+	err = request_threaded_irq(key_release_irq, NULL, pwrkey_release_irq,
 		 IRQF_TRIGGER_RISING, "pmic8xxx_pwrkey_release", pwrkey);
 	if (err < 0) {
 		dev_dbg(&pdev->dev, "Can't get %d IRQ for pwrkey: %d\n",