Merge commit 'AU_LINUX_ANDROID_ICS.04.00.04.00.126' into msm-3.4

AU_LINUX_ANDROID_ICS.04.00.04.00.126 from msm-3.0.
First parent is from google/android-3.4.

* commit 'AU_LINUX_ANDROID_ICS.04.00.04.00.126': (8712 commits)
  PRNG: Device tree entry for qrng device.
  vidc:1080p: Set video core timeout value for Thumbnail mode
  msm: sps: improve the debugging support in SPS driver
  board-8064 msm: Overlap secure and non secure video firmware heaps.
  msm: clock: Add handoff ops for 7x30 and copper XO clocks
  msm_fb: display: Wait for external vsync before DTV IOMMU unmap
  msm: Fix ciruclar dependency in debug UART settings
  msm: gdsc: Add GDSC regulator driver for msm-copper
  defconfig: Enable Mobicore Driver.
  mobicore: Add mobicore driver.
  mobicore: rename variable to lower case.
  mobicore: rename folder.
  mobicore: add makefiles
  mobicore: initial import of kernel driver
  ASoC: msm: Add SLIMBUS_2_RX CPU DAI
  board-8064-gpio: Update FUNC for EPM SPI CS
  msm_fb: display: Remove chicken bit config during video playback
  mmc: msm_sdcc: enable the sanitize capability
  msm-fb: display: lm2 writeback support on mpq platfroms
  msm_fb: display: Disable LVDS phy & pll during panel off
  ...

Signed-off-by: Steve Muckle <smuckle@codeaurora.org>
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index d2c5095..574ec8a 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -470,6 +470,32 @@
 	  This driver can also be built as a module.  If so, the module
 	  will be called i2c-mpc.
 
+config I2C_MSM
+	tristate "MSM"
+	depends on I2C && (ARCH_MSM || ARCH_QSD)
+	default y
+	help
+	  If you say yes to this option, support will be included for the
+	  built-in I2C interface on the MSM or QSD family processors.
+
+config I2C_QUP
+	tristate "I2C_QUP"
+	depends on ARCH_MSM
+	help
+	  If you say yes to this option, support will be included for the
+	  built-in I2C interface on the MSM family processors.
+
+config I2C_SSBI
+	tristate "Qualcomm Single-wire Serial Bus Interface (SSBI)"
+	depends on I2C && (ARCH_MSM7X30 || ARCH_MSM8X60 || ARCH_FSM9XXX)
+	default n
+	help
+	  If you say yes to this option, support will be included for the
+	  built-in SSBI interface on the MSM family processors.
+
+          Note that SSBI is not an I2C device, but is functionally related
+          enough such that it is able to leverages the I2C framework.
+
 config I2C_MV64XXX
 	tristate "Marvell mv64xxx I2C Controller"
 	depends on (MV64X60 || PLAT_ORION) && EXPERIMENTAL
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 569567b..4f494fc 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -46,6 +46,9 @@
 obj-$(CONFIG_I2C_IOP3XX)	+= i2c-iop3xx.o
 obj-$(CONFIG_I2C_IXP2000)	+= i2c-ixp2000.o
 obj-$(CONFIG_I2C_MPC)		+= i2c-mpc.o
+obj-$(CONFIG_I2C_MSM)		+= i2c-msm.o
+obj-$(CONFIG_I2C_QUP)           += i2c-qup.o
+obj-$(CONFIG_I2C_SSBI)          += i2c-ssbi.o
 obj-$(CONFIG_I2C_MV64XXX)	+= i2c-mv64xxx.o
 obj-$(CONFIG_I2C_MXS)		+= i2c-mxs.o
 obj-$(CONFIG_I2C_NOMADIK)	+= i2c-nomadik.o
diff --git a/drivers/i2c/busses/i2c-msm.c b/drivers/i2c/busses/i2c-msm.c
new file mode 100644
index 0000000..b753fd0
--- /dev/null
+++ b/drivers/i2c/busses/i2c-msm.c
@@ -0,0 +1,798 @@
+/* drivers/i2c/busses/i2c-msm.c
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+/* #define DEBUG */
+
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <mach/board.h>
+#include <linux/mutex.h>
+#include <linux/timer.h>
+#include <linux/remote_spinlock.h>
+#include <linux/pm_qos.h>
+#include <linux/gpio.h>
+#include <linux/module.h>
+
+
+enum {
+	I2C_WRITE_DATA          = 0x00,
+	I2C_CLK_CTL             = 0x04,
+	I2C_STATUS              = 0x08,
+	I2C_READ_DATA           = 0x0c,
+	I2C_INTERFACE_SELECT    = 0x10,
+
+	I2C_WRITE_DATA_DATA_BYTE            = 0xff,
+	I2C_WRITE_DATA_ADDR_BYTE            = 1U << 8,
+	I2C_WRITE_DATA_LAST_BYTE            = 1U << 9,
+
+	I2C_CLK_CTL_FS_DIVIDER_VALUE        = 0xff,
+	I2C_CLK_CTL_HS_DIVIDER_VALUE        = 7U << 8,
+
+	I2C_STATUS_WR_BUFFER_FULL           = 1U << 0,
+	I2C_STATUS_RD_BUFFER_FULL           = 1U << 1,
+	I2C_STATUS_BUS_ERROR                = 1U << 2,
+	I2C_STATUS_PACKET_NACKED            = 1U << 3,
+	I2C_STATUS_ARB_LOST                 = 1U << 4,
+	I2C_STATUS_INVALID_WRITE            = 1U << 5,
+	I2C_STATUS_FAILED                   = 3U << 6,
+	I2C_STATUS_BUS_ACTIVE               = 1U << 8,
+	I2C_STATUS_BUS_MASTER               = 1U << 9,
+	I2C_STATUS_ERROR_MASK               = 0xfc,
+
+	I2C_INTERFACE_SELECT_INTF_SELECT    = 1U << 0,
+	I2C_INTERFACE_SELECT_SCL            = 1U << 8,
+	I2C_INTERFACE_SELECT_SDA            = 1U << 9,
+	I2C_STATUS_RX_DATA_STATE            = 3U << 11,
+	I2C_STATUS_LOW_CLK_STATE            = 3U << 13,
+};
+
+struct msm_i2c_dev {
+	struct device                *dev;
+	void __iomem                 *base;	/* virtual */
+	int                          irq;
+	struct clk                   *clk;
+	struct i2c_adapter           adap_pri;
+	struct i2c_adapter           adap_aux;
+
+	spinlock_t                   lock;
+
+	struct i2c_msg               *msg;
+	int                          rem;
+	int                          pos;
+	int                          cnt;
+	int                          err;
+	int                          flush_cnt;
+	int                          rd_acked;
+	int                          one_bit_t;
+	remote_mutex_t               r_lock;
+	int                          suspended;
+	struct mutex                 mlock;
+	struct msm_i2c_platform_data *pdata;
+	struct timer_list            pwr_timer;
+	int                          clk_state;
+	void                         *complete;
+
+	struct pm_qos_request pm_qos_req;
+};
+
+static void
+msm_i2c_pwr_mgmt(struct msm_i2c_dev *dev, unsigned int state)
+{
+	dev->clk_state = state;
+	if (state != 0)
+		clk_enable(dev->clk);
+	else
+		clk_disable(dev->clk);
+}
+
+static void
+msm_i2c_pwr_timer(unsigned long data)
+{
+	struct msm_i2c_dev *dev = (struct msm_i2c_dev *) data;
+	dev_dbg(dev->dev, "I2C_Power: Inactivity based power management\n");
+	if (dev->clk_state == 1)
+		msm_i2c_pwr_mgmt(dev, 0);
+}
+
+#ifdef DEBUG
+static void
+dump_status(uint32_t status)
+{
+	printk("STATUS (0x%.8x): ", status);
+	if (status & I2C_STATUS_BUS_MASTER)
+		printk("MST ");
+	if (status & I2C_STATUS_BUS_ACTIVE)
+		printk("ACT ");
+	if (status & I2C_STATUS_INVALID_WRITE)
+		printk("INV_WR ");
+	if (status & I2C_STATUS_ARB_LOST)
+		printk("ARB_LST ");
+	if (status & I2C_STATUS_PACKET_NACKED)
+		printk("NAK ");
+	if (status & I2C_STATUS_BUS_ERROR)
+		printk("BUS_ERR ");
+	if (status & I2C_STATUS_RD_BUFFER_FULL)
+		printk("RD_FULL ");
+	if (status & I2C_STATUS_WR_BUFFER_FULL)
+		printk("WR_FULL ");
+	if (status & I2C_STATUS_FAILED)
+		printk("FAIL 0x%x", (status & I2C_STATUS_FAILED));
+	printk("\n");
+}
+#endif
+
+static irqreturn_t
+msm_i2c_interrupt(int irq, void *devid)
+{
+	struct msm_i2c_dev *dev = devid;
+	uint32_t status = readl(dev->base + I2C_STATUS);
+	int err = 0;
+
+#ifdef DEBUG
+	dump_status(status);
+#endif
+
+	spin_lock(&dev->lock);
+	if (!dev->msg) {
+		printk(KERN_ERR "%s: IRQ but nothing to do!\n", __func__);
+		spin_unlock(&dev->lock);
+		return IRQ_HANDLED;
+	}
+
+	if (status & I2C_STATUS_ERROR_MASK) {
+		err = -EIO;
+		goto out_err;
+	}
+
+	if (dev->msg->flags & I2C_M_RD) {
+		if (status & I2C_STATUS_RD_BUFFER_FULL) {
+
+			/*
+			 * Theres something in the FIFO.
+			 * Are we expecting data or flush crap?
+			 */
+			if (dev->cnt) { /* DATA */
+				uint8_t *data = &dev->msg->buf[dev->pos];
+
+				/* This is in spin-lock. So there will be no
+				 * scheduling between reading the second-last
+				 * byte and writing LAST_BYTE to the controller.
+				 * So extra read-cycle-clock won't be generated
+				 * Per I2C MSM HW Specs: Write LAST_BYTE befure
+				 * reading 2nd last byte
+				 */
+				if (dev->cnt == 2)
+					writel(I2C_WRITE_DATA_LAST_BYTE,
+						dev->base + I2C_WRITE_DATA);
+				*data = readl(dev->base + I2C_READ_DATA);
+				dev->cnt--;
+				dev->pos++;
+				if (dev->msg->len == 1)
+					dev->rd_acked = 0;
+				if (dev->cnt == 0)
+					goto out_complete;
+
+			} else {
+				/* Now that extra read-cycle-clocks aren't
+				 * generated, this becomes error condition
+				 */
+				dev_err(dev->dev,
+					"read did not stop, status - %x\n",
+					status);
+				err = -EIO;
+				goto out_err;
+			}
+		} else if (dev->msg->len == 1 && dev->rd_acked == 0 &&
+				((status & I2C_STATUS_RX_DATA_STATE) ==
+				 I2C_STATUS_RX_DATA_STATE))
+			writel(I2C_WRITE_DATA_LAST_BYTE,
+				dev->base + I2C_WRITE_DATA);
+	} else {
+		uint16_t data;
+
+		if (status & I2C_STATUS_WR_BUFFER_FULL) {
+			dev_err(dev->dev,
+				"Write buffer full in ISR on write?\n");
+			err = -EIO;
+			goto out_err;
+		}
+
+		if (dev->cnt) {
+			/* Ready to take a byte */
+			data = dev->msg->buf[dev->pos];
+			if (dev->cnt == 1 && dev->rem == 1)
+				data |= I2C_WRITE_DATA_LAST_BYTE;
+
+			status = readl(dev->base + I2C_STATUS);
+			/*
+			 * Due to a hardware timing issue, data line setup time
+			 * may be reduced to less than recommended 250 ns.
+			 * This happens when next byte is written in a
+			 * particular window of clock line being low and master
+			 * not stretching the clock line. Due to setup time
+			 * violation, some slaves may miss first-bit of data, or
+			 * misinterprete data as start condition.
+			 * We introduce delay of just over 1/2 clock cycle to
+			 * ensure master stretches the clock line thereby
+			 * avoiding setup time violation. Delay is introduced
+			 * only if I2C clock FSM is LOW. The delay is not needed
+			 * if I2C clock FSM is HIGH or FORCED_LOW.
+			 */
+			if ((status & I2C_STATUS_LOW_CLK_STATE) ==
+					I2C_STATUS_LOW_CLK_STATE)
+				udelay((dev->one_bit_t >> 1) + 1);
+			writel(data, dev->base + I2C_WRITE_DATA);
+			dev->pos++;
+			dev->cnt--;
+		} else
+			goto out_complete;
+	}
+
+	spin_unlock(&dev->lock);
+	return IRQ_HANDLED;
+
+ out_err:
+	dev->err = err;
+ out_complete:
+	complete(dev->complete);
+	spin_unlock(&dev->lock);
+	return IRQ_HANDLED;
+}
+
+static int
+msm_i2c_poll_writeready(struct msm_i2c_dev *dev)
+{
+	uint32_t retries = 0;
+
+	while (retries != 2000) {
+		uint32_t status = readl(dev->base + I2C_STATUS);
+
+		if (!(status & I2C_STATUS_WR_BUFFER_FULL))
+			return 0;
+		if (retries++ > 1000)
+			usleep_range(100, 200);
+	}
+	return -ETIMEDOUT;
+}
+
+static int
+msm_i2c_poll_notbusy(struct msm_i2c_dev *dev)
+{
+	uint32_t retries = 0;
+
+	while (retries != 2000) {
+		uint32_t status = readl(dev->base + I2C_STATUS);
+
+		if (!(status & I2C_STATUS_BUS_ACTIVE))
+			return 0;
+		if (retries++ > 1000)
+			usleep_range(100, 200);
+	}
+	return -ETIMEDOUT;
+}
+
+static int
+msm_i2c_recover_bus_busy(struct msm_i2c_dev *dev, struct i2c_adapter *adap)
+{
+	int i;
+	int gpio_clk;
+	int gpio_dat;
+	uint32_t status = readl(dev->base + I2C_STATUS);
+	bool gpio_clk_status = false;
+
+	if (!(status & (I2C_STATUS_BUS_ACTIVE | I2C_STATUS_WR_BUFFER_FULL)))
+		return 0;
+
+	dev->pdata->msm_i2c_config_gpio(adap->nr, 0);
+	/* Even adapter is primary and Odd adapter is AUX */
+	if (adap->nr % 2) {
+		gpio_clk = dev->pdata->aux_clk;
+		gpio_dat = dev->pdata->aux_dat;
+	} else {
+		gpio_clk = dev->pdata->pri_clk;
+		gpio_dat = dev->pdata->pri_dat;
+	}
+
+	disable_irq(dev->irq);
+	if (status & I2C_STATUS_RD_BUFFER_FULL) {
+		dev_warn(dev->dev, "Read buffer full, status %x, intf %x\n",
+			 status, readl(dev->base + I2C_INTERFACE_SELECT));
+		writel(I2C_WRITE_DATA_LAST_BYTE, dev->base + I2C_WRITE_DATA);
+		readl(dev->base + I2C_READ_DATA);
+	} else if (status & I2C_STATUS_BUS_MASTER) {
+		dev_warn(dev->dev, "Still the bus master, status %x, intf %x\n",
+			 status, readl(dev->base + I2C_INTERFACE_SELECT));
+		writel(I2C_WRITE_DATA_LAST_BYTE | 0xff,
+		       dev->base + I2C_WRITE_DATA);
+	}
+
+	for (i = 0; i < 9; i++) {
+		if (gpio_get_value(gpio_dat) && gpio_clk_status)
+			break;
+		gpio_direction_output(gpio_clk, 0);
+		udelay(5);
+		gpio_direction_output(gpio_dat, 0);
+		udelay(5);
+		gpio_direction_input(gpio_clk);
+		udelay(5);
+		if (!gpio_get_value(gpio_clk))
+			usleep_range(20, 30);
+		if (!gpio_get_value(gpio_clk))
+			msleep(10);
+		gpio_clk_status = gpio_get_value(gpio_clk);
+		gpio_direction_input(gpio_dat);
+		udelay(5);
+	}
+	dev->pdata->msm_i2c_config_gpio(adap->nr, 1);
+	udelay(10);
+
+	status = readl(dev->base + I2C_STATUS);
+	if (!(status & I2C_STATUS_BUS_ACTIVE)) {
+		dev_info(dev->dev, "Bus busy cleared after %d clock cycles, "
+			 "status %x, intf %x\n",
+			 i, status, readl(dev->base + I2C_INTERFACE_SELECT));
+		enable_irq(dev->irq);
+		return 0;
+	}
+
+	dev_err(dev->dev, "Bus still busy, status %x, intf %x\n",
+		 status, readl(dev->base + I2C_INTERFACE_SELECT));
+	enable_irq(dev->irq);
+	return -EBUSY;
+}
+
+static int
+msm_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
+{
+	DECLARE_COMPLETION_ONSTACK(complete);
+	struct msm_i2c_dev *dev = i2c_get_adapdata(adap);
+	int ret;
+	int rem = num;
+	uint16_t addr;
+	long timeout;
+	unsigned long flags;
+	int check_busy = 1;
+
+	del_timer_sync(&dev->pwr_timer);
+	mutex_lock(&dev->mlock);
+	if (dev->suspended) {
+		mutex_unlock(&dev->mlock);
+		return -EIO;
+	}
+
+	if (dev->clk_state == 0) {
+		dev_dbg(dev->dev, "I2C_Power: Enable I2C clock(s)\n");
+		msm_i2c_pwr_mgmt(dev, 1);
+	}
+
+	/* Don't allow power collapse until we release remote spinlock */
+	pm_qos_update_request(&dev->pm_qos_req,  dev->pdata->pm_lat);
+	if (dev->pdata->rmutex) {
+		remote_mutex_lock(&dev->r_lock);
+		/* If other processor did some transactions, we may have
+		 * interrupt pending. Clear it
+		 */
+		irq_get_chip(dev->irq)->irq_ack(irq_get_irq_data(dev->irq));
+	}
+
+	if (adap == &dev->adap_pri)
+		writel(0, dev->base + I2C_INTERFACE_SELECT);
+	else
+		writel(I2C_INTERFACE_SELECT_INTF_SELECT,
+				dev->base + I2C_INTERFACE_SELECT);
+	enable_irq(dev->irq);
+	while (rem) {
+		addr = msgs->addr << 1;
+		if (msgs->flags & I2C_M_RD)
+			addr |= 1;
+
+		spin_lock_irqsave(&dev->lock, flags);
+		dev->msg = msgs;
+		dev->rem = rem;
+		dev->pos = 0;
+		dev->err = 0;
+		dev->flush_cnt = 0;
+		dev->cnt = msgs->len;
+		dev->complete = &complete;
+		spin_unlock_irqrestore(&dev->lock, flags);
+
+		if (check_busy) {
+			ret = msm_i2c_poll_notbusy(dev);
+			if (ret)
+				ret = msm_i2c_recover_bus_busy(dev, adap);
+				if (ret) {
+					dev_err(dev->dev,
+						"Error waiting for notbusy\n");
+					goto out_err;
+				}
+			check_busy = 0;
+		}
+
+		if (rem == 1 && msgs->len == 0)
+			addr |= I2C_WRITE_DATA_LAST_BYTE;
+
+		/* Wait for WR buffer not full */
+		ret = msm_i2c_poll_writeready(dev);
+		if (ret) {
+			ret = msm_i2c_recover_bus_busy(dev, adap);
+			if (ret) {
+				dev_err(dev->dev,
+				"Error waiting for write ready before addr\n");
+				goto out_err;
+			}
+		}
+
+		/* special case for doing 1 byte read.
+		 * There should be no scheduling between I2C controller becoming
+		 * ready to read and writing LAST-BYTE to I2C controller
+		 * This will avoid potential of I2C controller starting to latch
+		 * another extra byte.
+		 */
+		if ((msgs->len == 1) && (msgs->flags & I2C_M_RD)) {
+			uint32_t retries = 0;
+			spin_lock_irqsave(&dev->lock, flags);
+
+			writel(I2C_WRITE_DATA_ADDR_BYTE | addr,
+				dev->base + I2C_WRITE_DATA);
+
+			/* Poll for I2C controller going into RX_DATA mode to
+			 * ensure controller goes into receive mode.
+			 * Just checking write_buffer_full may not work since
+			 * there is delay between the write-buffer becoming
+			 * empty and the slave sending ACK to ensure I2C
+			 * controller goes in receive mode to receive data.
+			 */
+			while (retries != 2000) {
+				uint32_t status = readl(dev->base + I2C_STATUS);
+
+					if ((status & I2C_STATUS_RX_DATA_STATE)
+						== I2C_STATUS_RX_DATA_STATE)
+						break;
+				retries++;
+			}
+			if (retries >= 2000) {
+				dev->rd_acked = 0;
+				spin_unlock_irqrestore(&dev->lock, flags);
+				/* 1-byte-reads from slow devices in interrupt
+				 * context
+				 */
+				goto wait_for_int;
+			}
+
+			dev->rd_acked = 1;
+			writel(I2C_WRITE_DATA_LAST_BYTE,
+					dev->base + I2C_WRITE_DATA);
+			spin_unlock_irqrestore(&dev->lock, flags);
+		} else {
+			writel(I2C_WRITE_DATA_ADDR_BYTE | addr,
+					 dev->base + I2C_WRITE_DATA);
+		}
+		/* Polling and waiting for write_buffer_empty is not necessary.
+		 * Even worse, if we do, it can result in invalid status and
+		 * error if interrupt(s) occur while polling.
+		 */
+
+		/*
+		 * Now that we've setup the xfer, the ISR will transfer the data
+		 * and wake us up with dev->err set if there was an error
+		 */
+wait_for_int:
+
+		timeout = wait_for_completion_timeout(&complete, HZ);
+		if (!timeout) {
+			dev_err(dev->dev, "Transaction timed out\n");
+			writel(I2C_WRITE_DATA_LAST_BYTE,
+				dev->base + I2C_WRITE_DATA);
+			msleep(100);
+			/* FLUSH */
+			readl(dev->base + I2C_READ_DATA);
+			readl(dev->base + I2C_STATUS);
+			ret = -ETIMEDOUT;
+			goto out_err;
+		}
+		if (dev->err) {
+			dev_err(dev->dev,
+				"(%04x) Error during data xfer (%d)\n",
+				addr, dev->err);
+			ret = dev->err;
+			goto out_err;
+		}
+
+		if (msgs->flags & I2C_M_RD)
+			check_busy = 1;
+
+		msgs++;
+		rem--;
+	}
+
+	ret = num;
+ out_err:
+	spin_lock_irqsave(&dev->lock, flags);
+	dev->complete = NULL;
+	dev->msg = NULL;
+	dev->rem = 0;
+	dev->pos = 0;
+	dev->err = 0;
+	dev->flush_cnt = 0;
+	dev->cnt = 0;
+	spin_unlock_irqrestore(&dev->lock, flags);
+	disable_irq(dev->irq);
+	if (dev->pdata->rmutex)
+		remote_mutex_unlock(&dev->r_lock);
+	pm_qos_update_request(&dev->pm_qos_req,
+			      PM_QOS_DEFAULT_VALUE);
+	mod_timer(&dev->pwr_timer, (jiffies + 3*HZ));
+	mutex_unlock(&dev->mlock);
+	return ret;
+}
+
+static u32
+msm_i2c_func(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
+}
+
+static const struct i2c_algorithm msm_i2c_algo = {
+	.master_xfer	= msm_i2c_xfer,
+	.functionality	= msm_i2c_func,
+};
+
+static int
+msm_i2c_probe(struct platform_device *pdev)
+{
+	struct msm_i2c_dev	*dev;
+	struct resource		*mem, *irq, *ioarea;
+	int ret;
+	int fs_div;
+	int hs_div;
+	int i2c_clk;
+	int clk_ctl;
+	struct clk *clk;
+	struct msm_i2c_platform_data *pdata;
+
+	printk(KERN_INFO "msm_i2c_probe\n");
+
+	/* NOTE: driver uses the static register mapping */
+	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!mem) {
+		dev_err(&pdev->dev, "no mem resource?\n");
+		return -ENODEV;
+	}
+	irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (!irq) {
+		dev_err(&pdev->dev, "no irq resource?\n");
+		return -ENODEV;
+	}
+
+	ioarea = request_mem_region(mem->start, (mem->end - mem->start) + 1,
+			pdev->name);
+	if (!ioarea) {
+		dev_err(&pdev->dev, "I2C region already claimed\n");
+		return -EBUSY;
+	}
+	clk = clk_get(&pdev->dev, "core_clk");
+	if (IS_ERR(clk)) {
+		dev_err(&pdev->dev, "Could not get clock\n");
+		ret = PTR_ERR(clk);
+		goto err_clk_get_failed;
+	}
+
+	pdata = pdev->dev.platform_data;
+	if (!pdata) {
+		dev_err(&pdev->dev, "platform data not initialized\n");
+		ret = -ENOSYS;
+		goto err_clk_get_failed;
+	}
+	if (!pdata->msm_i2c_config_gpio) {
+		dev_err(&pdev->dev, "config_gpio function not initialized\n");
+		ret = -ENOSYS;
+		goto err_clk_get_failed;
+	}
+	/* We support frequencies upto FAST Mode(400KHz) */
+	if (pdata->clk_freq <= 0 || pdata->clk_freq > 400000) {
+		dev_err(&pdev->dev, "clock frequency not supported\n");
+		ret = -EIO;
+		goto err_clk_get_failed;
+	}
+
+	dev = kzalloc(sizeof(struct msm_i2c_dev), GFP_KERNEL);
+	if (!dev) {
+		ret = -ENOMEM;
+		goto err_alloc_dev_failed;
+	}
+
+	dev->dev = &pdev->dev;
+	dev->irq = irq->start;
+	dev->clk = clk;
+	dev->pdata = pdata;
+	dev->base = ioremap(mem->start, (mem->end - mem->start) + 1);
+	if (!dev->base) {
+		ret = -ENOMEM;
+		goto err_ioremap_failed;
+	}
+
+	dev->one_bit_t = USEC_PER_SEC/pdata->clk_freq;
+	spin_lock_init(&dev->lock);
+	platform_set_drvdata(pdev, dev);
+
+	clk_enable(clk);
+
+	if (pdata->rmutex) {
+		struct remote_mutex_id rmid;
+		rmid.r_spinlock_id = pdata->rsl_id;
+		rmid.delay_us = 10000000/pdata->clk_freq;
+		if (remote_mutex_init(&dev->r_lock, &rmid) != 0)
+			pdata->rmutex = 0;
+	}
+	/* I2C_HS_CLK = I2C_CLK/(3*(HS_DIVIDER_VALUE+1) */
+	/* I2C_FS_CLK = I2C_CLK/(2*(FS_DIVIDER_VALUE+3) */
+	/* FS_DIVIDER_VALUE = ((I2C_CLK / I2C_FS_CLK) / 2) - 3 */
+	i2c_clk = 19200000; /* input clock */
+	fs_div = ((i2c_clk / pdata->clk_freq) / 2) - 3;
+	hs_div = 3;
+	clk_ctl = ((hs_div & 0x7) << 8) | (fs_div & 0xff);
+	writel(clk_ctl, dev->base + I2C_CLK_CTL);
+	printk(KERN_INFO "msm_i2c_probe: clk_ctl %x, %d Hz\n",
+	       clk_ctl, i2c_clk / (2 * ((clk_ctl & 0xff) + 3)));
+
+	i2c_set_adapdata(&dev->adap_pri, dev);
+	dev->adap_pri.algo = &msm_i2c_algo;
+	strlcpy(dev->adap_pri.name,
+		"MSM I2C adapter-PRI",
+		sizeof(dev->adap_pri.name));
+
+	dev->adap_pri.nr = pdev->id;
+	ret = i2c_add_numbered_adapter(&dev->adap_pri);
+	if (ret) {
+		dev_err(&pdev->dev, "Primary i2c_add_adapter failed\n");
+		goto err_i2c_add_adapter_failed;
+	}
+
+	i2c_set_adapdata(&dev->adap_aux, dev);
+	dev->adap_aux.algo = &msm_i2c_algo;
+	strlcpy(dev->adap_aux.name,
+		"MSM I2C adapter-AUX",
+		sizeof(dev->adap_aux.name));
+
+	dev->adap_aux.nr = pdev->id + 1;
+	ret = i2c_add_numbered_adapter(&dev->adap_aux);
+	if (ret) {
+		dev_err(&pdev->dev, "auxiliary i2c_add_adapter failed\n");
+		i2c_del_adapter(&dev->adap_pri);
+		goto err_i2c_add_adapter_failed;
+	}
+	ret = request_irq(dev->irq, msm_i2c_interrupt,
+			IRQF_TRIGGER_RISING, pdev->name, dev);
+	if (ret) {
+		dev_err(&pdev->dev, "request_irq failed\n");
+		goto err_request_irq_failed;
+	}
+	pm_qos_add_request(&dev->pm_qos_req, PM_QOS_CPU_DMA_LATENCY,
+					     PM_QOS_DEFAULT_VALUE);
+	disable_irq(dev->irq);
+	dev->suspended = 0;
+	mutex_init(&dev->mlock);
+	dev->clk_state = 0;
+	/* Config GPIOs for primary and secondary lines */
+	pdata->msm_i2c_config_gpio(dev->adap_pri.nr, 1);
+	pdata->msm_i2c_config_gpio(dev->adap_aux.nr, 1);
+	clk_disable(dev->clk);
+	setup_timer(&dev->pwr_timer, msm_i2c_pwr_timer, (unsigned long) dev);
+
+	return 0;
+
+err_request_irq_failed:
+	i2c_del_adapter(&dev->adap_pri);
+	i2c_del_adapter(&dev->adap_aux);
+err_i2c_add_adapter_failed:
+	clk_disable(clk);
+	iounmap(dev->base);
+err_ioremap_failed:
+	kfree(dev);
+err_alloc_dev_failed:
+	clk_put(clk);
+err_clk_get_failed:
+	release_mem_region(mem->start, (mem->end - mem->start) + 1);
+	return ret;
+}
+
+static int
+msm_i2c_remove(struct platform_device *pdev)
+{
+	struct msm_i2c_dev	*dev = platform_get_drvdata(pdev);
+	struct resource		*mem;
+
+	/* Grab mutex to ensure ongoing transaction is over */
+	mutex_lock(&dev->mlock);
+	dev->suspended = 1;
+	mutex_unlock(&dev->mlock);
+	mutex_destroy(&dev->mlock);
+	del_timer_sync(&dev->pwr_timer);
+	if (dev->clk_state != 0)
+		msm_i2c_pwr_mgmt(dev, 0);
+	platform_set_drvdata(pdev, NULL);
+	pm_qos_remove_request(&dev->pm_qos_req);
+	free_irq(dev->irq, dev);
+	i2c_del_adapter(&dev->adap_pri);
+	i2c_del_adapter(&dev->adap_aux);
+	clk_put(dev->clk);
+	iounmap(dev->base);
+	kfree(dev);
+	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (mem)
+		release_mem_region(mem->start, (mem->end - mem->start) + 1);
+	return 0;
+}
+
+static int msm_i2c_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct msm_i2c_dev *dev = platform_get_drvdata(pdev);
+	/* Wait until current transaction finishes
+	 * Make sure remote lock is released before we suspend
+	 */
+	if (dev) {
+		/* Grab mutex to ensure ongoing transaction is over */
+		mutex_lock(&dev->mlock);
+		dev->suspended = 1;
+		mutex_unlock(&dev->mlock);
+		del_timer_sync(&dev->pwr_timer);
+		if (dev->clk_state != 0)
+			msm_i2c_pwr_mgmt(dev, 0);
+	}
+
+	return 0;
+}
+
+static int msm_i2c_resume(struct platform_device *pdev)
+{
+	struct msm_i2c_dev *dev = platform_get_drvdata(pdev);
+	dev->suspended = 0;
+	return 0;
+}
+
+static struct platform_driver msm_i2c_driver = {
+	.probe		= msm_i2c_probe,
+	.remove		= msm_i2c_remove,
+	.suspend	= msm_i2c_suspend,
+	.resume		= msm_i2c_resume,
+	.driver		= {
+		.name	= "msm_i2c",
+		.owner	= THIS_MODULE,
+	},
+};
+
+/* I2C may be needed to bring up other drivers */
+static int __init
+msm_i2c_init_driver(void)
+{
+	return platform_driver_register(&msm_i2c_driver);
+}
+subsys_initcall(msm_i2c_init_driver);
+
+static void __exit msm_i2c_exit_driver(void)
+{
+	platform_driver_unregister(&msm_i2c_driver);
+}
+module_exit(msm_i2c_exit_driver);
+
diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
new file mode 100644
index 0000000..297afa7
--- /dev/null
+++ b/drivers/i2c/busses/i2c-qup.c
@@ -0,0 +1,1515 @@
+/* Copyright (c) 2009-2012, 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.
+ *
+ */
+/*
+ * QUP driver for Qualcomm MSM platforms
+ *
+ */
+
+/* #define DEBUG */
+
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/mutex.h>
+#include <linux/timer.h>
+#include <linux/slab.h>
+#include <mach/board.h>
+#include <mach/gpiomux.h>
+#include <linux/slab.h>
+#include <linux/pm_runtime.h>
+#include <linux/gpio.h>
+#include <linux/of.h>
+#include <linux/of_i2c.h>
+
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION("0.2");
+MODULE_ALIAS("platform:i2c_qup");
+
+/* QUP Registers */
+enum {
+	QUP_CONFIG              = 0x0,
+	QUP_STATE               = 0x4,
+	QUP_IO_MODE             = 0x8,
+	QUP_SW_RESET            = 0xC,
+	QUP_OPERATIONAL         = 0x18,
+	QUP_ERROR_FLAGS         = 0x1C,
+	QUP_ERROR_FLAGS_EN      = 0x20,
+	QUP_MX_READ_CNT         = 0x208,
+	QUP_MX_INPUT_CNT        = 0x200,
+	QUP_MX_WR_CNT           = 0x100,
+	QUP_OUT_DEBUG           = 0x108,
+	QUP_OUT_FIFO_CNT        = 0x10C,
+	QUP_OUT_FIFO_BASE       = 0x110,
+	QUP_IN_READ_CUR         = 0x20C,
+	QUP_IN_DEBUG            = 0x210,
+	QUP_IN_FIFO_CNT         = 0x214,
+	QUP_IN_FIFO_BASE        = 0x218,
+	QUP_I2C_CLK_CTL         = 0x400,
+	QUP_I2C_STATUS          = 0x404,
+};
+
+/* QUP States and reset values */
+enum {
+	QUP_RESET_STATE         = 0,
+	QUP_RUN_STATE           = 1U,
+	QUP_STATE_MASK          = 3U,
+	QUP_PAUSE_STATE         = 3U,
+	QUP_STATE_VALID         = 1U << 2,
+	QUP_I2C_MAST_GEN        = 1U << 4,
+	QUP_OPERATIONAL_RESET   = 0xFF0,
+	QUP_I2C_STATUS_RESET    = 0xFFFFFC,
+};
+
+/* QUP OPERATIONAL FLAGS */
+enum {
+	QUP_OUT_SVC_FLAG        = 1U << 8,
+	QUP_IN_SVC_FLAG         = 1U << 9,
+	QUP_MX_INPUT_DONE       = 1U << 11,
+};
+
+/* I2C mini core related values */
+enum {
+	I2C_MINI_CORE           = 2U << 8,
+	I2C_N_VAL               = 0xF,
+
+};
+
+/* Packing Unpacking words in FIFOs , and IO modes*/
+enum {
+	QUP_WR_BLK_MODE  = 1U << 10,
+	QUP_RD_BLK_MODE  = 1U << 12,
+	QUP_UNPACK_EN = 1U << 14,
+	QUP_PACK_EN = 1U << 15,
+};
+
+/* QUP tags */
+enum {
+	QUP_OUT_NOP   = 0,
+	QUP_OUT_START = 1U << 8,
+	QUP_OUT_DATA  = 2U << 8,
+	QUP_OUT_STOP  = 3U << 8,
+	QUP_OUT_REC   = 4U << 8,
+	QUP_IN_DATA   = 5U << 8,
+	QUP_IN_STOP   = 6U << 8,
+	QUP_IN_NACK   = 7U << 8,
+};
+
+/* Status, Error flags */
+enum {
+	I2C_STATUS_WR_BUFFER_FULL  = 1U << 0,
+	I2C_STATUS_BUS_ACTIVE      = 1U << 8,
+	I2C_STATUS_BUS_MASTER	   = 1U << 9,
+	I2C_STATUS_ERROR_MASK      = 0x38000FC,
+	QUP_I2C_NACK_FLAG          = 1U << 3,
+	QUP_IN_NOT_EMPTY           = 1U << 5,
+	QUP_STATUS_ERROR_FLAGS     = 0x7C,
+};
+
+/* Master status clock states */
+enum {
+	I2C_CLK_RESET_BUSIDLE_STATE	= 0,
+	I2C_CLK_FORCED_LOW_STATE	= 5,
+};
+
+#define QUP_MAX_CLK_STATE_RETRIES	300
+
+static char const * const i2c_rsrcs[] = {"i2c_clk", "i2c_sda"};
+
+static struct gpiomux_setting recovery_config = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+struct qup_i2c_dev {
+	struct device                *dev;
+	void __iomem                 *base;		/* virtual */
+	void __iomem                 *gsbi;		/* virtual */
+	int                          in_irq;
+	int                          out_irq;
+	int                          err_irq;
+	int                          num_irqs;
+	struct clk                   *clk;
+	struct clk                   *pclk;
+	struct i2c_adapter           adapter;
+
+	struct i2c_msg               *msg;
+	int                          pos;
+	int                          cnt;
+	int                          err;
+	int                          mode;
+	int                          clk_ctl;
+	int                          one_bit_t;
+	int                          out_fifo_sz;
+	int                          in_fifo_sz;
+	int                          out_blk_sz;
+	int                          in_blk_sz;
+	int                          wr_sz;
+	struct msm_i2c_platform_data *pdata;
+	int                          suspended;
+	int                          clk_state;
+	struct timer_list            pwr_timer;
+	struct mutex                 mlock;
+	void                         *complete;
+	int                          i2c_gpios[ARRAY_SIZE(i2c_rsrcs)];
+};
+
+#ifdef DEBUG
+static void
+qup_print_status(struct qup_i2c_dev *dev)
+{
+	uint32_t val;
+	val = readl_relaxed(dev->base+QUP_CONFIG);
+	dev_dbg(dev->dev, "Qup config is :0x%x\n", val);
+	val = readl_relaxed(dev->base+QUP_STATE);
+	dev_dbg(dev->dev, "Qup state is :0x%x\n", val);
+	val = readl_relaxed(dev->base+QUP_IO_MODE);
+	dev_dbg(dev->dev, "Qup mode is :0x%x\n", val);
+}
+#else
+static inline void qup_print_status(struct qup_i2c_dev *dev)
+{
+}
+#endif
+
+static irqreturn_t
+qup_i2c_interrupt(int irq, void *devid)
+{
+	struct qup_i2c_dev *dev = devid;
+	uint32_t status = readl_relaxed(dev->base + QUP_I2C_STATUS);
+	uint32_t status1 = readl_relaxed(dev->base + QUP_ERROR_FLAGS);
+	uint32_t op_flgs = readl_relaxed(dev->base + QUP_OPERATIONAL);
+	int err = 0;
+
+	if (!dev->msg || !dev->complete) {
+		/* Clear Error interrupt if it's a level triggered interrupt*/
+		if (dev->num_irqs == 1) {
+			writel_relaxed(QUP_RESET_STATE, dev->base+QUP_STATE);
+			/* Ensure that state is written before ISR exits */
+			mb();
+		}
+		return IRQ_HANDLED;
+	}
+
+	if (status & I2C_STATUS_ERROR_MASK) {
+		dev_err(dev->dev, "QUP: I2C status flags :0x%x, irq:%d\n",
+			status, irq);
+		err = status;
+		/* Clear Error interrupt if it's a level triggered interrupt*/
+		if (dev->num_irqs == 1) {
+			writel_relaxed(QUP_RESET_STATE, dev->base+QUP_STATE);
+			/* Ensure that state is written before ISR exits */
+			mb();
+		}
+		goto intr_done;
+	}
+
+	if (status1 & 0x7F) {
+		dev_err(dev->dev, "QUP: QUP status flags :0x%x\n", status1);
+		err = -status1;
+		/* Clear Error interrupt if it's a level triggered interrupt*/
+		if (dev->num_irqs == 1) {
+			writel_relaxed((status1 & QUP_STATUS_ERROR_FLAGS),
+				dev->base + QUP_ERROR_FLAGS);
+			/* Ensure that error flags are cleared before ISR
+			 * exits
+			 */
+			mb();
+		}
+		goto intr_done;
+	}
+
+	if ((dev->num_irqs == 3) && (dev->msg->flags == I2C_M_RD)
+		&& (irq == dev->out_irq))
+		return IRQ_HANDLED;
+	if (op_flgs & QUP_OUT_SVC_FLAG) {
+		writel_relaxed(QUP_OUT_SVC_FLAG, dev->base + QUP_OPERATIONAL);
+		/* Ensure that service flag is acknowledged before ISR exits */
+		mb();
+	}
+	if (dev->msg->flags == I2C_M_RD) {
+		if ((op_flgs & QUP_MX_INPUT_DONE) ||
+			(op_flgs & QUP_IN_SVC_FLAG)) {
+			writel_relaxed(QUP_IN_SVC_FLAG, dev->base
+					+ QUP_OPERATIONAL);
+			/* Ensure that service flag is acknowledged before ISR
+			 * exits
+			 */
+			mb();
+		} else
+			return IRQ_HANDLED;
+	}
+
+intr_done:
+	dev_dbg(dev->dev, "QUP intr= %d, i2c status=0x%x, qup status = 0x%x\n",
+			irq, status, status1);
+	qup_print_status(dev);
+	dev->err = err;
+	complete(dev->complete);
+	return IRQ_HANDLED;
+}
+
+static int
+qup_i2c_poll_state(struct qup_i2c_dev *dev, uint32_t req_state, bool only_valid)
+{
+	uint32_t retries = 0;
+
+	dev_dbg(dev->dev, "Polling for state:0x%x, or valid-only:%d\n",
+				req_state, only_valid);
+
+	while (retries != 2000) {
+		uint32_t status = readl_relaxed(dev->base + QUP_STATE);
+
+		/*
+		 * If only valid bit needs to be checked, requested state is
+		 * 'don't care'
+		 */
+		if (status & QUP_STATE_VALID) {
+			if (only_valid)
+				return 0;
+			else if ((req_state & QUP_I2C_MAST_GEN) &&
+					(status & QUP_I2C_MAST_GEN))
+				return 0;
+			else if ((status & QUP_STATE_MASK) == req_state)
+				return 0;
+		}
+		if (retries++ == 1000)
+			udelay(100);
+	}
+	return -ETIMEDOUT;
+}
+
+static int
+qup_update_state(struct qup_i2c_dev *dev, uint32_t state)
+{
+	if (qup_i2c_poll_state(dev, 0, true) != 0)
+		return -EIO;
+	writel_relaxed(state, dev->base + QUP_STATE);
+	if (qup_i2c_poll_state(dev, state, false) != 0)
+		return -EIO;
+	return 0;
+}
+
+/*
+ * Before calling qup_config_core_on_en(), please make
+ * sure that QuPE core is in RESET state.
+ */
+static void
+qup_config_core_on_en(struct qup_i2c_dev *dev)
+{
+	uint32_t status;
+
+	status = readl_relaxed(dev->base + QUP_CONFIG);
+	status |= BIT(13);
+	writel_relaxed(status, dev->base + QUP_CONFIG);
+	/* making sure that write has really gone through */
+	mb();
+}
+
+static void
+qup_i2c_pwr_mgmt(struct qup_i2c_dev *dev, unsigned int state)
+{
+	dev->clk_state = state;
+	if (state != 0) {
+		clk_enable(dev->clk);
+		clk_enable(dev->pclk);
+	} else {
+		qup_update_state(dev, QUP_RESET_STATE);
+		clk_disable(dev->clk);
+		qup_config_core_on_en(dev);
+		clk_disable(dev->pclk);
+	}
+}
+
+static void
+qup_i2c_pwr_timer(unsigned long data)
+{
+	struct qup_i2c_dev *dev = (struct qup_i2c_dev *) data;
+	dev_dbg(dev->dev, "QUP_Power: Inactivity based power management\n");
+	if (dev->clk_state == 1)
+		qup_i2c_pwr_mgmt(dev, 0);
+}
+
+static int
+qup_i2c_poll_writeready(struct qup_i2c_dev *dev, int rem)
+{
+	uint32_t retries = 0;
+
+	while (retries != 2000) {
+		uint32_t status = readl_relaxed(dev->base + QUP_I2C_STATUS);
+
+		if (!(status & I2C_STATUS_WR_BUFFER_FULL)) {
+			if (((dev->msg->flags & I2C_M_RD) || (rem == 0)) &&
+				!(status & I2C_STATUS_BUS_ACTIVE))
+				return 0;
+			else if ((dev->msg->flags == 0) && (rem > 0))
+				return 0;
+			else /* 1-bit delay before we check for bus busy */
+				udelay(dev->one_bit_t);
+		}
+		if (retries++ == 1000) {
+			/*
+			 * Wait for FIFO number of bytes to be absolutely sure
+			 * that I2C write state machine is not idle. Each byte
+			 * takes 9 clock cycles. (8 bits + 1 ack)
+			 */
+			usleep_range((dev->one_bit_t * (dev->out_fifo_sz * 9)),
+				(dev->one_bit_t * (dev->out_fifo_sz * 9)));
+		}
+	}
+	qup_print_status(dev);
+	return -ETIMEDOUT;
+}
+
+static int qup_i2c_poll_clock_ready(struct qup_i2c_dev *dev)
+{
+	uint32_t retries = 0;
+
+	/*
+	 * Wait for the clock state to transition to either IDLE or FORCED
+	 * LOW.  This will usually happen within one cycle of the i2c clock.
+	 */
+
+	while (retries++ < QUP_MAX_CLK_STATE_RETRIES) {
+		uint32_t status = readl_relaxed(dev->base + QUP_I2C_STATUS);
+		uint32_t clk_state = (status >> 13) & 0x7;
+
+		if (clk_state == I2C_CLK_RESET_BUSIDLE_STATE ||
+				clk_state == I2C_CLK_FORCED_LOW_STATE)
+			return 0;
+		/* 1-bit delay before we check again */
+		udelay(dev->one_bit_t);
+	}
+
+	dev_err(dev->dev, "Error waiting for clk ready\n");
+	return -ETIMEDOUT;
+}
+
+static inline int qup_i2c_request_gpios(struct qup_i2c_dev *dev)
+{
+	int i;
+	int result = 0;
+
+	for (i = 0; i < ARRAY_SIZE(i2c_rsrcs); ++i) {
+		if (dev->i2c_gpios[i] >= 0) {
+			result = gpio_request(dev->i2c_gpios[i], i2c_rsrcs[i]);
+			if (result) {
+				dev_err(dev->dev,
+					"gpio_request for pin %d failed\
+					with error %d\n", dev->i2c_gpios[i],
+					result);
+				goto error;
+			}
+		}
+	}
+	return 0;
+
+error:
+	for (; --i >= 0;) {
+		if (dev->i2c_gpios[i] >= 0)
+			gpio_free(dev->i2c_gpios[i]);
+	}
+	return result;
+}
+
+static inline void qup_i2c_free_gpios(struct qup_i2c_dev *dev)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(i2c_rsrcs); ++i) {
+		if (dev->i2c_gpios[i] >= 0)
+			gpio_free(dev->i2c_gpios[i]);
+	}
+}
+
+#ifdef DEBUG
+static void qup_verify_fifo(struct qup_i2c_dev *dev, uint32_t val,
+				uint32_t addr, int rdwr)
+{
+	if (rdwr)
+		dev_dbg(dev->dev, "RD:Wrote 0x%x to out_ff:0x%x\n", val, addr);
+	else
+		dev_dbg(dev->dev, "WR:Wrote 0x%x to out_ff:0x%x\n", val, addr);
+}
+#else
+static inline void qup_verify_fifo(struct qup_i2c_dev *dev, uint32_t val,
+				uint32_t addr, int rdwr)
+{
+}
+#endif
+
+static void
+qup_issue_read(struct qup_i2c_dev *dev, struct i2c_msg *msg, int *idx,
+		uint32_t carry_over)
+{
+	uint16_t addr = (msg->addr << 1) | 1;
+	/* QUP limit 256 bytes per read. By HW design, 0 in the 8-bit field
+	 * is treated as 256 byte read.
+	 */
+	uint16_t rd_len = ((dev->cnt == 256) ? 0 : dev->cnt);
+
+	if (*idx % 4) {
+		writel_relaxed(carry_over | ((QUP_OUT_START | addr) << 16),
+		dev->base + QUP_OUT_FIFO_BASE);/* + (*idx-2)); */
+
+		qup_verify_fifo(dev, carry_over |
+			((QUP_OUT_START | addr) << 16), (uint32_t)dev->base
+			+ QUP_OUT_FIFO_BASE + (*idx - 2), 1);
+		writel_relaxed((QUP_OUT_REC | rd_len),
+			dev->base + QUP_OUT_FIFO_BASE);/* + (*idx+2)); */
+
+		qup_verify_fifo(dev, (QUP_OUT_REC | rd_len),
+		(uint32_t)dev->base + QUP_OUT_FIFO_BASE + (*idx + 2), 1);
+	} else {
+		writel_relaxed(((QUP_OUT_REC | rd_len) << 16)
+			| QUP_OUT_START | addr,
+			dev->base + QUP_OUT_FIFO_BASE);/* + (*idx)); */
+
+		qup_verify_fifo(dev, QUP_OUT_REC << 16 | rd_len << 16 |
+		QUP_OUT_START | addr,
+		(uint32_t)dev->base + QUP_OUT_FIFO_BASE + (*idx), 1);
+	}
+	*idx += 4;
+}
+
+static void
+qup_issue_write(struct qup_i2c_dev *dev, struct i2c_msg *msg, int rem,
+			int *idx, uint32_t *carry_over)
+{
+	int entries = dev->cnt;
+	int empty_sl = dev->wr_sz - ((*idx) >> 1);
+	int i = 0;
+	uint32_t val = 0;
+	uint32_t last_entry = 0;
+	uint16_t addr = msg->addr << 1;
+
+	if (dev->pos == 0) {
+		if (*idx % 4) {
+			writel_relaxed(*carry_over | ((QUP_OUT_START |
+							addr) << 16),
+					dev->base + QUP_OUT_FIFO_BASE);
+
+			qup_verify_fifo(dev, *carry_over | QUP_OUT_START << 16 |
+				addr << 16, (uint32_t)dev->base +
+				QUP_OUT_FIFO_BASE + (*idx) - 2, 0);
+		} else
+			val = QUP_OUT_START | addr;
+		*idx += 2;
+		i++;
+		entries++;
+	} else {
+		/* Avoid setp time issue by adding 1 NOP when number of bytes
+		 * are more than FIFO/BLOCK size. setup time issue can't appear
+		 * otherwise since next byte to be written will always be ready
+		 */
+		val = (QUP_OUT_NOP | 1);
+		*idx += 2;
+		i++;
+		entries++;
+	}
+	if (entries > empty_sl)
+		entries = empty_sl;
+
+	for (; i < (entries - 1); i++) {
+		if (*idx % 4) {
+			writel_relaxed(val | ((QUP_OUT_DATA |
+				msg->buf[dev->pos]) << 16),
+				dev->base + QUP_OUT_FIFO_BASE);
+
+			qup_verify_fifo(dev, val | QUP_OUT_DATA << 16 |
+				msg->buf[dev->pos] << 16, (uint32_t)dev->base +
+				QUP_OUT_FIFO_BASE + (*idx) - 2, 0);
+		} else
+			val = QUP_OUT_DATA | msg->buf[dev->pos];
+		(*idx) += 2;
+		dev->pos++;
+	}
+	if (dev->pos < (msg->len - 1))
+		last_entry = QUP_OUT_DATA;
+	else if (rem > 1) /* not last array entry */
+		last_entry = QUP_OUT_DATA;
+	else
+		last_entry = QUP_OUT_STOP;
+	if ((*idx % 4) == 0) {
+		/*
+		 * If read-start and read-command end up in different fifos, it
+		 * may result in extra-byte being read due to extra-read cycle.
+		 * Avoid that by inserting NOP as the last entry of fifo only
+		 * if write command(s) leave 1 space in fifo.
+		 */
+		if (rem > 1) {
+			struct i2c_msg *next = msg + 1;
+			if (next->addr == msg->addr && (next->flags & I2C_M_RD)
+				&& *idx == ((dev->wr_sz*2) - 4)) {
+				writel_relaxed(((last_entry |
+					msg->buf[dev->pos]) |
+					((1 | QUP_OUT_NOP) << 16)), dev->base +
+					QUP_OUT_FIFO_BASE);/* + (*idx) - 2); */
+
+				qup_verify_fifo(dev,
+					((last_entry | msg->buf[dev->pos]) |
+					((1 | QUP_OUT_NOP) << 16)),
+					(uint32_t)dev->base +
+					QUP_OUT_FIFO_BASE + (*idx), 0);
+				*idx += 2;
+			} else if (next->flags == 0 && dev->pos == msg->len - 1
+					&& *idx < (dev->wr_sz*2) &&
+					(next->addr != msg->addr)) {
+				/* Last byte of an intermittent write */
+				writel_relaxed((QUP_OUT_STOP |
+						msg->buf[dev->pos]),
+					dev->base + QUP_OUT_FIFO_BASE);
+
+				qup_verify_fifo(dev,
+					QUP_OUT_STOP | msg->buf[dev->pos],
+					(uint32_t)dev->base +
+					QUP_OUT_FIFO_BASE + (*idx), 0);
+				*idx += 2;
+			} else
+				*carry_over = (last_entry | msg->buf[dev->pos]);
+		} else {
+			writel_relaxed((last_entry | msg->buf[dev->pos]),
+			dev->base + QUP_OUT_FIFO_BASE);/* + (*idx) - 2); */
+
+			qup_verify_fifo(dev, last_entry | msg->buf[dev->pos],
+			(uint32_t)dev->base + QUP_OUT_FIFO_BASE +
+			(*idx), 0);
+		}
+	} else {
+		writel_relaxed(val | ((last_entry | msg->buf[dev->pos]) << 16),
+		dev->base + QUP_OUT_FIFO_BASE);/* + (*idx) - 2); */
+
+		qup_verify_fifo(dev, val | (last_entry << 16) |
+		(msg->buf[dev->pos] << 16), (uint32_t)dev->base +
+		QUP_OUT_FIFO_BASE + (*idx) - 2, 0);
+	}
+
+	*idx += 2;
+	dev->pos++;
+	dev->cnt = msg->len - dev->pos;
+}
+
+static void
+qup_set_read_mode(struct qup_i2c_dev *dev, int rd_len)
+{
+	uint32_t wr_mode = (dev->wr_sz < dev->out_fifo_sz) ?
+				QUP_WR_BLK_MODE : 0;
+	if (rd_len > 256) {
+		dev_dbg(dev->dev, "HW limit: Breaking reads in chunk of 256\n");
+		rd_len = 256;
+	}
+	if (rd_len <= dev->in_fifo_sz) {
+		writel_relaxed(wr_mode | QUP_PACK_EN | QUP_UNPACK_EN,
+			dev->base + QUP_IO_MODE);
+		writel_relaxed(rd_len, dev->base + QUP_MX_READ_CNT);
+	} else {
+		writel_relaxed(wr_mode | QUP_RD_BLK_MODE |
+			QUP_PACK_EN | QUP_UNPACK_EN, dev->base + QUP_IO_MODE);
+		writel_relaxed(rd_len, dev->base + QUP_MX_INPUT_CNT);
+	}
+}
+
+static int
+qup_set_wr_mode(struct qup_i2c_dev *dev, int rem)
+{
+	int total_len = 0;
+	int ret = 0;
+	int len = dev->msg->len;
+	struct i2c_msg *next = NULL;
+	if (rem > 1)
+		next = dev->msg + 1;
+	while (rem > 1 && next->flags == 0 && (next->addr == dev->msg->addr)) {
+		len += next->len + 1;
+		next = next + 1;
+		rem--;
+	}
+	if (len >= (dev->out_fifo_sz - 1)) {
+		total_len = len + 1 + (len/(dev->out_blk_sz-1));
+
+		writel_relaxed(QUP_WR_BLK_MODE | QUP_PACK_EN | QUP_UNPACK_EN,
+			dev->base + QUP_IO_MODE);
+		dev->wr_sz = dev->out_blk_sz;
+	} else
+		writel_relaxed(QUP_PACK_EN | QUP_UNPACK_EN,
+			dev->base + QUP_IO_MODE);
+
+	if (rem > 1) {
+		if (next->addr == dev->msg->addr &&
+			next->flags == I2C_M_RD) {
+			qup_set_read_mode(dev, next->len);
+			/* make sure read start & read command are in 1 blk */
+			if ((total_len % dev->out_blk_sz) ==
+				(dev->out_blk_sz - 1))
+				total_len += 3;
+			else
+				total_len += 2;
+		}
+	}
+	/* WRITE COUNT register valid/used only in block mode */
+	if (dev->wr_sz == dev->out_blk_sz)
+		writel_relaxed(total_len, dev->base + QUP_MX_WR_CNT);
+	return ret;
+}
+
+
+static void qup_i2c_recover_bus_busy(struct qup_i2c_dev *dev)
+{
+	int i;
+	int gpio_clk;
+	int gpio_dat;
+	bool gpio_clk_status = false;
+	uint32_t status = readl_relaxed(dev->base + QUP_I2C_STATUS);
+	struct gpiomux_setting old_gpio_setting;
+
+	if (dev->pdata->msm_i2c_config_gpio)
+		return;
+
+	if (!(status & (I2C_STATUS_BUS_ACTIVE)) ||
+		(status & (I2C_STATUS_BUS_MASTER)))
+		return;
+
+	gpio_clk = dev->i2c_gpios[0];
+	gpio_dat = dev->i2c_gpios[1];
+
+	if ((gpio_clk == -1) && (gpio_dat == -1)) {
+		dev_err(dev->dev, "Recovery failed due to undefined GPIO's\n");
+		return;
+	}
+
+	disable_irq(dev->err_irq);
+	for (i = 0; i < ARRAY_SIZE(i2c_rsrcs); ++i) {
+		if (msm_gpiomux_write(dev->i2c_gpios[i], GPIOMUX_ACTIVE,
+				&recovery_config, &old_gpio_setting)) {
+			dev_err(dev->dev, "GPIO pins have no active setting\n");
+			goto recovery_end;
+		}
+	}
+
+	dev_warn(dev->dev, "i2c_scl: %d, i2c_sda: %d\n",
+		 gpio_get_value(gpio_clk), gpio_get_value(gpio_dat));
+
+	for (i = 0; i < 9; i++) {
+		if (gpio_get_value(gpio_dat) && gpio_clk_status)
+			break;
+		gpio_direction_output(gpio_clk, 0);
+		udelay(5);
+		gpio_direction_output(gpio_dat, 0);
+		udelay(5);
+		gpio_direction_input(gpio_clk);
+		udelay(5);
+		if (!gpio_get_value(gpio_clk))
+			udelay(20);
+		if (!gpio_get_value(gpio_clk))
+			usleep_range(10000, 10000);
+		gpio_clk_status = gpio_get_value(gpio_clk);
+		gpio_direction_input(gpio_dat);
+		udelay(5);
+	}
+
+	/* Configure ALT funciton to QUP I2C*/
+	for (i = 0; i < ARRAY_SIZE(i2c_rsrcs); ++i) {
+		msm_gpiomux_write(dev->i2c_gpios[i], GPIOMUX_ACTIVE,
+				&old_gpio_setting, NULL);
+	}
+
+	udelay(10);
+
+	status = readl_relaxed(dev->base + QUP_I2C_STATUS);
+	if (!(status & I2C_STATUS_BUS_ACTIVE)) {
+		dev_info(dev->dev, "Bus busy cleared after %d clock cycles, "
+			 "status %x\n",
+			 i, status);
+		goto recovery_end;
+	}
+
+	dev_warn(dev->dev, "Bus still busy, status %x\n", status);
+
+recovery_end:
+	enable_irq(dev->err_irq);
+}
+
+static int
+qup_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
+{
+	DECLARE_COMPLETION_ONSTACK(complete);
+	struct qup_i2c_dev *dev = i2c_get_adapdata(adap);
+	int ret;
+	int rem = num;
+	long timeout;
+	int err;
+
+	del_timer_sync(&dev->pwr_timer);
+	mutex_lock(&dev->mlock);
+
+	if (dev->suspended) {
+		mutex_unlock(&dev->mlock);
+		return -EIO;
+	}
+
+	if (dev->clk_state == 0)
+		qup_i2c_pwr_mgmt(dev, 1);
+
+	/* Initialize QUP registers during first transfer */
+	if (dev->clk_ctl == 0) {
+		int fs_div;
+		int hs_div;
+		uint32_t fifo_reg;
+
+		if (dev->gsbi) {
+			writel_relaxed(0x2 << 4, dev->gsbi);
+			/* GSBI memory is not in the same 1K region as other
+			 * QUP registers. mb() here ensures that the GSBI
+			 * register is updated in correct order and that the
+			 * write has gone through before programming QUP core
+			 * registers
+			 */
+			mb();
+		}
+
+		fs_div = ((dev->pdata->src_clk_rate
+				/ dev->pdata->clk_freq) / 2) - 3;
+		hs_div = 3;
+		dev->clk_ctl = ((hs_div & 0x7) << 8) | (fs_div & 0xff);
+		fifo_reg = readl_relaxed(dev->base + QUP_IO_MODE);
+		if (fifo_reg & 0x3)
+			dev->out_blk_sz = (fifo_reg & 0x3) * 16;
+		else
+			dev->out_blk_sz = 16;
+		if (fifo_reg & 0x60)
+			dev->in_blk_sz = ((fifo_reg & 0x60) >> 5) * 16;
+		else
+			dev->in_blk_sz = 16;
+		/*
+		 * The block/fifo size w.r.t. 'actual data' is 1/2 due to 'tag'
+		 * associated with each byte written/received
+		 */
+		dev->out_blk_sz /= 2;
+		dev->in_blk_sz /= 2;
+		dev->out_fifo_sz = dev->out_blk_sz *
+					(2 << ((fifo_reg & 0x1C) >> 2));
+		dev->in_fifo_sz = dev->in_blk_sz *
+					(2 << ((fifo_reg & 0x380) >> 7));
+		dev_dbg(dev->dev, "QUP IN:bl:%d, ff:%d, OUT:bl:%d, ff:%d\n",
+				dev->in_blk_sz, dev->in_fifo_sz,
+				dev->out_blk_sz, dev->out_fifo_sz);
+	}
+
+	writel_relaxed(1, dev->base + QUP_SW_RESET);
+	ret = qup_i2c_poll_state(dev, QUP_RESET_STATE, false);
+	if (ret) {
+		dev_err(dev->dev, "QUP Busy:Trying to recover\n");
+		goto out_err;
+	}
+
+	if (dev->num_irqs == 3) {
+		enable_irq(dev->in_irq);
+		enable_irq(dev->out_irq);
+	}
+	enable_irq(dev->err_irq);
+
+	/* Initialize QUP registers */
+	writel_relaxed(0, dev->base + QUP_CONFIG);
+	writel_relaxed(QUP_OPERATIONAL_RESET, dev->base + QUP_OPERATIONAL);
+	writel_relaxed(QUP_STATUS_ERROR_FLAGS, dev->base + QUP_ERROR_FLAGS_EN);
+
+	writel_relaxed(I2C_MINI_CORE | I2C_N_VAL, dev->base + QUP_CONFIG);
+
+	/* Initialize I2C mini core registers */
+	writel_relaxed(0, dev->base + QUP_I2C_CLK_CTL);
+	writel_relaxed(QUP_I2C_STATUS_RESET, dev->base + QUP_I2C_STATUS);
+
+	while (rem) {
+		bool filled = false;
+
+		dev->cnt = msgs->len - dev->pos;
+		dev->msg = msgs;
+
+		dev->wr_sz = dev->out_fifo_sz;
+		dev->err = 0;
+		dev->complete = &complete;
+
+		if (qup_i2c_poll_state(dev, QUP_I2C_MAST_GEN, false) != 0) {
+			ret = -EIO;
+			goto out_err;
+		}
+
+		qup_print_status(dev);
+		/* HW limits Read upto 256 bytes in 1 read without stop */
+		if (dev->msg->flags & I2C_M_RD) {
+			qup_set_read_mode(dev, dev->cnt);
+			if (dev->cnt > 256)
+				dev->cnt = 256;
+		} else {
+			ret = qup_set_wr_mode(dev, rem);
+			if (ret != 0)
+				goto out_err;
+			/* Don't fill block till we get interrupt */
+			if (dev->wr_sz == dev->out_blk_sz)
+				filled = true;
+		}
+
+		err = qup_update_state(dev, QUP_RUN_STATE);
+		if (err < 0) {
+			ret = err;
+			goto out_err;
+		}
+
+		qup_print_status(dev);
+		writel_relaxed(dev->clk_ctl, dev->base + QUP_I2C_CLK_CTL);
+		/* CLK_CTL register is not in the same 1K region as other QUP
+		 * registers. Ensure that clock control is written before
+		 * programming other QUP registers
+		 */
+		mb();
+
+		do {
+			int idx = 0;
+			uint32_t carry_over = 0;
+
+			/* Transition to PAUSE state only possible from RUN */
+			err = qup_update_state(dev, QUP_PAUSE_STATE);
+			if (err < 0) {
+				ret = err;
+				goto out_err;
+			}
+
+			qup_print_status(dev);
+			/* This operation is Write, check the next operation
+			 * and decide mode
+			 */
+			while (filled == false) {
+				if ((msgs->flags & I2C_M_RD))
+					qup_issue_read(dev, msgs, &idx,
+							carry_over);
+				else if (!(msgs->flags & I2C_M_RD))
+					qup_issue_write(dev, msgs, rem, &idx,
+							&carry_over);
+				if (idx >= (dev->wr_sz << 1))
+					filled = true;
+				/* Start new message */
+				if (filled == false) {
+					if (msgs->flags & I2C_M_RD)
+							filled = true;
+					else if (rem > 1) {
+						/* Only combine operations with
+						 * same address
+						 */
+						struct i2c_msg *next = msgs + 1;
+						if (next->addr != msgs->addr)
+							filled = true;
+						else {
+							rem--;
+							msgs++;
+							dev->msg = msgs;
+							dev->pos = 0;
+							dev->cnt = msgs->len;
+							if (msgs->len > 256)
+								dev->cnt = 256;
+						}
+					} else
+						filled = true;
+				}
+			}
+			err = qup_update_state(dev, QUP_RUN_STATE);
+			if (err < 0) {
+				ret = err;
+				goto out_err;
+			}
+			dev_dbg(dev->dev, "idx:%d, rem:%d, num:%d, mode:%d\n",
+				idx, rem, num, dev->mode);
+
+			qup_print_status(dev);
+			timeout = wait_for_completion_timeout(&complete,
+					msecs_to_jiffies(dev->out_fifo_sz));
+			if (!timeout) {
+				uint32_t istatus = readl_relaxed(dev->base +
+							QUP_I2C_STATUS);
+				uint32_t qstatus = readl_relaxed(dev->base +
+							QUP_ERROR_FLAGS);
+				uint32_t op_flgs = readl_relaxed(dev->base +
+							QUP_OPERATIONAL);
+
+				/*
+				 * Dont wait for 1 sec if i2c sees the bus
+				 * active and controller is not master.
+				 * A slave has pulled line low. Try to recover
+				 */
+				if (!(istatus & I2C_STATUS_BUS_ACTIVE) ||
+					(istatus & I2C_STATUS_BUS_MASTER)) {
+					timeout =
+					wait_for_completion_timeout(&complete,
+									HZ);
+					if (timeout)
+						goto timeout_err;
+				}
+				qup_i2c_recover_bus_busy(dev);
+				dev_err(dev->dev,
+					"Transaction timed out, SL-AD = 0x%x\n",
+					dev->msg->addr);
+
+				dev_err(dev->dev, "I2C Status: %x\n", istatus);
+				dev_err(dev->dev, "QUP Status: %x\n", qstatus);
+				dev_err(dev->dev, "OP Flags: %x\n", op_flgs);
+				writel_relaxed(1, dev->base + QUP_SW_RESET);
+				/* Make sure that the write has gone through
+				 * before returning from the function
+				 */
+				mb();
+				ret = -ETIMEDOUT;
+				goto out_err;
+			}
+timeout_err:
+			if (dev->err) {
+				if (dev->err > 0 &&
+					dev->err & QUP_I2C_NACK_FLAG) {
+					dev_err(dev->dev,
+					"I2C slave addr:0x%x not connected\n",
+					dev->msg->addr);
+					dev->err = ENOTCONN;
+				} else if (dev->err < 0) {
+					dev_err(dev->dev,
+					"QUP data xfer error %d\n", dev->err);
+					ret = dev->err;
+					goto out_err;
+				} else if (dev->err > 0) {
+					/*
+					 * ISR returns +ve error if error code
+					 * is I2C related, e.g. unexpected start
+					 * So you may call recover-bus-busy when
+					 * this error happens
+					 */
+					qup_i2c_recover_bus_busy(dev);
+				}
+				ret = -dev->err;
+				goto out_err;
+			}
+			if (dev->msg->flags & I2C_M_RD) {
+				int i;
+				uint32_t dval = 0;
+				for (i = 0; dev->pos < dev->msg->len; i++,
+						dev->pos++) {
+					uint32_t rd_status =
+						readl_relaxed(dev->base
+							+ QUP_OPERATIONAL);
+					if (i % 2 == 0) {
+						if ((rd_status &
+							QUP_IN_NOT_EMPTY) == 0)
+							break;
+						dval = readl_relaxed(dev->base +
+							QUP_IN_FIFO_BASE);
+						dev->msg->buf[dev->pos] =
+							dval & 0xFF;
+					} else
+						dev->msg->buf[dev->pos] =
+							((dval & 0xFF0000) >>
+							 16);
+				}
+				dev->cnt -= i;
+			} else
+				filled = false; /* refill output FIFO */
+			dev_dbg(dev->dev, "pos:%d, len:%d, cnt:%d\n",
+					dev->pos, msgs->len, dev->cnt);
+		} while (dev->cnt > 0);
+		if (dev->cnt == 0) {
+			if (msgs->len == dev->pos) {
+				rem--;
+				msgs++;
+				dev->pos = 0;
+			}
+			if (rem) {
+				err = qup_i2c_poll_clock_ready(dev);
+				if (err < 0) {
+					ret = err;
+					goto out_err;
+				}
+				err = qup_update_state(dev, QUP_RESET_STATE);
+				if (err < 0) {
+					ret = err;
+					goto out_err;
+				}
+			}
+		}
+		/* Wait for I2C bus to be idle */
+		ret = qup_i2c_poll_writeready(dev, rem);
+		if (ret) {
+			dev_err(dev->dev,
+				"Error waiting for write ready\n");
+			goto out_err;
+		}
+	}
+
+	ret = num;
+ out_err:
+	disable_irq(dev->err_irq);
+	if (dev->num_irqs == 3) {
+		disable_irq(dev->in_irq);
+		disable_irq(dev->out_irq);
+	}
+	dev->complete = NULL;
+	dev->msg = NULL;
+	dev->pos = 0;
+	dev->err = 0;
+	dev->cnt = 0;
+	dev->pwr_timer.expires = jiffies + 3*HZ;
+	add_timer(&dev->pwr_timer);
+	mutex_unlock(&dev->mlock);
+	return ret;
+}
+
+static u32
+qup_i2c_func(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
+}
+
+static const struct i2c_algorithm qup_i2c_algo = {
+	.master_xfer	= qup_i2c_xfer,
+	.functionality	= qup_i2c_func,
+};
+
+static int __devinit
+qup_i2c_probe(struct platform_device *pdev)
+{
+	struct qup_i2c_dev	*dev;
+	struct resource         *qup_mem, *gsbi_mem, *qup_io, *gsbi_io, *res;
+	struct resource		*in_irq, *out_irq, *err_irq;
+	struct clk         *clk, *pclk;
+	int ret = 0;
+	int i;
+	struct msm_i2c_platform_data *pdata;
+
+	gsbi_mem = NULL;
+	dev_dbg(&pdev->dev, "qup_i2c_probe\n");
+
+	if (pdev->dev.of_node) {
+		struct device_node *node = pdev->dev.of_node;
+		pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
+		if (!pdata)
+			return -ENOMEM;
+		ret = of_property_read_u32(node, "qcom,i2c-bus-freq",
+					&pdata->clk_freq);
+		if (ret)
+			goto get_res_failed;
+		ret = of_property_read_u32(node, "cell-index", &pdev->id);
+		if (ret)
+			goto get_res_failed;
+		/* Optional property */
+		of_property_read_u32(node, "qcom,i2c-src-freq",
+					&pdata->src_clk_rate);
+	} else
+		pdata = pdev->dev.platform_data;
+
+	if (!pdata) {
+		dev_err(&pdev->dev, "platform data not initialized\n");
+		return -ENOSYS;
+	}
+	qup_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+						"qup_phys_addr");
+	if (!qup_mem) {
+		dev_err(&pdev->dev, "no qup mem resource?\n");
+		ret = -ENODEV;
+		goto get_res_failed;
+	}
+
+	/*
+	 * We only have 1 interrupt for new hardware targets and in_irq,
+	 * out_irq will be NULL for those platforms
+	 */
+	in_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
+						"qup_in_intr");
+
+	out_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
+						"qup_out_intr");
+
+	err_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
+						"qup_err_intr");
+	if (!err_irq) {
+		dev_err(&pdev->dev, "no error irq resource?\n");
+		ret = -ENODEV;
+		goto get_res_failed;
+	}
+
+	qup_io = request_mem_region(qup_mem->start, resource_size(qup_mem),
+					pdev->name);
+	if (!qup_io) {
+		dev_err(&pdev->dev, "QUP region already claimed\n");
+		ret = -EBUSY;
+		goto get_res_failed;
+	}
+	if (!pdata->use_gsbi_shared_mode) {
+		gsbi_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+							"gsbi_qup_i2c_addr");
+		if (!gsbi_mem) {
+			dev_dbg(&pdev->dev, "Assume BLSP\n");
+			/*
+			 * BLSP core does not need protocol programming so this
+			 * resource is not expected
+			 */
+			goto blsp_core_init;
+		}
+		gsbi_io = request_mem_region(gsbi_mem->start,
+						resource_size(gsbi_mem),
+						pdev->name);
+		if (!gsbi_io) {
+			dev_err(&pdev->dev, "GSBI region already claimed\n");
+			ret = -EBUSY;
+			goto err_res_failed;
+		}
+	}
+
+blsp_core_init:
+	clk = clk_get(&pdev->dev, "core_clk");
+	if (IS_ERR(clk)) {
+		dev_err(&pdev->dev, "Could not get core_clk\n");
+		ret = PTR_ERR(clk);
+		goto err_clk_get_failed;
+	}
+
+	pclk = clk_get(&pdev->dev, "iface_clk");
+	if (IS_ERR(pclk)) {
+		dev_err(&pdev->dev, "Could not get iface_clk\n");
+		ret = PTR_ERR(pclk);
+		clk_put(clk);
+		goto err_clk_get_failed;
+	}
+
+	/* We support frequencies upto FAST Mode(400KHz) */
+	if (pdata->clk_freq <= 0 ||
+			pdata->clk_freq > 400000) {
+		dev_err(&pdev->dev, "clock frequency not supported\n");
+		ret = -EIO;
+		goto err_config_failed;
+	}
+
+	dev = kzalloc(sizeof(struct qup_i2c_dev), GFP_KERNEL);
+	if (!dev) {
+		ret = -ENOMEM;
+		goto err_alloc_dev_failed;
+	}
+
+	dev->dev = &pdev->dev;
+	if (in_irq)
+		dev->in_irq = in_irq->start;
+	if (out_irq)
+		dev->out_irq = out_irq->start;
+	dev->err_irq = err_irq->start;
+	if (in_irq && out_irq)
+		dev->num_irqs = 3;
+	else
+		dev->num_irqs = 1;
+	dev->clk = clk;
+	dev->pclk = pclk;
+	dev->base = ioremap(qup_mem->start, resource_size(qup_mem));
+	if (!dev->base) {
+		ret = -ENOMEM;
+		goto err_ioremap_failed;
+	}
+
+	/* Configure GSBI block to use I2C functionality */
+	if (gsbi_mem) {
+		dev->gsbi = ioremap(gsbi_mem->start, resource_size(gsbi_mem));
+		if (!dev->gsbi) {
+			ret = -ENOMEM;
+			goto err_gsbi_failed;
+		}
+	}
+
+	for (i = 0; i < ARRAY_SIZE(i2c_rsrcs); ++i) {
+		res = platform_get_resource_byname(pdev, IORESOURCE_IO,
+						   i2c_rsrcs[i]);
+		dev->i2c_gpios[i] = res ? res->start : -1;
+	}
+
+	ret = qup_i2c_request_gpios(dev);
+	if (ret)
+		goto err_request_gpio_failed;
+
+	platform_set_drvdata(pdev, dev);
+
+	dev->one_bit_t = (USEC_PER_SEC/pdata->clk_freq) + 1;
+	dev->pdata = pdata;
+	dev->clk_ctl = 0;
+	dev->pos = 0;
+
+	/*
+	 * If bootloaders leave a pending interrupt on certain GSBI's,
+	 * then we reset the core before registering for interrupts.
+	 */
+
+	if (dev->pdata->src_clk_rate > 0)
+		clk_set_rate(dev->clk, dev->pdata->src_clk_rate);
+	else
+		dev->pdata->src_clk_rate = 19200000;
+
+	clk_prepare_enable(dev->clk);
+	clk_prepare_enable(dev->pclk);
+	writel_relaxed(1, dev->base + QUP_SW_RESET);
+	if (qup_i2c_poll_state(dev, 0, true) != 0)
+		goto err_reset_failed;
+	clk_disable_unprepare(dev->clk);
+	clk_disable_unprepare(dev->pclk);
+
+	/*
+	 * We use num_irqs to also indicate if we got 3 interrupts or just 1.
+	 * If we have just 1, we use err_irq as the general purpose irq
+	 * and handle the changes in ISR accordingly
+	 * Per Hardware guidelines, if we have 3 interrupts, they are always
+	 * edge triggering, and if we have 1, it's always level-triggering
+	 */
+	if (dev->num_irqs == 3) {
+		ret = request_irq(dev->in_irq, qup_i2c_interrupt,
+				IRQF_TRIGGER_RISING, "qup_in_intr", dev);
+		if (ret) {
+			dev_err(&pdev->dev, "request_in_irq failed\n");
+			goto err_request_irq_failed;
+		}
+		/*
+		 * We assume out_irq exists if in_irq does since platform
+		 * configuration either has 3 interrupts assigned to QUP or 1
+		 */
+		ret = request_irq(dev->out_irq, qup_i2c_interrupt,
+				IRQF_TRIGGER_RISING, "qup_out_intr", dev);
+		if (ret) {
+			dev_err(&pdev->dev, "request_out_irq failed\n");
+			free_irq(dev->in_irq, dev);
+			goto err_request_irq_failed;
+		}
+		ret = request_irq(dev->err_irq, qup_i2c_interrupt,
+				IRQF_TRIGGER_RISING, "qup_err_intr", dev);
+		if (ret) {
+			dev_err(&pdev->dev, "request_err_irq failed\n");
+			free_irq(dev->out_irq, dev);
+			free_irq(dev->in_irq, dev);
+			goto err_request_irq_failed;
+		}
+	} else {
+		ret = request_irq(dev->err_irq, qup_i2c_interrupt,
+				IRQF_TRIGGER_HIGH, "qup_err_intr", dev);
+		if (ret) {
+			dev_err(&pdev->dev, "request_err_irq failed\n");
+			goto err_request_irq_failed;
+		}
+	}
+	disable_irq(dev->err_irq);
+	if (dev->num_irqs == 3) {
+		disable_irq(dev->in_irq);
+		disable_irq(dev->out_irq);
+	}
+	i2c_set_adapdata(&dev->adapter, dev);
+	dev->adapter.algo = &qup_i2c_algo;
+	strlcpy(dev->adapter.name,
+		"QUP I2C adapter",
+		sizeof(dev->adapter.name));
+	dev->adapter.nr = pdev->id;
+	if (pdata->msm_i2c_config_gpio)
+		pdata->msm_i2c_config_gpio(dev->adapter.nr, 1);
+
+	dev->suspended = 0;
+	mutex_init(&dev->mlock);
+	dev->clk_state = 0;
+	clk_prepare(dev->clk);
+	clk_prepare(dev->pclk);
+	setup_timer(&dev->pwr_timer, qup_i2c_pwr_timer, (unsigned long) dev);
+
+	pm_runtime_set_active(&pdev->dev);
+	pm_runtime_enable(&pdev->dev);
+
+	ret = i2c_add_numbered_adapter(&dev->adapter);
+	if (ret) {
+		dev_err(&pdev->dev, "i2c_add_adapter failed\n");
+		if (dev->num_irqs == 3) {
+			free_irq(dev->out_irq, dev);
+			free_irq(dev->in_irq, dev);
+		}
+		free_irq(dev->err_irq, dev);
+	} else {
+		if (dev->dev->of_node)
+			of_i2c_register_devices(&dev->adapter);
+		return 0;
+	}
+
+
+err_request_irq_failed:
+	qup_i2c_free_gpios(dev);
+	if (dev->gsbi)
+		iounmap(dev->gsbi);
+err_reset_failed:
+	clk_disable_unprepare(dev->clk);
+	clk_disable_unprepare(dev->pclk);
+err_request_gpio_failed:
+err_gsbi_failed:
+	iounmap(dev->base);
+err_ioremap_failed:
+	kfree(dev);
+err_alloc_dev_failed:
+err_config_failed:
+	clk_put(clk);
+	clk_put(pclk);
+err_clk_get_failed:
+	if (gsbi_mem)
+		release_mem_region(gsbi_mem->start, resource_size(gsbi_mem));
+err_res_failed:
+	release_mem_region(qup_mem->start, resource_size(qup_mem));
+get_res_failed:
+	if (pdev->dev.of_node)
+		kfree(pdata);
+	return ret;
+}
+
+static int __devexit
+qup_i2c_remove(struct platform_device *pdev)
+{
+	struct qup_i2c_dev	*dev = platform_get_drvdata(pdev);
+	struct resource		*qup_mem, *gsbi_mem;
+
+	/* Grab mutex to ensure ongoing transaction is over */
+	mutex_lock(&dev->mlock);
+	dev->suspended = 1;
+	mutex_unlock(&dev->mlock);
+	mutex_destroy(&dev->mlock);
+	del_timer_sync(&dev->pwr_timer);
+	if (dev->clk_state != 0)
+		qup_i2c_pwr_mgmt(dev, 0);
+	platform_set_drvdata(pdev, NULL);
+	if (dev->num_irqs == 3) {
+		free_irq(dev->out_irq, dev);
+		free_irq(dev->in_irq, dev);
+	}
+	free_irq(dev->err_irq, dev);
+	i2c_del_adapter(&dev->adapter);
+	clk_unprepare(dev->clk);
+	clk_unprepare(dev->pclk);
+	clk_put(dev->clk);
+	clk_put(dev->pclk);
+	qup_i2c_free_gpios(dev);
+	if (dev->gsbi)
+		iounmap(dev->gsbi);
+	iounmap(dev->base);
+
+	pm_runtime_disable(&pdev->dev);
+
+	if (!(dev->pdata->use_gsbi_shared_mode)) {
+		gsbi_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+							"gsbi_qup_i2c_addr");
+		release_mem_region(gsbi_mem->start, resource_size(gsbi_mem));
+	}
+	qup_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+						"qup_phys_addr");
+	release_mem_region(qup_mem->start, resource_size(qup_mem));
+	if (dev->dev->of_node)
+		kfree(dev->pdata);
+	kfree(dev);
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int qup_i2c_suspend(struct device *device)
+{
+	struct platform_device *pdev = to_platform_device(device);
+	struct qup_i2c_dev *dev = platform_get_drvdata(pdev);
+
+	/* Grab mutex to ensure ongoing transaction is over */
+	mutex_lock(&dev->mlock);
+	dev->suspended = 1;
+	mutex_unlock(&dev->mlock);
+	del_timer_sync(&dev->pwr_timer);
+	if (dev->clk_state != 0)
+		qup_i2c_pwr_mgmt(dev, 0);
+	clk_unprepare(dev->clk);
+	clk_unprepare(dev->pclk);
+	qup_i2c_free_gpios(dev);
+	return 0;
+}
+
+static int qup_i2c_resume(struct device *device)
+{
+	struct platform_device *pdev = to_platform_device(device);
+	struct qup_i2c_dev *dev = platform_get_drvdata(pdev);
+	BUG_ON(qup_i2c_request_gpios(dev) != 0);
+	clk_prepare(dev->clk);
+	clk_prepare(dev->pclk);
+	dev->suspended = 0;
+	return 0;
+}
+#endif /* CONFIG_PM */
+
+#ifdef CONFIG_PM_RUNTIME
+static int i2c_qup_runtime_idle(struct device *dev)
+{
+	dev_dbg(dev, "pm_runtime: idle...\n");
+	return 0;
+}
+
+static int i2c_qup_runtime_suspend(struct device *dev)
+{
+	dev_dbg(dev, "pm_runtime: suspending...\n");
+	return 0;
+}
+
+static int i2c_qup_runtime_resume(struct device *dev)
+{
+	dev_dbg(dev, "pm_runtime: resuming...\n");
+	return 0;
+}
+#endif
+
+static const struct dev_pm_ops i2c_qup_dev_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(
+		qup_i2c_suspend,
+		qup_i2c_resume
+	)
+	SET_RUNTIME_PM_OPS(
+		i2c_qup_runtime_suspend,
+		i2c_qup_runtime_resume,
+		i2c_qup_runtime_idle
+	)
+};
+
+static struct of_device_id i2c_qup_dt_match[] = {
+	{
+		.compatible = "qcom,i2c-qup",
+	},
+	{}
+};
+
+static struct platform_driver qup_i2c_driver = {
+	.probe		= qup_i2c_probe,
+	.remove		= __devexit_p(qup_i2c_remove),
+	.driver		= {
+		.name	= "qup_i2c",
+		.owner	= THIS_MODULE,
+		.pm = &i2c_qup_dev_pm_ops,
+		.of_match_table = i2c_qup_dt_match,
+	},
+};
+
+/* QUP may be needed to bring up other drivers */
+static int __init
+qup_i2c_init_driver(void)
+{
+	return platform_driver_register(&qup_i2c_driver);
+}
+arch_initcall(qup_i2c_init_driver);
+
+static void __exit qup_i2c_exit_driver(void)
+{
+	platform_driver_unregister(&qup_i2c_driver);
+}
+module_exit(qup_i2c_exit_driver);
+
diff --git a/drivers/i2c/busses/i2c-ssbi.c b/drivers/i2c/busses/i2c-ssbi.c
new file mode 100644
index 0000000..c803402
--- /dev/null
+++ b/drivers/i2c/busses/i2c-ssbi.c
@@ -0,0 +1,517 @@
+/* Copyright (c) 2009-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.
+ */
+/*
+ * SSBI driver for Qualcomm MSM platforms
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/i2c.h>
+#include <linux/remote_spinlock.h>
+#include <mach/board.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+
+/* SSBI 2.0 controller registers */
+#define SSBI2_CMD			0x0008
+#define SSBI2_RD			0x0010
+#define SSBI2_STATUS			0x0014
+#define SSBI2_MODE2			0x001C
+
+/* SSBI_CMD fields */
+#define SSBI_CMD_RDWRN			(0x01 << 24)
+#define SSBI_CMD_REG_ADDR_SHFT		(0x10)
+#define SSBI_CMD_REG_ADDR_MASK		(0xFF << SSBI_CMD_REG_ADDR_SHFT)
+#define SSBI_CMD_REG_DATA_SHFT		(0x00)
+#define SSBI_CMD_REG_DATA_MASK		(0xFF << SSBI_CMD_REG_DATA_SHFT)
+
+/* SSBI_STATUS fields */
+#define SSBI_STATUS_DATA_IN		0x10
+#define SSBI_STATUS_RD_CLOBBERED	0x08
+#define SSBI_STATUS_RD_READY		0x04
+#define SSBI_STATUS_READY		0x02
+#define SSBI_STATUS_MCHN_BUSY		0x01
+
+/* SSBI_RD fields */
+#define SSBI_RD_RDWRN			0x01000000
+#define SSBI_RD_REG_ADDR_SHFT		0x10
+#define SSBI_RD_REG_ADDR_MASK		(0xFF << SSBI_RD_REG_ADDR_SHFT)
+#define SSBI_RD_REG_DATA_SHFT		(0x00)
+#define SSBI_RD_REG_DATA_MASK		(0xFF << SSBI_RD_REG_DATA_SHFT)
+
+/* SSBI_MODE2 fields */
+#define SSBI_MODE2_REG_ADDR_15_8_SHFT	0x04
+#define SSBI_MODE2_REG_ADDR_15_8_MASK	(0x7F << SSBI_MODE2_REG_ADDR_15_8_SHFT)
+#define SSBI_MODE2_ADDR_WIDTH_SHFT	0x01
+#define SSBI_MODE2_ADDR_WIDTH_MASK	(0x07 << SSBI_MODE2_ADDR_WIDTH_SHFT)
+#define SSBI_MODE2_SSBI2_MODE		0x00000001
+
+#define SSBI_MODE2_REG_ADDR_15_8(MD, AD) \
+	(((MD) & 0x0F) | ((((AD) >> 8) << SSBI_MODE2_REG_ADDR_15_8_SHFT) & \
+	SSBI_MODE2_REG_ADDR_15_8_MASK))
+
+#define SSBI_MODE2_ADDR_WIDTH(N) \
+	((((N) - 8) << SSBI_MODE2_ADDR_WIDTH_SHFT) & SSBI_MODE2_ADDR_WIDTH_MASK)
+
+#define SSBI_TIMEOUT_US			100
+
+#define SSBI_CMD_READ(AD) \
+	(SSBI_CMD_RDWRN | (((AD) & 0xFF) << SSBI_CMD_REG_ADDR_SHFT))
+
+#define SSBI_CMD_WRITE(AD, DT) \
+	((((AD) & 0xFF) << SSBI_CMD_REG_ADDR_SHFT) | \
+	 (((DT) & 0xFF) << SSBI_CMD_REG_DATA_SHFT))
+
+/* SSBI PMIC Arbiter command registers */
+#define SSBI_PA_CMD			0x0000
+#define SSBI_PA_RD_STATUS		0x0004
+
+/* SSBI_PA_CMD fields */
+#define SSBI_PA_CMD_RDWRN		(0x01 << 24)
+#define SSBI_PA_CMD_REG_ADDR_14_8_SHFT	(0x10)
+#define SSBI_PA_CMD_REG_ADDR_14_8_MASK	(0x7F << SSBI_PA_CMD_REG_ADDR_14_8_SHFT)
+#define SSBI_PA_CMD_REG_ADDR_7_0_SHFT	(0x08)
+#define SSBI_PA_CMD_REG_ADDR_7_0_MASK	(0xFF << SSBI_PA_CMD_REG_ADDR_7_0_SHFT)
+#define SSBI_PA_CMD_REG_DATA_SHFT	(0x00)
+#define SSBI_PA_CMD_REG_DATA_MASK	(0xFF << SSBI_PA_CMD_REG_DATA_SHFT)
+
+#define SSBI_PA_CMD_REG_DATA(DT) \
+	(((DT) << SSBI_PA_CMD_REG_DATA_SHFT) & SSBI_PA_CMD_REG_DATA_MASK)
+
+#define SSBI_PA_CMD_REG_ADDR(AD) \
+	(((AD) << SSBI_PA_CMD_REG_ADDR_7_0_SHFT) & \
+	(SSBI_PA_CMD_REG_ADDR_14_8_MASK|SSBI_PA_CMD_REG_ADDR_7_0_MASK))
+
+/* SSBI_PA_RD_STATUS fields */
+#define SSBI_PA_RD_STATUS_TRANS_DONE	(0x01 << 27)
+#define SSBI_PA_RD_STATUS_TRANS_DENIED	(0x01 << 26)
+#define SSBI_PA_RD_STATUS_REG_DATA_SHFT	(0x00)
+#define SSBI_PA_RD_STATUS_REG_DATA_MASK	(0xFF << SSBI_PA_CMD_REG_DATA_SHFT)
+#define SSBI_PA_RD_STATUS_TRANS_COMPLETE \
+	(SSBI_PA_RD_STATUS_TRANS_DONE|SSBI_PA_RD_STATUS_TRANS_DENIED)
+
+/* SSBI_FSM Read and Write commands for the FSM9xxx SSBI implementation */
+#define SSBI_FSM_CMD_REG_ADDR_SHFT	(0x08)
+
+#define SSBI_FSM_CMD_READ(AD) \
+	(SSBI_CMD_RDWRN | (((AD) & 0xFFFF) << SSBI_FSM_CMD_REG_ADDR_SHFT))
+
+#define SSBI_FSM_CMD_WRITE(AD, DT) \
+	((((AD) & 0xFFFF) << SSBI_FSM_CMD_REG_ADDR_SHFT) | \
+	 (((DT) & 0xFF) << SSBI_CMD_REG_DATA_SHFT))
+
+#define SSBI_MSM_NAME			"i2c_ssbi"
+
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION("2.0");
+MODULE_ALIAS("platform:i2c_ssbi");
+
+struct i2c_ssbi_dev {
+	void __iomem		*base;
+	struct device           *dev;
+	struct i2c_adapter	 adapter;
+	unsigned long		 mem_phys_addr;
+	size_t			 mem_size;
+	bool			 use_rlock;
+	remote_spinlock_t	 rspin_lock;
+	enum msm_ssbi_controller_type controller_type;
+	int (*read)(struct i2c_ssbi_dev *, struct i2c_msg *);
+	int (*write)(struct i2c_ssbi_dev *, struct i2c_msg *);
+};
+
+static inline u32 ssbi_readl(struct i2c_ssbi_dev *ssbi, u32 reg)
+{
+	return readl_relaxed(ssbi->base + reg);
+}
+
+static inline void ssbi_writel(struct i2c_ssbi_dev *ssbi, u32 reg, u32 val)
+{
+	writel_relaxed(val, ssbi->base + reg);
+}
+
+static inline int
+i2c_ssbi_poll_for_device_ready(struct i2c_ssbi_dev *ssbi)
+{
+	u32 timeout = SSBI_TIMEOUT_US;
+
+	while (!(ssbi_readl(ssbi, SSBI2_STATUS) & SSBI_STATUS_READY)) {
+		if (--timeout == 0) {
+			dev_err(ssbi->dev, "%s: timeout, status %x\n", __func__,
+				ssbi_readl(ssbi, SSBI2_STATUS));
+			return -ETIMEDOUT;
+		}
+		udelay(1);
+	}
+
+	return 0;
+}
+
+static inline int
+i2c_ssbi_poll_for_read_completed(struct i2c_ssbi_dev *ssbi)
+{
+	u32 timeout = SSBI_TIMEOUT_US;
+
+	while (!(ssbi_readl(ssbi, SSBI2_STATUS) & SSBI_STATUS_RD_READY)) {
+		if (--timeout == 0) {
+			dev_err(ssbi->dev, "%s: timeout, status %x\n", __func__,
+				ssbi_readl(ssbi, SSBI2_STATUS));
+			return -ETIMEDOUT;
+		}
+		udelay(1);
+	}
+
+	return 0;
+}
+
+static inline int
+i2c_ssbi_poll_for_transfer_completed(struct i2c_ssbi_dev *ssbi)
+{
+	u32 timeout = SSBI_TIMEOUT_US;
+
+	while ((ssbi_readl(ssbi, SSBI2_STATUS) & SSBI_STATUS_MCHN_BUSY)) {
+		if (--timeout == 0) {
+			dev_err(ssbi->dev, "%s: timeout, status %x\n", __func__,
+				ssbi_readl(ssbi, SSBI2_STATUS));
+			return -ETIMEDOUT;
+		}
+		udelay(1);
+	}
+
+	return 0;
+}
+
+static int
+i2c_ssbi_read_bytes(struct i2c_ssbi_dev *ssbi, struct i2c_msg *msg)
+{
+	int ret = 0;
+	u8 *buf = msg->buf;
+	u16 len = msg->len;
+	u16 addr = msg->addr;
+	u32 read_cmd;
+
+	if (ssbi->controller_type == MSM_SBI_CTRL_SSBI2) {
+		u32 mode2 = ssbi_readl(ssbi, SSBI2_MODE2);
+		ssbi_writel(ssbi, SSBI2_MODE2,
+				SSBI_MODE2_REG_ADDR_15_8(mode2, addr));
+	}
+
+	if (ssbi->controller_type == FSM_SBI_CTRL_SSBI)
+		read_cmd = SSBI_FSM_CMD_READ(addr);
+	else
+		read_cmd = SSBI_CMD_READ(addr);
+
+	while (len) {
+		ret = i2c_ssbi_poll_for_device_ready(ssbi);
+		if (ret)
+			goto read_failed;
+
+		ssbi_writel(ssbi, SSBI2_CMD, read_cmd);
+
+		ret = i2c_ssbi_poll_for_read_completed(ssbi);
+		if (ret)
+			goto read_failed;
+
+		*buf++ = ssbi_readl(ssbi, SSBI2_RD) & SSBI_RD_REG_DATA_MASK;
+		len--;
+	}
+
+read_failed:
+	return ret;
+}
+
+static int
+i2c_ssbi_write_bytes(struct i2c_ssbi_dev *ssbi, struct i2c_msg *msg)
+{
+	int ret = 0;
+	u8 *buf = msg->buf;
+	u16 len = msg->len;
+	u16 addr = msg->addr;
+
+	if (ssbi->controller_type == MSM_SBI_CTRL_SSBI2) {
+		u32 mode2 = ssbi_readl(ssbi, SSBI2_MODE2);
+		ssbi_writel(ssbi, SSBI2_MODE2,
+				SSBI_MODE2_REG_ADDR_15_8(mode2, addr));
+	}
+
+	while (len) {
+		ret = i2c_ssbi_poll_for_device_ready(ssbi);
+		if (ret)
+			goto write_failed;
+
+		if (ssbi->controller_type == FSM_SBI_CTRL_SSBI)
+			ssbi_writel(ssbi, SSBI2_CMD,
+				SSBI_FSM_CMD_WRITE(addr, *buf++));
+		else
+			ssbi_writel(ssbi, SSBI2_CMD,
+				SSBI_CMD_WRITE(addr, *buf++));
+
+		ret = i2c_ssbi_poll_for_transfer_completed(ssbi);
+		if (ret)
+			goto write_failed;
+
+		len--;
+	}
+
+write_failed:
+	return ret;
+}
+
+static inline int
+i2c_ssbi_pa_transfer(struct i2c_ssbi_dev *ssbi, u32 cmd, u8 *data)
+{
+	u32 rd_status;
+	u32 timeout = SSBI_TIMEOUT_US;
+
+	ssbi_writel(ssbi, SSBI_PA_CMD, cmd);
+	rd_status = ssbi_readl(ssbi, SSBI_PA_RD_STATUS);
+
+	while ((rd_status & (SSBI_PA_RD_STATUS_TRANS_COMPLETE)) == 0) {
+
+		if (--timeout == 0) {
+			dev_err(ssbi->dev, "%s: timeout, status %x\n",
+					__func__, rd_status);
+			return -ETIMEDOUT;
+		}
+		udelay(1);
+		rd_status = ssbi_readl(ssbi, SSBI_PA_RD_STATUS);
+	}
+
+	if (rd_status & SSBI_PA_RD_STATUS_TRANS_DENIED) {
+		dev_err(ssbi->dev, "%s: transaction denied, status %x\n",
+				__func__, rd_status);
+		return -EPERM;
+	}
+
+	if (data)
+		*data = (rd_status & SSBI_PA_RD_STATUS_REG_DATA_MASK) >>
+					SSBI_PA_CMD_REG_DATA_SHFT;
+	return 0;
+}
+
+static int
+i2c_ssbi_pa_read_bytes(struct i2c_ssbi_dev *ssbi, struct i2c_msg *msg)
+{
+	int ret = 0;
+	u8  data;
+	u8 *buf = msg->buf;
+	u16 len = msg->len;
+	u32 read_cmd = (SSBI_PA_CMD_RDWRN | SSBI_PA_CMD_REG_ADDR(msg->addr));
+
+	while (len) {
+
+		ret = i2c_ssbi_pa_transfer(ssbi, read_cmd, &data);
+		if (ret)
+			goto read_failed;
+
+		*buf++ = data;
+		len--;
+	}
+
+read_failed:
+	return ret;
+}
+
+static int
+i2c_ssbi_pa_write_bytes(struct i2c_ssbi_dev *ssbi, struct i2c_msg *msg)
+{
+	int ret = 0;
+	u8 *buf = msg->buf;
+	u16 len = msg->len;
+	u32 addr = SSBI_PA_CMD_REG_ADDR(msg->addr);
+
+	while (len) {
+
+		u32 write_cmd = addr | (*buf++ & SSBI_PA_CMD_REG_DATA_MASK);
+
+		ret = i2c_ssbi_pa_transfer(ssbi, write_cmd, NULL);
+		if (ret)
+			goto write_failed;
+		len--;
+	}
+
+write_failed:
+	return ret;
+}
+
+static int
+i2c_ssbi_transfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
+{
+	int ret = 0;
+	int rem = num;
+	unsigned long flags = 0;
+	struct i2c_ssbi_dev *ssbi = i2c_get_adapdata(adap);
+
+	if (ssbi->use_rlock)
+		remote_spin_lock_irqsave(&ssbi->rspin_lock, flags);
+
+	while (rem) {
+		if (msgs->flags & I2C_M_RD) {
+			ret = ssbi->read(ssbi, msgs);
+			if (ret)
+				goto transfer_failed;
+		} else {
+			ret = ssbi->write(ssbi, msgs);
+			if (ret)
+				goto transfer_failed;
+		}
+
+		msgs++;
+		rem--;
+	}
+
+	if (ssbi->use_rlock)
+		remote_spin_unlock_irqrestore(&ssbi->rspin_lock, flags);
+
+	return num;
+
+transfer_failed:
+	if (ssbi->use_rlock)
+		remote_spin_unlock_irqrestore(&ssbi->rspin_lock, flags);
+	return ret;
+}
+
+static u32 i2c_ssbi_i2c_func(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_I2C;
+}
+
+static const struct i2c_algorithm msm_i2c_algo = {
+	.master_xfer	= i2c_ssbi_transfer,
+	.functionality	= i2c_ssbi_i2c_func,
+};
+
+static int __init i2c_ssbi_probe(struct platform_device *pdev)
+{
+	int			 ret = 0;
+	struct resource		*ssbi_res;
+	struct i2c_ssbi_dev	*ssbi;
+	const struct msm_i2c_ssbi_platform_data *pdata;
+
+	pdata = pdev->dev.platform_data;
+	if (!pdata) {
+		ret = -ENXIO;
+		dev_err(&pdev->dev, "platform data not initialized\n");
+		goto err_probe_exit;
+	}
+
+	ssbi = kzalloc(sizeof(struct i2c_ssbi_dev), GFP_KERNEL);
+	if (!ssbi) {
+		ret = -ENOMEM;
+		dev_err(&pdev->dev, "allocation failed\n");
+		goto err_probe_exit;
+	}
+
+	ssbi_res = platform_get_resource_byname(pdev,
+						IORESOURCE_MEM, "ssbi_base");
+	if (!ssbi_res) {
+		ret = -ENXIO;
+		dev_err(&pdev->dev, "get_resource_byname failed\n");
+		goto err_probe_res;
+	}
+
+	ssbi->mem_phys_addr = ssbi_res->start;
+	ssbi->mem_size = resource_size(ssbi_res);
+	if (!request_mem_region(ssbi->mem_phys_addr, ssbi->mem_size,
+				SSBI_MSM_NAME)) {
+		ret = -ENXIO;
+		dev_err(&pdev->dev, "request_mem_region failed\n");
+		goto err_probe_reqmem;
+	}
+
+	ssbi->base = ioremap(ssbi->mem_phys_addr, ssbi->mem_size);
+	if (!ssbi->base) {
+		dev_err(&pdev->dev, "ioremap failed\n");
+		goto err_probe_ioremap;
+	}
+
+	ssbi->dev = &pdev->dev;
+	platform_set_drvdata(pdev, ssbi);
+
+	ssbi->controller_type = pdata->controller_type;
+	if (ssbi->controller_type == MSM_SBI_CTRL_PMIC_ARBITER) {
+		ssbi->read = i2c_ssbi_pa_read_bytes;
+		ssbi->write = i2c_ssbi_pa_write_bytes;
+	} else {
+		ssbi->read = i2c_ssbi_read_bytes;
+		ssbi->write = i2c_ssbi_write_bytes;
+	}
+
+	i2c_set_adapdata(&ssbi->adapter, ssbi);
+	ssbi->adapter.algo = &msm_i2c_algo;
+	strlcpy(ssbi->adapter.name,
+		"MSM SSBI adapter",
+		sizeof(ssbi->adapter.name));
+
+	if (pdata->rsl_id) {
+		ret = remote_spin_lock_init(&ssbi->rspin_lock, pdata->rsl_id);
+		if (ret) {
+			dev_err(&pdev->dev, "remote spinlock init failed\n");
+			goto err_remote_spinlock_init_failed;
+		}
+		ssbi->use_rlock = 1;
+	}
+
+	ssbi->adapter.nr = pdev->id;
+	ret = i2c_add_numbered_adapter(&ssbi->adapter);
+	if (ret) {
+		dev_err(&pdev->dev, "i2c_add_numbered_adapter failed\n");
+		goto err_add_adapter_failed;
+	}
+	return 0;
+
+err_add_adapter_failed:
+err_remote_spinlock_init_failed:
+	iounmap(ssbi->base);
+	platform_set_drvdata(pdev, NULL);
+err_probe_ioremap:
+	release_mem_region(ssbi->mem_phys_addr, ssbi->mem_size);
+err_probe_reqmem:
+err_probe_res:
+	kfree(ssbi);
+err_probe_exit:
+	return ret;
+}
+
+static int __devexit i2c_ssbi_remove(struct platform_device *pdev)
+{
+	struct i2c_ssbi_dev *ssbi = platform_get_drvdata(pdev);
+
+	platform_set_drvdata(pdev, NULL);
+	i2c_del_adapter(&ssbi->adapter);
+	iounmap(ssbi->base);
+	release_mem_region(ssbi->mem_phys_addr, ssbi->mem_size);
+	kfree(ssbi);
+	return 0;
+}
+
+static struct platform_driver i2c_ssbi_driver = {
+	.driver		= {
+		.name	= "i2c_ssbi",
+		.owner	= THIS_MODULE,
+	},
+	.remove		= __exit_p(i2c_ssbi_remove),
+};
+
+static int __init i2c_ssbi_init(void)
+{
+	return platform_driver_probe(&i2c_ssbi_driver, i2c_ssbi_probe);
+}
+arch_initcall(i2c_ssbi_init);
+
+static void __exit i2c_ssbi_exit(void)
+{
+	platform_driver_unregister(&i2c_ssbi_driver);
+}
+module_exit(i2c_ssbi_exit);