[T106][ZXW-22]7520V3SCV2.01.01.02P42U09_VEC_V0.8_AP_VEC origin source commit

Change-Id: Ic6e05d89ecd62fc34f82b23dcf306c93764aec4b
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/Kconfig b/ap/os/linux/linux-3.4.x/drivers/i2c/Kconfig
new file mode 100644
index 0000000..5f13c62
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/Kconfig
@@ -0,0 +1,113 @@
+#
+# I2C subsystem configuration
+#
+
+menuconfig I2C
+	tristate "I2C support"
+	depends on HAS_IOMEM
+	select RT_MUTEXES
+	---help---
+	  I2C (pronounce: I-squared-C) is a slow serial bus protocol used in
+	  many micro controller applications and developed by Philips.  SMBus,
+	  or System Management Bus is a subset of the I2C protocol.  More
+	  information is contained in the directory <file:Documentation/i2c/>,
+	  especially in the file called "summary" there.
+
+	  Both I2C and SMBus are supported here. You will need this for
+	  hardware sensors support, and also for Video For Linux support.
+
+	  If you want I2C support, you should say Y here and also to the
+	  specific driver for your bus adapter(s) below.
+
+	  This I2C support can also be built as a module.  If so, the module
+	  will be called i2c-core.
+
+if I2C
+
+config I2C_BOARDINFO
+	boolean
+	default y
+
+config I2C_COMPAT
+	boolean "Enable compatibility bits for old user-space"
+	default y
+	help
+	  Say Y here if you intend to run lm-sensors 3.1.1 or older, or any
+	  other user-space package which expects i2c adapters to be class
+	  devices. If you don't know, say Y.
+
+config I2C_CHARDEV
+	tristate "I2C device interface"
+	help
+	  Say Y here to use i2c-* device files, usually found in the /dev
+	  directory on your system.  They make it possible to have user-space
+	  programs use the I2C bus.  Information on how to do this is
+	  contained in the file <file:Documentation/i2c/dev-interface>.
+
+	  This support is also available as a module.  If so, the module 
+	  will be called i2c-dev.
+
+config I2C_MUX
+	tristate "I2C bus multiplexing support"
+	depends on EXPERIMENTAL
+	help
+	  Say Y here if you want the I2C core to support the ability to
+	  handle multiplexed I2C bus topologies, by presenting each
+	  multiplexed segment as a I2C adapter.
+
+	  This support is also available as a module.  If so, the module
+	  will be called i2c-mux.
+
+source drivers/i2c/muxes/Kconfig
+
+config I2C_HELPER_AUTO
+	bool "Autoselect pertinent helper modules"
+	default y
+	help
+	  Some I2C bus drivers require so-called "I2C algorithm" modules
+	  to work. These are basically software-only abstractions of generic
+	  I2C interfaces. This option will autoselect them so that you don't
+	  have to care.
+
+	  Unselect this only if you need to enable additional helper
+	  modules, for example for use with external I2C bus drivers.
+
+	  In doubt, say Y.
+
+config I2C_SMBUS
+	tristate "SMBus-specific protocols" if !I2C_HELPER_AUTO
+	help
+	  Say Y here if you want support for SMBus extensions to the I2C
+	  specification. At the moment, the only supported extension is
+	  the SMBus alert protocol.
+
+	  This support is also available as a module.  If so, the module
+	  will be called i2c-smbus.
+
+source drivers/i2c/algos/Kconfig
+source drivers/i2c/busses/Kconfig
+
+config I2C_DEBUG_CORE
+	bool "I2C Core debugging messages"
+	help
+	  Say Y here if you want the I2C core to produce a bunch of debug
+	  messages to the system log.  Select this if you are having a
+	  problem with I2C support and want to see more of what is going on.
+
+config I2C_DEBUG_ALGO
+	bool "I2C Algorithm debugging messages"
+	help
+	  Say Y here if you want the I2C algorithm drivers to produce a bunch
+	  of debug messages to the system log.  Select this if you are having
+	  a problem with I2C support and want to see more of what is going
+	  on.
+
+config I2C_DEBUG_BUS
+	bool "I2C Bus debugging messages"
+	help
+	  Say Y here if you want the I2C bus drivers to produce a bunch of
+	  debug messages to the system log.  Select this if you are having
+	  a problem with I2C support and want to see more of what is going
+	  on.
+
+endif # I2C
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/Makefile b/ap/os/linux/linux-3.4.x/drivers/i2c/Makefile
new file mode 100644
index 0000000..beee6b2
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/Makefile
@@ -0,0 +1,13 @@
+#
+# Makefile for the i2c core.
+#
+
+obj-$(CONFIG_I2C_BOARDINFO)	+= i2c-boardinfo.o
+obj-$(CONFIG_I2C)		+= i2c-core.o
+obj-$(CONFIG_I2C_SMBUS)		+= i2c-smbus.o
+obj-$(CONFIG_I2C_CHARDEV)	+= i2c-dev.o
+obj-$(CONFIG_I2C_MUX)		+= i2c-mux.o
+obj-y				+= algos/ busses/ muxes/
+
+ccflags-$(CONFIG_I2C_DEBUG_CORE) := -DDEBUG
+CFLAGS_i2c-core.o := -Wno-deprecated-declarations
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/algos/Kconfig b/ap/os/linux/linux-3.4.x/drivers/i2c/algos/Kconfig
new file mode 100644
index 0000000..f1cfe7e
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/algos/Kconfig
@@ -0,0 +1,17 @@
+#
+# I2C algorithm drivers configuration
+#
+
+menu "I2C Algorithms"
+	visible if !I2C_HELPER_AUTO
+
+config I2C_ALGOBIT
+	tristate "I2C bit-banging interfaces"
+
+config I2C_ALGOPCF
+	tristate "I2C PCF 8584 interfaces"
+
+config I2C_ALGOPCA
+	tristate "I2C PCA 9564 interfaces"
+
+endmenu
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/algos/Makefile b/ap/os/linux/linux-3.4.x/drivers/i2c/algos/Makefile
new file mode 100644
index 0000000..215303f
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/algos/Makefile
@@ -0,0 +1,9 @@
+#
+# Makefile for the i2c algorithms
+#
+
+obj-$(CONFIG_I2C_ALGOBIT)	+= i2c-algo-bit.o
+obj-$(CONFIG_I2C_ALGOPCF)	+= i2c-algo-pcf.o
+obj-$(CONFIG_I2C_ALGOPCA)	+= i2c-algo-pca.o
+
+ccflags-$(CONFIG_I2C_DEBUG_ALGO) := -DDEBUG
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/algos/i2c-algo-bit.c b/ap/os/linux/linux-3.4.x/drivers/i2c/algos/i2c-algo-bit.c
new file mode 100644
index 0000000..7f0b832
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/algos/i2c-algo-bit.c
@@ -0,0 +1,671 @@
+/* -------------------------------------------------------------------------
+ * i2c-algo-bit.c i2c driver algorithms for bit-shift adapters
+ * -------------------------------------------------------------------------
+ *   Copyright (C) 1995-2000 Simon G. Vogl
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+    MA 02110-1301 USA.
+ * ------------------------------------------------------------------------- */
+
+/* With some changes from Frodo Looijaard <frodol@dds.nl>, Kyösti Mälkki
+   <kmalkki@cc.hut.fi> and Jean Delvare <khali@linux-fr.org> */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+
+
+/* ----- global defines ----------------------------------------------- */
+
+#ifdef DEBUG
+#define bit_dbg(level, dev, format, args...) \
+	do { \
+		if (i2c_debug >= level) \
+			dev_dbg(dev, format, ##args); \
+	} while (0)
+#else
+#define bit_dbg(level, dev, format, args...) \
+	do {} while (0)
+#endif /* DEBUG */
+
+/* ----- global variables ---------------------------------------------	*/
+
+static int bit_test;	/* see if the line-setting functions work	*/
+module_param(bit_test, int, S_IRUGO);
+MODULE_PARM_DESC(bit_test, "lines testing - 0 off; 1 report; 2 fail if stuck");
+
+#ifdef DEBUG
+static int i2c_debug = 1;
+module_param(i2c_debug, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(i2c_debug,
+		 "debug level - 0 off; 1 normal; 2 verbose; 3 very verbose");
+#endif
+
+/* --- setting states on the bus with the right timing: ---------------	*/
+
+#define setsda(adap, val)	adap->setsda(adap->data, val)
+#define setscl(adap, val)	adap->setscl(adap->data, val)
+#define getsda(adap)		adap->getsda(adap->data)
+#define getscl(adap)		adap->getscl(adap->data)
+
+static inline void sdalo(struct i2c_algo_bit_data *adap)
+{
+	setsda(adap, 0);
+	udelay((adap->udelay + 1) / 2);
+}
+
+static inline void sdahi(struct i2c_algo_bit_data *adap)
+{
+	setsda(adap, 1);
+	udelay((adap->udelay + 1) / 2);
+}
+
+static inline void scllo(struct i2c_algo_bit_data *adap)
+{
+	setscl(adap, 0);
+	udelay(adap->udelay / 2);
+}
+
+/*
+ * Raise scl line, and do checking for delays. This is necessary for slower
+ * devices.
+ */
+static int sclhi(struct i2c_algo_bit_data *adap)
+{
+	unsigned long start;
+
+	setscl(adap, 1);
+
+	/* Not all adapters have scl sense line... */
+	if (!adap->getscl)
+		goto done;
+
+	start = jiffies;
+	while (!getscl(adap)) {
+		/* This hw knows how to read the clock line, so we wait
+		 * until it actually gets high.  This is safer as some
+		 * chips may hold it low ("clock stretching") while they
+		 * are processing data internally.
+		 */
+		if (time_after(jiffies, start + adap->timeout)) {
+			/* Test one last time, as we may have been preempted
+			 * between last check and timeout test.
+			 */
+			if (getscl(adap))
+				break;
+			return -ETIMEDOUT;
+		}
+		cpu_relax();
+	}
+#ifdef DEBUG
+	if (jiffies != start && i2c_debug >= 3)
+		pr_debug("i2c-algo-bit: needed %ld jiffies for SCL to go "
+			 "high\n", jiffies - start);
+#endif
+
+done:
+	udelay(adap->udelay);
+	return 0;
+}
+
+
+/* --- other auxiliary functions --------------------------------------	*/
+static void i2c_start(struct i2c_algo_bit_data *adap)
+{
+	/* assert: scl, sda are high */
+	setsda(adap, 0);
+	udelay(adap->udelay);
+	scllo(adap);
+}
+
+static void i2c_repstart(struct i2c_algo_bit_data *adap)
+{
+	/* assert: scl is low */
+	sdahi(adap);
+	sclhi(adap);
+	setsda(adap, 0);
+	udelay(adap->udelay);
+	scllo(adap);
+}
+
+
+static void i2c_stop(struct i2c_algo_bit_data *adap)
+{
+	/* assert: scl is low */
+	sdalo(adap);
+	sclhi(adap);
+	setsda(adap, 1);
+	udelay(adap->udelay);
+}
+
+
+
+/* send a byte without start cond., look for arbitration,
+   check ackn. from slave */
+/* returns:
+ * 1 if the device acknowledged
+ * 0 if the device did not ack
+ * -ETIMEDOUT if an error occurred (while raising the scl line)
+ */
+static int i2c_outb(struct i2c_adapter *i2c_adap, unsigned char c)
+{
+	int i;
+	int sb;
+	int ack;
+	struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
+
+	/* assert: scl is low */
+	for (i = 7; i >= 0; i--) {
+		sb = (c >> i) & 1;
+		setsda(adap, sb);
+		udelay((adap->udelay + 1) / 2);
+		if (sclhi(adap) < 0) { /* timed out */
+			bit_dbg(1, &i2c_adap->dev, "i2c_outb: 0x%02x, "
+				"timeout at bit #%d\n", (int)c, i);
+			return -ETIMEDOUT;
+		}
+		/* FIXME do arbitration here:
+		 * if (sb && !getsda(adap)) -> ouch! Get out of here.
+		 *
+		 * Report a unique code, so higher level code can retry
+		 * the whole (combined) message and *NOT* issue STOP.
+		 */
+		scllo(adap);
+	}
+	sdahi(adap);
+	if (sclhi(adap) < 0) { /* timeout */
+		bit_dbg(1, &i2c_adap->dev, "i2c_outb: 0x%02x, "
+			"timeout at ack\n", (int)c);
+		return -ETIMEDOUT;
+	}
+
+	/* read ack: SDA should be pulled down by slave, or it may
+	 * NAK (usually to report problems with the data we wrote).
+	 */
+	ack = !getsda(adap);    /* ack: sda is pulled low -> success */
+	bit_dbg(2, &i2c_adap->dev, "i2c_outb: 0x%02x %s\n", (int)c,
+		ack ? "A" : "NA");
+
+	scllo(adap);
+	return ack;
+	/* assert: scl is low (sda undef) */
+}
+
+
+static int i2c_inb(struct i2c_adapter *i2c_adap)
+{
+	/* read byte via i2c port, without start/stop sequence	*/
+	/* acknowledge is sent in i2c_read.			*/
+	int i;
+	unsigned char indata = 0;
+	struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
+
+	/* assert: scl is low */
+	sdahi(adap);
+	for (i = 0; i < 8; i++) {
+		if (sclhi(adap) < 0) { /* timeout */
+			bit_dbg(1, &i2c_adap->dev, "i2c_inb: timeout at bit "
+				"#%d\n", 7 - i);
+			return -ETIMEDOUT;
+		}
+		indata *= 2;
+		if (getsda(adap))
+			indata |= 0x01;
+		setscl(adap, 0);
+		udelay(i == 7 ? adap->udelay / 2 : adap->udelay);
+	}
+	/* assert: scl is low */
+	return indata;
+}
+
+/*
+ * Sanity check for the adapter hardware - check the reaction of
+ * the bus lines only if it seems to be idle.
+ */
+static int test_bus(struct i2c_adapter *i2c_adap)
+{
+	struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
+	const char *name = i2c_adap->name;
+	int scl, sda, ret;
+
+	if (adap->pre_xfer) {
+		ret = adap->pre_xfer(i2c_adap);
+		if (ret < 0)
+			return -ENODEV;
+	}
+
+	if (adap->getscl == NULL)
+		pr_info("%s: Testing SDA only, SCL is not readable\n", name);
+
+	sda = getsda(adap);
+	scl = (adap->getscl == NULL) ? 1 : getscl(adap);
+	if (!scl || !sda) {
+		printk(KERN_WARNING
+		       "%s: bus seems to be busy (scl=%d, sda=%d)\n",
+		       name, scl, sda);
+		goto bailout;
+	}
+
+	sdalo(adap);
+	sda = getsda(adap);
+	scl = (adap->getscl == NULL) ? 1 : getscl(adap);
+	if (sda) {
+		printk(KERN_WARNING "%s: SDA stuck high!\n", name);
+		goto bailout;
+	}
+	if (!scl) {
+		printk(KERN_WARNING "%s: SCL unexpected low "
+		       "while pulling SDA low!\n", name);
+		goto bailout;
+	}
+
+	sdahi(adap);
+	sda = getsda(adap);
+	scl = (adap->getscl == NULL) ? 1 : getscl(adap);
+	if (!sda) {
+		printk(KERN_WARNING "%s: SDA stuck low!\n", name);
+		goto bailout;
+	}
+	if (!scl) {
+		printk(KERN_WARNING "%s: SCL unexpected low "
+		       "while pulling SDA high!\n", name);
+		goto bailout;
+	}
+
+	scllo(adap);
+	sda = getsda(adap);
+	scl = (adap->getscl == NULL) ? 0 : getscl(adap);
+	if (scl) {
+		printk(KERN_WARNING "%s: SCL stuck high!\n", name);
+		goto bailout;
+	}
+	if (!sda) {
+		printk(KERN_WARNING "%s: SDA unexpected low "
+		       "while pulling SCL low!\n", name);
+		goto bailout;
+	}
+
+	sclhi(adap);
+	sda = getsda(adap);
+	scl = (adap->getscl == NULL) ? 1 : getscl(adap);
+	if (!scl) {
+		printk(KERN_WARNING "%s: SCL stuck low!\n", name);
+		goto bailout;
+	}
+	if (!sda) {
+		printk(KERN_WARNING "%s: SDA unexpected low "
+		       "while pulling SCL high!\n", name);
+		goto bailout;
+	}
+
+	if (adap->post_xfer)
+		adap->post_xfer(i2c_adap);
+
+	pr_info("%s: Test OK\n", name);
+	return 0;
+bailout:
+	sdahi(adap);
+	sclhi(adap);
+
+	if (adap->post_xfer)
+		adap->post_xfer(i2c_adap);
+
+	return -ENODEV;
+}
+
+/* ----- Utility functions
+ */
+
+/* try_address tries to contact a chip for a number of
+ * times before it gives up.
+ * return values:
+ * 1 chip answered
+ * 0 chip did not answer
+ * -x transmission error
+ */
+static int try_address(struct i2c_adapter *i2c_adap,
+		       unsigned char addr, int retries)
+{
+	struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
+	int i, ret = 0;
+
+	for (i = 0; i <= retries; i++) {
+		ret = i2c_outb(i2c_adap, addr);
+		if (ret == 1 || i == retries)
+			break;
+		bit_dbg(3, &i2c_adap->dev, "emitting stop condition\n");
+		i2c_stop(adap);
+		udelay(adap->udelay);
+		yield();
+		bit_dbg(3, &i2c_adap->dev, "emitting start condition\n");
+		i2c_start(adap);
+	}
+	if (i && ret)
+		bit_dbg(1, &i2c_adap->dev, "Used %d tries to %s client at "
+			"0x%02x: %s\n", i + 1,
+			addr & 1 ? "read from" : "write to", addr >> 1,
+			ret == 1 ? "success" : "failed, timeout?");
+	return ret;
+}
+
+static int sendbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
+{
+	const unsigned char *temp = msg->buf;
+	int count = msg->len;
+	unsigned short nak_ok = msg->flags & I2C_M_IGNORE_NAK;
+	int retval;
+	int wrcount = 0;
+
+	while (count > 0) {
+		retval = i2c_outb(i2c_adap, *temp);
+
+		/* OK/ACK; or ignored NAK */
+		if ((retval > 0) || (nak_ok && (retval == 0))) {
+			count--;
+			temp++;
+			wrcount++;
+
+		/* A slave NAKing the master means the slave didn't like
+		 * something about the data it saw.  For example, maybe
+		 * the SMBus PEC was wrong.
+		 */
+		} else if (retval == 0) {
+			dev_err(&i2c_adap->dev, "sendbytes: NAK bailout.\n");
+			return -EIO;
+
+		/* Timeout; or (someday) lost arbitration
+		 *
+		 * FIXME Lost ARB implies retrying the transaction from
+		 * the first message, after the "winning" master issues
+		 * its STOP.  As a rule, upper layer code has no reason
+		 * to know or care about this ... it is *NOT* an error.
+		 */
+		} else {
+			dev_err(&i2c_adap->dev, "sendbytes: error %d\n",
+					retval);
+			return retval;
+		}
+	}
+	return wrcount;
+}
+
+static int acknak(struct i2c_adapter *i2c_adap, int is_ack)
+{
+	struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
+
+	/* assert: sda is high */
+	if (is_ack)		/* send ack */
+		setsda(adap, 0);
+	udelay((adap->udelay + 1) / 2);
+	if (sclhi(adap) < 0) {	/* timeout */
+		dev_err(&i2c_adap->dev, "readbytes: ack/nak timeout\n");
+		return -ETIMEDOUT;
+	}
+	scllo(adap);
+	return 0;
+}
+
+static int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
+{
+	int inval;
+	int rdcount = 0;	/* counts bytes read */
+	unsigned char *temp = msg->buf;
+	int count = msg->len;
+	const unsigned flags = msg->flags;
+
+	while (count > 0) {
+		inval = i2c_inb(i2c_adap);
+		if (inval >= 0) {
+			*temp = inval;
+			rdcount++;
+		} else {   /* read timed out */
+			break;
+		}
+
+		temp++;
+		count--;
+
+		/* Some SMBus transactions require that we receive the
+		   transaction length as the first read byte. */
+		if (rdcount == 1 && (flags & I2C_M_RECV_LEN)) {
+			if (inval <= 0 || inval > I2C_SMBUS_BLOCK_MAX) {
+				if (!(flags & I2C_M_NO_RD_ACK))
+					acknak(i2c_adap, 0);
+				dev_err(&i2c_adap->dev, "readbytes: invalid "
+					"block length (%d)\n", inval);
+				return -EPROTO;
+			}
+			/* The original count value accounts for the extra
+			   bytes, that is, either 1 for a regular transaction,
+			   or 2 for a PEC transaction. */
+			count += inval;
+			msg->len += inval;
+		}
+
+		bit_dbg(2, &i2c_adap->dev, "readbytes: 0x%02x %s\n",
+			inval,
+			(flags & I2C_M_NO_RD_ACK)
+				? "(no ack/nak)"
+				: (count ? "A" : "NA"));
+
+		if (!(flags & I2C_M_NO_RD_ACK)) {
+			inval = acknak(i2c_adap, count);
+			if (inval < 0)
+				return inval;
+		}
+	}
+	return rdcount;
+}
+
+/* doAddress initiates the transfer by generating the start condition (in
+ * try_address) and transmits the address in the necessary format to handle
+ * reads, writes as well as 10bit-addresses.
+ * returns:
+ *  0 everything went okay, the chip ack'ed, or IGNORE_NAK flag was set
+ * -x an error occurred (like: -ENXIO if the device did not answer, or
+ *	-ETIMEDOUT, for example if the lines are stuck...)
+ */
+static int bit_doAddress(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
+{
+	unsigned short flags = msg->flags;
+	unsigned short nak_ok = msg->flags & I2C_M_IGNORE_NAK;
+	struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
+
+	unsigned char addr;
+	int ret, retries;
+
+	retries = nak_ok ? 0 : i2c_adap->retries;
+
+	if (flags & I2C_M_TEN) {
+		/* a ten bit address */
+		addr = 0xf0 | ((msg->addr >> 7) & 0x06);
+		bit_dbg(2, &i2c_adap->dev, "addr0: %d\n", addr);
+		/* try extended address code...*/
+		ret = try_address(i2c_adap, addr, retries);
+		if ((ret != 1) && !nak_ok)  {
+			dev_err(&i2c_adap->dev,
+				"died at extended address code\n");
+			return -ENXIO;
+		}
+		/* the remaining 8 bit address */
+		ret = i2c_outb(i2c_adap, msg->addr & 0xff);
+		if ((ret != 1) && !nak_ok) {
+			/* the chip did not ack / xmission error occurred */
+			dev_err(&i2c_adap->dev, "died at 2nd address code\n");
+			return -ENXIO;
+		}
+		if (flags & I2C_M_RD) {
+			bit_dbg(3, &i2c_adap->dev, "emitting repeated "
+				"start condition\n");
+			i2c_repstart(adap);
+			/* okay, now switch into reading mode */
+			addr |= 0x01;
+			ret = try_address(i2c_adap, addr, retries);
+			if ((ret != 1) && !nak_ok) {
+				dev_err(&i2c_adap->dev,
+					"died at repeated address code\n");
+				return -EIO;
+			}
+		}
+	} else {		/* normal 7bit address	*/
+		addr = msg->addr << 1;
+		if (flags & I2C_M_RD)
+			addr |= 1;
+		if (flags & I2C_M_REV_DIR_ADDR)
+			addr ^= 1;
+		ret = try_address(i2c_adap, addr, retries);
+		if ((ret != 1) && !nak_ok)
+			return -ENXIO;
+	}
+
+	return 0;
+}
+
+static int bit_xfer(struct i2c_adapter *i2c_adap,
+		    struct i2c_msg msgs[], int num)
+{
+	struct i2c_msg *pmsg;
+	struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
+	int i, ret;
+	unsigned short nak_ok;
+
+	if (adap->pre_xfer) {
+		ret = adap->pre_xfer(i2c_adap);
+		if (ret < 0)
+			return ret;
+	}
+
+	bit_dbg(3, &i2c_adap->dev, "emitting start condition\n");
+	i2c_start(adap);
+	for (i = 0; i < num; i++) {
+		pmsg = &msgs[i];
+		nak_ok = pmsg->flags & I2C_M_IGNORE_NAK;
+		if (!(pmsg->flags & I2C_M_NOSTART)) {
+			if (i) {
+				bit_dbg(3, &i2c_adap->dev, "emitting "
+					"repeated start condition\n");
+				i2c_repstart(adap);
+			}
+			ret = bit_doAddress(i2c_adap, pmsg);
+			if ((ret != 0) && !nak_ok) {
+				bit_dbg(1, &i2c_adap->dev, "NAK from "
+					"device addr 0x%02x msg #%d\n",
+					msgs[i].addr, i);
+				goto bailout;
+			}
+		}
+		if (pmsg->flags & I2C_M_RD) {
+			/* read bytes into buffer*/
+			ret = readbytes(i2c_adap, pmsg);
+			if (ret >= 1)
+				bit_dbg(2, &i2c_adap->dev, "read %d byte%s\n",
+					ret, ret == 1 ? "" : "s");
+			if (ret < pmsg->len) {
+				if (ret >= 0)
+					ret = -EIO;
+				goto bailout;
+			}
+		} else {
+			/* write bytes from buffer */
+			ret = sendbytes(i2c_adap, pmsg);
+			if (ret >= 1)
+				bit_dbg(2, &i2c_adap->dev, "wrote %d byte%s\n",
+					ret, ret == 1 ? "" : "s");
+			if (ret < pmsg->len) {
+				if (ret >= 0)
+					ret = -EIO;
+				goto bailout;
+			}
+		}
+	}
+	ret = i;
+
+bailout:
+	bit_dbg(3, &i2c_adap->dev, "emitting stop condition\n");
+	i2c_stop(adap);
+
+	if (adap->post_xfer)
+		adap->post_xfer(i2c_adap);
+	return ret;
+}
+
+static u32 bit_func(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL |
+	       I2C_FUNC_SMBUS_READ_BLOCK_DATA |
+	       I2C_FUNC_SMBUS_BLOCK_PROC_CALL |
+	       I2C_FUNC_10BIT_ADDR | I2C_FUNC_PROTOCOL_MANGLING;
+}
+
+
+/* -----exported algorithm data: -------------------------------------	*/
+
+const struct i2c_algorithm i2c_bit_algo = {
+	.master_xfer	= bit_xfer,
+	.functionality	= bit_func,
+};
+EXPORT_SYMBOL(i2c_bit_algo);
+
+/*
+ * registering functions to load algorithms at runtime
+ */
+static int __i2c_bit_add_bus(struct i2c_adapter *adap,
+			     int (*add_adapter)(struct i2c_adapter *))
+{
+	struct i2c_algo_bit_data *bit_adap = adap->algo_data;
+	int ret;
+
+	if (bit_test) {
+		ret = test_bus(adap);
+		if (bit_test >= 2 && ret < 0)
+			return -ENODEV;
+	}
+
+	/* register new adapter to i2c module... */
+	adap->algo = &i2c_bit_algo;
+	adap->retries = 3;
+
+	ret = add_adapter(adap);
+	if (ret < 0)
+		return ret;
+
+	/* Complain if SCL can't be read */
+	if (bit_adap->getscl == NULL) {
+		dev_warn(&adap->dev, "Not I2C compliant: can't read SCL\n");
+		dev_warn(&adap->dev, "Bus may be unreliable\n");
+	}
+	return 0;
+}
+
+int i2c_bit_add_bus(struct i2c_adapter *adap)
+{
+	return __i2c_bit_add_bus(adap, i2c_add_adapter);
+}
+EXPORT_SYMBOL(i2c_bit_add_bus);
+
+int i2c_bit_add_numbered_bus(struct i2c_adapter *adap)
+{
+	return __i2c_bit_add_bus(adap, i2c_add_numbered_adapter);
+}
+EXPORT_SYMBOL(i2c_bit_add_numbered_bus);
+
+MODULE_AUTHOR("Simon G. Vogl <simon@tk.uni-linz.ac.at>");
+MODULE_DESCRIPTION("I2C-Bus bit-banging algorithm");
+MODULE_LICENSE("GPL");
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/algos/i2c-algo-pca.c b/ap/os/linux/linux-3.4.x/drivers/i2c/algos/i2c-algo-pca.c
new file mode 100644
index 0000000..73133b1
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/algos/i2c-algo-pca.c
@@ -0,0 +1,566 @@
+/*
+ *  i2c-algo-pca.c i2c driver algorithms for PCA9564 adapters
+ *    Copyright (C) 2004 Arcom Control Systems
+ *    Copyright (C) 2008 Pengutronix
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301 USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/delay.h>
+#include <linux/jiffies.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-pca.h>
+
+#define DEB1(fmt, args...) do { if (i2c_debug >= 1)			\
+				 printk(KERN_DEBUG fmt, ## args); } while (0)
+#define DEB2(fmt, args...) do { if (i2c_debug >= 2)			\
+				 printk(KERN_DEBUG fmt, ## args); } while (0)
+#define DEB3(fmt, args...) do { if (i2c_debug >= 3)			\
+				 printk(KERN_DEBUG fmt, ## args); } while (0)
+
+static int i2c_debug;
+
+#define pca_outw(adap, reg, val) adap->write_byte(adap->data, reg, val)
+#define pca_inw(adap, reg) adap->read_byte(adap->data, reg)
+
+#define pca_status(adap) pca_inw(adap, I2C_PCA_STA)
+#define pca_clock(adap) adap->i2c_clock
+#define pca_set_con(adap, val) pca_outw(adap, I2C_PCA_CON, val)
+#define pca_get_con(adap) pca_inw(adap, I2C_PCA_CON)
+#define pca_wait(adap) adap->wait_for_completion(adap->data)
+#define pca_reset(adap) adap->reset_chip(adap->data)
+
+static void pca9665_reset(void *pd)
+{
+	struct i2c_algo_pca_data *adap = pd;
+	pca_outw(adap, I2C_PCA_INDPTR, I2C_PCA_IPRESET);
+	pca_outw(adap, I2C_PCA_IND, 0xA5);
+	pca_outw(adap, I2C_PCA_IND, 0x5A);
+}
+
+/*
+ * Generate a start condition on the i2c bus.
+ *
+ * returns after the start condition has occurred
+ */
+static int pca_start(struct i2c_algo_pca_data *adap)
+{
+	int sta = pca_get_con(adap);
+	DEB2("=== START\n");
+	sta |= I2C_PCA_CON_STA;
+	sta &= ~(I2C_PCA_CON_STO|I2C_PCA_CON_SI);
+	pca_set_con(adap, sta);
+	return pca_wait(adap);
+}
+
+/*
+ * Generate a repeated start condition on the i2c bus
+ *
+ * return after the repeated start condition has occurred
+ */
+static int pca_repeated_start(struct i2c_algo_pca_data *adap)
+{
+	int sta = pca_get_con(adap);
+	DEB2("=== REPEATED START\n");
+	sta |= I2C_PCA_CON_STA;
+	sta &= ~(I2C_PCA_CON_STO|I2C_PCA_CON_SI);
+	pca_set_con(adap, sta);
+	return pca_wait(adap);
+}
+
+/*
+ * Generate a stop condition on the i2c bus
+ *
+ * returns after the stop condition has been generated
+ *
+ * STOPs do not generate an interrupt or set the SI flag, since the
+ * part returns the idle state (0xf8). Hence we don't need to
+ * pca_wait here.
+ */
+static void pca_stop(struct i2c_algo_pca_data *adap)
+{
+	int sta = pca_get_con(adap);
+	DEB2("=== STOP\n");
+	sta |= I2C_PCA_CON_STO;
+	sta &= ~(I2C_PCA_CON_STA|I2C_PCA_CON_SI);
+	pca_set_con(adap, sta);
+}
+
+/*
+ * Send the slave address and R/W bit
+ *
+ * returns after the address has been sent
+ */
+static int pca_address(struct i2c_algo_pca_data *adap,
+		       struct i2c_msg *msg)
+{
+	int sta = pca_get_con(adap);
+	int addr;
+
+	addr = ((0x7f & msg->addr) << 1);
+	if (msg->flags & I2C_M_RD)
+		addr |= 1;
+	DEB2("=== SLAVE ADDRESS %#04x+%c=%#04x\n",
+	     msg->addr, msg->flags & I2C_M_RD ? 'R' : 'W', addr);
+
+	pca_outw(adap, I2C_PCA_DAT, addr);
+
+	sta &= ~(I2C_PCA_CON_STO|I2C_PCA_CON_STA|I2C_PCA_CON_SI);
+	pca_set_con(adap, sta);
+
+	return pca_wait(adap);
+}
+
+/*
+ * Transmit a byte.
+ *
+ * Returns after the byte has been transmitted
+ */
+static int pca_tx_byte(struct i2c_algo_pca_data *adap,
+		       __u8 b)
+{
+	int sta = pca_get_con(adap);
+	DEB2("=== WRITE %#04x\n", b);
+	pca_outw(adap, I2C_PCA_DAT, b);
+
+	sta &= ~(I2C_PCA_CON_STO|I2C_PCA_CON_STA|I2C_PCA_CON_SI);
+	pca_set_con(adap, sta);
+
+	return pca_wait(adap);
+}
+
+/*
+ * Receive a byte
+ *
+ * returns immediately.
+ */
+static void pca_rx_byte(struct i2c_algo_pca_data *adap,
+			__u8 *b, int ack)
+{
+	*b = pca_inw(adap, I2C_PCA_DAT);
+	DEB2("=== READ %#04x %s\n", *b, ack ? "ACK" : "NACK");
+}
+
+/*
+ * Setup ACK or NACK for next received byte and wait for it to arrive.
+ *
+ * Returns after next byte has arrived.
+ */
+static int pca_rx_ack(struct i2c_algo_pca_data *adap,
+		      int ack)
+{
+	int sta = pca_get_con(adap);
+
+	sta &= ~(I2C_PCA_CON_STO|I2C_PCA_CON_STA|I2C_PCA_CON_SI|I2C_PCA_CON_AA);
+
+	if (ack)
+		sta |= I2C_PCA_CON_AA;
+
+	pca_set_con(adap, sta);
+	return pca_wait(adap);
+}
+
+static int pca_xfer(struct i2c_adapter *i2c_adap,
+		    struct i2c_msg *msgs,
+		    int num)
+{
+	struct i2c_algo_pca_data *adap = i2c_adap->algo_data;
+	struct i2c_msg *msg = NULL;
+	int curmsg;
+	int numbytes = 0;
+	int state;
+	int ret;
+	int completed = 1;
+	unsigned long timeout = jiffies + i2c_adap->timeout;
+
+	while ((state = pca_status(adap)) != 0xf8) {
+		if (time_before(jiffies, timeout)) {
+			msleep(10);
+		} else {
+			dev_dbg(&i2c_adap->dev, "bus is not idle. status is "
+				"%#04x\n", state);
+			return -EBUSY;
+		}
+	}
+
+	DEB1("{{{ XFER %d messages\n", num);
+
+	if (i2c_debug >= 2) {
+		for (curmsg = 0; curmsg < num; curmsg++) {
+			int addr, i;
+			msg = &msgs[curmsg];
+
+			addr = (0x7f & msg->addr) ;
+
+			if (msg->flags & I2C_M_RD)
+				printk(KERN_INFO "    [%02d] RD %d bytes from %#02x [%#02x, ...]\n",
+				       curmsg, msg->len, addr, (addr << 1) | 1);
+			else {
+				printk(KERN_INFO "    [%02d] WR %d bytes to %#02x [%#02x%s",
+				       curmsg, msg->len, addr, addr << 1,
+				       msg->len == 0 ? "" : ", ");
+				for (i = 0; i < msg->len; i++)
+					printk("%#04x%s", msg->buf[i], i == msg->len - 1 ? "" : ", ");
+				printk("]\n");
+			}
+		}
+	}
+
+	curmsg = 0;
+	ret = -EIO;
+	while (curmsg < num) {
+		state = pca_status(adap);
+
+		DEB3("STATE is 0x%02x\n", state);
+		msg = &msgs[curmsg];
+
+		switch (state) {
+		case 0xf8: /* On reset or stop the bus is idle */
+			completed = pca_start(adap);
+			break;
+
+		case 0x08: /* A START condition has been transmitted */
+		case 0x10: /* A repeated start condition has been transmitted */
+			completed = pca_address(adap, msg);
+			break;
+
+		case 0x18: /* SLA+W has been transmitted; ACK has been received */
+		case 0x28: /* Data byte in I2CDAT has been transmitted; ACK has been received */
+			if (numbytes < msg->len) {
+				completed = pca_tx_byte(adap,
+							msg->buf[numbytes]);
+				numbytes++;
+				break;
+			}
+			curmsg++; numbytes = 0;
+			if (curmsg == num)
+				pca_stop(adap);
+			else
+				completed = pca_repeated_start(adap);
+			break;
+
+		case 0x20: /* SLA+W has been transmitted; NOT ACK has been received */
+			DEB2("NOT ACK received after SLA+W\n");
+			pca_stop(adap);
+			ret = -ENXIO;
+			goto out;
+
+		case 0x40: /* SLA+R has been transmitted; ACK has been received */
+			completed = pca_rx_ack(adap, msg->len > 1);
+			break;
+
+		case 0x50: /* Data bytes has been received; ACK has been returned */
+			if (numbytes < msg->len) {
+				pca_rx_byte(adap, &msg->buf[numbytes], 1);
+				numbytes++;
+				completed = pca_rx_ack(adap,
+						       numbytes < msg->len - 1);
+				break;
+			}
+			curmsg++; numbytes = 0;
+			if (curmsg == num)
+				pca_stop(adap);
+			else
+				completed = pca_repeated_start(adap);
+			break;
+
+		case 0x48: /* SLA+R has been transmitted; NOT ACK has been received */
+			DEB2("NOT ACK received after SLA+R\n");
+			pca_stop(adap);
+			ret = -ENXIO;
+			goto out;
+
+		case 0x30: /* Data byte in I2CDAT has been transmitted; NOT ACK has been received */
+			DEB2("NOT ACK received after data byte\n");
+			pca_stop(adap);
+			goto out;
+
+		case 0x38: /* Arbitration lost during SLA+W, SLA+R or data bytes */
+			DEB2("Arbitration lost\n");
+			/*
+			 * The PCA9564 data sheet (2006-09-01) says "A
+			 * START condition will be transmitted when the
+			 * bus becomes free (STOP or SCL and SDA high)"
+			 * when the STA bit is set (p. 11).
+			 *
+			 * In case this won't work, try pca_reset()
+			 * instead.
+			 */
+			pca_start(adap);
+			goto out;
+
+		case 0x58: /* Data byte has been received; NOT ACK has been returned */
+			if (numbytes == msg->len - 1) {
+				pca_rx_byte(adap, &msg->buf[numbytes], 0);
+				curmsg++; numbytes = 0;
+				if (curmsg == num)
+					pca_stop(adap);
+				else
+					completed = pca_repeated_start(adap);
+			} else {
+				DEB2("NOT ACK sent after data byte received. "
+				     "Not final byte. numbytes %d. len %d\n",
+				     numbytes, msg->len);
+				pca_stop(adap);
+				goto out;
+			}
+			break;
+		case 0x70: /* Bus error - SDA stuck low */
+			DEB2("BUS ERROR - SDA Stuck low\n");
+			pca_reset(adap);
+			goto out;
+		case 0x90: /* Bus error - SCL stuck low */
+			DEB2("BUS ERROR - SCL Stuck low\n");
+			pca_reset(adap);
+			goto out;
+		case 0x00: /* Bus error during master or slave mode due to illegal START or STOP condition */
+			DEB2("BUS ERROR - Illegal START or STOP\n");
+			pca_reset(adap);
+			goto out;
+		default:
+			dev_err(&i2c_adap->dev, "unhandled SIO state 0x%02x\n", state);
+			break;
+		}
+
+		if (!completed)
+			goto out;
+	}
+
+	ret = curmsg;
+ out:
+	DEB1("}}} transferred %d/%d messages. "
+	     "status is %#04x. control is %#04x\n",
+	     curmsg, num, pca_status(adap),
+	     pca_get_con(adap));
+	return ret;
+}
+
+static u32 pca_func(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm pca_algo = {
+	.master_xfer	= pca_xfer,
+	.functionality	= pca_func,
+};
+
+static unsigned int pca_probe_chip(struct i2c_adapter *adap)
+{
+	struct i2c_algo_pca_data *pca_data = adap->algo_data;
+	/* The trick here is to check if there is an indirect register
+	 * available. If there is one, we will read the value we first
+	 * wrote on I2C_PCA_IADR. Otherwise, we will read the last value
+	 * we wrote on I2C_PCA_ADR
+	 */
+	pca_outw(pca_data, I2C_PCA_INDPTR, I2C_PCA_IADR);
+	pca_outw(pca_data, I2C_PCA_IND, 0xAA);
+	pca_outw(pca_data, I2C_PCA_INDPTR, I2C_PCA_ITO);
+	pca_outw(pca_data, I2C_PCA_IND, 0x00);
+	pca_outw(pca_data, I2C_PCA_INDPTR, I2C_PCA_IADR);
+	if (pca_inw(pca_data, I2C_PCA_IND) == 0xAA) {
+		printk(KERN_INFO "%s: PCA9665 detected.\n", adap->name);
+		return I2C_PCA_CHIP_9665;
+	} else {
+		printk(KERN_INFO "%s: PCA9564 detected.\n", adap->name);
+		return I2C_PCA_CHIP_9564;
+	}
+}
+
+static int pca_init(struct i2c_adapter *adap)
+{
+	struct i2c_algo_pca_data *pca_data = adap->algo_data;
+
+	adap->algo = &pca_algo;
+
+	if (pca_probe_chip(adap) == I2C_PCA_CHIP_9564) {
+		static int freqs[] = {330, 288, 217, 146, 88, 59, 44, 36};
+		int clock;
+
+		if (pca_data->i2c_clock > 7) {
+			switch (pca_data->i2c_clock) {
+			case 330000:
+				pca_data->i2c_clock = I2C_PCA_CON_330kHz;
+				break;
+			case 288000:
+				pca_data->i2c_clock = I2C_PCA_CON_288kHz;
+				break;
+			case 217000:
+				pca_data->i2c_clock = I2C_PCA_CON_217kHz;
+				break;
+			case 146000:
+				pca_data->i2c_clock = I2C_PCA_CON_146kHz;
+				break;
+			case 88000:
+				pca_data->i2c_clock = I2C_PCA_CON_88kHz;
+				break;
+			case 59000:
+				pca_data->i2c_clock = I2C_PCA_CON_59kHz;
+				break;
+			case 44000:
+				pca_data->i2c_clock = I2C_PCA_CON_44kHz;
+				break;
+			case 36000:
+				pca_data->i2c_clock = I2C_PCA_CON_36kHz;
+				break;
+			default:
+				printk(KERN_WARNING
+					"%s: Invalid I2C clock speed selected."
+					" Using default 59kHz.\n", adap->name);
+			pca_data->i2c_clock = I2C_PCA_CON_59kHz;
+			}
+		} else {
+			printk(KERN_WARNING "%s: "
+				"Choosing the clock frequency based on "
+				"index is deprecated."
+				" Use the nominal frequency.\n", adap->name);
+		}
+
+		pca_reset(pca_data);
+
+		clock = pca_clock(pca_data);
+		printk(KERN_INFO "%s: Clock frequency is %dkHz\n",
+		     adap->name, freqs[clock]);
+
+		pca_set_con(pca_data, I2C_PCA_CON_ENSIO | clock);
+	} else {
+		int clock;
+		int mode;
+		int tlow, thi;
+		/* Values can be found on PCA9665 datasheet section 7.3.2.6 */
+		int min_tlow, min_thi;
+		/* These values are the maximum raise and fall values allowed
+		 * by the I2C operation mode (Standard, Fast or Fast+)
+		 * They are used (added) below to calculate the clock dividers
+		 * of PCA9665. Note that they are slightly different of the
+		 * real maximum, to allow the change on mode exactly on the
+		 * maximum clock rate for each mode
+		 */
+		int raise_fall_time;
+
+		/* Ignore the reset function from the module,
+		 * we can use the parallel bus reset
+		 */
+		pca_data->reset_chip = pca9665_reset;
+
+		if (pca_data->i2c_clock > 1265800) {
+			printk(KERN_WARNING "%s: I2C clock speed too high."
+				" Using 1265.8kHz.\n", adap->name);
+			pca_data->i2c_clock = 1265800;
+		}
+
+		if (pca_data->i2c_clock < 60300) {
+			printk(KERN_WARNING "%s: I2C clock speed too low."
+				" Using 60.3kHz.\n", adap->name);
+			pca_data->i2c_clock = 60300;
+		}
+
+		/* To avoid integer overflow, use clock/100 for calculations */
+		clock = pca_clock(pca_data) / 100;
+
+		if (pca_data->i2c_clock > 10000) {
+			mode = I2C_PCA_MODE_TURBO;
+			min_tlow = 14;
+			min_thi  = 5;
+			raise_fall_time = 22; /* Raise 11e-8s, Fall 11e-8s */
+		} else if (pca_data->i2c_clock > 4000) {
+			mode = I2C_PCA_MODE_FASTP;
+			min_tlow = 17;
+			min_thi  = 9;
+			raise_fall_time = 22; /* Raise 11e-8s, Fall 11e-8s */
+		} else if (pca_data->i2c_clock > 1000) {
+			mode = I2C_PCA_MODE_FAST;
+			min_tlow = 44;
+			min_thi  = 20;
+			raise_fall_time = 58; /* Raise 29e-8s, Fall 29e-8s */
+		} else {
+			mode = I2C_PCA_MODE_STD;
+			min_tlow = 157;
+			min_thi  = 134;
+			raise_fall_time = 127; /* Raise 29e-8s, Fall 98e-8s */
+		}
+
+		/* The minimum clock that respects the thi/tlow = 134/157 is
+		 * 64800 Hz. Below that, we have to fix the tlow to 255 and
+		 * calculate the thi factor.
+		 */
+		if (clock < 648) {
+			tlow = 255;
+			thi = 1000000 - clock * raise_fall_time;
+			thi /= (I2C_PCA_OSC_PER * clock) - tlow;
+		} else {
+			tlow = (1000000 - clock * raise_fall_time) * min_tlow;
+			tlow /= I2C_PCA_OSC_PER * clock * (min_thi + min_tlow);
+			thi = tlow * min_thi / min_tlow;
+		}
+
+		pca_reset(pca_data);
+
+		printk(KERN_INFO
+		     "%s: Clock frequency is %dHz\n", adap->name, clock * 100);
+
+		pca_outw(pca_data, I2C_PCA_INDPTR, I2C_PCA_IMODE);
+		pca_outw(pca_data, I2C_PCA_IND, mode);
+		pca_outw(pca_data, I2C_PCA_INDPTR, I2C_PCA_ISCLL);
+		pca_outw(pca_data, I2C_PCA_IND, tlow);
+		pca_outw(pca_data, I2C_PCA_INDPTR, I2C_PCA_ISCLH);
+		pca_outw(pca_data, I2C_PCA_IND, thi);
+
+		pca_set_con(pca_data, I2C_PCA_CON_ENSIO);
+	}
+	udelay(500); /* 500 us for oscilator to stabilise */
+
+	return 0;
+}
+
+/*
+ * registering functions to load algorithms at runtime
+ */
+int i2c_pca_add_bus(struct i2c_adapter *adap)
+{
+	int rval;
+
+	rval = pca_init(adap);
+	if (rval)
+		return rval;
+
+	return i2c_add_adapter(adap);
+}
+EXPORT_SYMBOL(i2c_pca_add_bus);
+
+int i2c_pca_add_numbered_bus(struct i2c_adapter *adap)
+{
+	int rval;
+
+	rval = pca_init(adap);
+	if (rval)
+		return rval;
+
+	return i2c_add_numbered_adapter(adap);
+}
+EXPORT_SYMBOL(i2c_pca_add_numbered_bus);
+
+MODULE_AUTHOR("Ian Campbell <icampbell@arcom.com>, "
+	"Wolfram Sang <w.sang@pengutronix.de>");
+MODULE_DESCRIPTION("I2C-Bus PCA9564/PCA9665 algorithm");
+MODULE_LICENSE("GPL");
+
+module_param(i2c_debug, int, 0);
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/algos/i2c-algo-pcf.c b/ap/os/linux/linux-3.4.x/drivers/i2c/algos/i2c-algo-pcf.c
new file mode 100644
index 0000000..5c23795
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/algos/i2c-algo-pcf.c
@@ -0,0 +1,442 @@
+/*
+ * i2c-algo-pcf.c i2c driver algorithms for PCF8584 adapters
+ *
+ *   Copyright (C) 1995-1997 Simon G. Vogl
+ *		   1998-2000 Hans Berglund
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA 02110-1301 USA.
+ *
+ * With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and
+ * Frodo Looijaard <frodol@dds.nl>, and also from Martin Bailey
+ * <mbailey@littlefeet-inc.com>
+ *
+ * Partially rewriten by Oleg I. Vdovikin <vdovikin@jscc.ru> to handle multiple
+ * messages, proper stop/repstart signaling during receive, added detect code
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-pcf.h>
+#include "i2c-algo-pcf.h"
+
+
+#define DEB2(x) if (i2c_debug >= 2) x
+#define DEB3(x) if (i2c_debug >= 3) x /* print several statistical values */
+#define DEBPROTO(x) if (i2c_debug >= 9) x;
+	/* debug the protocol by showing transferred bits */
+#define DEF_TIMEOUT 16
+
+/*
+ * module parameters:
+ */
+static int i2c_debug;
+
+/* setting states on the bus with the right timing: */
+
+#define set_pcf(adap, ctl, val) adap->setpcf(adap->data, ctl, val)
+#define get_pcf(adap, ctl) adap->getpcf(adap->data, ctl)
+#define get_own(adap) adap->getown(adap->data)
+#define get_clock(adap) adap->getclock(adap->data)
+#define i2c_outb(adap, val) adap->setpcf(adap->data, 0, val)
+#define i2c_inb(adap) adap->getpcf(adap->data, 0)
+
+/* other auxiliary functions */
+
+static void i2c_start(struct i2c_algo_pcf_data *adap)
+{
+	DEBPROTO(printk(KERN_DEBUG "S "));
+	set_pcf(adap, 1, I2C_PCF_START);
+}
+
+static void i2c_repstart(struct i2c_algo_pcf_data *adap)
+{
+	DEBPROTO(printk(" Sr "));
+	set_pcf(adap, 1, I2C_PCF_REPSTART);
+}
+
+static void i2c_stop(struct i2c_algo_pcf_data *adap)
+{
+	DEBPROTO(printk("P\n"));
+	set_pcf(adap, 1, I2C_PCF_STOP);
+}
+
+static void handle_lab(struct i2c_algo_pcf_data *adap, const int *status)
+{
+	DEB2(printk(KERN_INFO
+		"i2c-algo-pcf.o: lost arbitration (CSR 0x%02x)\n",
+		*status));
+	/*
+	 * Cleanup from LAB -- reset and enable ESO.
+	 * This resets the PCF8584; since we've lost the bus, no
+	 * further attempts should be made by callers to clean up
+	 * (no i2c_stop() etc.)
+	 */
+	set_pcf(adap, 1, I2C_PCF_PIN);
+	set_pcf(adap, 1, I2C_PCF_ESO);
+	/*
+	 * We pause for a time period sufficient for any running
+	 * I2C transaction to complete -- the arbitration logic won't
+	 * work properly until the next START is seen.
+	 * It is assumed the bus driver or client has set a proper value.
+	 *
+	 * REVISIT: should probably use msleep instead of mdelay if we
+	 * know we can sleep.
+	 */
+	if (adap->lab_mdelay)
+		mdelay(adap->lab_mdelay);
+
+	DEB2(printk(KERN_INFO
+		"i2c-algo-pcf.o: reset LAB condition (CSR 0x%02x)\n",
+		get_pcf(adap, 1)));
+}
+
+static int wait_for_bb(struct i2c_algo_pcf_data *adap)
+{
+
+	int timeout = DEF_TIMEOUT;
+	int status;
+
+	status = get_pcf(adap, 1);
+
+	while (!(status & I2C_PCF_BB) && --timeout) {
+		udelay(100); /* wait for 100 us */
+		status = get_pcf(adap, 1);
+	}
+
+	if (timeout == 0) {
+		printk(KERN_ERR "Timeout waiting for Bus Busy\n");
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+static int wait_for_pin(struct i2c_algo_pcf_data *adap, int *status)
+{
+
+	int timeout = DEF_TIMEOUT;
+
+	*status = get_pcf(adap, 1);
+
+	while ((*status & I2C_PCF_PIN) && --timeout) {
+		adap->waitforpin(adap->data);
+		*status = get_pcf(adap, 1);
+	}
+	if (*status & I2C_PCF_LAB) {
+		handle_lab(adap, status);
+		return -EINTR;
+	}
+
+	if (timeout == 0)
+		return -ETIMEDOUT;
+
+	return 0;
+}
+
+/*
+ * This should perform the 'PCF8584 initialization sequence' as described
+ * in the Philips IC12 data book (1995, Aug 29).
+ * There should be a 30 clock cycle wait after reset, I assume this
+ * has been fulfilled.
+ * There should be a delay at the end equal to the longest I2C message
+ * to synchronize the BB-bit (in multimaster systems). How long is
+ * this? I assume 1 second is always long enough.
+ *
+ * vdovikin: added detect code for PCF8584
+ */
+static int pcf_init_8584 (struct i2c_algo_pcf_data *adap)
+{
+	unsigned char temp;
+
+	DEB3(printk(KERN_DEBUG "i2c-algo-pcf.o: PCF state 0x%02x\n",
+				get_pcf(adap, 1)));
+
+	/* S1=0x80: S0 selected, serial interface off */
+	set_pcf(adap, 1, I2C_PCF_PIN);
+	/*
+	 * check to see S1 now used as R/W ctrl -
+	 * PCF8584 does that when ESO is zero
+	 */
+	if (((temp = get_pcf(adap, 1)) & 0x7f) != (0)) {
+		DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't select S0 (0x%02x).\n", temp));
+		return -ENXIO; /* definitely not PCF8584 */
+	}
+
+	/* load own address in S0, effective address is (own << 1) */
+	i2c_outb(adap, get_own(adap));
+	/* check it's really written */
+	if ((temp = i2c_inb(adap)) != get_own(adap)) {
+		DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't set S0 (0x%02x).\n", temp));
+		return -ENXIO;
+	}
+
+	/* S1=0xA0, next byte in S2 */
+	set_pcf(adap, 1, I2C_PCF_PIN | I2C_PCF_ES1);
+	/* check to see S2 now selected */
+	if (((temp = get_pcf(adap, 1)) & 0x7f) != I2C_PCF_ES1) {
+		DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't select S2 (0x%02x).\n", temp));
+		return -ENXIO;
+	}
+
+	/* load clock register S2 */
+	i2c_outb(adap, get_clock(adap));
+	/* check it's really written, the only 5 lowest bits does matter */
+	if (((temp = i2c_inb(adap)) & 0x1f) != get_clock(adap)) {
+		DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't set S2 (0x%02x).\n", temp));
+		return -ENXIO;
+	}
+
+	/* Enable serial interface, idle, S0 selected */
+	set_pcf(adap, 1, I2C_PCF_IDLE);
+
+	/* check to see PCF is really idled and we can access status register */
+	if ((temp = get_pcf(adap, 1)) != (I2C_PCF_PIN | I2C_PCF_BB)) {
+		DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't select S1` (0x%02x).\n", temp));
+		return -ENXIO;
+	}
+
+	printk(KERN_DEBUG "i2c-algo-pcf.o: detected and initialized PCF8584.\n");
+
+	return 0;
+}
+
+static int pcf_sendbytes(struct i2c_adapter *i2c_adap, const char *buf,
+			 int count, int last)
+{
+	struct i2c_algo_pcf_data *adap = i2c_adap->algo_data;
+	int wrcount, status, timeout;
+
+	for (wrcount=0; wrcount<count; ++wrcount) {
+		DEB2(dev_dbg(&i2c_adap->dev, "i2c_write: writing %2.2X\n",
+				buf[wrcount] & 0xff));
+		i2c_outb(adap, buf[wrcount]);
+		timeout = wait_for_pin(adap, &status);
+		if (timeout) {
+			if (timeout == -EINTR)
+				return -EINTR; /* arbitration lost */
+
+			i2c_stop(adap);
+			dev_err(&i2c_adap->dev, "i2c_write: error - timeout.\n");
+			return -EREMOTEIO; /* got a better one ?? */
+		}
+		if (status & I2C_PCF_LRB) {
+			i2c_stop(adap);
+			dev_err(&i2c_adap->dev, "i2c_write: error - no ack.\n");
+			return -EREMOTEIO; /* got a better one ?? */
+		}
+	}
+	if (last)
+		i2c_stop(adap);
+	else
+		i2c_repstart(adap);
+
+	return wrcount;
+}
+
+static int pcf_readbytes(struct i2c_adapter *i2c_adap, char *buf,
+			 int count, int last)
+{
+	int i, status;
+	struct i2c_algo_pcf_data *adap = i2c_adap->algo_data;
+	int wfp;
+
+	/* increment number of bytes to read by one -- read dummy byte */
+	for (i = 0; i <= count; i++) {
+
+		if ((wfp = wait_for_pin(adap, &status))) {
+			if (wfp == -EINTR)
+				return -EINTR; /* arbitration lost */
+
+			i2c_stop(adap);
+			dev_err(&i2c_adap->dev, "pcf_readbytes timed out.\n");
+			return -1;
+		}
+
+		if ((status & I2C_PCF_LRB) && (i != count)) {
+			i2c_stop(adap);
+			dev_err(&i2c_adap->dev, "i2c_read: i2c_inb, No ack.\n");
+			return -1;
+		}
+
+		if (i == count - 1) {
+			set_pcf(adap, 1, I2C_PCF_ESO);
+		} else if (i == count) {
+			if (last)
+				i2c_stop(adap);
+			else
+				i2c_repstart(adap);
+		}
+
+		if (i)
+			buf[i - 1] = i2c_inb(adap);
+		else
+			i2c_inb(adap); /* dummy read */
+	}
+
+	return i - 1;
+}
+
+
+static int pcf_doAddress(struct i2c_algo_pcf_data *adap,
+			 struct i2c_msg *msg)
+{
+	unsigned short flags = msg->flags;
+	unsigned char addr;
+
+	addr = msg->addr << 1;
+	if (flags & I2C_M_RD)
+		addr |= 1;
+	if (flags & I2C_M_REV_DIR_ADDR)
+		addr ^= 1;
+	i2c_outb(adap, addr);
+
+	return 0;
+}
+
+static int pcf_xfer(struct i2c_adapter *i2c_adap,
+		    struct i2c_msg *msgs,
+		    int num)
+{
+	struct i2c_algo_pcf_data *adap = i2c_adap->algo_data;
+	struct i2c_msg *pmsg;
+	int i;
+	int ret=0, timeout, status;
+
+	if (adap->xfer_begin)
+		adap->xfer_begin(adap->data);
+
+	/* Check for bus busy */
+	timeout = wait_for_bb(adap);
+	if (timeout) {
+		DEB2(printk(KERN_ERR "i2c-algo-pcf.o: "
+			    "Timeout waiting for BB in pcf_xfer\n");)
+		i = -EIO;
+		goto out;
+	}
+
+	for (i = 0;ret >= 0 && i < num; i++) {
+		pmsg = &msgs[i];
+
+		DEB2(printk(KERN_DEBUG "i2c-algo-pcf.o: Doing %s %d bytes to 0x%02x - %d of %d messages\n",
+		     pmsg->flags & I2C_M_RD ? "read" : "write",
+		     pmsg->len, pmsg->addr, i + 1, num);)
+
+		ret = pcf_doAddress(adap, pmsg);
+
+		/* Send START */
+		if (i == 0)
+			i2c_start(adap);
+
+		/* Wait for PIN (pending interrupt NOT) */
+		timeout = wait_for_pin(adap, &status);
+		if (timeout) {
+			if (timeout == -EINTR) {
+				/* arbitration lost */
+				i = -EINTR;
+				goto out;
+			}
+			i2c_stop(adap);
+			DEB2(printk(KERN_ERR "i2c-algo-pcf.o: Timeout waiting "
+				    "for PIN(1) in pcf_xfer\n");)
+			i = -EREMOTEIO;
+			goto out;
+		}
+
+		/* Check LRB (last rcvd bit - slave ack) */
+		if (status & I2C_PCF_LRB) {
+			i2c_stop(adap);
+			DEB2(printk(KERN_ERR "i2c-algo-pcf.o: No LRB(1) in pcf_xfer\n");)
+			i = -EREMOTEIO;
+			goto out;
+		}
+
+		DEB3(printk(KERN_DEBUG "i2c-algo-pcf.o: Msg %d, addr=0x%x, flags=0x%x, len=%d\n",
+			    i, msgs[i].addr, msgs[i].flags, msgs[i].len);)
+
+		if (pmsg->flags & I2C_M_RD) {
+			ret = pcf_readbytes(i2c_adap, pmsg->buf, pmsg->len,
+					    (i + 1 == num));
+
+			if (ret != pmsg->len) {
+				DEB2(printk(KERN_DEBUG "i2c-algo-pcf.o: fail: "
+					    "only read %d bytes.\n",ret));
+			} else {
+				DEB2(printk(KERN_DEBUG "i2c-algo-pcf.o: read %d bytes.\n",ret));
+			}
+		} else {
+			ret = pcf_sendbytes(i2c_adap, pmsg->buf, pmsg->len,
+					    (i + 1 == num));
+
+			if (ret != pmsg->len) {
+				DEB2(printk(KERN_DEBUG "i2c-algo-pcf.o: fail: "
+					    "only wrote %d bytes.\n",ret));
+			} else {
+				DEB2(printk(KERN_DEBUG "i2c-algo-pcf.o: wrote %d bytes.\n",ret));
+			}
+		}
+	}
+
+out:
+	if (adap->xfer_end)
+		adap->xfer_end(adap->data);
+	return i;
+}
+
+static u32 pcf_func(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL |
+	       I2C_FUNC_PROTOCOL_MANGLING;
+}
+
+/* exported algorithm data: */
+static const struct i2c_algorithm pcf_algo = {
+	.master_xfer	= pcf_xfer,
+	.functionality	= pcf_func,
+};
+
+/*
+ * registering functions to load algorithms at runtime
+ */
+int i2c_pcf_add_bus(struct i2c_adapter *adap)
+{
+	struct i2c_algo_pcf_data *pcf_adap = adap->algo_data;
+	int rval;
+
+	DEB2(dev_dbg(&adap->dev, "hw routines registered.\n"));
+
+	/* register new adapter to i2c module... */
+	adap->algo = &pcf_algo;
+
+	if ((rval = pcf_init_8584(pcf_adap)))
+		return rval;
+
+	rval = i2c_add_adapter(adap);
+
+	return rval;
+}
+EXPORT_SYMBOL(i2c_pcf_add_bus);
+
+MODULE_AUTHOR("Hans Berglund <hb@spacetec.no>");
+MODULE_DESCRIPTION("I2C-Bus PCF8584 algorithm");
+MODULE_LICENSE("GPL");
+
+module_param(i2c_debug, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(i2c_debug,
+	"debug level - 0 off; 1 normal; 2,3 more verbose; 9 pcf-protocol");
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/algos/i2c-algo-pcf.h b/ap/os/linux/linux-3.4.x/drivers/i2c/algos/i2c-algo-pcf.h
new file mode 100644
index 0000000..1ec703e
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/algos/i2c-algo-pcf.h
@@ -0,0 +1,77 @@
+/* -------------------------------------------------------------------- */
+/* i2c-pcf8584.h: PCF 8584 global defines				*/
+/* -------------------------------------------------------------------- */
+/*   Copyright (C) 1996 Simon G. Vogl
+                   1999 Hans Berglund
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+    MA 02110-1301 USA.							*/
+/* --------------------------------------------------------------------	*/
+
+/* With some changes from Frodo Looijaard <frodol@dds.nl> */
+
+#ifndef I2C_PCF8584_H
+#define I2C_PCF8584_H 1
+
+/* ----- Control register bits ----------------------------------------	*/
+#define I2C_PCF_PIN	0x80
+#define I2C_PCF_ESO	0x40
+#define I2C_PCF_ES1	0x20
+#define I2C_PCF_ES2	0x10
+#define I2C_PCF_ENI	0x08
+#define I2C_PCF_STA	0x04
+#define I2C_PCF_STO	0x02
+#define I2C_PCF_ACK	0x01
+
+#define I2C_PCF_START    (I2C_PCF_PIN | I2C_PCF_ESO | I2C_PCF_STA | I2C_PCF_ACK)
+#define I2C_PCF_STOP     (I2C_PCF_PIN | I2C_PCF_ESO | I2C_PCF_STO | I2C_PCF_ACK)
+#define I2C_PCF_REPSTART (              I2C_PCF_ESO | I2C_PCF_STA | I2C_PCF_ACK)
+#define I2C_PCF_IDLE     (I2C_PCF_PIN | I2C_PCF_ESO               | I2C_PCF_ACK)
+
+/* ----- Status register bits -----------------------------------------	*/
+/*#define I2C_PCF_PIN  0x80    as above*/
+
+#define I2C_PCF_INI 0x40   /* 1 if not initialized */
+#define I2C_PCF_STS 0x20
+#define I2C_PCF_BER 0x10
+#define I2C_PCF_AD0 0x08
+#define I2C_PCF_LRB 0x08
+#define I2C_PCF_AAS 0x04
+#define I2C_PCF_LAB 0x02
+#define I2C_PCF_BB  0x01
+
+/* ----- Chip clock frequencies ---------------------------------------	*/
+#define I2C_PCF_CLK3	0x00
+#define I2C_PCF_CLK443	0x10
+#define I2C_PCF_CLK6	0x14
+#define I2C_PCF_CLK	0x18
+#define I2C_PCF_CLK12	0x1c
+
+/* ----- transmission frequencies -------------------------------------	*/
+#define I2C_PCF_TRNS90 0x00	/*  90 kHz */
+#define I2C_PCF_TRNS45 0x01	/*  45 kHz */
+#define I2C_PCF_TRNS11 0x02	/*  11 kHz */
+#define I2C_PCF_TRNS15 0x03	/* 1.5 kHz */
+
+
+/* ----- Access to internal registers according to ES1,ES2 ------------	*/
+/* they are mapped to the data port ( a0 = 0 ) 				*/
+/* available when ESO == 0 :						*/
+
+#define I2C_PCF_OWNADR	0
+#define I2C_PCF_INTREG	I2C_PCF_ES2
+#define I2C_PCF_CLKREG	I2C_PCF_ES1
+
+#endif /* I2C_PCF8584_H */
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/busses/Kconfig b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/Kconfig
new file mode 100644
index 0000000..9bb7bf9
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/Kconfig
@@ -0,0 +1,924 @@
+#
+# Sensor device configuration
+#
+
+menu "I2C Hardware Bus support"
+
+comment "PC SMBus host controller drivers"
+	depends on PCI
+
+config I2C_ALI1535
+	tristate "ALI 1535"
+	depends on PCI
+	help
+	  If you say yes to this option, support will be included for the SMB
+	  Host controller on Acer Labs Inc. (ALI) M1535 South Bridges.  The SMB
+	  controller is part of the 7101 device, which is an ACPI-compliant
+	  Power Management Unit (PMU).
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called i2c-ali1535.
+
+config I2C_ALI1563
+	tristate "ALI 1563"
+	depends on PCI && EXPERIMENTAL
+	help
+	  If you say yes to this option, support will be included for the SMB
+	  Host controller on Acer Labs Inc. (ALI) M1563 South Bridges.  The SMB
+	  controller is part of the 7101 device, which is an ACPI-compliant
+	  Power Management Unit (PMU).
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called i2c-ali1563.
+
+config I2C_ALI15X3
+	tristate "ALI 15x3"
+	depends on PCI
+	help
+	  If you say yes to this option, support will be included for the
+	  Acer Labs Inc. (ALI) M1514 and M1543 motherboard I2C interfaces.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called i2c-ali15x3.
+
+config I2C_AMD756
+	tristate "AMD 756/766/768/8111 and nVidia nForce"
+	depends on PCI
+	help
+	  If you say yes to this option, support will be included for the AMD
+	  756/766/768 mainboard I2C interfaces.  The driver also includes
+	  support for the first (SMBus 1.0) I2C interface of the AMD 8111 and
+	  the nVidia nForce I2C interface.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called i2c-amd756.
+
+config I2C_AMD756_S4882
+	tristate "SMBus multiplexing on the Tyan S4882"
+	depends on I2C_AMD756 && X86 && EXPERIMENTAL
+	help
+	  Enabling this option will add specific SMBus support for the Tyan
+	  S4882 motherboard.  On this 4-CPU board, the SMBus is multiplexed
+	  over 8 different channels, where the various memory module EEPROMs
+	  and temperature sensors live.  Saying yes here will give you access
+	  to these in addition to the trunk.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called i2c-amd756-s4882.
+
+config I2C_AMD8111
+	tristate "AMD 8111"
+	depends on PCI
+	help
+	  If you say yes to this option, support will be included for the
+	  second (SMBus 2.0) AMD 8111 mainboard I2C interface.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called i2c-amd8111.
+
+config I2C_I801
+	tristate "Intel 82801 (ICH/PCH)"
+	depends on PCI
+	select CHECK_SIGNATURE if X86 && DMI
+	help
+	  If you say yes to this option, support will be included for the Intel
+	  801 family of mainboard I2C interfaces.  Specifically, the following
+	  versions of the chipset are supported:
+	    82801AA
+	    82801AB
+	    82801BA
+	    82801CA/CAM
+	    82801DB
+	    82801EB/ER (ICH5/ICH5R)
+	    6300ESB
+	    ICH6
+	    ICH7
+	    ESB2
+	    ICH8
+	    ICH9
+	    EP80579 (Tolapai)
+	    ICH10
+	    5/3400 Series (PCH)
+	    6 Series (PCH)
+	    Patsburg (PCH)
+	    DH89xxCC (PCH)
+	    Panther Point (PCH)
+	    Lynx Point (PCH)
+	    Lynx Point-LP (PCH)
+	    Avoton (SOC)
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called i2c-i801.
+
+config I2C_ISCH
+	tristate "Intel SCH SMBus 1.0"
+	depends on PCI
+	select LPC_SCH
+	help
+	  Say Y here if you want to use SMBus controller on the Intel SCH
+	  based systems.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called i2c-isch.
+
+config I2C_PIIX4
+	tristate "Intel PIIX4 and compatible (ATI/AMD/Serverworks/Broadcom/SMSC)"
+	depends on PCI
+	help
+	  If you say yes to this option, support will be included for the Intel
+	  PIIX4 family of mainboard I2C interfaces.  Specifically, the following
+	  versions of the chipset are supported (note that Serverworks is part
+	  of Broadcom):
+	    Intel PIIX4
+	    Intel 440MX
+	    ATI IXP200
+	    ATI IXP300
+	    ATI IXP400
+	    ATI SB600
+	    ATI SB700
+	    ATI SB800
+	    AMD Hudson-2
+	    AMD CZ
+	    Serverworks OSB4
+	    Serverworks CSB5
+	    Serverworks CSB6
+	    Serverworks HT-1000
+	    Serverworks HT-1100
+	    SMSC Victory66
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called i2c-piix4.
+
+config I2C_NFORCE2
+	tristate "Nvidia nForce2, nForce3 and nForce4"
+	depends on PCI
+	help
+	  If you say yes to this option, support will be included for the Nvidia
+	  nForce2, nForce3 and nForce4 families of mainboard I2C interfaces.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called i2c-nforce2.
+
+config I2C_NFORCE2_S4985
+	tristate "SMBus multiplexing on the Tyan S4985"
+	depends on I2C_NFORCE2 && X86 && EXPERIMENTAL
+	help
+	  Enabling this option will add specific SMBus support for the Tyan
+	  S4985 motherboard.  On this 4-CPU board, the SMBus is multiplexed
+	  over 4 different channels, where the various memory module EEPROMs
+	  live.  Saying yes here will give you access to these in addition
+	  to the trunk.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called i2c-nforce2-s4985.
+
+config I2C_SIS5595
+	tristate "SiS 5595"
+	depends on PCI
+	help
+	  If you say yes to this option, support will be included for the
+	  SiS5595 SMBus (a subset of I2C) interface.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called i2c-sis5595.
+
+config I2C_SIS630
+	tristate "SiS 630/730"
+	depends on PCI
+	help
+	  If you say yes to this option, support will be included for the
+	  SiS630 and SiS730 SMBus (a subset of I2C) interface.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called i2c-sis630.
+
+config I2C_SIS96X
+	tristate "SiS 96x"
+	depends on PCI
+	help
+	  If you say yes to this option, support will be included for the SiS
+	  96x SMBus (a subset of I2C) interfaces.  Specifically, the following
+	  chipsets are supported:
+	    645/961
+	    645DX/961
+	    645DX/962
+	    648/961
+	    650/961
+	    735
+	    745
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called i2c-sis96x.
+
+config I2C_VIA
+	tristate "VIA VT82C586B"
+	depends on PCI && EXPERIMENTAL
+	select I2C_ALGOBIT
+	help
+	  If you say yes to this option, support will be included for the VIA
+          82C586B I2C interface
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called i2c-via.
+
+config I2C_VIAPRO
+	tristate "VIA VT82C596/82C686/82xx and CX700/VX8xx"
+	depends on PCI
+	help
+	  If you say yes to this option, support will be included for the VIA
+	  VT82C596 and later SMBus interface.  Specifically, the following
+	  chipsets are supported:
+	    VT82C596A/B
+	    VT82C686A/B
+	    VT8231
+	    VT8233/A
+	    VT8235
+	    VT8237R/A/S
+	    VT8251
+	    CX700
+	    VX800/VX820
+	    VX855/VX875
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called i2c-viapro.
+
+if ACPI
+
+comment "ACPI drivers"
+
+config I2C_SCMI
+	tristate "SMBus Control Method Interface"
+	help
+	  This driver supports the SMBus Control Method Interface. It needs the
+	  BIOS to declare ACPI control methods as described in the SMBus Control
+	  Method Interface specification.
+
+	  To compile this driver as a module, choose M here:
+	  the module will be called i2c-scmi.
+
+endif # ACPI
+
+comment "Mac SMBus host controller drivers"
+	depends on PPC_CHRP || PPC_PMAC
+
+config I2C_HYDRA
+	tristate "CHRP Apple Hydra Mac I/O I2C interface"
+	depends on PCI && PPC_CHRP && EXPERIMENTAL
+	select I2C_ALGOBIT
+	help
+	  This supports the use of the I2C interface in the Apple Hydra Mac
+	  I/O chip on some CHRP machines (e.g. the LongTrail).  Say Y if you
+	  have such a machine.
+
+	  This support is also available as a module.  If so, the module
+	  will be called i2c-hydra.
+
+config I2C_POWERMAC
+	tristate "Powermac I2C interface"
+	depends on PPC_PMAC
+	default y
+	help
+	  This exposes the various PowerMac i2c interfaces to the linux i2c
+	  layer and to userland. It is used by various drivers on the PowerMac
+	  platform, and should generally be enabled.
+
+	  This support is also available as a module.  If so, the module
+	  will be called i2c-powermac.
+
+comment "I2C system bus drivers (mostly embedded / system-on-chip)"
+
+config I2C_AT91
+	tristate "Atmel AT91 I2C Two-Wire interface (TWI)"
+	depends on ARCH_AT91 && EXPERIMENTAL && BROKEN
+	help
+	  This supports the use of the I2C interface on Atmel AT91
+	  processors.
+
+	  This driver is BROKEN because the controller which it uses
+	  will easily trigger RX overrun and TX underrun errors.  Using
+	  low I2C clock rates may partially work around those issues
+	  on some systems.  Another serious problem is that there is no
+	  documented way to issue repeated START conditions, as needed
+	  to support combined I2C messages.  Use the i2c-gpio driver
+	  unless your system can cope with those limitations.
+
+config I2C_AU1550
+	tristate "Au1550/Au1200/Au1300 SMBus interface"
+	depends on MIPS_ALCHEMY
+	help
+	  If you say yes to this option, support will be included for the
+	  Au1550/Au1200/Au1300 SMBus interface.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called i2c-au1550.
+
+config I2C_BLACKFIN_TWI
+	tristate "Blackfin TWI I2C support"
+	depends on BLACKFIN
+	depends on !BF561 && !BF531 && !BF532 && !BF533
+	help
+	  This is the I2C bus driver for Blackfin on-chip TWI interface.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called i2c-bfin-twi.
+
+config I2C_BLACKFIN_TWI_CLK_KHZ
+	int "Blackfin TWI I2C clock (kHz)"
+	depends on I2C_BLACKFIN_TWI
+	range 21 400
+	default 50
+	help
+	  The unit of the TWI clock is kHz.
+
+config I2C_CPM
+	tristate "Freescale CPM1 or CPM2 (MPC8xx/826x)"
+	depends on (CPM1 || CPM2) && OF_I2C
+	help
+	  This supports the use of the I2C interface on Freescale
+	  processors with CPM1 or CPM2.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called i2c-cpm.
+
+config I2C_DAVINCI
+	tristate "DaVinci I2C driver"
+	depends on ARCH_DAVINCI
+	help
+	  Support for TI DaVinci I2C controller driver.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called i2c-davinci.
+
+	  Please note that this driver might be needed to bring up other
+	  devices such as DaVinci NIC.
+	  For details please see http://www.ti.com/davinci
+
+config I2C_DESIGNWARE_CORE
+	tristate
+
+config I2C_DESIGNWARE_PLATFORM
+	tristate "Synopsys DesignWare Platfrom"
+	depends on HAVE_CLK
+	select I2C_DESIGNWARE_CORE
+	help
+	  If you say yes to this option, support will be included for the
+	  Synopsys DesignWare I2C adapter. Only master mode is supported.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called i2c-designware-platform.
+
+config I2C_DESIGNWARE_PCI
+	tristate "Synopsys DesignWare PCI"
+	depends on PCI
+	select I2C_DESIGNWARE_CORE
+	help
+	  If you say yes to this option, support will be included for the
+	  Synopsys DesignWare I2C adapter. Only master mode is supported.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called i2c-designware-pci.
+
+config I2C_EG20T
+	tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) I2C"
+	depends on PCI
+	help
+	  This driver is for PCH(Platform controller Hub) I2C of EG20T which
+	  is an IOH(Input/Output Hub) for x86 embedded processor.
+	  This driver can access PCH I2C bus device.
+
+	  This driver also can be used for LAPIS Semiconductor IOH(Input/
+	  Output Hub), ML7213, ML7223 and ML7831.
+	  ML7213 IOH is for IVI(In-Vehicle Infotainment) use, ML7223 IOH is
+	  for MP(Media Phone) use and ML7831 IOH is for general purpose use.
+	  ML7213/ML7223/ML7831 is companion chip for Intel Atom E6xx series.
+	  ML7213/ML7223/ML7831 is completely compatible for Intel EG20T PCH.
+
+config I2C_GPIO
+	tristate "GPIO-based bitbanging I2C"
+	depends on GENERIC_GPIO
+	select I2C_ALGOBIT
+	help
+	  This is a very simple bitbanging I2C driver utilizing the
+	  arch-neutral GPIO API to control the SCL and SDA lines.
+
+config I2C_HIGHLANDER
+	tristate "Highlander FPGA SMBus interface"
+	depends on SH_HIGHLANDER
+	help
+	  If you say yes to this option, support will be included for
+	  the SMBus interface located in the FPGA on various Highlander
+	  boards, particularly the R0P7780LC0011RL and R0P7785LC0011RL
+	  FPGAs. This is wholly unrelated to the SoC I2C.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called i2c-highlander.
+
+config I2C_IBM_IIC
+	tristate "IBM PPC 4xx on-chip I2C interface"
+	depends on 4xx
+	help
+	  Say Y here if you want to use IIC peripheral found on
+	  embedded IBM PPC 4xx based systems.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called i2c-ibm_iic.
+
+config I2C_IMX
+	tristate "IMX I2C interface"
+	depends on ARCH_MXC
+	help
+	  Say Y here if you want to use the IIC bus controller on
+	  the Freescale i.MX/MXC processors.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called i2c-imx.
+
+config I2C_INTEL_MID
+	tristate "Intel Moorestown/Medfield Platform I2C controller"
+	depends on PCI
+	help
+	  Say Y here if you have an Intel Moorestown/Medfield platform I2C
+	  controller.
+
+	  This support is also available as a module. If so, the module
+	  will be called i2c-intel-mid.
+
+config I2C_IOP3XX
+	tristate "Intel IOPx3xx and IXP4xx on-chip I2C interface"
+	depends on ARCH_IOP32X || ARCH_IOP33X || ARCH_IXP4XX || ARCH_IOP13XX
+	help
+	  Say Y here if you want to use the IIC bus controller on
+	  the Intel IOPx3xx I/O Processors or IXP4xx Network Processors.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called i2c-iop3xx.
+
+config I2C_IXP2000
+	tristate "IXP2000 GPIO-Based I2C Interface (DEPRECATED)"
+	depends on ARCH_IXP2000
+	select I2C_ALGOBIT
+	help
+	  Say Y here if you have an Intel IXP2000 (2400, 2800, 2850) based
+	  system and are using GPIO lines for an I2C bus.
+
+	  This support is also available as a module. If so, the module
+	  will be called i2c-ixp2000.
+
+	  This driver is deprecated and will be dropped soon. Use i2c-gpio
+	  instead.
+
+config I2C_MPC
+	tristate "MPC107/824x/85xx/512x/52xx/83xx/86xx"
+	depends on PPC
+	help
+	  If you say yes to this option, support will be included for the
+	  built-in I2C interface on the MPC107, Tsi107, MPC512x, MPC52xx,
+	  MPC8240, MPC8245, MPC83xx, MPC85xx and MPC8641 family processors.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called i2c-mpc.
+
+config I2C_MV64XXX
+	tristate "Marvell mv64xxx I2C Controller"
+	depends on (MV64X60 || PLAT_ORION) && EXPERIMENTAL
+	help
+	  If you say yes to this option, support will be included for the
+	  built-in I2C interface on the Marvell 64xxx line of host bridges.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called i2c-mv64xxx.
+
+config I2C_MXS
+	tristate "Freescale i.MX28 I2C interface"
+	depends on SOC_IMX28
+	help
+	  Say Y here if you want to use the I2C bus controller on
+	  the Freescale i.MX28 processors.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called i2c-mxs.
+
+config I2C_NOMADIK
+	tristate "ST-Ericsson Nomadik/Ux500 I2C Controller"
+	depends on PLAT_NOMADIK
+	help
+	  If you say yes to this option, support will be included for the
+	  I2C interface from ST-Ericsson's Nomadik and Ux500 architectures.
+
+config I2C_NUC900
+	tristate "NUC900 I2C Driver"
+	depends on ARCH_W90X900
+	help
+	  Say Y here to include support for I2C controller in the
+	  Winbond/Nuvoton NUC900 based System-on-Chip devices.
+
+config I2C_OCORES
+	tristate "OpenCores I2C Controller"
+	depends on EXPERIMENTAL
+	help
+	  If you say yes to this option, support will be included for the
+	  OpenCores I2C controller. For details see
+	  http://www.opencores.org/projects.cgi/web/i2c/overview
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called i2c-ocores.
+
+config I2C_OMAP
+	tristate "OMAP I2C adapter"
+	depends on ARCH_OMAP
+	default y if MACH_OMAP_H3 || MACH_OMAP_OSK
+	help
+	  If you say yes to this option, support will be included for the
+	  I2C interface on the Texas Instruments OMAP1/2 family of processors.
+	  Like OMAP1510/1610/1710/5912 and OMAP242x.
+	  For details see http://www.ti.com/omap.
+
+config I2C_PASEMI
+	tristate "PA Semi SMBus interface"
+	depends on PPC_PASEMI && PCI
+	help
+	  Supports the PA Semi PWRficient on-chip SMBus interfaces.
+
+config I2C_PCA_PLATFORM
+	tristate "PCA9564/PCA9665 as platform device"
+	select I2C_ALGOPCA
+	default n
+	help
+	  This driver supports a memory mapped Philips PCA9564/PCA9665
+	  parallel bus to I2C bus controller.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called i2c-pca-platform.
+
+config I2C_PMCMSP
+	tristate "PMC MSP I2C TWI Controller"
+	depends on PMC_MSP
+	help
+	  This driver supports the PMC TWI controller on MSP devices.
+
+	  This driver can also be built as module. If so, the module
+	  will be called i2c-pmcmsp.
+
+config I2C_PNX
+	tristate "I2C bus support for Philips PNX and NXP LPC targets"
+	depends on ARCH_PNX4008 || ARCH_LPC32XX
+	help
+	  This driver supports the Philips IP3204 I2C IP block master and/or
+	  slave controller
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called i2c-pnx.
+
+config I2C_PUV3
+	tristate "PKUnity v3 I2C bus support"
+	depends on UNICORE32 && ARCH_PUV3
+	select I2C_ALGOBIT
+	help
+	  This driver supports the I2C IP inside the PKUnity-v3 SoC.
+	  This I2C bus controller is under AMBA/AXI bus.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called i2c-puv3.
+
+config I2C_PXA
+	tristate "Intel PXA2XX I2C adapter"
+	depends on ARCH_PXA || ARCH_MMP || (X86_32 && PCI && OF)
+	help
+	  If you have devices in the PXA I2C bus, say yes to this option.
+	  This driver can also be built as a module.  If so, the module
+	  will be called i2c-pxa.
+
+config I2C_PXA_PCI
+	def_bool I2C_PXA && X86_32 && PCI && OF
+
+config I2C_PXA_SLAVE
+	bool "Intel PXA2XX I2C Slave comms support"
+	depends on I2C_PXA && !X86_32
+	help
+	  Support I2C slave mode communications on the PXA I2C bus.  This
+	  is necessary for systems where the PXA may be a target on the
+	  I2C bus.
+
+config HAVE_S3C2410_I2C
+	bool
+	help
+	  This will include I2C support for Samsung SoCs. If you want to
+	  include I2C support for any machine, kindly select this in the
+	  respective Kconfig file.
+
+config I2C_S3C2410
+	tristate "S3C2410 I2C Driver"
+	depends on HAVE_S3C2410_I2C
+	help
+	  Say Y here to include support for I2C controller in the
+	  Samsung SoCs.
+
+config I2C_S6000
+	tristate "S6000 I2C support"
+	depends on XTENSA_VARIANT_S6000
+	help
+	  This driver supports the on chip I2C device on the
+	  S6000 xtensa processor family.
+
+	  To compile this driver as a module, choose M here. The module
+	  will be called i2c-s6000.
+
+config I2C_SH7760
+	tristate "Renesas SH7760 I2C Controller"
+	depends on CPU_SUBTYPE_SH7760
+	help
+	  This driver supports the 2 I2C interfaces on the Renesas SH7760.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called i2c-sh7760.
+
+config I2C_SH_MOBILE
+	tristate "SuperH Mobile I2C Controller"
+	depends on SUPERH || ARCH_SHMOBILE
+	help
+	  If you say yes to this option, support will be included for the
+	  built-in I2C interface on the Renesas SH-Mobile processor.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called i2c-sh_mobile.
+
+config I2C_SIMTEC
+	tristate "Simtec Generic I2C interface"
+	select I2C_ALGOBIT
+	help
+	  If you say yes to this option, support will be included for
+	  the Simtec Generic I2C interface. This driver is for the
+	  simple I2C bus used on newer Simtec products for general
+	  I2C, such as DDC on the Simtec BBD2016A.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called i2c-simtec.
+
+config I2C_SIRF
+	tristate "CSR SiRFprimaII I2C interface"
+	depends on ARCH_PRIMA2
+	help
+	  If you say yes to this option, support will be included for the
+	  CSR SiRFprimaII I2C interface.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called i2c-sirf.
+
+config I2C_STU300
+	tristate "ST Microelectronics DDC I2C interface"
+	depends on MACH_U300
+	default y if MACH_U300
+	help
+	  If you say yes to this option, support will be included for the
+	  I2C interface from ST Microelectronics simply called "DDC I2C"
+	  supporting both I2C and DDC, used in e.g. the U300 series
+	  mobile platforms.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called i2c-stu300.
+
+config I2C_TEGRA
+	tristate "NVIDIA Tegra internal I2C controller"
+	depends on ARCH_TEGRA
+	help
+	  If you say yes to this option, support will be included for the
+	  I2C controller embedded in NVIDIA Tegra SOCs
+
+config I2C_VERSATILE
+	tristate "ARM Versatile/Realview I2C bus support"
+	depends on ARCH_VERSATILE || ARCH_REALVIEW || ARCH_VEXPRESS
+	select I2C_ALGOBIT
+	help
+	  Say yes if you want to support the I2C serial bus on ARMs Versatile
+	  range of platforms.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called i2c-versatile.
+
+config I2C_OCTEON
+	tristate "Cavium OCTEON I2C bus support"
+	depends on CPU_CAVIUM_OCTEON
+	help
+	  Say yes if you want to support the I2C serial bus on Cavium
+	  OCTEON SOC.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called i2c-octeon.
+
+config I2C_XILINX
+	tristate "Xilinx I2C Controller"
+	depends on EXPERIMENTAL && HAS_IOMEM
+	help
+	  If you say yes to this option, support will be included for the
+	  Xilinx I2C controller.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called xilinx_i2c.
+
+config I2C_XLR
+	tristate "XLR I2C support"
+	depends on CPU_XLR
+	help
+	  This driver enables support for the on-chip I2C interface of
+	  the Netlogic XLR/XLS MIPS processors.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called i2c-xlr.
+	  
+config I2C_ZX29
+	tristate "ZX29 serials I2C controller driver"
+	help
+	  Say Y here to include support for I2C controller on the
+	  ZTE-TSP zx29 serials socs.
+
+comment "External I2C/SMBus adapter drivers"
+
+config I2C_DIOLAN_U2C
+	tristate "Diolan U2C-12 USB adapter"
+	depends on USB
+	help
+	  If you say yes to this option, support will be included for Diolan
+	  U2C-12, a USB to I2C interface.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called i2c-diolan-u2c.
+
+config I2C_PARPORT
+	tristate "Parallel port adapter"
+	depends on PARPORT
+	select I2C_ALGOBIT
+	select I2C_SMBUS
+	help
+	  This supports parallel port I2C adapters such as the ones made by
+	  Philips or Velleman, Analog Devices evaluation boards, and more.
+	  Basically any adapter using the parallel port as an I2C bus with
+	  no extra chipset is supported by this driver, or could be.
+
+	  This driver is a replacement for (and was inspired by) an older
+	  driver named i2c-philips-par.  The new driver supports more devices,
+	  and makes it easier to add support for new devices.
+
+	  An adapter type parameter is now mandatory.  Please read the file
+	  Documentation/i2c/busses/i2c-parport for details.
+
+	  Another driver exists, named i2c-parport-light, which doesn't depend
+	  on the parport driver.  This is meant for embedded systems. Don't say
+	  Y here if you intend to say Y or M there.
+
+	  This support is also available as a module.  If so, the module
+	  will be called i2c-parport.
+
+config I2C_PARPORT_LIGHT
+	tristate "Parallel port adapter (light)"
+	select I2C_ALGOBIT
+	select I2C_SMBUS
+	help
+	  This supports parallel port I2C adapters such as the ones made by
+	  Philips or Velleman, Analog Devices evaluation boards, and more.
+	  Basically any adapter using the parallel port as an I2C bus with
+	  no extra chipset is supported by this driver, or could be.
+
+	  This driver is a light version of i2c-parport.  It doesn't depend
+	  on the parport driver, and uses direct I/O access instead.  This
+	  might be preferred on embedded systems where wasting memory for
+	  the clean but heavy parport handling is not an option.  The
+	  drawback is a reduced portability and the impossibility to
+	  daisy-chain other parallel port devices.
+
+	  Don't say Y here if you said Y or M to i2c-parport.  Saying M to
+	  both is possible but both modules should not be loaded at the same
+	  time.
+
+	  This support is also available as a module.  If so, the module
+	  will be called i2c-parport-light.
+
+config I2C_TAOS_EVM
+	tristate "TAOS evaluation module"
+	depends on EXPERIMENTAL
+	select SERIO
+	select SERIO_SERPORT
+	default n
+	help
+	  This supports TAOS evaluation modules on serial port. In order to
+	  use this driver, you will need the inputattach tool, which is part
+	  of the input-utils package.
+
+	  If unsure, say N.
+
+	  This support is also available as a module.  If so, the module
+	  will be called i2c-taos-evm.
+
+config I2C_TINY_USB
+	tristate "Tiny-USB adapter"
+	depends on USB
+	help
+	  If you say yes to this option, support will be included for the
+	  i2c-tiny-usb, a simple do-it-yourself USB to I2C interface. See
+	  http://www.harbaum.org/till/i2c_tiny_usb for hardware details.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called i2c-tiny-usb.
+
+comment "Other I2C/SMBus bus drivers"
+
+config I2C_ACORN
+	tristate "Acorn IOC/IOMD I2C bus support"
+	depends on ARCH_ACORN
+	default y
+	select I2C_ALGOBIT
+	help
+	  Say yes if you want to support the I2C bus on Acorn platforms.
+
+	  If you don't know, say Y.
+
+config I2C_ELEKTOR
+	tristate "Elektor ISA card"
+	depends on ISA && HAS_IOPORT && BROKEN_ON_SMP
+	select I2C_ALGOPCF
+	help
+	  This supports the PCF8584 ISA bus I2C adapter.  Say Y if you own
+	  such an adapter.
+
+	  This support is also available as a module.  If so, the module
+	  will be called i2c-elektor.
+
+config I2C_PCA_ISA
+	tristate "PCA9564/PCA9665 on an ISA bus"
+	depends on ISA
+	select I2C_ALGOPCA
+	default n
+	help
+	  This driver supports ISA boards using the Philips PCA9564/PCA9665
+	  parallel bus to I2C bus controller.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called i2c-pca-isa.
+
+	  This device is almost undetectable and using this driver on a
+	  system which doesn't have this device will result in long
+	  delays when I2C/SMBus chip drivers are loaded (e.g. at boot
+	  time).  If unsure, say N.
+
+config I2C_SIBYTE
+	tristate "SiByte SMBus interface"
+	depends on SIBYTE_SB1xxx_SOC
+	help
+	  Supports the SiByte SOC on-chip I2C interfaces (2 channels).
+
+config I2C_STUB
+	tristate "I2C/SMBus Test Stub"
+	depends on EXPERIMENTAL && m
+	default 'n'
+	help
+	  This module may be useful to developers of SMBus client drivers,
+	  especially for certain kinds of sensor chips.
+
+	  If you do build this module, be sure to read the notes and warnings
+	  in <file:Documentation/i2c/i2c-stub>.
+
+	  If you don't know what to do here, definitely say N.
+
+config SCx200_I2C
+	tristate "NatSemi SCx200 I2C using GPIO pins (DEPRECATED)"
+	depends on SCx200_GPIO
+	select I2C_ALGOBIT
+	help
+	  Enable the use of two GPIO pins of a SCx200 processor as an I2C bus.
+
+	  If you don't know what to do here, say N.
+
+	  This support is also available as a module.  If so, the module
+	  will be called scx200_i2c.
+
+	  This driver is deprecated and will be dropped soon. Use i2c-gpio
+	  (or scx200_acb) instead.
+
+config SCx200_I2C_SCL
+	int "GPIO pin used for SCL"
+	depends on SCx200_I2C
+	default "12"
+	help
+	  Enter the GPIO pin number used for the SCL signal.  This value can
+	  also be specified with a module parameter.
+
+config SCx200_I2C_SDA
+	int "GPIO pin used for SDA"
+	depends on SCx200_I2C
+	default "13"
+	help
+	  Enter the GPIO pin number used for the SSA signal.  This value can
+	  also be specified with a module parameter.
+
+config SCx200_ACB
+	tristate "Geode ACCESS.bus support"
+	depends on X86_32 && PCI
+	help
+	  Enable the use of the ACCESS.bus controllers on the Geode SCx200 and
+	  SC1100 processors and the CS5535 and CS5536 Geode companion devices.
+
+	  If you don't know what to do here, say N.
+
+	  This support is also available as a module.  If so, the module
+	  will be called scx200_acb.
+
+endmenu
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/busses/Makefile b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/Makefile
new file mode 100644
index 0000000..d3691bc
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/Makefile
@@ -0,0 +1,93 @@
+#
+# Makefile for the i2c bus drivers.
+#
+
+# ACPI drivers
+obj-$(CONFIG_I2C_SCMI)		+= i2c-scmi.o
+
+# PC SMBus host controller drivers
+obj-$(CONFIG_I2C_ALI1535)	+= i2c-ali1535.o
+obj-$(CONFIG_I2C_ALI1563)	+= i2c-ali1563.o
+obj-$(CONFIG_I2C_ALI15X3)	+= i2c-ali15x3.o
+obj-$(CONFIG_I2C_AMD756)	+= i2c-amd756.o
+obj-$(CONFIG_I2C_AMD756_S4882)	+= i2c-amd756-s4882.o
+obj-$(CONFIG_I2C_AMD8111)	+= i2c-amd8111.o
+obj-$(CONFIG_I2C_I801)		+= i2c-i801.o
+obj-$(CONFIG_I2C_ISCH)		+= i2c-isch.o
+obj-$(CONFIG_I2C_NFORCE2)	+= i2c-nforce2.o
+obj-$(CONFIG_I2C_NFORCE2_S4985)	+= i2c-nforce2-s4985.o
+obj-$(CONFIG_I2C_PIIX4)		+= i2c-piix4.o
+obj-$(CONFIG_I2C_SIS5595)	+= i2c-sis5595.o
+obj-$(CONFIG_I2C_SIS630)	+= i2c-sis630.o
+obj-$(CONFIG_I2C_SIS96X)	+= i2c-sis96x.o
+obj-$(CONFIG_I2C_VIA)		+= i2c-via.o
+obj-$(CONFIG_I2C_VIAPRO)	+= i2c-viapro.o
+
+# Mac SMBus host controller drivers
+obj-$(CONFIG_I2C_HYDRA)		+= i2c-hydra.o
+obj-$(CONFIG_I2C_POWERMAC)	+= i2c-powermac.o
+
+# Embedded system I2C/SMBus host controller drivers
+obj-$(CONFIG_I2C_AT91)		+= i2c-at91.o
+obj-$(CONFIG_I2C_AU1550)	+= i2c-au1550.o
+obj-$(CONFIG_I2C_BLACKFIN_TWI)	+= i2c-bfin-twi.o
+obj-$(CONFIG_I2C_CPM)		+= i2c-cpm.o
+obj-$(CONFIG_I2C_DAVINCI)	+= i2c-davinci.o
+obj-$(CONFIG_I2C_DESIGNWARE_CORE)	+= i2c-designware-core.o
+obj-$(CONFIG_I2C_DESIGNWARE_PLATFORM)	+= i2c-designware-platform.o
+i2c-designware-platform-objs := i2c-designware-platdrv.o
+obj-$(CONFIG_I2C_DESIGNWARE_PCI)	+= i2c-designware-pci.o
+i2c-designware-pci-objs := i2c-designware-pcidrv.o
+obj-$(CONFIG_I2C_EG20T)		+= i2c-eg20t.o
+obj-$(CONFIG_I2C_GPIO)		+= i2c-gpio.o
+obj-$(CONFIG_I2C_HIGHLANDER)	+= i2c-highlander.o
+obj-$(CONFIG_I2C_IBM_IIC)	+= i2c-ibm_iic.o
+obj-$(CONFIG_I2C_IMX)		+= i2c-imx.o
+obj-$(CONFIG_I2C_INTEL_MID)	+= i2c-intel-mid.o
+obj-$(CONFIG_I2C_IOP3XX)	+= i2c-iop3xx.o
+obj-$(CONFIG_I2C_IXP2000)	+= i2c-ixp2000.o
+obj-$(CONFIG_I2C_MPC)		+= i2c-mpc.o
+obj-$(CONFIG_I2C_MV64XXX)	+= i2c-mv64xxx.o
+obj-$(CONFIG_I2C_MXS)		+= i2c-mxs.o
+obj-$(CONFIG_I2C_NOMADIK)	+= i2c-nomadik.o
+obj-$(CONFIG_I2C_NUC900)	+= i2c-nuc900.o
+obj-$(CONFIG_I2C_OCORES)	+= i2c-ocores.o
+obj-$(CONFIG_I2C_OMAP)		+= i2c-omap.o
+obj-$(CONFIG_I2C_PASEMI)	+= i2c-pasemi.o
+obj-$(CONFIG_I2C_PCA_PLATFORM)	+= i2c-pca-platform.o
+obj-$(CONFIG_I2C_PMCMSP)	+= i2c-pmcmsp.o
+obj-$(CONFIG_I2C_PNX)		+= i2c-pnx.o
+obj-$(CONFIG_I2C_PUV3)		+= i2c-puv3.o
+obj-$(CONFIG_I2C_PXA)		+= i2c-pxa.o
+obj-$(CONFIG_I2C_PXA_PCI)	+= i2c-pxa-pci.o
+obj-$(CONFIG_I2C_S3C2410)	+= i2c-s3c2410.o
+obj-$(CONFIG_I2C_S6000)		+= i2c-s6000.o
+obj-$(CONFIG_I2C_SH7760)	+= i2c-sh7760.o
+obj-$(CONFIG_I2C_SH_MOBILE)	+= i2c-sh_mobile.o
+obj-$(CONFIG_I2C_SIMTEC)	+= i2c-simtec.o
+obj-$(CONFIG_I2C_SIRF)		+= i2c-sirf.o
+obj-$(CONFIG_I2C_STU300)	+= i2c-stu300.o
+obj-$(CONFIG_I2C_TEGRA)		+= i2c-tegra.o
+obj-$(CONFIG_I2C_VERSATILE)	+= i2c-versatile.o
+obj-$(CONFIG_I2C_OCTEON)	+= i2c-octeon.o
+obj-$(CONFIG_I2C_XILINX)	+= i2c-xiic.o
+obj-$(CONFIG_I2C_XLR)		+= i2c-xlr.o
+obj-$(CONFIG_I2C_ZX29)      += i2c-zx29.o i2c-zx29-noirq.o
+
+# External I2C/SMBus adapter drivers
+obj-$(CONFIG_I2C_DIOLAN_U2C)	+= i2c-diolan-u2c.o
+obj-$(CONFIG_I2C_PARPORT)	+= i2c-parport.o
+obj-$(CONFIG_I2C_PARPORT_LIGHT)	+= i2c-parport-light.o
+obj-$(CONFIG_I2C_TAOS_EVM)	+= i2c-taos-evm.o
+obj-$(CONFIG_I2C_TINY_USB)	+= i2c-tiny-usb.o
+
+# Other I2C/SMBus bus drivers
+obj-$(CONFIG_I2C_ACORN)		+= i2c-acorn.o
+obj-$(CONFIG_I2C_ELEKTOR)	+= i2c-elektor.o
+obj-$(CONFIG_I2C_PCA_ISA)	+= i2c-pca-isa.o
+obj-$(CONFIG_I2C_SIBYTE)	+= i2c-sibyte.o
+obj-$(CONFIG_I2C_STUB)		+= i2c-stub.o
+obj-$(CONFIG_SCx200_ACB)	+= scx200_acb.o
+obj-$(CONFIG_SCx200_I2C)	+= scx200_i2c.o
+
+ccflags-$(CONFIG_I2C_DEBUG_BUS) := -DDEBUG
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-acorn.c b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-acorn.c
new file mode 100644
index 0000000..ed9f48d
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-acorn.c
@@ -0,0 +1,96 @@
+/*
+ *  linux/drivers/acorn/char/i2c.c
+ *
+ *  Copyright (C) 2000 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ *  ARM IOC/IOMD i2c driver.
+ *
+ *  On Acorn machines, the following i2c devices are on the bus:
+ *	- PCF8583 real time clock & static RAM
+ */
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <linux/io.h>
+
+#include <mach/hardware.h>
+#include <asm/hardware/ioc.h>
+
+#define FORCE_ONES	0xdc
+#define SCL		0x02
+#define SDA		0x01
+
+/*
+ * We must preserve all non-i2c output bits in IOC_CONTROL.
+ * Note also that we need to preserve the value of SCL and
+ * SDA outputs as well (which may be different from the
+ * values read back from IOC_CONTROL).
+ */
+static u_int force_ones;
+
+static void ioc_setscl(void *data, int state)
+{
+	u_int ioc_control = ioc_readb(IOC_CONTROL) & ~(SCL | SDA);
+	u_int ones = force_ones;
+
+	if (state)
+		ones |= SCL;
+	else
+		ones &= ~SCL;
+
+	force_ones = ones;
+
+ 	ioc_writeb(ioc_control | ones, IOC_CONTROL);
+}
+
+static void ioc_setsda(void *data, int state)
+{
+	u_int ioc_control = ioc_readb(IOC_CONTROL) & ~(SCL | SDA);
+	u_int ones = force_ones;
+
+	if (state)
+		ones |= SDA;
+	else
+		ones &= ~SDA;
+
+	force_ones = ones;
+
+ 	ioc_writeb(ioc_control | ones, IOC_CONTROL);
+}
+
+static int ioc_getscl(void *data)
+{
+	return (ioc_readb(IOC_CONTROL) & SCL) != 0;
+}
+
+static int ioc_getsda(void *data)
+{
+	return (ioc_readb(IOC_CONTROL) & SDA) != 0;
+}
+
+static struct i2c_algo_bit_data ioc_data = {
+	.setsda		= ioc_setsda,
+	.setscl		= ioc_setscl,
+	.getsda		= ioc_getsda,
+	.getscl		= ioc_getscl,
+	.udelay		= 80,
+	.timeout	= HZ,
+};
+
+static struct i2c_adapter ioc_ops = {
+	.nr			= 0,
+	.algo_data		= &ioc_data,
+};
+
+static int __init i2c_ioc_init(void)
+{
+	force_ones = FORCE_ONES | SCL | SDA;
+
+	return i2c_bit_add_numbered_bus(&ioc_ops);
+}
+
+module_init(i2c_ioc_init);
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-ali1535.c b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-ali1535.c
new file mode 100644
index 0000000..e66d248
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-ali1535.c
@@ -0,0 +1,552 @@
+/*
+ * Copyright (c) 2000  Frodo Looijaard <frodol@dds.nl>,
+ *                      Philip Edelbrock <phil@netroedge.com>,
+ *                      Mark D. Studebaker <mdsxyz123@yahoo.com>,
+ *                      Dan Eaton <dan.eaton@rocketlogix.com> and
+ *                      Stephen Rousset <stephen.rousset@rocketlogix.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/*
+    This is the driver for the SMB Host controller on
+    Acer Labs Inc. (ALI) M1535 South Bridge.
+
+    The M1535 is a South bridge for portable systems.
+    It is very similar to the M15x3 South bridges also produced
+    by Acer Labs Inc.  Some of the registers within the part
+    have moved and some have been redefined slightly. Additionally,
+    the sequencing of the SMBus transactions has been modified
+    to be more consistent with the sequencing recommended by
+    the manufacturer and observed through testing.  These
+    changes are reflected in this driver and can be identified
+    by comparing this driver to the i2c-ali15x3 driver.
+    For an overview of these chips see http://www.acerlabs.com
+
+    The SMB controller is part of the 7101 device, which is an
+    ACPI-compliant Power Management Unit (PMU).
+
+    The whole 7101 device has to be enabled for the SMB to work.
+    You can't just enable the SMB alone.
+    The SMB and the ACPI have separate I/O spaces.
+    We make sure that the SMB is enabled. We leave the ACPI alone.
+
+    This driver controls the SMB Host only.
+
+    This driver does not use interrupts.
+*/
+
+
+/* Note: we assume there can only be one ALI1535, with one SMBus interface */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/stddef.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/acpi.h>
+#include <linux/io.h>
+
+
+/* ALI1535 SMBus address offsets */
+#define SMBHSTSTS	(0 + ali1535_smba)
+#define SMBHSTTYP	(1 + ali1535_smba)
+#define SMBHSTPORT	(2 + ali1535_smba)
+#define SMBHSTCMD	(7 + ali1535_smba)
+#define SMBHSTADD	(3 + ali1535_smba)
+#define SMBHSTDAT0	(4 + ali1535_smba)
+#define SMBHSTDAT1	(5 + ali1535_smba)
+#define SMBBLKDAT	(6 + ali1535_smba)
+
+/* PCI Address Constants */
+#define SMBCOM		0x004
+#define SMBREV		0x008
+#define SMBCFG		0x0D1
+#define SMBBA		0x0E2
+#define SMBHSTCFG	0x0F0
+#define SMBCLK		0x0F2
+
+/* Other settings */
+#define MAX_TIMEOUT		500	/* times 1/100 sec */
+#define ALI1535_SMB_IOSIZE	32
+
+#define ALI1535_SMB_DEFAULTBASE	0x8040
+
+/* ALI1535 address lock bits */
+#define ALI1535_LOCK		0x06	/* dwe */
+
+/* ALI1535 command constants */
+#define ALI1535_QUICK		0x00
+#define ALI1535_BYTE		0x10
+#define ALI1535_BYTE_DATA	0x20
+#define ALI1535_WORD_DATA	0x30
+#define ALI1535_BLOCK_DATA	0x40
+#define ALI1535_I2C_READ	0x60
+
+#define	ALI1535_DEV10B_EN	0x80	/* Enable 10-bit addressing in	*/
+					/*  I2C read			*/
+#define	ALI1535_T_OUT		0x08	/* Time-out Command (write)	*/
+#define	ALI1535_A_HIGH_BIT9	0x08	/* Bit 9 of 10-bit address in	*/
+					/* Alert-Response-Address	*/
+					/* (read)			*/
+#define	ALI1535_KILL		0x04	/* Kill Command (write)		*/
+#define	ALI1535_A_HIGH_BIT8	0x04	/* Bit 8 of 10-bit address in	*/
+					/*  Alert-Response-Address	*/
+					/*  (read)			*/
+
+#define	ALI1535_D_HI_MASK	0x03	/* Mask for isolating bits 9-8	*/
+					/*  of 10-bit address in I2C	*/
+					/*  Read Command		*/
+
+/* ALI1535 status register bits */
+#define ALI1535_STS_IDLE	0x04
+#define ALI1535_STS_BUSY	0x08	/* host busy */
+#define ALI1535_STS_DONE	0x10	/* transaction complete */
+#define ALI1535_STS_DEV		0x20	/* device error */
+#define ALI1535_STS_BUSERR	0x40	/* bus error    */
+#define ALI1535_STS_FAIL	0x80	/* failed bus transaction */
+#define ALI1535_STS_ERR		0xE0	/* all the bad error bits */
+
+#define ALI1535_BLOCK_CLR	0x04	/* reset block data index */
+
+/* ALI1535 device address register bits */
+#define	ALI1535_RD_ADDR		0x01	/* Read/Write Bit in Device	*/
+					/*  Address field		*/
+					/*  -> Write = 0		*/
+					/*  -> Read  = 1		*/
+#define	ALI1535_SMBIO_EN	0x04	/* SMB I/O Space enable		*/
+
+static struct pci_driver ali1535_driver;
+static unsigned long ali1535_smba;
+static unsigned short ali1535_offset;
+
+/* Detect whether a ALI1535 can be found, and initialize it, where necessary.
+   Note the differences between kernels with the old PCI BIOS interface and
+   newer kernels with the real PCI interface. In compat.h some things are
+   defined to make the transition easier. */
+static int __devinit ali1535_setup(struct pci_dev *dev)
+{
+	int retval;
+	unsigned char temp;
+
+	/* Check the following things:
+		- SMB I/O address is initialized
+		- Device is enabled
+		- We can use the addresses
+	*/
+
+	retval = pci_enable_device(dev);
+	if (retval) {
+		dev_err(&dev->dev, "ALI1535_smb can't enable device\n");
+		goto exit;
+	}
+
+	/* Determine the address of the SMBus area */
+	pci_read_config_word(dev, SMBBA, &ali1535_offset);
+	dev_dbg(&dev->dev, "ALI1535_smb is at offset 0x%04x\n", ali1535_offset);
+	ali1535_offset &= (0xffff & ~(ALI1535_SMB_IOSIZE - 1));
+	if (ali1535_offset == 0) {
+		dev_warn(&dev->dev,
+			"ALI1535_smb region uninitialized - upgrade BIOS?\n");
+		retval = -ENODEV;
+		goto exit;
+	}
+
+	if (pci_resource_flags(dev, 0) & IORESOURCE_IO)
+		ali1535_smba = pci_resource_start(dev, 0) + ali1535_offset;
+	else
+		ali1535_smba = ali1535_offset;
+
+	retval = acpi_check_region(ali1535_smba, ALI1535_SMB_IOSIZE,
+				   ali1535_driver.name);
+	if (retval)
+		goto exit;
+
+	if (!request_region(ali1535_smba, ALI1535_SMB_IOSIZE,
+			    ali1535_driver.name)) {
+		dev_err(&dev->dev, "ALI1535_smb region 0x%lx already in use!\n",
+			ali1535_smba);
+		retval = -EBUSY;
+		goto exit;
+	}
+
+	/* check if whole device is enabled */
+	pci_read_config_byte(dev, SMBCFG, &temp);
+	if ((temp & ALI1535_SMBIO_EN) == 0) {
+		dev_err(&dev->dev, "SMB device not enabled - upgrade BIOS?\n");
+		retval = -ENODEV;
+		goto exit_free;
+	}
+
+	/* Is SMB Host controller enabled? */
+	pci_read_config_byte(dev, SMBHSTCFG, &temp);
+	if ((temp & 1) == 0) {
+		dev_err(&dev->dev, "SMBus controller not enabled - upgrade BIOS?\n");
+		retval = -ENODEV;
+		goto exit_free;
+	}
+
+	/* set SMB clock to 74KHz as recommended in data sheet */
+	pci_write_config_byte(dev, SMBCLK, 0x20);
+
+	/*
+	  The interrupt routing for SMB is set up in register 0x77 in the
+	  1533 ISA Bridge device, NOT in the 7101 device.
+	  Don't bother with finding the 1533 device and reading the register.
+	if ((....... & 0x0F) == 1)
+		dev_dbg(&dev->dev, "ALI1535 using Interrupt 9 for SMBus.\n");
+	*/
+	pci_read_config_byte(dev, SMBREV, &temp);
+	dev_dbg(&dev->dev, "SMBREV = 0x%X\n", temp);
+	dev_dbg(&dev->dev, "ALI1535_smba = 0x%lx\n", ali1535_smba);
+
+	return 0;
+
+exit_free:
+	release_region(ali1535_smba, ALI1535_SMB_IOSIZE);
+exit:
+	return retval;
+}
+
+static int ali1535_transaction(struct i2c_adapter *adap)
+{
+	int temp;
+	int result = 0;
+	int timeout = 0;
+
+	dev_dbg(&adap->dev, "Transaction (pre): STS=%02x, TYP=%02x, "
+		"CMD=%02x, ADD=%02x, DAT0=%02x, DAT1=%02x\n",
+		inb_p(SMBHSTSTS), inb_p(SMBHSTTYP), inb_p(SMBHSTCMD),
+		inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1));
+
+	/* get status */
+	temp = inb_p(SMBHSTSTS);
+
+	/* Make sure the SMBus host is ready to start transmitting */
+	/* Check the busy bit first */
+	if (temp & ALI1535_STS_BUSY) {
+		/* If the host controller is still busy, it may have timed out
+		 * in the previous transaction, resulting in a "SMBus Timeout"
+		 * printk.  I've tried the following to reset a stuck busy bit.
+		 *   1. Reset the controller with an KILL command. (this
+		 *      doesn't seem to clear the controller if an external
+		 *      device is hung)
+		 *   2. Reset the controller and the other SMBus devices with a
+		 *      T_OUT command. (this clears the host busy bit if an
+		 *      external device is hung, but it comes back upon a new
+		 *      access to a device)
+		 *   3. Disable and reenable the controller in SMBHSTCFG. Worst
+		 *      case, nothing seems to work except power reset.
+		 */
+
+		/* Try resetting entire SMB bus, including other devices - This
+		 * may not work either - it clears the BUSY bit but then the
+		 * BUSY bit may come back on when you try and use the chip
+		 * again.  If that's the case you are stuck.
+		 */
+		dev_info(&adap->dev,
+			"Resetting entire SMB Bus to clear busy condition (%02x)\n",
+			temp);
+		outb_p(ALI1535_T_OUT, SMBHSTTYP);
+		temp = inb_p(SMBHSTSTS);
+	}
+
+	/* now check the error bits and the busy bit */
+	if (temp & (ALI1535_STS_ERR | ALI1535_STS_BUSY)) {
+		/* do a clear-on-write */
+		outb_p(0xFF, SMBHSTSTS);
+		temp = inb_p(SMBHSTSTS);
+		if (temp & (ALI1535_STS_ERR | ALI1535_STS_BUSY)) {
+			/* This is probably going to be correctable only by a
+			 * power reset as one of the bits now appears to be
+			 * stuck */
+			/* This may be a bus or device with electrical problems. */
+			dev_err(&adap->dev,
+				"SMBus reset failed! (0x%02x) - controller or "
+				"device on bus is probably hung\n", temp);
+			return -EBUSY;
+		}
+	} else {
+		/* check and clear done bit */
+		if (temp & ALI1535_STS_DONE)
+			outb_p(temp, SMBHSTSTS);
+	}
+
+	/* start the transaction by writing anything to the start register */
+	outb_p(0xFF, SMBHSTPORT);
+
+	/* We will always wait for a fraction of a second! */
+	timeout = 0;
+	do {
+		usleep_range(1000, 2000);
+		temp = inb_p(SMBHSTSTS);
+	} while (((temp & ALI1535_STS_BUSY) && !(temp & ALI1535_STS_IDLE))
+		 && (timeout++ < MAX_TIMEOUT));
+
+	/* If the SMBus is still busy, we give up */
+	if (timeout > MAX_TIMEOUT) {
+		result = -ETIMEDOUT;
+		dev_err(&adap->dev, "SMBus Timeout!\n");
+	}
+
+	if (temp & ALI1535_STS_FAIL) {
+		result = -EIO;
+		dev_dbg(&adap->dev, "Error: Failed bus transaction\n");
+	}
+
+	/* Unfortunately the ALI SMB controller maps "no response" and "bus
+	 * collision" into a single bit. No response is the usual case so don't
+	 * do a printk.  This means that bus collisions go unreported.
+	 */
+	if (temp & ALI1535_STS_BUSERR) {
+		result = -ENXIO;
+		dev_dbg(&adap->dev,
+			"Error: no response or bus collision ADD=%02x\n",
+			inb_p(SMBHSTADD));
+	}
+
+	/* haven't ever seen this */
+	if (temp & ALI1535_STS_DEV) {
+		result = -EIO;
+		dev_err(&adap->dev, "Error: device error\n");
+	}
+
+	/* check to see if the "command complete" indication is set */
+	if (!(temp & ALI1535_STS_DONE)) {
+		result = -ETIMEDOUT;
+		dev_err(&adap->dev, "Error: command never completed\n");
+	}
+
+	dev_dbg(&adap->dev, "Transaction (post): STS=%02x, TYP=%02x, "
+		"CMD=%02x, ADD=%02x, DAT0=%02x, DAT1=%02x\n",
+		inb_p(SMBHSTSTS), inb_p(SMBHSTTYP), inb_p(SMBHSTCMD),
+		inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1));
+
+	/* take consequent actions for error conditions */
+	if (!(temp & ALI1535_STS_DONE)) {
+		/* issue "kill" to reset host controller */
+		outb_p(ALI1535_KILL, SMBHSTTYP);
+		outb_p(0xFF, SMBHSTSTS);
+	} else if (temp & ALI1535_STS_ERR) {
+		/* issue "timeout" to reset all devices on bus */
+		outb_p(ALI1535_T_OUT, SMBHSTTYP);
+		outb_p(0xFF, SMBHSTSTS);
+	}
+
+	return result;
+}
+
+/* Return negative errno on error. */
+static s32 ali1535_access(struct i2c_adapter *adap, u16 addr,
+			  unsigned short flags, char read_write, u8 command,
+			  int size, union i2c_smbus_data *data)
+{
+	int i, len;
+	int temp;
+	int timeout;
+	s32 result = 0;
+
+	/* make sure SMBus is idle */
+	temp = inb_p(SMBHSTSTS);
+	for (timeout = 0;
+	     (timeout < MAX_TIMEOUT) && !(temp & ALI1535_STS_IDLE);
+	     timeout++) {
+		usleep_range(1000, 2000);
+		temp = inb_p(SMBHSTSTS);
+	}
+	if (timeout >= MAX_TIMEOUT)
+		dev_warn(&adap->dev, "Idle wait Timeout! STS=0x%02x\n", temp);
+
+	/* clear status register (clear-on-write) */
+	outb_p(0xFF, SMBHSTSTS);
+
+	switch (size) {
+	case I2C_SMBUS_QUICK:
+		outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+		       SMBHSTADD);
+		size = ALI1535_QUICK;
+		outb_p(size, SMBHSTTYP);	/* output command */
+		break;
+	case I2C_SMBUS_BYTE:
+		outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+		       SMBHSTADD);
+		size = ALI1535_BYTE;
+		outb_p(size, SMBHSTTYP);	/* output command */
+		if (read_write == I2C_SMBUS_WRITE)
+			outb_p(command, SMBHSTCMD);
+		break;
+	case I2C_SMBUS_BYTE_DATA:
+		outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+		       SMBHSTADD);
+		size = ALI1535_BYTE_DATA;
+		outb_p(size, SMBHSTTYP);	/* output command */
+		outb_p(command, SMBHSTCMD);
+		if (read_write == I2C_SMBUS_WRITE)
+			outb_p(data->byte, SMBHSTDAT0);
+		break;
+	case I2C_SMBUS_WORD_DATA:
+		outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+		       SMBHSTADD);
+		size = ALI1535_WORD_DATA;
+		outb_p(size, SMBHSTTYP);	/* output command */
+		outb_p(command, SMBHSTCMD);
+		if (read_write == I2C_SMBUS_WRITE) {
+			outb_p(data->word & 0xff, SMBHSTDAT0);
+			outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1);
+		}
+		break;
+	case I2C_SMBUS_BLOCK_DATA:
+		outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+		       SMBHSTADD);
+		size = ALI1535_BLOCK_DATA;
+		outb_p(size, SMBHSTTYP);	/* output command */
+		outb_p(command, SMBHSTCMD);
+		if (read_write == I2C_SMBUS_WRITE) {
+			len = data->block[0];
+			if (len < 0) {
+				len = 0;
+				data->block[0] = len;
+			}
+			if (len > 32) {
+				len = 32;
+				data->block[0] = len;
+			}
+			outb_p(len, SMBHSTDAT0);
+			/* Reset SMBBLKDAT */
+			outb_p(inb_p(SMBHSTTYP) | ALI1535_BLOCK_CLR, SMBHSTTYP);
+			for (i = 1; i <= len; i++)
+				outb_p(data->block[i], SMBBLKDAT);
+		}
+		break;
+	default:
+		dev_warn(&adap->dev, "Unsupported transaction %d\n", size);
+		result = -EOPNOTSUPP;
+		goto EXIT;
+	}
+
+	result = ali1535_transaction(adap);
+	if (result)
+		goto EXIT;
+
+	if ((read_write == I2C_SMBUS_WRITE) || (size == ALI1535_QUICK)) {
+		result = 0;
+		goto EXIT;
+	}
+
+	switch (size) {
+	case ALI1535_BYTE:	/* Result put in SMBHSTDAT0 */
+		data->byte = inb_p(SMBHSTDAT0);
+		break;
+	case ALI1535_BYTE_DATA:
+		data->byte = inb_p(SMBHSTDAT0);
+		break;
+	case ALI1535_WORD_DATA:
+		data->word = inb_p(SMBHSTDAT0) + (inb_p(SMBHSTDAT1) << 8);
+		break;
+	case ALI1535_BLOCK_DATA:
+		len = inb_p(SMBHSTDAT0);
+		if (len > 32)
+			len = 32;
+		data->block[0] = len;
+		/* Reset SMBBLKDAT */
+		outb_p(inb_p(SMBHSTTYP) | ALI1535_BLOCK_CLR, SMBHSTTYP);
+		for (i = 1; i <= data->block[0]; i++) {
+			data->block[i] = inb_p(SMBBLKDAT);
+			dev_dbg(&adap->dev, "Blk: len=%d, i=%d, data=%02x\n",
+				len, i, data->block[i]);
+		}
+		break;
+	}
+EXIT:
+	return result;
+}
+
+
+static u32 ali1535_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+	    I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+	    I2C_FUNC_SMBUS_BLOCK_DATA;
+}
+
+static const struct i2c_algorithm smbus_algorithm = {
+	.smbus_xfer	= ali1535_access,
+	.functionality	= ali1535_func,
+};
+
+static struct i2c_adapter ali1535_adapter = {
+	.owner		= THIS_MODULE,
+	.class          = I2C_CLASS_HWMON | I2C_CLASS_SPD,
+	.algo		= &smbus_algorithm,
+};
+
+static DEFINE_PCI_DEVICE_TABLE(ali1535_ids) = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101) },
+	{ },
+};
+
+MODULE_DEVICE_TABLE(pci, ali1535_ids);
+
+static int __devinit ali1535_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	if (ali1535_setup(dev)) {
+		dev_warn(&dev->dev,
+			"ALI1535 not detected, module not inserted.\n");
+		return -ENODEV;
+	}
+
+	/* set up the sysfs linkage to our parent device */
+	ali1535_adapter.dev.parent = &dev->dev;
+
+	snprintf(ali1535_adapter.name, sizeof(ali1535_adapter.name),
+		"SMBus ALI1535 adapter at %04x", ali1535_offset);
+	return i2c_add_adapter(&ali1535_adapter);
+}
+
+static void __devexit ali1535_remove(struct pci_dev *dev)
+{
+	i2c_del_adapter(&ali1535_adapter);
+	release_region(ali1535_smba, ALI1535_SMB_IOSIZE);
+}
+
+static struct pci_driver ali1535_driver = {
+	.name		= "ali1535_smbus",
+	.id_table	= ali1535_ids,
+	.probe		= ali1535_probe,
+	.remove		= __devexit_p(ali1535_remove),
+};
+
+static int __init i2c_ali1535_init(void)
+{
+	return pci_register_driver(&ali1535_driver);
+}
+
+static void __exit i2c_ali1535_exit(void)
+{
+	pci_unregister_driver(&ali1535_driver);
+}
+
+MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "
+	      "Philip Edelbrock <phil@netroedge.com>, "
+	      "Mark D. Studebaker <mdsxyz123@yahoo.com> "
+	      "and Dan Eaton <dan.eaton@rocketlogix.com>");
+MODULE_DESCRIPTION("ALI1535 SMBus driver");
+MODULE_LICENSE("GPL");
+
+module_init(i2c_ali1535_init);
+module_exit(i2c_ali1535_exit);
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-ali1563.c b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-ali1563.c
new file mode 100644
index 0000000..47ae009
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-ali1563.c
@@ -0,0 +1,448 @@
+/**
+ *	i2c-ali1563.c - i2c driver for the ALi 1563 Southbridge
+ *
+ *	Copyright (C) 2004 Patrick Mochel
+ *		      2005 Rudolf Marek <r.marek@assembler.cz>
+ *
+ *	The 1563 southbridge is deceptively similar to the 1533, with a
+ *	few notable exceptions. One of those happens to be the fact they
+ *	upgraded the i2c core to be 2.0 compliant, and happens to be almost
+ *	identical to the i2c controller found in the Intel 801 south
+ *	bridges.
+ *
+ *	This driver is based on a mix of the 15x3, 1535, and i801 drivers,
+ *	with a little help from the ALi 1563 spec.
+ *
+ *	This file is released under the GPLv2
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/acpi.h>
+
+#define ALI1563_MAX_TIMEOUT	500
+#define	ALI1563_SMBBA		0x80
+#define ALI1563_SMB_IOEN	1
+#define ALI1563_SMB_HOSTEN	2
+#define ALI1563_SMB_IOSIZE	16
+
+#define SMB_HST_STS	(ali1563_smba + 0)
+#define SMB_HST_CNTL1	(ali1563_smba + 1)
+#define SMB_HST_CNTL2	(ali1563_smba + 2)
+#define SMB_HST_CMD	(ali1563_smba + 3)
+#define SMB_HST_ADD	(ali1563_smba + 4)
+#define SMB_HST_DAT0	(ali1563_smba + 5)
+#define SMB_HST_DAT1	(ali1563_smba + 6)
+#define SMB_BLK_DAT	(ali1563_smba + 7)
+
+#define HST_STS_BUSY	0x01
+#define HST_STS_INTR	0x02
+#define HST_STS_DEVERR	0x04
+#define HST_STS_BUSERR	0x08
+#define HST_STS_FAIL	0x10
+#define HST_STS_DONE	0x80
+#define HST_STS_BAD	0x1c
+
+
+#define HST_CNTL1_TIMEOUT	0x80
+#define HST_CNTL1_LAST		0x40
+
+#define HST_CNTL2_KILL		0x04
+#define HST_CNTL2_START		0x40
+#define HST_CNTL2_QUICK		0x00
+#define HST_CNTL2_BYTE		0x01
+#define HST_CNTL2_BYTE_DATA	0x02
+#define HST_CNTL2_WORD_DATA	0x03
+#define HST_CNTL2_BLOCK		0x05
+
+
+#define HST_CNTL2_SIZEMASK	0x38
+
+static struct pci_driver ali1563_pci_driver;
+static unsigned short ali1563_smba;
+
+static int ali1563_transaction(struct i2c_adapter * a, int size)
+{
+	u32 data;
+	int timeout;
+	int status = -EIO;
+
+	dev_dbg(&a->dev, "Transaction (pre): STS=%02x, CNTL1=%02x, "
+		"CNTL2=%02x, CMD=%02x, ADD=%02x, DAT0=%02x, DAT1=%02x\n",
+		inb_p(SMB_HST_STS), inb_p(SMB_HST_CNTL1), inb_p(SMB_HST_CNTL2),
+		inb_p(SMB_HST_CMD), inb_p(SMB_HST_ADD), inb_p(SMB_HST_DAT0),
+		inb_p(SMB_HST_DAT1));
+
+	data = inb_p(SMB_HST_STS);
+	if (data & HST_STS_BAD) {
+		dev_err(&a->dev, "ali1563: Trying to reset busy device\n");
+		outb_p(data | HST_STS_BAD,SMB_HST_STS);
+		data = inb_p(SMB_HST_STS);
+		if (data & HST_STS_BAD)
+			return -EBUSY;
+	}
+	outb_p(inb_p(SMB_HST_CNTL2) | HST_CNTL2_START, SMB_HST_CNTL2);
+
+	timeout = ALI1563_MAX_TIMEOUT;
+	do {
+		msleep(1);
+	} while (((data = inb_p(SMB_HST_STS)) & HST_STS_BUSY) && --timeout);
+
+	dev_dbg(&a->dev, "Transaction (post): STS=%02x, CNTL1=%02x, "
+		"CNTL2=%02x, CMD=%02x, ADD=%02x, DAT0=%02x, DAT1=%02x\n",
+		inb_p(SMB_HST_STS), inb_p(SMB_HST_CNTL1), inb_p(SMB_HST_CNTL2),
+		inb_p(SMB_HST_CMD), inb_p(SMB_HST_ADD), inb_p(SMB_HST_DAT0),
+		inb_p(SMB_HST_DAT1));
+
+	if (timeout && !(data & HST_STS_BAD))
+		return 0;
+
+	if (!timeout) {
+		dev_err(&a->dev, "Timeout - Trying to KILL transaction!\n");
+		/* Issue 'kill' to host controller */
+		outb_p(HST_CNTL2_KILL,SMB_HST_CNTL2);
+		data = inb_p(SMB_HST_STS);
+		status = -ETIMEDOUT;
+ 	}
+
+	/* device error - no response, ignore the autodetection case */
+	if (data & HST_STS_DEVERR) {
+		if (size != HST_CNTL2_QUICK)
+			dev_err(&a->dev, "Device error!\n");
+		status = -ENXIO;
+	}
+	/* bus collision */
+	if (data & HST_STS_BUSERR) {
+		dev_err(&a->dev, "Bus collision!\n");
+		/* Issue timeout, hoping it helps */
+		outb_p(HST_CNTL1_TIMEOUT,SMB_HST_CNTL1);
+	}
+
+	if (data & HST_STS_FAIL) {
+		dev_err(&a->dev, "Cleaning fail after KILL!\n");
+		outb_p(0x0,SMB_HST_CNTL2);
+	}
+
+	return status;
+}
+
+static int ali1563_block_start(struct i2c_adapter * a)
+{
+	u32 data;
+	int timeout;
+	int status = -EIO;
+
+	dev_dbg(&a->dev, "Block (pre): STS=%02x, CNTL1=%02x, "
+		"CNTL2=%02x, CMD=%02x, ADD=%02x, DAT0=%02x, DAT1=%02x\n",
+		inb_p(SMB_HST_STS), inb_p(SMB_HST_CNTL1), inb_p(SMB_HST_CNTL2),
+		inb_p(SMB_HST_CMD), inb_p(SMB_HST_ADD), inb_p(SMB_HST_DAT0),
+		inb_p(SMB_HST_DAT1));
+
+	data = inb_p(SMB_HST_STS);
+	if (data & HST_STS_BAD) {
+		dev_warn(&a->dev,"ali1563: Trying to reset busy device\n");
+		outb_p(data | HST_STS_BAD,SMB_HST_STS);
+		data = inb_p(SMB_HST_STS);
+		if (data & HST_STS_BAD)
+			return -EBUSY;
+	}
+
+	/* Clear byte-ready bit */
+	outb_p(data | HST_STS_DONE, SMB_HST_STS);
+
+	/* Start transaction and wait for byte-ready bit to be set */
+	outb_p(inb_p(SMB_HST_CNTL2) | HST_CNTL2_START, SMB_HST_CNTL2);
+
+	timeout = ALI1563_MAX_TIMEOUT;
+	do {
+		msleep(1);
+	} while (!((data = inb_p(SMB_HST_STS)) & HST_STS_DONE) && --timeout);
+
+	dev_dbg(&a->dev, "Block (post): STS=%02x, CNTL1=%02x, "
+		"CNTL2=%02x, CMD=%02x, ADD=%02x, DAT0=%02x, DAT1=%02x\n",
+		inb_p(SMB_HST_STS), inb_p(SMB_HST_CNTL1), inb_p(SMB_HST_CNTL2),
+		inb_p(SMB_HST_CMD), inb_p(SMB_HST_ADD), inb_p(SMB_HST_DAT0),
+		inb_p(SMB_HST_DAT1));
+
+	if (timeout && !(data & HST_STS_BAD))
+		return 0;
+
+	if (timeout == 0)
+		status = -ETIMEDOUT;
+
+	if (data & HST_STS_DEVERR)
+		status = -ENXIO;
+
+	dev_err(&a->dev, "SMBus Error: %s%s%s%s%s\n",
+		timeout ? "" : "Timeout ",
+		data & HST_STS_FAIL ? "Transaction Failed " : "",
+		data & HST_STS_BUSERR ? "No response or Bus Collision " : "",
+		data & HST_STS_DEVERR ? "Device Error " : "",
+		!(data & HST_STS_DONE) ? "Transaction Never Finished " : "");
+	return status;
+}
+
+static int ali1563_block(struct i2c_adapter * a, union i2c_smbus_data * data, u8 rw)
+{
+	int i, len;
+	int error = 0;
+
+	/* Do we need this? */
+	outb_p(HST_CNTL1_LAST,SMB_HST_CNTL1);
+
+	if (rw == I2C_SMBUS_WRITE) {
+		len = data->block[0];
+		if (len < 1)
+			len = 1;
+		else if (len > 32)
+			len = 32;
+		outb_p(len,SMB_HST_DAT0);
+		outb_p(data->block[1],SMB_BLK_DAT);
+	} else
+		len = 32;
+
+	outb_p(inb_p(SMB_HST_CNTL2) | HST_CNTL2_BLOCK, SMB_HST_CNTL2);
+
+	for (i = 0; i < len; i++) {
+		if (rw == I2C_SMBUS_WRITE) {
+			outb_p(data->block[i + 1], SMB_BLK_DAT);
+			if ((error = ali1563_block_start(a)))
+				break;
+		} else {
+			if ((error = ali1563_block_start(a)))
+				break;
+			if (i == 0) {
+				len = inb_p(SMB_HST_DAT0);
+				if (len < 1)
+					len = 1;
+				else if (len > 32)
+					len = 32;
+			}
+			data->block[i+1] = inb_p(SMB_BLK_DAT);
+		}
+	}
+	/* Do we need this? */
+	outb_p(HST_CNTL1_LAST,SMB_HST_CNTL1);
+	return error;
+}
+
+static s32 ali1563_access(struct i2c_adapter * a, u16 addr,
+			  unsigned short flags, char rw, u8 cmd,
+			  int size, union i2c_smbus_data * data)
+{
+	int error = 0;
+	int timeout;
+	u32 reg;
+
+	for (timeout = ALI1563_MAX_TIMEOUT; timeout; timeout--) {
+		if (!(reg = inb_p(SMB_HST_STS) & HST_STS_BUSY))
+			break;
+	}
+	if (!timeout)
+		dev_warn(&a->dev,"SMBus not idle. HST_STS = %02x\n",reg);
+	outb_p(0xff,SMB_HST_STS);
+
+	/* Map the size to what the chip understands */
+	switch (size) {
+	case I2C_SMBUS_QUICK:
+		size = HST_CNTL2_QUICK;
+		break;
+	case I2C_SMBUS_BYTE:
+		size = HST_CNTL2_BYTE;
+		break;
+	case I2C_SMBUS_BYTE_DATA:
+		size = HST_CNTL2_BYTE_DATA;
+		break;
+	case I2C_SMBUS_WORD_DATA:
+		size = HST_CNTL2_WORD_DATA;
+		break;
+	case I2C_SMBUS_BLOCK_DATA:
+		size = HST_CNTL2_BLOCK;
+		break;
+	default:
+		dev_warn(&a->dev, "Unsupported transaction %d\n", size);
+		error = -EOPNOTSUPP;
+		goto Done;
+	}
+
+	outb_p(((addr & 0x7f) << 1) | (rw & 0x01), SMB_HST_ADD);
+	outb_p((inb_p(SMB_HST_CNTL2) & ~HST_CNTL2_SIZEMASK) | (size << 3), SMB_HST_CNTL2);
+
+	/* Write the command register */
+
+	switch(size) {
+	case HST_CNTL2_BYTE:
+		if (rw== I2C_SMBUS_WRITE)
+			/* Beware it uses DAT0 register and not CMD! */
+			outb_p(cmd, SMB_HST_DAT0);
+		break;
+	case HST_CNTL2_BYTE_DATA:
+		outb_p(cmd, SMB_HST_CMD);
+		if (rw == I2C_SMBUS_WRITE)
+			outb_p(data->byte, SMB_HST_DAT0);
+		break;
+	case HST_CNTL2_WORD_DATA:
+		outb_p(cmd, SMB_HST_CMD);
+		if (rw == I2C_SMBUS_WRITE) {
+			outb_p(data->word & 0xff, SMB_HST_DAT0);
+			outb_p((data->word & 0xff00) >> 8, SMB_HST_DAT1);
+		}
+		break;
+	case HST_CNTL2_BLOCK:
+		outb_p(cmd, SMB_HST_CMD);
+		error = ali1563_block(a,data,rw);
+		goto Done;
+	}
+
+	if ((error = ali1563_transaction(a, size)))
+		goto Done;
+
+	if ((rw == I2C_SMBUS_WRITE) || (size == HST_CNTL2_QUICK))
+		goto Done;
+
+	switch (size) {
+	case HST_CNTL2_BYTE:	/* Result put in SMBHSTDAT0 */
+		data->byte = inb_p(SMB_HST_DAT0);
+		break;
+	case HST_CNTL2_BYTE_DATA:
+		data->byte = inb_p(SMB_HST_DAT0);
+		break;
+	case HST_CNTL2_WORD_DATA:
+		data->word = inb_p(SMB_HST_DAT0) + (inb_p(SMB_HST_DAT1) << 8);
+		break;
+	}
+Done:
+	return error;
+}
+
+static u32 ali1563_func(struct i2c_adapter * a)
+{
+	return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+	    I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+	    I2C_FUNC_SMBUS_BLOCK_DATA;
+}
+
+
+static int __devinit ali1563_setup(struct pci_dev * dev)
+{
+	u16 ctrl;
+
+	pci_read_config_word(dev,ALI1563_SMBBA,&ctrl);
+
+	/* SMB I/O Base in high 12 bits and must be aligned with the
+	 * size of the I/O space. */
+	ali1563_smba = ctrl & ~(ALI1563_SMB_IOSIZE - 1);
+	if (!ali1563_smba) {
+		dev_warn(&dev->dev,"ali1563_smba Uninitialized\n");
+		goto Err;
+	}
+
+	/* Check if device is enabled */
+	if (!(ctrl & ALI1563_SMB_HOSTEN)) {
+		dev_warn(&dev->dev, "Host Controller not enabled\n");
+		goto Err;
+	}
+	if (!(ctrl & ALI1563_SMB_IOEN)) {
+		dev_warn(&dev->dev, "I/O space not enabled, trying manually\n");
+		pci_write_config_word(dev, ALI1563_SMBBA,
+				      ctrl | ALI1563_SMB_IOEN);
+		pci_read_config_word(dev, ALI1563_SMBBA, &ctrl);
+		if (!(ctrl & ALI1563_SMB_IOEN)) {
+			dev_err(&dev->dev, "I/O space still not enabled, "
+				"giving up\n");
+			goto Err;
+		}
+	}
+
+	if (acpi_check_region(ali1563_smba, ALI1563_SMB_IOSIZE,
+			      ali1563_pci_driver.name))
+		goto Err;
+
+	if (!request_region(ali1563_smba, ALI1563_SMB_IOSIZE,
+			    ali1563_pci_driver.name)) {
+		dev_err(&dev->dev, "Could not allocate I/O space at 0x%04x\n",
+			ali1563_smba);
+		goto Err;
+	}
+	dev_info(&dev->dev, "Found ALi1563 SMBus at 0x%04x\n", ali1563_smba);
+
+	return 0;
+Err:
+	return -ENODEV;
+}
+
+static void ali1563_shutdown(struct pci_dev *dev)
+{
+	release_region(ali1563_smba,ALI1563_SMB_IOSIZE);
+}
+
+static const struct i2c_algorithm ali1563_algorithm = {
+	.smbus_xfer	= ali1563_access,
+	.functionality	= ali1563_func,
+};
+
+static struct i2c_adapter ali1563_adapter = {
+	.owner	= THIS_MODULE,
+	.class	= I2C_CLASS_HWMON | I2C_CLASS_SPD,
+	.algo	= &ali1563_algorithm,
+};
+
+static int __devinit ali1563_probe(struct pci_dev * dev,
+				const struct pci_device_id * id_table)
+{
+	int error;
+
+	if ((error = ali1563_setup(dev)))
+		goto exit;
+	ali1563_adapter.dev.parent = &dev->dev;
+	snprintf(ali1563_adapter.name, sizeof(ali1563_adapter.name),
+		 "SMBus ALi 1563 Adapter @ %04x", ali1563_smba);
+	if ((error = i2c_add_adapter(&ali1563_adapter)))
+		goto exit_shutdown;
+	return 0;
+
+exit_shutdown:
+	ali1563_shutdown(dev);
+exit:
+	dev_warn(&dev->dev, "ALi1563 SMBus probe failed (%d)\n", error);
+	return error;
+}
+
+static void __devexit ali1563_remove(struct pci_dev * dev)
+{
+	i2c_del_adapter(&ali1563_adapter);
+	ali1563_shutdown(dev);
+}
+
+static DEFINE_PCI_DEVICE_TABLE(ali1563_id_table) = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1563) },
+	{},
+};
+
+MODULE_DEVICE_TABLE (pci, ali1563_id_table);
+
+static struct pci_driver ali1563_pci_driver = {
+ 	.name		= "ali1563_smbus",
+	.id_table	= ali1563_id_table,
+ 	.probe		= ali1563_probe,
+	.remove		= __devexit_p(ali1563_remove),
+};
+
+static int __init ali1563_init(void)
+{
+	return pci_register_driver(&ali1563_pci_driver);
+}
+
+module_init(ali1563_init);
+
+static void __exit ali1563_exit(void)
+{
+	pci_unregister_driver(&ali1563_pci_driver);
+}
+
+module_exit(ali1563_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-ali15x3.c b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-ali15x3.c
new file mode 100644
index 0000000..087ea9c
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-ali15x3.c
@@ -0,0 +1,533 @@
+/*
+    Copyright (c) 1999  Frodo Looijaard <frodol@dds.nl> and
+    Philip Edelbrock <phil@netroedge.com> and
+    Mark D. Studebaker <mdsxyz123@yahoo.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/*
+    This is the driver for the SMB Host controller on
+    Acer Labs Inc. (ALI) M1541 and M1543C South Bridges.
+
+    The M1543C is a South bridge for desktop systems.
+    The M1533 is a South bridge for portable systems.
+    They are part of the following ALI chipsets:
+       "Aladdin Pro 2": Includes the M1621 Slot 1 North bridge
+       with AGP and 100MHz CPU Front Side bus
+       "Aladdin V": Includes the M1541 Socket 7 North bridge
+       with AGP and 100MHz CPU Front Side bus
+       "Aladdin IV": Includes the M1541 Socket 7 North bridge
+       with host bus up to 83.3 MHz.
+    For an overview of these chips see http://www.acerlabs.com
+
+    The M1533/M1543C devices appear as FOUR separate devices
+    on the PCI bus. An output of lspci will show something similar
+    to the following:
+
+	00:02.0 USB Controller: Acer Laboratories Inc. M5237
+	00:03.0 Bridge: Acer Laboratories Inc. M7101
+	00:07.0 ISA bridge: Acer Laboratories Inc. M1533
+	00:0f.0 IDE interface: Acer Laboratories Inc. M5229
+
+    The SMB controller is part of the 7101 device, which is an
+    ACPI-compliant Power Management Unit (PMU).
+
+    The whole 7101 device has to be enabled for the SMB to work.
+    You can't just enable the SMB alone.
+    The SMB and the ACPI have separate I/O spaces.
+    We make sure that the SMB is enabled. We leave the ACPI alone.
+
+    This driver controls the SMB Host only.
+    The SMB Slave controller on the M15X3 is not enabled.
+
+    This driver does not use interrupts.
+*/
+
+/* Note: we assume there can only be one ALI15X3, with one SMBus interface */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/stddef.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/acpi.h>
+#include <linux/io.h>
+
+/* ALI15X3 SMBus address offsets */
+#define SMBHSTSTS	(0 + ali15x3_smba)
+#define SMBHSTCNT	(1 + ali15x3_smba)
+#define SMBHSTSTART	(2 + ali15x3_smba)
+#define SMBHSTCMD	(7 + ali15x3_smba)
+#define SMBHSTADD	(3 + ali15x3_smba)
+#define SMBHSTDAT0	(4 + ali15x3_smba)
+#define SMBHSTDAT1	(5 + ali15x3_smba)
+#define SMBBLKDAT	(6 + ali15x3_smba)
+
+/* PCI Address Constants */
+#define SMBCOM		0x004
+#define SMBBA		0x014
+#define SMBATPC		0x05B	/* used to unlock xxxBA registers */
+#define SMBHSTCFG	0x0E0
+#define SMBSLVC		0x0E1
+#define SMBCLK		0x0E2
+#define SMBREV		0x008
+
+/* Other settings */
+#define MAX_TIMEOUT		200	/* times 1/100 sec */
+#define ALI15X3_SMB_IOSIZE	32
+
+/* this is what the Award 1004 BIOS sets them to on a ASUS P5A MB.
+   We don't use these here. If the bases aren't set to some value we
+   tell user to upgrade BIOS and we fail.
+*/
+#define ALI15X3_SMB_DEFAULTBASE	0xE800
+
+/* ALI15X3 address lock bits */
+#define ALI15X3_LOCK		0x06
+
+/* ALI15X3 command constants */
+#define ALI15X3_ABORT		0x02
+#define ALI15X3_T_OUT		0x04
+#define ALI15X3_QUICK		0x00
+#define ALI15X3_BYTE		0x10
+#define ALI15X3_BYTE_DATA	0x20
+#define ALI15X3_WORD_DATA	0x30
+#define ALI15X3_BLOCK_DATA	0x40
+#define ALI15X3_BLOCK_CLR	0x80
+
+/* ALI15X3 status register bits */
+#define ALI15X3_STS_IDLE	0x04
+#define ALI15X3_STS_BUSY	0x08
+#define ALI15X3_STS_DONE	0x10
+#define ALI15X3_STS_DEV		0x20	/* device error */
+#define ALI15X3_STS_COLL	0x40	/* collision or no response */
+#define ALI15X3_STS_TERM	0x80	/* terminated by abort */
+#define ALI15X3_STS_ERR		0xE0	/* all the bad error bits */
+
+
+/* If force_addr is set to anything different from 0, we forcibly enable
+   the device at the given address. */
+static u16 force_addr;
+module_param(force_addr, ushort, 0);
+MODULE_PARM_DESC(force_addr,
+		 "Initialize the base address of the i2c controller");
+
+static struct pci_driver ali15x3_driver;
+static unsigned short ali15x3_smba;
+
+static int __devinit ali15x3_setup(struct pci_dev *ALI15X3_dev)
+{
+	u16 a;
+	unsigned char temp;
+
+	/* Check the following things:
+		- SMB I/O address is initialized
+		- Device is enabled
+		- We can use the addresses
+	*/
+
+	/* Unlock the register.
+	   The data sheet says that the address registers are read-only
+	   if the lock bits are 1, but in fact the address registers
+	   are zero unless you clear the lock bits.
+	*/
+	pci_read_config_byte(ALI15X3_dev, SMBATPC, &temp);
+	if (temp & ALI15X3_LOCK) {
+		temp &= ~ALI15X3_LOCK;
+		pci_write_config_byte(ALI15X3_dev, SMBATPC, temp);
+	}
+
+	/* Determine the address of the SMBus area */
+	pci_read_config_word(ALI15X3_dev, SMBBA, &ali15x3_smba);
+	ali15x3_smba &= (0xffff & ~(ALI15X3_SMB_IOSIZE - 1));
+	if (ali15x3_smba == 0 && force_addr == 0) {
+		dev_err(&ALI15X3_dev->dev, "ALI15X3_smb region uninitialized "
+			"- upgrade BIOS or use force_addr=0xaddr\n");
+		return -ENODEV;
+	}
+
+	if(force_addr)
+		ali15x3_smba = force_addr & ~(ALI15X3_SMB_IOSIZE - 1);
+
+	if (acpi_check_region(ali15x3_smba, ALI15X3_SMB_IOSIZE,
+			      ali15x3_driver.name))
+		return -EBUSY;
+
+	if (!request_region(ali15x3_smba, ALI15X3_SMB_IOSIZE,
+			    ali15x3_driver.name)) {
+		dev_err(&ALI15X3_dev->dev,
+			"ALI15X3_smb region 0x%x already in use!\n",
+			ali15x3_smba);
+		return -ENODEV;
+	}
+
+	if(force_addr) {
+		dev_info(&ALI15X3_dev->dev, "forcing ISA address 0x%04X\n",
+			ali15x3_smba);
+		if (PCIBIOS_SUCCESSFUL != pci_write_config_word(ALI15X3_dev,
+								SMBBA,
+								ali15x3_smba))
+			goto error;
+		if (PCIBIOS_SUCCESSFUL != pci_read_config_word(ALI15X3_dev,
+								SMBBA, &a))
+			goto error;
+		if ((a & ~(ALI15X3_SMB_IOSIZE - 1)) != ali15x3_smba) {
+			/* make sure it works */
+			dev_err(&ALI15X3_dev->dev,
+				"force address failed - not supported?\n");
+			goto error;
+		}
+	}
+	/* check if whole device is enabled */
+	pci_read_config_byte(ALI15X3_dev, SMBCOM, &temp);
+	if ((temp & 1) == 0) {
+		dev_info(&ALI15X3_dev->dev, "enabling SMBus device\n");
+		pci_write_config_byte(ALI15X3_dev, SMBCOM, temp | 0x01);
+	}
+
+	/* Is SMB Host controller enabled? */
+	pci_read_config_byte(ALI15X3_dev, SMBHSTCFG, &temp);
+	if ((temp & 1) == 0) {
+		dev_info(&ALI15X3_dev->dev, "enabling SMBus controller\n");
+		pci_write_config_byte(ALI15X3_dev, SMBHSTCFG, temp | 0x01);
+	}
+
+	/* set SMB clock to 74KHz as recommended in data sheet */
+	pci_write_config_byte(ALI15X3_dev, SMBCLK, 0x20);
+
+	/*
+	  The interrupt routing for SMB is set up in register 0x77 in the
+	  1533 ISA Bridge device, NOT in the 7101 device.
+	  Don't bother with finding the 1533 device and reading the register.
+	if ((....... & 0x0F) == 1)
+		dev_dbg(&ALI15X3_dev->dev, "ALI15X3 using Interrupt 9 for SMBus.\n");
+	*/
+	pci_read_config_byte(ALI15X3_dev, SMBREV, &temp);
+	dev_dbg(&ALI15X3_dev->dev, "SMBREV = 0x%X\n", temp);
+	dev_dbg(&ALI15X3_dev->dev, "iALI15X3_smba = 0x%X\n", ali15x3_smba);
+
+	return 0;
+error:
+	release_region(ali15x3_smba, ALI15X3_SMB_IOSIZE);
+	return -ENODEV;
+}
+
+/* Another internally used function */
+static int ali15x3_transaction(struct i2c_adapter *adap)
+{
+	int temp;
+	int result = 0;
+	int timeout = 0;
+
+	dev_dbg(&adap->dev, "Transaction (pre): STS=%02x, CNT=%02x, CMD=%02x, "
+		"ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTSTS),
+		inb_p(SMBHSTCNT), inb_p(SMBHSTCMD), inb_p(SMBHSTADD),
+		inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1));
+
+	/* get status */
+	temp = inb_p(SMBHSTSTS);
+
+	/* Make sure the SMBus host is ready to start transmitting */
+	/* Check the busy bit first */
+	if (temp & ALI15X3_STS_BUSY) {
+	/*
+	   If the host controller is still busy, it may have timed out in the
+	   previous transaction, resulting in a "SMBus Timeout" Dev.
+	   I've tried the following to reset a stuck busy bit.
+		1. Reset the controller with an ABORT command.
+		   (this doesn't seem to clear the controller if an external
+		   device is hung)
+		2. Reset the controller and the other SMBus devices with a
+		   T_OUT command.  (this clears the host busy bit if an
+		   external device is hung, but it comes back upon a new access
+		   to a device)
+		3. Disable and reenable the controller in SMBHSTCFG
+	   Worst case, nothing seems to work except power reset.
+	*/
+	/* Abort - reset the host controller */
+	/*
+	   Try resetting entire SMB bus, including other devices -
+	   This may not work either - it clears the BUSY bit but
+	   then the BUSY bit may come back on when you try and use the chip again.
+	   If that's the case you are stuck.
+	*/
+		dev_info(&adap->dev, "Resetting entire SMB Bus to "
+			"clear busy condition (%02x)\n", temp);
+		outb_p(ALI15X3_T_OUT, SMBHSTCNT);
+		temp = inb_p(SMBHSTSTS);
+	}
+
+	/* now check the error bits and the busy bit */
+	if (temp & (ALI15X3_STS_ERR | ALI15X3_STS_BUSY)) {
+		/* do a clear-on-write */
+		outb_p(0xFF, SMBHSTSTS);
+		if ((temp = inb_p(SMBHSTSTS)) &
+		    (ALI15X3_STS_ERR | ALI15X3_STS_BUSY)) {
+			/* this is probably going to be correctable only by a power reset
+			   as one of the bits now appears to be stuck */
+			/* This may be a bus or device with electrical problems. */
+			dev_err(&adap->dev, "SMBus reset failed! (0x%02x) - "
+				"controller or device on bus is probably hung\n",
+				temp);
+			return -EBUSY;
+		}
+	} else {
+		/* check and clear done bit */
+		if (temp & ALI15X3_STS_DONE) {
+			outb_p(temp, SMBHSTSTS);
+		}
+	}
+
+	/* start the transaction by writing anything to the start register */
+	outb_p(0xFF, SMBHSTSTART);
+
+	/* We will always wait for a fraction of a second! */
+	timeout = 0;
+	do {
+		msleep(1);
+		temp = inb_p(SMBHSTSTS);
+	} while ((!(temp & (ALI15X3_STS_ERR | ALI15X3_STS_DONE)))
+		 && (timeout++ < MAX_TIMEOUT));
+
+	/* If the SMBus is still busy, we give up */
+	if (timeout > MAX_TIMEOUT) {
+		result = -ETIMEDOUT;
+		dev_err(&adap->dev, "SMBus Timeout!\n");
+	}
+
+	if (temp & ALI15X3_STS_TERM) {
+		result = -EIO;
+		dev_dbg(&adap->dev, "Error: Failed bus transaction\n");
+	}
+
+	/*
+	  Unfortunately the ALI SMB controller maps "no response" and "bus
+	  collision" into a single bit. No response is the usual case so don't
+	  do a printk.
+	  This means that bus collisions go unreported.
+	*/
+	if (temp & ALI15X3_STS_COLL) {
+		result = -ENXIO;
+		dev_dbg(&adap->dev,
+			"Error: no response or bus collision ADD=%02x\n",
+			inb_p(SMBHSTADD));
+	}
+
+	/* haven't ever seen this */
+	if (temp & ALI15X3_STS_DEV) {
+		result = -EIO;
+		dev_err(&adap->dev, "Error: device error\n");
+	}
+	dev_dbg(&adap->dev, "Transaction (post): STS=%02x, CNT=%02x, CMD=%02x, "
+		"ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTSTS),
+		inb_p(SMBHSTCNT), inb_p(SMBHSTCMD), inb_p(SMBHSTADD),
+		inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1));
+	return result;
+}
+
+/* Return negative errno on error. */
+static s32 ali15x3_access(struct i2c_adapter * adap, u16 addr,
+		   unsigned short flags, char read_write, u8 command,
+		   int size, union i2c_smbus_data * data)
+{
+	int i, len;
+	int temp;
+	int timeout;
+
+	/* clear all the bits (clear-on-write) */
+	outb_p(0xFF, SMBHSTSTS);
+	/* make sure SMBus is idle */
+	temp = inb_p(SMBHSTSTS);
+	for (timeout = 0;
+	     (timeout < MAX_TIMEOUT) && !(temp & ALI15X3_STS_IDLE);
+	     timeout++) {
+		msleep(1);
+		temp = inb_p(SMBHSTSTS);
+	}
+	if (timeout >= MAX_TIMEOUT) {
+		dev_err(&adap->dev, "Idle wait Timeout! STS=0x%02x\n", temp);
+	}
+
+	switch (size) {
+	case I2C_SMBUS_QUICK:
+		outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+		       SMBHSTADD);
+		size = ALI15X3_QUICK;
+		break;
+	case I2C_SMBUS_BYTE:
+		outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+		       SMBHSTADD);
+		if (read_write == I2C_SMBUS_WRITE)
+			outb_p(command, SMBHSTCMD);
+		size = ALI15X3_BYTE;
+		break;
+	case I2C_SMBUS_BYTE_DATA:
+		outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+		       SMBHSTADD);
+		outb_p(command, SMBHSTCMD);
+		if (read_write == I2C_SMBUS_WRITE)
+			outb_p(data->byte, SMBHSTDAT0);
+		size = ALI15X3_BYTE_DATA;
+		break;
+	case I2C_SMBUS_WORD_DATA:
+		outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+		       SMBHSTADD);
+		outb_p(command, SMBHSTCMD);
+		if (read_write == I2C_SMBUS_WRITE) {
+			outb_p(data->word & 0xff, SMBHSTDAT0);
+			outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1);
+		}
+		size = ALI15X3_WORD_DATA;
+		break;
+	case I2C_SMBUS_BLOCK_DATA:
+		outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+		       SMBHSTADD);
+		outb_p(command, SMBHSTCMD);
+		if (read_write == I2C_SMBUS_WRITE) {
+			len = data->block[0];
+			if (len < 0) {
+				len = 0;
+				data->block[0] = len;
+			}
+			if (len > 32) {
+				len = 32;
+				data->block[0] = len;
+			}
+			outb_p(len, SMBHSTDAT0);
+			/* Reset SMBBLKDAT */
+			outb_p(inb_p(SMBHSTCNT) | ALI15X3_BLOCK_CLR, SMBHSTCNT);
+			for (i = 1; i <= len; i++)
+				outb_p(data->block[i], SMBBLKDAT);
+		}
+		size = ALI15X3_BLOCK_DATA;
+		break;
+	default:
+		dev_warn(&adap->dev, "Unsupported transaction %d\n", size);
+		return -EOPNOTSUPP;
+	}
+
+	outb_p(size, SMBHSTCNT);	/* output command */
+
+	temp = ali15x3_transaction(adap);
+	if (temp)
+		return temp;
+
+	if ((read_write == I2C_SMBUS_WRITE) || (size == ALI15X3_QUICK))
+		return 0;
+
+
+	switch (size) {
+	case ALI15X3_BYTE:	/* Result put in SMBHSTDAT0 */
+		data->byte = inb_p(SMBHSTDAT0);
+		break;
+	case ALI15X3_BYTE_DATA:
+		data->byte = inb_p(SMBHSTDAT0);
+		break;
+	case ALI15X3_WORD_DATA:
+		data->word = inb_p(SMBHSTDAT0) + (inb_p(SMBHSTDAT1) << 8);
+		break;
+	case ALI15X3_BLOCK_DATA:
+		len = inb_p(SMBHSTDAT0);
+		if (len > 32)
+			len = 32;
+		data->block[0] = len;
+		/* Reset SMBBLKDAT */
+		outb_p(inb_p(SMBHSTCNT) | ALI15X3_BLOCK_CLR, SMBHSTCNT);
+		for (i = 1; i <= data->block[0]; i++) {
+			data->block[i] = inb_p(SMBBLKDAT);
+			dev_dbg(&adap->dev, "Blk: len=%d, i=%d, data=%02x\n",
+				len, i, data->block[i]);
+		}
+		break;
+	}
+	return 0;
+}
+
+static u32 ali15x3_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+	    I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+	    I2C_FUNC_SMBUS_BLOCK_DATA;
+}
+
+static const struct i2c_algorithm smbus_algorithm = {
+	.smbus_xfer	= ali15x3_access,
+	.functionality	= ali15x3_func,
+};
+
+static struct i2c_adapter ali15x3_adapter = {
+	.owner		= THIS_MODULE,
+	.class          = I2C_CLASS_HWMON | I2C_CLASS_SPD,
+	.algo		= &smbus_algorithm,
+};
+
+static DEFINE_PCI_DEVICE_TABLE(ali15x3_ids) = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101) },
+	{ 0, }
+};
+
+MODULE_DEVICE_TABLE (pci, ali15x3_ids);
+
+static int __devinit ali15x3_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	if (ali15x3_setup(dev)) {
+		dev_err(&dev->dev,
+			"ALI15X3 not detected, module not inserted.\n");
+		return -ENODEV;
+	}
+
+	/* set up the sysfs linkage to our parent device */
+	ali15x3_adapter.dev.parent = &dev->dev;
+
+	snprintf(ali15x3_adapter.name, sizeof(ali15x3_adapter.name),
+		"SMBus ALI15X3 adapter at %04x", ali15x3_smba);
+	return i2c_add_adapter(&ali15x3_adapter);
+}
+
+static void __devexit ali15x3_remove(struct pci_dev *dev)
+{
+	i2c_del_adapter(&ali15x3_adapter);
+	release_region(ali15x3_smba, ALI15X3_SMB_IOSIZE);
+}
+
+static struct pci_driver ali15x3_driver = {
+	.name		= "ali15x3_smbus",
+	.id_table	= ali15x3_ids,
+	.probe		= ali15x3_probe,
+	.remove		= __devexit_p(ali15x3_remove),
+};
+
+static int __init i2c_ali15x3_init(void)
+{
+	return pci_register_driver(&ali15x3_driver);
+}
+
+static void __exit i2c_ali15x3_exit(void)
+{
+	pci_unregister_driver(&ali15x3_driver);
+}
+
+MODULE_AUTHOR ("Frodo Looijaard <frodol@dds.nl>, "
+		"Philip Edelbrock <phil@netroedge.com>, "
+		"and Mark D. Studebaker <mdsxyz123@yahoo.com>");
+MODULE_DESCRIPTION("ALI15X3 SMBus driver");
+MODULE_LICENSE("GPL");
+
+module_init(i2c_ali15x3_init);
+module_exit(i2c_ali15x3_exit);
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-amd756-s4882.c b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-amd756-s4882.c
new file mode 100644
index 0000000..378fcb5
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-amd756-s4882.c
@@ -0,0 +1,262 @@
+/*
+ * i2c-amd756-s4882.c - i2c-amd756 extras for the Tyan S4882 motherboard
+ *
+ * Copyright (C) 2004, 2008 Jean Delvare <khali@linux-fr.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+ 
+/*
+ * We select the channels by sending commands to the Philips
+ * PCA9556 chip at I2C address 0x18. The main adapter is used for
+ * the non-multiplexed part of the bus, and 4 virtual adapters
+ * are defined for the multiplexed addresses: 0x50-0x53 (memory
+ * module EEPROM) located on channels 1-4, and 0x4c (LM63)
+ * located on multiplexed channels 0 and 5-7. We define one
+ * virtual adapter per CPU, which corresponds to two multiplexed
+ * channels:
+ *   CPU0: virtual adapter 1, channels 1 and 0
+ *   CPU1: virtual adapter 2, channels 2 and 5
+ *   CPU2: virtual adapter 3, channels 3 and 6
+ *   CPU3: virtual adapter 4, channels 4 and 7
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+
+extern struct i2c_adapter amd756_smbus;
+
+static struct i2c_adapter *s4882_adapter;
+static struct i2c_algorithm *s4882_algo;
+
+/* Wrapper access functions for multiplexed SMBus */
+static DEFINE_MUTEX(amd756_lock);
+
+static s32 amd756_access_virt0(struct i2c_adapter * adap, u16 addr,
+			       unsigned short flags, char read_write,
+			       u8 command, int size,
+			       union i2c_smbus_data * data)
+{
+	int error;
+
+	/* We exclude the multiplexed addresses */
+	if (addr == 0x4c || (addr & 0xfc) == 0x50 || (addr & 0xfc) == 0x30
+	 || addr == 0x18)
+		return -ENXIO;
+
+	mutex_lock(&amd756_lock);
+
+	error = amd756_smbus.algo->smbus_xfer(adap, addr, flags, read_write,
+					      command, size, data);
+
+	mutex_unlock(&amd756_lock);
+
+	return error;
+}
+
+/* We remember the last used channels combination so as to only switch
+   channels when it is really needed. This greatly reduces the SMBus
+   overhead, but also assumes that nobody will be writing to the PCA9556
+   in our back. */
+static u8 last_channels;
+
+static inline s32 amd756_access_channel(struct i2c_adapter * adap, u16 addr,
+					unsigned short flags, char read_write,
+					u8 command, int size,
+					union i2c_smbus_data * data,
+					u8 channels)
+{
+	int error;
+
+	/* We exclude the non-multiplexed addresses */
+	if (addr != 0x4c && (addr & 0xfc) != 0x50 && (addr & 0xfc) != 0x30)
+		return -ENXIO;
+
+	mutex_lock(&amd756_lock);
+
+	if (last_channels != channels) {
+		union i2c_smbus_data mplxdata;
+		mplxdata.byte = channels;
+
+		error = amd756_smbus.algo->smbus_xfer(adap, 0x18, 0,
+						      I2C_SMBUS_WRITE, 0x01,
+						      I2C_SMBUS_BYTE_DATA,
+						      &mplxdata);
+		if (error)
+			goto UNLOCK;
+		last_channels = channels;
+	}
+	error = amd756_smbus.algo->smbus_xfer(adap, addr, flags, read_write,
+					      command, size, data);
+
+UNLOCK:
+	mutex_unlock(&amd756_lock);
+	return error;
+}
+
+static s32 amd756_access_virt1(struct i2c_adapter * adap, u16 addr,
+			       unsigned short flags, char read_write,
+			       u8 command, int size,
+			       union i2c_smbus_data * data)
+{
+	/* CPU0: channels 1 and 0 enabled */
+	return amd756_access_channel(adap, addr, flags, read_write, command,
+				     size, data, 0x03);
+}
+
+static s32 amd756_access_virt2(struct i2c_adapter * adap, u16 addr,
+			       unsigned short flags, char read_write,
+			       u8 command, int size,
+			       union i2c_smbus_data * data)
+{
+	/* CPU1: channels 2 and 5 enabled */
+	return amd756_access_channel(adap, addr, flags, read_write, command,
+				     size, data, 0x24);
+}
+
+static s32 amd756_access_virt3(struct i2c_adapter * adap, u16 addr,
+			       unsigned short flags, char read_write,
+			       u8 command, int size,
+			       union i2c_smbus_data * data)
+{
+	/* CPU2: channels 3 and 6 enabled */
+	return amd756_access_channel(adap, addr, flags, read_write, command,
+				     size, data, 0x48);
+}
+
+static s32 amd756_access_virt4(struct i2c_adapter * adap, u16 addr,
+			       unsigned short flags, char read_write,
+			       u8 command, int size,
+			       union i2c_smbus_data * data)
+{
+	/* CPU3: channels 4 and 7 enabled */
+	return amd756_access_channel(adap, addr, flags, read_write, command,
+				     size, data, 0x90);
+}
+
+static int __init amd756_s4882_init(void)
+{
+	int i, error;
+	union i2c_smbus_data ioconfig;
+
+	if (!amd756_smbus.dev.parent)
+		return -ENODEV;
+
+	/* Configure the PCA9556 multiplexer */
+	ioconfig.byte = 0x00; /* All I/O to output mode */
+	error = i2c_smbus_xfer(&amd756_smbus, 0x18, 0, I2C_SMBUS_WRITE, 0x03,
+			       I2C_SMBUS_BYTE_DATA, &ioconfig);
+	if (error) {
+		dev_err(&amd756_smbus.dev, "PCA9556 configuration failed\n");
+		error = -EIO;
+		goto ERROR0;
+	}
+
+	/* Unregister physical bus */
+	error = i2c_del_adapter(&amd756_smbus);
+	if (error) {
+		dev_err(&amd756_smbus.dev, "Physical bus removal failed\n");
+		goto ERROR0;
+	}
+
+	printk(KERN_INFO "Enabling SMBus multiplexing for Tyan S4882\n");
+	/* Define the 5 virtual adapters and algorithms structures */
+	if (!(s4882_adapter = kzalloc(5 * sizeof(struct i2c_adapter),
+				      GFP_KERNEL))) {
+		error = -ENOMEM;
+		goto ERROR1;
+	}
+	if (!(s4882_algo = kzalloc(5 * sizeof(struct i2c_algorithm),
+				   GFP_KERNEL))) {
+		error = -ENOMEM;
+		goto ERROR2;
+	}
+
+	/* Fill in the new structures */
+	s4882_algo[0] = *(amd756_smbus.algo);
+	s4882_algo[0].smbus_xfer = amd756_access_virt0;
+	s4882_adapter[0] = amd756_smbus;
+	s4882_adapter[0].algo = s4882_algo;
+	s4882_adapter[0].dev.parent = amd756_smbus.dev.parent;
+	for (i = 1; i < 5; i++) {
+		s4882_algo[i] = *(amd756_smbus.algo);
+		s4882_adapter[i] = amd756_smbus;
+		snprintf(s4882_adapter[i].name, sizeof(s4882_adapter[i].name),
+			 "SMBus 8111 adapter (CPU%d)", i-1);
+		s4882_adapter[i].algo = s4882_algo+i;
+		s4882_adapter[i].dev.parent = amd756_smbus.dev.parent;
+	}
+	s4882_algo[1].smbus_xfer = amd756_access_virt1;
+	s4882_algo[2].smbus_xfer = amd756_access_virt2;
+	s4882_algo[3].smbus_xfer = amd756_access_virt3;
+	s4882_algo[4].smbus_xfer = amd756_access_virt4;
+
+	/* Register virtual adapters */
+	for (i = 0; i < 5; i++) {
+		error = i2c_add_adapter(s4882_adapter+i);
+		if (error) {
+			printk(KERN_ERR "i2c-amd756-s4882: "
+			       "Virtual adapter %d registration "
+			       "failed, module not inserted\n", i);
+			for (i--; i >= 0; i--)
+				i2c_del_adapter(s4882_adapter+i);
+			goto ERROR3;
+		}
+	}
+
+	return 0;
+
+ERROR3:
+	kfree(s4882_algo);
+	s4882_algo = NULL;
+ERROR2:
+	kfree(s4882_adapter);
+	s4882_adapter = NULL;
+ERROR1:
+	/* Restore physical bus */
+	i2c_add_adapter(&amd756_smbus);
+ERROR0:
+	return error;
+}
+
+static void __exit amd756_s4882_exit(void)
+{
+	if (s4882_adapter) {
+		int i;
+
+		for (i = 0; i < 5; i++)
+			i2c_del_adapter(s4882_adapter+i);
+		kfree(s4882_adapter);
+		s4882_adapter = NULL;
+	}
+	kfree(s4882_algo);
+	s4882_algo = NULL;
+
+	/* Restore physical bus */
+	if (i2c_add_adapter(&amd756_smbus))
+		printk(KERN_ERR "i2c-amd756-s4882: "
+		       "Physical bus restoration failed\n");
+}
+
+MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
+MODULE_DESCRIPTION("S4882 SMBus multiplexing");
+MODULE_LICENSE("GPL");
+
+module_init(amd756_s4882_init);
+module_exit(amd756_s4882_exit);
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-amd756.c b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-amd756.c
new file mode 100644
index 0000000..eb778bf
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-amd756.c
@@ -0,0 +1,430 @@
+/*
+    Copyright (c) 1999-2002 Merlin Hughes <merlin@merlin.org>
+
+    Shamelessly ripped from i2c-piix4.c:
+
+    Copyright (c) 1998, 1999  Frodo Looijaard <frodol@dds.nl> and
+    Philip Edelbrock <phil@netroedge.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/*
+    2002-04-08: Added nForce support. (Csaba Halasz)
+    2002-10-03: Fixed nForce PnP I/O port. (Michael Steil)
+    2002-12-28: Rewritten into something that resembles a Linux driver (hch)
+    2003-11-29: Added back AMD8111 removed by the previous rewrite.
+                (Philip Pokorny)
+*/
+
+/*
+   Supports AMD756, AMD766, AMD768, AMD8111 and nVidia nForce
+   Note: we assume there can only be one device, with one SMBus interface.
+*/
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/stddef.h>
+#include <linux/ioport.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/acpi.h>
+#include <linux/io.h>
+
+/* AMD756 SMBus address offsets */
+#define SMB_ADDR_OFFSET		0xE0
+#define SMB_IOSIZE		16
+#define SMB_GLOBAL_STATUS	(0x0 + amd756_ioport)
+#define SMB_GLOBAL_ENABLE	(0x2 + amd756_ioport)
+#define SMB_HOST_ADDRESS	(0x4 + amd756_ioport)
+#define SMB_HOST_DATA		(0x6 + amd756_ioport)
+#define SMB_HOST_COMMAND	(0x8 + amd756_ioport)
+#define SMB_HOST_BLOCK_DATA	(0x9 + amd756_ioport)
+#define SMB_HAS_DATA		(0xA + amd756_ioport)
+#define SMB_HAS_DEVICE_ADDRESS	(0xC + amd756_ioport)
+#define SMB_HAS_HOST_ADDRESS	(0xE + amd756_ioport)
+#define SMB_SNOOP_ADDRESS	(0xF + amd756_ioport)
+
+/* PCI Address Constants */
+
+/* address of I/O space */
+#define SMBBA		0x058		/* mh */
+#define SMBBANFORCE	0x014
+
+/* general configuration */
+#define SMBGCFG		0x041		/* mh */
+
+/* silicon revision code */
+#define SMBREV		0x008
+
+/* Other settings */
+#define MAX_TIMEOUT	500
+
+/* AMD756 constants */
+#define AMD756_QUICK		0x00
+#define AMD756_BYTE		0x01
+#define AMD756_BYTE_DATA	0x02
+#define AMD756_WORD_DATA	0x03
+#define AMD756_PROCESS_CALL	0x04
+#define AMD756_BLOCK_DATA	0x05
+
+static struct pci_driver amd756_driver;
+static unsigned short amd756_ioport;
+
+/* 
+  SMBUS event = I/O 28-29 bit 11
+     see E0 for the status bits and enabled in E2
+     
+*/
+#define GS_ABRT_STS	(1 << 0)
+#define GS_COL_STS	(1 << 1)
+#define GS_PRERR_STS	(1 << 2)
+#define GS_HST_STS	(1 << 3)
+#define GS_HCYC_STS	(1 << 4)
+#define GS_TO_STS	(1 << 5)
+#define GS_SMB_STS	(1 << 11)
+
+#define GS_CLEAR_STS	(GS_ABRT_STS | GS_COL_STS | GS_PRERR_STS | \
+			 GS_HCYC_STS | GS_TO_STS )
+
+#define GE_CYC_TYPE_MASK	(7)
+#define GE_HOST_STC		(1 << 3)
+#define GE_ABORT		(1 << 5)
+
+
+static int amd756_transaction(struct i2c_adapter *adap)
+{
+	int temp;
+	int result = 0;
+	int timeout = 0;
+
+	dev_dbg(&adap->dev, "Transaction (pre): GS=%04x, GE=%04x, ADD=%04x, "
+		"DAT=%04x\n", inw_p(SMB_GLOBAL_STATUS),
+		inw_p(SMB_GLOBAL_ENABLE), inw_p(SMB_HOST_ADDRESS),
+		inb_p(SMB_HOST_DATA));
+
+	/* Make sure the SMBus host is ready to start transmitting */
+	if ((temp = inw_p(SMB_GLOBAL_STATUS)) & (GS_HST_STS | GS_SMB_STS)) {
+		dev_dbg(&adap->dev, "SMBus busy (%04x). Waiting...\n", temp);
+		do {
+			msleep(1);
+			temp = inw_p(SMB_GLOBAL_STATUS);
+		} while ((temp & (GS_HST_STS | GS_SMB_STS)) &&
+		         (timeout++ < MAX_TIMEOUT));
+		/* If the SMBus is still busy, we give up */
+		if (timeout > MAX_TIMEOUT) {
+			dev_dbg(&adap->dev, "Busy wait timeout (%04x)\n", temp);
+			goto abort;
+		}
+		timeout = 0;
+	}
+
+	/* start the transaction by setting the start bit */
+	outw_p(inw(SMB_GLOBAL_ENABLE) | GE_HOST_STC, SMB_GLOBAL_ENABLE);
+
+	/* We will always wait for a fraction of a second! */
+	do {
+		msleep(1);
+		temp = inw_p(SMB_GLOBAL_STATUS);
+	} while ((temp & GS_HST_STS) && (timeout++ < MAX_TIMEOUT));
+
+	/* If the SMBus is still busy, we give up */
+	if (timeout > MAX_TIMEOUT) {
+		dev_dbg(&adap->dev, "Completion timeout!\n");
+		goto abort;
+	}
+
+	if (temp & GS_PRERR_STS) {
+		result = -ENXIO;
+		dev_dbg(&adap->dev, "SMBus Protocol error (no response)!\n");
+	}
+
+	if (temp & GS_COL_STS) {
+		result = -EIO;
+		dev_warn(&adap->dev, "SMBus collision!\n");
+	}
+
+	if (temp & GS_TO_STS) {
+		result = -ETIMEDOUT;
+		dev_dbg(&adap->dev, "SMBus protocol timeout!\n");
+	}
+
+	if (temp & GS_HCYC_STS)
+		dev_dbg(&adap->dev, "SMBus protocol success!\n");
+
+	outw_p(GS_CLEAR_STS, SMB_GLOBAL_STATUS);
+
+#ifdef DEBUG
+	if (((temp = inw_p(SMB_GLOBAL_STATUS)) & GS_CLEAR_STS) != 0x00) {
+		dev_dbg(&adap->dev,
+			"Failed reset at end of transaction (%04x)\n", temp);
+	}
+#endif
+
+	dev_dbg(&adap->dev,
+		"Transaction (post): GS=%04x, GE=%04x, ADD=%04x, DAT=%04x\n",
+		inw_p(SMB_GLOBAL_STATUS), inw_p(SMB_GLOBAL_ENABLE),
+		inw_p(SMB_HOST_ADDRESS), inb_p(SMB_HOST_DATA));
+
+	return result;
+
+ abort:
+	dev_warn(&adap->dev, "Sending abort\n");
+	outw_p(inw(SMB_GLOBAL_ENABLE) | GE_ABORT, SMB_GLOBAL_ENABLE);
+	msleep(100);
+	outw_p(GS_CLEAR_STS, SMB_GLOBAL_STATUS);
+	return -EIO;
+}
+
+/* Return negative errno on error. */
+static s32 amd756_access(struct i2c_adapter * adap, u16 addr,
+		  unsigned short flags, char read_write,
+		  u8 command, int size, union i2c_smbus_data * data)
+{
+	int i, len;
+	int status;
+
+	switch (size) {
+	case I2C_SMBUS_QUICK:
+		outw_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+		       SMB_HOST_ADDRESS);
+		size = AMD756_QUICK;
+		break;
+	case I2C_SMBUS_BYTE:
+		outw_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+		       SMB_HOST_ADDRESS);
+		if (read_write == I2C_SMBUS_WRITE)
+			outb_p(command, SMB_HOST_DATA);
+		size = AMD756_BYTE;
+		break;
+	case I2C_SMBUS_BYTE_DATA:
+		outw_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+		       SMB_HOST_ADDRESS);
+		outb_p(command, SMB_HOST_COMMAND);
+		if (read_write == I2C_SMBUS_WRITE)
+			outw_p(data->byte, SMB_HOST_DATA);
+		size = AMD756_BYTE_DATA;
+		break;
+	case I2C_SMBUS_WORD_DATA:
+		outw_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+		       SMB_HOST_ADDRESS);
+		outb_p(command, SMB_HOST_COMMAND);
+		if (read_write == I2C_SMBUS_WRITE)
+			outw_p(data->word, SMB_HOST_DATA);	/* TODO: endian???? */
+		size = AMD756_WORD_DATA;
+		break;
+	case I2C_SMBUS_BLOCK_DATA:
+		outw_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+		       SMB_HOST_ADDRESS);
+		outb_p(command, SMB_HOST_COMMAND);
+		if (read_write == I2C_SMBUS_WRITE) {
+			len = data->block[0];
+			if (len < 0)
+				len = 0;
+			if (len > 32)
+				len = 32;
+			outw_p(len, SMB_HOST_DATA);
+			/* i = inw_p(SMBHSTCNT); Reset SMBBLKDAT */
+			for (i = 1; i <= len; i++)
+				outb_p(data->block[i],
+				       SMB_HOST_BLOCK_DATA);
+		}
+		size = AMD756_BLOCK_DATA;
+		break;
+	default:
+		dev_warn(&adap->dev, "Unsupported transaction %d\n", size);
+		return -EOPNOTSUPP;
+	}
+
+	/* How about enabling interrupts... */
+	outw_p(size & GE_CYC_TYPE_MASK, SMB_GLOBAL_ENABLE);
+
+	status = amd756_transaction(adap);
+	if (status)
+		return status;
+
+	if ((read_write == I2C_SMBUS_WRITE) || (size == AMD756_QUICK))
+		return 0;
+
+
+	switch (size) {
+	case AMD756_BYTE:
+		data->byte = inw_p(SMB_HOST_DATA);
+		break;
+	case AMD756_BYTE_DATA:
+		data->byte = inw_p(SMB_HOST_DATA);
+		break;
+	case AMD756_WORD_DATA:
+		data->word = inw_p(SMB_HOST_DATA);	/* TODO: endian???? */
+		break;
+	case AMD756_BLOCK_DATA:
+		data->block[0] = inw_p(SMB_HOST_DATA) & 0x3f;
+		if(data->block[0] > 32)
+			data->block[0] = 32;
+		/* i = inw_p(SMBHSTCNT); Reset SMBBLKDAT */
+		for (i = 1; i <= data->block[0]; i++)
+			data->block[i] = inb_p(SMB_HOST_BLOCK_DATA);
+		break;
+	}
+
+	return 0;
+}
+
+static u32 amd756_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+	    I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+	    I2C_FUNC_SMBUS_BLOCK_DATA;
+}
+
+static const struct i2c_algorithm smbus_algorithm = {
+	.smbus_xfer	= amd756_access,
+	.functionality	= amd756_func,
+};
+
+struct i2c_adapter amd756_smbus = {
+	.owner		= THIS_MODULE,
+	.class          = I2C_CLASS_HWMON | I2C_CLASS_SPD,
+	.algo		= &smbus_algorithm,
+};
+
+enum chiptype { AMD756, AMD766, AMD768, NFORCE, AMD8111 };
+static const char* chipname[] = {
+	"AMD756", "AMD766", "AMD768",
+	"nVidia nForce", "AMD8111",
+};
+
+static DEFINE_PCI_DEVICE_TABLE(amd756_ids) = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_740B),
+	  .driver_data = AMD756 },
+	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7413),
+	  .driver_data = AMD766 },
+	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_OPUS_7443),
+	  .driver_data = AMD768 },
+	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_SMBUS),
+	  .driver_data = AMD8111 },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_SMBUS),
+	  .driver_data = NFORCE },
+	{ 0, }
+};
+
+MODULE_DEVICE_TABLE (pci, amd756_ids);
+
+static int __devinit amd756_probe(struct pci_dev *pdev,
+				  const struct pci_device_id *id)
+{
+	int nforce = (id->driver_data == NFORCE);
+	int error;
+	u8 temp;
+	
+	if (amd756_ioport) {
+		dev_err(&pdev->dev, "Only one device supported "
+		       "(you have a strange motherboard, btw)\n");
+		return -ENODEV;
+	}
+
+	if (nforce) {
+		if (PCI_FUNC(pdev->devfn) != 1)
+			return -ENODEV;
+
+		pci_read_config_word(pdev, SMBBANFORCE, &amd756_ioport);
+		amd756_ioport &= 0xfffc;
+	} else { /* amd */
+		if (PCI_FUNC(pdev->devfn) != 3)
+			return -ENODEV;
+
+		pci_read_config_byte(pdev, SMBGCFG, &temp);
+		if ((temp & 128) == 0) {
+			dev_err(&pdev->dev,
+				"Error: SMBus controller I/O not enabled!\n");
+			return -ENODEV;
+		}
+
+		/* Determine the address of the SMBus areas */
+		/* Technically it is a dword but... */
+		pci_read_config_word(pdev, SMBBA, &amd756_ioport);
+		amd756_ioport &= 0xff00;
+		amd756_ioport += SMB_ADDR_OFFSET;
+	}
+
+	error = acpi_check_region(amd756_ioport, SMB_IOSIZE,
+				  amd756_driver.name);
+	if (error)
+		return -ENODEV;
+
+	if (!request_region(amd756_ioport, SMB_IOSIZE, amd756_driver.name)) {
+		dev_err(&pdev->dev, "SMB region 0x%x already in use!\n",
+			amd756_ioport);
+		return -ENODEV;
+	}
+
+	pci_read_config_byte(pdev, SMBREV, &temp);
+	dev_dbg(&pdev->dev, "SMBREV = 0x%X\n", temp);
+	dev_dbg(&pdev->dev, "AMD756_smba = 0x%X\n", amd756_ioport);
+
+	/* set up the sysfs linkage to our parent device */
+	amd756_smbus.dev.parent = &pdev->dev;
+
+	snprintf(amd756_smbus.name, sizeof(amd756_smbus.name),
+		 "SMBus %s adapter at %04x", chipname[id->driver_data],
+		 amd756_ioport);
+
+	error = i2c_add_adapter(&amd756_smbus);
+	if (error) {
+		dev_err(&pdev->dev,
+			"Adapter registration failed, module not inserted\n");
+		goto out_err;
+	}
+
+	return 0;
+
+ out_err:
+	release_region(amd756_ioport, SMB_IOSIZE);
+	return error;
+}
+
+static void __devexit amd756_remove(struct pci_dev *dev)
+{
+	i2c_del_adapter(&amd756_smbus);
+	release_region(amd756_ioport, SMB_IOSIZE);
+}
+
+static struct pci_driver amd756_driver = {
+	.name		= "amd756_smbus",
+	.id_table	= amd756_ids,
+	.probe		= amd756_probe,
+	.remove		= __devexit_p(amd756_remove),
+};
+
+static int __init amd756_init(void)
+{
+	return pci_register_driver(&amd756_driver);
+}
+
+static void __exit amd756_exit(void)
+{
+	pci_unregister_driver(&amd756_driver);
+}
+
+MODULE_AUTHOR("Merlin Hughes <merlin@merlin.org>");
+MODULE_DESCRIPTION("AMD756/766/768/8111 and nVidia nForce SMBus driver");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(amd756_smbus);
+
+module_init(amd756_init)
+module_exit(amd756_exit)
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-amd8111.c b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-amd8111.c
new file mode 100644
index 0000000..e5ac53b
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-amd8111.c
@@ -0,0 +1,505 @@
+/*
+ * SMBus 2.0 driver for AMD-8111 IO-Hub.
+ *
+ * Copyright (c) 2002 Vojtech Pavlik
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2.
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/stddef.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/acpi.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR ("Vojtech Pavlik <vojtech@suse.cz>");
+MODULE_DESCRIPTION("AMD8111 SMBus 2.0 driver");
+
+struct amd_smbus {
+	struct pci_dev *dev;
+	struct i2c_adapter adapter;
+	int base;
+	int size;
+};
+
+static struct pci_driver amd8111_driver;
+
+/*
+ * AMD PCI control registers definitions.
+ */
+
+#define AMD_PCI_MISC	0x48
+
+#define AMD_PCI_MISC_SCI	0x04	/* deliver SCI */
+#define AMD_PCI_MISC_INT	0x02	/* deliver PCI IRQ */
+#define AMD_PCI_MISC_SPEEDUP	0x01	/* 16x clock speedup */
+
+/*
+ * ACPI 2.0 chapter 13 PCI interface definitions.
+ */
+
+#define AMD_EC_DATA	0x00	/* data register */
+#define AMD_EC_SC	0x04	/* status of controller */
+#define AMD_EC_CMD	0x04	/* command register */
+#define AMD_EC_ICR	0x08	/* interrupt control register */
+
+#define AMD_EC_SC_SMI	0x04	/* smi event pending */
+#define AMD_EC_SC_SCI	0x02	/* sci event pending */
+#define AMD_EC_SC_BURST	0x01	/* burst mode enabled */
+#define AMD_EC_SC_CMD	0x08	/* byte in data reg is command */
+#define AMD_EC_SC_IBF	0x02	/* data ready for embedded controller */
+#define AMD_EC_SC_OBF	0x01	/* data ready for host */
+
+#define AMD_EC_CMD_RD	0x80	/* read EC */
+#define AMD_EC_CMD_WR	0x81	/* write EC */
+#define AMD_EC_CMD_BE	0x82	/* enable burst mode */
+#define AMD_EC_CMD_BD	0x83	/* disable burst mode */
+#define AMD_EC_CMD_QR	0x84	/* query EC */
+
+/*
+ * ACPI 2.0 chapter 13 access of registers of the EC
+ */
+
+static int amd_ec_wait_write(struct amd_smbus *smbus)
+{
+	int timeout = 500;
+
+	while ((inb(smbus->base + AMD_EC_SC) & AMD_EC_SC_IBF) && --timeout)
+		udelay(1);
+
+	if (!timeout) {
+		dev_warn(&smbus->dev->dev,
+			 "Timeout while waiting for IBF to clear\n");
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+static int amd_ec_wait_read(struct amd_smbus *smbus)
+{
+	int timeout = 500;
+
+	while ((~inb(smbus->base + AMD_EC_SC) & AMD_EC_SC_OBF) && --timeout)
+		udelay(1);
+
+	if (!timeout) {
+		dev_warn(&smbus->dev->dev,
+			 "Timeout while waiting for OBF to set\n");
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+static int amd_ec_read(struct amd_smbus *smbus, unsigned char address,
+		unsigned char *data)
+{
+	int status;
+
+	status = amd_ec_wait_write(smbus);
+	if (status)
+		return status;
+	outb(AMD_EC_CMD_RD, smbus->base + AMD_EC_CMD);
+
+	status = amd_ec_wait_write(smbus);
+	if (status)
+		return status;
+	outb(address, smbus->base + AMD_EC_DATA);
+
+	status = amd_ec_wait_read(smbus);
+	if (status)
+		return status;
+	*data = inb(smbus->base + AMD_EC_DATA);
+
+	return 0;
+}
+
+static int amd_ec_write(struct amd_smbus *smbus, unsigned char address,
+		unsigned char data)
+{
+	int status;
+
+	status = amd_ec_wait_write(smbus);
+	if (status)
+		return status;
+	outb(AMD_EC_CMD_WR, smbus->base + AMD_EC_CMD);
+
+	status = amd_ec_wait_write(smbus);
+	if (status)
+		return status;
+	outb(address, smbus->base + AMD_EC_DATA);
+
+	status = amd_ec_wait_write(smbus);
+	if (status)
+		return status;
+	outb(data, smbus->base + AMD_EC_DATA);
+
+	return 0;
+}
+
+/*
+ * ACPI 2.0 chapter 13 SMBus 2.0 EC register model
+ */
+
+#define AMD_SMB_PRTCL	0x00	/* protocol, PEC */
+#define AMD_SMB_STS	0x01	/* status */
+#define AMD_SMB_ADDR	0x02	/* address */
+#define AMD_SMB_CMD	0x03	/* command */
+#define AMD_SMB_DATA	0x04	/* 32 data registers */
+#define AMD_SMB_BCNT	0x24	/* number of data bytes */
+#define AMD_SMB_ALRM_A	0x25	/* alarm address */
+#define AMD_SMB_ALRM_D	0x26	/* 2 bytes alarm data */
+
+#define AMD_SMB_STS_DONE	0x80
+#define AMD_SMB_STS_ALRM	0x40
+#define AMD_SMB_STS_RES		0x20
+#define AMD_SMB_STS_STATUS	0x1f
+
+#define AMD_SMB_STATUS_OK	0x00
+#define AMD_SMB_STATUS_FAIL	0x07
+#define AMD_SMB_STATUS_DNAK	0x10
+#define AMD_SMB_STATUS_DERR	0x11
+#define AMD_SMB_STATUS_CMD_DENY	0x12
+#define AMD_SMB_STATUS_UNKNOWN	0x13
+#define AMD_SMB_STATUS_ACC_DENY	0x17
+#define AMD_SMB_STATUS_TIMEOUT	0x18
+#define AMD_SMB_STATUS_NOTSUP	0x19
+#define AMD_SMB_STATUS_BUSY	0x1A
+#define AMD_SMB_STATUS_PEC	0x1F
+
+#define AMD_SMB_PRTCL_WRITE		0x00
+#define AMD_SMB_PRTCL_READ		0x01
+#define AMD_SMB_PRTCL_QUICK		0x02
+#define AMD_SMB_PRTCL_BYTE		0x04
+#define AMD_SMB_PRTCL_BYTE_DATA		0x06
+#define AMD_SMB_PRTCL_WORD_DATA		0x08
+#define AMD_SMB_PRTCL_BLOCK_DATA	0x0a
+#define AMD_SMB_PRTCL_PROC_CALL		0x0c
+#define AMD_SMB_PRTCL_BLOCK_PROC_CALL	0x0d
+#define AMD_SMB_PRTCL_I2C_BLOCK_DATA	0x4a
+#define AMD_SMB_PRTCL_PEC		0x80
+
+
+static s32 amd8111_access(struct i2c_adapter * adap, u16 addr,
+		unsigned short flags, char read_write, u8 command, int size,
+		union i2c_smbus_data * data)
+{
+	struct amd_smbus *smbus = adap->algo_data;
+	unsigned char protocol, len, pec, temp[2];
+	int i, status;
+
+	protocol = (read_write == I2C_SMBUS_READ) ? AMD_SMB_PRTCL_READ
+						  : AMD_SMB_PRTCL_WRITE;
+	pec = (flags & I2C_CLIENT_PEC) ? AMD_SMB_PRTCL_PEC : 0;
+
+	switch (size) {
+		case I2C_SMBUS_QUICK:
+			protocol |= AMD_SMB_PRTCL_QUICK;
+			read_write = I2C_SMBUS_WRITE;
+			break;
+
+		case I2C_SMBUS_BYTE:
+			if (read_write == I2C_SMBUS_WRITE) {
+				status = amd_ec_write(smbus, AMD_SMB_CMD,
+						      command);
+				if (status)
+					return status;
+			}
+			protocol |= AMD_SMB_PRTCL_BYTE;
+			break;
+
+		case I2C_SMBUS_BYTE_DATA:
+			status = amd_ec_write(smbus, AMD_SMB_CMD, command);
+			if (status)
+				return status;
+			if (read_write == I2C_SMBUS_WRITE) {
+				status = amd_ec_write(smbus, AMD_SMB_DATA,
+						      data->byte);
+				if (status)
+					return status;
+			}
+			protocol |= AMD_SMB_PRTCL_BYTE_DATA;
+			break;
+
+		case I2C_SMBUS_WORD_DATA:
+			status = amd_ec_write(smbus, AMD_SMB_CMD, command);
+			if (status)
+				return status;
+			if (read_write == I2C_SMBUS_WRITE) {
+				status = amd_ec_write(smbus, AMD_SMB_DATA,
+						      data->word & 0xff);
+				if (status)
+					return status;
+				status = amd_ec_write(smbus, AMD_SMB_DATA + 1,
+						      data->word >> 8);
+				if (status)
+					return status;
+			}
+			protocol |= AMD_SMB_PRTCL_WORD_DATA | pec;
+			break;
+
+		case I2C_SMBUS_BLOCK_DATA:
+			status = amd_ec_write(smbus, AMD_SMB_CMD, command);
+			if (status)
+				return status;
+			if (read_write == I2C_SMBUS_WRITE) {
+				len = min_t(u8, data->block[0],
+					    I2C_SMBUS_BLOCK_MAX);
+				status = amd_ec_write(smbus, AMD_SMB_BCNT, len);
+				if (status)
+					return status;
+				for (i = 0; i < len; i++) {
+					status =
+					  amd_ec_write(smbus, AMD_SMB_DATA + i,
+						       data->block[i + 1]);
+					if (status)
+						return status;
+				}
+			}
+			protocol |= AMD_SMB_PRTCL_BLOCK_DATA | pec;
+			break;
+
+		case I2C_SMBUS_I2C_BLOCK_DATA:
+			len = min_t(u8, data->block[0],
+				    I2C_SMBUS_BLOCK_MAX);
+			status = amd_ec_write(smbus, AMD_SMB_CMD, command);
+			if (status)
+				return status;
+			status = amd_ec_write(smbus, AMD_SMB_BCNT, len);
+			if (status)
+				return status;
+			if (read_write == I2C_SMBUS_WRITE)
+				for (i = 0; i < len; i++) {
+					status =
+					  amd_ec_write(smbus, AMD_SMB_DATA + i,
+						       data->block[i + 1]);
+					if (status)
+						return status;
+				}
+			protocol |= AMD_SMB_PRTCL_I2C_BLOCK_DATA;
+			break;
+
+		case I2C_SMBUS_PROC_CALL:
+			status = amd_ec_write(smbus, AMD_SMB_CMD, command);
+			if (status)
+				return status;
+			status = amd_ec_write(smbus, AMD_SMB_DATA,
+					      data->word & 0xff);
+			if (status)
+				return status;
+			status = amd_ec_write(smbus, AMD_SMB_DATA + 1,
+					      data->word >> 8);
+			if (status)
+				return status;
+			protocol = AMD_SMB_PRTCL_PROC_CALL | pec;
+			read_write = I2C_SMBUS_READ;
+			break;
+
+		case I2C_SMBUS_BLOCK_PROC_CALL:
+			len = min_t(u8, data->block[0],
+				    I2C_SMBUS_BLOCK_MAX - 1);
+			status = amd_ec_write(smbus, AMD_SMB_CMD, command);
+			if (status)
+				return status;
+			status = amd_ec_write(smbus, AMD_SMB_BCNT, len);
+			if (status)
+				return status;
+			for (i = 0; i < len; i++) {
+				status = amd_ec_write(smbus, AMD_SMB_DATA + i,
+						      data->block[i + 1]);
+				if (status)
+					return status;
+			}
+			protocol = AMD_SMB_PRTCL_BLOCK_PROC_CALL | pec;
+			read_write = I2C_SMBUS_READ;
+			break;
+
+		default:
+			dev_warn(&adap->dev, "Unsupported transaction %d\n", size);
+			return -EOPNOTSUPP;
+	}
+
+	status = amd_ec_write(smbus, AMD_SMB_ADDR, addr << 1);
+	if (status)
+		return status;
+	status = amd_ec_write(smbus, AMD_SMB_PRTCL, protocol);
+	if (status)
+		return status;
+
+	status = amd_ec_read(smbus, AMD_SMB_STS, temp + 0);
+	if (status)
+		return status;
+
+	if (~temp[0] & AMD_SMB_STS_DONE) {
+		udelay(500);
+		status = amd_ec_read(smbus, AMD_SMB_STS, temp + 0);
+		if (status)
+			return status;
+	}
+
+	if (~temp[0] & AMD_SMB_STS_DONE) {
+		msleep(1);
+		status = amd_ec_read(smbus, AMD_SMB_STS, temp + 0);
+		if (status)
+			return status;
+	}
+
+	if ((~temp[0] & AMD_SMB_STS_DONE) || (temp[0] & AMD_SMB_STS_STATUS))
+		return -EIO;
+
+	if (read_write == I2C_SMBUS_WRITE)
+		return 0;
+
+	switch (size) {
+		case I2C_SMBUS_BYTE:
+		case I2C_SMBUS_BYTE_DATA:
+			status = amd_ec_read(smbus, AMD_SMB_DATA, &data->byte);
+			if (status)
+				return status;
+			break;
+
+		case I2C_SMBUS_WORD_DATA:
+		case I2C_SMBUS_PROC_CALL:
+			status = amd_ec_read(smbus, AMD_SMB_DATA, temp + 0);
+			if (status)
+				return status;
+			status = amd_ec_read(smbus, AMD_SMB_DATA + 1, temp + 1);
+			if (status)
+				return status;
+			data->word = (temp[1] << 8) | temp[0];
+			break;
+
+		case I2C_SMBUS_BLOCK_DATA:
+		case I2C_SMBUS_BLOCK_PROC_CALL:
+			status = amd_ec_read(smbus, AMD_SMB_BCNT, &len);
+			if (status)
+				return status;
+			len = min_t(u8, len, I2C_SMBUS_BLOCK_MAX);
+		case I2C_SMBUS_I2C_BLOCK_DATA:
+			for (i = 0; i < len; i++) {
+				status = amd_ec_read(smbus, AMD_SMB_DATA + i,
+						     data->block + i + 1);
+				if (status)
+					return status;
+			}
+			data->block[0] = len;
+			break;
+	}
+
+	return 0;
+}
+
+
+static u32 amd8111_func(struct i2c_adapter *adapter)
+{
+	return	I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+		I2C_FUNC_SMBUS_BYTE_DATA |
+		I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BLOCK_DATA |
+		I2C_FUNC_SMBUS_PROC_CALL | I2C_FUNC_SMBUS_BLOCK_PROC_CALL |
+		I2C_FUNC_SMBUS_I2C_BLOCK | I2C_FUNC_SMBUS_PEC;
+}
+
+static const struct i2c_algorithm smbus_algorithm = {
+	.smbus_xfer = amd8111_access,
+	.functionality = amd8111_func,
+};
+
+
+static DEFINE_PCI_DEVICE_TABLE(amd8111_ids) = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_SMBUS2) },
+	{ 0, }
+};
+
+MODULE_DEVICE_TABLE (pci, amd8111_ids);
+
+static int __devinit amd8111_probe(struct pci_dev *dev,
+		const struct pci_device_id *id)
+{
+	struct amd_smbus *smbus;
+	int error;
+
+	if (!(pci_resource_flags(dev, 0) & IORESOURCE_IO))
+		return -ENODEV;
+
+	smbus = kzalloc(sizeof(struct amd_smbus), GFP_KERNEL);
+	if (!smbus)
+		return -ENOMEM;
+
+	smbus->dev = dev;
+	smbus->base = pci_resource_start(dev, 0);
+	smbus->size = pci_resource_len(dev, 0);
+
+	error = acpi_check_resource_conflict(&dev->resource[0]);
+	if (error) {
+		error = -ENODEV;
+		goto out_kfree;
+	}
+
+	if (!request_region(smbus->base, smbus->size, amd8111_driver.name)) {
+		error = -EBUSY;
+		goto out_kfree;
+	}
+
+	smbus->adapter.owner = THIS_MODULE;
+	snprintf(smbus->adapter.name, sizeof(smbus->adapter.name),
+		"SMBus2 AMD8111 adapter at %04x", smbus->base);
+	smbus->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
+	smbus->adapter.algo = &smbus_algorithm;
+	smbus->adapter.algo_data = smbus;
+
+	/* set up the sysfs linkage to our parent device */
+	smbus->adapter.dev.parent = &dev->dev;
+
+	pci_write_config_dword(smbus->dev, AMD_PCI_MISC, 0);
+	error = i2c_add_adapter(&smbus->adapter);
+	if (error)
+		goto out_release_region;
+
+	pci_set_drvdata(dev, smbus);
+	return 0;
+
+ out_release_region:
+	release_region(smbus->base, smbus->size);
+ out_kfree:
+	kfree(smbus);
+	return error;
+}
+
+static void __devexit amd8111_remove(struct pci_dev *dev)
+{
+	struct amd_smbus *smbus = pci_get_drvdata(dev);
+
+	i2c_del_adapter(&smbus->adapter);
+	release_region(smbus->base, smbus->size);
+	kfree(smbus);
+}
+
+static struct pci_driver amd8111_driver = {
+	.name		= "amd8111_smbus2",
+	.id_table	= amd8111_ids,
+	.probe		= amd8111_probe,
+	.remove		= __devexit_p(amd8111_remove),
+};
+
+static int __init i2c_amd8111_init(void)
+{
+	return pci_register_driver(&amd8111_driver);
+}
+
+static void __exit i2c_amd8111_exit(void)
+{
+	pci_unregister_driver(&amd8111_driver);
+}
+
+module_init(i2c_amd8111_init);
+module_exit(i2c_amd8111_exit);
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-at91.c b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-at91.c
new file mode 100644
index 0000000..1679dee
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-at91.c
@@ -0,0 +1,314 @@
+/*
+    i2c Support for Atmel's AT91 Two-Wire Interface (TWI)
+
+    Copyright (C) 2004 Rick Bronson
+    Converted to 2.6 by Andrew Victor <andrew@sanpeople.com>
+
+    Borrowed heavily from original work by:
+    Copyright (C) 2000 Philip Edelbrock <phil@stimpy.netroedge.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+*/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+#include <mach/at91_twi.h>
+#include <mach/board.h>
+#include <mach/cpu.h>
+
+#define TWI_CLOCK		100000		/* Hz. max 400 Kbits/sec */
+
+
+static struct clk *twi_clk;
+static void __iomem *twi_base;
+
+#define at91_twi_read(reg)		__raw_readl(twi_base + (reg))
+#define at91_twi_write(reg, val)	__raw_writel((val), twi_base + (reg))
+
+
+/*
+ * Initialize the TWI hardware registers.
+ */
+static void __devinit at91_twi_hwinit(void)
+{
+	unsigned long cdiv, ckdiv;
+
+	at91_twi_write(AT91_TWI_IDR, 0xffffffff);	/* Disable all interrupts */
+	at91_twi_write(AT91_TWI_CR, AT91_TWI_SWRST);	/* Reset peripheral */
+	at91_twi_write(AT91_TWI_CR, AT91_TWI_MSEN);	/* Set Master mode */
+
+	/* Calcuate clock dividers */
+	cdiv = (clk_get_rate(twi_clk) / (2 * TWI_CLOCK)) - 3;
+	cdiv = cdiv + 1;	/* round up */
+	ckdiv = 0;
+	while (cdiv > 255) {
+		ckdiv++;
+		cdiv = cdiv >> 1;
+	}
+
+	if (cpu_is_at91rm9200()) {			/* AT91RM9200 Errata #22 */
+		if (ckdiv > 5) {
+			printk(KERN_ERR "AT91 I2C: Invalid TWI_CLOCK value!\n");
+			ckdiv = 5;
+		}
+	}
+
+	at91_twi_write(AT91_TWI_CWGR, (ckdiv << 16) | (cdiv << 8) | cdiv);
+}
+
+/*
+ * Poll the i2c status register until the specified bit is set.
+ * Returns 0 if timed out (100 msec).
+ */
+static short at91_poll_status(unsigned long bit)
+{
+	int loop_cntr = 10000;
+
+	do {
+		udelay(10);
+	} while (!(at91_twi_read(AT91_TWI_SR) & bit) && (--loop_cntr > 0));
+
+	return (loop_cntr > 0);
+}
+
+static int xfer_read(struct i2c_adapter *adap, unsigned char *buf, int length)
+{
+	/* Send Start */
+	at91_twi_write(AT91_TWI_CR, AT91_TWI_START);
+
+	/* Read data */
+	while (length--) {
+		if (!length)	/* need to send Stop before reading last byte */
+			at91_twi_write(AT91_TWI_CR, AT91_TWI_STOP);
+		if (!at91_poll_status(AT91_TWI_RXRDY)) {
+			dev_dbg(&adap->dev, "RXRDY timeout\n");
+			return -ETIMEDOUT;
+		}
+		*buf++ = (at91_twi_read(AT91_TWI_RHR) & 0xff);
+	}
+
+	return 0;
+}
+
+static int xfer_write(struct i2c_adapter *adap, unsigned char *buf, int length)
+{
+	/* Load first byte into transmitter */
+	at91_twi_write(AT91_TWI_THR, *buf++);
+
+	/* Send Start */
+	at91_twi_write(AT91_TWI_CR, AT91_TWI_START);
+
+	do {
+		if (!at91_poll_status(AT91_TWI_TXRDY)) {
+			dev_dbg(&adap->dev, "TXRDY timeout\n");
+			return -ETIMEDOUT;
+		}
+
+		length--;	/* byte was transmitted */
+
+		if (length > 0)		/* more data to send? */
+			at91_twi_write(AT91_TWI_THR, *buf++);
+	} while (length);
+
+	/* Send Stop */
+	at91_twi_write(AT91_TWI_CR, AT91_TWI_STOP);
+
+	return 0;
+}
+
+/*
+ * Generic i2c master transfer entrypoint.
+ *
+ * Note: We do not use Atmel's feature of storing the "internal device address".
+ * Instead the "internal device address" has to be written using a separate
+ * i2c message.
+ * http://lists.arm.linux.org.uk/pipermail/linux-arm-kernel/2004-September/024411.html
+ */
+static int at91_xfer(struct i2c_adapter *adap, struct i2c_msg *pmsg, int num)
+{
+	int i, ret;
+
+	dev_dbg(&adap->dev, "at91_xfer: processing %d messages:\n", num);
+
+	for (i = 0; i < num; i++) {
+		dev_dbg(&adap->dev, " #%d: %sing %d byte%s %s 0x%02x\n", i,
+			pmsg->flags & I2C_M_RD ? "read" : "writ",
+			pmsg->len, pmsg->len > 1 ? "s" : "",
+			pmsg->flags & I2C_M_RD ? "from" : "to",	pmsg->addr);
+
+		at91_twi_write(AT91_TWI_MMR, (pmsg->addr << 16)
+			| ((pmsg->flags & I2C_M_RD) ? AT91_TWI_MREAD : 0));
+
+		if (pmsg->len && pmsg->buf) {	/* sanity check */
+			if (pmsg->flags & I2C_M_RD)
+				ret = xfer_read(adap, pmsg->buf, pmsg->len);
+			else
+				ret = xfer_write(adap, pmsg->buf, pmsg->len);
+
+			if (ret)
+				return ret;
+
+			/* Wait until transfer is finished */
+			if (!at91_poll_status(AT91_TWI_TXCOMP)) {
+				dev_dbg(&adap->dev, "TXCOMP timeout\n");
+				return -ETIMEDOUT;
+			}
+		}
+		dev_dbg(&adap->dev, "transfer complete\n");
+		pmsg++;		/* next message */
+	}
+	return i;
+}
+
+/*
+ * Return list of supported functionality.
+ */
+static u32 at91_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static struct i2c_algorithm at91_algorithm = {
+	.master_xfer	= at91_xfer,
+	.functionality	= at91_func,
+};
+
+/*
+ * Main initialization routine.
+ */
+static int __devinit at91_i2c_probe(struct platform_device *pdev)
+{
+	struct i2c_adapter *adapter;
+	struct resource *res;
+	int rc;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENXIO;
+
+	if (!request_mem_region(res->start, resource_size(res), "at91_i2c"))
+		return -EBUSY;
+
+	twi_base = ioremap(res->start, resource_size(res));
+	if (!twi_base) {
+		rc = -ENOMEM;
+		goto fail0;
+	}
+
+	twi_clk = clk_get(NULL, "twi_clk");
+	if (IS_ERR(twi_clk)) {
+		dev_err(&pdev->dev, "no clock defined\n");
+		rc = -ENODEV;
+		goto fail1;
+	}
+
+	adapter = kzalloc(sizeof(struct i2c_adapter), GFP_KERNEL);
+	if (adapter == NULL) {
+		dev_err(&pdev->dev, "can't allocate inteface!\n");
+		rc = -ENOMEM;
+		goto fail2;
+	}
+	snprintf(adapter->name, sizeof(adapter->name), "AT91");
+	adapter->algo = &at91_algorithm;
+	adapter->class = I2C_CLASS_HWMON;
+	adapter->dev.parent = &pdev->dev;
+	/* adapter->id == 0 ... only one TWI controller for now */
+
+	platform_set_drvdata(pdev, adapter);
+
+	clk_enable(twi_clk);		/* enable peripheral clock */
+	at91_twi_hwinit();		/* initialize TWI controller */
+
+	rc = i2c_add_numbered_adapter(adapter);
+	if (rc) {
+		dev_err(&pdev->dev, "Adapter %s registration failed\n",
+				adapter->name);
+		goto fail3;
+	}
+
+	dev_info(&pdev->dev, "AT91 i2c bus driver.\n");
+	return 0;
+
+fail3:
+	platform_set_drvdata(pdev, NULL);
+	kfree(adapter);
+	clk_disable(twi_clk);
+fail2:
+	clk_put(twi_clk);
+fail1:
+	iounmap(twi_base);
+fail0:
+	release_mem_region(res->start, resource_size(res));
+
+	return rc;
+}
+
+static int __devexit at91_i2c_remove(struct platform_device *pdev)
+{
+	struct i2c_adapter *adapter = platform_get_drvdata(pdev);
+	struct resource *res;
+	int rc;
+
+	rc = i2c_del_adapter(adapter);
+	platform_set_drvdata(pdev, NULL);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	iounmap(twi_base);
+	release_mem_region(res->start, resource_size(res));
+
+	clk_disable(twi_clk);		/* disable peripheral clock */
+	clk_put(twi_clk);
+
+	return rc;
+}
+
+#ifdef CONFIG_PM
+
+/* NOTE: could save a few mA by keeping clock off outside of at91_xfer... */
+
+static int at91_i2c_suspend(struct platform_device *pdev, pm_message_t mesg)
+{
+	clk_disable(twi_clk);
+	return 0;
+}
+
+static int at91_i2c_resume(struct platform_device *pdev)
+{
+	return clk_enable(twi_clk);
+}
+
+#else
+#define at91_i2c_suspend	NULL
+#define at91_i2c_resume		NULL
+#endif
+
+static struct platform_driver at91_i2c_driver = {
+	.probe		= at91_i2c_probe,
+	.remove		= __devexit_p(at91_i2c_remove),
+	.suspend	= at91_i2c_suspend,
+	.resume		= at91_i2c_resume,
+	.driver		= {
+		.name	= "at91_i2c",
+		.owner	= THIS_MODULE,
+	},
+};
+
+module_platform_driver(at91_i2c_driver);
+
+MODULE_AUTHOR("Rick Bronson");
+MODULE_DESCRIPTION("I2C (TWI) driver for Atmel AT91");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:at91_i2c");
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-au1550.c b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-au1550.c
new file mode 100644
index 0000000..582d616
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-au1550.c
@@ -0,0 +1,434 @@
+/*
+ * i2c-au1550.c: SMBus (i2c) adapter for Alchemy PSC interface
+ * Copyright (C) 2004 Embedded Edge, LLC <dan@embeddededge.com>
+ *
+ * 2.6 port by Matt Porter <mporter@kernel.crashing.org>
+ *
+ * The documentation describes this as an SMBus controller, but it doesn't
+ * understand any of the SMBus protocol in hardware.  It's really an I2C
+ * controller that could emulate most of the SMBus in software.
+ *
+ * This is just a skeleton adapter to use with the Au1550 PSC
+ * algorithm.  It was developed for the Pb1550, but will work with
+ * any Au1550 board that has a similar PSC configuration.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+
+#include <asm/mach-au1x00/au1000.h>
+#include <asm/mach-au1x00/au1xxx_psc.h>
+
+#define PSC_SEL		0x00
+#define PSC_CTRL	0x04
+#define PSC_SMBCFG	0x08
+#define PSC_SMBMSK	0x0C
+#define PSC_SMBPCR	0x10
+#define PSC_SMBSTAT	0x14
+#define PSC_SMBEVNT	0x18
+#define PSC_SMBTXRX	0x1C
+#define PSC_SMBTMR	0x20
+
+struct i2c_au1550_data {
+	void __iomem *psc_base;
+	int	xfer_timeout;
+	struct i2c_adapter adap;
+	struct resource *ioarea;
+};
+
+static inline void WR(struct i2c_au1550_data *a, int r, unsigned long v)
+{
+	__raw_writel(v, a->psc_base + r);
+	wmb();
+}
+
+static inline unsigned long RD(struct i2c_au1550_data *a, int r)
+{
+	return __raw_readl(a->psc_base + r);
+}
+
+static int wait_xfer_done(struct i2c_au1550_data *adap)
+{
+	int i;
+
+	/* Wait for Tx Buffer Empty */
+	for (i = 0; i < adap->xfer_timeout; i++) {
+		if (RD(adap, PSC_SMBSTAT) & PSC_SMBSTAT_TE)
+			return 0;
+
+		udelay(1);
+	}
+
+	return -ETIMEDOUT;
+}
+
+static int wait_ack(struct i2c_au1550_data *adap)
+{
+	unsigned long stat;
+
+	if (wait_xfer_done(adap))
+		return -ETIMEDOUT;
+
+	stat = RD(adap, PSC_SMBEVNT);
+	if ((stat & (PSC_SMBEVNT_DN | PSC_SMBEVNT_AN | PSC_SMBEVNT_AL)) != 0)
+		return -ETIMEDOUT;
+
+	return 0;
+}
+
+static int wait_master_done(struct i2c_au1550_data *adap)
+{
+	int i;
+
+	/* Wait for Master Done. */
+	for (i = 0; i < 2 * adap->xfer_timeout; i++) {
+		if ((RD(adap, PSC_SMBEVNT) & PSC_SMBEVNT_MD) != 0)
+			return 0;
+		udelay(1);
+	}
+
+	return -ETIMEDOUT;
+}
+
+static int
+do_address(struct i2c_au1550_data *adap, unsigned int addr, int rd, int q)
+{
+	unsigned long stat;
+
+	/* Reset the FIFOs, clear events. */
+	stat = RD(adap, PSC_SMBSTAT);
+	WR(adap, PSC_SMBEVNT, PSC_SMBEVNT_ALLCLR);
+
+	if (!(stat & PSC_SMBSTAT_TE) || !(stat & PSC_SMBSTAT_RE)) {
+		WR(adap, PSC_SMBPCR, PSC_SMBPCR_DC);
+		while ((RD(adap, PSC_SMBPCR) & PSC_SMBPCR_DC) != 0)
+			cpu_relax();
+		udelay(50);
+	}
+
+	/* Write out the i2c chip address and specify operation */
+	addr <<= 1;
+	if (rd)
+		addr |= 1;
+
+	/* zero-byte xfers stop immediately */
+	if (q)
+		addr |= PSC_SMBTXRX_STP;
+
+	/* Put byte into fifo, start up master. */
+	WR(adap, PSC_SMBTXRX, addr);
+	WR(adap, PSC_SMBPCR, PSC_SMBPCR_MS);
+	if (wait_ack(adap))
+		return -EIO;
+	return (q) ? wait_master_done(adap) : 0;
+}
+
+static int wait_for_rx_byte(struct i2c_au1550_data *adap, unsigned char *out)
+{
+	int j;
+
+	if (wait_xfer_done(adap))
+		return -EIO;
+
+	j =  adap->xfer_timeout * 100;
+	do {
+		j--;
+		if (j <= 0)
+			return -EIO;
+
+		if ((RD(adap, PSC_SMBSTAT) & PSC_SMBSTAT_RE) == 0)
+			j = 0;
+		else
+			udelay(1);
+	} while (j > 0);
+
+	*out = RD(adap, PSC_SMBTXRX);
+
+	return 0;
+}
+
+static int i2c_read(struct i2c_au1550_data *adap, unsigned char *buf,
+		    unsigned int len)
+{
+	int i;
+
+	if (len == 0)
+		return 0;
+
+	/* A read is performed by stuffing the transmit fifo with
+	 * zero bytes for timing, waiting for bytes to appear in the
+	 * receive fifo, then reading the bytes.
+	 */
+	i = 0;
+	while (i < (len - 1)) {
+		WR(adap, PSC_SMBTXRX, 0);
+		if (wait_for_rx_byte(adap, &buf[i]))
+			return -EIO;
+
+		i++;
+	}
+
+	/* The last byte has to indicate transfer done. */
+	WR(adap, PSC_SMBTXRX, PSC_SMBTXRX_STP);
+	if (wait_master_done(adap))
+		return -EIO;
+
+	buf[i] = (unsigned char)(RD(adap, PSC_SMBTXRX) & 0xff);
+	return 0;
+}
+
+static int i2c_write(struct i2c_au1550_data *adap, unsigned char *buf,
+		     unsigned int len)
+{
+	int i;
+	unsigned long data;
+
+	if (len == 0)
+		return 0;
+
+	i = 0;
+	while (i < (len-1)) {
+		data = buf[i];
+		WR(adap, PSC_SMBTXRX, data);
+		if (wait_ack(adap))
+			return -EIO;
+		i++;
+	}
+
+	/* The last byte has to indicate transfer done. */
+	data = buf[i];
+	data |= PSC_SMBTXRX_STP;
+	WR(adap, PSC_SMBTXRX, data);
+	if (wait_master_done(adap))
+		return -EIO;
+	return 0;
+}
+
+static int
+au1550_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num)
+{
+	struct i2c_au1550_data *adap = i2c_adap->algo_data;
+	struct i2c_msg *p;
+	int i, err = 0;
+
+	WR(adap, PSC_CTRL, PSC_CTRL_ENABLE);
+
+	for (i = 0; !err && i < num; i++) {
+		p = &msgs[i];
+		err = do_address(adap, p->addr, p->flags & I2C_M_RD,
+				 (p->len == 0));
+		if (err || !p->len)
+			continue;
+		if (p->flags & I2C_M_RD)
+			err = i2c_read(adap, p->buf, p->len);
+		else
+			err = i2c_write(adap, p->buf, p->len);
+	}
+
+	/* Return the number of messages processed, or the error code.
+	*/
+	if (err == 0)
+		err = num;
+
+	WR(adap, PSC_CTRL, PSC_CTRL_SUSPEND);
+
+	return err;
+}
+
+static u32 au1550_func(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm au1550_algo = {
+	.master_xfer	= au1550_xfer,
+	.functionality	= au1550_func,
+};
+
+static void i2c_au1550_setup(struct i2c_au1550_data *priv)
+{
+	unsigned long cfg;
+
+	WR(priv, PSC_CTRL, PSC_CTRL_DISABLE);
+	WR(priv, PSC_SEL, PSC_SEL_PS_SMBUSMODE);
+	WR(priv, PSC_SMBCFG, 0);
+	WR(priv, PSC_CTRL, PSC_CTRL_ENABLE);
+	while ((RD(priv, PSC_SMBSTAT) & PSC_SMBSTAT_SR) == 0)
+		cpu_relax();
+
+	cfg = PSC_SMBCFG_RT_FIFO8 | PSC_SMBCFG_TT_FIFO8 | PSC_SMBCFG_DD_DISABLE;
+	WR(priv, PSC_SMBCFG, cfg);
+
+	/* Divide by 8 to get a 6.25 MHz clock.  The later protocol
+	 * timings are based on this clock.
+	 */
+	cfg |= PSC_SMBCFG_SET_DIV(PSC_SMBCFG_DIV8);
+	WR(priv, PSC_SMBCFG, cfg);
+	WR(priv, PSC_SMBMSK, PSC_SMBMSK_ALLMASK);
+
+	/* Set the protocol timer values.  See Table 71 in the
+	 * Au1550 Data Book for standard timing values.
+	 */
+	WR(priv, PSC_SMBTMR, PSC_SMBTMR_SET_TH(0) | PSC_SMBTMR_SET_PS(15) | \
+		PSC_SMBTMR_SET_PU(15) | PSC_SMBTMR_SET_SH(15) | \
+		PSC_SMBTMR_SET_SU(15) | PSC_SMBTMR_SET_CL(15) | \
+		PSC_SMBTMR_SET_CH(15));
+
+	cfg |= PSC_SMBCFG_DE_ENABLE;
+	WR(priv, PSC_SMBCFG, cfg);
+	while ((RD(priv, PSC_SMBSTAT) & PSC_SMBSTAT_SR) == 0)
+		cpu_relax();
+
+	WR(priv, PSC_CTRL, PSC_CTRL_SUSPEND);
+}
+
+static void i2c_au1550_disable(struct i2c_au1550_data *priv)
+{
+	WR(priv, PSC_SMBCFG, 0);
+	WR(priv, PSC_CTRL, PSC_CTRL_DISABLE);
+}
+
+/*
+ * registering functions to load algorithms at runtime
+ * Prior to calling us, the 50MHz clock frequency and routing
+ * must have been set up for the PSC indicated by the adapter.
+ */
+static int __devinit
+i2c_au1550_probe(struct platform_device *pdev)
+{
+	struct i2c_au1550_data *priv;
+	struct resource *r;
+	int ret;
+
+	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!r) {
+		ret = -ENODEV;
+		goto out;
+	}
+
+	priv = kzalloc(sizeof(struct i2c_au1550_data), GFP_KERNEL);
+	if (!priv) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	priv->ioarea = request_mem_region(r->start, resource_size(r),
+					  pdev->name);
+	if (!priv->ioarea) {
+		ret = -EBUSY;
+		goto out_mem;
+	}
+
+	priv->psc_base = ioremap(r->start, resource_size(r));
+	if (!priv->psc_base) {
+		ret = -EIO;
+		goto out_map;
+	}
+	priv->xfer_timeout = 200;
+
+	priv->adap.nr = pdev->id;
+	priv->adap.algo = &au1550_algo;
+	priv->adap.algo_data = priv;
+	priv->adap.dev.parent = &pdev->dev;
+	strlcpy(priv->adap.name, "Au1xxx PSC I2C", sizeof(priv->adap.name));
+
+	/* Now, set up the PSC for SMBus PIO mode. */
+	i2c_au1550_setup(priv);
+
+	ret = i2c_add_numbered_adapter(&priv->adap);
+	if (ret == 0) {
+		platform_set_drvdata(pdev, priv);
+		return 0;
+	}
+
+	i2c_au1550_disable(priv);
+	iounmap(priv->psc_base);
+out_map:
+	release_resource(priv->ioarea);
+	kfree(priv->ioarea);
+out_mem:
+	kfree(priv);
+out:
+	return ret;
+}
+
+static int __devexit i2c_au1550_remove(struct platform_device *pdev)
+{
+	struct i2c_au1550_data *priv = platform_get_drvdata(pdev);
+
+	platform_set_drvdata(pdev, NULL);
+	i2c_del_adapter(&priv->adap);
+	i2c_au1550_disable(priv);
+	iounmap(priv->psc_base);
+	release_resource(priv->ioarea);
+	kfree(priv->ioarea);
+	kfree(priv);
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int i2c_au1550_suspend(struct device *dev)
+{
+	struct i2c_au1550_data *priv = dev_get_drvdata(dev);
+
+	i2c_au1550_disable(priv);
+
+	return 0;
+}
+
+static int i2c_au1550_resume(struct device *dev)
+{
+	struct i2c_au1550_data *priv = dev_get_drvdata(dev);
+
+	i2c_au1550_setup(priv);
+
+	return 0;
+}
+
+static const struct dev_pm_ops i2c_au1550_pmops = {
+	.suspend	= i2c_au1550_suspend,
+	.resume		= i2c_au1550_resume,
+};
+
+#define AU1XPSC_SMBUS_PMOPS (&i2c_au1550_pmops)
+
+#else
+#define AU1XPSC_SMBUS_PMOPS NULL
+#endif
+
+static struct platform_driver au1xpsc_smbus_driver = {
+	.driver = {
+		.name	= "au1xpsc_smbus",
+		.owner	= THIS_MODULE,
+		.pm	= AU1XPSC_SMBUS_PMOPS,
+	},
+	.probe		= i2c_au1550_probe,
+	.remove		= __devexit_p(i2c_au1550_remove),
+};
+
+module_platform_driver(au1xpsc_smbus_driver);
+
+MODULE_AUTHOR("Dan Malek, Embedded Edge, LLC.");
+MODULE_DESCRIPTION("SMBus adapter Alchemy pb1550");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:au1xpsc_smbus");
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-bfin-twi.c b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-bfin-twi.c
new file mode 100644
index 0000000..cdb59e5
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-bfin-twi.c
@@ -0,0 +1,797 @@
+/*
+ * Blackfin On-Chip Two Wire Interface Driver
+ *
+ * Copyright 2005-2007 Analog Devices Inc.
+ *
+ * Enter bugs at http://blackfin.uclinux.org/
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/mm.h>
+#include <linux/timer.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+
+#include <asm/blackfin.h>
+#include <asm/portmux.h>
+#include <asm/irq.h>
+
+/* SMBus mode*/
+#define TWI_I2C_MODE_STANDARD		1
+#define TWI_I2C_MODE_STANDARDSUB	2
+#define TWI_I2C_MODE_COMBINED		3
+#define TWI_I2C_MODE_REPEAT		4
+
+struct bfin_twi_iface {
+	int			irq;
+	spinlock_t		lock;
+	char			read_write;
+	u8			command;
+	u8			*transPtr;
+	int			readNum;
+	int			writeNum;
+	int			cur_mode;
+	int			manual_stop;
+	int			result;
+	struct i2c_adapter	adap;
+	struct completion	complete;
+	struct i2c_msg 		*pmsg;
+	int			msg_num;
+	int			cur_msg;
+	u16			saved_clkdiv;
+	u16			saved_control;
+	void __iomem		*regs_base;
+};
+
+
+#define DEFINE_TWI_REG(reg, off) \
+static inline u16 read_##reg(struct bfin_twi_iface *iface) \
+	{ return bfin_read16(iface->regs_base + (off)); } \
+static inline void write_##reg(struct bfin_twi_iface *iface, u16 v) \
+	{ bfin_write16(iface->regs_base + (off), v); }
+
+DEFINE_TWI_REG(CLKDIV, 0x00)
+DEFINE_TWI_REG(CONTROL, 0x04)
+DEFINE_TWI_REG(SLAVE_CTL, 0x08)
+DEFINE_TWI_REG(SLAVE_STAT, 0x0C)
+DEFINE_TWI_REG(SLAVE_ADDR, 0x10)
+DEFINE_TWI_REG(MASTER_CTL, 0x14)
+DEFINE_TWI_REG(MASTER_STAT, 0x18)
+DEFINE_TWI_REG(MASTER_ADDR, 0x1C)
+DEFINE_TWI_REG(INT_STAT, 0x20)
+DEFINE_TWI_REG(INT_MASK, 0x24)
+DEFINE_TWI_REG(FIFO_CTL, 0x28)
+DEFINE_TWI_REG(FIFO_STAT, 0x2C)
+DEFINE_TWI_REG(XMT_DATA8, 0x80)
+DEFINE_TWI_REG(XMT_DATA16, 0x84)
+DEFINE_TWI_REG(RCV_DATA8, 0x88)
+DEFINE_TWI_REG(RCV_DATA16, 0x8C)
+
+static const u16 pin_req[2][3] = {
+	{P_TWI0_SCL, P_TWI0_SDA, 0},
+	{P_TWI1_SCL, P_TWI1_SDA, 0},
+};
+
+static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface,
+					unsigned short twi_int_status)
+{
+	unsigned short mast_stat = read_MASTER_STAT(iface);
+
+	if (twi_int_status & XMTSERV) {
+		/* Transmit next data */
+		if (iface->writeNum > 0) {
+			SSYNC();
+			write_XMT_DATA8(iface, *(iface->transPtr++));
+			iface->writeNum--;
+		}
+		/* start receive immediately after complete sending in
+		 * combine mode.
+		 */
+		else if (iface->cur_mode == TWI_I2C_MODE_COMBINED)
+			write_MASTER_CTL(iface,
+				read_MASTER_CTL(iface) | MDIR | RSTART);
+		else if (iface->manual_stop)
+			write_MASTER_CTL(iface,
+				read_MASTER_CTL(iface) | STOP);
+		else if (iface->cur_mode == TWI_I2C_MODE_REPEAT &&
+		         iface->cur_msg + 1 < iface->msg_num) {
+			if (iface->pmsg[iface->cur_msg + 1].flags & I2C_M_RD)
+				write_MASTER_CTL(iface,
+					read_MASTER_CTL(iface) | RSTART | MDIR);
+			else
+				write_MASTER_CTL(iface,
+					(read_MASTER_CTL(iface) | RSTART) & ~MDIR);
+		}
+	}
+	if (twi_int_status & RCVSERV) {
+		if (iface->readNum > 0) {
+			/* Receive next data */
+			*(iface->transPtr) = read_RCV_DATA8(iface);
+			if (iface->cur_mode == TWI_I2C_MODE_COMBINED) {
+				/* Change combine mode into sub mode after
+				 * read first data.
+				 */
+				iface->cur_mode = TWI_I2C_MODE_STANDARDSUB;
+				/* Get read number from first byte in block
+				 * combine mode.
+				 */
+				if (iface->readNum == 1 && iface->manual_stop)
+					iface->readNum = *iface->transPtr + 1;
+			}
+			iface->transPtr++;
+			iface->readNum--;
+		} else if (iface->manual_stop) {
+			write_MASTER_CTL(iface,
+				read_MASTER_CTL(iface) | STOP);
+		} else if (iface->cur_mode == TWI_I2C_MODE_REPEAT &&
+		           iface->cur_msg + 1 < iface->msg_num) {
+			if (iface->pmsg[iface->cur_msg + 1].flags & I2C_M_RD)
+				write_MASTER_CTL(iface,
+					read_MASTER_CTL(iface) | RSTART | MDIR);
+			else
+				write_MASTER_CTL(iface,
+					(read_MASTER_CTL(iface) | RSTART) & ~MDIR);
+		}
+	}
+	if (twi_int_status & MERR) {
+		write_INT_MASK(iface, 0);
+		write_MASTER_STAT(iface, 0x3e);
+		write_MASTER_CTL(iface, 0);
+		iface->result = -EIO;
+
+		if (mast_stat & LOSTARB)
+			dev_dbg(&iface->adap.dev, "Lost Arbitration\n");
+		if (mast_stat & ANAK)
+			dev_dbg(&iface->adap.dev, "Address Not Acknowledged\n");
+		if (mast_stat & DNAK)
+			dev_dbg(&iface->adap.dev, "Data Not Acknowledged\n");
+		if (mast_stat & BUFRDERR)
+			dev_dbg(&iface->adap.dev, "Buffer Read Error\n");
+		if (mast_stat & BUFWRERR)
+			dev_dbg(&iface->adap.dev, "Buffer Write Error\n");
+
+		/* Faulty slave devices, may drive SDA low after a transfer
+		 * finishes. To release the bus this code generates up to 9
+		 * extra clocks until SDA is released.
+		 */
+
+		if (read_MASTER_STAT(iface) & SDASEN) {
+			int cnt = 9;
+			do {
+				write_MASTER_CTL(iface, SCLOVR);
+				udelay(6);
+				write_MASTER_CTL(iface, 0);
+				udelay(6);
+			} while ((read_MASTER_STAT(iface) & SDASEN) && cnt--);
+
+			write_MASTER_CTL(iface, SDAOVR | SCLOVR);
+			udelay(6);
+			write_MASTER_CTL(iface, SDAOVR);
+			udelay(6);
+			write_MASTER_CTL(iface, 0);
+		}
+
+		/* If it is a quick transfer, only address without data,
+		 * not an err, return 1.
+		 */
+		if (iface->cur_mode == TWI_I2C_MODE_STANDARD &&
+			iface->transPtr == NULL &&
+			(twi_int_status & MCOMP) && (mast_stat & DNAK))
+			iface->result = 1;
+
+		complete(&iface->complete);
+		return;
+	}
+	if (twi_int_status & MCOMP) {
+		if ((read_MASTER_CTL(iface) & MEN) == 0 &&
+			(iface->cur_mode == TWI_I2C_MODE_REPEAT ||
+			iface->cur_mode == TWI_I2C_MODE_COMBINED)) {
+			iface->result = -1;
+			write_INT_MASK(iface, 0);
+			write_MASTER_CTL(iface, 0);
+		} else if (iface->cur_mode == TWI_I2C_MODE_COMBINED) {
+			if (iface->readNum == 0) {
+				/* set the read number to 1 and ask for manual
+				 * stop in block combine mode
+				 */
+				iface->readNum = 1;
+				iface->manual_stop = 1;
+				write_MASTER_CTL(iface,
+					read_MASTER_CTL(iface) | (0xff << 6));
+			} else {
+				/* set the readd number in other
+				 * combine mode.
+				 */
+				write_MASTER_CTL(iface,
+					(read_MASTER_CTL(iface) &
+					(~(0xff << 6))) |
+					(iface->readNum << 6));
+			}
+			/* remove restart bit and enable master receive */
+			write_MASTER_CTL(iface,
+				read_MASTER_CTL(iface) & ~RSTART);
+		} else if (iface->cur_mode == TWI_I2C_MODE_REPEAT &&
+				iface->cur_msg+1 < iface->msg_num) {
+			iface->cur_msg++;
+			iface->transPtr = iface->pmsg[iface->cur_msg].buf;
+			iface->writeNum = iface->readNum =
+				iface->pmsg[iface->cur_msg].len;
+			/* Set Transmit device address */
+			write_MASTER_ADDR(iface,
+				iface->pmsg[iface->cur_msg].addr);
+			if (iface->pmsg[iface->cur_msg].flags & I2C_M_RD)
+				iface->read_write = I2C_SMBUS_READ;
+			else {
+				iface->read_write = I2C_SMBUS_WRITE;
+				/* Transmit first data */
+				if (iface->writeNum > 0) {
+					write_XMT_DATA8(iface,
+						*(iface->transPtr++));
+					iface->writeNum--;
+				}
+			}
+
+			if (iface->pmsg[iface->cur_msg].len <= 255)
+					write_MASTER_CTL(iface,
+					(read_MASTER_CTL(iface) &
+					(~(0xff << 6))) |
+				(iface->pmsg[iface->cur_msg].len << 6));
+			else {
+				write_MASTER_CTL(iface,
+					(read_MASTER_CTL(iface) |
+					(0xff << 6)));
+				iface->manual_stop = 1;
+			}
+			/* remove restart bit and enable master receive */
+			write_MASTER_CTL(iface,
+				read_MASTER_CTL(iface) & ~RSTART);
+		} else {
+			iface->result = 1;
+			write_INT_MASK(iface, 0);
+			write_MASTER_CTL(iface, 0);
+		}
+	}
+	complete(&iface->complete);
+}
+
+/* Interrupt handler */
+static irqreturn_t bfin_twi_interrupt_entry(int irq, void *dev_id)
+{
+	struct bfin_twi_iface *iface = dev_id;
+	unsigned long flags;
+	unsigned short twi_int_status;
+
+	spin_lock_irqsave(&iface->lock, flags);
+	while (1) {
+		twi_int_status = read_INT_STAT(iface);
+		if (!twi_int_status)
+			break;
+		/* Clear interrupt status */
+		write_INT_STAT(iface, twi_int_status);
+		bfin_twi_handle_interrupt(iface, twi_int_status);
+		SSYNC();
+	}
+	spin_unlock_irqrestore(&iface->lock, flags);
+	return IRQ_HANDLED;
+}
+
+/*
+ * One i2c master transfer
+ */
+static int bfin_twi_do_master_xfer(struct i2c_adapter *adap,
+				struct i2c_msg *msgs, int num)
+{
+	struct bfin_twi_iface *iface = adap->algo_data;
+	struct i2c_msg *pmsg;
+	int rc = 0;
+
+	if (!(read_CONTROL(iface) & TWI_ENA))
+		return -ENXIO;
+
+	while (read_MASTER_STAT(iface) & BUSBUSY)
+		yield();
+
+	iface->pmsg = msgs;
+	iface->msg_num = num;
+	iface->cur_msg = 0;
+
+	pmsg = &msgs[0];
+	if (pmsg->flags & I2C_M_TEN) {
+		dev_err(&adap->dev, "10 bits addr not supported!\n");
+		return -EINVAL;
+	}
+
+	iface->cur_mode = TWI_I2C_MODE_REPEAT;
+	iface->manual_stop = 0;
+	iface->transPtr = pmsg->buf;
+	iface->writeNum = iface->readNum = pmsg->len;
+	iface->result = 0;
+	init_completion(&(iface->complete));
+	/* Set Transmit device address */
+	write_MASTER_ADDR(iface, pmsg->addr);
+
+	/* FIFO Initiation. Data in FIFO should be
+	 *  discarded before start a new operation.
+	 */
+	write_FIFO_CTL(iface, 0x3);
+	SSYNC();
+	write_FIFO_CTL(iface, 0);
+	SSYNC();
+
+	if (pmsg->flags & I2C_M_RD)
+		iface->read_write = I2C_SMBUS_READ;
+	else {
+		iface->read_write = I2C_SMBUS_WRITE;
+		/* Transmit first data */
+		if (iface->writeNum > 0) {
+			write_XMT_DATA8(iface, *(iface->transPtr++));
+			iface->writeNum--;
+			SSYNC();
+		}
+	}
+
+	/* clear int stat */
+	write_INT_STAT(iface, MERR | MCOMP | XMTSERV | RCVSERV);
+
+	/* Interrupt mask . Enable XMT, RCV interrupt */
+	write_INT_MASK(iface, MCOMP | MERR | RCVSERV | XMTSERV);
+	SSYNC();
+
+	if (pmsg->len <= 255)
+		write_MASTER_CTL(iface, pmsg->len << 6);
+	else {
+		write_MASTER_CTL(iface, 0xff << 6);
+		iface->manual_stop = 1;
+	}
+
+	/* Master enable */
+	write_MASTER_CTL(iface, read_MASTER_CTL(iface) | MEN |
+		((iface->read_write == I2C_SMBUS_READ) ? MDIR : 0) |
+		((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ > 100) ? FAST : 0));
+	SSYNC();
+
+	while (!iface->result) {
+		if (!wait_for_completion_timeout(&iface->complete,
+			adap->timeout)) {
+			iface->result = -1;
+			dev_err(&adap->dev, "master transfer timeout\n");
+		}
+	}
+
+	if (iface->result == 1)
+		rc = iface->cur_msg + 1;
+	else
+		rc = iface->result;
+
+	return rc;
+}
+
+/*
+ * Generic i2c master transfer entrypoint
+ */
+static int bfin_twi_master_xfer(struct i2c_adapter *adap,
+				struct i2c_msg *msgs, int num)
+{
+	return bfin_twi_do_master_xfer(adap, msgs, num);
+}
+
+/*
+ * One I2C SMBus transfer
+ */
+int bfin_twi_do_smbus_xfer(struct i2c_adapter *adap, u16 addr,
+			unsigned short flags, char read_write,
+			u8 command, int size, union i2c_smbus_data *data)
+{
+	struct bfin_twi_iface *iface = adap->algo_data;
+	int rc = 0;
+
+	if (!(read_CONTROL(iface) & TWI_ENA))
+		return -ENXIO;
+
+	while (read_MASTER_STAT(iface) & BUSBUSY)
+		yield();
+
+	iface->writeNum = 0;
+	iface->readNum = 0;
+
+	/* Prepare datas & select mode */
+	switch (size) {
+	case I2C_SMBUS_QUICK:
+		iface->transPtr = NULL;
+		iface->cur_mode = TWI_I2C_MODE_STANDARD;
+		break;
+	case I2C_SMBUS_BYTE:
+		if (data == NULL)
+			iface->transPtr = NULL;
+		else {
+			if (read_write == I2C_SMBUS_READ)
+				iface->readNum = 1;
+			else
+				iface->writeNum = 1;
+			iface->transPtr = &data->byte;
+		}
+		iface->cur_mode = TWI_I2C_MODE_STANDARD;
+		break;
+	case I2C_SMBUS_BYTE_DATA:
+		if (read_write == I2C_SMBUS_READ) {
+			iface->readNum = 1;
+			iface->cur_mode = TWI_I2C_MODE_COMBINED;
+		} else {
+			iface->writeNum = 1;
+			iface->cur_mode = TWI_I2C_MODE_STANDARDSUB;
+		}
+		iface->transPtr = &data->byte;
+		break;
+	case I2C_SMBUS_WORD_DATA:
+		if (read_write == I2C_SMBUS_READ) {
+			iface->readNum = 2;
+			iface->cur_mode = TWI_I2C_MODE_COMBINED;
+		} else {
+			iface->writeNum = 2;
+			iface->cur_mode = TWI_I2C_MODE_STANDARDSUB;
+		}
+		iface->transPtr = (u8 *)&data->word;
+		break;
+	case I2C_SMBUS_PROC_CALL:
+		iface->writeNum = 2;
+		iface->readNum = 2;
+		iface->cur_mode = TWI_I2C_MODE_COMBINED;
+		iface->transPtr = (u8 *)&data->word;
+		break;
+	case I2C_SMBUS_BLOCK_DATA:
+		if (read_write == I2C_SMBUS_READ) {
+			iface->readNum = 0;
+			iface->cur_mode = TWI_I2C_MODE_COMBINED;
+		} else {
+			iface->writeNum = data->block[0] + 1;
+			iface->cur_mode = TWI_I2C_MODE_STANDARDSUB;
+		}
+		iface->transPtr = data->block;
+		break;
+	case I2C_SMBUS_I2C_BLOCK_DATA:
+		if (read_write == I2C_SMBUS_READ) {
+			iface->readNum = data->block[0];
+			iface->cur_mode = TWI_I2C_MODE_COMBINED;
+		} else {
+			iface->writeNum = data->block[0];
+			iface->cur_mode = TWI_I2C_MODE_STANDARDSUB;
+		}
+		iface->transPtr = (u8 *)&data->block[1];
+		break;
+	default:
+		return -1;
+	}
+
+	iface->result = 0;
+	iface->manual_stop = 0;
+	iface->read_write = read_write;
+	iface->command = command;
+	init_completion(&(iface->complete));
+
+	/* FIFO Initiation. Data in FIFO should be discarded before
+	 * start a new operation.
+	 */
+	write_FIFO_CTL(iface, 0x3);
+	SSYNC();
+	write_FIFO_CTL(iface, 0);
+
+	/* clear int stat */
+	write_INT_STAT(iface, MERR | MCOMP | XMTSERV | RCVSERV);
+
+	/* Set Transmit device address */
+	write_MASTER_ADDR(iface, addr);
+	SSYNC();
+
+	switch (iface->cur_mode) {
+	case TWI_I2C_MODE_STANDARDSUB:
+		write_XMT_DATA8(iface, iface->command);
+		write_INT_MASK(iface, MCOMP | MERR |
+			((iface->read_write == I2C_SMBUS_READ) ?
+			RCVSERV : XMTSERV));
+		SSYNC();
+
+		if (iface->writeNum + 1 <= 255)
+			write_MASTER_CTL(iface, (iface->writeNum + 1) << 6);
+		else {
+			write_MASTER_CTL(iface, 0xff << 6);
+			iface->manual_stop = 1;
+		}
+		/* Master enable */
+		write_MASTER_CTL(iface, read_MASTER_CTL(iface) | MEN |
+			((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ>100) ? FAST : 0));
+		break;
+	case TWI_I2C_MODE_COMBINED:
+		write_XMT_DATA8(iface, iface->command);
+		write_INT_MASK(iface, MCOMP | MERR | RCVSERV | XMTSERV);
+		SSYNC();
+
+		if (iface->writeNum > 0)
+			write_MASTER_CTL(iface, (iface->writeNum + 1) << 6);
+		else
+			write_MASTER_CTL(iface, 0x1 << 6);
+		/* Master enable */
+		write_MASTER_CTL(iface, read_MASTER_CTL(iface) | MEN |
+			((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ>100) ? FAST : 0));
+		break;
+	default:
+		write_MASTER_CTL(iface, 0);
+		if (size != I2C_SMBUS_QUICK) {
+			/* Don't access xmit data register when this is a
+			 * read operation.
+			 */
+			if (iface->read_write != I2C_SMBUS_READ) {
+				if (iface->writeNum > 0) {
+					write_XMT_DATA8(iface,
+						*(iface->transPtr++));
+					if (iface->writeNum <= 255)
+						write_MASTER_CTL(iface,
+							iface->writeNum << 6);
+					else {
+						write_MASTER_CTL(iface,
+							0xff << 6);
+						iface->manual_stop = 1;
+					}
+					iface->writeNum--;
+				} else {
+					write_XMT_DATA8(iface, iface->command);
+					write_MASTER_CTL(iface, 1 << 6);
+				}
+			} else {
+				if (iface->readNum > 0 && iface->readNum <= 255)
+					write_MASTER_CTL(iface,
+						iface->readNum << 6);
+				else if (iface->readNum > 255) {
+					write_MASTER_CTL(iface, 0xff << 6);
+					iface->manual_stop = 1;
+				} else
+					break;
+			}
+		}
+		write_INT_MASK(iface, MCOMP | MERR |
+			((iface->read_write == I2C_SMBUS_READ) ?
+			RCVSERV : XMTSERV));
+		SSYNC();
+
+		/* Master enable */
+		write_MASTER_CTL(iface, read_MASTER_CTL(iface) | MEN |
+			((iface->read_write == I2C_SMBUS_READ) ? MDIR : 0) |
+			((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ > 100) ? FAST : 0));
+		break;
+	}
+	SSYNC();
+
+	while (!iface->result) {
+		if (!wait_for_completion_timeout(&iface->complete,
+			adap->timeout)) {
+			iface->result = -1;
+			dev_err(&adap->dev, "smbus transfer timeout\n");
+		}
+	}
+
+	rc = (iface->result >= 0) ? 0 : -1;
+
+	return rc;
+}
+
+/*
+ * Generic I2C SMBus transfer entrypoint
+ */
+int bfin_twi_smbus_xfer(struct i2c_adapter *adap, u16 addr,
+			unsigned short flags, char read_write,
+			u8 command, int size, union i2c_smbus_data *data)
+{
+	return bfin_twi_do_smbus_xfer(adap, addr, flags,
+			read_write, command, size, data);
+}
+
+/*
+ * Return what the adapter supports
+ */
+static u32 bfin_twi_functionality(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+	       I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+	       I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_PROC_CALL |
+	       I2C_FUNC_I2C | I2C_FUNC_SMBUS_I2C_BLOCK;
+}
+
+static struct i2c_algorithm bfin_twi_algorithm = {
+	.master_xfer   = bfin_twi_master_xfer,
+	.smbus_xfer    = bfin_twi_smbus_xfer,
+	.functionality = bfin_twi_functionality,
+};
+
+static int i2c_bfin_twi_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct bfin_twi_iface *iface = platform_get_drvdata(pdev);
+
+	iface->saved_clkdiv = read_CLKDIV(iface);
+	iface->saved_control = read_CONTROL(iface);
+
+	free_irq(iface->irq, iface);
+
+	/* Disable TWI */
+	write_CONTROL(iface, iface->saved_control & ~TWI_ENA);
+
+	return 0;
+}
+
+static int i2c_bfin_twi_resume(struct platform_device *pdev)
+{
+	struct bfin_twi_iface *iface = platform_get_drvdata(pdev);
+
+	int rc = request_irq(iface->irq, bfin_twi_interrupt_entry,
+		0, pdev->name, iface);
+	if (rc) {
+		dev_err(&pdev->dev, "Can't get IRQ %d !\n", iface->irq);
+		return -ENODEV;
+	}
+
+	/* Resume TWI interface clock as specified */
+	write_CLKDIV(iface, iface->saved_clkdiv);
+
+	/* Resume TWI */
+	write_CONTROL(iface, iface->saved_control);
+
+	return 0;
+}
+
+static int i2c_bfin_twi_probe(struct platform_device *pdev)
+{
+	struct bfin_twi_iface *iface;
+	struct i2c_adapter *p_adap;
+	struct resource *res;
+	int rc;
+	unsigned int clkhilow;
+
+	iface = kzalloc(sizeof(struct bfin_twi_iface), GFP_KERNEL);
+	if (!iface) {
+		dev_err(&pdev->dev, "Cannot allocate memory\n");
+		rc = -ENOMEM;
+		goto out_error_nomem;
+	}
+
+	spin_lock_init(&(iface->lock));
+
+	/* Find and map our resources */
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (res == NULL) {
+		dev_err(&pdev->dev, "Cannot get IORESOURCE_MEM\n");
+		rc = -ENOENT;
+		goto out_error_get_res;
+	}
+
+	iface->regs_base = ioremap(res->start, resource_size(res));
+	if (iface->regs_base == NULL) {
+		dev_err(&pdev->dev, "Cannot map IO\n");
+		rc = -ENXIO;
+		goto out_error_ioremap;
+	}
+
+	iface->irq = platform_get_irq(pdev, 0);
+	if (iface->irq < 0) {
+		dev_err(&pdev->dev, "No IRQ specified\n");
+		rc = -ENOENT;
+		goto out_error_no_irq;
+	}
+
+	p_adap = &iface->adap;
+	p_adap->nr = pdev->id;
+	strlcpy(p_adap->name, pdev->name, sizeof(p_adap->name));
+	p_adap->algo = &bfin_twi_algorithm;
+	p_adap->algo_data = iface;
+	p_adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
+	p_adap->dev.parent = &pdev->dev;
+	p_adap->timeout = 5 * HZ;
+	p_adap->retries = 3;
+
+	rc = peripheral_request_list(pin_req[pdev->id], "i2c-bfin-twi");
+	if (rc) {
+		dev_err(&pdev->dev, "Can't setup pin mux!\n");
+		goto out_error_pin_mux;
+	}
+
+	rc = request_irq(iface->irq, bfin_twi_interrupt_entry,
+		0, pdev->name, iface);
+	if (rc) {
+		dev_err(&pdev->dev, "Can't get IRQ %d !\n", iface->irq);
+		rc = -ENODEV;
+		goto out_error_req_irq;
+	}
+
+	/* Set TWI internal clock as 10MHz */
+	write_CONTROL(iface, ((get_sclk() / 1000 / 1000 + 5) / 10) & 0x7F);
+
+	/*
+	 * We will not end up with a CLKDIV=0 because no one will specify
+	 * 20kHz SCL or less in Kconfig now. (5 * 1000 / 20 = 250)
+	 */
+	clkhilow = ((10 * 1000 / CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ) + 1) / 2;
+
+	/* Set Twi interface clock as specified */
+	write_CLKDIV(iface, (clkhilow << 8) | clkhilow);
+
+	/* Enable TWI */
+	write_CONTROL(iface, read_CONTROL(iface) | TWI_ENA);
+	SSYNC();
+
+	rc = i2c_add_numbered_adapter(p_adap);
+	if (rc < 0) {
+		dev_err(&pdev->dev, "Can't add i2c adapter!\n");
+		goto out_error_add_adapter;
+	}
+
+	platform_set_drvdata(pdev, iface);
+
+	dev_info(&pdev->dev, "Blackfin BF5xx on-chip I2C TWI Contoller, "
+		"regs_base@%p\n", iface->regs_base);
+
+	return 0;
+
+out_error_add_adapter:
+	free_irq(iface->irq, iface);
+out_error_req_irq:
+out_error_no_irq:
+	peripheral_free_list(pin_req[pdev->id]);
+out_error_pin_mux:
+	iounmap(iface->regs_base);
+out_error_ioremap:
+out_error_get_res:
+	kfree(iface);
+out_error_nomem:
+	return rc;
+}
+
+static int i2c_bfin_twi_remove(struct platform_device *pdev)
+{
+	struct bfin_twi_iface *iface = platform_get_drvdata(pdev);
+
+	platform_set_drvdata(pdev, NULL);
+
+	i2c_del_adapter(&(iface->adap));
+	free_irq(iface->irq, iface);
+	peripheral_free_list(pin_req[pdev->id]);
+	iounmap(iface->regs_base);
+	kfree(iface);
+
+	return 0;
+}
+
+static struct platform_driver i2c_bfin_twi_driver = {
+	.probe		= i2c_bfin_twi_probe,
+	.remove		= i2c_bfin_twi_remove,
+	.suspend	= i2c_bfin_twi_suspend,
+	.resume		= i2c_bfin_twi_resume,
+	.driver		= {
+		.name	= "i2c-bfin-twi",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init i2c_bfin_twi_init(void)
+{
+	return platform_driver_register(&i2c_bfin_twi_driver);
+}
+
+static void __exit i2c_bfin_twi_exit(void)
+{
+	platform_driver_unregister(&i2c_bfin_twi_driver);
+}
+
+subsys_initcall(i2c_bfin_twi_init);
+module_exit(i2c_bfin_twi_exit);
+
+MODULE_AUTHOR("Bryan Wu, Sonic Zhang");
+MODULE_DESCRIPTION("Blackfin BF5xx on-chip I2C TWI Contoller Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:i2c-bfin-twi");
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-cpm.c b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-cpm.c
new file mode 100644
index 0000000..c1e1096
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-cpm.c
@@ -0,0 +1,731 @@
+/*
+ * Freescale CPM1/CPM2 I2C interface.
+ * Copyright (c) 1999 Dan Malek (dmalek@jlc.net).
+ *
+ * moved into proper i2c interface;
+ * Brad Parker (brad@heeltoe.com)
+ *
+ * Parts from dbox2_i2c.c (cvs.tuxbox.org)
+ * (C) 2000-2001 Felix Domke (tmbinc@gmx.net), Gillem (htoa@gmx.net)
+ *
+ * (C) 2007 Montavista Software, Inc.
+ * Vitaly Bordug <vitb@kernel.crashing.org>
+ *
+ * Converted to of_platform_device. Renamed to i2c-cpm.c.
+ * (C) 2007,2008 Jochen Friedrich <jochen@scram.de>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/errno.h>
+#include <linux/stddef.h>
+#include <linux/i2c.h>
+#include <linux/io.h>
+#include <linux/dma-mapping.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+#include <linux/of_i2c.h>
+#include <sysdev/fsl_soc.h>
+#include <asm/cpm.h>
+
+/* Try to define this if you have an older CPU (earlier than rev D4) */
+/* However, better use a GPIO based bitbang driver in this case :/   */
+#undef	I2C_CHIP_ERRATA
+
+#define CPM_MAX_READ    513
+#define CPM_MAXBD       4
+
+#define I2C_EB			(0x10) /* Big endian mode */
+#define I2C_EB_CPM2		(0x30) /* Big endian mode, memory snoop */
+
+#define DPRAM_BASE		((u8 __iomem __force *)cpm_muram_addr(0))
+
+/* I2C parameter RAM. */
+struct i2c_ram {
+	ushort  rbase;		/* Rx Buffer descriptor base address */
+	ushort  tbase;		/* Tx Buffer descriptor base address */
+	u_char  rfcr;		/* Rx function code */
+	u_char  tfcr;		/* Tx function code */
+	ushort  mrblr;		/* Max receive buffer length */
+	uint    rstate;		/* Internal */
+	uint    rdp;		/* Internal */
+	ushort  rbptr;		/* Rx Buffer descriptor pointer */
+	ushort  rbc;		/* Internal */
+	uint    rxtmp;		/* Internal */
+	uint    tstate;		/* Internal */
+	uint    tdp;		/* Internal */
+	ushort  tbptr;		/* Tx Buffer descriptor pointer */
+	ushort  tbc;		/* Internal */
+	uint    txtmp;		/* Internal */
+	char    res1[4];	/* Reserved */
+	ushort  rpbase;		/* Relocation pointer */
+	char    res2[2];	/* Reserved */
+};
+
+#define I2COM_START	0x80
+#define I2COM_MASTER	0x01
+#define I2CER_TXE	0x10
+#define I2CER_BUSY	0x04
+#define I2CER_TXB	0x02
+#define I2CER_RXB	0x01
+#define I2MOD_EN	0x01
+
+/* I2C Registers */
+struct i2c_reg {
+	u8	i2mod;
+	u8	res1[3];
+	u8	i2add;
+	u8	res2[3];
+	u8	i2brg;
+	u8	res3[3];
+	u8	i2com;
+	u8	res4[3];
+	u8	i2cer;
+	u8	res5[3];
+	u8	i2cmr;
+};
+
+struct cpm_i2c {
+	char *base;
+	struct platform_device *ofdev;
+	struct i2c_adapter adap;
+	uint dp_addr;
+	int version; /* CPM1=1, CPM2=2 */
+	int irq;
+	int cp_command;
+	int freq;
+	struct i2c_reg __iomem *i2c_reg;
+	struct i2c_ram __iomem *i2c_ram;
+	u16 i2c_addr;
+	wait_queue_head_t i2c_wait;
+	cbd_t __iomem *tbase;
+	cbd_t __iomem *rbase;
+	u_char *txbuf[CPM_MAXBD];
+	u_char *rxbuf[CPM_MAXBD];
+	u32 txdma[CPM_MAXBD];
+	u32 rxdma[CPM_MAXBD];
+};
+
+static irqreturn_t cpm_i2c_interrupt(int irq, void *dev_id)
+{
+	struct cpm_i2c *cpm;
+	struct i2c_reg __iomem *i2c_reg;
+	struct i2c_adapter *adap = dev_id;
+	int i;
+
+	cpm = i2c_get_adapdata(dev_id);
+	i2c_reg = cpm->i2c_reg;
+
+	/* Clear interrupt. */
+	i = in_8(&i2c_reg->i2cer);
+	out_8(&i2c_reg->i2cer, i);
+
+	dev_dbg(&adap->dev, "Interrupt: %x\n", i);
+
+	wake_up(&cpm->i2c_wait);
+
+	return i ? IRQ_HANDLED : IRQ_NONE;
+}
+
+static void cpm_reset_i2c_params(struct cpm_i2c *cpm)
+{
+	struct i2c_ram __iomem *i2c_ram = cpm->i2c_ram;
+
+	/* Set up the I2C parameters in the parameter ram. */
+	out_be16(&i2c_ram->tbase, (u8 __iomem *)cpm->tbase - DPRAM_BASE);
+	out_be16(&i2c_ram->rbase, (u8 __iomem *)cpm->rbase - DPRAM_BASE);
+
+	if (cpm->version == 1) {
+		out_8(&i2c_ram->tfcr, I2C_EB);
+		out_8(&i2c_ram->rfcr, I2C_EB);
+	} else {
+		out_8(&i2c_ram->tfcr, I2C_EB_CPM2);
+		out_8(&i2c_ram->rfcr, I2C_EB_CPM2);
+	}
+
+	out_be16(&i2c_ram->mrblr, CPM_MAX_READ);
+
+	out_be32(&i2c_ram->rstate, 0);
+	out_be32(&i2c_ram->rdp, 0);
+	out_be16(&i2c_ram->rbptr, 0);
+	out_be16(&i2c_ram->rbc, 0);
+	out_be32(&i2c_ram->rxtmp, 0);
+	out_be32(&i2c_ram->tstate, 0);
+	out_be32(&i2c_ram->tdp, 0);
+	out_be16(&i2c_ram->tbptr, 0);
+	out_be16(&i2c_ram->tbc, 0);
+	out_be32(&i2c_ram->txtmp, 0);
+}
+
+static void cpm_i2c_force_close(struct i2c_adapter *adap)
+{
+	struct cpm_i2c *cpm = i2c_get_adapdata(adap);
+	struct i2c_reg __iomem *i2c_reg = cpm->i2c_reg;
+
+	dev_dbg(&adap->dev, "cpm_i2c_force_close()\n");
+
+	cpm_command(cpm->cp_command, CPM_CR_CLOSE_RX_BD);
+
+	out_8(&i2c_reg->i2cmr, 0x00);	/* Disable all interrupts */
+	out_8(&i2c_reg->i2cer, 0xff);
+}
+
+static void cpm_i2c_parse_message(struct i2c_adapter *adap,
+	struct i2c_msg *pmsg, int num, int tx, int rx)
+{
+	cbd_t __iomem *tbdf;
+	cbd_t __iomem *rbdf;
+	u_char addr;
+	u_char *tb;
+	u_char *rb;
+	struct cpm_i2c *cpm = i2c_get_adapdata(adap);
+
+	tbdf = cpm->tbase + tx;
+	rbdf = cpm->rbase + rx;
+
+	addr = pmsg->addr << 1;
+	if (pmsg->flags & I2C_M_RD)
+		addr |= 1;
+
+	tb = cpm->txbuf[tx];
+	rb = cpm->rxbuf[rx];
+
+	/* Align read buffer */
+	rb = (u_char *) (((ulong) rb + 1) & ~1);
+
+	tb[0] = addr;		/* Device address byte w/rw flag */
+
+	out_be16(&tbdf->cbd_datlen, pmsg->len + 1);
+	out_be16(&tbdf->cbd_sc, 0);
+
+	if (!(pmsg->flags & I2C_M_NOSTART))
+		setbits16(&tbdf->cbd_sc, BD_I2C_START);
+
+	if (tx + 1 == num)
+		setbits16(&tbdf->cbd_sc, BD_SC_LAST | BD_SC_WRAP);
+
+	if (pmsg->flags & I2C_M_RD) {
+		/*
+		 * To read, we need an empty buffer of the proper length.
+		 * All that is used is the first byte for address, the remainder
+		 * is just used for timing (and doesn't really have to exist).
+		 */
+
+		dev_dbg(&adap->dev, "cpm_i2c_read(abyte=0x%x)\n", addr);
+
+		out_be16(&rbdf->cbd_datlen, 0);
+		out_be16(&rbdf->cbd_sc, BD_SC_EMPTY | BD_SC_INTRPT);
+
+		if (rx + 1 == CPM_MAXBD)
+			setbits16(&rbdf->cbd_sc, BD_SC_WRAP);
+
+		eieio();
+		setbits16(&tbdf->cbd_sc, BD_SC_READY);
+	} else {
+		dev_dbg(&adap->dev, "cpm_i2c_write(abyte=0x%x)\n", addr);
+
+		memcpy(tb+1, pmsg->buf, pmsg->len);
+
+		eieio();
+		setbits16(&tbdf->cbd_sc, BD_SC_READY | BD_SC_INTRPT);
+	}
+}
+
+static int cpm_i2c_check_message(struct i2c_adapter *adap,
+	struct i2c_msg *pmsg, int tx, int rx)
+{
+	cbd_t __iomem *tbdf;
+	cbd_t __iomem *rbdf;
+	u_char *tb;
+	u_char *rb;
+	struct cpm_i2c *cpm = i2c_get_adapdata(adap);
+
+	tbdf = cpm->tbase + tx;
+	rbdf = cpm->rbase + rx;
+
+	tb = cpm->txbuf[tx];
+	rb = cpm->rxbuf[rx];
+
+	/* Align read buffer */
+	rb = (u_char *) (((uint) rb + 1) & ~1);
+
+	eieio();
+	if (pmsg->flags & I2C_M_RD) {
+		dev_dbg(&adap->dev, "tx sc 0x%04x, rx sc 0x%04x\n",
+			in_be16(&tbdf->cbd_sc), in_be16(&rbdf->cbd_sc));
+
+		if (in_be16(&tbdf->cbd_sc) & BD_SC_NAK) {
+			dev_dbg(&adap->dev, "I2C read; No ack\n");
+			return -ENXIO;
+		}
+		if (in_be16(&rbdf->cbd_sc) & BD_SC_EMPTY) {
+			dev_err(&adap->dev,
+				"I2C read; complete but rbuf empty\n");
+			return -EREMOTEIO;
+		}
+		if (in_be16(&rbdf->cbd_sc) & BD_SC_OV) {
+			dev_err(&adap->dev, "I2C read; Overrun\n");
+			return -EREMOTEIO;
+		}
+		memcpy(pmsg->buf, rb, pmsg->len);
+	} else {
+		dev_dbg(&adap->dev, "tx sc %d 0x%04x\n", tx,
+			in_be16(&tbdf->cbd_sc));
+
+		if (in_be16(&tbdf->cbd_sc) & BD_SC_NAK) {
+			dev_dbg(&adap->dev, "I2C write; No ack\n");
+			return -ENXIO;
+		}
+		if (in_be16(&tbdf->cbd_sc) & BD_SC_UN) {
+			dev_err(&adap->dev, "I2C write; Underrun\n");
+			return -EIO;
+		}
+		if (in_be16(&tbdf->cbd_sc) & BD_SC_CL) {
+			dev_err(&adap->dev, "I2C write; Collision\n");
+			return -EIO;
+		}
+	}
+	return 0;
+}
+
+static int cpm_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+{
+	struct cpm_i2c *cpm = i2c_get_adapdata(adap);
+	struct i2c_reg __iomem *i2c_reg = cpm->i2c_reg;
+	struct i2c_ram __iomem *i2c_ram = cpm->i2c_ram;
+	struct i2c_msg *pmsg;
+	int ret, i;
+	int tptr;
+	int rptr;
+	cbd_t __iomem *tbdf;
+	cbd_t __iomem *rbdf;
+
+	if (num > CPM_MAXBD)
+		return -EINVAL;
+
+	/* Check if we have any oversized READ requests */
+	for (i = 0; i < num; i++) {
+		pmsg = &msgs[i];
+		if (pmsg->len >= CPM_MAX_READ)
+			return -EINVAL;
+	}
+
+	/* Reset to use first buffer */
+	out_be16(&i2c_ram->rbptr, in_be16(&i2c_ram->rbase));
+	out_be16(&i2c_ram->tbptr, in_be16(&i2c_ram->tbase));
+
+	tbdf = cpm->tbase;
+	rbdf = cpm->rbase;
+
+	tptr = 0;
+	rptr = 0;
+
+	while (tptr < num) {
+		pmsg = &msgs[tptr];
+		dev_dbg(&adap->dev, "R: %d T: %d\n", rptr, tptr);
+
+		cpm_i2c_parse_message(adap, pmsg, num, tptr, rptr);
+		if (pmsg->flags & I2C_M_RD)
+			rptr++;
+		tptr++;
+	}
+	/* Start transfer now */
+	/* Enable RX/TX/Error interupts */
+	out_8(&i2c_reg->i2cmr, I2CER_TXE | I2CER_TXB | I2CER_RXB);
+	out_8(&i2c_reg->i2cer, 0xff);	/* Clear interrupt status */
+	/* Chip bug, set enable here */
+	setbits8(&i2c_reg->i2mod, I2MOD_EN);	/* Enable */
+	/* Begin transmission */
+	setbits8(&i2c_reg->i2com, I2COM_START);
+
+	tptr = 0;
+	rptr = 0;
+
+	while (tptr < num) {
+		/* Check for outstanding messages */
+		dev_dbg(&adap->dev, "test ready.\n");
+		pmsg = &msgs[tptr];
+		if (pmsg->flags & I2C_M_RD)
+			ret = wait_event_timeout(cpm->i2c_wait,
+				(in_be16(&tbdf[tptr].cbd_sc) & BD_SC_NAK) ||
+				!(in_be16(&rbdf[rptr].cbd_sc) & BD_SC_EMPTY),
+				1 * HZ);
+		else
+			ret = wait_event_timeout(cpm->i2c_wait,
+				!(in_be16(&tbdf[tptr].cbd_sc) & BD_SC_READY),
+				1 * HZ);
+		if (ret == 0) {
+			ret = -EREMOTEIO;
+			dev_err(&adap->dev, "I2C transfer: timeout\n");
+			goto out_err;
+		}
+		if (ret > 0) {
+			dev_dbg(&adap->dev, "ready.\n");
+			ret = cpm_i2c_check_message(adap, pmsg, tptr, rptr);
+			tptr++;
+			if (pmsg->flags & I2C_M_RD)
+				rptr++;
+			if (ret)
+				goto out_err;
+		}
+	}
+#ifdef I2C_CHIP_ERRATA
+	/*
+	 * Chip errata, clear enable. This is not needed on rev D4 CPUs.
+	 * Disabling I2C too early may cause too short stop condition
+	 */
+	udelay(4);
+	clrbits8(&i2c_reg->i2mod, I2MOD_EN);
+#endif
+	return (num);
+
+out_err:
+	cpm_i2c_force_close(adap);
+#ifdef I2C_CHIP_ERRATA
+	/*
+	 * Chip errata, clear enable. This is not needed on rev D4 CPUs.
+	 */
+	clrbits8(&i2c_reg->i2mod, I2MOD_EN);
+#endif
+	return ret;
+}
+
+static u32 cpm_i2c_func(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
+}
+
+/* -----exported algorithm data: -------------------------------------	*/
+
+static const struct i2c_algorithm cpm_i2c_algo = {
+	.master_xfer = cpm_i2c_xfer,
+	.functionality = cpm_i2c_func,
+};
+
+static const struct i2c_adapter cpm_ops = {
+	.owner		= THIS_MODULE,
+	.name		= "i2c-cpm",
+	.algo		= &cpm_i2c_algo,
+};
+
+static int __devinit cpm_i2c_setup(struct cpm_i2c *cpm)
+{
+	struct platform_device *ofdev = cpm->ofdev;
+	const u32 *data;
+	int len, ret, i;
+	void __iomem *i2c_base;
+	cbd_t __iomem *tbdf;
+	cbd_t __iomem *rbdf;
+	unsigned char brg;
+
+	dev_dbg(&cpm->ofdev->dev, "cpm_i2c_setup()\n");
+
+	init_waitqueue_head(&cpm->i2c_wait);
+
+	cpm->irq = of_irq_to_resource(ofdev->dev.of_node, 0, NULL);
+	if (!cpm->irq)
+		return -EINVAL;
+
+	/* Install interrupt handler. */
+	ret = request_irq(cpm->irq, cpm_i2c_interrupt, 0, "cpm_i2c",
+			  &cpm->adap);
+	if (ret)
+		return ret;
+
+	/* I2C parameter RAM */
+	i2c_base = of_iomap(ofdev->dev.of_node, 1);
+	if (i2c_base == NULL) {
+		ret = -EINVAL;
+		goto out_irq;
+	}
+
+	if (of_device_is_compatible(ofdev->dev.of_node, "fsl,cpm1-i2c")) {
+
+		/* Check for and use a microcode relocation patch. */
+		cpm->i2c_ram = i2c_base;
+		cpm->i2c_addr = in_be16(&cpm->i2c_ram->rpbase);
+
+		/*
+		 * Maybe should use cpm_muram_alloc instead of hardcoding
+		 * this in micropatch.c
+		 */
+		if (cpm->i2c_addr) {
+			cpm->i2c_ram = cpm_muram_addr(cpm->i2c_addr);
+			iounmap(i2c_base);
+		}
+
+		cpm->version = 1;
+
+	} else if (of_device_is_compatible(ofdev->dev.of_node, "fsl,cpm2-i2c")) {
+		cpm->i2c_addr = cpm_muram_alloc(sizeof(struct i2c_ram), 64);
+		cpm->i2c_ram = cpm_muram_addr(cpm->i2c_addr);
+		out_be16(i2c_base, cpm->i2c_addr);
+		iounmap(i2c_base);
+
+		cpm->version = 2;
+
+	} else {
+		iounmap(i2c_base);
+		ret = -EINVAL;
+		goto out_irq;
+	}
+
+	/* I2C control/status registers */
+	cpm->i2c_reg = of_iomap(ofdev->dev.of_node, 0);
+	if (cpm->i2c_reg == NULL) {
+		ret = -EINVAL;
+		goto out_ram;
+	}
+
+	data = of_get_property(ofdev->dev.of_node, "fsl,cpm-command", &len);
+	if (!data || len != 4) {
+		ret = -EINVAL;
+		goto out_reg;
+	}
+	cpm->cp_command = *data;
+
+	data = of_get_property(ofdev->dev.of_node, "linux,i2c-class", &len);
+	if (data && len == 4)
+		cpm->adap.class = *data;
+
+	data = of_get_property(ofdev->dev.of_node, "clock-frequency", &len);
+	if (data && len == 4)
+		cpm->freq = *data;
+	else
+		cpm->freq = 60000; /* use 60kHz i2c clock by default */
+
+	/*
+	 * Allocate space for CPM_MAXBD transmit and receive buffer
+	 * descriptors in the DP ram.
+	 */
+	cpm->dp_addr = cpm_muram_alloc(sizeof(cbd_t) * 2 * CPM_MAXBD, 8);
+	if (!cpm->dp_addr) {
+		ret = -ENOMEM;
+		goto out_reg;
+	}
+
+	cpm->tbase = cpm_muram_addr(cpm->dp_addr);
+	cpm->rbase = cpm_muram_addr(cpm->dp_addr + sizeof(cbd_t) * CPM_MAXBD);
+
+	/* Allocate TX and RX buffers */
+
+	tbdf = cpm->tbase;
+	rbdf = cpm->rbase;
+
+	for (i = 0; i < CPM_MAXBD; i++) {
+		cpm->rxbuf[i] = dma_alloc_coherent(&cpm->ofdev->dev,
+						   CPM_MAX_READ + 1,
+						   &cpm->rxdma[i], GFP_KERNEL);
+		if (!cpm->rxbuf[i]) {
+			ret = -ENOMEM;
+			goto out_muram;
+		}
+		out_be32(&rbdf[i].cbd_bufaddr, ((cpm->rxdma[i] + 1) & ~1));
+
+		cpm->txbuf[i] = (unsigned char *)dma_alloc_coherent(&cpm->ofdev->dev, CPM_MAX_READ + 1, &cpm->txdma[i], GFP_KERNEL);
+		if (!cpm->txbuf[i]) {
+			ret = -ENOMEM;
+			goto out_muram;
+		}
+		out_be32(&tbdf[i].cbd_bufaddr, cpm->txdma[i]);
+	}
+
+	/* Initialize Tx/Rx parameters. */
+
+	cpm_reset_i2c_params(cpm);
+
+	dev_dbg(&cpm->ofdev->dev, "i2c_ram 0x%p, i2c_addr 0x%04x, freq %d\n",
+		cpm->i2c_ram, cpm->i2c_addr, cpm->freq);
+	dev_dbg(&cpm->ofdev->dev, "tbase 0x%04x, rbase 0x%04x\n",
+		(u8 __iomem *)cpm->tbase - DPRAM_BASE,
+		(u8 __iomem *)cpm->rbase - DPRAM_BASE);
+
+	cpm_command(cpm->cp_command, CPM_CR_INIT_TRX);
+
+	/*
+	 * Select an invalid address. Just make sure we don't use loopback mode
+	 */
+	out_8(&cpm->i2c_reg->i2add, 0x7f << 1);
+
+	/*
+	 * PDIV is set to 00 in i2mod, so brgclk/32 is used as input to the
+	 * i2c baud rate generator. This is divided by 2 x (DIV + 3) to get
+	 * the actual i2c bus frequency.
+	 */
+	brg = get_brgfreq() / (32 * 2 * cpm->freq) - 3;
+	out_8(&cpm->i2c_reg->i2brg, brg);
+
+	out_8(&cpm->i2c_reg->i2mod, 0x00);
+	out_8(&cpm->i2c_reg->i2com, I2COM_MASTER);	/* Master mode */
+
+	/* Disable interrupts. */
+	out_8(&cpm->i2c_reg->i2cmr, 0);
+	out_8(&cpm->i2c_reg->i2cer, 0xff);
+
+	return 0;
+
+out_muram:
+	for (i = 0; i < CPM_MAXBD; i++) {
+		if (cpm->rxbuf[i])
+			dma_free_coherent(&cpm->ofdev->dev, CPM_MAX_READ + 1,
+				cpm->rxbuf[i], cpm->rxdma[i]);
+		if (cpm->txbuf[i])
+			dma_free_coherent(&cpm->ofdev->dev, CPM_MAX_READ + 1,
+				cpm->txbuf[i], cpm->txdma[i]);
+	}
+	cpm_muram_free(cpm->dp_addr);
+out_reg:
+	iounmap(cpm->i2c_reg);
+out_ram:
+	if ((cpm->version == 1) && (!cpm->i2c_addr))
+		iounmap(cpm->i2c_ram);
+	if (cpm->version == 2)
+		cpm_muram_free(cpm->i2c_addr);
+out_irq:
+	free_irq(cpm->irq, &cpm->adap);
+	return ret;
+}
+
+static void cpm_i2c_shutdown(struct cpm_i2c *cpm)
+{
+	int i;
+
+	/* Shut down I2C. */
+	clrbits8(&cpm->i2c_reg->i2mod, I2MOD_EN);
+
+	/* Disable interrupts */
+	out_8(&cpm->i2c_reg->i2cmr, 0);
+	out_8(&cpm->i2c_reg->i2cer, 0xff);
+
+	free_irq(cpm->irq, &cpm->adap);
+
+	/* Free all memory */
+	for (i = 0; i < CPM_MAXBD; i++) {
+		dma_free_coherent(&cpm->ofdev->dev, CPM_MAX_READ + 1,
+			cpm->rxbuf[i], cpm->rxdma[i]);
+		dma_free_coherent(&cpm->ofdev->dev, CPM_MAX_READ + 1,
+			cpm->txbuf[i], cpm->txdma[i]);
+	}
+
+	cpm_muram_free(cpm->dp_addr);
+	iounmap(cpm->i2c_reg);
+
+	if ((cpm->version == 1) && (!cpm->i2c_addr))
+		iounmap(cpm->i2c_ram);
+	if (cpm->version == 2)
+		cpm_muram_free(cpm->i2c_addr);
+}
+
+static int __devinit cpm_i2c_probe(struct platform_device *ofdev)
+{
+	int result, len;
+	struct cpm_i2c *cpm;
+	const u32 *data;
+
+	cpm = kzalloc(sizeof(struct cpm_i2c), GFP_KERNEL);
+	if (!cpm)
+		return -ENOMEM;
+
+	cpm->ofdev = ofdev;
+
+	dev_set_drvdata(&ofdev->dev, cpm);
+
+	cpm->adap = cpm_ops;
+	i2c_set_adapdata(&cpm->adap, cpm);
+	cpm->adap.dev.parent = &ofdev->dev;
+	cpm->adap.dev.of_node = of_node_get(ofdev->dev.of_node);
+
+	result = cpm_i2c_setup(cpm);
+	if (result) {
+		dev_err(&ofdev->dev, "Unable to init hardware\n");
+		goto out_free;
+	}
+
+	/* register new adapter to i2c module... */
+
+	data = of_get_property(ofdev->dev.of_node, "linux,i2c-index", &len);
+	cpm->adap.nr = (data && len == 4) ? be32_to_cpup(data) : -1;
+	result = i2c_add_numbered_adapter(&cpm->adap);
+
+	if (result < 0) {
+		dev_err(&ofdev->dev, "Unable to register with I2C\n");
+		goto out_shut;
+	}
+
+	dev_dbg(&ofdev->dev, "hw routines for %s registered.\n",
+		cpm->adap.name);
+
+	/*
+	 * register OF I2C devices
+	 */
+	of_i2c_register_devices(&cpm->adap);
+
+	return 0;
+out_shut:
+	cpm_i2c_shutdown(cpm);
+out_free:
+	dev_set_drvdata(&ofdev->dev, NULL);
+	kfree(cpm);
+
+	return result;
+}
+
+static int __devexit cpm_i2c_remove(struct platform_device *ofdev)
+{
+	struct cpm_i2c *cpm = dev_get_drvdata(&ofdev->dev);
+
+	i2c_del_adapter(&cpm->adap);
+
+	cpm_i2c_shutdown(cpm);
+
+	dev_set_drvdata(&ofdev->dev, NULL);
+	kfree(cpm);
+
+	return 0;
+}
+
+static const struct of_device_id cpm_i2c_match[] = {
+	{
+		.compatible = "fsl,cpm1-i2c",
+	},
+	{
+		.compatible = "fsl,cpm2-i2c",
+	},
+	{},
+};
+
+MODULE_DEVICE_TABLE(of, cpm_i2c_match);
+
+static struct platform_driver cpm_i2c_driver = {
+	.probe		= cpm_i2c_probe,
+	.remove		= __devexit_p(cpm_i2c_remove),
+	.driver = {
+		.name = "fsl-i2c-cpm",
+		.owner = THIS_MODULE,
+		.of_match_table = cpm_i2c_match,
+	},
+};
+
+module_platform_driver(cpm_i2c_driver);
+
+MODULE_AUTHOR("Jochen Friedrich <jochen@scram.de>");
+MODULE_DESCRIPTION("I2C-Bus adapter routines for CPM boards");
+MODULE_LICENSE("GPL");
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-davinci.c b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-davinci.c
new file mode 100644
index 0000000..1837fe6
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-davinci.c
@@ -0,0 +1,828 @@
+/*
+ * TI DAVINCI I2C adapter driver.
+ *
+ * Copyright (C) 2006 Texas Instruments.
+ * Copyright (C) 2007 MontaVista Software Inc.
+ *
+ * Updated by Vinod & Sudhakar Feb 2005
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * ----------------------------------------------------------------------------
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/clk.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/cpufreq.h>
+#include <linux/gpio.h>
+
+#include <mach/hardware.h>
+#include <mach/i2c.h>
+
+/* ----- global defines ----------------------------------------------- */
+
+#define DAVINCI_I2C_TIMEOUT	(1*HZ)
+#define DAVINCI_I2C_MAX_TRIES	2
+#define I2C_DAVINCI_INTR_ALL    (DAVINCI_I2C_IMR_AAS | \
+				 DAVINCI_I2C_IMR_SCD | \
+				 DAVINCI_I2C_IMR_ARDY | \
+				 DAVINCI_I2C_IMR_NACK | \
+				 DAVINCI_I2C_IMR_AL)
+
+#define DAVINCI_I2C_OAR_REG	0x00
+#define DAVINCI_I2C_IMR_REG	0x04
+#define DAVINCI_I2C_STR_REG	0x08
+#define DAVINCI_I2C_CLKL_REG	0x0c
+#define DAVINCI_I2C_CLKH_REG	0x10
+#define DAVINCI_I2C_CNT_REG	0x14
+#define DAVINCI_I2C_DRR_REG	0x18
+#define DAVINCI_I2C_SAR_REG	0x1c
+#define DAVINCI_I2C_DXR_REG	0x20
+#define DAVINCI_I2C_MDR_REG	0x24
+#define DAVINCI_I2C_IVR_REG	0x28
+#define DAVINCI_I2C_EMDR_REG	0x2c
+#define DAVINCI_I2C_PSC_REG	0x30
+
+#define DAVINCI_I2C_IVR_AAS	0x07
+#define DAVINCI_I2C_IVR_SCD	0x06
+#define DAVINCI_I2C_IVR_XRDY	0x05
+#define DAVINCI_I2C_IVR_RDR	0x04
+#define DAVINCI_I2C_IVR_ARDY	0x03
+#define DAVINCI_I2C_IVR_NACK	0x02
+#define DAVINCI_I2C_IVR_AL	0x01
+
+#define DAVINCI_I2C_STR_BB	BIT(12)
+#define DAVINCI_I2C_STR_RSFULL	BIT(11)
+#define DAVINCI_I2C_STR_SCD	BIT(5)
+#define DAVINCI_I2C_STR_ARDY	BIT(2)
+#define DAVINCI_I2C_STR_NACK	BIT(1)
+#define DAVINCI_I2C_STR_AL	BIT(0)
+
+#define DAVINCI_I2C_MDR_NACK	BIT(15)
+#define DAVINCI_I2C_MDR_STT	BIT(13)
+#define DAVINCI_I2C_MDR_STP	BIT(11)
+#define DAVINCI_I2C_MDR_MST	BIT(10)
+#define DAVINCI_I2C_MDR_TRX	BIT(9)
+#define DAVINCI_I2C_MDR_XA	BIT(8)
+#define DAVINCI_I2C_MDR_RM	BIT(7)
+#define DAVINCI_I2C_MDR_IRS	BIT(5)
+
+#define DAVINCI_I2C_IMR_AAS	BIT(6)
+#define DAVINCI_I2C_IMR_SCD	BIT(5)
+#define DAVINCI_I2C_IMR_XRDY	BIT(4)
+#define DAVINCI_I2C_IMR_RRDY	BIT(3)
+#define DAVINCI_I2C_IMR_ARDY	BIT(2)
+#define DAVINCI_I2C_IMR_NACK	BIT(1)
+#define DAVINCI_I2C_IMR_AL	BIT(0)
+
+struct davinci_i2c_dev {
+	struct device           *dev;
+	void __iomem		*base;
+	struct completion	cmd_complete;
+	struct clk              *clk;
+	int			cmd_err;
+	u8			*buf;
+	size_t			buf_len;
+	int			irq;
+	int			stop;
+	u8			terminate;
+	struct i2c_adapter	adapter;
+#ifdef CONFIG_CPU_FREQ
+	struct completion	xfr_complete;
+	struct notifier_block	freq_transition;
+#endif
+};
+
+/* default platform data to use if not supplied in the platform_device */
+static struct davinci_i2c_platform_data davinci_i2c_platform_data_default = {
+	.bus_freq	= 100,
+	.bus_delay	= 0,
+};
+
+static inline void davinci_i2c_write_reg(struct davinci_i2c_dev *i2c_dev,
+					 int reg, u16 val)
+{
+	__raw_writew(val, i2c_dev->base + reg);
+}
+
+static inline u16 davinci_i2c_read_reg(struct davinci_i2c_dev *i2c_dev, int reg)
+{
+	return __raw_readw(i2c_dev->base + reg);
+}
+
+/* Generate a pulse on the i2c clock pin. */
+static void generic_i2c_clock_pulse(unsigned int scl_pin)
+{
+	u16 i;
+
+	if (scl_pin) {
+		/* Send high and low on the SCL line */
+		for (i = 0; i < 9; i++) {
+			gpio_set_value(scl_pin, 0);
+			udelay(20);
+			gpio_set_value(scl_pin, 1);
+			udelay(20);
+		}
+	}
+}
+
+/* This routine does i2c bus recovery as specified in the
+ * i2c protocol Rev. 03 section 3.16 titled "Bus clear"
+ */
+static void i2c_recover_bus(struct davinci_i2c_dev *dev)
+{
+	u32 flag = 0;
+	struct davinci_i2c_platform_data *pdata = dev->dev->platform_data;
+
+	dev_err(dev->dev, "initiating i2c bus recovery\n");
+	/* Send NACK to the slave */
+	flag = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG);
+	flag |=  DAVINCI_I2C_MDR_NACK;
+	/* write the data into mode register */
+	davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, flag);
+	if (pdata)
+		generic_i2c_clock_pulse(pdata->scl_pin);
+	/* Send STOP */
+	flag = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG);
+	flag |= DAVINCI_I2C_MDR_STP;
+	davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, flag);
+}
+
+static inline void davinci_i2c_reset_ctrl(struct davinci_i2c_dev *i2c_dev,
+								int val)
+{
+	u16 w;
+
+	w = davinci_i2c_read_reg(i2c_dev, DAVINCI_I2C_MDR_REG);
+	if (!val)	/* put I2C into reset */
+		w &= ~DAVINCI_I2C_MDR_IRS;
+	else		/* take I2C out of reset */
+		w |= DAVINCI_I2C_MDR_IRS;
+
+	davinci_i2c_write_reg(i2c_dev, DAVINCI_I2C_MDR_REG, w);
+}
+
+static void i2c_davinci_calc_clk_dividers(struct davinci_i2c_dev *dev)
+{
+	struct davinci_i2c_platform_data *pdata = dev->dev->platform_data;
+	u16 psc;
+	u32 clk;
+	u32 d;
+	u32 clkh;
+	u32 clkl;
+	u32 input_clock = clk_get_rate(dev->clk);
+
+	/* NOTE: I2C Clock divider programming info
+	 * As per I2C specs the following formulas provide prescaler
+	 * and low/high divider values
+	 * input clk --> PSC Div -----------> ICCL/H Div --> output clock
+	 *                       module clk
+	 *
+	 * output clk = module clk / (PSC + 1) [ (ICCL + d) + (ICCH + d) ]
+	 *
+	 * Thus,
+	 * (ICCL + ICCH) = clk = (input clk / ((psc +1) * output clk)) - 2d;
+	 *
+	 * where if PSC == 0, d = 7,
+	 *       if PSC == 1, d = 6
+	 *       if PSC > 1 , d = 5
+	 */
+
+	/* get minimum of 7 MHz clock, but max of 12 MHz */
+	psc = (input_clock / 7000000) - 1;
+	if ((input_clock / (psc + 1)) > 12000000)
+		psc++;	/* better to run under spec than over */
+	d = (psc >= 2) ? 5 : 7 - psc;
+
+	clk = ((input_clock / (psc + 1)) / (pdata->bus_freq * 1000)) - (d << 1);
+	clkh = clk >> 1;
+	clkl = clk - clkh;
+
+	davinci_i2c_write_reg(dev, DAVINCI_I2C_PSC_REG, psc);
+	davinci_i2c_write_reg(dev, DAVINCI_I2C_CLKH_REG, clkh);
+	davinci_i2c_write_reg(dev, DAVINCI_I2C_CLKL_REG, clkl);
+
+	dev_dbg(dev->dev, "input_clock = %d, CLK = %d\n", input_clock, clk);
+}
+
+/*
+ * This function configures I2C and brings I2C out of reset.
+ * This function is called during I2C init function. This function
+ * also gets called if I2C encounters any errors.
+ */
+static int i2c_davinci_init(struct davinci_i2c_dev *dev)
+{
+	struct davinci_i2c_platform_data *pdata = dev->dev->platform_data;
+
+	if (!pdata)
+		pdata = &davinci_i2c_platform_data_default;
+
+	/* put I2C into reset */
+	davinci_i2c_reset_ctrl(dev, 0);
+
+	/* compute clock dividers */
+	i2c_davinci_calc_clk_dividers(dev);
+
+	/* Respond at reserved "SMBus Host" slave address" (and zero);
+	 * we seem to have no option to not respond...
+	 */
+	davinci_i2c_write_reg(dev, DAVINCI_I2C_OAR_REG, 0x08);
+
+	dev_dbg(dev->dev, "PSC  = %d\n",
+		davinci_i2c_read_reg(dev, DAVINCI_I2C_PSC_REG));
+	dev_dbg(dev->dev, "CLKL = %d\n",
+		davinci_i2c_read_reg(dev, DAVINCI_I2C_CLKL_REG));
+	dev_dbg(dev->dev, "CLKH = %d\n",
+		davinci_i2c_read_reg(dev, DAVINCI_I2C_CLKH_REG));
+	dev_dbg(dev->dev, "bus_freq = %dkHz, bus_delay = %d\n",
+		pdata->bus_freq, pdata->bus_delay);
+
+	/* Take the I2C module out of reset: */
+	davinci_i2c_reset_ctrl(dev, 1);
+
+	/* Enable interrupts */
+	davinci_i2c_write_reg(dev, DAVINCI_I2C_IMR_REG, I2C_DAVINCI_INTR_ALL);
+
+	return 0;
+}
+
+/*
+ * Waiting for bus not busy
+ */
+static int i2c_davinci_wait_bus_not_busy(struct davinci_i2c_dev *dev,
+					 char allow_sleep)
+{
+	unsigned long timeout;
+	static u16 to_cnt;
+
+	timeout = jiffies + dev->adapter.timeout;
+	while (davinci_i2c_read_reg(dev, DAVINCI_I2C_STR_REG)
+	       & DAVINCI_I2C_STR_BB) {
+		if (to_cnt <= DAVINCI_I2C_MAX_TRIES) {
+			if (time_after(jiffies, timeout)) {
+				dev_warn(dev->dev,
+				"timeout waiting for bus ready\n");
+				to_cnt++;
+				return -ETIMEDOUT;
+			} else {
+				to_cnt = 0;
+				i2c_recover_bus(dev);
+				i2c_davinci_init(dev);
+			}
+		}
+		if (allow_sleep)
+			schedule_timeout(1);
+	}
+
+	return 0;
+}
+
+/*
+ * Low level master read/write transaction. This function is called
+ * from i2c_davinci_xfer.
+ */
+static int
+i2c_davinci_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop)
+{
+	struct davinci_i2c_dev *dev = i2c_get_adapdata(adap);
+	struct davinci_i2c_platform_data *pdata = dev->dev->platform_data;
+	u32 flag;
+	u16 w;
+	int r;
+
+	if (!pdata)
+		pdata = &davinci_i2c_platform_data_default;
+	/* Introduce a delay, required for some boards (e.g Davinci EVM) */
+	if (pdata->bus_delay)
+		udelay(pdata->bus_delay);
+
+	/* set the slave address */
+	davinci_i2c_write_reg(dev, DAVINCI_I2C_SAR_REG, msg->addr);
+
+	dev->buf = msg->buf;
+	dev->buf_len = msg->len;
+	dev->stop = stop;
+
+	davinci_i2c_write_reg(dev, DAVINCI_I2C_CNT_REG, dev->buf_len);
+
+	INIT_COMPLETION(dev->cmd_complete);
+	dev->cmd_err = 0;
+
+	/* Take I2C out of reset and configure it as master */
+	flag = DAVINCI_I2C_MDR_IRS | DAVINCI_I2C_MDR_MST;
+
+	/* if the slave address is ten bit address, enable XA bit */
+	if (msg->flags & I2C_M_TEN)
+		flag |= DAVINCI_I2C_MDR_XA;
+	if (!(msg->flags & I2C_M_RD))
+		flag |= DAVINCI_I2C_MDR_TRX;
+	if (msg->len == 0)
+		flag |= DAVINCI_I2C_MDR_RM;
+
+	/* Enable receive or transmit interrupts */
+	w = davinci_i2c_read_reg(dev, DAVINCI_I2C_IMR_REG);
+	if (msg->flags & I2C_M_RD)
+		w |= DAVINCI_I2C_IMR_RRDY;
+	else
+		w |= DAVINCI_I2C_IMR_XRDY;
+	davinci_i2c_write_reg(dev, DAVINCI_I2C_IMR_REG, w);
+
+	dev->terminate = 0;
+
+	/*
+	 * Write mode register first as needed for correct behaviour
+	 * on OMAP-L138, but don't set STT yet to avoid a race with XRDY
+	 * occurring before we have loaded DXR
+	 */
+	davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, flag);
+
+	/*
+	 * First byte should be set here, not after interrupt,
+	 * because transmit-data-ready interrupt can come before
+	 * NACK-interrupt during sending of previous message and
+	 * ICDXR may have wrong data
+	 * It also saves us one interrupt, slightly faster
+	 */
+	if ((!(msg->flags & I2C_M_RD)) && dev->buf_len) {
+		davinci_i2c_write_reg(dev, DAVINCI_I2C_DXR_REG, *dev->buf++);
+		dev->buf_len--;
+	}
+
+	/* Set STT to begin transmit now DXR is loaded */
+	flag |= DAVINCI_I2C_MDR_STT;
+	if (stop && msg->len != 0)
+		flag |= DAVINCI_I2C_MDR_STP;
+	davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, flag);
+
+	r = wait_for_completion_interruptible_timeout(&dev->cmd_complete,
+						      dev->adapter.timeout);
+	if (r == 0) {
+		dev_err(dev->dev, "controller timed out\n");
+		i2c_recover_bus(dev);
+		i2c_davinci_init(dev);
+		dev->buf_len = 0;
+		return -ETIMEDOUT;
+	}
+	if (dev->buf_len) {
+		/* This should be 0 if all bytes were transferred
+		 * or dev->cmd_err denotes an error.
+		 * A signal may have aborted the transfer.
+		 */
+		if (r >= 0) {
+			dev_err(dev->dev, "abnormal termination buf_len=%i\n",
+				dev->buf_len);
+			r = -EREMOTEIO;
+		}
+		dev->terminate = 1;
+		wmb();
+		dev->buf_len = 0;
+	}
+	if (r < 0)
+		return r;
+
+	/* no error */
+	if (likely(!dev->cmd_err))
+		return msg->len;
+
+	/* We have an error */
+	if (dev->cmd_err & DAVINCI_I2C_STR_AL) {
+		i2c_davinci_init(dev);
+		return -EIO;
+	}
+
+	if (dev->cmd_err & DAVINCI_I2C_STR_NACK) {
+		if (msg->flags & I2C_M_IGNORE_NAK)
+			return msg->len;
+		w = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG);
+		w |= DAVINCI_I2C_MDR_STP;
+		davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, w);
+		return -EREMOTEIO;
+	}
+	return -EIO;
+}
+
+/*
+ * Prepare controller for a transaction and call i2c_davinci_xfer_msg
+ */
+static int
+i2c_davinci_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
+{
+	struct davinci_i2c_dev *dev = i2c_get_adapdata(adap);
+	int i;
+	int ret;
+
+	dev_dbg(dev->dev, "%s: msgs: %d\n", __func__, num);
+
+	ret = i2c_davinci_wait_bus_not_busy(dev, 1);
+	if (ret < 0) {
+		dev_warn(dev->dev, "timeout waiting for bus ready\n");
+		return ret;
+	}
+
+	for (i = 0; i < num; i++) {
+		ret = i2c_davinci_xfer_msg(adap, &msgs[i], (i == (num - 1)));
+		dev_dbg(dev->dev, "%s [%d/%d] ret: %d\n", __func__, i + 1, num,
+			ret);
+		if (ret < 0)
+			return ret;
+	}
+
+#ifdef CONFIG_CPU_FREQ
+	complete(&dev->xfr_complete);
+#endif
+
+	return num;
+}
+
+static u32 i2c_davinci_func(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static void terminate_read(struct davinci_i2c_dev *dev)
+{
+	u16 w = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG);
+	w |= DAVINCI_I2C_MDR_NACK;
+	davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, w);
+
+	/* Throw away data */
+	davinci_i2c_read_reg(dev, DAVINCI_I2C_DRR_REG);
+	if (!dev->terminate)
+		dev_err(dev->dev, "RDR IRQ while no data requested\n");
+}
+static void terminate_write(struct davinci_i2c_dev *dev)
+{
+	u16 w = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG);
+	w |= DAVINCI_I2C_MDR_RM | DAVINCI_I2C_MDR_STP;
+	davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, w);
+
+	if (!dev->terminate)
+		dev_dbg(dev->dev, "TDR IRQ while no data to send\n");
+}
+
+/*
+ * Interrupt service routine. This gets called whenever an I2C interrupt
+ * occurs.
+ */
+static irqreturn_t i2c_davinci_isr(int this_irq, void *dev_id)
+{
+	struct davinci_i2c_dev *dev = dev_id;
+	u32 stat;
+	int count = 0;
+	u16 w;
+
+	while ((stat = davinci_i2c_read_reg(dev, DAVINCI_I2C_IVR_REG))) {
+		dev_dbg(dev->dev, "%s: stat=0x%x\n", __func__, stat);
+		if (count++ == 100) {
+			dev_warn(dev->dev, "Too much work in one IRQ\n");
+			break;
+		}
+
+		switch (stat) {
+		case DAVINCI_I2C_IVR_AL:
+			/* Arbitration lost, must retry */
+			dev->cmd_err |= DAVINCI_I2C_STR_AL;
+			dev->buf_len = 0;
+			complete(&dev->cmd_complete);
+			break;
+
+		case DAVINCI_I2C_IVR_NACK:
+			dev->cmd_err |= DAVINCI_I2C_STR_NACK;
+			dev->buf_len = 0;
+			complete(&dev->cmd_complete);
+			break;
+
+		case DAVINCI_I2C_IVR_ARDY:
+			davinci_i2c_write_reg(dev,
+				DAVINCI_I2C_STR_REG, DAVINCI_I2C_STR_ARDY);
+			if (((dev->buf_len == 0) && (dev->stop != 0)) ||
+			    (dev->cmd_err & DAVINCI_I2C_STR_NACK)) {
+				w = davinci_i2c_read_reg(dev,
+							 DAVINCI_I2C_MDR_REG);
+				w |= DAVINCI_I2C_MDR_STP;
+				davinci_i2c_write_reg(dev,
+						      DAVINCI_I2C_MDR_REG, w);
+			}
+			complete(&dev->cmd_complete);
+			break;
+
+		case DAVINCI_I2C_IVR_RDR:
+			if (dev->buf_len) {
+				*dev->buf++ =
+				    davinci_i2c_read_reg(dev,
+							 DAVINCI_I2C_DRR_REG);
+				dev->buf_len--;
+				if (dev->buf_len)
+					continue;
+
+				davinci_i2c_write_reg(dev,
+					DAVINCI_I2C_STR_REG,
+					DAVINCI_I2C_IMR_RRDY);
+			} else {
+				/* signal can terminate transfer */
+				terminate_read(dev);
+			}
+			break;
+
+		case DAVINCI_I2C_IVR_XRDY:
+			if (dev->buf_len) {
+				davinci_i2c_write_reg(dev, DAVINCI_I2C_DXR_REG,
+						      *dev->buf++);
+				dev->buf_len--;
+				if (dev->buf_len)
+					continue;
+
+				w = davinci_i2c_read_reg(dev,
+							 DAVINCI_I2C_IMR_REG);
+				w &= ~DAVINCI_I2C_IMR_XRDY;
+				davinci_i2c_write_reg(dev,
+						      DAVINCI_I2C_IMR_REG,
+						      w);
+			} else {
+				/* signal can terminate transfer */
+				terminate_write(dev);
+			}
+			break;
+
+		case DAVINCI_I2C_IVR_SCD:
+			davinci_i2c_write_reg(dev,
+				DAVINCI_I2C_STR_REG, DAVINCI_I2C_STR_SCD);
+			complete(&dev->cmd_complete);
+			break;
+
+		case DAVINCI_I2C_IVR_AAS:
+			dev_dbg(dev->dev, "Address as slave interrupt\n");
+			break;
+
+		default:
+			dev_warn(dev->dev, "Unrecognized irq stat %d\n", stat);
+			break;
+		}
+	}
+
+	return count ? IRQ_HANDLED : IRQ_NONE;
+}
+
+#ifdef CONFIG_CPU_FREQ
+static int i2c_davinci_cpufreq_transition(struct notifier_block *nb,
+				     unsigned long val, void *data)
+{
+	struct davinci_i2c_dev *dev;
+
+	dev = container_of(nb, struct davinci_i2c_dev, freq_transition);
+	if (val == CPUFREQ_PRECHANGE) {
+		wait_for_completion(&dev->xfr_complete);
+		davinci_i2c_reset_ctrl(dev, 0);
+	} else if (val == CPUFREQ_POSTCHANGE) {
+		i2c_davinci_calc_clk_dividers(dev);
+		davinci_i2c_reset_ctrl(dev, 1);
+	}
+
+	return 0;
+}
+
+static inline int i2c_davinci_cpufreq_register(struct davinci_i2c_dev *dev)
+{
+	dev->freq_transition.notifier_call = i2c_davinci_cpufreq_transition;
+
+	return cpufreq_register_notifier(&dev->freq_transition,
+					 CPUFREQ_TRANSITION_NOTIFIER);
+}
+
+static inline void i2c_davinci_cpufreq_deregister(struct davinci_i2c_dev *dev)
+{
+	cpufreq_unregister_notifier(&dev->freq_transition,
+				    CPUFREQ_TRANSITION_NOTIFIER);
+}
+#else
+static inline int i2c_davinci_cpufreq_register(struct davinci_i2c_dev *dev)
+{
+	return 0;
+}
+
+static inline void i2c_davinci_cpufreq_deregister(struct davinci_i2c_dev *dev)
+{
+}
+#endif
+
+static struct i2c_algorithm i2c_davinci_algo = {
+	.master_xfer	= i2c_davinci_xfer,
+	.functionality	= i2c_davinci_func,
+};
+
+static int davinci_i2c_probe(struct platform_device *pdev)
+{
+	struct davinci_i2c_dev *dev;
+	struct i2c_adapter *adap;
+	struct resource *mem, *irq, *ioarea;
+	int r;
+
+	/* 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, resource_size(mem),
+				    pdev->name);
+	if (!ioarea) {
+		dev_err(&pdev->dev, "I2C region already claimed\n");
+		return -EBUSY;
+	}
+
+	dev = kzalloc(sizeof(struct davinci_i2c_dev), GFP_KERNEL);
+	if (!dev) {
+		r = -ENOMEM;
+		goto err_release_region;
+	}
+
+	init_completion(&dev->cmd_complete);
+#ifdef CONFIG_CPU_FREQ
+	init_completion(&dev->xfr_complete);
+#endif
+	dev->dev = get_device(&pdev->dev);
+	dev->irq = irq->start;
+	platform_set_drvdata(pdev, dev);
+
+	dev->clk = clk_get(&pdev->dev, NULL);
+	if (IS_ERR(dev->clk)) {
+		r = -ENODEV;
+		goto err_free_mem;
+	}
+	clk_enable(dev->clk);
+
+	dev->base = ioremap(mem->start, resource_size(mem));
+	if (!dev->base) {
+		r = -EBUSY;
+		goto err_mem_ioremap;
+	}
+
+	i2c_davinci_init(dev);
+
+	r = request_irq(dev->irq, i2c_davinci_isr, 0, pdev->name, dev);
+	if (r) {
+		dev_err(&pdev->dev, "failure requesting irq %i\n", dev->irq);
+		goto err_unuse_clocks;
+	}
+
+	r = i2c_davinci_cpufreq_register(dev);
+	if (r) {
+		dev_err(&pdev->dev, "failed to register cpufreq\n");
+		goto err_free_irq;
+	}
+
+	adap = &dev->adapter;
+	i2c_set_adapdata(adap, dev);
+	adap->owner = THIS_MODULE;
+	adap->class = I2C_CLASS_HWMON;
+	strlcpy(adap->name, "DaVinci I2C adapter", sizeof(adap->name));
+	adap->algo = &i2c_davinci_algo;
+	adap->dev.parent = &pdev->dev;
+	adap->timeout = DAVINCI_I2C_TIMEOUT;
+
+	adap->nr = pdev->id;
+	r = i2c_add_numbered_adapter(adap);
+	if (r) {
+		dev_err(&pdev->dev, "failure adding adapter\n");
+		goto err_free_irq;
+	}
+
+	return 0;
+
+err_free_irq:
+	free_irq(dev->irq, dev);
+err_unuse_clocks:
+	iounmap(dev->base);
+err_mem_ioremap:
+	clk_disable(dev->clk);
+	clk_put(dev->clk);
+	dev->clk = NULL;
+err_free_mem:
+	platform_set_drvdata(pdev, NULL);
+	put_device(&pdev->dev);
+	kfree(dev);
+err_release_region:
+	release_mem_region(mem->start, resource_size(mem));
+
+	return r;
+}
+
+static int davinci_i2c_remove(struct platform_device *pdev)
+{
+	struct davinci_i2c_dev *dev = platform_get_drvdata(pdev);
+	struct resource *mem;
+
+	i2c_davinci_cpufreq_deregister(dev);
+
+	platform_set_drvdata(pdev, NULL);
+	i2c_del_adapter(&dev->adapter);
+	put_device(&pdev->dev);
+
+	clk_disable(dev->clk);
+	clk_put(dev->clk);
+	dev->clk = NULL;
+
+	davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, 0);
+	free_irq(dev->irq, dev);
+	iounmap(dev->base);
+	kfree(dev);
+
+	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	release_mem_region(mem->start, resource_size(mem));
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int davinci_i2c_suspend(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct davinci_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
+
+	/* put I2C into reset */
+	davinci_i2c_reset_ctrl(i2c_dev, 0);
+	clk_disable(i2c_dev->clk);
+
+	return 0;
+}
+
+static int davinci_i2c_resume(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct davinci_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
+
+	clk_enable(i2c_dev->clk);
+	/* take I2C out of reset */
+	davinci_i2c_reset_ctrl(i2c_dev, 1);
+
+	return 0;
+}
+
+static const struct dev_pm_ops davinci_i2c_pm = {
+	.suspend        = davinci_i2c_suspend,
+	.resume         = davinci_i2c_resume,
+};
+
+#define davinci_i2c_pm_ops (&davinci_i2c_pm)
+#else
+#define davinci_i2c_pm_ops NULL
+#endif
+
+/* work with hotplug and coldplug */
+MODULE_ALIAS("platform:i2c_davinci");
+
+static struct platform_driver davinci_i2c_driver = {
+	.probe		= davinci_i2c_probe,
+	.remove		= davinci_i2c_remove,
+	.driver		= {
+		.name	= "i2c_davinci",
+		.owner	= THIS_MODULE,
+		.pm	= davinci_i2c_pm_ops,
+	},
+};
+
+/* I2C may be needed to bring up other drivers */
+static int __init davinci_i2c_init_driver(void)
+{
+	return platform_driver_register(&davinci_i2c_driver);
+}
+subsys_initcall(davinci_i2c_init_driver);
+
+static void __exit davinci_i2c_exit_driver(void)
+{
+	platform_driver_unregister(&davinci_i2c_driver);
+}
+module_exit(davinci_i2c_exit_driver);
+
+MODULE_AUTHOR("Texas Instruments India");
+MODULE_DESCRIPTION("TI DaVinci I2C bus adapter");
+MODULE_LICENSE("GPL");
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-designware-core.c b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-designware-core.c
new file mode 100644
index 0000000..aadb398
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-designware-core.c
@@ -0,0 +1,720 @@
+/*
+ * Synopsys DesignWare I2C adapter driver (master only).
+ *
+ * Based on the TI DAVINCI I2C adapter driver.
+ *
+ * Copyright (C) 2006 Texas Instruments.
+ * Copyright (C) 2007 MontaVista Software Inc.
+ * Copyright (C) 2009 Provigent Ltd.
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * ----------------------------------------------------------------------------
+ *
+ */
+#include <linux/export.h>
+#include <linux/clk.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/pm_runtime.h>
+#include <linux/delay.h>
+#include "i2c-designware-core.h"
+
+/*
+ * Registers offset
+ */
+#define DW_IC_CON		0x0
+#define DW_IC_TAR		0x4
+#define DW_IC_DATA_CMD		0x10
+#define DW_IC_SS_SCL_HCNT	0x14
+#define DW_IC_SS_SCL_LCNT	0x18
+#define DW_IC_FS_SCL_HCNT	0x1c
+#define DW_IC_FS_SCL_LCNT	0x20
+#define DW_IC_INTR_STAT		0x2c
+#define DW_IC_INTR_MASK		0x30
+#define DW_IC_RAW_INTR_STAT	0x34
+#define DW_IC_RX_TL		0x38
+#define DW_IC_TX_TL		0x3c
+#define DW_IC_CLR_INTR		0x40
+#define DW_IC_CLR_RX_UNDER	0x44
+#define DW_IC_CLR_RX_OVER	0x48
+#define DW_IC_CLR_TX_OVER	0x4c
+#define DW_IC_CLR_RD_REQ	0x50
+#define DW_IC_CLR_TX_ABRT	0x54
+#define DW_IC_CLR_RX_DONE	0x58
+#define DW_IC_CLR_ACTIVITY	0x5c
+#define DW_IC_CLR_STOP_DET	0x60
+#define DW_IC_CLR_START_DET	0x64
+#define DW_IC_CLR_GEN_CALL	0x68
+#define DW_IC_ENABLE		0x6c
+#define DW_IC_STATUS		0x70
+#define DW_IC_TXFLR		0x74
+#define DW_IC_RXFLR		0x78
+#define DW_IC_TX_ABRT_SOURCE	0x80
+#define DW_IC_COMP_PARAM_1	0xf4
+#define DW_IC_COMP_TYPE		0xfc
+#define DW_IC_COMP_TYPE_VALUE	0x44570140
+
+#define DW_IC_INTR_RX_UNDER	0x001
+#define DW_IC_INTR_RX_OVER	0x002
+#define DW_IC_INTR_RX_FULL	0x004
+#define DW_IC_INTR_TX_OVER	0x008
+#define DW_IC_INTR_TX_EMPTY	0x010
+#define DW_IC_INTR_RD_REQ	0x020
+#define DW_IC_INTR_TX_ABRT	0x040
+#define DW_IC_INTR_RX_DONE	0x080
+#define DW_IC_INTR_ACTIVITY	0x100
+#define DW_IC_INTR_STOP_DET	0x200
+#define DW_IC_INTR_START_DET	0x400
+#define DW_IC_INTR_GEN_CALL	0x800
+
+#define DW_IC_INTR_DEFAULT_MASK		(DW_IC_INTR_RX_FULL | \
+					 DW_IC_INTR_TX_EMPTY | \
+					 DW_IC_INTR_TX_ABRT | \
+					 DW_IC_INTR_STOP_DET)
+
+#define DW_IC_STATUS_ACTIVITY	0x1
+
+#define DW_IC_ERR_TX_ABRT	0x1
+
+/*
+ * status codes
+ */
+#define STATUS_IDLE			0x0
+#define STATUS_WRITE_IN_PROGRESS	0x1
+#define STATUS_READ_IN_PROGRESS		0x2
+
+#define TIMEOUT			20 /* ms */
+
+/*
+ * hardware abort codes from the DW_IC_TX_ABRT_SOURCE register
+ *
+ * only expected abort codes are listed here
+ * refer to the datasheet for the full list
+ */
+#define ABRT_7B_ADDR_NOACK	0
+#define ABRT_10ADDR1_NOACK	1
+#define ABRT_10ADDR2_NOACK	2
+#define ABRT_TXDATA_NOACK	3
+#define ABRT_GCALL_NOACK	4
+#define ABRT_GCALL_READ		5
+#define ABRT_SBYTE_ACKDET	7
+#define ABRT_SBYTE_NORSTRT	9
+#define ABRT_10B_RD_NORSTRT	10
+#define ABRT_MASTER_DIS		11
+#define ARB_LOST		12
+
+#define DW_IC_TX_ABRT_7B_ADDR_NOACK	(1UL << ABRT_7B_ADDR_NOACK)
+#define DW_IC_TX_ABRT_10ADDR1_NOACK	(1UL << ABRT_10ADDR1_NOACK)
+#define DW_IC_TX_ABRT_10ADDR2_NOACK	(1UL << ABRT_10ADDR2_NOACK)
+#define DW_IC_TX_ABRT_TXDATA_NOACK	(1UL << ABRT_TXDATA_NOACK)
+#define DW_IC_TX_ABRT_GCALL_NOACK	(1UL << ABRT_GCALL_NOACK)
+#define DW_IC_TX_ABRT_GCALL_READ	(1UL << ABRT_GCALL_READ)
+#define DW_IC_TX_ABRT_SBYTE_ACKDET	(1UL << ABRT_SBYTE_ACKDET)
+#define DW_IC_TX_ABRT_SBYTE_NORSTRT	(1UL << ABRT_SBYTE_NORSTRT)
+#define DW_IC_TX_ABRT_10B_RD_NORSTRT	(1UL << ABRT_10B_RD_NORSTRT)
+#define DW_IC_TX_ABRT_MASTER_DIS	(1UL << ABRT_MASTER_DIS)
+#define DW_IC_TX_ARB_LOST		(1UL << ARB_LOST)
+
+#define DW_IC_TX_ABRT_NOACK		(DW_IC_TX_ABRT_7B_ADDR_NOACK | \
+					 DW_IC_TX_ABRT_10ADDR1_NOACK | \
+					 DW_IC_TX_ABRT_10ADDR2_NOACK | \
+					 DW_IC_TX_ABRT_TXDATA_NOACK | \
+					 DW_IC_TX_ABRT_GCALL_NOACK)
+
+static char *abort_sources[] = {
+	[ABRT_7B_ADDR_NOACK] =
+		"slave address not acknowledged (7bit mode)",
+	[ABRT_10ADDR1_NOACK] =
+		"first address byte not acknowledged (10bit mode)",
+	[ABRT_10ADDR2_NOACK] =
+		"second address byte not acknowledged (10bit mode)",
+	[ABRT_TXDATA_NOACK] =
+		"data not acknowledged",
+	[ABRT_GCALL_NOACK] =
+		"no acknowledgement for a general call",
+	[ABRT_GCALL_READ] =
+		"read after general call",
+	[ABRT_SBYTE_ACKDET] =
+		"start byte acknowledged",
+	[ABRT_SBYTE_NORSTRT] =
+		"trying to send start byte when restart is disabled",
+	[ABRT_10B_RD_NORSTRT] =
+		"trying to read when restart is disabled (10bit mode)",
+	[ABRT_MASTER_DIS] =
+		"trying to use disabled adapter",
+	[ARB_LOST] =
+		"lost arbitration",
+};
+
+u32 dw_readl(struct dw_i2c_dev *dev, int offset)
+{
+	u32 value = readl(dev->base + offset);
+
+	if (dev->swab)
+		return swab32(value);
+	else
+		return value;
+}
+
+void dw_writel(struct dw_i2c_dev *dev, u32 b, int offset)
+{
+	if (dev->swab)
+		b = swab32(b);
+
+	writel(b, dev->base + offset);
+}
+
+static u32
+i2c_dw_scl_hcnt(u32 ic_clk, u32 tSYMBOL, u32 tf, int cond, int offset)
+{
+	/*
+	 * DesignWare I2C core doesn't seem to have solid strategy to meet
+	 * the tHD;STA timing spec.  Configuring _HCNT based on tHIGH spec
+	 * will result in violation of the tHD;STA spec.
+	 */
+	if (cond)
+		/*
+		 * Conditional expression:
+		 *
+		 *   IC_[FS]S_SCL_HCNT + (1+4+3) >= IC_CLK * tHIGH
+		 *
+		 * This is based on the DW manuals, and represents an ideal
+		 * configuration.  The resulting I2C bus speed will be
+		 * faster than any of the others.
+		 *
+		 * If your hardware is free from tHD;STA issue, try this one.
+		 */
+		return (ic_clk * tSYMBOL + 5000) / 10000 - 8 + offset;
+	else
+		/*
+		 * Conditional expression:
+		 *
+		 *   IC_[FS]S_SCL_HCNT + 3 >= IC_CLK * (tHD;STA + tf)
+		 *
+		 * This is just experimental rule; the tHD;STA period turned
+		 * out to be proportinal to (_HCNT + 3).  With this setting,
+		 * we could meet both tHIGH and tHD;STA timing specs.
+		 *
+		 * If unsure, you'd better to take this alternative.
+		 *
+		 * The reason why we need to take into account "tf" here,
+		 * is the same as described in i2c_dw_scl_lcnt().
+		 */
+		return (ic_clk * (tSYMBOL + tf) + 5000) / 10000 - 3 + offset;
+}
+
+static u32 i2c_dw_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, int offset)
+{
+	/*
+	 * Conditional expression:
+	 *
+	 *   IC_[FS]S_SCL_LCNT + 1 >= IC_CLK * (tLOW + tf)
+	 *
+	 * DW I2C core starts counting the SCL CNTs for the LOW period
+	 * of the SCL clock (tLOW) as soon as it pulls the SCL line.
+	 * In order to meet the tLOW timing spec, we need to take into
+	 * account the fall time of SCL signal (tf).  Default tf value
+	 * should be 0.3 us, for safety.
+	 */
+	return ((ic_clk * (tLOW + tf) + 5000) / 10000) - 1 + offset;
+}
+
+/**
+ * i2c_dw_init() - initialize the designware i2c master hardware
+ * @dev: device private data
+ *
+ * This functions configures and enables the I2C master.
+ * This function is called during I2C init function, and in case of timeout at
+ * run time.
+ */
+int i2c_dw_init(struct dw_i2c_dev *dev)
+{
+	u32 input_clock_khz;
+	u32 hcnt, lcnt;
+	u32 reg;
+
+	input_clock_khz = dev->get_clk_rate_khz(dev);
+
+	/* Configure register endianess access */
+	reg = dw_readl(dev, DW_IC_COMP_TYPE);
+	if (reg == ___constant_swab32(DW_IC_COMP_TYPE_VALUE)) {
+		dev->swab = 1;
+		reg = DW_IC_COMP_TYPE_VALUE;
+	}
+
+	if (reg != DW_IC_COMP_TYPE_VALUE) {
+		dev_err(dev->dev, "Unknown Synopsys component type: "
+			"0x%08x\n", reg);
+		return -ENODEV;
+	}
+
+	/* Disable the adapter */
+	dw_writel(dev, 0, DW_IC_ENABLE);
+
+	/* set standard and fast speed deviders for high/low periods */
+
+	/* Standard-mode */
+	hcnt = i2c_dw_scl_hcnt(input_clock_khz,
+				40,	/* tHD;STA = tHIGH = 4.0 us */
+				3,	/* tf = 0.3 us */
+				0,	/* 0: DW default, 1: Ideal */
+				0);	/* No offset */
+	lcnt = i2c_dw_scl_lcnt(input_clock_khz,
+				47,	/* tLOW = 4.7 us */
+				3,	/* tf = 0.3 us */
+				0);	/* No offset */
+	dw_writel(dev, hcnt, DW_IC_SS_SCL_HCNT);
+	dw_writel(dev, lcnt, DW_IC_SS_SCL_LCNT);
+	dev_dbg(dev->dev, "Standard-mode HCNT:LCNT = %d:%d\n", hcnt, lcnt);
+
+	/* Fast-mode */
+	hcnt = i2c_dw_scl_hcnt(input_clock_khz,
+				6,	/* tHD;STA = tHIGH = 0.6 us */
+				3,	/* tf = 0.3 us */
+				0,	/* 0: DW default, 1: Ideal */
+				0);	/* No offset */
+	lcnt = i2c_dw_scl_lcnt(input_clock_khz,
+				13,	/* tLOW = 1.3 us */
+				3,	/* tf = 0.3 us */
+				0);	/* No offset */
+	dw_writel(dev, hcnt, DW_IC_FS_SCL_HCNT);
+	dw_writel(dev, lcnt, DW_IC_FS_SCL_LCNT);
+	dev_dbg(dev->dev, "Fast-mode HCNT:LCNT = %d:%d\n", hcnt, lcnt);
+
+	/* Configure Tx/Rx FIFO threshold levels */
+	dw_writel(dev, dev->tx_fifo_depth - 1, DW_IC_TX_TL);
+	dw_writel(dev, 0, DW_IC_RX_TL);
+
+	/* configure the i2c master */
+	dw_writel(dev, dev->master_cfg , DW_IC_CON);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(i2c_dw_init);
+
+/*
+ * Waiting for bus not busy
+ */
+static int i2c_dw_wait_bus_not_busy(struct dw_i2c_dev *dev)
+{
+	int timeout = TIMEOUT;
+
+	while (dw_readl(dev, DW_IC_STATUS) & DW_IC_STATUS_ACTIVITY) {
+		if (timeout <= 0) {
+			dev_warn(dev->dev, "timeout waiting for bus ready\n");
+			return -ETIMEDOUT;
+		}
+		timeout--;
+		mdelay(1);
+	}
+
+	return 0;
+}
+
+static void i2c_dw_xfer_init(struct dw_i2c_dev *dev)
+{
+	struct i2c_msg *msgs = dev->msgs;
+	u32 ic_con;
+
+	/* Disable the adapter */
+	dw_writel(dev, 0, DW_IC_ENABLE);
+
+	/* set the slave (target) address */
+	dw_writel(dev, msgs[dev->msg_write_idx].addr, DW_IC_TAR);
+
+	/* if the slave address is ten bit address, enable 10BITADDR */
+	ic_con = dw_readl(dev, DW_IC_CON);
+	if (msgs[dev->msg_write_idx].flags & I2C_M_TEN)
+		ic_con |= DW_IC_CON_10BITADDR_MASTER;
+	else
+		ic_con &= ~DW_IC_CON_10BITADDR_MASTER;
+	dw_writel(dev, ic_con, DW_IC_CON);
+
+	/* enforce disabled interrupts (due to HW issues) */
+	i2c_dw_disable_int(dev);
+
+	/* Enable the adapter */
+	dw_writel(dev, 1, DW_IC_ENABLE);
+
+	/* Clear and enable interrupts */
+	i2c_dw_clear_int(dev);
+	dw_writel(dev, DW_IC_INTR_DEFAULT_MASK, DW_IC_INTR_MASK);
+}
+
+/*
+ * Initiate (and continue) low level master read/write transaction.
+ * This function is only called from i2c_dw_isr, and pumping i2c_msg
+ * messages into the tx buffer.  Even if the size of i2c_msg data is
+ * longer than the size of the tx buffer, it handles everything.
+ */
+void
+i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
+{
+	struct i2c_msg *msgs = dev->msgs;
+	u32 intr_mask;
+	int tx_limit, rx_limit;
+	u32 addr = msgs[dev->msg_write_idx].addr;
+	u32 buf_len = dev->tx_buf_len;
+	u8 *buf = dev->tx_buf;
+
+	intr_mask = DW_IC_INTR_DEFAULT_MASK;
+
+	for (; dev->msg_write_idx < dev->msgs_num; dev->msg_write_idx++) {
+		/*
+		 * if target address has changed, we need to
+		 * reprogram the target address in the i2c
+		 * adapter when we are done with this transfer
+		 */
+		if (msgs[dev->msg_write_idx].addr != addr) {
+			dev_err(dev->dev,
+				"%s: invalid target address\n", __func__);
+			dev->msg_err = -EINVAL;
+			break;
+		}
+
+		if (msgs[dev->msg_write_idx].len == 0) {
+			dev_err(dev->dev,
+				"%s: invalid message length\n", __func__);
+			dev->msg_err = -EINVAL;
+			break;
+		}
+
+		if (!(dev->status & STATUS_WRITE_IN_PROGRESS)) {
+			/* new i2c_msg */
+			buf = msgs[dev->msg_write_idx].buf;
+			buf_len = msgs[dev->msg_write_idx].len;
+		}
+
+		tx_limit = dev->tx_fifo_depth - dw_readl(dev, DW_IC_TXFLR);
+		rx_limit = dev->rx_fifo_depth - dw_readl(dev, DW_IC_RXFLR);
+
+		while (buf_len > 0 && tx_limit > 0 && rx_limit > 0) {
+			if (msgs[dev->msg_write_idx].flags & I2C_M_RD) {
+				dw_writel(dev, 0x100, DW_IC_DATA_CMD);
+				rx_limit--;
+			} else
+				dw_writel(dev, *buf++, DW_IC_DATA_CMD);
+			tx_limit--; buf_len--;
+		}
+
+		dev->tx_buf = buf;
+		dev->tx_buf_len = buf_len;
+
+		if (buf_len > 0) {
+			/* more bytes to be written */
+			dev->status |= STATUS_WRITE_IN_PROGRESS;
+			break;
+		} else
+			dev->status &= ~STATUS_WRITE_IN_PROGRESS;
+	}
+
+	/*
+	 * If i2c_msg index search is completed, we don't need TX_EMPTY
+	 * interrupt any more.
+	 */
+	if (dev->msg_write_idx == dev->msgs_num)
+		intr_mask &= ~DW_IC_INTR_TX_EMPTY;
+
+	if (dev->msg_err)
+		intr_mask = 0;
+
+	dw_writel(dev, intr_mask,  DW_IC_INTR_MASK);
+}
+
+static void
+i2c_dw_read(struct dw_i2c_dev *dev)
+{
+	struct i2c_msg *msgs = dev->msgs;
+	int rx_valid;
+
+	for (; dev->msg_read_idx < dev->msgs_num; dev->msg_read_idx++) {
+		u32 len;
+		u8 *buf;
+
+		if (!(msgs[dev->msg_read_idx].flags & I2C_M_RD))
+			continue;
+
+		if (!(dev->status & STATUS_READ_IN_PROGRESS)) {
+			len = msgs[dev->msg_read_idx].len;
+			buf = msgs[dev->msg_read_idx].buf;
+		} else {
+			len = dev->rx_buf_len;
+			buf = dev->rx_buf;
+		}
+
+		rx_valid = dw_readl(dev, DW_IC_RXFLR);
+
+		for (; len > 0 && rx_valid > 0; len--, rx_valid--)
+			*buf++ = dw_readl(dev, DW_IC_DATA_CMD);
+
+		if (len > 0) {
+			dev->status |= STATUS_READ_IN_PROGRESS;
+			dev->rx_buf_len = len;
+			dev->rx_buf = buf;
+			return;
+		} else
+			dev->status &= ~STATUS_READ_IN_PROGRESS;
+	}
+}
+
+static int i2c_dw_handle_tx_abort(struct dw_i2c_dev *dev)
+{
+	unsigned long abort_source = dev->abort_source;
+	int i;
+
+	if (abort_source & DW_IC_TX_ABRT_NOACK) {
+		for_each_set_bit(i, &abort_source, ARRAY_SIZE(abort_sources))
+			dev_dbg(dev->dev,
+				"%s: %s\n", __func__, abort_sources[i]);
+		return -EREMOTEIO;
+	}
+
+	for_each_set_bit(i, &abort_source, ARRAY_SIZE(abort_sources))
+		dev_err(dev->dev, "%s: %s\n", __func__, abort_sources[i]);
+
+	if (abort_source & DW_IC_TX_ARB_LOST)
+		return -EAGAIN;
+	else if (abort_source & DW_IC_TX_ABRT_GCALL_READ)
+		return -EINVAL; /* wrong msgs[] data */
+	else
+		return -EIO;
+}
+
+/*
+ * Prepare controller for a transaction and call i2c_dw_xfer_msg
+ */
+int
+i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
+{
+	struct dw_i2c_dev *dev = i2c_get_adapdata(adap);
+	int ret;
+
+	dev_dbg(dev->dev, "%s: msgs: %d\n", __func__, num);
+
+	mutex_lock(&dev->lock);
+	pm_runtime_get_sync(dev->dev);
+
+	INIT_COMPLETION(dev->cmd_complete);
+	dev->msgs = msgs;
+	dev->msgs_num = num;
+	dev->cmd_err = 0;
+	dev->msg_write_idx = 0;
+	dev->msg_read_idx = 0;
+	dev->msg_err = 0;
+	dev->status = STATUS_IDLE;
+	dev->abort_source = 0;
+
+	ret = i2c_dw_wait_bus_not_busy(dev);
+	if (ret < 0)
+		goto done;
+
+	/* start the transfers */
+	i2c_dw_xfer_init(dev);
+
+	/* wait for tx to complete */
+	ret = wait_for_completion_interruptible_timeout(&dev->cmd_complete, HZ);
+	if (ret == 0) {
+		dev_err(dev->dev, "controller timed out\n");
+		i2c_dw_init(dev);
+		ret = -ETIMEDOUT;
+		goto done;
+	} else if (ret < 0)
+		goto done;
+
+	if (dev->msg_err) {
+		ret = dev->msg_err;
+		goto done;
+	}
+
+	/* no error */
+	if (likely(!dev->cmd_err)) {
+		/* Disable the adapter */
+		dw_writel(dev, 0, DW_IC_ENABLE);
+		ret = num;
+		goto done;
+	}
+
+	/* We have an error */
+	if (dev->cmd_err == DW_IC_ERR_TX_ABRT) {
+		ret = i2c_dw_handle_tx_abort(dev);
+		goto done;
+	}
+	ret = -EIO;
+
+done:
+	pm_runtime_put(dev->dev);
+	mutex_unlock(&dev->lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(i2c_dw_xfer);
+
+u32 i2c_dw_func(struct i2c_adapter *adap)
+{
+	struct dw_i2c_dev *dev = i2c_get_adapdata(adap);
+	return dev->functionality;
+}
+EXPORT_SYMBOL_GPL(i2c_dw_func);
+
+static u32 i2c_dw_read_clear_intrbits(struct dw_i2c_dev *dev)
+{
+	u32 stat;
+
+	/*
+	 * The IC_INTR_STAT register just indicates "enabled" interrupts.
+	 * Ths unmasked raw version of interrupt status bits are available
+	 * in the IC_RAW_INTR_STAT register.
+	 *
+	 * That is,
+	 *   stat = dw_readl(IC_INTR_STAT);
+	 * equals to,
+	 *   stat = dw_readl(IC_RAW_INTR_STAT) & dw_readl(IC_INTR_MASK);
+	 *
+	 * The raw version might be useful for debugging purposes.
+	 */
+	stat = dw_readl(dev, DW_IC_INTR_STAT);
+
+	/*
+	 * Do not use the IC_CLR_INTR register to clear interrupts, or
+	 * you'll miss some interrupts, triggered during the period from
+	 * dw_readl(IC_INTR_STAT) to dw_readl(IC_CLR_INTR).
+	 *
+	 * Instead, use the separately-prepared IC_CLR_* registers.
+	 */
+	if (stat & DW_IC_INTR_RX_UNDER)
+		dw_readl(dev, DW_IC_CLR_RX_UNDER);
+	if (stat & DW_IC_INTR_RX_OVER)
+		dw_readl(dev, DW_IC_CLR_RX_OVER);
+	if (stat & DW_IC_INTR_TX_OVER)
+		dw_readl(dev, DW_IC_CLR_TX_OVER);
+	if (stat & DW_IC_INTR_RD_REQ)
+		dw_readl(dev, DW_IC_CLR_RD_REQ);
+	if (stat & DW_IC_INTR_TX_ABRT) {
+		/*
+		 * The IC_TX_ABRT_SOURCE register is cleared whenever
+		 * the IC_CLR_TX_ABRT is read.  Preserve it beforehand.
+		 */
+		dev->abort_source = dw_readl(dev, DW_IC_TX_ABRT_SOURCE);
+		dw_readl(dev, DW_IC_CLR_TX_ABRT);
+	}
+	if (stat & DW_IC_INTR_RX_DONE)
+		dw_readl(dev, DW_IC_CLR_RX_DONE);
+	if (stat & DW_IC_INTR_ACTIVITY)
+		dw_readl(dev, DW_IC_CLR_ACTIVITY);
+	if (stat & DW_IC_INTR_STOP_DET)
+		dw_readl(dev, DW_IC_CLR_STOP_DET);
+	if (stat & DW_IC_INTR_START_DET)
+		dw_readl(dev, DW_IC_CLR_START_DET);
+	if (stat & DW_IC_INTR_GEN_CALL)
+		dw_readl(dev, DW_IC_CLR_GEN_CALL);
+
+	return stat;
+}
+
+/*
+ * Interrupt service routine. This gets called whenever an I2C interrupt
+ * occurs.
+ */
+irqreturn_t i2c_dw_isr(int this_irq, void *dev_id)
+{
+	struct dw_i2c_dev *dev = dev_id;
+	u32 stat, enabled;
+
+	enabled = dw_readl(dev, DW_IC_ENABLE);
+	stat = dw_readl(dev, DW_IC_RAW_INTR_STAT);
+	dev_dbg(dev->dev, "%s:  %s enabled= 0x%x stat=0x%x\n", __func__,
+		dev->adapter.name, enabled, stat);
+	if (!enabled || !(stat & ~DW_IC_INTR_ACTIVITY))
+		return IRQ_NONE;
+
+	stat = i2c_dw_read_clear_intrbits(dev);
+
+	if (stat & DW_IC_INTR_TX_ABRT) {
+		dev->cmd_err |= DW_IC_ERR_TX_ABRT;
+		dev->status = STATUS_IDLE;
+
+		/*
+		 * Anytime TX_ABRT is set, the contents of the tx/rx
+		 * buffers are flushed.  Make sure to skip them.
+		 */
+		dw_writel(dev, 0, DW_IC_INTR_MASK);
+		goto tx_aborted;
+	}
+
+	if (stat & DW_IC_INTR_RX_FULL)
+		i2c_dw_read(dev);
+
+	if (stat & DW_IC_INTR_TX_EMPTY)
+		i2c_dw_xfer_msg(dev);
+
+	/*
+	 * No need to modify or disable the interrupt mask here.
+	 * i2c_dw_xfer_msg() will take care of it according to
+	 * the current transmit status.
+	 */
+
+tx_aborted:
+	if ((stat & (DW_IC_INTR_TX_ABRT | DW_IC_INTR_STOP_DET)) || dev->msg_err)
+		complete(&dev->cmd_complete);
+
+	return IRQ_HANDLED;
+}
+EXPORT_SYMBOL_GPL(i2c_dw_isr);
+
+void i2c_dw_enable(struct dw_i2c_dev *dev)
+{
+       /* Enable the adapter */
+	dw_writel(dev, 1, DW_IC_ENABLE);
+}
+EXPORT_SYMBOL_GPL(i2c_dw_enable);
+
+u32 i2c_dw_is_enabled(struct dw_i2c_dev *dev)
+{
+	return dw_readl(dev, DW_IC_ENABLE);
+}
+EXPORT_SYMBOL_GPL(i2c_dw_is_enabled);
+
+void i2c_dw_disable(struct dw_i2c_dev *dev)
+{
+	/* Disable controller */
+	dw_writel(dev, 0, DW_IC_ENABLE);
+
+	/* Disable all interupts */
+	dw_writel(dev, 0, DW_IC_INTR_MASK);
+	dw_readl(dev, DW_IC_CLR_INTR);
+}
+EXPORT_SYMBOL_GPL(i2c_dw_disable);
+
+void i2c_dw_clear_int(struct dw_i2c_dev *dev)
+{
+	dw_readl(dev, DW_IC_CLR_INTR);
+}
+EXPORT_SYMBOL_GPL(i2c_dw_clear_int);
+
+void i2c_dw_disable_int(struct dw_i2c_dev *dev)
+{
+	dw_writel(dev, 0, DW_IC_INTR_MASK);
+}
+EXPORT_SYMBOL_GPL(i2c_dw_disable_int);
+
+u32 i2c_dw_read_comp_param(struct dw_i2c_dev *dev)
+{
+	return dw_readl(dev, DW_IC_COMP_PARAM_1);
+}
+EXPORT_SYMBOL_GPL(i2c_dw_read_comp_param);
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-designware-core.h b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-designware-core.h
new file mode 100644
index 0000000..02d1a2d
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-designware-core.h
@@ -0,0 +1,105 @@
+/*
+ * Synopsys DesignWare I2C adapter driver (master only).
+ *
+ * Based on the TI DAVINCI I2C adapter driver.
+ *
+ * Copyright (C) 2006 Texas Instruments.
+ * Copyright (C) 2007 MontaVista Software Inc.
+ * Copyright (C) 2009 Provigent Ltd.
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * ----------------------------------------------------------------------------
+ *
+ */
+
+
+#define DW_IC_CON_MASTER		0x1
+#define DW_IC_CON_SPEED_STD		0x2
+#define DW_IC_CON_SPEED_FAST		0x4
+#define DW_IC_CON_10BITADDR_MASTER	0x10
+#define DW_IC_CON_RESTART_EN		0x20
+#define DW_IC_CON_SLAVE_DISABLE		0x40
+
+
+/**
+ * struct dw_i2c_dev - private i2c-designware data
+ * @dev: driver model device node
+ * @base: IO registers pointer
+ * @cmd_complete: tx completion indicator
+ * @lock: protect this struct and IO registers
+ * @clk: input reference clock
+ * @cmd_err: run time hadware error code
+ * @msgs: points to an array of messages currently being transfered
+ * @msgs_num: the number of elements in msgs
+ * @msg_write_idx: the element index of the current tx message in the msgs
+ *	array
+ * @tx_buf_len: the length of the current tx buffer
+ * @tx_buf: the current tx buffer
+ * @msg_read_idx: the element index of the current rx message in the msgs
+ *	array
+ * @rx_buf_len: the length of the current rx buffer
+ * @rx_buf: the current rx buffer
+ * @msg_err: error status of the current transfer
+ * @status: i2c master status, one of STATUS_*
+ * @abort_source: copy of the TX_ABRT_SOURCE register
+ * @irq: interrupt number for the i2c master
+ * @adapter: i2c subsystem adapter node
+ * @tx_fifo_depth: depth of the hardware tx fifo
+ * @rx_fifo_depth: depth of the hardware rx fifo
+ */
+struct dw_i2c_dev {
+	struct device		*dev;
+	void __iomem		*base;
+	struct completion	cmd_complete;
+	struct mutex		lock;
+	struct clk		*clk;
+	u32			(*get_clk_rate_khz) (struct dw_i2c_dev *dev);
+	struct dw_pci_controller *controller;
+	int			cmd_err;
+	struct i2c_msg		*msgs;
+	int			msgs_num;
+	int			msg_write_idx;
+	u32			tx_buf_len;
+	u8			*tx_buf;
+	int			msg_read_idx;
+	u32			rx_buf_len;
+	u8			*rx_buf;
+	int			msg_err;
+	unsigned int		status;
+	u32			abort_source;
+	int			irq;
+	int			swab;
+	struct i2c_adapter	adapter;
+	u32			functionality;
+	u32			master_cfg;
+	unsigned int		tx_fifo_depth;
+	unsigned int		rx_fifo_depth;
+};
+
+extern u32 dw_readl(struct dw_i2c_dev *dev, int offset);
+extern void dw_writel(struct dw_i2c_dev *dev, u32 b, int offset);
+extern int i2c_dw_init(struct dw_i2c_dev *dev);
+extern int i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
+		int num);
+extern u32 i2c_dw_func(struct i2c_adapter *adap);
+extern irqreturn_t i2c_dw_isr(int this_irq, void *dev_id);
+extern void i2c_dw_enable(struct dw_i2c_dev *dev);
+extern u32 i2c_dw_is_enabled(struct dw_i2c_dev *dev);
+extern void i2c_dw_disable(struct dw_i2c_dev *dev);
+extern void i2c_dw_clear_int(struct dw_i2c_dev *dev);
+extern void i2c_dw_disable_int(struct dw_i2c_dev *dev);
+extern u32 i2c_dw_read_comp_param(struct dw_i2c_dev *dev);
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-designware-pcidrv.c b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-designware-pcidrv.c
new file mode 100644
index 0000000..00e8f21
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-designware-pcidrv.c
@@ -0,0 +1,391 @@
+/*
+ * Synopsys DesignWare I2C adapter driver (master only).
+ *
+ * Based on the TI DAVINCI I2C adapter driver.
+ *
+ * Copyright (C) 2006 Texas Instruments.
+ * Copyright (C) 2007 MontaVista Software Inc.
+ * Copyright (C) 2009 Provigent Ltd.
+ * Copyright (C) 2011 Intel corporation.
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * ----------------------------------------------------------------------------
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/pm_runtime.h>
+#include "i2c-designware-core.h"
+
+#define DRIVER_NAME "i2c-designware-pci"
+
+enum dw_pci_ctl_id_t {
+	moorestown_0,
+	moorestown_1,
+	moorestown_2,
+
+	medfield_0,
+	medfield_1,
+	medfield_2,
+	medfield_3,
+	medfield_4,
+	medfield_5,
+};
+
+struct dw_pci_controller {
+	u32 bus_num;
+	u32 bus_cfg;
+	u32 tx_fifo_depth;
+	u32 rx_fifo_depth;
+	u32 clk_khz;
+};
+
+#define INTEL_MID_STD_CFG  (DW_IC_CON_MASTER |			\
+				DW_IC_CON_SLAVE_DISABLE |	\
+				DW_IC_CON_RESTART_EN)
+
+static struct  dw_pci_controller  dw_pci_controllers[] = {
+	[moorestown_0] = {
+		.bus_num     = 0,
+		.bus_cfg   = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
+		.tx_fifo_depth = 32,
+		.rx_fifo_depth = 32,
+		.clk_khz      = 25000,
+	},
+	[moorestown_1] = {
+		.bus_num     = 1,
+		.bus_cfg   = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
+		.tx_fifo_depth = 32,
+		.rx_fifo_depth = 32,
+		.clk_khz      = 25000,
+	},
+	[moorestown_2] = {
+		.bus_num     = 2,
+		.bus_cfg   = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
+		.tx_fifo_depth = 32,
+		.rx_fifo_depth = 32,
+		.clk_khz      = 25000,
+	},
+	[medfield_0] = {
+		.bus_num     = 0,
+		.bus_cfg   = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
+		.tx_fifo_depth = 32,
+		.rx_fifo_depth = 32,
+		.clk_khz      = 25000,
+	},
+	[medfield_1] = {
+		.bus_num     = 1,
+		.bus_cfg   = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
+		.tx_fifo_depth = 32,
+		.rx_fifo_depth = 32,
+		.clk_khz      = 25000,
+	},
+	[medfield_2] = {
+		.bus_num     = 2,
+		.bus_cfg   = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
+		.tx_fifo_depth = 32,
+		.rx_fifo_depth = 32,
+		.clk_khz      = 25000,
+	},
+	[medfield_3] = {
+		.bus_num     = 3,
+		.bus_cfg   = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_STD,
+		.tx_fifo_depth = 32,
+		.rx_fifo_depth = 32,
+		.clk_khz      = 25000,
+	},
+	[medfield_4] = {
+		.bus_num     = 4,
+		.bus_cfg   = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
+		.tx_fifo_depth = 32,
+		.rx_fifo_depth = 32,
+		.clk_khz      = 25000,
+	},
+	[medfield_5] = {
+		.bus_num     = 5,
+		.bus_cfg   = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
+		.tx_fifo_depth = 32,
+		.rx_fifo_depth = 32,
+		.clk_khz      = 25000,
+	},
+};
+static struct i2c_algorithm i2c_dw_algo = {
+	.master_xfer	= i2c_dw_xfer,
+	.functionality	= i2c_dw_func,
+};
+
+static int i2c_dw_pci_suspend(struct device *dev)
+{
+	struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
+	struct dw_i2c_dev *i2c = pci_get_drvdata(pdev);
+	int err;
+
+
+	i2c_dw_disable(i2c);
+
+	err = pci_save_state(pdev);
+	if (err) {
+		dev_err(&pdev->dev, "pci_save_state failed\n");
+		return err;
+	}
+
+	err = pci_set_power_state(pdev, PCI_D3hot);
+	if (err) {
+		dev_err(&pdev->dev, "pci_set_power_state failed\n");
+		return err;
+	}
+
+	return 0;
+}
+
+static int i2c_dw_pci_resume(struct device *dev)
+{
+	struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
+	struct dw_i2c_dev *i2c = pci_get_drvdata(pdev);
+	int err;
+	u32 enabled;
+
+	enabled = i2c_dw_is_enabled(i2c);
+	if (enabled)
+		return 0;
+
+	err = pci_set_power_state(pdev, PCI_D0);
+	if (err) {
+		dev_err(&pdev->dev, "pci_set_power_state() failed\n");
+		return err;
+	}
+
+	pci_restore_state(pdev);
+
+	i2c_dw_init(i2c);
+	return 0;
+}
+
+static int i2c_dw_pci_runtime_idle(struct device *dev)
+{
+	int err = pm_schedule_suspend(dev, 500);
+	dev_dbg(dev, "runtime_idle called\n");
+
+	if (err != 0)
+		return 0;
+	return -EBUSY;
+}
+
+static const struct dev_pm_ops i2c_dw_pm_ops = {
+	.resume         = i2c_dw_pci_resume,
+	.suspend        = i2c_dw_pci_suspend,
+	SET_RUNTIME_PM_OPS(i2c_dw_pci_suspend, i2c_dw_pci_resume,
+			   i2c_dw_pci_runtime_idle)
+};
+
+static u32 i2c_dw_get_clk_rate_khz(struct dw_i2c_dev *dev)
+{
+	return dev->controller->clk_khz;
+}
+
+static int __devinit i2c_dw_pci_probe(struct pci_dev *pdev,
+const struct pci_device_id *id)
+{
+	struct dw_i2c_dev *dev;
+	struct i2c_adapter *adap;
+	unsigned long start, len;
+	void __iomem *base;
+	int r;
+	struct  dw_pci_controller *controller;
+
+	if (id->driver_data >= ARRAY_SIZE(dw_pci_controllers)) {
+		printk(KERN_ERR "dw_i2c_pci_probe: invalid driver data %ld\n",
+			id->driver_data);
+		return -EINVAL;
+	}
+
+	controller = &dw_pci_controllers[id->driver_data];
+
+	r = pci_enable_device(pdev);
+	if (r) {
+		dev_err(&pdev->dev, "Failed to enable I2C PCI device (%d)\n",
+			r);
+		goto exit;
+	}
+
+	/* Determine the address of the I2C area */
+	start = pci_resource_start(pdev, 0);
+	len = pci_resource_len(pdev, 0);
+	if (!start || len == 0) {
+		dev_err(&pdev->dev, "base address not set\n");
+		r = -ENODEV;
+		goto exit;
+	}
+
+	r = pci_request_region(pdev, 0, DRIVER_NAME);
+	if (r) {
+		dev_err(&pdev->dev, "failed to request I2C region "
+			"0x%lx-0x%lx\n", start,
+			(unsigned long)pci_resource_end(pdev, 0));
+		goto exit;
+	}
+
+	base = ioremap_nocache(start, len);
+	if (!base) {
+		dev_err(&pdev->dev, "I/O memory remapping failed\n");
+		r = -ENOMEM;
+		goto err_release_region;
+	}
+
+
+	dev = kzalloc(sizeof(struct dw_i2c_dev), GFP_KERNEL);
+	if (!dev) {
+		r = -ENOMEM;
+		goto err_release_region;
+	}
+
+	init_completion(&dev->cmd_complete);
+	mutex_init(&dev->lock);
+	dev->clk = NULL;
+	dev->controller = controller;
+	dev->get_clk_rate_khz = i2c_dw_get_clk_rate_khz;
+	dev->base = base;
+	dev->dev = get_device(&pdev->dev);
+	dev->functionality =
+		I2C_FUNC_I2C |
+		I2C_FUNC_SMBUS_BYTE |
+		I2C_FUNC_SMBUS_BYTE_DATA |
+		I2C_FUNC_SMBUS_WORD_DATA |
+		I2C_FUNC_SMBUS_I2C_BLOCK;
+	dev->master_cfg =  controller->bus_cfg;
+
+	pci_set_drvdata(pdev, dev);
+
+	dev->tx_fifo_depth = controller->tx_fifo_depth;
+	dev->rx_fifo_depth = controller->rx_fifo_depth;
+	r = i2c_dw_init(dev);
+	if (r)
+		goto err_iounmap;
+
+	adap = &dev->adapter;
+	i2c_set_adapdata(adap, dev);
+	adap->owner = THIS_MODULE;
+	adap->class = 0;
+	adap->algo = &i2c_dw_algo;
+	adap->dev.parent = &pdev->dev;
+	adap->nr = controller->bus_num;
+	snprintf(adap->name, sizeof(adap->name), "i2c-designware-pci-%d",
+		adap->nr);
+
+	r = request_irq(pdev->irq, i2c_dw_isr, IRQF_SHARED, adap->name, dev);
+	if (r) {
+		dev_err(&pdev->dev, "failure requesting irq %i\n", dev->irq);
+		goto err_iounmap;
+	}
+
+	i2c_dw_disable_int(dev);
+	i2c_dw_clear_int(dev);
+	r = i2c_add_numbered_adapter(adap);
+	if (r) {
+		dev_err(&pdev->dev, "failure adding adapter\n");
+		goto err_free_irq;
+	}
+
+	pm_runtime_put_noidle(&pdev->dev);
+	pm_runtime_allow(&pdev->dev);
+
+	return 0;
+
+err_free_irq:
+	free_irq(pdev->irq, dev);
+err_iounmap:
+	iounmap(dev->base);
+	pci_set_drvdata(pdev, NULL);
+	put_device(&pdev->dev);
+	kfree(dev);
+err_release_region:
+	pci_release_region(pdev, 0);
+exit:
+	return r;
+}
+
+static void __devexit i2c_dw_pci_remove(struct pci_dev *pdev)
+{
+	struct dw_i2c_dev *dev = pci_get_drvdata(pdev);
+
+	i2c_dw_disable(dev);
+	pm_runtime_forbid(&pdev->dev);
+	pm_runtime_get_noresume(&pdev->dev);
+
+	pci_set_drvdata(pdev, NULL);
+	i2c_del_adapter(&dev->adapter);
+	put_device(&pdev->dev);
+
+	free_irq(dev->irq, dev);
+	kfree(dev);
+	pci_release_region(pdev, 0);
+}
+
+/* work with hotplug and coldplug */
+MODULE_ALIAS("i2c_designware-pci");
+
+static DEFINE_PCI_DEVICE_TABLE(i2_designware_pci_ids) = {
+	/* Moorestown */
+	{ PCI_VDEVICE(INTEL, 0x0802), moorestown_0 },
+	{ PCI_VDEVICE(INTEL, 0x0803), moorestown_1 },
+	{ PCI_VDEVICE(INTEL, 0x0804), moorestown_2 },
+	/* Medfield */
+	{ PCI_VDEVICE(INTEL, 0x0817), medfield_3,},
+	{ PCI_VDEVICE(INTEL, 0x0818), medfield_4 },
+	{ PCI_VDEVICE(INTEL, 0x0819), medfield_5 },
+	{ PCI_VDEVICE(INTEL, 0x082C), medfield_0 },
+	{ PCI_VDEVICE(INTEL, 0x082D), medfield_1 },
+	{ PCI_VDEVICE(INTEL, 0x082E), medfield_2 },
+	{ 0,}
+};
+MODULE_DEVICE_TABLE(pci, i2_designware_pci_ids);
+
+static struct pci_driver dw_i2c_driver = {
+	.name		= DRIVER_NAME,
+	.id_table	= i2_designware_pci_ids,
+	.probe		= i2c_dw_pci_probe,
+	.remove		= __devexit_p(i2c_dw_pci_remove),
+	.driver         = {
+		.pm     = &i2c_dw_pm_ops,
+	},
+};
+
+static int __init dw_i2c_init_driver(void)
+{
+	return  pci_register_driver(&dw_i2c_driver);
+}
+module_init(dw_i2c_init_driver);
+
+static void __exit dw_i2c_exit_driver(void)
+{
+	pci_unregister_driver(&dw_i2c_driver);
+}
+module_exit(dw_i2c_exit_driver);
+
+MODULE_AUTHOR("Baruch Siach <baruch@tkos.co.il>");
+MODULE_DESCRIPTION("Synopsys DesignWare PCI I2C bus adapter");
+MODULE_LICENSE("GPL");
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-designware-platdrv.c b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-designware-platdrv.c
new file mode 100644
index 0000000..4ba589a
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-designware-platdrv.c
@@ -0,0 +1,227 @@
+/*
+ * Synopsys DesignWare I2C adapter driver (master only).
+ *
+ * Based on the TI DAVINCI I2C adapter driver.
+ *
+ * Copyright (C) 2006 Texas Instruments.
+ * Copyright (C) 2007 MontaVista Software Inc.
+ * Copyright (C) 2009 Provigent Ltd.
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * ----------------------------------------------------------------------------
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/clk.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/of_i2c.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include "i2c-designware-core.h"
+
+static struct i2c_algorithm i2c_dw_algo = {
+	.master_xfer	= i2c_dw_xfer,
+	.functionality	= i2c_dw_func,
+};
+static u32 i2c_dw_get_clk_rate_khz(struct dw_i2c_dev *dev)
+{
+	return clk_get_rate(dev->clk)/1000;
+}
+
+static int __devinit dw_i2c_probe(struct platform_device *pdev)
+{
+	struct dw_i2c_dev *dev;
+	struct i2c_adapter *adap;
+	struct resource *mem, *ioarea;
+	int irq, r;
+
+	/* 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 -EINVAL;
+	}
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		dev_err(&pdev->dev, "no irq resource?\n");
+		return irq; /* -ENXIO */
+	}
+
+	ioarea = request_mem_region(mem->start, resource_size(mem),
+			pdev->name);
+	if (!ioarea) {
+		dev_err(&pdev->dev, "I2C region already claimed\n");
+		return -EBUSY;
+	}
+
+	dev = kzalloc(sizeof(struct dw_i2c_dev), GFP_KERNEL);
+	if (!dev) {
+		r = -ENOMEM;
+		goto err_release_region;
+	}
+
+	init_completion(&dev->cmd_complete);
+	mutex_init(&dev->lock);
+	dev->dev = get_device(&pdev->dev);
+	dev->irq = irq;
+	platform_set_drvdata(pdev, dev);
+
+	dev->clk = clk_get(&pdev->dev, NULL);
+	dev->get_clk_rate_khz = i2c_dw_get_clk_rate_khz;
+
+	if (IS_ERR(dev->clk)) {
+		r = -ENODEV;
+		goto err_free_mem;
+	}
+	clk_enable(dev->clk);
+
+	dev->functionality =
+		I2C_FUNC_I2C |
+		I2C_FUNC_10BIT_ADDR |
+		I2C_FUNC_SMBUS_BYTE |
+		I2C_FUNC_SMBUS_BYTE_DATA |
+		I2C_FUNC_SMBUS_WORD_DATA |
+		I2C_FUNC_SMBUS_I2C_BLOCK;
+	dev->master_cfg =  DW_IC_CON_MASTER | DW_IC_CON_SLAVE_DISABLE |
+		DW_IC_CON_RESTART_EN | DW_IC_CON_SPEED_FAST;
+
+	dev->base = ioremap(mem->start, resource_size(mem));
+	if (dev->base == NULL) {
+		dev_err(&pdev->dev, "failure mapping io resources\n");
+		r = -EBUSY;
+		goto err_unuse_clocks;
+	}
+	{
+		u32 param1 = i2c_dw_read_comp_param(dev);
+
+		dev->tx_fifo_depth = ((param1 >> 16) & 0xff) + 1;
+		dev->rx_fifo_depth = ((param1 >> 8)  & 0xff) + 1;
+	}
+	r = i2c_dw_init(dev);
+	if (r)
+		goto err_iounmap;
+
+	i2c_dw_disable_int(dev);
+	r = request_irq(dev->irq, i2c_dw_isr, IRQF_DISABLED, pdev->name, dev);
+	if (r) {
+		dev_err(&pdev->dev, "failure requesting irq %i\n", dev->irq);
+		goto err_iounmap;
+	}
+
+	adap = &dev->adapter;
+	i2c_set_adapdata(adap, dev);
+	adap->owner = THIS_MODULE;
+	adap->class = I2C_CLASS_HWMON;
+	strlcpy(adap->name, "Synopsys DesignWare I2C adapter",
+			sizeof(adap->name));
+	adap->algo = &i2c_dw_algo;
+	adap->dev.parent = &pdev->dev;
+	adap->dev.of_node = pdev->dev.of_node;
+
+	adap->nr = pdev->id;
+	r = i2c_add_numbered_adapter(adap);
+	if (r) {
+		dev_err(&pdev->dev, "failure adding adapter\n");
+		goto err_free_irq;
+	}
+	of_i2c_register_devices(adap);
+
+	return 0;
+
+err_free_irq:
+	free_irq(dev->irq, dev);
+err_iounmap:
+	iounmap(dev->base);
+err_unuse_clocks:
+	clk_disable(dev->clk);
+	clk_put(dev->clk);
+	dev->clk = NULL;
+err_free_mem:
+	platform_set_drvdata(pdev, NULL);
+	put_device(&pdev->dev);
+	kfree(dev);
+err_release_region:
+	release_mem_region(mem->start, resource_size(mem));
+
+	return r;
+}
+
+static int __devexit dw_i2c_remove(struct platform_device *pdev)
+{
+	struct dw_i2c_dev *dev = platform_get_drvdata(pdev);
+	struct resource *mem;
+
+	platform_set_drvdata(pdev, NULL);
+	i2c_del_adapter(&dev->adapter);
+	put_device(&pdev->dev);
+
+	clk_disable(dev->clk);
+	clk_put(dev->clk);
+	dev->clk = NULL;
+
+	i2c_dw_disable(dev);
+	free_irq(dev->irq, dev);
+	kfree(dev);
+
+	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	release_mem_region(mem->start, resource_size(mem));
+	return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id dw_i2c_of_match[] = {
+	{ .compatible = "snps,designware-i2c", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, dw_i2c_of_match);
+#endif
+
+/* work with hotplug and coldplug */
+MODULE_ALIAS("platform:i2c_designware");
+
+static struct platform_driver dw_i2c_driver = {
+	.remove		= __devexit_p(dw_i2c_remove),
+	.driver		= {
+		.name	= "i2c_designware",
+		.owner	= THIS_MODULE,
+		.of_match_table = of_match_ptr(dw_i2c_of_match),
+	},
+};
+
+static int __init dw_i2c_init_driver(void)
+{
+	return platform_driver_probe(&dw_i2c_driver, dw_i2c_probe);
+}
+subsys_initcall(dw_i2c_init_driver);
+
+static void __exit dw_i2c_exit_driver(void)
+{
+	platform_driver_unregister(&dw_i2c_driver);
+}
+module_exit(dw_i2c_exit_driver);
+
+MODULE_AUTHOR("Baruch Siach <baruch@tkos.co.il>");
+MODULE_DESCRIPTION("Synopsys DesignWare I2C bus adapter");
+MODULE_LICENSE("GPL");
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-diolan-u2c.c b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-diolan-u2c.c
new file mode 100644
index 0000000..7eb19a5
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-diolan-u2c.c
@@ -0,0 +1,522 @@
+/*
+ * Driver for the Diolan u2c-12 USB-I2C adapter
+ *
+ * Copyright (c) 2010-2011 Ericsson AB
+ *
+ * Derived from:
+ *  i2c-tiny-usb.c
+ *  Copyright (C) 2006-2007 Till Harbaum (Till@Harbaum.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+#include <linux/i2c.h>
+
+#define DRIVER_NAME		"i2c-diolan-u2c"
+
+#define USB_VENDOR_ID_DIOLAN		0x0abf
+#define USB_DEVICE_ID_DIOLAN_U2C	0x3370
+
+#define DIOLAN_OUT_EP		0x02
+#define DIOLAN_IN_EP		0x84
+
+/* commands via USB, must match command ids in the firmware */
+#define CMD_I2C_READ		0x01
+#define CMD_I2C_WRITE		0x02
+#define CMD_I2C_SCAN		0x03	/* Returns list of detected devices */
+#define CMD_I2C_RELEASE_SDA	0x04
+#define CMD_I2C_RELEASE_SCL	0x05
+#define CMD_I2C_DROP_SDA	0x06
+#define CMD_I2C_DROP_SCL	0x07
+#define CMD_I2C_READ_SDA	0x08
+#define CMD_I2C_READ_SCL	0x09
+#define CMD_GET_FW_VERSION	0x0a
+#define CMD_GET_SERIAL		0x0b
+#define CMD_I2C_START		0x0c
+#define CMD_I2C_STOP		0x0d
+#define CMD_I2C_REPEATED_START	0x0e
+#define CMD_I2C_PUT_BYTE	0x0f
+#define CMD_I2C_GET_BYTE	0x10
+#define CMD_I2C_PUT_ACK		0x11
+#define CMD_I2C_GET_ACK		0x12
+#define CMD_I2C_PUT_BYTE_ACK	0x13
+#define CMD_I2C_GET_BYTE_ACK	0x14
+#define CMD_I2C_SET_SPEED	0x1b
+#define CMD_I2C_GET_SPEED	0x1c
+#define CMD_I2C_SET_CLK_SYNC	0x24
+#define CMD_I2C_GET_CLK_SYNC	0x25
+#define CMD_I2C_SET_CLK_SYNC_TO	0x26
+#define CMD_I2C_GET_CLK_SYNC_TO	0x27
+
+#define RESP_OK			0x00
+#define RESP_FAILED		0x01
+#define RESP_BAD_MEMADDR	0x04
+#define RESP_DATA_ERR		0x05
+#define RESP_NOT_IMPLEMENTED	0x06
+#define RESP_NACK		0x07
+#define RESP_TIMEOUT		0x09
+
+#define U2C_I2C_SPEED_FAST	0	/* 400 kHz */
+#define U2C_I2C_SPEED_STD	1	/* 100 kHz */
+#define U2C_I2C_SPEED_2KHZ	242	/* 2 kHz, minimum speed */
+#define U2C_I2C_SPEED(f)	((DIV_ROUND_UP(1000000, (f)) - 10) / 2 + 1)
+
+#define U2C_I2C_FREQ_FAST	400000
+#define U2C_I2C_FREQ_STD	100000
+#define U2C_I2C_FREQ(s)		(1000000 / (2 * (s - 1) + 10))
+
+#define DIOLAN_USB_TIMEOUT	100	/* in ms */
+#define DIOLAN_SYNC_TIMEOUT	20	/* in ms */
+
+#define DIOLAN_OUTBUF_LEN	128
+#define DIOLAN_FLUSH_LEN	(DIOLAN_OUTBUF_LEN - 4)
+#define DIOLAN_INBUF_LEN	256	/* Maximum supported receive length */
+
+/* Structure to hold all of our device specific stuff */
+struct i2c_diolan_u2c {
+	u8 obuffer[DIOLAN_OUTBUF_LEN];	/* output buffer */
+	u8 ibuffer[DIOLAN_INBUF_LEN];	/* input buffer */
+	struct usb_device *usb_dev;	/* the usb device for this device */
+	struct usb_interface *interface;/* the interface for this device */
+	struct i2c_adapter adapter;	/* i2c related things */
+	int olen;			/* Output buffer length */
+	int ocount;			/* Number of enqueued messages */
+};
+
+static uint frequency = U2C_I2C_FREQ_STD;	/* I2C clock frequency in Hz */
+
+module_param(frequency, uint, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(frequency, "I2C clock frequency in hertz");
+
+/* usb layer */
+
+/* Send command to device, and get response. */
+static int diolan_usb_transfer(struct i2c_diolan_u2c *dev)
+{
+	int ret = 0;
+	int actual;
+	int i;
+
+	if (!dev->olen || !dev->ocount)
+		return -EINVAL;
+
+	ret = usb_bulk_msg(dev->usb_dev,
+			   usb_sndbulkpipe(dev->usb_dev, DIOLAN_OUT_EP),
+			   dev->obuffer, dev->olen, &actual,
+			   DIOLAN_USB_TIMEOUT);
+	if (!ret) {
+		for (i = 0; i < dev->ocount; i++) {
+			int tmpret;
+
+			tmpret = usb_bulk_msg(dev->usb_dev,
+					      usb_rcvbulkpipe(dev->usb_dev,
+							      DIOLAN_IN_EP),
+					      dev->ibuffer,
+					      sizeof(dev->ibuffer), &actual,
+					      DIOLAN_USB_TIMEOUT);
+			/*
+			 * Stop command processing if a previous command
+			 * returned an error.
+			 * Note that we still need to retrieve all messages.
+			 */
+			if (ret < 0)
+				continue;
+			ret = tmpret;
+			if (ret == 0 && actual > 0) {
+				switch (dev->ibuffer[actual - 1]) {
+				case RESP_NACK:
+					/*
+					 * Return ENXIO if NACK was received as
+					 * response to the address phase,
+					 * EIO otherwise
+					 */
+					ret = i == 1 ? -ENXIO : -EIO;
+					break;
+				case RESP_TIMEOUT:
+					ret = -ETIMEDOUT;
+					break;
+				case RESP_OK:
+					/* strip off return code */
+					ret = actual - 1;
+					break;
+				default:
+					ret = -EIO;
+					break;
+				}
+			}
+		}
+	}
+	dev->olen = 0;
+	dev->ocount = 0;
+	return ret;
+}
+
+static int diolan_write_cmd(struct i2c_diolan_u2c *dev, bool flush)
+{
+	if (flush || dev->olen >= DIOLAN_FLUSH_LEN)
+		return diolan_usb_transfer(dev);
+	return 0;
+}
+
+/* Send command (no data) */
+static int diolan_usb_cmd(struct i2c_diolan_u2c *dev, u8 command, bool flush)
+{
+	dev->obuffer[dev->olen++] = command;
+	dev->ocount++;
+	return diolan_write_cmd(dev, flush);
+}
+
+/* Send command with one byte of data */
+static int diolan_usb_cmd_data(struct i2c_diolan_u2c *dev, u8 command, u8 data,
+			       bool flush)
+{
+	dev->obuffer[dev->olen++] = command;
+	dev->obuffer[dev->olen++] = data;
+	dev->ocount++;
+	return diolan_write_cmd(dev, flush);
+}
+
+/* Send command with two bytes of data */
+static int diolan_usb_cmd_data2(struct i2c_diolan_u2c *dev, u8 command, u8 d1,
+				u8 d2, bool flush)
+{
+	dev->obuffer[dev->olen++] = command;
+	dev->obuffer[dev->olen++] = d1;
+	dev->obuffer[dev->olen++] = d2;
+	dev->ocount++;
+	return diolan_write_cmd(dev, flush);
+}
+
+/*
+ * Flush input queue.
+ * If we don't do this at startup and the controller has queued up
+ * messages which were not retrieved, it will stop responding
+ * at some point.
+ */
+static void diolan_flush_input(struct i2c_diolan_u2c *dev)
+{
+	int i;
+
+	for (i = 0; i < 10; i++) {
+		int actual = 0;
+		int ret;
+
+		ret = usb_bulk_msg(dev->usb_dev,
+				   usb_rcvbulkpipe(dev->usb_dev, DIOLAN_IN_EP),
+				   dev->ibuffer, sizeof(dev->ibuffer), &actual,
+				   DIOLAN_USB_TIMEOUT);
+		if (ret < 0 || actual == 0)
+			break;
+	}
+	if (i == 10)
+		dev_err(&dev->interface->dev, "Failed to flush input buffer\n");
+}
+
+static int diolan_i2c_start(struct i2c_diolan_u2c *dev)
+{
+	return diolan_usb_cmd(dev, CMD_I2C_START, false);
+}
+
+static int diolan_i2c_repeated_start(struct i2c_diolan_u2c *dev)
+{
+	return diolan_usb_cmd(dev, CMD_I2C_REPEATED_START, false);
+}
+
+static int diolan_i2c_stop(struct i2c_diolan_u2c *dev)
+{
+	return diolan_usb_cmd(dev, CMD_I2C_STOP, true);
+}
+
+static int diolan_i2c_get_byte_ack(struct i2c_diolan_u2c *dev, bool ack,
+				   u8 *byte)
+{
+	int ret;
+
+	ret = diolan_usb_cmd_data(dev, CMD_I2C_GET_BYTE_ACK, ack, true);
+	if (ret > 0)
+		*byte = dev->ibuffer[0];
+	else if (ret == 0)
+		ret = -EIO;
+
+	return ret;
+}
+
+static int diolan_i2c_put_byte_ack(struct i2c_diolan_u2c *dev, u8 byte)
+{
+	return diolan_usb_cmd_data(dev, CMD_I2C_PUT_BYTE_ACK, byte, false);
+}
+
+static int diolan_set_speed(struct i2c_diolan_u2c *dev, u8 speed)
+{
+	return diolan_usb_cmd_data(dev, CMD_I2C_SET_SPEED, speed, true);
+}
+
+/* Enable or disable clock synchronization (stretching) */
+static int diolan_set_clock_synch(struct i2c_diolan_u2c *dev, bool enable)
+{
+	return diolan_usb_cmd_data(dev, CMD_I2C_SET_CLK_SYNC, enable, true);
+}
+
+/* Set clock synchronization timeout in ms */
+static int diolan_set_clock_synch_timeout(struct i2c_diolan_u2c *dev, int ms)
+{
+	int to_val = ms * 10;
+
+	return diolan_usb_cmd_data2(dev, CMD_I2C_SET_CLK_SYNC_TO,
+				    to_val & 0xff, (to_val >> 8) & 0xff, true);
+}
+
+static void diolan_fw_version(struct i2c_diolan_u2c *dev)
+{
+	int ret;
+
+	ret = diolan_usb_cmd(dev, CMD_GET_FW_VERSION, true);
+	if (ret >= 2)
+		dev_info(&dev->interface->dev,
+			 "Diolan U2C firmware version %u.%u\n",
+			 (unsigned int)dev->ibuffer[0],
+			 (unsigned int)dev->ibuffer[1]);
+}
+
+static void diolan_get_serial(struct i2c_diolan_u2c *dev)
+{
+	int ret;
+	u32 serial;
+
+	ret = diolan_usb_cmd(dev, CMD_GET_SERIAL, true);
+	if (ret >= 4) {
+		serial = le32_to_cpu(*(u32 *)dev->ibuffer);
+		dev_info(&dev->interface->dev,
+			 "Diolan U2C serial number %u\n", serial);
+	}
+}
+
+static int diolan_init(struct i2c_diolan_u2c *dev)
+{
+	int speed, ret;
+
+	if (frequency >= 200000) {
+		speed = U2C_I2C_SPEED_FAST;
+		frequency = U2C_I2C_FREQ_FAST;
+	} else if (frequency >= 100000 || frequency == 0) {
+		speed = U2C_I2C_SPEED_STD;
+		frequency = U2C_I2C_FREQ_STD;
+	} else {
+		speed = U2C_I2C_SPEED(frequency);
+		if (speed > U2C_I2C_SPEED_2KHZ)
+			speed = U2C_I2C_SPEED_2KHZ;
+		frequency = U2C_I2C_FREQ(speed);
+	}
+
+	dev_info(&dev->interface->dev,
+		 "Diolan U2C at USB bus %03d address %03d speed %d Hz\n",
+		 dev->usb_dev->bus->busnum, dev->usb_dev->devnum, frequency);
+
+	diolan_flush_input(dev);
+	diolan_fw_version(dev);
+	diolan_get_serial(dev);
+
+	/* Set I2C speed */
+	ret = diolan_set_speed(dev, speed);
+	if (ret < 0)
+		return ret;
+
+	/* Configure I2C clock synchronization */
+	ret = diolan_set_clock_synch(dev, speed != U2C_I2C_SPEED_FAST);
+	if (ret < 0)
+		return ret;
+
+	if (speed != U2C_I2C_SPEED_FAST)
+		ret = diolan_set_clock_synch_timeout(dev, DIOLAN_SYNC_TIMEOUT);
+
+	return ret;
+}
+
+/* i2c layer */
+
+static int diolan_usb_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
+			   int num)
+{
+	struct i2c_diolan_u2c *dev = i2c_get_adapdata(adapter);
+	struct i2c_msg *pmsg;
+	int i, j;
+	int ret, sret;
+
+	ret = diolan_i2c_start(dev);
+	if (ret < 0)
+		return ret;
+
+	for (i = 0; i < num; i++) {
+		pmsg = &msgs[i];
+		if (i) {
+			ret = diolan_i2c_repeated_start(dev);
+			if (ret < 0)
+				goto abort;
+		}
+		if (pmsg->flags & I2C_M_RD) {
+			ret =
+			    diolan_i2c_put_byte_ack(dev, (pmsg->addr << 1) | 1);
+			if (ret < 0)
+				goto abort;
+			for (j = 0; j < pmsg->len; j++) {
+				u8 byte;
+				bool ack = j < pmsg->len - 1;
+
+				/*
+				 * Don't send NACK if this is the first byte
+				 * of a SMBUS_BLOCK message.
+				 */
+				if (j == 0 && (pmsg->flags & I2C_M_RECV_LEN))
+					ack = true;
+
+				ret = diolan_i2c_get_byte_ack(dev, ack, &byte);
+				if (ret < 0)
+					goto abort;
+				/*
+				 * Adjust count if first received byte is length
+				 */
+				if (j == 0 && (pmsg->flags & I2C_M_RECV_LEN)) {
+					if (byte == 0
+					    || byte > I2C_SMBUS_BLOCK_MAX) {
+						ret = -EPROTO;
+						goto abort;
+					}
+					pmsg->len += byte;
+				}
+				pmsg->buf[j] = byte;
+			}
+		} else {
+			ret = diolan_i2c_put_byte_ack(dev, pmsg->addr << 1);
+			if (ret < 0)
+				goto abort;
+			for (j = 0; j < pmsg->len; j++) {
+				ret = diolan_i2c_put_byte_ack(dev,
+							      pmsg->buf[j]);
+				if (ret < 0)
+					goto abort;
+			}
+		}
+	}
+abort:
+	sret = diolan_i2c_stop(dev);
+	if (sret < 0 && ret >= 0)
+		ret = sret;
+	return ret;
+}
+
+/*
+ * Return list of supported functionality.
+ */
+static u32 diolan_usb_func(struct i2c_adapter *a)
+{
+	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL |
+	       I2C_FUNC_SMBUS_READ_BLOCK_DATA | I2C_FUNC_SMBUS_BLOCK_PROC_CALL;
+}
+
+static const struct i2c_algorithm diolan_usb_algorithm = {
+	.master_xfer = diolan_usb_xfer,
+	.functionality = diolan_usb_func,
+};
+
+/* device layer */
+
+static const struct usb_device_id diolan_u2c_table[] = {
+	{ USB_DEVICE(USB_VENDOR_ID_DIOLAN, USB_DEVICE_ID_DIOLAN_U2C) },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(usb, diolan_u2c_table);
+
+static void diolan_u2c_free(struct i2c_diolan_u2c *dev)
+{
+	usb_put_dev(dev->usb_dev);
+	kfree(dev);
+}
+
+static int diolan_u2c_probe(struct usb_interface *interface,
+			    const struct usb_device_id *id)
+{
+	struct i2c_diolan_u2c *dev;
+	int ret;
+
+	/* allocate memory for our device state and initialize it */
+	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+	if (dev == NULL) {
+		dev_err(&interface->dev, "no memory for device state\n");
+		ret = -ENOMEM;
+		goto error;
+	}
+
+	dev->usb_dev = usb_get_dev(interface_to_usbdev(interface));
+	dev->interface = interface;
+
+	/* save our data pointer in this interface device */
+	usb_set_intfdata(interface, dev);
+
+	/* setup i2c adapter description */
+	dev->adapter.owner = THIS_MODULE;
+	dev->adapter.class = I2C_CLASS_HWMON;
+	dev->adapter.algo = &diolan_usb_algorithm;
+	i2c_set_adapdata(&dev->adapter, dev);
+	snprintf(dev->adapter.name, sizeof(dev->adapter.name),
+		 DRIVER_NAME " at bus %03d device %03d",
+		 dev->usb_dev->bus->busnum, dev->usb_dev->devnum);
+
+	dev->adapter.dev.parent = &dev->interface->dev;
+
+	/* initialize diolan i2c interface */
+	ret = diolan_init(dev);
+	if (ret < 0) {
+		dev_err(&interface->dev, "failed to initialize adapter\n");
+		goto error_free;
+	}
+
+	/* and finally attach to i2c layer */
+	ret = i2c_add_adapter(&dev->adapter);
+	if (ret < 0) {
+		dev_err(&interface->dev, "failed to add I2C adapter\n");
+		goto error_free;
+	}
+
+	dev_dbg(&interface->dev, "connected " DRIVER_NAME "\n");
+
+	return 0;
+
+error_free:
+	usb_set_intfdata(interface, NULL);
+	diolan_u2c_free(dev);
+error:
+	return ret;
+}
+
+static void diolan_u2c_disconnect(struct usb_interface *interface)
+{
+	struct i2c_diolan_u2c *dev = usb_get_intfdata(interface);
+
+	i2c_del_adapter(&dev->adapter);
+	usb_set_intfdata(interface, NULL);
+	diolan_u2c_free(dev);
+
+	dev_dbg(&interface->dev, "disconnected\n");
+}
+
+static struct usb_driver diolan_u2c_driver = {
+	.name = DRIVER_NAME,
+	.probe = diolan_u2c_probe,
+	.disconnect = diolan_u2c_disconnect,
+	.id_table = diolan_u2c_table,
+};
+
+module_usb_driver(diolan_u2c_driver);
+
+MODULE_AUTHOR("Guenter Roeck <guenter.roeck@ericsson.com>");
+MODULE_DESCRIPTION(DRIVER_NAME " driver");
+MODULE_LICENSE("GPL");
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-eg20t.c b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-eg20t.c
new file mode 100644
index 0000000..c811289
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-eg20t.c
@@ -0,0 +1,1068 @@
+/*
+ * Copyright (C) 2011 LAPIS Semiconductor Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/i2c.h>
+#include <linux/fs.h>
+#include <linux/io.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/jiffies.h>
+#include <linux/pci.h>
+#include <linux/mutex.h>
+#include <linux/ktime.h>
+#include <linux/slab.h>
+
+#define PCH_EVENT_SET	0	/* I2C Interrupt Event Set Status */
+#define PCH_EVENT_NONE	1	/* I2C Interrupt Event Clear Status */
+#define PCH_MAX_CLK		100000	/* Maximum Clock speed in MHz */
+#define PCH_BUFFER_MODE_ENABLE	0x0002	/* flag for Buffer mode enable */
+#define PCH_EEPROM_SW_RST_MODE_ENABLE	0x0008	/* EEPROM SW RST enable flag */
+
+#define PCH_I2CSADR	0x00	/* I2C slave address register */
+#define PCH_I2CCTL	0x04	/* I2C control register */
+#define PCH_I2CSR	0x08	/* I2C status register */
+#define PCH_I2CDR	0x0C	/* I2C data register */
+#define PCH_I2CMON	0x10	/* I2C bus monitor register */
+#define PCH_I2CBC	0x14	/* I2C bus transfer rate setup counter */
+#define PCH_I2CMOD	0x18	/* I2C mode register */
+#define PCH_I2CBUFSLV	0x1C	/* I2C buffer mode slave address register */
+#define PCH_I2CBUFSUB	0x20	/* I2C buffer mode subaddress register */
+#define PCH_I2CBUFFOR	0x24	/* I2C buffer mode format register */
+#define PCH_I2CBUFCTL	0x28	/* I2C buffer mode control register */
+#define PCH_I2CBUFMSK	0x2C	/* I2C buffer mode interrupt mask register */
+#define PCH_I2CBUFSTA	0x30	/* I2C buffer mode status register */
+#define PCH_I2CBUFLEV	0x34	/* I2C buffer mode level register */
+#define PCH_I2CESRFOR	0x38	/* EEPROM software reset mode format register */
+#define PCH_I2CESRCTL	0x3C	/* EEPROM software reset mode ctrl register */
+#define PCH_I2CESRMSK	0x40	/* EEPROM software reset mode */
+#define PCH_I2CESRSTA	0x44	/* EEPROM software reset mode status register */
+#define PCH_I2CTMR	0x48	/* I2C timer register */
+#define PCH_I2CSRST	0xFC	/* I2C reset register */
+#define PCH_I2CNF	0xF8	/* I2C noise filter register */
+
+#define BUS_IDLE_TIMEOUT	20
+#define PCH_I2CCTL_I2CMEN	0x0080
+#define TEN_BIT_ADDR_DEFAULT	0xF000
+#define TEN_BIT_ADDR_MASK	0xF0
+#define PCH_START		0x0020
+#define PCH_RESTART		0x0004
+#define PCH_ESR_START		0x0001
+#define PCH_BUFF_START		0x1
+#define PCH_REPSTART		0x0004
+#define PCH_ACK			0x0008
+#define PCH_GETACK		0x0001
+#define CLR_REG			0x0
+#define I2C_RD			0x1
+#define I2CMCF_BIT		0x0080
+#define I2CMIF_BIT		0x0002
+#define I2CMAL_BIT		0x0010
+#define I2CBMFI_BIT		0x0001
+#define I2CBMAL_BIT		0x0002
+#define I2CBMNA_BIT		0x0004
+#define I2CBMTO_BIT		0x0008
+#define I2CBMIS_BIT		0x0010
+#define I2CESRFI_BIT		0X0001
+#define I2CESRTO_BIT		0x0002
+#define I2CESRFIIE_BIT		0x1
+#define I2CESRTOIE_BIT		0x2
+#define I2CBMDZ_BIT		0x0040
+#define I2CBMAG_BIT		0x0020
+#define I2CMBB_BIT		0x0020
+#define BUFFER_MODE_MASK	(I2CBMFI_BIT | I2CBMAL_BIT | I2CBMNA_BIT | \
+				I2CBMTO_BIT | I2CBMIS_BIT)
+#define I2C_ADDR_MSK		0xFF
+#define I2C_MSB_2B_MSK		0x300
+#define FAST_MODE_CLK		400
+#define FAST_MODE_EN		0x0001
+#define SUB_ADDR_LEN_MAX	4
+#define BUF_LEN_MAX		32
+#define PCH_BUFFER_MODE		0x1
+#define EEPROM_SW_RST_MODE	0x0002
+#define NORMAL_INTR_ENBL	0x0300
+#define EEPROM_RST_INTR_ENBL	(I2CESRFIIE_BIT | I2CESRTOIE_BIT)
+#define EEPROM_RST_INTR_DISBL	0x0
+#define BUFFER_MODE_INTR_ENBL	0x001F
+#define BUFFER_MODE_INTR_DISBL	0x0
+#define NORMAL_MODE		0x0
+#define BUFFER_MODE		0x1
+#define EEPROM_SR_MODE		0x2
+#define I2C_TX_MODE		0x0010
+#define PCH_BUF_TX		0xFFF7
+#define PCH_BUF_RD		0x0008
+#define I2C_ERROR_MASK	(I2CESRTO_EVENT | I2CBMIS_EVENT | I2CBMTO_EVENT | \
+			I2CBMNA_EVENT | I2CBMAL_EVENT | I2CMAL_EVENT)
+#define I2CMAL_EVENT		0x0001
+#define I2CMCF_EVENT		0x0002
+#define I2CBMFI_EVENT		0x0004
+#define I2CBMAL_EVENT		0x0008
+#define I2CBMNA_EVENT		0x0010
+#define I2CBMTO_EVENT		0x0020
+#define I2CBMIS_EVENT		0x0040
+#define I2CESRFI_EVENT		0x0080
+#define I2CESRTO_EVENT		0x0100
+#define PCI_DEVICE_ID_PCH_I2C	0x8817
+
+#define pch_dbg(adap, fmt, arg...)  \
+	dev_dbg(adap->pch_adapter.dev.parent, "%s :" fmt, __func__, ##arg)
+
+#define pch_err(adap, fmt, arg...)  \
+	dev_err(adap->pch_adapter.dev.parent, "%s :" fmt, __func__, ##arg)
+
+#define pch_pci_err(pdev, fmt, arg...)  \
+	dev_err(&pdev->dev, "%s :" fmt, __func__, ##arg)
+
+#define pch_pci_dbg(pdev, fmt, arg...)  \
+	dev_dbg(&pdev->dev, "%s :" fmt, __func__, ##arg)
+
+/*
+Set the number of I2C instance max
+Intel EG20T PCH :		1ch
+LAPIS Semiconductor ML7213 IOH :	2ch
+LAPIS Semiconductor ML7831 IOH :	1ch
+*/
+#define PCH_I2C_MAX_DEV			2
+
+/**
+ * struct i2c_algo_pch_data - for I2C driver functionalities
+ * @pch_adapter:		stores the reference to i2c_adapter structure
+ * @p_adapter_info:		stores the reference to adapter_info structure
+ * @pch_base_address:		specifies the remapped base address
+ * @pch_buff_mode_en:		specifies if buffer mode is enabled
+ * @pch_event_flag:		specifies occurrence of interrupt events
+ * @pch_i2c_xfer_in_progress:	specifies whether the transfer is completed
+ */
+struct i2c_algo_pch_data {
+	struct i2c_adapter pch_adapter;
+	struct adapter_info *p_adapter_info;
+	void __iomem *pch_base_address;
+	int pch_buff_mode_en;
+	u32 pch_event_flag;
+	bool pch_i2c_xfer_in_progress;
+};
+
+/**
+ * struct adapter_info - This structure holds the adapter information for the
+			 PCH i2c controller
+ * @pch_data:		stores a list of i2c_algo_pch_data
+ * @pch_i2c_suspended:	specifies whether the system is suspended or not
+ *			perhaps with more lines and words.
+ * @ch_num:		specifies the number of i2c instance
+ *
+ * pch_data has as many elements as maximum I2C channels
+ */
+struct adapter_info {
+	struct i2c_algo_pch_data pch_data[PCH_I2C_MAX_DEV];
+	bool pch_i2c_suspended;
+	int ch_num;
+};
+
+
+static int pch_i2c_speed = 100; /* I2C bus speed in Kbps */
+static int pch_clk = 50000;	/* specifies I2C clock speed in KHz */
+static wait_queue_head_t pch_event;
+static DEFINE_MUTEX(pch_mutex);
+
+/* Definition for ML7213 by LAPIS Semiconductor */
+#define PCI_VENDOR_ID_ROHM		0x10DB
+#define PCI_DEVICE_ID_ML7213_I2C	0x802D
+#define PCI_DEVICE_ID_ML7223_I2C	0x8010
+#define PCI_DEVICE_ID_ML7831_I2C	0x8817
+
+static DEFINE_PCI_DEVICE_TABLE(pch_pcidev_id) = {
+	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_PCH_I2C),   1, },
+	{ PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7213_I2C), 2, },
+	{ PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7223_I2C), 1, },
+	{ PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7831_I2C), 1, },
+	{0,}
+};
+
+static irqreturn_t pch_i2c_handler(int irq, void *pData);
+
+static inline void pch_setbit(void __iomem *addr, u32 offset, u32 bitmask)
+{
+	u32 val;
+	val = ioread32(addr + offset);
+	val |= bitmask;
+	iowrite32(val, addr + offset);
+}
+
+static inline void pch_clrbit(void __iomem *addr, u32 offset, u32 bitmask)
+{
+	u32 val;
+	val = ioread32(addr + offset);
+	val &= (~bitmask);
+	iowrite32(val, addr + offset);
+}
+
+/**
+ * pch_i2c_init() - hardware initialization of I2C module
+ * @adap:	Pointer to struct i2c_algo_pch_data.
+ */
+static void pch_i2c_init(struct i2c_algo_pch_data *adap)
+{
+	void __iomem *p = adap->pch_base_address;
+	u32 pch_i2cbc;
+	u32 pch_i2ctmr;
+	u32 reg_value;
+
+	/* reset I2C controller */
+	iowrite32(0x01, p + PCH_I2CSRST);
+	msleep(20);
+	iowrite32(0x0, p + PCH_I2CSRST);
+
+	/* Initialize I2C registers */
+	iowrite32(0x21, p + PCH_I2CNF);
+
+	pch_setbit(adap->pch_base_address, PCH_I2CCTL, PCH_I2CCTL_I2CMEN);
+
+	if (pch_i2c_speed != 400)
+		pch_i2c_speed = 100;
+
+	reg_value = PCH_I2CCTL_I2CMEN;
+	if (pch_i2c_speed == FAST_MODE_CLK) {
+		reg_value |= FAST_MODE_EN;
+		pch_dbg(adap, "Fast mode enabled\n");
+	}
+
+	if (pch_clk > PCH_MAX_CLK)
+		pch_clk = 62500;
+
+	pch_i2cbc = (pch_clk + (pch_i2c_speed * 4)) / (pch_i2c_speed * 8);
+	/* Set transfer speed in I2CBC */
+	iowrite32(pch_i2cbc, p + PCH_I2CBC);
+
+	pch_i2ctmr = (pch_clk) / 8;
+	iowrite32(pch_i2ctmr, p + PCH_I2CTMR);
+
+	reg_value |= NORMAL_INTR_ENBL;	/* Enable interrupts in normal mode */
+	iowrite32(reg_value, p + PCH_I2CCTL);
+
+	pch_dbg(adap,
+		"I2CCTL=%x pch_i2cbc=%x pch_i2ctmr=%x Enable interrupts\n",
+		ioread32(p + PCH_I2CCTL), pch_i2cbc, pch_i2ctmr);
+
+	init_waitqueue_head(&pch_event);
+}
+
+static inline bool ktime_lt(const ktime_t cmp1, const ktime_t cmp2)
+{
+	return cmp1.tv64 < cmp2.tv64;
+}
+
+/**
+ * pch_i2c_wait_for_bus_idle() - check the status of bus.
+ * @adap:	Pointer to struct i2c_algo_pch_data.
+ * @timeout:	waiting time counter (ms).
+ */
+static s32 pch_i2c_wait_for_bus_idle(struct i2c_algo_pch_data *adap,
+				     s32 timeout)
+{
+	void __iomem *p = adap->pch_base_address;
+	int schedule = 0;
+	unsigned long end = jiffies + msecs_to_jiffies(timeout);
+
+	while (ioread32(p + PCH_I2CSR) & I2CMBB_BIT) {
+		if (time_after(jiffies, end)) {
+			pch_dbg(adap, "I2CSR = %x\n", ioread32(p + PCH_I2CSR));
+			pch_err(adap, "%s: Timeout Error.return%d\n",
+					__func__, -ETIME);
+			pch_i2c_init(adap);
+
+			return -ETIME;
+		}
+
+		if (!schedule)
+			/* Retry after some usecs */
+			udelay(5);
+		else
+			/* Wait a bit more without consuming CPU */
+			usleep_range(20, 1000);
+
+		schedule = 1;
+	}
+
+	return 0;
+}
+
+/**
+ * pch_i2c_start() - Generate I2C start condition in normal mode.
+ * @adap:	Pointer to struct i2c_algo_pch_data.
+ *
+ * Generate I2C start condition in normal mode by setting I2CCTL.I2CMSTA to 1.
+ */
+static void pch_i2c_start(struct i2c_algo_pch_data *adap)
+{
+	void __iomem *p = adap->pch_base_address;
+	pch_dbg(adap, "I2CCTL = %x\n", ioread32(p + PCH_I2CCTL));
+	pch_setbit(adap->pch_base_address, PCH_I2CCTL, PCH_START);
+}
+
+/**
+ * pch_i2c_wait_for_xfer_complete() - initiates a wait for the tx complete event
+ * @adap:	Pointer to struct i2c_algo_pch_data.
+ */
+static s32 pch_i2c_wait_for_xfer_complete(struct i2c_algo_pch_data *adap)
+{
+	long ret;
+	ret = wait_event_timeout(pch_event,
+			(adap->pch_event_flag != 0), msecs_to_jiffies(1000));
+
+	if (ret == 0) {
+		pch_err(adap, "timeout: %x\n", adap->pch_event_flag);
+		adap->pch_event_flag = 0;
+		return -ETIMEDOUT;
+	}
+
+	if (adap->pch_event_flag & I2C_ERROR_MASK) {
+		pch_err(adap, "error bits set: %x\n", adap->pch_event_flag);
+		adap->pch_event_flag = 0;
+		return -EIO;
+	}
+
+	adap->pch_event_flag = 0;
+
+	return 0;
+}
+
+/**
+ * pch_i2c_getack() - to confirm ACK/NACK
+ * @adap:	Pointer to struct i2c_algo_pch_data.
+ */
+static s32 pch_i2c_getack(struct i2c_algo_pch_data *adap)
+{
+	u32 reg_val;
+	void __iomem *p = adap->pch_base_address;
+	reg_val = ioread32(p + PCH_I2CSR) & PCH_GETACK;
+
+	if (reg_val != 0) {
+		pch_err(adap, "return%d\n", -EPROTO);
+		return -EPROTO;
+	}
+
+	return 0;
+}
+
+/**
+ * pch_i2c_stop() - generate stop condition in normal mode.
+ * @adap:	Pointer to struct i2c_algo_pch_data.
+ */
+static void pch_i2c_stop(struct i2c_algo_pch_data *adap)
+{
+	void __iomem *p = adap->pch_base_address;
+	pch_dbg(adap, "I2CCTL = %x\n", ioread32(p + PCH_I2CCTL));
+	/* clear the start bit */
+	pch_clrbit(adap->pch_base_address, PCH_I2CCTL, PCH_START);
+}
+
+/**
+ * pch_i2c_repstart() - generate repeated start condition in normal mode
+ * @adap:	Pointer to struct i2c_algo_pch_data.
+ */
+static void pch_i2c_repstart(struct i2c_algo_pch_data *adap)
+{
+	void __iomem *p = adap->pch_base_address;
+	pch_dbg(adap, "I2CCTL = %x\n", ioread32(p + PCH_I2CCTL));
+	pch_setbit(adap->pch_base_address, PCH_I2CCTL, PCH_REPSTART);
+}
+
+/**
+ * pch_i2c_writebytes() - write data to I2C bus in normal mode
+ * @i2c_adap:	Pointer to the struct i2c_adapter.
+ * @last:	specifies whether last message or not.
+ *		In the case of compound mode it will be 1 for last message,
+ *		otherwise 0.
+ * @first:	specifies whether first message or not.
+ *		1 for first message otherwise 0.
+ */
+static s32 pch_i2c_writebytes(struct i2c_adapter *i2c_adap,
+			      struct i2c_msg *msgs, u32 last, u32 first)
+{
+	struct i2c_algo_pch_data *adap = i2c_adap->algo_data;
+	u8 *buf;
+	u32 length;
+	u32 addr;
+	u32 addr_2_msb;
+	u32 addr_8_lsb;
+	s32 wrcount;
+	s32 rtn;
+	void __iomem *p = adap->pch_base_address;
+
+	length = msgs->len;
+	buf = msgs->buf;
+	addr = msgs->addr;
+
+	/* enable master tx */
+	pch_setbit(adap->pch_base_address, PCH_I2CCTL, I2C_TX_MODE);
+
+	pch_dbg(adap, "I2CCTL = %x msgs->len = %d\n", ioread32(p + PCH_I2CCTL),
+		length);
+
+	if (first) {
+		if (pch_i2c_wait_for_bus_idle(adap, BUS_IDLE_TIMEOUT) == -ETIME)
+			return -ETIME;
+	}
+
+	if (msgs->flags & I2C_M_TEN) {
+		addr_2_msb = ((addr & I2C_MSB_2B_MSK) >> 7) & 0x06;
+		iowrite32(addr_2_msb | TEN_BIT_ADDR_MASK, p + PCH_I2CDR);
+		if (first)
+			pch_i2c_start(adap);
+
+		rtn = pch_i2c_wait_for_xfer_complete(adap);
+		if (rtn == 0) {
+			if (pch_i2c_getack(adap)) {
+				pch_dbg(adap, "Receive NACK for slave address"
+					"setting\n");
+				return -EIO;
+			}
+			addr_8_lsb = (addr & I2C_ADDR_MSK);
+			iowrite32(addr_8_lsb, p + PCH_I2CDR);
+		} else if (rtn == -EIO) { /* Arbitration Lost */
+			pch_err(adap, "Lost Arbitration\n");
+			pch_clrbit(adap->pch_base_address, PCH_I2CSR,
+				   I2CMAL_BIT);
+			pch_clrbit(adap->pch_base_address, PCH_I2CSR,
+				   I2CMIF_BIT);
+			pch_i2c_init(adap);
+			return -EAGAIN;
+		} else { /* wait-event timeout */
+			pch_i2c_stop(adap);
+			return -ETIME;
+		}
+	} else {
+		/* set 7 bit slave address and R/W bit as 0 */
+		iowrite32(addr << 1, p + PCH_I2CDR);
+		if (first)
+			pch_i2c_start(adap);
+	}
+
+	rtn = pch_i2c_wait_for_xfer_complete(adap);
+	if (rtn == 0) {
+		if (pch_i2c_getack(adap)) {
+			pch_dbg(adap, "Receive NACK for slave address"
+				"setting\n");
+			return -EIO;
+		}
+	} else if (rtn == -EIO) { /* Arbitration Lost */
+		pch_err(adap, "Lost Arbitration\n");
+		pch_clrbit(adap->pch_base_address, PCH_I2CSR, I2CMAL_BIT);
+		pch_clrbit(adap->pch_base_address, PCH_I2CSR, I2CMIF_BIT);
+		pch_i2c_init(adap);
+		return -EAGAIN;
+	} else { /* wait-event timeout */
+		pch_i2c_stop(adap);
+		return -ETIME;
+	}
+
+	for (wrcount = 0; wrcount < length; ++wrcount) {
+		/* write buffer value to I2C data register */
+		iowrite32(buf[wrcount], p + PCH_I2CDR);
+		pch_dbg(adap, "writing %x to Data register\n", buf[wrcount]);
+
+		rtn = pch_i2c_wait_for_xfer_complete(adap);
+		if (rtn == 0) {
+			if (pch_i2c_getack(adap)) {
+				pch_dbg(adap, "Receive NACK for slave address"
+					"setting\n");
+				return -EIO;
+			}
+			pch_clrbit(adap->pch_base_address, PCH_I2CSR,
+				   I2CMCF_BIT);
+			pch_clrbit(adap->pch_base_address, PCH_I2CSR,
+				   I2CMIF_BIT);
+		} else { /* wait-event timeout */
+			pch_i2c_stop(adap);
+			return -ETIME;
+		}
+	}
+
+	/* check if this is the last message */
+	if (last)
+		pch_i2c_stop(adap);
+	else
+		pch_i2c_repstart(adap);
+
+	pch_dbg(adap, "return=%d\n", wrcount);
+
+	return wrcount;
+}
+
+/**
+ * pch_i2c_sendack() - send ACK
+ * @adap:	Pointer to struct i2c_algo_pch_data.
+ */
+static void pch_i2c_sendack(struct i2c_algo_pch_data *adap)
+{
+	void __iomem *p = adap->pch_base_address;
+	pch_dbg(adap, "I2CCTL = %x\n", ioread32(p + PCH_I2CCTL));
+	pch_clrbit(adap->pch_base_address, PCH_I2CCTL, PCH_ACK);
+}
+
+/**
+ * pch_i2c_sendnack() - send NACK
+ * @adap:	Pointer to struct i2c_algo_pch_data.
+ */
+static void pch_i2c_sendnack(struct i2c_algo_pch_data *adap)
+{
+	void __iomem *p = adap->pch_base_address;
+	pch_dbg(adap, "I2CCTL = %x\n", ioread32(p + PCH_I2CCTL));
+	pch_setbit(adap->pch_base_address, PCH_I2CCTL, PCH_ACK);
+}
+
+/**
+ * pch_i2c_restart() - Generate I2C restart condition in normal mode.
+ * @adap:	Pointer to struct i2c_algo_pch_data.
+ *
+ * Generate I2C restart condition in normal mode by setting I2CCTL.I2CRSTA.
+ */
+static void pch_i2c_restart(struct i2c_algo_pch_data *adap)
+{
+	void __iomem *p = adap->pch_base_address;
+	pch_dbg(adap, "I2CCTL = %x\n", ioread32(p + PCH_I2CCTL));
+	pch_setbit(adap->pch_base_address, PCH_I2CCTL, PCH_RESTART);
+}
+
+/**
+ * pch_i2c_readbytes() - read data  from I2C bus in normal mode.
+ * @i2c_adap:	Pointer to the struct i2c_adapter.
+ * @msgs:	Pointer to i2c_msg structure.
+ * @last:	specifies whether last message or not.
+ * @first:	specifies whether first message or not.
+ */
+static s32 pch_i2c_readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs,
+			     u32 last, u32 first)
+{
+	struct i2c_algo_pch_data *adap = i2c_adap->algo_data;
+
+	u8 *buf;
+	u32 count;
+	u32 length;
+	u32 addr;
+	u32 addr_2_msb;
+	u32 addr_8_lsb;
+	void __iomem *p = adap->pch_base_address;
+	s32 rtn;
+
+	length = msgs->len;
+	buf = msgs->buf;
+	addr = msgs->addr;
+
+	/* enable master reception */
+	pch_clrbit(adap->pch_base_address, PCH_I2CCTL, I2C_TX_MODE);
+
+	if (first) {
+		if (pch_i2c_wait_for_bus_idle(adap, BUS_IDLE_TIMEOUT) == -ETIME)
+			return -ETIME;
+	}
+
+	if (msgs->flags & I2C_M_TEN) {
+		addr_2_msb = ((addr & I2C_MSB_2B_MSK) >> 7);
+		iowrite32(addr_2_msb | TEN_BIT_ADDR_MASK, p + PCH_I2CDR);
+		if (first)
+			pch_i2c_start(adap);
+
+		rtn = pch_i2c_wait_for_xfer_complete(adap);
+		if (rtn == 0) {
+			if (pch_i2c_getack(adap)) {
+				pch_dbg(adap, "Receive NACK for slave address"
+					"setting\n");
+				return -EIO;
+			}
+			addr_8_lsb = (addr & I2C_ADDR_MSK);
+			iowrite32(addr_8_lsb, p + PCH_I2CDR);
+		} else if (rtn == -EIO) { /* Arbitration Lost */
+			pch_err(adap, "Lost Arbitration\n");
+			pch_clrbit(adap->pch_base_address, PCH_I2CSR,
+				   I2CMAL_BIT);
+			pch_clrbit(adap->pch_base_address, PCH_I2CSR,
+				   I2CMIF_BIT);
+			pch_i2c_init(adap);
+			return -EAGAIN;
+		} else { /* wait-event timeout */
+			pch_i2c_stop(adap);
+			return -ETIME;
+		}
+		pch_i2c_restart(adap);
+		rtn = pch_i2c_wait_for_xfer_complete(adap);
+		if (rtn == 0) {
+			if (pch_i2c_getack(adap)) {
+				pch_dbg(adap, "Receive NACK for slave address"
+					"setting\n");
+				return -EIO;
+			}
+			addr_2_msb |= I2C_RD;
+			iowrite32(addr_2_msb | TEN_BIT_ADDR_MASK,
+				  p + PCH_I2CDR);
+		} else if (rtn == -EIO) { /* Arbitration Lost */
+			pch_err(adap, "Lost Arbitration\n");
+			pch_clrbit(adap->pch_base_address, PCH_I2CSR,
+				   I2CMAL_BIT);
+			pch_clrbit(adap->pch_base_address, PCH_I2CSR,
+				   I2CMIF_BIT);
+			pch_i2c_init(adap);
+			return -EAGAIN;
+		} else { /* wait-event timeout */
+			pch_i2c_stop(adap);
+			return -ETIME;
+		}
+	} else {
+		/* 7 address bits + R/W bit */
+		addr = (((addr) << 1) | (I2C_RD));
+		iowrite32(addr, p + PCH_I2CDR);
+	}
+
+	/* check if it is the first message */
+	if (first)
+		pch_i2c_start(adap);
+
+	rtn = pch_i2c_wait_for_xfer_complete(adap);
+	if (rtn == 0) {
+		if (pch_i2c_getack(adap)) {
+			pch_dbg(adap, "Receive NACK for slave address"
+				"setting\n");
+			return -EIO;
+		}
+	} else if (rtn == -EIO) { /* Arbitration Lost */
+		pch_err(adap, "Lost Arbitration\n");
+		pch_clrbit(adap->pch_base_address, PCH_I2CSR, I2CMAL_BIT);
+		pch_clrbit(adap->pch_base_address, PCH_I2CSR, I2CMIF_BIT);
+		pch_i2c_init(adap);
+		return -EAGAIN;
+	} else { /* wait-event timeout */
+		pch_i2c_stop(adap);
+		return -ETIME;
+	}
+
+	if (length == 0) {
+		pch_i2c_stop(adap);
+		ioread32(p + PCH_I2CDR); /* Dummy read needs */
+
+		count = length;
+	} else {
+		int read_index;
+		int loop;
+		pch_i2c_sendack(adap);
+
+		/* Dummy read */
+		for (loop = 1, read_index = 0; loop < length; loop++) {
+			buf[read_index] = ioread32(p + PCH_I2CDR);
+
+			if (loop != 1)
+				read_index++;
+
+			rtn = pch_i2c_wait_for_xfer_complete(adap);
+			if (rtn == 0) {
+				if (pch_i2c_getack(adap)) {
+					pch_dbg(adap, "Receive NACK for slave"
+						"address setting\n");
+					return -EIO;
+				}
+			} else { /* wait-event timeout */
+				pch_i2c_stop(adap);
+				return -ETIME;
+			}
+
+		}	/* end for */
+
+		pch_i2c_sendnack(adap);
+
+		buf[read_index] = ioread32(p + PCH_I2CDR); /* Read final - 1 */
+
+		if (length != 1)
+			read_index++;
+
+		rtn = pch_i2c_wait_for_xfer_complete(adap);
+		if (rtn == 0) {
+			if (pch_i2c_getack(adap)) {
+				pch_dbg(adap, "Receive NACK for slave"
+					"address setting\n");
+				return -EIO;
+			}
+		} else { /* wait-event timeout */
+			pch_i2c_stop(adap);
+			return -ETIME;
+		}
+
+		if (last)
+			pch_i2c_stop(adap);
+		else
+			pch_i2c_repstart(adap);
+
+		buf[read_index++] = ioread32(p + PCH_I2CDR); /* Read Final */
+		count = read_index;
+	}
+
+	return count;
+}
+
+/**
+ * pch_i2c_cb() - Interrupt handler Call back function
+ * @adap:	Pointer to struct i2c_algo_pch_data.
+ */
+static void pch_i2c_cb(struct i2c_algo_pch_data *adap)
+{
+	u32 sts;
+	void __iomem *p = adap->pch_base_address;
+
+	sts = ioread32(p + PCH_I2CSR);
+	sts &= (I2CMAL_BIT | I2CMCF_BIT | I2CMIF_BIT);
+	if (sts & I2CMAL_BIT)
+		adap->pch_event_flag |= I2CMAL_EVENT;
+
+	if (sts & I2CMCF_BIT)
+		adap->pch_event_flag |= I2CMCF_EVENT;
+
+	/* clear the applicable bits */
+	pch_clrbit(adap->pch_base_address, PCH_I2CSR, sts);
+
+	pch_dbg(adap, "PCH_I2CSR = %x\n", ioread32(p + PCH_I2CSR));
+
+	wake_up(&pch_event);
+}
+
+/**
+ * pch_i2c_handler() - interrupt handler for the PCH I2C controller
+ * @irq:	irq number.
+ * @pData:	cookie passed back to the handler function.
+ */
+static irqreturn_t pch_i2c_handler(int irq, void *pData)
+{
+	u32 reg_val;
+	int flag;
+	int i;
+	struct adapter_info *adap_info = pData;
+	void __iomem *p;
+	u32 mode;
+
+	for (i = 0, flag = 0; i < adap_info->ch_num; i++) {
+		p = adap_info->pch_data[i].pch_base_address;
+		mode = ioread32(p + PCH_I2CMOD);
+		mode &= BUFFER_MODE | EEPROM_SR_MODE;
+		if (mode != NORMAL_MODE) {
+			pch_err(adap_info->pch_data,
+				"I2C-%d mode(%d) is not supported\n", mode, i);
+			continue;
+		}
+		reg_val = ioread32(p + PCH_I2CSR);
+		if (reg_val & (I2CMAL_BIT | I2CMCF_BIT | I2CMIF_BIT)) {
+			pch_i2c_cb(&adap_info->pch_data[i]);
+			flag = 1;
+		}
+	}
+
+	return flag ? IRQ_HANDLED : IRQ_NONE;
+}
+
+/**
+ * pch_i2c_xfer() - Reading adnd writing data through I2C bus
+ * @i2c_adap:	Pointer to the struct i2c_adapter.
+ * @msgs:	Pointer to i2c_msg structure.
+ * @num:	number of messages.
+ */
+static s32 pch_i2c_xfer(struct i2c_adapter *i2c_adap,
+			struct i2c_msg *msgs, s32 num)
+{
+	struct i2c_msg *pmsg;
+	u32 i = 0;
+	u32 status;
+	s32 ret;
+
+	struct i2c_algo_pch_data *adap = i2c_adap->algo_data;
+
+	ret = mutex_lock_interruptible(&pch_mutex);
+	if (ret)
+		return -ERESTARTSYS;
+
+	if (adap->p_adapter_info->pch_i2c_suspended) {
+		mutex_unlock(&pch_mutex);
+		return -EBUSY;
+	}
+
+	pch_dbg(adap, "adap->p_adapter_info->pch_i2c_suspended is %d\n",
+		adap->p_adapter_info->pch_i2c_suspended);
+	/* transfer not completed */
+	adap->pch_i2c_xfer_in_progress = true;
+
+	for (i = 0; i < num && ret >= 0; i++) {
+		pmsg = &msgs[i];
+		pmsg->flags |= adap->pch_buff_mode_en;
+		status = pmsg->flags;
+		pch_dbg(adap,
+			"After invoking I2C_MODE_SEL :flag= 0x%x\n", status);
+
+		if ((status & (I2C_M_RD)) != false) {
+			ret = pch_i2c_readbytes(i2c_adap, pmsg, (i + 1 == num),
+						(i == 0));
+		} else {
+			ret = pch_i2c_writebytes(i2c_adap, pmsg, (i + 1 == num),
+						 (i == 0));
+		}
+	}
+
+	adap->pch_i2c_xfer_in_progress = false;	/* transfer completed */
+
+	mutex_unlock(&pch_mutex);
+
+	return (ret < 0) ? ret : num;
+}
+
+/**
+ * pch_i2c_func() - return the functionality of the I2C driver
+ * @adap:	Pointer to struct i2c_algo_pch_data.
+ */
+static u32 pch_i2c_func(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR;
+}
+
+static struct i2c_algorithm pch_algorithm = {
+	.master_xfer = pch_i2c_xfer,
+	.functionality = pch_i2c_func
+};
+
+/**
+ * pch_i2c_disbl_int() - Disable PCH I2C interrupts
+ * @adap:	Pointer to struct i2c_algo_pch_data.
+ */
+static void pch_i2c_disbl_int(struct i2c_algo_pch_data *adap)
+{
+	void __iomem *p = adap->pch_base_address;
+
+	pch_clrbit(adap->pch_base_address, PCH_I2CCTL, NORMAL_INTR_ENBL);
+
+	iowrite32(EEPROM_RST_INTR_DISBL, p + PCH_I2CESRMSK);
+
+	iowrite32(BUFFER_MODE_INTR_DISBL, p + PCH_I2CBUFMSK);
+}
+
+static int __devinit pch_i2c_probe(struct pci_dev *pdev,
+				   const struct pci_device_id *id)
+{
+	void __iomem *base_addr;
+	int ret;
+	int i, j;
+	struct adapter_info *adap_info;
+	struct i2c_adapter *pch_adap;
+
+	pch_pci_dbg(pdev, "Entered.\n");
+
+	adap_info = kzalloc((sizeof(struct adapter_info)), GFP_KERNEL);
+	if (adap_info == NULL) {
+		pch_pci_err(pdev, "Memory allocation FAILED\n");
+		return -ENOMEM;
+	}
+
+	ret = pci_enable_device(pdev);
+	if (ret) {
+		pch_pci_err(pdev, "pci_enable_device FAILED\n");
+		goto err_pci_enable;
+	}
+
+	ret = pci_request_regions(pdev, KBUILD_MODNAME);
+	if (ret) {
+		pch_pci_err(pdev, "pci_request_regions FAILED\n");
+		goto err_pci_req;
+	}
+
+	base_addr = pci_iomap(pdev, 1, 0);
+
+	if (base_addr == NULL) {
+		pch_pci_err(pdev, "pci_iomap FAILED\n");
+		ret = -ENOMEM;
+		goto err_pci_iomap;
+	}
+
+	/* Set the number of I2C channel instance */
+	adap_info->ch_num = id->driver_data;
+
+	ret = request_irq(pdev->irq, pch_i2c_handler, IRQF_SHARED,
+		  KBUILD_MODNAME, adap_info);
+	if (ret) {
+		pch_pci_err(pdev, "request_irq FAILED\n");
+		goto err_request_irq;
+	}
+
+	for (i = 0; i < adap_info->ch_num; i++) {
+		pch_adap = &adap_info->pch_data[i].pch_adapter;
+		adap_info->pch_i2c_suspended = false;
+
+		adap_info->pch_data[i].p_adapter_info = adap_info;
+
+		pch_adap->owner = THIS_MODULE;
+		pch_adap->class = I2C_CLASS_HWMON;
+		strcpy(pch_adap->name, KBUILD_MODNAME);
+		pch_adap->algo = &pch_algorithm;
+		pch_adap->algo_data = &adap_info->pch_data[i];
+
+		/* base_addr + offset; */
+		adap_info->pch_data[i].pch_base_address = base_addr + 0x100 * i;
+
+		pch_adap->dev.parent = &pdev->dev;
+
+		pch_i2c_init(&adap_info->pch_data[i]);
+
+		pch_adap->nr = i;
+		ret = i2c_add_numbered_adapter(pch_adap);
+		if (ret) {
+			pch_pci_err(pdev, "i2c_add_adapter[ch:%d] FAILED\n", i);
+			goto err_add_adapter;
+		}
+	}
+
+	pci_set_drvdata(pdev, adap_info);
+	pch_pci_dbg(pdev, "returns %d.\n", ret);
+	return 0;
+
+err_add_adapter:
+	for (j = 0; j < i; j++)
+		i2c_del_adapter(&adap_info->pch_data[j].pch_adapter);
+	free_irq(pdev->irq, adap_info);
+err_request_irq:
+	pci_iounmap(pdev, base_addr);
+err_pci_iomap:
+	pci_release_regions(pdev);
+err_pci_req:
+	pci_disable_device(pdev);
+err_pci_enable:
+	kfree(adap_info);
+	return ret;
+}
+
+static void __devexit pch_i2c_remove(struct pci_dev *pdev)
+{
+	int i;
+	struct adapter_info *adap_info = pci_get_drvdata(pdev);
+
+	free_irq(pdev->irq, adap_info);
+
+	for (i = 0; i < adap_info->ch_num; i++) {
+		pch_i2c_disbl_int(&adap_info->pch_data[i]);
+		i2c_del_adapter(&adap_info->pch_data[i].pch_adapter);
+	}
+
+	if (adap_info->pch_data[0].pch_base_address)
+		pci_iounmap(pdev, adap_info->pch_data[0].pch_base_address);
+
+	for (i = 0; i < adap_info->ch_num; i++)
+		adap_info->pch_data[i].pch_base_address = 0;
+
+	pci_set_drvdata(pdev, NULL);
+
+	pci_release_regions(pdev);
+
+	pci_disable_device(pdev);
+	kfree(adap_info);
+}
+
+#ifdef CONFIG_PM
+static int pch_i2c_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+	int ret;
+	int i;
+	struct adapter_info *adap_info = pci_get_drvdata(pdev);
+	void __iomem *p = adap_info->pch_data[0].pch_base_address;
+
+	adap_info->pch_i2c_suspended = true;
+
+	for (i = 0; i < adap_info->ch_num; i++) {
+		while ((adap_info->pch_data[i].pch_i2c_xfer_in_progress)) {
+			/* Wait until all channel transfers are completed */
+			msleep(20);
+		}
+	}
+
+	/* Disable the i2c interrupts */
+	for (i = 0; i < adap_info->ch_num; i++)
+		pch_i2c_disbl_int(&adap_info->pch_data[i]);
+
+	pch_pci_dbg(pdev, "I2CSR = %x I2CBUFSTA = %x I2CESRSTA = %x "
+		"invoked function pch_i2c_disbl_int successfully\n",
+		ioread32(p + PCH_I2CSR), ioread32(p + PCH_I2CBUFSTA),
+		ioread32(p + PCH_I2CESRSTA));
+
+	ret = pci_save_state(pdev);
+
+	if (ret) {
+		pch_pci_err(pdev, "pci_save_state\n");
+		return ret;
+	}
+
+	pci_enable_wake(pdev, PCI_D3hot, 0);
+	pci_disable_device(pdev);
+	pci_set_power_state(pdev, pci_choose_state(pdev, state));
+
+	return 0;
+}
+
+static int pch_i2c_resume(struct pci_dev *pdev)
+{
+	int i;
+	struct adapter_info *adap_info = pci_get_drvdata(pdev);
+
+	pci_set_power_state(pdev, PCI_D0);
+	pci_restore_state(pdev);
+
+	if (pci_enable_device(pdev) < 0) {
+		pch_pci_err(pdev, "pch_i2c_resume:pci_enable_device FAILED\n");
+		return -EIO;
+	}
+
+	pci_enable_wake(pdev, PCI_D3hot, 0);
+
+	for (i = 0; i < adap_info->ch_num; i++)
+		pch_i2c_init(&adap_info->pch_data[i]);
+
+	adap_info->pch_i2c_suspended = false;
+
+	return 0;
+}
+#else
+#define pch_i2c_suspend NULL
+#define pch_i2c_resume NULL
+#endif
+
+static struct pci_driver pch_pcidriver = {
+	.name = KBUILD_MODNAME,
+	.id_table = pch_pcidev_id,
+	.probe = pch_i2c_probe,
+	.remove = __devexit_p(pch_i2c_remove),
+	.suspend = pch_i2c_suspend,
+	.resume = pch_i2c_resume
+};
+
+static int __init pch_pci_init(void)
+{
+	return pci_register_driver(&pch_pcidriver);
+}
+module_init(pch_pci_init);
+
+static void __exit pch_pci_exit(void)
+{
+	pci_unregister_driver(&pch_pcidriver);
+}
+module_exit(pch_pci_exit);
+
+MODULE_DESCRIPTION("Intel EG20T PCH/LAPIS Semico ML7213/ML7223/ML7831 IOH I2C");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Tomoya MORINAGA. <tomoya.rohm@gmail.com>");
+module_param(pch_i2c_speed, int, (S_IRUSR | S_IWUSR));
+module_param(pch_clk, int, (S_IRUSR | S_IWUSR));
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-elektor.c b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-elektor.c
new file mode 100644
index 0000000..37e2e82
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-elektor.c
@@ -0,0 +1,347 @@
+/* ------------------------------------------------------------------------- */
+/* i2c-elektor.c i2c-hw access for PCF8584 style isa bus adaptes             */
+/* ------------------------------------------------------------------------- */
+/*   Copyright (C) 1995-97 Simon G. Vogl
+                   1998-99 Hans Berglund
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.		     */
+/* ------------------------------------------------------------------------- */
+
+/* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even
+   Frodo Looijaard <frodol@dds.nl> */
+
+/* Partially rewriten by Oleg I. Vdovikin for mmapped support of
+   for Alpha Processor Inc. UP-2000(+) boards */
+
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/wait.h>
+
+#include <linux/isa.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-pcf.h>
+#include <linux/io.h>
+
+#include <asm/irq.h>
+
+#include "../algos/i2c-algo-pcf.h"
+
+#define DEFAULT_BASE 0x330
+
+static int base;
+static u8 __iomem *base_iomem;
+
+static int irq;
+static int clock  = 0x1c;
+static int own    = 0x55;
+static int mmapped;
+
+/* vdovikin: removed static struct i2c_pcf_isa gpi; code -
+  this module in real supports only one device, due to missing arguments
+  in some functions, called from the algo-pcf module. Sometimes it's
+  need to be rewriten - but for now just remove this for simpler reading */
+
+static wait_queue_head_t pcf_wait;
+static int pcf_pending;
+static spinlock_t lock;
+
+static struct i2c_adapter pcf_isa_ops;
+
+/* ----- local functions ----------------------------------------------	*/
+
+static void pcf_isa_setbyte(void *data, int ctl, int val)
+{
+	u8 __iomem *address = ctl ? (base_iomem + 1) : base_iomem;
+
+	/* enable irq if any specified for serial operation */
+	if (ctl && irq && (val & I2C_PCF_ESO)) {
+		val |= I2C_PCF_ENI;
+	}
+
+	pr_debug("%s: Write %p 0x%02X\n", pcf_isa_ops.name, address, val);
+	iowrite8(val, address);
+#ifdef __alpha__
+	/* API UP2000 needs some hardware fudging to make the write stick */
+	iowrite8(val, address);
+#endif
+}
+
+static int pcf_isa_getbyte(void *data, int ctl)
+{
+	u8 __iomem *address = ctl ? (base_iomem + 1) : base_iomem;
+	int val = ioread8(address);
+
+	pr_debug("%s: Read %p 0x%02X\n", pcf_isa_ops.name, address, val);
+	return (val);
+}
+
+static int pcf_isa_getown(void *data)
+{
+	return (own);
+}
+
+
+static int pcf_isa_getclock(void *data)
+{
+	return (clock);
+}
+
+static void pcf_isa_waitforpin(void *data)
+{
+	DEFINE_WAIT(wait);
+	int timeout = 2;
+	unsigned long flags;
+
+	if (irq > 0) {
+		spin_lock_irqsave(&lock, flags);
+		if (pcf_pending == 0) {
+			spin_unlock_irqrestore(&lock, flags);
+			prepare_to_wait(&pcf_wait, &wait, TASK_INTERRUPTIBLE);
+			if (schedule_timeout(timeout*HZ)) {
+				spin_lock_irqsave(&lock, flags);
+				if (pcf_pending == 1) {
+					pcf_pending = 0;
+				}
+				spin_unlock_irqrestore(&lock, flags);
+			}
+			finish_wait(&pcf_wait, &wait);
+		} else {
+			pcf_pending = 0;
+			spin_unlock_irqrestore(&lock, flags);
+		}
+	} else {
+		udelay(100);
+	}
+}
+
+
+static irqreturn_t pcf_isa_handler(int this_irq, void *dev_id) {
+	spin_lock(&lock);
+	pcf_pending = 1;
+	spin_unlock(&lock);
+	wake_up_interruptible(&pcf_wait);
+	return IRQ_HANDLED;
+}
+
+
+static int pcf_isa_init(void)
+{
+	spin_lock_init(&lock);
+	if (!mmapped) {
+		if (!request_region(base, 2, pcf_isa_ops.name)) {
+			printk(KERN_ERR "%s: requested I/O region (%#x:2) is "
+			       "in use\n", pcf_isa_ops.name, base);
+			return -ENODEV;
+		}
+		base_iomem = ioport_map(base, 2);
+		if (!base_iomem) {
+			printk(KERN_ERR "%s: remap of I/O region %#x failed\n",
+			       pcf_isa_ops.name, base);
+			release_region(base, 2);
+			return -ENODEV;
+		}
+	} else {
+		if (!request_mem_region(base, 2, pcf_isa_ops.name)) {
+			printk(KERN_ERR "%s: requested memory region (%#x:2) "
+			       "is in use\n", pcf_isa_ops.name, base);
+			return -ENODEV;
+		}
+		base_iomem = ioremap(base, 2);
+		if (base_iomem == NULL) {
+			printk(KERN_ERR "%s: remap of memory region %#x "
+			       "failed\n", pcf_isa_ops.name, base);
+			release_mem_region(base, 2);
+			return -ENODEV;
+		}
+	}
+	pr_debug("%s: registers %#x remapped to %p\n", pcf_isa_ops.name, base,
+		 base_iomem);
+
+	if (irq > 0) {
+		if (request_irq(irq, pcf_isa_handler, 0, pcf_isa_ops.name,
+				NULL) < 0) {
+			printk(KERN_ERR "%s: Request irq%d failed\n",
+			       pcf_isa_ops.name, irq);
+			irq = 0;
+		} else
+			enable_irq(irq);
+	}
+	return 0;
+}
+
+/* ------------------------------------------------------------------------
+ * Encapsulate the above functions in the correct operations structure.
+ * This is only done when more than one hardware adapter is supported.
+ */
+static struct i2c_algo_pcf_data pcf_isa_data = {
+	.setpcf	    = pcf_isa_setbyte,
+	.getpcf	    = pcf_isa_getbyte,
+	.getown	    = pcf_isa_getown,
+	.getclock   = pcf_isa_getclock,
+	.waitforpin = pcf_isa_waitforpin,
+};
+
+static struct i2c_adapter pcf_isa_ops = {
+	.owner		= THIS_MODULE,
+	.class		= I2C_CLASS_HWMON | I2C_CLASS_SPD,
+	.algo_data	= &pcf_isa_data,
+	.name		= "i2c-elektor",
+};
+
+static int __devinit elektor_match(struct device *dev, unsigned int id)
+{
+#ifdef __alpha__
+	/* check to see we have memory mapped PCF8584 connected to the
+	Cypress cy82c693 PCI-ISA bridge as on UP2000 board */
+	if (base == 0) {
+		struct pci_dev *cy693_dev;
+
+		cy693_dev = pci_get_device(PCI_VENDOR_ID_CONTAQ,
+					   PCI_DEVICE_ID_CONTAQ_82C693, NULL);
+		if (cy693_dev) {
+			unsigned char config;
+			/* yeap, we've found cypress, let's check config */
+			if (!pci_read_config_byte(cy693_dev, 0x47, &config)) {
+
+				dev_dbg(dev, "found cy82c693, config "
+					"register 0x47 = 0x%02x\n", config);
+
+				/* UP2000 board has this register set to 0xe1,
+				   but the most significant bit as seems can be
+				   reset during the proper initialisation
+				   sequence if guys from API decides to do that
+				   (so, we can even enable Tsunami Pchip
+				   window for the upper 1 Gb) */
+
+				/* so just check for ROMCS at 0xe0000,
+				   ROMCS enabled for writes
+				   and external XD Bus buffer in use. */
+				if ((config & 0x7f) == 0x61) {
+					/* seems to be UP2000 like board */
+					base = 0xe0000;
+					mmapped = 1;
+					/* UP2000 drives ISA with
+					   8.25 MHz (PCI/4) clock
+					   (this can be read from cypress) */
+					clock = I2C_PCF_CLK | I2C_PCF_TRNS90;
+					dev_info(dev, "found API UP2000 like "
+						 "board, will probe PCF8584 "
+						 "later\n");
+				}
+			}
+			pci_dev_put(cy693_dev);
+		}
+	}
+#endif
+
+	/* sanity checks for mmapped I/O */
+	if (mmapped && base < 0xc8000) {
+		dev_err(dev, "incorrect base address (%#x) specified "
+		       "for mmapped I/O\n", base);
+		return 0;
+	}
+
+	if (base == 0) {
+		base = DEFAULT_BASE;
+	}
+	return 1;
+}
+
+static int __devinit elektor_probe(struct device *dev, unsigned int id)
+{
+	init_waitqueue_head(&pcf_wait);
+	if (pcf_isa_init())
+		return -ENODEV;
+	pcf_isa_ops.dev.parent = dev;
+	if (i2c_pcf_add_bus(&pcf_isa_ops) < 0)
+		goto fail;
+
+	dev_info(dev, "found device at %#x\n", base);
+
+	return 0;
+
+ fail:
+	if (irq > 0) {
+		disable_irq(irq);
+		free_irq(irq, NULL);
+	}
+
+	if (!mmapped) {
+		ioport_unmap(base_iomem);
+		release_region(base, 2);
+	} else {
+		iounmap(base_iomem);
+		release_mem_region(base, 2);
+	}
+	return -ENODEV;
+}
+
+static int __devexit elektor_remove(struct device *dev, unsigned int id)
+{
+	i2c_del_adapter(&pcf_isa_ops);
+
+	if (irq > 0) {
+		disable_irq(irq);
+		free_irq(irq, NULL);
+	}
+
+	if (!mmapped) {
+		ioport_unmap(base_iomem);
+		release_region(base, 2);
+	} else {
+		iounmap(base_iomem);
+		release_mem_region(base, 2);
+	}
+
+	return 0;
+}
+
+static struct isa_driver i2c_elektor_driver = {
+	.match		= elektor_match,
+	.probe		= elektor_probe,
+	.remove		= __devexit_p(elektor_remove),
+	.driver = {
+		.owner	= THIS_MODULE,
+		.name	= "i2c-elektor",
+	},
+};
+
+static int __init i2c_pcfisa_init(void)
+{
+	return isa_register_driver(&i2c_elektor_driver, 1);
+}
+
+static void __exit i2c_pcfisa_exit(void)
+{
+	isa_unregister_driver(&i2c_elektor_driver);
+}
+
+MODULE_AUTHOR("Hans Berglund <hb@spacetec.no>");
+MODULE_DESCRIPTION("I2C-Bus adapter routines for PCF8584 ISA bus adapter");
+MODULE_LICENSE("GPL");
+
+module_param(base, int, 0);
+module_param(irq, int, 0);
+module_param(clock, int, 0);
+module_param(own, int, 0);
+module_param(mmapped, int, 0);
+
+module_init(i2c_pcfisa_init);
+module_exit(i2c_pcfisa_exit);
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-gpio.c b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-gpio.c
new file mode 100644
index 0000000..c0330a4
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-gpio.c
@@ -0,0 +1,279 @@
+/*
+ * Bitbanging I2C bus driver using the GPIO API
+ *
+ * Copyright (C) 2007 Atmel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <linux/i2c-gpio.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/of_i2c.h>
+
+struct i2c_gpio_private_data {
+	struct i2c_adapter adap;
+	struct i2c_algo_bit_data bit_data;
+	struct i2c_gpio_platform_data pdata;
+};
+
+/* Toggle SDA by changing the direction of the pin */
+static void i2c_gpio_setsda_dir(void *data, int state)
+{
+	struct i2c_gpio_platform_data *pdata = data;
+
+	if (state)
+		gpio_direction_input(pdata->sda_pin);
+	else
+		gpio_direction_output(pdata->sda_pin, 0);
+}
+
+/*
+ * Toggle SDA by changing the output value of the pin. This is only
+ * valid for pins configured as open drain (i.e. setting the value
+ * high effectively turns off the output driver.)
+ */
+static void i2c_gpio_setsda_val(void *data, int state)
+{
+	struct i2c_gpio_platform_data *pdata = data;
+
+	gpio_set_value(pdata->sda_pin, state);
+}
+
+/* Toggle SCL by changing the direction of the pin. */
+static void i2c_gpio_setscl_dir(void *data, int state)
+{
+	struct i2c_gpio_platform_data *pdata = data;
+
+	if (state)
+		gpio_direction_input(pdata->scl_pin);
+	else
+		gpio_direction_output(pdata->scl_pin, 0);
+}
+
+/*
+ * Toggle SCL by changing the output value of the pin. This is used
+ * for pins that are configured as open drain and for output-only
+ * pins. The latter case will break the i2c protocol, but it will
+ * often work in practice.
+ */
+static void i2c_gpio_setscl_val(void *data, int state)
+{
+	struct i2c_gpio_platform_data *pdata = data;
+
+	gpio_set_value(pdata->scl_pin, state);
+}
+
+static int i2c_gpio_getsda(void *data)
+{
+	struct i2c_gpio_platform_data *pdata = data;
+
+	return gpio_get_value(pdata->sda_pin);
+}
+
+static int i2c_gpio_getscl(void *data)
+{
+	struct i2c_gpio_platform_data *pdata = data;
+
+	return gpio_get_value(pdata->scl_pin);
+}
+
+static int __devinit of_i2c_gpio_probe(struct device_node *np,
+			     struct i2c_gpio_platform_data *pdata)
+{
+	u32 reg;
+
+	if (of_gpio_count(np) < 2)
+		return -ENODEV;
+
+	pdata->sda_pin = of_get_gpio(np, 0);
+	pdata->scl_pin = of_get_gpio(np, 1);
+
+	if (!gpio_is_valid(pdata->sda_pin) || !gpio_is_valid(pdata->scl_pin)) {
+		pr_err("%s: invalid GPIO pins, sda=%d/scl=%d\n",
+		       np->full_name, pdata->sda_pin, pdata->scl_pin);
+		return -ENODEV;
+	}
+
+	of_property_read_u32(np, "i2c-gpio,delay-us", &pdata->udelay);
+
+	if (!of_property_read_u32(np, "i2c-gpio,timeout-ms", &reg))
+		pdata->timeout = msecs_to_jiffies(reg);
+
+	pdata->sda_is_open_drain =
+		of_property_read_bool(np, "i2c-gpio,sda-open-drain");
+	pdata->scl_is_open_drain =
+		of_property_read_bool(np, "i2c-gpio,scl-open-drain");
+	pdata->scl_is_output_only =
+		of_property_read_bool(np, "i2c-gpio,scl-output-only");
+
+	return 0;
+}
+
+static int __devinit i2c_gpio_probe(struct platform_device *pdev)
+{
+	struct i2c_gpio_private_data *priv;
+	struct i2c_gpio_platform_data *pdata;
+	struct i2c_algo_bit_data *bit_data;
+	struct i2c_adapter *adap;
+	int ret;
+
+	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+	adap = &priv->adap;
+	bit_data = &priv->bit_data;
+	pdata = &priv->pdata;
+
+	if (pdev->dev.of_node) {
+		ret = of_i2c_gpio_probe(pdev->dev.of_node, pdata);
+		if (ret)
+			return ret;
+	} else {
+		if (!pdev->dev.platform_data)
+			return -ENXIO;
+		memcpy(pdata, pdev->dev.platform_data, sizeof(*pdata));
+	}
+
+	ret = gpio_request(pdata->sda_pin, "sda");
+	if (ret)
+		goto err_request_sda;
+	ret = gpio_request(pdata->scl_pin, "scl");
+	if (ret)
+		goto err_request_scl;
+
+	if (pdata->sda_is_open_drain) {
+		gpio_direction_output(pdata->sda_pin, 1);
+		bit_data->setsda = i2c_gpio_setsda_val;
+	} else {
+		gpio_direction_input(pdata->sda_pin);
+		bit_data->setsda = i2c_gpio_setsda_dir;
+	}
+
+	if (pdata->scl_is_open_drain || pdata->scl_is_output_only) {
+		gpio_direction_output(pdata->scl_pin, 1);
+		bit_data->setscl = i2c_gpio_setscl_val;
+	} else {
+		gpio_direction_input(pdata->scl_pin);
+		bit_data->setscl = i2c_gpio_setscl_dir;
+	}
+
+	if (!pdata->scl_is_output_only)
+		bit_data->getscl = i2c_gpio_getscl;
+	bit_data->getsda = i2c_gpio_getsda;
+
+	if (pdata->udelay)
+		bit_data->udelay = pdata->udelay;
+	else if (pdata->scl_is_output_only)
+		bit_data->udelay = 50;			/* 10 kHz */
+	else
+		bit_data->udelay = 5;			/* 100 kHz */
+
+	if (pdata->timeout)
+		bit_data->timeout = pdata->timeout;
+	else
+		bit_data->timeout = HZ / 10;		/* 100 ms */
+
+	bit_data->data = pdata;
+
+	adap->owner = THIS_MODULE;
+	snprintf(adap->name, sizeof(adap->name), "i2c-gpio%d", pdev->id);
+	adap->algo_data = bit_data;
+	adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
+	adap->dev.parent = &pdev->dev;
+	adap->dev.of_node = pdev->dev.of_node;
+
+	/*
+	 * If "dev->id" is negative we consider it as zero.
+	 * The reason to do so is to avoid sysfs names that only make
+	 * sense when there are multiple adapters.
+	 */
+	adap->nr = (pdev->id != -1) ? pdev->id : 0;
+	ret = i2c_bit_add_numbered_bus(adap);
+	if (ret)
+		goto err_add_bus;
+
+	of_i2c_register_devices(adap);
+
+	platform_set_drvdata(pdev, priv);
+
+	dev_info(&pdev->dev, "using pins %u (SDA) and %u (SCL%s)\n",
+		 pdata->sda_pin, pdata->scl_pin,
+		 pdata->scl_is_output_only
+		 ? ", no clock stretching" : "");
+
+	return 0;
+
+err_add_bus:
+	gpio_free(pdata->scl_pin);
+err_request_scl:
+	gpio_free(pdata->sda_pin);
+err_request_sda:
+	return ret;
+}
+
+static int __devexit i2c_gpio_remove(struct platform_device *pdev)
+{
+	struct i2c_gpio_private_data *priv;
+	struct i2c_gpio_platform_data *pdata;
+	struct i2c_adapter *adap;
+
+	priv = platform_get_drvdata(pdev);
+	adap = &priv->adap;
+	pdata = &priv->pdata;
+
+	i2c_del_adapter(adap);
+	gpio_free(pdata->scl_pin);
+	gpio_free(pdata->sda_pin);
+
+	return 0;
+}
+
+#if defined(CONFIG_OF)
+static const struct of_device_id i2c_gpio_dt_ids[] = {
+	{ .compatible = "i2c-gpio", },
+	{ /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, i2c_gpio_dt_ids);
+#endif
+
+static struct platform_driver i2c_gpio_driver = {
+	.driver		= {
+		.name	= "i2c-gpio",
+		.owner	= THIS_MODULE,
+		.of_match_table	= of_match_ptr(i2c_gpio_dt_ids),
+	},
+	.probe		= i2c_gpio_probe,
+	.remove		= __devexit_p(i2c_gpio_remove),
+};
+
+static int __init i2c_gpio_init(void)
+{
+	int ret;
+
+	ret = platform_driver_register(&i2c_gpio_driver);
+	if (ret)
+		printk(KERN_ERR "i2c-gpio: probe failed: %d\n", ret);
+
+	return ret;
+}
+subsys_initcall(i2c_gpio_init);
+
+static void __exit i2c_gpio_exit(void)
+{
+	platform_driver_unregister(&i2c_gpio_driver);
+}
+module_exit(i2c_gpio_exit);
+
+MODULE_AUTHOR("Haavard Skinnemoen (Atmel)");
+MODULE_DESCRIPTION("Platform-independent bitbanging I2C driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:i2c-gpio");
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-highlander.c b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-highlander.c
new file mode 100644
index 0000000..19515df
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-highlander.c
@@ -0,0 +1,487 @@
+/*
+ * Renesas Solutions Highlander FPGA I2C/SMBus support.
+ *
+ * Supported devices: R0P7780LC0011RL, R0P7785LC0011RL
+ *
+ * Copyright (C) 2008  Paul Mundt
+ * Copyright (C) 2008  Renesas Solutions Corp.
+ * Copyright (C) 2008  Atom Create Engineering Co., Ltd.
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License version 2. See the file "COPYING" in the main directory
+ * of this archive for more details.
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/completion.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+
+#define SMCR		0x00
+#define SMCR_START	(1 << 0)
+#define SMCR_IRIC	(1 << 1)
+#define SMCR_BBSY	(1 << 2)
+#define SMCR_ACKE	(1 << 3)
+#define SMCR_RST	(1 << 4)
+#define SMCR_IEIC	(1 << 6)
+
+#define SMSMADR		0x02
+
+#define SMMR		0x04
+#define SMMR_MODE0	(1 << 0)
+#define SMMR_MODE1	(1 << 1)
+#define SMMR_CAP	(1 << 3)
+#define SMMR_TMMD	(1 << 4)
+#define SMMR_SP		(1 << 7)
+
+#define SMSADR		0x06
+#define SMTRDR		0x46
+
+struct highlander_i2c_dev {
+	struct device		*dev;
+	void __iomem		*base;
+	struct i2c_adapter	adapter;
+	struct completion	cmd_complete;
+	unsigned long		last_read_time;
+	int			irq;
+	u8			*buf;
+	size_t			buf_len;
+};
+
+static bool iic_force_poll, iic_force_normal;
+static int iic_timeout = 1000, iic_read_delay;
+
+static inline void highlander_i2c_irq_enable(struct highlander_i2c_dev *dev)
+{
+	iowrite16(ioread16(dev->base + SMCR) | SMCR_IEIC, dev->base + SMCR);
+}
+
+static inline void highlander_i2c_irq_disable(struct highlander_i2c_dev *dev)
+{
+	iowrite16(ioread16(dev->base + SMCR) & ~SMCR_IEIC, dev->base + SMCR);
+}
+
+static inline void highlander_i2c_start(struct highlander_i2c_dev *dev)
+{
+	iowrite16(ioread16(dev->base + SMCR) | SMCR_START, dev->base + SMCR);
+}
+
+static inline void highlander_i2c_done(struct highlander_i2c_dev *dev)
+{
+	iowrite16(ioread16(dev->base + SMCR) | SMCR_IRIC, dev->base + SMCR);
+}
+
+static void highlander_i2c_setup(struct highlander_i2c_dev *dev)
+{
+	u16 smmr;
+
+	smmr = ioread16(dev->base + SMMR);
+	smmr |= SMMR_TMMD;
+
+	if (iic_force_normal)
+		smmr &= ~SMMR_SP;
+	else
+		smmr |= SMMR_SP;
+
+	iowrite16(smmr, dev->base + SMMR);
+}
+
+static void smbus_write_data(u8 *src, u16 *dst, int len)
+{
+	for (; len > 1; len -= 2) {
+		*dst++ = be16_to_cpup((__be16 *)src);
+		src += 2;
+	}
+
+	if (len)
+		*dst = *src << 8;
+}
+
+static void smbus_read_data(u16 *src, u8 *dst, int len)
+{
+	for (; len > 1; len -= 2) {
+		*(__be16 *)dst = cpu_to_be16p(src++);
+		dst += 2;
+	}
+
+	if (len)
+		*dst = *src >> 8;
+}
+
+static void highlander_i2c_command(struct highlander_i2c_dev *dev,
+				   u8 command, int len)
+{
+	unsigned int i;
+	u16 cmd = (command << 8) | command;
+
+	for (i = 0; i < len; i += 2) {
+		if (len - i == 1)
+			cmd = command << 8;
+		iowrite16(cmd, dev->base + SMSADR + i);
+		dev_dbg(dev->dev, "command data[%x] 0x%04x\n", i/2, cmd);
+	}
+}
+
+static int highlander_i2c_wait_for_bbsy(struct highlander_i2c_dev *dev)
+{
+	unsigned long timeout;
+
+	timeout = jiffies + msecs_to_jiffies(iic_timeout);
+	while (ioread16(dev->base + SMCR) & SMCR_BBSY) {
+		if (time_after(jiffies, timeout)) {
+			dev_warn(dev->dev, "timeout waiting for bus ready\n");
+			return -ETIMEDOUT;
+		}
+
+		msleep(1);
+	}
+
+	return 0;
+}
+
+static int highlander_i2c_reset(struct highlander_i2c_dev *dev)
+{
+	iowrite16(ioread16(dev->base + SMCR) | SMCR_RST, dev->base + SMCR);
+	return highlander_i2c_wait_for_bbsy(dev);
+}
+
+static int highlander_i2c_wait_for_ack(struct highlander_i2c_dev *dev)
+{
+	u16 tmp = ioread16(dev->base + SMCR);
+
+	if ((tmp & (SMCR_IRIC | SMCR_ACKE)) == SMCR_ACKE) {
+		dev_warn(dev->dev, "ack abnormality\n");
+		return highlander_i2c_reset(dev);
+	}
+
+	return 0;
+}
+
+static irqreturn_t highlander_i2c_irq(int irq, void *dev_id)
+{
+	struct highlander_i2c_dev *dev = dev_id;
+
+	highlander_i2c_done(dev);
+	complete(&dev->cmd_complete);
+
+	return IRQ_HANDLED;
+}
+
+static void highlander_i2c_poll(struct highlander_i2c_dev *dev)
+{
+	unsigned long timeout;
+	u16 smcr;
+
+	timeout = jiffies + msecs_to_jiffies(iic_timeout);
+	for (;;) {
+		smcr = ioread16(dev->base + SMCR);
+
+		/*
+		 * Don't bother checking ACKE here, this and the reset
+		 * are handled in highlander_i2c_wait_xfer_done() when
+		 * waiting for the ACK.
+		 */
+
+		if (smcr & SMCR_IRIC)
+			return;
+		if (time_after(jiffies, timeout))
+			break;
+
+		cpu_relax();
+		cond_resched();
+	}
+
+	dev_err(dev->dev, "polling timed out\n");
+}
+
+static inline int highlander_i2c_wait_xfer_done(struct highlander_i2c_dev *dev)
+{
+	if (dev->irq)
+		wait_for_completion_timeout(&dev->cmd_complete,
+					  msecs_to_jiffies(iic_timeout));
+	else
+		/* busy looping, the IRQ of champions */
+		highlander_i2c_poll(dev);
+
+	return highlander_i2c_wait_for_ack(dev);
+}
+
+static int highlander_i2c_read(struct highlander_i2c_dev *dev)
+{
+	int i, cnt;
+	u16 data[16];
+
+	if (highlander_i2c_wait_for_bbsy(dev))
+		return -EAGAIN;
+
+	highlander_i2c_start(dev);
+
+	if (highlander_i2c_wait_xfer_done(dev)) {
+		dev_err(dev->dev, "Arbitration loss\n");
+		return -EAGAIN;
+	}
+
+	/*
+	 * The R0P7780LC0011RL FPGA needs a significant delay between
+	 * data read cycles, otherwise the transceiver gets confused and
+	 * garbage is returned when the read is subsequently aborted.
+	 *
+	 * It is not sufficient to wait for BBSY.
+	 *
+	 * While this generally only applies to the older SH7780-based
+	 * Highlanders, the same issue can be observed on SH7785 ones,
+	 * albeit less frequently. SH7780-based Highlanders may need
+	 * this to be as high as 1000 ms.
+	 */
+	if (iic_read_delay && time_before(jiffies, dev->last_read_time +
+				 msecs_to_jiffies(iic_read_delay)))
+		msleep(jiffies_to_msecs((dev->last_read_time +
+				msecs_to_jiffies(iic_read_delay)) - jiffies));
+
+	cnt = (dev->buf_len + 1) >> 1;
+	for (i = 0; i < cnt; i++) {
+		data[i] = ioread16(dev->base + SMTRDR + (i * sizeof(u16)));
+		dev_dbg(dev->dev, "read data[%x] 0x%04x\n", i, data[i]);
+	}
+
+	smbus_read_data(data, dev->buf, dev->buf_len);
+
+	dev->last_read_time = jiffies;
+
+	return 0;
+}
+
+static int highlander_i2c_write(struct highlander_i2c_dev *dev)
+{
+	int i, cnt;
+	u16 data[16];
+
+	smbus_write_data(dev->buf, data, dev->buf_len);
+
+	cnt = (dev->buf_len + 1) >> 1;
+	for (i = 0; i < cnt; i++) {
+		iowrite16(data[i], dev->base + SMTRDR + (i * sizeof(u16)));
+		dev_dbg(dev->dev, "write data[%x] 0x%04x\n", i, data[i]);
+	}
+
+	if (highlander_i2c_wait_for_bbsy(dev))
+		return -EAGAIN;
+
+	highlander_i2c_start(dev);
+
+	return highlander_i2c_wait_xfer_done(dev);
+}
+
+static int highlander_i2c_smbus_xfer(struct i2c_adapter *adap, u16 addr,
+				  unsigned short flags, char read_write,
+				  u8 command, int size,
+				  union i2c_smbus_data *data)
+{
+	struct highlander_i2c_dev *dev = i2c_get_adapdata(adap);
+	u16 tmp;
+
+	init_completion(&dev->cmd_complete);
+
+	dev_dbg(dev->dev, "addr %04x, command %02x, read_write %d, size %d\n",
+		addr, command, read_write, size);
+
+	/*
+	 * Set up the buffer and transfer size
+	 */
+	switch (size) {
+	case I2C_SMBUS_BYTE_DATA:
+		dev->buf = &data->byte;
+		dev->buf_len = 1;
+		break;
+	case I2C_SMBUS_I2C_BLOCK_DATA:
+		dev->buf = &data->block[1];
+		dev->buf_len = data->block[0];
+		break;
+	default:
+		dev_err(dev->dev, "unsupported command %d\n", size);
+		return -EINVAL;
+	}
+
+	/*
+	 * Encode the mode setting
+	 */
+	tmp = ioread16(dev->base + SMMR);
+	tmp &= ~(SMMR_MODE0 | SMMR_MODE1);
+
+	switch (dev->buf_len) {
+	case 1:
+		/* default */
+		break;
+	case 8:
+		tmp |= SMMR_MODE0;
+		break;
+	case 16:
+		tmp |= SMMR_MODE1;
+		break;
+	case 32:
+		tmp |= (SMMR_MODE0 | SMMR_MODE1);
+		break;
+	default:
+		dev_err(dev->dev, "unsupported xfer size %d\n", dev->buf_len);
+		return -EINVAL;
+	}
+
+	iowrite16(tmp, dev->base + SMMR);
+
+	/* Ensure we're in a sane state */
+	highlander_i2c_done(dev);
+
+	/* Set slave address */
+	iowrite16((addr << 1) | read_write, dev->base + SMSMADR);
+
+	highlander_i2c_command(dev, command, dev->buf_len);
+
+	if (read_write == I2C_SMBUS_READ)
+		return highlander_i2c_read(dev);
+	else
+		return highlander_i2c_write(dev);
+}
+
+static u32 highlander_i2c_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_I2C_BLOCK;
+}
+
+static const struct i2c_algorithm highlander_i2c_algo = {
+	.smbus_xfer	= highlander_i2c_smbus_xfer,
+	.functionality	= highlander_i2c_func,
+};
+
+static int __devinit highlander_i2c_probe(struct platform_device *pdev)
+{
+	struct highlander_i2c_dev *dev;
+	struct i2c_adapter *adap;
+	struct resource *res;
+	int ret;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (unlikely(!res)) {
+		dev_err(&pdev->dev, "no mem resource\n");
+		return -ENODEV;
+	}
+
+	dev = kzalloc(sizeof(struct highlander_i2c_dev), GFP_KERNEL);
+	if (unlikely(!dev))
+		return -ENOMEM;
+
+	dev->base = ioremap_nocache(res->start, resource_size(res));
+	if (unlikely(!dev->base)) {
+		ret = -ENXIO;
+		goto err;
+	}
+
+	dev->dev = &pdev->dev;
+	platform_set_drvdata(pdev, dev);
+
+	dev->irq = platform_get_irq(pdev, 0);
+	if (iic_force_poll)
+		dev->irq = 0;
+
+	if (dev->irq) {
+		ret = request_irq(dev->irq, highlander_i2c_irq, 0,
+				  pdev->name, dev);
+		if (unlikely(ret))
+			goto err_unmap;
+
+		highlander_i2c_irq_enable(dev);
+	} else {
+		dev_notice(&pdev->dev, "no IRQ, using polling mode\n");
+		highlander_i2c_irq_disable(dev);
+	}
+
+	dev->last_read_time = jiffies;	/* initial read jiffies */
+
+	highlander_i2c_setup(dev);
+
+	adap = &dev->adapter;
+	i2c_set_adapdata(adap, dev);
+	adap->owner = THIS_MODULE;
+	adap->class = I2C_CLASS_HWMON;
+	strlcpy(adap->name, "HL FPGA I2C adapter", sizeof(adap->name));
+	adap->algo = &highlander_i2c_algo;
+	adap->dev.parent = &pdev->dev;
+	adap->nr = pdev->id;
+
+	/*
+	 * Reset the adapter
+	 */
+	ret = highlander_i2c_reset(dev);
+	if (unlikely(ret)) {
+		dev_err(&pdev->dev, "controller didn't come up\n");
+		goto err_free_irq;
+	}
+
+	ret = i2c_add_numbered_adapter(adap);
+	if (unlikely(ret)) {
+		dev_err(&pdev->dev, "failure adding adapter\n");
+		goto err_free_irq;
+	}
+
+	return 0;
+
+err_free_irq:
+	if (dev->irq)
+		free_irq(dev->irq, dev);
+err_unmap:
+	iounmap(dev->base);
+err:
+	kfree(dev);
+
+	platform_set_drvdata(pdev, NULL);
+
+	return ret;
+}
+
+static int __devexit highlander_i2c_remove(struct platform_device *pdev)
+{
+	struct highlander_i2c_dev *dev = platform_get_drvdata(pdev);
+
+	i2c_del_adapter(&dev->adapter);
+
+	if (dev->irq)
+		free_irq(dev->irq, dev);
+
+	iounmap(dev->base);
+	kfree(dev);
+
+	platform_set_drvdata(pdev, NULL);
+
+	return 0;
+}
+
+static struct platform_driver highlander_i2c_driver = {
+	.driver		= {
+		.name	= "i2c-highlander",
+		.owner	= THIS_MODULE,
+	},
+
+	.probe		= highlander_i2c_probe,
+	.remove		= __devexit_p(highlander_i2c_remove),
+};
+
+module_platform_driver(highlander_i2c_driver);
+
+MODULE_AUTHOR("Paul Mundt");
+MODULE_DESCRIPTION("Renesas Highlander FPGA I2C/SMBus adapter");
+MODULE_LICENSE("GPL v2");
+
+module_param(iic_force_poll, bool, 0);
+module_param(iic_force_normal, bool, 0);
+module_param(iic_timeout, int, 0);
+module_param(iic_read_delay, int, 0);
+
+MODULE_PARM_DESC(iic_force_poll, "Force polling mode");
+MODULE_PARM_DESC(iic_force_normal,
+		 "Force normal mode (100 kHz), default is fast mode (400 kHz)");
+MODULE_PARM_DESC(iic_timeout, "Set timeout value in msecs (default 1000 ms)");
+MODULE_PARM_DESC(iic_read_delay,
+		 "Delay between data read cycles (default 0 ms)");
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-hydra.c b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-hydra.c
new file mode 100644
index 0000000..c527de1
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-hydra.c
@@ -0,0 +1,178 @@
+/*
+    i2c Support for the Apple `Hydra' Mac I/O
+
+    Copyright (c) 1999-2004 Geert Uytterhoeven <geert@linux-m68k.org>
+
+    Based on i2c Support for Via Technologies 82C586B South Bridge
+    Copyright (c) 1998, 1999 Kyösti Mälkki <kmalkki@cc.hut.fi>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <asm/hydra.h>
+
+
+#define HYDRA_CPD_PD0	0x00000001	/* CachePD lines */
+#define HYDRA_CPD_PD1	0x00000002
+#define HYDRA_CPD_PD2	0x00000004
+#define HYDRA_CPD_PD3	0x00000008
+
+#define HYDRA_SCLK	HYDRA_CPD_PD0
+#define HYDRA_SDAT	HYDRA_CPD_PD1
+#define HYDRA_SCLK_OE	0x00000010
+#define HYDRA_SDAT_OE	0x00000020
+
+static inline void pdregw(void *data, u32 val)
+{
+	struct Hydra *hydra = (struct Hydra *)data;
+	writel(val, &hydra->CachePD);
+}
+
+static inline u32 pdregr(void *data)
+{
+	struct Hydra *hydra = (struct Hydra *)data;
+	return readl(&hydra->CachePD);
+}
+
+static void hydra_bit_setscl(void *data, int state)
+{
+	u32 val = pdregr(data);
+	if (state)
+		val &= ~HYDRA_SCLK_OE;
+	else {
+		val &= ~HYDRA_SCLK;
+		val |= HYDRA_SCLK_OE;
+	}
+	pdregw(data, val);
+}
+
+static void hydra_bit_setsda(void *data, int state)
+{
+	u32 val = pdregr(data);
+	if (state)
+		val &= ~HYDRA_SDAT_OE;
+	else {
+		val &= ~HYDRA_SDAT;
+		val |= HYDRA_SDAT_OE;
+	}
+	pdregw(data, val);
+}
+
+static int hydra_bit_getscl(void *data)
+{
+	return (pdregr(data) & HYDRA_SCLK) != 0;
+}
+
+static int hydra_bit_getsda(void *data)
+{
+	return (pdregr(data) & HYDRA_SDAT) != 0;
+}
+
+/* ------------------------------------------------------------------------ */
+
+static struct i2c_algo_bit_data hydra_bit_data = {
+	.setsda		= hydra_bit_setsda,
+	.setscl		= hydra_bit_setscl,
+	.getsda		= hydra_bit_getsda,
+	.getscl		= hydra_bit_getscl,
+	.udelay		= 5,
+	.timeout	= HZ
+};
+
+static struct i2c_adapter hydra_adap = {
+	.owner		= THIS_MODULE,
+	.name		= "Hydra i2c",
+	.algo_data	= &hydra_bit_data,
+};
+
+static DEFINE_PCI_DEVICE_TABLE(hydra_ids) = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_HYDRA) },
+	{ 0, }
+};
+
+MODULE_DEVICE_TABLE (pci, hydra_ids);
+
+static int __devinit hydra_probe(struct pci_dev *dev,
+				 const struct pci_device_id *id)
+{
+	unsigned long base = pci_resource_start(dev, 0);
+	int res;
+
+	if (!request_mem_region(base+offsetof(struct Hydra, CachePD), 4,
+				hydra_adap.name))
+		return -EBUSY;
+
+	hydra_bit_data.data = pci_ioremap_bar(dev, 0);
+	if (hydra_bit_data.data == NULL) {
+		release_mem_region(base+offsetof(struct Hydra, CachePD), 4);
+		return -ENODEV;
+	}
+
+	pdregw(hydra_bit_data.data, 0);		/* clear SCLK_OE and SDAT_OE */
+	hydra_adap.dev.parent = &dev->dev;
+	res = i2c_bit_add_bus(&hydra_adap);
+	if (res < 0) {
+		iounmap(hydra_bit_data.data);
+		release_mem_region(base+offsetof(struct Hydra, CachePD), 4);
+		return res;
+	}
+	return 0;
+}
+
+static void __devexit hydra_remove(struct pci_dev *dev)
+{
+	pdregw(hydra_bit_data.data, 0);		/* clear SCLK_OE and SDAT_OE */
+	i2c_del_adapter(&hydra_adap);
+	iounmap(hydra_bit_data.data);
+	release_mem_region(pci_resource_start(dev, 0)+
+			   offsetof(struct Hydra, CachePD), 4);
+}
+
+
+static struct pci_driver hydra_driver = {
+	.name		= "hydra_smbus",
+	.id_table	= hydra_ids,
+	.probe		= hydra_probe,
+	.remove		= __devexit_p(hydra_remove),
+};
+
+static int __init i2c_hydra_init(void)
+{
+	return pci_register_driver(&hydra_driver);
+}
+
+
+static void __exit i2c_hydra_exit(void)
+{
+	pci_unregister_driver(&hydra_driver);
+}
+
+
+
+MODULE_AUTHOR("Geert Uytterhoeven <geert@linux-m68k.org>");
+MODULE_DESCRIPTION("i2c for Apple Hydra Mac I/O");
+MODULE_LICENSE("GPL");
+
+module_init(i2c_hydra_init);
+module_exit(i2c_hydra_exit);
+
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-i801.c b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-i801.c
new file mode 100644
index 0000000..d63e130
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-i801.c
@@ -0,0 +1,955 @@
+/*
+    Copyright (c) 1998 - 2002  Frodo Looijaard <frodol@dds.nl>,
+    Philip Edelbrock <phil@netroedge.com>, and Mark D. Studebaker
+    <mdsxyz123@yahoo.com>
+    Copyright (C) 2007 - 2012  Jean Delvare <khali@linux-fr.org>
+    Copyright (C) 2010         Intel Corporation,
+                               David Woodhouse <dwmw2@infradead.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/*
+  Supports the following Intel I/O Controller Hubs (ICH):
+
+                                  I/O                     Block   I2C
+                                  region  SMBus   Block   proc.   block
+  Chip name             PCI ID    size    PEC     buffer  call    read
+  ----------------------------------------------------------------------
+  82801AA  (ICH)        0x2413     16      no      no      no      no
+  82801AB  (ICH0)       0x2423     16      no      no      no      no
+  82801BA  (ICH2)       0x2443     16      no      no      no      no
+  82801CA  (ICH3)       0x2483     32     soft     no      no      no
+  82801DB  (ICH4)       0x24c3     32     hard     yes     no      no
+  82801E   (ICH5)       0x24d3     32     hard     yes     yes     yes
+  6300ESB               0x25a4     32     hard     yes     yes     yes
+  82801F   (ICH6)       0x266a     32     hard     yes     yes     yes
+  6310ESB/6320ESB       0x269b     32     hard     yes     yes     yes
+  82801G   (ICH7)       0x27da     32     hard     yes     yes     yes
+  82801H   (ICH8)       0x283e     32     hard     yes     yes     yes
+  82801I   (ICH9)       0x2930     32     hard     yes     yes     yes
+  EP80579 (Tolapai)     0x5032     32     hard     yes     yes     yes
+  ICH10                 0x3a30     32     hard     yes     yes     yes
+  ICH10                 0x3a60     32     hard     yes     yes     yes
+  5/3400 Series (PCH)   0x3b30     32     hard     yes     yes     yes
+  6 Series (PCH)        0x1c22     32     hard     yes     yes     yes
+  Patsburg (PCH)        0x1d22     32     hard     yes     yes     yes
+  Patsburg (PCH) IDF    0x1d70     32     hard     yes     yes     yes
+  Patsburg (PCH) IDF    0x1d71     32     hard     yes     yes     yes
+  Patsburg (PCH) IDF    0x1d72     32     hard     yes     yes     yes
+  DH89xxCC (PCH)        0x2330     32     hard     yes     yes     yes
+  Panther Point (PCH)   0x1e22     32     hard     yes     yes     yes
+  Lynx Point (PCH)      0x8c22     32     hard     yes     yes     yes
+  Lynx Point-LP (PCH)   0x9c22     32     hard     yes     yes     yes
+  Avoton (SOC)          0x1f3c     32     hard     yes     yes     yes
+
+  Features supported by this driver:
+  Software PEC                     no
+  Hardware PEC                     yes
+  Block buffer                     yes
+  Block process call transaction   no
+  I2C block read transaction       yes  (doesn't use the block buffer)
+  Slave mode                       no
+
+  See the file Documentation/i2c/busses/i2c-i801 for details.
+*/
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/stddef.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/acpi.h>
+#include <linux/io.h>
+#include <linux/dmi.h>
+#include <linux/slab.h>
+
+/* I801 SMBus address offsets */
+#define SMBHSTSTS(p)	(0 + (p)->smba)
+#define SMBHSTCNT(p)	(2 + (p)->smba)
+#define SMBHSTCMD(p)	(3 + (p)->smba)
+#define SMBHSTADD(p)	(4 + (p)->smba)
+#define SMBHSTDAT0(p)	(5 + (p)->smba)
+#define SMBHSTDAT1(p)	(6 + (p)->smba)
+#define SMBBLKDAT(p)	(7 + (p)->smba)
+#define SMBPEC(p)	(8 + (p)->smba)		/* ICH3 and later */
+#define SMBAUXSTS(p)	(12 + (p)->smba)	/* ICH4 and later */
+#define SMBAUXCTL(p)	(13 + (p)->smba)	/* ICH4 and later */
+
+/* PCI Address Constants */
+#define SMBBAR		4
+#define SMBHSTCFG	0x040
+
+/* Host configuration bits for SMBHSTCFG */
+#define SMBHSTCFG_HST_EN	1
+#define SMBHSTCFG_SMB_SMI_EN	2
+#define SMBHSTCFG_I2C_EN	4
+
+/* Auxiliary control register bits, ICH4+ only */
+#define SMBAUXCTL_CRC		1
+#define SMBAUXCTL_E32B		2
+
+/* kill bit for SMBHSTCNT */
+#define SMBHSTCNT_KILL		2
+
+/* Other settings */
+#define MAX_RETRIES		400
+#define ENABLE_INT9		0	/* set to 0x01 to enable - untested */
+
+/* I801 command constants */
+#define I801_QUICK		0x00
+#define I801_BYTE		0x04
+#define I801_BYTE_DATA		0x08
+#define I801_WORD_DATA		0x0C
+#define I801_PROC_CALL		0x10	/* unimplemented */
+#define I801_BLOCK_DATA		0x14
+#define I801_I2C_BLOCK_DATA	0x18	/* ICH5 and later */
+#define I801_BLOCK_LAST		0x34
+#define I801_I2C_BLOCK_LAST	0x38	/* ICH5 and later */
+#define I801_START		0x40
+#define I801_PEC_EN		0x80	/* ICH3 and later */
+
+/* I801 Hosts Status register bits */
+#define SMBHSTSTS_BYTE_DONE	0x80
+#define SMBHSTSTS_INUSE_STS	0x40
+#define SMBHSTSTS_SMBALERT_STS	0x20
+#define SMBHSTSTS_FAILED	0x10
+#define SMBHSTSTS_BUS_ERR	0x08
+#define SMBHSTSTS_DEV_ERR	0x04
+#define SMBHSTSTS_INTR		0x02
+#define SMBHSTSTS_HOST_BUSY	0x01
+
+#define STATUS_FLAGS		(SMBHSTSTS_BYTE_DONE | SMBHSTSTS_FAILED | \
+				 SMBHSTSTS_BUS_ERR | SMBHSTSTS_DEV_ERR | \
+				 SMBHSTSTS_INTR)
+
+/* Older devices have their ID defined in <linux/pci_ids.h> */
+#define PCI_DEVICE_ID_INTEL_COUGARPOINT_SMBUS	0x1c22
+#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS	0x1d22
+/* Patsburg also has three 'Integrated Device Function' SMBus controllers */
+#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF0	0x1d70
+#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF1	0x1d71
+#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF2	0x1d72
+#define PCI_DEVICE_ID_INTEL_PANTHERPOINT_SMBUS	0x1e22
+#define PCI_DEVICE_ID_INTEL_AVOTON_SMBUS	0x1f3c
+#define PCI_DEVICE_ID_INTEL_DH89XXCC_SMBUS	0x2330
+#define PCI_DEVICE_ID_INTEL_5_3400_SERIES_SMBUS	0x3b30
+#define PCI_DEVICE_ID_INTEL_LYNXPOINT_SMBUS	0x8c22
+#define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_SMBUS	0x9c22
+
+struct i801_priv {
+	struct i2c_adapter adapter;
+	unsigned long smba;
+	unsigned char original_hstcfg;
+	struct pci_dev *pci_dev;
+	unsigned int features;
+};
+
+static struct pci_driver i801_driver;
+
+#define FEATURE_SMBUS_PEC	(1 << 0)
+#define FEATURE_BLOCK_BUFFER	(1 << 1)
+#define FEATURE_BLOCK_PROC	(1 << 2)
+#define FEATURE_I2C_BLOCK_READ	(1 << 3)
+/* Not really a feature, but it's convenient to handle it as such */
+#define FEATURE_IDF		(1 << 15)
+
+static const char *i801_feature_names[] = {
+	"SMBus PEC",
+	"Block buffer",
+	"Block process call",
+	"I2C block read",
+};
+
+static unsigned int disable_features;
+module_param(disable_features, uint, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(disable_features, "Disable selected driver features");
+
+/* Make sure the SMBus host is ready to start transmitting.
+   Return 0 if it is, -EBUSY if it is not. */
+static int i801_check_pre(struct i801_priv *priv)
+{
+	int status;
+
+	status = inb_p(SMBHSTSTS(priv));
+	if (status & SMBHSTSTS_HOST_BUSY) {
+		dev_err(&priv->pci_dev->dev, "SMBus is busy, can't use it!\n");
+		return -EBUSY;
+	}
+
+	status &= STATUS_FLAGS;
+	if (status) {
+		dev_dbg(&priv->pci_dev->dev, "Clearing status flags (%02x)\n",
+			status);
+		outb_p(status, SMBHSTSTS(priv));
+		status = inb_p(SMBHSTSTS(priv)) & STATUS_FLAGS;
+		if (status) {
+			dev_err(&priv->pci_dev->dev,
+				"Failed clearing status flags (%02x)\n",
+				status);
+			return -EBUSY;
+		}
+	}
+
+	return 0;
+}
+
+/* Convert the status register to an error code, and clear it. */
+static int i801_check_post(struct i801_priv *priv, int status, int timeout)
+{
+	int result = 0;
+
+	/* If the SMBus is still busy, we give up */
+	if (timeout) {
+		dev_err(&priv->pci_dev->dev, "Transaction timeout\n");
+		/* try to stop the current command */
+		dev_dbg(&priv->pci_dev->dev, "Terminating the current operation\n");
+		outb_p(inb_p(SMBHSTCNT(priv)) | SMBHSTCNT_KILL,
+		       SMBHSTCNT(priv));
+		usleep_range(1000, 2000);
+		outb_p(inb_p(SMBHSTCNT(priv)) & (~SMBHSTCNT_KILL),
+		       SMBHSTCNT(priv));
+
+		/* Check if it worked */
+		status = inb_p(SMBHSTSTS(priv));
+		if ((status & SMBHSTSTS_HOST_BUSY) ||
+		    !(status & SMBHSTSTS_FAILED))
+			dev_err(&priv->pci_dev->dev,
+				"Failed terminating the transaction\n");
+		outb_p(STATUS_FLAGS, SMBHSTSTS(priv));
+		return -ETIMEDOUT;
+	}
+
+	if (status & SMBHSTSTS_FAILED) {
+		result = -EIO;
+		dev_err(&priv->pci_dev->dev, "Transaction failed\n");
+	}
+	if (status & SMBHSTSTS_DEV_ERR) {
+		result = -ENXIO;
+		dev_dbg(&priv->pci_dev->dev, "No response\n");
+	}
+	if (status & SMBHSTSTS_BUS_ERR) {
+		result = -EAGAIN;
+		dev_dbg(&priv->pci_dev->dev, "Lost arbitration\n");
+	}
+
+	if (result) {
+		/* Clear error flags */
+		outb_p(status & STATUS_FLAGS, SMBHSTSTS(priv));
+		status = inb_p(SMBHSTSTS(priv)) & STATUS_FLAGS;
+		if (status) {
+			dev_warn(&priv->pci_dev->dev, "Failed clearing status "
+				 "flags at end of transaction (%02x)\n",
+				 status);
+		}
+	}
+
+	return result;
+}
+
+static int i801_transaction(struct i801_priv *priv, int xact)
+{
+	int status;
+	int result;
+	int timeout = 0;
+
+	result = i801_check_pre(priv);
+	if (result < 0)
+		return result;
+
+	/* the current contents of SMBHSTCNT can be overwritten, since PEC,
+	 * INTREN, SMBSCMD are passed in xact */
+	outb_p(xact | I801_START, SMBHSTCNT(priv));
+
+	/* We will always wait for a fraction of a second! */
+	do {
+		usleep_range(250, 500);
+		status = inb_p(SMBHSTSTS(priv));
+	} while ((status & SMBHSTSTS_HOST_BUSY) && (timeout++ < MAX_RETRIES));
+
+	result = i801_check_post(priv, status, timeout > MAX_RETRIES);
+	if (result < 0)
+		return result;
+
+	outb_p(SMBHSTSTS_INTR, SMBHSTSTS(priv));
+	return 0;
+}
+
+/* wait for INTR bit as advised by Intel */
+static void i801_wait_hwpec(struct i801_priv *priv)
+{
+	int timeout = 0;
+	int status;
+
+	do {
+		usleep_range(250, 500);
+		status = inb_p(SMBHSTSTS(priv));
+	} while ((!(status & SMBHSTSTS_INTR))
+		 && (timeout++ < MAX_RETRIES));
+
+	if (timeout > MAX_RETRIES)
+		dev_dbg(&priv->pci_dev->dev, "PEC Timeout!\n");
+
+	outb_p(status, SMBHSTSTS(priv));
+}
+
+static int i801_block_transaction_by_block(struct i801_priv *priv,
+					   union i2c_smbus_data *data,
+					   char read_write, int hwpec)
+{
+	int i, len;
+	int status;
+
+	inb_p(SMBHSTCNT(priv)); /* reset the data buffer index */
+
+	/* Use 32-byte buffer to process this transaction */
+	if (read_write == I2C_SMBUS_WRITE) {
+		len = data->block[0];
+		outb_p(len, SMBHSTDAT0(priv));
+		for (i = 0; i < len; i++)
+			outb_p(data->block[i+1], SMBBLKDAT(priv));
+	}
+
+	status = i801_transaction(priv, I801_BLOCK_DATA | ENABLE_INT9 |
+				  I801_PEC_EN * hwpec);
+	if (status)
+		return status;
+
+	if (read_write == I2C_SMBUS_READ) {
+		len = inb_p(SMBHSTDAT0(priv));
+		if (len < 1 || len > I2C_SMBUS_BLOCK_MAX)
+			return -EPROTO;
+
+		data->block[0] = len;
+		for (i = 0; i < len; i++)
+			data->block[i + 1] = inb_p(SMBBLKDAT(priv));
+	}
+	return 0;
+}
+
+static int i801_block_transaction_byte_by_byte(struct i801_priv *priv,
+					       union i2c_smbus_data *data,
+					       char read_write, int command,
+					       int hwpec)
+{
+	int i, len;
+	int smbcmd;
+	int status;
+	int result;
+	int timeout;
+
+	result = i801_check_pre(priv);
+	if (result < 0)
+		return result;
+
+	len = data->block[0];
+
+	if (read_write == I2C_SMBUS_WRITE) {
+		outb_p(len, SMBHSTDAT0(priv));
+		outb_p(data->block[1], SMBBLKDAT(priv));
+	}
+
+	for (i = 1; i <= len; i++) {
+		if (i == len && read_write == I2C_SMBUS_READ) {
+			if (command == I2C_SMBUS_I2C_BLOCK_DATA)
+				smbcmd = I801_I2C_BLOCK_LAST;
+			else
+				smbcmd = I801_BLOCK_LAST;
+		} else {
+			if (command == I2C_SMBUS_I2C_BLOCK_DATA
+			 && read_write == I2C_SMBUS_READ)
+				smbcmd = I801_I2C_BLOCK_DATA;
+			else
+				smbcmd = I801_BLOCK_DATA;
+		}
+		outb_p(smbcmd | ENABLE_INT9, SMBHSTCNT(priv));
+
+		if (i == 1)
+			outb_p(inb(SMBHSTCNT(priv)) | I801_START,
+			       SMBHSTCNT(priv));
+
+		/* We will always wait for a fraction of a second! */
+		timeout = 0;
+		do {
+			usleep_range(250, 500);
+			status = inb_p(SMBHSTSTS(priv));
+		} while ((!(status & SMBHSTSTS_BYTE_DONE))
+			 && (timeout++ < MAX_RETRIES));
+
+		result = i801_check_post(priv, status, timeout > MAX_RETRIES);
+		if (result < 0)
+			return result;
+
+		if (i == 1 && read_write == I2C_SMBUS_READ
+		 && command != I2C_SMBUS_I2C_BLOCK_DATA) {
+			len = inb_p(SMBHSTDAT0(priv));
+			if (len < 1 || len > I2C_SMBUS_BLOCK_MAX) {
+				dev_err(&priv->pci_dev->dev,
+					"Illegal SMBus block read size %d\n",
+					len);
+				/* Recover */
+				while (inb_p(SMBHSTSTS(priv)) &
+				       SMBHSTSTS_HOST_BUSY)
+					outb_p(SMBHSTSTS_BYTE_DONE,
+					       SMBHSTSTS(priv));
+				outb_p(SMBHSTSTS_INTR, SMBHSTSTS(priv));
+				return -EPROTO;
+			}
+			data->block[0] = len;
+		}
+
+		/* Retrieve/store value in SMBBLKDAT */
+		if (read_write == I2C_SMBUS_READ)
+			data->block[i] = inb_p(SMBBLKDAT(priv));
+		if (read_write == I2C_SMBUS_WRITE && i+1 <= len)
+			outb_p(data->block[i+1], SMBBLKDAT(priv));
+
+		/* signals SMBBLKDAT ready */
+		outb_p(SMBHSTSTS_BYTE_DONE | SMBHSTSTS_INTR, SMBHSTSTS(priv));
+	}
+
+	return 0;
+}
+
+static int i801_set_block_buffer_mode(struct i801_priv *priv)
+{
+	outb_p(inb_p(SMBAUXCTL(priv)) | SMBAUXCTL_E32B, SMBAUXCTL(priv));
+	if ((inb_p(SMBAUXCTL(priv)) & SMBAUXCTL_E32B) == 0)
+		return -EIO;
+	return 0;
+}
+
+/* Block transaction function */
+static int i801_block_transaction(struct i801_priv *priv,
+				  union i2c_smbus_data *data, char read_write,
+				  int command, int hwpec)
+{
+	int result = 0;
+	unsigned char hostc;
+
+	if (command == I2C_SMBUS_I2C_BLOCK_DATA) {
+		if (read_write == I2C_SMBUS_WRITE) {
+			/* set I2C_EN bit in configuration register */
+			pci_read_config_byte(priv->pci_dev, SMBHSTCFG, &hostc);
+			pci_write_config_byte(priv->pci_dev, SMBHSTCFG,
+					      hostc | SMBHSTCFG_I2C_EN);
+		} else if (!(priv->features & FEATURE_I2C_BLOCK_READ)) {
+			dev_err(&priv->pci_dev->dev,
+				"I2C block read is unsupported!\n");
+			return -EOPNOTSUPP;
+		}
+	}
+
+	if (read_write == I2C_SMBUS_WRITE
+	 || command == I2C_SMBUS_I2C_BLOCK_DATA) {
+		if (data->block[0] < 1)
+			data->block[0] = 1;
+		if (data->block[0] > I2C_SMBUS_BLOCK_MAX)
+			data->block[0] = I2C_SMBUS_BLOCK_MAX;
+	} else {
+		data->block[0] = 32;	/* max for SMBus block reads */
+	}
+
+	/* Experience has shown that the block buffer can only be used for
+	   SMBus (not I2C) block transactions, even though the datasheet
+	   doesn't mention this limitation. */
+	if ((priv->features & FEATURE_BLOCK_BUFFER)
+	 && command != I2C_SMBUS_I2C_BLOCK_DATA
+	 && i801_set_block_buffer_mode(priv) == 0)
+		result = i801_block_transaction_by_block(priv, data,
+							 read_write, hwpec);
+	else
+		result = i801_block_transaction_byte_by_byte(priv, data,
+							     read_write,
+							     command, hwpec);
+
+	if (result == 0 && hwpec)
+		i801_wait_hwpec(priv);
+
+	if (command == I2C_SMBUS_I2C_BLOCK_DATA
+	 && read_write == I2C_SMBUS_WRITE) {
+		/* restore saved configuration register value */
+		pci_write_config_byte(priv->pci_dev, SMBHSTCFG, hostc);
+	}
+	return result;
+}
+
+/* Return negative errno on error. */
+static s32 i801_access(struct i2c_adapter *adap, u16 addr,
+		       unsigned short flags, char read_write, u8 command,
+		       int size, union i2c_smbus_data *data)
+{
+	int hwpec;
+	int block = 0;
+	int ret, xact = 0;
+	struct i801_priv *priv = i2c_get_adapdata(adap);
+
+	hwpec = (priv->features & FEATURE_SMBUS_PEC) && (flags & I2C_CLIENT_PEC)
+		&& size != I2C_SMBUS_QUICK
+		&& size != I2C_SMBUS_I2C_BLOCK_DATA;
+
+	switch (size) {
+	case I2C_SMBUS_QUICK:
+		outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+		       SMBHSTADD(priv));
+		xact = I801_QUICK;
+		break;
+	case I2C_SMBUS_BYTE:
+		outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+		       SMBHSTADD(priv));
+		if (read_write == I2C_SMBUS_WRITE)
+			outb_p(command, SMBHSTCMD(priv));
+		xact = I801_BYTE;
+		break;
+	case I2C_SMBUS_BYTE_DATA:
+		outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+		       SMBHSTADD(priv));
+		outb_p(command, SMBHSTCMD(priv));
+		if (read_write == I2C_SMBUS_WRITE)
+			outb_p(data->byte, SMBHSTDAT0(priv));
+		xact = I801_BYTE_DATA;
+		break;
+	case I2C_SMBUS_WORD_DATA:
+		outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+		       SMBHSTADD(priv));
+		outb_p(command, SMBHSTCMD(priv));
+		if (read_write == I2C_SMBUS_WRITE) {
+			outb_p(data->word & 0xff, SMBHSTDAT0(priv));
+			outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1(priv));
+		}
+		xact = I801_WORD_DATA;
+		break;
+	case I2C_SMBUS_BLOCK_DATA:
+		outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
+		       SMBHSTADD(priv));
+		outb_p(command, SMBHSTCMD(priv));
+		block = 1;
+		break;
+	case I2C_SMBUS_I2C_BLOCK_DATA:
+		/* NB: page 240 of ICH5 datasheet shows that the R/#W
+		 * bit should be cleared here, even when reading */
+		outb_p((addr & 0x7f) << 1, SMBHSTADD(priv));
+		if (read_write == I2C_SMBUS_READ) {
+			/* NB: page 240 of ICH5 datasheet also shows
+			 * that DATA1 is the cmd field when reading */
+			outb_p(command, SMBHSTDAT1(priv));
+		} else
+			outb_p(command, SMBHSTCMD(priv));
+		block = 1;
+		break;
+	default:
+		dev_err(&priv->pci_dev->dev, "Unsupported transaction %d\n",
+			size);
+		return -EOPNOTSUPP;
+	}
+
+	if (hwpec)	/* enable/disable hardware PEC */
+		outb_p(inb_p(SMBAUXCTL(priv)) | SMBAUXCTL_CRC, SMBAUXCTL(priv));
+	else
+		outb_p(inb_p(SMBAUXCTL(priv)) & (~SMBAUXCTL_CRC),
+		       SMBAUXCTL(priv));
+
+	if (block)
+		ret = i801_block_transaction(priv, data, read_write, size,
+					     hwpec);
+	else
+		ret = i801_transaction(priv, xact | ENABLE_INT9);
+
+	/* Some BIOSes don't like it when PEC is enabled at reboot or resume
+	   time, so we forcibly disable it after every transaction. Turn off
+	   E32B for the same reason. */
+	if (hwpec || block)
+		outb_p(inb_p(SMBAUXCTL(priv)) &
+		       ~(SMBAUXCTL_CRC | SMBAUXCTL_E32B), SMBAUXCTL(priv));
+
+	if (block)
+		return ret;
+	if (ret)
+		return ret;
+	if ((read_write == I2C_SMBUS_WRITE) || (xact == I801_QUICK))
+		return 0;
+
+	switch (xact & 0x7f) {
+	case I801_BYTE:	/* Result put in SMBHSTDAT0 */
+	case I801_BYTE_DATA:
+		data->byte = inb_p(SMBHSTDAT0(priv));
+		break;
+	case I801_WORD_DATA:
+		data->word = inb_p(SMBHSTDAT0(priv)) +
+			     (inb_p(SMBHSTDAT1(priv)) << 8);
+		break;
+	}
+	return 0;
+}
+
+
+static u32 i801_func(struct i2c_adapter *adapter)
+{
+	struct i801_priv *priv = i2c_get_adapdata(adapter);
+
+	return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+	       I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+	       I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_WRITE_I2C_BLOCK |
+	       ((priv->features & FEATURE_SMBUS_PEC) ? I2C_FUNC_SMBUS_PEC : 0) |
+	       ((priv->features & FEATURE_I2C_BLOCK_READ) ?
+		I2C_FUNC_SMBUS_READ_I2C_BLOCK : 0);
+}
+
+static const struct i2c_algorithm smbus_algorithm = {
+	.smbus_xfer	= i801_access,
+	.functionality	= i801_func,
+};
+
+static DEFINE_PCI_DEVICE_TABLE(i801_ids) = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_3) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_3) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_2) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_3) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_3) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_3) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_4) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_16) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_17) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB2_17) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_5) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_6) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_EP80579_1) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH10_4) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH10_5) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_5_3400_SERIES_SMBUS) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_COUGARPOINT_SMBUS) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF0) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF1) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF2) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_DH89XXCC_SMBUS) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PANTHERPOINT_SMBUS) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LYNXPOINT_SMBUS) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_SMBUS) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_AVOTON_SMBUS) },
+	{ 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, i801_ids);
+
+#if defined CONFIG_X86 && defined CONFIG_DMI
+static unsigned char apanel_addr;
+
+/* Scan the system ROM for the signature "FJKEYINF" */
+static __init const void __iomem *bios_signature(const void __iomem *bios)
+{
+	ssize_t offset;
+	const unsigned char signature[] = "FJKEYINF";
+
+	for (offset = 0; offset < 0x10000; offset += 0x10) {
+		if (check_signature(bios + offset, signature,
+				    sizeof(signature)-1))
+			return bios + offset;
+	}
+	return NULL;
+}
+
+static void __init input_apanel_init(void)
+{
+	void __iomem *bios;
+	const void __iomem *p;
+
+	bios = ioremap(0xF0000, 0x10000); /* Can't fail */
+	p = bios_signature(bios);
+	if (p) {
+		/* just use the first address */
+		apanel_addr = readb(p + 8 + 3) >> 1;
+	}
+	iounmap(bios);
+}
+
+struct dmi_onboard_device_info {
+	const char *name;
+	u8 type;
+	unsigned short i2c_addr;
+	const char *i2c_type;
+};
+
+static struct dmi_onboard_device_info __devinitdata dmi_devices[] = {
+	{ "Syleus", DMI_DEV_TYPE_OTHER, 0x73, "fscsyl" },
+	{ "Hermes", DMI_DEV_TYPE_OTHER, 0x73, "fscher" },
+	{ "Hades",  DMI_DEV_TYPE_OTHER, 0x73, "fschds" },
+};
+
+static void __devinit dmi_check_onboard_device(u8 type, const char *name,
+					       struct i2c_adapter *adap)
+{
+	int i;
+	struct i2c_board_info info;
+
+	for (i = 0; i < ARRAY_SIZE(dmi_devices); i++) {
+		/* & ~0x80, ignore enabled/disabled bit */
+		if ((type & ~0x80) != dmi_devices[i].type)
+			continue;
+		if (strcasecmp(name, dmi_devices[i].name))
+			continue;
+
+		memset(&info, 0, sizeof(struct i2c_board_info));
+		info.addr = dmi_devices[i].i2c_addr;
+		strlcpy(info.type, dmi_devices[i].i2c_type, I2C_NAME_SIZE);
+		i2c_new_device(adap, &info);
+		break;
+	}
+}
+
+/* We use our own function to check for onboard devices instead of
+   dmi_find_device() as some buggy BIOS's have the devices we are interested
+   in marked as disabled */
+static void __devinit dmi_check_onboard_devices(const struct dmi_header *dm,
+						void *adap)
+{
+	int i, count;
+
+	if (dm->type != 10)
+		return;
+
+	count = (dm->length - sizeof(struct dmi_header)) / 2;
+	for (i = 0; i < count; i++) {
+		const u8 *d = (char *)(dm + 1) + (i * 2);
+		const char *name = ((char *) dm) + dm->length;
+		u8 type = d[0];
+		u8 s = d[1];
+
+		if (!s)
+			continue;
+		s--;
+		while (s > 0 && name[0]) {
+			name += strlen(name) + 1;
+			s--;
+		}
+		if (name[0] == 0) /* Bogus string reference */
+			continue;
+
+		dmi_check_onboard_device(type, name, adap);
+	}
+}
+
+/* Register optional slaves */
+static void __devinit i801_probe_optional_slaves(struct i801_priv *priv)
+{
+	/* Only register slaves on main SMBus channel */
+	if (priv->features & FEATURE_IDF)
+		return;
+
+	if (apanel_addr) {
+		struct i2c_board_info info;
+
+		memset(&info, 0, sizeof(struct i2c_board_info));
+		info.addr = apanel_addr;
+		strlcpy(info.type, "fujitsu_apanel", I2C_NAME_SIZE);
+		i2c_new_device(&priv->adapter, &info);
+	}
+
+	if (dmi_name_in_vendors("FUJITSU"))
+		dmi_walk(dmi_check_onboard_devices, &priv->adapter);
+}
+#else
+static void __init input_apanel_init(void) {}
+static void __devinit i801_probe_optional_slaves(struct i801_priv *priv) {}
+#endif	/* CONFIG_X86 && CONFIG_DMI */
+
+static int __devinit i801_probe(struct pci_dev *dev,
+				const struct pci_device_id *id)
+{
+	unsigned char temp;
+	int err, i;
+	struct i801_priv *priv;
+
+	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	i2c_set_adapdata(&priv->adapter, priv);
+	priv->adapter.owner = THIS_MODULE;
+	priv->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
+	priv->adapter.algo = &smbus_algorithm;
+
+	priv->pci_dev = dev;
+	switch (dev->device) {
+	case PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF0:
+	case PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF1:
+	case PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF2:
+		priv->features |= FEATURE_IDF;
+		/* fall through */
+	default:
+		priv->features |= FEATURE_I2C_BLOCK_READ;
+		/* fall through */
+	case PCI_DEVICE_ID_INTEL_82801DB_3:
+		priv->features |= FEATURE_SMBUS_PEC;
+		priv->features |= FEATURE_BLOCK_BUFFER;
+		/* fall through */
+	case PCI_DEVICE_ID_INTEL_82801CA_3:
+	case PCI_DEVICE_ID_INTEL_82801BA_2:
+	case PCI_DEVICE_ID_INTEL_82801AB_3:
+	case PCI_DEVICE_ID_INTEL_82801AA_3:
+		break;
+	}
+
+	/* Disable features on user request */
+	for (i = 0; i < ARRAY_SIZE(i801_feature_names); i++) {
+		if (priv->features & disable_features & (1 << i))
+			dev_notice(&dev->dev, "%s disabled by user\n",
+				   i801_feature_names[i]);
+	}
+	priv->features &= ~disable_features;
+
+	err = pci_enable_device(dev);
+	if (err) {
+		dev_err(&dev->dev, "Failed to enable SMBus PCI device (%d)\n",
+			err);
+		goto exit;
+	}
+
+	/* Determine the address of the SMBus area */
+	priv->smba = pci_resource_start(dev, SMBBAR);
+	if (!priv->smba) {
+		dev_err(&dev->dev, "SMBus base address uninitialized, "
+			"upgrade BIOS\n");
+		err = -ENODEV;
+		goto exit;
+	}
+
+	err = acpi_check_resource_conflict(&dev->resource[SMBBAR]);
+	if (err) {
+		err = -ENODEV;
+		goto exit;
+	}
+
+	err = pci_request_region(dev, SMBBAR, i801_driver.name);
+	if (err) {
+		dev_err(&dev->dev, "Failed to request SMBus region "
+			"0x%lx-0x%Lx\n", priv->smba,
+			(unsigned long long)pci_resource_end(dev, SMBBAR));
+		goto exit;
+	}
+
+	pci_read_config_byte(priv->pci_dev, SMBHSTCFG, &temp);
+	priv->original_hstcfg = temp;
+	temp &= ~SMBHSTCFG_I2C_EN;	/* SMBus timing */
+	if (!(temp & SMBHSTCFG_HST_EN)) {
+		dev_info(&dev->dev, "Enabling SMBus device\n");
+		temp |= SMBHSTCFG_HST_EN;
+	}
+	pci_write_config_byte(priv->pci_dev, SMBHSTCFG, temp);
+
+	if (temp & SMBHSTCFG_SMB_SMI_EN)
+		dev_dbg(&dev->dev, "SMBus using interrupt SMI#\n");
+	else
+		dev_dbg(&dev->dev, "SMBus using PCI Interrupt\n");
+
+	/* Clear special mode bits */
+	if (priv->features & (FEATURE_SMBUS_PEC | FEATURE_BLOCK_BUFFER))
+		outb_p(inb_p(SMBAUXCTL(priv)) &
+		       ~(SMBAUXCTL_CRC | SMBAUXCTL_E32B), SMBAUXCTL(priv));
+
+	/* set up the sysfs linkage to our parent device */
+	priv->adapter.dev.parent = &dev->dev;
+
+	/* Retry up to 3 times on lost arbitration */
+	priv->adapter.retries = 3;
+
+	snprintf(priv->adapter.name, sizeof(priv->adapter.name),
+		"SMBus I801 adapter at %04lx", priv->smba);
+	err = i2c_add_adapter(&priv->adapter);
+	if (err) {
+		dev_err(&dev->dev, "Failed to add SMBus adapter\n");
+		goto exit_release;
+	}
+
+	i801_probe_optional_slaves(priv);
+
+	pci_set_drvdata(dev, priv);
+	return 0;
+
+exit_release:
+	pci_release_region(dev, SMBBAR);
+exit:
+	kfree(priv);
+	return err;
+}
+
+static void __devexit i801_remove(struct pci_dev *dev)
+{
+	struct i801_priv *priv = pci_get_drvdata(dev);
+
+	i2c_del_adapter(&priv->adapter);
+	pci_write_config_byte(dev, SMBHSTCFG, priv->original_hstcfg);
+	pci_release_region(dev, SMBBAR);
+	pci_set_drvdata(dev, NULL);
+	kfree(priv);
+	/*
+	 * do not call pci_disable_device(dev) since it can cause hard hangs on
+	 * some systems during power-off (eg. Fujitsu-Siemens Lifebook E8010)
+	 */
+}
+
+#ifdef CONFIG_PM
+static int i801_suspend(struct pci_dev *dev, pm_message_t mesg)
+{
+	struct i801_priv *priv = pci_get_drvdata(dev);
+
+	pci_save_state(dev);
+	pci_write_config_byte(dev, SMBHSTCFG, priv->original_hstcfg);
+	pci_set_power_state(dev, pci_choose_state(dev, mesg));
+	return 0;
+}
+
+static int i801_resume(struct pci_dev *dev)
+{
+	pci_set_power_state(dev, PCI_D0);
+	pci_restore_state(dev);
+	return pci_enable_device(dev);
+}
+#else
+#define i801_suspend NULL
+#define i801_resume NULL
+#endif
+
+static struct pci_driver i801_driver = {
+	.name		= "i801_smbus",
+	.id_table	= i801_ids,
+	.probe		= i801_probe,
+	.remove		= __devexit_p(i801_remove),
+	.suspend	= i801_suspend,
+	.resume		= i801_resume,
+};
+
+static int __init i2c_i801_init(void)
+{
+	if (dmi_name_in_vendors("FUJITSU"))
+		input_apanel_init();
+	return pci_register_driver(&i801_driver);
+}
+
+static void __exit i2c_i801_exit(void)
+{
+	pci_unregister_driver(&i801_driver);
+}
+
+MODULE_AUTHOR("Mark D. Studebaker <mdsxyz123@yahoo.com>, "
+	      "Jean Delvare <khali@linux-fr.org>");
+MODULE_DESCRIPTION("I801 SMBus driver");
+MODULE_LICENSE("GPL");
+
+module_init(i2c_i801_init);
+module_exit(i2c_i801_exit);
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-ibm_iic.c b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-ibm_iic.c
new file mode 100644
index 0000000..806e225
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-ibm_iic.c
@@ -0,0 +1,818 @@
+/*
+ * drivers/i2c/busses/i2c-ibm_iic.c
+ *
+ * Support for the IIC peripheral on IBM PPC 4xx
+ *
+ * Copyright (c) 2003, 2004 Zultys Technologies.
+ * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
+ *
+ * Copyright (c) 2008 PIKA Technologies
+ * Sean MacLennan <smaclennan@pikatech.com>
+ *
+ * Based on original work by
+ * 	Ian DaSilva  <idasilva@mvista.com>
+ *      Armin Kuster <akuster@mvista.com>
+ * 	Matt Porter  <mporter@mvista.com>
+ *
+ *      Copyright 2000-2003 MontaVista Software Inc.
+ *
+ * Original driver version was highly leveraged from i2c-elektor.c
+ *
+ *   	Copyright 1995-97 Simon G. Vogl
+ *                1998-99 Hans Berglund
+ *
+ *   	With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi>
+ *	and even Frodo Looijaard <frodol@dds.nl>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <asm/irq.h>
+#include <linux/io.h>
+#include <linux/i2c.h>
+#include <linux/of_platform.h>
+#include <linux/of_i2c.h>
+
+#include "i2c-ibm_iic.h"
+
+#define DRIVER_VERSION "2.2"
+
+MODULE_DESCRIPTION("IBM IIC driver v" DRIVER_VERSION);
+MODULE_LICENSE("GPL");
+
+static bool iic_force_poll;
+module_param(iic_force_poll, bool, 0);
+MODULE_PARM_DESC(iic_force_poll, "Force polling mode");
+
+static bool iic_force_fast;
+module_param(iic_force_fast, bool, 0);
+MODULE_PARM_DESC(iic_force_fast, "Force fast mode (400 kHz)");
+
+#define DBG_LEVEL 0
+
+#ifdef DBG
+#undef DBG
+#endif
+
+#ifdef DBG2
+#undef DBG2
+#endif
+
+#if DBG_LEVEL > 0
+#  define DBG(f,x...)	printk(KERN_DEBUG "ibm-iic" f, ##x)
+#else
+#  define DBG(f,x...)	((void)0)
+#endif
+#if DBG_LEVEL > 1
+#  define DBG2(f,x...) 	DBG(f, ##x)
+#else
+#  define DBG2(f,x...) 	((void)0)
+#endif
+#if DBG_LEVEL > 2
+static void dump_iic_regs(const char* header, struct ibm_iic_private* dev)
+{
+	volatile struct iic_regs __iomem *iic = dev->vaddr;
+	printk(KERN_DEBUG "ibm-iic%d: %s\n", dev->idx, header);
+	printk(KERN_DEBUG
+	       "  cntl     = 0x%02x, mdcntl = 0x%02x\n"
+	       "  sts      = 0x%02x, extsts = 0x%02x\n"
+	       "  clkdiv   = 0x%02x, xfrcnt = 0x%02x\n"
+	       "  xtcntlss = 0x%02x, directcntl = 0x%02x\n",
+		in_8(&iic->cntl), in_8(&iic->mdcntl), in_8(&iic->sts),
+		in_8(&iic->extsts), in_8(&iic->clkdiv), in_8(&iic->xfrcnt),
+		in_8(&iic->xtcntlss), in_8(&iic->directcntl));
+}
+#  define DUMP_REGS(h,dev)	dump_iic_regs((h),(dev))
+#else
+#  define DUMP_REGS(h,dev)	((void)0)
+#endif
+
+/* Bus timings (in ns) for bit-banging */
+static struct i2c_timings {
+	unsigned int hd_sta;
+	unsigned int su_sto;
+	unsigned int low;
+	unsigned int high;
+	unsigned int buf;
+} timings [] = {
+/* Standard mode (100 KHz) */
+{
+	.hd_sta	= 4000,
+	.su_sto	= 4000,
+	.low	= 4700,
+	.high	= 4000,
+	.buf	= 4700,
+},
+/* Fast mode (400 KHz) */
+{
+	.hd_sta = 600,
+	.su_sto	= 600,
+	.low 	= 1300,
+	.high 	= 600,
+	.buf	= 1300,
+}};
+
+/* Enable/disable interrupt generation */
+static inline void iic_interrupt_mode(struct ibm_iic_private* dev, int enable)
+{
+	out_8(&dev->vaddr->intmsk, enable ? INTRMSK_EIMTC : 0);
+}
+
+/*
+ * Initialize IIC interface.
+ */
+static void iic_dev_init(struct ibm_iic_private* dev)
+{
+	volatile struct iic_regs __iomem *iic = dev->vaddr;
+
+	DBG("%d: init\n", dev->idx);
+
+	/* Clear master address */
+	out_8(&iic->lmadr, 0);
+	out_8(&iic->hmadr, 0);
+
+	/* Clear slave address */
+	out_8(&iic->lsadr, 0);
+	out_8(&iic->hsadr, 0);
+
+	/* Clear status & extended status */
+	out_8(&iic->sts, STS_SCMP | STS_IRQA);
+	out_8(&iic->extsts, EXTSTS_IRQP | EXTSTS_IRQD | EXTSTS_LA
+			    | EXTSTS_ICT | EXTSTS_XFRA);
+
+	/* Set clock divider */
+	out_8(&iic->clkdiv, dev->clckdiv);
+
+	/* Clear transfer count */
+	out_8(&iic->xfrcnt, 0);
+
+	/* Clear extended control and status */
+	out_8(&iic->xtcntlss, XTCNTLSS_SRC | XTCNTLSS_SRS | XTCNTLSS_SWC
+			    | XTCNTLSS_SWS);
+
+	/* Clear control register */
+	out_8(&iic->cntl, 0);
+
+	/* Enable interrupts if possible */
+	iic_interrupt_mode(dev, dev->irq >= 0);
+
+	/* Set mode control */
+	out_8(&iic->mdcntl, MDCNTL_FMDB | MDCNTL_EINT | MDCNTL_EUBS
+			    | (dev->fast_mode ? MDCNTL_FSM : 0));
+
+	DUMP_REGS("iic_init", dev);
+}
+
+/*
+ * Reset IIC interface
+ */
+static void iic_dev_reset(struct ibm_iic_private* dev)
+{
+	volatile struct iic_regs __iomem *iic = dev->vaddr;
+	int i;
+	u8 dc;
+
+	DBG("%d: soft reset\n", dev->idx);
+	DUMP_REGS("reset", dev);
+
+    	/* Place chip in the reset state */
+	out_8(&iic->xtcntlss, XTCNTLSS_SRST);
+
+	/* Check if bus is free */
+	dc = in_8(&iic->directcntl);
+	if (!DIRCTNL_FREE(dc)){
+		DBG("%d: trying to regain bus control\n", dev->idx);
+
+		/* Try to set bus free state */
+		out_8(&iic->directcntl, DIRCNTL_SDAC | DIRCNTL_SCC);
+
+		/* Wait until we regain bus control */
+		for (i = 0; i < 100; ++i){
+			dc = in_8(&iic->directcntl);
+			if (DIRCTNL_FREE(dc))
+				break;
+
+			/* Toggle SCL line */
+			dc ^= DIRCNTL_SCC;
+			out_8(&iic->directcntl, dc);
+			udelay(10);
+			dc ^= DIRCNTL_SCC;
+			out_8(&iic->directcntl, dc);
+
+			/* be nice */
+			cond_resched();
+		}
+	}
+
+	/* Remove reset */
+	out_8(&iic->xtcntlss, 0);
+
+	/* Reinitialize interface */
+	iic_dev_init(dev);
+}
+
+/*
+ * Do 0-length transaction using bit-banging through IIC_DIRECTCNTL register.
+ */
+
+/* Wait for SCL and/or SDA to be high */
+static int iic_dc_wait(volatile struct iic_regs __iomem *iic, u8 mask)
+{
+	unsigned long x = jiffies + HZ / 28 + 2;
+	while ((in_8(&iic->directcntl) & mask) != mask){
+		if (unlikely(time_after(jiffies, x)))
+			return -1;
+		cond_resched();
+	}
+	return 0;
+}
+
+static int iic_smbus_quick(struct ibm_iic_private* dev, const struct i2c_msg* p)
+{
+	volatile struct iic_regs __iomem *iic = dev->vaddr;
+	const struct i2c_timings* t = &timings[dev->fast_mode ? 1 : 0];
+	u8 mask, v, sda;
+	int i, res;
+
+	/* Only 7-bit addresses are supported */
+	if (unlikely(p->flags & I2C_M_TEN)){
+		DBG("%d: smbus_quick - 10 bit addresses are not supported\n",
+			dev->idx);
+		return -EINVAL;
+	}
+
+	DBG("%d: smbus_quick(0x%02x)\n", dev->idx, p->addr);
+
+	/* Reset IIC interface */
+	out_8(&iic->xtcntlss, XTCNTLSS_SRST);
+
+	/* Wait for bus to become free */
+	out_8(&iic->directcntl, DIRCNTL_SDAC | DIRCNTL_SCC);
+	if (unlikely(iic_dc_wait(iic, DIRCNTL_MSDA | DIRCNTL_MSC)))
+		goto err;
+	ndelay(t->buf);
+
+	/* START */
+	out_8(&iic->directcntl, DIRCNTL_SCC);
+	sda = 0;
+	ndelay(t->hd_sta);
+
+	/* Send address */
+	v = (u8)((p->addr << 1) | ((p->flags & I2C_M_RD) ? 1 : 0));
+	for (i = 0, mask = 0x80; i < 8; ++i, mask >>= 1){
+		out_8(&iic->directcntl, sda);
+		ndelay(t->low / 2);
+		sda = (v & mask) ? DIRCNTL_SDAC : 0;
+		out_8(&iic->directcntl, sda);
+		ndelay(t->low / 2);
+
+		out_8(&iic->directcntl, DIRCNTL_SCC | sda);
+		if (unlikely(iic_dc_wait(iic, DIRCNTL_MSC)))
+			goto err;
+		ndelay(t->high);
+	}
+
+	/* ACK */
+	out_8(&iic->directcntl, sda);
+	ndelay(t->low / 2);
+	out_8(&iic->directcntl, DIRCNTL_SDAC);
+	ndelay(t->low / 2);
+	out_8(&iic->directcntl, DIRCNTL_SDAC | DIRCNTL_SCC);
+	if (unlikely(iic_dc_wait(iic, DIRCNTL_MSC)))
+		goto err;
+	res = (in_8(&iic->directcntl) & DIRCNTL_MSDA) ? -EREMOTEIO : 1;
+	ndelay(t->high);
+
+	/* STOP */
+	out_8(&iic->directcntl, 0);
+	ndelay(t->low);
+	out_8(&iic->directcntl, DIRCNTL_SCC);
+	if (unlikely(iic_dc_wait(iic, DIRCNTL_MSC)))
+		goto err;
+	ndelay(t->su_sto);
+	out_8(&iic->directcntl, DIRCNTL_SDAC | DIRCNTL_SCC);
+
+	ndelay(t->buf);
+
+	DBG("%d: smbus_quick -> %s\n", dev->idx, res ? "NACK" : "ACK");
+out:
+	/* Remove reset */
+	out_8(&iic->xtcntlss, 0);
+
+	/* Reinitialize interface */
+	iic_dev_init(dev);
+
+	return res;
+err:
+	DBG("%d: smbus_quick - bus is stuck\n", dev->idx);
+	res = -EREMOTEIO;
+	goto out;
+}
+
+/*
+ * IIC interrupt handler
+ */
+static irqreturn_t iic_handler(int irq, void *dev_id)
+{
+	struct ibm_iic_private* dev = (struct ibm_iic_private*)dev_id;
+	volatile struct iic_regs __iomem *iic = dev->vaddr;
+
+	DBG2("%d: irq handler, STS = 0x%02x, EXTSTS = 0x%02x\n",
+	     dev->idx, in_8(&iic->sts), in_8(&iic->extsts));
+
+	/* Acknowledge IRQ and wakeup iic_wait_for_tc */
+	out_8(&iic->sts, STS_IRQA | STS_SCMP);
+	wake_up_interruptible(&dev->wq);
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * Get master transfer result and clear errors if any.
+ * Returns the number of actually transferred bytes or error (<0)
+ */
+static int iic_xfer_result(struct ibm_iic_private* dev)
+{
+	volatile struct iic_regs __iomem *iic = dev->vaddr;
+
+	if (unlikely(in_8(&iic->sts) & STS_ERR)){
+		DBG("%d: xfer error, EXTSTS = 0x%02x\n", dev->idx,
+			in_8(&iic->extsts));
+
+		/* Clear errors and possible pending IRQs */
+		out_8(&iic->extsts, EXTSTS_IRQP | EXTSTS_IRQD |
+			EXTSTS_LA | EXTSTS_ICT | EXTSTS_XFRA);
+
+		/* Flush master data buffer */
+		out_8(&iic->mdcntl, in_8(&iic->mdcntl) | MDCNTL_FMDB);
+
+		/* Is bus free?
+		 * If error happened during combined xfer
+		 * IIC interface is usually stuck in some strange
+		 * state, the only way out - soft reset.
+		 */
+		if ((in_8(&iic->extsts) & EXTSTS_BCS_MASK) != EXTSTS_BCS_FREE){
+			DBG("%d: bus is stuck, resetting\n", dev->idx);
+			iic_dev_reset(dev);
+		}
+		return -EREMOTEIO;
+	}
+	else
+		return in_8(&iic->xfrcnt) & XFRCNT_MTC_MASK;
+}
+
+/*
+ * Try to abort active transfer.
+ */
+static void iic_abort_xfer(struct ibm_iic_private* dev)
+{
+	volatile struct iic_regs __iomem *iic = dev->vaddr;
+	unsigned long x;
+
+	DBG("%d: iic_abort_xfer\n", dev->idx);
+
+	out_8(&iic->cntl, CNTL_HMT);
+
+	/*
+	 * Wait for the abort command to complete.
+	 * It's not worth to be optimized, just poll (timeout >= 1 tick)
+	 */
+	x = jiffies + 2;
+	while ((in_8(&iic->extsts) & EXTSTS_BCS_MASK) != EXTSTS_BCS_FREE){
+		if (time_after(jiffies, x)){
+			DBG("%d: abort timeout, resetting...\n", dev->idx);
+			iic_dev_reset(dev);
+			return;
+		}
+		schedule();
+	}
+
+	/* Just to clear errors */
+	iic_xfer_result(dev);
+}
+
+/*
+ * Wait for master transfer to complete.
+ * It puts current process to sleep until we get interrupt or timeout expires.
+ * Returns the number of transferred bytes or error (<0)
+ */
+static int iic_wait_for_tc(struct ibm_iic_private* dev){
+
+	volatile struct iic_regs __iomem *iic = dev->vaddr;
+	int ret = 0;
+
+	if (dev->irq >= 0){
+		/* Interrupt mode */
+		ret = wait_event_interruptible_timeout(dev->wq,
+			!(in_8(&iic->sts) & STS_PT), dev->adap.timeout);
+
+		if (unlikely(ret < 0))
+			DBG("%d: wait interrupted\n", dev->idx);
+		else if (unlikely(in_8(&iic->sts) & STS_PT)){
+			DBG("%d: wait timeout\n", dev->idx);
+			ret = -ETIMEDOUT;
+		}
+	}
+	else {
+		/* Polling mode */
+		unsigned long x = jiffies + dev->adap.timeout;
+
+		while (in_8(&iic->sts) & STS_PT){
+			if (unlikely(time_after(jiffies, x))){
+				DBG("%d: poll timeout\n", dev->idx);
+				ret = -ETIMEDOUT;
+				break;
+			}
+
+			if (unlikely(signal_pending(current))){
+				DBG("%d: poll interrupted\n", dev->idx);
+				ret = -ERESTARTSYS;
+				break;
+			}
+			schedule();
+		}
+	}
+
+	if (unlikely(ret < 0))
+		iic_abort_xfer(dev);
+	else
+		ret = iic_xfer_result(dev);
+
+	DBG2("%d: iic_wait_for_tc -> %d\n", dev->idx, ret);
+
+	return ret;
+}
+
+/*
+ * Low level master transfer routine
+ */
+static int iic_xfer_bytes(struct ibm_iic_private* dev, struct i2c_msg* pm,
+			  int combined_xfer)
+{
+	volatile struct iic_regs __iomem *iic = dev->vaddr;
+	char* buf = pm->buf;
+	int i, j, loops, ret = 0;
+	int len = pm->len;
+
+	u8 cntl = (in_8(&iic->cntl) & CNTL_AMD) | CNTL_PT;
+	if (pm->flags & I2C_M_RD)
+		cntl |= CNTL_RW;
+
+	loops = (len + 3) / 4;
+	for (i = 0; i < loops; ++i, len -= 4){
+		int count = len > 4 ? 4 : len;
+		u8 cmd = cntl | ((count - 1) << CNTL_TCT_SHIFT);
+
+		if (!(cntl & CNTL_RW))
+			for (j = 0; j < count; ++j)
+				out_8((void __iomem *)&iic->mdbuf, *buf++);
+
+		if (i < loops - 1)
+			cmd |= CNTL_CHT;
+		else if (combined_xfer)
+			cmd |= CNTL_RPST;
+
+		DBG2("%d: xfer_bytes, %d, CNTL = 0x%02x\n", dev->idx, count, cmd);
+
+		/* Start transfer */
+		out_8(&iic->cntl, cmd);
+
+		/* Wait for completion */
+		ret = iic_wait_for_tc(dev);
+
+		if (unlikely(ret < 0))
+			break;
+		else if (unlikely(ret != count)){
+			DBG("%d: xfer_bytes, requested %d, transferred %d\n",
+				dev->idx, count, ret);
+
+			/* If it's not a last part of xfer, abort it */
+			if (combined_xfer || (i < loops - 1))
+    				iic_abort_xfer(dev);
+
+			ret = -EREMOTEIO;
+			break;
+		}
+
+		if (cntl & CNTL_RW)
+			for (j = 0; j < count; ++j)
+				*buf++ = in_8((void __iomem *)&iic->mdbuf);
+	}
+
+	return ret > 0 ? 0 : ret;
+}
+
+/*
+ * Set target slave address for master transfer
+ */
+static inline void iic_address(struct ibm_iic_private* dev, struct i2c_msg* msg)
+{
+	volatile struct iic_regs __iomem *iic = dev->vaddr;
+	u16 addr = msg->addr;
+
+	DBG2("%d: iic_address, 0x%03x (%d-bit)\n", dev->idx,
+		addr, msg->flags & I2C_M_TEN ? 10 : 7);
+
+	if (msg->flags & I2C_M_TEN){
+	    out_8(&iic->cntl, CNTL_AMD);
+	    out_8(&iic->lmadr, addr);
+	    out_8(&iic->hmadr, 0xf0 | ((addr >> 7) & 0x06));
+	}
+	else {
+	    out_8(&iic->cntl, 0);
+	    out_8(&iic->lmadr, addr << 1);
+	}
+}
+
+static inline int iic_invalid_address(const struct i2c_msg* p)
+{
+	return (p->addr > 0x3ff) || (!(p->flags & I2C_M_TEN) && (p->addr > 0x7f));
+}
+
+static inline int iic_address_neq(const struct i2c_msg* p1,
+				  const struct i2c_msg* p2)
+{
+	return (p1->addr != p2->addr)
+		|| ((p1->flags & I2C_M_TEN) != (p2->flags & I2C_M_TEN));
+}
+
+/*
+ * Generic master transfer entrypoint.
+ * Returns the number of processed messages or error (<0)
+ */
+static int iic_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+{
+    	struct ibm_iic_private* dev = (struct ibm_iic_private*)(i2c_get_adapdata(adap));
+	volatile struct iic_regs __iomem *iic = dev->vaddr;
+	int i, ret = 0;
+
+	DBG2("%d: iic_xfer, %d msg(s)\n", dev->idx, num);
+
+	if (!num)
+		return 0;
+
+	/* Check the sanity of the passed messages.
+	 * Uhh, generic i2c layer is more suitable place for such code...
+	 */
+	if (unlikely(iic_invalid_address(&msgs[0]))){
+		DBG("%d: invalid address 0x%03x (%d-bit)\n", dev->idx,
+			msgs[0].addr, msgs[0].flags & I2C_M_TEN ? 10 : 7);
+		return -EINVAL;
+	}
+	for (i = 0; i < num; ++i){
+		if (unlikely(msgs[i].len <= 0)){
+			if (num == 1 && !msgs[0].len){
+				/* Special case for I2C_SMBUS_QUICK emulation.
+				 * IBM IIC doesn't support 0-length transactions
+				 * so we have to emulate them using bit-banging.
+				 */
+				return iic_smbus_quick(dev, &msgs[0]);
+			}
+			DBG("%d: invalid len %d in msg[%d]\n", dev->idx,
+				msgs[i].len, i);
+			return -EINVAL;
+		}
+		if (unlikely(iic_address_neq(&msgs[0], &msgs[i]))){
+			DBG("%d: invalid addr in msg[%d]\n", dev->idx, i);
+			return -EINVAL;
+		}
+	}
+
+	/* Check bus state */
+	if (unlikely((in_8(&iic->extsts) & EXTSTS_BCS_MASK) != EXTSTS_BCS_FREE)){
+		DBG("%d: iic_xfer, bus is not free\n", dev->idx);
+
+		/* Usually it means something serious has happened.
+		 * We *cannot* have unfinished previous transfer
+		 * so it doesn't make any sense to try to stop it.
+		 * Probably we were not able to recover from the
+		 * previous error.
+		 * The only *reasonable* thing I can think of here
+		 * is soft reset.  --ebs
+		 */
+		iic_dev_reset(dev);
+
+		if ((in_8(&iic->extsts) & EXTSTS_BCS_MASK) != EXTSTS_BCS_FREE){
+			DBG("%d: iic_xfer, bus is still not free\n", dev->idx);
+			return -EREMOTEIO;
+		}
+	}
+	else {
+		/* Flush master data buffer (just in case) */
+		out_8(&iic->mdcntl, in_8(&iic->mdcntl) | MDCNTL_FMDB);
+	}
+
+	/* Load slave address */
+	iic_address(dev, &msgs[0]);
+
+	/* Do real transfer */
+    	for (i = 0; i < num && !ret; ++i)
+		ret = iic_xfer_bytes(dev, &msgs[i], i < num - 1);
+
+	return ret < 0 ? ret : num;
+}
+
+static u32 iic_func(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR;
+}
+
+static const struct i2c_algorithm iic_algo = {
+	.master_xfer 	= iic_xfer,
+	.functionality	= iic_func
+};
+
+/*
+ * Calculates IICx_CLCKDIV value for a specific OPB clock frequency
+ */
+static inline u8 iic_clckdiv(unsigned int opb)
+{
+	/* Compatibility kludge, should go away after all cards
+	 * are fixed to fill correct value for opbfreq.
+	 * Previous driver version used hardcoded divider value 4,
+	 * it corresponds to OPB frequency from the range (40, 50] MHz
+	 */
+	if (!opb){
+		printk(KERN_WARNING "ibm-iic: using compatibility value for OPB freq,"
+			" fix your board specific setup\n");
+		opb = 50000000;
+	}
+
+	/* Convert to MHz */
+	opb /= 1000000;
+
+	if (opb < 20 || opb > 150){
+		printk(KERN_WARNING "ibm-iic: invalid OPB clock frequency %u MHz\n",
+			opb);
+		opb = opb < 20 ? 20 : 150;
+	}
+	return (u8)((opb + 9) / 10 - 1);
+}
+
+static int __devinit iic_request_irq(struct platform_device *ofdev,
+				     struct ibm_iic_private *dev)
+{
+	struct device_node *np = ofdev->dev.of_node;
+	int irq;
+
+	if (iic_force_poll)
+		return 0;
+
+	irq = irq_of_parse_and_map(np, 0);
+	if (!irq) {
+		dev_err(&ofdev->dev, "irq_of_parse_and_map failed\n");
+		return 0;
+	}
+
+	/* Disable interrupts until we finish initialization, assumes
+	 *  level-sensitive IRQ setup...
+	 */
+	iic_interrupt_mode(dev, 0);
+	if (request_irq(irq, iic_handler, 0, "IBM IIC", dev)) {
+		dev_err(&ofdev->dev, "request_irq %d failed\n", irq);
+		/* Fallback to the polling mode */
+		return 0;
+	}
+
+	return irq;
+}
+
+/*
+ * Register single IIC interface
+ */
+static int __devinit iic_probe(struct platform_device *ofdev)
+{
+	struct device_node *np = ofdev->dev.of_node;
+	struct ibm_iic_private *dev;
+	struct i2c_adapter *adap;
+	const u32 *freq;
+	int ret;
+
+	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+	if (!dev) {
+		dev_err(&ofdev->dev, "failed to allocate device data\n");
+		return -ENOMEM;
+	}
+
+	dev_set_drvdata(&ofdev->dev, dev);
+
+	dev->vaddr = of_iomap(np, 0);
+	if (dev->vaddr == NULL) {
+		dev_err(&ofdev->dev, "failed to iomap device\n");
+		ret = -ENXIO;
+		goto error_cleanup;
+	}
+
+	init_waitqueue_head(&dev->wq);
+
+	dev->irq = iic_request_irq(ofdev, dev);
+	if (!dev->irq)
+		dev_warn(&ofdev->dev, "using polling mode\n");
+
+	/* Board specific settings */
+	if (iic_force_fast || of_get_property(np, "fast-mode", NULL))
+		dev->fast_mode = 1;
+
+	freq = of_get_property(np, "clock-frequency", NULL);
+	if (freq == NULL) {
+		freq = of_get_property(np->parent, "clock-frequency", NULL);
+		if (freq == NULL) {
+			dev_err(&ofdev->dev, "Unable to get bus frequency\n");
+			ret = -EINVAL;
+			goto error_cleanup;
+		}
+	}
+
+	dev->clckdiv = iic_clckdiv(*freq);
+	dev_dbg(&ofdev->dev, "clckdiv = %d\n", dev->clckdiv);
+
+	/* Initialize IIC interface */
+	iic_dev_init(dev);
+
+	/* Register it with i2c layer */
+	adap = &dev->adap;
+	adap->dev.parent = &ofdev->dev;
+	adap->dev.of_node = of_node_get(np);
+	strlcpy(adap->name, "IBM IIC", sizeof(adap->name));
+	i2c_set_adapdata(adap, dev);
+	adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
+	adap->algo = &iic_algo;
+	adap->timeout = HZ;
+
+	ret = i2c_add_adapter(adap);
+	if (ret  < 0) {
+		dev_err(&ofdev->dev, "failed to register i2c adapter\n");
+		goto error_cleanup;
+	}
+
+	dev_info(&ofdev->dev, "using %s mode\n",
+		 dev->fast_mode ? "fast (400 kHz)" : "standard (100 kHz)");
+
+	/* Now register all the child nodes */
+	of_i2c_register_devices(adap);
+
+	return 0;
+
+error_cleanup:
+	if (dev->irq) {
+		iic_interrupt_mode(dev, 0);
+		free_irq(dev->irq, dev);
+	}
+
+	if (dev->vaddr)
+		iounmap(dev->vaddr);
+
+	dev_set_drvdata(&ofdev->dev, NULL);
+	kfree(dev);
+	return ret;
+}
+
+/*
+ * Cleanup initialized IIC interface
+ */
+static int __devexit iic_remove(struct platform_device *ofdev)
+{
+	struct ibm_iic_private *dev = dev_get_drvdata(&ofdev->dev);
+
+	dev_set_drvdata(&ofdev->dev, NULL);
+
+	i2c_del_adapter(&dev->adap);
+
+	if (dev->irq) {
+		iic_interrupt_mode(dev, 0);
+		free_irq(dev->irq, dev);
+	}
+
+	iounmap(dev->vaddr);
+	kfree(dev);
+
+	return 0;
+}
+
+static const struct of_device_id ibm_iic_match[] = {
+	{ .compatible = "ibm,iic", },
+	{}
+};
+
+static struct platform_driver ibm_iic_driver = {
+	.driver = {
+		.name = "ibm-iic",
+		.owner = THIS_MODULE,
+		.of_match_table = ibm_iic_match,
+	},
+	.probe	= iic_probe,
+	.remove	= __devexit_p(iic_remove),
+};
+
+module_platform_driver(ibm_iic_driver);
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-ibm_iic.h b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-ibm_iic.h
new file mode 100644
index 0000000..fdaa482
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-ibm_iic.h
@@ -0,0 +1,123 @@
+/*
+ * drivers/i2c/busses/i2c-ibm_iic.h
+ *
+ * Support for the IIC peripheral on IBM PPC 4xx
+ *
+ * Copyright (c) 2003 Zultys Technologies.
+ * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
+ *
+ * Based on original work by
+ * 	Ian DaSilva  <idasilva@mvista.com>
+ *      Armin Kuster <akuster@mvista.com>
+ * 	Matt Porter  <mporter@mvista.com>
+ *
+ *      Copyright 2000-2003 MontaVista Software Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+#ifndef __I2C_IBM_IIC_H_
+#define __I2C_IBM_IIC_H_
+
+#include <linux/i2c.h>
+
+struct iic_regs {
+	u16 mdbuf;
+	u16 sbbuf;
+	u8 lmadr;
+	u8 hmadr;
+	u8 cntl;
+	u8 mdcntl;
+	u8 sts;
+	u8 extsts;
+	u8 lsadr;
+	u8 hsadr;
+	u8 clkdiv;
+	u8 intmsk;
+	u8 xfrcnt;
+	u8 xtcntlss;
+	u8 directcntl;
+};
+
+struct ibm_iic_private {
+	struct i2c_adapter adap;
+	volatile struct iic_regs __iomem *vaddr;
+	wait_queue_head_t wq;
+	int idx;
+	int irq;
+	int fast_mode;
+	u8  clckdiv;
+};
+
+/* IICx_CNTL register */
+#define CNTL_HMT	0x80
+#define CNTL_AMD	0x40
+#define CNTL_TCT_MASK	0x30
+#define CNTL_TCT_SHIFT	4
+#define CNTL_RPST	0x08
+#define CNTL_CHT	0x04
+#define CNTL_RW		0x02
+#define CNTL_PT		0x01
+
+/* IICx_MDCNTL register */
+#define MDCNTL_FSDB	0x80
+#define MDCNTL_FMDB	0x40
+#define MDCNTL_EGC	0x20
+#define MDCNTL_FSM	0x10
+#define MDCNTL_ESM	0x08
+#define MDCNTL_EINT	0x04
+#define MDCNTL_EUBS	0x02
+#define MDCNTL_HSCL	0x01
+
+/* IICx_STS register */
+#define STS_SSS		0x80
+#define STS_SLPR	0x40
+#define STS_MDBS	0x20
+#define STS_MDBF	0x10
+#define STS_SCMP	0x08
+#define STS_ERR		0x04
+#define STS_IRQA	0x02
+#define STS_PT		0x01
+
+/* IICx_EXTSTS register */
+#define EXTSTS_IRQP	0x80
+#define EXTSTS_BCS_MASK	0x70
+#define   EXTSTS_BCS_FREE  0x40
+#define EXTSTS_IRQD	0x08
+#define EXTSTS_LA	0x04
+#define EXTSTS_ICT	0x02
+#define EXTSTS_XFRA	0x01
+
+/* IICx_INTRMSK register */
+#define INTRMSK_EIRC	0x80
+#define INTRMSK_EIRS	0x40
+#define INTRMSK_EIWC	0x20
+#define INTRMSK_EIWS	0x10
+#define INTRMSK_EIHE	0x08
+#define INTRMSK_EIIC	0x04
+#define INTRMSK_EITA	0x02
+#define INTRMSK_EIMTC	0x01
+
+/* IICx_XFRCNT register */
+#define XFRCNT_MTC_MASK	0x07
+
+/* IICx_XTCNTLSS register */
+#define XTCNTLSS_SRC	0x80
+#define XTCNTLSS_SRS	0x40
+#define XTCNTLSS_SWC	0x20
+#define XTCNTLSS_SWS	0x10
+#define XTCNTLSS_SRST	0x01
+
+/* IICx_DIRECTCNTL register */
+#define DIRCNTL_SDAC	0x08
+#define DIRCNTL_SCC	0x04
+#define DIRCNTL_MSDA	0x02
+#define DIRCNTL_MSC	0x01
+
+/* Check if we really control the I2C bus and bus is free */
+#define DIRCTNL_FREE(v)	(((v) & 0x0f) == 0x0f)
+
+#endif /* __I2C_IBM_IIC_H_ */
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-imx.c b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-imx.c
new file mode 100644
index 0000000..dfb84b7
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-imx.c
@@ -0,0 +1,642 @@
+/*
+ *	Copyright (C) 2002 Motorola GSG-China
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License
+ *	as published by the Free Software Foundation; either version 2
+ *	of the License, or (at your option) any later version.
+ *
+ *	This program is distributed in the hope that it will be useful,
+ *	but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *	GNU General Public License for more details.
+ *
+ *	You should have received a copy of the GNU General Public License
+ *	along with this program; if not, write to the Free Software
+ *	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+ *	USA.
+ *
+ * Author:
+ *	Darius Augulis, Teltonika Inc.
+ *
+ * Desc.:
+ *	Implementation of I2C Adapter/Algorithm Driver
+ *	for I2C Bus integrated in Freescale i.MX/MXC processors
+ *
+ *	Derived from Motorola GSG China I2C example driver
+ *
+ *	Copyright (C) 2005 Torsten Koschorrek <koschorrek at synertronixx.de
+ *	Copyright (C) 2005 Matthias Blaschke <blaschke at synertronixx.de
+ *	Copyright (C) 2007 RightHand Technologies, Inc.
+ *	Copyright (C) 2008 Darius Augulis <darius.augulis at teltonika.lt>
+ *
+ */
+
+/** Includes *******************************************************************
+*******************************************************************************/
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/io.h>
+#include <linux/sched.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_i2c.h>
+
+#include <mach/irqs.h>
+#include <mach/hardware.h>
+#include <mach/i2c.h>
+
+/** Defines ********************************************************************
+*******************************************************************************/
+
+/* This will be the driver name the kernel reports */
+#define DRIVER_NAME "imx-i2c"
+
+/* Default value */
+#define IMX_I2C_BIT_RATE	100000	/* 100kHz */
+
+/* IMX I2C registers */
+#define IMX_I2C_IADR	0x00	/* i2c slave address */
+#define IMX_I2C_IFDR	0x04	/* i2c frequency divider */
+#define IMX_I2C_I2CR	0x08	/* i2c control */
+#define IMX_I2C_I2SR	0x0C	/* i2c status */
+#define IMX_I2C_I2DR	0x10	/* i2c transfer data */
+
+/* Bits of IMX I2C registers */
+#define I2SR_RXAK	0x01
+#define I2SR_IIF	0x02
+#define I2SR_SRW	0x04
+#define I2SR_IAL	0x10
+#define I2SR_IBB	0x20
+#define I2SR_IAAS	0x40
+#define I2SR_ICF	0x80
+#define I2CR_RSTA	0x04
+#define I2CR_TXAK	0x08
+#define I2CR_MTX	0x10
+#define I2CR_MSTA	0x20
+#define I2CR_IIEN	0x40
+#define I2CR_IEN	0x80
+
+/** Variables ******************************************************************
+*******************************************************************************/
+
+/*
+ * sorted list of clock divider, register value pairs
+ * taken from table 26-5, p.26-9, Freescale i.MX
+ * Integrated Portable System Processor Reference Manual
+ * Document Number: MC9328MXLRM, Rev. 5.1, 06/2007
+ *
+ * Duplicated divider values removed from list
+ */
+
+static u16 __initdata i2c_clk_div[50][2] = {
+	{ 22,	0x20 }, { 24,	0x21 }, { 26,	0x22 }, { 28,	0x23 },
+	{ 30,	0x00 },	{ 32,	0x24 }, { 36,	0x25 }, { 40,	0x26 },
+	{ 42,	0x03 }, { 44,	0x27 },	{ 48,	0x28 }, { 52,	0x05 },
+	{ 56,	0x29 }, { 60,	0x06 }, { 64,	0x2A },	{ 72,	0x2B },
+	{ 80,	0x2C }, { 88,	0x09 }, { 96,	0x2D }, { 104,	0x0A },
+	{ 112,	0x2E }, { 128,	0x2F }, { 144,	0x0C }, { 160,	0x30 },
+	{ 192,	0x31 },	{ 224,	0x32 }, { 240,	0x0F }, { 256,	0x33 },
+	{ 288,	0x10 }, { 320,	0x34 },	{ 384,	0x35 }, { 448,	0x36 },
+	{ 480,	0x13 }, { 512,	0x37 }, { 576,	0x14 },	{ 640,	0x38 },
+	{ 768,	0x39 }, { 896,	0x3A }, { 960,	0x17 }, { 1024,	0x3B },
+	{ 1152,	0x18 }, { 1280,	0x3C }, { 1536,	0x3D }, { 1792,	0x3E },
+	{ 1920,	0x1B },	{ 2048,	0x3F }, { 2304,	0x1C }, { 2560,	0x1D },
+	{ 3072,	0x1E }, { 3840,	0x1F }
+};
+
+struct imx_i2c_struct {
+	struct i2c_adapter	adapter;
+	struct resource		*res;
+	struct clk		*clk;
+	void __iomem		*base;
+	int			irq;
+	wait_queue_head_t	queue;
+	unsigned long		i2csr;
+	unsigned int 		disable_delay;
+	int			stopped;
+	unsigned int		ifdr; /* IMX_I2C_IFDR */
+};
+
+static const struct of_device_id i2c_imx_dt_ids[] = {
+	{ .compatible = "fsl,imx1-i2c", },
+	{ /* sentinel */ }
+};
+
+/** Functions for IMX I2C adapter driver ***************************************
+*******************************************************************************/
+
+static int i2c_imx_bus_busy(struct imx_i2c_struct *i2c_imx, int for_busy)
+{
+	unsigned long orig_jiffies = jiffies;
+	unsigned int temp;
+
+	dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__);
+
+	while (1) {
+		temp = readb(i2c_imx->base + IMX_I2C_I2SR);
+		if (for_busy && (temp & I2SR_IBB))
+			break;
+		if (!for_busy && !(temp & I2SR_IBB))
+			break;
+		if (time_after(jiffies, orig_jiffies + msecs_to_jiffies(500))) {
+			dev_dbg(&i2c_imx->adapter.dev,
+				"<%s> I2C bus is busy\n", __func__);
+			return -ETIMEDOUT;
+		}
+		schedule();
+	}
+
+	return 0;
+}
+
+static int i2c_imx_trx_complete(struct imx_i2c_struct *i2c_imx)
+{
+	wait_event_timeout(i2c_imx->queue, i2c_imx->i2csr & I2SR_IIF, HZ / 10);
+
+	if (unlikely(!(i2c_imx->i2csr & I2SR_IIF))) {
+		dev_dbg(&i2c_imx->adapter.dev, "<%s> Timeout\n", __func__);
+		return -ETIMEDOUT;
+	}
+	dev_dbg(&i2c_imx->adapter.dev, "<%s> TRX complete\n", __func__);
+	i2c_imx->i2csr = 0;
+	return 0;
+}
+
+static int i2c_imx_acked(struct imx_i2c_struct *i2c_imx)
+{
+	if (readb(i2c_imx->base + IMX_I2C_I2SR) & I2SR_RXAK) {
+		dev_dbg(&i2c_imx->adapter.dev, "<%s> No ACK\n", __func__);
+		return -EIO;  /* No ACK */
+	}
+
+	dev_dbg(&i2c_imx->adapter.dev, "<%s> ACK received\n", __func__);
+	return 0;
+}
+
+static int i2c_imx_start(struct imx_i2c_struct *i2c_imx)
+{
+	unsigned int temp = 0;
+	int result;
+
+	dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__);
+
+	clk_prepare_enable(i2c_imx->clk);
+	writeb(i2c_imx->ifdr, i2c_imx->base + IMX_I2C_IFDR);
+	/* Enable I2C controller */
+	writeb(0, i2c_imx->base + IMX_I2C_I2SR);
+	writeb(I2CR_IEN, i2c_imx->base + IMX_I2C_I2CR);
+
+	/* Wait controller to be stable */
+	udelay(50);
+
+	/* Start I2C transaction */
+	temp = readb(i2c_imx->base + IMX_I2C_I2CR);
+	temp |= I2CR_MSTA;
+	writeb(temp, i2c_imx->base + IMX_I2C_I2CR);
+	result = i2c_imx_bus_busy(i2c_imx, 1);
+	if (result)
+		return result;
+	i2c_imx->stopped = 0;
+
+	temp |= I2CR_IIEN | I2CR_MTX | I2CR_TXAK;
+	writeb(temp, i2c_imx->base + IMX_I2C_I2CR);
+	return result;
+}
+
+static void i2c_imx_stop(struct imx_i2c_struct *i2c_imx)
+{
+	unsigned int temp = 0;
+
+	if (!i2c_imx->stopped) {
+		/* Stop I2C transaction */
+		dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__);
+		temp = readb(i2c_imx->base + IMX_I2C_I2CR);
+		temp &= ~(I2CR_MSTA | I2CR_MTX);
+		writeb(temp, i2c_imx->base + IMX_I2C_I2CR);
+	}
+	if (cpu_is_mx1()) {
+		/*
+		 * This delay caused by an i.MXL hardware bug.
+		 * If no (or too short) delay, no "STOP" bit will be generated.
+		 */
+		udelay(i2c_imx->disable_delay);
+	}
+
+	if (!i2c_imx->stopped) {
+		i2c_imx_bus_busy(i2c_imx, 0);
+		i2c_imx->stopped = 1;
+	}
+
+	/* Disable I2C controller */
+	writeb(0, i2c_imx->base + IMX_I2C_I2CR);
+	clk_disable_unprepare(i2c_imx->clk);
+}
+
+static void __init i2c_imx_set_clk(struct imx_i2c_struct *i2c_imx,
+							unsigned int rate)
+{
+	unsigned int i2c_clk_rate;
+	unsigned int div;
+	int i;
+
+	/* Divider value calculation */
+	i2c_clk_rate = clk_get_rate(i2c_imx->clk);
+	div = (i2c_clk_rate + rate - 1) / rate;
+	if (div < i2c_clk_div[0][0])
+		i = 0;
+	else if (div > i2c_clk_div[ARRAY_SIZE(i2c_clk_div) - 1][0])
+		i = ARRAY_SIZE(i2c_clk_div) - 1;
+	else
+		for (i = 0; i2c_clk_div[i][0] < div; i++);
+
+	/* Store divider value */
+	i2c_imx->ifdr = i2c_clk_div[i][1];
+
+	/*
+	 * There dummy delay is calculated.
+	 * It should be about one I2C clock period long.
+	 * This delay is used in I2C bus disable function
+	 * to fix chip hardware bug.
+	 */
+	i2c_imx->disable_delay = (500000U * i2c_clk_div[i][0]
+		+ (i2c_clk_rate / 2) - 1) / (i2c_clk_rate / 2);
+
+	/* dev_dbg() can't be used, because adapter is not yet registered */
+#ifdef CONFIG_I2C_DEBUG_BUS
+	printk(KERN_DEBUG "I2C: <%s> I2C_CLK=%d, REQ DIV=%d\n",
+		__func__, i2c_clk_rate, div);
+	printk(KERN_DEBUG "I2C: <%s> IFDR[IC]=0x%x, REAL DIV=%d\n",
+		__func__, i2c_clk_div[i][1], i2c_clk_div[i][0]);
+#endif
+}
+
+static irqreturn_t i2c_imx_isr(int irq, void *dev_id)
+{
+	struct imx_i2c_struct *i2c_imx = dev_id;
+	unsigned int temp;
+
+	temp = readb(i2c_imx->base + IMX_I2C_I2SR);
+	if (temp & I2SR_IIF) {
+		/* save status register */
+		i2c_imx->i2csr = temp;
+		temp &= ~I2SR_IIF;
+		writeb(temp, i2c_imx->base + IMX_I2C_I2SR);
+		wake_up(&i2c_imx->queue);
+		return IRQ_HANDLED;
+	}
+
+	return IRQ_NONE;
+}
+
+static int i2c_imx_write(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs)
+{
+	int i, result;
+
+	dev_dbg(&i2c_imx->adapter.dev, "<%s> write slave address: addr=0x%x\n",
+		__func__, msgs->addr << 1);
+
+	/* write slave address */
+	writeb(msgs->addr << 1, i2c_imx->base + IMX_I2C_I2DR);
+	result = i2c_imx_trx_complete(i2c_imx);
+	if (result)
+		return result;
+	result = i2c_imx_acked(i2c_imx);
+	if (result)
+		return result;
+	dev_dbg(&i2c_imx->adapter.dev, "<%s> write data\n", __func__);
+
+	/* write data */
+	for (i = 0; i < msgs->len; i++) {
+		dev_dbg(&i2c_imx->adapter.dev,
+			"<%s> write byte: B%d=0x%X\n",
+			__func__, i, msgs->buf[i]);
+		writeb(msgs->buf[i], i2c_imx->base + IMX_I2C_I2DR);
+		result = i2c_imx_trx_complete(i2c_imx);
+		if (result)
+			return result;
+		result = i2c_imx_acked(i2c_imx);
+		if (result)
+			return result;
+	}
+	return 0;
+}
+
+static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs)
+{
+	int i, result;
+	unsigned int temp;
+
+	dev_dbg(&i2c_imx->adapter.dev,
+		"<%s> write slave address: addr=0x%x\n",
+		__func__, (msgs->addr << 1) | 0x01);
+
+	/* write slave address */
+	writeb((msgs->addr << 1) | 0x01, i2c_imx->base + IMX_I2C_I2DR);
+	result = i2c_imx_trx_complete(i2c_imx);
+	if (result)
+		return result;
+	result = i2c_imx_acked(i2c_imx);
+	if (result)
+		return result;
+
+	dev_dbg(&i2c_imx->adapter.dev, "<%s> setup bus\n", __func__);
+
+	/* setup bus to read data */
+	temp = readb(i2c_imx->base + IMX_I2C_I2CR);
+	temp &= ~I2CR_MTX;
+	if (msgs->len - 1)
+		temp &= ~I2CR_TXAK;
+	writeb(temp, i2c_imx->base + IMX_I2C_I2CR);
+	readb(i2c_imx->base + IMX_I2C_I2DR); /* dummy read */
+
+	dev_dbg(&i2c_imx->adapter.dev, "<%s> read data\n", __func__);
+
+	/* read data */
+	for (i = 0; i < msgs->len; i++) {
+		result = i2c_imx_trx_complete(i2c_imx);
+		if (result)
+			return result;
+		if (i == (msgs->len - 1)) {
+			/* It must generate STOP before read I2DR to prevent
+			   controller from generating another clock cycle */
+			dev_dbg(&i2c_imx->adapter.dev,
+				"<%s> clear MSTA\n", __func__);
+			temp = readb(i2c_imx->base + IMX_I2C_I2CR);
+			temp &= ~(I2CR_MSTA | I2CR_MTX);
+			writeb(temp, i2c_imx->base + IMX_I2C_I2CR);
+			i2c_imx_bus_busy(i2c_imx, 0);
+			i2c_imx->stopped = 1;
+		} else if (i == (msgs->len - 2)) {
+			dev_dbg(&i2c_imx->adapter.dev,
+				"<%s> set TXAK\n", __func__);
+			temp = readb(i2c_imx->base + IMX_I2C_I2CR);
+			temp |= I2CR_TXAK;
+			writeb(temp, i2c_imx->base + IMX_I2C_I2CR);
+		}
+		msgs->buf[i] = readb(i2c_imx->base + IMX_I2C_I2DR);
+		dev_dbg(&i2c_imx->adapter.dev,
+			"<%s> read byte: B%d=0x%X\n",
+			__func__, i, msgs->buf[i]);
+	}
+	return 0;
+}
+
+static int i2c_imx_xfer(struct i2c_adapter *adapter,
+						struct i2c_msg *msgs, int num)
+{
+	unsigned int i, temp;
+	int result;
+	struct imx_i2c_struct *i2c_imx = i2c_get_adapdata(adapter);
+
+	dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__);
+
+	/* Start I2C transfer */
+	result = i2c_imx_start(i2c_imx);
+	if (result)
+		goto fail0;
+
+	/* read/write data */
+	for (i = 0; i < num; i++) {
+		if (i) {
+			dev_dbg(&i2c_imx->adapter.dev,
+				"<%s> repeated start\n", __func__);
+			temp = readb(i2c_imx->base + IMX_I2C_I2CR);
+			temp |= I2CR_RSTA;
+			writeb(temp, i2c_imx->base + IMX_I2C_I2CR);
+			result =  i2c_imx_bus_busy(i2c_imx, 1);
+			if (result)
+				goto fail0;
+		}
+		dev_dbg(&i2c_imx->adapter.dev,
+			"<%s> transfer message: %d\n", __func__, i);
+		/* write/read data */
+#ifdef CONFIG_I2C_DEBUG_BUS
+		temp = readb(i2c_imx->base + IMX_I2C_I2CR);
+		dev_dbg(&i2c_imx->adapter.dev, "<%s> CONTROL: IEN=%d, IIEN=%d, "
+			"MSTA=%d, MTX=%d, TXAK=%d, RSTA=%d\n", __func__,
+			(temp & I2CR_IEN ? 1 : 0), (temp & I2CR_IIEN ? 1 : 0),
+			(temp & I2CR_MSTA ? 1 : 0), (temp & I2CR_MTX ? 1 : 0),
+			(temp & I2CR_TXAK ? 1 : 0), (temp & I2CR_RSTA ? 1 : 0));
+		temp = readb(i2c_imx->base + IMX_I2C_I2SR);
+		dev_dbg(&i2c_imx->adapter.dev,
+			"<%s> STATUS: ICF=%d, IAAS=%d, IBB=%d, "
+			"IAL=%d, SRW=%d, IIF=%d, RXAK=%d\n", __func__,
+			(temp & I2SR_ICF ? 1 : 0), (temp & I2SR_IAAS ? 1 : 0),
+			(temp & I2SR_IBB ? 1 : 0), (temp & I2SR_IAL ? 1 : 0),
+			(temp & I2SR_SRW ? 1 : 0), (temp & I2SR_IIF ? 1 : 0),
+			(temp & I2SR_RXAK ? 1 : 0));
+#endif
+		if (msgs[i].flags & I2C_M_RD)
+			result = i2c_imx_read(i2c_imx, &msgs[i]);
+		else
+			result = i2c_imx_write(i2c_imx, &msgs[i]);
+		if (result)
+			goto fail0;
+	}
+
+fail0:
+	/* Stop I2C transfer */
+	i2c_imx_stop(i2c_imx);
+
+	dev_dbg(&i2c_imx->adapter.dev, "<%s> exit with: %s: %d\n", __func__,
+		(result < 0) ? "error" : "success msg",
+			(result < 0) ? result : num);
+	return (result < 0) ? result : num;
+}
+
+static u32 i2c_imx_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static struct i2c_algorithm i2c_imx_algo = {
+	.master_xfer	= i2c_imx_xfer,
+	.functionality	= i2c_imx_func,
+};
+
+static int __init i2c_imx_probe(struct platform_device *pdev)
+{
+	struct imx_i2c_struct *i2c_imx;
+	struct resource *res;
+	struct imxi2c_platform_data *pdata = pdev->dev.platform_data;
+	void __iomem *base;
+	resource_size_t res_size;
+	int irq, bitrate;
+	int ret;
+
+	dev_dbg(&pdev->dev, "<%s>\n", __func__);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "can't get device resources\n");
+		return -ENOENT;
+	}
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		dev_err(&pdev->dev, "can't get irq number\n");
+		return -ENOENT;
+	}
+
+	res_size = resource_size(res);
+
+	if (!request_mem_region(res->start, res_size, DRIVER_NAME)) {
+		dev_err(&pdev->dev, "request_mem_region failed\n");
+		return -EBUSY;
+	}
+
+	base = ioremap(res->start, res_size);
+	if (!base) {
+		dev_err(&pdev->dev, "ioremap failed\n");
+		ret = -EIO;
+		goto fail1;
+	}
+
+	i2c_imx = kzalloc(sizeof(struct imx_i2c_struct), GFP_KERNEL);
+	if (!i2c_imx) {
+		dev_err(&pdev->dev, "can't allocate interface\n");
+		ret = -ENOMEM;
+		goto fail2;
+	}
+
+	/* Setup i2c_imx driver structure */
+	strcpy(i2c_imx->adapter.name, pdev->name);
+	i2c_imx->adapter.owner		= THIS_MODULE;
+	i2c_imx->adapter.algo		= &i2c_imx_algo;
+	i2c_imx->adapter.dev.parent	= &pdev->dev;
+	i2c_imx->adapter.nr 		= pdev->id;
+	i2c_imx->adapter.dev.of_node	= pdev->dev.of_node;
+	i2c_imx->irq			= irq;
+	i2c_imx->base			= base;
+	i2c_imx->res			= res;
+
+	/* Get I2C clock */
+	i2c_imx->clk = clk_get(&pdev->dev, "i2c_clk");
+	if (IS_ERR(i2c_imx->clk)) {
+		ret = PTR_ERR(i2c_imx->clk);
+		dev_err(&pdev->dev, "can't get I2C clock\n");
+		goto fail3;
+	}
+
+	/* Request IRQ */
+	ret = request_irq(i2c_imx->irq, i2c_imx_isr, 0, pdev->name, i2c_imx);
+	if (ret) {
+		dev_err(&pdev->dev, "can't claim irq %d\n", i2c_imx->irq);
+		goto fail4;
+	}
+
+	/* Init queue */
+	init_waitqueue_head(&i2c_imx->queue);
+
+	/* Set up adapter data */
+	i2c_set_adapdata(&i2c_imx->adapter, i2c_imx);
+
+	/* Set up clock divider */
+	bitrate = IMX_I2C_BIT_RATE;
+	ret = of_property_read_u32(pdev->dev.of_node,
+				   "clock-frequency", &bitrate);
+	if (ret < 0 && pdata && pdata->bitrate)
+		bitrate = pdata->bitrate;
+	i2c_imx_set_clk(i2c_imx, bitrate);
+
+	/* Set up chip registers to defaults */
+	writeb(0, i2c_imx->base + IMX_I2C_I2CR);
+	writeb(0, i2c_imx->base + IMX_I2C_I2SR);
+
+	/* Add I2C adapter */
+	ret = i2c_add_numbered_adapter(&i2c_imx->adapter);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "registration failed\n");
+		goto fail5;
+	}
+
+	of_i2c_register_devices(&i2c_imx->adapter);
+
+	/* Set up platform driver data */
+	platform_set_drvdata(pdev, i2c_imx);
+
+	dev_dbg(&i2c_imx->adapter.dev, "claimed irq %d\n", i2c_imx->irq);
+	dev_dbg(&i2c_imx->adapter.dev, "device resources from 0x%x to 0x%x\n",
+		i2c_imx->res->start, i2c_imx->res->end);
+	dev_dbg(&i2c_imx->adapter.dev, "allocated %d bytes at 0x%x \n",
+		res_size, i2c_imx->res->start);
+	dev_dbg(&i2c_imx->adapter.dev, "adapter name: \"%s\"\n",
+		i2c_imx->adapter.name);
+	dev_dbg(&i2c_imx->adapter.dev, "IMX I2C adapter registered\n");
+
+	return 0;   /* Return OK */
+
+fail5:
+	free_irq(i2c_imx->irq, i2c_imx);
+fail4:
+	clk_put(i2c_imx->clk);
+fail3:
+	kfree(i2c_imx);
+fail2:
+	iounmap(base);
+fail1:
+	release_mem_region(res->start, resource_size(res));
+	return ret; /* Return error number */
+}
+
+static int __exit i2c_imx_remove(struct platform_device *pdev)
+{
+	struct imx_i2c_struct *i2c_imx = platform_get_drvdata(pdev);
+
+	/* remove adapter */
+	dev_dbg(&i2c_imx->adapter.dev, "adapter removed\n");
+	i2c_del_adapter(&i2c_imx->adapter);
+	platform_set_drvdata(pdev, NULL);
+
+	/* free interrupt */
+	free_irq(i2c_imx->irq, i2c_imx);
+
+	/* setup chip registers to defaults */
+	writeb(0, i2c_imx->base + IMX_I2C_IADR);
+	writeb(0, i2c_imx->base + IMX_I2C_IFDR);
+	writeb(0, i2c_imx->base + IMX_I2C_I2CR);
+	writeb(0, i2c_imx->base + IMX_I2C_I2SR);
+
+	clk_put(i2c_imx->clk);
+
+	iounmap(i2c_imx->base);
+	release_mem_region(i2c_imx->res->start, resource_size(i2c_imx->res));
+	kfree(i2c_imx);
+	return 0;
+}
+
+static struct platform_driver i2c_imx_driver = {
+	.remove		= __exit_p(i2c_imx_remove),
+	.driver	= {
+		.name	= DRIVER_NAME,
+		.owner	= THIS_MODULE,
+		.of_match_table = i2c_imx_dt_ids,
+	}
+};
+
+static int __init i2c_adap_imx_init(void)
+{
+	return platform_driver_probe(&i2c_imx_driver, i2c_imx_probe);
+}
+subsys_initcall(i2c_adap_imx_init);
+
+static void __exit i2c_adap_imx_exit(void)
+{
+	platform_driver_unregister(&i2c_imx_driver);
+}
+module_exit(i2c_adap_imx_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Darius Augulis");
+MODULE_DESCRIPTION("I2C adapter driver for IMX I2C bus");
+MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-intel-mid.c b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-intel-mid.c
new file mode 100644
index 0000000..365bad5
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-intel-mid.c
@@ -0,0 +1,1135 @@
+/*
+ * Support for Moorestown/Medfield I2C chip
+ *
+ * Copyright (c) 2009 Intel Corporation.
+ * Copyright (c) 2009 Synopsys. Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License, version
+ * 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/stat.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/pm_runtime.h>
+#include <linux/io.h>
+
+#define DRIVER_NAME	"i2c-intel-mid"
+#define VERSION		"Version 0.5ac2"
+#define PLATFORM	"Moorestown/Medfield"
+
+/* Tables use: 0 Moorestown, 1 Medfield */
+#define NUM_PLATFORMS	2
+enum platform_enum {
+	MOORESTOWN = 0,
+	MEDFIELD = 1,
+};
+
+enum mid_i2c_status {
+	STATUS_IDLE = 0,
+	STATUS_READ_START,
+	STATUS_READ_IN_PROGRESS,
+	STATUS_READ_SUCCESS,
+	STATUS_WRITE_START,
+	STATUS_WRITE_SUCCESS,
+	STATUS_XFER_ABORT,
+	STATUS_STANDBY
+};
+
+/**
+ * struct intel_mid_i2c_private	- per device I²C context
+ * @adap: core i2c layer adapter information
+ * @dev: device reference for power management
+ * @base: register base
+ * @speed: speed mode for this port
+ * @complete: completion object for transaction wait
+ * @abort: reason for last abort
+ * @rx_buf: pointer into working receive buffer
+ * @rx_buf_len: receive buffer length
+ * @status: adapter state machine
+ * @msg: the message we are currently processing
+ * @platform: the MID device type we are part of
+ * @lock: transaction serialization
+ *
+ * We allocate one of these per device we discover, it holds the core
+ * i2c layer objects and the data we need to track privately.
+ */
+struct intel_mid_i2c_private {
+	struct i2c_adapter adap;
+	struct device *dev;
+	void __iomem *base;
+	int speed;
+	struct completion complete;
+	int abort;
+	u8 *rx_buf;
+	int rx_buf_len;
+	enum mid_i2c_status status;
+	struct i2c_msg *msg;
+	enum platform_enum platform;
+	struct mutex lock;
+};
+
+#define NUM_SPEEDS		3
+
+#define ACTIVE			0
+#define STANDBY			1
+
+
+/* Control register */
+#define IC_CON			0x00
+#define SLV_DIS			(1 << 6)	/* Disable slave mode */
+#define RESTART			(1 << 5)	/* Send a Restart condition */
+#define	ADDR_10BIT		(1 << 4)	/* 10-bit addressing */
+#define	STANDARD_MODE		(1 << 1)	/* standard mode */
+#define FAST_MODE		(2 << 1)	/* fast mode */
+#define HIGH_MODE		(3 << 1)	/* high speed mode */
+#define	MASTER_EN		(1 << 0)	/* Master mode */
+
+/* Target address register */
+#define IC_TAR			0x04
+#define IC_TAR_10BIT_ADDR	(1 << 12)	/* 10-bit addressing */
+#define IC_TAR_SPECIAL		(1 << 11)	/* Perform special I2C cmd */
+#define IC_TAR_GC_OR_START	(1 << 10)	/* 0: Gerneral Call Address */
+						/* 1: START BYTE */
+/* Slave Address Register */
+#define IC_SAR			0x08		/* Not used in Master mode */
+
+/* High Speed Master Mode Code Address Register */
+#define IC_HS_MADDR		0x0c
+
+/* Rx/Tx Data Buffer and Command Register */
+#define IC_DATA_CMD		0x10
+#define IC_RD			(1 << 8)	/* 1: Read 0: Write */
+
+/* Standard Speed Clock SCL High Count Register */
+#define IC_SS_SCL_HCNT		0x14
+
+/* Standard Speed Clock SCL Low Count Register */
+#define IC_SS_SCL_LCNT		0x18
+
+/* Fast Speed Clock SCL High Count Register */
+#define IC_FS_SCL_HCNT		0x1c
+
+/* Fast Spedd Clock SCL Low Count Register */
+#define IC_FS_SCL_LCNT		0x20
+
+/* High Speed Clock SCL High Count Register */
+#define IC_HS_SCL_HCNT		0x24
+
+/* High Speed Clock SCL Low Count Register */
+#define IC_HS_SCL_LCNT		0x28
+
+/* Interrupt Status Register */
+#define IC_INTR_STAT		0x2c		/* Read only */
+#define R_GEN_CALL		(1 << 11)
+#define R_START_DET		(1 << 10)
+#define R_STOP_DET		(1 << 9)
+#define R_ACTIVITY		(1 << 8)
+#define R_RX_DONE		(1 << 7)
+#define	R_TX_ABRT		(1 << 6)
+#define R_RD_REQ		(1 << 5)
+#define R_TX_EMPTY		(1 << 4)
+#define R_TX_OVER		(1 << 3)
+#define	R_RX_FULL		(1 << 2)
+#define	R_RX_OVER		(1 << 1)
+#define R_RX_UNDER		(1 << 0)
+
+/* Interrupt Mask Register */
+#define IC_INTR_MASK		0x30		/* Read and Write */
+#define M_GEN_CALL		(1 << 11)
+#define M_START_DET		(1 << 10)
+#define M_STOP_DET		(1 << 9)
+#define M_ACTIVITY		(1 << 8)
+#define M_RX_DONE		(1 << 7)
+#define	M_TX_ABRT		(1 << 6)
+#define M_RD_REQ		(1 << 5)
+#define M_TX_EMPTY		(1 << 4)
+#define M_TX_OVER		(1 << 3)
+#define	M_RX_FULL		(1 << 2)
+#define	M_RX_OVER		(1 << 1)
+#define M_RX_UNDER		(1 << 0)
+
+/* Raw Interrupt Status Register */
+#define IC_RAW_INTR_STAT	0x34		/* Read Only */
+#define GEN_CALL		(1 << 11)	/* General call */
+#define START_DET		(1 << 10)	/* (RE)START occurred */
+#define STOP_DET		(1 << 9)	/* STOP occurred */
+#define ACTIVITY		(1 << 8)	/* Bus busy */
+#define RX_DONE			(1 << 7)	/* Not used in Master mode */
+#define	TX_ABRT			(1 << 6)	/* Transmit Abort */
+#define RD_REQ			(1 << 5)	/* Not used in Master mode */
+#define TX_EMPTY		(1 << 4)	/* TX FIFO <= threshold */
+#define TX_OVER			(1 << 3)	/* TX FIFO overflow */
+#define	RX_FULL			(1 << 2)	/* RX FIFO >= threshold */
+#define	RX_OVER			(1 << 1)	/* RX FIFO overflow */
+#define RX_UNDER		(1 << 0)	/* RX FIFO empty */
+
+/* Receive FIFO Threshold Register */
+#define IC_RX_TL		0x38
+
+/* Transmit FIFO Treshold Register */
+#define IC_TX_TL		0x3c
+
+/* Clear Combined and Individual Interrupt Register */
+#define IC_CLR_INTR		0x40
+#define CLR_INTR		(1 << 0)
+
+/* Clear RX_UNDER Interrupt Register */
+#define IC_CLR_RX_UNDER		0x44
+#define CLR_RX_UNDER		(1 << 0)
+
+/* Clear RX_OVER Interrupt Register */
+#define IC_CLR_RX_OVER		0x48
+#define CLR_RX_OVER		(1 << 0)
+
+/* Clear TX_OVER Interrupt Register */
+#define IC_CLR_TX_OVER		0x4c
+#define CLR_TX_OVER		(1 << 0)
+
+#define IC_CLR_RD_REQ		0x50
+
+/* Clear TX_ABRT Interrupt Register */
+#define IC_CLR_TX_ABRT		0x54
+#define CLR_TX_ABRT		(1 << 0)
+#define IC_CLR_RX_DONE		0x58
+
+/* Clear ACTIVITY Interrupt Register */
+#define IC_CLR_ACTIVITY		0x5c
+#define CLR_ACTIVITY		(1 << 0)
+
+/* Clear STOP_DET Interrupt Register */
+#define IC_CLR_STOP_DET		0x60
+#define CLR_STOP_DET		(1 << 0)
+
+/* Clear START_DET Interrupt Register */
+#define IC_CLR_START_DET	0x64
+#define CLR_START_DET		(1 << 0)
+
+/* Clear GEN_CALL Interrupt Register */
+#define IC_CLR_GEN_CALL		0x68
+#define CLR_GEN_CALL		(1 << 0)
+
+/* Enable Register */
+#define IC_ENABLE		0x6c
+#define ENABLE			(1 << 0)
+
+/* Status Register */
+#define IC_STATUS		0x70		/* Read Only */
+#define STAT_SLV_ACTIVITY	(1 << 6)	/* Slave not in idle */
+#define STAT_MST_ACTIVITY	(1 << 5)	/* Master not in idle */
+#define STAT_RFF		(1 << 4)	/* RX FIFO Full */
+#define STAT_RFNE		(1 << 3)	/* RX FIFO Not Empty */
+#define STAT_TFE		(1 << 2)	/* TX FIFO Empty */
+#define STAT_TFNF		(1 << 1)	/* TX FIFO Not Full */
+#define STAT_ACTIVITY		(1 << 0)	/* Activity Status */
+
+/* Transmit FIFO Level Register */
+#define IC_TXFLR		0x74		/* Read Only */
+#define TXFLR			(1 << 0)	/* TX FIFO level */
+
+/* Receive FIFO Level Register */
+#define IC_RXFLR		0x78		/* Read Only */
+#define RXFLR			(1 << 0)	/* RX FIFO level */
+
+/* Transmit Abort Source Register */
+#define IC_TX_ABRT_SOURCE	0x80
+#define ABRT_SLVRD_INTX		(1 << 15)
+#define ABRT_SLV_ARBLOST	(1 << 14)
+#define ABRT_SLVFLUSH_TXFIFO	(1 << 13)
+#define	ARB_LOST		(1 << 12)
+#define ABRT_MASTER_DIS		(1 << 11)
+#define ABRT_10B_RD_NORSTRT	(1 << 10)
+#define ABRT_SBYTE_NORSTRT	(1 << 9)
+#define ABRT_HS_NORSTRT		(1 << 8)
+#define ABRT_SBYTE_ACKDET	(1 << 7)
+#define ABRT_HS_ACKDET		(1 << 6)
+#define ABRT_GCALL_READ		(1 << 5)
+#define ABRT_GCALL_NOACK	(1 << 4)
+#define ABRT_TXDATA_NOACK	(1 << 3)
+#define ABRT_10ADDR2_NOACK	(1 << 2)
+#define ABRT_10ADDR1_NOACK	(1 << 1)
+#define ABRT_7B_ADDR_NOACK	(1 << 0)
+
+/* Enable Status Register */
+#define IC_ENABLE_STATUS	0x9c
+#define IC_EN			(1 << 0)	/* I2C in an enabled state */
+
+/* Component Parameter Register 1*/
+#define IC_COMP_PARAM_1		0xf4
+#define APB_DATA_WIDTH		(0x3 << 0)
+
+/* added by xiaolin --begin */
+#define SS_MIN_SCL_HIGH         4000
+#define SS_MIN_SCL_LOW          4700
+#define FS_MIN_SCL_HIGH         600
+#define FS_MIN_SCL_LOW          1300
+#define HS_MIN_SCL_HIGH_100PF   60
+#define HS_MIN_SCL_LOW_100PF    120
+
+#define STANDARD		0
+#define FAST			1
+#define HIGH			2
+
+#define NUM_SPEEDS		3
+
+static int speed_mode[6] = {
+	FAST,
+	FAST,
+	FAST,
+	STANDARD,
+	FAST,
+	FAST
+};
+
+static int ctl_num = 6;
+module_param_array(speed_mode, int, &ctl_num, S_IRUGO);
+MODULE_PARM_DESC(speed_mode, "Set the speed of the i2c interface (0-2)");
+
+/**
+ * intel_mid_i2c_disable - Disable I2C controller
+ * @adap: struct pointer to i2c_adapter
+ *
+ * Return Value:
+ * 0		success
+ * -EBUSY	if device is busy
+ * -ETIMEDOUT	if i2c cannot be disabled within the given time
+ *
+ * I2C bus state should be checked prior to disabling the hardware. If bus is
+ * not in idle state, an errno is returned. Write "0" to IC_ENABLE to disable
+ * I2C controller.
+ */
+static int intel_mid_i2c_disable(struct i2c_adapter *adap)
+{
+	struct intel_mid_i2c_private *i2c = i2c_get_adapdata(adap);
+	int err = 0;
+	int count = 0;
+	int ret1, ret2;
+	static const u16 delay[NUM_SPEEDS] = {100, 25, 3};
+
+	/* Set IC_ENABLE to 0 */
+	writel(0, i2c->base + IC_ENABLE);
+
+	/* Check if device is busy */
+	dev_dbg(&adap->dev, "mrst i2c disable\n");
+	while ((ret1 = readl(i2c->base + IC_ENABLE_STATUS) & 0x1)
+		|| (ret2 = readl(i2c->base + IC_STATUS) & 0x1)) {
+		udelay(delay[i2c->speed]);
+		writel(0, i2c->base + IC_ENABLE);
+		dev_dbg(&adap->dev, "i2c is busy, count is %d speed %d\n",
+			count, i2c->speed);
+		if (count++ > 10) {
+			err = -ETIMEDOUT;
+			break;
+		}
+	}
+
+	/* Clear all interrupts */
+	readl(i2c->base + IC_CLR_INTR);
+	readl(i2c->base + IC_CLR_STOP_DET);
+	readl(i2c->base + IC_CLR_START_DET);
+	readl(i2c->base + IC_CLR_ACTIVITY);
+	readl(i2c->base + IC_CLR_TX_ABRT);
+	readl(i2c->base + IC_CLR_RX_OVER);
+	readl(i2c->base + IC_CLR_RX_UNDER);
+	readl(i2c->base + IC_CLR_TX_OVER);
+	readl(i2c->base + IC_CLR_RX_DONE);
+	readl(i2c->base + IC_CLR_GEN_CALL);
+
+	/* Disable all interupts */
+	writel(0x0000, i2c->base + IC_INTR_MASK);
+
+	return err;
+}
+
+/**
+ * intel_mid_i2c_hwinit - Initialize the I2C hardware registers
+ * @dev: pci device struct pointer
+ *
+ * This function will be called in intel_mid_i2c_probe() before device
+ * registration.
+ *
+ * Return Values:
+ * 0		success
+ * -EBUSY	i2c cannot be disabled
+ * -ETIMEDOUT	i2c cannot be disabled
+ * -EFAULT	If APB data width is not 32-bit wide
+ *
+ * I2C should be disabled prior to other register operation. If failed, an
+ * errno is returned. Mask and Clear all interrpts, this should be done at
+ * first.  Set common registers which will not be modified during normal
+ * transfers, including: control register, FIFO threshold and clock freq.
+ * Check APB data width at last.
+ */
+static int intel_mid_i2c_hwinit(struct intel_mid_i2c_private *i2c)
+{
+	int err;
+
+	static const u16 hcnt[NUM_PLATFORMS][NUM_SPEEDS] = {
+		{ 0x75,  0x15, 0x07 },
+		{ 0x04c,  0x10, 0x06 }
+	};
+	static const u16 lcnt[NUM_PLATFORMS][NUM_SPEEDS] = {
+		{ 0x7C,  0x21, 0x0E },
+		{ 0x053, 0x19, 0x0F }
+	};
+
+	/* Disable i2c first */
+	err = intel_mid_i2c_disable(&i2c->adap);
+	if (err)
+		return err;
+
+	/*
+	 * Setup clock frequency and speed mode
+	 * Enable restart condition,
+	 * enable master FSM, disable slave FSM,
+	 * use target address when initiating transfer
+	 */
+
+	writel((i2c->speed + 1) << 1 | SLV_DIS | RESTART | MASTER_EN,
+		i2c->base + IC_CON);
+	writel(hcnt[i2c->platform][i2c->speed],
+		i2c->base + (IC_SS_SCL_HCNT + (i2c->speed << 3)));
+	writel(lcnt[i2c->platform][i2c->speed],
+		i2c->base + (IC_SS_SCL_LCNT + (i2c->speed << 3)));
+
+	/* Set tranmit & receive FIFO threshold to zero */
+	writel(0x0, i2c->base + IC_RX_TL);
+	writel(0x0, i2c->base + IC_TX_TL);
+
+	return 0;
+}
+
+/**
+ * intel_mid_i2c_func - Return the supported three I2C operations.
+ * @adapter: i2c_adapter struct pointer
+ */
+static u32 intel_mid_i2c_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR | I2C_FUNC_SMBUS_EMUL;
+}
+
+/**
+ * intel_mid_i2c_address_neq - To check if the addresses for different i2c messages
+ * are equal.
+ * @p1: first i2c_msg
+ * @p2: second i2c_msg
+ *
+ * Return Values:
+ * 0	 if addresses are equal
+ * 1	 if not equal
+ *
+ * Within a single transfer, the I2C client may need to send its address more
+ * than once. So a check if the addresses match is needed.
+ */
+static inline bool intel_mid_i2c_address_neq(const struct i2c_msg *p1,
+				       const struct i2c_msg *p2)
+{
+	if (p1->addr != p2->addr)
+		return 1;
+	if ((p1->flags ^ p2->flags) & I2C_M_TEN)
+		return 1;
+	return 0;
+}
+
+/**
+ * intel_mid_i2c_abort - To handle transfer abortions and print error messages.
+ * @adap: i2c_adapter struct pointer
+ *
+ * By reading register IC_TX_ABRT_SOURCE, various transfer errors can be
+ * distingushed. At present, no circumstances have been found out that
+ * multiple errors would be occurred simutaneously, so we simply use the
+ * register value directly.
+ *
+ * At last the error bits are cleared. (Note clear ABRT_SBYTE_NORSTRT bit need
+ * a few extra steps)
+ */
+static void intel_mid_i2c_abort(struct intel_mid_i2c_private *i2c)
+{
+	/* Read about source register */
+	int abort = i2c->abort;
+	struct i2c_adapter *adap = &i2c->adap;
+
+	/* Single transfer error check:
+	 * According to databook, TX/RX FIFOs would be flushed when
+	 * the abort interrupt occurred.
+	 */
+	if (abort & ABRT_MASTER_DIS)
+		dev_err(&adap->dev,
+		"initiate master operation with master mode disabled.\n");
+	if (abort & ABRT_10B_RD_NORSTRT)
+		dev_err(&adap->dev,
+	"RESTART disabled and master sent READ cmd in 10-bit addressing.\n");
+
+	if (abort & ABRT_SBYTE_NORSTRT) {
+		dev_err(&adap->dev,
+		"RESTART disabled and user is trying to send START byte.\n");
+		writel(~ABRT_SBYTE_NORSTRT, i2c->base + IC_TX_ABRT_SOURCE);
+		writel(RESTART, i2c->base + IC_CON);
+		writel(~IC_TAR_SPECIAL, i2c->base + IC_TAR);
+	}
+
+	if (abort & ABRT_SBYTE_ACKDET)
+		dev_err(&adap->dev,
+			"START byte was not acknowledged.\n");
+	if (abort & ABRT_TXDATA_NOACK)
+		dev_dbg(&adap->dev,
+			"No acknowledgement received from slave.\n");
+	if (abort & ABRT_10ADDR2_NOACK)
+		dev_dbg(&adap->dev,
+	"The 2nd address byte of the 10-bit address was not acknowledged.\n");
+	if (abort & ABRT_10ADDR1_NOACK)
+		dev_dbg(&adap->dev,
+	"The 1st address byte of 10-bit address was not acknowledged.\n");
+	if (abort & ABRT_7B_ADDR_NOACK)
+		dev_dbg(&adap->dev,
+			"I2C slave device not acknowledged.\n");
+
+	/* Clear TX_ABRT bit */
+	readl(i2c->base + IC_CLR_TX_ABRT);
+	i2c->status = STATUS_XFER_ABORT;
+}
+
+/**
+ * xfer_read - Internal function to implement master read transfer.
+ * @adap: i2c_adapter struct pointer
+ * @buf: buffer in i2c_msg
+ * @length: number of bytes to be read
+ *
+ * Return Values:
+ * 0		if the read transfer succeeds
+ * -ETIMEDOUT	if cannot read the "raw" interrupt register
+ * -EINVAL	if a transfer abort occurred
+ *
+ * For every byte, a "READ" command will be loaded into IC_DATA_CMD prior to
+ * data transfer. The actual "read" operation will be performed if an RX_FULL
+ * interrupt occurred.
+ *
+ * Note there may be two interrupt signals captured, one should read
+ * IC_RAW_INTR_STAT to separate between errors and actual data.
+ */
+static int xfer_read(struct i2c_adapter *adap, unsigned char *buf, int length)
+{
+	struct intel_mid_i2c_private *i2c = i2c_get_adapdata(adap);
+	int i = length;
+	int err;
+
+	if (length >= 256) {
+		dev_err(&adap->dev,
+			"I2C FIFO cannot support larger than 256 bytes\n");
+		return -EMSGSIZE;
+	}
+
+	INIT_COMPLETION(i2c->complete);
+
+	readl(i2c->base + IC_CLR_INTR);
+	writel(0x0044, i2c->base + IC_INTR_MASK);
+
+	i2c->status = STATUS_READ_START;
+
+	while (i--)
+		writel(IC_RD, i2c->base + IC_DATA_CMD);
+
+	i2c->status = STATUS_READ_START;
+	err = wait_for_completion_interruptible_timeout(&i2c->complete, HZ);
+	if (!err) {
+		dev_err(&adap->dev, "Timeout for ACK from I2C slave device\n");
+		intel_mid_i2c_hwinit(i2c);
+		return -ETIMEDOUT;
+	}
+	if (i2c->status == STATUS_READ_SUCCESS)
+		return 0;
+	else
+		return -EIO;
+}
+
+/**
+ * xfer_write - Internal function to implement master write transfer.
+ * @adap: i2c_adapter struct pointer
+ * @buf: buffer in i2c_msg
+ * @length: number of bytes to be read
+ *
+ * Return Values:
+ * 0	if the read transfer succeeds
+ * -ETIMEDOUT	if we cannot read the "raw" interrupt register
+ * -EINVAL	if a transfer abort occurred
+ *
+ * For every byte, a "WRITE" command will be loaded into IC_DATA_CMD prior to
+ * data transfer. The actual "write" operation will be performed when the
+ * RX_FULL interrupt signal occurs.
+ *
+ * Note there may be two interrupt signals captured, one should read
+ * IC_RAW_INTR_STAT to separate between errors and actual data.
+ */
+static int xfer_write(struct i2c_adapter *adap,
+		      unsigned char *buf, int length)
+{
+	struct intel_mid_i2c_private *i2c = i2c_get_adapdata(adap);
+	int i, err;
+
+	if (length >= 256) {
+		dev_err(&adap->dev,
+			"I2C FIFO cannot support larger than 256 bytes\n");
+		return -EMSGSIZE;
+	}
+
+	INIT_COMPLETION(i2c->complete);
+
+	readl(i2c->base + IC_CLR_INTR);
+	writel(0x0050, i2c->base + IC_INTR_MASK);
+
+	i2c->status = STATUS_WRITE_START;
+	for (i = 0; i < length; i++)
+		writel((u16)(*(buf + i)), i2c->base + IC_DATA_CMD);
+
+	i2c->status = STATUS_WRITE_START;
+	err = wait_for_completion_interruptible_timeout(&i2c->complete, HZ);
+	if (!err) {
+		dev_err(&adap->dev, "Timeout for ACK from I2C slave device\n");
+		intel_mid_i2c_hwinit(i2c);
+		return -ETIMEDOUT;
+	} else {
+		if (i2c->status == STATUS_WRITE_SUCCESS)
+			return 0;
+		else
+			return -EIO;
+	}
+}
+
+static int intel_mid_i2c_setup(struct i2c_adapter *adap,  struct i2c_msg *pmsg)
+{
+	struct intel_mid_i2c_private *i2c = i2c_get_adapdata(adap);
+	int err;
+	u32 reg;
+	u32 bit_mask;
+	u32 mode;
+
+	/* Disable device first */
+	err = intel_mid_i2c_disable(adap);
+	if (err) {
+		dev_err(&adap->dev,
+			"Cannot disable i2c controller, timeout\n");
+		return err;
+	}
+
+	mode = (1 + i2c->speed) << 1;
+	/* set the speed mode */
+	reg = readl(i2c->base + IC_CON);
+	if ((reg & 0x06) != mode) {
+		dev_dbg(&adap->dev, "set mode %d\n", i2c->speed);
+		writel((reg & ~0x6) | mode, i2c->base + IC_CON);
+	}
+
+	reg = readl(i2c->base + IC_CON);
+	/* use 7-bit addressing */
+	if (pmsg->flags & I2C_M_TEN) {
+		if ((reg & ADDR_10BIT) != ADDR_10BIT) {
+			dev_dbg(&adap->dev, "set i2c 10 bit address mode\n");
+			writel(reg | ADDR_10BIT, i2c->base + IC_CON);
+		}
+	} else {
+		if ((reg & ADDR_10BIT) != 0x0) {
+			dev_dbg(&adap->dev, "set i2c 7 bit address mode\n");
+			writel(reg & ~ADDR_10BIT, i2c->base + IC_CON);
+		}
+	}
+	/* enable restart conditions */
+	reg = readl(i2c->base + IC_CON);
+	if ((reg & RESTART) != RESTART) {
+		dev_dbg(&adap->dev, "enable restart conditions\n");
+		writel(reg | RESTART, i2c->base + IC_CON);
+	}
+
+	/* enable master FSM */
+	reg = readl(i2c->base + IC_CON);
+	dev_dbg(&adap->dev, "ic_con reg is 0x%x\n", reg);
+	writel(reg | MASTER_EN, i2c->base + IC_CON);
+	if ((reg & SLV_DIS) != SLV_DIS) {
+		dev_dbg(&adap->dev, "enable master FSM\n");
+		writel(reg | SLV_DIS, i2c->base + IC_CON);
+		dev_dbg(&adap->dev, "ic_con reg is 0x%x\n", reg);
+	}
+
+	/* use target address when initiating transfer */
+	reg = readl(i2c->base + IC_TAR);
+	bit_mask = IC_TAR_SPECIAL | IC_TAR_GC_OR_START;
+
+	if ((reg & bit_mask) != 0x0) {
+		dev_dbg(&adap->dev,
+	 "WR: use target address when intiating transfer, i2c_tx_target\n");
+		writel(reg & ~bit_mask, i2c->base + IC_TAR);
+	}
+
+	/* set target address to the I2C slave address */
+	dev_dbg(&adap->dev,
+		"set target address to the I2C slave address, addr is %x\n",
+			pmsg->addr);
+	writel(pmsg->addr | (pmsg->flags & I2C_M_TEN ? IC_TAR_10BIT_ADDR : 0),
+		i2c->base + IC_TAR);
+
+	/* Enable I2C controller */
+	writel(ENABLE, i2c->base + IC_ENABLE);
+
+	return 0;
+}
+
+/**
+ * intel_mid_i2c_xfer - Main master transfer routine.
+ * @adap: i2c_adapter struct pointer
+ * @pmsg: i2c_msg struct pointer
+ * @num: number of i2c_msg
+ *
+ * Return Values:
+ * +		number of messages transferred
+ * -ETIMEDOUT	If cannot disable I2C controller or read IC_STATUS
+ * -EINVAL	If the address in i2c_msg is invalid
+ *
+ * This function will be registered in i2c-core and exposed to external
+ * I2C clients.
+ * 1. Disable I2C controller
+ * 2. Unmask three interrupts: RX_FULL, TX_EMPTY, TX_ABRT
+ * 3. Check if address in i2c_msg is valid
+ * 4. Enable I2C controller
+ * 5. Perform real transfer (call xfer_read or xfer_write)
+ * 6. Wait until the current transfer is finished (check bus state)
+ * 7. Mask and clear all interrupts
+ */
+static int intel_mid_i2c_xfer(struct i2c_adapter *adap,
+			 struct i2c_msg *pmsg,
+			 int num)
+{
+	struct intel_mid_i2c_private *i2c = i2c_get_adapdata(adap);
+	int i, err = 0;
+
+	/* if number of messages equal 0*/
+	if (num == 0)
+		return 0;
+
+	pm_runtime_get(i2c->dev);
+
+	mutex_lock(&i2c->lock);
+	dev_dbg(&adap->dev, "intel_mid_i2c_xfer, process %d msg(s)\n", num);
+	dev_dbg(&adap->dev, "slave address is %x\n", pmsg->addr);
+
+
+	if (i2c->status != STATUS_IDLE) {
+		dev_err(&adap->dev, "Adapter %d in transfer/standby\n",
+								adap->nr);
+		mutex_unlock(&i2c->lock);
+		pm_runtime_put(i2c->dev);
+		return -1;
+	}
+
+
+	for (i = 1; i < num; i++) {
+		/* Message address equal? */
+		if (unlikely(intel_mid_i2c_address_neq(&pmsg[0], &pmsg[i]))) {
+			dev_err(&adap->dev, "Invalid address in msg[%d]\n", i);
+			mutex_unlock(&i2c->lock);
+			pm_runtime_put(i2c->dev);
+			return -EINVAL;
+		}
+	}
+
+	if (intel_mid_i2c_setup(adap, pmsg)) {
+		mutex_unlock(&i2c->lock);
+		pm_runtime_put(i2c->dev);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < num; i++) {
+		i2c->msg = pmsg;
+		i2c->status = STATUS_IDLE;
+		/* Read or Write */
+		if (pmsg->flags & I2C_M_RD) {
+			dev_dbg(&adap->dev, "I2C_M_RD\n");
+			err = xfer_read(adap, pmsg->buf, pmsg->len);
+		} else {
+			dev_dbg(&adap->dev, "I2C_M_WR\n");
+			err = xfer_write(adap, pmsg->buf, pmsg->len);
+		}
+		if (err < 0)
+			break;
+		dev_dbg(&adap->dev, "msg[%d] transfer complete\n", i);
+		pmsg++;		/* next message */
+	}
+
+	/* Mask interrupts */
+	writel(0x0000, i2c->base + IC_INTR_MASK);
+	/* Clear all interrupts */
+	readl(i2c->base + IC_CLR_INTR);
+
+	i2c->status = STATUS_IDLE;
+	mutex_unlock(&i2c->lock);
+	pm_runtime_put(i2c->dev);
+
+	return err;
+}
+
+static int intel_mid_i2c_runtime_suspend(struct device *dev)
+{
+	struct pci_dev *pdev = to_pci_dev(dev);
+	struct intel_mid_i2c_private *i2c = pci_get_drvdata(pdev);
+	struct i2c_adapter *adap = to_i2c_adapter(dev);
+	int err;
+
+	if (i2c->status != STATUS_IDLE)
+		return -1;
+
+	intel_mid_i2c_disable(adap);
+
+	err = pci_save_state(pdev);
+	if (err) {
+		dev_err(dev, "pci_save_state failed\n");
+		return err;
+	}
+
+	err = pci_set_power_state(pdev, PCI_D3hot);
+	if (err) {
+		dev_err(dev, "pci_set_power_state failed\n");
+		return err;
+	}
+	i2c->status = STATUS_STANDBY;
+
+	return 0;
+}
+
+static int intel_mid_i2c_runtime_resume(struct device *dev)
+{
+	struct pci_dev *pdev = to_pci_dev(dev);
+	struct intel_mid_i2c_private *i2c = pci_get_drvdata(pdev);
+	int err;
+
+	if (i2c->status != STATUS_STANDBY)
+		return 0;
+
+	pci_set_power_state(pdev, PCI_D0);
+	pci_restore_state(pdev);
+	err = pci_enable_device(pdev);
+	if (err) {
+		dev_err(dev, "pci_enable_device failed\n");
+		return err;
+	}
+
+	i2c->status = STATUS_IDLE;
+
+	intel_mid_i2c_hwinit(i2c);
+	return err;
+}
+
+static void i2c_isr_read(struct intel_mid_i2c_private *i2c)
+{
+	struct i2c_msg *msg = i2c->msg;
+	int rx_num;
+	u32 len;
+	u8 *buf;
+
+	if (!(msg->flags & I2C_M_RD))
+		return;
+
+	if (i2c->status != STATUS_READ_IN_PROGRESS) {
+		len = msg->len;
+		buf = msg->buf;
+	} else {
+		len = i2c->rx_buf_len;
+		buf = i2c->rx_buf;
+	}
+
+	rx_num = readl(i2c->base + IC_RXFLR);
+
+	for (; len > 0 && rx_num > 0; len--, rx_num--)
+		*buf++ = readl(i2c->base + IC_DATA_CMD);
+
+	if (len > 0) {
+		i2c->status = STATUS_READ_IN_PROGRESS;
+		i2c->rx_buf_len = len;
+		i2c->rx_buf = buf;
+	} else
+		i2c->status = STATUS_READ_SUCCESS;
+
+	return;
+}
+
+static irqreturn_t intel_mid_i2c_isr(int this_irq, void *dev)
+{
+	struct intel_mid_i2c_private *i2c = dev;
+	u32 stat = readl(i2c->base + IC_INTR_STAT);
+
+	if (!stat)
+		return IRQ_NONE;
+
+	dev_dbg(&i2c->adap.dev, "%s, stat = 0x%x\n", __func__, stat);
+	stat &= 0x54;
+
+	if (i2c->status != STATUS_WRITE_START &&
+	    i2c->status != STATUS_READ_START &&
+	    i2c->status != STATUS_READ_IN_PROGRESS)
+		goto err;
+
+	if (stat & TX_ABRT)
+		i2c->abort = readl(i2c->base + IC_TX_ABRT_SOURCE);
+
+	readl(i2c->base + IC_CLR_INTR);
+
+	if (stat & TX_ABRT) {
+		intel_mid_i2c_abort(i2c);
+		goto exit;
+	}
+
+	if (stat & RX_FULL) {
+		i2c_isr_read(i2c);
+		goto exit;
+	}
+
+	if (stat & TX_EMPTY) {
+		if (readl(i2c->base + IC_STATUS) & 0x4)
+			i2c->status = STATUS_WRITE_SUCCESS;
+	}
+
+exit:
+	if (i2c->status == STATUS_READ_SUCCESS ||
+	    i2c->status == STATUS_WRITE_SUCCESS ||
+	    i2c->status == STATUS_XFER_ABORT) {
+		/* Clear all interrupts */
+		readl(i2c->base + IC_CLR_INTR);
+		/* Mask interrupts */
+		writel(0, i2c->base + IC_INTR_MASK);
+		complete(&i2c->complete);
+	}
+err:
+	return IRQ_HANDLED;
+}
+
+static struct i2c_algorithm intel_mid_i2c_algorithm = {
+	.master_xfer	= intel_mid_i2c_xfer,
+	.functionality	= intel_mid_i2c_func,
+};
+
+
+static const struct dev_pm_ops intel_mid_i2c_pm_ops = {
+	.runtime_suspend = intel_mid_i2c_runtime_suspend,
+	.runtime_resume = intel_mid_i2c_runtime_resume,
+};
+
+/**
+ * intel_mid_i2c_probe - I2C controller initialization routine
+ * @dev: pci device
+ * @id: device id
+ *
+ * Return Values:
+ * 0		success
+ * -ENODEV	If cannot allocate pci resource
+ * -ENOMEM	If the register base remapping failed, or
+ *		if kzalloc failed
+ *
+ * Initialization steps:
+ * 1. Request for PCI resource
+ * 2. Remap the start address of PCI resource to register base
+ * 3. Request for device memory region
+ * 4. Fill in the struct members of intel_mid_i2c_private
+ * 5. Call intel_mid_i2c_hwinit() for hardware initialization
+ * 6. Register I2C adapter in i2c-core
+ */
+static int __devinit intel_mid_i2c_probe(struct pci_dev *dev,
+				    const struct pci_device_id *id)
+{
+	struct intel_mid_i2c_private *mrst;
+	unsigned long start, len;
+	int err, busnum;
+	void __iomem *base = NULL;
+
+	dev_dbg(&dev->dev, "Get into probe function for I2C\n");
+	err = pci_enable_device(dev);
+	if (err) {
+		dev_err(&dev->dev, "Failed to enable I2C PCI device (%d)\n",
+			err);
+		goto exit;
+	}
+
+	/* Determine the address of the I2C area */
+	start = pci_resource_start(dev, 0);
+	len = pci_resource_len(dev, 0);
+	if (!start || len == 0) {
+		dev_err(&dev->dev, "base address not set\n");
+		err = -ENODEV;
+		goto exit;
+	}
+	dev_dbg(&dev->dev, "%s i2c resource start 0x%lx, len=%ld\n",
+		PLATFORM, start, len);
+
+	err = pci_request_region(dev, 0, DRIVER_NAME);
+	if (err) {
+		dev_err(&dev->dev, "failed to request I2C region "
+			"0x%lx-0x%lx\n", start,
+			(unsigned long)pci_resource_end(dev, 0));
+		goto exit;
+	}
+
+	base = ioremap_nocache(start, len);
+	if (!base) {
+		dev_err(&dev->dev, "I/O memory remapping failed\n");
+		err = -ENOMEM;
+		goto fail0;
+	}
+
+	/* Allocate the per-device data structure, intel_mid_i2c_private */
+	mrst = kzalloc(sizeof(struct intel_mid_i2c_private), GFP_KERNEL);
+	if (mrst == NULL) {
+		dev_err(&dev->dev, "can't allocate interface\n");
+		err = -ENOMEM;
+		goto fail1;
+	}
+
+	/* Initialize struct members */
+	snprintf(mrst->adap.name, sizeof(mrst->adap.name),
+		"Intel MID I2C at %lx", start);
+	mrst->adap.owner = THIS_MODULE;
+	mrst->adap.algo = &intel_mid_i2c_algorithm;
+	mrst->adap.dev.parent = &dev->dev;
+	mrst->dev = &dev->dev;
+	mrst->base = base;
+	mrst->speed = STANDARD;
+	mrst->abort = 0;
+	mrst->rx_buf_len = 0;
+	mrst->status = STATUS_IDLE;
+
+	pci_set_drvdata(dev, mrst);
+	i2c_set_adapdata(&mrst->adap, mrst);
+
+	mrst->adap.nr = busnum = id->driver_data;
+	if (dev->device <= 0x0804)
+		mrst->platform = MOORESTOWN;
+	else
+		mrst->platform = MEDFIELD;
+
+	dev_dbg(&dev->dev, "I2C%d\n", busnum);
+
+	if (ctl_num > busnum) {
+		if (speed_mode[busnum] < 0 || speed_mode[busnum] >= NUM_SPEEDS)
+			dev_warn(&dev->dev, "invalid speed %d ignored.\n",
+							speed_mode[busnum]);
+		else
+			mrst->speed = speed_mode[busnum];
+	}
+
+	/* Initialize i2c controller */
+	err = intel_mid_i2c_hwinit(mrst);
+	if (err < 0) {
+		dev_err(&dev->dev, "I2C interface initialization failed\n");
+		goto fail2;
+	}
+
+	mutex_init(&mrst->lock);
+	init_completion(&mrst->complete);
+
+	/* Clear all interrupts */
+	readl(mrst->base + IC_CLR_INTR);
+	writel(0x0000, mrst->base + IC_INTR_MASK);
+
+	err = request_irq(dev->irq, intel_mid_i2c_isr, IRQF_SHARED,
+					mrst->adap.name, mrst);
+	if (err) {
+		dev_err(&dev->dev, "Failed to request IRQ for I2C controller: "
+			"%s", mrst->adap.name);
+		goto fail2;
+	}
+
+	/* Adapter registration */
+	err = i2c_add_numbered_adapter(&mrst->adap);
+	if (err) {
+		dev_err(&dev->dev, "Adapter %s registration failed\n",
+			mrst->adap.name);
+		goto fail3;
+	}
+
+	dev_dbg(&dev->dev, "%s I2C bus %d driver bind success.\n",
+		(mrst->platform == MOORESTOWN) ? "Moorestown" : "Medfield",
+		busnum);
+
+	pm_runtime_enable(&dev->dev);
+	return 0;
+
+fail3:
+	free_irq(dev->irq, mrst);
+fail2:
+	pci_set_drvdata(dev, NULL);
+	kfree(mrst);
+fail1:
+	iounmap(base);
+fail0:
+	pci_release_region(dev, 0);
+exit:
+	return err;
+}
+
+static void __devexit intel_mid_i2c_remove(struct pci_dev *dev)
+{
+	struct intel_mid_i2c_private *mrst = pci_get_drvdata(dev);
+	intel_mid_i2c_disable(&mrst->adap);
+	if (i2c_del_adapter(&mrst->adap))
+		dev_err(&dev->dev, "Failed to delete i2c adapter");
+
+	free_irq(dev->irq, mrst);
+	pci_set_drvdata(dev, NULL);
+	iounmap(mrst->base);
+	kfree(mrst);
+	pci_release_region(dev, 0);
+}
+
+static DEFINE_PCI_DEVICE_TABLE(intel_mid_i2c_ids) = {
+	/* Moorestown */
+	{ PCI_VDEVICE(INTEL, 0x0802), 0 },
+	{ PCI_VDEVICE(INTEL, 0x0803), 1 },
+	{ PCI_VDEVICE(INTEL, 0x0804), 2 },
+	/* Medfield */
+	{ PCI_VDEVICE(INTEL, 0x0817), 3,},
+	{ PCI_VDEVICE(INTEL, 0x0818), 4 },
+	{ PCI_VDEVICE(INTEL, 0x0819), 5 },
+	{ PCI_VDEVICE(INTEL, 0x082C), 0 },
+	{ PCI_VDEVICE(INTEL, 0x082D), 1 },
+	{ PCI_VDEVICE(INTEL, 0x082E), 2 },
+	{ 0,}
+};
+MODULE_DEVICE_TABLE(pci, intel_mid_i2c_ids);
+
+static struct pci_driver intel_mid_i2c_driver = {
+	.name		= DRIVER_NAME,
+	.id_table	= intel_mid_i2c_ids,
+	.probe		= intel_mid_i2c_probe,
+	.remove		= __devexit_p(intel_mid_i2c_remove),
+};
+
+static int __init intel_mid_i2c_init(void)
+{
+	return pci_register_driver(&intel_mid_i2c_driver);
+}
+
+static void __exit intel_mid_i2c_exit(void)
+{
+	pci_unregister_driver(&intel_mid_i2c_driver);
+}
+
+module_init(intel_mid_i2c_init);
+module_exit(intel_mid_i2c_exit);
+
+MODULE_AUTHOR("Ba Zheng <zheng.ba@intel.com>");
+MODULE_DESCRIPTION("I2C driver for Moorestown Platform");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(VERSION);
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-iop3xx.c b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-iop3xx.c
new file mode 100644
index 0000000..93f147a
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-iop3xx.c
@@ -0,0 +1,531 @@
+/* ------------------------------------------------------------------------- */
+/* i2c-iop3xx.c i2c driver algorithms for Intel XScale IOP3xx & IXP46x       */
+/* ------------------------------------------------------------------------- */
+/* Copyright (C) 2003 Peter Milne, D-TACQ Solutions Ltd
+ *                    <Peter dot Milne at D hyphen TACQ dot com>
+ *
+ * With acknowledgements to i2c-algo-ibm_ocp.c by 
+ * Ian DaSilva, MontaVista Software, Inc. idasilva@mvista.com
+ *
+ * And i2c-algo-pcf.c, which was created by Simon G. Vogl and Hans Berglund:
+ *
+ * Copyright (C) 1995-1997 Simon G. Vogl, 1998-2000 Hans Berglund
+ *  
+ * And which acknowledged Kyösti Mälkki <kmalkki@cc.hut.fi>,
+ * Frodo Looijaard <frodol@dds.nl>, Martin Bailey<mbailey@littlefeet-inc.com>
+ *
+ * Major cleanup by Deepak Saxena <dsaxena@plexity.net>, 01/2005:
+ *
+ * - Use driver model to pass per-chip info instead of hardcoding and #ifdefs
+ * - Use ioremap/__raw_readl/__raw_writel instead of direct dereference
+ * - Make it work with IXP46x chips
+ * - Cleanup function names, coding style, etc
+ *
+ * - writing to slave address causes latchup on iop331.
+ *	fix: driver refuses to address self.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/io.h>
+
+#include "i2c-iop3xx.h"
+
+/* global unit counter */
+static int i2c_id;
+
+static inline unsigned char 
+iic_cook_addr(struct i2c_msg *msg) 
+{
+	unsigned char addr;
+
+	addr = (msg->addr << 1);
+
+	if (msg->flags & I2C_M_RD)
+		addr |= 1;
+
+	return addr;   
+}
+
+static void 
+iop3xx_i2c_reset(struct i2c_algo_iop3xx_data *iop3xx_adap)
+{
+	/* Follows devman 9.3 */
+	__raw_writel(IOP3XX_ICR_UNIT_RESET, iop3xx_adap->ioaddr + CR_OFFSET);
+	__raw_writel(IOP3XX_ISR_CLEARBITS, iop3xx_adap->ioaddr + SR_OFFSET);
+	__raw_writel(0, iop3xx_adap->ioaddr + CR_OFFSET);
+} 
+
+static void 
+iop3xx_i2c_enable(struct i2c_algo_iop3xx_data *iop3xx_adap)
+{
+	u32 cr = IOP3XX_ICR_GCD | IOP3XX_ICR_SCLEN | IOP3XX_ICR_UE;
+
+	/* 
+	 * Every time unit enable is asserted, GPOD needs to be cleared
+	 * on IOP3XX to avoid data corruption on the bus.
+	 */
+#if defined(CONFIG_ARCH_IOP32X) || defined(CONFIG_ARCH_IOP33X)
+	if (iop3xx_adap->id == 0) {
+		gpio_line_set(IOP3XX_GPIO_LINE(7), GPIO_LOW);
+		gpio_line_set(IOP3XX_GPIO_LINE(6), GPIO_LOW);
+	} else {
+		gpio_line_set(IOP3XX_GPIO_LINE(5), GPIO_LOW);
+		gpio_line_set(IOP3XX_GPIO_LINE(4), GPIO_LOW);
+	}
+#endif
+	/* NB SR bits not same position as CR IE bits :-( */
+	iop3xx_adap->SR_enabled = 
+		IOP3XX_ISR_ALD | IOP3XX_ISR_BERRD |
+		IOP3XX_ISR_RXFULL | IOP3XX_ISR_TXEMPTY;
+
+	cr |= IOP3XX_ICR_ALD_IE | IOP3XX_ICR_BERR_IE |
+		IOP3XX_ICR_RXFULL_IE | IOP3XX_ICR_TXEMPTY_IE;
+
+	__raw_writel(cr, iop3xx_adap->ioaddr + CR_OFFSET);
+}
+
+static void 
+iop3xx_i2c_transaction_cleanup(struct i2c_algo_iop3xx_data *iop3xx_adap)
+{
+	unsigned long cr = __raw_readl(iop3xx_adap->ioaddr + CR_OFFSET);
+	
+	cr &= ~(IOP3XX_ICR_MSTART | IOP3XX_ICR_TBYTE | 
+		IOP3XX_ICR_MSTOP | IOP3XX_ICR_SCLEN);
+
+	__raw_writel(cr, iop3xx_adap->ioaddr + CR_OFFSET);
+}
+
+/* 
+ * NB: the handler has to clear the source of the interrupt! 
+ * Then it passes the SR flags of interest to BH via adap data
+ */
+static irqreturn_t 
+iop3xx_i2c_irq_handler(int this_irq, void *dev_id) 
+{
+	struct i2c_algo_iop3xx_data *iop3xx_adap = dev_id;
+	u32 sr = __raw_readl(iop3xx_adap->ioaddr + SR_OFFSET);
+
+	if ((sr &= iop3xx_adap->SR_enabled)) {
+		__raw_writel(sr, iop3xx_adap->ioaddr + SR_OFFSET);
+		iop3xx_adap->SR_received |= sr;
+		wake_up_interruptible(&iop3xx_adap->waitq);
+	}
+	return IRQ_HANDLED;
+}
+
+/* check all error conditions, clear them , report most important */
+static int 
+iop3xx_i2c_error(u32 sr)
+{
+	int rc = 0;
+
+	if ((sr & IOP3XX_ISR_BERRD)) {
+		if ( !rc ) rc = -I2C_ERR_BERR;
+	}
+	if ((sr & IOP3XX_ISR_ALD)) {
+		if ( !rc ) rc = -I2C_ERR_ALD;		
+	}
+	return rc;	
+}
+
+static inline u32 
+iop3xx_i2c_get_srstat(struct i2c_algo_iop3xx_data *iop3xx_adap)
+{
+	unsigned long flags;
+	u32 sr;
+
+	spin_lock_irqsave(&iop3xx_adap->lock, flags);
+	sr = iop3xx_adap->SR_received;
+	iop3xx_adap->SR_received = 0;
+	spin_unlock_irqrestore(&iop3xx_adap->lock, flags);
+
+	return sr;
+}
+
+/*
+ * sleep until interrupted, then recover and analyse the SR
+ * saved by handler
+ */
+typedef int (* compare_func)(unsigned test, unsigned mask);
+/* returns 1 on correct comparison */
+
+static int 
+iop3xx_i2c_wait_event(struct i2c_algo_iop3xx_data *iop3xx_adap, 
+			  unsigned flags, unsigned* status,
+			  compare_func compare)
+{
+	unsigned sr = 0;
+	int interrupted;
+	int done;
+	int rc = 0;
+
+	do {
+		interrupted = wait_event_interruptible_timeout (
+			iop3xx_adap->waitq,
+			(done = compare( sr = iop3xx_i2c_get_srstat(iop3xx_adap) ,flags )),
+			1 * HZ;
+			);
+		if ((rc = iop3xx_i2c_error(sr)) < 0) {
+			*status = sr;
+			return rc;
+		} else if (!interrupted) {
+			*status = sr;
+			return -ETIMEDOUT;
+		}
+	} while(!done);
+
+	*status = sr;
+
+	return 0;
+}
+
+/*
+ * Concrete compare_funcs 
+ */
+static int 
+all_bits_clear(unsigned test, unsigned mask)
+{
+	return (test & mask) == 0;
+}
+
+static int 
+any_bits_set(unsigned test, unsigned mask)
+{
+	return (test & mask) != 0;
+}
+
+static int 
+iop3xx_i2c_wait_tx_done(struct i2c_algo_iop3xx_data *iop3xx_adap, int *status)
+{
+	return iop3xx_i2c_wait_event( 
+		iop3xx_adap, 
+	        IOP3XX_ISR_TXEMPTY | IOP3XX_ISR_ALD | IOP3XX_ISR_BERRD,
+		status, any_bits_set);
+}
+
+static int 
+iop3xx_i2c_wait_rx_done(struct i2c_algo_iop3xx_data *iop3xx_adap, int *status)
+{
+	return iop3xx_i2c_wait_event( 
+		iop3xx_adap, 
+		IOP3XX_ISR_RXFULL | IOP3XX_ISR_ALD | IOP3XX_ISR_BERRD,
+		status,	any_bits_set);
+}
+
+static int 
+iop3xx_i2c_wait_idle(struct i2c_algo_iop3xx_data *iop3xx_adap, int *status)
+{
+	return iop3xx_i2c_wait_event( 
+		iop3xx_adap, IOP3XX_ISR_UNITBUSY, status, all_bits_clear);
+}
+
+static int 
+iop3xx_i2c_send_target_addr(struct i2c_algo_iop3xx_data *iop3xx_adap, 
+				struct i2c_msg* msg)
+{
+	unsigned long cr = __raw_readl(iop3xx_adap->ioaddr + CR_OFFSET);
+	int status;
+	int rc;
+
+	/* avoid writing to my slave address (hangs on 80331),
+	 * forbidden in Intel developer manual
+	 */
+	if (msg->addr == MYSAR) {
+		return -EBUSY;
+	}
+
+	__raw_writel(iic_cook_addr(msg), iop3xx_adap->ioaddr + DBR_OFFSET);
+	
+	cr &= ~(IOP3XX_ICR_MSTOP | IOP3XX_ICR_NACK);
+	cr |= IOP3XX_ICR_MSTART | IOP3XX_ICR_TBYTE;
+
+	__raw_writel(cr, iop3xx_adap->ioaddr + CR_OFFSET);
+	rc = iop3xx_i2c_wait_tx_done(iop3xx_adap, &status);
+
+	return rc;
+}
+
+static int 
+iop3xx_i2c_write_byte(struct i2c_algo_iop3xx_data *iop3xx_adap, char byte, 
+				int stop)
+{
+	unsigned long cr = __raw_readl(iop3xx_adap->ioaddr + CR_OFFSET);
+	int status;
+	int rc = 0;
+
+	__raw_writel(byte, iop3xx_adap->ioaddr + DBR_OFFSET);
+	cr &= ~IOP3XX_ICR_MSTART;
+	if (stop) {
+		cr |= IOP3XX_ICR_MSTOP;
+	} else {
+		cr &= ~IOP3XX_ICR_MSTOP;
+	}
+	cr |= IOP3XX_ICR_TBYTE;
+	__raw_writel(cr, iop3xx_adap->ioaddr + CR_OFFSET);
+	rc = iop3xx_i2c_wait_tx_done(iop3xx_adap, &status);
+
+	return rc;
+} 
+
+static int 
+iop3xx_i2c_read_byte(struct i2c_algo_iop3xx_data *iop3xx_adap, char* byte, 
+				int stop)
+{
+	unsigned long cr = __raw_readl(iop3xx_adap->ioaddr + CR_OFFSET);
+	int status;
+	int rc = 0;
+
+	cr &= ~IOP3XX_ICR_MSTART;
+
+	if (stop) {
+		cr |= IOP3XX_ICR_MSTOP | IOP3XX_ICR_NACK;
+	} else {
+		cr &= ~(IOP3XX_ICR_MSTOP | IOP3XX_ICR_NACK);
+	}
+	cr |= IOP3XX_ICR_TBYTE;
+	__raw_writel(cr, iop3xx_adap->ioaddr + CR_OFFSET);
+
+	rc = iop3xx_i2c_wait_rx_done(iop3xx_adap, &status);
+
+	*byte = __raw_readl(iop3xx_adap->ioaddr + DBR_OFFSET);
+
+	return rc;
+}
+
+static int 
+iop3xx_i2c_writebytes(struct i2c_adapter *i2c_adap, const char *buf, int count)
+{
+	struct i2c_algo_iop3xx_data *iop3xx_adap = i2c_adap->algo_data;
+	int ii;
+	int rc = 0;
+
+	for (ii = 0; rc == 0 && ii != count; ++ii) 
+		rc = iop3xx_i2c_write_byte(iop3xx_adap, buf[ii], ii==count-1);
+	return rc;
+}
+
+static int 
+iop3xx_i2c_readbytes(struct i2c_adapter *i2c_adap, char *buf, int count)
+{
+	struct i2c_algo_iop3xx_data *iop3xx_adap = i2c_adap->algo_data;
+	int ii;
+	int rc = 0;
+
+	for (ii = 0; rc == 0 && ii != count; ++ii)
+		rc = iop3xx_i2c_read_byte(iop3xx_adap, &buf[ii], ii==count-1);
+	
+	return rc;
+}
+
+/*
+ * Description:  This function implements combined transactions.  Combined
+ * transactions consist of combinations of reading and writing blocks of data.
+ * FROM THE SAME ADDRESS
+ * Each transfer (i.e. a read or a write) is separated by a repeated start
+ * condition.
+ */
+static int 
+iop3xx_i2c_handle_msg(struct i2c_adapter *i2c_adap, struct i2c_msg* pmsg) 
+{
+	struct i2c_algo_iop3xx_data *iop3xx_adap = i2c_adap->algo_data;
+	int rc;
+
+	rc = iop3xx_i2c_send_target_addr(iop3xx_adap, pmsg);
+	if (rc < 0) {
+		return rc;
+	}
+
+	if ((pmsg->flags&I2C_M_RD)) {
+		return iop3xx_i2c_readbytes(i2c_adap, pmsg->buf, pmsg->len);
+	} else {
+		return iop3xx_i2c_writebytes(i2c_adap, pmsg->buf, pmsg->len);
+	}
+}
+
+/*
+ * master_xfer() - main read/write entry
+ */
+static int 
+iop3xx_i2c_master_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, 
+				int num)
+{
+	struct i2c_algo_iop3xx_data *iop3xx_adap = i2c_adap->algo_data;
+	int im = 0;
+	int ret = 0;
+	int status;
+
+	iop3xx_i2c_wait_idle(iop3xx_adap, &status);
+	iop3xx_i2c_reset(iop3xx_adap);
+	iop3xx_i2c_enable(iop3xx_adap);
+
+	for (im = 0; ret == 0 && im != num; im++) {
+		ret = iop3xx_i2c_handle_msg(i2c_adap, &msgs[im]);
+	}
+
+	iop3xx_i2c_transaction_cleanup(iop3xx_adap);
+	
+	if(ret)
+		return ret;
+
+	return im;   
+}
+
+static u32 
+iop3xx_i2c_func(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm iop3xx_i2c_algo = {
+	.master_xfer	= iop3xx_i2c_master_xfer,
+	.functionality	= iop3xx_i2c_func,
+};
+
+static int 
+iop3xx_i2c_remove(struct platform_device *pdev)
+{
+	struct i2c_adapter *padapter = platform_get_drvdata(pdev);
+	struct i2c_algo_iop3xx_data *adapter_data = 
+		(struct i2c_algo_iop3xx_data *)padapter->algo_data;
+	struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	unsigned long cr = __raw_readl(adapter_data->ioaddr + CR_OFFSET);
+
+	/*
+	 * Disable the actual HW unit
+	 */
+	cr &= ~(IOP3XX_ICR_ALD_IE | IOP3XX_ICR_BERR_IE |
+		IOP3XX_ICR_RXFULL_IE | IOP3XX_ICR_TXEMPTY_IE);
+	__raw_writel(cr, adapter_data->ioaddr + CR_OFFSET);
+
+	iounmap(adapter_data->ioaddr);
+	release_mem_region(res->start, IOP3XX_I2C_IO_SIZE);
+	kfree(adapter_data);
+	kfree(padapter);
+
+	platform_set_drvdata(pdev, NULL);
+
+	return 0;
+}
+
+static int 
+iop3xx_i2c_probe(struct platform_device *pdev)
+{
+	struct resource *res;
+	int ret, irq;
+	struct i2c_adapter *new_adapter;
+	struct i2c_algo_iop3xx_data *adapter_data;
+
+	new_adapter = kzalloc(sizeof(struct i2c_adapter), GFP_KERNEL);
+	if (!new_adapter) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	adapter_data = kzalloc(sizeof(struct i2c_algo_iop3xx_data), GFP_KERNEL);
+	if (!adapter_data) {
+		ret = -ENOMEM;
+		goto free_adapter;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		ret = -ENODEV;
+		goto free_both;
+	}
+
+	if (!request_mem_region(res->start, IOP3XX_I2C_IO_SIZE, pdev->name)) {
+		ret = -EBUSY;
+		goto free_both;
+	}
+
+	/* set the adapter enumeration # */
+	adapter_data->id = i2c_id++;
+
+	adapter_data->ioaddr = ioremap(res->start, IOP3XX_I2C_IO_SIZE);
+	if (!adapter_data->ioaddr) {
+		ret = -ENOMEM;
+		goto release_region;
+	}
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		ret = -ENXIO;
+		goto unmap;
+	}
+	ret = request_irq(irq, iop3xx_i2c_irq_handler, 0,
+				pdev->name, adapter_data);
+
+	if (ret) {
+		ret = -EIO;
+		goto unmap;
+	}
+
+	memcpy(new_adapter->name, pdev->name, strlen(pdev->name));
+	new_adapter->owner = THIS_MODULE;
+	new_adapter->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
+	new_adapter->dev.parent = &pdev->dev;
+	new_adapter->nr = pdev->id;
+
+	/*
+	 * Default values...should these come in from board code?
+	 */
+	new_adapter->timeout = HZ;
+	new_adapter->algo = &iop3xx_i2c_algo;
+
+	init_waitqueue_head(&adapter_data->waitq);
+	spin_lock_init(&adapter_data->lock);
+
+	iop3xx_i2c_reset(adapter_data);
+	iop3xx_i2c_enable(adapter_data);
+
+	platform_set_drvdata(pdev, new_adapter);
+	new_adapter->algo_data = adapter_data;
+
+	i2c_add_numbered_adapter(new_adapter);
+
+	return 0;
+
+unmap:
+	iounmap(adapter_data->ioaddr);
+
+release_region:
+	release_mem_region(res->start, IOP3XX_I2C_IO_SIZE);
+
+free_both:
+	kfree(adapter_data);
+
+free_adapter:
+	kfree(new_adapter);
+
+out:
+	return ret;
+}
+
+
+static struct platform_driver iop3xx_i2c_driver = {
+	.probe		= iop3xx_i2c_probe,
+	.remove		= iop3xx_i2c_remove,
+	.driver		= {
+		.owner	= THIS_MODULE,
+		.name	= "IOP3xx-I2C",
+	},
+};
+
+module_platform_driver(iop3xx_i2c_driver);
+
+MODULE_AUTHOR("D-TACQ Solutions Ltd <www.d-tacq.com>");
+MODULE_DESCRIPTION("IOP3xx iic algorithm and driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:IOP3xx-I2C");
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-iop3xx.h b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-iop3xx.h
new file mode 100644
index 0000000..097e270
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-iop3xx.h
@@ -0,0 +1,107 @@
+/* ------------------------------------------------------------------------- */
+/* i2c-iop3xx.h algorithm driver definitions private to i2c-iop3xx.c         */
+/* ------------------------------------------------------------------------- */
+/*   Copyright (C) 2003 Peter Milne, D-TACQ Solutions Ltd
+ *                      <Peter dot Milne at D hyphen TACQ dot com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, version 2.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.                */
+/* ------------------------------------------------------------------------- */
+
+
+#ifndef I2C_IOP3XX_H
+#define I2C_IOP3XX_H 1
+
+/*
+ * iop321 hardware bit definitions
+ */
+#define IOP3XX_ICR_FAST_MODE	0x8000	/* 1=400kBps, 0=100kBps */
+#define IOP3XX_ICR_UNIT_RESET	0x4000	/* 1=RESET */
+#define IOP3XX_ICR_SAD_IE	0x2000	/* 1=Slave Detect Interrupt Enable */
+#define IOP3XX_ICR_ALD_IE	0x1000	/* 1=Arb Loss Detect Interrupt Enable */
+#define IOP3XX_ICR_SSD_IE	0x0800	/* 1=Slave STOP Detect Interrupt Enable */
+#define IOP3XX_ICR_BERR_IE	0x0400	/* 1=Bus Error Interrupt Enable */
+#define IOP3XX_ICR_RXFULL_IE	0x0200	/* 1=Receive Full Interrupt Enable */
+#define IOP3XX_ICR_TXEMPTY_IE	0x0100	/* 1=Transmit Empty Interrupt Enable */
+#define IOP3XX_ICR_GCD		0x0080	/* 1=General Call Disable */
+/*
+ * IOP3XX_ICR_GCD: 1 disables response as slave. "This bit must be set
+ * when sending a master mode general call message from the I2C unit"
+ */
+#define IOP3XX_ICR_UE		0x0040	/* 1=Unit Enable */
+/*
+ * "NOTE: To avoid I2C bus integrity problems, 
+ * the user needs to ensure that the GPIO Output Data Register - 
+ * GPOD bits associated with an I2C port are cleared prior to setting 
+ * the enable bit for that I2C serial port. 
+ * The user prepares to enable I2C port 0 and 
+ * I2C port 1 by clearing GPOD bits 7:6 and GPOD bits 5:4, respectively.
+ */
+#define IOP3XX_ICR_SCLEN	0x0020	/* 1=SCL enable for master mode */
+#define IOP3XX_ICR_MABORT	0x0010	/* 1=Send a STOP with no data 
+					 * NB TBYTE must be clear */
+#define IOP3XX_ICR_TBYTE	0x0008	/* 1=Send/Receive a byte. i2c clears */
+#define IOP3XX_ICR_NACK		0x0004	/* 1=reply with NACK */
+#define IOP3XX_ICR_MSTOP	0x0002	/* 1=send a STOP after next data byte */
+#define IOP3XX_ICR_MSTART	0x0001	/* 1=initiate a START */
+
+
+#define IOP3XX_ISR_BERRD	0x0400	/* 1=BUS ERROR Detected */
+#define IOP3XX_ISR_SAD		0x0200	/* 1=Slave ADdress Detected */
+#define IOP3XX_ISR_GCAD		0x0100	/* 1=General Call Address Detected */
+#define IOP3XX_ISR_RXFULL	0x0080	/* 1=Receive Full */
+#define IOP3XX_ISR_TXEMPTY	0x0040	/* 1=Transmit Empty */
+#define IOP3XX_ISR_ALD		0x0020	/* 1=Arbitration Loss Detected */
+#define IOP3XX_ISR_SSD		0x0010	/* 1=Slave STOP Detected */
+#define IOP3XX_ISR_BBUSY	0x0008	/* 1=Bus BUSY */
+#define IOP3XX_ISR_UNITBUSY	0x0004	/* 1=Unit Busy */
+#define IOP3XX_ISR_NACK		0x0002	/* 1=Unit Rx or Tx a NACK */
+#define IOP3XX_ISR_RXREAD	0x0001	/* 1=READ 0=WRITE (R/W bit of slave addr */
+
+#define IOP3XX_ISR_CLEARBITS	0x07f0
+
+#define IOP3XX_ISAR_SAMASK	0x007f
+
+#define IOP3XX_IDBR_MASK	0x00ff
+
+#define IOP3XX_IBMR_SCL		0x0002
+#define IOP3XX_IBMR_SDA		0x0001
+
+#define IOP3XX_GPOD_I2C0	0x00c0	/* clear these bits to enable ch0 */
+#define IOP3XX_GPOD_I2C1	0x0030	/* clear these bits to enable ch1 */
+
+#define MYSAR			0	/* default slave address */
+
+#define I2C_ERR			321
+#define I2C_ERR_BERR		(I2C_ERR+0)
+#define I2C_ERR_ALD		(I2C_ERR+1)
+
+
+#define	CR_OFFSET		0
+#define	SR_OFFSET		0x4
+#define	SAR_OFFSET		0x8
+#define	DBR_OFFSET		0xc
+#define	CCR_OFFSET		0x10
+#define	BMR_OFFSET		0x14
+
+#define	IOP3XX_I2C_IO_SIZE	0x18
+
+struct i2c_algo_iop3xx_data {
+	void __iomem *ioaddr;
+	wait_queue_head_t waitq;
+	spinlock_t lock;
+	u32 SR_enabled, SR_received;
+	int id;
+};
+
+#endif /* I2C_IOP3XX_H */
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-isch.c b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-isch.c
new file mode 100644
index 0000000..f90a605
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-isch.c
@@ -0,0 +1,314 @@
+/*
+    i2c-isch.c - Linux kernel driver for Intel SCH chipset SMBus
+    - Based on i2c-piix4.c
+    Copyright (c) 1998 - 2002 Frodo Looijaard <frodol@dds.nl> and
+    Philip Edelbrock <phil@netroedge.com>
+    - Intel SCH support
+    Copyright (c) 2007 - 2008 Jacob Jun Pan <jacob.jun.pan@intel.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License version 2 as
+    published by the Free Software Foundation.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/*
+   Supports:
+	Intel SCH chipsets (AF82US15W, AF82US15L, AF82UL11L)
+   Note: we assume there can only be one device, with one SMBus interface.
+*/
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/stddef.h>
+#include <linux/ioport.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/acpi.h>
+
+/* SCH SMBus address offsets */
+#define SMBHSTCNT	(0 + sch_smba)
+#define SMBHSTSTS	(1 + sch_smba)
+#define SMBHSTADD	(4 + sch_smba) /* TSA */
+#define SMBHSTCMD	(5 + sch_smba)
+#define SMBHSTDAT0	(6 + sch_smba)
+#define SMBHSTDAT1	(7 + sch_smba)
+#define SMBBLKDAT	(0x20 + sch_smba)
+
+/* Other settings */
+#define MAX_RETRIES	5000
+
+/* I2C constants */
+#define SCH_QUICK		0x00
+#define SCH_BYTE		0x01
+#define SCH_BYTE_DATA		0x02
+#define SCH_WORD_DATA		0x03
+#define SCH_BLOCK_DATA		0x05
+
+static unsigned short sch_smba;
+static struct i2c_adapter sch_adapter;
+
+/*
+ * Start the i2c transaction -- the i2c_access will prepare the transaction
+ * and this function will execute it.
+ * return 0 for success and others for failure.
+ */
+static int sch_transaction(void)
+{
+	int temp;
+	int result = 0;
+	int retries = 0;
+
+	dev_dbg(&sch_adapter.dev, "Transaction (pre): CNT=%02x, CMD=%02x, "
+		"ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb(SMBHSTCNT),
+		inb(SMBHSTCMD), inb(SMBHSTADD), inb(SMBHSTDAT0),
+		inb(SMBHSTDAT1));
+
+	/* Make sure the SMBus host is ready to start transmitting */
+	temp = inb(SMBHSTSTS) & 0x0f;
+	if (temp) {
+		/* Can not be busy since we checked it in sch_access */
+		if (temp & 0x01) {
+			dev_dbg(&sch_adapter.dev, "Completion (%02x). "
+				"Clear...\n", temp);
+		}
+		if (temp & 0x06) {
+			dev_dbg(&sch_adapter.dev, "SMBus error (%02x). "
+				"Resetting...\n", temp);
+		}
+		outb(temp, SMBHSTSTS);
+		temp = inb(SMBHSTSTS) & 0x0f;
+		if (temp) {
+			dev_err(&sch_adapter.dev,
+				"SMBus is not ready: (%02x)\n", temp);
+			return -EAGAIN;
+		}
+	}
+
+	/* start the transaction by setting bit 4 */
+	outb(inb(SMBHSTCNT) | 0x10, SMBHSTCNT);
+
+	do {
+		usleep_range(100, 200);
+		temp = inb(SMBHSTSTS) & 0x0f;
+	} while ((temp & 0x08) && (retries++ < MAX_RETRIES));
+
+	/* If the SMBus is still busy, we give up */
+	if (retries > MAX_RETRIES) {
+		dev_err(&sch_adapter.dev, "SMBus Timeout!\n");
+		result = -ETIMEDOUT;
+	}
+	if (temp & 0x04) {
+		result = -EIO;
+		dev_dbg(&sch_adapter.dev, "Bus collision! SMBus may be "
+			"locked until next hard reset. (sorry!)\n");
+		/* Clock stops and slave is stuck in mid-transmission */
+	} else if (temp & 0x02) {
+		result = -EIO;
+		dev_err(&sch_adapter.dev, "Error: no response!\n");
+	} else if (temp & 0x01) {
+		dev_dbg(&sch_adapter.dev, "Post complete!\n");
+		outb(temp, SMBHSTSTS);
+		temp = inb(SMBHSTSTS) & 0x07;
+		if (temp & 0x06) {
+			/* Completion clear failed */
+			dev_dbg(&sch_adapter.dev, "Failed reset at end of "
+				"transaction (%02x), Bus error!\n", temp);
+		}
+	} else {
+		result = -ENXIO;
+		dev_dbg(&sch_adapter.dev, "No such address.\n");
+	}
+	dev_dbg(&sch_adapter.dev, "Transaction (post): CNT=%02x, CMD=%02x, "
+		"ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb(SMBHSTCNT),
+		inb(SMBHSTCMD), inb(SMBHSTADD), inb(SMBHSTDAT0),
+		inb(SMBHSTDAT1));
+	return result;
+}
+
+/*
+ * This is the main access entry for i2c-sch access
+ * adap is i2c_adapter pointer, addr is the i2c device bus address, read_write
+ * (0 for read and 1 for write), size is i2c transaction type and data is the
+ * union of transaction for data to be transferred or data read from bus.
+ * return 0 for success and others for failure.
+ */
+static s32 sch_access(struct i2c_adapter *adap, u16 addr,
+		 unsigned short flags, char read_write,
+		 u8 command, int size, union i2c_smbus_data *data)
+{
+	int i, len, temp, rc;
+
+	/* Make sure the SMBus host is not busy */
+	temp = inb(SMBHSTSTS) & 0x0f;
+	if (temp & 0x08) {
+		dev_dbg(&sch_adapter.dev, "SMBus busy (%02x)\n", temp);
+		return -EAGAIN;
+	}
+	dev_dbg(&sch_adapter.dev, "access size: %d %s\n", size,
+		(read_write)?"READ":"WRITE");
+	switch (size) {
+	case I2C_SMBUS_QUICK:
+		outb((addr << 1) | read_write, SMBHSTADD);
+		size = SCH_QUICK;
+		break;
+	case I2C_SMBUS_BYTE:
+		outb((addr << 1) | read_write, SMBHSTADD);
+		if (read_write == I2C_SMBUS_WRITE)
+			outb(command, SMBHSTCMD);
+		size = SCH_BYTE;
+		break;
+	case I2C_SMBUS_BYTE_DATA:
+		outb((addr << 1) | read_write, SMBHSTADD);
+		outb(command, SMBHSTCMD);
+		if (read_write == I2C_SMBUS_WRITE)
+			outb(data->byte, SMBHSTDAT0);
+		size = SCH_BYTE_DATA;
+		break;
+	case I2C_SMBUS_WORD_DATA:
+		outb((addr << 1) | read_write, SMBHSTADD);
+		outb(command, SMBHSTCMD);
+		if (read_write == I2C_SMBUS_WRITE) {
+			outb(data->word & 0xff, SMBHSTDAT0);
+			outb((data->word & 0xff00) >> 8, SMBHSTDAT1);
+		}
+		size = SCH_WORD_DATA;
+		break;
+	case I2C_SMBUS_BLOCK_DATA:
+		outb((addr << 1) | read_write, SMBHSTADD);
+		outb(command, SMBHSTCMD);
+		if (read_write == I2C_SMBUS_WRITE) {
+			len = data->block[0];
+			if (len == 0 || len > I2C_SMBUS_BLOCK_MAX)
+				return -EINVAL;
+			outb(len, SMBHSTDAT0);
+			for (i = 1; i <= len; i++)
+				outb(data->block[i], SMBBLKDAT+i-1);
+		}
+		size = SCH_BLOCK_DATA;
+		break;
+	default:
+		dev_warn(&adap->dev, "Unsupported transaction %d\n", size);
+		return -EOPNOTSUPP;
+	}
+	dev_dbg(&sch_adapter.dev, "write size %d to 0x%04x\n", size, SMBHSTCNT);
+	outb((inb(SMBHSTCNT) & 0xb0) | (size & 0x7), SMBHSTCNT);
+
+	rc = sch_transaction();
+	if (rc)	/* Error in transaction */
+		return rc;
+
+	if ((read_write == I2C_SMBUS_WRITE) || (size == SCH_QUICK))
+		return 0;
+
+	switch (size) {
+	case SCH_BYTE:
+	case SCH_BYTE_DATA:
+		data->byte = inb(SMBHSTDAT0);
+		break;
+	case SCH_WORD_DATA:
+		data->word = inb(SMBHSTDAT0) + (inb(SMBHSTDAT1) << 8);
+		break;
+	case SCH_BLOCK_DATA:
+		data->block[0] = inb(SMBHSTDAT0);
+		if (data->block[0] == 0 || data->block[0] > I2C_SMBUS_BLOCK_MAX)
+			return -EPROTO;
+		for (i = 1; i <= data->block[0]; i++)
+			data->block[i] = inb(SMBBLKDAT+i-1);
+		break;
+	}
+	return 0;
+}
+
+static u32 sch_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+	    I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+	    I2C_FUNC_SMBUS_BLOCK_DATA;
+}
+
+static const struct i2c_algorithm smbus_algorithm = {
+	.smbus_xfer	= sch_access,
+	.functionality	= sch_func,
+};
+
+static struct i2c_adapter sch_adapter = {
+	.owner		= THIS_MODULE,
+	.class		= I2C_CLASS_HWMON | I2C_CLASS_SPD,
+	.algo		= &smbus_algorithm,
+};
+
+static int __devinit smbus_sch_probe(struct platform_device *dev)
+{
+	struct resource *res;
+	int retval;
+
+	res = platform_get_resource(dev, IORESOURCE_IO, 0);
+	if (!res)
+		return -EBUSY;
+
+	if (!request_region(res->start, resource_size(res), dev->name)) {
+		dev_err(&dev->dev, "SMBus region 0x%x already in use!\n",
+			sch_smba);
+		return -EBUSY;
+	}
+
+	sch_smba = res->start;
+
+	dev_dbg(&dev->dev, "SMBA = 0x%X\n", sch_smba);
+
+	/* set up the sysfs linkage to our parent device */
+	sch_adapter.dev.parent = &dev->dev;
+
+	snprintf(sch_adapter.name, sizeof(sch_adapter.name),
+		"SMBus SCH adapter at %04x", sch_smba);
+
+	retval = i2c_add_adapter(&sch_adapter);
+	if (retval) {
+		dev_err(&dev->dev, "Couldn't register adapter!\n");
+		release_region(res->start, resource_size(res));
+		sch_smba = 0;
+	}
+
+	return retval;
+}
+
+static int __devexit smbus_sch_remove(struct platform_device *pdev)
+{
+	struct resource *res;
+	if (sch_smba) {
+		i2c_del_adapter(&sch_adapter);
+		res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+		release_region(res->start, resource_size(res));
+		sch_smba = 0;
+	}
+
+	return 0;
+}
+
+static struct platform_driver smbus_sch_driver = {
+	.driver = {
+		.name = "isch_smbus",
+		.owner = THIS_MODULE,
+	},
+	.probe		= smbus_sch_probe,
+	.remove		= __devexit_p(smbus_sch_remove),
+};
+
+module_platform_driver(smbus_sch_driver);
+
+MODULE_AUTHOR("Jacob Pan <jacob.jun.pan@intel.com>");
+MODULE_DESCRIPTION("Intel SCH SMBus driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:isch_smbus");
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-ixp2000.c b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-ixp2000.c
new file mode 100644
index 0000000..5d263f9
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-ixp2000.c
@@ -0,0 +1,157 @@
+/*
+ * drivers/i2c/busses/i2c-ixp2000.c
+ *
+ * I2C adapter for IXP2000 systems using GPIOs for I2C bus
+ *
+ * Author: Deepak Saxena <dsaxena@plexity.net>
+ * Based on IXDP2400 code by: Naeem M. Afzal <naeem.m.afzal@intel.com>
+ * Made generic by: Jeff Daly <jeffrey.daly@intel.com>
+ *
+ * Copyright (c) 2003-2004 MontaVista Software Inc.
+ *
+ * This file is licensed under  the terms of the GNU General Public 
+ * License version 2. This program is licensed "as is" without any 
+ * warranty of any kind, whether express or implied.
+ *
+ * From Jeff Daly:
+ *
+ * I2C adapter driver for Intel IXDP2xxx platforms. This should work for any
+ * IXP2000 platform if it uses the HW GPIO in the same manner.  Basically, 
+ * SDA and SCL GPIOs have external pullups.  Setting the respective GPIO to 
+ * an input will make the signal a '1' via the pullup.  Setting them to 
+ * outputs will pull them down. 
+ *
+ * The GPIOs are open drain signals and are used as configuration strap inputs
+ * during power-up so there's generally a buffer on the board that needs to be 
+ * 'enabled' to drive the GPIOs.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <linux/slab.h>
+
+#include <mach/hardware.h>	/* Pick up IXP2000-specific bits */
+#include <mach/gpio-ixp2000.h>
+
+static inline int ixp2000_scl_pin(void *data)
+{
+	return ((struct ixp2000_i2c_pins*)data)->scl_pin;
+}
+
+static inline int ixp2000_sda_pin(void *data)
+{
+	return ((struct ixp2000_i2c_pins*)data)->sda_pin;
+}
+
+
+static void ixp2000_bit_setscl(void *data, int val)
+{
+	int i = 5000;
+
+	if (val) {
+		gpio_line_config(ixp2000_scl_pin(data), GPIO_IN);
+		while(!gpio_line_get(ixp2000_scl_pin(data)) && i--);
+	} else {
+		gpio_line_config(ixp2000_scl_pin(data), GPIO_OUT);
+	}
+}
+
+static void ixp2000_bit_setsda(void *data, int val)
+{
+	if (val) {
+		gpio_line_config(ixp2000_sda_pin(data), GPIO_IN);
+	} else {
+		gpio_line_config(ixp2000_sda_pin(data), GPIO_OUT);
+	}
+}
+
+static int ixp2000_bit_getscl(void *data)
+{
+	return gpio_line_get(ixp2000_scl_pin(data));
+}
+
+static int ixp2000_bit_getsda(void *data)
+{
+	return gpio_line_get(ixp2000_sda_pin(data));
+}
+
+struct ixp2000_i2c_data {
+	struct ixp2000_i2c_pins *gpio_pins;
+	struct i2c_adapter adapter;
+	struct i2c_algo_bit_data algo_data;
+};
+
+static int ixp2000_i2c_remove(struct platform_device *plat_dev)
+{
+	struct ixp2000_i2c_data *drv_data = platform_get_drvdata(plat_dev);
+
+	platform_set_drvdata(plat_dev, NULL);
+
+	i2c_del_adapter(&drv_data->adapter);
+
+	kfree(drv_data);
+
+	return 0;
+}
+
+static int ixp2000_i2c_probe(struct platform_device *plat_dev)
+{
+	int err;
+	struct ixp2000_i2c_pins *gpio = plat_dev->dev.platform_data;
+	struct ixp2000_i2c_data *drv_data = 
+		kzalloc(sizeof(struct ixp2000_i2c_data), GFP_KERNEL);
+
+	if (!drv_data)
+		return -ENOMEM;
+	drv_data->gpio_pins = gpio;
+
+	drv_data->algo_data.data = gpio;
+	drv_data->algo_data.setsda = ixp2000_bit_setsda;
+	drv_data->algo_data.setscl = ixp2000_bit_setscl;
+	drv_data->algo_data.getsda = ixp2000_bit_getsda;
+	drv_data->algo_data.getscl = ixp2000_bit_getscl;
+	drv_data->algo_data.udelay = 6;
+	drv_data->algo_data.timeout = HZ;
+
+	strlcpy(drv_data->adapter.name, plat_dev->dev.driver->name,
+		sizeof(drv_data->adapter.name));
+	drv_data->adapter.algo_data = &drv_data->algo_data,
+
+	drv_data->adapter.dev.parent = &plat_dev->dev;
+
+	gpio_line_config(gpio->sda_pin, GPIO_IN);
+	gpio_line_config(gpio->scl_pin, GPIO_IN);
+	gpio_line_set(gpio->scl_pin, 0);
+	gpio_line_set(gpio->sda_pin, 0);
+
+	if ((err = i2c_bit_add_bus(&drv_data->adapter)) != 0) {
+		dev_err(&plat_dev->dev, "Could not install, error %d\n", err);
+		kfree(drv_data);
+		return err;
+	} 
+
+	platform_set_drvdata(plat_dev, drv_data);
+
+	return 0;
+}
+
+static struct platform_driver ixp2000_i2c_driver = {
+	.probe		= ixp2000_i2c_probe,
+	.remove		= ixp2000_i2c_remove,
+	.driver		= {
+		.name	= "IXP2000-I2C",
+		.owner	= THIS_MODULE,
+	},
+};
+
+module_platform_driver(ixp2000_i2c_driver);
+
+MODULE_AUTHOR ("Deepak Saxena <dsaxena@plexity.net>");
+MODULE_DESCRIPTION("IXP2000 GPIO-based I2C bus driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:IXP2000-I2C");
+
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-mpc.c b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-mpc.c
new file mode 100644
index 0000000..206caac
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-mpc.c
@@ -0,0 +1,758 @@
+/*
+ * (C) Copyright 2003-2004
+ * Humboldt Solutions Ltd, adrian@humboldt.co.uk.
+
+ * This is a combined i2c adapter and algorithm driver for the
+ * MPC107/Tsi107 PowerPC northbridge and processors that include
+ * the same I2C unit (8240, 8245, 85xx).
+ *
+ * Release 0.8
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/of_platform.h>
+#include <linux/of_i2c.h>
+#include <linux/slab.h>
+
+#include <linux/io.h>
+#include <linux/fsl_devices.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+
+#include <asm/mpc52xx.h>
+#include <sysdev/fsl_soc.h>
+
+#define DRV_NAME "mpc-i2c"
+
+#define MPC_I2C_CLOCK_LEGACY   0
+#define MPC_I2C_CLOCK_PRESERVE (~0U)
+
+#define MPC_I2C_FDR   0x04
+#define MPC_I2C_CR    0x08
+#define MPC_I2C_SR    0x0c
+#define MPC_I2C_DR    0x10
+#define MPC_I2C_DFSRR 0x14
+
+#define CCR_MEN  0x80
+#define CCR_MIEN 0x40
+#define CCR_MSTA 0x20
+#define CCR_MTX  0x10
+#define CCR_TXAK 0x08
+#define CCR_RSTA 0x04
+
+#define CSR_MCF  0x80
+#define CSR_MAAS 0x40
+#define CSR_MBB  0x20
+#define CSR_MAL  0x10
+#define CSR_SRW  0x04
+#define CSR_MIF  0x02
+#define CSR_RXAK 0x01
+
+struct mpc_i2c {
+	struct device *dev;
+	void __iomem *base;
+	u32 interrupt;
+	wait_queue_head_t queue;
+	struct i2c_adapter adap;
+	int irq;
+	u32 real_clk;
+};
+
+struct mpc_i2c_divider {
+	u16 divider;
+	u16 fdr;	/* including dfsrr */
+};
+
+struct mpc_i2c_data {
+	void (*setup)(struct device_node *node, struct mpc_i2c *i2c,
+		      u32 clock, u32 prescaler);
+	u32 prescaler;
+};
+
+static inline void writeccr(struct mpc_i2c *i2c, u32 x)
+{
+	writeb(x, i2c->base + MPC_I2C_CR);
+}
+
+static irqreturn_t mpc_i2c_isr(int irq, void *dev_id)
+{
+	struct mpc_i2c *i2c = dev_id;
+	if (readb(i2c->base + MPC_I2C_SR) & CSR_MIF) {
+		/* Read again to allow register to stabilise */
+		i2c->interrupt = readb(i2c->base + MPC_I2C_SR);
+		writeb(0, i2c->base + MPC_I2C_SR);
+		wake_up(&i2c->queue);
+	}
+	return IRQ_HANDLED;
+}
+
+/* Sometimes 9th clock pulse isn't generated, and slave doesn't release
+ * the bus, because it wants to send ACK.
+ * Following sequence of enabling/disabling and sending start/stop generates
+ * the 9 pulses, so it's all OK.
+ */
+static void mpc_i2c_fixup(struct mpc_i2c *i2c)
+{
+	int k;
+	u32 delay_val = 1000000 / i2c->real_clk + 1;
+
+	if (delay_val < 2)
+		delay_val = 2;
+
+	for (k = 9; k; k--) {
+		writeccr(i2c, 0);
+		writeccr(i2c, CCR_MSTA | CCR_MTX | CCR_MEN);
+		udelay(delay_val);
+		writeccr(i2c, CCR_MEN);
+		udelay(delay_val << 1);
+	}
+}
+
+static int i2c_wait(struct mpc_i2c *i2c, unsigned timeout, int writing)
+{
+	unsigned long orig_jiffies = jiffies;
+	u32 x;
+	int result = 0;
+
+	if (!i2c->irq) {
+		while (!(readb(i2c->base + MPC_I2C_SR) & CSR_MIF)) {
+			schedule();
+			if (time_after(jiffies, orig_jiffies + timeout)) {
+				dev_dbg(i2c->dev, "timeout\n");
+				writeccr(i2c, 0);
+				result = -EIO;
+				break;
+			}
+		}
+		x = readb(i2c->base + MPC_I2C_SR);
+		writeb(0, i2c->base + MPC_I2C_SR);
+	} else {
+		/* Interrupt mode */
+		result = wait_event_timeout(i2c->queue,
+			(i2c->interrupt & CSR_MIF), timeout);
+
+		if (unlikely(!(i2c->interrupt & CSR_MIF))) {
+			dev_dbg(i2c->dev, "wait timeout\n");
+			writeccr(i2c, 0);
+			result = -ETIMEDOUT;
+		}
+
+		x = i2c->interrupt;
+		i2c->interrupt = 0;
+	}
+
+	if (result < 0)
+		return result;
+
+	if (!(x & CSR_MCF)) {
+		dev_dbg(i2c->dev, "unfinished\n");
+		return -EIO;
+	}
+
+	if (x & CSR_MAL) {
+		dev_dbg(i2c->dev, "MAL\n");
+		return -EIO;
+	}
+
+	if (writing && (x & CSR_RXAK)) {
+		dev_dbg(i2c->dev, "No RXAK\n");
+		/* generate stop */
+		writeccr(i2c, CCR_MEN);
+		return -EIO;
+	}
+	return 0;
+}
+
+#if defined(CONFIG_PPC_MPC52xx) || defined(CONFIG_PPC_MPC512x)
+static const struct mpc_i2c_divider mpc_i2c_dividers_52xx[] __devinitconst = {
+	{20, 0x20}, {22, 0x21}, {24, 0x22}, {26, 0x23},
+	{28, 0x24}, {30, 0x01}, {32, 0x25}, {34, 0x02},
+	{36, 0x26}, {40, 0x27}, {44, 0x04}, {48, 0x28},
+	{52, 0x63}, {56, 0x29}, {60, 0x41}, {64, 0x2a},
+	{68, 0x07}, {72, 0x2b}, {80, 0x2c}, {88, 0x09},
+	{96, 0x2d}, {104, 0x0a}, {112, 0x2e}, {120, 0x81},
+	{128, 0x2f}, {136, 0x47}, {144, 0x0c}, {160, 0x30},
+	{176, 0x49}, {192, 0x31}, {208, 0x4a}, {224, 0x32},
+	{240, 0x0f}, {256, 0x33}, {272, 0x87}, {288, 0x10},
+	{320, 0x34}, {352, 0x89}, {384, 0x35}, {416, 0x8a},
+	{448, 0x36}, {480, 0x13}, {512, 0x37}, {576, 0x14},
+	{640, 0x38}, {768, 0x39}, {896, 0x3a}, {960, 0x17},
+	{1024, 0x3b}, {1152, 0x18}, {1280, 0x3c}, {1536, 0x3d},
+	{1792, 0x3e}, {1920, 0x1b}, {2048, 0x3f}, {2304, 0x1c},
+	{2560, 0x1d}, {3072, 0x1e}, {3584, 0x7e}, {3840, 0x1f},
+	{4096, 0x7f}, {4608, 0x5c}, {5120, 0x5d}, {6144, 0x5e},
+	{7168, 0xbe}, {7680, 0x5f}, {8192, 0xbf}, {9216, 0x9c},
+	{10240, 0x9d}, {12288, 0x9e}, {15360, 0x9f}
+};
+
+static int __devinit mpc_i2c_get_fdr_52xx(struct device_node *node, u32 clock,
+					  int prescaler, u32 *real_clk)
+{
+	const struct mpc_i2c_divider *div = NULL;
+	unsigned int pvr = mfspr(SPRN_PVR);
+	u32 divider;
+	int i;
+
+	if (clock == MPC_I2C_CLOCK_LEGACY) {
+		/* see below - default fdr = 0x3f -> div = 2048 */
+		*real_clk = mpc5xxx_get_bus_frequency(node) / 2048;
+		return -EINVAL;
+	}
+
+	/* Determine divider value */
+	divider = mpc5xxx_get_bus_frequency(node) / clock;
+
+	/*
+	 * We want to choose an FDR/DFSR that generates an I2C bus speed that
+	 * is equal to or lower than the requested speed.
+	 */
+	for (i = 0; i < ARRAY_SIZE(mpc_i2c_dividers_52xx); i++) {
+		div = &mpc_i2c_dividers_52xx[i];
+		/* Old MPC5200 rev A CPUs do not support the high bits */
+		if (div->fdr & 0xc0 && pvr == 0x80822011)
+			continue;
+		if (div->divider >= divider)
+			break;
+	}
+
+	*real_clk = mpc5xxx_get_bus_frequency(node) / div->divider;
+	return (int)div->fdr;
+}
+
+static void __devinit mpc_i2c_setup_52xx(struct device_node *node,
+					 struct mpc_i2c *i2c,
+					 u32 clock, u32 prescaler)
+{
+	int ret, fdr;
+
+	if (clock == MPC_I2C_CLOCK_PRESERVE) {
+		dev_dbg(i2c->dev, "using fdr %d\n",
+			readb(i2c->base + MPC_I2C_FDR));
+		return;
+	}
+
+	ret = mpc_i2c_get_fdr_52xx(node, clock, prescaler, &i2c->real_clk);
+	fdr = (ret >= 0) ? ret : 0x3f; /* backward compatibility */
+
+	writeb(fdr & 0xff, i2c->base + MPC_I2C_FDR);
+
+	if (ret >= 0)
+		dev_info(i2c->dev, "clock %u Hz (fdr=%d)\n", i2c->real_clk,
+			 fdr);
+}
+#else /* !(CONFIG_PPC_MPC52xx || CONFIG_PPC_MPC512x) */
+static void __devinit mpc_i2c_setup_52xx(struct device_node *node,
+					 struct mpc_i2c *i2c,
+					 u32 clock, u32 prescaler)
+{
+}
+#endif /* CONFIG_PPC_MPC52xx || CONFIG_PPC_MPC512x */
+
+#ifdef CONFIG_PPC_MPC512x
+static void __devinit mpc_i2c_setup_512x(struct device_node *node,
+					 struct mpc_i2c *i2c,
+					 u32 clock, u32 prescaler)
+{
+	struct device_node *node_ctrl;
+	void __iomem *ctrl;
+	const u32 *pval;
+	u32 idx;
+
+	/* Enable I2C interrupts for mpc5121 */
+	node_ctrl = of_find_compatible_node(NULL, NULL,
+					    "fsl,mpc5121-i2c-ctrl");
+	if (node_ctrl) {
+		ctrl = of_iomap(node_ctrl, 0);
+		if (ctrl) {
+			/* Interrupt enable bits for i2c-0/1/2: bit 24/26/28 */
+			pval = of_get_property(node, "reg", NULL);
+			idx = (*pval & 0xff) / 0x20;
+			setbits32(ctrl, 1 << (24 + idx * 2));
+			iounmap(ctrl);
+		}
+		of_node_put(node_ctrl);
+	}
+
+	/* The clock setup for the 52xx works also fine for the 512x */
+	mpc_i2c_setup_52xx(node, i2c, clock, prescaler);
+}
+#else /* CONFIG_PPC_MPC512x */
+static void __devinit mpc_i2c_setup_512x(struct device_node *node,
+					 struct mpc_i2c *i2c,
+					 u32 clock, u32 prescaler)
+{
+}
+#endif /* CONFIG_PPC_MPC512x */
+
+#ifdef CONFIG_FSL_SOC
+static const struct mpc_i2c_divider mpc_i2c_dividers_8xxx[] __devinitconst = {
+	{160, 0x0120}, {192, 0x0121}, {224, 0x0122}, {256, 0x0123},
+	{288, 0x0100}, {320, 0x0101}, {352, 0x0601}, {384, 0x0102},
+	{416, 0x0602}, {448, 0x0126}, {480, 0x0103}, {512, 0x0127},
+	{544, 0x0b03}, {576, 0x0104}, {608, 0x1603}, {640, 0x0105},
+	{672, 0x2003}, {704, 0x0b05}, {736, 0x2b03}, {768, 0x0106},
+	{800, 0x3603}, {832, 0x0b06}, {896, 0x012a}, {960, 0x0107},
+	{1024, 0x012b}, {1088, 0x1607}, {1152, 0x0108}, {1216, 0x2b07},
+	{1280, 0x0109}, {1408, 0x1609}, {1536, 0x010a}, {1664, 0x160a},
+	{1792, 0x012e}, {1920, 0x010b}, {2048, 0x012f}, {2176, 0x2b0b},
+	{2304, 0x010c}, {2560, 0x010d}, {2816, 0x2b0d}, {3072, 0x010e},
+	{3328, 0x2b0e}, {3584, 0x0132}, {3840, 0x010f}, {4096, 0x0133},
+	{4608, 0x0110}, {5120, 0x0111}, {6144, 0x0112}, {7168, 0x0136},
+	{7680, 0x0113}, {8192, 0x0137}, {9216, 0x0114}, {10240, 0x0115},
+	{12288, 0x0116}, {14336, 0x013a}, {15360, 0x0117}, {16384, 0x013b},
+	{18432, 0x0118}, {20480, 0x0119}, {24576, 0x011a}, {28672, 0x013e},
+	{30720, 0x011b}, {32768, 0x013f}, {36864, 0x011c}, {40960, 0x011d},
+	{49152, 0x011e}, {61440, 0x011f}
+};
+
+static u32 __devinit mpc_i2c_get_sec_cfg_8xxx(void)
+{
+	struct device_node *node = NULL;
+	u32 __iomem *reg;
+	u32 val = 0;
+
+	node = of_find_node_by_name(NULL, "global-utilities");
+	if (node) {
+		const u32 *prop = of_get_property(node, "reg", NULL);
+		if (prop) {
+			/*
+			 * Map and check POR Device Status Register 2
+			 * (PORDEVSR2) at 0xE0014
+			 */
+			reg = ioremap(get_immrbase() + *prop + 0x14, 0x4);
+			if (!reg)
+				printk(KERN_ERR
+				       "Error: couldn't map PORDEVSR2\n");
+			else
+				val = in_be32(reg) & 0x00000080; /* sec-cfg */
+			iounmap(reg);
+		}
+	}
+	if (node)
+		of_node_put(node);
+
+	return val;
+}
+
+static int __devinit mpc_i2c_get_fdr_8xxx(struct device_node *node, u32 clock,
+					  u32 prescaler, u32 *real_clk)
+{
+	const struct mpc_i2c_divider *div = NULL;
+	u32 divider;
+	int i;
+
+	if (clock == MPC_I2C_CLOCK_LEGACY) {
+		/* see below - default fdr = 0x1031 -> div = 16 * 3072 */
+		*real_clk = fsl_get_sys_freq() / prescaler / (16 * 3072);
+		return -EINVAL;
+	}
+
+	/* Determine proper divider value */
+	if (of_device_is_compatible(node, "fsl,mpc8544-i2c"))
+		prescaler = mpc_i2c_get_sec_cfg_8xxx() ? 3 : 2;
+	if (!prescaler)
+		prescaler = 1;
+
+	divider = fsl_get_sys_freq() / clock / prescaler;
+
+	pr_debug("I2C: src_clock=%d clock=%d divider=%d\n",
+		 fsl_get_sys_freq(), clock, divider);
+
+	/*
+	 * We want to choose an FDR/DFSR that generates an I2C bus speed that
+	 * is equal to or lower than the requested speed.
+	 */
+	for (i = 0; i < ARRAY_SIZE(mpc_i2c_dividers_8xxx); i++) {
+		div = &mpc_i2c_dividers_8xxx[i];
+		if (div->divider >= divider)
+			break;
+	}
+
+	*real_clk = fsl_get_sys_freq() / prescaler / div->divider;
+	return div ? (int)div->fdr : -EINVAL;
+}
+
+static void __devinit mpc_i2c_setup_8xxx(struct device_node *node,
+					 struct mpc_i2c *i2c,
+					 u32 clock, u32 prescaler)
+{
+	int ret, fdr;
+
+	if (clock == MPC_I2C_CLOCK_PRESERVE) {
+		dev_dbg(i2c->dev, "using dfsrr %d, fdr %d\n",
+			readb(i2c->base + MPC_I2C_DFSRR),
+			readb(i2c->base + MPC_I2C_FDR));
+		return;
+	}
+
+	ret = mpc_i2c_get_fdr_8xxx(node, clock, prescaler, &i2c->real_clk);
+	fdr = (ret >= 0) ? ret : 0x1031; /* backward compatibility */
+
+	writeb(fdr & 0xff, i2c->base + MPC_I2C_FDR);
+	writeb((fdr >> 8) & 0xff, i2c->base + MPC_I2C_DFSRR);
+
+	if (ret >= 0)
+		dev_info(i2c->dev, "clock %d Hz (dfsrr=%d fdr=%d)\n",
+			 i2c->real_clk, fdr >> 8, fdr & 0xff);
+}
+
+#else /* !CONFIG_FSL_SOC */
+static void __devinit mpc_i2c_setup_8xxx(struct device_node *node,
+					 struct mpc_i2c *i2c,
+					 u32 clock, u32 prescaler)
+{
+}
+#endif /* CONFIG_FSL_SOC */
+
+static void mpc_i2c_start(struct mpc_i2c *i2c)
+{
+	/* Clear arbitration */
+	writeb(0, i2c->base + MPC_I2C_SR);
+	/* Start with MEN */
+	writeccr(i2c, CCR_MEN);
+}
+
+static void mpc_i2c_stop(struct mpc_i2c *i2c)
+{
+	writeccr(i2c, CCR_MEN);
+}
+
+static int mpc_write(struct mpc_i2c *i2c, int target,
+		     const u8 *data, int length, int restart)
+{
+	int i, result;
+	unsigned timeout = i2c->adap.timeout;
+	u32 flags = restart ? CCR_RSTA : 0;
+
+	/* Start as master */
+	writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_MTX | flags);
+	/* Write target byte */
+	writeb((target << 1), i2c->base + MPC_I2C_DR);
+
+	result = i2c_wait(i2c, timeout, 1);
+	if (result < 0)
+		return result;
+
+	for (i = 0; i < length; i++) {
+		/* Write data byte */
+		writeb(data[i], i2c->base + MPC_I2C_DR);
+
+		result = i2c_wait(i2c, timeout, 1);
+		if (result < 0)
+			return result;
+	}
+
+	return 0;
+}
+
+static int mpc_read(struct mpc_i2c *i2c, int target,
+		    u8 *data, int length, int restart, bool recv_len)
+{
+	unsigned timeout = i2c->adap.timeout;
+	int i, result;
+	u32 flags = restart ? CCR_RSTA : 0;
+
+	/* Switch to read - restart */
+	writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_MTX | flags);
+	/* Write target address byte - this time with the read flag set */
+	writeb((target << 1) | 1, i2c->base + MPC_I2C_DR);
+
+	result = i2c_wait(i2c, timeout, 1);
+	if (result < 0)
+		return result;
+
+	if (length) {
+		if (length == 1 && !recv_len)
+			writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_TXAK);
+		else
+			writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA);
+		/* Dummy read */
+		readb(i2c->base + MPC_I2C_DR);
+	}
+
+	for (i = 0; i < length; i++) {
+		u8 byte;
+
+		result = i2c_wait(i2c, timeout, 0);
+		if (result < 0)
+			return result;
+
+		/*
+		 * For block reads, we have to know the total length (1st byte)
+		 * before we can determine if we are done.
+		 */
+		if (i || !recv_len) {
+			/* Generate txack on next to last byte */
+			if (i == length - 2)
+				writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA
+					 | CCR_TXAK);
+			/* Do not generate stop on last byte */
+			if (i == length - 1)
+				writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA
+					 | CCR_MTX);
+		}
+
+		byte = readb(i2c->base + MPC_I2C_DR);
+
+		/*
+		 * Adjust length if first received byte is length.
+		 * The length is 1 length byte plus actually data length
+		 */
+		if (i == 0 && recv_len) {
+			if (byte == 0 || byte > I2C_SMBUS_BLOCK_MAX)
+				return -EPROTO;
+			length += byte;
+			/*
+			 * For block reads, generate txack here if data length
+			 * is 1 byte (total length is 2 bytes).
+			 */
+			if (length == 2)
+				writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA
+					 | CCR_TXAK);
+		}
+		data[i] = byte;
+	}
+
+	return length;
+}
+
+static int mpc_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+{
+	struct i2c_msg *pmsg;
+	int i;
+	int ret = 0;
+	unsigned long orig_jiffies = jiffies;
+	struct mpc_i2c *i2c = i2c_get_adapdata(adap);
+
+	mpc_i2c_start(i2c);
+
+	/* Allow bus up to 1s to become not busy */
+	while (readb(i2c->base + MPC_I2C_SR) & CSR_MBB) {
+		if (signal_pending(current)) {
+			dev_dbg(i2c->dev, "Interrupted\n");
+			writeccr(i2c, 0);
+			return -EINTR;
+		}
+		if (time_after(jiffies, orig_jiffies + HZ)) {
+			u8 status = readb(i2c->base + MPC_I2C_SR);
+
+			dev_dbg(i2c->dev, "timeout\n");
+			if ((status & (CSR_MCF | CSR_MBB | CSR_RXAK)) != 0) {
+				writeb(status & ~CSR_MAL,
+				       i2c->base + MPC_I2C_SR);
+				mpc_i2c_fixup(i2c);
+			}
+			return -EIO;
+		}
+		schedule();
+	}
+
+	for (i = 0; ret >= 0 && i < num; i++) {
+		pmsg = &msgs[i];
+		dev_dbg(i2c->dev,
+			"Doing %s %d bytes to 0x%02x - %d of %d messages\n",
+			pmsg->flags & I2C_M_RD ? "read" : "write",
+			pmsg->len, pmsg->addr, i + 1, num);
+		if (pmsg->flags & I2C_M_RD) {
+			bool recv_len = pmsg->flags & I2C_M_RECV_LEN;
+
+			ret = mpc_read(i2c, pmsg->addr, pmsg->buf, pmsg->len, i,
+				       recv_len);
+			if (recv_len && ret > 0)
+				pmsg->len = ret;
+		} else {
+			ret =
+			    mpc_write(i2c, pmsg->addr, pmsg->buf, pmsg->len, i);
+		}
+	}
+	mpc_i2c_stop(i2c);
+	return (ret < 0) ? ret : num;
+}
+
+static u32 mpc_functionality(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL
+	  | I2C_FUNC_SMBUS_READ_BLOCK_DATA | I2C_FUNC_SMBUS_BLOCK_PROC_CALL;
+}
+
+static const struct i2c_algorithm mpc_algo = {
+	.master_xfer = mpc_xfer,
+	.functionality = mpc_functionality,
+};
+
+static struct i2c_adapter mpc_ops = {
+	.owner = THIS_MODULE,
+	.name = "MPC adapter",
+	.algo = &mpc_algo,
+	.timeout = HZ,
+};
+
+static const struct of_device_id mpc_i2c_of_match[];
+static int __devinit fsl_i2c_probe(struct platform_device *op)
+{
+	const struct of_device_id *match;
+	struct mpc_i2c *i2c;
+	const u32 *prop;
+	u32 clock = MPC_I2C_CLOCK_LEGACY;
+	int result = 0;
+	int plen;
+
+	match = of_match_device(mpc_i2c_of_match, &op->dev);
+	if (!match)
+		return -EINVAL;
+
+	i2c = kzalloc(sizeof(*i2c), GFP_KERNEL);
+	if (!i2c)
+		return -ENOMEM;
+
+	i2c->dev = &op->dev; /* for debug and error output */
+
+	init_waitqueue_head(&i2c->queue);
+
+	i2c->base = of_iomap(op->dev.of_node, 0);
+	if (!i2c->base) {
+		dev_err(i2c->dev, "failed to map controller\n");
+		result = -ENOMEM;
+		goto fail_map;
+	}
+
+	i2c->irq = irq_of_parse_and_map(op->dev.of_node, 0);
+	if (i2c->irq) { /* no i2c->irq implies polling */
+		result = request_irq(i2c->irq, mpc_i2c_isr,
+				     IRQF_SHARED, "i2c-mpc", i2c);
+		if (result < 0) {
+			dev_err(i2c->dev, "failed to attach interrupt\n");
+			goto fail_request;
+		}
+	}
+
+	if (of_get_property(op->dev.of_node, "fsl,preserve-clocking", NULL)) {
+		clock = MPC_I2C_CLOCK_PRESERVE;
+	} else {
+		prop = of_get_property(op->dev.of_node, "clock-frequency",
+					&plen);
+		if (prop && plen == sizeof(u32))
+			clock = *prop;
+	}
+
+	if (match->data) {
+		struct mpc_i2c_data *data = match->data;
+		data->setup(op->dev.of_node, i2c, clock, data->prescaler);
+	} else {
+		/* Backwards compatibility */
+		if (of_get_property(op->dev.of_node, "dfsrr", NULL))
+			mpc_i2c_setup_8xxx(op->dev.of_node, i2c, clock, 0);
+	}
+
+	prop = of_get_property(op->dev.of_node, "fsl,timeout", &plen);
+	if (prop && plen == sizeof(u32)) {
+		mpc_ops.timeout = *prop * HZ / 1000000;
+		if (mpc_ops.timeout < 5)
+			mpc_ops.timeout = 5;
+	}
+	dev_info(i2c->dev, "timeout %u us\n", mpc_ops.timeout * 1000000 / HZ);
+
+	dev_set_drvdata(&op->dev, i2c);
+
+	i2c->adap = mpc_ops;
+	i2c_set_adapdata(&i2c->adap, i2c);
+	i2c->adap.dev.parent = &op->dev;
+	i2c->adap.dev.of_node = of_node_get(op->dev.of_node);
+
+	result = i2c_add_adapter(&i2c->adap);
+	if (result < 0) {
+		dev_err(i2c->dev, "failed to add adapter\n");
+		goto fail_add;
+	}
+	of_i2c_register_devices(&i2c->adap);
+
+	return result;
+
+ fail_add:
+	dev_set_drvdata(&op->dev, NULL);
+	free_irq(i2c->irq, i2c);
+ fail_request:
+	irq_dispose_mapping(i2c->irq);
+	iounmap(i2c->base);
+ fail_map:
+	kfree(i2c);
+	return result;
+};
+
+static int __devexit fsl_i2c_remove(struct platform_device *op)
+{
+	struct mpc_i2c *i2c = dev_get_drvdata(&op->dev);
+
+	i2c_del_adapter(&i2c->adap);
+	dev_set_drvdata(&op->dev, NULL);
+
+	if (i2c->irq)
+		free_irq(i2c->irq, i2c);
+
+	irq_dispose_mapping(i2c->irq);
+	iounmap(i2c->base);
+	kfree(i2c);
+	return 0;
+};
+
+static struct mpc_i2c_data mpc_i2c_data_512x __devinitdata = {
+	.setup = mpc_i2c_setup_512x,
+};
+
+static struct mpc_i2c_data mpc_i2c_data_52xx __devinitdata = {
+	.setup = mpc_i2c_setup_52xx,
+};
+
+static struct mpc_i2c_data mpc_i2c_data_8313 __devinitdata = {
+	.setup = mpc_i2c_setup_8xxx,
+};
+
+static struct mpc_i2c_data mpc_i2c_data_8543 __devinitdata = {
+	.setup = mpc_i2c_setup_8xxx,
+	.prescaler = 2,
+};
+
+static struct mpc_i2c_data mpc_i2c_data_8544 __devinitdata = {
+	.setup = mpc_i2c_setup_8xxx,
+	.prescaler = 3,
+};
+
+static const struct of_device_id mpc_i2c_of_match[] = {
+	{.compatible = "mpc5200-i2c", .data = &mpc_i2c_data_52xx, },
+	{.compatible = "fsl,mpc5200b-i2c", .data = &mpc_i2c_data_52xx, },
+	{.compatible = "fsl,mpc5200-i2c", .data = &mpc_i2c_data_52xx, },
+	{.compatible = "fsl,mpc5121-i2c", .data = &mpc_i2c_data_512x, },
+	{.compatible = "fsl,mpc8313-i2c", .data = &mpc_i2c_data_8313, },
+	{.compatible = "fsl,mpc8543-i2c", .data = &mpc_i2c_data_8543, },
+	{.compatible = "fsl,mpc8544-i2c", .data = &mpc_i2c_data_8544, },
+	/* Backward compatibility */
+	{.compatible = "fsl-i2c", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, mpc_i2c_of_match);
+
+/* Structure for a device driver */
+static struct platform_driver mpc_i2c_driver = {
+	.probe		= fsl_i2c_probe,
+	.remove		= __devexit_p(fsl_i2c_remove),
+	.driver = {
+		.owner = THIS_MODULE,
+		.name = DRV_NAME,
+		.of_match_table = mpc_i2c_of_match,
+	},
+};
+
+module_platform_driver(mpc_i2c_driver);
+
+MODULE_AUTHOR("Adrian Cox <adrian@humboldt.co.uk>");
+MODULE_DESCRIPTION("I2C-Bus adapter for MPC107 bridge and "
+		   "MPC824x/83xx/85xx/86xx/512x/52xx processors");
+MODULE_LICENSE("GPL");
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-mv64xxx.c b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-mv64xxx.c
new file mode 100644
index 0000000..4f44a33
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-mv64xxx.c
@@ -0,0 +1,618 @@
+/*
+ * Driver for the i2c controller on the Marvell line of host bridges
+ * (e.g, gt642[46]0, mv643[46]0, mv644[46]0, and Orion SoC family).
+ *
+ * Author: Mark A. Greer <mgreer@mvista.com>
+ *
+ * 2005 (c) MontaVista, Software, Inc.  This file is licensed under
+ * the terms of the GNU General Public License version 2.  This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/mv643xx_i2c.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+/* Register defines */
+#define	MV64XXX_I2C_REG_SLAVE_ADDR			0x00
+#define	MV64XXX_I2C_REG_DATA				0x04
+#define	MV64XXX_I2C_REG_CONTROL				0x08
+#define	MV64XXX_I2C_REG_STATUS				0x0c
+#define	MV64XXX_I2C_REG_BAUD				0x0c
+#define	MV64XXX_I2C_REG_EXT_SLAVE_ADDR			0x10
+#define	MV64XXX_I2C_REG_SOFT_RESET			0x1c
+
+#define	MV64XXX_I2C_REG_CONTROL_ACK			0x00000004
+#define	MV64XXX_I2C_REG_CONTROL_IFLG			0x00000008
+#define	MV64XXX_I2C_REG_CONTROL_STOP			0x00000010
+#define	MV64XXX_I2C_REG_CONTROL_START			0x00000020
+#define	MV64XXX_I2C_REG_CONTROL_TWSIEN			0x00000040
+#define	MV64XXX_I2C_REG_CONTROL_INTEN			0x00000080
+
+/* Ctlr status values */
+#define	MV64XXX_I2C_STATUS_BUS_ERR			0x00
+#define	MV64XXX_I2C_STATUS_MAST_START			0x08
+#define	MV64XXX_I2C_STATUS_MAST_REPEAT_START		0x10
+#define	MV64XXX_I2C_STATUS_MAST_WR_ADDR_ACK		0x18
+#define	MV64XXX_I2C_STATUS_MAST_WR_ADDR_NO_ACK		0x20
+#define	MV64XXX_I2C_STATUS_MAST_WR_ACK			0x28
+#define	MV64XXX_I2C_STATUS_MAST_WR_NO_ACK		0x30
+#define	MV64XXX_I2C_STATUS_MAST_LOST_ARB		0x38
+#define	MV64XXX_I2C_STATUS_MAST_RD_ADDR_ACK		0x40
+#define	MV64XXX_I2C_STATUS_MAST_RD_ADDR_NO_ACK		0x48
+#define	MV64XXX_I2C_STATUS_MAST_RD_DATA_ACK		0x50
+#define	MV64XXX_I2C_STATUS_MAST_RD_DATA_NO_ACK		0x58
+#define	MV64XXX_I2C_STATUS_MAST_WR_ADDR_2_ACK		0xd0
+#define	MV64XXX_I2C_STATUS_MAST_WR_ADDR_2_NO_ACK	0xd8
+#define	MV64XXX_I2C_STATUS_MAST_RD_ADDR_2_ACK		0xe0
+#define	MV64XXX_I2C_STATUS_MAST_RD_ADDR_2_NO_ACK	0xe8
+#define	MV64XXX_I2C_STATUS_NO_STATUS			0xf8
+
+/* Driver states */
+enum {
+	MV64XXX_I2C_STATE_INVALID,
+	MV64XXX_I2C_STATE_IDLE,
+	MV64XXX_I2C_STATE_WAITING_FOR_START_COND,
+	MV64XXX_I2C_STATE_WAITING_FOR_RESTART,
+	MV64XXX_I2C_STATE_WAITING_FOR_ADDR_1_ACK,
+	MV64XXX_I2C_STATE_WAITING_FOR_ADDR_2_ACK,
+	MV64XXX_I2C_STATE_WAITING_FOR_SLAVE_ACK,
+	MV64XXX_I2C_STATE_WAITING_FOR_SLAVE_DATA,
+};
+
+/* Driver actions */
+enum {
+	MV64XXX_I2C_ACTION_INVALID,
+	MV64XXX_I2C_ACTION_CONTINUE,
+	MV64XXX_I2C_ACTION_SEND_START,
+	MV64XXX_I2C_ACTION_SEND_RESTART,
+	MV64XXX_I2C_ACTION_SEND_ADDR_1,
+	MV64XXX_I2C_ACTION_SEND_ADDR_2,
+	MV64XXX_I2C_ACTION_SEND_DATA,
+	MV64XXX_I2C_ACTION_RCV_DATA,
+	MV64XXX_I2C_ACTION_RCV_DATA_STOP,
+	MV64XXX_I2C_ACTION_SEND_STOP,
+};
+
+struct mv64xxx_i2c_data {
+	int			irq;
+	u32			state;
+	u32			action;
+	u32			aborting;
+	u32			cntl_bits;
+	void __iomem		*reg_base;
+	u32			reg_base_p;
+	u32			reg_size;
+	u32			addr1;
+	u32			addr2;
+	u32			bytes_left;
+	u32			byte_posn;
+	u32			send_stop;
+	u32			block;
+	int			rc;
+	u32			freq_m;
+	u32			freq_n;
+	wait_queue_head_t	waitq;
+	spinlock_t		lock;
+	struct i2c_msg		*msg;
+	struct i2c_adapter	adapter;
+};
+
+/*
+ *****************************************************************************
+ *
+ *	Finite State Machine & Interrupt Routines
+ *
+ *****************************************************************************
+ */
+
+/* Reset hardware and initialize FSM */
+static void
+mv64xxx_i2c_hw_init(struct mv64xxx_i2c_data *drv_data)
+{
+	writel(0, drv_data->reg_base + MV64XXX_I2C_REG_SOFT_RESET);
+	writel((((drv_data->freq_m & 0xf) << 3) | (drv_data->freq_n & 0x7)),
+		drv_data->reg_base + MV64XXX_I2C_REG_BAUD);
+	writel(0, drv_data->reg_base + MV64XXX_I2C_REG_SLAVE_ADDR);
+	writel(0, drv_data->reg_base + MV64XXX_I2C_REG_EXT_SLAVE_ADDR);
+	writel(MV64XXX_I2C_REG_CONTROL_TWSIEN | MV64XXX_I2C_REG_CONTROL_STOP,
+		drv_data->reg_base + MV64XXX_I2C_REG_CONTROL);
+	drv_data->state = MV64XXX_I2C_STATE_IDLE;
+}
+
+static void
+mv64xxx_i2c_fsm(struct mv64xxx_i2c_data *drv_data, u32 status)
+{
+	/*
+	 * If state is idle, then this is likely the remnants of an old
+	 * operation that driver has given up on or the user has killed.
+	 * If so, issue the stop condition and go to idle.
+	 */
+	if (drv_data->state == MV64XXX_I2C_STATE_IDLE) {
+		drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP;
+		return;
+	}
+
+	/* The status from the ctlr [mostly] tells us what to do next */
+	switch (status) {
+	/* Start condition interrupt */
+	case MV64XXX_I2C_STATUS_MAST_START: /* 0x08 */
+	case MV64XXX_I2C_STATUS_MAST_REPEAT_START: /* 0x10 */
+		drv_data->action = MV64XXX_I2C_ACTION_SEND_ADDR_1;
+		drv_data->state = MV64XXX_I2C_STATE_WAITING_FOR_ADDR_1_ACK;
+		break;
+
+	/* Performing a write */
+	case MV64XXX_I2C_STATUS_MAST_WR_ADDR_ACK: /* 0x18 */
+		if (drv_data->msg->flags & I2C_M_TEN) {
+			drv_data->action = MV64XXX_I2C_ACTION_SEND_ADDR_2;
+			drv_data->state =
+				MV64XXX_I2C_STATE_WAITING_FOR_ADDR_2_ACK;
+			break;
+		}
+		/* FALLTHRU */
+	case MV64XXX_I2C_STATUS_MAST_WR_ADDR_2_ACK: /* 0xd0 */
+	case MV64XXX_I2C_STATUS_MAST_WR_ACK: /* 0x28 */
+		if ((drv_data->bytes_left == 0)
+				|| (drv_data->aborting
+					&& (drv_data->byte_posn != 0))) {
+			if (drv_data->send_stop) {
+				drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP;
+				drv_data->state = MV64XXX_I2C_STATE_IDLE;
+			} else {
+				drv_data->action =
+					MV64XXX_I2C_ACTION_SEND_RESTART;
+				drv_data->state =
+					MV64XXX_I2C_STATE_WAITING_FOR_RESTART;
+			}
+		} else {
+			drv_data->action = MV64XXX_I2C_ACTION_SEND_DATA;
+			drv_data->state =
+				MV64XXX_I2C_STATE_WAITING_FOR_SLAVE_ACK;
+			drv_data->bytes_left--;
+		}
+		break;
+
+	/* Performing a read */
+	case MV64XXX_I2C_STATUS_MAST_RD_ADDR_ACK: /* 40 */
+		if (drv_data->msg->flags & I2C_M_TEN) {
+			drv_data->action = MV64XXX_I2C_ACTION_SEND_ADDR_2;
+			drv_data->state =
+				MV64XXX_I2C_STATE_WAITING_FOR_ADDR_2_ACK;
+			break;
+		}
+		/* FALLTHRU */
+	case MV64XXX_I2C_STATUS_MAST_RD_ADDR_2_ACK: /* 0xe0 */
+		if (drv_data->bytes_left == 0) {
+			drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP;
+			drv_data->state = MV64XXX_I2C_STATE_IDLE;
+			break;
+		}
+		/* FALLTHRU */
+	case MV64XXX_I2C_STATUS_MAST_RD_DATA_ACK: /* 0x50 */
+		if (status != MV64XXX_I2C_STATUS_MAST_RD_DATA_ACK)
+			drv_data->action = MV64XXX_I2C_ACTION_CONTINUE;
+		else {
+			drv_data->action = MV64XXX_I2C_ACTION_RCV_DATA;
+			drv_data->bytes_left--;
+		}
+		drv_data->state = MV64XXX_I2C_STATE_WAITING_FOR_SLAVE_DATA;
+
+		if ((drv_data->bytes_left == 1) || drv_data->aborting)
+			drv_data->cntl_bits &= ~MV64XXX_I2C_REG_CONTROL_ACK;
+		break;
+
+	case MV64XXX_I2C_STATUS_MAST_RD_DATA_NO_ACK: /* 0x58 */
+		drv_data->action = MV64XXX_I2C_ACTION_RCV_DATA_STOP;
+		drv_data->state = MV64XXX_I2C_STATE_IDLE;
+		break;
+
+	case MV64XXX_I2C_STATUS_MAST_WR_ADDR_NO_ACK: /* 0x20 */
+	case MV64XXX_I2C_STATUS_MAST_WR_NO_ACK: /* 30 */
+	case MV64XXX_I2C_STATUS_MAST_RD_ADDR_NO_ACK: /* 48 */
+		/* Doesn't seem to be a device at other end */
+		drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP;
+		drv_data->state = MV64XXX_I2C_STATE_IDLE;
+		drv_data->rc = -ENODEV;
+		break;
+
+	default:
+		dev_err(&drv_data->adapter.dev,
+			"mv64xxx_i2c_fsm: Ctlr Error -- state: 0x%x, "
+			"status: 0x%x, addr: 0x%x, flags: 0x%x\n",
+			 drv_data->state, status, drv_data->msg->addr,
+			 drv_data->msg->flags);
+		drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP;
+		mv64xxx_i2c_hw_init(drv_data);
+		drv_data->rc = -EIO;
+	}
+}
+
+static void
+mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data)
+{
+	switch(drv_data->action) {
+	case MV64XXX_I2C_ACTION_SEND_RESTART:
+		drv_data->cntl_bits |= MV64XXX_I2C_REG_CONTROL_START;
+		drv_data->cntl_bits &= ~MV64XXX_I2C_REG_CONTROL_INTEN;
+		writel(drv_data->cntl_bits,
+			drv_data->reg_base + MV64XXX_I2C_REG_CONTROL);
+		drv_data->block = 0;
+		wake_up_interruptible(&drv_data->waitq);
+		break;
+
+	case MV64XXX_I2C_ACTION_CONTINUE:
+		writel(drv_data->cntl_bits,
+			drv_data->reg_base + MV64XXX_I2C_REG_CONTROL);
+		break;
+
+	case MV64XXX_I2C_ACTION_SEND_START:
+		writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_START,
+			drv_data->reg_base + MV64XXX_I2C_REG_CONTROL);
+		break;
+
+	case MV64XXX_I2C_ACTION_SEND_ADDR_1:
+		writel(drv_data->addr1,
+			drv_data->reg_base + MV64XXX_I2C_REG_DATA);
+		writel(drv_data->cntl_bits,
+			drv_data->reg_base + MV64XXX_I2C_REG_CONTROL);
+		break;
+
+	case MV64XXX_I2C_ACTION_SEND_ADDR_2:
+		writel(drv_data->addr2,
+			drv_data->reg_base + MV64XXX_I2C_REG_DATA);
+		writel(drv_data->cntl_bits,
+			drv_data->reg_base + MV64XXX_I2C_REG_CONTROL);
+		break;
+
+	case MV64XXX_I2C_ACTION_SEND_DATA:
+		writel(drv_data->msg->buf[drv_data->byte_posn++],
+			drv_data->reg_base + MV64XXX_I2C_REG_DATA);
+		writel(drv_data->cntl_bits,
+			drv_data->reg_base + MV64XXX_I2C_REG_CONTROL);
+		break;
+
+	case MV64XXX_I2C_ACTION_RCV_DATA:
+		drv_data->msg->buf[drv_data->byte_posn++] =
+			readl(drv_data->reg_base + MV64XXX_I2C_REG_DATA);
+		writel(drv_data->cntl_bits,
+			drv_data->reg_base + MV64XXX_I2C_REG_CONTROL);
+		break;
+
+	case MV64XXX_I2C_ACTION_RCV_DATA_STOP:
+		drv_data->msg->buf[drv_data->byte_posn++] =
+			readl(drv_data->reg_base + MV64XXX_I2C_REG_DATA);
+		drv_data->cntl_bits &= ~MV64XXX_I2C_REG_CONTROL_INTEN;
+		writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_STOP,
+			drv_data->reg_base + MV64XXX_I2C_REG_CONTROL);
+		drv_data->block = 0;
+		wake_up_interruptible(&drv_data->waitq);
+		break;
+
+	case MV64XXX_I2C_ACTION_INVALID:
+	default:
+		dev_err(&drv_data->adapter.dev,
+			"mv64xxx_i2c_do_action: Invalid action: %d\n",
+			drv_data->action);
+		drv_data->rc = -EIO;
+		/* FALLTHRU */
+	case MV64XXX_I2C_ACTION_SEND_STOP:
+		drv_data->cntl_bits &= ~MV64XXX_I2C_REG_CONTROL_INTEN;
+		writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_STOP,
+			drv_data->reg_base + MV64XXX_I2C_REG_CONTROL);
+		drv_data->block = 0;
+		wake_up_interruptible(&drv_data->waitq);
+		break;
+	}
+}
+
+static irqreturn_t
+mv64xxx_i2c_intr(int irq, void *dev_id)
+{
+	struct mv64xxx_i2c_data	*drv_data = dev_id;
+	unsigned long	flags;
+	u32		status;
+	irqreturn_t	rc = IRQ_NONE;
+
+	spin_lock_irqsave(&drv_data->lock, flags);
+	while (readl(drv_data->reg_base + MV64XXX_I2C_REG_CONTROL) &
+						MV64XXX_I2C_REG_CONTROL_IFLG) {
+		status = readl(drv_data->reg_base + MV64XXX_I2C_REG_STATUS);
+		mv64xxx_i2c_fsm(drv_data, status);
+		mv64xxx_i2c_do_action(drv_data);
+		rc = IRQ_HANDLED;
+	}
+	spin_unlock_irqrestore(&drv_data->lock, flags);
+
+	return rc;
+}
+
+/*
+ *****************************************************************************
+ *
+ *	I2C Msg Execution Routines
+ *
+ *****************************************************************************
+ */
+static void
+mv64xxx_i2c_prepare_for_io(struct mv64xxx_i2c_data *drv_data,
+	struct i2c_msg *msg)
+{
+	u32	dir = 0;
+
+	drv_data->msg = msg;
+	drv_data->byte_posn = 0;
+	drv_data->bytes_left = msg->len;
+	drv_data->aborting = 0;
+	drv_data->rc = 0;
+	drv_data->cntl_bits = MV64XXX_I2C_REG_CONTROL_ACK |
+		MV64XXX_I2C_REG_CONTROL_INTEN | MV64XXX_I2C_REG_CONTROL_TWSIEN;
+
+	if (msg->flags & I2C_M_RD)
+		dir = 1;
+
+	if (msg->flags & I2C_M_TEN) {
+		drv_data->addr1 = 0xf0 | (((u32)msg->addr & 0x300) >> 7) | dir;
+		drv_data->addr2 = (u32)msg->addr & 0xff;
+	} else {
+		drv_data->addr1 = ((u32)msg->addr & 0x7f) << 1 | dir;
+		drv_data->addr2 = 0;
+	}
+}
+
+static void
+mv64xxx_i2c_wait_for_completion(struct mv64xxx_i2c_data *drv_data)
+{
+	long		time_left;
+	unsigned long	flags;
+	char		abort = 0;
+
+	time_left = wait_event_interruptible_timeout(drv_data->waitq,
+		!drv_data->block, drv_data->adapter.timeout);
+
+	spin_lock_irqsave(&drv_data->lock, flags);
+	if (!time_left) { /* Timed out */
+		drv_data->rc = -ETIMEDOUT;
+		abort = 1;
+	} else if (time_left < 0) { /* Interrupted/Error */
+		drv_data->rc = time_left; /* errno value */
+		abort = 1;
+	}
+
+	if (abort && drv_data->block) {
+		drv_data->aborting = 1;
+		spin_unlock_irqrestore(&drv_data->lock, flags);
+
+		time_left = wait_event_timeout(drv_data->waitq,
+			!drv_data->block, drv_data->adapter.timeout);
+
+		if ((time_left <= 0) && drv_data->block) {
+			drv_data->state = MV64XXX_I2C_STATE_IDLE;
+			dev_err(&drv_data->adapter.dev,
+				"mv64xxx: I2C bus locked, block: %d, "
+				"time_left: %d\n", drv_data->block,
+				(int)time_left);
+			mv64xxx_i2c_hw_init(drv_data);
+		}
+	} else
+		spin_unlock_irqrestore(&drv_data->lock, flags);
+}
+
+static int
+mv64xxx_i2c_execute_msg(struct mv64xxx_i2c_data *drv_data, struct i2c_msg *msg,
+				int is_first, int is_last)
+{
+	unsigned long	flags;
+
+	spin_lock_irqsave(&drv_data->lock, flags);
+	mv64xxx_i2c_prepare_for_io(drv_data, msg);
+
+	if (unlikely(msg->flags & I2C_M_NOSTART)) { /* Skip start/addr phases */
+		if (drv_data->msg->flags & I2C_M_RD) {
+			/* No action to do, wait for slave to send a byte */
+			drv_data->action = MV64XXX_I2C_ACTION_CONTINUE;
+			drv_data->state =
+				MV64XXX_I2C_STATE_WAITING_FOR_SLAVE_DATA;
+		} else {
+			drv_data->action = MV64XXX_I2C_ACTION_SEND_DATA;
+			drv_data->state =
+				MV64XXX_I2C_STATE_WAITING_FOR_SLAVE_ACK;
+			drv_data->bytes_left--;
+		}
+	} else {
+		if (is_first) {
+			drv_data->action = MV64XXX_I2C_ACTION_SEND_START;
+			drv_data->state =
+				MV64XXX_I2C_STATE_WAITING_FOR_START_COND;
+		} else {
+			drv_data->action = MV64XXX_I2C_ACTION_SEND_ADDR_1;
+			drv_data->state =
+				MV64XXX_I2C_STATE_WAITING_FOR_ADDR_1_ACK;
+		}
+	}
+
+	drv_data->send_stop = is_last;
+	drv_data->block = 1;
+	mv64xxx_i2c_do_action(drv_data);
+	spin_unlock_irqrestore(&drv_data->lock, flags);
+
+	mv64xxx_i2c_wait_for_completion(drv_data);
+	return drv_data->rc;
+}
+
+/*
+ *****************************************************************************
+ *
+ *	I2C Core Support Routines (Interface to higher level I2C code)
+ *
+ *****************************************************************************
+ */
+static u32
+mv64xxx_i2c_functionality(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR | I2C_FUNC_SMBUS_EMUL;
+}
+
+static int
+mv64xxx_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
+{
+	struct mv64xxx_i2c_data *drv_data = i2c_get_adapdata(adap);
+	int	i, rc;
+
+	for (i = 0; i < num; i++) {
+		rc = mv64xxx_i2c_execute_msg(drv_data, &msgs[i],
+						i == 0, i + 1 == num);
+		if (rc < 0)
+			return rc;
+	}
+
+	return num;
+}
+
+static const struct i2c_algorithm mv64xxx_i2c_algo = {
+	.master_xfer = mv64xxx_i2c_xfer,
+	.functionality = mv64xxx_i2c_functionality,
+};
+
+/*
+ *****************************************************************************
+ *
+ *	Driver Interface & Early Init Routines
+ *
+ *****************************************************************************
+ */
+static int __devinit
+mv64xxx_i2c_map_regs(struct platform_device *pd,
+	struct mv64xxx_i2c_data *drv_data)
+{
+	int size;
+	struct resource	*r = platform_get_resource(pd, IORESOURCE_MEM, 0);
+
+	if (!r)
+		return -ENODEV;
+
+	size = resource_size(r);
+
+	if (!request_mem_region(r->start, size, drv_data->adapter.name))
+		return -EBUSY;
+
+	drv_data->reg_base = ioremap(r->start, size);
+	drv_data->reg_base_p = r->start;
+	drv_data->reg_size = size;
+
+	return 0;
+}
+
+static void
+mv64xxx_i2c_unmap_regs(struct mv64xxx_i2c_data *drv_data)
+{
+	if (drv_data->reg_base) {
+		iounmap(drv_data->reg_base);
+		release_mem_region(drv_data->reg_base_p, drv_data->reg_size);
+	}
+
+	drv_data->reg_base = NULL;
+	drv_data->reg_base_p = 0;
+}
+
+static int __devinit
+mv64xxx_i2c_probe(struct platform_device *pd)
+{
+	struct mv64xxx_i2c_data		*drv_data;
+	struct mv64xxx_i2c_pdata	*pdata = pd->dev.platform_data;
+	int	rc;
+
+	if ((pd->id != 0) || !pdata)
+		return -ENODEV;
+
+	drv_data = kzalloc(sizeof(struct mv64xxx_i2c_data), GFP_KERNEL);
+	if (!drv_data)
+		return -ENOMEM;
+
+	if (mv64xxx_i2c_map_regs(pd, drv_data)) {
+		rc = -ENODEV;
+		goto exit_kfree;
+	}
+
+	strlcpy(drv_data->adapter.name, MV64XXX_I2C_CTLR_NAME " adapter",
+		sizeof(drv_data->adapter.name));
+
+	init_waitqueue_head(&drv_data->waitq);
+	spin_lock_init(&drv_data->lock);
+
+	drv_data->freq_m = pdata->freq_m;
+	drv_data->freq_n = pdata->freq_n;
+	drv_data->irq = platform_get_irq(pd, 0);
+	if (drv_data->irq < 0) {
+		rc = -ENXIO;
+		goto exit_unmap_regs;
+	}
+	drv_data->adapter.dev.parent = &pd->dev;
+	drv_data->adapter.algo = &mv64xxx_i2c_algo;
+	drv_data->adapter.owner = THIS_MODULE;
+	drv_data->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
+	drv_data->adapter.timeout = msecs_to_jiffies(pdata->timeout);
+	drv_data->adapter.nr = pd->id;
+	platform_set_drvdata(pd, drv_data);
+	i2c_set_adapdata(&drv_data->adapter, drv_data);
+
+	mv64xxx_i2c_hw_init(drv_data);
+
+	if (request_irq(drv_data->irq, mv64xxx_i2c_intr, 0,
+			MV64XXX_I2C_CTLR_NAME, drv_data)) {
+		dev_err(&drv_data->adapter.dev,
+			"mv64xxx: Can't register intr handler irq: %d\n",
+			drv_data->irq);
+		rc = -EINVAL;
+		goto exit_unmap_regs;
+	} else if ((rc = i2c_add_numbered_adapter(&drv_data->adapter)) != 0) {
+		dev_err(&drv_data->adapter.dev,
+			"mv64xxx: Can't add i2c adapter, rc: %d\n", -rc);
+		goto exit_free_irq;
+	}
+
+	return 0;
+
+	exit_free_irq:
+		free_irq(drv_data->irq, drv_data);
+	exit_unmap_regs:
+		mv64xxx_i2c_unmap_regs(drv_data);
+	exit_kfree:
+		kfree(drv_data);
+	return rc;
+}
+
+static int __devexit
+mv64xxx_i2c_remove(struct platform_device *dev)
+{
+	struct mv64xxx_i2c_data		*drv_data = platform_get_drvdata(dev);
+	int	rc;
+
+	rc = i2c_del_adapter(&drv_data->adapter);
+	free_irq(drv_data->irq, drv_data);
+	mv64xxx_i2c_unmap_regs(drv_data);
+	kfree(drv_data);
+
+	return rc;
+}
+
+static struct platform_driver mv64xxx_i2c_driver = {
+	.probe	= mv64xxx_i2c_probe,
+	.remove	= __devexit_p(mv64xxx_i2c_remove),
+	.driver	= {
+		.owner	= THIS_MODULE,
+		.name	= MV64XXX_I2C_CTLR_NAME,
+	},
+};
+
+module_platform_driver(mv64xxx_i2c_driver);
+
+MODULE_AUTHOR("Mark A. Greer <mgreer@mvista.com>");
+MODULE_DESCRIPTION("Marvell mv64xxx host bridge i2c ctlr driver");
+MODULE_LICENSE("GPL");
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-mxs.c b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-mxs.c
new file mode 100644
index 0000000..76b8af4
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-mxs.c
@@ -0,0 +1,419 @@
+/*
+ * Freescale MXS I2C bus driver
+ *
+ * Copyright (C) 2011 Wolfram Sang, Pengutronix e.K.
+ *
+ * based on a (non-working) driver which was:
+ *
+ * Copyright (C) 2009-2010 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * TODO: add dma-support if platform-support for it is available
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/completion.h>
+#include <linux/platform_device.h>
+#include <linux/jiffies.h>
+#include <linux/io.h>
+
+#include <mach/common.h>
+
+#define DRIVER_NAME "mxs-i2c"
+
+#define MXS_I2C_CTRL0		(0x00)
+#define MXS_I2C_CTRL0_SET	(0x04)
+
+#define MXS_I2C_CTRL0_SFTRST			0x80000000
+#define MXS_I2C_CTRL0_SEND_NAK_ON_LAST		0x02000000
+#define MXS_I2C_CTRL0_RETAIN_CLOCK		0x00200000
+#define MXS_I2C_CTRL0_POST_SEND_STOP		0x00100000
+#define MXS_I2C_CTRL0_PRE_SEND_START		0x00080000
+#define MXS_I2C_CTRL0_MASTER_MODE		0x00020000
+#define MXS_I2C_CTRL0_DIRECTION			0x00010000
+#define MXS_I2C_CTRL0_XFER_COUNT(v)		((v) & 0x0000FFFF)
+
+#define MXS_I2C_CTRL1		(0x40)
+#define MXS_I2C_CTRL1_SET	(0x44)
+#define MXS_I2C_CTRL1_CLR	(0x48)
+
+#define MXS_I2C_CTRL1_BUS_FREE_IRQ		0x80
+#define MXS_I2C_CTRL1_DATA_ENGINE_CMPLT_IRQ	0x40
+#define MXS_I2C_CTRL1_NO_SLAVE_ACK_IRQ		0x20
+#define MXS_I2C_CTRL1_OVERSIZE_XFER_TERM_IRQ	0x10
+#define MXS_I2C_CTRL1_EARLY_TERM_IRQ		0x08
+#define MXS_I2C_CTRL1_MASTER_LOSS_IRQ		0x04
+#define MXS_I2C_CTRL1_SLAVE_STOP_IRQ		0x02
+#define MXS_I2C_CTRL1_SLAVE_IRQ			0x01
+
+#define MXS_I2C_IRQ_MASK	(MXS_I2C_CTRL1_DATA_ENGINE_CMPLT_IRQ | \
+				 MXS_I2C_CTRL1_NO_SLAVE_ACK_IRQ | \
+				 MXS_I2C_CTRL1_EARLY_TERM_IRQ | \
+				 MXS_I2C_CTRL1_MASTER_LOSS_IRQ | \
+				 MXS_I2C_CTRL1_SLAVE_STOP_IRQ | \
+				 MXS_I2C_CTRL1_SLAVE_IRQ)
+
+#define MXS_I2C_QUEUECTRL	(0x60)
+#define MXS_I2C_QUEUECTRL_SET	(0x64)
+#define MXS_I2C_QUEUECTRL_CLR	(0x68)
+
+#define MXS_I2C_QUEUECTRL_QUEUE_RUN		0x20
+#define MXS_I2C_QUEUECTRL_PIO_QUEUE_MODE	0x04
+
+#define MXS_I2C_QUEUESTAT	(0x70)
+#define MXS_I2C_QUEUESTAT_RD_QUEUE_EMPTY        0x00002000
+#define MXS_I2C_QUEUESTAT_WRITE_QUEUE_CNT_MASK	0x0000001F
+
+#define MXS_I2C_QUEUECMD	(0x80)
+
+#define MXS_I2C_QUEUEDATA	(0x90)
+
+#define MXS_I2C_DATA		(0xa0)
+
+
+#define MXS_CMD_I2C_SELECT	(MXS_I2C_CTRL0_RETAIN_CLOCK |	\
+				 MXS_I2C_CTRL0_PRE_SEND_START |	\
+				 MXS_I2C_CTRL0_MASTER_MODE |	\
+				 MXS_I2C_CTRL0_DIRECTION |	\
+				 MXS_I2C_CTRL0_XFER_COUNT(1))
+
+#define MXS_CMD_I2C_WRITE	(MXS_I2C_CTRL0_PRE_SEND_START |	\
+				 MXS_I2C_CTRL0_MASTER_MODE |	\
+				 MXS_I2C_CTRL0_DIRECTION)
+
+#define MXS_CMD_I2C_READ	(MXS_I2C_CTRL0_SEND_NAK_ON_LAST | \
+				 MXS_I2C_CTRL0_MASTER_MODE)
+
+/**
+ * struct mxs_i2c_dev - per device, private MXS-I2C data
+ *
+ * @dev: driver model device node
+ * @regs: IO registers pointer
+ * @cmd_complete: completion object for transaction wait
+ * @cmd_err: error code for last transaction
+ * @adapter: i2c subsystem adapter node
+ */
+struct mxs_i2c_dev {
+	struct device *dev;
+	void __iomem *regs;
+	struct completion cmd_complete;
+	u32 cmd_err;
+	struct i2c_adapter adapter;
+};
+
+/*
+ * TODO: check if calls to here are really needed. If not, we could get rid of
+ * mxs_reset_block and the mach-dependency. Needs an I2C analyzer, probably.
+ */
+static void mxs_i2c_reset(struct mxs_i2c_dev *i2c)
+{
+	mxs_reset_block(i2c->regs);
+	writel(MXS_I2C_IRQ_MASK << 8, i2c->regs + MXS_I2C_CTRL1_SET);
+	writel(MXS_I2C_QUEUECTRL_PIO_QUEUE_MODE,
+			i2c->regs + MXS_I2C_QUEUECTRL_SET);
+}
+
+static void mxs_i2c_pioq_setup_read(struct mxs_i2c_dev *i2c, u8 addr, int len,
+					int flags)
+{
+	u32 data;
+
+	writel(MXS_CMD_I2C_SELECT, i2c->regs + MXS_I2C_QUEUECMD);
+
+	data = (addr << 1) | I2C_SMBUS_READ;
+	writel(data, i2c->regs + MXS_I2C_DATA);
+
+	data = MXS_CMD_I2C_READ | MXS_I2C_CTRL0_XFER_COUNT(len) | flags;
+	writel(data, i2c->regs + MXS_I2C_QUEUECMD);
+}
+
+static void mxs_i2c_pioq_setup_write(struct mxs_i2c_dev *i2c,
+				    u8 addr, u8 *buf, int len, int flags)
+{
+	u32 data;
+	int i, shifts_left;
+
+	data = MXS_CMD_I2C_WRITE | MXS_I2C_CTRL0_XFER_COUNT(len + 1) | flags;
+	writel(data, i2c->regs + MXS_I2C_QUEUECMD);
+
+	/*
+	 * We have to copy the slave address (u8) and buffer (arbitrary number
+	 * of u8) into the data register (u32). To achieve that, the u8 are put
+	 * into the MSBs of 'data' which is then shifted for the next u8. When
+	 * appropriate, 'data' is written to MXS_I2C_DATA. So, the first u32
+	 * looks like this:
+	 *
+	 *  3          2          1          0
+	 * 10987654|32109876|54321098|76543210
+	 * --------+--------+--------+--------
+	 * buffer+2|buffer+1|buffer+0|slave_addr
+	 */
+
+	data = ((addr << 1) | I2C_SMBUS_WRITE) << 24;
+
+	for (i = 0; i < len; i++) {
+		data >>= 8;
+		data |= buf[i] << 24;
+		if ((i & 3) == 2)
+			writel(data, i2c->regs + MXS_I2C_DATA);
+	}
+
+	/* Write out the remaining bytes if any */
+	shifts_left = 24 - (i & 3) * 8;
+	if (shifts_left)
+		writel(data >> shifts_left, i2c->regs + MXS_I2C_DATA);
+}
+
+/*
+ * TODO: should be replaceable with a waitqueue and RD_QUEUE_IRQ (setting the
+ * rd_threshold to 1). Couldn't get this to work, though.
+ */
+static int mxs_i2c_wait_for_data(struct mxs_i2c_dev *i2c)
+{
+	unsigned long timeout = jiffies + msecs_to_jiffies(1000);
+
+	while (readl(i2c->regs + MXS_I2C_QUEUESTAT)
+			& MXS_I2C_QUEUESTAT_RD_QUEUE_EMPTY) {
+			if (time_after(jiffies, timeout))
+				return -ETIMEDOUT;
+			cond_resched();
+	}
+
+	return 0;
+}
+
+static int mxs_i2c_finish_read(struct mxs_i2c_dev *i2c, u8 *buf, int len)
+{
+	u32 data;
+	int i;
+
+	for (i = 0; i < len; i++) {
+		if ((i & 3) == 0) {
+			if (mxs_i2c_wait_for_data(i2c))
+				return -ETIMEDOUT;
+			data = readl(i2c->regs + MXS_I2C_QUEUEDATA);
+		}
+		buf[i] = data & 0xff;
+		data >>= 8;
+	}
+
+	return 0;
+}
+
+/*
+ * Low level master read/write transaction.
+ */
+static int mxs_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg,
+				int stop)
+{
+	struct mxs_i2c_dev *i2c = i2c_get_adapdata(adap);
+	int ret;
+	int flags;
+
+	dev_dbg(i2c->dev, "addr: 0x%04x, len: %d, flags: 0x%x, stop: %d\n",
+		msg->addr, msg->len, msg->flags, stop);
+
+	if (msg->len == 0)
+		return -EINVAL;
+
+	init_completion(&i2c->cmd_complete);
+	i2c->cmd_err = 0;
+
+	flags = stop ? MXS_I2C_CTRL0_POST_SEND_STOP : 0;
+
+	if (msg->flags & I2C_M_RD)
+		mxs_i2c_pioq_setup_read(i2c, msg->addr, msg->len, flags);
+	else
+		mxs_i2c_pioq_setup_write(i2c, msg->addr, msg->buf, msg->len,
+					flags);
+
+	writel(MXS_I2C_QUEUECTRL_QUEUE_RUN,
+			i2c->regs + MXS_I2C_QUEUECTRL_SET);
+
+	ret = wait_for_completion_timeout(&i2c->cmd_complete,
+						msecs_to_jiffies(1000));
+	if (ret == 0)
+		goto timeout;
+
+	if ((!i2c->cmd_err) && (msg->flags & I2C_M_RD)) {
+		ret = mxs_i2c_finish_read(i2c, msg->buf, msg->len);
+		if (ret)
+			goto timeout;
+	}
+
+	if (i2c->cmd_err == -ENXIO)
+		mxs_i2c_reset(i2c);
+	else
+		writel(MXS_I2C_QUEUECTRL_QUEUE_RUN,
+				i2c->regs + MXS_I2C_QUEUECTRL_CLR);
+
+	dev_dbg(i2c->dev, "Done with err=%d\n", i2c->cmd_err);
+
+	return i2c->cmd_err;
+
+timeout:
+	dev_dbg(i2c->dev, "Timeout!\n");
+	mxs_i2c_reset(i2c);
+	return -ETIMEDOUT;
+}
+
+static int mxs_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
+			int num)
+{
+	int i;
+	int err;
+
+	for (i = 0; i < num; i++) {
+		err = mxs_i2c_xfer_msg(adap, &msgs[i], i == (num - 1));
+		if (err)
+			return err;
+	}
+
+	return num;
+}
+
+static u32 mxs_i2c_func(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
+}
+
+static irqreturn_t mxs_i2c_isr(int this_irq, void *dev_id)
+{
+	struct mxs_i2c_dev *i2c = dev_id;
+	u32 stat = readl(i2c->regs + MXS_I2C_CTRL1) & MXS_I2C_IRQ_MASK;
+	bool is_last_cmd;
+
+	if (!stat)
+		return IRQ_NONE;
+
+	if (stat & MXS_I2C_CTRL1_NO_SLAVE_ACK_IRQ)
+		i2c->cmd_err = -ENXIO;
+	else if (stat & (MXS_I2C_CTRL1_EARLY_TERM_IRQ |
+		    MXS_I2C_CTRL1_MASTER_LOSS_IRQ |
+		    MXS_I2C_CTRL1_SLAVE_STOP_IRQ | MXS_I2C_CTRL1_SLAVE_IRQ))
+		/* MXS_I2C_CTRL1_OVERSIZE_XFER_TERM_IRQ is only for slaves */
+		i2c->cmd_err = -EIO;
+
+	is_last_cmd = (readl(i2c->regs + MXS_I2C_QUEUESTAT) &
+		MXS_I2C_QUEUESTAT_WRITE_QUEUE_CNT_MASK) == 0;
+
+	if (is_last_cmd || i2c->cmd_err)
+		complete(&i2c->cmd_complete);
+
+	writel(stat, i2c->regs + MXS_I2C_CTRL1_CLR);
+
+	return IRQ_HANDLED;
+}
+
+static const struct i2c_algorithm mxs_i2c_algo = {
+	.master_xfer = mxs_i2c_xfer,
+	.functionality = mxs_i2c_func,
+};
+
+static int __devinit mxs_i2c_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct mxs_i2c_dev *i2c;
+	struct i2c_adapter *adap;
+	struct resource *res;
+	resource_size_t res_size;
+	int err, irq;
+
+	i2c = devm_kzalloc(dev, sizeof(struct mxs_i2c_dev), GFP_KERNEL);
+	if (!i2c)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENOENT;
+
+	res_size = resource_size(res);
+	if (!devm_request_mem_region(dev, res->start, res_size, res->name))
+		return -EBUSY;
+
+	i2c->regs = devm_ioremap_nocache(dev, res->start, res_size);
+	if (!i2c->regs)
+		return -EBUSY;
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0)
+		return irq;
+
+	err = devm_request_irq(dev, irq, mxs_i2c_isr, 0, dev_name(dev), i2c);
+	if (err)
+		return err;
+
+	i2c->dev = dev;
+	platform_set_drvdata(pdev, i2c);
+
+	/* Do reset to enforce correct startup after pinmuxing */
+	mxs_i2c_reset(i2c);
+
+	adap = &i2c->adapter;
+	strlcpy(adap->name, "MXS I2C adapter", sizeof(adap->name));
+	adap->owner = THIS_MODULE;
+	adap->algo = &mxs_i2c_algo;
+	adap->dev.parent = dev;
+	adap->nr = pdev->id;
+	i2c_set_adapdata(adap, i2c);
+	err = i2c_add_numbered_adapter(adap);
+	if (err) {
+		dev_err(dev, "Failed to add adapter (%d)\n", err);
+		writel(MXS_I2C_CTRL0_SFTRST,
+				i2c->regs + MXS_I2C_CTRL0_SET);
+		return err;
+	}
+
+	return 0;
+}
+
+static int __devexit mxs_i2c_remove(struct platform_device *pdev)
+{
+	struct mxs_i2c_dev *i2c = platform_get_drvdata(pdev);
+	int ret;
+
+	ret = i2c_del_adapter(&i2c->adapter);
+	if (ret)
+		return -EBUSY;
+
+	writel(MXS_I2C_CTRL0_SFTRST, i2c->regs + MXS_I2C_CTRL0_SET);
+
+	platform_set_drvdata(pdev, NULL);
+
+	return 0;
+}
+
+static struct platform_driver mxs_i2c_driver = {
+	.driver = {
+		   .name = DRIVER_NAME,
+		   .owner = THIS_MODULE,
+		   },
+	.remove = __devexit_p(mxs_i2c_remove),
+};
+
+static int __init mxs_i2c_init(void)
+{
+	return platform_driver_probe(&mxs_i2c_driver, mxs_i2c_probe);
+}
+subsys_initcall(mxs_i2c_init);
+
+static void __exit mxs_i2c_exit(void)
+{
+	platform_driver_unregister(&mxs_i2c_driver);
+}
+module_exit(mxs_i2c_exit);
+
+MODULE_AUTHOR("Wolfram Sang <w.sang@pengutronix.de>");
+MODULE_DESCRIPTION("MXS I2C Bus Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-nforce2-s4985.c b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-nforce2-s4985.c
new file mode 100644
index 0000000..29015eb
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-nforce2-s4985.c
@@ -0,0 +1,257 @@
+/*
+ * i2c-nforce2-s4985.c - i2c-nforce2 extras for the Tyan S4985 motherboard
+ *
+ * Copyright (C) 2008 Jean Delvare <khali@linux-fr.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * We select the channels by sending commands to the Philips
+ * PCA9556 chip at I2C address 0x18. The main adapter is used for
+ * the non-multiplexed part of the bus, and 4 virtual adapters
+ * are defined for the multiplexed addresses: 0x50-0x53 (memory
+ * module EEPROM) located on channels 1-4. We define one virtual
+ * adapter per CPU, which corresponds to one multiplexed channel:
+ *   CPU0: virtual adapter 1, channel 1
+ *   CPU1: virtual adapter 2, channel 2
+ *   CPU2: virtual adapter 3, channel 3
+ *   CPU3: virtual adapter 4, channel 4
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+
+extern struct i2c_adapter *nforce2_smbus;
+
+static struct i2c_adapter *s4985_adapter;
+static struct i2c_algorithm *s4985_algo;
+
+/* Wrapper access functions for multiplexed SMBus */
+static DEFINE_MUTEX(nforce2_lock);
+
+static s32 nforce2_access_virt0(struct i2c_adapter *adap, u16 addr,
+				unsigned short flags, char read_write,
+				u8 command, int size,
+				union i2c_smbus_data *data)
+{
+	int error;
+
+	/* We exclude the multiplexed addresses */
+	if ((addr & 0xfc) == 0x50 || (addr & 0xfc) == 0x30
+	 || addr == 0x18)
+		return -ENXIO;
+
+	mutex_lock(&nforce2_lock);
+	error = nforce2_smbus->algo->smbus_xfer(adap, addr, flags, read_write,
+						command, size, data);
+	mutex_unlock(&nforce2_lock);
+
+	return error;
+}
+
+/* We remember the last used channels combination so as to only switch
+   channels when it is really needed. This greatly reduces the SMBus
+   overhead, but also assumes that nobody will be writing to the PCA9556
+   in our back. */
+static u8 last_channels;
+
+static inline s32 nforce2_access_channel(struct i2c_adapter *adap, u16 addr,
+					 unsigned short flags, char read_write,
+					 u8 command, int size,
+					 union i2c_smbus_data *data,
+					 u8 channels)
+{
+	int error;
+
+	/* We exclude the non-multiplexed addresses */
+	if ((addr & 0xfc) != 0x50 && (addr & 0xfc) != 0x30)
+		return -ENXIO;
+
+	mutex_lock(&nforce2_lock);
+	if (last_channels != channels) {
+		union i2c_smbus_data mplxdata;
+		mplxdata.byte = channels;
+
+		error = nforce2_smbus->algo->smbus_xfer(adap, 0x18, 0,
+							I2C_SMBUS_WRITE, 0x01,
+							I2C_SMBUS_BYTE_DATA,
+							&mplxdata);
+		if (error)
+			goto UNLOCK;
+		last_channels = channels;
+	}
+	error = nforce2_smbus->algo->smbus_xfer(adap, addr, flags, read_write,
+						command, size, data);
+
+UNLOCK:
+	mutex_unlock(&nforce2_lock);
+	return error;
+}
+
+static s32 nforce2_access_virt1(struct i2c_adapter *adap, u16 addr,
+				unsigned short flags, char read_write,
+				u8 command, int size,
+				union i2c_smbus_data *data)
+{
+	/* CPU0: channel 1 enabled */
+	return nforce2_access_channel(adap, addr, flags, read_write, command,
+				      size, data, 0x02);
+}
+
+static s32 nforce2_access_virt2(struct i2c_adapter *adap, u16 addr,
+				unsigned short flags, char read_write,
+				u8 command, int size,
+				union i2c_smbus_data *data)
+{
+	/* CPU1: channel 2 enabled */
+	return nforce2_access_channel(adap, addr, flags, read_write, command,
+				      size, data, 0x04);
+}
+
+static s32 nforce2_access_virt3(struct i2c_adapter *adap, u16 addr,
+				unsigned short flags, char read_write,
+				u8 command, int size,
+				union i2c_smbus_data *data)
+{
+	/* CPU2: channel 3 enabled */
+	return nforce2_access_channel(adap, addr, flags, read_write, command,
+				      size, data, 0x08);
+}
+
+static s32 nforce2_access_virt4(struct i2c_adapter *adap, u16 addr,
+				unsigned short flags, char read_write,
+				u8 command, int size,
+				union i2c_smbus_data *data)
+{
+	/* CPU3: channel 4 enabled */
+	return nforce2_access_channel(adap, addr, flags, read_write, command,
+				      size, data, 0x10);
+}
+
+static int __init nforce2_s4985_init(void)
+{
+	int i, error;
+	union i2c_smbus_data ioconfig;
+
+	if (!nforce2_smbus)
+		return -ENODEV;
+
+	/* Configure the PCA9556 multiplexer */
+	ioconfig.byte = 0x00; /* All I/O to output mode */
+	error = i2c_smbus_xfer(nforce2_smbus, 0x18, 0, I2C_SMBUS_WRITE, 0x03,
+			       I2C_SMBUS_BYTE_DATA, &ioconfig);
+	if (error) {
+		dev_err(&nforce2_smbus->dev, "PCA9556 configuration failed\n");
+		error = -EIO;
+		goto ERROR0;
+	}
+
+	/* Unregister physical bus */
+	error = i2c_del_adapter(nforce2_smbus);
+	if (error) {
+		dev_err(&nforce2_smbus->dev, "Physical bus removal failed\n");
+		goto ERROR0;
+	}
+
+	printk(KERN_INFO "Enabling SMBus multiplexing for Tyan S4985\n");
+	/* Define the 5 virtual adapters and algorithms structures */
+	s4985_adapter = kzalloc(5 * sizeof(struct i2c_adapter), GFP_KERNEL);
+	if (!s4985_adapter) {
+		error = -ENOMEM;
+		goto ERROR1;
+	}
+	s4985_algo = kzalloc(5 * sizeof(struct i2c_algorithm), GFP_KERNEL);
+	if (!s4985_algo) {
+		error = -ENOMEM;
+		goto ERROR2;
+	}
+
+	/* Fill in the new structures */
+	s4985_algo[0] = *(nforce2_smbus->algo);
+	s4985_algo[0].smbus_xfer = nforce2_access_virt0;
+	s4985_adapter[0] = *nforce2_smbus;
+	s4985_adapter[0].algo = s4985_algo;
+	s4985_adapter[0].dev.parent = nforce2_smbus->dev.parent;
+	for (i = 1; i < 5; i++) {
+		s4985_algo[i] = *(nforce2_smbus->algo);
+		s4985_adapter[i] = *nforce2_smbus;
+		snprintf(s4985_adapter[i].name, sizeof(s4985_adapter[i].name),
+			 "SMBus nForce2 adapter (CPU%d)", i - 1);
+		s4985_adapter[i].algo = s4985_algo + i;
+		s4985_adapter[i].dev.parent = nforce2_smbus->dev.parent;
+	}
+	s4985_algo[1].smbus_xfer = nforce2_access_virt1;
+	s4985_algo[2].smbus_xfer = nforce2_access_virt2;
+	s4985_algo[3].smbus_xfer = nforce2_access_virt3;
+	s4985_algo[4].smbus_xfer = nforce2_access_virt4;
+
+	/* Register virtual adapters */
+	for (i = 0; i < 5; i++) {
+		error = i2c_add_adapter(s4985_adapter + i);
+		if (error) {
+			printk(KERN_ERR "i2c-nforce2-s4985: "
+			       "Virtual adapter %d registration "
+			       "failed, module not inserted\n", i);
+			for (i--; i >= 0; i--)
+				i2c_del_adapter(s4985_adapter + i);
+			goto ERROR3;
+		}
+	}
+
+	return 0;
+
+ERROR3:
+	kfree(s4985_algo);
+	s4985_algo = NULL;
+ERROR2:
+	kfree(s4985_adapter);
+	s4985_adapter = NULL;
+ERROR1:
+	/* Restore physical bus */
+	i2c_add_adapter(nforce2_smbus);
+ERROR0:
+	return error;
+}
+
+static void __exit nforce2_s4985_exit(void)
+{
+	if (s4985_adapter) {
+		int i;
+
+		for (i = 0; i < 5; i++)
+			i2c_del_adapter(s4985_adapter+i);
+		kfree(s4985_adapter);
+		s4985_adapter = NULL;
+	}
+	kfree(s4985_algo);
+	s4985_algo = NULL;
+
+	/* Restore physical bus */
+	if (i2c_add_adapter(nforce2_smbus))
+		printk(KERN_ERR "i2c-nforce2-s4985: "
+		       "Physical bus restoration failed\n");
+}
+
+MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
+MODULE_DESCRIPTION("S4985 SMBus multiplexing");
+MODULE_LICENSE("GPL");
+
+module_init(nforce2_s4985_init);
+module_exit(nforce2_s4985_exit);
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-nforce2.c b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-nforce2.c
new file mode 100644
index 0000000..43a96a1
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-nforce2.c
@@ -0,0 +1,468 @@
+/*
+    SMBus driver for nVidia nForce2 MCP
+
+    Added nForce3 Pro 150  Thomas Leibold <thomas@plx.com>,
+	Ported to 2.5 Patrick Dreker <patrick@dreker.de>,
+    Copyright (c) 2003  Hans-Frieder Vogt <hfvogt@arcor.de>,
+    Based on
+    SMBus 2.0 driver for AMD-8111 IO-Hub
+    Copyright (c) 2002 Vojtech Pavlik
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/*
+    SUPPORTED DEVICES		PCI ID
+    nForce2 MCP			0064
+    nForce2 Ultra 400 MCP	0084
+    nForce3 Pro150 MCP		00D4
+    nForce3 250Gb MCP		00E4
+    nForce4 MCP			0052
+    nForce4 MCP-04		0034
+    nForce MCP51		0264
+    nForce MCP55		0368
+    nForce MCP61		03EB
+    nForce MCP65		0446
+    nForce MCP67		0542
+    nForce MCP73		07D8
+    nForce MCP78S		0752
+    nForce MCP79		0AA2
+
+    This driver supports the 2 SMBuses that are included in the MCP of the
+    nForce2/3/4/5xx chipsets.
+*/
+
+/* Note: we assume there can only be one nForce2, with two SMBus interfaces */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/stddef.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/dmi.h>
+#include <linux/acpi.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR ("Hans-Frieder Vogt <hfvogt@gmx.net>");
+MODULE_DESCRIPTION("nForce2/3/4/5xx SMBus driver");
+
+
+struct nforce2_smbus {
+	struct i2c_adapter adapter;
+	int base;
+	int size;
+	int blockops;
+	int can_abort;
+};
+
+
+/*
+ * nVidia nForce2 SMBus control register definitions
+ * (Newer incarnations use standard BARs 4 and 5 instead)
+ */
+#define NFORCE_PCI_SMB1	0x50
+#define NFORCE_PCI_SMB2	0x54
+
+
+/*
+ * ACPI 2.0 chapter 13 SMBus 2.0 EC register model
+ */
+#define NVIDIA_SMB_PRTCL	(smbus->base + 0x00)	/* protocol, PEC */
+#define NVIDIA_SMB_STS		(smbus->base + 0x01)	/* status */
+#define NVIDIA_SMB_ADDR		(smbus->base + 0x02)	/* address */
+#define NVIDIA_SMB_CMD		(smbus->base + 0x03)	/* command */
+#define NVIDIA_SMB_DATA		(smbus->base + 0x04)	/* 32 data registers */
+#define NVIDIA_SMB_BCNT		(smbus->base + 0x24)	/* number of data
+							   bytes */
+#define NVIDIA_SMB_STATUS_ABRT	(smbus->base + 0x3c)	/* register used to
+							   check the status of
+							   the abort command */
+#define NVIDIA_SMB_CTRL		(smbus->base + 0x3e)	/* control register */
+
+#define NVIDIA_SMB_STATUS_ABRT_STS	0x01		/* Bit to notify that
+							   abort succeeded */
+#define NVIDIA_SMB_CTRL_ABORT	0x20
+#define NVIDIA_SMB_STS_DONE	0x80
+#define NVIDIA_SMB_STS_ALRM	0x40
+#define NVIDIA_SMB_STS_RES	0x20
+#define NVIDIA_SMB_STS_STATUS	0x1f
+
+#define NVIDIA_SMB_PRTCL_WRITE			0x00
+#define NVIDIA_SMB_PRTCL_READ			0x01
+#define NVIDIA_SMB_PRTCL_QUICK			0x02
+#define NVIDIA_SMB_PRTCL_BYTE			0x04
+#define NVIDIA_SMB_PRTCL_BYTE_DATA		0x06
+#define NVIDIA_SMB_PRTCL_WORD_DATA		0x08
+#define NVIDIA_SMB_PRTCL_BLOCK_DATA		0x0a
+#define NVIDIA_SMB_PRTCL_PEC			0x80
+
+/* Misc definitions */
+#define MAX_TIMEOUT	100
+
+/* We disable the second SMBus channel on these boards */
+static struct dmi_system_id __devinitdata nforce2_dmi_blacklist2[] = {
+	{
+		.ident = "DFI Lanparty NF4 Expert",
+		.matches = {
+			DMI_MATCH(DMI_BOARD_VENDOR, "DFI Corp,LTD"),
+			DMI_MATCH(DMI_BOARD_NAME, "LP UT NF4 Expert"),
+		},
+	},
+	{ }
+};
+
+static struct pci_driver nforce2_driver;
+
+/* For multiplexing support, we need a global reference to the 1st
+   SMBus channel */
+#if defined CONFIG_I2C_NFORCE2_S4985 || defined CONFIG_I2C_NFORCE2_S4985_MODULE
+struct i2c_adapter *nforce2_smbus;
+EXPORT_SYMBOL_GPL(nforce2_smbus);
+
+static void nforce2_set_reference(struct i2c_adapter *adap)
+{
+	nforce2_smbus = adap;
+}
+#else
+static inline void nforce2_set_reference(struct i2c_adapter *adap) { }
+#endif
+
+static void nforce2_abort(struct i2c_adapter *adap)
+{
+	struct nforce2_smbus *smbus = adap->algo_data;
+	int timeout = 0;
+	unsigned char temp;
+
+	dev_dbg(&adap->dev, "Aborting current transaction\n");
+
+	outb_p(NVIDIA_SMB_CTRL_ABORT, NVIDIA_SMB_CTRL);
+	do {
+		msleep(1);
+		temp = inb_p(NVIDIA_SMB_STATUS_ABRT);
+	} while (!(temp & NVIDIA_SMB_STATUS_ABRT_STS) &&
+			(timeout++ < MAX_TIMEOUT));
+	if (!(temp & NVIDIA_SMB_STATUS_ABRT_STS))
+		dev_err(&adap->dev, "Can't reset the smbus\n");
+	outb_p(NVIDIA_SMB_STATUS_ABRT_STS, NVIDIA_SMB_STATUS_ABRT);
+}
+
+static int nforce2_check_status(struct i2c_adapter *adap)
+{
+	struct nforce2_smbus *smbus = adap->algo_data;
+	int timeout = 0;
+	unsigned char temp;
+
+	do {
+		msleep(1);
+		temp = inb_p(NVIDIA_SMB_STS);
+	} while ((!temp) && (timeout++ < MAX_TIMEOUT));
+
+	if (timeout > MAX_TIMEOUT) {
+		dev_dbg(&adap->dev, "SMBus Timeout!\n");
+		if (smbus->can_abort)
+			nforce2_abort(adap);
+		return -ETIMEDOUT;
+	}
+	if (!(temp & NVIDIA_SMB_STS_DONE) || (temp & NVIDIA_SMB_STS_STATUS)) {
+		dev_dbg(&adap->dev, "Transaction failed (0x%02x)!\n", temp);
+		return -EIO;
+	}
+	return 0;
+}
+
+/* Return negative errno on error */
+static s32 nforce2_access(struct i2c_adapter * adap, u16 addr,
+		unsigned short flags, char read_write,
+		u8 command, int size, union i2c_smbus_data * data)
+{
+	struct nforce2_smbus *smbus = adap->algo_data;
+	unsigned char protocol, pec;
+	u8 len;
+	int i, status;
+
+	protocol = (read_write == I2C_SMBUS_READ) ? NVIDIA_SMB_PRTCL_READ :
+		NVIDIA_SMB_PRTCL_WRITE;
+	pec = (flags & I2C_CLIENT_PEC) ? NVIDIA_SMB_PRTCL_PEC : 0;
+
+	switch (size) {
+
+		case I2C_SMBUS_QUICK:
+			protocol |= NVIDIA_SMB_PRTCL_QUICK;
+			read_write = I2C_SMBUS_WRITE;
+			break;
+
+		case I2C_SMBUS_BYTE:
+			if (read_write == I2C_SMBUS_WRITE)
+				outb_p(command, NVIDIA_SMB_CMD);
+			protocol |= NVIDIA_SMB_PRTCL_BYTE;
+			break;
+
+		case I2C_SMBUS_BYTE_DATA:
+			outb_p(command, NVIDIA_SMB_CMD);
+			if (read_write == I2C_SMBUS_WRITE)
+				outb_p(data->byte, NVIDIA_SMB_DATA);
+			protocol |= NVIDIA_SMB_PRTCL_BYTE_DATA;
+			break;
+
+		case I2C_SMBUS_WORD_DATA:
+			outb_p(command, NVIDIA_SMB_CMD);
+			if (read_write == I2C_SMBUS_WRITE) {
+				 outb_p(data->word, NVIDIA_SMB_DATA);
+				 outb_p(data->word >> 8, NVIDIA_SMB_DATA+1);
+			}
+			protocol |= NVIDIA_SMB_PRTCL_WORD_DATA | pec;
+			break;
+
+		case I2C_SMBUS_BLOCK_DATA:
+			outb_p(command, NVIDIA_SMB_CMD);
+			if (read_write == I2C_SMBUS_WRITE) {
+				len = data->block[0];
+				if ((len == 0) || (len > I2C_SMBUS_BLOCK_MAX)) {
+					dev_err(&adap->dev,
+						"Transaction failed "
+						"(requested block size: %d)\n",
+						len);
+					return -EINVAL;
+				}
+				outb_p(len, NVIDIA_SMB_BCNT);
+				for (i = 0; i < I2C_SMBUS_BLOCK_MAX; i++)
+					outb_p(data->block[i + 1],
+					       NVIDIA_SMB_DATA+i);
+			}
+			protocol |= NVIDIA_SMB_PRTCL_BLOCK_DATA | pec;
+			break;
+
+		default:
+			dev_err(&adap->dev, "Unsupported transaction %d\n", size);
+			return -EOPNOTSUPP;
+	}
+
+	outb_p((addr & 0x7f) << 1, NVIDIA_SMB_ADDR);
+	outb_p(protocol, NVIDIA_SMB_PRTCL);
+
+	status = nforce2_check_status(adap);
+	if (status)
+		return status;
+
+	if (read_write == I2C_SMBUS_WRITE)
+		return 0;
+
+	switch (size) {
+
+		case I2C_SMBUS_BYTE:
+		case I2C_SMBUS_BYTE_DATA:
+			data->byte = inb_p(NVIDIA_SMB_DATA);
+			break;
+
+		case I2C_SMBUS_WORD_DATA:
+			data->word = inb_p(NVIDIA_SMB_DATA) | (inb_p(NVIDIA_SMB_DATA+1) << 8);
+			break;
+
+		case I2C_SMBUS_BLOCK_DATA:
+			len = inb_p(NVIDIA_SMB_BCNT);
+			if ((len <= 0) || (len > I2C_SMBUS_BLOCK_MAX)) {
+				dev_err(&adap->dev, "Transaction failed "
+					"(received block size: 0x%02x)\n",
+					len);
+				return -EPROTO;
+			}
+			for (i = 0; i < len; i++)
+				data->block[i+1] = inb_p(NVIDIA_SMB_DATA + i);
+			data->block[0] = len;
+			break;
+	}
+
+	return 0;
+}
+
+
+static u32 nforce2_func(struct i2c_adapter *adapter)
+{
+	/* other functionality might be possible, but is not tested */
+	return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+	       I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+	       I2C_FUNC_SMBUS_PEC |
+	       (((struct nforce2_smbus*)adapter->algo_data)->blockops ?
+		I2C_FUNC_SMBUS_BLOCK_DATA : 0);
+}
+
+static struct i2c_algorithm smbus_algorithm = {
+	.smbus_xfer	= nforce2_access,
+	.functionality	= nforce2_func,
+};
+
+
+static DEFINE_PCI_DEVICE_TABLE(nforce2_ids) = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2_SMBUS) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_SMBUS) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3_SMBUS) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SMBUS) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE4_SMBUS) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SMBUS) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SMBUS) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SMBUS) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SMBUS) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP65_SMBUS) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP67_SMBUS) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP73_SMBUS) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP78S_SMBUS) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP79_SMBUS) },
+	{ 0 }
+};
+
+MODULE_DEVICE_TABLE (pci, nforce2_ids);
+
+
+static int __devinit nforce2_probe_smb (struct pci_dev *dev, int bar,
+	int alt_reg, struct nforce2_smbus *smbus, const char *name)
+{
+	int error;
+
+	smbus->base = pci_resource_start(dev, bar);
+	if (smbus->base) {
+		smbus->size = pci_resource_len(dev, bar);
+	} else {
+		/* Older incarnations of the device used non-standard BARs */
+		u16 iobase;
+
+		if (pci_read_config_word(dev, alt_reg, &iobase)
+		    != PCIBIOS_SUCCESSFUL) {
+			dev_err(&dev->dev, "Error reading PCI config for %s\n",
+				name);
+			return -EIO;
+		}
+
+		smbus->base = iobase & PCI_BASE_ADDRESS_IO_MASK;
+		smbus->size = 64;
+	}
+
+	error = acpi_check_region(smbus->base, smbus->size,
+				  nforce2_driver.name);
+	if (error)
+		return error;
+
+	if (!request_region(smbus->base, smbus->size, nforce2_driver.name)) {
+		dev_err(&smbus->adapter.dev, "Error requesting region %02x .. %02X for %s\n",
+			smbus->base, smbus->base+smbus->size-1, name);
+		return -EBUSY;
+	}
+	smbus->adapter.owner = THIS_MODULE;
+	smbus->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
+	smbus->adapter.algo = &smbus_algorithm;
+	smbus->adapter.algo_data = smbus;
+	smbus->adapter.dev.parent = &dev->dev;
+	snprintf(smbus->adapter.name, sizeof(smbus->adapter.name),
+		"SMBus nForce2 adapter at %04x", smbus->base);
+
+	error = i2c_add_adapter(&smbus->adapter);
+	if (error) {
+		dev_err(&smbus->adapter.dev, "Failed to register adapter.\n");
+		release_region(smbus->base, smbus->size);
+		return error;
+	}
+	dev_info(&smbus->adapter.dev, "nForce2 SMBus adapter at %#x\n", smbus->base);
+	return 0;
+}
+
+
+static int __devinit nforce2_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	struct nforce2_smbus *smbuses;
+	int res1, res2;
+
+	/* we support 2 SMBus adapters */
+	if (!(smbuses = kzalloc(2*sizeof(struct nforce2_smbus), GFP_KERNEL)))
+		return -ENOMEM;
+	pci_set_drvdata(dev, smbuses);
+
+	switch(dev->device) {
+	case PCI_DEVICE_ID_NVIDIA_NFORCE2_SMBUS:
+	case PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SMBUS:
+	case PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SMBUS:
+		smbuses[0].blockops = 1;
+		smbuses[1].blockops = 1;
+		smbuses[0].can_abort = 1;
+		smbuses[1].can_abort = 1;
+	}
+
+	/* SMBus adapter 1 */
+	res1 = nforce2_probe_smb(dev, 4, NFORCE_PCI_SMB1, &smbuses[0], "SMB1");
+	if (res1 < 0)
+		smbuses[0].base = 0;	/* to have a check value */
+
+	/* SMBus adapter 2 */
+	if (dmi_check_system(nforce2_dmi_blacklist2)) {
+		dev_err(&dev->dev, "Disabling SMB2 for safety reasons.\n");
+		res2 = -EPERM;
+		smbuses[1].base = 0;
+	} else {
+		res2 = nforce2_probe_smb(dev, 5, NFORCE_PCI_SMB2, &smbuses[1],
+					 "SMB2");
+		if (res2 < 0)
+			smbuses[1].base = 0;	/* to have a check value */
+	}
+
+	if ((res1 < 0) && (res2 < 0)) {
+		/* we did not find even one of the SMBuses, so we give up */
+		kfree(smbuses);
+		return -ENODEV;
+	}
+
+	nforce2_set_reference(&smbuses[0].adapter);
+	return 0;
+}
+
+
+static void __devexit nforce2_remove(struct pci_dev *dev)
+{
+	struct nforce2_smbus *smbuses = pci_get_drvdata(dev);
+
+	nforce2_set_reference(NULL);
+	if (smbuses[0].base) {
+		i2c_del_adapter(&smbuses[0].adapter);
+		release_region(smbuses[0].base, smbuses[0].size);
+	}
+	if (smbuses[1].base) {
+		i2c_del_adapter(&smbuses[1].adapter);
+		release_region(smbuses[1].base, smbuses[1].size);
+	}
+	kfree(smbuses);
+}
+
+static struct pci_driver nforce2_driver = {
+	.name		= "nForce2_smbus",
+	.id_table	= nforce2_ids,
+	.probe		= nforce2_probe,
+	.remove		= __devexit_p(nforce2_remove),
+};
+
+static int __init nforce2_init(void)
+{
+	return pci_register_driver(&nforce2_driver);
+}
+
+static void __exit nforce2_exit(void)
+{
+	pci_unregister_driver(&nforce2_driver);
+}
+
+module_init(nforce2_init);
+module_exit(nforce2_exit);
+
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-nomadik.c b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-nomadik.c
new file mode 100644
index 0000000..5267ab9
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-nomadik.c
@@ -0,0 +1,1068 @@
+/*
+ * Copyright (C) 2009 ST-Ericsson SA
+ * Copyright (C) 2009 STMicroelectronics
+ *
+ * I2C master mode controller driver, used in Nomadik 8815
+ * and Ux500 platforms.
+ *
+ * Author: Srinidhi Kasagar <srinidhi.kasagar@stericsson.com>
+ * Author: Sachin Verma <sachin.verma@st.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/regulator/consumer.h>
+#include <linux/pm_runtime.h>
+
+#include <plat/i2c.h>
+
+#define DRIVER_NAME "nmk-i2c"
+
+/* I2C Controller register offsets */
+#define I2C_CR		(0x000)
+#define I2C_SCR		(0x004)
+#define I2C_HSMCR	(0x008)
+#define I2C_MCR		(0x00C)
+#define I2C_TFR		(0x010)
+#define I2C_SR		(0x014)
+#define I2C_RFR		(0x018)
+#define I2C_TFTR	(0x01C)
+#define I2C_RFTR	(0x020)
+#define I2C_DMAR	(0x024)
+#define I2C_BRCR	(0x028)
+#define I2C_IMSCR	(0x02C)
+#define I2C_RISR	(0x030)
+#define I2C_MISR	(0x034)
+#define I2C_ICR		(0x038)
+
+/* Control registers */
+#define I2C_CR_PE		(0x1 << 0)	/* Peripheral Enable */
+#define I2C_CR_OM		(0x3 << 1)	/* Operating mode */
+#define I2C_CR_SAM		(0x1 << 3)	/* Slave addressing mode */
+#define I2C_CR_SM		(0x3 << 4)	/* Speed mode */
+#define I2C_CR_SGCM		(0x1 << 6)	/* Slave general call mode */
+#define I2C_CR_FTX		(0x1 << 7)	/* Flush Transmit */
+#define I2C_CR_FRX		(0x1 << 8)	/* Flush Receive */
+#define I2C_CR_DMA_TX_EN	(0x1 << 9)	/* DMA Tx enable */
+#define I2C_CR_DMA_RX_EN	(0x1 << 10)	/* DMA Rx Enable */
+#define I2C_CR_DMA_SLE		(0x1 << 11)	/* DMA sync. logic enable */
+#define I2C_CR_LM		(0x1 << 12)	/* Loopback mode */
+#define I2C_CR_FON		(0x3 << 13)	/* Filtering on */
+#define I2C_CR_FS		(0x3 << 15)	/* Force stop enable */
+
+/* Master controller (MCR) register */
+#define I2C_MCR_OP		(0x1 << 0)	/* Operation */
+#define I2C_MCR_A7		(0x7f << 1)	/* 7-bit address */
+#define I2C_MCR_EA10		(0x7 << 8)	/* 10-bit Extended address */
+#define I2C_MCR_SB		(0x1 << 11)	/* Extended address */
+#define I2C_MCR_AM		(0x3 << 12)	/* Address type */
+#define I2C_MCR_STOP		(0x1 << 14)	/* Stop condition */
+#define I2C_MCR_LENGTH		(0x7ff << 15)	/* Transaction length */
+
+/* Status register (SR) */
+#define I2C_SR_OP		(0x3 << 0)	/* Operation */
+#define I2C_SR_STATUS		(0x3 << 2)	/* controller status */
+#define I2C_SR_CAUSE		(0x7 << 4)	/* Abort cause */
+#define I2C_SR_TYPE		(0x3 << 7)	/* Receive type */
+#define I2C_SR_LENGTH		(0x7ff << 9)	/* Transfer length */
+
+/* Interrupt mask set/clear (IMSCR) bits */
+#define I2C_IT_TXFE		(0x1 << 0)
+#define I2C_IT_TXFNE		(0x1 << 1)
+#define I2C_IT_TXFF		(0x1 << 2)
+#define I2C_IT_TXFOVR		(0x1 << 3)
+#define I2C_IT_RXFE		(0x1 << 4)
+#define I2C_IT_RXFNF		(0x1 << 5)
+#define I2C_IT_RXFF		(0x1 << 6)
+#define I2C_IT_RFSR		(0x1 << 16)
+#define I2C_IT_RFSE		(0x1 << 17)
+#define I2C_IT_WTSR		(0x1 << 18)
+#define I2C_IT_MTD		(0x1 << 19)
+#define I2C_IT_STD		(0x1 << 20)
+#define I2C_IT_MAL		(0x1 << 24)
+#define I2C_IT_BERR		(0x1 << 25)
+#define I2C_IT_MTDWS		(0x1 << 28)
+
+#define GEN_MASK(val, mask, sb)  (((val) << (sb)) & (mask))
+
+/* some bits in ICR are reserved */
+#define I2C_CLEAR_ALL_INTS	0x131f007f
+
+/* first three msb bits are reserved */
+#define IRQ_MASK(mask)		(mask & 0x1fffffff)
+
+/* maximum threshold value */
+#define MAX_I2C_FIFO_THRESHOLD	15
+
+enum i2c_status {
+	I2C_NOP,
+	I2C_ON_GOING,
+	I2C_OK,
+	I2C_ABORT
+};
+
+/* operation */
+enum i2c_operation {
+	I2C_NO_OPERATION = 0xff,
+	I2C_WRITE = 0x00,
+	I2C_READ = 0x01
+};
+
+/**
+ * struct i2c_nmk_client - client specific data
+ * @slave_adr: 7-bit slave address
+ * @count: no. bytes to be transferred
+ * @buffer: client data buffer
+ * @xfer_bytes: bytes transferred till now
+ * @operation: current I2C operation
+ */
+struct i2c_nmk_client {
+	unsigned short		slave_adr;
+	unsigned long		count;
+	unsigned char		*buffer;
+	unsigned long		xfer_bytes;
+	enum i2c_operation	operation;
+};
+
+/**
+ * struct nmk_i2c_dev - private data structure of the controller.
+ * @pdev: parent platform device.
+ * @adap: corresponding I2C adapter.
+ * @irq: interrupt line for the controller.
+ * @virtbase: virtual io memory area.
+ * @clk: hardware i2c block clock.
+ * @cfg: machine provided controller configuration.
+ * @cli: holder of client specific data.
+ * @stop: stop condition.
+ * @xfer_complete: acknowledge completion for a I2C message.
+ * @result: controller propogated result.
+ * @regulator: pointer to i2c regulator.
+ * @busy: Busy doing transfer.
+ */
+struct nmk_i2c_dev {
+	struct platform_device		*pdev;
+	struct i2c_adapter		adap;
+	int				irq;
+	void __iomem			*virtbase;
+	struct clk			*clk;
+	struct nmk_i2c_controller	cfg;
+	struct i2c_nmk_client		cli;
+	int				stop;
+	struct completion		xfer_complete;
+	int				result;
+	struct regulator		*regulator;
+	bool				busy;
+};
+
+/* controller's abort causes */
+static const char *abort_causes[] = {
+	"no ack received after address transmission",
+	"no ack received during data phase",
+	"ack received after xmission of master code",
+	"master lost arbitration",
+	"slave restarts",
+	"slave reset",
+	"overflow, maxsize is 2047 bytes",
+};
+
+static inline void i2c_set_bit(void __iomem *reg, u32 mask)
+{
+	writel(readl(reg) | mask, reg);
+}
+
+static inline void i2c_clr_bit(void __iomem *reg, u32 mask)
+{
+	writel(readl(reg) & ~mask, reg);
+}
+
+/**
+ * flush_i2c_fifo() - This function flushes the I2C FIFO
+ * @dev: private data of I2C Driver
+ *
+ * This function flushes the I2C Tx and Rx FIFOs. It returns
+ * 0 on successful flushing of FIFO
+ */
+static int flush_i2c_fifo(struct nmk_i2c_dev *dev)
+{
+#define LOOP_ATTEMPTS 10
+	int i;
+	unsigned long timeout;
+
+	/*
+	 * flush the transmit and receive FIFO. The flushing
+	 * operation takes several cycles before to be completed.
+	 * On the completion, the I2C internal logic clears these
+	 * bits, until then no one must access Tx, Rx FIFO and
+	 * should poll on these bits waiting for the completion.
+	 */
+	writel((I2C_CR_FTX | I2C_CR_FRX), dev->virtbase + I2C_CR);
+
+	for (i = 0; i < LOOP_ATTEMPTS; i++) {
+		timeout = jiffies + dev->adap.timeout;
+
+		while (!time_after(jiffies, timeout)) {
+			if ((readl(dev->virtbase + I2C_CR) &
+				(I2C_CR_FTX | I2C_CR_FRX)) == 0)
+					return 0;
+		}
+	}
+
+	dev_err(&dev->pdev->dev,
+		"flushing operation timed out giving up after %d attempts",
+		LOOP_ATTEMPTS);
+
+	return -ETIMEDOUT;
+}
+
+/**
+ * disable_all_interrupts() - Disable all interrupts of this I2c Bus
+ * @dev: private data of I2C Driver
+ */
+static void disable_all_interrupts(struct nmk_i2c_dev *dev)
+{
+	u32 mask = IRQ_MASK(0);
+	writel(mask, dev->virtbase + I2C_IMSCR);
+}
+
+/**
+ * clear_all_interrupts() - Clear all interrupts of I2C Controller
+ * @dev: private data of I2C Driver
+ */
+static void clear_all_interrupts(struct nmk_i2c_dev *dev)
+{
+	u32 mask;
+	mask = IRQ_MASK(I2C_CLEAR_ALL_INTS);
+	writel(mask, dev->virtbase + I2C_ICR);
+}
+
+/**
+ * init_hw() - initialize the I2C hardware
+ * @dev: private data of I2C Driver
+ */
+static int init_hw(struct nmk_i2c_dev *dev)
+{
+	int stat;
+
+	stat = flush_i2c_fifo(dev);
+	if (stat)
+		goto exit;
+
+	/* disable the controller */
+	i2c_clr_bit(dev->virtbase + I2C_CR , I2C_CR_PE);
+
+	disable_all_interrupts(dev);
+
+	clear_all_interrupts(dev);
+
+	dev->cli.operation = I2C_NO_OPERATION;
+
+exit:
+	return stat;
+}
+
+/* enable peripheral, master mode operation */
+#define DEFAULT_I2C_REG_CR	((1 << 1) | I2C_CR_PE)
+
+/**
+ * load_i2c_mcr_reg() - load the MCR register
+ * @dev: private data of controller
+ */
+static u32 load_i2c_mcr_reg(struct nmk_i2c_dev *dev)
+{
+	u32 mcr = 0;
+
+	/* 7-bit address transaction */
+	mcr |= GEN_MASK(1, I2C_MCR_AM, 12);
+	mcr |= GEN_MASK(dev->cli.slave_adr, I2C_MCR_A7, 1);
+
+	/* start byte procedure not applied */
+	mcr |= GEN_MASK(0, I2C_MCR_SB, 11);
+
+	/* check the operation, master read/write? */
+	if (dev->cli.operation == I2C_WRITE)
+		mcr |= GEN_MASK(I2C_WRITE, I2C_MCR_OP, 0);
+	else
+		mcr |= GEN_MASK(I2C_READ, I2C_MCR_OP, 0);
+
+	/* stop or repeated start? */
+	if (dev->stop)
+		mcr |= GEN_MASK(1, I2C_MCR_STOP, 14);
+	else
+		mcr &= ~(GEN_MASK(1, I2C_MCR_STOP, 14));
+
+	mcr |= GEN_MASK(dev->cli.count, I2C_MCR_LENGTH, 15);
+
+	return mcr;
+}
+
+/**
+ * setup_i2c_controller() - setup the controller
+ * @dev: private data of controller
+ */
+static void setup_i2c_controller(struct nmk_i2c_dev *dev)
+{
+	u32 brcr1, brcr2;
+	u32 i2c_clk, div;
+
+	writel(0x0, dev->virtbase + I2C_CR);
+	writel(0x0, dev->virtbase + I2C_HSMCR);
+	writel(0x0, dev->virtbase + I2C_TFTR);
+	writel(0x0, dev->virtbase + I2C_RFTR);
+	writel(0x0, dev->virtbase + I2C_DMAR);
+
+	/*
+	 * set the slsu:
+	 *
+	 * slsu defines the data setup time after SCL clock
+	 * stretching in terms of i2c clk cycles. The
+	 * needed setup time for the three modes are 250ns,
+	 * 100ns, 10ns respectively thus leading to the values
+	 * of 14, 6, 2 for a 48 MHz i2c clk.
+	 */
+	writel(dev->cfg.slsu << 16, dev->virtbase + I2C_SCR);
+
+	i2c_clk = clk_get_rate(dev->clk);
+
+	/* fallback to std. mode if machine has not provided it */
+	if (dev->cfg.clk_freq == 0)
+		dev->cfg.clk_freq = 100000;
+
+	/*
+	 * The spec says, in case of std. mode the divider is
+	 * 2 whereas it is 3 for fast and fastplus mode of
+	 * operation. TODO - high speed support.
+	 */
+	div = (dev->cfg.clk_freq > 100000) ? 3 : 2;
+
+	/*
+	 * generate the mask for baud rate counters. The controller
+	 * has two baud rate counters. One is used for High speed
+	 * operation, and the other is for std, fast mode, fast mode
+	 * plus operation. Currently we do not supprt high speed mode
+	 * so set brcr1 to 0.
+	 */
+	brcr1 = 0 << 16;
+	brcr2 = (i2c_clk/(dev->cfg.clk_freq * div)) & 0xffff;
+
+	/* set the baud rate counter register */
+	writel((brcr1 | brcr2), dev->virtbase + I2C_BRCR);
+
+	/*
+	 * set the speed mode. Currently we support
+	 * only standard and fast mode of operation
+	 * TODO - support for fast mode plus (up to 1Mb/s)
+	 * and high speed (up to 3.4 Mb/s)
+	 */
+	if (dev->cfg.sm > I2C_FREQ_MODE_FAST) {
+		dev_err(&dev->pdev->dev,
+			"do not support this mode defaulting to std. mode\n");
+		brcr2 = i2c_clk/(100000 * 2) & 0xffff;
+		writel((brcr1 | brcr2), dev->virtbase + I2C_BRCR);
+		writel(I2C_FREQ_MODE_STANDARD << 4,
+				dev->virtbase + I2C_CR);
+	}
+	writel(dev->cfg.sm << 4, dev->virtbase + I2C_CR);
+
+	/* set the Tx and Rx FIFO threshold */
+	writel(dev->cfg.tft, dev->virtbase + I2C_TFTR);
+	writel(dev->cfg.rft, dev->virtbase + I2C_RFTR);
+}
+
+/**
+ * read_i2c() - Read from I2C client device
+ * @dev: private data of I2C Driver
+ *
+ * This function reads from i2c client device when controller is in
+ * master mode. There is a completion timeout. If there is no transfer
+ * before timeout error is returned.
+ */
+static int read_i2c(struct nmk_i2c_dev *dev)
+{
+	u32 status = 0;
+	u32 mcr;
+	u32 irq_mask = 0;
+	int timeout;
+
+	mcr = load_i2c_mcr_reg(dev);
+	writel(mcr, dev->virtbase + I2C_MCR);
+
+	/* load the current CR value */
+	writel(readl(dev->virtbase + I2C_CR) | DEFAULT_I2C_REG_CR,
+			dev->virtbase + I2C_CR);
+
+	/* enable the controller */
+	i2c_set_bit(dev->virtbase + I2C_CR, I2C_CR_PE);
+
+	init_completion(&dev->xfer_complete);
+
+	/* enable interrupts by setting the mask */
+	irq_mask = (I2C_IT_RXFNF | I2C_IT_RXFF |
+			I2C_IT_MAL | I2C_IT_BERR);
+
+	if (dev->stop)
+		irq_mask |= I2C_IT_MTD;
+	else
+		irq_mask |= I2C_IT_MTDWS;
+
+	irq_mask = I2C_CLEAR_ALL_INTS & IRQ_MASK(irq_mask);
+
+	writel(readl(dev->virtbase + I2C_IMSCR) | irq_mask,
+			dev->virtbase + I2C_IMSCR);
+
+	timeout = wait_for_completion_timeout(
+		&dev->xfer_complete, dev->adap.timeout);
+
+	if (timeout < 0) {
+		dev_err(&dev->pdev->dev,
+			"wait_for_completion_timeout "
+			"returned %d waiting for event\n", timeout);
+		status = timeout;
+	}
+
+	if (timeout == 0) {
+		/* Controller timed out */
+		dev_err(&dev->pdev->dev, "read from slave 0x%x timed out\n",
+				dev->cli.slave_adr);
+		status = -ETIMEDOUT;
+	}
+	return status;
+}
+
+static void fill_tx_fifo(struct nmk_i2c_dev *dev, int no_bytes)
+{
+	int count;
+
+	for (count = (no_bytes - 2);
+			(count > 0) &&
+			(dev->cli.count != 0);
+			count--) {
+		/* write to the Tx FIFO */
+		writeb(*dev->cli.buffer,
+			dev->virtbase + I2C_TFR);
+		dev->cli.buffer++;
+		dev->cli.count--;
+		dev->cli.xfer_bytes++;
+	}
+
+}
+
+/**
+ * write_i2c() - Write data to I2C client.
+ * @dev: private data of I2C Driver
+ *
+ * This function writes data to I2C client
+ */
+static int write_i2c(struct nmk_i2c_dev *dev)
+{
+	u32 status = 0;
+	u32 mcr;
+	u32 irq_mask = 0;
+	int timeout;
+
+	mcr = load_i2c_mcr_reg(dev);
+
+	writel(mcr, dev->virtbase + I2C_MCR);
+
+	/* load the current CR value */
+	writel(readl(dev->virtbase + I2C_CR) | DEFAULT_I2C_REG_CR,
+			dev->virtbase + I2C_CR);
+
+	/* enable the controller */
+	i2c_set_bit(dev->virtbase + I2C_CR , I2C_CR_PE);
+
+	init_completion(&dev->xfer_complete);
+
+	/* enable interrupts by settings the masks */
+	irq_mask = (I2C_IT_TXFOVR | I2C_IT_MAL | I2C_IT_BERR);
+
+	/* Fill the TX FIFO with transmit data */
+	fill_tx_fifo(dev, MAX_I2C_FIFO_THRESHOLD);
+
+	if (dev->cli.count != 0)
+		irq_mask |= I2C_IT_TXFNE;
+
+	/*
+	 * check if we want to transfer a single or multiple bytes, if so
+	 * set the MTDWS bit (Master Transaction Done Without Stop)
+	 * to start repeated start operation
+	 */
+	if (dev->stop)
+		irq_mask |= I2C_IT_MTD;
+	else
+		irq_mask |= I2C_IT_MTDWS;
+
+	irq_mask = I2C_CLEAR_ALL_INTS & IRQ_MASK(irq_mask);
+
+	writel(readl(dev->virtbase + I2C_IMSCR) | irq_mask,
+			dev->virtbase + I2C_IMSCR);
+
+	timeout = wait_for_completion_timeout(
+		&dev->xfer_complete, dev->adap.timeout);
+
+	if (timeout < 0) {
+		dev_err(&dev->pdev->dev,
+			"wait_for_completion_timeout "
+			"returned %d waiting for event\n", timeout);
+		status = timeout;
+	}
+
+	if (timeout == 0) {
+		/* Controller timed out */
+		dev_err(&dev->pdev->dev, "write to slave 0x%x timed out\n",
+				dev->cli.slave_adr);
+		status = -ETIMEDOUT;
+	}
+
+	return status;
+}
+
+/**
+ * nmk_i2c_xfer_one() - transmit a single I2C message
+ * @dev: device with a message encoded into it
+ * @flags: message flags
+ */
+static int nmk_i2c_xfer_one(struct nmk_i2c_dev *dev, u16 flags)
+{
+	int status;
+
+	if (flags & I2C_M_RD) {
+		/* read operation */
+		dev->cli.operation = I2C_READ;
+		status = read_i2c(dev);
+	} else {
+		/* write operation */
+		dev->cli.operation = I2C_WRITE;
+		status = write_i2c(dev);
+	}
+
+	if (status || (dev->result)) {
+		u32 i2c_sr;
+		u32 cause;
+
+		i2c_sr = readl(dev->virtbase + I2C_SR);
+		/*
+		 * Check if the controller I2C operation status
+		 * is set to ABORT(11b).
+		 */
+		if (((i2c_sr >> 2) & 0x3) == 0x3) {
+			/* get the abort cause */
+			cause =	(i2c_sr >> 4) & 0x7;
+			dev_err(&dev->pdev->dev, "%s\n",
+				cause >= ARRAY_SIZE(abort_causes) ?
+				"unknown reason" :
+				abort_causes[cause]);
+		}
+
+		(void) init_hw(dev);
+
+		status = status ? status : dev->result;
+	}
+
+	return status;
+}
+
+/**
+ * nmk_i2c_xfer() - I2C transfer function used by kernel framework
+ * @i2c_adap: Adapter pointer to the controller
+ * @msgs: Pointer to data to be written.
+ * @num_msgs: Number of messages to be executed
+ *
+ * This is the function called by the generic kernel i2c_transfer()
+ * or i2c_smbus...() API calls. Note that this code is protected by the
+ * semaphore set in the kernel i2c_transfer() function.
+ *
+ * NOTE:
+ * READ TRANSFER : We impose a restriction of the first message to be the
+ *		index message for any read transaction.
+ *		- a no index is coded as '0',
+ *		- 2byte big endian index is coded as '3'
+ *		!!! msg[0].buf holds the actual index.
+ *		This is compatible with generic messages of smbus emulator
+ *		that send a one byte index.
+ *		eg. a I2C transation to read 2 bytes from index 0
+ *			idx = 0;
+ *			msg[0].addr = client->addr;
+ *			msg[0].flags = 0x0;
+ *			msg[0].len = 1;
+ *			msg[0].buf = &idx;
+ *
+ *			msg[1].addr = client->addr;
+ *			msg[1].flags = I2C_M_RD;
+ *			msg[1].len = 2;
+ *			msg[1].buf = rd_buff
+ *			i2c_transfer(adap, msg, 2);
+ *
+ * WRITE TRANSFER : The I2C standard interface interprets all data as payload.
+ *		If you want to emulate an SMBUS write transaction put the
+ *		index as first byte(or first and second) in the payload.
+ *		eg. a I2C transation to write 2 bytes from index 1
+ *			wr_buff[0] = 0x1;
+ *			wr_buff[1] = 0x23;
+ *			wr_buff[2] = 0x46;
+ *			msg[0].flags = 0x0;
+ *			msg[0].len = 3;
+ *			msg[0].buf = wr_buff;
+ *			i2c_transfer(adap, msg, 1);
+ *
+ * To read or write a block of data (multiple bytes) using SMBUS emulation
+ * please use the i2c_smbus_read_i2c_block_data()
+ * or i2c_smbus_write_i2c_block_data() API
+ */
+static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap,
+		struct i2c_msg msgs[], int num_msgs)
+{
+	int status;
+	int i;
+	struct nmk_i2c_dev *dev = i2c_get_adapdata(i2c_adap);
+	int j;
+
+	dev->busy = true;
+
+	if (dev->regulator)
+		regulator_enable(dev->regulator);
+	pm_runtime_get_sync(&dev->pdev->dev);
+
+	clk_enable(dev->clk);
+
+	status = init_hw(dev);
+	if (status)
+		goto out;
+
+	/* Attempt three times to send the message queue */
+	for (j = 0; j < 3; j++) {
+		/* setup the i2c controller */
+		setup_i2c_controller(dev);
+
+		for (i = 0; i < num_msgs; i++) {
+			if (unlikely(msgs[i].flags & I2C_M_TEN)) {
+				dev_err(&dev->pdev->dev,
+					"10 bit addressing not supported\n");
+
+				status = -EINVAL;
+				goto out;
+			}
+			dev->cli.slave_adr	= msgs[i].addr;
+			dev->cli.buffer		= msgs[i].buf;
+			dev->cli.count		= msgs[i].len;
+			dev->stop = (i < (num_msgs - 1)) ? 0 : 1;
+			dev->result = 0;
+
+			status = nmk_i2c_xfer_one(dev, msgs[i].flags);
+			if (status != 0)
+				break;
+		}
+		if (status == 0)
+			break;
+	}
+
+out:
+	clk_disable(dev->clk);
+	pm_runtime_put_sync(&dev->pdev->dev);
+	if (dev->regulator)
+		regulator_disable(dev->regulator);
+
+	dev->busy = false;
+
+	/* return the no. messages processed */
+	if (status)
+		return status;
+	else
+		return num_msgs;
+}
+
+/**
+ * disable_interrupts() - disable the interrupts
+ * @dev: private data of controller
+ * @irq: interrupt number
+ */
+static int disable_interrupts(struct nmk_i2c_dev *dev, u32 irq)
+{
+	irq = IRQ_MASK(irq);
+	writel(readl(dev->virtbase + I2C_IMSCR) & ~(I2C_CLEAR_ALL_INTS & irq),
+			dev->virtbase + I2C_IMSCR);
+	return 0;
+}
+
+/**
+ * i2c_irq_handler() - interrupt routine
+ * @irq: interrupt number
+ * @arg: data passed to the handler
+ *
+ * This is the interrupt handler for the i2c driver. Currently
+ * it handles the major interrupts like Rx & Tx FIFO management
+ * interrupts, master transaction interrupts, arbitration and
+ * bus error interrupts. The rest of the interrupts are treated as
+ * unhandled.
+ */
+static irqreturn_t i2c_irq_handler(int irq, void *arg)
+{
+	struct nmk_i2c_dev *dev = arg;
+	u32 tft, rft;
+	u32 count;
+	u32 misr;
+	u32 src = 0;
+
+	/* load Tx FIFO and Rx FIFO threshold values */
+	tft = readl(dev->virtbase + I2C_TFTR);
+	rft = readl(dev->virtbase + I2C_RFTR);
+
+	/* read interrupt status register */
+	misr = readl(dev->virtbase + I2C_MISR);
+
+	src = __ffs(misr);
+	switch ((1 << src)) {
+
+	/* Transmit FIFO nearly empty interrupt */
+	case I2C_IT_TXFNE:
+	{
+		if (dev->cli.operation == I2C_READ) {
+			/*
+			 * in read operation why do we care for writing?
+			 * so disable the Transmit FIFO interrupt
+			 */
+			disable_interrupts(dev, I2C_IT_TXFNE);
+		} else {
+			fill_tx_fifo(dev, (MAX_I2C_FIFO_THRESHOLD - tft));
+			/*
+			 * if done, close the transfer by disabling the
+			 * corresponding TXFNE interrupt
+			 */
+			if (dev->cli.count == 0)
+				disable_interrupts(dev,	I2C_IT_TXFNE);
+		}
+	}
+	break;
+
+	/*
+	 * Rx FIFO nearly full interrupt.
+	 * This is set when the numer of entries in Rx FIFO is
+	 * greater or equal than the threshold value programmed
+	 * in RFT
+	 */
+	case I2C_IT_RXFNF:
+		for (count = rft; count > 0; count--) {
+			/* Read the Rx FIFO */
+			*dev->cli.buffer = readb(dev->virtbase + I2C_RFR);
+			dev->cli.buffer++;
+		}
+		dev->cli.count -= rft;
+		dev->cli.xfer_bytes += rft;
+		break;
+
+	/* Rx FIFO full */
+	case I2C_IT_RXFF:
+		for (count = MAX_I2C_FIFO_THRESHOLD; count > 0; count--) {
+			*dev->cli.buffer = readb(dev->virtbase + I2C_RFR);
+			dev->cli.buffer++;
+		}
+		dev->cli.count -= MAX_I2C_FIFO_THRESHOLD;
+		dev->cli.xfer_bytes += MAX_I2C_FIFO_THRESHOLD;
+		break;
+
+	/* Master Transaction Done with/without stop */
+	case I2C_IT_MTD:
+	case I2C_IT_MTDWS:
+		if (dev->cli.operation == I2C_READ) {
+			while (!(readl(dev->virtbase + I2C_RISR)
+				 & I2C_IT_RXFE)) {
+				if (dev->cli.count == 0)
+					break;
+				*dev->cli.buffer =
+					readb(dev->virtbase + I2C_RFR);
+				dev->cli.buffer++;
+				dev->cli.count--;
+				dev->cli.xfer_bytes++;
+			}
+		}
+
+		disable_all_interrupts(dev);
+		clear_all_interrupts(dev);
+
+		if (dev->cli.count) {
+			dev->result = -EIO;
+			dev_err(&dev->pdev->dev,
+				"%lu bytes still remain to be xfered\n",
+				dev->cli.count);
+			(void) init_hw(dev);
+		}
+		complete(&dev->xfer_complete);
+
+		break;
+
+	/* Master Arbitration lost interrupt */
+	case I2C_IT_MAL:
+		dev->result = -EIO;
+		(void) init_hw(dev);
+
+		i2c_set_bit(dev->virtbase + I2C_ICR, I2C_IT_MAL);
+		complete(&dev->xfer_complete);
+
+		break;
+
+	/*
+	 * Bus Error interrupt.
+	 * This happens when an unexpected start/stop condition occurs
+	 * during the transaction.
+	 */
+	case I2C_IT_BERR:
+		dev->result = -EIO;
+		/* get the status */
+		if (((readl(dev->virtbase + I2C_SR) >> 2) & 0x3) == I2C_ABORT)
+			(void) init_hw(dev);
+
+		i2c_set_bit(dev->virtbase + I2C_ICR, I2C_IT_BERR);
+		complete(&dev->xfer_complete);
+
+		break;
+
+	/*
+	 * Tx FIFO overrun interrupt.
+	 * This is set when a write operation in Tx FIFO is performed and
+	 * the Tx FIFO is full.
+	 */
+	case I2C_IT_TXFOVR:
+		dev->result = -EIO;
+		(void) init_hw(dev);
+
+		dev_err(&dev->pdev->dev, "Tx Fifo Over run\n");
+		complete(&dev->xfer_complete);
+
+		break;
+
+	/* unhandled interrupts by this driver - TODO*/
+	case I2C_IT_TXFE:
+	case I2C_IT_TXFF:
+	case I2C_IT_RXFE:
+	case I2C_IT_RFSR:
+	case I2C_IT_RFSE:
+	case I2C_IT_WTSR:
+	case I2C_IT_STD:
+		dev_err(&dev->pdev->dev, "unhandled Interrupt\n");
+		break;
+	default:
+		dev_err(&dev->pdev->dev, "spurious Interrupt..\n");
+		break;
+	}
+
+	return IRQ_HANDLED;
+}
+
+
+#ifdef CONFIG_PM
+static int nmk_i2c_suspend(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct nmk_i2c_dev *nmk_i2c = platform_get_drvdata(pdev);
+
+	if (nmk_i2c->busy)
+		return -EBUSY;
+
+	return 0;
+}
+
+static int nmk_i2c_resume(struct device *dev)
+{
+	return 0;
+}
+#else
+#define nmk_i2c_suspend	NULL
+#define nmk_i2c_resume	NULL
+#endif
+
+/*
+ * We use noirq so that we suspend late and resume before the wakeup interrupt
+ * to ensure that we do the !pm_runtime_suspended() check in resume before
+ * there has been a regular pm runtime resume (via pm_runtime_get_sync()).
+ */
+static const struct dev_pm_ops nmk_i2c_pm = {
+	.suspend_noirq	= nmk_i2c_suspend,
+	.resume_noirq	= nmk_i2c_resume,
+};
+
+static unsigned int nmk_i2c_functionality(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm nmk_i2c_algo = {
+	.master_xfer	= nmk_i2c_xfer,
+	.functionality	= nmk_i2c_functionality
+};
+
+static int __devinit nmk_i2c_probe(struct platform_device *pdev)
+{
+	int ret = 0;
+	struct resource *res;
+	struct nmk_i2c_controller *pdata =
+			pdev->dev.platform_data;
+	struct nmk_i2c_dev	*dev;
+	struct i2c_adapter *adap;
+
+	dev = kzalloc(sizeof(struct nmk_i2c_dev), GFP_KERNEL);
+	if (!dev) {
+		dev_err(&pdev->dev, "cannot allocate memory\n");
+		ret = -ENOMEM;
+		goto err_no_mem;
+	}
+	dev->busy = false;
+	dev->pdev = pdev;
+	platform_set_drvdata(pdev, dev);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		ret = -ENOENT;
+		goto err_no_resource;
+	}
+
+	if (request_mem_region(res->start, resource_size(res),
+		DRIVER_NAME "I/O region") == NULL) {
+		ret = -EBUSY;
+		goto err_no_region;
+	}
+
+	dev->virtbase = ioremap(res->start, resource_size(res));
+	if (!dev->virtbase) {
+		ret = -ENOMEM;
+		goto err_no_ioremap;
+	}
+
+	dev->irq = platform_get_irq(pdev, 0);
+	ret = request_irq(dev->irq, i2c_irq_handler, 0,
+				DRIVER_NAME, dev);
+	if (ret) {
+		dev_err(&pdev->dev, "cannot claim the irq %d\n", dev->irq);
+		goto err_irq;
+	}
+
+	dev->regulator = regulator_get(&pdev->dev, "v-i2c");
+	if (IS_ERR(dev->regulator)) {
+		dev_warn(&pdev->dev, "could not get i2c regulator\n");
+		dev->regulator = NULL;
+	}
+
+	pm_suspend_ignore_children(&pdev->dev, true);
+	pm_runtime_enable(&pdev->dev);
+
+	dev->clk = clk_get(&pdev->dev, NULL);
+	if (IS_ERR(dev->clk)) {
+		dev_err(&pdev->dev, "could not get i2c clock\n");
+		ret = PTR_ERR(dev->clk);
+		goto err_no_clk;
+	}
+
+	adap = &dev->adap;
+	adap->dev.parent = &pdev->dev;
+	adap->owner	= THIS_MODULE;
+	adap->class	= I2C_CLASS_HWMON | I2C_CLASS_SPD;
+	adap->algo	= &nmk_i2c_algo;
+	adap->timeout	= pdata->timeout ? msecs_to_jiffies(pdata->timeout) :
+		msecs_to_jiffies(20000);
+	snprintf(adap->name, sizeof(adap->name),
+		 "Nomadik I2C%d at %lx", pdev->id, (unsigned long)res->start);
+
+	/* fetch the controller id */
+	adap->nr	= pdev->id;
+
+	/* fetch the controller configuration from machine */
+	dev->cfg.clk_freq = pdata->clk_freq;
+	dev->cfg.slsu	= pdata->slsu;
+	dev->cfg.tft	= pdata->tft;
+	dev->cfg.rft	= pdata->rft;
+	dev->cfg.sm	= pdata->sm;
+
+	i2c_set_adapdata(adap, dev);
+
+	dev_info(&pdev->dev,
+		 "initialize %s on virtual base %p\n",
+		 adap->name, dev->virtbase);
+
+	ret = i2c_add_numbered_adapter(adap);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to add adapter\n");
+		goto err_add_adap;
+	}
+
+	return 0;
+
+ err_add_adap:
+	clk_put(dev->clk);
+ err_no_clk:
+	if (dev->regulator)
+		regulator_put(dev->regulator);
+	pm_runtime_disable(&pdev->dev);
+	free_irq(dev->irq, dev);
+ err_irq:
+	iounmap(dev->virtbase);
+ err_no_ioremap:
+	release_mem_region(res->start, resource_size(res));
+ err_no_region:
+	platform_set_drvdata(pdev, NULL);
+ err_no_resource:
+	kfree(dev);
+ err_no_mem:
+
+	return ret;
+}
+
+static int __devexit nmk_i2c_remove(struct platform_device *pdev)
+{
+	struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	struct nmk_i2c_dev *dev = platform_get_drvdata(pdev);
+
+	i2c_del_adapter(&dev->adap);
+	flush_i2c_fifo(dev);
+	disable_all_interrupts(dev);
+	clear_all_interrupts(dev);
+	/* disable the controller */
+	i2c_clr_bit(dev->virtbase + I2C_CR, I2C_CR_PE);
+	free_irq(dev->irq, dev);
+	iounmap(dev->virtbase);
+	if (res)
+		release_mem_region(res->start, resource_size(res));
+	clk_put(dev->clk);
+	if (dev->regulator)
+		regulator_put(dev->regulator);
+	pm_runtime_disable(&pdev->dev);
+	platform_set_drvdata(pdev, NULL);
+	kfree(dev);
+
+	return 0;
+}
+
+static struct platform_driver nmk_i2c_driver = {
+	.driver = {
+		.owner = THIS_MODULE,
+		.name = DRIVER_NAME,
+		.pm = &nmk_i2c_pm,
+	},
+	.probe = nmk_i2c_probe,
+	.remove = __devexit_p(nmk_i2c_remove),
+};
+
+static int __init nmk_i2c_init(void)
+{
+	return platform_driver_register(&nmk_i2c_driver);
+}
+
+static void __exit nmk_i2c_exit(void)
+{
+	platform_driver_unregister(&nmk_i2c_driver);
+}
+
+subsys_initcall(nmk_i2c_init);
+module_exit(nmk_i2c_exit);
+
+MODULE_AUTHOR("Sachin Verma, Srinidhi KASAGAR");
+MODULE_DESCRIPTION("Nomadik/Ux500 I2C driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-nuc900.c b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-nuc900.c
new file mode 100644
index 0000000..03b6157
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-nuc900.c
@@ -0,0 +1,708 @@
+/*
+ * linux/drivers/i2c/busses/i2c-nuc900.c
+ *
+ * Copyright (c) 2010 Nuvoton technology corporation.
+ *
+ * This driver based on S3C2410 I2C driver of Ben Dooks <ben-Y5A6D6n0/KfQXOPxS62xeg@public.gmane.org>.
+ * Written by Wan ZongShun <mcuos.com-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation;version 2 of the License.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/time.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/cpufreq.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+
+#include <mach/mfp.h>
+#include <mach/i2c.h>
+
+/* nuc900 i2c registers offset */
+
+#define CSR		0x00
+#define DIVIDER		0x04
+#define CMDR		0x08
+#define SWR		0x0C
+#define RXR		0x10
+#define TXR		0x14
+
+/* nuc900 i2c CSR register bits */
+
+#define IRQEN		0x003
+#define I2CBUSY		0x400
+#define I2CSTART	0x018
+#define IRQFLAG		0x004
+#define ARBIT_LOST	0x200
+#define SLAVE_ACK	0x800
+
+/* nuc900 i2c CMDR register bits */
+
+#define I2C_CMD_START	0x10
+#define I2C_CMD_STOP	0x08
+#define I2C_CMD_READ	0x04
+#define I2C_CMD_WRITE	0x02
+#define I2C_CMD_NACK	0x01
+
+/* i2c controller state */
+
+enum nuc900_i2c_state {
+	STATE_IDLE,
+	STATE_START,
+	STATE_READ,
+	STATE_WRITE,
+	STATE_STOP
+};
+
+/* i2c controller private data */
+
+struct nuc900_i2c {
+	spinlock_t		lock;
+	wait_queue_head_t	wait;
+
+	struct i2c_msg		*msg;
+	unsigned int		msg_num;
+	unsigned int		msg_idx;
+	unsigned int		msg_ptr;
+	unsigned int		irq;
+
+	enum nuc900_i2c_state	state;
+
+	void __iomem		*regs;
+	struct clk		*clk;
+	struct device		*dev;
+	struct resource		*ioarea;
+	struct i2c_adapter	adap;
+};
+
+/* nuc900_i2c_master_complete
+ *
+ * complete the message and wake up the caller, using the given return code,
+ * or zero to mean ok.
+*/
+
+static inline void nuc900_i2c_master_complete(struct nuc900_i2c *i2c, int ret)
+{
+	dev_dbg(i2c->dev, "master_complete %d\n", ret);
+
+	i2c->msg_ptr = 0;
+	i2c->msg = NULL;
+	i2c->msg_idx++;
+	i2c->msg_num = 0;
+	if (ret)
+		i2c->msg_idx = ret;
+
+	wake_up(&i2c->wait);
+}
+
+/* irq enable/disable functions */
+
+static inline void nuc900_i2c_disable_irq(struct nuc900_i2c *i2c)
+{
+	unsigned long tmp;
+
+	tmp = readl(i2c->regs + CSR);
+	writel(tmp & ~IRQEN, i2c->regs + CSR);
+}
+
+static inline void nuc900_i2c_enable_irq(struct nuc900_i2c *i2c)
+{
+	unsigned long tmp;
+
+	tmp = readl(i2c->regs + CSR);
+	writel(tmp | IRQEN, i2c->regs + CSR);
+}
+
+
+/* nuc900_i2c_message_start
+ *
+ * put the start of a message onto the bus
+*/
+
+static void nuc900_i2c_message_start(struct nuc900_i2c *i2c,
+				      struct i2c_msg *msg)
+{
+	unsigned int addr = (msg->addr & 0x7f) << 1;
+
+	if (msg->flags & I2C_M_RD)
+		addr |= 0x1;
+	writel(addr & 0xff, i2c->regs + TXR);
+	writel(I2C_CMD_START | I2C_CMD_WRITE, i2c->regs + CMDR);
+}
+
+static inline void nuc900_i2c_stop(struct nuc900_i2c *i2c, int ret)
+{
+
+	dev_dbg(i2c->dev, "STOP\n");
+
+	/* stop the transfer */
+	i2c->state = STATE_STOP;
+	writel(I2C_CMD_STOP, i2c->regs + CMDR);
+
+	nuc900_i2c_master_complete(i2c, ret);
+	nuc900_i2c_disable_irq(i2c);
+}
+
+/* helper functions to determine the current state in the set of
+ * messages we are sending
+*/
+
+/* is_lastmsg()
+ *
+ * returns TRUE if the current message is the last in the set
+*/
+
+static inline int is_lastmsg(struct nuc900_i2c *i2c)
+{
+	return i2c->msg_idx >= (i2c->msg_num - 1);
+}
+
+/* is_msglast
+ *
+ * returns TRUE if we this is the last byte in the current message
+*/
+
+static inline int is_msglast(struct nuc900_i2c *i2c)
+{
+	return i2c->msg_ptr == i2c->msg->len-1;
+}
+
+/* is_msgend
+ *
+ * returns TRUE if we reached the end of the current message
+*/
+
+static inline int is_msgend(struct nuc900_i2c *i2c)
+{
+	return i2c->msg_ptr >= i2c->msg->len;
+}
+
+/* i2c_nuc900_irq_nextbyte
+ *
+ * process an interrupt and work out what to do
+ */
+
+static void i2c_nuc900_irq_nextbyte(struct nuc900_i2c *i2c,
+							unsigned long iicstat)
+{
+	unsigned char byte;
+
+	switch (i2c->state) {
+
+	case STATE_IDLE:
+		dev_err(i2c->dev, "%s: called in STATE_IDLE\n", __func__);
+		break;
+
+	case STATE_STOP:
+		dev_err(i2c->dev, "%s: called in STATE_STOP\n", __func__);
+		nuc900_i2c_disable_irq(i2c);
+		break;
+
+	case STATE_START:
+		/* last thing we did was send a start condition on the
+		 * bus, or started a new i2c message
+		 */
+
+		if (iicstat & SLAVE_ACK &&
+		    !(i2c->msg->flags & I2C_M_IGNORE_NAK)) {
+			/* ack was not received... */
+
+			dev_dbg(i2c->dev, "ack was not received\n");
+			nuc900_i2c_stop(i2c, -ENXIO);
+			break;
+		}
+
+		if (i2c->msg->flags & I2C_M_RD)
+			i2c->state = STATE_READ;
+		else
+			i2c->state = STATE_WRITE;
+
+		/* terminate the transfer if there is nothing to do
+		 * as this is used by the i2c probe to find devices.
+		*/
+
+		if (is_lastmsg(i2c) && i2c->msg->len == 0) {
+			nuc900_i2c_stop(i2c, 0);
+			break;
+		}
+
+		if (i2c->state == STATE_READ)
+			goto prepare_read;
+
+		/* fall through to the write state, as we will need to
+		 * send a byte as well
+		*/
+
+	case STATE_WRITE:
+		/* we are writing data to the device... check for the
+		 * end of the message, and if so, work out what to do
+		 */
+
+		if (!(i2c->msg->flags & I2C_M_IGNORE_NAK)) {
+			if (iicstat & SLAVE_ACK) {
+				dev_dbg(i2c->dev, "WRITE: No Ack\n");
+
+				nuc900_i2c_stop(i2c, -ECONNREFUSED);
+				break;
+			}
+		}
+
+retry_write:
+
+		if (!is_msgend(i2c)) {
+			byte = i2c->msg->buf[i2c->msg_ptr++];
+			writeb(byte, i2c->regs + TXR);
+			writel(I2C_CMD_WRITE, i2c->regs + CMDR);
+
+		} else if (!is_lastmsg(i2c)) {
+			/* we need to go to the next i2c message */
+
+			dev_dbg(i2c->dev, "WRITE: Next Message\n");
+
+			i2c->msg_ptr = 0;
+			i2c->msg_idx++;
+			i2c->msg++;
+
+			/* check to see if we need to do another message */
+			if (i2c->msg->flags & I2C_M_NOSTART) {
+
+				if (i2c->msg->flags & I2C_M_RD) {
+					/* cannot do this, the controller
+					 * forces us to send a new START
+					 * when we change direction
+					*/
+
+					nuc900_i2c_stop(i2c, -EINVAL);
+				}
+
+				goto retry_write;
+			} else {
+				/* send the new start */
+				nuc900_i2c_message_start(i2c, i2c->msg);
+				i2c->state = STATE_START;
+			}
+
+		} else {
+			/* send stop */
+
+			nuc900_i2c_stop(i2c, 0);
+		}
+		break;
+
+	case STATE_READ:
+		/* we have a byte of data in the data register, do
+		 * something with it, and then work out wether we are
+		 * going to do any more read/write
+		 */
+
+		byte = readb(i2c->regs + RXR);
+		i2c->msg->buf[i2c->msg_ptr++] = byte;
+
+prepare_read:
+		if (is_msglast(i2c)) {
+			/* last byte of buffer */
+
+			if (is_lastmsg(i2c))
+				writel(I2C_CMD_READ | I2C_CMD_NACK,
+							i2c->regs + CMDR);
+
+		} else if (is_msgend(i2c)) {
+			/* ok, we've read the entire buffer, see if there
+			 * is anything else we need to do
+			*/
+
+			if (is_lastmsg(i2c)) {
+				/* last message, send stop and complete */
+				dev_dbg(i2c->dev, "READ: Send Stop\n");
+
+				nuc900_i2c_stop(i2c, 0);
+			} else {
+				/* go to the next transfer */
+				dev_dbg(i2c->dev, "READ: Next Transfer\n");
+
+				i2c->msg_ptr = 0;
+				i2c->msg_idx++;
+				i2c->msg++;
+
+				writel(I2C_CMD_READ, i2c->regs + CMDR);
+			}
+
+		} else {
+			writel(I2C_CMD_READ, i2c->regs + CMDR);
+		}
+
+		break;
+	}
+}
+
+/* nuc900_i2c_irq
+ *
+ * top level IRQ servicing routine
+*/
+
+static irqreturn_t nuc900_i2c_irq(int irqno, void *dev_id)
+{
+	struct nuc900_i2c *i2c = dev_id;
+	unsigned long status;
+
+	status = readl(i2c->regs + CSR);
+	writel(status | IRQFLAG, i2c->regs + CSR);
+
+	if (status & ARBIT_LOST) {
+		/* deal with arbitration loss */
+		dev_err(i2c->dev, "deal with arbitration loss\n");
+		goto out;
+	}
+
+	if (i2c->state == STATE_IDLE) {
+		dev_dbg(i2c->dev, "IRQ: error i2c->state == IDLE\n");
+		goto out;
+	}
+
+	/* pretty much this leaves us with the fact that we've
+	 * transmitted or received whatever byte we last sent
+	*/
+
+	i2c_nuc900_irq_nextbyte(i2c, status);
+
+ out:
+	return IRQ_HANDLED;
+}
+
+
+/* nuc900_i2c_set_master
+ *
+ * get the i2c bus for a master transaction
+*/
+
+static int nuc900_i2c_set_master(struct nuc900_i2c *i2c)
+{
+	int timeout = 400;
+
+	while (timeout-- > 0) {
+		if (((readl(i2c->regs + SWR) & I2CSTART) == I2CSTART) &&
+				((readl(i2c->regs + CSR) & I2CBUSY) == 0)) {
+			return 0;
+		}
+
+		msleep(1);
+	}
+
+	return -ETIMEDOUT;
+}
+
+/* nuc900_i2c_doxfer
+ *
+ * this starts an i2c transfer
+*/
+
+static int nuc900_i2c_doxfer(struct nuc900_i2c *i2c,
+			      struct i2c_msg *msgs, int num)
+{
+	unsigned long iicstat, timeout;
+	int spins = 20;
+	int ret;
+
+	ret = nuc900_i2c_set_master(i2c);
+	if (ret != 0) {
+		dev_err(i2c->dev, "cannot get bus (error %d)\n", ret);
+		ret = -EAGAIN;
+		goto out;
+	}
+
+	spin_lock_irq(&i2c->lock);
+
+	i2c->msg     = msgs;
+	i2c->msg_num = num;
+	i2c->msg_ptr = 0;
+	i2c->msg_idx = 0;
+	i2c->state   = STATE_START;
+
+	nuc900_i2c_message_start(i2c, msgs);
+	spin_unlock_irq(&i2c->lock);
+
+	timeout = wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5);
+
+	ret = i2c->msg_idx;
+
+	/* having these next two as dev_err() makes life very
+	 * noisy when doing an i2cdetect
+	*/
+
+	if (timeout == 0)
+		dev_dbg(i2c->dev, "timeout\n");
+	else if (ret != num)
+		dev_dbg(i2c->dev, "incomplete xfer (%d)\n", ret);
+
+	/* ensure the stop has been through the bus */
+
+	dev_dbg(i2c->dev, "waiting for bus idle\n");
+
+	/* first, try busy waiting briefly */
+	do {
+		iicstat = readl(i2c->regs + CSR);
+	} while ((iicstat & I2CBUSY) && --spins);
+
+	/* if that timed out sleep */
+	if (!spins) {
+		msleep(1);
+		iicstat = readl(i2c->regs + CSR);
+	}
+
+	if (iicstat & I2CBUSY)
+		dev_warn(i2c->dev, "timeout waiting for bus idle\n");
+
+ out:
+	return ret;
+}
+
+/* nuc900_i2c_xfer
+ *
+ * first port of call from the i2c bus code when an message needs
+ * transferring across the i2c bus.
+*/
+
+static int nuc900_i2c_xfer(struct i2c_adapter *adap,
+			struct i2c_msg *msgs, int num)
+{
+	struct nuc900_i2c *i2c = (struct nuc900_i2c *)adap->algo_data;
+	int retry;
+	int ret;
+
+	nuc900_i2c_enable_irq(i2c);
+
+	for (retry = 0; retry < adap->retries; retry++) {
+
+		ret = nuc900_i2c_doxfer(i2c, msgs, num);
+
+		if (ret != -EAGAIN)
+			return ret;
+
+		dev_dbg(i2c->dev, "Retrying transmission (%d)\n", retry);
+
+		udelay(100);
+	}
+
+	return -EREMOTEIO;
+}
+
+/* declare our i2c functionality */
+static u32 nuc900_i2c_func(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_PROTOCOL_MANGLING;
+}
+
+/* i2c bus registration info */
+
+static const struct i2c_algorithm nuc900_i2c_algorithm = {
+	.master_xfer		= nuc900_i2c_xfer,
+	.functionality		= nuc900_i2c_func,
+};
+
+/* nuc900_i2c_probe
+ *
+ * called by the bus driver when a suitable device is found
+*/
+
+static int __devinit nuc900_i2c_probe(struct platform_device *pdev)
+{
+	struct nuc900_i2c *i2c;
+	struct nuc900_platform_i2c *pdata;
+	struct resource *res;
+	int ret;
+
+	pdata = pdev->dev.platform_data;
+	if (!pdata) {
+		dev_err(&pdev->dev, "no platform data\n");
+		return -EINVAL;
+	}
+
+	i2c = kzalloc(sizeof(struct nuc900_i2c), GFP_KERNEL);
+	if (!i2c) {
+		dev_err(&pdev->dev, "no memory for state\n");
+		return -ENOMEM;
+	}
+
+	strlcpy(i2c->adap.name, "nuc900-i2c0", sizeof(i2c->adap.name));
+	i2c->adap.owner   = THIS_MODULE;
+	i2c->adap.algo    = &nuc900_i2c_algorithm;
+	i2c->adap.retries = 2;
+	i2c->adap.class   = I2C_CLASS_HWMON | I2C_CLASS_SPD;
+
+	spin_lock_init(&i2c->lock);
+	init_waitqueue_head(&i2c->wait);
+
+	/* find the clock and enable it */
+
+	i2c->dev = &pdev->dev;
+	i2c->clk = clk_get(&pdev->dev, NULL);
+	if (IS_ERR(i2c->clk)) {
+		dev_err(&pdev->dev, "cannot get clock\n");
+		ret = -ENOENT;
+		goto err_noclk;
+	}
+
+	dev_dbg(&pdev->dev, "clock source %p\n", i2c->clk);
+
+	clk_enable(i2c->clk);
+
+	/* map the registers */
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (res == NULL) {
+		dev_err(&pdev->dev, "cannot find IO resource\n");
+		ret = -ENOENT;
+		goto err_clk;
+	}
+
+	i2c->ioarea = request_mem_region(res->start, resource_size(res),
+					 pdev->name);
+
+	if (i2c->ioarea == NULL) {
+		dev_err(&pdev->dev, "cannot request IO\n");
+		ret = -ENXIO;
+		goto err_clk;
+	}
+
+	i2c->regs = ioremap(res->start, resource_size(res));
+
+	if (i2c->regs == NULL) {
+		dev_err(&pdev->dev, "cannot map IO\n");
+		ret = -ENXIO;
+		goto err_ioarea;
+	}
+
+	dev_dbg(&pdev->dev, "registers %p (%p, %p)\n",
+		i2c->regs, i2c->ioarea, res);
+
+	/* setup info block for the i2c core */
+
+	i2c->adap.algo_data = i2c;
+	i2c->adap.dev.parent = &pdev->dev;
+
+	mfp_set_groupg(&pdev->dev, NULL);
+
+	clk_get_rate(i2c->clk);
+
+	ret = (i2c->clk.apbfreq)/(pdata->bus_freq * 5) - 1;
+	writel(ret & 0xffff, i2c->regs + DIVIDER);
+
+	/* find the IRQ for this unit (note, this relies on the init call to
+	 * ensure no current IRQs pending
+	 */
+
+	i2c->irq = ret = platform_get_irq(pdev, 0);
+	if (ret <= 0) {
+		dev_err(&pdev->dev, "cannot find IRQ\n");
+		goto err_iomap;
+	}
+
+	ret = request_irq(i2c->irq, nuc900_i2c_irq, IRQF_SHARED,
+			  dev_name(&pdev->dev), i2c);
+
+	if (ret != 0) {
+		dev_err(&pdev->dev, "cannot claim IRQ %d\n", i2c->irq);
+		goto err_iomap;
+	}
+
+	/* Note, previous versions of the driver used i2c_add_adapter()
+	 * to add the bus at any number. We now pass the bus number via
+	 * the platform data, so if unset it will now default to always
+	 * being bus 0.
+	 */
+
+	i2c->adap.nr = pdata->bus_num;
+
+	ret = i2c_add_numbered_adapter(&i2c->adap);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "failed to add bus to i2c core\n");
+		goto err_irq;
+	}
+
+	platform_set_drvdata(pdev, i2c);
+
+	dev_info(&pdev->dev, "%s: NUC900 I2C adapter\n",
+						dev_name(&i2c->adap.dev));
+	return 0;
+
+ err_irq:
+	free_irq(i2c->irq, i2c);
+
+ err_iomap:
+	iounmap(i2c->regs);
+
+ err_ioarea:
+	release_resource(i2c->ioarea);
+	kfree(i2c->ioarea);
+
+ err_clk:
+	clk_disable(i2c->clk);
+	clk_put(i2c->clk);
+
+ err_noclk:
+	kfree(i2c);
+	return ret;
+}
+
+/* nuc900_i2c_remove
+ *
+ * called when device is removed from the bus
+*/
+
+static int __devexit nuc900_i2c_remove(struct platform_device *pdev)
+{
+	struct nuc900_i2c *i2c = platform_get_drvdata(pdev);
+
+	i2c_del_adapter(&i2c->adap);
+	free_irq(i2c->irq, i2c);
+
+	clk_disable(i2c->clk);
+	clk_put(i2c->clk);
+
+	iounmap(i2c->regs);
+
+	release_resource(i2c->ioarea);
+	kfree(i2c->ioarea);
+	kfree(i2c);
+
+	return 0;
+}
+
+static struct platform_driver nuc900_i2c_driver = {
+	.probe		= nuc900_i2c_probe,
+	.remove		= __devexit_p(nuc900_i2c_remove),
+	.driver		= {
+		.owner	= THIS_MODULE,
+		.name	= "nuc900-i2c0",
+	},
+};
+
+static int __init i2c_adap_nuc900_init(void)
+{
+	return platform_driver_register(&nuc900_i2c_driver);
+}
+
+static void __exit i2c_adap_nuc900_exit(void)
+{
+	platform_driver_unregister(&nuc900_i2c_driver);
+}
+subsys_initcall(i2c_adap_nuc900_init);
+module_exit(i2c_adap_nuc900_exit);
+
+MODULE_DESCRIPTION("NUC900 I2C Bus driver");
+MODULE_AUTHOR("Wan ZongShun, <mcuos.com-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:nuc900-i2c0");
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-ocores.c b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-ocores.c
new file mode 100644
index 0000000..18068de
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-ocores.c
@@ -0,0 +1,414 @@
+/*
+ * i2c-ocores.c: I2C bus driver for OpenCores I2C controller
+ * (http://www.opencores.org/projects.cgi/web/i2c/overview).
+ *
+ * Peter Korsgaard <jacmet@sunsite.dk>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2.  This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+/*
+ * Device tree configuration:
+ *
+ * Required properties:
+ * - compatible      : "opencores,i2c-ocores"
+ * - reg             : bus address start and address range size of device
+ * - interrupts      : interrupt number
+ * - regstep         : size of device registers in bytes
+ * - clock-frequency : frequency of bus clock in Hz
+ * 
+ * Example:
+ *
+ *  i2c0: ocores@a0000000 {
+ *              compatible = "opencores,i2c-ocores";
+ *              reg = <0xa0000000 0x8>;
+ *              interrupts = <10>;
+ *
+ *              regstep = <1>;
+ *              clock-frequency = <20000000>;
+ *
+ * -- Devices connected on this I2C bus get
+ * -- defined here; address- and size-cells
+ * -- apply to these child devices
+ *
+ *              #address-cells = <1>;
+ *              #size-cells = <0>;
+ *
+ *              dummy@60 {
+ *                     compatible = "dummy";
+ *                     reg = <60>;
+ *              };
+ *  };
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/wait.h>
+#include <linux/i2c-ocores.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+
+struct ocores_i2c {
+	void __iomem *base;
+	int regstep;
+	wait_queue_head_t wait;
+	struct i2c_adapter adap;
+	struct i2c_msg *msg;
+	int pos;
+	int nmsgs;
+	int state; /* see STATE_ */
+	int clock_khz;
+};
+
+/* registers */
+#define OCI2C_PRELOW		0
+#define OCI2C_PREHIGH		1
+#define OCI2C_CONTROL		2
+#define OCI2C_DATA		3
+#define OCI2C_CMD		4 /* write only */
+#define OCI2C_STATUS		4 /* read only, same address as OCI2C_CMD */
+
+#define OCI2C_CTRL_IEN		0x40
+#define OCI2C_CTRL_EN		0x80
+
+#define OCI2C_CMD_START		0x91
+#define OCI2C_CMD_STOP		0x41
+#define OCI2C_CMD_READ		0x21
+#define OCI2C_CMD_WRITE		0x11
+#define OCI2C_CMD_READ_ACK	0x21
+#define OCI2C_CMD_READ_NACK	0x29
+#define OCI2C_CMD_IACK		0x01
+
+#define OCI2C_STAT_IF		0x01
+#define OCI2C_STAT_TIP		0x02
+#define OCI2C_STAT_ARBLOST	0x20
+#define OCI2C_STAT_BUSY		0x40
+#define OCI2C_STAT_NACK		0x80
+
+#define STATE_DONE		0
+#define STATE_START		1
+#define STATE_WRITE		2
+#define STATE_READ		3
+#define STATE_ERROR		4
+
+static inline void oc_setreg(struct ocores_i2c *i2c, int reg, u8 value)
+{
+	iowrite8(value, i2c->base + reg * i2c->regstep);
+}
+
+static inline u8 oc_getreg(struct ocores_i2c *i2c, int reg)
+{
+	return ioread8(i2c->base + reg * i2c->regstep);
+}
+
+static void ocores_process(struct ocores_i2c *i2c)
+{
+	struct i2c_msg *msg = i2c->msg;
+	u8 stat = oc_getreg(i2c, OCI2C_STATUS);
+
+	if ((i2c->state == STATE_DONE) || (i2c->state == STATE_ERROR)) {
+		/* stop has been sent */
+		oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_IACK);
+		wake_up(&i2c->wait);
+		return;
+	}
+
+	/* error? */
+	if (stat & OCI2C_STAT_ARBLOST) {
+		i2c->state = STATE_ERROR;
+		oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP);
+		return;
+	}
+
+	if ((i2c->state == STATE_START) || (i2c->state == STATE_WRITE)) {
+		i2c->state =
+			(msg->flags & I2C_M_RD) ? STATE_READ : STATE_WRITE;
+
+		if (stat & OCI2C_STAT_NACK) {
+			i2c->state = STATE_ERROR;
+			oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP);
+			return;
+		}
+	} else
+		msg->buf[i2c->pos++] = oc_getreg(i2c, OCI2C_DATA);
+
+	/* end of msg? */
+	if (i2c->pos == msg->len) {
+		i2c->nmsgs--;
+		i2c->msg++;
+		i2c->pos = 0;
+		msg = i2c->msg;
+
+		if (i2c->nmsgs) {	/* end? */
+			/* send start? */
+			if (!(msg->flags & I2C_M_NOSTART)) {
+				u8 addr = (msg->addr << 1);
+
+				if (msg->flags & I2C_M_RD)
+					addr |= 1;
+
+				i2c->state = STATE_START;
+
+				oc_setreg(i2c, OCI2C_DATA, addr);
+				oc_setreg(i2c, OCI2C_CMD,  OCI2C_CMD_START);
+				return;
+			} else
+				i2c->state = (msg->flags & I2C_M_RD)
+					? STATE_READ : STATE_WRITE;
+		} else {
+			i2c->state = STATE_DONE;
+			oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP);
+			return;
+		}
+	}
+
+	if (i2c->state == STATE_READ) {
+		oc_setreg(i2c, OCI2C_CMD, i2c->pos == (msg->len-1) ?
+			  OCI2C_CMD_READ_NACK : OCI2C_CMD_READ_ACK);
+	} else {
+		oc_setreg(i2c, OCI2C_DATA, msg->buf[i2c->pos++]);
+		oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_WRITE);
+	}
+}
+
+static irqreturn_t ocores_isr(int irq, void *dev_id)
+{
+	struct ocores_i2c *i2c = dev_id;
+
+	ocores_process(i2c);
+
+	return IRQ_HANDLED;
+}
+
+static int ocores_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+{
+	struct ocores_i2c *i2c = i2c_get_adapdata(adap);
+
+	i2c->msg = msgs;
+	i2c->pos = 0;
+	i2c->nmsgs = num;
+	i2c->state = STATE_START;
+
+	oc_setreg(i2c, OCI2C_DATA,
+			(i2c->msg->addr << 1) |
+			((i2c->msg->flags & I2C_M_RD) ? 1:0));
+
+	oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_START);
+
+	if (wait_event_timeout(i2c->wait, (i2c->state == STATE_ERROR) ||
+			       (i2c->state == STATE_DONE), HZ))
+		return (i2c->state == STATE_DONE) ? num : -EIO;
+	else
+		return -ETIMEDOUT;
+}
+
+static void ocores_init(struct ocores_i2c *i2c)
+{
+	int prescale;
+	u8 ctrl = oc_getreg(i2c, OCI2C_CONTROL);
+
+	/* make sure the device is disabled */
+	oc_setreg(i2c, OCI2C_CONTROL, ctrl & ~(OCI2C_CTRL_EN|OCI2C_CTRL_IEN));
+
+	prescale = (i2c->clock_khz / (5*100)) - 1;
+	oc_setreg(i2c, OCI2C_PRELOW, prescale & 0xff);
+	oc_setreg(i2c, OCI2C_PREHIGH, prescale >> 8);
+
+	/* Init the device */
+	oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_IACK);
+	oc_setreg(i2c, OCI2C_CONTROL, ctrl | OCI2C_CTRL_IEN | OCI2C_CTRL_EN);
+}
+
+
+static u32 ocores_func(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm ocores_algorithm = {
+	.master_xfer	= ocores_xfer,
+	.functionality	= ocores_func,
+};
+
+static struct i2c_adapter ocores_adapter = {
+	.owner		= THIS_MODULE,
+	.name		= "i2c-ocores",
+	.class		= I2C_CLASS_HWMON | I2C_CLASS_SPD,
+	.algo		= &ocores_algorithm,
+};
+
+#ifdef CONFIG_OF
+static int ocores_i2c_of_probe(struct platform_device* pdev,
+				struct ocores_i2c* i2c)
+{
+	const __be32* val;
+
+	val = of_get_property(pdev->dev.of_node, "regstep", NULL);
+	if (!val) {
+		dev_err(&pdev->dev, "Missing required parameter 'regstep'");
+		return -ENODEV;
+	}
+	i2c->regstep = be32_to_cpup(val);
+
+	val = of_get_property(pdev->dev.of_node, "clock-frequency", NULL);
+	if (!val) {
+		dev_err(&pdev->dev,
+			"Missing required parameter 'clock-frequency'");
+		return -ENODEV;
+	}
+	i2c->clock_khz = be32_to_cpup(val) / 1000;
+
+	return 0;
+}
+#else
+#define ocores_i2c_of_probe(pdev,i2c) -ENODEV
+#endif
+
+static int __devinit ocores_i2c_probe(struct platform_device *pdev)
+{
+	struct ocores_i2c *i2c;
+	struct ocores_i2c_platform_data *pdata;
+	struct resource *res, *res2;
+	int ret;
+	int i;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENODEV;
+
+	res2 = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (!res2)
+		return -ENODEV;
+
+	i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL);
+	if (!i2c)
+		return -ENOMEM;
+
+	if (!devm_request_mem_region(&pdev->dev, res->start,
+				     resource_size(res), pdev->name)) {
+		dev_err(&pdev->dev, "Memory region busy\n");
+		return -EBUSY;
+	}
+
+	i2c->base = devm_ioremap_nocache(&pdev->dev, res->start,
+					 resource_size(res));
+	if (!i2c->base) {
+		dev_err(&pdev->dev, "Unable to map registers\n");
+		return -EIO;
+	}
+
+	pdata = pdev->dev.platform_data;
+	if (pdata) {
+		i2c->regstep = pdata->regstep;
+		i2c->clock_khz = pdata->clock_khz;
+	} else {
+		ret = ocores_i2c_of_probe(pdev, i2c);
+		if (ret)
+			return ret;
+	}
+
+	ocores_init(i2c);
+
+	init_waitqueue_head(&i2c->wait);
+	ret = devm_request_irq(&pdev->dev, res2->start, ocores_isr, 0,
+			       pdev->name, i2c);
+	if (ret) {
+		dev_err(&pdev->dev, "Cannot claim IRQ\n");
+		return ret;
+	}
+
+	/* hook up driver to tree */
+	platform_set_drvdata(pdev, i2c);
+	i2c->adap = ocores_adapter;
+	i2c_set_adapdata(&i2c->adap, i2c);
+	i2c->adap.dev.parent = &pdev->dev;
+	i2c->adap.dev.of_node = pdev->dev.of_node;
+
+	/* add i2c adapter to i2c tree */
+	ret = i2c_add_adapter(&i2c->adap);
+	if (ret) {
+		dev_err(&pdev->dev, "Failed to add adapter\n");
+		return ret;
+	}
+
+	/* add in known devices to the bus */
+	if (pdata) {
+		for (i = 0; i < pdata->num_devices; i++)
+			i2c_new_device(&i2c->adap, pdata->devices + i);
+	}
+
+	return 0;
+}
+
+static int __devexit ocores_i2c_remove(struct platform_device* pdev)
+{
+	struct ocores_i2c *i2c = platform_get_drvdata(pdev);
+
+	/* disable i2c logic */
+	oc_setreg(i2c, OCI2C_CONTROL, oc_getreg(i2c, OCI2C_CONTROL)
+		  & ~(OCI2C_CTRL_EN|OCI2C_CTRL_IEN));
+
+	/* remove adapter & data */
+	i2c_del_adapter(&i2c->adap);
+	platform_set_drvdata(pdev, NULL);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int ocores_i2c_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct ocores_i2c *i2c = platform_get_drvdata(pdev);
+	u8 ctrl = oc_getreg(i2c, OCI2C_CONTROL);
+
+	/* make sure the device is disabled */
+	oc_setreg(i2c, OCI2C_CONTROL, ctrl & ~(OCI2C_CTRL_EN|OCI2C_CTRL_IEN));
+
+	return 0;
+}
+
+static int ocores_i2c_resume(struct platform_device *pdev)
+{
+	struct ocores_i2c *i2c = platform_get_drvdata(pdev);
+
+	ocores_init(i2c);
+
+	return 0;
+}
+#else
+#define ocores_i2c_suspend	NULL
+#define ocores_i2c_resume	NULL
+#endif
+
+static struct of_device_id ocores_i2c_match[] = {
+	{ .compatible = "opencores,i2c-ocores", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, ocores_i2c_match);
+
+static struct platform_driver ocores_i2c_driver = {
+	.probe   = ocores_i2c_probe,
+	.remove  = __devexit_p(ocores_i2c_remove),
+	.suspend = ocores_i2c_suspend,
+	.resume  = ocores_i2c_resume,
+	.driver  = {
+		.owner = THIS_MODULE,
+		.name = "ocores-i2c",
+		.of_match_table = ocores_i2c_match,
+	},
+};
+
+module_platform_driver(ocores_i2c_driver);
+
+MODULE_AUTHOR("Peter Korsgaard <jacmet@sunsite.dk>");
+MODULE_DESCRIPTION("OpenCores I2C bus driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:ocores-i2c");
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-octeon.c b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-octeon.c
new file mode 100644
index 0000000..ee139a5
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-octeon.c
@@ -0,0 +1,638 @@
+/*
+ * (C) Copyright 2009-2010
+ * Nokia Siemens Networks, michael.lawnick.ext@nsn.com
+ *
+ * Portions Copyright (C) 2010 Cavium Networks, Inc.
+ *
+ * This is a driver for the i2c adapter in Cavium Networks' OCTEON processors.
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+
+#include <linux/io.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+
+#include <asm/octeon/octeon.h>
+
+#define DRV_NAME "i2c-octeon"
+
+/* The previous out-of-tree version was implicitly version 1.0. */
+#define DRV_VERSION	"2.0"
+
+/* register offsets */
+#define SW_TWSI	 0x00
+#define TWSI_INT 0x10
+
+/* Controller command patterns */
+#define SW_TWSI_V               0x8000000000000000ull
+#define SW_TWSI_EOP_TWSI_DATA   0x0C00000100000000ull
+#define SW_TWSI_EOP_TWSI_CTL    0x0C00000200000000ull
+#define SW_TWSI_EOP_TWSI_CLKCTL 0x0C00000300000000ull
+#define SW_TWSI_EOP_TWSI_STAT   0x0C00000300000000ull
+#define SW_TWSI_EOP_TWSI_RST    0x0C00000700000000ull
+#define SW_TWSI_OP_TWSI_CLK     0x0800000000000000ull
+#define SW_TWSI_R               0x0100000000000000ull
+
+/* Controller command and status bits */
+#define TWSI_CTL_CE   0x80
+#define TWSI_CTL_ENAB 0x40
+#define TWSI_CTL_STA  0x20
+#define TWSI_CTL_STP  0x10
+#define TWSI_CTL_IFLG 0x08
+#define TWSI_CTL_AAK  0x04
+
+/* Some status values */
+#define STAT_START      0x08
+#define STAT_RSTART     0x10
+#define STAT_TXADDR_ACK 0x18
+#define STAT_TXDATA_ACK 0x28
+#define STAT_RXADDR_ACK 0x40
+#define STAT_RXDATA_ACK 0x50
+#define STAT_IDLE       0xF8
+
+struct octeon_i2c {
+	wait_queue_head_t queue;
+	struct i2c_adapter adap;
+	int irq;
+	int twsi_freq;
+	int sys_freq;
+	resource_size_t twsi_phys;
+	void __iomem *twsi_base;
+	resource_size_t regsize;
+	struct device *dev;
+};
+
+/**
+ * octeon_i2c_write_sw - write an I2C core register.
+ * @i2c: The struct octeon_i2c.
+ * @eop_reg: Register selector.
+ * @data: Value to be written.
+ *
+ * The I2C core registers are accessed indirectly via the SW_TWSI CSR.
+ */
+static void octeon_i2c_write_sw(struct octeon_i2c *i2c,
+				u64 eop_reg,
+				u8 data)
+{
+	u64 tmp;
+
+	__raw_writeq(SW_TWSI_V | eop_reg | data, i2c->twsi_base + SW_TWSI);
+	do {
+		tmp = __raw_readq(i2c->twsi_base + SW_TWSI);
+	} while ((tmp & SW_TWSI_V) != 0);
+}
+
+/**
+ * octeon_i2c_read_sw - write an I2C core register.
+ * @i2c: The struct octeon_i2c.
+ * @eop_reg: Register selector.
+ *
+ * Returns the data.
+ *
+ * The I2C core registers are accessed indirectly via the SW_TWSI CSR.
+ */
+static u8 octeon_i2c_read_sw(struct octeon_i2c *i2c, u64 eop_reg)
+{
+	u64 tmp;
+
+	__raw_writeq(SW_TWSI_V | eop_reg | SW_TWSI_R, i2c->twsi_base + SW_TWSI);
+	do {
+		tmp = __raw_readq(i2c->twsi_base + SW_TWSI);
+	} while ((tmp & SW_TWSI_V) != 0);
+
+	return tmp & 0xFF;
+}
+
+/**
+ * octeon_i2c_write_int - write the TWSI_INT register
+ * @i2c: The struct octeon_i2c.
+ * @data: Value to be written.
+ */
+static void octeon_i2c_write_int(struct octeon_i2c *i2c, u64 data)
+{
+	u64 tmp;
+
+	__raw_writeq(data, i2c->twsi_base + TWSI_INT);
+	tmp = __raw_readq(i2c->twsi_base + TWSI_INT);
+}
+
+/**
+ * octeon_i2c_int_enable - enable the TS interrupt.
+ * @i2c: The struct octeon_i2c.
+ *
+ * The interrupt will be asserted when there is non-STAT_IDLE state in
+ * the SW_TWSI_EOP_TWSI_STAT register.
+ */
+static void octeon_i2c_int_enable(struct octeon_i2c *i2c)
+{
+	octeon_i2c_write_int(i2c, 0x40);
+}
+
+/**
+ * octeon_i2c_int_disable - disable the TS interrupt.
+ * @i2c: The struct octeon_i2c.
+ */
+static void octeon_i2c_int_disable(struct octeon_i2c *i2c)
+{
+	octeon_i2c_write_int(i2c, 0);
+}
+
+/**
+ * octeon_i2c_unblock - unblock the bus.
+ * @i2c: The struct octeon_i2c.
+ *
+ * If there was a reset while a device was driving 0 to bus,
+ * bus is blocked. We toggle it free manually by some clock
+ * cycles and send a stop.
+ */
+static void octeon_i2c_unblock(struct octeon_i2c *i2c)
+{
+	int i;
+
+	dev_dbg(i2c->dev, "%s\n", __func__);
+	for (i = 0; i < 9; i++) {
+		octeon_i2c_write_int(i2c, 0x0);
+		udelay(5);
+		octeon_i2c_write_int(i2c, 0x200);
+		udelay(5);
+	}
+	octeon_i2c_write_int(i2c, 0x300);
+	udelay(5);
+	octeon_i2c_write_int(i2c, 0x100);
+	udelay(5);
+	octeon_i2c_write_int(i2c, 0x0);
+}
+
+/**
+ * octeon_i2c_isr - the interrupt service routine.
+ * @int: The irq, unused.
+ * @dev_id: Our struct octeon_i2c.
+ */
+static irqreturn_t octeon_i2c_isr(int irq, void *dev_id)
+{
+	struct octeon_i2c *i2c = dev_id;
+
+	octeon_i2c_int_disable(i2c);
+	wake_up_interruptible(&i2c->queue);
+
+	return IRQ_HANDLED;
+}
+
+
+static int octeon_i2c_test_iflg(struct octeon_i2c *i2c)
+{
+	return (octeon_i2c_read_sw(i2c, SW_TWSI_EOP_TWSI_CTL) & TWSI_CTL_IFLG) != 0;
+}
+
+/**
+ * octeon_i2c_wait - wait for the IFLG to be set.
+ * @i2c: The struct octeon_i2c.
+ *
+ * Returns 0 on success, otherwise a negative errno.
+ */
+static int octeon_i2c_wait(struct octeon_i2c *i2c)
+{
+	int result;
+
+	octeon_i2c_int_enable(i2c);
+
+	result = wait_event_interruptible_timeout(i2c->queue,
+						  octeon_i2c_test_iflg(i2c),
+						  i2c->adap.timeout);
+
+	octeon_i2c_int_disable(i2c);
+
+	if (result < 0) {
+		dev_dbg(i2c->dev, "%s: wait interrupted\n", __func__);
+		return result;
+	} else if (result == 0) {
+		dev_dbg(i2c->dev, "%s: timeout\n", __func__);
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+/**
+ * octeon_i2c_start - send START to the bus.
+ * @i2c: The struct octeon_i2c.
+ *
+ * Returns 0 on success, otherwise a negative errno.
+ */
+static int octeon_i2c_start(struct octeon_i2c *i2c)
+{
+	u8 data;
+	int result;
+
+	octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL,
+				TWSI_CTL_ENAB | TWSI_CTL_STA);
+
+	result = octeon_i2c_wait(i2c);
+	if (result) {
+		if (octeon_i2c_read_sw(i2c, SW_TWSI_EOP_TWSI_STAT) == STAT_IDLE) {
+			/*
+			 * Controller refused to send start flag May
+			 * be a client is holding SDA low - let's try
+			 * to free it.
+			 */
+			octeon_i2c_unblock(i2c);
+			octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL,
+					    TWSI_CTL_ENAB | TWSI_CTL_STA);
+
+			result = octeon_i2c_wait(i2c);
+		}
+		if (result)
+			return result;
+	}
+
+	data = octeon_i2c_read_sw(i2c, SW_TWSI_EOP_TWSI_STAT);
+	if ((data != STAT_START) && (data != STAT_RSTART)) {
+		dev_err(i2c->dev, "%s: bad status (0x%x)\n", __func__, data);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+/**
+ * octeon_i2c_stop - send STOP to the bus.
+ * @i2c: The struct octeon_i2c.
+ *
+ * Returns 0 on success, otherwise a negative errno.
+ */
+static int octeon_i2c_stop(struct octeon_i2c *i2c)
+{
+	u8 data;
+
+	octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL,
+			    TWSI_CTL_ENAB | TWSI_CTL_STP);
+
+	data = octeon_i2c_read_sw(i2c, SW_TWSI_EOP_TWSI_STAT);
+
+	if (data != STAT_IDLE) {
+		dev_err(i2c->dev, "%s: bad status(0x%x)\n", __func__, data);
+		return -EIO;
+	}
+	return 0;
+}
+
+/**
+ * octeon_i2c_write - send data to the bus.
+ * @i2c: The struct octeon_i2c.
+ * @target: Target address.
+ * @data: Pointer to the data to be sent.
+ * @length: Length of the data.
+ *
+ * The address is sent over the bus, then the data.
+ *
+ * Returns 0 on success, otherwise a negative errno.
+ */
+static int octeon_i2c_write(struct octeon_i2c *i2c, int target,
+			    const u8 *data, int length)
+{
+	int i, result;
+	u8 tmp;
+
+	result = octeon_i2c_start(i2c);
+	if (result)
+		return result;
+
+	octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_DATA, target << 1);
+	octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL, TWSI_CTL_ENAB);
+
+	result = octeon_i2c_wait(i2c);
+	if (result)
+		return result;
+
+	for (i = 0; i < length; i++) {
+		tmp = octeon_i2c_read_sw(i2c, SW_TWSI_EOP_TWSI_STAT);
+		if ((tmp != STAT_TXADDR_ACK) && (tmp != STAT_TXDATA_ACK)) {
+			dev_err(i2c->dev,
+				"%s: bad status before write (0x%x)\n",
+				__func__, tmp);
+			return -EIO;
+		}
+
+		octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_DATA, data[i]);
+		octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL, TWSI_CTL_ENAB);
+
+		result = octeon_i2c_wait(i2c);
+		if (result)
+			return result;
+	}
+
+	return 0;
+}
+
+/**
+ * octeon_i2c_read - receive data from the bus.
+ * @i2c: The struct octeon_i2c.
+ * @target: Target address.
+ * @data: Pointer to the location to store the datae .
+ * @length: Length of the data.
+ *
+ * The address is sent over the bus, then the data is read.
+ *
+ * Returns 0 on success, otherwise a negative errno.
+ */
+static int octeon_i2c_read(struct octeon_i2c *i2c, int target,
+			   u8 *data, int length)
+{
+	int i, result;
+	u8 tmp;
+
+	if (length < 1)
+		return -EINVAL;
+
+	result = octeon_i2c_start(i2c);
+	if (result)
+		return result;
+
+	octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_DATA, (target<<1) | 1);
+	octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL, TWSI_CTL_ENAB);
+
+	result = octeon_i2c_wait(i2c);
+	if (result)
+		return result;
+
+	for (i = 0; i < length; i++) {
+		tmp = octeon_i2c_read_sw(i2c, SW_TWSI_EOP_TWSI_STAT);
+		if ((tmp != STAT_RXDATA_ACK) && (tmp != STAT_RXADDR_ACK)) {
+			dev_err(i2c->dev,
+				"%s: bad status before read (0x%x)\n",
+				__func__, tmp);
+			return -EIO;
+		}
+
+		if (i+1 < length)
+			octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL,
+						TWSI_CTL_ENAB | TWSI_CTL_AAK);
+		else
+			octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL,
+						TWSI_CTL_ENAB);
+
+		result = octeon_i2c_wait(i2c);
+		if (result)
+			return result;
+
+		data[i] = octeon_i2c_read_sw(i2c, SW_TWSI_EOP_TWSI_DATA);
+	}
+	return 0;
+}
+
+/**
+ * octeon_i2c_xfer - The driver's master_xfer function.
+ * @adap: Pointer to the i2c_adapter structure.
+ * @msgs: Pointer to the messages to be processed.
+ * @num: Length of the MSGS array.
+ *
+ * Returns the number of messages processed, or a negative errno on
+ * failure.
+ */
+static int octeon_i2c_xfer(struct i2c_adapter *adap,
+			   struct i2c_msg *msgs,
+			   int num)
+{
+	struct i2c_msg *pmsg;
+	int i;
+	int ret = 0;
+	struct octeon_i2c *i2c = i2c_get_adapdata(adap);
+
+	for (i = 0; ret == 0 && i < num; i++) {
+		pmsg = &msgs[i];
+		dev_dbg(i2c->dev,
+			"Doing %s %d byte(s) to/from 0x%02x - %d of %d messages\n",
+			 pmsg->flags & I2C_M_RD ? "read" : "write",
+			 pmsg->len, pmsg->addr, i + 1, num);
+		if (pmsg->flags & I2C_M_RD)
+			ret = octeon_i2c_read(i2c, pmsg->addr, pmsg->buf,
+						pmsg->len);
+		else
+			ret = octeon_i2c_write(i2c, pmsg->addr, pmsg->buf,
+						pmsg->len);
+	}
+	octeon_i2c_stop(i2c);
+
+	return (ret != 0) ? ret : num;
+}
+
+static u32 octeon_i2c_functionality(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm octeon_i2c_algo = {
+	.master_xfer = octeon_i2c_xfer,
+	.functionality = octeon_i2c_functionality,
+};
+
+static struct i2c_adapter octeon_i2c_ops = {
+	.owner = THIS_MODULE,
+	.name = "OCTEON adapter",
+	.algo = &octeon_i2c_algo,
+	.timeout = 2,
+};
+
+/**
+ * octeon_i2c_setclock - Calculate and set clock divisors.
+ */
+static int __devinit octeon_i2c_setclock(struct octeon_i2c *i2c)
+{
+	int tclk, thp_base, inc, thp_idx, mdiv_idx, ndiv_idx, foscl, diff;
+	int thp = 0x18, mdiv = 2, ndiv = 0, delta_hz = 1000000;
+
+	for (ndiv_idx = 0; ndiv_idx < 8 && delta_hz != 0; ndiv_idx++) {
+		/*
+		 * An mdiv value of less than 2 seems to not work well
+		 * with ds1337 RTCs, so we constrain it to larger
+		 * values.
+		 */
+		for (mdiv_idx = 15; mdiv_idx >= 2 && delta_hz != 0; mdiv_idx--) {
+			/*
+			 * For given ndiv and mdiv values check the
+			 * two closest thp values.
+			 */
+			tclk = i2c->twsi_freq * (mdiv_idx + 1) * 10;
+			tclk *= (1 << ndiv_idx);
+			thp_base = (i2c->sys_freq / (tclk * 2)) - 1;
+			for (inc = 0; inc <= 1; inc++) {
+				thp_idx = thp_base + inc;
+				if (thp_idx < 5 || thp_idx > 0xff)
+					continue;
+
+				foscl = i2c->sys_freq / (2 * (thp_idx + 1));
+				foscl = foscl / (1 << ndiv_idx);
+				foscl = foscl / (mdiv_idx + 1) / 10;
+				diff = abs(foscl - i2c->twsi_freq);
+				if (diff < delta_hz) {
+					delta_hz = diff;
+					thp = thp_idx;
+					mdiv = mdiv_idx;
+					ndiv = ndiv_idx;
+				}
+			}
+		}
+	}
+	octeon_i2c_write_sw(i2c, SW_TWSI_OP_TWSI_CLK, thp);
+	octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CLKCTL, (mdiv << 3) | ndiv);
+
+	return 0;
+}
+
+static int __devinit octeon_i2c_initlowlevel(struct octeon_i2c *i2c)
+{
+	u8 status;
+	int tries;
+
+	/* disable high level controller, enable bus access */
+	octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_CTL, TWSI_CTL_ENAB);
+
+	/* reset controller */
+	octeon_i2c_write_sw(i2c, SW_TWSI_EOP_TWSI_RST, 0);
+
+	for (tries = 10; tries; tries--) {
+		udelay(1);
+		status = octeon_i2c_read_sw(i2c, SW_TWSI_EOP_TWSI_STAT);
+		if (status == STAT_IDLE)
+			return 0;
+	}
+	dev_err(i2c->dev, "%s: TWSI_RST failed! (0x%x)\n", __func__, status);
+	return -EIO;
+}
+
+static int __devinit octeon_i2c_probe(struct platform_device *pdev)
+{
+	int irq, result = 0;
+	struct octeon_i2c *i2c;
+	struct octeon_i2c_data *i2c_data;
+	struct resource *res_mem;
+
+	/* All adaptors have an irq.  */
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0)
+		return irq;
+
+	i2c = kzalloc(sizeof(*i2c), GFP_KERNEL);
+	if (!i2c) {
+		dev_err(&pdev->dev, "kzalloc failed\n");
+		result = -ENOMEM;
+		goto out;
+	}
+	i2c->dev = &pdev->dev;
+	i2c_data = pdev->dev.platform_data;
+
+	res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+	if (res_mem == NULL) {
+		dev_err(i2c->dev, "found no memory resource\n");
+		result = -ENXIO;
+		goto fail_region;
+	}
+
+	if (i2c_data == NULL) {
+		dev_err(i2c->dev, "no I2C frequency data\n");
+		result = -ENXIO;
+		goto fail_region;
+	}
+
+	i2c->twsi_phys = res_mem->start;
+	i2c->regsize = resource_size(res_mem);
+	i2c->twsi_freq = i2c_data->i2c_freq;
+	i2c->sys_freq = i2c_data->sys_freq;
+
+	if (!request_mem_region(i2c->twsi_phys, i2c->regsize, res_mem->name)) {
+		dev_err(i2c->dev, "request_mem_region failed\n");
+		goto fail_region;
+	}
+	i2c->twsi_base = ioremap(i2c->twsi_phys, i2c->regsize);
+
+	init_waitqueue_head(&i2c->queue);
+
+	i2c->irq = irq;
+
+	result = request_irq(i2c->irq, octeon_i2c_isr, 0, DRV_NAME, i2c);
+	if (result < 0) {
+		dev_err(i2c->dev, "failed to attach interrupt\n");
+		goto fail_irq;
+	}
+
+	result = octeon_i2c_initlowlevel(i2c);
+	if (result) {
+		dev_err(i2c->dev, "init low level failed\n");
+		goto  fail_add;
+	}
+
+	result = octeon_i2c_setclock(i2c);
+	if (result) {
+		dev_err(i2c->dev, "clock init failed\n");
+		goto  fail_add;
+	}
+
+	i2c->adap = octeon_i2c_ops;
+	i2c->adap.dev.parent = &pdev->dev;
+	i2c->adap.nr = pdev->id >= 0 ? pdev->id : 0;
+	i2c_set_adapdata(&i2c->adap, i2c);
+	platform_set_drvdata(pdev, i2c);
+
+	result = i2c_add_numbered_adapter(&i2c->adap);
+	if (result < 0) {
+		dev_err(i2c->dev, "failed to add adapter\n");
+		goto fail_add;
+	}
+
+	dev_info(i2c->dev, "version %s\n", DRV_VERSION);
+
+	return result;
+
+fail_add:
+	platform_set_drvdata(pdev, NULL);
+	free_irq(i2c->irq, i2c);
+fail_irq:
+	iounmap(i2c->twsi_base);
+	release_mem_region(i2c->twsi_phys, i2c->regsize);
+fail_region:
+	kfree(i2c);
+out:
+	return result;
+};
+
+static int __devexit octeon_i2c_remove(struct platform_device *pdev)
+{
+	struct octeon_i2c *i2c = platform_get_drvdata(pdev);
+
+	i2c_del_adapter(&i2c->adap);
+	platform_set_drvdata(pdev, NULL);
+	free_irq(i2c->irq, i2c);
+	iounmap(i2c->twsi_base);
+	release_mem_region(i2c->twsi_phys, i2c->regsize);
+	kfree(i2c);
+	return 0;
+};
+
+static struct platform_driver octeon_i2c_driver = {
+	.probe		= octeon_i2c_probe,
+	.remove		= __devexit_p(octeon_i2c_remove),
+	.driver		= {
+		.owner	= THIS_MODULE,
+		.name	= DRV_NAME,
+	},
+};
+
+module_platform_driver(octeon_i2c_driver);
+
+MODULE_AUTHOR("Michael Lawnick <michael.lawnick.ext@nsn.com>");
+MODULE_DESCRIPTION("I2C-Bus adapter for Cavium OCTEON processors");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-omap.c b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-omap.c
new file mode 100644
index 0000000..801df60
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-omap.c
@@ -0,0 +1,1219 @@
+/*
+ * TI OMAP I2C master mode driver
+ *
+ * Copyright (C) 2003 MontaVista Software, Inc.
+ * Copyright (C) 2005 Nokia Corporation
+ * Copyright (C) 2004 - 2007 Texas Instruments.
+ *
+ * Originally written by MontaVista Software, Inc.
+ * Additional contributions by:
+ *	Tony Lindgren <tony@atomide.com>
+ *	Imre Deak <imre.deak@nokia.com>
+ *	Juha Yrjölä <juha.yrjola@solidboot.com>
+ *	Syed Khasim <x0khasim@ti.com>
+ *	Nishant Menon <nm@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/completion.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_i2c.h>
+#include <linux/of_device.h>
+#include <linux/slab.h>
+#include <linux/i2c-omap.h>
+#include <linux/pm_runtime.h>
+
+/* I2C controller revisions */
+#define OMAP_I2C_OMAP1_REV_2		0x20
+
+/* I2C controller revisions present on specific hardware */
+#define OMAP_I2C_REV_ON_2430		0x36
+#define OMAP_I2C_REV_ON_3430		0x3C
+#define OMAP_I2C_REV_ON_3530_4430	0x40
+
+/* timeout waiting for the controller to respond */
+#define OMAP_I2C_TIMEOUT (msecs_to_jiffies(1000))
+
+/* For OMAP3 I2C_IV has changed to I2C_WE (wakeup enable) */
+enum {
+	OMAP_I2C_REV_REG = 0,
+	OMAP_I2C_IE_REG,
+	OMAP_I2C_STAT_REG,
+	OMAP_I2C_IV_REG,
+	OMAP_I2C_WE_REG,
+	OMAP_I2C_SYSS_REG,
+	OMAP_I2C_BUF_REG,
+	OMAP_I2C_CNT_REG,
+	OMAP_I2C_DATA_REG,
+	OMAP_I2C_SYSC_REG,
+	OMAP_I2C_CON_REG,
+	OMAP_I2C_OA_REG,
+	OMAP_I2C_SA_REG,
+	OMAP_I2C_PSC_REG,
+	OMAP_I2C_SCLL_REG,
+	OMAP_I2C_SCLH_REG,
+	OMAP_I2C_SYSTEST_REG,
+	OMAP_I2C_BUFSTAT_REG,
+	/* only on OMAP4430 */
+	OMAP_I2C_IP_V2_REVNB_LO,
+	OMAP_I2C_IP_V2_REVNB_HI,
+	OMAP_I2C_IP_V2_IRQSTATUS_RAW,
+	OMAP_I2C_IP_V2_IRQENABLE_SET,
+	OMAP_I2C_IP_V2_IRQENABLE_CLR,
+};
+
+/* I2C Interrupt Enable Register (OMAP_I2C_IE): */
+#define OMAP_I2C_IE_XDR		(1 << 14)	/* TX Buffer drain int enable */
+#define OMAP_I2C_IE_RDR		(1 << 13)	/* RX Buffer drain int enable */
+#define OMAP_I2C_IE_XRDY	(1 << 4)	/* TX data ready int enable */
+#define OMAP_I2C_IE_RRDY	(1 << 3)	/* RX data ready int enable */
+#define OMAP_I2C_IE_ARDY	(1 << 2)	/* Access ready int enable */
+#define OMAP_I2C_IE_NACK	(1 << 1)	/* No ack interrupt enable */
+#define OMAP_I2C_IE_AL		(1 << 0)	/* Arbitration lost int ena */
+
+/* I2C Status Register (OMAP_I2C_STAT): */
+#define OMAP_I2C_STAT_XDR	(1 << 14)	/* TX Buffer draining */
+#define OMAP_I2C_STAT_RDR	(1 << 13)	/* RX Buffer draining */
+#define OMAP_I2C_STAT_BB	(1 << 12)	/* Bus busy */
+#define OMAP_I2C_STAT_ROVR	(1 << 11)	/* Receive overrun */
+#define OMAP_I2C_STAT_XUDF	(1 << 10)	/* Transmit underflow */
+#define OMAP_I2C_STAT_AAS	(1 << 9)	/* Address as slave */
+#define OMAP_I2C_STAT_AD0	(1 << 8)	/* Address zero */
+#define OMAP_I2C_STAT_XRDY	(1 << 4)	/* Transmit data ready */
+#define OMAP_I2C_STAT_RRDY	(1 << 3)	/* Receive data ready */
+#define OMAP_I2C_STAT_ARDY	(1 << 2)	/* Register access ready */
+#define OMAP_I2C_STAT_NACK	(1 << 1)	/* No ack interrupt enable */
+#define OMAP_I2C_STAT_AL	(1 << 0)	/* Arbitration lost int ena */
+
+/* I2C WE wakeup enable register */
+#define OMAP_I2C_WE_XDR_WE	(1 << 14)	/* TX drain wakup */
+#define OMAP_I2C_WE_RDR_WE	(1 << 13)	/* RX drain wakeup */
+#define OMAP_I2C_WE_AAS_WE	(1 << 9)	/* Address as slave wakeup*/
+#define OMAP_I2C_WE_BF_WE	(1 << 8)	/* Bus free wakeup */
+#define OMAP_I2C_WE_STC_WE	(1 << 6)	/* Start condition wakeup */
+#define OMAP_I2C_WE_GC_WE	(1 << 5)	/* General call wakeup */
+#define OMAP_I2C_WE_DRDY_WE	(1 << 3)	/* TX/RX data ready wakeup */
+#define OMAP_I2C_WE_ARDY_WE	(1 << 2)	/* Reg access ready wakeup */
+#define OMAP_I2C_WE_NACK_WE	(1 << 1)	/* No acknowledgment wakeup */
+#define OMAP_I2C_WE_AL_WE	(1 << 0)	/* Arbitration lost wakeup */
+
+#define OMAP_I2C_WE_ALL		(OMAP_I2C_WE_XDR_WE | OMAP_I2C_WE_RDR_WE | \
+				OMAP_I2C_WE_AAS_WE | OMAP_I2C_WE_BF_WE | \
+				OMAP_I2C_WE_STC_WE | OMAP_I2C_WE_GC_WE | \
+				OMAP_I2C_WE_DRDY_WE | OMAP_I2C_WE_ARDY_WE | \
+				OMAP_I2C_WE_NACK_WE | OMAP_I2C_WE_AL_WE)
+
+/* I2C Buffer Configuration Register (OMAP_I2C_BUF): */
+#define OMAP_I2C_BUF_RDMA_EN	(1 << 15)	/* RX DMA channel enable */
+#define OMAP_I2C_BUF_RXFIF_CLR	(1 << 14)	/* RX FIFO Clear */
+#define OMAP_I2C_BUF_XDMA_EN	(1 << 7)	/* TX DMA channel enable */
+#define OMAP_I2C_BUF_TXFIF_CLR	(1 << 6)	/* TX FIFO Clear */
+
+/* I2C Configuration Register (OMAP_I2C_CON): */
+#define OMAP_I2C_CON_EN		(1 << 15)	/* I2C module enable */
+#define OMAP_I2C_CON_BE		(1 << 14)	/* Big endian mode */
+#define OMAP_I2C_CON_OPMODE_HS	(1 << 12)	/* High Speed support */
+#define OMAP_I2C_CON_STB	(1 << 11)	/* Start byte mode (master) */
+#define OMAP_I2C_CON_MST	(1 << 10)	/* Master/slave mode */
+#define OMAP_I2C_CON_TRX	(1 << 9)	/* TX/RX mode (master only) */
+#define OMAP_I2C_CON_XA		(1 << 8)	/* Expand address */
+#define OMAP_I2C_CON_RM		(1 << 2)	/* Repeat mode (master only) */
+#define OMAP_I2C_CON_STP	(1 << 1)	/* Stop cond (master only) */
+#define OMAP_I2C_CON_STT	(1 << 0)	/* Start condition (master) */
+
+/* I2C SCL time value when Master */
+#define OMAP_I2C_SCLL_HSSCLL	8
+#define OMAP_I2C_SCLH_HSSCLH	8
+
+/* I2C System Test Register (OMAP_I2C_SYSTEST): */
+#ifdef DEBUG
+#define OMAP_I2C_SYSTEST_ST_EN		(1 << 15)	/* System test enable */
+#define OMAP_I2C_SYSTEST_FREE		(1 << 14)	/* Free running mode */
+#define OMAP_I2C_SYSTEST_TMODE_MASK	(3 << 12)	/* Test mode select */
+#define OMAP_I2C_SYSTEST_TMODE_SHIFT	(12)		/* Test mode select */
+#define OMAP_I2C_SYSTEST_SCL_I		(1 << 3)	/* SCL line sense in */
+#define OMAP_I2C_SYSTEST_SCL_O		(1 << 2)	/* SCL line drive out */
+#define OMAP_I2C_SYSTEST_SDA_I		(1 << 1)	/* SDA line sense in */
+#define OMAP_I2C_SYSTEST_SDA_O		(1 << 0)	/* SDA line drive out */
+#endif
+
+/* OCP_SYSSTATUS bit definitions */
+#define SYSS_RESETDONE_MASK		(1 << 0)
+
+/* OCP_SYSCONFIG bit definitions */
+#define SYSC_CLOCKACTIVITY_MASK		(0x3 << 8)
+#define SYSC_SIDLEMODE_MASK		(0x3 << 3)
+#define SYSC_ENAWAKEUP_MASK		(1 << 2)
+#define SYSC_SOFTRESET_MASK		(1 << 1)
+#define SYSC_AUTOIDLE_MASK		(1 << 0)
+
+#define SYSC_IDLEMODE_SMART		0x2
+#define SYSC_CLOCKACTIVITY_FCLK		0x2
+
+/* Errata definitions */
+#define I2C_OMAP_ERRATA_I207		(1 << 0)
+#define I2C_OMAP3_1P153			(1 << 1)
+
+struct omap_i2c_dev {
+	struct device		*dev;
+	void __iomem		*base;		/* virtual */
+	int			irq;
+	int			reg_shift;      /* bit shift for I2C register addresses */
+	struct completion	cmd_complete;
+	struct resource		*ioarea;
+	u32			latency;	/* maximum mpu wkup latency */
+	void			(*set_mpu_wkup_lat)(struct device *dev,
+						    long latency);
+	u32			speed;		/* Speed of bus in kHz */
+	u32			dtrev;		/* extra revision from DT */
+	u32			flags;
+	u16			cmd_err;
+	u8			*buf;
+	u8			*regs;
+	size_t			buf_len;
+	struct i2c_adapter	adapter;
+	u8			fifo_size;	/* use as flag and value
+						 * fifo_size==0 implies no fifo
+						 * if set, should be trsh+1
+						 */
+	u8			rev;
+	unsigned		b_hw:1;		/* bad h/w fixes */
+	u16			iestate;	/* Saved interrupt register */
+	u16			pscstate;
+	u16			scllstate;
+	u16			sclhstate;
+	u16			bufstate;
+	u16			syscstate;
+	u16			westate;
+	u16			errata;
+};
+
+static const u8 reg_map_ip_v1[] = {
+	[OMAP_I2C_REV_REG] = 0x00,
+	[OMAP_I2C_IE_REG] = 0x01,
+	[OMAP_I2C_STAT_REG] = 0x02,
+	[OMAP_I2C_IV_REG] = 0x03,
+	[OMAP_I2C_WE_REG] = 0x03,
+	[OMAP_I2C_SYSS_REG] = 0x04,
+	[OMAP_I2C_BUF_REG] = 0x05,
+	[OMAP_I2C_CNT_REG] = 0x06,
+	[OMAP_I2C_DATA_REG] = 0x07,
+	[OMAP_I2C_SYSC_REG] = 0x08,
+	[OMAP_I2C_CON_REG] = 0x09,
+	[OMAP_I2C_OA_REG] = 0x0a,
+	[OMAP_I2C_SA_REG] = 0x0b,
+	[OMAP_I2C_PSC_REG] = 0x0c,
+	[OMAP_I2C_SCLL_REG] = 0x0d,
+	[OMAP_I2C_SCLH_REG] = 0x0e,
+	[OMAP_I2C_SYSTEST_REG] = 0x0f,
+	[OMAP_I2C_BUFSTAT_REG] = 0x10,
+};
+
+static const u8 reg_map_ip_v2[] = {
+	[OMAP_I2C_REV_REG] = 0x04,
+	[OMAP_I2C_IE_REG] = 0x2c,
+	[OMAP_I2C_STAT_REG] = 0x28,
+	[OMAP_I2C_IV_REG] = 0x34,
+	[OMAP_I2C_WE_REG] = 0x34,
+	[OMAP_I2C_SYSS_REG] = 0x90,
+	[OMAP_I2C_BUF_REG] = 0x94,
+	[OMAP_I2C_CNT_REG] = 0x98,
+	[OMAP_I2C_DATA_REG] = 0x9c,
+	[OMAP_I2C_SYSC_REG] = 0x10,
+	[OMAP_I2C_CON_REG] = 0xa4,
+	[OMAP_I2C_OA_REG] = 0xa8,
+	[OMAP_I2C_SA_REG] = 0xac,
+	[OMAP_I2C_PSC_REG] = 0xb0,
+	[OMAP_I2C_SCLL_REG] = 0xb4,
+	[OMAP_I2C_SCLH_REG] = 0xb8,
+	[OMAP_I2C_SYSTEST_REG] = 0xbC,
+	[OMAP_I2C_BUFSTAT_REG] = 0xc0,
+	[OMAP_I2C_IP_V2_REVNB_LO] = 0x00,
+	[OMAP_I2C_IP_V2_REVNB_HI] = 0x04,
+	[OMAP_I2C_IP_V2_IRQSTATUS_RAW] = 0x24,
+	[OMAP_I2C_IP_V2_IRQENABLE_SET] = 0x2c,
+	[OMAP_I2C_IP_V2_IRQENABLE_CLR] = 0x30,
+};
+
+static inline void omap_i2c_write_reg(struct omap_i2c_dev *i2c_dev,
+				      int reg, u16 val)
+{
+	__raw_writew(val, i2c_dev->base +
+			(i2c_dev->regs[reg] << i2c_dev->reg_shift));
+}
+
+static inline u16 omap_i2c_read_reg(struct omap_i2c_dev *i2c_dev, int reg)
+{
+	return __raw_readw(i2c_dev->base +
+				(i2c_dev->regs[reg] << i2c_dev->reg_shift));
+}
+
+static void omap_i2c_unidle(struct omap_i2c_dev *dev)
+{
+	if (dev->flags & OMAP_I2C_FLAG_RESET_REGS_POSTIDLE) {
+		omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
+		omap_i2c_write_reg(dev, OMAP_I2C_PSC_REG, dev->pscstate);
+		omap_i2c_write_reg(dev, OMAP_I2C_SCLL_REG, dev->scllstate);
+		omap_i2c_write_reg(dev, OMAP_I2C_SCLH_REG, dev->sclhstate);
+		omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG, dev->bufstate);
+		omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG, dev->syscstate);
+		omap_i2c_write_reg(dev, OMAP_I2C_WE_REG, dev->westate);
+		omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN);
+	}
+
+	/*
+	 * Don't write to this register if the IE state is 0 as it can
+	 * cause deadlock.
+	 */
+	if (dev->iestate)
+		omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, dev->iestate);
+}
+
+static void omap_i2c_idle(struct omap_i2c_dev *dev)
+{
+	u16 iv;
+
+	dev->iestate = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG);
+	if (dev->dtrev == OMAP_I2C_IP_VERSION_2)
+		omap_i2c_write_reg(dev, OMAP_I2C_IP_V2_IRQENABLE_CLR, 1);
+	else
+		omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, 0);
+
+	if (dev->rev < OMAP_I2C_OMAP1_REV_2) {
+		iv = omap_i2c_read_reg(dev, OMAP_I2C_IV_REG); /* Read clears */
+	} else {
+		omap_i2c_write_reg(dev, OMAP_I2C_STAT_REG, dev->iestate);
+
+		/* Flush posted write */
+		omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG);
+	}
+}
+
+static int omap_i2c_init(struct omap_i2c_dev *dev)
+{
+	u16 psc = 0, scll = 0, sclh = 0, buf = 0;
+	u16 fsscll = 0, fssclh = 0, hsscll = 0, hssclh = 0;
+	unsigned long fclk_rate = 12000000;
+	unsigned long timeout;
+	unsigned long internal_clk = 0;
+	struct clk *fclk;
+
+	if (dev->rev >= OMAP_I2C_OMAP1_REV_2) {
+		/* Disable I2C controller before soft reset */
+		omap_i2c_write_reg(dev, OMAP_I2C_CON_REG,
+			omap_i2c_read_reg(dev, OMAP_I2C_CON_REG) &
+				~(OMAP_I2C_CON_EN));
+
+		omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG, SYSC_SOFTRESET_MASK);
+		/* For some reason we need to set the EN bit before the
+		 * reset done bit gets set. */
+		timeout = jiffies + OMAP_I2C_TIMEOUT;
+		omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN);
+		while (!(omap_i2c_read_reg(dev, OMAP_I2C_SYSS_REG) &
+			 SYSS_RESETDONE_MASK)) {
+			if (time_after(jiffies, timeout)) {
+				dev_warn(dev->dev, "timeout waiting "
+						"for controller reset\n");
+				return -ETIMEDOUT;
+			}
+			msleep(1);
+		}
+
+		/* SYSC register is cleared by the reset; rewrite it */
+		if (dev->rev == OMAP_I2C_REV_ON_2430) {
+
+			omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG,
+					   SYSC_AUTOIDLE_MASK);
+
+		} else if (dev->rev >= OMAP_I2C_REV_ON_3430) {
+			dev->syscstate = SYSC_AUTOIDLE_MASK;
+			dev->syscstate |= SYSC_ENAWAKEUP_MASK;
+			dev->syscstate |= (SYSC_IDLEMODE_SMART <<
+			      __ffs(SYSC_SIDLEMODE_MASK));
+			dev->syscstate |= (SYSC_CLOCKACTIVITY_FCLK <<
+			      __ffs(SYSC_CLOCKACTIVITY_MASK));
+
+			omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG,
+							dev->syscstate);
+			/*
+			 * Enabling all wakup sources to stop I2C freezing on
+			 * WFI instruction.
+			 * REVISIT: Some wkup sources might not be needed.
+			 */
+			dev->westate = OMAP_I2C_WE_ALL;
+			omap_i2c_write_reg(dev, OMAP_I2C_WE_REG,
+							dev->westate);
+		}
+	}
+	omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
+
+	if (dev->flags & OMAP_I2C_FLAG_ALWAYS_ARMXOR_CLK) {
+		/*
+		 * The I2C functional clock is the armxor_ck, so there's
+		 * no need to get "armxor_ck" separately.  Now, if OMAP2420
+		 * always returns 12MHz for the functional clock, we can
+		 * do this bit unconditionally.
+		 */
+		fclk = clk_get(dev->dev, "fck");
+		fclk_rate = clk_get_rate(fclk);
+		clk_put(fclk);
+
+		/* TRM for 5912 says the I2C clock must be prescaled to be
+		 * between 7 - 12 MHz. The XOR input clock is typically
+		 * 12, 13 or 19.2 MHz. So we should have code that produces:
+		 *
+		 * XOR MHz	Divider		Prescaler
+		 * 12		1		0
+		 * 13		2		1
+		 * 19.2		2		1
+		 */
+		if (fclk_rate > 12000000)
+			psc = fclk_rate / 12000000;
+	}
+
+	if (!(dev->flags & OMAP_I2C_FLAG_SIMPLE_CLOCK)) {
+
+		/*
+		 * HSI2C controller internal clk rate should be 19.2 Mhz for
+		 * HS and for all modes on 2430. On 34xx we can use lower rate
+		 * to get longer filter period for better noise suppression.
+		 * The filter is iclk (fclk for HS) period.
+		 */
+		if (dev->speed > 400 ||
+			       dev->flags & OMAP_I2C_FLAG_FORCE_19200_INT_CLK)
+			internal_clk = 19200;
+		else if (dev->speed > 100)
+			internal_clk = 9600;
+		else
+			internal_clk = 4000;
+		fclk = clk_get(dev->dev, "fck");
+		fclk_rate = clk_get_rate(fclk) / 1000;
+		clk_put(fclk);
+
+		/* Compute prescaler divisor */
+		psc = fclk_rate / internal_clk;
+		psc = psc - 1;
+
+		/* If configured for High Speed */
+		if (dev->speed > 400) {
+			unsigned long scl;
+
+			/* For first phase of HS mode */
+			scl = internal_clk / 400;
+			fsscll = scl - (scl / 3) - 7;
+			fssclh = (scl / 3) - 5;
+
+			/* For second phase of HS mode */
+			scl = fclk_rate / dev->speed;
+			hsscll = scl - (scl / 3) - 7;
+			hssclh = (scl / 3) - 5;
+		} else if (dev->speed > 100) {
+			unsigned long scl;
+
+			/* Fast mode */
+			scl = internal_clk / dev->speed;
+			fsscll = scl - (scl / 3) - 7;
+			fssclh = (scl / 3) - 5;
+		} else {
+			/* Standard mode */
+			fsscll = internal_clk / (dev->speed * 2) - 7;
+			fssclh = internal_clk / (dev->speed * 2) - 5;
+		}
+		scll = (hsscll << OMAP_I2C_SCLL_HSSCLL) | fsscll;
+		sclh = (hssclh << OMAP_I2C_SCLH_HSSCLH) | fssclh;
+	} else {
+		/* Program desired operating rate */
+		fclk_rate /= (psc + 1) * 1000;
+		if (psc > 2)
+			psc = 2;
+		scll = fclk_rate / (dev->speed * 2) - 7 + psc;
+		sclh = fclk_rate / (dev->speed * 2) - 7 + psc;
+	}
+
+	/* Setup clock prescaler to obtain approx 12MHz I2C module clock: */
+	omap_i2c_write_reg(dev, OMAP_I2C_PSC_REG, psc);
+
+	/* SCL low and high time values */
+	omap_i2c_write_reg(dev, OMAP_I2C_SCLL_REG, scll);
+	omap_i2c_write_reg(dev, OMAP_I2C_SCLH_REG, sclh);
+
+	if (dev->fifo_size) {
+		/* Note: setup required fifo size - 1. RTRSH and XTRSH */
+		buf = (dev->fifo_size - 1) << 8 | OMAP_I2C_BUF_RXFIF_CLR |
+			(dev->fifo_size - 1) | OMAP_I2C_BUF_TXFIF_CLR;
+		omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG, buf);
+	}
+
+	/* Take the I2C module out of reset: */
+	omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN);
+
+	dev->errata = 0;
+
+	if (dev->flags & OMAP_I2C_FLAG_APPLY_ERRATA_I207)
+		dev->errata |= I2C_OMAP_ERRATA_I207;
+
+	/* Enable interrupts */
+	dev->iestate = (OMAP_I2C_IE_XRDY | OMAP_I2C_IE_RRDY |
+			OMAP_I2C_IE_ARDY | OMAP_I2C_IE_NACK |
+			OMAP_I2C_IE_AL)  | ((dev->fifo_size) ?
+				(OMAP_I2C_IE_RDR | OMAP_I2C_IE_XDR) : 0);
+	omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, dev->iestate);
+	if (dev->flags & OMAP_I2C_FLAG_RESET_REGS_POSTIDLE) {
+		dev->pscstate = psc;
+		dev->scllstate = scll;
+		dev->sclhstate = sclh;
+		dev->bufstate = buf;
+	}
+	return 0;
+}
+
+/*
+ * Waiting on Bus Busy
+ */
+static int omap_i2c_wait_for_bb(struct omap_i2c_dev *dev)
+{
+	unsigned long timeout;
+
+	timeout = jiffies + OMAP_I2C_TIMEOUT;
+	while (omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG) & OMAP_I2C_STAT_BB) {
+		if (time_after(jiffies, timeout)) {
+			dev_warn(dev->dev, "timeout waiting for bus ready\n");
+			return -ETIMEDOUT;
+		}
+		msleep(1);
+	}
+
+	return 0;
+}
+
+/*
+ * Low level master read/write transaction.
+ */
+static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
+			     struct i2c_msg *msg, int stop)
+{
+	struct omap_i2c_dev *dev = i2c_get_adapdata(adap);
+	int r;
+	u16 w;
+
+	dev_dbg(dev->dev, "addr: 0x%04x, len: %d, flags: 0x%x, stop: %d\n",
+		msg->addr, msg->len, msg->flags, stop);
+
+	if (msg->len == 0)
+		return -EINVAL;
+
+	omap_i2c_write_reg(dev, OMAP_I2C_SA_REG, msg->addr);
+
+	/* REVISIT: Could the STB bit of I2C_CON be used with probing? */
+	dev->buf = msg->buf;
+	dev->buf_len = msg->len;
+
+	omap_i2c_write_reg(dev, OMAP_I2C_CNT_REG, dev->buf_len);
+
+	/* Clear the FIFO Buffers */
+	w = omap_i2c_read_reg(dev, OMAP_I2C_BUF_REG);
+	w |= OMAP_I2C_BUF_RXFIF_CLR | OMAP_I2C_BUF_TXFIF_CLR;
+	omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG, w);
+
+	init_completion(&dev->cmd_complete);
+	dev->cmd_err = 0;
+
+	w = OMAP_I2C_CON_EN | OMAP_I2C_CON_MST | OMAP_I2C_CON_STT;
+
+	/* High speed configuration */
+	if (dev->speed > 400)
+		w |= OMAP_I2C_CON_OPMODE_HS;
+
+	if (msg->flags & I2C_M_TEN)
+		w |= OMAP_I2C_CON_XA;
+	if (!(msg->flags & I2C_M_RD))
+		w |= OMAP_I2C_CON_TRX;
+
+	if (!dev->b_hw && stop)
+		w |= OMAP_I2C_CON_STP;
+
+	omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, w);
+
+	/*
+	 * Don't write stt and stp together on some hardware.
+	 */
+	if (dev->b_hw && stop) {
+		unsigned long delay = jiffies + OMAP_I2C_TIMEOUT;
+		u16 con = omap_i2c_read_reg(dev, OMAP_I2C_CON_REG);
+		while (con & OMAP_I2C_CON_STT) {
+			con = omap_i2c_read_reg(dev, OMAP_I2C_CON_REG);
+
+			/* Let the user know if i2c is in a bad state */
+			if (time_after(jiffies, delay)) {
+				dev_err(dev->dev, "controller timed out "
+				"waiting for start condition to finish\n");
+				return -ETIMEDOUT;
+			}
+			cpu_relax();
+		}
+
+		w |= OMAP_I2C_CON_STP;
+		w &= ~OMAP_I2C_CON_STT;
+		omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, w);
+	}
+
+	/*
+	 * REVISIT: We should abort the transfer on signals, but the bus goes
+	 * into arbitration and we're currently unable to recover from it.
+	 */
+	r = wait_for_completion_timeout(&dev->cmd_complete,
+					OMAP_I2C_TIMEOUT);
+	dev->buf_len = 0;
+	if (r < 0)
+		return r;
+	if (r == 0) {
+		dev_err(dev->dev, "controller timed out\n");
+		omap_i2c_init(dev);
+		return -ETIMEDOUT;
+	}
+
+	if (likely(!dev->cmd_err))
+		return 0;
+
+	/* We have an error */
+	if (dev->cmd_err & (OMAP_I2C_STAT_AL | OMAP_I2C_STAT_ROVR |
+			    OMAP_I2C_STAT_XUDF)) {
+		omap_i2c_init(dev);
+		return -EIO;
+	}
+
+	if (dev->cmd_err & OMAP_I2C_STAT_NACK) {
+		if (msg->flags & I2C_M_IGNORE_NAK)
+			return 0;
+		if (stop) {
+			w = omap_i2c_read_reg(dev, OMAP_I2C_CON_REG);
+			w |= OMAP_I2C_CON_STP;
+			omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, w);
+		}
+		return -EREMOTEIO;
+	}
+	return -EIO;
+}
+
+
+/*
+ * Prepare controller for a transaction and call omap_i2c_xfer_msg
+ * to do the work during IRQ processing.
+ */
+static int
+omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
+{
+	struct omap_i2c_dev *dev = i2c_get_adapdata(adap);
+	int i;
+	int r;
+
+	pm_runtime_get_sync(dev->dev);
+
+	r = omap_i2c_wait_for_bb(dev);
+	if (r < 0)
+		goto out;
+
+	if (dev->set_mpu_wkup_lat != NULL)
+		dev->set_mpu_wkup_lat(dev->dev, dev->latency);
+
+	for (i = 0; i < num; i++) {
+		r = omap_i2c_xfer_msg(adap, &msgs[i], (i == (num - 1)));
+		if (r != 0)
+			break;
+	}
+
+	if (dev->set_mpu_wkup_lat != NULL)
+		dev->set_mpu_wkup_lat(dev->dev, -1);
+
+	if (r == 0)
+		r = num;
+
+	omap_i2c_wait_for_bb(dev);
+out:
+	pm_runtime_put(dev->dev);
+	return r;
+}
+
+static u32
+omap_i2c_func(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
+}
+
+static inline void
+omap_i2c_complete_cmd(struct omap_i2c_dev *dev, u16 err)
+{
+	dev->cmd_err |= err;
+	complete(&dev->cmd_complete);
+}
+
+static inline void
+omap_i2c_ack_stat(struct omap_i2c_dev *dev, u16 stat)
+{
+	omap_i2c_write_reg(dev, OMAP_I2C_STAT_REG, stat);
+}
+
+static inline void i2c_omap_errata_i207(struct omap_i2c_dev *dev, u16 stat)
+{
+	/*
+	 * I2C Errata(Errata Nos. OMAP2: 1.67, OMAP3: 1.8)
+	 * Not applicable for OMAP4.
+	 * Under certain rare conditions, RDR could be set again
+	 * when the bus is busy, then ignore the interrupt and
+	 * clear the interrupt.
+	 */
+	if (stat & OMAP_I2C_STAT_RDR) {
+		/* Step 1: If RDR is set, clear it */
+		omap_i2c_ack_stat(dev, OMAP_I2C_STAT_RDR);
+
+		/* Step 2: */
+		if (!(omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG)
+						& OMAP_I2C_STAT_BB)) {
+
+			/* Step 3: */
+			if (omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG)
+						& OMAP_I2C_STAT_RDR) {
+				omap_i2c_ack_stat(dev, OMAP_I2C_STAT_RDR);
+				dev_dbg(dev->dev, "RDR when bus is busy.\n");
+			}
+
+		}
+	}
+}
+
+/* rev1 devices are apparently only on some 15xx */
+#ifdef CONFIG_ARCH_OMAP15XX
+
+static irqreturn_t
+omap_i2c_omap1_isr(int this_irq, void *dev_id)
+{
+	struct omap_i2c_dev *dev = dev_id;
+	u16 iv, w;
+
+	if (pm_runtime_suspended(dev->dev))
+		return IRQ_NONE;
+
+	iv = omap_i2c_read_reg(dev, OMAP_I2C_IV_REG);
+	switch (iv) {
+	case 0x00:	/* None */
+		break;
+	case 0x01:	/* Arbitration lost */
+		dev_err(dev->dev, "Arbitration lost\n");
+		omap_i2c_complete_cmd(dev, OMAP_I2C_STAT_AL);
+		break;
+	case 0x02:	/* No acknowledgement */
+		omap_i2c_complete_cmd(dev, OMAP_I2C_STAT_NACK);
+		omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_STP);
+		break;
+	case 0x03:	/* Register access ready */
+		omap_i2c_complete_cmd(dev, 0);
+		break;
+	case 0x04:	/* Receive data ready */
+		if (dev->buf_len) {
+			w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG);
+			*dev->buf++ = w;
+			dev->buf_len--;
+			if (dev->buf_len) {
+				*dev->buf++ = w >> 8;
+				dev->buf_len--;
+			}
+		} else
+			dev_err(dev->dev, "RRDY IRQ while no data requested\n");
+		break;
+	case 0x05:	/* Transmit data ready */
+		if (dev->buf_len) {
+			w = *dev->buf++;
+			dev->buf_len--;
+			if (dev->buf_len) {
+				w |= *dev->buf++ << 8;
+				dev->buf_len--;
+			}
+			omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w);
+		} else
+			dev_err(dev->dev, "XRDY IRQ while no data to send\n");
+		break;
+	default:
+		return IRQ_NONE;
+	}
+
+	return IRQ_HANDLED;
+}
+#else
+#define omap_i2c_omap1_isr		NULL
+#endif
+
+/*
+ * OMAP3430 Errata 1.153: When an XRDY/XDR is hit, wait for XUDF before writing
+ * data to DATA_REG. Otherwise some data bytes can be lost while transferring
+ * them from the memory to the I2C interface.
+ */
+static int errata_omap3_1p153(struct omap_i2c_dev *dev, u16 *stat, int *err)
+{
+	unsigned long timeout = 10000;
+
+	while (--timeout && !(*stat & OMAP_I2C_STAT_XUDF)) {
+		if (*stat & (OMAP_I2C_STAT_NACK | OMAP_I2C_STAT_AL)) {
+			omap_i2c_ack_stat(dev, *stat & (OMAP_I2C_STAT_XRDY |
+							OMAP_I2C_STAT_XDR));
+			*err |= OMAP_I2C_STAT_XUDF;
+			return -ETIMEDOUT;
+		}
+
+		cpu_relax();
+		*stat = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG);
+	}
+
+	if (!timeout) {
+		dev_err(dev->dev, "timeout waiting on XUDF bit\n");
+		return 0;
+	}
+
+	return 0;
+}
+
+static irqreturn_t
+omap_i2c_isr(int this_irq, void *dev_id)
+{
+	struct omap_i2c_dev *dev = dev_id;
+	u16 bits;
+	u16 stat, w;
+	int err, count = 0;
+
+	if (pm_runtime_suspended(dev->dev))
+		return IRQ_NONE;
+
+	bits = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG);
+	while ((stat = (omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG))) & bits) {
+		dev_dbg(dev->dev, "IRQ (ISR = 0x%04x)\n", stat);
+		if (count++ == 100) {
+			dev_warn(dev->dev, "Too much work in one IRQ\n");
+			break;
+		}
+
+		err = 0;
+complete:
+		/*
+		 * Ack the stat in one go, but [R/X]DR and [R/X]RDY should be
+		 * acked after the data operation is complete.
+		 * Ref: TRM SWPU114Q Figure 18-31
+		 */
+		omap_i2c_write_reg(dev, OMAP_I2C_STAT_REG, stat &
+				~(OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR |
+				OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR));
+
+		if (stat & OMAP_I2C_STAT_NACK)
+			err |= OMAP_I2C_STAT_NACK;
+
+		if (stat & OMAP_I2C_STAT_AL) {
+			dev_err(dev->dev, "Arbitration lost\n");
+			err |= OMAP_I2C_STAT_AL;
+		}
+		/*
+		 * ProDB0017052: Clear ARDY bit twice
+		 */
+		if (stat & (OMAP_I2C_STAT_ARDY | OMAP_I2C_STAT_NACK |
+					OMAP_I2C_STAT_AL)) {
+			omap_i2c_ack_stat(dev, stat &
+				(OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR |
+				OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR |
+				OMAP_I2C_STAT_ARDY));
+			omap_i2c_complete_cmd(dev, err);
+			return IRQ_HANDLED;
+		}
+		if (stat & (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR)) {
+			u8 num_bytes = 1;
+
+			if (dev->errata & I2C_OMAP_ERRATA_I207)
+				i2c_omap_errata_i207(dev, stat);
+
+			if (dev->fifo_size) {
+				if (stat & OMAP_I2C_STAT_RRDY)
+					num_bytes = dev->fifo_size;
+				else    /* read RXSTAT on RDR interrupt */
+					num_bytes = (omap_i2c_read_reg(dev,
+							OMAP_I2C_BUFSTAT_REG)
+							>> 8) & 0x3F;
+			}
+			while (num_bytes) {
+				num_bytes--;
+				w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG);
+				if (dev->buf_len) {
+					*dev->buf++ = w;
+					dev->buf_len--;
+					/*
+					 * Data reg in 2430, omap3 and
+					 * omap4 is 8 bit wide
+					 */
+					if (dev->flags &
+						 OMAP_I2C_FLAG_16BIT_DATA_REG) {
+						if (dev->buf_len) {
+							*dev->buf++ = w >> 8;
+							dev->buf_len--;
+						}
+					}
+				} else {
+					if (stat & OMAP_I2C_STAT_RRDY)
+						dev_err(dev->dev,
+							"RRDY IRQ while no data"
+								" requested\n");
+					if (stat & OMAP_I2C_STAT_RDR)
+						dev_err(dev->dev,
+							"RDR IRQ while no data"
+								" requested\n");
+					break;
+				}
+			}
+			omap_i2c_ack_stat(dev,
+				stat & (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR));
+			continue;
+		}
+		if (stat & (OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR)) {
+			u8 num_bytes = 1;
+			if (dev->fifo_size) {
+				if (stat & OMAP_I2C_STAT_XRDY)
+					num_bytes = dev->fifo_size;
+				else    /* read TXSTAT on XDR interrupt */
+					num_bytes = omap_i2c_read_reg(dev,
+							OMAP_I2C_BUFSTAT_REG)
+							& 0x3F;
+			}
+			while (num_bytes) {
+				num_bytes--;
+				w = 0;
+				if (dev->buf_len) {
+					w = *dev->buf++;
+					dev->buf_len--;
+					/*
+					 * Data reg in 2430, omap3 and
+					 * omap4 is 8 bit wide
+					 */
+					if (dev->flags &
+						 OMAP_I2C_FLAG_16BIT_DATA_REG) {
+						if (dev->buf_len) {
+							w |= *dev->buf++ << 8;
+							dev->buf_len--;
+						}
+					}
+				} else {
+					if (stat & OMAP_I2C_STAT_XRDY)
+						dev_err(dev->dev,
+							"XRDY IRQ while no "
+							"data to send\n");
+					if (stat & OMAP_I2C_STAT_XDR)
+						dev_err(dev->dev,
+							"XDR IRQ while no "
+							"data to send\n");
+					break;
+				}
+
+				if ((dev->errata & I2C_OMAP3_1P153) &&
+				    errata_omap3_1p153(dev, &stat, &err))
+					goto complete;
+
+				omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w);
+			}
+			omap_i2c_ack_stat(dev,
+				stat & (OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR));
+			continue;
+		}
+		if (stat & OMAP_I2C_STAT_ROVR) {
+			dev_err(dev->dev, "Receive overrun\n");
+			dev->cmd_err |= OMAP_I2C_STAT_ROVR;
+		}
+		if (stat & OMAP_I2C_STAT_XUDF) {
+			dev_err(dev->dev, "Transmit underflow\n");
+			dev->cmd_err |= OMAP_I2C_STAT_XUDF;
+		}
+	}
+
+	return count ? IRQ_HANDLED : IRQ_NONE;
+}
+
+static const struct i2c_algorithm omap_i2c_algo = {
+	.master_xfer	= omap_i2c_xfer,
+	.functionality	= omap_i2c_func,
+};
+
+#ifdef CONFIG_OF
+static struct omap_i2c_bus_platform_data omap3_pdata = {
+	.rev = OMAP_I2C_IP_VERSION_1,
+	.flags = OMAP_I2C_FLAG_APPLY_ERRATA_I207 |
+		 OMAP_I2C_FLAG_RESET_REGS_POSTIDLE |
+		 OMAP_I2C_FLAG_BUS_SHIFT_2,
+};
+
+static struct omap_i2c_bus_platform_data omap4_pdata = {
+	.rev = OMAP_I2C_IP_VERSION_2,
+};
+
+static const struct of_device_id omap_i2c_of_match[] = {
+	{
+		.compatible = "ti,omap4-i2c",
+		.data = &omap4_pdata,
+	},
+	{
+		.compatible = "ti,omap3-i2c",
+		.data = &omap3_pdata,
+	},
+	{ },
+};
+MODULE_DEVICE_TABLE(of, omap_i2c_of_match);
+#endif
+
+static int __devinit
+omap_i2c_probe(struct platform_device *pdev)
+{
+	struct omap_i2c_dev	*dev;
+	struct i2c_adapter	*adap;
+	struct resource		*mem, *irq, *ioarea;
+	struct omap_i2c_bus_platform_data *pdata = pdev->dev.platform_data;
+	struct device_node	*node = pdev->dev.of_node;
+	const struct of_device_id *match;
+	irq_handler_t isr;
+	int r;
+
+	/* 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, resource_size(mem),
+			pdev->name);
+	if (!ioarea) {
+		dev_err(&pdev->dev, "I2C region already claimed\n");
+		return -EBUSY;
+	}
+
+	dev = kzalloc(sizeof(struct omap_i2c_dev), GFP_KERNEL);
+	if (!dev) {
+		r = -ENOMEM;
+		goto err_release_region;
+	}
+
+	match = of_match_device(of_match_ptr(omap_i2c_of_match), &pdev->dev);
+	if (match) {
+		u32 freq = 100000; /* default to 100000 Hz */
+
+		pdata = match->data;
+		dev->dtrev = pdata->rev;
+		dev->flags = pdata->flags;
+
+		of_property_read_u32(node, "clock-frequency", &freq);
+		/* convert DT freq value in Hz into kHz for speed */
+		dev->speed = freq / 1000;
+	} else if (pdata != NULL) {
+		dev->speed = pdata->clkrate;
+		dev->flags = pdata->flags;
+		dev->set_mpu_wkup_lat = pdata->set_mpu_wkup_lat;
+		dev->dtrev = pdata->rev;
+	}
+
+	dev->dev = &pdev->dev;
+	dev->irq = irq->start;
+	dev->base = ioremap(mem->start, resource_size(mem));
+	if (!dev->base) {
+		r = -ENOMEM;
+		goto err_free_mem;
+	}
+
+	platform_set_drvdata(pdev, dev);
+
+	dev->reg_shift = (dev->flags >> OMAP_I2C_FLAG_BUS_SHIFT__SHIFT) & 3;
+
+	if (dev->dtrev == OMAP_I2C_IP_VERSION_2)
+		dev->regs = (u8 *)reg_map_ip_v2;
+	else
+		dev->regs = (u8 *)reg_map_ip_v1;
+
+	pm_runtime_enable(dev->dev);
+	pm_runtime_get_sync(dev->dev);
+
+	dev->rev = omap_i2c_read_reg(dev, OMAP_I2C_REV_REG) & 0xff;
+
+	if (dev->rev <= OMAP_I2C_REV_ON_3430)
+		dev->errata |= I2C_OMAP3_1P153;
+
+	if (!(dev->flags & OMAP_I2C_FLAG_NO_FIFO)) {
+		u16 s;
+
+		/* Set up the fifo size - Get total size */
+		s = (omap_i2c_read_reg(dev, OMAP_I2C_BUFSTAT_REG) >> 14) & 0x3;
+		dev->fifo_size = 0x8 << s;
+
+		/*
+		 * Set up notification threshold as half the total available
+		 * size. This is to ensure that we can handle the status on int
+		 * call back latencies.
+		 */
+
+		dev->fifo_size = (dev->fifo_size / 2);
+
+		if (dev->rev >= OMAP_I2C_REV_ON_3530_4430)
+			dev->b_hw = 0; /* Disable hardware fixes */
+		else
+			dev->b_hw = 1; /* Enable hardware fixes */
+
+		/* calculate wakeup latency constraint for MPU */
+		if (dev->set_mpu_wkup_lat != NULL)
+			dev->latency = (1000000 * dev->fifo_size) /
+				       (1000 * dev->speed / 8);
+	}
+
+	/* reset ASAP, clearing any IRQs */
+	omap_i2c_init(dev);
+
+	isr = (dev->rev < OMAP_I2C_OMAP1_REV_2) ? omap_i2c_omap1_isr :
+								   omap_i2c_isr;
+	r = request_irq(dev->irq, isr, 0, pdev->name, dev);
+
+	if (r) {
+		dev_err(dev->dev, "failure requesting irq %i\n", dev->irq);
+		goto err_unuse_clocks;
+	}
+
+	dev_info(dev->dev, "bus %d rev%d.%d.%d at %d kHz\n", pdev->id,
+		 dev->dtrev, dev->rev >> 4, dev->rev & 0xf, dev->speed);
+
+	pm_runtime_put(dev->dev);
+
+	adap = &dev->adapter;
+	i2c_set_adapdata(adap, dev);
+	adap->owner = THIS_MODULE;
+	adap->class = I2C_CLASS_HWMON;
+	strlcpy(adap->name, "OMAP I2C adapter", sizeof(adap->name));
+	adap->algo = &omap_i2c_algo;
+	adap->dev.parent = &pdev->dev;
+	adap->dev.of_node = pdev->dev.of_node;
+
+	/* i2c device drivers may be active on return from add_adapter() */
+	adap->nr = pdev->id;
+	r = i2c_add_numbered_adapter(adap);
+	if (r) {
+		dev_err(dev->dev, "failure adding adapter\n");
+		goto err_free_irq;
+	}
+
+	of_i2c_register_devices(adap);
+
+	return 0;
+
+err_free_irq:
+	free_irq(dev->irq, dev);
+err_unuse_clocks:
+	omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
+	pm_runtime_put(dev->dev);
+	iounmap(dev->base);
+err_free_mem:
+	platform_set_drvdata(pdev, NULL);
+	kfree(dev);
+err_release_region:
+	release_mem_region(mem->start, resource_size(mem));
+
+	return r;
+}
+
+static int
+omap_i2c_remove(struct platform_device *pdev)
+{
+	struct omap_i2c_dev	*dev = platform_get_drvdata(pdev);
+	struct resource		*mem;
+
+	platform_set_drvdata(pdev, NULL);
+
+	free_irq(dev->irq, dev);
+	i2c_del_adapter(&dev->adapter);
+	omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
+	iounmap(dev->base);
+	kfree(dev);
+	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	release_mem_region(mem->start, resource_size(mem));
+	return 0;
+}
+
+#ifdef CONFIG_PM_RUNTIME
+static int omap_i2c_runtime_suspend(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct omap_i2c_dev *_dev = platform_get_drvdata(pdev);
+
+	omap_i2c_idle(_dev);
+
+	return 0;
+}
+
+static int omap_i2c_runtime_resume(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct omap_i2c_dev *_dev = platform_get_drvdata(pdev);
+
+	omap_i2c_unidle(_dev);
+
+	return 0;
+}
+
+static struct dev_pm_ops omap_i2c_pm_ops = {
+	.runtime_suspend = omap_i2c_runtime_suspend,
+	.runtime_resume = omap_i2c_runtime_resume,
+};
+#define OMAP_I2C_PM_OPS (&omap_i2c_pm_ops)
+#else
+#define OMAP_I2C_PM_OPS NULL
+#endif
+
+static struct platform_driver omap_i2c_driver = {
+	.probe		= omap_i2c_probe,
+	.remove		= omap_i2c_remove,
+	.driver		= {
+		.name	= "omap_i2c",
+		.owner	= THIS_MODULE,
+		.pm	= OMAP_I2C_PM_OPS,
+		.of_match_table = of_match_ptr(omap_i2c_of_match),
+	},
+};
+
+/* I2C may be needed to bring up other drivers */
+static int __init
+omap_i2c_init_driver(void)
+{
+	return platform_driver_register(&omap_i2c_driver);
+}
+subsys_initcall(omap_i2c_init_driver);
+
+static void __exit omap_i2c_exit_driver(void)
+{
+	platform_driver_unregister(&omap_i2c_driver);
+}
+module_exit(omap_i2c_exit_driver);
+
+MODULE_AUTHOR("MontaVista Software, Inc. (and others)");
+MODULE_DESCRIPTION("TI OMAP I2C bus adapter");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:omap_i2c");
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-parport-light.c b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-parport-light.c
new file mode 100644
index 0000000..4b95f7a
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-parport-light.c
@@ -0,0 +1,281 @@
+/* ------------------------------------------------------------------------ *
+ * i2c-parport-light.c I2C bus over parallel port                           *
+ * ------------------------------------------------------------------------ *
+   Copyright (C) 2003-2010 Jean Delvare <khali@linux-fr.org>
+
+   Based on older i2c-velleman.c driver
+   Copyright (C) 1995-2000 Simon G. Vogl
+   With some changes from:
+   Frodo Looijaard <frodol@dds.nl>
+   Kyösti Mälkki <kmalkki@cc.hut.fi>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * ------------------------------------------------------------------------ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/ioport.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <linux/i2c-smbus.h>
+#include <linux/io.h>
+#include "i2c-parport.h"
+
+#define DEFAULT_BASE 0x378
+#define DRVNAME "i2c-parport-light"
+
+static struct platform_device *pdev;
+
+static u16 base;
+module_param(base, ushort, 0);
+MODULE_PARM_DESC(base, "Base I/O address");
+
+static int irq;
+module_param(irq, int, 0);
+MODULE_PARM_DESC(irq, "IRQ (optional)");
+
+/* ----- Low-level parallel port access ----------------------------------- */
+
+static inline void port_write(unsigned char p, unsigned char d)
+{
+	outb(d, base+p);
+}
+
+static inline unsigned char port_read(unsigned char p)
+{
+	return inb(base+p);
+}
+
+/* ----- Unified line operation functions --------------------------------- */
+
+static inline void line_set(int state, const struct lineop *op)
+{
+	u8 oldval = port_read(op->port);
+
+	/* Touch only the bit(s) needed */
+	if ((op->inverted && !state) || (!op->inverted && state))
+		port_write(op->port, oldval | op->val);
+	else
+		port_write(op->port, oldval & ~op->val);
+}
+
+static inline int line_get(const struct lineop *op)
+{
+	u8 oldval = port_read(op->port);
+
+	return ((op->inverted && (oldval & op->val) != op->val)
+	    || (!op->inverted && (oldval & op->val) == op->val));
+}
+
+/* ----- I2C algorithm call-back functions and structures ----------------- */
+
+static void parport_setscl(void *data, int state)
+{
+	line_set(state, &adapter_parm[type].setscl);
+}
+
+static void parport_setsda(void *data, int state)
+{
+	line_set(state, &adapter_parm[type].setsda);
+}
+
+static int parport_getscl(void *data)
+{
+	return line_get(&adapter_parm[type].getscl);
+}
+
+static int parport_getsda(void *data)
+{
+	return line_get(&adapter_parm[type].getsda);
+}
+
+/* Encapsulate the functions above in the correct structure
+   Note that getscl will be set to NULL by the attaching code for adapters
+   that cannot read SCL back */
+static struct i2c_algo_bit_data parport_algo_data = {
+	.setsda		= parport_setsda,
+	.setscl		= parport_setscl,
+	.getsda		= parport_getsda,
+	.getscl		= parport_getscl,
+	.udelay		= 50,
+	.timeout	= HZ,
+};
+
+/* ----- Driver registration ---------------------------------------------- */
+
+static struct i2c_adapter parport_adapter = {
+	.owner		= THIS_MODULE,
+	.class		= I2C_CLASS_HWMON,
+	.algo_data	= &parport_algo_data,
+	.name		= "Parallel port adapter (light)",
+};
+
+/* SMBus alert support */
+static struct i2c_smbus_alert_setup alert_data = {
+	.alert_edge_triggered	= 1,
+};
+static struct i2c_client *ara;
+static struct lineop parport_ctrl_irq = {
+	.val		= (1 << 4),
+	.port		= PORT_CTRL,
+};
+
+static int __devinit i2c_parport_probe(struct platform_device *pdev)
+{
+	int err;
+
+	/* Reset hardware to a sane state (SCL and SDA high) */
+	parport_setsda(NULL, 1);
+	parport_setscl(NULL, 1);
+	/* Other init if needed (power on...) */
+	if (adapter_parm[type].init.val) {
+		line_set(1, &adapter_parm[type].init);
+		/* Give powered devices some time to settle */
+		msleep(100);
+	}
+
+	parport_adapter.dev.parent = &pdev->dev;
+	err = i2c_bit_add_bus(&parport_adapter);
+	if (err) {
+		dev_err(&pdev->dev, "Unable to register with I2C\n");
+		return err;
+	}
+
+	/* Setup SMBus alert if supported */
+	if (adapter_parm[type].smbus_alert && irq) {
+		alert_data.irq = irq;
+		ara = i2c_setup_smbus_alert(&parport_adapter, &alert_data);
+		if (ara)
+			line_set(1, &parport_ctrl_irq);
+		else
+			dev_warn(&pdev->dev, "Failed to register ARA client\n");
+	}
+
+	return 0;
+}
+
+static int __devexit i2c_parport_remove(struct platform_device *pdev)
+{
+	if (ara) {
+		line_set(0, &parport_ctrl_irq);
+		i2c_unregister_device(ara);
+		ara = NULL;
+	}
+	i2c_del_adapter(&parport_adapter);
+
+	/* Un-init if needed (power off...) */
+	if (adapter_parm[type].init.val)
+		line_set(0, &adapter_parm[type].init);
+
+	return 0;
+}
+
+static struct platform_driver i2c_parport_driver = {
+	.driver = {
+		.owner	= THIS_MODULE,
+		.name	= DRVNAME,
+	},
+	.probe		= i2c_parport_probe,
+	.remove		= __devexit_p(i2c_parport_remove),
+};
+
+static int __init i2c_parport_device_add(u16 address)
+{
+	int err;
+
+	pdev = platform_device_alloc(DRVNAME, -1);
+	if (!pdev) {
+		err = -ENOMEM;
+		printk(KERN_ERR DRVNAME ": Device allocation failed\n");
+		goto exit;
+	}
+
+	err = platform_device_add(pdev);
+	if (err) {
+		printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
+		       err);
+		goto exit_device_put;
+	}
+
+	return 0;
+
+exit_device_put:
+	platform_device_put(pdev);
+exit:
+	return err;
+}
+
+static int __init i2c_parport_init(void)
+{
+	int err;
+
+	if (type < 0) {
+		printk(KERN_ERR DRVNAME ": adapter type unspecified\n");
+		return -ENODEV;
+	}
+
+	if (type >= ARRAY_SIZE(adapter_parm)) {
+		printk(KERN_ERR DRVNAME ": invalid type (%d)\n", type);
+		return -ENODEV;
+	}
+
+	if (base == 0) {
+		pr_info(DRVNAME ": using default base 0x%x\n", DEFAULT_BASE);
+		base = DEFAULT_BASE;
+	}
+
+	if (!request_region(base, 3, DRVNAME))
+		return -EBUSY;
+
+	if (irq != 0)
+		pr_info(DRVNAME ": using irq %d\n", irq);
+
+	if (!adapter_parm[type].getscl.val)
+		parport_algo_data.getscl = NULL;
+
+	/* Sets global pdev as a side effect */
+	err = i2c_parport_device_add(base);
+	if (err)
+		goto exit_release;
+
+	err = platform_driver_register(&i2c_parport_driver);
+	if (err)
+		goto exit_device;
+
+	return 0;
+
+exit_device:
+	platform_device_unregister(pdev);
+exit_release:
+	release_region(base, 3);
+	return err;
+}
+
+static void __exit i2c_parport_exit(void)
+{
+	platform_driver_unregister(&i2c_parport_driver);
+	platform_device_unregister(pdev);
+	release_region(base, 3);
+}
+
+MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
+MODULE_DESCRIPTION("I2C bus over parallel port (light)");
+MODULE_LICENSE("GPL");
+
+module_init(i2c_parport_init);
+module_exit(i2c_parport_exit);
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-parport.c b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-parport.c
new file mode 100644
index 0000000..2456568
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-parport.c
@@ -0,0 +1,306 @@
+/* ------------------------------------------------------------------------ *
+ * i2c-parport.c I2C bus over parallel port                                 *
+ * ------------------------------------------------------------------------ *
+   Copyright (C) 2003-2011 Jean Delvare <khali@linux-fr.org>
+
+   Based on older i2c-philips-par.c driver
+   Copyright (C) 1995-2000 Simon G. Vogl
+   With some changes from:
+   Frodo Looijaard <frodol@dds.nl>
+   Kyösti Mälkki <kmalkki@cc.hut.fi>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * ------------------------------------------------------------------------ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/parport.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <linux/i2c-smbus.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include "i2c-parport.h"
+
+/* ----- Device list ------------------------------------------------------ */
+
+struct i2c_par {
+	struct pardevice *pdev;
+	struct i2c_adapter adapter;
+	struct i2c_algo_bit_data algo_data;
+	struct i2c_smbus_alert_setup alert_data;
+	struct i2c_client *ara;
+	struct list_head node;
+};
+
+static LIST_HEAD(adapter_list);
+static DEFINE_MUTEX(adapter_list_lock);
+
+/* ----- Low-level parallel port access ----------------------------------- */
+
+static void port_write_data(struct parport *p, unsigned char d)
+{
+	parport_write_data(p, d);
+}
+
+static void port_write_control(struct parport *p, unsigned char d)
+{
+	parport_write_control(p, d);
+}
+
+static unsigned char port_read_data(struct parport *p)
+{
+	return parport_read_data(p);
+}
+
+static unsigned char port_read_status(struct parport *p)
+{
+	return parport_read_status(p);
+}
+
+static unsigned char port_read_control(struct parport *p)
+{
+	return parport_read_control(p);
+}
+
+static void (* const port_write[])(struct parport *, unsigned char) = {
+	port_write_data,
+	NULL,
+	port_write_control,
+};
+
+static unsigned char (* const port_read[])(struct parport *) = {
+	port_read_data,
+	port_read_status,
+	port_read_control,
+};
+
+/* ----- Unified line operation functions --------------------------------- */
+
+static inline void line_set(struct parport *data, int state,
+	const struct lineop *op)
+{
+	u8 oldval = port_read[op->port](data);
+
+	/* Touch only the bit(s) needed */
+	if ((op->inverted && !state) || (!op->inverted && state))
+		port_write[op->port](data, oldval | op->val);
+	else
+		port_write[op->port](data, oldval & ~op->val);
+}
+
+static inline int line_get(struct parport *data,
+	const struct lineop *op)
+{
+	u8 oldval = port_read[op->port](data);
+
+	return ((op->inverted && (oldval & op->val) != op->val)
+	    || (!op->inverted && (oldval & op->val) == op->val));
+}
+
+/* ----- I2C algorithm call-back functions and structures ----------------- */
+
+static void parport_setscl(void *data, int state)
+{
+	line_set((struct parport *) data, state, &adapter_parm[type].setscl);
+}
+
+static void parport_setsda(void *data, int state)
+{
+	line_set((struct parport *) data, state, &adapter_parm[type].setsda);
+}
+
+static int parport_getscl(void *data)
+{
+	return line_get((struct parport *) data, &adapter_parm[type].getscl);
+}
+
+static int parport_getsda(void *data)
+{
+	return line_get((struct parport *) data, &adapter_parm[type].getsda);
+}
+
+/* Encapsulate the functions above in the correct structure.
+   Note that this is only a template, from which the real structures are
+   copied. The attaching code will set getscl to NULL for adapters that
+   cannot read SCL back, and will also make the data field point to
+   the parallel port structure. */
+static const struct i2c_algo_bit_data parport_algo_data = {
+	.setsda		= parport_setsda,
+	.setscl		= parport_setscl,
+	.getsda		= parport_getsda,
+	.getscl		= parport_getscl,
+	.udelay		= 10, /* ~50 kbps */
+	.timeout	= HZ,
+};
+
+/* ----- I2c and parallel port call-back functions and structures --------- */
+
+void i2c_parport_irq(void *data)
+{
+	struct i2c_par *adapter = data;
+	struct i2c_client *ara = adapter->ara;
+
+	if (ara) {
+		dev_dbg(&ara->dev, "SMBus alert received\n");
+		i2c_handle_smbus_alert(ara);
+	} else
+		dev_dbg(&adapter->adapter.dev,
+			"SMBus alert received but no ARA client!\n");
+}
+
+static void i2c_parport_attach(struct parport *port)
+{
+	struct i2c_par *adapter;
+
+	adapter = kzalloc(sizeof(struct i2c_par), GFP_KERNEL);
+	if (adapter == NULL) {
+		printk(KERN_ERR "i2c-parport: Failed to kzalloc\n");
+		return;
+	}
+
+	pr_debug("i2c-parport: attaching to %s\n", port->name);
+	parport_disable_irq(port);
+	adapter->pdev = parport_register_device(port, "i2c-parport",
+		NULL, NULL, i2c_parport_irq, PARPORT_FLAG_EXCL, adapter);
+	if (!adapter->pdev) {
+		printk(KERN_ERR "i2c-parport: Unable to register with parport\n");
+		goto err_free;
+	}
+
+	/* Fill the rest of the structure */
+	adapter->adapter.owner = THIS_MODULE;
+	adapter->adapter.class = I2C_CLASS_HWMON;
+	strlcpy(adapter->adapter.name, "Parallel port adapter",
+		sizeof(adapter->adapter.name));
+	adapter->algo_data = parport_algo_data;
+	/* Slow down if we can't sense SCL */
+	if (!adapter_parm[type].getscl.val) {
+		adapter->algo_data.getscl = NULL;
+		adapter->algo_data.udelay = 50; /* ~10 kbps */
+	}
+	adapter->algo_data.data = port;
+	adapter->adapter.algo_data = &adapter->algo_data;
+	adapter->adapter.dev.parent = port->physport->dev;
+
+	if (parport_claim_or_block(adapter->pdev) < 0) {
+		printk(KERN_ERR "i2c-parport: Could not claim parallel port\n");
+		goto err_unregister;
+	}
+
+	/* Reset hardware to a sane state (SCL and SDA high) */
+	parport_setsda(port, 1);
+	parport_setscl(port, 1);
+	/* Other init if needed (power on...) */
+	if (adapter_parm[type].init.val) {
+		line_set(port, 1, &adapter_parm[type].init);
+		/* Give powered devices some time to settle */
+		msleep(100);
+	}
+
+	if (i2c_bit_add_bus(&adapter->adapter) < 0) {
+		printk(KERN_ERR "i2c-parport: Unable to register with I2C\n");
+		goto err_unregister;
+	}
+
+	/* Setup SMBus alert if supported */
+	if (adapter_parm[type].smbus_alert) {
+		adapter->alert_data.alert_edge_triggered = 1;
+		adapter->ara = i2c_setup_smbus_alert(&adapter->adapter,
+						     &adapter->alert_data);
+		if (adapter->ara)
+			parport_enable_irq(port);
+		else
+			printk(KERN_WARNING "i2c-parport: Failed to register "
+			       "ARA client\n");
+	}
+
+	/* Add the new adapter to the list */
+	mutex_lock(&adapter_list_lock);
+	list_add_tail(&adapter->node, &adapter_list);
+	mutex_unlock(&adapter_list_lock);
+	return;
+
+ err_unregister:
+	parport_release(adapter->pdev);
+	parport_unregister_device(adapter->pdev);
+ err_free:
+	kfree(adapter);
+}
+
+static void i2c_parport_detach(struct parport *port)
+{
+	struct i2c_par *adapter, *_n;
+
+	/* Walk the list */
+	mutex_lock(&adapter_list_lock);
+	list_for_each_entry_safe(adapter, _n, &adapter_list, node) {
+		if (adapter->pdev->port == port) {
+			if (adapter->ara) {
+				parport_disable_irq(port);
+				i2c_unregister_device(adapter->ara);
+			}
+			i2c_del_adapter(&adapter->adapter);
+
+			/* Un-init if needed (power off...) */
+			if (adapter_parm[type].init.val)
+				line_set(port, 0, &adapter_parm[type].init);
+
+			parport_release(adapter->pdev);
+			parport_unregister_device(adapter->pdev);
+			list_del(&adapter->node);
+			kfree(adapter);
+		}
+	}
+	mutex_unlock(&adapter_list_lock);
+}
+
+static struct parport_driver i2c_parport_driver = {
+	.name	= "i2c-parport",
+	.attach	= i2c_parport_attach,
+	.detach	= i2c_parport_detach,
+};
+
+/* ----- Module loading, unloading and information ------------------------ */
+
+static int __init i2c_parport_init(void)
+{
+	if (type < 0) {
+		printk(KERN_WARNING "i2c-parport: adapter type unspecified\n");
+		return -ENODEV;
+	}
+
+	if (type >= ARRAY_SIZE(adapter_parm)) {
+		printk(KERN_WARNING "i2c-parport: invalid type (%d)\n", type);
+		return -ENODEV;
+	}
+
+	return parport_register_driver(&i2c_parport_driver);
+}
+
+static void __exit i2c_parport_exit(void)
+{
+	parport_unregister_driver(&i2c_parport_driver);
+}
+
+MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
+MODULE_DESCRIPTION("I2C bus over parallel port");
+MODULE_LICENSE("GPL");
+
+module_init(i2c_parport_init);
+module_exit(i2c_parport_exit);
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-parport.h b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-parport.h
new file mode 100644
index 0000000..3fe6523
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-parport.h
@@ -0,0 +1,110 @@
+/* ------------------------------------------------------------------------ *
+ * i2c-parport.h I2C bus over parallel port                                 *
+ * ------------------------------------------------------------------------ *
+   Copyright (C) 2003-2010 Jean Delvare <khali@linux-fr.org>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * ------------------------------------------------------------------------ */
+
+#define PORT_DATA	0
+#define PORT_STAT	1
+#define PORT_CTRL	2
+
+struct lineop {
+	u8 val;
+	u8 port;
+	u8 inverted;
+};
+
+struct adapter_parm {
+	struct lineop setsda;
+	struct lineop setscl;
+	struct lineop getsda;
+	struct lineop getscl;
+	struct lineop init;
+	unsigned int smbus_alert:1;
+};
+
+static const struct adapter_parm adapter_parm[] = {
+	/* type 0: Philips adapter */
+	{
+		.setsda	= { 0x80, PORT_DATA, 1 },
+		.setscl	= { 0x08, PORT_CTRL, 0 },
+		.getsda	= { 0x80, PORT_STAT, 0 },
+		.getscl	= { 0x08, PORT_STAT, 0 },
+	},
+	/* type 1: home brew teletext adapter */
+	{
+		.setsda	= { 0x02, PORT_DATA, 0 },
+		.setscl	= { 0x01, PORT_DATA, 0 },
+		.getsda	= { 0x80, PORT_STAT, 1 },
+	},
+	/* type 2: Velleman K8000 adapter */
+	{
+		.setsda	= { 0x02, PORT_CTRL, 1 },
+		.setscl	= { 0x08, PORT_CTRL, 1 },
+		.getsda	= { 0x10, PORT_STAT, 0 },
+	},
+	/* type 3: ELV adapter */
+	{
+		.setsda	= { 0x02, PORT_DATA, 1 },
+		.setscl	= { 0x01, PORT_DATA, 1 },
+		.getsda	= { 0x40, PORT_STAT, 1 },
+		.getscl	= { 0x08, PORT_STAT, 1 },
+	},
+	/* type 4: ADM1032 evaluation board */
+	{
+		.setsda	= { 0x02, PORT_DATA, 1 },
+		.setscl	= { 0x01, PORT_DATA, 1 },
+		.getsda	= { 0x10, PORT_STAT, 1 },
+		.init	= { 0xf0, PORT_DATA, 0 },
+		.smbus_alert = 1,
+	},
+	/* type 5: ADM1025, ADM1030 and ADM1031 evaluation boards */
+	{
+		.setsda	= { 0x02, PORT_DATA, 1 },
+		.setscl	= { 0x01, PORT_DATA, 1 },
+		.getsda	= { 0x10, PORT_STAT, 1 },
+	},
+	/* type 6: Barco LPT->DVI (K5800236) adapter */
+	{
+		.setsda	= { 0x02, PORT_DATA, 1 },
+		.setscl	= { 0x01, PORT_DATA, 1 },
+		.getsda	= { 0x20, PORT_STAT, 0 },
+		.getscl	= { 0x40, PORT_STAT, 0 },
+		.init	= { 0xfc, PORT_DATA, 0 },
+	},
+	/* type 7: One For All JP1 parallel port adapter */
+	{
+		.setsda	= { 0x01, PORT_DATA, 0 },
+		.setscl	= { 0x02, PORT_DATA, 0 },
+		.getsda	= { 0x80, PORT_STAT, 1 },
+		.init	= { 0x04, PORT_DATA, 1 },
+	},
+};
+
+static int type = -1;
+module_param(type, int, 0);
+MODULE_PARM_DESC(type,
+	"Type of adapter:\n"
+	" 0 = Philips adapter\n"
+	" 1 = home brew teletext adapter\n"
+	" 2 = Velleman K8000 adapter\n"
+	" 3 = ELV adapter\n"
+	" 4 = ADM1032 evaluation board\n"
+	" 5 = ADM1025, ADM1030 and ADM1031 evaluation boards\n"
+	" 6 = Barco LPT->DVI (K5800236) adapter\n"
+	" 7 = One For All JP1 parallel port adapter\n"
+);
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-pasemi.c b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-pasemi.c
new file mode 100644
index 0000000..eaaea73
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-pasemi.c
@@ -0,0 +1,433 @@
+/*
+ * Copyright (C) 2006-2007 PA Semi, Inc
+ *
+ * SMBus host driver for PA Semi PWRficient
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/stddef.h>
+#include <linux/sched.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+
+static struct pci_driver pasemi_smb_driver;
+
+struct pasemi_smbus {
+	struct pci_dev		*dev;
+	struct i2c_adapter	 adapter;
+	unsigned long		 base;
+	int			 size;
+};
+
+/* Register offsets */
+#define REG_MTXFIFO	0x00
+#define REG_MRXFIFO	0x04
+#define REG_SMSTA	0x14
+#define REG_CTL		0x1c
+
+/* Register defs */
+#define MTXFIFO_READ	0x00000400
+#define MTXFIFO_STOP	0x00000200
+#define MTXFIFO_START	0x00000100
+#define MTXFIFO_DATA_M	0x000000ff
+
+#define MRXFIFO_EMPTY	0x00000100
+#define MRXFIFO_DATA_M	0x000000ff
+
+#define SMSTA_XEN	0x08000000
+#define SMSTA_MTN	0x00200000
+
+#define CTL_MRR		0x00000400
+#define CTL_MTR		0x00000200
+#define CTL_CLK_M	0x000000ff
+
+#define CLK_100K_DIV	84
+#define CLK_400K_DIV	21
+
+static inline void reg_write(struct pasemi_smbus *smbus, int reg, int val)
+{
+	dev_dbg(&smbus->dev->dev, "smbus write reg %lx val %08x\n",
+		smbus->base + reg, val);
+	outl(val, smbus->base + reg);
+}
+
+static inline int reg_read(struct pasemi_smbus *smbus, int reg)
+{
+	int ret;
+	ret = inl(smbus->base + reg);
+	dev_dbg(&smbus->dev->dev, "smbus read reg %lx val %08x\n",
+		smbus->base + reg, ret);
+	return ret;
+}
+
+#define TXFIFO_WR(smbus, reg)	reg_write((smbus), REG_MTXFIFO, (reg))
+#define RXFIFO_RD(smbus)	reg_read((smbus), REG_MRXFIFO)
+
+static void pasemi_smb_clear(struct pasemi_smbus *smbus)
+{
+	unsigned int status;
+
+	status = reg_read(smbus, REG_SMSTA);
+	reg_write(smbus, REG_SMSTA, status);
+}
+
+static int pasemi_smb_waitready(struct pasemi_smbus *smbus)
+{
+	int timeout = 10;
+	unsigned int status;
+
+	status = reg_read(smbus, REG_SMSTA);
+
+	while (!(status & SMSTA_XEN) && timeout--) {
+		msleep(1);
+		status = reg_read(smbus, REG_SMSTA);
+	}
+
+	/* Got NACK? */
+	if (status & SMSTA_MTN)
+		return -ENXIO;
+
+	if (timeout < 0) {
+		dev_warn(&smbus->dev->dev, "Timeout, status 0x%08x\n", status);
+		reg_write(smbus, REG_SMSTA, status);
+		return -ETIME;
+	}
+
+	/* Clear XEN */
+	reg_write(smbus, REG_SMSTA, SMSTA_XEN);
+
+	return 0;
+}
+
+static int pasemi_i2c_xfer_msg(struct i2c_adapter *adapter,
+			       struct i2c_msg *msg, int stop)
+{
+	struct pasemi_smbus *smbus = adapter->algo_data;
+	int read, i, err;
+	u32 rd;
+
+	read = msg->flags & I2C_M_RD ? 1 : 0;
+
+	TXFIFO_WR(smbus, MTXFIFO_START | (msg->addr << 1) | read);
+
+	if (read) {
+		TXFIFO_WR(smbus, msg->len | MTXFIFO_READ |
+				 (stop ? MTXFIFO_STOP : 0));
+
+		err = pasemi_smb_waitready(smbus);
+		if (err)
+			goto reset_out;
+
+		for (i = 0; i < msg->len; i++) {
+			rd = RXFIFO_RD(smbus);
+			if (rd & MRXFIFO_EMPTY) {
+				err = -ENODATA;
+				goto reset_out;
+			}
+			msg->buf[i] = rd & MRXFIFO_DATA_M;
+		}
+	} else {
+		for (i = 0; i < msg->len - 1; i++)
+			TXFIFO_WR(smbus, msg->buf[i]);
+
+		TXFIFO_WR(smbus, msg->buf[msg->len-1] |
+			  (stop ? MTXFIFO_STOP : 0));
+	}
+
+	return 0;
+
+ reset_out:
+	reg_write(smbus, REG_CTL, (CTL_MTR | CTL_MRR |
+		  (CLK_100K_DIV & CTL_CLK_M)));
+	return err;
+}
+
+static int pasemi_i2c_xfer(struct i2c_adapter *adapter,
+			   struct i2c_msg *msgs, int num)
+{
+	struct pasemi_smbus *smbus = adapter->algo_data;
+	int ret, i;
+
+	pasemi_smb_clear(smbus);
+
+	ret = 0;
+
+	for (i = 0; i < num && !ret; i++)
+		ret = pasemi_i2c_xfer_msg(adapter, &msgs[i], (i == (num - 1)));
+
+	return ret ? ret : num;
+}
+
+static int pasemi_smb_xfer(struct i2c_adapter *adapter,
+		u16 addr, unsigned short flags, char read_write, u8 command,
+		int size, union i2c_smbus_data *data)
+{
+	struct pasemi_smbus *smbus = adapter->algo_data;
+	unsigned int rd;
+	int read_flag, err;
+	int len = 0, i;
+
+	/* All our ops take 8-bit shifted addresses */
+	addr <<= 1;
+	read_flag = read_write == I2C_SMBUS_READ;
+
+	pasemi_smb_clear(smbus);
+
+	switch (size) {
+	case I2C_SMBUS_QUICK:
+		TXFIFO_WR(smbus, addr | read_flag | MTXFIFO_START |
+			  MTXFIFO_STOP);
+		break;
+	case I2C_SMBUS_BYTE:
+		TXFIFO_WR(smbus, addr | read_flag | MTXFIFO_START);
+		if (read_write)
+			TXFIFO_WR(smbus, 1 | MTXFIFO_STOP | MTXFIFO_READ);
+		else
+			TXFIFO_WR(smbus, MTXFIFO_STOP | command);
+		break;
+	case I2C_SMBUS_BYTE_DATA:
+		TXFIFO_WR(smbus, addr | MTXFIFO_START);
+		TXFIFO_WR(smbus, command);
+		if (read_write) {
+			TXFIFO_WR(smbus, addr | I2C_SMBUS_READ | MTXFIFO_START);
+			TXFIFO_WR(smbus, 1 | MTXFIFO_READ | MTXFIFO_STOP);
+		} else {
+			TXFIFO_WR(smbus, MTXFIFO_STOP | data->byte);
+		}
+		break;
+	case I2C_SMBUS_WORD_DATA:
+		TXFIFO_WR(smbus, addr | MTXFIFO_START);
+		TXFIFO_WR(smbus, command);
+		if (read_write) {
+			TXFIFO_WR(smbus, addr | I2C_SMBUS_READ | MTXFIFO_START);
+			TXFIFO_WR(smbus, 2 | MTXFIFO_READ | MTXFIFO_STOP);
+		} else {
+			TXFIFO_WR(smbus, data->word & MTXFIFO_DATA_M);
+			TXFIFO_WR(smbus, MTXFIFO_STOP | (data->word >> 8));
+		}
+		break;
+	case I2C_SMBUS_BLOCK_DATA:
+		TXFIFO_WR(smbus, addr | MTXFIFO_START);
+		TXFIFO_WR(smbus, command);
+		if (read_write) {
+			TXFIFO_WR(smbus, addr | I2C_SMBUS_READ | MTXFIFO_START);
+			TXFIFO_WR(smbus, 1 | MTXFIFO_READ);
+			rd = RXFIFO_RD(smbus);
+			len = min_t(u8, (rd & MRXFIFO_DATA_M),
+				    I2C_SMBUS_BLOCK_MAX);
+			TXFIFO_WR(smbus, len | MTXFIFO_READ |
+					 MTXFIFO_STOP);
+		} else {
+			len = min_t(u8, data->block[0], I2C_SMBUS_BLOCK_MAX);
+			TXFIFO_WR(smbus, len);
+			for (i = 1; i < len; i++)
+				TXFIFO_WR(smbus, data->block[i]);
+			TXFIFO_WR(smbus, data->block[len] | MTXFIFO_STOP);
+		}
+		break;
+	case I2C_SMBUS_PROC_CALL:
+		read_write = I2C_SMBUS_READ;
+		TXFIFO_WR(smbus, addr | MTXFIFO_START);
+		TXFIFO_WR(smbus, command);
+		TXFIFO_WR(smbus, data->word & MTXFIFO_DATA_M);
+		TXFIFO_WR(smbus, (data->word >> 8) & MTXFIFO_DATA_M);
+		TXFIFO_WR(smbus, addr | I2C_SMBUS_READ | MTXFIFO_START);
+		TXFIFO_WR(smbus, 2 | MTXFIFO_STOP | MTXFIFO_READ);
+		break;
+	case I2C_SMBUS_BLOCK_PROC_CALL:
+		len = min_t(u8, data->block[0], I2C_SMBUS_BLOCK_MAX - 1);
+		read_write = I2C_SMBUS_READ;
+		TXFIFO_WR(smbus, addr | MTXFIFO_START);
+		TXFIFO_WR(smbus, command);
+		TXFIFO_WR(smbus, len);
+		for (i = 1; i <= len; i++)
+			TXFIFO_WR(smbus, data->block[i]);
+		TXFIFO_WR(smbus, addr | I2C_SMBUS_READ);
+		TXFIFO_WR(smbus, MTXFIFO_READ | 1);
+		rd = RXFIFO_RD(smbus);
+		len = min_t(u8, (rd & MRXFIFO_DATA_M),
+			    I2C_SMBUS_BLOCK_MAX - len);
+		TXFIFO_WR(smbus, len | MTXFIFO_READ | MTXFIFO_STOP);
+		break;
+
+	default:
+		dev_warn(&adapter->dev, "Unsupported transaction %d\n", size);
+		return -EINVAL;
+	}
+
+	err = pasemi_smb_waitready(smbus);
+	if (err)
+		goto reset_out;
+
+	if (read_write == I2C_SMBUS_WRITE)
+		return 0;
+
+	switch (size) {
+	case I2C_SMBUS_BYTE:
+	case I2C_SMBUS_BYTE_DATA:
+		rd = RXFIFO_RD(smbus);
+		if (rd & MRXFIFO_EMPTY) {
+			err = -ENODATA;
+			goto reset_out;
+		}
+		data->byte = rd & MRXFIFO_DATA_M;
+		break;
+	case I2C_SMBUS_WORD_DATA:
+	case I2C_SMBUS_PROC_CALL:
+		rd = RXFIFO_RD(smbus);
+		if (rd & MRXFIFO_EMPTY) {
+			err = -ENODATA;
+			goto reset_out;
+		}
+		data->word = rd & MRXFIFO_DATA_M;
+		rd = RXFIFO_RD(smbus);
+		if (rd & MRXFIFO_EMPTY) {
+			err = -ENODATA;
+			goto reset_out;
+		}
+		data->word |= (rd & MRXFIFO_DATA_M) << 8;
+		break;
+	case I2C_SMBUS_BLOCK_DATA:
+	case I2C_SMBUS_BLOCK_PROC_CALL:
+		data->block[0] = len;
+		for (i = 1; i <= len; i ++) {
+			rd = RXFIFO_RD(smbus);
+			if (rd & MRXFIFO_EMPTY) {
+				err = -ENODATA;
+				goto reset_out;
+			}
+			data->block[i] = rd & MRXFIFO_DATA_M;
+		}
+		break;
+	}
+
+	return 0;
+
+ reset_out:
+	reg_write(smbus, REG_CTL, (CTL_MTR | CTL_MRR |
+		  (CLK_100K_DIV & CTL_CLK_M)));
+	return err;
+}
+
+static u32 pasemi_smb_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+	       I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+	       I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_PROC_CALL |
+	       I2C_FUNC_SMBUS_BLOCK_PROC_CALL | I2C_FUNC_I2C;
+}
+
+static const struct i2c_algorithm smbus_algorithm = {
+	.master_xfer	= pasemi_i2c_xfer,
+	.smbus_xfer	= pasemi_smb_xfer,
+	.functionality	= pasemi_smb_func,
+};
+
+static int __devinit pasemi_smb_probe(struct pci_dev *dev,
+				      const struct pci_device_id *id)
+{
+	struct pasemi_smbus *smbus;
+	int error;
+
+	if (!(pci_resource_flags(dev, 0) & IORESOURCE_IO))
+		return -ENODEV;
+
+	smbus = kzalloc(sizeof(struct pasemi_smbus), GFP_KERNEL);
+	if (!smbus)
+		return -ENOMEM;
+
+	smbus->dev = dev;
+	smbus->base = pci_resource_start(dev, 0);
+	smbus->size = pci_resource_len(dev, 0);
+
+	if (!request_region(smbus->base, smbus->size,
+			    pasemi_smb_driver.name)) {
+		error = -EBUSY;
+		goto out_kfree;
+	}
+
+	smbus->adapter.owner = THIS_MODULE;
+	snprintf(smbus->adapter.name, sizeof(smbus->adapter.name),
+		 "PA Semi SMBus adapter at 0x%lx", smbus->base);
+	smbus->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
+	smbus->adapter.algo = &smbus_algorithm;
+	smbus->adapter.algo_data = smbus;
+	smbus->adapter.nr = PCI_FUNC(dev->devfn);
+
+	/* set up the sysfs linkage to our parent device */
+	smbus->adapter.dev.parent = &dev->dev;
+
+	reg_write(smbus, REG_CTL, (CTL_MTR | CTL_MRR |
+		  (CLK_100K_DIV & CTL_CLK_M)));
+
+	error = i2c_add_numbered_adapter(&smbus->adapter);
+	if (error)
+		goto out_release_region;
+
+	pci_set_drvdata(dev, smbus);
+
+	return 0;
+
+ out_release_region:
+	release_region(smbus->base, smbus->size);
+ out_kfree:
+	kfree(smbus);
+	return error;
+}
+
+static void __devexit pasemi_smb_remove(struct pci_dev *dev)
+{
+	struct pasemi_smbus *smbus = pci_get_drvdata(dev);
+
+	i2c_del_adapter(&smbus->adapter);
+	release_region(smbus->base, smbus->size);
+	kfree(smbus);
+}
+
+static DEFINE_PCI_DEVICE_TABLE(pasemi_smb_ids) = {
+	{ PCI_DEVICE(0x1959, 0xa003) },
+	{ 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, pasemi_smb_ids);
+
+static struct pci_driver pasemi_smb_driver = {
+	.name		= "i2c-pasemi",
+	.id_table	= pasemi_smb_ids,
+	.probe		= pasemi_smb_probe,
+	.remove		= __devexit_p(pasemi_smb_remove),
+};
+
+static int __init pasemi_smb_init(void)
+{
+	return pci_register_driver(&pasemi_smb_driver);
+}
+
+static void __exit pasemi_smb_exit(void)
+{
+	pci_unregister_driver(&pasemi_smb_driver);
+}
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR ("Olof Johansson <olof@lixom.net>");
+MODULE_DESCRIPTION("PA Semi PWRficient SMBus driver");
+
+module_init(pasemi_smb_init);
+module_exit(pasemi_smb_exit);
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-pca-isa.c b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-pca-isa.c
new file mode 100644
index 0000000..29933f8
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-pca-isa.c
@@ -0,0 +1,229 @@
+/*
+ *  i2c-pca-isa.c driver for PCA9564 on ISA boards
+ *    Copyright (C) 2004 Arcom Control Systems
+ *    Copyright (C) 2008 Pengutronix
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/delay.h>
+#include <linux/jiffies.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/wait.h>
+#include <linux/isa.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-pca.h>
+#include <linux/io.h>
+
+#include <asm/irq.h>
+
+#define DRIVER "i2c-pca-isa"
+#define IO_SIZE 4
+
+static unsigned long base;
+static int irq = -1;
+
+/* Data sheet recommends 59kHz for 100kHz operation due to variation
+ * in the actual clock rate */
+static int clock  = 59000;
+
+static struct i2c_adapter pca_isa_ops;
+static wait_queue_head_t pca_wait;
+
+static void pca_isa_writebyte(void *pd, int reg, int val)
+{
+#ifdef DEBUG_IO
+	static char *names[] = { "T/O", "DAT", "ADR", "CON" };
+	printk(KERN_DEBUG "*** write %s at %#lx <= %#04x\n", names[reg],
+	       base+reg, val);
+#endif
+	outb(val, base+reg);
+}
+
+static int pca_isa_readbyte(void *pd, int reg)
+{
+	int res = inb(base+reg);
+#ifdef DEBUG_IO
+	{
+		static char *names[] = { "STA", "DAT", "ADR", "CON" };
+		printk(KERN_DEBUG "*** read  %s => %#04x\n", names[reg], res);
+	}
+#endif
+	return res;
+}
+
+static int pca_isa_waitforcompletion(void *pd)
+{
+	unsigned long timeout;
+	long ret;
+
+	if (irq > -1) {
+		ret = wait_event_timeout(pca_wait,
+				pca_isa_readbyte(pd, I2C_PCA_CON)
+				& I2C_PCA_CON_SI, pca_isa_ops.timeout);
+	} else {
+		/* Do polling */
+		timeout = jiffies + pca_isa_ops.timeout;
+		do {
+			ret = time_before(jiffies, timeout);
+			if (pca_isa_readbyte(pd, I2C_PCA_CON)
+					& I2C_PCA_CON_SI)
+				break;
+			udelay(100);
+		} while (ret);
+	}
+
+	return ret > 0;
+}
+
+static void pca_isa_resetchip(void *pd)
+{
+	/* apparently only an external reset will do it. not a lot can be done */
+	printk(KERN_WARNING DRIVER ": Haven't figured out how to do a reset yet\n");
+}
+
+static irqreturn_t pca_handler(int this_irq, void *dev_id) {
+	wake_up(&pca_wait);
+	return IRQ_HANDLED;
+}
+
+static struct i2c_algo_pca_data pca_isa_data = {
+	/* .data intentionally left NULL, not needed with ISA */
+	.write_byte		= pca_isa_writebyte,
+	.read_byte		= pca_isa_readbyte,
+	.wait_for_completion	= pca_isa_waitforcompletion,
+	.reset_chip		= pca_isa_resetchip,
+};
+
+static struct i2c_adapter pca_isa_ops = {
+	.owner          = THIS_MODULE,
+	.algo_data	= &pca_isa_data,
+	.name		= "PCA9564/PCA9665 ISA Adapter",
+	.timeout	= HZ,
+};
+
+static int __devinit pca_isa_match(struct device *dev, unsigned int id)
+{
+	int match = base != 0;
+
+	if (match) {
+		if (irq <= -1)
+			dev_warn(dev, "Using polling mode (specify irq)\n");
+	} else
+		dev_err(dev, "Please specify I/O base\n");
+
+	return match;
+}
+
+static int __devinit pca_isa_probe(struct device *dev, unsigned int id)
+{
+	init_waitqueue_head(&pca_wait);
+
+	dev_info(dev, "i/o base %#08lx. irq %d\n", base, irq);
+
+#ifdef CONFIG_PPC
+	if (check_legacy_ioport(base)) {
+		dev_err(dev, "I/O address %#08lx is not available\n", base);
+		goto out;
+	}
+#endif
+
+	if (!request_region(base, IO_SIZE, "i2c-pca-isa")) {
+		dev_err(dev, "I/O address %#08lx is in use\n", base);
+		goto out;
+	}
+
+	if (irq > -1) {
+		if (request_irq(irq, pca_handler, 0, "i2c-pca-isa", &pca_isa_ops) < 0) {
+			dev_err(dev, "Request irq%d failed\n", irq);
+			goto out_region;
+		}
+	}
+
+	pca_isa_data.i2c_clock = clock;
+	if (i2c_pca_add_bus(&pca_isa_ops) < 0) {
+		dev_err(dev, "Failed to add i2c bus\n");
+		goto out_irq;
+	}
+
+	return 0;
+
+ out_irq:
+	if (irq > -1)
+		free_irq(irq, &pca_isa_ops);
+ out_region:
+	release_region(base, IO_SIZE);
+ out:
+	return -ENODEV;
+}
+
+static int __devexit pca_isa_remove(struct device *dev, unsigned int id)
+{
+	i2c_del_adapter(&pca_isa_ops);
+
+	if (irq > -1) {
+		disable_irq(irq);
+		free_irq(irq, &pca_isa_ops);
+	}
+	release_region(base, IO_SIZE);
+
+	return 0;
+}
+
+static struct isa_driver pca_isa_driver = {
+	.match		= pca_isa_match,
+	.probe		= pca_isa_probe,
+	.remove		= __devexit_p(pca_isa_remove),
+	.driver = {
+		.owner	= THIS_MODULE,
+		.name	= DRIVER,
+	}
+};
+
+static int __init pca_isa_init(void)
+{
+	return isa_register_driver(&pca_isa_driver, 1);
+}
+
+static void __exit pca_isa_exit(void)
+{
+	isa_unregister_driver(&pca_isa_driver);
+}
+
+MODULE_AUTHOR("Ian Campbell <icampbell@arcom.com>");
+MODULE_DESCRIPTION("ISA base PCA9564/PCA9665 driver");
+MODULE_LICENSE("GPL");
+
+module_param(base, ulong, 0);
+MODULE_PARM_DESC(base, "I/O base address");
+
+module_param(irq, int, 0);
+MODULE_PARM_DESC(irq, "IRQ");
+module_param(clock, int, 0);
+MODULE_PARM_DESC(clock, "Clock rate in hertz.\n\t\t"
+		"For PCA9564: 330000,288000,217000,146000,"
+		"88000,59000,44000,36000\n"
+		"\t\tFor PCA9665:\tStandard: 60300 - 100099\n"
+		"\t\t\t\tFast: 100100 - 400099\n"
+		"\t\t\t\tFast+: 400100 - 10000099\n"
+		"\t\t\t\tTurbo: Up to 1265800");
+
+module_init(pca_isa_init);
+module_exit(pca_isa_exit);
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-pca-platform.c b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-pca-platform.c
new file mode 100644
index 0000000..2adbf1a
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-pca-platform.c
@@ -0,0 +1,293 @@
+/*
+ *  i2c_pca_platform.c
+ *
+ *  Platform driver for the PCA9564 I2C controller.
+ *
+ *  Copyright (C) 2008 Pengutronix
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/jiffies.h>
+#include <linux/errno.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/i2c-algo-pca.h>
+#include <linux/i2c-pca-platform.h>
+#include <linux/gpio.h>
+#include <linux/io.h>
+
+#include <asm/irq.h>
+
+struct i2c_pca_pf_data {
+	void __iomem			*reg_base;
+	int				irq;	/* if 0, use polling */
+	int				gpio;
+	wait_queue_head_t		wait;
+	struct i2c_adapter		adap;
+	struct i2c_algo_pca_data	algo_data;
+	unsigned long			io_base;
+	unsigned long			io_size;
+};
+
+/* Read/Write functions for different register alignments */
+
+static int i2c_pca_pf_readbyte8(void *pd, int reg)
+{
+	struct i2c_pca_pf_data *i2c = pd;
+	return ioread8(i2c->reg_base + reg);
+}
+
+static int i2c_pca_pf_readbyte16(void *pd, int reg)
+{
+	struct i2c_pca_pf_data *i2c = pd;
+	return ioread8(i2c->reg_base + reg * 2);
+}
+
+static int i2c_pca_pf_readbyte32(void *pd, int reg)
+{
+	struct i2c_pca_pf_data *i2c = pd;
+	return ioread8(i2c->reg_base + reg * 4);
+}
+
+static void i2c_pca_pf_writebyte8(void *pd, int reg, int val)
+{
+	struct i2c_pca_pf_data *i2c = pd;
+	iowrite8(val, i2c->reg_base + reg);
+}
+
+static void i2c_pca_pf_writebyte16(void *pd, int reg, int val)
+{
+	struct i2c_pca_pf_data *i2c = pd;
+	iowrite8(val, i2c->reg_base + reg * 2);
+}
+
+static void i2c_pca_pf_writebyte32(void *pd, int reg, int val)
+{
+	struct i2c_pca_pf_data *i2c = pd;
+	iowrite8(val, i2c->reg_base + reg * 4);
+}
+
+
+static int i2c_pca_pf_waitforcompletion(void *pd)
+{
+	struct i2c_pca_pf_data *i2c = pd;
+	unsigned long timeout;
+	long ret;
+
+	if (i2c->irq) {
+		ret = wait_event_timeout(i2c->wait,
+			i2c->algo_data.read_byte(i2c, I2C_PCA_CON)
+			& I2C_PCA_CON_SI, i2c->adap.timeout);
+	} else {
+		/* Do polling */
+		timeout = jiffies + i2c->adap.timeout;
+		do {
+			ret = time_before(jiffies, timeout);
+			if (i2c->algo_data.read_byte(i2c, I2C_PCA_CON)
+					& I2C_PCA_CON_SI)
+				break;
+			udelay(100);
+		} while (ret);
+	}
+
+	return ret > 0;
+}
+
+static void i2c_pca_pf_dummyreset(void *pd)
+{
+	struct i2c_pca_pf_data *i2c = pd;
+	printk(KERN_WARNING "%s: No reset-pin found. Chip may get stuck!\n",
+		i2c->adap.name);
+}
+
+static void i2c_pca_pf_resetchip(void *pd)
+{
+	struct i2c_pca_pf_data *i2c = pd;
+
+	gpio_set_value(i2c->gpio, 0);
+	ndelay(100);
+	gpio_set_value(i2c->gpio, 1);
+}
+
+static irqreturn_t i2c_pca_pf_handler(int this_irq, void *dev_id)
+{
+	struct i2c_pca_pf_data *i2c = dev_id;
+
+	if ((i2c->algo_data.read_byte(i2c, I2C_PCA_CON) & I2C_PCA_CON_SI) == 0)
+		return IRQ_NONE;
+
+	wake_up(&i2c->wait);
+
+	return IRQ_HANDLED;
+}
+
+
+static int __devinit i2c_pca_pf_probe(struct platform_device *pdev)
+{
+	struct i2c_pca_pf_data *i2c;
+	struct resource *res;
+	struct i2c_pca9564_pf_platform_data *platform_data =
+				pdev->dev.platform_data;
+	int ret = 0;
+	int irq;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	irq = platform_get_irq(pdev, 0);
+	/* If irq is 0, we do polling. */
+
+	if (res == NULL) {
+		ret = -ENODEV;
+		goto e_print;
+	}
+
+	if (!request_mem_region(res->start, resource_size(res), res->name)) {
+		ret = -ENOMEM;
+		goto e_print;
+	}
+
+	i2c = kzalloc(sizeof(struct i2c_pca_pf_data), GFP_KERNEL);
+	if (!i2c) {
+		ret = -ENOMEM;
+		goto e_alloc;
+	}
+
+	init_waitqueue_head(&i2c->wait);
+
+	i2c->reg_base = ioremap(res->start, resource_size(res));
+	if (!i2c->reg_base) {
+		ret = -ENOMEM;
+		goto e_remap;
+	}
+	i2c->io_base = res->start;
+	i2c->io_size = resource_size(res);
+	i2c->irq = irq;
+
+	i2c->adap.nr = pdev->id >= 0 ? pdev->id : 0;
+	i2c->adap.owner = THIS_MODULE;
+	snprintf(i2c->adap.name, sizeof(i2c->adap.name),
+		 "PCA9564/PCA9665 at 0x%08lx",
+		 (unsigned long) res->start);
+	i2c->adap.algo_data = &i2c->algo_data;
+	i2c->adap.dev.parent = &pdev->dev;
+
+	if (platform_data) {
+		i2c->adap.timeout = platform_data->timeout;
+		i2c->algo_data.i2c_clock = platform_data->i2c_clock_speed;
+		i2c->gpio = platform_data->gpio;
+	} else {
+		i2c->adap.timeout = HZ;
+		i2c->algo_data.i2c_clock = 59000;
+		i2c->gpio = -1;
+	}
+
+	i2c->algo_data.data = i2c;
+	i2c->algo_data.wait_for_completion = i2c_pca_pf_waitforcompletion;
+	i2c->algo_data.reset_chip = i2c_pca_pf_dummyreset;
+
+	switch (res->flags & IORESOURCE_MEM_TYPE_MASK) {
+	case IORESOURCE_MEM_32BIT:
+		i2c->algo_data.write_byte = i2c_pca_pf_writebyte32;
+		i2c->algo_data.read_byte = i2c_pca_pf_readbyte32;
+		break;
+	case IORESOURCE_MEM_16BIT:
+		i2c->algo_data.write_byte = i2c_pca_pf_writebyte16;
+		i2c->algo_data.read_byte = i2c_pca_pf_readbyte16;
+		break;
+	case IORESOURCE_MEM_8BIT:
+	default:
+		i2c->algo_data.write_byte = i2c_pca_pf_writebyte8;
+		i2c->algo_data.read_byte = i2c_pca_pf_readbyte8;
+		break;
+	}
+
+	/* Use gpio_is_valid() when in mainline */
+	if (i2c->gpio > -1) {
+		ret = gpio_request(i2c->gpio, i2c->adap.name);
+		if (ret == 0) {
+			gpio_direction_output(i2c->gpio, 1);
+			i2c->algo_data.reset_chip = i2c_pca_pf_resetchip;
+		} else {
+			printk(KERN_WARNING "%s: Registering gpio failed!\n",
+				i2c->adap.name);
+			i2c->gpio = ret;
+		}
+	}
+
+	if (irq) {
+		ret = request_irq(irq, i2c_pca_pf_handler,
+			IRQF_TRIGGER_FALLING, pdev->name, i2c);
+		if (ret)
+			goto e_reqirq;
+	}
+
+	if (i2c_pca_add_numbered_bus(&i2c->adap) < 0) {
+		ret = -ENODEV;
+		goto e_adapt;
+	}
+
+	platform_set_drvdata(pdev, i2c);
+
+	printk(KERN_INFO "%s registered.\n", i2c->adap.name);
+
+	return 0;
+
+e_adapt:
+	if (irq)
+		free_irq(irq, i2c);
+e_reqirq:
+	if (i2c->gpio > -1)
+		gpio_free(i2c->gpio);
+
+	iounmap(i2c->reg_base);
+e_remap:
+	kfree(i2c);
+e_alloc:
+	release_mem_region(res->start, resource_size(res));
+e_print:
+	printk(KERN_ERR "Registering PCA9564/PCA9665 FAILED! (%d)\n", ret);
+	return ret;
+}
+
+static int __devexit i2c_pca_pf_remove(struct platform_device *pdev)
+{
+	struct i2c_pca_pf_data *i2c = platform_get_drvdata(pdev);
+	platform_set_drvdata(pdev, NULL);
+
+	i2c_del_adapter(&i2c->adap);
+
+	if (i2c->irq)
+		free_irq(i2c->irq, i2c);
+
+	if (i2c->gpio > -1)
+		gpio_free(i2c->gpio);
+
+	iounmap(i2c->reg_base);
+	release_mem_region(i2c->io_base, i2c->io_size);
+	kfree(i2c);
+
+	return 0;
+}
+
+static struct platform_driver i2c_pca_pf_driver = {
+	.probe = i2c_pca_pf_probe,
+	.remove = __devexit_p(i2c_pca_pf_remove),
+	.driver = {
+		.name = "i2c-pca-platform",
+		.owner = THIS_MODULE,
+	},
+};
+
+module_platform_driver(i2c_pca_pf_driver);
+
+MODULE_AUTHOR("Wolfram Sang <w.sang@pengutronix.de>");
+MODULE_DESCRIPTION("I2C-PCA9564/PCA9665 platform driver");
+MODULE_LICENSE("GPL");
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-piix4.c b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-piix4.c
new file mode 100644
index 0000000..a356974
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-piix4.c
@@ -0,0 +1,564 @@
+/*
+    Copyright (c) 1998 - 2002 Frodo Looijaard <frodol@dds.nl> and
+    Philip Edelbrock <phil@netroedge.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/*
+   Supports:
+	Intel PIIX4, 440MX
+	Serverworks OSB4, CSB5, CSB6, HT-1000, HT-1100
+	ATI IXP200, IXP300, IXP400, SB600, SB700, SB800
+	AMD Hudson-2, CZ
+	SMSC Victory66
+
+   Note: we assume there can only be one device, with one SMBus interface.
+*/
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/stddef.h>
+#include <linux/ioport.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/dmi.h>
+#include <linux/acpi.h>
+#include <linux/io.h>
+
+
+/* PIIX4 SMBus address offsets */
+#define SMBHSTSTS	(0 + piix4_smba)
+#define SMBHSLVSTS	(1 + piix4_smba)
+#define SMBHSTCNT	(2 + piix4_smba)
+#define SMBHSTCMD	(3 + piix4_smba)
+#define SMBHSTADD	(4 + piix4_smba)
+#define SMBHSTDAT0	(5 + piix4_smba)
+#define SMBHSTDAT1	(6 + piix4_smba)
+#define SMBBLKDAT	(7 + piix4_smba)
+#define SMBSLVCNT	(8 + piix4_smba)
+#define SMBSHDWCMD	(9 + piix4_smba)
+#define SMBSLVEVT	(0xA + piix4_smba)
+#define SMBSLVDAT	(0xC + piix4_smba)
+
+/* count for request_region */
+#define SMBIOSIZE	8
+
+/* PCI Address Constants */
+#define SMBBA		0x090
+#define SMBHSTCFG	0x0D2
+#define SMBSLVC		0x0D3
+#define SMBSHDW1	0x0D4
+#define SMBSHDW2	0x0D5
+#define SMBREV		0x0D6
+
+/* Other settings */
+#define MAX_TIMEOUT	500
+#define  ENABLE_INT9	0
+
+/* PIIX4 constants */
+#define PIIX4_QUICK		0x00
+#define PIIX4_BYTE		0x04
+#define PIIX4_BYTE_DATA		0x08
+#define PIIX4_WORD_DATA		0x0C
+#define PIIX4_BLOCK_DATA	0x14
+
+/* insmod parameters */
+
+/* If force is set to anything different from 0, we forcibly enable the
+   PIIX4. DANGEROUS! */
+static int force;
+module_param (force, int, 0);
+MODULE_PARM_DESC(force, "Forcibly enable the PIIX4. DANGEROUS!");
+
+/* If force_addr is set to anything different from 0, we forcibly enable
+   the PIIX4 at the given address. VERY DANGEROUS! */
+static int force_addr;
+module_param (force_addr, int, 0);
+MODULE_PARM_DESC(force_addr,
+		 "Forcibly enable the PIIX4 at the given address. "
+		 "EXTREMELY DANGEROUS!");
+
+static unsigned short piix4_smba;
+static int srvrworks_csb5_delay;
+static struct pci_driver piix4_driver;
+static struct i2c_adapter piix4_adapter;
+
+static struct dmi_system_id __devinitdata piix4_dmi_blacklist[] = {
+	{
+		.ident = "Sapphire AM2RD790",
+		.matches = {
+			DMI_MATCH(DMI_BOARD_VENDOR, "SAPPHIRE Inc."),
+			DMI_MATCH(DMI_BOARD_NAME, "PC-AM2RD790"),
+		},
+	},
+	{
+		.ident = "DFI Lanparty UT 790FX",
+		.matches = {
+			DMI_MATCH(DMI_BOARD_VENDOR, "DFI Inc."),
+			DMI_MATCH(DMI_BOARD_NAME, "LP UT 790FX"),
+		},
+	},
+	{ }
+};
+
+/* The IBM entry is in a separate table because we only check it
+   on Intel-based systems */
+static struct dmi_system_id __devinitdata piix4_dmi_ibm[] = {
+	{
+		.ident = "IBM",
+		.matches = { DMI_MATCH(DMI_SYS_VENDOR, "IBM"), },
+	},
+	{ },
+};
+
+static int __devinit piix4_setup(struct pci_dev *PIIX4_dev,
+				const struct pci_device_id *id)
+{
+	unsigned char temp;
+
+	if ((PIIX4_dev->vendor == PCI_VENDOR_ID_SERVERWORKS) &&
+	    (PIIX4_dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5))
+		srvrworks_csb5_delay = 1;
+
+	/* On some motherboards, it was reported that accessing the SMBus
+	   caused severe hardware problems */
+	if (dmi_check_system(piix4_dmi_blacklist)) {
+		dev_err(&PIIX4_dev->dev,
+			"Accessing the SMBus on this system is unsafe!\n");
+		return -EPERM;
+	}
+
+	/* Don't access SMBus on IBM systems which get corrupted eeproms */
+	if (dmi_check_system(piix4_dmi_ibm) &&
+			PIIX4_dev->vendor == PCI_VENDOR_ID_INTEL) {
+		dev_err(&PIIX4_dev->dev, "IBM system detected; this module "
+			"may corrupt your serial eeprom! Refusing to load "
+			"module!\n");
+		return -EPERM;
+	}
+
+	/* Determine the address of the SMBus areas */
+	if (force_addr) {
+		piix4_smba = force_addr & 0xfff0;
+		force = 0;
+	} else {
+		pci_read_config_word(PIIX4_dev, SMBBA, &piix4_smba);
+		piix4_smba &= 0xfff0;
+		if(piix4_smba == 0) {
+			dev_err(&PIIX4_dev->dev, "SMBus base address "
+				"uninitialized - upgrade BIOS or use "
+				"force_addr=0xaddr\n");
+			return -ENODEV;
+		}
+	}
+
+	if (acpi_check_region(piix4_smba, SMBIOSIZE, piix4_driver.name))
+		return -ENODEV;
+
+	if (!request_region(piix4_smba, SMBIOSIZE, piix4_driver.name)) {
+		dev_err(&PIIX4_dev->dev, "SMBus region 0x%x already in use!\n",
+			piix4_smba);
+		return -EBUSY;
+	}
+
+	pci_read_config_byte(PIIX4_dev, SMBHSTCFG, &temp);
+
+	/* If force_addr is set, we program the new address here. Just to make
+	   sure, we disable the PIIX4 first. */
+	if (force_addr) {
+		pci_write_config_byte(PIIX4_dev, SMBHSTCFG, temp & 0xfe);
+		pci_write_config_word(PIIX4_dev, SMBBA, piix4_smba);
+		pci_write_config_byte(PIIX4_dev, SMBHSTCFG, temp | 0x01);
+		dev_info(&PIIX4_dev->dev, "WARNING: SMBus interface set to "
+			"new address %04x!\n", piix4_smba);
+	} else if ((temp & 1) == 0) {
+		if (force) {
+			/* This should never need to be done, but has been
+			 * noted that many Dell machines have the SMBus
+			 * interface on the PIIX4 disabled!? NOTE: This assumes
+			 * I/O space and other allocations WERE done by the
+			 * Bios!  Don't complain if your hardware does weird
+			 * things after enabling this. :') Check for Bios
+			 * updates before resorting to this.
+			 */
+			pci_write_config_byte(PIIX4_dev, SMBHSTCFG,
+					      temp | 1);
+			dev_printk(KERN_NOTICE, &PIIX4_dev->dev,
+				"WARNING: SMBus interface has been "
+				"FORCEFULLY ENABLED!\n");
+		} else {
+			dev_err(&PIIX4_dev->dev,
+				"Host SMBus controller not enabled!\n");
+			release_region(piix4_smba, SMBIOSIZE);
+			piix4_smba = 0;
+			return -ENODEV;
+		}
+	}
+
+	if (((temp & 0x0E) == 8) || ((temp & 0x0E) == 2))
+		dev_dbg(&PIIX4_dev->dev, "Using Interrupt 9 for SMBus.\n");
+	else if ((temp & 0x0E) == 0)
+		dev_dbg(&PIIX4_dev->dev, "Using Interrupt SMI# for SMBus.\n");
+	else
+		dev_err(&PIIX4_dev->dev, "Illegal Interrupt configuration "
+			"(or code out of date)!\n");
+
+	pci_read_config_byte(PIIX4_dev, SMBREV, &temp);
+	dev_info(&PIIX4_dev->dev,
+		 "SMBus Host Controller at 0x%x, revision %d\n",
+		 piix4_smba, temp);
+
+	return 0;
+}
+
+static int __devinit piix4_setup_sb800(struct pci_dev *PIIX4_dev,
+				const struct pci_device_id *id)
+{
+	unsigned short smba_idx = 0xcd6;
+	u8 smba_en_lo, smba_en_hi, i2ccfg, i2ccfg_offset = 0x10, smb_en = 0x2c;
+
+	/* SB800 and later SMBus does not support forcing address */
+	if (force || force_addr) {
+		dev_err(&PIIX4_dev->dev, "SMBus does not support "
+			"forcing address!\n");
+		return -EINVAL;
+	}
+
+	/* Determine the address of the SMBus areas */
+	if (!request_region(smba_idx, 2, "smba_idx")) {
+		dev_err(&PIIX4_dev->dev, "SMBus base address index region "
+			"0x%x already in use!\n", smba_idx);
+		return -EBUSY;
+	}
+	outb_p(smb_en, smba_idx);
+	smba_en_lo = inb_p(smba_idx + 1);
+	outb_p(smb_en + 1, smba_idx);
+	smba_en_hi = inb_p(smba_idx + 1);
+	release_region(smba_idx, 2);
+
+	if ((smba_en_lo & 1) == 0) {
+		dev_err(&PIIX4_dev->dev,
+			"Host SMBus controller not enabled!\n");
+		return -ENODEV;
+	}
+
+	piix4_smba = ((smba_en_hi << 8) | smba_en_lo) & 0xffe0;
+	if (acpi_check_region(piix4_smba, SMBIOSIZE, piix4_driver.name))
+		return -ENODEV;
+
+	if (!request_region(piix4_smba, SMBIOSIZE, piix4_driver.name)) {
+		dev_err(&PIIX4_dev->dev, "SMBus region 0x%x already in use!\n",
+			piix4_smba);
+		return -EBUSY;
+	}
+
+	/* Request the SMBus I2C bus config region */
+	if (!request_region(piix4_smba + i2ccfg_offset, 1, "i2ccfg")) {
+		dev_err(&PIIX4_dev->dev, "SMBus I2C bus config region "
+			"0x%x already in use!\n", piix4_smba + i2ccfg_offset);
+		release_region(piix4_smba, SMBIOSIZE);
+		piix4_smba = 0;
+		return -EBUSY;
+	}
+	i2ccfg = inb_p(piix4_smba + i2ccfg_offset);
+	release_region(piix4_smba + i2ccfg_offset, 1);
+
+	if (i2ccfg & 1)
+		dev_dbg(&PIIX4_dev->dev, "Using IRQ for SMBus.\n");
+	else
+		dev_dbg(&PIIX4_dev->dev, "Using SMI# for SMBus.\n");
+
+	dev_info(&PIIX4_dev->dev,
+		 "SMBus Host Controller at 0x%x, revision %d\n",
+		 piix4_smba, i2ccfg >> 4);
+
+	return 0;
+}
+
+static int piix4_transaction(void)
+{
+	int temp;
+	int result = 0;
+	int timeout = 0;
+
+	dev_dbg(&piix4_adapter.dev, "Transaction (pre): CNT=%02x, CMD=%02x, "
+		"ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT),
+		inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0),
+		inb_p(SMBHSTDAT1));
+
+	/* Make sure the SMBus host is ready to start transmitting */
+	if ((temp = inb_p(SMBHSTSTS)) != 0x00) {
+		dev_dbg(&piix4_adapter.dev, "SMBus busy (%02x). "
+			"Resetting...\n", temp);
+		outb_p(temp, SMBHSTSTS);
+		if ((temp = inb_p(SMBHSTSTS)) != 0x00) {
+			dev_err(&piix4_adapter.dev, "Failed! (%02x)\n", temp);
+			return -EBUSY;
+		} else {
+			dev_dbg(&piix4_adapter.dev, "Successful!\n");
+		}
+	}
+
+	/* start the transaction by setting bit 6 */
+	outb_p(inb(SMBHSTCNT) | 0x040, SMBHSTCNT);
+
+	/* We will always wait for a fraction of a second! (See PIIX4 docs errata) */
+	if (srvrworks_csb5_delay) /* Extra delay for SERVERWORKS_CSB5 */
+		msleep(2);
+	else
+		msleep(1);
+
+	while ((++timeout < MAX_TIMEOUT) &&
+	       ((temp = inb_p(SMBHSTSTS)) & 0x01))
+		msleep(1);
+
+	/* If the SMBus is still busy, we give up */
+	if (timeout == MAX_TIMEOUT) {
+		dev_err(&piix4_adapter.dev, "SMBus Timeout!\n");
+		result = -ETIMEDOUT;
+	}
+
+	if (temp & 0x10) {
+		result = -EIO;
+		dev_err(&piix4_adapter.dev, "Error: Failed bus transaction\n");
+	}
+
+	if (temp & 0x08) {
+		result = -EIO;
+		dev_dbg(&piix4_adapter.dev, "Bus collision! SMBus may be "
+			"locked until next hard reset. (sorry!)\n");
+		/* Clock stops and slave is stuck in mid-transmission */
+	}
+
+	if (temp & 0x04) {
+		result = -ENXIO;
+		dev_dbg(&piix4_adapter.dev, "Error: no response!\n");
+	}
+
+	if (inb_p(SMBHSTSTS) != 0x00)
+		outb_p(inb(SMBHSTSTS), SMBHSTSTS);
+
+	if ((temp = inb_p(SMBHSTSTS)) != 0x00) {
+		dev_err(&piix4_adapter.dev, "Failed reset at end of "
+			"transaction (%02x)\n", temp);
+	}
+	dev_dbg(&piix4_adapter.dev, "Transaction (post): CNT=%02x, CMD=%02x, "
+		"ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT),
+		inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0),
+		inb_p(SMBHSTDAT1));
+	return result;
+}
+
+/* Return negative errno on error. */
+static s32 piix4_access(struct i2c_adapter * adap, u16 addr,
+		 unsigned short flags, char read_write,
+		 u8 command, int size, union i2c_smbus_data * data)
+{
+	int i, len;
+	int status;
+
+	switch (size) {
+	case I2C_SMBUS_QUICK:
+		outb_p((addr << 1) | read_write,
+		       SMBHSTADD);
+		size = PIIX4_QUICK;
+		break;
+	case I2C_SMBUS_BYTE:
+		outb_p((addr << 1) | read_write,
+		       SMBHSTADD);
+		if (read_write == I2C_SMBUS_WRITE)
+			outb_p(command, SMBHSTCMD);
+		size = PIIX4_BYTE;
+		break;
+	case I2C_SMBUS_BYTE_DATA:
+		outb_p((addr << 1) | read_write,
+		       SMBHSTADD);
+		outb_p(command, SMBHSTCMD);
+		if (read_write == I2C_SMBUS_WRITE)
+			outb_p(data->byte, SMBHSTDAT0);
+		size = PIIX4_BYTE_DATA;
+		break;
+	case I2C_SMBUS_WORD_DATA:
+		outb_p((addr << 1) | read_write,
+		       SMBHSTADD);
+		outb_p(command, SMBHSTCMD);
+		if (read_write == I2C_SMBUS_WRITE) {
+			outb_p(data->word & 0xff, SMBHSTDAT0);
+			outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1);
+		}
+		size = PIIX4_WORD_DATA;
+		break;
+	case I2C_SMBUS_BLOCK_DATA:
+		outb_p((addr << 1) | read_write,
+		       SMBHSTADD);
+		outb_p(command, SMBHSTCMD);
+		if (read_write == I2C_SMBUS_WRITE) {
+			len = data->block[0];
+			if (len == 0 || len > I2C_SMBUS_BLOCK_MAX)
+				return -EINVAL;
+			outb_p(len, SMBHSTDAT0);
+			i = inb_p(SMBHSTCNT);	/* Reset SMBBLKDAT */
+			for (i = 1; i <= len; i++)
+				outb_p(data->block[i], SMBBLKDAT);
+		}
+		size = PIIX4_BLOCK_DATA;
+		break;
+	default:
+		dev_warn(&adap->dev, "Unsupported transaction %d\n", size);
+		return -EOPNOTSUPP;
+	}
+
+	outb_p((size & 0x1C) + (ENABLE_INT9 & 1), SMBHSTCNT);
+
+	status = piix4_transaction();
+	if (status)
+		return status;
+
+	if ((read_write == I2C_SMBUS_WRITE) || (size == PIIX4_QUICK))
+		return 0;
+
+
+	switch (size) {
+	case PIIX4_BYTE:
+	case PIIX4_BYTE_DATA:
+		data->byte = inb_p(SMBHSTDAT0);
+		break;
+	case PIIX4_WORD_DATA:
+		data->word = inb_p(SMBHSTDAT0) + (inb_p(SMBHSTDAT1) << 8);
+		break;
+	case PIIX4_BLOCK_DATA:
+		data->block[0] = inb_p(SMBHSTDAT0);
+		if (data->block[0] == 0 || data->block[0] > I2C_SMBUS_BLOCK_MAX)
+			return -EPROTO;
+		i = inb_p(SMBHSTCNT);	/* Reset SMBBLKDAT */
+		for (i = 1; i <= data->block[0]; i++)
+			data->block[i] = inb_p(SMBBLKDAT);
+		break;
+	}
+	return 0;
+}
+
+static u32 piix4_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+	    I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+	    I2C_FUNC_SMBUS_BLOCK_DATA;
+}
+
+static const struct i2c_algorithm smbus_algorithm = {
+	.smbus_xfer	= piix4_access,
+	.functionality	= piix4_func,
+};
+
+static struct i2c_adapter piix4_adapter = {
+	.owner		= THIS_MODULE,
+	.class		= I2C_CLASS_HWMON | I2C_CLASS_SPD,
+	.algo		= &smbus_algorithm,
+};
+
+static DEFINE_PCI_DEVICE_TABLE(piix4_ids) = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_3) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_EFAR, PCI_DEVICE_ID_EFAR_SLC90E66_3) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP200_SMBUS) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP300_SMBUS) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP400_SMBUS) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_SBX00_SMBUS) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_HUDSON2_SMBUS) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x790b) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS,
+		     PCI_DEVICE_ID_SERVERWORKS_OSB4) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS,
+		     PCI_DEVICE_ID_SERVERWORKS_CSB5) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS,
+		     PCI_DEVICE_ID_SERVERWORKS_CSB6) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS,
+		     PCI_DEVICE_ID_SERVERWORKS_HT1000SB) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS,
+		     PCI_DEVICE_ID_SERVERWORKS_HT1100LD) },
+	{ 0, }
+};
+
+MODULE_DEVICE_TABLE (pci, piix4_ids);
+
+static int __devinit piix4_probe(struct pci_dev *dev,
+				const struct pci_device_id *id)
+{
+	int retval;
+
+	if ((dev->vendor == PCI_VENDOR_ID_ATI &&
+	     dev->device == PCI_DEVICE_ID_ATI_SBX00_SMBUS &&
+	     dev->revision >= 0x40) ||
+	    dev->vendor == PCI_VENDOR_ID_AMD)
+		/* base address location etc changed in SB800 */
+		retval = piix4_setup_sb800(dev, id);
+	else
+		retval = piix4_setup(dev, id);
+
+	if (retval)
+		return retval;
+
+	/* set up the sysfs linkage to our parent device */
+	piix4_adapter.dev.parent = &dev->dev;
+
+	snprintf(piix4_adapter.name, sizeof(piix4_adapter.name),
+		"SMBus PIIX4 adapter at %04x", piix4_smba);
+
+	if ((retval = i2c_add_adapter(&piix4_adapter))) {
+		dev_err(&dev->dev, "Couldn't register adapter!\n");
+		release_region(piix4_smba, SMBIOSIZE);
+		piix4_smba = 0;
+	}
+
+	return retval;
+}
+
+static void __devexit piix4_remove(struct pci_dev *dev)
+{
+	if (piix4_smba) {
+		i2c_del_adapter(&piix4_adapter);
+		release_region(piix4_smba, SMBIOSIZE);
+		piix4_smba = 0;
+	}
+}
+
+static struct pci_driver piix4_driver = {
+	.name		= "piix4_smbus",
+	.id_table	= piix4_ids,
+	.probe		= piix4_probe,
+	.remove		= __devexit_p(piix4_remove),
+};
+
+static int __init i2c_piix4_init(void)
+{
+	return pci_register_driver(&piix4_driver);
+}
+
+static void __exit i2c_piix4_exit(void)
+{
+	pci_unregister_driver(&piix4_driver);
+}
+
+MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl> and "
+		"Philip Edelbrock <phil@netroedge.com>");
+MODULE_DESCRIPTION("PIIX4 SMBus driver");
+MODULE_LICENSE("GPL");
+
+module_init(i2c_piix4_init);
+module_exit(i2c_piix4_exit);
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-pmcmsp.c b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-pmcmsp.c
new file mode 100644
index 0000000..07b7447
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-pmcmsp.c
@@ -0,0 +1,643 @@
+/*
+ * Specific bus support for PMC-TWI compliant implementation on MSP71xx.
+ *
+ * Copyright 2005-2007 PMC-Sierra, Inc.
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ *  THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
+ *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+ *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  You should have received a copy of the  GNU General Public License along
+ *  with this program; if not, write  to the Free Software Foundation, Inc.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/completion.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+
+#define DRV_NAME	"pmcmsptwi"
+
+#define MSP_TWI_SF_CLK_REG_OFFSET	0x00
+#define MSP_TWI_HS_CLK_REG_OFFSET	0x04
+#define MSP_TWI_CFG_REG_OFFSET		0x08
+#define MSP_TWI_CMD_REG_OFFSET		0x0c
+#define MSP_TWI_ADD_REG_OFFSET		0x10
+#define MSP_TWI_DAT_0_REG_OFFSET	0x14
+#define MSP_TWI_DAT_1_REG_OFFSET	0x18
+#define MSP_TWI_INT_STS_REG_OFFSET	0x1c
+#define MSP_TWI_INT_MSK_REG_OFFSET	0x20
+#define MSP_TWI_BUSY_REG_OFFSET		0x24
+
+#define MSP_TWI_INT_STS_DONE			(1 << 0)
+#define MSP_TWI_INT_STS_LOST_ARBITRATION	(1 << 1)
+#define MSP_TWI_INT_STS_NO_RESPONSE		(1 << 2)
+#define MSP_TWI_INT_STS_DATA_COLLISION		(1 << 3)
+#define MSP_TWI_INT_STS_BUSY			(1 << 4)
+#define MSP_TWI_INT_STS_ALL			0x1f
+
+#define MSP_MAX_BYTES_PER_RW		8
+#define MSP_MAX_POLL			5
+#define MSP_POLL_DELAY			10
+#define MSP_IRQ_TIMEOUT			(MSP_MAX_POLL * MSP_POLL_DELAY)
+
+/* IO Operation macros */
+#define pmcmsptwi_readl		__raw_readl
+#define pmcmsptwi_writel	__raw_writel
+
+/* TWI command type */
+enum pmcmsptwi_cmd_type {
+	MSP_TWI_CMD_WRITE	= 0,	/* Write only */
+	MSP_TWI_CMD_READ	= 1,	/* Read only */
+	MSP_TWI_CMD_WRITE_READ	= 2,	/* Write then Read */
+};
+
+/* The possible results of the xferCmd */
+enum pmcmsptwi_xfer_result {
+	MSP_TWI_XFER_OK	= 0,
+	MSP_TWI_XFER_TIMEOUT,
+	MSP_TWI_XFER_BUSY,
+	MSP_TWI_XFER_DATA_COLLISION,
+	MSP_TWI_XFER_NO_RESPONSE,
+	MSP_TWI_XFER_LOST_ARBITRATION,
+};
+
+/* Corresponds to a PMCTWI clock configuration register */
+struct pmcmsptwi_clock {
+	u8 filter;	/* Bits 15:12,	default = 0x03 */
+	u16 clock;	/* Bits 9:0,	default = 0x001f */
+};
+
+struct pmcmsptwi_clockcfg {
+	struct pmcmsptwi_clock standard;  /* The standard/fast clock config */
+	struct pmcmsptwi_clock highspeed; /* The highspeed clock config */
+};
+
+/* Corresponds to the main TWI configuration register */
+struct pmcmsptwi_cfg {
+	u8 arbf;	/* Bits 15:12,	default=0x03 */
+	u8 nak;		/* Bits 11:8,	default=0x03 */
+	u8 add10;	/* Bit 7,	default=0x00 */
+	u8 mst_code;	/* Bits 6:4,	default=0x00 */
+	u8 arb;		/* Bit 1,	default=0x01 */
+	u8 highspeed;	/* Bit 0,	default=0x00 */
+};
+
+/* A single pmctwi command to issue */
+struct pmcmsptwi_cmd {
+	u16 addr;	/* The slave address (7 or 10 bits) */
+	enum pmcmsptwi_cmd_type type;	/* The command type */
+	u8 write_len;	/* Number of bytes in the write buffer */
+	u8 read_len;	/* Number of bytes in the read buffer */
+	u8 *write_data;	/* Buffer of characters to send */
+	u8 *read_data;	/* Buffer to fill with incoming data */
+};
+
+/* The private data */
+struct pmcmsptwi_data {
+	void __iomem *iobase;			/* iomapped base for IO */
+	int irq;				/* IRQ to use (0 disables) */
+	struct completion wait;			/* Completion for xfer */
+	struct mutex lock;			/* Used for threadsafeness */
+	enum pmcmsptwi_xfer_result last_result;	/* result of last xfer */
+};
+
+/* The default settings */
+static const struct pmcmsptwi_clockcfg pmcmsptwi_defclockcfg = {
+	.standard = {
+		.filter	= 0x3,
+		.clock	= 0x1f,
+	},
+	.highspeed = {
+		.filter	= 0x3,
+		.clock	= 0x1f,
+	},
+};
+
+static const struct pmcmsptwi_cfg pmcmsptwi_defcfg = {
+	.arbf		= 0x03,
+	.nak		= 0x03,
+	.add10		= 0x00,
+	.mst_code	= 0x00,
+	.arb		= 0x01,
+	.highspeed	= 0x00,
+};
+
+static struct pmcmsptwi_data pmcmsptwi_data;
+
+static struct i2c_adapter pmcmsptwi_adapter;
+
+/* inline helper functions */
+static inline u32 pmcmsptwi_clock_to_reg(
+			const struct pmcmsptwi_clock *clock)
+{
+	return ((clock->filter & 0xf) << 12) | (clock->clock & 0x03ff);
+}
+
+static inline void pmcmsptwi_reg_to_clock(
+			u32 reg, struct pmcmsptwi_clock *clock)
+{
+	clock->filter = (reg >> 12) & 0xf;
+	clock->clock = reg & 0x03ff;
+}
+
+static inline u32 pmcmsptwi_cfg_to_reg(const struct pmcmsptwi_cfg *cfg)
+{
+	return ((cfg->arbf & 0xf) << 12) |
+		((cfg->nak & 0xf) << 8) |
+		((cfg->add10 & 0x1) << 7) |
+		((cfg->mst_code & 0x7) << 4) |
+		((cfg->arb & 0x1) << 1) |
+		(cfg->highspeed & 0x1);
+}
+
+static inline void pmcmsptwi_reg_to_cfg(u32 reg, struct pmcmsptwi_cfg *cfg)
+{
+	cfg->arbf = (reg >> 12) & 0xf;
+	cfg->nak = (reg >> 8) & 0xf;
+	cfg->add10 = (reg >> 7) & 0x1;
+	cfg->mst_code = (reg >> 4) & 0x7;
+	cfg->arb = (reg >> 1) & 0x1;
+	cfg->highspeed = reg & 0x1;
+}
+
+/*
+ * Sets the current clock configuration
+ */
+static void pmcmsptwi_set_clock_config(const struct pmcmsptwi_clockcfg *cfg,
+					struct pmcmsptwi_data *data)
+{
+	mutex_lock(&data->lock);
+	pmcmsptwi_writel(pmcmsptwi_clock_to_reg(&cfg->standard),
+				data->iobase + MSP_TWI_SF_CLK_REG_OFFSET);
+	pmcmsptwi_writel(pmcmsptwi_clock_to_reg(&cfg->highspeed),
+				data->iobase + MSP_TWI_HS_CLK_REG_OFFSET);
+	mutex_unlock(&data->lock);
+}
+
+/*
+ * Gets the current TWI bus configuration
+ */
+static void pmcmsptwi_get_twi_config(struct pmcmsptwi_cfg *cfg,
+					struct pmcmsptwi_data *data)
+{
+	mutex_lock(&data->lock);
+	pmcmsptwi_reg_to_cfg(pmcmsptwi_readl(
+				data->iobase + MSP_TWI_CFG_REG_OFFSET), cfg);
+	mutex_unlock(&data->lock);
+}
+
+/*
+ * Sets the current TWI bus configuration
+ */
+static void pmcmsptwi_set_twi_config(const struct pmcmsptwi_cfg *cfg,
+					struct pmcmsptwi_data *data)
+{
+	mutex_lock(&data->lock);
+	pmcmsptwi_writel(pmcmsptwi_cfg_to_reg(cfg),
+				data->iobase + MSP_TWI_CFG_REG_OFFSET);
+	mutex_unlock(&data->lock);
+}
+
+/*
+ * Parses the 'int_sts' register and returns a well-defined error code
+ */
+static enum pmcmsptwi_xfer_result pmcmsptwi_get_result(u32 reg)
+{
+	if (reg & MSP_TWI_INT_STS_LOST_ARBITRATION) {
+		dev_dbg(&pmcmsptwi_adapter.dev,
+			"Result: Lost arbitration\n");
+		return MSP_TWI_XFER_LOST_ARBITRATION;
+	} else if (reg & MSP_TWI_INT_STS_NO_RESPONSE) {
+		dev_dbg(&pmcmsptwi_adapter.dev,
+			"Result: No response\n");
+		return MSP_TWI_XFER_NO_RESPONSE;
+	} else if (reg & MSP_TWI_INT_STS_DATA_COLLISION) {
+		dev_dbg(&pmcmsptwi_adapter.dev,
+			"Result: Data collision\n");
+		return MSP_TWI_XFER_DATA_COLLISION;
+	} else if (reg & MSP_TWI_INT_STS_BUSY) {
+		dev_dbg(&pmcmsptwi_adapter.dev,
+			"Result: Bus busy\n");
+		return MSP_TWI_XFER_BUSY;
+	}
+
+	dev_dbg(&pmcmsptwi_adapter.dev, "Result: Operation succeeded\n");
+	return MSP_TWI_XFER_OK;
+}
+
+/*
+ * In interrupt mode, handle the interrupt.
+ * NOTE: Assumes data->lock is held.
+ */
+static irqreturn_t pmcmsptwi_interrupt(int irq, void *ptr)
+{
+	struct pmcmsptwi_data *data = ptr;
+
+	u32 reason = pmcmsptwi_readl(data->iobase +
+					MSP_TWI_INT_STS_REG_OFFSET);
+	pmcmsptwi_writel(reason, data->iobase + MSP_TWI_INT_STS_REG_OFFSET);
+
+	dev_dbg(&pmcmsptwi_adapter.dev, "Got interrupt 0x%08x\n", reason);
+	if (!(reason & MSP_TWI_INT_STS_DONE))
+		return IRQ_NONE;
+
+	data->last_result = pmcmsptwi_get_result(reason);
+	complete(&data->wait);
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * Probe for and register the device and return 0 if there is one.
+ */
+static int __devinit pmcmsptwi_probe(struct platform_device *pldev)
+{
+	struct resource *res;
+	int rc = -ENODEV;
+
+	/* get the static platform resources */
+	res = platform_get_resource(pldev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pldev->dev, "IOMEM resource not found\n");
+		goto ret_err;
+	}
+
+	/* reserve the memory region */
+	if (!request_mem_region(res->start, resource_size(res),
+				pldev->name)) {
+		dev_err(&pldev->dev,
+			"Unable to get memory/io address region 0x%08x\n",
+			res->start);
+		rc = -EBUSY;
+		goto ret_err;
+	}
+
+	/* remap the memory */
+	pmcmsptwi_data.iobase = ioremap_nocache(res->start,
+						resource_size(res));
+	if (!pmcmsptwi_data.iobase) {
+		dev_err(&pldev->dev,
+			"Unable to ioremap address 0x%08x\n", res->start);
+		rc = -EIO;
+		goto ret_unreserve;
+	}
+
+	/* request the irq */
+	pmcmsptwi_data.irq = platform_get_irq(pldev, 0);
+	if (pmcmsptwi_data.irq) {
+		rc = request_irq(pmcmsptwi_data.irq, &pmcmsptwi_interrupt,
+			IRQF_SHARED | IRQF_SAMPLE_RANDOM,
+			pldev->name, &pmcmsptwi_data);
+		if (rc == 0) {
+			/*
+			 * Enable 'DONE' interrupt only.
+			 *
+			 * If you enable all interrupts, you will get one on
+			 * error and another when the operation completes.
+			 * This way you only have to handle one interrupt,
+			 * but you can still check all result flags.
+			 */
+			pmcmsptwi_writel(MSP_TWI_INT_STS_DONE,
+					pmcmsptwi_data.iobase +
+					MSP_TWI_INT_MSK_REG_OFFSET);
+		} else {
+			dev_warn(&pldev->dev,
+				"Could not assign TWI IRQ handler "
+				"to irq %d (continuing with poll)\n",
+				pmcmsptwi_data.irq);
+			pmcmsptwi_data.irq = 0;
+		}
+	}
+
+	init_completion(&pmcmsptwi_data.wait);
+	mutex_init(&pmcmsptwi_data.lock);
+
+	pmcmsptwi_set_clock_config(&pmcmsptwi_defclockcfg, &pmcmsptwi_data);
+	pmcmsptwi_set_twi_config(&pmcmsptwi_defcfg, &pmcmsptwi_data);
+
+	printk(KERN_INFO DRV_NAME ": Registering MSP71xx I2C adapter\n");
+
+	pmcmsptwi_adapter.dev.parent = &pldev->dev;
+	platform_set_drvdata(pldev, &pmcmsptwi_adapter);
+	i2c_set_adapdata(&pmcmsptwi_adapter, &pmcmsptwi_data);
+
+	rc = i2c_add_adapter(&pmcmsptwi_adapter);
+	if (rc) {
+		dev_err(&pldev->dev, "Unable to register I2C adapter\n");
+		goto ret_unmap;
+	}
+
+	return 0;
+
+ret_unmap:
+	platform_set_drvdata(pldev, NULL);
+	if (pmcmsptwi_data.irq) {
+		pmcmsptwi_writel(0,
+			pmcmsptwi_data.iobase + MSP_TWI_INT_MSK_REG_OFFSET);
+		free_irq(pmcmsptwi_data.irq, &pmcmsptwi_data);
+	}
+
+	iounmap(pmcmsptwi_data.iobase);
+
+ret_unreserve:
+	release_mem_region(res->start, resource_size(res));
+
+ret_err:
+	return rc;
+}
+
+/*
+ * Release the device and return 0 if there is one.
+ */
+static int __devexit pmcmsptwi_remove(struct platform_device *pldev)
+{
+	struct resource *res;
+
+	i2c_del_adapter(&pmcmsptwi_adapter);
+
+	platform_set_drvdata(pldev, NULL);
+	if (pmcmsptwi_data.irq) {
+		pmcmsptwi_writel(0,
+			pmcmsptwi_data.iobase + MSP_TWI_INT_MSK_REG_OFFSET);
+		free_irq(pmcmsptwi_data.irq, &pmcmsptwi_data);
+	}
+
+	iounmap(pmcmsptwi_data.iobase);
+
+	res = platform_get_resource(pldev, IORESOURCE_MEM, 0);
+	release_mem_region(res->start, resource_size(res));
+
+	return 0;
+}
+
+/*
+ * Polls the 'busy' register until the command is complete.
+ * NOTE: Assumes data->lock is held.
+ */
+static void pmcmsptwi_poll_complete(struct pmcmsptwi_data *data)
+{
+	int i;
+
+	for (i = 0; i < MSP_MAX_POLL; i++) {
+		u32 val = pmcmsptwi_readl(data->iobase +
+						MSP_TWI_BUSY_REG_OFFSET);
+		if (val == 0) {
+			u32 reason = pmcmsptwi_readl(data->iobase +
+						MSP_TWI_INT_STS_REG_OFFSET);
+			pmcmsptwi_writel(reason, data->iobase +
+						MSP_TWI_INT_STS_REG_OFFSET);
+			data->last_result = pmcmsptwi_get_result(reason);
+			return;
+		}
+		udelay(MSP_POLL_DELAY);
+	}
+
+	dev_dbg(&pmcmsptwi_adapter.dev, "Result: Poll timeout\n");
+	data->last_result = MSP_TWI_XFER_TIMEOUT;
+}
+
+/*
+ * Do the transfer (low level):
+ *   May use interrupt-driven or polling, depending on if an IRQ is
+ *   presently registered.
+ * NOTE: Assumes data->lock is held.
+ */
+static enum pmcmsptwi_xfer_result pmcmsptwi_do_xfer(
+			u32 reg, struct pmcmsptwi_data *data)
+{
+	dev_dbg(&pmcmsptwi_adapter.dev, "Writing cmd reg 0x%08x\n", reg);
+	pmcmsptwi_writel(reg, data->iobase + MSP_TWI_CMD_REG_OFFSET);
+	if (data->irq) {
+		unsigned long timeleft = wait_for_completion_timeout(
+						&data->wait, MSP_IRQ_TIMEOUT);
+		if (timeleft == 0) {
+			dev_dbg(&pmcmsptwi_adapter.dev,
+				"Result: IRQ timeout\n");
+			complete(&data->wait);
+			data->last_result = MSP_TWI_XFER_TIMEOUT;
+		}
+	} else
+		pmcmsptwi_poll_complete(data);
+
+	return data->last_result;
+}
+
+/*
+ * Helper routine, converts 'pmctwi_cmd' struct to register format
+ */
+static inline u32 pmcmsptwi_cmd_to_reg(const struct pmcmsptwi_cmd *cmd)
+{
+	return ((cmd->type & 0x3) << 8) |
+		(((cmd->write_len - 1) & 0x7) << 4) |
+		((cmd->read_len - 1) & 0x7);
+}
+
+/*
+ * Do the transfer (high level)
+ */
+static enum pmcmsptwi_xfer_result pmcmsptwi_xfer_cmd(
+			struct pmcmsptwi_cmd *cmd,
+			struct pmcmsptwi_data *data)
+{
+	enum pmcmsptwi_xfer_result retval;
+
+	if ((cmd->type == MSP_TWI_CMD_WRITE && cmd->write_len == 0) ||
+	    (cmd->type == MSP_TWI_CMD_READ && cmd->read_len == 0) ||
+	    (cmd->type == MSP_TWI_CMD_WRITE_READ &&
+	    (cmd->read_len == 0 || cmd->write_len == 0))) {
+		dev_err(&pmcmsptwi_adapter.dev,
+			"%s: Cannot transfer less than 1 byte\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	if (cmd->read_len > MSP_MAX_BYTES_PER_RW ||
+	    cmd->write_len > MSP_MAX_BYTES_PER_RW) {
+		dev_err(&pmcmsptwi_adapter.dev,
+			"%s: Cannot transfer more than %d bytes\n",
+			__func__, MSP_MAX_BYTES_PER_RW);
+		return -EINVAL;
+	}
+
+	mutex_lock(&data->lock);
+	dev_dbg(&pmcmsptwi_adapter.dev,
+		"Setting address to 0x%04x\n", cmd->addr);
+	pmcmsptwi_writel(cmd->addr, data->iobase + MSP_TWI_ADD_REG_OFFSET);
+
+	if (cmd->type == MSP_TWI_CMD_WRITE ||
+	    cmd->type == MSP_TWI_CMD_WRITE_READ) {
+		u64 tmp = be64_to_cpup((__be64 *)cmd->write_data);
+		tmp >>= (MSP_MAX_BYTES_PER_RW - cmd->write_len) * 8;
+		dev_dbg(&pmcmsptwi_adapter.dev, "Writing 0x%016llx\n", tmp);
+		pmcmsptwi_writel(tmp & 0x00000000ffffffffLL,
+				data->iobase + MSP_TWI_DAT_0_REG_OFFSET);
+		if (cmd->write_len > 4)
+			pmcmsptwi_writel(tmp >> 32,
+				data->iobase + MSP_TWI_DAT_1_REG_OFFSET);
+	}
+
+	retval = pmcmsptwi_do_xfer(pmcmsptwi_cmd_to_reg(cmd), data);
+	if (retval != MSP_TWI_XFER_OK)
+		goto xfer_err;
+
+	if (cmd->type == MSP_TWI_CMD_READ ||
+	    cmd->type == MSP_TWI_CMD_WRITE_READ) {
+		int i;
+		u64 rmsk = ~(0xffffffffffffffffLL << (cmd->read_len * 8));
+		u64 tmp = (u64)pmcmsptwi_readl(data->iobase +
+					MSP_TWI_DAT_0_REG_OFFSET);
+		if (cmd->read_len > 4)
+			tmp |= (u64)pmcmsptwi_readl(data->iobase +
+					MSP_TWI_DAT_1_REG_OFFSET) << 32;
+		tmp &= rmsk;
+		dev_dbg(&pmcmsptwi_adapter.dev, "Read 0x%016llx\n", tmp);
+
+		for (i = 0; i < cmd->read_len; i++)
+			cmd->read_data[i] = tmp >> i;
+	}
+
+xfer_err:
+	mutex_unlock(&data->lock);
+
+	return retval;
+}
+
+/* -- Algorithm functions -- */
+
+/*
+ * Sends an i2c command out on the adapter
+ */
+static int pmcmsptwi_master_xfer(struct i2c_adapter *adap,
+				struct i2c_msg *msg, int num)
+{
+	struct pmcmsptwi_data *data = i2c_get_adapdata(adap);
+	struct pmcmsptwi_cmd cmd;
+	struct pmcmsptwi_cfg oldcfg, newcfg;
+	int ret;
+
+	if (num > 2) {
+		dev_dbg(&adap->dev, "%d messages unsupported\n", num);
+		return -EINVAL;
+	} else if (num == 2) {
+		/* Check for a dual write-then-read command */
+		struct i2c_msg *nextmsg = msg + 1;
+		if (!(msg->flags & I2C_M_RD) &&
+		    (nextmsg->flags & I2C_M_RD) &&
+		    msg->addr == nextmsg->addr) {
+			cmd.type = MSP_TWI_CMD_WRITE_READ;
+			cmd.write_len = msg->len;
+			cmd.write_data = msg->buf;
+			cmd.read_len = nextmsg->len;
+			cmd.read_data = nextmsg->buf;
+		} else {
+			dev_dbg(&adap->dev,
+				"Non write-read dual messages unsupported\n");
+			return -EINVAL;
+		}
+	} else if (msg->flags & I2C_M_RD) {
+		cmd.type = MSP_TWI_CMD_READ;
+		cmd.read_len = msg->len;
+		cmd.read_data = msg->buf;
+		cmd.write_len = 0;
+		cmd.write_data = NULL;
+	} else {
+		cmd.type = MSP_TWI_CMD_WRITE;
+		cmd.read_len = 0;
+		cmd.read_data = NULL;
+		cmd.write_len = msg->len;
+		cmd.write_data = msg->buf;
+	}
+
+	if (msg->len == 0) {
+		dev_err(&adap->dev, "Zero-byte messages unsupported\n");
+		return -EINVAL;
+	}
+
+	cmd.addr = msg->addr;
+
+	if (msg->flags & I2C_M_TEN) {
+		pmcmsptwi_get_twi_config(&newcfg, data);
+		memcpy(&oldcfg, &newcfg, sizeof(oldcfg));
+
+		/* Set the special 10-bit address flag */
+		newcfg.add10 = 1;
+
+		pmcmsptwi_set_twi_config(&newcfg, data);
+	}
+
+	/* Execute the command */
+	ret = pmcmsptwi_xfer_cmd(&cmd, data);
+
+	if (msg->flags & I2C_M_TEN)
+		pmcmsptwi_set_twi_config(&oldcfg, data);
+
+	dev_dbg(&adap->dev, "I2C %s of %d bytes %s\n",
+		(msg->flags & I2C_M_RD) ? "read" : "write", msg->len,
+		(ret == MSP_TWI_XFER_OK) ? "succeeded" : "failed");
+
+	if (ret != MSP_TWI_XFER_OK) {
+		/*
+		 * TODO: We could potentially loop and retry in the case
+		 * of MSP_TWI_XFER_TIMEOUT.
+		 */
+		return -1;
+	}
+
+	return 0;
+}
+
+static u32 pmcmsptwi_i2c_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR |
+		I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA |
+		I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_PROC_CALL;
+}
+
+/* -- Initialization -- */
+
+static struct i2c_algorithm pmcmsptwi_algo = {
+	.master_xfer	= pmcmsptwi_master_xfer,
+	.functionality	= pmcmsptwi_i2c_func,
+};
+
+static struct i2c_adapter pmcmsptwi_adapter = {
+	.owner		= THIS_MODULE,
+	.class		= I2C_CLASS_HWMON | I2C_CLASS_SPD,
+	.algo		= &pmcmsptwi_algo,
+	.name		= DRV_NAME,
+};
+
+static struct platform_driver pmcmsptwi_driver = {
+	.probe  = pmcmsptwi_probe,
+	.remove	= __devexit_p(pmcmsptwi_remove),
+	.driver = {
+		.name	= DRV_NAME,
+		.owner	= THIS_MODULE,
+	},
+};
+
+module_platform_driver(pmcmsptwi_driver);
+
+MODULE_DESCRIPTION("PMC MSP TWI/SMBus/I2C driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-pnx.c b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-pnx.c
new file mode 100644
index 0000000..eb8ad53
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-pnx.c
@@ -0,0 +1,733 @@
+/*
+ * Provides I2C support for Philips PNX010x/PNX4008 boards.
+ *
+ * Authors: Dennis Kovalev <dkovalev@ru.mvista.com>
+ *	    Vitaly Wool <vwool@ru.mvista.com>
+ *
+ * 2004-2006 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/timer.h>
+#include <linux/completion.h>
+#include <linux/platform_device.h>
+#include <linux/i2c-pnx.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/slab.h>
+
+#include <mach/hardware.h>
+#include <mach/i2c.h>
+
+#define I2C_PNX_TIMEOUT		10 /* msec */
+#define I2C_PNX_SPEED_KHZ	100
+#define I2C_PNX_REGION_SIZE	0x100
+
+static inline int wait_timeout(long timeout, struct i2c_pnx_algo_data *data)
+{
+	while (timeout > 0 &&
+			(ioread32(I2C_REG_STS(data)) & mstatus_active)) {
+		mdelay(1);
+		timeout--;
+	}
+	return (timeout <= 0);
+}
+
+static inline int wait_reset(long timeout, struct i2c_pnx_algo_data *data)
+{
+	while (timeout > 0 &&
+			(ioread32(I2C_REG_CTL(data)) & mcntrl_reset)) {
+		mdelay(1);
+		timeout--;
+	}
+	return (timeout <= 0);
+}
+
+static inline void i2c_pnx_arm_timer(struct i2c_pnx_algo_data *alg_data)
+{
+	struct timer_list *timer = &alg_data->mif.timer;
+	unsigned long expires = msecs_to_jiffies(I2C_PNX_TIMEOUT);
+
+	if (expires <= 1)
+		expires = 2;
+
+	del_timer_sync(timer);
+
+	dev_dbg(&alg_data->adapter.dev, "Timer armed at %lu plus %lu jiffies.\n",
+		jiffies, expires);
+
+	timer->expires = jiffies + expires;
+	timer->data = (unsigned long)alg_data;
+
+	add_timer(timer);
+}
+
+/**
+ * i2c_pnx_start - start a device
+ * @slave_addr:		slave address
+ * @adap:		pointer to adapter structure
+ *
+ * Generate a START signal in the desired mode.
+ */
+static int i2c_pnx_start(unsigned char slave_addr,
+	struct i2c_pnx_algo_data *alg_data)
+{
+	dev_dbg(&alg_data->adapter.dev, "%s(): addr 0x%x mode %d\n", __func__,
+		slave_addr, alg_data->mif.mode);
+
+	/* Check for 7 bit slave addresses only */
+	if (slave_addr & ~0x7f) {
+		dev_err(&alg_data->adapter.dev,
+			"%s: Invalid slave address %x. Only 7-bit addresses are supported\n",
+			alg_data->adapter.name, slave_addr);
+		return -EINVAL;
+	}
+
+	/* First, make sure bus is idle */
+	if (wait_timeout(I2C_PNX_TIMEOUT, alg_data)) {
+		/* Somebody else is monopolizing the bus */
+		dev_err(&alg_data->adapter.dev,
+			"%s: Bus busy. Slave addr = %02x, cntrl = %x, stat = %x\n",
+			alg_data->adapter.name, slave_addr,
+			ioread32(I2C_REG_CTL(alg_data)),
+			ioread32(I2C_REG_STS(alg_data)));
+		return -EBUSY;
+	} else if (ioread32(I2C_REG_STS(alg_data)) & mstatus_afi) {
+		/* Sorry, we lost the bus */
+		dev_err(&alg_data->adapter.dev,
+		        "%s: Arbitration failure. Slave addr = %02x\n",
+			alg_data->adapter.name, slave_addr);
+		return -EIO;
+	}
+
+	/*
+	 * OK, I2C is enabled and we have the bus.
+	 * Clear the current TDI and AFI status flags.
+	 */
+	iowrite32(ioread32(I2C_REG_STS(alg_data)) | mstatus_tdi | mstatus_afi,
+		  I2C_REG_STS(alg_data));
+
+	dev_dbg(&alg_data->adapter.dev, "%s(): sending %#x\n", __func__,
+		(slave_addr << 1) | start_bit | alg_data->mif.mode);
+
+	/* Write the slave address, START bit and R/W bit */
+	iowrite32((slave_addr << 1) | start_bit | alg_data->mif.mode,
+		  I2C_REG_TX(alg_data));
+
+	dev_dbg(&alg_data->adapter.dev, "%s(): exit\n", __func__);
+
+	return 0;
+}
+
+/**
+ * i2c_pnx_stop - stop a device
+ * @adap:		pointer to I2C adapter structure
+ *
+ * Generate a STOP signal to terminate the master transaction.
+ */
+static void i2c_pnx_stop(struct i2c_pnx_algo_data *alg_data)
+{
+	/* Only 1 msec max timeout due to interrupt context */
+	long timeout = 1000;
+
+	dev_dbg(&alg_data->adapter.dev, "%s(): entering: stat = %04x.\n",
+		__func__, ioread32(I2C_REG_STS(alg_data)));
+
+	/* Write a STOP bit to TX FIFO */
+	iowrite32(0xff | stop_bit, I2C_REG_TX(alg_data));
+
+	/* Wait until the STOP is seen. */
+	while (timeout > 0 &&
+	       (ioread32(I2C_REG_STS(alg_data)) & mstatus_active)) {
+		/* may be called from interrupt context */
+		udelay(1);
+		timeout--;
+	}
+
+	dev_dbg(&alg_data->adapter.dev, "%s(): exiting: stat = %04x.\n",
+		__func__, ioread32(I2C_REG_STS(alg_data)));
+}
+
+/**
+ * i2c_pnx_master_xmit - transmit data to slave
+ * @adap:		pointer to I2C adapter structure
+ *
+ * Sends one byte of data to the slave
+ */
+static int i2c_pnx_master_xmit(struct i2c_pnx_algo_data *alg_data)
+{
+	u32 val;
+
+	dev_dbg(&alg_data->adapter.dev, "%s(): entering: stat = %04x.\n",
+		__func__, ioread32(I2C_REG_STS(alg_data)));
+
+	if (alg_data->mif.len > 0) {
+		/* We still have something to talk about... */
+		val = *alg_data->mif.buf++;
+
+		if (alg_data->mif.len == 1)
+			val |= stop_bit;
+
+		alg_data->mif.len--;
+		iowrite32(val, I2C_REG_TX(alg_data));
+
+		dev_dbg(&alg_data->adapter.dev, "%s(): xmit %#x [%d]\n",
+			__func__, val, alg_data->mif.len + 1);
+
+		if (alg_data->mif.len == 0) {
+			if (alg_data->last) {
+				/* Wait until the STOP is seen. */
+				if (wait_timeout(I2C_PNX_TIMEOUT, alg_data))
+					dev_err(&alg_data->adapter.dev,
+						"The bus is still active after timeout\n");
+			}
+			/* Disable master interrupts */
+			iowrite32(ioread32(I2C_REG_CTL(alg_data)) &
+				~(mcntrl_afie | mcntrl_naie | mcntrl_drmie),
+				  I2C_REG_CTL(alg_data));
+
+			del_timer_sync(&alg_data->mif.timer);
+
+			dev_dbg(&alg_data->adapter.dev,
+				"%s(): Waking up xfer routine.\n",
+				__func__);
+
+			complete(&alg_data->mif.complete);
+		}
+	} else if (alg_data->mif.len == 0) {
+		/* zero-sized transfer */
+		i2c_pnx_stop(alg_data);
+
+		/* Disable master interrupts. */
+		iowrite32(ioread32(I2C_REG_CTL(alg_data)) &
+			~(mcntrl_afie | mcntrl_naie | mcntrl_drmie),
+			  I2C_REG_CTL(alg_data));
+
+		/* Stop timer. */
+		del_timer_sync(&alg_data->mif.timer);
+		dev_dbg(&alg_data->adapter.dev,
+			"%s(): Waking up xfer routine after zero-xfer.\n",
+			__func__);
+
+		complete(&alg_data->mif.complete);
+	}
+
+	dev_dbg(&alg_data->adapter.dev, "%s(): exiting: stat = %04x.\n",
+		__func__, ioread32(I2C_REG_STS(alg_data)));
+
+	return 0;
+}
+
+/**
+ * i2c_pnx_master_rcv - receive data from slave
+ * @adap:		pointer to I2C adapter structure
+ *
+ * Reads one byte data from the slave
+ */
+static int i2c_pnx_master_rcv(struct i2c_pnx_algo_data *alg_data)
+{
+	unsigned int val = 0;
+	u32 ctl = 0;
+
+	dev_dbg(&alg_data->adapter.dev, "%s(): entering: stat = %04x.\n",
+		__func__, ioread32(I2C_REG_STS(alg_data)));
+
+	/* Check, whether there is already data,
+	 * or we didn't 'ask' for it yet.
+	 */
+	if (ioread32(I2C_REG_STS(alg_data)) & mstatus_rfe) {
+		dev_dbg(&alg_data->adapter.dev,
+			"%s(): Write dummy data to fill Rx-fifo...\n",
+			__func__);
+
+		if (alg_data->mif.len == 1) {
+			/* Last byte, do not acknowledge next rcv. */
+			val |= stop_bit;
+
+			/*
+			 * Enable interrupt RFDAIE (data in Rx fifo),
+			 * and disable DRMIE (need data for Tx)
+			 */
+			ctl = ioread32(I2C_REG_CTL(alg_data));
+			ctl |= mcntrl_rffie | mcntrl_daie;
+			ctl &= ~mcntrl_drmie;
+			iowrite32(ctl, I2C_REG_CTL(alg_data));
+		}
+
+		/*
+		 * Now we'll 'ask' for data:
+		 * For each byte we want to receive, we must
+		 * write a (dummy) byte to the Tx-FIFO.
+		 */
+		iowrite32(val, I2C_REG_TX(alg_data));
+
+		return 0;
+	}
+
+	/* Handle data. */
+	if (alg_data->mif.len > 0) {
+		val = ioread32(I2C_REG_RX(alg_data));
+		*alg_data->mif.buf++ = (u8) (val & 0xff);
+		dev_dbg(&alg_data->adapter.dev, "%s(): rcv 0x%x [%d]\n",
+			__func__, val, alg_data->mif.len);
+
+		alg_data->mif.len--;
+		if (alg_data->mif.len == 0) {
+			if (alg_data->last)
+				/* Wait until the STOP is seen. */
+				if (wait_timeout(I2C_PNX_TIMEOUT, alg_data))
+					dev_err(&alg_data->adapter.dev,
+						"The bus is still active after timeout\n");
+
+			/* Disable master interrupts */
+			ctl = ioread32(I2C_REG_CTL(alg_data));
+			ctl &= ~(mcntrl_afie | mcntrl_naie | mcntrl_rffie |
+				 mcntrl_drmie | mcntrl_daie);
+			iowrite32(ctl, I2C_REG_CTL(alg_data));
+
+			/* Kill timer. */
+			del_timer_sync(&alg_data->mif.timer);
+			complete(&alg_data->mif.complete);
+		}
+	}
+
+	dev_dbg(&alg_data->adapter.dev, "%s(): exiting: stat = %04x.\n",
+		__func__, ioread32(I2C_REG_STS(alg_data)));
+
+	return 0;
+}
+
+static irqreturn_t i2c_pnx_interrupt(int irq, void *dev_id)
+{
+	struct i2c_pnx_algo_data *alg_data = dev_id;
+	u32 stat, ctl;
+
+	dev_dbg(&alg_data->adapter.dev,
+		"%s(): mstat = %x mctrl = %x, mode = %d\n",
+		__func__,
+		ioread32(I2C_REG_STS(alg_data)),
+		ioread32(I2C_REG_CTL(alg_data)),
+		alg_data->mif.mode);
+	stat = ioread32(I2C_REG_STS(alg_data));
+
+	/* let's see what kind of event this is */
+	if (stat & mstatus_afi) {
+		/* We lost arbitration in the midst of a transfer */
+		alg_data->mif.ret = -EIO;
+
+		/* Disable master interrupts. */
+		ctl = ioread32(I2C_REG_CTL(alg_data));
+		ctl &= ~(mcntrl_afie | mcntrl_naie | mcntrl_rffie |
+			 mcntrl_drmie);
+		iowrite32(ctl, I2C_REG_CTL(alg_data));
+
+		/* Stop timer, to prevent timeout. */
+		del_timer_sync(&alg_data->mif.timer);
+		complete(&alg_data->mif.complete);
+	} else if (stat & mstatus_nai) {
+		/* Slave did not acknowledge, generate a STOP */
+		dev_dbg(&alg_data->adapter.dev,
+			"%s(): Slave did not acknowledge, generating a STOP.\n",
+			__func__);
+		i2c_pnx_stop(alg_data);
+
+		/* Disable master interrupts. */
+		ctl = ioread32(I2C_REG_CTL(alg_data));
+		ctl &= ~(mcntrl_afie | mcntrl_naie | mcntrl_rffie |
+			 mcntrl_drmie);
+		iowrite32(ctl, I2C_REG_CTL(alg_data));
+
+		/* Our return value. */
+		alg_data->mif.ret = -EIO;
+
+		/* Stop timer, to prevent timeout. */
+		del_timer_sync(&alg_data->mif.timer);
+		complete(&alg_data->mif.complete);
+	} else {
+		/*
+		 * Two options:
+		 * - Master Tx needs data.
+		 * - There is data in the Rx-fifo
+		 * The latter is only the case if we have requested for data,
+		 * via a dummy write. (See 'i2c_pnx_master_rcv'.)
+		 * We therefore check, as a sanity check, whether that interrupt
+		 * has been enabled.
+		 */
+		if ((stat & mstatus_drmi) || !(stat & mstatus_rfe)) {
+			if (alg_data->mif.mode == I2C_SMBUS_WRITE) {
+				i2c_pnx_master_xmit(alg_data);
+			} else if (alg_data->mif.mode == I2C_SMBUS_READ) {
+				i2c_pnx_master_rcv(alg_data);
+			}
+		}
+	}
+
+	/* Clear TDI and AFI bits */
+	stat = ioread32(I2C_REG_STS(alg_data));
+	iowrite32(stat | mstatus_tdi | mstatus_afi, I2C_REG_STS(alg_data));
+
+	dev_dbg(&alg_data->adapter.dev,
+		"%s(): exiting, stat = %x ctrl = %x.\n",
+		 __func__, ioread32(I2C_REG_STS(alg_data)),
+		 ioread32(I2C_REG_CTL(alg_data)));
+
+	return IRQ_HANDLED;
+}
+
+static void i2c_pnx_timeout(unsigned long data)
+{
+	struct i2c_pnx_algo_data *alg_data = (struct i2c_pnx_algo_data *)data;
+	u32 ctl;
+
+	dev_err(&alg_data->adapter.dev,
+		"Master timed out. stat = %04x, cntrl = %04x. Resetting master...\n",
+		ioread32(I2C_REG_STS(alg_data)),
+		ioread32(I2C_REG_CTL(alg_data)));
+
+	/* Reset master and disable interrupts */
+	ctl = ioread32(I2C_REG_CTL(alg_data));
+	ctl &= ~(mcntrl_afie | mcntrl_naie | mcntrl_rffie | mcntrl_drmie);
+	iowrite32(ctl, I2C_REG_CTL(alg_data));
+
+	ctl |= mcntrl_reset;
+	iowrite32(ctl, I2C_REG_CTL(alg_data));
+	wait_reset(I2C_PNX_TIMEOUT, alg_data);
+	alg_data->mif.ret = -EIO;
+	complete(&alg_data->mif.complete);
+}
+
+static inline void bus_reset_if_active(struct i2c_pnx_algo_data *alg_data)
+{
+	u32 stat;
+
+	if ((stat = ioread32(I2C_REG_STS(alg_data))) & mstatus_active) {
+		dev_err(&alg_data->adapter.dev,
+			"%s: Bus is still active after xfer. Reset it...\n",
+			alg_data->adapter.name);
+		iowrite32(ioread32(I2C_REG_CTL(alg_data)) | mcntrl_reset,
+			  I2C_REG_CTL(alg_data));
+		wait_reset(I2C_PNX_TIMEOUT, alg_data);
+	} else if (!(stat & mstatus_rfe) || !(stat & mstatus_tfe)) {
+		/* If there is data in the fifo's after transfer,
+		 * flush fifo's by reset.
+		 */
+		iowrite32(ioread32(I2C_REG_CTL(alg_data)) | mcntrl_reset,
+			  I2C_REG_CTL(alg_data));
+		wait_reset(I2C_PNX_TIMEOUT, alg_data);
+	} else if (stat & mstatus_nai) {
+		iowrite32(ioread32(I2C_REG_CTL(alg_data)) | mcntrl_reset,
+			  I2C_REG_CTL(alg_data));
+		wait_reset(I2C_PNX_TIMEOUT, alg_data);
+	}
+}
+
+/**
+ * i2c_pnx_xfer - generic transfer entry point
+ * @adap:		pointer to I2C adapter structure
+ * @msgs:		array of messages
+ * @num:		number of messages
+ *
+ * Initiates the transfer
+ */
+static int
+i2c_pnx_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+{
+	struct i2c_msg *pmsg;
+	int rc = 0, completed = 0, i;
+	struct i2c_pnx_algo_data *alg_data = adap->algo_data;
+	u32 stat = ioread32(I2C_REG_STS(alg_data));
+
+	dev_dbg(&alg_data->adapter.dev,
+		"%s(): entering: %d messages, stat = %04x.\n",
+		__func__, num, ioread32(I2C_REG_STS(alg_data)));
+
+	bus_reset_if_active(alg_data);
+
+	/* Process transactions in a loop. */
+	for (i = 0; rc >= 0 && i < num; i++) {
+		u8 addr;
+
+		pmsg = &msgs[i];
+		addr = pmsg->addr;
+
+		if (pmsg->flags & I2C_M_TEN) {
+			dev_err(&alg_data->adapter.dev,
+				"%s: 10 bits addr not supported!\n",
+				alg_data->adapter.name);
+			rc = -EINVAL;
+			break;
+		}
+
+		alg_data->mif.buf = pmsg->buf;
+		alg_data->mif.len = pmsg->len;
+		alg_data->mif.mode = (pmsg->flags & I2C_M_RD) ?
+			I2C_SMBUS_READ : I2C_SMBUS_WRITE;
+		alg_data->mif.ret = 0;
+		alg_data->last = (i == num - 1);
+
+		dev_dbg(&alg_data->adapter.dev, "%s(): mode %d, %d bytes\n",
+			__func__, alg_data->mif.mode, alg_data->mif.len);
+
+		i2c_pnx_arm_timer(alg_data);
+
+		/* initialize the completion var */
+		init_completion(&alg_data->mif.complete);
+
+		/* Enable master interrupt */
+		iowrite32(ioread32(I2C_REG_CTL(alg_data)) | mcntrl_afie |
+				mcntrl_naie | mcntrl_drmie,
+			  I2C_REG_CTL(alg_data));
+
+		/* Put start-code and slave-address on the bus. */
+		rc = i2c_pnx_start(addr, alg_data);
+		if (rc < 0)
+			break;
+
+		/* Wait for completion */
+		wait_for_completion(&alg_data->mif.complete);
+
+		if (!(rc = alg_data->mif.ret))
+			completed++;
+		dev_dbg(&alg_data->adapter.dev,
+			"%s(): Complete, return code = %d.\n",
+			__func__, rc);
+
+		/* Clear TDI and AFI bits in case they are set. */
+		if ((stat = ioread32(I2C_REG_STS(alg_data))) & mstatus_tdi) {
+			dev_dbg(&alg_data->adapter.dev,
+				"%s: TDI still set... clearing now.\n",
+				alg_data->adapter.name);
+			iowrite32(stat, I2C_REG_STS(alg_data));
+		}
+		if ((stat = ioread32(I2C_REG_STS(alg_data))) & mstatus_afi) {
+			dev_dbg(&alg_data->adapter.dev,
+				"%s: AFI still set... clearing now.\n",
+				alg_data->adapter.name);
+			iowrite32(stat, I2C_REG_STS(alg_data));
+		}
+	}
+
+	bus_reset_if_active(alg_data);
+
+	/* Cleanup to be sure... */
+	alg_data->mif.buf = NULL;
+	alg_data->mif.len = 0;
+
+	dev_dbg(&alg_data->adapter.dev, "%s(): exiting, stat = %x\n",
+		__func__, ioread32(I2C_REG_STS(alg_data)));
+
+	if (completed != num)
+		return ((rc < 0) ? rc : -EREMOTEIO);
+
+	return num;
+}
+
+static u32 i2c_pnx_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static struct i2c_algorithm pnx_algorithm = {
+	.master_xfer = i2c_pnx_xfer,
+	.functionality = i2c_pnx_func,
+};
+
+#ifdef CONFIG_PM
+static int i2c_pnx_controller_suspend(struct platform_device *pdev,
+				      pm_message_t state)
+{
+	struct i2c_pnx_algo_data *alg_data = platform_get_drvdata(pdev);
+
+	clk_disable(alg_data->clk);
+
+	return 0;
+}
+
+static int i2c_pnx_controller_resume(struct platform_device *pdev)
+{
+	struct i2c_pnx_algo_data *alg_data = platform_get_drvdata(pdev);
+
+	return clk_enable(alg_data->clk);
+}
+#else
+#define i2c_pnx_controller_suspend	NULL
+#define i2c_pnx_controller_resume	NULL
+#endif
+
+static int __devinit i2c_pnx_probe(struct platform_device *pdev)
+{
+	unsigned long tmp;
+	int ret = 0;
+	struct i2c_pnx_algo_data *alg_data;
+	unsigned long freq;
+	struct i2c_pnx_data *i2c_pnx = pdev->dev.platform_data;
+
+	if (!i2c_pnx || !i2c_pnx->name) {
+		dev_err(&pdev->dev, "%s: no platform data supplied\n",
+		       __func__);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	alg_data = kzalloc(sizeof(*alg_data), GFP_KERNEL);
+	if (!alg_data) {
+		ret = -ENOMEM;
+		goto err_kzalloc;
+	}
+
+	platform_set_drvdata(pdev, alg_data);
+
+	strlcpy(alg_data->adapter.name, i2c_pnx->name,
+		sizeof(alg_data->adapter.name));
+	alg_data->adapter.dev.parent = &pdev->dev;
+	alg_data->adapter.algo = &pnx_algorithm;
+	alg_data->adapter.algo_data = alg_data;
+	alg_data->adapter.nr = pdev->id;
+	alg_data->i2c_pnx = i2c_pnx;
+
+	alg_data->clk = clk_get(&pdev->dev, NULL);
+	if (IS_ERR(alg_data->clk)) {
+		ret = PTR_ERR(alg_data->clk);
+		goto out_drvdata;
+	}
+
+	init_timer(&alg_data->mif.timer);
+	alg_data->mif.timer.function = i2c_pnx_timeout;
+	alg_data->mif.timer.data = (unsigned long)alg_data;
+
+	/* Register I/O resource */
+	if (!request_mem_region(i2c_pnx->base, I2C_PNX_REGION_SIZE,
+				pdev->name)) {
+		dev_err(&pdev->dev,
+		       "I/O region 0x%08x for I2C already in use.\n",
+		       i2c_pnx->base);
+		ret = -ENODEV;
+		goto out_clkget;
+	}
+
+	alg_data->ioaddr = ioremap(i2c_pnx->base, I2C_PNX_REGION_SIZE);
+	if (!alg_data->ioaddr) {
+		dev_err(&pdev->dev, "Couldn't ioremap I2C I/O region\n");
+		ret = -ENOMEM;
+		goto out_release;
+	}
+
+	ret = clk_enable(alg_data->clk);
+	if (ret)
+		goto out_unmap;
+
+	freq = clk_get_rate(alg_data->clk);
+
+	/*
+	 * Clock Divisor High This value is the number of system clocks
+	 * the serial clock (SCL) will be high.
+	 * For example, if the system clock period is 50 ns and the maximum
+	 * desired serial period is 10000 ns (100 kHz), then CLKHI would be
+	 * set to 0.5*(f_sys/f_i2c)-2=0.5*(20e6/100e3)-2=98. The actual value
+	 * programmed into CLKHI will vary from this slightly due to
+	 * variations in the output pad's rise and fall times as well as
+	 * the deglitching filter length.
+	 */
+
+	tmp = ((freq / 1000) / I2C_PNX_SPEED_KHZ) / 2 - 2;
+	if (tmp > 0x3FF)
+		tmp = 0x3FF;
+	iowrite32(tmp, I2C_REG_CKH(alg_data));
+	iowrite32(tmp, I2C_REG_CKL(alg_data));
+
+	iowrite32(mcntrl_reset, I2C_REG_CTL(alg_data));
+	if (wait_reset(I2C_PNX_TIMEOUT, alg_data)) {
+		ret = -ENODEV;
+		goto out_clock;
+	}
+	init_completion(&alg_data->mif.complete);
+
+	ret = request_irq(i2c_pnx->irq, i2c_pnx_interrupt,
+			0, pdev->name, alg_data);
+	if (ret)
+		goto out_clock;
+
+	/* Register this adapter with the I2C subsystem */
+	ret = i2c_add_numbered_adapter(&alg_data->adapter);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "I2C: Failed to add bus\n");
+		goto out_irq;
+	}
+
+	dev_dbg(&pdev->dev, "%s: Master at %#8x, irq %d.\n",
+	       alg_data->adapter.name, i2c_pnx->base, i2c_pnx->irq);
+
+	return 0;
+
+out_irq:
+	free_irq(i2c_pnx->irq, alg_data);
+out_clock:
+	clk_disable(alg_data->clk);
+out_unmap:
+	iounmap(alg_data->ioaddr);
+out_release:
+	release_mem_region(i2c_pnx->base, I2C_PNX_REGION_SIZE);
+out_clkget:
+	clk_put(alg_data->clk);
+out_drvdata:
+	kfree(alg_data);
+err_kzalloc:
+	platform_set_drvdata(pdev, NULL);
+out:
+	return ret;
+}
+
+static int __devexit i2c_pnx_remove(struct platform_device *pdev)
+{
+	struct i2c_pnx_algo_data *alg_data = platform_get_drvdata(pdev);
+	struct i2c_pnx_data *i2c_pnx = alg_data->i2c_pnx;
+
+	free_irq(i2c_pnx->irq, alg_data);
+	i2c_del_adapter(&alg_data->adapter);
+	clk_disable(alg_data->clk);
+	iounmap(alg_data->ioaddr);
+	release_mem_region(i2c_pnx->base, I2C_PNX_REGION_SIZE);
+	clk_put(alg_data->clk);
+	kfree(alg_data);
+	platform_set_drvdata(pdev, NULL);
+
+	return 0;
+}
+
+static struct platform_driver i2c_pnx_driver = {
+	.driver = {
+		.name = "pnx-i2c",
+		.owner = THIS_MODULE,
+	},
+	.probe = i2c_pnx_probe,
+	.remove = __devexit_p(i2c_pnx_remove),
+	.suspend = i2c_pnx_controller_suspend,
+	.resume = i2c_pnx_controller_resume,
+};
+
+static int __init i2c_adap_pnx_init(void)
+{
+	return platform_driver_register(&i2c_pnx_driver);
+}
+
+static void __exit i2c_adap_pnx_exit(void)
+{
+	platform_driver_unregister(&i2c_pnx_driver);
+}
+
+MODULE_AUTHOR("Vitaly Wool, Dennis Kovalev <source@mvista.com>");
+MODULE_DESCRIPTION("I2C driver for Philips IP3204-based I2C busses");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pnx-i2c");
+
+/* We need to make sure I2C is initialized before USB */
+subsys_initcall(i2c_adap_pnx_init);
+module_exit(i2c_adap_pnx_exit);
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-powermac.c b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-powermac.c
new file mode 100644
index 0000000..7b397c6
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-powermac.c
@@ -0,0 +1,326 @@
+/*
+    i2c Support for Apple SMU Controller
+
+    Copyright (c) 2005 Benjamin Herrenschmidt, IBM Corp.
+                       <benh@kernel.crashing.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <asm/prom.h>
+#include <asm/pmac_low_i2c.h>
+
+MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
+MODULE_DESCRIPTION("I2C driver for Apple PowerMac");
+MODULE_LICENSE("GPL");
+
+/*
+ * SMBUS-type transfer entrypoint
+ */
+static s32 i2c_powermac_smbus_xfer(	struct i2c_adapter*	adap,
+					u16			addr,
+					unsigned short		flags,
+					char			read_write,
+					u8			command,
+					int			size,
+					union i2c_smbus_data*	data)
+{
+	struct pmac_i2c_bus	*bus = i2c_get_adapdata(adap);
+	int			rc = 0;
+	int			read = (read_write == I2C_SMBUS_READ);
+	int			addrdir = (addr << 1) | read;
+	int			mode, subsize, len;
+	u32			subaddr;
+	u8			*buf;
+	u8			local[2];
+
+	if (size == I2C_SMBUS_QUICK || size == I2C_SMBUS_BYTE) {
+		mode = pmac_i2c_mode_std;
+		subsize = 0;
+		subaddr = 0;
+	} else {
+		mode = read ? pmac_i2c_mode_combined : pmac_i2c_mode_stdsub;
+		subsize = 1;
+		subaddr = command;
+	}
+
+	switch (size) {
+        case I2C_SMBUS_QUICK:
+		buf = NULL;
+		len = 0;
+	    	break;
+        case I2C_SMBUS_BYTE:
+        case I2C_SMBUS_BYTE_DATA:
+		buf = &data->byte;
+		len = 1;
+	    	break;
+        case I2C_SMBUS_WORD_DATA:
+		if (!read) {
+			local[0] = data->word & 0xff;
+			local[1] = (data->word >> 8) & 0xff;
+		}
+		buf = local;
+		len = 2;
+	    	break;
+
+	/* Note that these are broken vs. the expected smbus API where
+	 * on reads, the length is actually returned from the function,
+	 * but I think the current API makes no sense and I don't want
+	 * any driver that I haven't verified for correctness to go
+	 * anywhere near a pmac i2c bus anyway ...
+	 *
+	 * I'm also not completely sure what kind of phases to do between
+	 * the actual command and the data (what I am _supposed_ to do that
+	 * is). For now, I assume writes are a single stream and reads have
+	 * a repeat start/addr phase (but not stop in between)
+	 */
+        case I2C_SMBUS_BLOCK_DATA:
+		buf = data->block;
+		len = data->block[0] + 1;
+		break;
+	case I2C_SMBUS_I2C_BLOCK_DATA:
+		buf = &data->block[1];
+		len = data->block[0];
+		break;
+
+        default:
+		return -EINVAL;
+	}
+
+	rc = pmac_i2c_open(bus, 0);
+	if (rc) {
+		dev_err(&adap->dev, "Failed to open I2C, err %d\n", rc);
+		return rc;
+	}
+
+	rc = pmac_i2c_setmode(bus, mode);
+	if (rc) {
+		dev_err(&adap->dev, "Failed to set I2C mode %d, err %d\n",
+			mode, rc);
+		goto bail;
+	}
+
+	rc = pmac_i2c_xfer(bus, addrdir, subsize, subaddr, buf, len);
+	if (rc) {
+		if (rc == -ENXIO)
+			dev_dbg(&adap->dev,
+				"I2C transfer at 0x%02x failed, size %d, "
+				"err %d\n", addrdir >> 1, size, rc);
+		else
+			dev_err(&adap->dev,
+				"I2C transfer at 0x%02x failed, size %d, "
+				"err %d\n", addrdir >> 1, size, rc);
+		goto bail;
+	}
+
+	if (size == I2C_SMBUS_WORD_DATA && read) {
+		data->word = ((u16)local[1]) << 8;
+		data->word |= local[0];
+	}
+
+ bail:
+	pmac_i2c_close(bus);
+	return rc;
+}
+
+/*
+ * Generic i2c master transfer entrypoint. This driver only support single
+ * messages (for "lame i2c" transfers). Anything else should use the smbus
+ * entry point
+ */
+static int i2c_powermac_master_xfer(	struct i2c_adapter *adap,
+					struct i2c_msg *msgs,
+					int num)
+{
+	struct pmac_i2c_bus	*bus = i2c_get_adapdata(adap);
+	int			rc = 0;
+	int			read;
+	int			addrdir;
+
+	if (num != 1) {
+		dev_err(&adap->dev,
+			"Multi-message I2C transactions not supported\n");
+		return -EOPNOTSUPP;
+	}
+
+	if (msgs->flags & I2C_M_TEN)
+		return -EINVAL;
+	read = (msgs->flags & I2C_M_RD) != 0;
+	addrdir = (msgs->addr << 1) | read;
+
+	rc = pmac_i2c_open(bus, 0);
+	if (rc) {
+		dev_err(&adap->dev, "Failed to open I2C, err %d\n", rc);
+		return rc;
+	}
+	rc = pmac_i2c_setmode(bus, pmac_i2c_mode_std);
+	if (rc) {
+		dev_err(&adap->dev, "Failed to set I2C mode %d, err %d\n",
+			pmac_i2c_mode_std, rc);
+		goto bail;
+	}
+	rc = pmac_i2c_xfer(bus, addrdir, 0, 0, msgs->buf, msgs->len);
+	if (rc < 0) {
+		if (rc == -ENXIO)
+			dev_dbg(&adap->dev, "I2C %s 0x%02x failed, err %d\n",
+				addrdir & 1 ? "read from" : "write to",
+				addrdir >> 1, rc);
+		else
+			dev_err(&adap->dev, "I2C %s 0x%02x failed, err %d\n",
+				addrdir & 1 ? "read from" : "write to",
+				addrdir >> 1, rc);
+	}
+ bail:
+	pmac_i2c_close(bus);
+	return rc < 0 ? rc : 1;
+}
+
+static u32 i2c_powermac_func(struct i2c_adapter * adapter)
+{
+	return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+		I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+		I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_I2C;
+}
+
+/* For now, we only handle smbus */
+static const struct i2c_algorithm i2c_powermac_algorithm = {
+	.smbus_xfer	= i2c_powermac_smbus_xfer,
+	.master_xfer	= i2c_powermac_master_xfer,
+	.functionality	= i2c_powermac_func,
+};
+
+
+static int __devexit i2c_powermac_remove(struct platform_device *dev)
+{
+	struct i2c_adapter	*adapter = platform_get_drvdata(dev);
+	int			rc;
+
+	rc = i2c_del_adapter(adapter);
+	/* We aren't that prepared to deal with this... */
+	if (rc)
+		printk(KERN_WARNING
+		       "i2c-powermac.c: Failed to remove bus %s !\n",
+		       adapter->name);
+	platform_set_drvdata(dev, NULL);
+	memset(adapter, 0, sizeof(*adapter));
+
+	return 0;
+}
+
+
+static int __devinit i2c_powermac_probe(struct platform_device *dev)
+{
+	struct pmac_i2c_bus *bus = dev->dev.platform_data;
+	struct device_node *parent = NULL;
+	struct i2c_adapter *adapter;
+	const char *basename;
+	int rc;
+
+	if (bus == NULL)
+		return -EINVAL;
+	adapter = pmac_i2c_get_adapter(bus);
+
+	/* Ok, now we need to make up a name for the interface that will
+	 * match what we used to do in the past, that is basically the
+	 * controller's parent device node for keywest. PMU didn't have a
+	 * naming convention and SMU has a different one
+	 */
+	switch(pmac_i2c_get_type(bus)) {
+	case pmac_i2c_bus_keywest:
+		parent = of_get_parent(pmac_i2c_get_controller(bus));
+		if (parent == NULL)
+			return -EINVAL;
+		basename = parent->name;
+		break;
+	case pmac_i2c_bus_pmu:
+		basename = "pmu";
+		break;
+	case pmac_i2c_bus_smu:
+		/* This is not what we used to do but I'm fixing drivers at
+		 * the same time as this change
+		 */
+		basename = "smu";
+		break;
+	default:
+		return -EINVAL;
+	}
+	snprintf(adapter->name, sizeof(adapter->name), "%s %d", basename,
+		 pmac_i2c_get_channel(bus));
+	of_node_put(parent);
+
+	platform_set_drvdata(dev, adapter);
+	adapter->algo = &i2c_powermac_algorithm;
+	i2c_set_adapdata(adapter, bus);
+	adapter->dev.parent = &dev->dev;
+	rc = i2c_add_adapter(adapter);
+	if (rc) {
+		printk(KERN_ERR "i2c-powermac: Adapter %s registration "
+		       "failed\n", adapter->name);
+		memset(adapter, 0, sizeof(*adapter));
+	}
+
+	printk(KERN_INFO "PowerMac i2c bus %s registered\n", adapter->name);
+
+	if (!strncmp(basename, "uni-n", 5)) {
+		struct device_node *np;
+		const u32 *prop;
+		struct i2c_board_info info;
+
+		/* Instantiate I2C motion sensor if present */
+		np = of_find_node_by_name(NULL, "accelerometer");
+		if (np && of_device_is_compatible(np, "AAPL,accelerometer_1") &&
+		    (prop = of_get_property(np, "reg", NULL))) {
+			int i2c_bus;
+			const char *tmp_bus;
+
+			/* look for bus either using "reg" or by path */
+			tmp_bus = strstr(np->full_name, "/i2c-bus@");
+			if (tmp_bus)
+				i2c_bus = *(tmp_bus + 9) - '0';
+			else
+				i2c_bus = ((*prop) >> 8) & 0x0f;
+
+			if (pmac_i2c_get_channel(bus) == i2c_bus) {
+				memset(&info, 0, sizeof(struct i2c_board_info));
+				info.addr = ((*prop) & 0xff) >> 1;
+				strlcpy(info.type, "ams", I2C_NAME_SIZE);
+				i2c_new_device(adapter, &info);
+			}
+		}
+	}
+
+	return rc;
+}
+
+static struct platform_driver i2c_powermac_driver = {
+	.probe = i2c_powermac_probe,
+	.remove = __devexit_p(i2c_powermac_remove),
+	.driver = {
+		.name = "i2c-powermac",
+		.bus = &platform_bus_type,
+	},
+};
+
+module_platform_driver(i2c_powermac_driver);
+
+MODULE_ALIAS("platform:i2c-powermac");
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-puv3.c b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-puv3.c
new file mode 100644
index 0000000..93709fb
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-puv3.c
@@ -0,0 +1,294 @@
+/*
+ * I2C driver for PKUnity-v3 SoC
+ * Code specific to PKUnity SoC and UniCore ISA
+ *
+ *	Maintained by GUAN Xue-tao <gxt@mprc.pku.edu.cn>
+ *	Copyright (C) 2001-2010 Guan Xuetao
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <mach/hardware.h>
+
+/*
+ * Poll the i2c status register until the specified bit is set.
+ * Returns 0 if timed out (100 msec).
+ */
+static short poll_status(unsigned long bit)
+{
+	int loop_cntr = 1000;
+
+	if (bit & I2C_STATUS_TFNF) {
+		do {
+			udelay(10);
+		} while (!(readl(I2C_STATUS) & bit) && (--loop_cntr > 0));
+	} else {
+		/* RXRDY handler */
+		do {
+			if (readl(I2C_TAR) == I2C_TAR_EEPROM)
+				msleep(20);
+			else
+				udelay(10);
+		} while (!(readl(I2C_RXFLR) & 0xf) && (--loop_cntr > 0));
+	}
+
+	return (loop_cntr > 0);
+}
+
+static int xfer_read(struct i2c_adapter *adap, unsigned char *buf, int length)
+{
+	int i2c_reg = *buf;
+
+	/* Read data */
+	while (length--) {
+		if (!poll_status(I2C_STATUS_TFNF)) {
+			dev_dbg(&adap->dev, "Tx FIFO Not Full timeout\n");
+			return -ETIMEDOUT;
+		}
+
+		/* send addr */
+		writel(i2c_reg | I2C_DATACMD_WRITE, I2C_DATACMD);
+
+		/* get ready to next write */
+		i2c_reg++;
+
+		/* send read CMD */
+		writel(I2C_DATACMD_READ, I2C_DATACMD);
+
+		/* wait until the Rx FIFO have available */
+		if (!poll_status(I2C_STATUS_RFNE)) {
+			dev_dbg(&adap->dev, "RXRDY timeout\n");
+			return -ETIMEDOUT;
+		}
+
+		/* read the data to buf */
+		*buf = (readl(I2C_DATACMD) & I2C_DATACMD_DAT_MASK);
+		buf++;
+	}
+
+	return 0;
+}
+
+static int xfer_write(struct i2c_adapter *adap, unsigned char *buf, int length)
+{
+	int i2c_reg = *buf;
+
+	/* Do nothing but storing the reg_num to a static variable */
+	if (i2c_reg == -1) {
+		printk(KERN_WARNING "Error i2c reg\n");
+		return -ETIMEDOUT;
+	}
+
+	if (length == 1)
+		return 0;
+
+	buf++;
+	length--;
+	while (length--) {
+		/* send addr */
+		writel(i2c_reg | I2C_DATACMD_WRITE, I2C_DATACMD);
+
+		/* send write CMD */
+		writel(*buf | I2C_DATACMD_WRITE, I2C_DATACMD);
+
+		/* wait until the Rx FIFO have available */
+		msleep(20);
+
+		/* read the data to buf */
+		i2c_reg++;
+		buf++;
+	}
+
+	return 0;
+}
+
+/*
+ * Generic i2c master transfer entrypoint.
+ *
+ */
+static int puv3_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *pmsg,
+		int num)
+{
+	int i, ret;
+	unsigned char swap;
+
+	/* Disable i2c */
+	writel(I2C_ENABLE_DISABLE, I2C_ENABLE);
+
+	/* Set the work mode and speed*/
+	writel(I2C_CON_MASTER | I2C_CON_SPEED_STD | I2C_CON_SLAVEDISABLE, I2C_CON);
+
+	writel(pmsg->addr, I2C_TAR);
+
+	/* Enable i2c */
+	writel(I2C_ENABLE_ENABLE, I2C_ENABLE);
+
+	dev_dbg(&adap->dev, "puv3_i2c_xfer: processing %d messages:\n", num);
+
+	for (i = 0; i < num; i++) {
+		dev_dbg(&adap->dev, " #%d: %sing %d byte%s %s 0x%02x\n", i,
+			pmsg->flags & I2C_M_RD ? "read" : "writ",
+			pmsg->len, pmsg->len > 1 ? "s" : "",
+			pmsg->flags & I2C_M_RD ? "from" : "to",	pmsg->addr);
+
+		if (pmsg->len && pmsg->buf) {	/* sanity check */
+			if (pmsg->flags & I2C_M_RD)
+				ret = xfer_read(adap, pmsg->buf, pmsg->len);
+			else
+				ret = xfer_write(adap, pmsg->buf, pmsg->len);
+
+			if (ret)
+				return ret;
+
+		}
+		dev_dbg(&adap->dev, "transfer complete\n");
+		pmsg++;		/* next message */
+	}
+
+	/* XXX: fixup be16_to_cpu in bq27x00_battery.c */
+	if (pmsg->addr == I2C_TAR_PWIC) {
+		swap = pmsg->buf[0];
+		pmsg->buf[0] = pmsg->buf[1];
+		pmsg->buf[1] = swap;
+	}
+
+	return i;
+}
+
+/*
+ * Return list of supported functionality.
+ */
+static u32 puv3_i2c_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static struct i2c_algorithm puv3_i2c_algorithm = {
+	.master_xfer	= puv3_i2c_xfer,
+	.functionality	= puv3_i2c_func,
+};
+
+/*
+ * Main initialization routine.
+ */
+static int __devinit puv3_i2c_probe(struct platform_device *pdev)
+{
+	struct i2c_adapter *adapter;
+	struct resource *mem;
+	int rc;
+
+	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!mem)
+		return -ENODEV;
+
+	if (!request_mem_region(mem->start, resource_size(mem), "puv3_i2c"))
+		return -EBUSY;
+
+	adapter = kzalloc(sizeof(struct i2c_adapter), GFP_KERNEL);
+	if (adapter == NULL) {
+		dev_err(&pdev->dev, "can't allocate inteface!\n");
+		rc = -ENOMEM;
+		goto fail_nomem;
+	}
+	snprintf(adapter->name, sizeof(adapter->name), "PUV3-I2C at 0x%08x",
+			mem->start);
+	adapter->algo = &puv3_i2c_algorithm;
+	adapter->class = I2C_CLASS_HWMON;
+	adapter->dev.parent = &pdev->dev;
+
+	platform_set_drvdata(pdev, adapter);
+
+	adapter->nr = pdev->id;
+	rc = i2c_add_numbered_adapter(adapter);
+	if (rc) {
+		dev_err(&pdev->dev, "Adapter '%s' registration failed\n",
+				adapter->name);
+		goto fail_add_adapter;
+	}
+
+	dev_info(&pdev->dev, "PKUnity v3 i2c bus adapter.\n");
+	return 0;
+
+fail_add_adapter:
+	platform_set_drvdata(pdev, NULL);
+	kfree(adapter);
+fail_nomem:
+	release_mem_region(mem->start, resource_size(mem));
+
+	return rc;
+}
+
+static int __devexit puv3_i2c_remove(struct platform_device *pdev)
+{
+	struct i2c_adapter *adapter = platform_get_drvdata(pdev);
+	struct resource *mem;
+	int rc;
+
+	rc = i2c_del_adapter(adapter);
+	if (rc) {
+		dev_err(&pdev->dev, "Adapter '%s' delete fail\n",
+				adapter->name);
+		return rc;
+	}
+
+	put_device(&pdev->dev);
+	platform_set_drvdata(pdev, NULL);
+
+	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	release_mem_region(mem->start, resource_size(mem));
+
+	return rc;
+}
+
+#ifdef CONFIG_PM
+static int puv3_i2c_suspend(struct platform_device *dev, pm_message_t state)
+{
+	int poll_count;
+	/* Disable the IIC */
+	writel(I2C_ENABLE_DISABLE, I2C_ENABLE);
+	for (poll_count = 0; poll_count < 50; poll_count++) {
+		if (readl(I2C_ENSTATUS) & I2C_ENSTATUS_ENABLE)
+			udelay(25);
+	}
+
+	return 0;
+}
+
+static int puv3_i2c_resume(struct platform_device *dev)
+{
+	return 0 ;
+}
+#else
+#define puv3_i2c_suspend NULL
+#define puv3_i2c_resume NULL
+#endif
+
+static struct platform_driver puv3_i2c_driver = {
+	.probe		= puv3_i2c_probe,
+	.remove		= __devexit_p(puv3_i2c_remove),
+	.suspend	= puv3_i2c_suspend,
+	.resume		= puv3_i2c_resume,
+	.driver		= {
+		.name	= "PKUnity-v3-I2C",
+		.owner	= THIS_MODULE,
+	}
+};
+
+module_platform_driver(puv3_i2c_driver);
+
+MODULE_DESCRIPTION("PKUnity v3 I2C driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:puv3_i2c");
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-pxa-pci.c b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-pxa-pci.c
new file mode 100644
index 0000000..a058179
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-pxa-pci.c
@@ -0,0 +1,180 @@
+/*
+ * The CE4100's I2C device is more or less the same one as found on PXA.
+ * It does not support slave mode, the register slightly moved. This PCI
+ * device provides three bars, every contains a single I2C controller.
+ */
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/i2c/pxa-i2c.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_address.h>
+
+#define CE4100_PCI_I2C_DEVS	3
+
+struct ce4100_devices {
+	struct platform_device *pdev[CE4100_PCI_I2C_DEVS];
+};
+
+static struct platform_device *add_i2c_device(struct pci_dev *dev, int bar)
+{
+	struct platform_device *pdev;
+	struct i2c_pxa_platform_data pdata;
+	struct resource res[2];
+	struct device_node *child;
+	static int devnum;
+	int ret;
+
+	memset(&pdata, 0, sizeof(struct i2c_pxa_platform_data));
+	memset(&res, 0, sizeof(res));
+
+	res[0].flags = IORESOURCE_MEM;
+	res[0].start = pci_resource_start(dev, bar);
+	res[0].end = pci_resource_end(dev, bar);
+
+	res[1].flags = IORESOURCE_IRQ;
+	res[1].start = dev->irq;
+	res[1].end = dev->irq;
+
+	for_each_child_of_node(dev->dev.of_node, child) {
+		const void *prop;
+		struct resource r;
+		int ret;
+
+		ret = of_address_to_resource(child, 0, &r);
+		if (ret < 0)
+			continue;
+		if (r.start != res[0].start)
+			continue;
+		if (r.end != res[0].end)
+			continue;
+		if (r.flags != res[0].flags)
+			continue;
+
+		prop = of_get_property(child, "fast-mode", NULL);
+		if (prop)
+			pdata.fast_mode = 1;
+
+		break;
+	}
+
+	if (!child) {
+		dev_err(&dev->dev, "failed to match a DT node for bar %d.\n",
+				bar);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	pdev = platform_device_alloc("ce4100-i2c", devnum);
+	if (!pdev) {
+		of_node_put(child);
+		ret = -ENOMEM;
+		goto out;
+	}
+	pdev->dev.parent = &dev->dev;
+	pdev->dev.of_node = child;
+
+	ret = platform_device_add_resources(pdev, res, ARRAY_SIZE(res));
+	if (ret)
+		goto err;
+
+	ret = platform_device_add_data(pdev, &pdata, sizeof(pdata));
+	if (ret)
+		goto err;
+
+	ret = platform_device_add(pdev);
+	if (ret)
+		goto err;
+	devnum++;
+	return pdev;
+err:
+	platform_device_put(pdev);
+out:
+	return ERR_PTR(ret);
+}
+
+static int __devinit ce4100_i2c_probe(struct pci_dev *dev,
+		const struct pci_device_id *ent)
+{
+	int ret;
+	int i;
+	struct ce4100_devices *sds;
+
+	ret = pci_enable_device_mem(dev);
+	if (ret)
+		return ret;
+
+	if (!dev->dev.of_node) {
+		dev_err(&dev->dev, "Missing device tree node.\n");
+		return -EINVAL;
+	}
+	sds = kzalloc(sizeof(*sds), GFP_KERNEL);
+	if (!sds) {
+		ret = -ENOMEM;
+		goto err_mem;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(sds->pdev); i++) {
+		sds->pdev[i] = add_i2c_device(dev, i);
+		if (IS_ERR(sds->pdev[i])) {
+			ret = PTR_ERR(sds->pdev[i]);
+			while (--i >= 0)
+				platform_device_unregister(sds->pdev[i]);
+			goto err_dev_add;
+		}
+	}
+	pci_set_drvdata(dev, sds);
+	return 0;
+
+err_dev_add:
+	pci_set_drvdata(dev, NULL);
+	kfree(sds);
+err_mem:
+	pci_disable_device(dev);
+	return ret;
+}
+
+static void __devexit ce4100_i2c_remove(struct pci_dev *dev)
+{
+	struct ce4100_devices *sds;
+	unsigned int i;
+
+	sds = pci_get_drvdata(dev);
+	pci_set_drvdata(dev, NULL);
+
+	for (i = 0; i < ARRAY_SIZE(sds->pdev); i++)
+		platform_device_unregister(sds->pdev[i]);
+
+	pci_disable_device(dev);
+	kfree(sds);
+}
+
+static DEFINE_PCI_DEVICE_TABLE(ce4100_i2c_devices) = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2e68)},
+	{ },
+};
+MODULE_DEVICE_TABLE(pci, ce4100_i2c_devices);
+
+static struct pci_driver ce4100_i2c_driver = {
+	.name           = "ce4100_i2c",
+	.id_table       = ce4100_i2c_devices,
+	.probe          = ce4100_i2c_probe,
+	.remove         = __devexit_p(ce4100_i2c_remove),
+};
+
+static int __init ce4100_i2c_init(void)
+{
+	return pci_register_driver(&ce4100_i2c_driver);
+}
+module_init(ce4100_i2c_init);
+
+static void __exit ce4100_i2c_exit(void)
+{
+	pci_unregister_driver(&ce4100_i2c_driver);
+}
+module_exit(ce4100_i2c_exit);
+
+MODULE_DESCRIPTION("CE4100 PCI-I2C glue code for PXA's driver");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Sebastian Andrzej Siewior <bigeasy@linutronix.de>");
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-pxa.c b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-pxa.c
new file mode 100644
index 0000000..f673326
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-pxa.c
@@ -0,0 +1,1308 @@
+/*
+ *  i2c_adap_pxa.c
+ *
+ *  I2C adapter for the PXA I2C bus access.
+ *
+ *  Copyright (C) 2002 Intrinsyc Software Inc.
+ *  Copyright (C) 2004-2005 Deep Blue Solutions Ltd.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ *  History:
+ *    Apr 2002: Initial version [CS]
+ *    Jun 2002: Properly separated algo/adap [FB]
+ *    Jan 2003: Fixed several bugs concerning interrupt handling [Kai-Uwe Bloem]
+ *    Jan 2003: added limited signal handling [Kai-Uwe Bloem]
+ *    Sep 2004: Major rework to ensure efficient bus handling [RMK]
+ *    Dec 2004: Added support for PXA27x and slave device probing [Liam Girdwood]
+ *    Feb 2005: Rework slave mode handling [RMK]
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/time.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/i2c-pxa.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_i2c.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/i2c/pxa-i2c.h>
+
+#include <asm/irq.h>
+
+#ifndef CONFIG_HAVE_CLK
+#define clk_get(dev, id)	NULL
+#define clk_put(clk)		do { } while (0)
+#define clk_disable(clk)	do { } while (0)
+#define clk_enable(clk)		do { } while (0)
+#endif
+
+struct pxa_reg_layout {
+	u32 ibmr;
+	u32 idbr;
+	u32 icr;
+	u32 isr;
+	u32 isar;
+};
+
+enum pxa_i2c_types {
+	REGS_PXA2XX,
+	REGS_PXA3XX,
+	REGS_CE4100,
+};
+
+/*
+ * I2C registers definitions
+ */
+static struct pxa_reg_layout pxa_reg_layout[] = {
+	[REGS_PXA2XX] = {
+		.ibmr =	0x00,
+		.idbr =	0x08,
+		.icr =	0x10,
+		.isr =	0x18,
+		.isar =	0x20,
+	},
+	[REGS_PXA3XX] = {
+		.ibmr =	0x00,
+		.idbr =	0x04,
+		.icr =	0x08,
+		.isr =	0x0c,
+		.isar =	0x10,
+	},
+	[REGS_CE4100] = {
+		.ibmr =	0x14,
+		.idbr =	0x0c,
+		.icr =	0x00,
+		.isr =	0x04,
+		/* no isar register */
+	},
+};
+
+static const struct platform_device_id i2c_pxa_id_table[] = {
+	{ "pxa2xx-i2c",		REGS_PXA2XX },
+	{ "pxa3xx-pwri2c",	REGS_PXA3XX },
+	{ "ce4100-i2c",		REGS_CE4100 },
+	{ },
+};
+MODULE_DEVICE_TABLE(platform, i2c_pxa_id_table);
+
+/*
+ * I2C bit definitions
+ */
+
+#define ICR_START	(1 << 0)	   /* start bit */
+#define ICR_STOP	(1 << 1)	   /* stop bit */
+#define ICR_ACKNAK	(1 << 2)	   /* send ACK(0) or NAK(1) */
+#define ICR_TB		(1 << 3)	   /* transfer byte bit */
+#define ICR_MA		(1 << 4)	   /* master abort */
+#define ICR_SCLE	(1 << 5)	   /* master clock enable */
+#define ICR_IUE		(1 << 6)	   /* unit enable */
+#define ICR_GCD		(1 << 7)	   /* general call disable */
+#define ICR_ITEIE	(1 << 8)	   /* enable tx interrupts */
+#define ICR_IRFIE	(1 << 9)	   /* enable rx interrupts */
+#define ICR_BEIE	(1 << 10)	   /* enable bus error ints */
+#define ICR_SSDIE	(1 << 11)	   /* slave STOP detected int enable */
+#define ICR_ALDIE	(1 << 12)	   /* enable arbitration interrupt */
+#define ICR_SADIE	(1 << 13)	   /* slave address detected int enable */
+#define ICR_UR		(1 << 14)	   /* unit reset */
+#define ICR_FM		(1 << 15)	   /* fast mode */
+
+#define ISR_RWM		(1 << 0)	   /* read/write mode */
+#define ISR_ACKNAK	(1 << 1)	   /* ack/nak status */
+#define ISR_UB		(1 << 2)	   /* unit busy */
+#define ISR_IBB		(1 << 3)	   /* bus busy */
+#define ISR_SSD		(1 << 4)	   /* slave stop detected */
+#define ISR_ALD		(1 << 5)	   /* arbitration loss detected */
+#define ISR_ITE		(1 << 6)	   /* tx buffer empty */
+#define ISR_IRF		(1 << 7)	   /* rx buffer full */
+#define ISR_GCAD	(1 << 8)	   /* general call address detected */
+#define ISR_SAD		(1 << 9)	   /* slave address detected */
+#define ISR_BED		(1 << 10)	   /* bus error no ACK/NAK */
+
+struct pxa_i2c {
+	spinlock_t		lock;
+	wait_queue_head_t	wait;
+	struct i2c_msg		*msg;
+	unsigned int		msg_num;
+	unsigned int		msg_idx;
+	unsigned int		msg_ptr;
+	unsigned int		slave_addr;
+
+	struct i2c_adapter	adap;
+	struct clk		*clk;
+#ifdef CONFIG_I2C_PXA_SLAVE
+	struct i2c_slave_client *slave;
+#endif
+
+	unsigned int		irqlogidx;
+	u32			isrlog[32];
+	u32			icrlog[32];
+
+	void __iomem		*reg_base;
+	void __iomem		*reg_ibmr;
+	void __iomem		*reg_idbr;
+	void __iomem		*reg_icr;
+	void __iomem		*reg_isr;
+	void __iomem		*reg_isar;
+
+	unsigned long		iobase;
+	unsigned long		iosize;
+
+	int			irq;
+	unsigned int		use_pio :1;
+	unsigned int		fast_mode :1;
+};
+
+#define _IBMR(i2c)	((i2c)->reg_ibmr)
+#define _IDBR(i2c)	((i2c)->reg_idbr)
+#define _ICR(i2c)	((i2c)->reg_icr)
+#define _ISR(i2c)	((i2c)->reg_isr)
+#define _ISAR(i2c)	((i2c)->reg_isar)
+
+/*
+ * I2C Slave mode address
+ */
+#define I2C_PXA_SLAVE_ADDR      0x1
+
+#ifdef DEBUG
+
+struct bits {
+	u32	mask;
+	const char *set;
+	const char *unset;
+};
+#define PXA_BIT(m, s, u)	{ .mask = m, .set = s, .unset = u }
+
+static inline void
+decode_bits(const char *prefix, const struct bits *bits, int num, u32 val)
+{
+	printk("%s %08x: ", prefix, val);
+	while (num--) {
+		const char *str = val & bits->mask ? bits->set : bits->unset;
+		if (str)
+			printk("%s ", str);
+		bits++;
+	}
+}
+
+static const struct bits isr_bits[] = {
+	PXA_BIT(ISR_RWM,	"RX",		"TX"),
+	PXA_BIT(ISR_ACKNAK,	"NAK",		"ACK"),
+	PXA_BIT(ISR_UB,		"Bsy",		"Rdy"),
+	PXA_BIT(ISR_IBB,	"BusBsy",	"BusRdy"),
+	PXA_BIT(ISR_SSD,	"SlaveStop",	NULL),
+	PXA_BIT(ISR_ALD,	"ALD",		NULL),
+	PXA_BIT(ISR_ITE,	"TxEmpty",	NULL),
+	PXA_BIT(ISR_IRF,	"RxFull",	NULL),
+	PXA_BIT(ISR_GCAD,	"GenCall",	NULL),
+	PXA_BIT(ISR_SAD,	"SlaveAddr",	NULL),
+	PXA_BIT(ISR_BED,	"BusErr",	NULL),
+};
+
+static void decode_ISR(unsigned int val)
+{
+	decode_bits(KERN_DEBUG "ISR", isr_bits, ARRAY_SIZE(isr_bits), val);
+	printk("\n");
+}
+
+static const struct bits icr_bits[] = {
+	PXA_BIT(ICR_START,  "START",	NULL),
+	PXA_BIT(ICR_STOP,   "STOP",	NULL),
+	PXA_BIT(ICR_ACKNAK, "ACKNAK",	NULL),
+	PXA_BIT(ICR_TB,     "TB",	NULL),
+	PXA_BIT(ICR_MA,     "MA",	NULL),
+	PXA_BIT(ICR_SCLE,   "SCLE",	"scle"),
+	PXA_BIT(ICR_IUE,    "IUE",	"iue"),
+	PXA_BIT(ICR_GCD,    "GCD",	NULL),
+	PXA_BIT(ICR_ITEIE,  "ITEIE",	NULL),
+	PXA_BIT(ICR_IRFIE,  "IRFIE",	NULL),
+	PXA_BIT(ICR_BEIE,   "BEIE",	NULL),
+	PXA_BIT(ICR_SSDIE,  "SSDIE",	NULL),
+	PXA_BIT(ICR_ALDIE,  "ALDIE",	NULL),
+	PXA_BIT(ICR_SADIE,  "SADIE",	NULL),
+	PXA_BIT(ICR_UR,     "UR",		"ur"),
+};
+
+#ifdef CONFIG_I2C_PXA_SLAVE
+static void decode_ICR(unsigned int val)
+{
+	decode_bits(KERN_DEBUG "ICR", icr_bits, ARRAY_SIZE(icr_bits), val);
+	printk("\n");
+}
+#endif
+
+static unsigned int i2c_debug = DEBUG;
+
+static void i2c_pxa_show_state(struct pxa_i2c *i2c, int lno, const char *fname)
+{
+	dev_dbg(&i2c->adap.dev, "state:%s:%d: ISR=%08x, ICR=%08x, IBMR=%02x\n", fname, lno,
+		readl(_ISR(i2c)), readl(_ICR(i2c)), readl(_IBMR(i2c)));
+}
+
+#define show_state(i2c) i2c_pxa_show_state(i2c, __LINE__, __func__)
+
+static void i2c_pxa_scream_blue_murder(struct pxa_i2c *i2c, const char *why)
+{
+	unsigned int i;
+	printk(KERN_ERR "i2c: error: %s\n", why);
+	printk(KERN_ERR "i2c: msg_num: %d msg_idx: %d msg_ptr: %d\n",
+		i2c->msg_num, i2c->msg_idx, i2c->msg_ptr);
+	printk(KERN_ERR "i2c: ICR: %08x ISR: %08x\n",
+	       readl(_ICR(i2c)), readl(_ISR(i2c)));
+	printk(KERN_DEBUG "i2c: log: ");
+	for (i = 0; i < i2c->irqlogidx; i++)
+		printk("[%08x:%08x] ", i2c->isrlog[i], i2c->icrlog[i]);
+	printk("\n");
+}
+
+#else /* ifdef DEBUG */
+
+#define i2c_debug	0
+
+#define show_state(i2c) do { } while (0)
+#define decode_ISR(val) do { } while (0)
+#define decode_ICR(val) do { } while (0)
+#define i2c_pxa_scream_blue_murder(i2c, why) do { } while (0)
+
+#endif /* ifdef DEBUG / else */
+
+static void i2c_pxa_master_complete(struct pxa_i2c *i2c, int ret);
+static irqreturn_t i2c_pxa_handler(int this_irq, void *dev_id);
+
+static inline int i2c_pxa_is_slavemode(struct pxa_i2c *i2c)
+{
+	return !(readl(_ICR(i2c)) & ICR_SCLE);
+}
+
+static void i2c_pxa_abort(struct pxa_i2c *i2c)
+{
+	int i = 250;
+
+	if (i2c_pxa_is_slavemode(i2c)) {
+		dev_dbg(&i2c->adap.dev, "%s: called in slave mode\n", __func__);
+		return;
+	}
+
+	while ((i > 0) && (readl(_IBMR(i2c)) & 0x1) == 0) {
+		unsigned long icr = readl(_ICR(i2c));
+
+		icr &= ~ICR_START;
+		icr |= ICR_ACKNAK | ICR_STOP | ICR_TB;
+
+		writel(icr, _ICR(i2c));
+
+		show_state(i2c);
+
+		mdelay(1);
+		i --;
+	}
+
+	writel(readl(_ICR(i2c)) & ~(ICR_MA | ICR_START | ICR_STOP),
+	       _ICR(i2c));
+}
+
+static int i2c_pxa_wait_bus_not_busy(struct pxa_i2c *i2c)
+{
+	int timeout = DEF_TIMEOUT;
+
+	while (timeout-- && readl(_ISR(i2c)) & (ISR_IBB | ISR_UB)) {
+		if ((readl(_ISR(i2c)) & ISR_SAD) != 0)
+			timeout += 4;
+
+		msleep(2);
+		show_state(i2c);
+	}
+
+	if (timeout < 0)
+		show_state(i2c);
+
+	return timeout < 0 ? I2C_RETRY : 0;
+}
+
+static int i2c_pxa_wait_master(struct pxa_i2c *i2c)
+{
+	unsigned long timeout = jiffies + HZ*4;
+
+	while (time_before(jiffies, timeout)) {
+		if (i2c_debug > 1)
+			dev_dbg(&i2c->adap.dev, "%s: %ld: ISR=%08x, ICR=%08x, IBMR=%02x\n",
+				__func__, (long)jiffies, readl(_ISR(i2c)), readl(_ICR(i2c)), readl(_IBMR(i2c)));
+
+		if (readl(_ISR(i2c)) & ISR_SAD) {
+			if (i2c_debug > 0)
+				dev_dbg(&i2c->adap.dev, "%s: Slave detected\n", __func__);
+			goto out;
+		}
+
+		/* wait for unit and bus being not busy, and we also do a
+		 * quick check of the i2c lines themselves to ensure they've
+		 * gone high...
+		 */
+		if ((readl(_ISR(i2c)) & (ISR_UB | ISR_IBB)) == 0 && readl(_IBMR(i2c)) == 3) {
+			if (i2c_debug > 0)
+				dev_dbg(&i2c->adap.dev, "%s: done\n", __func__);
+			return 1;
+		}
+
+		msleep(1);
+	}
+
+	if (i2c_debug > 0)
+		dev_dbg(&i2c->adap.dev, "%s: did not free\n", __func__);
+ out:
+	return 0;
+}
+
+static int i2c_pxa_set_master(struct pxa_i2c *i2c)
+{
+	if (i2c_debug)
+		dev_dbg(&i2c->adap.dev, "setting to bus master\n");
+
+	if ((readl(_ISR(i2c)) & (ISR_UB | ISR_IBB)) != 0) {
+		dev_dbg(&i2c->adap.dev, "%s: unit is busy\n", __func__);
+		if (!i2c_pxa_wait_master(i2c)) {
+			dev_dbg(&i2c->adap.dev, "%s: error: unit busy\n", __func__);
+			return I2C_RETRY;
+		}
+	}
+
+	writel(readl(_ICR(i2c)) | ICR_SCLE, _ICR(i2c));
+	return 0;
+}
+
+#ifdef CONFIG_I2C_PXA_SLAVE
+static int i2c_pxa_wait_slave(struct pxa_i2c *i2c)
+{
+	unsigned long timeout = jiffies + HZ*1;
+
+	/* wait for stop */
+
+	show_state(i2c);
+
+	while (time_before(jiffies, timeout)) {
+		if (i2c_debug > 1)
+			dev_dbg(&i2c->adap.dev, "%s: %ld: ISR=%08x, ICR=%08x, IBMR=%02x\n",
+				__func__, (long)jiffies, readl(_ISR(i2c)), readl(_ICR(i2c)), readl(_IBMR(i2c)));
+
+		if ((readl(_ISR(i2c)) & (ISR_UB|ISR_IBB)) == 0 ||
+		    (readl(_ISR(i2c)) & ISR_SAD) != 0 ||
+		    (readl(_ICR(i2c)) & ICR_SCLE) == 0) {
+			if (i2c_debug > 1)
+				dev_dbg(&i2c->adap.dev, "%s: done\n", __func__);
+			return 1;
+		}
+
+		msleep(1);
+	}
+
+	if (i2c_debug > 0)
+		dev_dbg(&i2c->adap.dev, "%s: did not free\n", __func__);
+	return 0;
+}
+
+/*
+ * clear the hold on the bus, and take of anything else
+ * that has been configured
+ */
+static void i2c_pxa_set_slave(struct pxa_i2c *i2c, int errcode)
+{
+	show_state(i2c);
+
+	if (errcode < 0) {
+		udelay(100);   /* simple delay */
+	} else {
+		/* we need to wait for the stop condition to end */
+
+		/* if we where in stop, then clear... */
+		if (readl(_ICR(i2c)) & ICR_STOP) {
+			udelay(100);
+			writel(readl(_ICR(i2c)) & ~ICR_STOP, _ICR(i2c));
+		}
+
+		if (!i2c_pxa_wait_slave(i2c)) {
+			dev_err(&i2c->adap.dev, "%s: wait timedout\n",
+				__func__);
+			return;
+		}
+	}
+
+	writel(readl(_ICR(i2c)) & ~(ICR_STOP|ICR_ACKNAK|ICR_MA), _ICR(i2c));
+	writel(readl(_ICR(i2c)) & ~ICR_SCLE, _ICR(i2c));
+
+	if (i2c_debug) {
+		dev_dbg(&i2c->adap.dev, "ICR now %08x, ISR %08x\n", readl(_ICR(i2c)), readl(_ISR(i2c)));
+		decode_ICR(readl(_ICR(i2c)));
+	}
+}
+#else
+#define i2c_pxa_set_slave(i2c, err)	do { } while (0)
+#endif
+
+static void i2c_pxa_reset(struct pxa_i2c *i2c)
+{
+	pr_debug("Resetting I2C Controller Unit\n");
+
+	/* abort any transfer currently under way */
+	i2c_pxa_abort(i2c);
+
+	/* reset according to 9.8 */
+	writel(ICR_UR, _ICR(i2c));
+	writel(I2C_ISR_INIT, _ISR(i2c));
+	writel(readl(_ICR(i2c)) & ~ICR_UR, _ICR(i2c));
+
+	if (i2c->reg_isar)
+		writel(i2c->slave_addr, _ISAR(i2c));
+
+	/* set control register values */
+	writel(I2C_ICR_INIT | (i2c->fast_mode ? ICR_FM : 0), _ICR(i2c));
+
+#ifdef CONFIG_I2C_PXA_SLAVE
+	dev_info(&i2c->adap.dev, "Enabling slave mode\n");
+	writel(readl(_ICR(i2c)) | ICR_SADIE | ICR_ALDIE | ICR_SSDIE, _ICR(i2c));
+#endif
+
+	i2c_pxa_set_slave(i2c, 0);
+
+	/* enable unit */
+	writel(readl(_ICR(i2c)) | ICR_IUE, _ICR(i2c));
+	udelay(100);
+}
+
+
+#ifdef CONFIG_I2C_PXA_SLAVE
+/*
+ * PXA I2C Slave mode
+ */
+
+static void i2c_pxa_slave_txempty(struct pxa_i2c *i2c, u32 isr)
+{
+	if (isr & ISR_BED) {
+		/* what should we do here? */
+	} else {
+		int ret = 0;
+
+		if (i2c->slave != NULL)
+			ret = i2c->slave->read(i2c->slave->data);
+
+		writel(ret, _IDBR(i2c));
+		writel(readl(_ICR(i2c)) | ICR_TB, _ICR(i2c));   /* allow next byte */
+	}
+}
+
+static void i2c_pxa_slave_rxfull(struct pxa_i2c *i2c, u32 isr)
+{
+	unsigned int byte = readl(_IDBR(i2c));
+
+	if (i2c->slave != NULL)
+		i2c->slave->write(i2c->slave->data, byte);
+
+	writel(readl(_ICR(i2c)) | ICR_TB, _ICR(i2c));
+}
+
+static void i2c_pxa_slave_start(struct pxa_i2c *i2c, u32 isr)
+{
+	int timeout;
+
+	if (i2c_debug > 0)
+		dev_dbg(&i2c->adap.dev, "SAD, mode is slave-%cx\n",
+		       (isr & ISR_RWM) ? 'r' : 't');
+
+	if (i2c->slave != NULL)
+		i2c->slave->event(i2c->slave->data,
+				 (isr & ISR_RWM) ? I2C_SLAVE_EVENT_START_READ : I2C_SLAVE_EVENT_START_WRITE);
+
+	/*
+	 * slave could interrupt in the middle of us generating a
+	 * start condition... if this happens, we'd better back off
+	 * and stop holding the poor thing up
+	 */
+	writel(readl(_ICR(i2c)) & ~(ICR_START|ICR_STOP), _ICR(i2c));
+	writel(readl(_ICR(i2c)) | ICR_TB, _ICR(i2c));
+
+	timeout = 0x10000;
+
+	while (1) {
+		if ((readl(_IBMR(i2c)) & 2) == 2)
+			break;
+
+		timeout--;
+
+		if (timeout <= 0) {
+			dev_err(&i2c->adap.dev, "timeout waiting for SCL high\n");
+			break;
+		}
+	}
+
+	writel(readl(_ICR(i2c)) & ~ICR_SCLE, _ICR(i2c));
+}
+
+static void i2c_pxa_slave_stop(struct pxa_i2c *i2c)
+{
+	if (i2c_debug > 2)
+		dev_dbg(&i2c->adap.dev, "ISR: SSD (Slave Stop)\n");
+
+	if (i2c->slave != NULL)
+		i2c->slave->event(i2c->slave->data, I2C_SLAVE_EVENT_STOP);
+
+	if (i2c_debug > 2)
+		dev_dbg(&i2c->adap.dev, "ISR: SSD (Slave Stop) acked\n");
+
+	/*
+	 * If we have a master-mode message waiting,
+	 * kick it off now that the slave has completed.
+	 */
+	if (i2c->msg)
+		i2c_pxa_master_complete(i2c, I2C_RETRY);
+}
+#else
+static void i2c_pxa_slave_txempty(struct pxa_i2c *i2c, u32 isr)
+{
+	if (isr & ISR_BED) {
+		/* what should we do here? */
+	} else {
+		writel(0, _IDBR(i2c));
+		writel(readl(_ICR(i2c)) | ICR_TB, _ICR(i2c));
+	}
+}
+
+static void i2c_pxa_slave_rxfull(struct pxa_i2c *i2c, u32 isr)
+{
+	writel(readl(_ICR(i2c)) | ICR_TB | ICR_ACKNAK, _ICR(i2c));
+}
+
+static void i2c_pxa_slave_start(struct pxa_i2c *i2c, u32 isr)
+{
+	int timeout;
+
+	/*
+	 * slave could interrupt in the middle of us generating a
+	 * start condition... if this happens, we'd better back off
+	 * and stop holding the poor thing up
+	 */
+	writel(readl(_ICR(i2c)) & ~(ICR_START|ICR_STOP), _ICR(i2c));
+	writel(readl(_ICR(i2c)) | ICR_TB | ICR_ACKNAK, _ICR(i2c));
+
+	timeout = 0x10000;
+
+	while (1) {
+		if ((readl(_IBMR(i2c)) & 2) == 2)
+			break;
+
+		timeout--;
+
+		if (timeout <= 0) {
+			dev_err(&i2c->adap.dev, "timeout waiting for SCL high\n");
+			break;
+		}
+	}
+
+	writel(readl(_ICR(i2c)) & ~ICR_SCLE, _ICR(i2c));
+}
+
+static void i2c_pxa_slave_stop(struct pxa_i2c *i2c)
+{
+	if (i2c->msg)
+		i2c_pxa_master_complete(i2c, I2C_RETRY);
+}
+#endif
+
+/*
+ * PXA I2C Master mode
+ */
+
+static inline unsigned int i2c_pxa_addr_byte(struct i2c_msg *msg)
+{
+	unsigned int addr = (msg->addr & 0x7f) << 1;
+
+	if (msg->flags & I2C_M_RD)
+		addr |= 1;
+
+	return addr;
+}
+
+static inline void i2c_pxa_start_message(struct pxa_i2c *i2c)
+{
+	u32 icr;
+
+	/*
+	 * Step 1: target slave address into IDBR
+	 */
+	writel(i2c_pxa_addr_byte(i2c->msg), _IDBR(i2c));
+
+	/*
+	 * Step 2: initiate the write.
+	 */
+	icr = readl(_ICR(i2c)) & ~(ICR_STOP | ICR_ALDIE);
+	writel(icr | ICR_START | ICR_TB, _ICR(i2c));
+}
+
+static inline void i2c_pxa_stop_message(struct pxa_i2c *i2c)
+{
+	u32 icr;
+
+	/*
+	 * Clear the STOP and ACK flags
+	 */
+	icr = readl(_ICR(i2c));
+	icr &= ~(ICR_STOP | ICR_ACKNAK);
+	writel(icr, _ICR(i2c));
+}
+
+static int i2c_pxa_pio_set_master(struct pxa_i2c *i2c)
+{
+	/* make timeout the same as for interrupt based functions */
+	long timeout = 2 * DEF_TIMEOUT;
+
+	/*
+	 * Wait for the bus to become free.
+	 */
+	while (timeout-- && readl(_ISR(i2c)) & (ISR_IBB | ISR_UB)) {
+		udelay(1000);
+		show_state(i2c);
+	}
+
+	if (timeout < 0) {
+		show_state(i2c);
+		dev_err(&i2c->adap.dev,
+			"i2c_pxa: timeout waiting for bus free\n");
+		return I2C_RETRY;
+	}
+
+	/*
+	 * Set master mode.
+	 */
+	writel(readl(_ICR(i2c)) | ICR_SCLE, _ICR(i2c));
+
+	return 0;
+}
+
+static int i2c_pxa_do_pio_xfer(struct pxa_i2c *i2c,
+			       struct i2c_msg *msg, int num)
+{
+	unsigned long timeout = 500000; /* 5 seconds */
+	int ret = 0;
+
+	ret = i2c_pxa_pio_set_master(i2c);
+	if (ret)
+		goto out;
+
+	i2c->msg = msg;
+	i2c->msg_num = num;
+	i2c->msg_idx = 0;
+	i2c->msg_ptr = 0;
+	i2c->irqlogidx = 0;
+
+	i2c_pxa_start_message(i2c);
+
+	while (i2c->msg_num > 0 && --timeout) {
+		i2c_pxa_handler(0, i2c);
+		udelay(10);
+	}
+
+	i2c_pxa_stop_message(i2c);
+
+	/*
+	 * We place the return code in i2c->msg_idx.
+	 */
+	ret = i2c->msg_idx;
+
+out:
+	if (timeout == 0)
+		i2c_pxa_scream_blue_murder(i2c, "timeout");
+
+	return ret;
+}
+
+/*
+ * We are protected by the adapter bus mutex.
+ */
+static int i2c_pxa_do_xfer(struct pxa_i2c *i2c, struct i2c_msg *msg, int num)
+{
+	long timeout;
+	int ret;
+
+	/*
+	 * Wait for the bus to become free.
+	 */
+	ret = i2c_pxa_wait_bus_not_busy(i2c);
+	if (ret) {
+		dev_err(&i2c->adap.dev, "i2c_pxa: timeout waiting for bus free\n");
+		goto out;
+	}
+
+	/*
+	 * Set master mode.
+	 */
+	ret = i2c_pxa_set_master(i2c);
+	if (ret) {
+		dev_err(&i2c->adap.dev, "i2c_pxa_set_master: error %d\n", ret);
+		goto out;
+	}
+
+	spin_lock_irq(&i2c->lock);
+
+	i2c->msg = msg;
+	i2c->msg_num = num;
+	i2c->msg_idx = 0;
+	i2c->msg_ptr = 0;
+	i2c->irqlogidx = 0;
+
+	i2c_pxa_start_message(i2c);
+
+	spin_unlock_irq(&i2c->lock);
+
+	/*
+	 * The rest of the processing occurs in the interrupt handler.
+	 */
+	timeout = wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5);
+	i2c_pxa_stop_message(i2c);
+
+	/*
+	 * We place the return code in i2c->msg_idx.
+	 */
+	ret = i2c->msg_idx;
+
+	if (!timeout && i2c->msg_num) {
+		i2c_pxa_scream_blue_murder(i2c, "timeout");
+		ret = I2C_RETRY;
+	}
+
+ out:
+	return ret;
+}
+
+static int i2c_pxa_pio_xfer(struct i2c_adapter *adap,
+			    struct i2c_msg msgs[], int num)
+{
+	struct pxa_i2c *i2c = adap->algo_data;
+	int ret, i;
+
+	/* If the I2C controller is disabled we need to reset it
+	  (probably due to a suspend/resume destroying state). We do
+	  this here as we can then avoid worrying about resuming the
+	  controller before its users. */
+	if (!(readl(_ICR(i2c)) & ICR_IUE))
+		i2c_pxa_reset(i2c);
+
+	for (i = adap->retries; i >= 0; i--) {
+		ret = i2c_pxa_do_pio_xfer(i2c, msgs, num);
+		if (ret != I2C_RETRY)
+			goto out;
+
+		if (i2c_debug)
+			dev_dbg(&adap->dev, "Retrying transmission\n");
+		udelay(100);
+	}
+	i2c_pxa_scream_blue_murder(i2c, "exhausted retries");
+	ret = -EREMOTEIO;
+ out:
+	i2c_pxa_set_slave(i2c, ret);
+	return ret;
+}
+
+/*
+ * i2c_pxa_master_complete - complete the message and wake up.
+ */
+static void i2c_pxa_master_complete(struct pxa_i2c *i2c, int ret)
+{
+	i2c->msg_ptr = 0;
+	i2c->msg = NULL;
+	i2c->msg_idx ++;
+	i2c->msg_num = 0;
+	if (ret)
+		i2c->msg_idx = ret;
+	if (!i2c->use_pio)
+		wake_up(&i2c->wait);
+}
+
+static void i2c_pxa_irq_txempty(struct pxa_i2c *i2c, u32 isr)
+{
+	u32 icr = readl(_ICR(i2c)) & ~(ICR_START|ICR_STOP|ICR_ACKNAK|ICR_TB);
+
+ again:
+	/*
+	 * If ISR_ALD is set, we lost arbitration.
+	 */
+	if (isr & ISR_ALD) {
+		/*
+		 * Do we need to do anything here?  The PXA docs
+		 * are vague about what happens.
+		 */
+		i2c_pxa_scream_blue_murder(i2c, "ALD set");
+
+		/*
+		 * We ignore this error.  We seem to see spurious ALDs
+		 * for seemingly no reason.  If we handle them as I think
+		 * they should, we end up causing an I2C error, which
+		 * is painful for some systems.
+		 */
+		return; /* ignore */
+	}
+
+	if (isr & ISR_BED) {
+		int ret = BUS_ERROR;
+
+		/*
+		 * I2C bus error - either the device NAK'd us, or
+		 * something more serious happened.  If we were NAK'd
+		 * on the initial address phase, we can retry.
+		 */
+		if (isr & ISR_ACKNAK) {
+			if (i2c->msg_ptr == 0 && i2c->msg_idx == 0)
+				ret = I2C_RETRY;
+			else
+				ret = XFER_NAKED;
+		}
+		i2c_pxa_master_complete(i2c, ret);
+	} else if (isr & ISR_RWM) {
+		/*
+		 * Read mode.  We have just sent the address byte, and
+		 * now we must initiate the transfer.
+		 */
+		if (i2c->msg_ptr == i2c->msg->len - 1 &&
+		    i2c->msg_idx == i2c->msg_num - 1)
+			icr |= ICR_STOP | ICR_ACKNAK;
+
+		icr |= ICR_ALDIE | ICR_TB;
+	} else if (i2c->msg_ptr < i2c->msg->len) {
+		/*
+		 * Write mode.  Write the next data byte.
+		 */
+		writel(i2c->msg->buf[i2c->msg_ptr++], _IDBR(i2c));
+
+		icr |= ICR_ALDIE | ICR_TB;
+
+		/*
+		 * If this is the last byte of the last message, send
+		 * a STOP.
+		 */
+		if (i2c->msg_ptr == i2c->msg->len &&
+		    i2c->msg_idx == i2c->msg_num - 1)
+			icr |= ICR_STOP;
+	} else if (i2c->msg_idx < i2c->msg_num - 1) {
+		/*
+		 * Next segment of the message.
+		 */
+		i2c->msg_ptr = 0;
+		i2c->msg_idx ++;
+		i2c->msg++;
+
+		/*
+		 * If we aren't doing a repeated start and address,
+		 * go back and try to send the next byte.  Note that
+		 * we do not support switching the R/W direction here.
+		 */
+		if (i2c->msg->flags & I2C_M_NOSTART)
+			goto again;
+
+		/*
+		 * Write the next address.
+		 */
+		writel(i2c_pxa_addr_byte(i2c->msg), _IDBR(i2c));
+
+		/*
+		 * And trigger a repeated start, and send the byte.
+		 */
+		icr &= ~ICR_ALDIE;
+		icr |= ICR_START | ICR_TB;
+	} else {
+		if (i2c->msg->len == 0) {
+			/*
+			 * Device probes have a message length of zero
+			 * and need the bus to be reset before it can
+			 * be used again.
+			 */
+			i2c_pxa_reset(i2c);
+		}
+		i2c_pxa_master_complete(i2c, 0);
+	}
+
+	i2c->icrlog[i2c->irqlogidx-1] = icr;
+
+	writel(icr, _ICR(i2c));
+	show_state(i2c);
+}
+
+static void i2c_pxa_irq_rxfull(struct pxa_i2c *i2c, u32 isr)
+{
+	u32 icr = readl(_ICR(i2c)) & ~(ICR_START|ICR_STOP|ICR_ACKNAK|ICR_TB);
+
+	/*
+	 * Read the byte.
+	 */
+	i2c->msg->buf[i2c->msg_ptr++] = readl(_IDBR(i2c));
+
+	if (i2c->msg_ptr < i2c->msg->len) {
+		/*
+		 * If this is the last byte of the last
+		 * message, send a STOP.
+		 */
+		if (i2c->msg_ptr == i2c->msg->len - 1)
+			icr |= ICR_STOP | ICR_ACKNAK;
+
+		icr |= ICR_ALDIE | ICR_TB;
+	} else {
+		i2c_pxa_master_complete(i2c, 0);
+	}
+
+	i2c->icrlog[i2c->irqlogidx-1] = icr;
+
+	writel(icr, _ICR(i2c));
+}
+
+#define VALID_INT_SOURCE	(ISR_SSD | ISR_ALD | ISR_ITE | ISR_IRF | \
+				ISR_SAD | ISR_BED)
+static irqreturn_t i2c_pxa_handler(int this_irq, void *dev_id)
+{
+	struct pxa_i2c *i2c = dev_id;
+	u32 isr = readl(_ISR(i2c));
+
+	if (!(isr & VALID_INT_SOURCE))
+		return IRQ_NONE;
+
+	if (i2c_debug > 2 && 0) {
+		dev_dbg(&i2c->adap.dev, "%s: ISR=%08x, ICR=%08x, IBMR=%02x\n",
+			__func__, isr, readl(_ICR(i2c)), readl(_IBMR(i2c)));
+		decode_ISR(isr);
+	}
+
+	if (i2c->irqlogidx < ARRAY_SIZE(i2c->isrlog))
+		i2c->isrlog[i2c->irqlogidx++] = isr;
+
+	show_state(i2c);
+
+	/*
+	 * Always clear all pending IRQs.
+	 */
+	writel(isr & VALID_INT_SOURCE, _ISR(i2c));
+
+	if (isr & ISR_SAD)
+		i2c_pxa_slave_start(i2c, isr);
+	if (isr & ISR_SSD)
+		i2c_pxa_slave_stop(i2c);
+
+	if (i2c_pxa_is_slavemode(i2c)) {
+		if (isr & ISR_ITE)
+			i2c_pxa_slave_txempty(i2c, isr);
+		if (isr & ISR_IRF)
+			i2c_pxa_slave_rxfull(i2c, isr);
+	} else if (i2c->msg) {
+		if (isr & ISR_ITE)
+			i2c_pxa_irq_txempty(i2c, isr);
+		if (isr & ISR_IRF)
+			i2c_pxa_irq_rxfull(i2c, isr);
+	} else {
+		i2c_pxa_scream_blue_murder(i2c, "spurious irq");
+	}
+
+	return IRQ_HANDLED;
+}
+
+
+static int i2c_pxa_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
+{
+	struct pxa_i2c *i2c = adap->algo_data;
+	int ret, i;
+
+	for (i = adap->retries; i >= 0; i--) {
+		ret = i2c_pxa_do_xfer(i2c, msgs, num);
+		if (ret != I2C_RETRY)
+			goto out;
+
+		if (i2c_debug)
+			dev_dbg(&adap->dev, "Retrying transmission\n");
+		udelay(100);
+	}
+	i2c_pxa_scream_blue_murder(i2c, "exhausted retries");
+	ret = -EREMOTEIO;
+ out:
+	i2c_pxa_set_slave(i2c, ret);
+	return ret;
+}
+
+static u32 i2c_pxa_functionality(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm i2c_pxa_algorithm = {
+	.master_xfer	= i2c_pxa_xfer,
+	.functionality	= i2c_pxa_functionality,
+};
+
+static const struct i2c_algorithm i2c_pxa_pio_algorithm = {
+	.master_xfer	= i2c_pxa_pio_xfer,
+	.functionality	= i2c_pxa_functionality,
+};
+
+static struct of_device_id i2c_pxa_dt_ids[] = {
+	{ .compatible = "mrvl,pxa-i2c", .data = (void *)REGS_PXA2XX },
+	{ .compatible = "mrvl,pwri2c", .data = (void *)REGS_PXA3XX },
+	{ .compatible = "mrvl,mmp-twsi", .data = (void *)REGS_PXA2XX },
+	{}
+};
+MODULE_DEVICE_TABLE(of, i2c_pxa_dt_ids);
+
+static int i2c_pxa_probe_dt(struct platform_device *pdev, struct pxa_i2c *i2c,
+			    enum pxa_i2c_types *i2c_types)
+{
+	struct device_node *np = pdev->dev.of_node;
+	const struct of_device_id *of_id =
+			of_match_device(i2c_pxa_dt_ids, &pdev->dev);
+	int ret;
+
+	if (!of_id)
+		return 1;
+	ret = of_alias_get_id(np, "i2c");
+	if (ret < 0) {
+		dev_err(&pdev->dev, "failed to get alias id, errno %d\n", ret);
+		return ret;
+	}
+	pdev->id = ret;
+	if (of_get_property(np, "mrvl,i2c-polling", NULL))
+		i2c->use_pio = 1;
+	if (of_get_property(np, "mrvl,i2c-fast-mode", NULL))
+		i2c->fast_mode = 1;
+	*i2c_types = (u32)(of_id->data);
+	return 0;
+}
+
+static int i2c_pxa_probe_pdata(struct platform_device *pdev,
+			       struct pxa_i2c *i2c,
+			       enum pxa_i2c_types *i2c_types)
+{
+	struct i2c_pxa_platform_data *plat = pdev->dev.platform_data;
+	const struct platform_device_id *id = platform_get_device_id(pdev);
+
+	*i2c_types = id->driver_data;
+	if (plat) {
+		i2c->use_pio = plat->use_pio;
+		i2c->fast_mode = plat->fast_mode;
+	}
+	return 0;
+}
+
+static int i2c_pxa_probe(struct platform_device *dev)
+{
+	struct i2c_pxa_platform_data *plat = dev->dev.platform_data;
+	enum pxa_i2c_types i2c_type;
+	struct pxa_i2c *i2c;
+	struct resource *res = NULL;
+	int ret, irq;
+
+	i2c = kzalloc(sizeof(struct pxa_i2c), GFP_KERNEL);
+	if (!i2c) {
+		ret = -ENOMEM;
+		goto emalloc;
+	}
+
+	ret = i2c_pxa_probe_dt(dev, i2c, &i2c_type);
+	if (ret > 0)
+		ret = i2c_pxa_probe_pdata(dev, i2c, &i2c_type);
+	if (ret < 0)
+		goto eclk;
+
+	res = platform_get_resource(dev, IORESOURCE_MEM, 0);
+	irq = platform_get_irq(dev, 0);
+	if (res == NULL || irq < 0) {
+		ret = -ENODEV;
+		goto eclk;
+	}
+
+	if (!request_mem_region(res->start, resource_size(res), res->name)) {
+		ret = -ENOMEM;
+		goto eclk;
+	}
+
+	i2c->adap.owner   = THIS_MODULE;
+	i2c->adap.retries = 5;
+
+	spin_lock_init(&i2c->lock);
+	init_waitqueue_head(&i2c->wait);
+
+	/*
+	 * If "dev->id" is negative we consider it as zero.
+	 * The reason to do so is to avoid sysfs names that only make
+	 * sense when there are multiple adapters.
+	 */
+	i2c->adap.nr = dev->id;
+	snprintf(i2c->adap.name, sizeof(i2c->adap.name), "pxa_i2c-i2c.%u",
+		 i2c->adap.nr);
+
+	i2c->clk = clk_get(&dev->dev, NULL);
+	if (IS_ERR(i2c->clk)) {
+		ret = PTR_ERR(i2c->clk);
+		goto eclk;
+	}
+
+	i2c->reg_base = ioremap(res->start, resource_size(res));
+	if (!i2c->reg_base) {
+		ret = -EIO;
+		goto eremap;
+	}
+
+	i2c->reg_ibmr = i2c->reg_base + pxa_reg_layout[i2c_type].ibmr;
+	i2c->reg_idbr = i2c->reg_base + pxa_reg_layout[i2c_type].idbr;
+	i2c->reg_icr = i2c->reg_base + pxa_reg_layout[i2c_type].icr;
+	i2c->reg_isr = i2c->reg_base + pxa_reg_layout[i2c_type].isr;
+	if (i2c_type != REGS_CE4100)
+		i2c->reg_isar = i2c->reg_base + pxa_reg_layout[i2c_type].isar;
+
+	i2c->iobase = res->start;
+	i2c->iosize = resource_size(res);
+
+	i2c->irq = irq;
+
+	i2c->slave_addr = I2C_PXA_SLAVE_ADDR;
+
+	if (plat) {
+#ifdef CONFIG_I2C_PXA_SLAVE
+		i2c->slave_addr = plat->slave_addr;
+		i2c->slave = plat->slave;
+#endif
+		i2c->adap.class = plat->class;
+	}
+
+	clk_enable(i2c->clk);
+
+	if (i2c->use_pio) {
+		i2c->adap.algo = &i2c_pxa_pio_algorithm;
+	} else {
+		i2c->adap.algo = &i2c_pxa_algorithm;
+		ret = request_irq(irq, i2c_pxa_handler, IRQF_SHARED,
+				  i2c->adap.name, i2c);
+		if (ret)
+			goto ereqirq;
+	}
+
+	i2c_pxa_reset(i2c);
+
+	i2c->adap.algo_data = i2c;
+	i2c->adap.dev.parent = &dev->dev;
+#ifdef CONFIG_OF
+	i2c->adap.dev.of_node = dev->dev.of_node;
+#endif
+
+	ret = i2c_add_numbered_adapter(&i2c->adap);
+	if (ret < 0) {
+		printk(KERN_INFO "I2C: Failed to add bus\n");
+		goto eadapt;
+	}
+	of_i2c_register_devices(&i2c->adap);
+
+	platform_set_drvdata(dev, i2c);
+
+#ifdef CONFIG_I2C_PXA_SLAVE
+	printk(KERN_INFO "I2C: %s: PXA I2C adapter, slave address %d\n",
+	       dev_name(&i2c->adap.dev), i2c->slave_addr);
+#else
+	printk(KERN_INFO "I2C: %s: PXA I2C adapter\n",
+	       dev_name(&i2c->adap.dev));
+#endif
+	return 0;
+
+eadapt:
+	if (!i2c->use_pio)
+		free_irq(irq, i2c);
+ereqirq:
+	clk_disable(i2c->clk);
+	iounmap(i2c->reg_base);
+eremap:
+	clk_put(i2c->clk);
+eclk:
+	kfree(i2c);
+emalloc:
+	release_mem_region(res->start, resource_size(res));
+	return ret;
+}
+
+static int __exit i2c_pxa_remove(struct platform_device *dev)
+{
+	struct pxa_i2c *i2c = platform_get_drvdata(dev);
+
+	platform_set_drvdata(dev, NULL);
+
+	i2c_del_adapter(&i2c->adap);
+	if (!i2c->use_pio)
+		free_irq(i2c->irq, i2c);
+
+	clk_disable(i2c->clk);
+	clk_put(i2c->clk);
+
+	iounmap(i2c->reg_base);
+	release_mem_region(i2c->iobase, i2c->iosize);
+	kfree(i2c);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int i2c_pxa_suspend_noirq(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct pxa_i2c *i2c = platform_get_drvdata(pdev);
+
+	clk_disable(i2c->clk);
+
+	return 0;
+}
+
+static int i2c_pxa_resume_noirq(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct pxa_i2c *i2c = platform_get_drvdata(pdev);
+
+	clk_enable(i2c->clk);
+	i2c_pxa_reset(i2c);
+
+	return 0;
+}
+
+static const struct dev_pm_ops i2c_pxa_dev_pm_ops = {
+	.suspend_noirq = i2c_pxa_suspend_noirq,
+	.resume_noirq = i2c_pxa_resume_noirq,
+};
+
+#define I2C_PXA_DEV_PM_OPS (&i2c_pxa_dev_pm_ops)
+#else
+#define I2C_PXA_DEV_PM_OPS NULL
+#endif
+
+static struct platform_driver i2c_pxa_driver = {
+	.probe		= i2c_pxa_probe,
+	.remove		= __exit_p(i2c_pxa_remove),
+	.driver		= {
+		.name	= "pxa2xx-i2c",
+		.owner	= THIS_MODULE,
+		.pm	= I2C_PXA_DEV_PM_OPS,
+		.of_match_table = i2c_pxa_dt_ids,
+	},
+	.id_table	= i2c_pxa_id_table,
+};
+
+static int __init i2c_adap_pxa_init(void)
+{
+	return platform_driver_register(&i2c_pxa_driver);
+}
+
+static void __exit i2c_adap_pxa_exit(void)
+{
+	platform_driver_unregister(&i2c_pxa_driver);
+}
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pxa2xx-i2c");
+
+subsys_initcall(i2c_adap_pxa_init);
+module_exit(i2c_adap_pxa_exit);
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-s3c2410.c b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-s3c2410.c
new file mode 100644
index 0000000..737f721
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-s3c2410.c
@@ -0,0 +1,1161 @@
+/* linux/drivers/i2c/busses/i2c-s3c2410.c
+ *
+ * Copyright (C) 2004,2005,2009 Simtec Electronics
+ *	Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C2410 I2C Controller
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/time.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/clk.h>
+#include <linux/cpufreq.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/of_i2c.h>
+#include <linux/of_gpio.h>
+
+#include <asm/irq.h>
+
+#include <plat/regs-iic.h>
+#include <plat/iic.h>
+
+/* i2c controller state */
+
+enum s3c24xx_i2c_state {
+	STATE_IDLE,
+	STATE_START,
+	STATE_READ,
+	STATE_WRITE,
+	STATE_STOP
+};
+
+enum s3c24xx_i2c_type {
+	TYPE_S3C2410,
+	TYPE_S3C2440,
+};
+
+struct s3c24xx_i2c {
+	spinlock_t		lock;
+	wait_queue_head_t	wait;
+	unsigned int		suspended:1;
+
+	struct i2c_msg		*msg;
+	unsigned int		msg_num;
+	unsigned int		msg_idx;
+	unsigned int		msg_ptr;
+
+	unsigned int		tx_setup;
+	unsigned int		irq;
+
+	enum s3c24xx_i2c_state	state;
+	unsigned long		clkrate;
+
+	void __iomem		*regs;
+	struct clk		*clk;
+	struct device		*dev;
+	struct resource		*ioarea;
+	struct i2c_adapter	adap;
+
+	struct s3c2410_platform_i2c	*pdata;
+	int			gpios[2];
+#ifdef CONFIG_CPU_FREQ
+	struct notifier_block	freq_transition;
+#endif
+};
+
+/* default platform data removed, dev should always carry data. */
+
+/* s3c24xx_i2c_is2440()
+ *
+ * return true is this is an s3c2440
+*/
+
+static inline int s3c24xx_i2c_is2440(struct s3c24xx_i2c *i2c)
+{
+	struct platform_device *pdev = to_platform_device(i2c->dev);
+	enum s3c24xx_i2c_type type;
+
+#ifdef CONFIG_OF
+	if (i2c->dev->of_node)
+		return of_device_is_compatible(i2c->dev->of_node,
+				"samsung,s3c2440-i2c");
+#endif
+
+	type = platform_get_device_id(pdev)->driver_data;
+	return type == TYPE_S3C2440;
+}
+
+/* s3c24xx_i2c_master_complete
+ *
+ * complete the message and wake up the caller, using the given return code,
+ * or zero to mean ok.
+*/
+
+static inline void s3c24xx_i2c_master_complete(struct s3c24xx_i2c *i2c, int ret)
+{
+	dev_dbg(i2c->dev, "master_complete %d\n", ret);
+
+	i2c->msg_ptr = 0;
+	i2c->msg = NULL;
+	i2c->msg_idx++;
+	i2c->msg_num = 0;
+	if (ret)
+		i2c->msg_idx = ret;
+
+	wake_up(&i2c->wait);
+}
+
+static inline void s3c24xx_i2c_disable_ack(struct s3c24xx_i2c *i2c)
+{
+	unsigned long tmp;
+
+	tmp = readl(i2c->regs + S3C2410_IICCON);
+	writel(tmp & ~S3C2410_IICCON_ACKEN, i2c->regs + S3C2410_IICCON);
+}
+
+static inline void s3c24xx_i2c_enable_ack(struct s3c24xx_i2c *i2c)
+{
+	unsigned long tmp;
+
+	tmp = readl(i2c->regs + S3C2410_IICCON);
+	writel(tmp | S3C2410_IICCON_ACKEN, i2c->regs + S3C2410_IICCON);
+}
+
+/* irq enable/disable functions */
+
+static inline void s3c24xx_i2c_disable_irq(struct s3c24xx_i2c *i2c)
+{
+	unsigned long tmp;
+
+	tmp = readl(i2c->regs + S3C2410_IICCON);
+	writel(tmp & ~S3C2410_IICCON_IRQEN, i2c->regs + S3C2410_IICCON);
+}
+
+static inline void s3c24xx_i2c_enable_irq(struct s3c24xx_i2c *i2c)
+{
+	unsigned long tmp;
+
+	tmp = readl(i2c->regs + S3C2410_IICCON);
+	writel(tmp | S3C2410_IICCON_IRQEN, i2c->regs + S3C2410_IICCON);
+}
+
+
+/* s3c24xx_i2c_message_start
+ *
+ * put the start of a message onto the bus
+*/
+
+static void s3c24xx_i2c_message_start(struct s3c24xx_i2c *i2c,
+				      struct i2c_msg *msg)
+{
+	unsigned int addr = (msg->addr & 0x7f) << 1;
+	unsigned long stat;
+	unsigned long iiccon;
+
+	stat = 0;
+	stat |=  S3C2410_IICSTAT_TXRXEN;
+
+	if (msg->flags & I2C_M_RD) {
+		stat |= S3C2410_IICSTAT_MASTER_RX;
+		addr |= 1;
+	} else
+		stat |= S3C2410_IICSTAT_MASTER_TX;
+
+	if (msg->flags & I2C_M_REV_DIR_ADDR)
+		addr ^= 1;
+
+	/* todo - check for wether ack wanted or not */
+	s3c24xx_i2c_enable_ack(i2c);
+
+	iiccon = readl(i2c->regs + S3C2410_IICCON);
+	writel(stat, i2c->regs + S3C2410_IICSTAT);
+
+	dev_dbg(i2c->dev, "START: %08lx to IICSTAT, %02x to DS\n", stat, addr);
+	writeb(addr, i2c->regs + S3C2410_IICDS);
+
+	/* delay here to ensure the data byte has gotten onto the bus
+	 * before the transaction is started */
+
+	ndelay(i2c->tx_setup);
+
+	dev_dbg(i2c->dev, "iiccon, %08lx\n", iiccon);
+	writel(iiccon, i2c->regs + S3C2410_IICCON);
+
+	stat |= S3C2410_IICSTAT_START;
+	writel(stat, i2c->regs + S3C2410_IICSTAT);
+}
+
+static inline void s3c24xx_i2c_stop(struct s3c24xx_i2c *i2c, int ret)
+{
+	unsigned long iicstat = readl(i2c->regs + S3C2410_IICSTAT);
+
+	dev_dbg(i2c->dev, "STOP\n");
+
+	/* stop the transfer */
+	iicstat &= ~S3C2410_IICSTAT_START;
+	writel(iicstat, i2c->regs + S3C2410_IICSTAT);
+
+	i2c->state = STATE_STOP;
+
+	s3c24xx_i2c_master_complete(i2c, ret);
+	s3c24xx_i2c_disable_irq(i2c);
+}
+
+/* helper functions to determine the current state in the set of
+ * messages we are sending */
+
+/* is_lastmsg()
+ *
+ * returns TRUE if the current message is the last in the set
+*/
+
+static inline int is_lastmsg(struct s3c24xx_i2c *i2c)
+{
+	return i2c->msg_idx >= (i2c->msg_num - 1);
+}
+
+/* is_msglast
+ *
+ * returns TRUE if we this is the last byte in the current message
+*/
+
+static inline int is_msglast(struct s3c24xx_i2c *i2c)
+{
+	return i2c->msg_ptr == i2c->msg->len-1;
+}
+
+/* is_msgend
+ *
+ * returns TRUE if we reached the end of the current message
+*/
+
+static inline int is_msgend(struct s3c24xx_i2c *i2c)
+{
+	return i2c->msg_ptr >= i2c->msg->len;
+}
+
+/* i2c_s3c_irq_nextbyte
+ *
+ * process an interrupt and work out what to do
+ */
+
+static int i2c_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat)
+{
+	unsigned long tmp;
+	unsigned char byte;
+	int ret = 0;
+
+	switch (i2c->state) {
+
+	case STATE_IDLE:
+		dev_err(i2c->dev, "%s: called in STATE_IDLE\n", __func__);
+		goto out;
+
+	case STATE_STOP:
+		dev_err(i2c->dev, "%s: called in STATE_STOP\n", __func__);
+		s3c24xx_i2c_disable_irq(i2c);
+		goto out_ack;
+
+	case STATE_START:
+		/* last thing we did was send a start condition on the
+		 * bus, or started a new i2c message
+		 */
+
+		if (iicstat & S3C2410_IICSTAT_LASTBIT &&
+		    !(i2c->msg->flags & I2C_M_IGNORE_NAK)) {
+			/* ack was not received... */
+
+			dev_dbg(i2c->dev, "ack was not received\n");
+			s3c24xx_i2c_stop(i2c, -ENXIO);
+			goto out_ack;
+		}
+
+		if (i2c->msg->flags & I2C_M_RD)
+			i2c->state = STATE_READ;
+		else
+			i2c->state = STATE_WRITE;
+
+		/* terminate the transfer if there is nothing to do
+		 * as this is used by the i2c probe to find devices. */
+
+		if (is_lastmsg(i2c) && i2c->msg->len == 0) {
+			s3c24xx_i2c_stop(i2c, 0);
+			goto out_ack;
+		}
+
+		if (i2c->state == STATE_READ)
+			goto prepare_read;
+
+		/* fall through to the write state, as we will need to
+		 * send a byte as well */
+
+	case STATE_WRITE:
+		/* we are writing data to the device... check for the
+		 * end of the message, and if so, work out what to do
+		 */
+
+		if (!(i2c->msg->flags & I2C_M_IGNORE_NAK)) {
+			if (iicstat & S3C2410_IICSTAT_LASTBIT) {
+				dev_dbg(i2c->dev, "WRITE: No Ack\n");
+
+				s3c24xx_i2c_stop(i2c, -ECONNREFUSED);
+				goto out_ack;
+			}
+		}
+
+ retry_write:
+
+		if (!is_msgend(i2c)) {
+			byte = i2c->msg->buf[i2c->msg_ptr++];
+			writeb(byte, i2c->regs + S3C2410_IICDS);
+
+			/* delay after writing the byte to allow the
+			 * data setup time on the bus, as writing the
+			 * data to the register causes the first bit
+			 * to appear on SDA, and SCL will change as
+			 * soon as the interrupt is acknowledged */
+
+			ndelay(i2c->tx_setup);
+
+		} else if (!is_lastmsg(i2c)) {
+			/* we need to go to the next i2c message */
+
+			dev_dbg(i2c->dev, "WRITE: Next Message\n");
+
+			i2c->msg_ptr = 0;
+			i2c->msg_idx++;
+			i2c->msg++;
+
+			/* check to see if we need to do another message */
+			if (i2c->msg->flags & I2C_M_NOSTART) {
+
+				if (i2c->msg->flags & I2C_M_RD) {
+					/* cannot do this, the controller
+					 * forces us to send a new START
+					 * when we change direction */
+
+					s3c24xx_i2c_stop(i2c, -EINVAL);
+				}
+
+				goto retry_write;
+			} else {
+				/* send the new start */
+				s3c24xx_i2c_message_start(i2c, i2c->msg);
+				i2c->state = STATE_START;
+			}
+
+		} else {
+			/* send stop */
+
+			s3c24xx_i2c_stop(i2c, 0);
+		}
+		break;
+
+	case STATE_READ:
+		/* we have a byte of data in the data register, do
+		 * something with it, and then work out wether we are
+		 * going to do any more read/write
+		 */
+
+		byte = readb(i2c->regs + S3C2410_IICDS);
+		i2c->msg->buf[i2c->msg_ptr++] = byte;
+
+ prepare_read:
+		if (is_msglast(i2c)) {
+			/* last byte of buffer */
+
+			if (is_lastmsg(i2c))
+				s3c24xx_i2c_disable_ack(i2c);
+
+		} else if (is_msgend(i2c)) {
+			/* ok, we've read the entire buffer, see if there
+			 * is anything else we need to do */
+
+			if (is_lastmsg(i2c)) {
+				/* last message, send stop and complete */
+				dev_dbg(i2c->dev, "READ: Send Stop\n");
+
+				s3c24xx_i2c_stop(i2c, 0);
+			} else {
+				/* go to the next transfer */
+				dev_dbg(i2c->dev, "READ: Next Transfer\n");
+
+				i2c->msg_ptr = 0;
+				i2c->msg_idx++;
+				i2c->msg++;
+			}
+		}
+
+		break;
+	}
+
+	/* acknowlegde the IRQ and get back on with the work */
+
+ out_ack:
+	tmp = readl(i2c->regs + S3C2410_IICCON);
+	tmp &= ~S3C2410_IICCON_IRQPEND;
+	writel(tmp, i2c->regs + S3C2410_IICCON);
+ out:
+	return ret;
+}
+
+/* s3c24xx_i2c_irq
+ *
+ * top level IRQ servicing routine
+*/
+
+static irqreturn_t s3c24xx_i2c_irq(int irqno, void *dev_id)
+{
+	struct s3c24xx_i2c *i2c = dev_id;
+	unsigned long status;
+	unsigned long tmp;
+
+	status = readl(i2c->regs + S3C2410_IICSTAT);
+
+	if (status & S3C2410_IICSTAT_ARBITR) {
+		/* deal with arbitration loss */
+		dev_err(i2c->dev, "deal with arbitration loss\n");
+	}
+
+	if (i2c->state == STATE_IDLE) {
+		dev_dbg(i2c->dev, "IRQ: error i2c->state == IDLE\n");
+
+		tmp = readl(i2c->regs + S3C2410_IICCON);
+		tmp &= ~S3C2410_IICCON_IRQPEND;
+		writel(tmp, i2c->regs +  S3C2410_IICCON);
+		goto out;
+	}
+
+	/* pretty much this leaves us with the fact that we've
+	 * transmitted or received whatever byte we last sent */
+
+	i2c_s3c_irq_nextbyte(i2c, status);
+
+ out:
+	return IRQ_HANDLED;
+}
+
+
+/* s3c24xx_i2c_set_master
+ *
+ * get the i2c bus for a master transaction
+*/
+
+static int s3c24xx_i2c_set_master(struct s3c24xx_i2c *i2c)
+{
+	unsigned long iicstat;
+	int timeout = 400;
+
+	while (timeout-- > 0) {
+		iicstat = readl(i2c->regs + S3C2410_IICSTAT);
+
+		if (!(iicstat & S3C2410_IICSTAT_BUSBUSY))
+			return 0;
+
+		msleep(1);
+	}
+
+	return -ETIMEDOUT;
+}
+
+/* s3c24xx_i2c_doxfer
+ *
+ * this starts an i2c transfer
+*/
+
+static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c,
+			      struct i2c_msg *msgs, int num)
+{
+	unsigned long iicstat, timeout;
+	int spins = 20;
+	int ret;
+
+	if (i2c->suspended)
+		return -EIO;
+
+	ret = s3c24xx_i2c_set_master(i2c);
+	if (ret != 0) {
+		dev_err(i2c->dev, "cannot get bus (error %d)\n", ret);
+		ret = -EAGAIN;
+		goto out;
+	}
+
+	spin_lock_irq(&i2c->lock);
+
+	i2c->msg     = msgs;
+	i2c->msg_num = num;
+	i2c->msg_ptr = 0;
+	i2c->msg_idx = 0;
+	i2c->state   = STATE_START;
+
+	s3c24xx_i2c_enable_irq(i2c);
+	s3c24xx_i2c_message_start(i2c, msgs);
+	spin_unlock_irq(&i2c->lock);
+
+	timeout = wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5);
+
+	ret = i2c->msg_idx;
+
+	/* having these next two as dev_err() makes life very
+	 * noisy when doing an i2cdetect */
+
+	if (timeout == 0)
+		dev_dbg(i2c->dev, "timeout\n");
+	else if (ret != num)
+		dev_dbg(i2c->dev, "incomplete xfer (%d)\n", ret);
+
+	/* ensure the stop has been through the bus */
+
+	dev_dbg(i2c->dev, "waiting for bus idle\n");
+
+	/* first, try busy waiting briefly */
+	do {
+		cpu_relax();
+		iicstat = readl(i2c->regs + S3C2410_IICSTAT);
+	} while ((iicstat & S3C2410_IICSTAT_START) && --spins);
+
+	/* if that timed out sleep */
+	if (!spins) {
+		msleep(1);
+		iicstat = readl(i2c->regs + S3C2410_IICSTAT);
+	}
+
+	if (iicstat & S3C2410_IICSTAT_START)
+		dev_warn(i2c->dev, "timeout waiting for bus idle\n");
+
+ out:
+	return ret;
+}
+
+/* s3c24xx_i2c_xfer
+ *
+ * first port of call from the i2c bus code when an message needs
+ * transferring across the i2c bus.
+*/
+
+static int s3c24xx_i2c_xfer(struct i2c_adapter *adap,
+			struct i2c_msg *msgs, int num)
+{
+	struct s3c24xx_i2c *i2c = (struct s3c24xx_i2c *)adap->algo_data;
+	int retry;
+	int ret;
+
+	pm_runtime_get_sync(&adap->dev);
+	clk_enable(i2c->clk);
+
+	for (retry = 0; retry < adap->retries; retry++) {
+
+		ret = s3c24xx_i2c_doxfer(i2c, msgs, num);
+
+		if (ret != -EAGAIN) {
+			clk_disable(i2c->clk);
+			pm_runtime_put_sync(&adap->dev);
+			return ret;
+		}
+
+		dev_dbg(i2c->dev, "Retrying transmission (%d)\n", retry);
+
+		udelay(100);
+	}
+
+	clk_disable(i2c->clk);
+	pm_runtime_put_sync(&adap->dev);
+	return -EREMOTEIO;
+}
+
+/* declare our i2c functionality */
+static u32 s3c24xx_i2c_func(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_PROTOCOL_MANGLING;
+}
+
+/* i2c bus registration info */
+
+static const struct i2c_algorithm s3c24xx_i2c_algorithm = {
+	.master_xfer		= s3c24xx_i2c_xfer,
+	.functionality		= s3c24xx_i2c_func,
+};
+
+/* s3c24xx_i2c_calcdivisor
+ *
+ * return the divisor settings for a given frequency
+*/
+
+static int s3c24xx_i2c_calcdivisor(unsigned long clkin, unsigned int wanted,
+				   unsigned int *div1, unsigned int *divs)
+{
+	unsigned int calc_divs = clkin / wanted;
+	unsigned int calc_div1;
+
+	if (calc_divs > (16*16))
+		calc_div1 = 512;
+	else
+		calc_div1 = 16;
+
+	calc_divs += calc_div1-1;
+	calc_divs /= calc_div1;
+
+	if (calc_divs == 0)
+		calc_divs = 1;
+	if (calc_divs > 17)
+		calc_divs = 17;
+
+	*divs = calc_divs;
+	*div1 = calc_div1;
+
+	return clkin / (calc_divs * calc_div1);
+}
+
+/* s3c24xx_i2c_clockrate
+ *
+ * work out a divisor for the user requested frequency setting,
+ * either by the requested frequency, or scanning the acceptable
+ * range of frequencies until something is found
+*/
+
+static int s3c24xx_i2c_clockrate(struct s3c24xx_i2c *i2c, unsigned int *got)
+{
+	struct s3c2410_platform_i2c *pdata = i2c->pdata;
+	unsigned long clkin = clk_get_rate(i2c->clk);
+	unsigned int divs, div1;
+	unsigned long target_frequency;
+	u32 iiccon;
+	int freq;
+
+	i2c->clkrate = clkin;
+	clkin /= 1000;		/* clkin now in KHz */
+
+	dev_dbg(i2c->dev, "pdata desired frequency %lu\n", pdata->frequency);
+
+	target_frequency = pdata->frequency ? pdata->frequency : 100000;
+
+	target_frequency /= 1000; /* Target frequency now in KHz */
+
+	freq = s3c24xx_i2c_calcdivisor(clkin, target_frequency, &div1, &divs);
+
+	if (freq > target_frequency) {
+		dev_err(i2c->dev,
+			"Unable to achieve desired frequency %luKHz."	\
+			" Lowest achievable %dKHz\n", target_frequency, freq);
+		return -EINVAL;
+	}
+
+	*got = freq;
+
+	iiccon = readl(i2c->regs + S3C2410_IICCON);
+	iiccon &= ~(S3C2410_IICCON_SCALEMASK | S3C2410_IICCON_TXDIV_512);
+	iiccon |= (divs-1);
+
+	if (div1 == 512)
+		iiccon |= S3C2410_IICCON_TXDIV_512;
+
+	writel(iiccon, i2c->regs + S3C2410_IICCON);
+
+	if (s3c24xx_i2c_is2440(i2c)) {
+		unsigned long sda_delay;
+
+		if (pdata->sda_delay) {
+			sda_delay = clkin * pdata->sda_delay;
+			sda_delay = DIV_ROUND_UP(sda_delay, 1000000);
+			sda_delay = DIV_ROUND_UP(sda_delay, 5);
+			if (sda_delay > 3)
+				sda_delay = 3;
+			sda_delay |= S3C2410_IICLC_FILTER_ON;
+		} else
+			sda_delay = 0;
+
+		dev_dbg(i2c->dev, "IICLC=%08lx\n", sda_delay);
+		writel(sda_delay, i2c->regs + S3C2440_IICLC);
+	}
+
+	return 0;
+}
+
+#ifdef CONFIG_CPU_FREQ
+
+#define freq_to_i2c(_n) container_of(_n, struct s3c24xx_i2c, freq_transition)
+
+static int s3c24xx_i2c_cpufreq_transition(struct notifier_block *nb,
+					  unsigned long val, void *data)
+{
+	struct s3c24xx_i2c *i2c = freq_to_i2c(nb);
+	unsigned long flags;
+	unsigned int got;
+	int delta_f;
+	int ret;
+
+	delta_f = clk_get_rate(i2c->clk) - i2c->clkrate;
+
+	/* if we're post-change and the input clock has slowed down
+	 * or at pre-change and the clock is about to speed up, then
+	 * adjust our clock rate. <0 is slow, >0 speedup.
+	 */
+
+	if ((val == CPUFREQ_POSTCHANGE && delta_f < 0) ||
+	    (val == CPUFREQ_PRECHANGE && delta_f > 0)) {
+		spin_lock_irqsave(&i2c->lock, flags);
+		ret = s3c24xx_i2c_clockrate(i2c, &got);
+		spin_unlock_irqrestore(&i2c->lock, flags);
+
+		if (ret < 0)
+			dev_err(i2c->dev, "cannot find frequency\n");
+		else
+			dev_info(i2c->dev, "setting freq %d\n", got);
+	}
+
+	return 0;
+}
+
+static inline int s3c24xx_i2c_register_cpufreq(struct s3c24xx_i2c *i2c)
+{
+	i2c->freq_transition.notifier_call = s3c24xx_i2c_cpufreq_transition;
+
+	return cpufreq_register_notifier(&i2c->freq_transition,
+					 CPUFREQ_TRANSITION_NOTIFIER);
+}
+
+static inline void s3c24xx_i2c_deregister_cpufreq(struct s3c24xx_i2c *i2c)
+{
+	cpufreq_unregister_notifier(&i2c->freq_transition,
+				    CPUFREQ_TRANSITION_NOTIFIER);
+}
+
+#else
+static inline int s3c24xx_i2c_register_cpufreq(struct s3c24xx_i2c *i2c)
+{
+	return 0;
+}
+
+static inline void s3c24xx_i2c_deregister_cpufreq(struct s3c24xx_i2c *i2c)
+{
+}
+#endif
+
+#ifdef CONFIG_OF
+static int s3c24xx_i2c_parse_dt_gpio(struct s3c24xx_i2c *i2c)
+{
+	int idx, gpio, ret;
+
+	for (idx = 0; idx < 2; idx++) {
+		gpio = of_get_gpio(i2c->dev->of_node, idx);
+		if (!gpio_is_valid(gpio)) {
+			dev_err(i2c->dev, "invalid gpio[%d]: %d\n", idx, gpio);
+			goto free_gpio;
+		}
+
+		ret = gpio_request(gpio, "i2c-bus");
+		if (ret) {
+			dev_err(i2c->dev, "gpio [%d] request failed\n", gpio);
+			goto free_gpio;
+		}
+	}
+	return 0;
+
+free_gpio:
+	while (--idx >= 0)
+		gpio_free(i2c->gpios[idx]);
+	return -EINVAL;
+}
+
+static void s3c24xx_i2c_dt_gpio_free(struct s3c24xx_i2c *i2c)
+{
+	unsigned int idx;
+	for (idx = 0; idx < 2; idx++)
+		gpio_free(i2c->gpios[idx]);
+}
+#else
+static int s3c24xx_i2c_parse_dt_gpio(struct s3c24xx_i2c *i2c)
+{
+	return 0;
+}
+
+static void s3c24xx_i2c_dt_gpio_free(struct s3c24xx_i2c *i2c)
+{
+}
+#endif
+
+/* s3c24xx_i2c_init
+ *
+ * initialise the controller, set the IO lines and frequency
+*/
+
+static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c)
+{
+	unsigned long iicon = S3C2410_IICCON_IRQEN | S3C2410_IICCON_ACKEN;
+	struct s3c2410_platform_i2c *pdata;
+	unsigned int freq;
+
+	/* get the plafrom data */
+
+	pdata = i2c->pdata;
+
+	/* inititalise the gpio */
+
+	if (pdata->cfg_gpio)
+		pdata->cfg_gpio(to_platform_device(i2c->dev));
+	else
+		if (s3c24xx_i2c_parse_dt_gpio(i2c))
+			return -EINVAL;
+
+	/* write slave address */
+
+	writeb(pdata->slave_addr, i2c->regs + S3C2410_IICADD);
+
+	dev_info(i2c->dev, "slave address 0x%02x\n", pdata->slave_addr);
+
+	writel(iicon, i2c->regs + S3C2410_IICCON);
+
+	/* we need to work out the divisors for the clock... */
+
+	if (s3c24xx_i2c_clockrate(i2c, &freq) != 0) {
+		writel(0, i2c->regs + S3C2410_IICCON);
+		dev_err(i2c->dev, "cannot meet bus frequency required\n");
+		return -EINVAL;
+	}
+
+	/* todo - check that the i2c lines aren't being dragged anywhere */
+
+	dev_info(i2c->dev, "bus frequency set to %d KHz\n", freq);
+	dev_dbg(i2c->dev, "S3C2410_IICCON=0x%02lx\n", iicon);
+
+	return 0;
+}
+
+#ifdef CONFIG_OF
+/* s3c24xx_i2c_parse_dt
+ *
+ * Parse the device tree node and retreive the platform data.
+*/
+
+static void
+s3c24xx_i2c_parse_dt(struct device_node *np, struct s3c24xx_i2c *i2c)
+{
+	struct s3c2410_platform_i2c *pdata = i2c->pdata;
+
+	if (!np)
+		return;
+
+	pdata->bus_num = -1; /* i2c bus number is dynamically assigned */
+	of_property_read_u32(np, "samsung,i2c-sda-delay", &pdata->sda_delay);
+	of_property_read_u32(np, "samsung,i2c-slave-addr", &pdata->slave_addr);
+	of_property_read_u32(np, "samsung,i2c-max-bus-freq",
+				(u32 *)&pdata->frequency);
+}
+#else
+static void
+s3c24xx_i2c_parse_dt(struct device_node *np, struct s3c24xx_i2c *i2c)
+{
+	return;
+}
+#endif
+
+/* s3c24xx_i2c_probe
+ *
+ * called by the bus driver when a suitable device is found
+*/
+
+static int s3c24xx_i2c_probe(struct platform_device *pdev)
+{
+	struct s3c24xx_i2c *i2c;
+	struct s3c2410_platform_i2c *pdata = NULL;
+	struct resource *res;
+	int ret;
+
+	if (!pdev->dev.of_node) {
+		pdata = pdev->dev.platform_data;
+		if (!pdata) {
+			dev_err(&pdev->dev, "no platform data\n");
+			return -EINVAL;
+		}
+	}
+
+	i2c = devm_kzalloc(&pdev->dev, sizeof(struct s3c24xx_i2c), GFP_KERNEL);
+	if (!i2c) {
+		dev_err(&pdev->dev, "no memory for state\n");
+		return -ENOMEM;
+	}
+
+	i2c->pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+	if (!i2c->pdata) {
+		ret = -ENOMEM;
+		goto err_noclk;
+	}
+
+	if (pdata)
+		memcpy(i2c->pdata, pdata, sizeof(*pdata));
+	else
+		s3c24xx_i2c_parse_dt(pdev->dev.of_node, i2c);
+
+	strlcpy(i2c->adap.name, "s3c2410-i2c", sizeof(i2c->adap.name));
+	i2c->adap.owner   = THIS_MODULE;
+	i2c->adap.algo    = &s3c24xx_i2c_algorithm;
+	i2c->adap.retries = 2;
+	i2c->adap.class   = I2C_CLASS_HWMON | I2C_CLASS_SPD;
+	i2c->tx_setup     = 50;
+
+	spin_lock_init(&i2c->lock);
+	init_waitqueue_head(&i2c->wait);
+
+	/* find the clock and enable it */
+
+	i2c->dev = &pdev->dev;
+	i2c->clk = clk_get(&pdev->dev, "i2c");
+	if (IS_ERR(i2c->clk)) {
+		dev_err(&pdev->dev, "cannot get clock\n");
+		ret = -ENOENT;
+		goto err_noclk;
+	}
+
+	dev_dbg(&pdev->dev, "clock source %p\n", i2c->clk);
+
+	clk_enable(i2c->clk);
+
+	/* map the registers */
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (res == NULL) {
+		dev_err(&pdev->dev, "cannot find IO resource\n");
+		ret = -ENOENT;
+		goto err_clk;
+	}
+
+	i2c->ioarea = request_mem_region(res->start, resource_size(res),
+					 pdev->name);
+
+	if (i2c->ioarea == NULL) {
+		dev_err(&pdev->dev, "cannot request IO\n");
+		ret = -ENXIO;
+		goto err_clk;
+	}
+
+	i2c->regs = ioremap(res->start, resource_size(res));
+
+	if (i2c->regs == NULL) {
+		dev_err(&pdev->dev, "cannot map IO\n");
+		ret = -ENXIO;
+		goto err_ioarea;
+	}
+
+	dev_dbg(&pdev->dev, "registers %p (%p, %p)\n",
+		i2c->regs, i2c->ioarea, res);
+
+	/* setup info block for the i2c core */
+
+	i2c->adap.algo_data = i2c;
+	i2c->adap.dev.parent = &pdev->dev;
+
+	/* initialise the i2c controller */
+
+	ret = s3c24xx_i2c_init(i2c);
+	if (ret != 0)
+		goto err_iomap;
+
+	/* find the IRQ for this unit (note, this relies on the init call to
+	 * ensure no current IRQs pending
+	 */
+
+	i2c->irq = ret = platform_get_irq(pdev, 0);
+	if (ret <= 0) {
+		dev_err(&pdev->dev, "cannot find IRQ\n");
+		goto err_iomap;
+	}
+
+	ret = request_irq(i2c->irq, s3c24xx_i2c_irq, 0,
+			  dev_name(&pdev->dev), i2c);
+
+	if (ret != 0) {
+		dev_err(&pdev->dev, "cannot claim IRQ %d\n", i2c->irq);
+		goto err_iomap;
+	}
+
+	ret = s3c24xx_i2c_register_cpufreq(i2c);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "failed to register cpufreq notifier\n");
+		goto err_irq;
+	}
+
+	/* Note, previous versions of the driver used i2c_add_adapter()
+	 * to add the bus at any number. We now pass the bus number via
+	 * the platform data, so if unset it will now default to always
+	 * being bus 0.
+	 */
+
+	i2c->adap.nr = i2c->pdata->bus_num;
+	i2c->adap.dev.of_node = pdev->dev.of_node;
+
+	ret = i2c_add_numbered_adapter(&i2c->adap);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "failed to add bus to i2c core\n");
+		goto err_cpufreq;
+	}
+
+	of_i2c_register_devices(&i2c->adap);
+	platform_set_drvdata(pdev, i2c);
+
+	pm_runtime_enable(&pdev->dev);
+	pm_runtime_enable(&i2c->adap.dev);
+
+	dev_info(&pdev->dev, "%s: S3C I2C adapter\n", dev_name(&i2c->adap.dev));
+	clk_disable(i2c->clk);
+	return 0;
+
+ err_cpufreq:
+	s3c24xx_i2c_deregister_cpufreq(i2c);
+
+ err_irq:
+	free_irq(i2c->irq, i2c);
+
+ err_iomap:
+	iounmap(i2c->regs);
+
+ err_ioarea:
+	release_resource(i2c->ioarea);
+	kfree(i2c->ioarea);
+
+ err_clk:
+	clk_disable(i2c->clk);
+	clk_put(i2c->clk);
+
+ err_noclk:
+	return ret;
+}
+
+/* s3c24xx_i2c_remove
+ *
+ * called when device is removed from the bus
+*/
+
+static int s3c24xx_i2c_remove(struct platform_device *pdev)
+{
+	struct s3c24xx_i2c *i2c = platform_get_drvdata(pdev);
+
+	pm_runtime_disable(&i2c->adap.dev);
+	pm_runtime_disable(&pdev->dev);
+
+	s3c24xx_i2c_deregister_cpufreq(i2c);
+
+	i2c_del_adapter(&i2c->adap);
+	free_irq(i2c->irq, i2c);
+
+	clk_disable(i2c->clk);
+	clk_put(i2c->clk);
+
+	iounmap(i2c->regs);
+
+	release_resource(i2c->ioarea);
+	s3c24xx_i2c_dt_gpio_free(i2c);
+	kfree(i2c->ioarea);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int s3c24xx_i2c_suspend_noirq(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct s3c24xx_i2c *i2c = platform_get_drvdata(pdev);
+
+	i2c->suspended = 1;
+
+	return 0;
+}
+
+static int s3c24xx_i2c_resume(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct s3c24xx_i2c *i2c = platform_get_drvdata(pdev);
+
+	i2c->suspended = 0;
+	clk_enable(i2c->clk);
+	s3c24xx_i2c_init(i2c);
+	clk_disable(i2c->clk);
+
+	return 0;
+}
+
+static const struct dev_pm_ops s3c24xx_i2c_dev_pm_ops = {
+	.suspend_noirq = s3c24xx_i2c_suspend_noirq,
+	.resume = s3c24xx_i2c_resume,
+};
+
+#define S3C24XX_DEV_PM_OPS (&s3c24xx_i2c_dev_pm_ops)
+#else
+#define S3C24XX_DEV_PM_OPS NULL
+#endif
+
+/* device driver for platform bus bits */
+
+static struct platform_device_id s3c24xx_driver_ids[] = {
+	{
+		.name		= "s3c2410-i2c",
+		.driver_data	= TYPE_S3C2410,
+	}, {
+		.name		= "s3c2440-i2c",
+		.driver_data	= TYPE_S3C2440,
+	}, { },
+};
+MODULE_DEVICE_TABLE(platform, s3c24xx_driver_ids);
+
+#ifdef CONFIG_OF
+static const struct of_device_id s3c24xx_i2c_match[] = {
+	{ .compatible = "samsung,s3c2410-i2c" },
+	{ .compatible = "samsung,s3c2440-i2c" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, s3c24xx_i2c_match);
+#else
+#define s3c24xx_i2c_match NULL
+#endif
+
+static struct platform_driver s3c24xx_i2c_driver = {
+	.probe		= s3c24xx_i2c_probe,
+	.remove		= s3c24xx_i2c_remove,
+	.id_table	= s3c24xx_driver_ids,
+	.driver		= {
+		.owner	= THIS_MODULE,
+		.name	= "s3c-i2c",
+		.pm	= S3C24XX_DEV_PM_OPS,
+		.of_match_table = s3c24xx_i2c_match,
+	},
+};
+
+static int __init i2c_adap_s3c_init(void)
+{
+	return platform_driver_register(&s3c24xx_i2c_driver);
+}
+subsys_initcall(i2c_adap_s3c_init);
+
+static void __exit i2c_adap_s3c_exit(void)
+{
+	platform_driver_unregister(&s3c24xx_i2c_driver);
+}
+module_exit(i2c_adap_s3c_exit);
+
+MODULE_DESCRIPTION("S3C24XX I2C Bus driver");
+MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
+MODULE_LICENSE("GPL");
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-s6000.c b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-s6000.c
new file mode 100644
index 0000000..c64ba73
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-s6000.c
@@ -0,0 +1,404 @@
+/*
+ * drivers/i2c/busses/i2c-s6000.c
+ *
+ * Description: Driver for S6000 Family I2C Interface
+ * Copyright (c) 2008 emlix GmbH
+ * Author:	Oskar Schirmer <os@emlix.com>
+ *
+ * Partially based on i2c-bfin-twi.c driver by <sonic.zhang@analog.com>
+ * Copyright (c) 2005-2007 Analog Devices, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/i2c/s6000.h>
+#include <linux/timer.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+#include "i2c-s6000.h"
+
+#define DRV_NAME "i2c-s6000"
+
+#define POLL_TIMEOUT	(2 * HZ)
+
+struct s6i2c_if {
+	u8 __iomem		*reg; /* memory mapped registers */
+	int			irq;
+	spinlock_t		lock;
+	struct i2c_msg		*msgs; /* messages currently handled */
+	int			msgs_num; /* nb of msgs to do */
+	int			msgs_push; /* nb of msgs read/written */
+	int			msgs_done; /* nb of msgs finally handled */
+	unsigned		push; /* nb of bytes read/written in msg */
+	unsigned		done; /* nb of bytes finally handled */
+	int			timeout_count; /* timeout retries left */
+	struct timer_list	timeout_timer;
+	struct i2c_adapter	adap;
+	struct completion	complete;
+	struct clk		*clk;
+	struct resource		*res;
+};
+
+static inline u16 i2c_rd16(struct s6i2c_if *iface, unsigned n)
+{
+	return readw(iface->reg + (n));
+}
+
+static inline void i2c_wr16(struct s6i2c_if *iface, unsigned n, u16 v)
+{
+	writew(v, iface->reg + (n));
+}
+
+static inline u32 i2c_rd32(struct s6i2c_if *iface, unsigned n)
+{
+	return readl(iface->reg + (n));
+}
+
+static inline void i2c_wr32(struct s6i2c_if *iface, unsigned n, u32 v)
+{
+	writel(v, iface->reg + (n));
+}
+
+static struct s6i2c_if s6i2c_if;
+
+static void s6i2c_handle_interrupt(struct s6i2c_if *iface)
+{
+	if (i2c_rd16(iface, S6_I2C_INTRSTAT) & (1 << S6_I2C_INTR_TXABRT)) {
+		i2c_rd16(iface, S6_I2C_CLRTXABRT);
+		i2c_wr16(iface, S6_I2C_INTRMASK, 0);
+		complete(&iface->complete);
+		return;
+	}
+	if (iface->msgs_done >= iface->msgs_num) {
+		dev_err(&iface->adap.dev, "s6i2c: spurious I2C irq: %04x\n",
+			i2c_rd16(iface, S6_I2C_INTRSTAT));
+		i2c_wr16(iface, S6_I2C_INTRMASK, 0);
+		return;
+	}
+	while ((iface->msgs_push < iface->msgs_num)
+	    && (i2c_rd16(iface, S6_I2C_STATUS) & (1 << S6_I2C_STATUS_TFNF))) {
+		struct i2c_msg *m = &iface->msgs[iface->msgs_push];
+		if (!(m->flags & I2C_M_RD))
+			i2c_wr16(iface, S6_I2C_DATACMD, m->buf[iface->push]);
+		else
+			i2c_wr16(iface, S6_I2C_DATACMD,
+				 1 << S6_I2C_DATACMD_READ);
+		if (++iface->push >= m->len) {
+			iface->push = 0;
+			iface->msgs_push += 1;
+		}
+	}
+	do {
+		struct i2c_msg *m = &iface->msgs[iface->msgs_done];
+		if (!(m->flags & I2C_M_RD)) {
+			if (iface->msgs_done < iface->msgs_push)
+				iface->msgs_done += 1;
+			else
+				break;
+		} else if (i2c_rd16(iface, S6_I2C_STATUS)
+				& (1 << S6_I2C_STATUS_RFNE)) {
+			m->buf[iface->done] = i2c_rd16(iface, S6_I2C_DATACMD);
+			if (++iface->done >= m->len) {
+				iface->done = 0;
+				iface->msgs_done += 1;
+			}
+		} else{
+			break;
+		}
+	} while (iface->msgs_done < iface->msgs_num);
+	if (iface->msgs_done >= iface->msgs_num) {
+		i2c_wr16(iface, S6_I2C_INTRMASK, 1 << S6_I2C_INTR_TXABRT);
+		complete(&iface->complete);
+	} else if (iface->msgs_push >= iface->msgs_num) {
+		i2c_wr16(iface, S6_I2C_INTRMASK, (1 << S6_I2C_INTR_TXABRT) |
+						 (1 << S6_I2C_INTR_RXFULL));
+	} else {
+		i2c_wr16(iface, S6_I2C_INTRMASK, (1 << S6_I2C_INTR_TXABRT) |
+						 (1 << S6_I2C_INTR_TXEMPTY) |
+						 (1 << S6_I2C_INTR_RXFULL));
+	}
+}
+
+static irqreturn_t s6i2c_interrupt_entry(int irq, void *dev_id)
+{
+	struct s6i2c_if *iface = dev_id;
+	if (!(i2c_rd16(iface, S6_I2C_STATUS) & ((1 << S6_I2C_INTR_RXUNDER)
+					      | (1 << S6_I2C_INTR_RXOVER)
+					      | (1 << S6_I2C_INTR_RXFULL)
+					      | (1 << S6_I2C_INTR_TXOVER)
+					      | (1 << S6_I2C_INTR_TXEMPTY)
+					      | (1 << S6_I2C_INTR_RDREQ)
+					      | (1 << S6_I2C_INTR_TXABRT)
+					      | (1 << S6_I2C_INTR_RXDONE)
+					      | (1 << S6_I2C_INTR_ACTIVITY)
+					      | (1 << S6_I2C_INTR_STOPDET)
+					      | (1 << S6_I2C_INTR_STARTDET)
+					      | (1 << S6_I2C_INTR_GENCALL))))
+		return IRQ_NONE;
+
+	spin_lock(&iface->lock);
+	del_timer(&iface->timeout_timer);
+	s6i2c_handle_interrupt(iface);
+	spin_unlock(&iface->lock);
+	return IRQ_HANDLED;
+}
+
+static void s6i2c_timeout(unsigned long data)
+{
+	struct s6i2c_if *iface = (struct s6i2c_if *)data;
+	unsigned long flags;
+
+	spin_lock_irqsave(&iface->lock, flags);
+	s6i2c_handle_interrupt(iface);
+	if (--iface->timeout_count > 0) {
+		iface->timeout_timer.expires = jiffies + POLL_TIMEOUT;
+		add_timer(&iface->timeout_timer);
+	} else {
+		complete(&iface->complete);
+		i2c_wr16(iface, S6_I2C_INTRMASK, 0);
+	}
+	spin_unlock_irqrestore(&iface->lock, flags);
+}
+
+static int s6i2c_master_xfer(struct i2c_adapter *adap,
+				struct i2c_msg *msgs, int num)
+{
+	struct s6i2c_if *iface = adap->algo_data;
+	int i;
+	if (num == 0)
+		return 0;
+	if (i2c_rd16(iface, S6_I2C_STATUS) & (1 << S6_I2C_STATUS_ACTIVITY))
+		yield();
+	i2c_wr16(iface, S6_I2C_INTRMASK, 0);
+	i2c_rd16(iface, S6_I2C_CLRINTR);
+	for (i = 0; i < num; i++) {
+		if (msgs[i].flags & I2C_M_TEN) {
+			dev_err(&adap->dev,
+				"s6i2c: 10 bits addr not supported\n");
+			return -EINVAL;
+		}
+		if (msgs[i].len == 0) {
+			dev_err(&adap->dev,
+				"s6i2c: zero length message not supported\n");
+			return -EINVAL;
+		}
+		if (msgs[i].addr != msgs[0].addr) {
+			dev_err(&adap->dev,
+				"s6i2c: multiple xfer cannot change target\n");
+			return -EINVAL;
+		}
+	}
+
+	iface->msgs = msgs;
+	iface->msgs_num = num;
+	iface->msgs_push = 0;
+	iface->msgs_done = 0;
+	iface->push = 0;
+	iface->done = 0;
+	iface->timeout_count = 10;
+	i2c_wr16(iface, S6_I2C_TAR, msgs[0].addr);
+	i2c_wr16(iface, S6_I2C_ENABLE, 1);
+	i2c_wr16(iface, S6_I2C_INTRMASK, (1 << S6_I2C_INTR_TXEMPTY) |
+					 (1 << S6_I2C_INTR_TXABRT));
+
+	iface->timeout_timer.expires = jiffies + POLL_TIMEOUT;
+	add_timer(&iface->timeout_timer);
+	wait_for_completion(&iface->complete);
+	del_timer_sync(&iface->timeout_timer);
+	while (i2c_rd32(iface, S6_I2C_TXFLR) > 0)
+		schedule();
+	while (i2c_rd16(iface, S6_I2C_STATUS) & (1 << S6_I2C_STATUS_ACTIVITY))
+		schedule();
+
+	i2c_wr16(iface, S6_I2C_INTRMASK, 0);
+	i2c_wr16(iface, S6_I2C_ENABLE, 0);
+	return iface->msgs_done;
+}
+
+static u32 s6i2c_functionality(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static struct i2c_algorithm s6i2c_algorithm = {
+	.master_xfer   = s6i2c_master_xfer,
+	.functionality = s6i2c_functionality,
+};
+
+static u16 __devinit nanoseconds_on_clk(struct s6i2c_if *iface, u32 ns)
+{
+	u32 dividend = ((clk_get_rate(iface->clk) / 1000) * ns) / 1000000;
+	if (dividend > 0xffff)
+		return 0xffff;
+	return dividend;
+}
+
+static int __devinit s6i2c_probe(struct platform_device *dev)
+{
+	struct s6i2c_if *iface = &s6i2c_if;
+	struct i2c_adapter *p_adap;
+	const char *clock;
+	int bus_num, rc;
+	spin_lock_init(&iface->lock);
+	init_completion(&iface->complete);
+	iface->irq = platform_get_irq(dev, 0);
+	if (iface->irq < 0) {
+		rc = iface->irq;
+		goto err_out;
+	}
+	iface->res = platform_get_resource(dev, IORESOURCE_MEM, 0);
+	if (!iface->res) {
+		rc = -ENXIO;
+		goto err_out;
+	}
+	iface->res = request_mem_region(iface->res->start,
+					resource_size(iface->res),
+					dev->dev.bus_id);
+	if (!iface->res) {
+		rc = -EBUSY;
+		goto err_out;
+	}
+	iface->reg = ioremap_nocache(iface->res->start,
+				     resource_size(iface->res));
+	if (!iface->reg) {
+		rc = -ENOMEM;
+		goto err_reg;
+	}
+
+	clock = 0;
+	bus_num = -1;
+	if (dev->dev.platform_data) {
+		struct s6_i2c_platform_data *pdata = dev->dev.platform_data;
+		bus_num = pdata->bus_num;
+		clock = pdata->clock;
+	}
+	iface->clk = clk_get(&dev->dev, clock);
+	if (IS_ERR(iface->clk)) {
+		rc = PTR_ERR(iface->clk);
+		goto err_map;
+	}
+	rc = clk_enable(iface->clk);
+	if (rc < 0)
+		goto err_clk_put;
+	init_timer(&iface->timeout_timer);
+	iface->timeout_timer.function = s6i2c_timeout;
+	iface->timeout_timer.data = (unsigned long)iface;
+
+	p_adap = &iface->adap;
+	strlcpy(p_adap->name, dev->name, sizeof(p_adap->name));
+	p_adap->algo = &s6i2c_algorithm;
+	p_adap->algo_data = iface;
+	p_adap->nr = bus_num;
+	p_adap->class = 0;
+	p_adap->dev.parent = &dev->dev;
+	i2c_wr16(iface, S6_I2C_INTRMASK, 0);
+	rc = request_irq(iface->irq, s6i2c_interrupt_entry,
+			 IRQF_SHARED, dev->name, iface);
+	if (rc) {
+		dev_err(&p_adap->dev, "s6i2c: can't get IRQ %d\n", iface->irq);
+		goto err_clk_dis;
+	}
+
+	i2c_wr16(iface, S6_I2C_ENABLE, 0);
+	udelay(1);
+	i2c_wr32(iface, S6_I2C_SRESET, 1 << S6_I2C_SRESET_IC_SRST);
+	i2c_wr16(iface, S6_I2C_CLRTXABRT, 1);
+	i2c_wr16(iface, S6_I2C_CON,
+			(1 << S6_I2C_CON_MASTER) |
+			(S6_I2C_CON_SPEED_NORMAL << S6_I2C_CON_SPEED) |
+			(0 << S6_I2C_CON_10BITSLAVE) |
+			(0 << S6_I2C_CON_10BITMASTER) |
+			(1 << S6_I2C_CON_RESTARTENA) |
+			(1 << S6_I2C_CON_SLAVEDISABLE));
+	i2c_wr16(iface, S6_I2C_SSHCNT, nanoseconds_on_clk(iface, 4000));
+	i2c_wr16(iface, S6_I2C_SSLCNT, nanoseconds_on_clk(iface, 4700));
+	i2c_wr16(iface, S6_I2C_FSHCNT, nanoseconds_on_clk(iface, 600));
+	i2c_wr16(iface, S6_I2C_FSLCNT, nanoseconds_on_clk(iface, 1300));
+	i2c_wr16(iface, S6_I2C_RXTL, 0);
+	i2c_wr16(iface, S6_I2C_TXTL, 0);
+
+	platform_set_drvdata(dev, iface);
+	rc = i2c_add_numbered_adapter(p_adap);
+	if (rc)
+		goto err_irq_free;
+	return 0;
+
+err_irq_free:
+	free_irq(iface->irq, iface);
+err_clk_dis:
+	clk_disable(iface->clk);
+err_clk_put:
+	clk_put(iface->clk);
+err_map:
+	iounmap(iface->reg);
+err_reg:
+	release_mem_region(iface->res->start,
+			   resource_size(iface->res));
+err_out:
+	return rc;
+}
+
+static int __devexit s6i2c_remove(struct platform_device *pdev)
+{
+	struct s6i2c_if *iface = platform_get_drvdata(pdev);
+	i2c_wr16(iface, S6_I2C_ENABLE, 0);
+	platform_set_drvdata(pdev, NULL);
+	i2c_del_adapter(&iface->adap);
+	free_irq(iface->irq, iface);
+	clk_disable(iface->clk);
+	clk_put(iface->clk);
+	iounmap(iface->reg);
+	release_mem_region(iface->res->start,
+			   resource_size(iface->res));
+	return 0;
+}
+
+static struct platform_driver s6i2c_driver = {
+	.probe		= s6i2c_probe,
+	.remove		= __devexit_p(s6i2c_remove),
+	.driver		= {
+		.name	= DRV_NAME,
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init s6i2c_init(void)
+{
+	pr_info("I2C: S6000 I2C driver\n");
+	return platform_driver_register(&s6i2c_driver);
+}
+
+static void __exit s6i2c_exit(void)
+{
+	platform_driver_unregister(&s6i2c_driver);
+}
+
+MODULE_DESCRIPTION("I2C-Bus adapter routines for S6000 I2C");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
+
+subsys_initcall(s6i2c_init);
+module_exit(s6i2c_exit);
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-s6000.h b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-s6000.h
new file mode 100644
index 0000000..ff23b81
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-s6000.h
@@ -0,0 +1,79 @@
+/*
+ * drivers/i2c/busses/i2c-s6000.h
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2008 Emlix GmbH <info@emlix.com>
+ * Author:	Oskar Schirmer <os@emlix.com>
+ */
+
+#ifndef __DRIVERS_I2C_BUSSES_I2C_S6000_H
+#define __DRIVERS_I2C_BUSSES_I2C_S6000_H
+
+#define S6_I2C_CON		0x000
+#define S6_I2C_CON_MASTER		0
+#define S6_I2C_CON_SPEED		1
+#define S6_I2C_CON_SPEED_NORMAL			1
+#define S6_I2C_CON_SPEED_FAST			2
+#define S6_I2C_CON_SPEED_MASK			3
+#define S6_I2C_CON_10BITSLAVE		3
+#define S6_I2C_CON_10BITMASTER		4
+#define S6_I2C_CON_RESTARTENA		5
+#define S6_I2C_CON_SLAVEDISABLE		6
+#define S6_I2C_TAR		0x004
+#define S6_I2C_TAR_GCORSTART		10
+#define S6_I2C_TAR_SPECIAL		11
+#define S6_I2C_SAR		0x008
+#define S6_I2C_HSMADDR		0x00C
+#define S6_I2C_DATACMD		0x010
+#define S6_I2C_DATACMD_READ		8
+#define S6_I2C_SSHCNT		0x014
+#define S6_I2C_SSLCNT		0x018
+#define S6_I2C_FSHCNT		0x01C
+#define S6_I2C_FSLCNT		0x020
+#define S6_I2C_INTRSTAT		0x02C
+#define S6_I2C_INTRMASK		0x030
+#define S6_I2C_RAWINTR		0x034
+#define S6_I2C_INTR_RXUNDER		0
+#define S6_I2C_INTR_RXOVER		1
+#define S6_I2C_INTR_RXFULL		2
+#define S6_I2C_INTR_TXOVER		3
+#define S6_I2C_INTR_TXEMPTY		4
+#define S6_I2C_INTR_RDREQ		5
+#define S6_I2C_INTR_TXABRT		6
+#define S6_I2C_INTR_RXDONE		7
+#define S6_I2C_INTR_ACTIVITY		8
+#define S6_I2C_INTR_STOPDET		9
+#define S6_I2C_INTR_STARTDET		10
+#define S6_I2C_INTR_GENCALL		11
+#define S6_I2C_RXTL		0x038
+#define S6_I2C_TXTL		0x03C
+#define S6_I2C_CLRINTR		0x040
+#define S6_I2C_CLRRXUNDER	0x044
+#define S6_I2C_CLRRXOVER	0x048
+#define S6_I2C_CLRTXOVER	0x04C
+#define S6_I2C_CLRRDREQ		0x050
+#define S6_I2C_CLRTXABRT	0x054
+#define S6_I2C_CLRRXDONE	0x058
+#define S6_I2C_CLRACTIVITY	0x05C
+#define S6_I2C_CLRSTOPDET	0x060
+#define S6_I2C_CLRSTARTDET	0x064
+#define S6_I2C_CLRGENCALL	0x068
+#define S6_I2C_ENABLE		0x06C
+#define S6_I2C_STATUS		0x070
+#define S6_I2C_STATUS_ACTIVITY		0
+#define S6_I2C_STATUS_TFNF		1
+#define S6_I2C_STATUS_TFE		2
+#define S6_I2C_STATUS_RFNE		3
+#define S6_I2C_STATUS_RFF		4
+#define S6_I2C_TXFLR		0x074
+#define S6_I2C_RXFLR		0x078
+#define S6_I2C_SRESET		0x07C
+#define S6_I2C_SRESET_IC_SRST		0
+#define S6_I2C_SRESET_IC_MASTER_SRST	1
+#define S6_I2C_SRESET_IC_SLAVE_SRST	2
+#define S6_I2C_TXABRTSOURCE	0x080
+
+#endif
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-scmi.c b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-scmi.c
new file mode 100644
index 0000000..388cbdc
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-scmi.c
@@ -0,0 +1,445 @@
+/*
+ * SMBus driver for ACPI SMBus CMI
+ *
+ * Copyright (C) 2009 Crane Cai <crane.cai@amd.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/stddef.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/acpi.h>
+
+#define ACPI_SMBUS_HC_CLASS		"smbus"
+#define ACPI_SMBUS_HC_DEVICE_NAME	"cmi"
+
+ACPI_MODULE_NAME("smbus_cmi");
+
+struct smbus_methods_t {
+	char *mt_info;
+	char *mt_sbr;
+	char *mt_sbw;
+};
+
+struct acpi_smbus_cmi {
+	acpi_handle handle;
+	struct i2c_adapter adapter;
+	u8 cap_info:1;
+	u8 cap_read:1;
+	u8 cap_write:1;
+	struct smbus_methods_t *methods;
+};
+
+static const struct smbus_methods_t smbus_methods = {
+	.mt_info = "_SBI",
+	.mt_sbr  = "_SBR",
+	.mt_sbw  = "_SBW",
+};
+
+/* Some IBM BIOSes omit the leading underscore */
+static const struct smbus_methods_t ibm_smbus_methods = {
+	.mt_info = "SBI_",
+	.mt_sbr  = "SBR_",
+	.mt_sbw  = "SBW_",
+};
+
+static const struct acpi_device_id acpi_smbus_cmi_ids[] = {
+	{"SMBUS01", (kernel_ulong_t)&smbus_methods},
+	{ACPI_SMBUS_IBM_HID, (kernel_ulong_t)&ibm_smbus_methods},
+	{"", 0}
+};
+MODULE_DEVICE_TABLE(acpi, acpi_smbus_cmi_ids);
+
+#define ACPI_SMBUS_STATUS_OK			0x00
+#define ACPI_SMBUS_STATUS_FAIL			0x07
+#define ACPI_SMBUS_STATUS_DNAK			0x10
+#define ACPI_SMBUS_STATUS_DERR			0x11
+#define ACPI_SMBUS_STATUS_CMD_DENY		0x12
+#define ACPI_SMBUS_STATUS_UNKNOWN		0x13
+#define ACPI_SMBUS_STATUS_ACC_DENY		0x17
+#define ACPI_SMBUS_STATUS_TIMEOUT		0x18
+#define ACPI_SMBUS_STATUS_NOTSUP		0x19
+#define ACPI_SMBUS_STATUS_BUSY			0x1a
+#define ACPI_SMBUS_STATUS_PEC			0x1f
+
+#define ACPI_SMBUS_PRTCL_WRITE			0x00
+#define ACPI_SMBUS_PRTCL_READ			0x01
+#define ACPI_SMBUS_PRTCL_QUICK			0x02
+#define ACPI_SMBUS_PRTCL_BYTE			0x04
+#define ACPI_SMBUS_PRTCL_BYTE_DATA		0x06
+#define ACPI_SMBUS_PRTCL_WORD_DATA		0x08
+#define ACPI_SMBUS_PRTCL_BLOCK_DATA		0x0a
+
+
+static int
+acpi_smbus_cmi_access(struct i2c_adapter *adap, u16 addr, unsigned short flags,
+		   char read_write, u8 command, int size,
+		   union i2c_smbus_data *data)
+{
+	int result = 0;
+	struct acpi_smbus_cmi *smbus_cmi = adap->algo_data;
+	unsigned char protocol;
+	acpi_status status = 0;
+	struct acpi_object_list input;
+	union acpi_object mt_params[5];
+	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+	union acpi_object *obj;
+	union acpi_object *pkg;
+	char *method;
+	int len = 0;
+
+	dev_dbg(&adap->dev, "access size: %d %s\n", size,
+		(read_write) ? "READ" : "WRITE");
+	switch (size) {
+	case I2C_SMBUS_QUICK:
+		protocol = ACPI_SMBUS_PRTCL_QUICK;
+		command = 0;
+		if (read_write == I2C_SMBUS_WRITE) {
+			mt_params[3].type = ACPI_TYPE_INTEGER;
+			mt_params[3].integer.value = 0;
+			mt_params[4].type = ACPI_TYPE_INTEGER;
+			mt_params[4].integer.value = 0;
+		}
+		break;
+
+	case I2C_SMBUS_BYTE:
+		protocol = ACPI_SMBUS_PRTCL_BYTE;
+		if (read_write == I2C_SMBUS_WRITE) {
+			mt_params[3].type = ACPI_TYPE_INTEGER;
+			mt_params[3].integer.value = 0;
+			mt_params[4].type = ACPI_TYPE_INTEGER;
+			mt_params[4].integer.value = 0;
+		} else {
+			command = 0;
+		}
+		break;
+
+	case I2C_SMBUS_BYTE_DATA:
+		protocol = ACPI_SMBUS_PRTCL_BYTE_DATA;
+		if (read_write == I2C_SMBUS_WRITE) {
+			mt_params[3].type = ACPI_TYPE_INTEGER;
+			mt_params[3].integer.value = 1;
+			mt_params[4].type = ACPI_TYPE_INTEGER;
+			mt_params[4].integer.value = data->byte;
+		}
+		break;
+
+	case I2C_SMBUS_WORD_DATA:
+		protocol = ACPI_SMBUS_PRTCL_WORD_DATA;
+		if (read_write == I2C_SMBUS_WRITE) {
+			mt_params[3].type = ACPI_TYPE_INTEGER;
+			mt_params[3].integer.value = 2;
+			mt_params[4].type = ACPI_TYPE_INTEGER;
+			mt_params[4].integer.value = data->word;
+		}
+		break;
+
+	case I2C_SMBUS_BLOCK_DATA:
+		protocol = ACPI_SMBUS_PRTCL_BLOCK_DATA;
+		if (read_write == I2C_SMBUS_WRITE) {
+			len = data->block[0];
+			if (len == 0 || len > I2C_SMBUS_BLOCK_MAX)
+				return -EINVAL;
+			mt_params[3].type = ACPI_TYPE_INTEGER;
+			mt_params[3].integer.value = len;
+			mt_params[4].type = ACPI_TYPE_BUFFER;
+			mt_params[4].buffer.pointer = data->block + 1;
+		}
+		break;
+
+	default:
+		dev_warn(&adap->dev, "Unsupported transaction %d\n", size);
+		return -EOPNOTSUPP;
+	}
+
+	if (read_write == I2C_SMBUS_READ) {
+		protocol |= ACPI_SMBUS_PRTCL_READ;
+		method = smbus_cmi->methods->mt_sbr;
+		input.count = 3;
+	} else {
+		protocol |= ACPI_SMBUS_PRTCL_WRITE;
+		method = smbus_cmi->methods->mt_sbw;
+		input.count = 5;
+	}
+
+	input.pointer = mt_params;
+	mt_params[0].type = ACPI_TYPE_INTEGER;
+	mt_params[0].integer.value = protocol;
+	mt_params[1].type = ACPI_TYPE_INTEGER;
+	mt_params[1].integer.value = addr;
+	mt_params[2].type = ACPI_TYPE_INTEGER;
+	mt_params[2].integer.value = command;
+
+	status = acpi_evaluate_object(smbus_cmi->handle, method, &input,
+				      &buffer);
+	if (ACPI_FAILURE(status)) {
+		ACPI_ERROR((AE_INFO, "Evaluating %s: %i", method, status));
+		return -EIO;
+	}
+
+	pkg = buffer.pointer;
+	if (pkg && pkg->type == ACPI_TYPE_PACKAGE)
+		obj = pkg->package.elements;
+	else {
+		ACPI_ERROR((AE_INFO, "Invalid argument type"));
+		result = -EIO;
+		goto out;
+	}
+	if (obj == NULL || obj->type != ACPI_TYPE_INTEGER) {
+		ACPI_ERROR((AE_INFO, "Invalid argument type"));
+		result = -EIO;
+		goto out;
+	}
+
+	result = obj->integer.value;
+	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s return status: %i\n",
+			  method, result));
+
+	switch (result) {
+	case ACPI_SMBUS_STATUS_OK:
+		result = 0;
+		break;
+	case ACPI_SMBUS_STATUS_BUSY:
+		result = -EBUSY;
+		goto out;
+	case ACPI_SMBUS_STATUS_TIMEOUT:
+		result = -ETIMEDOUT;
+		goto out;
+	case ACPI_SMBUS_STATUS_DNAK:
+		result = -ENXIO;
+		goto out;
+	default:
+		result = -EIO;
+		goto out;
+	}
+
+	if (read_write == I2C_SMBUS_WRITE || size == I2C_SMBUS_QUICK)
+		goto out;
+
+	obj = pkg->package.elements + 1;
+	if (obj == NULL || obj->type != ACPI_TYPE_INTEGER) {
+		ACPI_ERROR((AE_INFO, "Invalid argument type"));
+		result = -EIO;
+		goto out;
+	}
+
+	len = obj->integer.value;
+	obj = pkg->package.elements + 2;
+	switch (size) {
+	case I2C_SMBUS_BYTE:
+	case I2C_SMBUS_BYTE_DATA:
+	case I2C_SMBUS_WORD_DATA:
+		if (obj == NULL || obj->type != ACPI_TYPE_INTEGER) {
+			ACPI_ERROR((AE_INFO, "Invalid argument type"));
+			result = -EIO;
+			goto out;
+		}
+		if (len == 2)
+			data->word = obj->integer.value;
+		else
+			data->byte = obj->integer.value;
+		break;
+	case I2C_SMBUS_BLOCK_DATA:
+		if (obj == NULL || obj->type != ACPI_TYPE_BUFFER) {
+			ACPI_ERROR((AE_INFO, "Invalid argument type"));
+			result = -EIO;
+			goto out;
+		}
+		if (len == 0 || len > I2C_SMBUS_BLOCK_MAX)
+			return -EPROTO;
+		data->block[0] = len;
+		memcpy(data->block + 1, obj->buffer.pointer, len);
+		break;
+	}
+
+out:
+	kfree(buffer.pointer);
+	dev_dbg(&adap->dev, "Transaction status: %i\n", result);
+	return result;
+}
+
+static u32 acpi_smbus_cmi_func(struct i2c_adapter *adapter)
+{
+	struct acpi_smbus_cmi *smbus_cmi = adapter->algo_data;
+	u32 ret;
+
+	ret = smbus_cmi->cap_read | smbus_cmi->cap_write ?
+		I2C_FUNC_SMBUS_QUICK : 0;
+
+	ret |= smbus_cmi->cap_read ?
+		(I2C_FUNC_SMBUS_READ_BYTE |
+		I2C_FUNC_SMBUS_READ_BYTE_DATA |
+		I2C_FUNC_SMBUS_READ_WORD_DATA |
+		I2C_FUNC_SMBUS_READ_BLOCK_DATA) : 0;
+
+	ret |= smbus_cmi->cap_write ?
+		(I2C_FUNC_SMBUS_WRITE_BYTE |
+		I2C_FUNC_SMBUS_WRITE_BYTE_DATA |
+		I2C_FUNC_SMBUS_WRITE_WORD_DATA |
+		I2C_FUNC_SMBUS_WRITE_BLOCK_DATA) : 0;
+
+	return ret;
+}
+
+static const struct i2c_algorithm acpi_smbus_cmi_algorithm = {
+	.smbus_xfer = acpi_smbus_cmi_access,
+	.functionality = acpi_smbus_cmi_func,
+};
+
+
+static int acpi_smbus_cmi_add_cap(struct acpi_smbus_cmi *smbus_cmi,
+				  const char *name)
+{
+	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+	union acpi_object *obj;
+	acpi_status status;
+
+	if (!strcmp(name, smbus_cmi->methods->mt_info)) {
+		status = acpi_evaluate_object(smbus_cmi->handle,
+					smbus_cmi->methods->mt_info,
+					NULL, &buffer);
+		if (ACPI_FAILURE(status)) {
+			ACPI_ERROR((AE_INFO, "Evaluating %s: %i",
+				   smbus_cmi->methods->mt_info, status));
+			return -EIO;
+		}
+
+		obj = buffer.pointer;
+		if (obj && obj->type == ACPI_TYPE_PACKAGE)
+			obj = obj->package.elements;
+		else {
+			ACPI_ERROR((AE_INFO, "Invalid argument type"));
+			kfree(buffer.pointer);
+			return -EIO;
+		}
+
+		if (obj->type != ACPI_TYPE_INTEGER) {
+			ACPI_ERROR((AE_INFO, "Invalid argument type"));
+			kfree(buffer.pointer);
+			return -EIO;
+		} else
+			ACPI_DEBUG_PRINT((ACPI_DB_INFO, "SMBus CMI Version %x"
+					  "\n", (int)obj->integer.value));
+
+		kfree(buffer.pointer);
+		smbus_cmi->cap_info = 1;
+	} else if (!strcmp(name, smbus_cmi->methods->mt_sbr))
+		smbus_cmi->cap_read = 1;
+	else if (!strcmp(name, smbus_cmi->methods->mt_sbw))
+		smbus_cmi->cap_write = 1;
+	else
+		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Unsupported CMI method: %s\n",
+				 name));
+
+	return 0;
+}
+
+static acpi_status acpi_smbus_cmi_query_methods(acpi_handle handle, u32 level,
+			void *context, void **return_value)
+{
+	char node_name[5];
+	struct acpi_buffer buffer = { sizeof(node_name), node_name };
+	struct acpi_smbus_cmi *smbus_cmi = context;
+	acpi_status status;
+
+	status = acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer);
+
+	if (ACPI_SUCCESS(status))
+		acpi_smbus_cmi_add_cap(smbus_cmi, node_name);
+
+	return AE_OK;
+}
+
+static int acpi_smbus_cmi_add(struct acpi_device *device)
+{
+	struct acpi_smbus_cmi *smbus_cmi;
+	const struct acpi_device_id *id;
+
+	smbus_cmi = kzalloc(sizeof(struct acpi_smbus_cmi), GFP_KERNEL);
+	if (!smbus_cmi)
+		return -ENOMEM;
+
+	smbus_cmi->handle = device->handle;
+	strcpy(acpi_device_name(device), ACPI_SMBUS_HC_DEVICE_NAME);
+	strcpy(acpi_device_class(device), ACPI_SMBUS_HC_CLASS);
+	device->driver_data = smbus_cmi;
+	smbus_cmi->cap_info = 0;
+	smbus_cmi->cap_read = 0;
+	smbus_cmi->cap_write = 0;
+
+	for (id = acpi_smbus_cmi_ids; id->id[0]; id++)
+		if (!strcmp(id->id, acpi_device_hid(device)))
+			smbus_cmi->methods =
+				(struct smbus_methods_t *) id->driver_data;
+
+	acpi_walk_namespace(ACPI_TYPE_METHOD, smbus_cmi->handle, 1,
+			    acpi_smbus_cmi_query_methods, NULL, smbus_cmi, NULL);
+
+	if (smbus_cmi->cap_info == 0)
+		goto err;
+
+	snprintf(smbus_cmi->adapter.name, sizeof(smbus_cmi->adapter.name),
+		"SMBus CMI adapter %s",
+		acpi_device_name(device));
+	smbus_cmi->adapter.owner = THIS_MODULE;
+	smbus_cmi->adapter.algo = &acpi_smbus_cmi_algorithm;
+	smbus_cmi->adapter.algo_data = smbus_cmi;
+	smbus_cmi->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
+	smbus_cmi->adapter.dev.parent = &device->dev;
+
+	if (i2c_add_adapter(&smbus_cmi->adapter)) {
+		dev_err(&device->dev, "Couldn't register adapter!\n");
+		goto err;
+	}
+
+	return 0;
+
+err:
+	kfree(smbus_cmi);
+	device->driver_data = NULL;
+	return -EIO;
+}
+
+static int acpi_smbus_cmi_remove(struct acpi_device *device, int type)
+{
+	struct acpi_smbus_cmi *smbus_cmi = acpi_driver_data(device);
+
+	i2c_del_adapter(&smbus_cmi->adapter);
+	kfree(smbus_cmi);
+	device->driver_data = NULL;
+
+	return 0;
+}
+
+static struct acpi_driver acpi_smbus_cmi_driver = {
+	.name = ACPI_SMBUS_HC_DEVICE_NAME,
+	.class = ACPI_SMBUS_HC_CLASS,
+	.ids = acpi_smbus_cmi_ids,
+	.ops = {
+		.add = acpi_smbus_cmi_add,
+		.remove = acpi_smbus_cmi_remove,
+	},
+};
+
+static int __init acpi_smbus_cmi_init(void)
+{
+	return acpi_bus_register_driver(&acpi_smbus_cmi_driver);
+}
+
+static void __exit acpi_smbus_cmi_exit(void)
+{
+	acpi_bus_unregister_driver(&acpi_smbus_cmi_driver);
+}
+
+module_init(acpi_smbus_cmi_init);
+module_exit(acpi_smbus_cmi_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Crane Cai <crane.cai@amd.com>");
+MODULE_DESCRIPTION("ACPI SMBus CMI driver");
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-sh7760.c b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-sh7760.c
new file mode 100644
index 0000000..c0c9dff
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-sh7760.c
@@ -0,0 +1,567 @@
+/*
+ * I2C bus driver for the SH7760 I2C Interfaces.
+ *
+ * (c) 2005-2008 MSC Vertriebsges.m.b.H, Manuel Lauss <mlau@msc-ge.com>
+ *
+ * licensed under the terms outlined in the file COPYING.
+ *
+ */
+
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/module.h>
+
+#include <asm/clock.h>
+#include <asm/i2c-sh7760.h>
+
+/* register offsets */
+#define I2CSCR		0x0		/* slave ctrl		*/
+#define I2CMCR		0x4		/* master ctrl		*/
+#define I2CSSR		0x8		/* slave status		*/
+#define I2CMSR		0xC		/* master status	*/
+#define I2CSIER		0x10		/* slave irq enable	*/
+#define I2CMIER		0x14		/* master irq enable	*/
+#define I2CCCR		0x18		/* clock dividers	*/
+#define I2CSAR		0x1c		/* slave address	*/
+#define I2CMAR		0x20		/* master address	*/
+#define I2CRXTX		0x24		/* data port		*/
+#define I2CFCR		0x28		/* fifo control		*/
+#define I2CFSR		0x2C		/* fifo status		*/
+#define I2CFIER		0x30		/* fifo irq enable	*/
+#define I2CRFDR		0x34		/* rx fifo count	*/
+#define I2CTFDR		0x38		/* tx fifo count	*/
+
+#define REGSIZE		0x3C
+
+#define MCR_MDBS	0x80		/* non-fifo mode switch	*/
+#define MCR_FSCL	0x40		/* override SCL pin	*/
+#define MCR_FSDA	0x20		/* override SDA pin	*/
+#define MCR_OBPC	0x10		/* override pins	*/
+#define MCR_MIE		0x08		/* master if enable	*/
+#define MCR_TSBE	0x04
+#define MCR_FSB		0x02		/* force stop bit	*/
+#define MCR_ESG		0x01		/* en startbit gen.	*/
+
+#define MSR_MNR		0x40		/* nack received	*/
+#define MSR_MAL		0x20		/* arbitration lost	*/
+#define MSR_MST		0x10		/* sent a stop		*/
+#define MSR_MDE		0x08
+#define MSR_MDT		0x04
+#define MSR_MDR		0x02
+#define MSR_MAT		0x01		/* slave addr xfer done	*/
+
+#define MIE_MNRE	0x40		/* nack irq en		*/
+#define MIE_MALE	0x20		/* arblos irq en	*/
+#define MIE_MSTE	0x10		/* stop irq en		*/
+#define MIE_MDEE	0x08
+#define MIE_MDTE	0x04
+#define MIE_MDRE	0x02
+#define MIE_MATE	0x01		/* address sent irq en	*/
+
+#define FCR_RFRST	0x02		/* reset rx fifo	*/
+#define FCR_TFRST	0x01		/* reset tx fifo	*/
+
+#define FSR_TEND	0x04		/* last byte sent	*/
+#define FSR_RDF		0x02		/* rx fifo trigger	*/
+#define FSR_TDFE	0x01		/* tx fifo empty	*/
+
+#define FIER_TEIE	0x04		/* tx fifo empty irq en	*/
+#define FIER_RXIE	0x02		/* rx fifo trig irq en	*/
+#define FIER_TXIE	0x01		/* tx fifo trig irq en	*/
+
+#define FIFO_SIZE	16
+
+struct cami2c {
+	void __iomem *iobase;
+	struct i2c_adapter adap;
+
+	/* message processing */
+	struct i2c_msg	*msg;
+#define IDF_SEND	1
+#define IDF_RECV	2
+#define IDF_STOP	4
+	int		flags;
+
+#define IDS_DONE	1
+#define IDS_ARBLOST	2
+#define IDS_NACK	4
+	int		status;
+	struct completion xfer_done;
+
+	int irq;
+	struct resource *ioarea;
+};
+
+static inline void OUT32(struct cami2c *cam, int reg, unsigned long val)
+{
+	__raw_writel(val, (unsigned long)cam->iobase + reg);
+}
+
+static inline unsigned long IN32(struct cami2c *cam, int reg)
+{
+	return __raw_readl((unsigned long)cam->iobase + reg);
+}
+
+static irqreturn_t sh7760_i2c_irq(int irq, void *ptr)
+{
+	struct cami2c *id = ptr;
+	struct i2c_msg *msg = id->msg;
+	char *data = msg->buf;
+	unsigned long msr, fsr, fier, len;
+
+	msr = IN32(id, I2CMSR);
+	fsr = IN32(id, I2CFSR);
+
+	/* arbitration lost */
+	if (msr & MSR_MAL) {
+		OUT32(id, I2CMCR, 0);
+		OUT32(id, I2CSCR, 0);
+		OUT32(id, I2CSAR, 0);
+		id->status |= IDS_DONE | IDS_ARBLOST;
+		goto out;
+	}
+
+	if (msr & MSR_MNR) {
+		/* NACK handling is very screwed up.  After receiving a
+		 * NAK IRQ one has to wait a bit  before writing to any
+		 * registers, or the ctl will lock up. After that delay
+		 * do a normal i2c stop. Then wait at least 1 ms before
+		 * attempting another transfer or ctl will stop working
+		 */
+		udelay(100);	/* wait or risk ctl hang */
+		OUT32(id, I2CFCR, FCR_RFRST | FCR_TFRST);
+		OUT32(id, I2CMCR, MCR_MIE | MCR_FSB);
+		OUT32(id, I2CFIER, 0);
+		OUT32(id, I2CMIER, MIE_MSTE);
+		OUT32(id, I2CSCR, 0);
+		OUT32(id, I2CSAR, 0);
+		id->status |= IDS_NACK;
+		msr &= ~MSR_MAT;
+		fsr = 0;
+		/* In some cases the MST bit is also set. */
+	}
+
+	/* i2c-stop was sent */
+	if (msr & MSR_MST) {
+		id->status |= IDS_DONE;
+		goto out;
+	}
+
+	/* i2c slave addr was sent; set to "normal" operation */
+	if (msr & MSR_MAT)
+		OUT32(id, I2CMCR, MCR_MIE);
+
+	fier = IN32(id, I2CFIER);
+
+	if (fsr & FSR_RDF) {
+		len = IN32(id, I2CRFDR);
+		if (msg->len <= len) {
+			if (id->flags & IDF_STOP) {
+				OUT32(id, I2CMCR, MCR_MIE | MCR_FSB);
+				OUT32(id, I2CFIER, 0);
+				/* manual says: wait >= 0.5 SCL times */
+				udelay(5);
+				/* next int should be MST */
+			} else {
+				id->status |= IDS_DONE;
+				/* keep the RDF bit: ctrl holds SCL low
+				 * until the setup for the next i2c_msg
+				 * clears this bit.
+				 */
+				fsr &= ~FSR_RDF;
+			}
+		}
+		while (msg->len && len) {
+			*data++ = IN32(id, I2CRXTX);
+			msg->len--;
+			len--;
+		}
+
+		if (msg->len) {
+			len = (msg->len >= FIFO_SIZE) ? FIFO_SIZE - 1
+						      : msg->len - 1;
+
+			OUT32(id, I2CFCR, FCR_TFRST | ((len & 0xf) << 4));
+		}
+
+	} else if (id->flags & IDF_SEND) {
+		if ((fsr & FSR_TEND) && (msg->len < 1)) {
+			if (id->flags & IDF_STOP) {
+				OUT32(id, I2CMCR, MCR_MIE | MCR_FSB);
+			} else {
+				id->status |= IDS_DONE;
+				/* keep the TEND bit: ctl holds SCL low
+				 * until the setup for the next i2c_msg
+				 * clears this bit.
+				 */
+				fsr &= ~FSR_TEND;
+			}
+		}
+		if (fsr & FSR_TDFE) {
+			while (msg->len && (IN32(id, I2CTFDR) < FIFO_SIZE)) {
+				OUT32(id, I2CRXTX, *data++);
+				msg->len--;
+			}
+
+			if (msg->len < 1) {
+				fier &= ~FIER_TXIE;
+				OUT32(id, I2CFIER, fier);
+			} else {
+				len = (msg->len >= FIFO_SIZE) ? 2 : 0;
+				OUT32(id, I2CFCR,
+					  FCR_RFRST | ((len & 3) << 2));
+			}
+		}
+	}
+out:
+	if (id->status & IDS_DONE) {
+		OUT32(id, I2CMIER, 0);
+		OUT32(id, I2CFIER, 0);
+		id->msg = NULL;
+		complete(&id->xfer_done);
+	}
+	/* clear status flags and ctrl resumes work */
+	OUT32(id, I2CMSR, ~msr);
+	OUT32(id, I2CFSR, ~fsr);
+	OUT32(id, I2CSSR, 0);
+
+	return IRQ_HANDLED;
+}
+
+
+/* prepare and start a master receive operation */
+static void sh7760_i2c_mrecv(struct cami2c *id)
+{
+	int len;
+
+	id->flags |= IDF_RECV;
+
+	/* set the slave addr reg; otherwise rcv wont work! */
+	OUT32(id, I2CSAR, 0xfe);
+	OUT32(id, I2CMAR, (id->msg->addr << 1) | 1);
+
+	/* adjust rx fifo trigger */
+	if (id->msg->len >= FIFO_SIZE)
+		len = FIFO_SIZE - 1;	/* trigger at fifo full */
+	else
+		len = id->msg->len - 1;	/* trigger before all received */
+
+	OUT32(id, I2CFCR, FCR_RFRST | FCR_TFRST);
+	OUT32(id, I2CFCR, FCR_TFRST | ((len & 0xF) << 4));
+
+	OUT32(id, I2CMSR, 0);
+	OUT32(id, I2CMCR, MCR_MIE | MCR_ESG);
+	OUT32(id, I2CMIER, MIE_MNRE | MIE_MALE | MIE_MSTE | MIE_MATE);
+	OUT32(id, I2CFIER, FIER_RXIE);
+}
+
+/* prepare and start a master send operation */
+static void sh7760_i2c_msend(struct cami2c *id)
+{
+	int len;
+
+	id->flags |= IDF_SEND;
+
+	/* set the slave addr reg; otherwise xmit wont work! */
+	OUT32(id, I2CSAR, 0xfe);
+	OUT32(id, I2CMAR, (id->msg->addr << 1) | 0);
+
+	/* adjust tx fifo trigger */
+	if (id->msg->len >= FIFO_SIZE)
+		len = 2;	/* trig: 2 bytes left in TX fifo */
+	else
+		len = 0;	/* trig: 8 bytes left in TX fifo */
+
+	OUT32(id, I2CFCR, FCR_RFRST | FCR_TFRST);
+	OUT32(id, I2CFCR, FCR_RFRST | ((len & 3) << 2));
+
+	while (id->msg->len && IN32(id, I2CTFDR) < FIFO_SIZE) {
+		OUT32(id, I2CRXTX, *(id->msg->buf));
+		(id->msg->len)--;
+		(id->msg->buf)++;
+	}
+
+	OUT32(id, I2CMSR, 0);
+	OUT32(id, I2CMCR, MCR_MIE | MCR_ESG);
+	OUT32(id, I2CFSR, 0);
+	OUT32(id, I2CMIER, MIE_MNRE | MIE_MALE | MIE_MSTE | MIE_MATE);
+	OUT32(id, I2CFIER, FIER_TEIE | (id->msg->len ? FIER_TXIE : 0));
+}
+
+static inline int sh7760_i2c_busy_check(struct cami2c *id)
+{
+	return (IN32(id, I2CMCR) & MCR_FSDA);
+}
+
+static int sh7760_i2c_master_xfer(struct i2c_adapter *adap,
+				  struct i2c_msg *msgs,
+				  int num)
+{
+	struct cami2c *id = adap->algo_data;
+	int i, retr;
+
+	if (sh7760_i2c_busy_check(id)) {
+		dev_err(&adap->dev, "sh7760-i2c%d: bus busy!\n", adap->nr);
+		return -EBUSY;
+	}
+
+	i = 0;
+	while (i < num) {
+		retr = adap->retries;
+retry:
+		id->flags = ((i == (num-1)) ? IDF_STOP : 0);
+		id->status = 0;
+		id->msg = msgs;
+		init_completion(&id->xfer_done);
+
+		if (msgs->flags & I2C_M_RD)
+			sh7760_i2c_mrecv(id);
+		else
+			sh7760_i2c_msend(id);
+
+		wait_for_completion(&id->xfer_done);
+
+		if (id->status == 0) {
+			num = -EIO;
+			break;
+		}
+
+		if (id->status & IDS_NACK) {
+			/* wait a bit or i2c module stops working */
+			mdelay(1);
+			num = -EREMOTEIO;
+			break;
+		}
+
+		if (id->status & IDS_ARBLOST) {
+			if (retr--) {
+				mdelay(2);
+				goto retry;
+			}
+			num = -EREMOTEIO;
+			break;
+		}
+
+		msgs++;
+		i++;
+	}
+
+	id->msg = NULL;
+	id->flags = 0;
+	id->status = 0;
+
+	OUT32(id, I2CMCR, 0);
+	OUT32(id, I2CMSR, 0);
+	OUT32(id, I2CMIER, 0);
+	OUT32(id, I2CFIER, 0);
+
+	/* reset slave module registers too: master mode enables slave
+	 * module for receive ops (ack, data). Without this reset,
+	 * eternal bus activity might be reported after NACK / ARBLOST.
+	 */
+	OUT32(id, I2CSCR, 0);
+	OUT32(id, I2CSAR, 0);
+	OUT32(id, I2CSSR, 0);
+
+	return num;
+}
+
+static u32 sh7760_i2c_func(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
+}
+
+static const struct i2c_algorithm sh7760_i2c_algo = {
+	.master_xfer	= sh7760_i2c_master_xfer,
+	.functionality	= sh7760_i2c_func,
+};
+
+/* calculate CCR register setting for a desired scl clock.  SCL clock is
+ * derived from I2C module clock  (iclk)  which in turn is derived from
+ * peripheral module clock (mclk, usually around 33MHz):
+ * iclk = mclk/(CDF + 1).  iclk must be < 20MHz.
+ * scl = iclk/(SCGD*8 + 20).
+ */
+static int __devinit calc_CCR(unsigned long scl_hz)
+{
+	struct clk *mclk;
+	unsigned long mck, m1, dff, odff, iclk;
+	signed char cdf, cdfm;
+	int scgd, scgdm, scgds;
+
+	mclk = clk_get(NULL, "peripheral_clk");
+	if (IS_ERR(mclk)) {
+		return PTR_ERR(mclk);
+	} else {
+		mck = mclk->rate;
+		clk_put(mclk);
+	}
+
+	odff = scl_hz;
+	scgdm = cdfm = m1 = 0;
+	for (cdf = 3; cdf >= 0; cdf--) {
+		iclk = mck / (1 + cdf);
+		if (iclk >= 20000000)
+			continue;
+		scgds = ((iclk / scl_hz) - 20) >> 3;
+		for (scgd = scgds; (scgd < 63) && scgd <= scgds + 1; scgd++) {
+			m1 = iclk / (20 + (scgd << 3));
+			dff = abs(scl_hz - m1);
+			if (dff < odff) {
+				odff = dff;
+				cdfm = cdf;
+				scgdm = scgd;
+			}
+		}
+	}
+	/* fail if more than 25% off of requested SCL */
+	if (odff > (scl_hz >> 2))
+		return -EINVAL;
+
+	/* create a CCR register value */
+	return ((scgdm << 2) | cdfm);
+}
+
+static int __devinit sh7760_i2c_probe(struct platform_device *pdev)
+{
+	struct sh7760_i2c_platdata *pd;
+	struct resource *res;
+	struct cami2c *id;
+	int ret;
+
+	pd = pdev->dev.platform_data;
+	if (!pd) {
+		dev_err(&pdev->dev, "no platform_data!\n");
+		ret = -ENODEV;
+		goto out0;
+	}
+
+	id = kzalloc(sizeof(struct cami2c), GFP_KERNEL);
+	if (!id) {
+		dev_err(&pdev->dev, "no mem for private data\n");
+		ret = -ENOMEM;
+		goto out0;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "no mmio resources\n");
+		ret = -ENODEV;
+		goto out1;
+	}
+
+	id->ioarea = request_mem_region(res->start, REGSIZE, pdev->name);
+	if (!id->ioarea) {
+		dev_err(&pdev->dev, "mmio already reserved\n");
+		ret = -EBUSY;
+		goto out1;
+	}
+
+	id->iobase = ioremap(res->start, REGSIZE);
+	if (!id->iobase) {
+		dev_err(&pdev->dev, "cannot ioremap\n");
+		ret = -ENODEV;
+		goto out2;
+	}
+
+	id->irq = platform_get_irq(pdev, 0);
+
+	id->adap.nr = pdev->id;
+	id->adap.algo = &sh7760_i2c_algo;
+	id->adap.class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
+	id->adap.retries = 3;
+	id->adap.algo_data = id;
+	id->adap.dev.parent = &pdev->dev;
+	snprintf(id->adap.name, sizeof(id->adap.name),
+		"SH7760 I2C at %08lx", (unsigned long)res->start);
+
+	OUT32(id, I2CMCR, 0);
+	OUT32(id, I2CMSR, 0);
+	OUT32(id, I2CMIER, 0);
+	OUT32(id, I2CMAR, 0);
+	OUT32(id, I2CSIER, 0);
+	OUT32(id, I2CSAR, 0);
+	OUT32(id, I2CSCR, 0);
+	OUT32(id, I2CSSR, 0);
+	OUT32(id, I2CFIER, 0);
+	OUT32(id, I2CFCR, FCR_RFRST | FCR_TFRST);
+	OUT32(id, I2CFSR, 0);
+
+	ret = calc_CCR(pd->speed_khz * 1000);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "invalid SCL clock: %dkHz\n",
+			pd->speed_khz);
+		goto out3;
+	}
+	OUT32(id, I2CCCR, ret);
+
+	if (request_irq(id->irq, sh7760_i2c_irq, 0,
+			SH7760_I2C_DEVNAME, id)) {
+		dev_err(&pdev->dev, "cannot get irq %d\n", id->irq);
+		ret = -EBUSY;
+		goto out3;
+	}
+
+	ret = i2c_add_numbered_adapter(&id->adap);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "reg adap failed: %d\n", ret);
+		goto out4;
+	}
+
+	platform_set_drvdata(pdev, id);
+
+	dev_info(&pdev->dev, "%d kHz mmio %08x irq %d\n",
+		 pd->speed_khz, res->start, id->irq);
+
+	return 0;
+
+out4:
+	free_irq(id->irq, id);
+out3:
+	iounmap(id->iobase);
+out2:
+	release_resource(id->ioarea);
+	kfree(id->ioarea);
+out1:
+	kfree(id);
+out0:
+	return ret;
+}
+
+static int __devexit sh7760_i2c_remove(struct platform_device *pdev)
+{
+	struct cami2c *id = platform_get_drvdata(pdev);
+
+	i2c_del_adapter(&id->adap);
+	free_irq(id->irq, id);
+	iounmap(id->iobase);
+	release_resource(id->ioarea);
+	kfree(id->ioarea);
+	kfree(id);
+	platform_set_drvdata(pdev, NULL);
+
+	return 0;
+}
+
+static struct platform_driver sh7760_i2c_drv = {
+	.driver	= {
+		.name	= SH7760_I2C_DEVNAME,
+		.owner	= THIS_MODULE,
+	},
+	.probe		= sh7760_i2c_probe,
+	.remove		= __devexit_p(sh7760_i2c_remove),
+};
+
+module_platform_driver(sh7760_i2c_drv);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("SH7760 I2C bus driver");
+MODULE_AUTHOR("Manuel Lauss <mano@roarinelk.homelinux.net>");
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-sh_mobile.c b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-sh_mobile.c
new file mode 100644
index 0000000..675c969
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-sh_mobile.c
@@ -0,0 +1,739 @@
+/*
+ * SuperH Mobile I2C Controller
+ *
+ * Copyright (C) 2008 Magnus Damm
+ *
+ * Portions of the code based on out-of-tree driver i2c-sh7343.c
+ * Copyright (c) 2006 Carlos Munoz <carlos@kenati.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/err.h>
+#include <linux/pm_runtime.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/i2c/i2c-sh_mobile.h>
+
+/* Transmit operation:                                                      */
+/*                                                                          */
+/* 0 byte transmit                                                          */
+/* BUS:     S     A8     ACK   P                                            */
+/* IRQ:       DTE   WAIT                                                    */
+/* ICIC:                                                                    */
+/* ICCR: 0x94 0x90                                                          */
+/* ICDR:      A8                                                            */
+/*                                                                          */
+/* 1 byte transmit                                                          */
+/* BUS:     S     A8     ACK   D8(1)   ACK   P                              */
+/* IRQ:       DTE   WAIT         WAIT                                       */
+/* ICIC:      -DTE                                                          */
+/* ICCR: 0x94       0x90                                                    */
+/* ICDR:      A8    D8(1)                                                   */
+/*                                                                          */
+/* 2 byte transmit                                                          */
+/* BUS:     S     A8     ACK   D8(1)   ACK   D8(2)   ACK   P                */
+/* IRQ:       DTE   WAIT         WAIT          WAIT                         */
+/* ICIC:      -DTE                                                          */
+/* ICCR: 0x94                    0x90                                       */
+/* ICDR:      A8    D8(1)        D8(2)                                      */
+/*                                                                          */
+/* 3 bytes or more, +---------+ gets repeated                               */
+/*                                                                          */
+/*                                                                          */
+/* Receive operation:                                                       */
+/*                                                                          */
+/* 0 byte receive - not supported since slave may hold SDA low              */
+/*                                                                          */
+/* 1 byte receive       [TX] | [RX]                                         */
+/* BUS:     S     A8     ACK | D8(1)   ACK   P                              */
+/* IRQ:       DTE   WAIT     |   WAIT     DTE                               */
+/* ICIC:      -DTE           |   +DTE                                       */
+/* ICCR: 0x94       0x81     |   0xc0                                       */
+/* ICDR:      A8             |            D8(1)                             */
+/*                                                                          */
+/* 2 byte receive        [TX]| [RX]                                         */
+/* BUS:     S     A8     ACK | D8(1)   ACK   D8(2)   ACK   P                */
+/* IRQ:       DTE   WAIT     |   WAIT          WAIT     DTE                 */
+/* ICIC:      -DTE           |                 +DTE                         */
+/* ICCR: 0x94       0x81     |                 0xc0                         */
+/* ICDR:      A8             |                 D8(1)    D8(2)               */
+/*                                                                          */
+/* 3 byte receive       [TX] | [RX]                                         */
+/* BUS:     S     A8     ACK | D8(1)   ACK   D8(2)   ACK   D8(3)   ACK    P */
+/* IRQ:       DTE   WAIT     |   WAIT          WAIT         WAIT      DTE   */
+/* ICIC:      -DTE           |                              +DTE            */
+/* ICCR: 0x94       0x81     |                              0xc0            */
+/* ICDR:      A8             |                 D8(1)        D8(2)     D8(3) */
+/*                                                                          */
+/* 4 bytes or more, this part is repeated    +---------+                    */
+/*                                                                          */
+/*                                                                          */
+/* Interrupt order and BUSY flag                                            */
+/*     ___                                                 _                */
+/* SDA ___\___XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXAAAAAAAAA___/                 */
+/* SCL      \_/1\_/2\_/3\_/4\_/5\_/6\_/7\_/8\___/9\_____/                   */
+/*                                                                          */
+/*        S   D7  D6  D5  D4  D3  D2  D1  D0              P                 */
+/*                                           ___                            */
+/* WAIT IRQ ________________________________/   \___________                */
+/* TACK IRQ ____________________________________/   \_______                */
+/* DTE  IRQ __________________________________________/   \_                */
+/* AL   IRQ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX                */
+/*         _______________________________________________                  */
+/* BUSY __/                                               \_                */
+/*                                                                          */
+
+enum sh_mobile_i2c_op {
+	OP_START = 0,
+	OP_TX_FIRST,
+	OP_TX,
+	OP_TX_STOP,
+	OP_TX_TO_RX,
+	OP_RX,
+	OP_RX_STOP,
+	OP_RX_STOP_DATA,
+};
+
+struct sh_mobile_i2c_data {
+	struct device *dev;
+	void __iomem *reg;
+	struct i2c_adapter adap;
+	unsigned long bus_speed;
+	struct clk *clk;
+	u_int8_t icic;
+	u_int8_t iccl;
+	u_int8_t icch;
+	u_int8_t flags;
+
+	spinlock_t lock;
+	wait_queue_head_t wait;
+	struct i2c_msg *msg;
+	int pos;
+	int sr;
+};
+
+#define IIC_FLAG_HAS_ICIC67	(1 << 0)
+
+#define NORMAL_SPEED		100000 /* FAST_SPEED 400000 */
+
+/* Register offsets */
+#define ICDR			0x00
+#define ICCR			0x04
+#define ICSR			0x08
+#define ICIC			0x0c
+#define ICCL			0x10
+#define ICCH			0x14
+
+/* Register bits */
+#define ICCR_ICE		0x80
+#define ICCR_RACK		0x40
+#define ICCR_TRS		0x10
+#define ICCR_BBSY		0x04
+#define ICCR_SCP		0x01
+
+#define ICSR_SCLM		0x80
+#define ICSR_SDAM		0x40
+#define SW_DONE			0x20
+#define ICSR_BUSY		0x10
+#define ICSR_AL			0x08
+#define ICSR_TACK		0x04
+#define ICSR_WAIT		0x02
+#define ICSR_DTE		0x01
+
+#define ICIC_ICCLB8		0x80
+#define ICIC_ICCHB8		0x40
+#define ICIC_ALE		0x08
+#define ICIC_TACKE		0x04
+#define ICIC_WAITE		0x02
+#define ICIC_DTEE		0x01
+
+static void iic_wr(struct sh_mobile_i2c_data *pd, int offs, unsigned char data)
+{
+	if (offs == ICIC)
+		data |= pd->icic;
+
+	iowrite8(data, pd->reg + offs);
+}
+
+static unsigned char iic_rd(struct sh_mobile_i2c_data *pd, int offs)
+{
+	return ioread8(pd->reg + offs);
+}
+
+static void iic_set_clr(struct sh_mobile_i2c_data *pd, int offs,
+			unsigned char set, unsigned char clr)
+{
+	iic_wr(pd, offs, (iic_rd(pd, offs) | set) & ~clr);
+}
+
+static void activate_ch(struct sh_mobile_i2c_data *pd)
+{
+	unsigned long i2c_clk;
+	u_int32_t num;
+	u_int32_t denom;
+	u_int32_t tmp;
+
+	/* Wake up device and enable clock */
+	pm_runtime_get_sync(pd->dev);
+	clk_enable(pd->clk);
+
+	/* Get clock rate after clock is enabled */
+	i2c_clk = clk_get_rate(pd->clk);
+
+	/* Calculate the value for iccl. From the data sheet:
+	 * iccl = (p clock / transfer rate) * (L / (L + H))
+	 * where L and H are the SCL low/high ratio (5/4 in this case).
+	 * We also round off the result.
+	 */
+	num = i2c_clk * 5;
+	denom = pd->bus_speed * 9;
+	tmp = num * 10 / denom;
+	if (tmp % 10 >= 5)
+		pd->iccl = (u_int8_t)((num/denom) + 1);
+	else
+		pd->iccl = (u_int8_t)(num/denom);
+
+	/* one more bit of ICCL in ICIC */
+	if (pd->flags & IIC_FLAG_HAS_ICIC67) {
+		if ((num/denom) > 0xff)
+			pd->icic |= ICIC_ICCLB8;
+		else
+			pd->icic &= ~ICIC_ICCLB8;
+	}
+
+	/* Calculate the value for icch. From the data sheet:
+	   icch = (p clock / transfer rate) * (H / (L + H)) */
+	num = i2c_clk * 4;
+	tmp = num * 10 / denom;
+	if (tmp % 10 >= 5)
+		pd->icch = (u_int8_t)((num/denom) + 1);
+	else
+		pd->icch = (u_int8_t)(num/denom);
+
+	/* one more bit of ICCH in ICIC */
+	if (pd->flags & IIC_FLAG_HAS_ICIC67) {
+		if ((num/denom) > 0xff)
+			pd->icic |= ICIC_ICCHB8;
+		else
+			pd->icic &= ~ICIC_ICCHB8;
+	}
+
+	/* Enable channel and configure rx ack */
+	iic_set_clr(pd, ICCR, ICCR_ICE, 0);
+
+	/* Mask all interrupts */
+	iic_wr(pd, ICIC, 0);
+
+	/* Set the clock */
+	iic_wr(pd, ICCL, pd->iccl);
+	iic_wr(pd, ICCH, pd->icch);
+}
+
+static void deactivate_ch(struct sh_mobile_i2c_data *pd)
+{
+	/* Clear/disable interrupts */
+	iic_wr(pd, ICSR, 0);
+	iic_wr(pd, ICIC, 0);
+
+	/* Disable channel */
+	iic_set_clr(pd, ICCR, 0, ICCR_ICE);
+
+	/* Disable clock and mark device as idle */
+	clk_disable(pd->clk);
+	pm_runtime_put_sync(pd->dev);
+}
+
+static unsigned char i2c_op(struct sh_mobile_i2c_data *pd,
+			    enum sh_mobile_i2c_op op, unsigned char data)
+{
+	unsigned char ret = 0;
+	unsigned long flags;
+
+	dev_dbg(pd->dev, "op %d, data in 0x%02x\n", op, data);
+
+	spin_lock_irqsave(&pd->lock, flags);
+
+	switch (op) {
+	case OP_START: /* issue start and trigger DTE interrupt */
+		iic_wr(pd, ICCR, 0x94);
+		break;
+	case OP_TX_FIRST: /* disable DTE interrupt and write data */
+		iic_wr(pd, ICIC, ICIC_WAITE | ICIC_ALE | ICIC_TACKE);
+		iic_wr(pd, ICDR, data);
+		break;
+	case OP_TX: /* write data */
+		iic_wr(pd, ICDR, data);
+		break;
+	case OP_TX_STOP: /* write data and issue a stop afterwards */
+		iic_wr(pd, ICDR, data);
+		iic_wr(pd, ICCR, 0x90);
+		break;
+	case OP_TX_TO_RX: /* select read mode */
+		iic_wr(pd, ICCR, 0x81);
+		break;
+	case OP_RX: /* just read data */
+		ret = iic_rd(pd, ICDR);
+		break;
+	case OP_RX_STOP: /* enable DTE interrupt, issue stop */
+		iic_wr(pd, ICIC,
+		       ICIC_DTEE | ICIC_WAITE | ICIC_ALE | ICIC_TACKE);
+		iic_wr(pd, ICCR, 0xc0);
+		break;
+	case OP_RX_STOP_DATA: /* enable DTE interrupt, read data, issue stop */
+		iic_wr(pd, ICIC,
+		       ICIC_DTEE | ICIC_WAITE | ICIC_ALE | ICIC_TACKE);
+		ret = iic_rd(pd, ICDR);
+		iic_wr(pd, ICCR, 0xc0);
+		break;
+	}
+
+	spin_unlock_irqrestore(&pd->lock, flags);
+
+	dev_dbg(pd->dev, "op %d, data out 0x%02x\n", op, ret);
+	return ret;
+}
+
+static int sh_mobile_i2c_is_first_byte(struct sh_mobile_i2c_data *pd)
+{
+	if (pd->pos == -1)
+		return 1;
+
+	return 0;
+}
+
+static int sh_mobile_i2c_is_last_byte(struct sh_mobile_i2c_data *pd)
+{
+	if (pd->pos == (pd->msg->len - 1))
+		return 1;
+
+	return 0;
+}
+
+static void sh_mobile_i2c_get_data(struct sh_mobile_i2c_data *pd,
+				   unsigned char *buf)
+{
+	switch (pd->pos) {
+	case -1:
+		*buf = (pd->msg->addr & 0x7f) << 1;
+		*buf |= (pd->msg->flags & I2C_M_RD) ? 1 : 0;
+		break;
+	default:
+		*buf = pd->msg->buf[pd->pos];
+	}
+}
+
+static int sh_mobile_i2c_isr_tx(struct sh_mobile_i2c_data *pd)
+{
+	unsigned char data;
+
+	if (pd->pos == pd->msg->len)
+		return 1;
+
+	sh_mobile_i2c_get_data(pd, &data);
+
+	if (sh_mobile_i2c_is_last_byte(pd))
+		i2c_op(pd, OP_TX_STOP, data);
+	else if (sh_mobile_i2c_is_first_byte(pd))
+		i2c_op(pd, OP_TX_FIRST, data);
+	else
+		i2c_op(pd, OP_TX, data);
+
+	pd->pos++;
+	return 0;
+}
+
+static int sh_mobile_i2c_isr_rx(struct sh_mobile_i2c_data *pd)
+{
+	unsigned char data;
+	int real_pos;
+
+	do {
+		if (pd->pos <= -1) {
+			sh_mobile_i2c_get_data(pd, &data);
+
+			if (sh_mobile_i2c_is_first_byte(pd))
+				i2c_op(pd, OP_TX_FIRST, data);
+			else
+				i2c_op(pd, OP_TX, data);
+			break;
+		}
+
+		if (pd->pos == 0) {
+			i2c_op(pd, OP_TX_TO_RX, 0);
+			break;
+		}
+
+		real_pos = pd->pos - 2;
+
+		if (pd->pos == pd->msg->len) {
+			if (real_pos < 0) {
+				i2c_op(pd, OP_RX_STOP, 0);
+				break;
+			}
+			data = i2c_op(pd, OP_RX_STOP_DATA, 0);
+		} else
+			data = i2c_op(pd, OP_RX, 0);
+
+		if (real_pos >= 0)
+			pd->msg->buf[real_pos] = data;
+	} while (0);
+
+	pd->pos++;
+	return pd->pos == (pd->msg->len + 2);
+}
+
+static irqreturn_t sh_mobile_i2c_isr(int irq, void *dev_id)
+{
+	struct platform_device *dev = dev_id;
+	struct sh_mobile_i2c_data *pd = platform_get_drvdata(dev);
+	unsigned char sr;
+	int wakeup;
+
+	sr = iic_rd(pd, ICSR);
+	pd->sr |= sr; /* remember state */
+
+	dev_dbg(pd->dev, "i2c_isr 0x%02x 0x%02x %s %d %d!\n", sr, pd->sr,
+	       (pd->msg->flags & I2C_M_RD) ? "read" : "write",
+	       pd->pos, pd->msg->len);
+
+	if (sr & (ICSR_AL | ICSR_TACK)) {
+		/* don't interrupt transaction - continue to issue stop */
+		iic_wr(pd, ICSR, sr & ~(ICSR_AL | ICSR_TACK));
+		wakeup = 0;
+	} else if (pd->msg->flags & I2C_M_RD)
+		wakeup = sh_mobile_i2c_isr_rx(pd);
+	else
+		wakeup = sh_mobile_i2c_isr_tx(pd);
+
+	if (sr & ICSR_WAIT) /* TODO: add delay here to support slow acks */
+		iic_wr(pd, ICSR, sr & ~ICSR_WAIT);
+
+	if (wakeup) {
+		pd->sr |= SW_DONE;
+		wake_up(&pd->wait);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int start_ch(struct sh_mobile_i2c_data *pd, struct i2c_msg *usr_msg)
+{
+	if (usr_msg->len == 0 && (usr_msg->flags & I2C_M_RD)) {
+		dev_err(pd->dev, "Unsupported zero length i2c read\n");
+		return -EIO;
+	}
+
+	/* Initialize channel registers */
+	iic_set_clr(pd, ICCR, 0, ICCR_ICE);
+
+	/* Enable channel and configure rx ack */
+	iic_set_clr(pd, ICCR, ICCR_ICE, 0);
+
+	/* Set the clock */
+	iic_wr(pd, ICCL, pd->iccl);
+	iic_wr(pd, ICCH, pd->icch);
+
+	pd->msg = usr_msg;
+	pd->pos = -1;
+	pd->sr = 0;
+
+	/* Enable all interrupts to begin with */
+	iic_wr(pd, ICIC, ICIC_DTEE | ICIC_WAITE | ICIC_ALE | ICIC_TACKE);
+	return 0;
+}
+
+static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter,
+			      struct i2c_msg *msgs,
+			      int num)
+{
+	struct sh_mobile_i2c_data *pd = i2c_get_adapdata(adapter);
+	struct i2c_msg	*msg;
+	int err = 0;
+	u_int8_t val;
+	int i, k, retry_count;
+
+	activate_ch(pd);
+
+	/* Process all messages */
+	for (i = 0; i < num; i++) {
+		msg = &msgs[i];
+
+		err = start_ch(pd, msg);
+		if (err)
+			break;
+
+		i2c_op(pd, OP_START, 0);
+
+		/* The interrupt handler takes care of the rest... */
+		k = wait_event_timeout(pd->wait,
+				       pd->sr & (ICSR_TACK | SW_DONE),
+				       5 * HZ);
+		if (!k)
+			dev_err(pd->dev, "Transfer request timed out\n");
+
+		retry_count = 1000;
+again:
+		val = iic_rd(pd, ICSR);
+
+		dev_dbg(pd->dev, "val 0x%02x pd->sr 0x%02x\n", val, pd->sr);
+
+		/* the interrupt handler may wake us up before the
+		 * transfer is finished, so poll the hardware
+		 * until we're done.
+		 */
+		if (val & ICSR_BUSY) {
+			udelay(10);
+			if (retry_count--)
+				goto again;
+
+			err = -EIO;
+			dev_err(pd->dev, "Polling timed out\n");
+			break;
+		}
+
+		/* handle missing acknowledge and arbitration lost */
+		if ((val | pd->sr) & (ICSR_TACK | ICSR_AL)) {
+			err = -EIO;
+			break;
+		}
+	}
+
+	deactivate_ch(pd);
+
+	if (!err)
+		err = num;
+	return err;
+}
+
+static u32 sh_mobile_i2c_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static struct i2c_algorithm sh_mobile_i2c_algorithm = {
+	.functionality	= sh_mobile_i2c_func,
+	.master_xfer	= sh_mobile_i2c_xfer,
+};
+
+static int sh_mobile_i2c_hook_irqs(struct platform_device *dev, int hook)
+{
+	struct resource *res;
+	int ret = -ENXIO;
+	int n, k = 0;
+
+	while ((res = platform_get_resource(dev, IORESOURCE_IRQ, k))) {
+		for (n = res->start; hook && n <= res->end; n++) {
+			if (request_irq(n, sh_mobile_i2c_isr, 0,
+					dev_name(&dev->dev), dev)) {
+				for (n--; n >= res->start; n--)
+					free_irq(n, dev);
+
+				goto rollback;
+			}
+		}
+		k++;
+	}
+
+	if (hook)
+		return k > 0 ? 0 : -ENOENT;
+
+	ret = 0;
+
+ rollback:
+	k--;
+
+	while (k >= 0) {
+		res = platform_get_resource(dev, IORESOURCE_IRQ, k);
+		for (n = res->start; n <= res->end; n++)
+			free_irq(n, dev);
+
+		k--;
+	}
+
+	return ret;
+}
+
+static int sh_mobile_i2c_probe(struct platform_device *dev)
+{
+	struct i2c_sh_mobile_platform_data *pdata = dev->dev.platform_data;
+	struct sh_mobile_i2c_data *pd;
+	struct i2c_adapter *adap;
+	struct resource *res;
+	int size;
+	int ret;
+
+	pd = kzalloc(sizeof(struct sh_mobile_i2c_data), GFP_KERNEL);
+	if (pd == NULL) {
+		dev_err(&dev->dev, "cannot allocate private data\n");
+		return -ENOMEM;
+	}
+
+	pd->clk = clk_get(&dev->dev, NULL);
+	if (IS_ERR(pd->clk)) {
+		dev_err(&dev->dev, "cannot get clock\n");
+		ret = PTR_ERR(pd->clk);
+		goto err;
+	}
+
+	ret = sh_mobile_i2c_hook_irqs(dev, 1);
+	if (ret) {
+		dev_err(&dev->dev, "cannot request IRQ\n");
+		goto err_clk;
+	}
+
+	pd->dev = &dev->dev;
+	platform_set_drvdata(dev, pd);
+
+	res = platform_get_resource(dev, IORESOURCE_MEM, 0);
+	if (res == NULL) {
+		dev_err(&dev->dev, "cannot find IO resource\n");
+		ret = -ENOENT;
+		goto err_irq;
+	}
+
+	size = resource_size(res);
+
+	pd->reg = ioremap(res->start, size);
+	if (pd->reg == NULL) {
+		dev_err(&dev->dev, "cannot map IO\n");
+		ret = -ENXIO;
+		goto err_irq;
+	}
+
+	/* Use platformd data bus speed or NORMAL_SPEED */
+	pd->bus_speed = NORMAL_SPEED;
+	if (pdata && pdata->bus_speed)
+		pd->bus_speed = pdata->bus_speed;
+
+	/* The IIC blocks on SH-Mobile ARM processors
+	 * come with two new bits in ICIC.
+	 */
+	if (size > 0x17)
+		pd->flags |= IIC_FLAG_HAS_ICIC67;
+
+	/* Enable Runtime PM for this device.
+	 *
+	 * Also tell the Runtime PM core to ignore children
+	 * for this device since it is valid for us to suspend
+	 * this I2C master driver even though the slave devices
+	 * on the I2C bus may not be suspended.
+	 *
+	 * The state of the I2C hardware bus is unaffected by
+	 * the Runtime PM state.
+	 */
+	pm_suspend_ignore_children(&dev->dev, true);
+	pm_runtime_enable(&dev->dev);
+
+	/* setup the private data */
+	adap = &pd->adap;
+	i2c_set_adapdata(adap, pd);
+
+	adap->owner = THIS_MODULE;
+	adap->algo = &sh_mobile_i2c_algorithm;
+	adap->dev.parent = &dev->dev;
+	adap->retries = 5;
+	adap->nr = dev->id;
+
+	strlcpy(adap->name, dev->name, sizeof(adap->name));
+
+	spin_lock_init(&pd->lock);
+	init_waitqueue_head(&pd->wait);
+
+	ret = i2c_add_numbered_adapter(adap);
+	if (ret < 0) {
+		dev_err(&dev->dev, "cannot add numbered adapter\n");
+		goto err_all;
+	}
+
+	dev_info(&dev->dev, "I2C adapter %d with bus speed %lu Hz\n",
+		 adap->nr, pd->bus_speed);
+	return 0;
+
+ err_all:
+	iounmap(pd->reg);
+ err_irq:
+	sh_mobile_i2c_hook_irqs(dev, 0);
+ err_clk:
+	clk_put(pd->clk);
+ err:
+	kfree(pd);
+	return ret;
+}
+
+static int sh_mobile_i2c_remove(struct platform_device *dev)
+{
+	struct sh_mobile_i2c_data *pd = platform_get_drvdata(dev);
+
+	i2c_del_adapter(&pd->adap);
+	iounmap(pd->reg);
+	sh_mobile_i2c_hook_irqs(dev, 0);
+	clk_put(pd->clk);
+	pm_runtime_disable(&dev->dev);
+	kfree(pd);
+	return 0;
+}
+
+static int sh_mobile_i2c_runtime_nop(struct device *dev)
+{
+	/* Runtime PM callback shared between ->runtime_suspend()
+	 * and ->runtime_resume(). Simply returns success.
+	 *
+	 * This driver re-initializes all registers after
+	 * pm_runtime_get_sync() anyway so there is no need
+	 * to save and restore registers here.
+	 */
+	return 0;
+}
+
+static const struct dev_pm_ops sh_mobile_i2c_dev_pm_ops = {
+	.runtime_suspend = sh_mobile_i2c_runtime_nop,
+	.runtime_resume = sh_mobile_i2c_runtime_nop,
+};
+
+static struct platform_driver sh_mobile_i2c_driver = {
+	.driver		= {
+		.name		= "i2c-sh_mobile",
+		.owner		= THIS_MODULE,
+		.pm		= &sh_mobile_i2c_dev_pm_ops,
+	},
+	.probe		= sh_mobile_i2c_probe,
+	.remove		= sh_mobile_i2c_remove,
+};
+
+static int __init sh_mobile_i2c_adap_init(void)
+{
+	return platform_driver_register(&sh_mobile_i2c_driver);
+}
+
+static void __exit sh_mobile_i2c_adap_exit(void)
+{
+	platform_driver_unregister(&sh_mobile_i2c_driver);
+}
+
+subsys_initcall(sh_mobile_i2c_adap_init);
+module_exit(sh_mobile_i2c_adap_exit);
+
+MODULE_DESCRIPTION("SuperH Mobile I2C Bus Controller driver");
+MODULE_AUTHOR("Magnus Damm");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:i2c-sh_mobile");
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-sibyte.c b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-sibyte.c
new file mode 100644
index 0000000..0fe505d
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-sibyte.c
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2004 Steven J. Hill
+ * Copyright (C) 2001,2002,2003 Broadcom Corporation
+ * Copyright (C) 1995-2000 Simon G. Vogl
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/io.h>
+#include <asm/sibyte/sb1250_regs.h>
+#include <asm/sibyte/sb1250_smbus.h>
+
+
+struct i2c_algo_sibyte_data {
+	void *data;		/* private data */
+	int   bus;		/* which bus */
+	void *reg_base;		/* CSR base */
+};
+
+/* ----- global defines ----------------------------------------------- */
+#define SMB_CSR(a,r) ((long)(a->reg_base + r))
+
+
+static int smbus_xfer(struct i2c_adapter *i2c_adap, u16 addr,
+		      unsigned short flags, char read_write,
+		      u8 command, int size, union i2c_smbus_data * data)
+{
+	struct i2c_algo_sibyte_data *adap = i2c_adap->algo_data;
+	int data_bytes = 0;
+	int error;
+
+	while (csr_in32(SMB_CSR(adap, R_SMB_STATUS)) & M_SMB_BUSY)
+		;
+
+	switch (size) {
+	case I2C_SMBUS_QUICK:
+		csr_out32((V_SMB_ADDR(addr) |
+			   (read_write == I2C_SMBUS_READ ? M_SMB_QDATA : 0) |
+			   V_SMB_TT_QUICKCMD), SMB_CSR(adap, R_SMB_START));
+		break;
+	case I2C_SMBUS_BYTE:
+		if (read_write == I2C_SMBUS_READ) {
+			csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_RD1BYTE),
+				  SMB_CSR(adap, R_SMB_START));
+			data_bytes = 1;
+		} else {
+			csr_out32(V_SMB_CMD(command), SMB_CSR(adap, R_SMB_CMD));
+			csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_WR1BYTE),
+				  SMB_CSR(adap, R_SMB_START));
+		}
+		break;
+	case I2C_SMBUS_BYTE_DATA:
+		csr_out32(V_SMB_CMD(command), SMB_CSR(adap, R_SMB_CMD));
+		if (read_write == I2C_SMBUS_READ) {
+			csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_CMD_RD1BYTE),
+				  SMB_CSR(adap, R_SMB_START));
+			data_bytes = 1;
+		} else {
+			csr_out32(V_SMB_LB(data->byte),
+				  SMB_CSR(adap, R_SMB_DATA));
+			csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_WR2BYTE),
+				  SMB_CSR(adap, R_SMB_START));
+		}
+		break;
+	case I2C_SMBUS_WORD_DATA:
+		csr_out32(V_SMB_CMD(command), SMB_CSR(adap, R_SMB_CMD));
+		if (read_write == I2C_SMBUS_READ) {
+			csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_CMD_RD2BYTE),
+				  SMB_CSR(adap, R_SMB_START));
+			data_bytes = 2;
+		} else {
+			csr_out32(V_SMB_LB(data->word & 0xff),
+				  SMB_CSR(adap, R_SMB_DATA));
+			csr_out32(V_SMB_MB(data->word >> 8),
+				  SMB_CSR(adap, R_SMB_DATA));
+			csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_WR2BYTE),
+				  SMB_CSR(adap, R_SMB_START));
+		}
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	while (csr_in32(SMB_CSR(adap, R_SMB_STATUS)) & M_SMB_BUSY)
+		;
+
+	error = csr_in32(SMB_CSR(adap, R_SMB_STATUS));
+	if (error & M_SMB_ERROR) {
+		/* Clear error bit by writing a 1 */
+		csr_out32(M_SMB_ERROR, SMB_CSR(adap, R_SMB_STATUS));
+		return (error & M_SMB_ERROR_TYPE) ? -EIO : -ENXIO;
+	}
+
+	if (data_bytes == 1)
+		data->byte = csr_in32(SMB_CSR(adap, R_SMB_DATA)) & 0xff;
+	if (data_bytes == 2)
+		data->word = csr_in32(SMB_CSR(adap, R_SMB_DATA)) & 0xffff;
+
+	return 0;
+}
+
+static u32 bit_func(struct i2c_adapter *adap)
+{
+	return (I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+		I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA);
+}
+
+
+/* -----exported algorithm data: -------------------------------------	*/
+
+static const struct i2c_algorithm i2c_sibyte_algo = {
+	.smbus_xfer	= smbus_xfer,
+	.functionality	= bit_func,
+};
+
+/*
+ * registering functions to load algorithms at runtime
+ */
+static int __init i2c_sibyte_add_bus(struct i2c_adapter *i2c_adap, int speed)
+{
+	struct i2c_algo_sibyte_data *adap = i2c_adap->algo_data;
+
+	/* Register new adapter to i2c module... */
+	i2c_adap->algo = &i2c_sibyte_algo;
+
+	/* Set the requested frequency. */
+	csr_out32(speed, SMB_CSR(adap,R_SMB_FREQ));
+	csr_out32(0, SMB_CSR(adap,R_SMB_CONTROL));
+
+	return i2c_add_numbered_adapter(i2c_adap);
+}
+
+
+static struct i2c_algo_sibyte_data sibyte_board_data[2] = {
+	{ NULL, 0, (void *) (CKSEG1+A_SMB_BASE(0)) },
+	{ NULL, 1, (void *) (CKSEG1+A_SMB_BASE(1)) }
+};
+
+static struct i2c_adapter sibyte_board_adapter[2] = {
+	{
+		.owner		= THIS_MODULE,
+		.class		= I2C_CLASS_HWMON | I2C_CLASS_SPD,
+		.algo		= NULL,
+		.algo_data	= &sibyte_board_data[0],
+		.nr		= 0,
+		.name		= "SiByte SMBus 0",
+	},
+	{
+		.owner		= THIS_MODULE,
+		.class		= I2C_CLASS_HWMON | I2C_CLASS_SPD,
+		.algo		= NULL,
+		.algo_data	= &sibyte_board_data[1],
+		.nr		= 1,
+		.name		= "SiByte SMBus 1",
+	},
+};
+
+static int __init i2c_sibyte_init(void)
+{
+	pr_info("i2c-sibyte: i2c SMBus adapter module for SiByte board\n");
+	if (i2c_sibyte_add_bus(&sibyte_board_adapter[0], K_SMB_FREQ_100KHZ) < 0)
+		return -ENODEV;
+	if (i2c_sibyte_add_bus(&sibyte_board_adapter[1],
+			       K_SMB_FREQ_400KHZ) < 0) {
+		i2c_del_adapter(&sibyte_board_adapter[0]);
+		return -ENODEV;
+	}
+	return 0;
+}
+
+static void __exit i2c_sibyte_exit(void)
+{
+	i2c_del_adapter(&sibyte_board_adapter[0]);
+	i2c_del_adapter(&sibyte_board_adapter[1]);
+}
+
+module_init(i2c_sibyte_init);
+module_exit(i2c_sibyte_exit);
+
+MODULE_AUTHOR("Kip Walker (Broadcom Corp.), Steven J. Hill <sjhill@realitydiluted.com>");
+MODULE_DESCRIPTION("SMBus adapter routines for SiByte boards");
+MODULE_LICENSE("GPL");
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-simtec.c b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-simtec.c
new file mode 100644
index 0000000..4fc87e7
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-simtec.c
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2005 Simtec Electronics
+ *	Ben Dooks <ben@simtec.co.uk>
+ *
+ * Simtec Generic I2C Controller
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+
+struct simtec_i2c_data {
+	struct resource		*ioarea;
+	void __iomem		*reg;
+	struct i2c_adapter	 adap;
+	struct i2c_algo_bit_data bit;
+};
+
+#define CMD_SET_SDA	(1<<2)
+#define CMD_SET_SCL	(1<<3)
+
+#define STATE_SDA	(1<<0)
+#define STATE_SCL	(1<<1)
+
+/* i2c bit-bus functions */
+
+static void simtec_i2c_setsda(void *pw, int state)
+{
+	struct simtec_i2c_data *pd = pw;
+	writeb(CMD_SET_SDA | (state ? STATE_SDA : 0), pd->reg);
+}
+
+static void simtec_i2c_setscl(void *pw, int state)
+{
+	struct simtec_i2c_data *pd = pw;
+	writeb(CMD_SET_SCL | (state ? STATE_SCL : 0), pd->reg);
+}
+
+static int simtec_i2c_getsda(void *pw)
+{
+	struct simtec_i2c_data *pd = pw;
+	return readb(pd->reg) & STATE_SDA ? 1 : 0;
+}
+
+static int simtec_i2c_getscl(void *pw)
+{
+	struct simtec_i2c_data *pd = pw;
+	return readb(pd->reg) & STATE_SCL ? 1 : 0;
+}
+
+/* device registration */
+
+static int simtec_i2c_probe(struct platform_device *dev)
+{
+	struct simtec_i2c_data *pd;
+	struct resource *res;
+	int size;
+	int ret;
+
+	pd = kzalloc(sizeof(struct simtec_i2c_data), GFP_KERNEL);
+	if (pd == NULL) {
+		dev_err(&dev->dev, "cannot allocate private data\n");
+		return -ENOMEM;
+	}
+
+	platform_set_drvdata(dev, pd);
+
+	res = platform_get_resource(dev, IORESOURCE_MEM, 0);
+	if (res == NULL) {
+		dev_err(&dev->dev, "cannot find IO resource\n");
+		ret = -ENOENT;
+		goto err;
+	}
+
+	size = resource_size(res);
+
+	pd->ioarea = request_mem_region(res->start, size, dev->name);
+	if (pd->ioarea == NULL) {
+		dev_err(&dev->dev, "cannot request IO\n");
+		ret = -ENXIO;
+		goto err;
+	}
+
+	pd->reg = ioremap(res->start, size);
+	if (pd->reg == NULL) {
+		dev_err(&dev->dev, "cannot map IO\n");
+		ret = -ENXIO;
+		goto err_res;
+	}
+
+	/* setup the private data */
+
+	pd->adap.owner = THIS_MODULE;
+	pd->adap.algo_data = &pd->bit;
+	pd->adap.dev.parent = &dev->dev;
+
+	strlcpy(pd->adap.name, "Simtec I2C", sizeof(pd->adap.name));
+
+	pd->bit.data = pd;
+	pd->bit.setsda = simtec_i2c_setsda;
+	pd->bit.setscl = simtec_i2c_setscl;
+	pd->bit.getsda = simtec_i2c_getsda;
+	pd->bit.getscl = simtec_i2c_getscl;
+	pd->bit.timeout = HZ;
+	pd->bit.udelay = 20;
+
+	ret = i2c_bit_add_bus(&pd->adap);
+	if (ret)
+		goto err_all;
+
+	return 0;
+
+ err_all:
+	iounmap(pd->reg);
+
+ err_res:
+	release_resource(pd->ioarea);
+	kfree(pd->ioarea);
+
+ err:
+	kfree(pd);
+	return ret;
+}
+
+static int simtec_i2c_remove(struct platform_device *dev)
+{
+	struct simtec_i2c_data *pd = platform_get_drvdata(dev);
+
+	i2c_del_adapter(&pd->adap);
+
+	iounmap(pd->reg);
+	release_resource(pd->ioarea);
+	kfree(pd->ioarea);
+	kfree(pd);
+
+	return 0;
+}
+
+/* device driver */
+
+static struct platform_driver simtec_i2c_driver = {
+	.driver		= {
+		.name		= "simtec-i2c",
+		.owner		= THIS_MODULE,
+	},
+	.probe		= simtec_i2c_probe,
+	.remove		= simtec_i2c_remove,
+};
+
+module_platform_driver(simtec_i2c_driver);
+
+MODULE_DESCRIPTION("Simtec Generic I2C Bus driver");
+MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:simtec-i2c");
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-sirf.c b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-sirf.c
new file mode 100644
index 0000000..5574a47
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-sirf.c
@@ -0,0 +1,459 @@
+/*
+ * I2C bus driver for CSR SiRFprimaII
+ *
+ * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+
+#define SIRFSOC_I2C_CLK_CTRL		0x00
+#define SIRFSOC_I2C_STATUS		0x0C
+#define SIRFSOC_I2C_CTRL		0x10
+#define SIRFSOC_I2C_IO_CTRL		0x14
+#define SIRFSOC_I2C_SDA_DELAY		0x18
+#define SIRFSOC_I2C_CMD_START		0x1C
+#define SIRFSOC_I2C_CMD_BUF		0x30
+#define SIRFSOC_I2C_DATA_BUF		0x80
+
+#define SIRFSOC_I2C_CMD_BUF_MAX		16
+#define SIRFSOC_I2C_DATA_BUF_MAX	16
+
+#define SIRFSOC_I2C_CMD(x)		(SIRFSOC_I2C_CMD_BUF + (x)*0x04)
+#define SIRFSOC_I2C_DATA_MASK(x)        (0xFF<<(((x)&3)*8))
+#define SIRFSOC_I2C_DATA_SHIFT(x)       (((x)&3)*8)
+
+#define SIRFSOC_I2C_DIV_MASK		(0xFFFF)
+
+/* I2C status flags */
+#define SIRFSOC_I2C_STAT_BUSY		BIT(0)
+#define SIRFSOC_I2C_STAT_TIP		BIT(1)
+#define SIRFSOC_I2C_STAT_NACK		BIT(2)
+#define SIRFSOC_I2C_STAT_TR_INT		BIT(4)
+#define SIRFSOC_I2C_STAT_STOP		BIT(6)
+#define SIRFSOC_I2C_STAT_CMD_DONE	BIT(8)
+#define SIRFSOC_I2C_STAT_ERR		BIT(9)
+#define SIRFSOC_I2C_CMD_INDEX		(0x1F<<16)
+
+/* I2C control flags */
+#define SIRFSOC_I2C_RESET		BIT(0)
+#define SIRFSOC_I2C_CORE_EN		BIT(1)
+#define SIRFSOC_I2C_MASTER_MODE		BIT(2)
+#define SIRFSOC_I2C_CMD_DONE_EN		BIT(11)
+#define SIRFSOC_I2C_ERR_INT_EN		BIT(12)
+
+#define SIRFSOC_I2C_SDA_DELAY_MASK	(0xFF)
+#define SIRFSOC_I2C_SCLF_FILTER		(3<<8)
+
+#define SIRFSOC_I2C_START_CMD		BIT(0)
+
+#define SIRFSOC_I2C_CMD_RP(x)		((x)&0x7)
+#define SIRFSOC_I2C_NACK		BIT(3)
+#define SIRFSOC_I2C_WRITE		BIT(4)
+#define SIRFSOC_I2C_READ		BIT(5)
+#define SIRFSOC_I2C_STOP		BIT(6)
+#define SIRFSOC_I2C_START		BIT(7)
+
+#define SIRFSOC_I2C_DEFAULT_SPEED 100000
+
+struct sirfsoc_i2c {
+	void __iomem *base;
+	struct clk *clk;
+	u32 cmd_ptr;		/* Current position in CMD buffer */
+	u8 *buf;		/* Buffer passed by user */
+	u32 msg_len;		/* Message length */
+	u32 finished_len;	/* number of bytes read/written */
+	u32 read_cmd_len;	/* number of read cmd sent */
+	int msg_read;		/* 1 indicates a read message */
+	int err_status;		/* 1 indicates an error on bus */
+
+	u32 sda_delay;		/* For suspend/resume */
+	u32 clk_div;
+	int last;		/* Last message in transfer, STOP cmd can be sent */
+
+	struct completion done;	/* indicates completion of message transfer */
+	struct i2c_adapter adapter;
+};
+
+static void i2c_sirfsoc_read_data(struct sirfsoc_i2c *siic)
+{
+	u32 data = 0;
+	int i;
+
+	for (i = 0; i < siic->read_cmd_len; i++) {
+		if (!(i & 0x3))
+			data = readl(siic->base + SIRFSOC_I2C_DATA_BUF + i);
+		siic->buf[siic->finished_len++] =
+			(u8)((data & SIRFSOC_I2C_DATA_MASK(i)) >>
+				SIRFSOC_I2C_DATA_SHIFT(i));
+	}
+}
+
+static void i2c_sirfsoc_queue_cmd(struct sirfsoc_i2c *siic)
+{
+	u32 regval;
+	int i = 0;
+
+	if (siic->msg_read) {
+		while (((siic->finished_len + i) < siic->msg_len)
+				&& (siic->cmd_ptr < SIRFSOC_I2C_CMD_BUF_MAX)) {
+			regval = SIRFSOC_I2C_READ | SIRFSOC_I2C_CMD_RP(0);
+			if (((siic->finished_len + i) ==
+					(siic->msg_len - 1)) && siic->last)
+				regval |= SIRFSOC_I2C_STOP | SIRFSOC_I2C_NACK;
+			writel(regval,
+				siic->base + SIRFSOC_I2C_CMD(siic->cmd_ptr++));
+			i++;
+		}
+
+		siic->read_cmd_len = i;
+	} else {
+		while ((siic->cmd_ptr < SIRFSOC_I2C_CMD_BUF_MAX - 1)
+				&& (siic->finished_len < siic->msg_len)) {
+			regval = SIRFSOC_I2C_WRITE | SIRFSOC_I2C_CMD_RP(0);
+			if ((siic->finished_len == (siic->msg_len - 1))
+				&& siic->last)
+				regval |= SIRFSOC_I2C_STOP;
+			writel(regval,
+				siic->base + SIRFSOC_I2C_CMD(siic->cmd_ptr++));
+			writel(siic->buf[siic->finished_len++],
+				siic->base + SIRFSOC_I2C_CMD(siic->cmd_ptr++));
+		}
+	}
+	siic->cmd_ptr = 0;
+
+	/* Trigger the transfer */
+	writel(SIRFSOC_I2C_START_CMD, siic->base + SIRFSOC_I2C_CMD_START);
+}
+
+static irqreturn_t i2c_sirfsoc_irq(int irq, void *dev_id)
+{
+	struct sirfsoc_i2c *siic = (struct sirfsoc_i2c *)dev_id;
+	u32 i2c_stat = readl(siic->base + SIRFSOC_I2C_STATUS);
+
+	if (i2c_stat & SIRFSOC_I2C_STAT_ERR) {
+		/* Error conditions */
+		siic->err_status = 1;
+		writel(SIRFSOC_I2C_STAT_ERR, siic->base + SIRFSOC_I2C_STATUS);
+
+		if (i2c_stat & SIRFSOC_I2C_STAT_NACK)
+			dev_err(&siic->adapter.dev, "ACK not received\n");
+		else
+			dev_err(&siic->adapter.dev, "I2C error\n");
+
+		complete(&siic->done);
+	} else if (i2c_stat & SIRFSOC_I2C_STAT_CMD_DONE) {
+		/* CMD buffer execution complete */
+		if (siic->msg_read)
+			i2c_sirfsoc_read_data(siic);
+		if (siic->finished_len == siic->msg_len)
+			complete(&siic->done);
+		else /* Fill a new CMD buffer for left data */
+			i2c_sirfsoc_queue_cmd(siic);
+
+		writel(SIRFSOC_I2C_STAT_CMD_DONE, siic->base + SIRFSOC_I2C_STATUS);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static void i2c_sirfsoc_set_address(struct sirfsoc_i2c *siic,
+	struct i2c_msg *msg)
+{
+	unsigned char addr;
+	u32 regval = SIRFSOC_I2C_START | SIRFSOC_I2C_CMD_RP(0) | SIRFSOC_I2C_WRITE;
+
+	/* no data and last message -> add STOP */
+	if (siic->last && (msg->len == 0))
+		regval |= SIRFSOC_I2C_STOP;
+
+	writel(regval, siic->base + SIRFSOC_I2C_CMD(siic->cmd_ptr++));
+
+	addr = msg->addr << 1;	/* Generate address */
+	if (msg->flags & I2C_M_RD)
+		addr |= 1;
+
+	writel(addr, siic->base + SIRFSOC_I2C_CMD(siic->cmd_ptr++));
+}
+
+static int i2c_sirfsoc_xfer_msg(struct sirfsoc_i2c *siic, struct i2c_msg *msg)
+{
+	u32 regval = readl(siic->base + SIRFSOC_I2C_CTRL);
+	/* timeout waiting for the xfer to finish or fail */
+	int timeout = msecs_to_jiffies((msg->len + 1) * 50);
+	int ret = 0;
+
+	i2c_sirfsoc_set_address(siic, msg);
+
+	writel(regval | SIRFSOC_I2C_CMD_DONE_EN | SIRFSOC_I2C_ERR_INT_EN,
+		siic->base + SIRFSOC_I2C_CTRL);
+	i2c_sirfsoc_queue_cmd(siic);
+
+	if (wait_for_completion_timeout(&siic->done, timeout) == 0) {
+		siic->err_status = 1;
+		dev_err(&siic->adapter.dev, "Transfer timeout\n");
+	}
+
+	writel(regval & ~(SIRFSOC_I2C_CMD_DONE_EN | SIRFSOC_I2C_ERR_INT_EN),
+		siic->base + SIRFSOC_I2C_CTRL);
+	writel(0, siic->base + SIRFSOC_I2C_CMD_START);
+
+	if (siic->err_status) {
+		writel(readl(siic->base + SIRFSOC_I2C_CTRL) | SIRFSOC_I2C_RESET,
+			siic->base + SIRFSOC_I2C_CTRL);
+		while (readl(siic->base + SIRFSOC_I2C_CTRL) & SIRFSOC_I2C_RESET)
+			cpu_relax();
+
+		ret = -EIO;
+	}
+
+	return ret;
+}
+
+static u32 i2c_sirfsoc_func(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static int i2c_sirfsoc_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
+	int num)
+{
+	struct sirfsoc_i2c *siic = adap->algo_data;
+	int i, ret;
+
+	clk_enable(siic->clk);
+
+	for (i = 0; i < num; i++) {
+		siic->buf = msgs[i].buf;
+		siic->msg_len = msgs[i].len;
+		siic->msg_read = !!(msgs[i].flags & I2C_M_RD);
+		siic->err_status = 0;
+		siic->cmd_ptr = 0;
+		siic->finished_len = 0;
+		siic->last = (i == (num - 1));
+
+		ret = i2c_sirfsoc_xfer_msg(siic, &msgs[i]);
+		if (ret) {
+			clk_disable(siic->clk);
+			return ret;
+		}
+	}
+
+	clk_disable(siic->clk);
+	return num;
+}
+
+/* I2C algorithms associated with this master controller driver */
+static const struct i2c_algorithm i2c_sirfsoc_algo = {
+	.master_xfer = i2c_sirfsoc_xfer,
+	.functionality = i2c_sirfsoc_func,
+};
+
+static int __devinit i2c_sirfsoc_probe(struct platform_device *pdev)
+{
+	struct sirfsoc_i2c *siic;
+	struct i2c_adapter *adap;
+	struct resource *mem_res;
+	struct clk *clk;
+	int bitrate;
+	int ctrl_speed;
+	int irq;
+
+	int err;
+	u32 regval;
+
+	clk = clk_get(&pdev->dev, NULL);
+	if (IS_ERR(clk)) {
+		err = PTR_ERR(clk);
+		dev_err(&pdev->dev, "Clock get failed\n");
+		goto err_get_clk;
+	}
+
+	err = clk_prepare(clk);
+	if (err) {
+		dev_err(&pdev->dev, "Clock prepare failed\n");
+		goto err_clk_prep;
+	}
+
+	err = clk_enable(clk);
+	if (err) {
+		dev_err(&pdev->dev, "Clock enable failed\n");
+		goto err_clk_en;
+	}
+
+	ctrl_speed = clk_get_rate(clk);
+
+	siic = devm_kzalloc(&pdev->dev, sizeof(*siic), GFP_KERNEL);
+	if (!siic) {
+		dev_err(&pdev->dev, "Can't allocate driver data\n");
+		err = -ENOMEM;
+		goto out;
+	}
+	adap = &siic->adapter;
+	adap->class = I2C_CLASS_HWMON;
+
+	mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (mem_res == NULL) {
+		dev_err(&pdev->dev, "Unable to get MEM resource\n");
+		err = -EINVAL;
+		goto out;
+	}
+
+	siic->base = devm_request_and_ioremap(&pdev->dev, mem_res);
+	if (siic->base == NULL) {
+		dev_err(&pdev->dev, "IO remap failed!\n");
+		err = -ENOMEM;
+		goto out;
+	}
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		err = irq;
+		goto out;
+	}
+	err = devm_request_irq(&pdev->dev, irq, i2c_sirfsoc_irq, 0,
+		dev_name(&pdev->dev), siic);
+	if (err)
+		goto out;
+
+	adap->algo = &i2c_sirfsoc_algo;
+	adap->algo_data = siic;
+
+	adap->dev.parent = &pdev->dev;
+	adap->nr = pdev->id;
+
+	strlcpy(adap->name, "sirfsoc-i2c", sizeof(adap->name));
+
+	platform_set_drvdata(pdev, adap);
+	init_completion(&siic->done);
+
+	/* Controller Initalisation */
+
+	writel(SIRFSOC_I2C_RESET, siic->base + SIRFSOC_I2C_CTRL);
+	while (readl(siic->base + SIRFSOC_I2C_CTRL) & SIRFSOC_I2C_RESET)
+		cpu_relax();
+	writel(SIRFSOC_I2C_CORE_EN | SIRFSOC_I2C_MASTER_MODE,
+		siic->base + SIRFSOC_I2C_CTRL);
+
+	siic->clk = clk;
+
+	err = of_property_read_u32(pdev->dev.of_node,
+		"clock-frequency", &bitrate);
+	if (err < 0)
+		bitrate = SIRFSOC_I2C_DEFAULT_SPEED;
+
+	if (bitrate < 100000)
+		regval =
+			(2 * ctrl_speed) / (2 * bitrate * 11);
+	else
+		regval = ctrl_speed / (bitrate * 5);
+
+	writel(regval, siic->base + SIRFSOC_I2C_CLK_CTRL);
+	if (regval > 0xFF)
+		writel(0xFF, siic->base + SIRFSOC_I2C_SDA_DELAY);
+	else
+		writel(regval, siic->base + SIRFSOC_I2C_SDA_DELAY);
+
+	err = i2c_add_numbered_adapter(adap);
+	if (err < 0) {
+		dev_err(&pdev->dev, "Can't add new i2c adapter\n");
+		goto out;
+	}
+
+	clk_disable(clk);
+
+	dev_info(&pdev->dev, " I2C adapter ready to operate\n");
+
+	return 0;
+
+out:
+	clk_disable(clk);
+err_clk_en:
+	clk_unprepare(clk);
+err_clk_prep:
+	clk_put(clk);
+err_get_clk:
+	return err;
+}
+
+static int __devexit i2c_sirfsoc_remove(struct platform_device *pdev)
+{
+	struct i2c_adapter *adapter = platform_get_drvdata(pdev);
+	struct sirfsoc_i2c *siic = adapter->algo_data;
+
+	writel(SIRFSOC_I2C_RESET, siic->base + SIRFSOC_I2C_CTRL);
+	i2c_del_adapter(adapter);
+	clk_unprepare(siic->clk);
+	clk_put(siic->clk);
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int i2c_sirfsoc_suspend(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct i2c_adapter *adapter = platform_get_drvdata(pdev);
+	struct sirfsoc_i2c *siic = adapter->algo_data;
+
+	clk_enable(siic->clk);
+	siic->sda_delay = readl(siic->base + SIRFSOC_I2C_SDA_DELAY);
+	siic->clk_div = readl(siic->base + SIRFSOC_I2C_CLK_CTRL);
+	clk_disable(siic->clk);
+	return 0;
+}
+
+static int i2c_sirfsoc_resume(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct i2c_adapter *adapter = platform_get_drvdata(pdev);
+	struct sirfsoc_i2c *siic = adapter->algo_data;
+
+	clk_enable(siic->clk);
+	writel(SIRFSOC_I2C_RESET, siic->base + SIRFSOC_I2C_CTRL);
+	writel(SIRFSOC_I2C_CORE_EN | SIRFSOC_I2C_MASTER_MODE,
+		siic->base + SIRFSOC_I2C_CTRL);
+	writel(siic->clk_div, siic->base + SIRFSOC_I2C_CLK_CTRL);
+	writel(siic->sda_delay, siic->base + SIRFSOC_I2C_SDA_DELAY);
+	clk_disable(siic->clk);
+	return 0;
+}
+
+static const struct dev_pm_ops i2c_sirfsoc_pm_ops = {
+	.suspend = i2c_sirfsoc_suspend,
+	.resume = i2c_sirfsoc_resume,
+};
+#endif
+
+static const struct of_device_id sirfsoc_i2c_of_match[] __devinitconst = {
+	{ .compatible = "sirf,prima2-i2c", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, sirfsoc_i2c_of_match);
+
+static struct platform_driver i2c_sirfsoc_driver = {
+	.driver = {
+		.name = "sirfsoc_i2c",
+		.owner = THIS_MODULE,
+#ifdef CONFIG_PM
+		.pm = &i2c_sirfsoc_pm_ops,
+#endif
+		.of_match_table = sirfsoc_i2c_of_match,
+	},
+	.probe = i2c_sirfsoc_probe,
+	.remove = __devexit_p(i2c_sirfsoc_remove),
+};
+module_platform_driver(i2c_sirfsoc_driver);
+
+MODULE_DESCRIPTION("SiRF SoC I2C master controller driver");
+MODULE_AUTHOR("Zhiwu Song <Zhiwu.Song@csr.com>, "
+	"Xiangzhen Ye <Xiangzhen.Ye@csr.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-sis5595.c b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-sis5595.c
new file mode 100644
index 0000000..87e5126
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-sis5595.c
@@ -0,0 +1,434 @@
+/*
+    Copyright (c) 1998, 1999  Frodo Looijaard <frodol@dds.nl> and
+    Philip Edelbrock <phil@netroedge.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/* Note: we assume there can only be one SIS5595 with one SMBus interface */
+
+/*
+   Note: all have mfr. ID 0x1039.
+   SUPPORTED		PCI ID		
+	5595		0008
+
+   Note: these chips contain a 0008 device which is incompatible with the
+         5595. We recognize these by the presence of the listed
+         "blacklist" PCI ID and refuse to load.
+
+   NOT SUPPORTED	PCI ID		BLACKLIST PCI ID	
+	 540		0008		0540
+	 550		0008		0550
+	5513		0008		5511
+	5581		0008		5597
+	5582		0008		5597
+	5597		0008		5597
+	5598		0008		5597/5598
+	 630		0008		0630
+	 645		0008		0645
+	 646		0008		0646
+	 648		0008		0648
+	 650		0008		0650
+	 651		0008		0651
+	 730		0008		0730
+	 735		0008		0735
+	 745		0008		0745
+	 746		0008		0746
+*/
+
+/* TO DO: 
+ * Add Block Transfers (ugly, but supported by the adapter)
+ * Add adapter resets
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/acpi.h>
+#include <linux/io.h>
+
+static int blacklist[] = {
+	PCI_DEVICE_ID_SI_540,
+	PCI_DEVICE_ID_SI_550,
+	PCI_DEVICE_ID_SI_630,
+	PCI_DEVICE_ID_SI_645,
+	PCI_DEVICE_ID_SI_646,
+	PCI_DEVICE_ID_SI_648,
+	PCI_DEVICE_ID_SI_650,
+	PCI_DEVICE_ID_SI_651,
+	PCI_DEVICE_ID_SI_730,
+	PCI_DEVICE_ID_SI_735,
+	PCI_DEVICE_ID_SI_745,
+	PCI_DEVICE_ID_SI_746,
+	PCI_DEVICE_ID_SI_5511,	/* 5513 chip has the 0008 device but that ID
+				   shows up in other chips so we use the 5511
+				   ID for recognition */
+	PCI_DEVICE_ID_SI_5597,
+	PCI_DEVICE_ID_SI_5598,
+	0,			/* terminates the list */
+};
+
+/* Length of ISA address segment */
+#define SIS5595_EXTENT		8
+/* SIS5595 SMBus registers */
+#define SMB_STS_LO		0x00
+#define SMB_STS_HI		0x01
+#define SMB_CTL_LO		0x02
+#define SMB_CTL_HI		0x03
+#define SMB_ADDR		0x04
+#define SMB_CMD			0x05
+#define SMB_PCNT		0x06
+#define SMB_CNT			0x07
+#define SMB_BYTE		0x08
+#define SMB_DEV			0x10
+#define SMB_DB0			0x11
+#define SMB_DB1			0x12
+#define SMB_HAA			0x13
+
+/* PCI Address Constants */
+#define SMB_INDEX		0x38
+#define SMB_DAT			0x39
+#define SIS5595_ENABLE_REG	0x40
+#define ACPI_BASE		0x90
+
+/* Other settings */
+#define MAX_TIMEOUT		500
+
+/* SIS5595 constants */
+#define SIS5595_QUICK		0x00
+#define SIS5595_BYTE		0x02
+#define SIS5595_BYTE_DATA	0x04
+#define SIS5595_WORD_DATA	0x06
+#define SIS5595_PROC_CALL	0x08
+#define SIS5595_BLOCK_DATA	0x0A
+
+/* insmod parameters */
+
+/* If force_addr is set to anything different from 0, we forcibly enable
+   the device at the given address. */
+static u16 force_addr;
+module_param(force_addr, ushort, 0);
+MODULE_PARM_DESC(force_addr, "Initialize the base address of the i2c controller");
+
+static struct pci_driver sis5595_driver;
+static unsigned short sis5595_base;
+static struct pci_dev *sis5595_pdev;
+
+static u8 sis5595_read(u8 reg)
+{
+	outb(reg, sis5595_base + SMB_INDEX);
+	return inb(sis5595_base + SMB_DAT);
+}
+
+static void sis5595_write(u8 reg, u8 data)
+{
+	outb(reg, sis5595_base + SMB_INDEX);
+	outb(data, sis5595_base + SMB_DAT);
+}
+
+static int __devinit sis5595_setup(struct pci_dev *SIS5595_dev)
+{
+	u16 a;
+	u8 val;
+	int *i;
+	int retval;
+
+	/* Look for imposters */
+	for (i = blacklist; *i != 0; i++) {
+		struct pci_dev *dev;
+		dev = pci_get_device(PCI_VENDOR_ID_SI, *i, NULL);
+		if (dev) {
+			dev_err(&SIS5595_dev->dev, "Looked for SIS5595 but found unsupported device %.4x\n", *i);
+			pci_dev_put(dev);
+			return -ENODEV;
+		}
+	}
+
+	/* Determine the address of the SMBus areas */
+	pci_read_config_word(SIS5595_dev, ACPI_BASE, &sis5595_base);
+	if (sis5595_base == 0 && force_addr == 0) {
+		dev_err(&SIS5595_dev->dev, "ACPI base address uninitialized - upgrade BIOS or use force_addr=0xaddr\n");
+		return -ENODEV;
+	}
+
+	if (force_addr)
+		sis5595_base = force_addr & ~(SIS5595_EXTENT - 1);
+	dev_dbg(&SIS5595_dev->dev, "ACPI Base address: %04x\n", sis5595_base);
+
+	/* NB: We grab just the two SMBus registers here, but this may still
+	 * interfere with ACPI :-(  */
+	retval = acpi_check_region(sis5595_base + SMB_INDEX, 2,
+				   sis5595_driver.name);
+	if (retval)
+		return retval;
+
+	if (!request_region(sis5595_base + SMB_INDEX, 2,
+			    sis5595_driver.name)) {
+		dev_err(&SIS5595_dev->dev, "SMBus registers 0x%04x-0x%04x already in use!\n",
+			sis5595_base + SMB_INDEX, sis5595_base + SMB_INDEX + 1);
+		return -ENODEV;
+	}
+
+	if (force_addr) {
+		dev_info(&SIS5595_dev->dev, "forcing ISA address 0x%04X\n", sis5595_base);
+		if (pci_write_config_word(SIS5595_dev, ACPI_BASE, sis5595_base)
+		    != PCIBIOS_SUCCESSFUL)
+			goto error;
+		if (pci_read_config_word(SIS5595_dev, ACPI_BASE, &a)
+		    != PCIBIOS_SUCCESSFUL)
+			goto error;
+		if ((a & ~(SIS5595_EXTENT - 1)) != sis5595_base) {
+			/* doesn't work for some chips! */
+			dev_err(&SIS5595_dev->dev, "force address failed - not supported?\n");
+			goto error;
+		}
+	}
+
+	if (pci_read_config_byte(SIS5595_dev, SIS5595_ENABLE_REG, &val)
+	    != PCIBIOS_SUCCESSFUL)
+		goto error;
+	if ((val & 0x80) == 0) {
+		dev_info(&SIS5595_dev->dev, "enabling ACPI\n");
+		if (pci_write_config_byte(SIS5595_dev, SIS5595_ENABLE_REG, val | 0x80)
+		    != PCIBIOS_SUCCESSFUL)
+			goto error;
+		if (pci_read_config_byte(SIS5595_dev, SIS5595_ENABLE_REG, &val)
+		    != PCIBIOS_SUCCESSFUL)
+			goto error;
+		if ((val & 0x80) == 0) {
+			/* doesn't work for some chips? */
+			dev_err(&SIS5595_dev->dev, "ACPI enable failed - not supported?\n");
+			goto error;
+		}
+	}
+
+	/* Everything is happy */
+	return 0;
+
+error:
+	release_region(sis5595_base + SMB_INDEX, 2);
+	return -ENODEV;
+}
+
+static int sis5595_transaction(struct i2c_adapter *adap)
+{
+	int temp;
+	int result = 0;
+	int timeout = 0;
+
+	/* Make sure the SMBus host is ready to start transmitting */
+	temp = sis5595_read(SMB_STS_LO) + (sis5595_read(SMB_STS_HI) << 8);
+	if (temp != 0x00) {
+		dev_dbg(&adap->dev, "SMBus busy (%04x). Resetting...\n", temp);
+		sis5595_write(SMB_STS_LO, temp & 0xff);
+		sis5595_write(SMB_STS_HI, temp >> 8);
+		if ((temp = sis5595_read(SMB_STS_LO) + (sis5595_read(SMB_STS_HI) << 8)) != 0x00) {
+			dev_dbg(&adap->dev, "Failed! (%02x)\n", temp);
+			return -EBUSY;
+		} else {
+			dev_dbg(&adap->dev, "Successful!\n");
+		}
+	}
+
+	/* start the transaction by setting bit 4 */
+	sis5595_write(SMB_CTL_LO, sis5595_read(SMB_CTL_LO) | 0x10);
+
+	/* We will always wait for a fraction of a second! */
+	do {
+		msleep(1);
+		temp = sis5595_read(SMB_STS_LO);
+	} while (!(temp & 0x40) && (timeout++ < MAX_TIMEOUT));
+
+	/* If the SMBus is still busy, we give up */
+	if (timeout > MAX_TIMEOUT) {
+		dev_dbg(&adap->dev, "SMBus Timeout!\n");
+		result = -ETIMEDOUT;
+	}
+
+	if (temp & 0x10) {
+		dev_dbg(&adap->dev, "Error: Failed bus transaction\n");
+		result = -ENXIO;
+	}
+
+	if (temp & 0x20) {
+		dev_err(&adap->dev, "Bus collision! SMBus may be locked until "
+			"next hard reset (or not...)\n");
+		/* Clock stops and slave is stuck in mid-transmission */
+		result = -EIO;
+	}
+
+	temp = sis5595_read(SMB_STS_LO) + (sis5595_read(SMB_STS_HI) << 8);
+	if (temp != 0x00) {
+		sis5595_write(SMB_STS_LO, temp & 0xff);
+		sis5595_write(SMB_STS_HI, temp >> 8);
+	}
+
+	temp = sis5595_read(SMB_STS_LO) + (sis5595_read(SMB_STS_HI) << 8);
+	if (temp != 0x00)
+		dev_dbg(&adap->dev, "Failed reset at end of transaction (%02x)\n", temp);
+
+	return result;
+}
+
+/* Return negative errno on error. */
+static s32 sis5595_access(struct i2c_adapter *adap, u16 addr,
+			  unsigned short flags, char read_write,
+			  u8 command, int size, union i2c_smbus_data *data)
+{
+	int status;
+
+	switch (size) {
+	case I2C_SMBUS_QUICK:
+		sis5595_write(SMB_ADDR, ((addr & 0x7f) << 1) | (read_write & 0x01));
+		size = SIS5595_QUICK;
+		break;
+	case I2C_SMBUS_BYTE:
+		sis5595_write(SMB_ADDR, ((addr & 0x7f) << 1) | (read_write & 0x01));
+		if (read_write == I2C_SMBUS_WRITE)
+			sis5595_write(SMB_CMD, command);
+		size = SIS5595_BYTE;
+		break;
+	case I2C_SMBUS_BYTE_DATA:
+		sis5595_write(SMB_ADDR, ((addr & 0x7f) << 1) | (read_write & 0x01));
+		sis5595_write(SMB_CMD, command);
+		if (read_write == I2C_SMBUS_WRITE)
+			sis5595_write(SMB_BYTE, data->byte);
+		size = SIS5595_BYTE_DATA;
+		break;
+	case I2C_SMBUS_PROC_CALL:
+	case I2C_SMBUS_WORD_DATA:
+		sis5595_write(SMB_ADDR, ((addr & 0x7f) << 1) | (read_write & 0x01));
+		sis5595_write(SMB_CMD, command);
+		if (read_write == I2C_SMBUS_WRITE) {
+			sis5595_write(SMB_BYTE, data->word & 0xff);
+			sis5595_write(SMB_BYTE + 1,
+				      (data->word & 0xff00) >> 8);
+		}
+		size = (size == I2C_SMBUS_PROC_CALL) ? SIS5595_PROC_CALL : SIS5595_WORD_DATA;
+		break;
+	default:
+		dev_warn(&adap->dev, "Unsupported transaction %d\n", size);
+		return -EOPNOTSUPP;
+	}
+
+	sis5595_write(SMB_CTL_LO, ((size & 0x0E)));
+
+	status = sis5595_transaction(adap);
+	if (status)
+		return status;
+
+	if ((size != SIS5595_PROC_CALL) &&
+	    ((read_write == I2C_SMBUS_WRITE) || (size == SIS5595_QUICK)))
+		return 0;
+
+
+	switch (size) {
+	case SIS5595_BYTE:
+	case SIS5595_BYTE_DATA:
+		data->byte = sis5595_read(SMB_BYTE);
+		break;
+	case SIS5595_WORD_DATA:
+	case SIS5595_PROC_CALL:
+		data->word = sis5595_read(SMB_BYTE) + (sis5595_read(SMB_BYTE + 1) << 8);
+		break;
+	}
+	return 0;
+}
+
+static u32 sis5595_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+	    I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+	    I2C_FUNC_SMBUS_PROC_CALL;
+}
+
+static const struct i2c_algorithm smbus_algorithm = {
+	.smbus_xfer	= sis5595_access,
+	.functionality	= sis5595_func,
+};
+
+static struct i2c_adapter sis5595_adapter = {
+	.owner		= THIS_MODULE,
+	.class          = I2C_CLASS_HWMON | I2C_CLASS_SPD,
+	.algo		= &smbus_algorithm,
+};
+
+static DEFINE_PCI_DEVICE_TABLE(sis5595_ids) = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503) }, 
+	{ 0, }
+};
+
+MODULE_DEVICE_TABLE (pci, sis5595_ids);
+
+static int __devinit sis5595_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	int err;
+
+	if (sis5595_setup(dev)) {
+		dev_err(&dev->dev, "SIS5595 not detected, module not inserted.\n");
+		return -ENODEV;
+	}
+
+	/* set up the sysfs linkage to our parent device */
+	sis5595_adapter.dev.parent = &dev->dev;
+
+	snprintf(sis5595_adapter.name, sizeof(sis5595_adapter.name),
+		 "SMBus SIS5595 adapter at %04x", sis5595_base + SMB_INDEX);
+	err = i2c_add_adapter(&sis5595_adapter);
+	if (err) {
+		release_region(sis5595_base + SMB_INDEX, 2);
+		return err;
+	}
+
+	/* Always return failure here.  This is to allow other drivers to bind
+	 * to this pci device.  We don't really want to have control over the
+	 * pci device, we only wanted to read as few register values from it.
+	 */
+	sis5595_pdev =  pci_dev_get(dev);
+	return -ENODEV;
+}
+
+static struct pci_driver sis5595_driver = {
+	.name		= "sis5595_smbus",
+	.id_table	= sis5595_ids,
+	.probe		= sis5595_probe,
+};
+
+static int __init i2c_sis5595_init(void)
+{
+	return pci_register_driver(&sis5595_driver);
+}
+
+static void __exit i2c_sis5595_exit(void)
+{
+	pci_unregister_driver(&sis5595_driver);
+	if (sis5595_pdev) {
+		i2c_del_adapter(&sis5595_adapter);
+		release_region(sis5595_base + SMB_INDEX, 2);
+		pci_dev_put(sis5595_pdev);
+		sis5595_pdev = NULL;
+	}
+}
+
+MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>");
+MODULE_DESCRIPTION("SIS5595 SMBus driver");
+MODULE_LICENSE("GPL");
+
+module_init(i2c_sis5595_init);
+module_exit(i2c_sis5595_exit);
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-sis630.c b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-sis630.c
new file mode 100644
index 0000000..15cf78f
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-sis630.c
@@ -0,0 +1,533 @@
+/*
+    Copyright (c) 2002,2003 Alexander Malysh <amalysh@web.de>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/*
+   Changes:
+   24.08.2002
+   	Fixed the typo in sis630_access (Thanks to Mark M. Hoffman)
+	Changed sis630_transaction.(Thanks to Mark M. Hoffman)
+   18.09.2002
+	Added SIS730 as supported.
+   21.09.2002
+	Added high_clock module option.If this option is set
+	used Host Master Clock 56KHz (default 14KHz).For now we save old Host
+	Master Clock and after transaction completed restore (otherwise
+	it's confuse BIOS and hung Machine).
+   24.09.2002
+	Fixed typo in sis630_access
+	Fixed logical error by restoring of Host Master Clock
+   31.07.2003
+   	Added block data read/write support.
+*/
+
+/*
+   Status: beta
+
+   Supports:
+	SIS 630
+	SIS 730
+
+   Note: we assume there can only be one device, with one SMBus interface.
+*/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/acpi.h>
+#include <linux/io.h>
+
+/* SIS630 SMBus registers */
+#define SMB_STS			0x80	/* status */
+#define SMB_EN			0x81	/* status enable */
+#define SMB_CNT			0x82
+#define SMBHOST_CNT		0x83
+#define SMB_ADDR		0x84
+#define SMB_CMD			0x85
+#define SMB_PCOUNT		0x86	/* processed count */
+#define SMB_COUNT		0x87
+#define SMB_BYTE		0x88	/* ~0x8F data byte field */
+#define SMBDEV_ADDR		0x90
+#define SMB_DB0			0x91
+#define SMB_DB1			0x92
+#define SMB_SAA			0x93
+
+/* register count for request_region */
+#define SIS630_SMB_IOREGION	20
+
+/* PCI address constants */
+/* acpi base address register  */
+#define SIS630_ACPI_BASE_REG	0x74
+/* bios control register */
+#define SIS630_BIOS_CTL_REG	0x40
+
+/* Other settings */
+#define MAX_TIMEOUT		500
+
+/* SIS630 constants */
+#define SIS630_QUICK		0x00
+#define SIS630_BYTE		0x01
+#define SIS630_BYTE_DATA	0x02
+#define SIS630_WORD_DATA	0x03
+#define SIS630_PCALL		0x04
+#define SIS630_BLOCK_DATA	0x05
+
+static struct pci_driver sis630_driver;
+
+/* insmod parameters */
+static bool high_clock;
+static bool force;
+module_param(high_clock, bool, 0);
+MODULE_PARM_DESC(high_clock, "Set Host Master Clock to 56KHz (default 14KHz).");
+module_param(force, bool, 0);
+MODULE_PARM_DESC(force, "Forcibly enable the SIS630. DANGEROUS!");
+
+/* acpi base address */
+static unsigned short acpi_base;
+
+/* supported chips */
+static int supported[] = {
+	PCI_DEVICE_ID_SI_630,
+	PCI_DEVICE_ID_SI_730,
+	0 /* terminates the list */
+};
+
+static inline u8 sis630_read(u8 reg)
+{
+	return inb(acpi_base + reg);
+}
+
+static inline void sis630_write(u8 reg, u8 data)
+{
+	outb(data, acpi_base + reg);
+}
+
+static int sis630_transaction_start(struct i2c_adapter *adap, int size, u8 *oldclock)
+{
+        int temp;
+
+	/* Make sure the SMBus host is ready to start transmitting. */
+	if ((temp = sis630_read(SMB_CNT) & 0x03) != 0x00) {
+		dev_dbg(&adap->dev, "SMBus busy (%02x).Resetting...\n",temp);
+		/* kill smbus transaction */
+		sis630_write(SMBHOST_CNT, 0x20);
+
+		if ((temp = sis630_read(SMB_CNT) & 0x03) != 0x00) {
+			dev_dbg(&adap->dev, "Failed! (%02x)\n", temp);
+			return -EBUSY;
+                } else {
+			dev_dbg(&adap->dev, "Successful!\n");
+		}
+        }
+
+	/* save old clock, so we can prevent machine for hung */
+	*oldclock = sis630_read(SMB_CNT);
+
+	dev_dbg(&adap->dev, "saved clock 0x%02x\n", *oldclock);
+
+	/* disable timeout interrupt , set Host Master Clock to 56KHz if requested */
+	if (high_clock)
+		sis630_write(SMB_CNT, 0x20);
+	else
+		sis630_write(SMB_CNT, (*oldclock & ~0x40));
+
+	/* clear all sticky bits */
+	temp = sis630_read(SMB_STS);
+	sis630_write(SMB_STS, temp & 0x1e);
+
+	/* start the transaction by setting bit 4 and size */
+	sis630_write(SMBHOST_CNT,0x10 | (size & 0x07));
+
+	return 0;
+}
+
+static int sis630_transaction_wait(struct i2c_adapter *adap, int size)
+{
+	int temp, result = 0, timeout = 0;
+
+	/* We will always wait for a fraction of a second! */
+	do {
+		msleep(1);
+		temp = sis630_read(SMB_STS);
+		/* check if block transmitted */
+		if (size == SIS630_BLOCK_DATA && (temp & 0x10))
+			break;
+	} while (!(temp & 0x0e) && (timeout++ < MAX_TIMEOUT));
+
+	/* If the SMBus is still busy, we give up */
+	if (timeout > MAX_TIMEOUT) {
+		dev_dbg(&adap->dev, "SMBus Timeout!\n");
+		result = -ETIMEDOUT;
+	}
+
+	if (temp & 0x02) {
+		dev_dbg(&adap->dev, "Error: Failed bus transaction\n");
+		result = -ENXIO;
+	}
+
+	if (temp & 0x04) {
+		dev_err(&adap->dev, "Bus collision!\n");
+		result = -EIO;
+		/*
+		  TBD: Datasheet say:
+		  the software should clear this bit and restart SMBUS operation.
+		  Should we do it or user start request again?
+		*/
+	}
+
+	return result;
+}
+
+static void sis630_transaction_end(struct i2c_adapter *adap, u8 oldclock)
+{
+	int temp = 0;
+
+	/* clear all status "sticky" bits */
+	sis630_write(SMB_STS, temp);
+
+	dev_dbg(&adap->dev, "SMB_CNT before clock restore 0x%02x\n", sis630_read(SMB_CNT));
+
+	/*
+	 * restore old Host Master Clock if high_clock is set
+	 * and oldclock was not 56KHz
+	 */
+	if (high_clock && !(oldclock & 0x20))
+		sis630_write(SMB_CNT,(sis630_read(SMB_CNT) & ~0x20));
+
+	dev_dbg(&adap->dev, "SMB_CNT after clock restore 0x%02x\n", sis630_read(SMB_CNT));
+}
+
+static int sis630_transaction(struct i2c_adapter *adap, int size)
+{
+	int result = 0;
+	u8 oldclock = 0;
+
+	result = sis630_transaction_start(adap, size, &oldclock);
+	if (!result) {
+		result = sis630_transaction_wait(adap, size);
+		sis630_transaction_end(adap, oldclock);
+	}
+
+	return result;
+}
+
+static int sis630_block_data(struct i2c_adapter *adap, union i2c_smbus_data *data, int read_write)
+{
+	int i, len = 0, rc = 0;
+	u8 oldclock = 0;
+
+	if (read_write == I2C_SMBUS_WRITE) {
+		len = data->block[0];
+		if (len < 0)
+			len = 0;
+		else if (len > 32)
+			len = 32;
+		sis630_write(SMB_COUNT, len);
+		for (i=1; i <= len; i++) {
+			dev_dbg(&adap->dev, "set data 0x%02x\n", data->block[i]);
+			/* set data */
+			sis630_write(SMB_BYTE+(i-1)%8, data->block[i]);
+			if (i==8 || (len<8 && i==len)) {
+				dev_dbg(&adap->dev, "start trans len=%d i=%d\n",len ,i);
+				/* first transaction */
+				rc = sis630_transaction_start(adap,
+						SIS630_BLOCK_DATA, &oldclock);
+				if (rc)
+					return rc;
+			}
+			else if ((i-1)%8 == 7 || i==len) {
+				dev_dbg(&adap->dev, "trans_wait len=%d i=%d\n",len,i);
+				if (i>8) {
+					dev_dbg(&adap->dev, "clear smbary_sts len=%d i=%d\n",len,i);
+					/*
+					   If this is not first transaction,
+					   we must clear sticky bit.
+					   clear SMBARY_STS
+					*/
+					sis630_write(SMB_STS,0x10);
+				}
+				rc = sis630_transaction_wait(adap,
+						SIS630_BLOCK_DATA);
+				if (rc) {
+					dev_dbg(&adap->dev, "trans_wait failed\n");
+					break;
+				}
+			}
+		}
+	}
+	else {
+		/* read request */
+		data->block[0] = len = 0;
+		rc = sis630_transaction_start(adap,
+				SIS630_BLOCK_DATA, &oldclock);
+		if (rc)
+			return rc;
+		do {
+			rc = sis630_transaction_wait(adap, SIS630_BLOCK_DATA);
+			if (rc) {
+				dev_dbg(&adap->dev, "trans_wait failed\n");
+				break;
+			}
+			/* if this first transaction then read byte count */
+			if (len == 0)
+				data->block[0] = sis630_read(SMB_COUNT);
+
+			/* just to be sure */
+			if (data->block[0] > 32)
+				data->block[0] = 32;
+
+			dev_dbg(&adap->dev, "block data read len=0x%x\n", data->block[0]);
+
+			for (i=0; i < 8 && len < data->block[0]; i++,len++) {
+				dev_dbg(&adap->dev, "read i=%d len=%d\n", i, len);
+				data->block[len+1] = sis630_read(SMB_BYTE+i);
+			}
+
+			dev_dbg(&adap->dev, "clear smbary_sts len=%d i=%d\n",len,i);
+
+			/* clear SMBARY_STS */
+			sis630_write(SMB_STS,0x10);
+		} while(len < data->block[0]);
+	}
+
+	sis630_transaction_end(adap, oldclock);
+
+	return rc;
+}
+
+/* Return negative errno on error. */
+static s32 sis630_access(struct i2c_adapter *adap, u16 addr,
+			 unsigned short flags, char read_write,
+			 u8 command, int size, union i2c_smbus_data *data)
+{
+	int status;
+
+	switch (size) {
+		case I2C_SMBUS_QUICK:
+			sis630_write(SMB_ADDR, ((addr & 0x7f) << 1) | (read_write & 0x01));
+			size = SIS630_QUICK;
+			break;
+		case I2C_SMBUS_BYTE:
+			sis630_write(SMB_ADDR, ((addr & 0x7f) << 1) | (read_write & 0x01));
+			if (read_write == I2C_SMBUS_WRITE)
+				sis630_write(SMB_CMD, command);
+			size = SIS630_BYTE;
+			break;
+		case I2C_SMBUS_BYTE_DATA:
+			sis630_write(SMB_ADDR, ((addr & 0x7f) << 1) | (read_write & 0x01));
+			sis630_write(SMB_CMD, command);
+			if (read_write == I2C_SMBUS_WRITE)
+				sis630_write(SMB_BYTE, data->byte);
+			size = SIS630_BYTE_DATA;
+			break;
+		case I2C_SMBUS_PROC_CALL:
+		case I2C_SMBUS_WORD_DATA:
+			sis630_write(SMB_ADDR,((addr & 0x7f) << 1) | (read_write & 0x01));
+			sis630_write(SMB_CMD, command);
+			if (read_write == I2C_SMBUS_WRITE) {
+				sis630_write(SMB_BYTE, data->word & 0xff);
+				sis630_write(SMB_BYTE + 1,(data->word & 0xff00) >> 8);
+			}
+			size = (size == I2C_SMBUS_PROC_CALL ? SIS630_PCALL : SIS630_WORD_DATA);
+			break;
+		case I2C_SMBUS_BLOCK_DATA:
+			sis630_write(SMB_ADDR,((addr & 0x7f) << 1) | (read_write & 0x01));
+			sis630_write(SMB_CMD, command);
+			size = SIS630_BLOCK_DATA;
+			return sis630_block_data(adap, data, read_write);
+		default:
+			dev_warn(&adap->dev, "Unsupported transaction %d\n",
+				 size);
+			return -EOPNOTSUPP;
+	}
+
+	status = sis630_transaction(adap, size);
+	if (status)
+		return status;
+
+	if ((size != SIS630_PCALL) &&
+		((read_write == I2C_SMBUS_WRITE) || (size == SIS630_QUICK))) {
+		return 0;
+	}
+
+	switch(size) {
+		case SIS630_BYTE:
+		case SIS630_BYTE_DATA:
+			data->byte = sis630_read(SMB_BYTE);
+			break;
+		case SIS630_PCALL:
+		case SIS630_WORD_DATA:
+			data->word = sis630_read(SMB_BYTE) + (sis630_read(SMB_BYTE + 1) << 8);
+			break;
+	}
+
+	return 0;
+}
+
+static u32 sis630_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA |
+		I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_PROC_CALL |
+		I2C_FUNC_SMBUS_BLOCK_DATA;
+}
+
+static int __devinit sis630_setup(struct pci_dev *sis630_dev)
+{
+	unsigned char b;
+	struct pci_dev *dummy = NULL;
+	int retval, i;
+
+	/* check for supported SiS devices */
+	for (i=0; supported[i] > 0 ; i++) {
+		if ((dummy = pci_get_device(PCI_VENDOR_ID_SI, supported[i], dummy)))
+			break; /* found */
+	}
+
+	if (dummy) {
+		pci_dev_put(dummy);
+	}
+        else if (force) {
+		dev_err(&sis630_dev->dev, "WARNING: Can't detect SIS630 compatible device, but "
+			"loading because of force option enabled\n");
+ 	}
+	else {
+		return -ENODEV;
+	}
+
+	/*
+	   Enable ACPI first , so we can accsess reg 74-75
+	   in acpi io space and read acpi base addr
+	*/
+	if (pci_read_config_byte(sis630_dev, SIS630_BIOS_CTL_REG,&b)) {
+		dev_err(&sis630_dev->dev, "Error: Can't read bios ctl reg\n");
+		retval = -ENODEV;
+		goto exit;
+	}
+	/* if ACPI already enabled , do nothing */
+	if (!(b & 0x80) &&
+	    pci_write_config_byte(sis630_dev, SIS630_BIOS_CTL_REG, b | 0x80)) {
+		dev_err(&sis630_dev->dev, "Error: Can't enable ACPI\n");
+		retval = -ENODEV;
+		goto exit;
+	}
+
+	/* Determine the ACPI base address */
+	if (pci_read_config_word(sis630_dev,SIS630_ACPI_BASE_REG,&acpi_base)) {
+		dev_err(&sis630_dev->dev, "Error: Can't determine ACPI base address\n");
+		retval = -ENODEV;
+		goto exit;
+	}
+
+	dev_dbg(&sis630_dev->dev, "ACPI base at 0x%04x\n", acpi_base);
+
+	retval = acpi_check_region(acpi_base + SMB_STS, SIS630_SMB_IOREGION,
+				   sis630_driver.name);
+	if (retval)
+		goto exit;
+
+	/* Everything is happy, let's grab the memory and set things up. */
+	if (!request_region(acpi_base + SMB_STS, SIS630_SMB_IOREGION,
+			    sis630_driver.name)) {
+		dev_err(&sis630_dev->dev, "SMBus registers 0x%04x-0x%04x already "
+			"in use!\n", acpi_base + SMB_STS, acpi_base + SMB_SAA);
+		retval = -EBUSY;
+		goto exit;
+	}
+
+	retval = 0;
+
+exit:
+	if (retval)
+		acpi_base = 0;
+	return retval;
+}
+
+
+static const struct i2c_algorithm smbus_algorithm = {
+	.smbus_xfer	= sis630_access,
+	.functionality	= sis630_func,
+};
+
+static struct i2c_adapter sis630_adapter = {
+	.owner		= THIS_MODULE,
+	.class		= I2C_CLASS_HWMON | I2C_CLASS_SPD,
+	.algo		= &smbus_algorithm,
+};
+
+static DEFINE_PCI_DEVICE_TABLE(sis630_ids) = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_LPC) },
+	{ 0, }
+};
+
+MODULE_DEVICE_TABLE (pci, sis630_ids);
+
+static int __devinit sis630_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	if (sis630_setup(dev)) {
+		dev_err(&dev->dev, "SIS630 comp. bus not detected, module not inserted.\n");
+		return -ENODEV;
+	}
+
+	/* set up the sysfs linkage to our parent device */
+	sis630_adapter.dev.parent = &dev->dev;
+
+	snprintf(sis630_adapter.name, sizeof(sis630_adapter.name),
+		 "SMBus SIS630 adapter at %04x", acpi_base + SMB_STS);
+
+	return i2c_add_adapter(&sis630_adapter);
+}
+
+static void __devexit sis630_remove(struct pci_dev *dev)
+{
+	if (acpi_base) {
+		i2c_del_adapter(&sis630_adapter);
+		release_region(acpi_base + SMB_STS, SIS630_SMB_IOREGION);
+		acpi_base = 0;
+	}
+}
+
+
+static struct pci_driver sis630_driver = {
+	.name		= "sis630_smbus",
+	.id_table	= sis630_ids,
+	.probe		= sis630_probe,
+	.remove		= __devexit_p(sis630_remove),
+};
+
+static int __init i2c_sis630_init(void)
+{
+	return pci_register_driver(&sis630_driver);
+}
+
+
+static void __exit i2c_sis630_exit(void)
+{
+	pci_unregister_driver(&sis630_driver);
+}
+
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Alexander Malysh <amalysh@web.de>");
+MODULE_DESCRIPTION("SIS630 SMBus driver");
+
+module_init(i2c_sis630_init);
+module_exit(i2c_sis630_exit);
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-sis96x.c b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-sis96x.c
new file mode 100644
index 0000000..cc5d149
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-sis96x.c
@@ -0,0 +1,344 @@
+/*
+    Copyright (c) 2003 Mark M. Hoffman <mhoffman@lightlink.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/*
+    This module must be considered BETA unless and until
+    the chipset manufacturer releases a datasheet.
+    The register definitions are based on the SiS630.
+
+    This module relies on quirk_sis_96x_smbus (drivers/pci/quirks.c)
+    for just about every machine for which users have reported.
+    If this module isn't detecting your 96x south bridge, have a 
+    look there.
+
+    We assume there can only be one SiS96x with one SMBus interface.
+*/
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/stddef.h>
+#include <linux/ioport.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/acpi.h>
+#include <linux/io.h>
+
+/* base address register in PCI config space */
+#define SIS96x_BAR 0x04
+
+/* SiS96x SMBus registers */
+#define SMB_STS      0x00
+#define SMB_EN       0x01
+#define SMB_CNT      0x02
+#define SMB_HOST_CNT 0x03
+#define SMB_ADDR     0x04
+#define SMB_CMD      0x05
+#define SMB_PCOUNT   0x06
+#define SMB_COUNT    0x07
+#define SMB_BYTE     0x08
+#define SMB_DEV_ADDR 0x10
+#define SMB_DB0      0x11
+#define SMB_DB1      0x12
+#define SMB_SAA      0x13
+
+/* register count for request_region */
+#define SMB_IOSIZE 0x20
+
+/* Other settings */
+#define MAX_TIMEOUT 500
+
+/* SiS96x SMBus constants */
+#define SIS96x_QUICK      0x00
+#define SIS96x_BYTE       0x01
+#define SIS96x_BYTE_DATA  0x02
+#define SIS96x_WORD_DATA  0x03
+#define SIS96x_PROC_CALL  0x04
+#define SIS96x_BLOCK_DATA 0x05
+
+static struct pci_driver sis96x_driver;
+static struct i2c_adapter sis96x_adapter;
+static u16 sis96x_smbus_base;
+
+static inline u8 sis96x_read(u8 reg)
+{
+	return inb(sis96x_smbus_base + reg) ;
+}
+
+static inline void sis96x_write(u8 reg, u8 data)
+{
+	outb(data, sis96x_smbus_base + reg) ;
+}
+
+/* Execute a SMBus transaction.
+   int size is from SIS96x_QUICK to SIS96x_BLOCK_DATA
+ */
+static int sis96x_transaction(int size)
+{
+	int temp;
+	int result = 0;
+	int timeout = 0;
+
+	dev_dbg(&sis96x_adapter.dev, "SMBus transaction %d\n", size);
+
+	/* Make sure the SMBus host is ready to start transmitting */
+	if (((temp = sis96x_read(SMB_CNT)) & 0x03) != 0x00) {
+
+		dev_dbg(&sis96x_adapter.dev, "SMBus busy (0x%02x). "
+			"Resetting...\n", temp);
+
+		/* kill the transaction */
+		sis96x_write(SMB_HOST_CNT, 0x20);
+
+		/* check it again */
+		if (((temp = sis96x_read(SMB_CNT)) & 0x03) != 0x00) {
+			dev_dbg(&sis96x_adapter.dev, "Failed (0x%02x)\n", temp);
+			return -EBUSY;
+		} else {
+			dev_dbg(&sis96x_adapter.dev, "Successful\n");
+		}
+	}
+
+	/* Turn off timeout interrupts, set fast host clock */
+	sis96x_write(SMB_CNT, 0x20);
+
+	/* clear all (sticky) status flags */
+	temp = sis96x_read(SMB_STS);
+	sis96x_write(SMB_STS, temp & 0x1e);
+
+	/* start the transaction by setting bit 4 and size bits */
+	sis96x_write(SMB_HOST_CNT, 0x10 | (size & 0x07));
+
+	/* We will always wait for a fraction of a second! */
+	do {
+		msleep(1);
+		temp = sis96x_read(SMB_STS);
+	} while (!(temp & 0x0e) && (timeout++ < MAX_TIMEOUT));
+
+	/* If the SMBus is still busy, we give up */
+	if (timeout > MAX_TIMEOUT) {
+		dev_dbg(&sis96x_adapter.dev, "SMBus Timeout! (0x%02x)\n", temp);
+		result = -ETIMEDOUT;
+	}
+
+	/* device error - probably missing ACK */
+	if (temp & 0x02) {
+		dev_dbg(&sis96x_adapter.dev, "Failed bus transaction!\n");
+		result = -ENXIO;
+	}
+
+	/* bus collision */
+	if (temp & 0x04) {
+		dev_dbg(&sis96x_adapter.dev, "Bus collision!\n");
+		result = -EIO;
+	}
+
+	/* Finish up by resetting the bus */
+	sis96x_write(SMB_STS, temp);
+	if ((temp = sis96x_read(SMB_STS))) {
+		dev_dbg(&sis96x_adapter.dev, "Failed reset at "
+			"end of transaction! (0x%02x)\n", temp);
+	}
+
+	return result;
+}
+
+/* Return negative errno on error. */
+static s32 sis96x_access(struct i2c_adapter * adap, u16 addr,
+			 unsigned short flags, char read_write,
+			 u8 command, int size, union i2c_smbus_data * data)
+{
+	int status;
+
+	switch (size) {
+	case I2C_SMBUS_QUICK:
+		sis96x_write(SMB_ADDR, ((addr & 0x7f) << 1) | (read_write & 0x01));
+		size = SIS96x_QUICK;
+		break;
+
+	case I2C_SMBUS_BYTE:
+		sis96x_write(SMB_ADDR, ((addr & 0x7f) << 1) | (read_write & 0x01));
+		if (read_write == I2C_SMBUS_WRITE)
+			sis96x_write(SMB_CMD, command);
+		size = SIS96x_BYTE;
+		break;
+
+	case I2C_SMBUS_BYTE_DATA:
+		sis96x_write(SMB_ADDR, ((addr & 0x7f) << 1) | (read_write & 0x01));
+		sis96x_write(SMB_CMD, command);
+		if (read_write == I2C_SMBUS_WRITE)
+			sis96x_write(SMB_BYTE, data->byte);
+		size = SIS96x_BYTE_DATA;
+		break;
+
+	case I2C_SMBUS_PROC_CALL:
+	case I2C_SMBUS_WORD_DATA:
+		sis96x_write(SMB_ADDR, ((addr & 0x7f) << 1) | (read_write & 0x01));
+		sis96x_write(SMB_CMD, command);
+		if (read_write == I2C_SMBUS_WRITE) {
+			sis96x_write(SMB_BYTE, data->word & 0xff);
+			sis96x_write(SMB_BYTE + 1, (data->word & 0xff00) >> 8);
+		}
+		size = (size == I2C_SMBUS_PROC_CALL ? 
+			SIS96x_PROC_CALL : SIS96x_WORD_DATA);
+		break;
+
+	default:
+		dev_warn(&adap->dev, "Unsupported transaction %d\n", size);
+		return -EOPNOTSUPP;
+	}
+
+	status = sis96x_transaction(size);
+	if (status)
+		return status;
+
+	if ((size != SIS96x_PROC_CALL) &&
+		((read_write == I2C_SMBUS_WRITE) || (size == SIS96x_QUICK)))
+		return 0;
+
+	switch (size) {
+	case SIS96x_BYTE:
+	case SIS96x_BYTE_DATA:
+		data->byte = sis96x_read(SMB_BYTE);
+		break;
+
+	case SIS96x_WORD_DATA:
+	case SIS96x_PROC_CALL:
+		data->word = sis96x_read(SMB_BYTE) +
+				(sis96x_read(SMB_BYTE + 1) << 8);
+		break;
+	}
+	return 0;
+}
+
+static u32 sis96x_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+	    I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+	    I2C_FUNC_SMBUS_PROC_CALL;
+}
+
+static const struct i2c_algorithm smbus_algorithm = {
+	.smbus_xfer	= sis96x_access,
+	.functionality	= sis96x_func,
+};
+
+static struct i2c_adapter sis96x_adapter = {
+	.owner		= THIS_MODULE,
+	.class		= I2C_CLASS_HWMON | I2C_CLASS_SPD,
+	.algo		= &smbus_algorithm,
+};
+
+static DEFINE_PCI_DEVICE_TABLE(sis96x_ids) = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_SMBUS) },
+	{ 0, }
+};
+
+MODULE_DEVICE_TABLE (pci, sis96x_ids);
+
+static int __devinit sis96x_probe(struct pci_dev *dev,
+				const struct pci_device_id *id)
+{
+	u16 ww = 0;
+	int retval;
+
+	if (sis96x_smbus_base) {
+		dev_err(&dev->dev, "Only one device supported.\n");
+		return -EBUSY;
+	}
+
+	pci_read_config_word(dev, PCI_CLASS_DEVICE, &ww);
+	if (PCI_CLASS_SERIAL_SMBUS != ww) {
+		dev_err(&dev->dev, "Unsupported device class 0x%04x!\n", ww);
+		return -ENODEV;
+	}
+
+	sis96x_smbus_base = pci_resource_start(dev, SIS96x_BAR);
+	if (!sis96x_smbus_base) {
+		dev_err(&dev->dev, "SiS96x SMBus base address "
+			"not initialized!\n");
+		return -EINVAL;
+	}
+	dev_info(&dev->dev, "SiS96x SMBus base address: 0x%04x\n",
+			sis96x_smbus_base);
+
+	retval = acpi_check_resource_conflict(&dev->resource[SIS96x_BAR]);
+	if (retval)
+		return -ENODEV;
+
+	/* Everything is happy, let's grab the memory and set things up. */
+	if (!request_region(sis96x_smbus_base, SMB_IOSIZE,
+			    sis96x_driver.name)) {
+		dev_err(&dev->dev, "SMBus registers 0x%04x-0x%04x "
+			"already in use!\n", sis96x_smbus_base,
+			sis96x_smbus_base + SMB_IOSIZE - 1);
+
+		sis96x_smbus_base = 0;
+		return -EINVAL;
+	}
+
+	/* set up the sysfs linkage to our parent device */
+	sis96x_adapter.dev.parent = &dev->dev;
+
+	snprintf(sis96x_adapter.name, sizeof(sis96x_adapter.name),
+		"SiS96x SMBus adapter at 0x%04x", sis96x_smbus_base);
+
+	if ((retval = i2c_add_adapter(&sis96x_adapter))) {
+		dev_err(&dev->dev, "Couldn't register adapter!\n");
+		release_region(sis96x_smbus_base, SMB_IOSIZE);
+		sis96x_smbus_base = 0;
+	}
+
+	return retval;
+}
+
+static void __devexit sis96x_remove(struct pci_dev *dev)
+{
+	if (sis96x_smbus_base) {
+		i2c_del_adapter(&sis96x_adapter);
+		release_region(sis96x_smbus_base, SMB_IOSIZE);
+		sis96x_smbus_base = 0;
+	}
+}
+
+static struct pci_driver sis96x_driver = {
+	.name		= "sis96x_smbus",
+	.id_table	= sis96x_ids,
+	.probe		= sis96x_probe,
+	.remove		= __devexit_p(sis96x_remove),
+};
+
+static int __init i2c_sis96x_init(void)
+{
+	return pci_register_driver(&sis96x_driver);
+}
+
+static void __exit i2c_sis96x_exit(void)
+{
+	pci_unregister_driver(&sis96x_driver);
+}
+
+MODULE_AUTHOR("Mark M. Hoffman <mhoffman@lightlink.com>");
+MODULE_DESCRIPTION("SiS96x SMBus driver");
+MODULE_LICENSE("GPL");
+
+/* Register initialization functions using helper macros */
+module_init(i2c_sis96x_init);
+module_exit(i2c_sis96x_exit);
+
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-stu300.c b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-stu300.c
new file mode 100644
index 0000000..4d44af1
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-stu300.c
@@ -0,0 +1,1057 @@
+/*
+ * Copyright (C) 2007-2009 ST-Ericsson AB
+ * License terms: GNU General Public License (GPL) version 2
+ * ST DDC I2C master mode driver, used in e.g. U300 series platforms.
+ * Author: Linus Walleij <linus.walleij@stericsson.com>
+ * Author: Jonas Aaberg <jonas.aberg@stericsson.com>
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+
+/* the name of this kernel module */
+#define NAME "stu300"
+
+/* CR (Control Register) 8bit (R/W) */
+#define I2C_CR					(0x00000000)
+#define I2C_CR_RESET_VALUE			(0x00)
+#define I2C_CR_RESET_UMASK			(0x00)
+#define I2C_CR_DDC1_ENABLE			(0x80)
+#define I2C_CR_TRANS_ENABLE			(0x40)
+#define I2C_CR_PERIPHERAL_ENABLE		(0x20)
+#define I2C_CR_DDC2B_ENABLE			(0x10)
+#define I2C_CR_START_ENABLE			(0x08)
+#define I2C_CR_ACK_ENABLE			(0x04)
+#define I2C_CR_STOP_ENABLE			(0x02)
+#define I2C_CR_INTERRUPT_ENABLE			(0x01)
+/* SR1 (Status Register 1) 8bit (R/-) */
+#define I2C_SR1					(0x00000004)
+#define I2C_SR1_RESET_VALUE			(0x00)
+#define I2C_SR1_RESET_UMASK			(0x00)
+#define I2C_SR1_EVF_IND				(0x80)
+#define I2C_SR1_ADD10_IND			(0x40)
+#define I2C_SR1_TRA_IND				(0x20)
+#define I2C_SR1_BUSY_IND			(0x10)
+#define I2C_SR1_BTF_IND				(0x08)
+#define I2C_SR1_ADSL_IND			(0x04)
+#define I2C_SR1_MSL_IND				(0x02)
+#define I2C_SR1_SB_IND				(0x01)
+/* SR2 (Status Register 2) 8bit (R/-) */
+#define I2C_SR2					(0x00000008)
+#define I2C_SR2_RESET_VALUE			(0x00)
+#define I2C_SR2_RESET_UMASK			(0x40)
+#define I2C_SR2_MASK				(0xBF)
+#define I2C_SR2_SCLFAL_IND			(0x80)
+#define I2C_SR2_ENDAD_IND			(0x20)
+#define I2C_SR2_AF_IND				(0x10)
+#define I2C_SR2_STOPF_IND			(0x08)
+#define I2C_SR2_ARLO_IND			(0x04)
+#define I2C_SR2_BERR_IND			(0x02)
+#define I2C_SR2_DDC2BF_IND			(0x01)
+/* CCR (Clock Control Register) 8bit (R/W) */
+#define I2C_CCR					(0x0000000C)
+#define I2C_CCR_RESET_VALUE			(0x00)
+#define I2C_CCR_RESET_UMASK			(0x00)
+#define I2C_CCR_MASK				(0xFF)
+#define I2C_CCR_FMSM				(0x80)
+#define I2C_CCR_CC_MASK				(0x7F)
+/* OAR1 (Own Address Register 1) 8bit (R/W) */
+#define I2C_OAR1				(0x00000010)
+#define I2C_OAR1_RESET_VALUE			(0x00)
+#define I2C_OAR1_RESET_UMASK			(0x00)
+#define I2C_OAR1_ADD_MASK			(0xFF)
+/* OAR2 (Own Address Register 2) 8bit (R/W) */
+#define I2C_OAR2				(0x00000014)
+#define I2C_OAR2_RESET_VALUE			(0x40)
+#define I2C_OAR2_RESET_UMASK			(0x19)
+#define I2C_OAR2_MASK				(0xE6)
+#define I2C_OAR2_FR_25_10MHZ			(0x00)
+#define I2C_OAR2_FR_10_1667MHZ			(0x20)
+#define I2C_OAR2_FR_1667_2667MHZ		(0x40)
+#define I2C_OAR2_FR_2667_40MHZ			(0x60)
+#define I2C_OAR2_FR_40_5333MHZ			(0x80)
+#define I2C_OAR2_FR_5333_66MHZ			(0xA0)
+#define I2C_OAR2_FR_66_80MHZ			(0xC0)
+#define I2C_OAR2_FR_80_100MHZ			(0xE0)
+#define I2C_OAR2_FR_MASK			(0xE0)
+#define I2C_OAR2_ADD_MASK			(0x06)
+/* DR (Data Register) 8bit (R/W) */
+#define I2C_DR					(0x00000018)
+#define I2C_DR_RESET_VALUE			(0x00)
+#define I2C_DR_RESET_UMASK			(0xFF)
+#define I2C_DR_D_MASK				(0xFF)
+/* ECCR (Extended Clock Control Register) 8bit (R/W) */
+#define I2C_ECCR				(0x0000001C)
+#define I2C_ECCR_RESET_VALUE			(0x00)
+#define I2C_ECCR_RESET_UMASK			(0xE0)
+#define I2C_ECCR_MASK				(0x1F)
+#define I2C_ECCR_CC_MASK			(0x1F)
+
+/*
+ * These events are more or less responses to commands
+ * sent into the hardware, presumably reflecting the state
+ * of an internal state machine.
+ */
+enum stu300_event {
+	STU300_EVENT_NONE = 0,
+	STU300_EVENT_1,
+	STU300_EVENT_2,
+	STU300_EVENT_3,
+	STU300_EVENT_4,
+	STU300_EVENT_5,
+	STU300_EVENT_6,
+	STU300_EVENT_7,
+	STU300_EVENT_8,
+	STU300_EVENT_9
+};
+
+enum stu300_error {
+	STU300_ERROR_NONE = 0,
+	STU300_ERROR_ACKNOWLEDGE_FAILURE,
+	STU300_ERROR_BUS_ERROR,
+	STU300_ERROR_ARBITRATION_LOST,
+	STU300_ERROR_UNKNOWN
+};
+
+/* timeout waiting for the controller to respond */
+#define STU300_TIMEOUT (msecs_to_jiffies(1000))
+
+/*
+ * The number of address send athemps tried before giving up.
+ * If the first one failes it seems like 5 to 8 attempts are required.
+ */
+#define NUM_ADDR_RESEND_ATTEMPTS 12
+
+/* I2C clock speed, in Hz 0-400kHz*/
+static unsigned int scl_frequency = 100000;
+module_param(scl_frequency, uint,  0644);
+
+/**
+ * struct stu300_dev - the stu300 driver state holder
+ * @pdev: parent platform device
+ * @adapter: corresponding I2C adapter
+ * @phybase: location of I/O area in memory
+ * @physize: size of I/O area in memory
+ * @clk: hardware block clock
+ * @irq: assigned interrupt line
+ * @cmd_issue_lock: this locks the following cmd_ variables
+ * @cmd_complete: acknowledge completion for an I2C command
+ * @cmd_event: expected event coming in as a response to a command
+ * @cmd_err: error code as response to a command
+ * @speed: current bus speed in Hz
+ * @msg_index: index of current message
+ * @msg_len: length of current message
+ */
+
+struct stu300_dev {
+	struct platform_device	*pdev;
+	struct i2c_adapter	adapter;
+	resource_size_t		phybase;
+	resource_size_t		physize;
+	void __iomem		*virtbase;
+	struct clk		*clk;
+	int			irq;
+	spinlock_t		cmd_issue_lock;
+	struct completion	cmd_complete;
+	enum stu300_event	cmd_event;
+	enum stu300_error	cmd_err;
+	unsigned int		speed;
+	int			msg_index;
+	int			msg_len;
+};
+
+/* Local forward function declarations */
+static int stu300_init_hw(struct stu300_dev *dev);
+
+/*
+ * The block needs writes in both MSW and LSW in order
+ * for all data lines to reach their destination.
+ */
+static inline void stu300_wr8(u32 value, void __iomem *address)
+{
+	writel((value << 16) | value, address);
+}
+
+/*
+ * This merely masks off the duplicates which appear
+ * in bytes 1-3. You _MUST_ use 32-bit bus access on this
+ * device, else it will not work.
+ */
+static inline u32 stu300_r8(void __iomem *address)
+{
+	return readl(address) & 0x000000FFU;
+}
+
+static void stu300_irq_enable(struct stu300_dev *dev)
+{
+	u32 val;
+	val = stu300_r8(dev->virtbase + I2C_CR);
+	val |= I2C_CR_INTERRUPT_ENABLE;
+	/* Twice paranoia (possible HW glitch) */
+	stu300_wr8(val, dev->virtbase + I2C_CR);
+	stu300_wr8(val, dev->virtbase + I2C_CR);
+}
+
+static void stu300_irq_disable(struct stu300_dev *dev)
+{
+	u32 val;
+	val = stu300_r8(dev->virtbase + I2C_CR);
+	val &= ~I2C_CR_INTERRUPT_ENABLE;
+	/* Twice paranoia (possible HW glitch) */
+	stu300_wr8(val, dev->virtbase + I2C_CR);
+	stu300_wr8(val, dev->virtbase + I2C_CR);
+}
+
+
+/*
+ * Tells whether a certain event or events occurred in
+ * response to a command. The events represent states in
+ * the internal state machine of the hardware. The events
+ * are not very well described in the hardware
+ * documentation and can only be treated as abstract state
+ * machine states.
+ *
+ * @ret 0 = event has not occurred or unknown error, any
+ * other value means the correct event occurred or an error.
+ */
+
+static int stu300_event_occurred(struct stu300_dev *dev,
+				   enum stu300_event mr_event) {
+	u32 status1;
+	u32 status2;
+
+	/* What event happened? */
+	status1 = stu300_r8(dev->virtbase + I2C_SR1);
+
+	if (!(status1 & I2C_SR1_EVF_IND))
+		/* No event at all */
+		return 0;
+
+	status2 = stu300_r8(dev->virtbase + I2C_SR2);
+
+	/* Block any multiple interrupts */
+	stu300_irq_disable(dev);
+
+	/* Check for errors first */
+	if (status2 & I2C_SR2_AF_IND) {
+		dev->cmd_err = STU300_ERROR_ACKNOWLEDGE_FAILURE;
+		return 1;
+	} else if (status2 & I2C_SR2_BERR_IND) {
+		dev->cmd_err = STU300_ERROR_BUS_ERROR;
+		return 1;
+	} else if (status2 & I2C_SR2_ARLO_IND) {
+		dev->cmd_err = STU300_ERROR_ARBITRATION_LOST;
+		return 1;
+	}
+
+	switch (mr_event) {
+	case STU300_EVENT_1:
+		if (status1 & I2C_SR1_ADSL_IND)
+			return 1;
+		break;
+	case STU300_EVENT_2:
+	case STU300_EVENT_3:
+	case STU300_EVENT_7:
+	case STU300_EVENT_8:
+		if (status1 & I2C_SR1_BTF_IND) {
+			return 1;
+		}
+		break;
+	case STU300_EVENT_4:
+		if (status2 & I2C_SR2_STOPF_IND)
+			return 1;
+		break;
+	case STU300_EVENT_5:
+		if (status1 & I2C_SR1_SB_IND)
+			/* Clear start bit */
+			return 1;
+		break;
+	case STU300_EVENT_6:
+		if (status2 & I2C_SR2_ENDAD_IND) {
+			/* First check for any errors */
+			return 1;
+		}
+		break;
+	case STU300_EVENT_9:
+		if (status1 & I2C_SR1_ADD10_IND)
+			return 1;
+		break;
+	default:
+		break;
+	}
+	/* If we get here, we're on thin ice.
+	 * Here we are in a status where we have
+	 * gotten a response that does not match
+	 * what we requested.
+	 */
+	dev->cmd_err = STU300_ERROR_UNKNOWN;
+	dev_err(&dev->pdev->dev,
+		"Unhandled interrupt! %d sr1: 0x%x sr2: 0x%x\n",
+		mr_event, status1, status2);
+	return 0;
+}
+
+static irqreturn_t stu300_irh(int irq, void *data)
+{
+	struct stu300_dev *dev = data;
+	int res;
+
+	/* Just make sure that the block is clocked */
+	clk_enable(dev->clk);
+
+	/* See if this was what we were waiting for */
+	spin_lock(&dev->cmd_issue_lock);
+
+	res = stu300_event_occurred(dev, dev->cmd_event);
+	if (res || dev->cmd_err != STU300_ERROR_NONE)
+		complete(&dev->cmd_complete);
+
+	spin_unlock(&dev->cmd_issue_lock);
+
+	clk_disable(dev->clk);
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * Sends a command and then waits for the bits masked by *flagmask*
+ * to go high or low by IRQ awaiting.
+ */
+static int stu300_start_and_await_event(struct stu300_dev *dev,
+					  u8 cr_value,
+					  enum stu300_event mr_event)
+{
+	int ret;
+
+	if (unlikely(irqs_disabled())) {
+		/* TODO: implement polling for this case if need be. */
+		WARN(1, "irqs are disabled, cannot poll for event\n");
+		return -EIO;
+	}
+
+	/* Lock command issue, fill in an event we wait for */
+	spin_lock_irq(&dev->cmd_issue_lock);
+	init_completion(&dev->cmd_complete);
+	dev->cmd_err = STU300_ERROR_NONE;
+	dev->cmd_event = mr_event;
+	spin_unlock_irq(&dev->cmd_issue_lock);
+
+	/* Turn on interrupt, send command and wait. */
+	cr_value |= I2C_CR_INTERRUPT_ENABLE;
+	stu300_wr8(cr_value, dev->virtbase + I2C_CR);
+	ret = wait_for_completion_interruptible_timeout(&dev->cmd_complete,
+							STU300_TIMEOUT);
+	if (ret < 0) {
+		dev_err(&dev->pdev->dev,
+		       "wait_for_completion_interruptible_timeout() "
+		       "returned %d waiting for event %04x\n", ret, mr_event);
+		return ret;
+	}
+
+	if (ret == 0) {
+		dev_err(&dev->pdev->dev, "controller timed out "
+		       "waiting for event %d, reinit hardware\n", mr_event);
+		(void) stu300_init_hw(dev);
+		return -ETIMEDOUT;
+	}
+
+	if (dev->cmd_err != STU300_ERROR_NONE) {
+		dev_err(&dev->pdev->dev, "controller (start) "
+		       "error %d waiting for event %d, reinit hardware\n",
+		       dev->cmd_err, mr_event);
+		(void) stu300_init_hw(dev);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+/*
+ * This waits for a flag to be set, if it is not set on entry, an interrupt is
+ * configured to wait for the flag using a completion.
+ */
+static int stu300_await_event(struct stu300_dev *dev,
+				enum stu300_event mr_event)
+{
+	int ret;
+
+	if (unlikely(irqs_disabled())) {
+		/* TODO: implement polling for this case if need be. */
+		dev_err(&dev->pdev->dev, "irqs are disabled on this "
+			"system!\n");
+		return -EIO;
+	}
+
+	/* Is it already here? */
+	spin_lock_irq(&dev->cmd_issue_lock);
+	dev->cmd_err = STU300_ERROR_NONE;
+	dev->cmd_event = mr_event;
+
+	init_completion(&dev->cmd_complete);
+
+	/* Turn on the I2C interrupt for current operation */
+	stu300_irq_enable(dev);
+
+	/* Unlock the command block and wait for the event to occur */
+	spin_unlock_irq(&dev->cmd_issue_lock);
+
+	ret = wait_for_completion_interruptible_timeout(&dev->cmd_complete,
+							STU300_TIMEOUT);
+	if (ret < 0) {
+		dev_err(&dev->pdev->dev,
+		       "wait_for_completion_interruptible_timeout()"
+		       "returned %d waiting for event %04x\n", ret, mr_event);
+		return ret;
+	}
+
+	if (ret == 0) {
+		if (mr_event != STU300_EVENT_6) {
+			dev_err(&dev->pdev->dev, "controller "
+				"timed out waiting for event %d, reinit "
+				"hardware\n", mr_event);
+			(void) stu300_init_hw(dev);
+		}
+		return -ETIMEDOUT;
+	}
+
+	if (dev->cmd_err != STU300_ERROR_NONE) {
+		if (mr_event != STU300_EVENT_6) {
+			dev_err(&dev->pdev->dev, "controller "
+				"error (await_event) %d waiting for event %d, "
+			       "reinit hardware\n", dev->cmd_err, mr_event);
+			(void) stu300_init_hw(dev);
+		}
+		return -EIO;
+	}
+
+	return 0;
+}
+
+/*
+ * Waits for the busy bit to go low by repeated polling.
+ */
+#define BUSY_RELEASE_ATTEMPTS 10
+static int stu300_wait_while_busy(struct stu300_dev *dev)
+{
+	unsigned long timeout;
+	int i;
+
+	for (i = 0; i < BUSY_RELEASE_ATTEMPTS; i++) {
+		timeout = jiffies + STU300_TIMEOUT;
+
+		while (!time_after(jiffies, timeout)) {
+			/* Is not busy? */
+			if ((stu300_r8(dev->virtbase + I2C_SR1) &
+			     I2C_SR1_BUSY_IND) == 0)
+				return 0;
+			msleep(1);
+		}
+
+		dev_err(&dev->pdev->dev, "transaction timed out "
+			"waiting for device to be free (not busy). "
+		       "Attempt: %d\n", i+1);
+
+		dev_err(&dev->pdev->dev, "base address = "
+			"0x%08x, reinit hardware\n", (u32) dev->virtbase);
+
+		(void) stu300_init_hw(dev);
+	}
+
+	dev_err(&dev->pdev->dev, "giving up after %d attempts "
+		"to reset the bus.\n",  BUSY_RELEASE_ATTEMPTS);
+
+	return -ETIMEDOUT;
+}
+
+struct stu300_clkset {
+	unsigned long rate;
+	u32 setting;
+};
+
+static const struct stu300_clkset stu300_clktable[] = {
+	{ 0,         0xFFU },
+	{ 2500000,   I2C_OAR2_FR_25_10MHZ },
+	{ 10000000,  I2C_OAR2_FR_10_1667MHZ },
+	{ 16670000,  I2C_OAR2_FR_1667_2667MHZ },
+	{ 26670000,  I2C_OAR2_FR_2667_40MHZ },
+	{ 40000000,  I2C_OAR2_FR_40_5333MHZ },
+	{ 53330000,  I2C_OAR2_FR_5333_66MHZ },
+	{ 66000000,  I2C_OAR2_FR_66_80MHZ },
+	{ 80000000,  I2C_OAR2_FR_80_100MHZ },
+	{ 100000000, 0xFFU },
+};
+
+
+static int stu300_set_clk(struct stu300_dev *dev, unsigned long clkrate)
+{
+
+	u32 val;
+	int i = 0;
+
+	/* Locate the appropriate clock setting */
+	while (i < ARRAY_SIZE(stu300_clktable) - 1 &&
+	       stu300_clktable[i].rate < clkrate)
+		i++;
+
+	if (stu300_clktable[i].setting == 0xFFU) {
+		dev_err(&dev->pdev->dev, "too %s clock rate requested "
+			"(%lu Hz).\n", i ? "high" : "low", clkrate);
+		return -EINVAL;
+	}
+
+	stu300_wr8(stu300_clktable[i].setting,
+		   dev->virtbase + I2C_OAR2);
+
+	dev_dbg(&dev->pdev->dev, "Clock rate %lu Hz, I2C bus speed %d Hz "
+		"virtbase %p\n", clkrate, dev->speed, dev->virtbase);
+
+	if (dev->speed > 100000)
+		/* Fast Mode I2C */
+		val = ((clkrate/dev->speed) - 9)/3 + 1;
+	else
+		/* Standard Mode I2C */
+		val = ((clkrate/dev->speed) - 7)/2 + 1;
+
+	/* According to spec the divider must be > 2 */
+	if (val < 0x002) {
+		dev_err(&dev->pdev->dev, "too low clock rate (%lu Hz).\n",
+			clkrate);
+		return -EINVAL;
+	}
+
+	/* We have 12 bits clock divider only! */
+	if (val & 0xFFFFF000U) {
+		dev_err(&dev->pdev->dev, "too high clock rate (%lu Hz).\n",
+			clkrate);
+		return -EINVAL;
+	}
+
+	if (dev->speed > 100000) {
+		/* CC6..CC0 */
+		stu300_wr8((val & I2C_CCR_CC_MASK) | I2C_CCR_FMSM,
+			   dev->virtbase + I2C_CCR);
+		dev_dbg(&dev->pdev->dev, "set clock divider to 0x%08x, "
+			"Fast Mode I2C\n", val);
+	} else {
+		/* CC6..CC0 */
+		stu300_wr8((val & I2C_CCR_CC_MASK),
+			   dev->virtbase + I2C_CCR);
+		dev_dbg(&dev->pdev->dev, "set clock divider to "
+			"0x%08x, Standard Mode I2C\n", val);
+	}
+
+	/* CC11..CC7 */
+	stu300_wr8(((val >> 7) & 0x1F),
+		   dev->virtbase + I2C_ECCR);
+
+	return 0;
+}
+
+
+static int stu300_init_hw(struct stu300_dev *dev)
+{
+	u32 dummy;
+	unsigned long clkrate;
+	int ret;
+
+	/* Disable controller */
+	stu300_wr8(0x00, dev->virtbase + I2C_CR);
+	/*
+	 * Set own address to some default value (0x00).
+	 * We do not support slave mode anyway.
+	 */
+	stu300_wr8(0x00, dev->virtbase + I2C_OAR1);
+	/*
+	 * The I2C controller only operates properly in 26 MHz but we
+	 * program this driver as if we didn't know. This will also set the two
+	 * high bits of the own address to zero as well.
+	 * There is no known hardware issue with running in 13 MHz
+	 * However, speeds over 200 kHz are not used.
+	 */
+	clkrate = clk_get_rate(dev->clk);
+	ret = stu300_set_clk(dev, clkrate);
+
+	if (ret)
+		return ret;
+	/*
+	 * Enable block, do it TWICE (hardware glitch)
+	 * Setting bit 7 can enable DDC mode. (Not used currently.)
+	 */
+	stu300_wr8(I2C_CR_PERIPHERAL_ENABLE,
+				  dev->virtbase + I2C_CR);
+	stu300_wr8(I2C_CR_PERIPHERAL_ENABLE,
+				  dev->virtbase + I2C_CR);
+	/* Make a dummy read of the status register SR1 & SR2 */
+	dummy = stu300_r8(dev->virtbase + I2C_SR2);
+	dummy = stu300_r8(dev->virtbase + I2C_SR1);
+
+	return 0;
+}
+
+
+
+/* Send slave address. */
+static int stu300_send_address(struct stu300_dev *dev,
+				 struct i2c_msg *msg, int resend)
+{
+	u32 val;
+	int ret;
+
+	if (msg->flags & I2C_M_TEN)
+		/* This is probably how 10 bit addresses look */
+		val = (0xf0 | (((u32) msg->addr & 0x300) >> 7)) &
+			I2C_DR_D_MASK;
+	else
+		val = ((msg->addr << 1) & I2C_DR_D_MASK);
+
+	if (msg->flags & I2C_M_RD) {
+		/* This is the direction bit */
+		val |= 0x01;
+		if (resend)
+			dev_dbg(&dev->pdev->dev, "read resend\n");
+	} else if (resend)
+		dev_dbg(&dev->pdev->dev, "write resend\n");
+	stu300_wr8(val, dev->virtbase + I2C_DR);
+
+	/* For 10bit addressing, await 10bit request (EVENT 9) */
+	if (msg->flags & I2C_M_TEN) {
+		ret = stu300_await_event(dev, STU300_EVENT_9);
+		/*
+		 * The slave device wants a 10bit address, send the rest
+		 * of the bits (the LSBits)
+		 */
+		val = msg->addr & I2C_DR_D_MASK;
+		/* This clears "event 9" */
+		stu300_wr8(val, dev->virtbase + I2C_DR);
+		if (ret != 0)
+			return ret;
+	}
+	/* FIXME: Why no else here? two events for 10bit?
+	 * Await event 6 (normal) or event 9 (10bit)
+	 */
+
+	if (resend)
+		dev_dbg(&dev->pdev->dev, "await event 6\n");
+	ret = stu300_await_event(dev, STU300_EVENT_6);
+
+	/*
+	 * Clear any pending EVENT 6 no matter what happened during
+	 * await_event.
+	 */
+	val = stu300_r8(dev->virtbase + I2C_CR);
+	val |= I2C_CR_PERIPHERAL_ENABLE;
+	stu300_wr8(val, dev->virtbase + I2C_CR);
+
+	return ret;
+}
+
+static int stu300_xfer_msg(struct i2c_adapter *adap,
+			     struct i2c_msg *msg, int stop)
+{
+	u32 cr;
+	u32 val;
+	u32 i;
+	int ret;
+	int attempts = 0;
+	struct stu300_dev *dev = i2c_get_adapdata(adap);
+
+	clk_enable(dev->clk);
+
+	/* Remove this if (0) to trace each and every message. */
+	if (0) {
+		dev_dbg(&dev->pdev->dev, "I2C message to: 0x%04x, len: %d, "
+			"flags: 0x%04x, stop: %d\n",
+			msg->addr, msg->len, msg->flags, stop);
+	}
+
+	/* Zero-length messages are not supported by this hardware */
+	if (msg->len == 0) {
+		ret = -EINVAL;
+		goto exit_disable;
+	}
+
+	/*
+	 * For some reason, sending the address sometimes fails when running
+	 * on  the 13 MHz clock. No interrupt arrives. This is a work around,
+	 * which tries to restart and send the address up to 10 times before
+	 * really giving up. Usually 5 to 8 attempts are enough.
+	 */
+	do {
+		if (attempts)
+			dev_dbg(&dev->pdev->dev, "wait while busy\n");
+		/* Check that the bus is free, or wait until some timeout */
+		ret = stu300_wait_while_busy(dev);
+		if (ret != 0)
+			goto exit_disable;
+
+		if (attempts)
+			dev_dbg(&dev->pdev->dev, "re-int hw\n");
+		/*
+		 * According to ST, there is no problem if the clock is
+		 * changed between 13 and 26 MHz during a transfer.
+		 */
+		ret = stu300_init_hw(dev);
+		if (ret)
+			goto exit_disable;
+
+		/* Send a start condition */
+		cr = I2C_CR_PERIPHERAL_ENABLE;
+		/* Setting the START bit puts the block in master mode */
+		if (!(msg->flags & I2C_M_NOSTART))
+			cr |= I2C_CR_START_ENABLE;
+		if ((msg->flags & I2C_M_RD) && (msg->len > 1))
+			/* On read more than 1 byte, we need ack. */
+			cr |= I2C_CR_ACK_ENABLE;
+		/* Check that it gets through */
+		if (!(msg->flags & I2C_M_NOSTART)) {
+			if (attempts)
+				dev_dbg(&dev->pdev->dev, "send start event\n");
+			ret = stu300_start_and_await_event(dev, cr,
+							     STU300_EVENT_5);
+		}
+
+		if (attempts)
+			dev_dbg(&dev->pdev->dev, "send address\n");
+
+		if (ret == 0)
+			/* Send address */
+			ret = stu300_send_address(dev, msg, attempts != 0);
+
+		if (ret != 0) {
+			attempts++;
+			dev_dbg(&dev->pdev->dev, "failed sending address, "
+				"retrying. Attempt: %d msg_index: %d/%d\n",
+			       attempts, dev->msg_index, dev->msg_len);
+		}
+
+	} while (ret != 0 && attempts < NUM_ADDR_RESEND_ATTEMPTS);
+
+	if (attempts < NUM_ADDR_RESEND_ATTEMPTS && attempts > 0) {
+		dev_dbg(&dev->pdev->dev, "managed to get address "
+			"through after %d attempts\n", attempts);
+	} else if (attempts == NUM_ADDR_RESEND_ATTEMPTS) {
+		dev_dbg(&dev->pdev->dev, "I give up, tried %d times "
+			"to resend address.\n",
+			NUM_ADDR_RESEND_ATTEMPTS);
+		goto exit_disable;
+	}
+
+
+	if (msg->flags & I2C_M_RD) {
+		/* READ: we read the actual bytes one at a time */
+		for (i = 0; i < msg->len; i++) {
+			if (i == msg->len-1) {
+				/*
+				 * Disable ACK and set STOP condition before
+				 * reading last byte
+				 */
+				val = I2C_CR_PERIPHERAL_ENABLE;
+
+				if (stop)
+					val |= I2C_CR_STOP_ENABLE;
+
+				stu300_wr8(val,
+					   dev->virtbase + I2C_CR);
+			}
+			/* Wait for this byte... */
+			ret = stu300_await_event(dev, STU300_EVENT_7);
+			if (ret != 0)
+				goto exit_disable;
+			/* This clears event 7 */
+			msg->buf[i] = (u8) stu300_r8(dev->virtbase + I2C_DR);
+		}
+	} else {
+		/* WRITE: we send the actual bytes one at a time */
+		for (i = 0; i < msg->len; i++) {
+			/* Write the byte */
+			stu300_wr8(msg->buf[i],
+				   dev->virtbase + I2C_DR);
+			/* Check status */
+			ret = stu300_await_event(dev, STU300_EVENT_8);
+			/* Next write to DR will clear event 8 */
+			if (ret != 0) {
+				dev_err(&dev->pdev->dev, "error awaiting "
+				       "event 8 (%d)\n", ret);
+				goto exit_disable;
+			}
+		}
+		/* Check NAK */
+		if (!(msg->flags & I2C_M_IGNORE_NAK)) {
+			if (stu300_r8(dev->virtbase + I2C_SR2) &
+			    I2C_SR2_AF_IND) {
+				dev_err(&dev->pdev->dev, "I2C payload "
+				       "send returned NAK!\n");
+				ret = -EIO;
+				goto exit_disable;
+			}
+		}
+		if (stop) {
+			/* Send stop condition */
+			val = I2C_CR_PERIPHERAL_ENABLE;
+			val |= I2C_CR_STOP_ENABLE;
+			stu300_wr8(val, dev->virtbase + I2C_CR);
+		}
+	}
+
+	/* Check that the bus is free, or wait until some timeout occurs */
+	ret = stu300_wait_while_busy(dev);
+	if (ret != 0) {
+		dev_err(&dev->pdev->dev, "timout waiting for transfer "
+		       "to commence.\n");
+		goto exit_disable;
+	}
+
+	/* Dummy read status registers */
+	val = stu300_r8(dev->virtbase + I2C_SR2);
+	val = stu300_r8(dev->virtbase + I2C_SR1);
+	ret = 0;
+
+ exit_disable:
+	/* Disable controller */
+	stu300_wr8(0x00, dev->virtbase + I2C_CR);
+	clk_disable(dev->clk);
+	return ret;
+}
+
+static int stu300_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
+			 int num)
+{
+	int ret = -1;
+	int i;
+
+	struct stu300_dev *dev = i2c_get_adapdata(adap);
+	dev->msg_len = num;
+
+	for (i = 0; i < num; i++) {
+		/*
+		 * Another driver appears to send stop for each message,
+		 * here we only do that for the last message. Possibly some
+		 * peripherals require this behaviour, then their drivers
+		 * have to send single messages in order to get "stop" for
+		 * each message.
+		 */
+		dev->msg_index = i;
+
+		ret = stu300_xfer_msg(adap, &msgs[i], (i == (num - 1)));
+
+		if (ret != 0) {
+			num = ret;
+			break;
+		}
+	}
+
+	return num;
+}
+
+static u32 stu300_func(struct i2c_adapter *adap)
+{
+	/* This is the simplest thing you can think of... */
+	return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR;
+}
+
+static const struct i2c_algorithm stu300_algo = {
+	.master_xfer	= stu300_xfer,
+	.functionality	= stu300_func,
+};
+
+static int __init
+stu300_probe(struct platform_device *pdev)
+{
+	struct stu300_dev *dev;
+	struct i2c_adapter *adap;
+	struct resource *res;
+	int bus_nr;
+	int ret = 0;
+	char clk_name[] = "I2C0";
+
+	dev = kzalloc(sizeof(struct stu300_dev), GFP_KERNEL);
+	if (!dev) {
+		dev_err(&pdev->dev, "could not allocate device struct\n");
+		ret = -ENOMEM;
+		goto err_no_devmem;
+	}
+
+	bus_nr = pdev->id;
+	clk_name[3] += (char)bus_nr;
+	dev->clk = clk_get(&pdev->dev, clk_name);
+	if (IS_ERR(dev->clk)) {
+		ret = PTR_ERR(dev->clk);
+		dev_err(&pdev->dev, "could not retrieve i2c bus clock\n");
+		goto err_no_clk;
+	}
+
+	dev->pdev = pdev;
+	platform_set_drvdata(pdev, dev);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		ret = -ENOENT;
+		goto err_no_resource;
+	}
+
+	dev->phybase = res->start;
+	dev->physize = resource_size(res);
+
+	if (request_mem_region(dev->phybase, dev->physize,
+			       NAME " I/O Area") == NULL) {
+		ret = -EBUSY;
+		goto err_no_ioregion;
+	}
+
+	dev->virtbase = ioremap(dev->phybase, dev->physize);
+	dev_dbg(&pdev->dev, "initialize bus device I2C%d on virtual "
+		"base %p\n", bus_nr, dev->virtbase);
+	if (!dev->virtbase) {
+		ret = -ENOMEM;
+		goto err_no_ioremap;
+	}
+
+	dev->irq = platform_get_irq(pdev, 0);
+	if (request_irq(dev->irq, stu300_irh, 0,
+			NAME, dev)) {
+		ret = -EIO;
+		goto err_no_irq;
+	}
+
+	dev->speed = scl_frequency;
+
+	clk_enable(dev->clk);
+	ret = stu300_init_hw(dev);
+	clk_disable(dev->clk);
+
+	if (ret != 0) {
+		dev_err(&dev->pdev->dev, "error initializing hardware.\n");
+		goto err_init_hw;
+	}
+
+	/* IRQ event handling initialization */
+	spin_lock_init(&dev->cmd_issue_lock);
+	dev->cmd_event = STU300_EVENT_NONE;
+	dev->cmd_err = STU300_ERROR_NONE;
+
+	adap = &dev->adapter;
+	adap->owner = THIS_MODULE;
+	/* DDC class but actually often used for more generic I2C */
+	adap->class = I2C_CLASS_DDC;
+	strlcpy(adap->name, "ST Microelectronics DDC I2C adapter",
+		sizeof(adap->name));
+	adap->nr = bus_nr;
+	adap->algo = &stu300_algo;
+	adap->dev.parent = &pdev->dev;
+	i2c_set_adapdata(adap, dev);
+
+	/* i2c device drivers may be active on return from add_adapter() */
+	ret = i2c_add_numbered_adapter(adap);
+	if (ret) {
+		dev_err(&dev->pdev->dev, "failure adding ST Micro DDC "
+		       "I2C adapter\n");
+		goto err_add_adapter;
+	}
+	return 0;
+
+ err_add_adapter:
+ err_init_hw:
+	free_irq(dev->irq, dev);
+ err_no_irq:
+	iounmap(dev->virtbase);
+ err_no_ioremap:
+	release_mem_region(dev->phybase, dev->physize);
+ err_no_ioregion:
+	platform_set_drvdata(pdev, NULL);
+ err_no_resource:
+	clk_put(dev->clk);
+ err_no_clk:
+	kfree(dev);
+ err_no_devmem:
+	dev_err(&pdev->dev, "failed to add " NAME " adapter: %d\n",
+		pdev->id);
+	return ret;
+}
+
+#ifdef CONFIG_PM
+static int stu300_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct stu300_dev *dev = platform_get_drvdata(pdev);
+
+	/* Turn off everything */
+	stu300_wr8(0x00, dev->virtbase + I2C_CR);
+	return 0;
+}
+
+static int stu300_resume(struct platform_device *pdev)
+{
+	int ret = 0;
+	struct stu300_dev *dev = platform_get_drvdata(pdev);
+
+	clk_enable(dev->clk);
+	ret = stu300_init_hw(dev);
+	clk_disable(dev->clk);
+
+	if (ret != 0)
+		dev_err(&pdev->dev, "error re-initializing hardware.\n");
+	return ret;
+}
+#else
+#define stu300_suspend NULL
+#define stu300_resume NULL
+#endif
+
+static int __exit
+stu300_remove(struct platform_device *pdev)
+{
+	struct stu300_dev *dev = platform_get_drvdata(pdev);
+
+	i2c_del_adapter(&dev->adapter);
+	/* Turn off everything */
+	stu300_wr8(0x00, dev->virtbase + I2C_CR);
+	free_irq(dev->irq, dev);
+	iounmap(dev->virtbase);
+	release_mem_region(dev->phybase, dev->physize);
+	clk_put(dev->clk);
+	platform_set_drvdata(pdev, NULL);
+	kfree(dev);
+	return 0;
+}
+
+static struct platform_driver stu300_i2c_driver = {
+	.driver = {
+		.name	= NAME,
+		.owner	= THIS_MODULE,
+	},
+	.remove		= __exit_p(stu300_remove),
+	.suspend        = stu300_suspend,
+	.resume         = stu300_resume,
+
+};
+
+static int __init stu300_init(void)
+{
+	return platform_driver_probe(&stu300_i2c_driver, stu300_probe);
+}
+
+static void __exit stu300_exit(void)
+{
+	platform_driver_unregister(&stu300_i2c_driver);
+}
+
+/*
+ * The systems using this bus often have very basic devices such
+ * as regulators on the I2C bus, so this needs to be loaded early.
+ * Therefore it is registered in the subsys_initcall().
+ */
+subsys_initcall(stu300_init);
+module_exit(stu300_exit);
+
+MODULE_AUTHOR("Linus Walleij <linus.walleij@stericsson.com>");
+MODULE_DESCRIPTION("ST Micro DDC I2C adapter (" NAME ")");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" NAME);
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-stub.c b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-stub.c
new file mode 100644
index 0000000..b1b3447
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-stub.c
@@ -0,0 +1,222 @@
+/*
+    i2c-stub.c - I2C/SMBus chip emulator
+
+    Copyright (c) 2004 Mark M. Hoffman <mhoffman@lightlink.com>
+    Copyright (C) 2007 Jean Delvare <khali@linux-fr.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#define DEBUG 1
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/i2c.h>
+
+#define MAX_CHIPS 10
+#define STUB_FUNC (I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | \
+		   I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | \
+		   I2C_FUNC_SMBUS_I2C_BLOCK)
+
+static unsigned short chip_addr[MAX_CHIPS];
+module_param_array(chip_addr, ushort, NULL, S_IRUGO);
+MODULE_PARM_DESC(chip_addr,
+		 "Chip addresses (up to 10, between 0x03 and 0x77)");
+
+static unsigned long functionality = STUB_FUNC;
+module_param(functionality, ulong, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(functionality, "Override functionality bitfield");
+
+struct stub_chip {
+	u8 pointer;
+	u16 words[256];		/* Byte operations use the LSB as per SMBus
+				   specification */
+};
+
+static struct stub_chip *stub_chips;
+
+/* Return negative errno on error. */
+static s32 stub_xfer(struct i2c_adapter * adap, u16 addr, unsigned short flags,
+	char read_write, u8 command, int size, union i2c_smbus_data * data)
+{
+	s32 ret;
+	int i, len;
+	struct stub_chip *chip = NULL;
+
+	/* Search for the right chip */
+	for (i = 0; i < MAX_CHIPS && chip_addr[i]; i++) {
+		if (addr == chip_addr[i]) {
+			chip = stub_chips + i;
+			break;
+		}
+	}
+	if (!chip)
+		return -ENODEV;
+
+	switch (size) {
+
+	case I2C_SMBUS_QUICK:
+		dev_dbg(&adap->dev, "smbus quick - addr 0x%02x\n", addr);
+		ret = 0;
+		break;
+
+	case I2C_SMBUS_BYTE:
+		if (read_write == I2C_SMBUS_WRITE) {
+			chip->pointer = command;
+			dev_dbg(&adap->dev, "smbus byte - addr 0x%02x, "
+					"wrote 0x%02x.\n",
+					addr, command);
+		} else {
+			data->byte = chip->words[chip->pointer++] & 0xff;
+			dev_dbg(&adap->dev, "smbus byte - addr 0x%02x, "
+					"read  0x%02x.\n",
+					addr, data->byte);
+		}
+
+		ret = 0;
+		break;
+
+	case I2C_SMBUS_BYTE_DATA:
+		if (read_write == I2C_SMBUS_WRITE) {
+			chip->words[command] &= 0xff00;
+			chip->words[command] |= data->byte;
+			dev_dbg(&adap->dev, "smbus byte data - addr 0x%02x, "
+					"wrote 0x%02x at 0x%02x.\n",
+					addr, data->byte, command);
+		} else {
+			data->byte = chip->words[command] & 0xff;
+			dev_dbg(&adap->dev, "smbus byte data - addr 0x%02x, "
+					"read  0x%02x at 0x%02x.\n",
+					addr, data->byte, command);
+		}
+		chip->pointer = command + 1;
+
+		ret = 0;
+		break;
+
+	case I2C_SMBUS_WORD_DATA:
+		if (read_write == I2C_SMBUS_WRITE) {
+			chip->words[command] = data->word;
+			dev_dbg(&adap->dev, "smbus word data - addr 0x%02x, "
+					"wrote 0x%04x at 0x%02x.\n",
+					addr, data->word, command);
+		} else {
+			data->word = chip->words[command];
+			dev_dbg(&adap->dev, "smbus word data - addr 0x%02x, "
+					"read  0x%04x at 0x%02x.\n",
+					addr, data->word, command);
+		}
+
+		ret = 0;
+		break;
+
+	case I2C_SMBUS_I2C_BLOCK_DATA:
+		len = data->block[0];
+		if (read_write == I2C_SMBUS_WRITE) {
+			for (i = 0; i < len; i++) {
+				chip->words[command + i] &= 0xff00;
+				chip->words[command + i] |= data->block[1 + i];
+			}
+			dev_dbg(&adap->dev, "i2c block data - addr 0x%02x, "
+					"wrote %d bytes at 0x%02x.\n",
+					addr, len, command);
+		} else {
+			for (i = 0; i < len; i++) {
+				data->block[1 + i] =
+					chip->words[command + i] & 0xff;
+			}
+			dev_dbg(&adap->dev, "i2c block data - addr 0x%02x, "
+					"read  %d bytes at 0x%02x.\n",
+					addr, len, command);
+		}
+
+		ret = 0;
+		break;
+
+	default:
+		dev_dbg(&adap->dev, "Unsupported I2C/SMBus command\n");
+		ret = -EOPNOTSUPP;
+		break;
+	} /* switch (size) */
+
+	return ret;
+}
+
+static u32 stub_func(struct i2c_adapter *adapter)
+{
+	return STUB_FUNC & functionality;
+}
+
+static const struct i2c_algorithm smbus_algorithm = {
+	.functionality	= stub_func,
+	.smbus_xfer	= stub_xfer,
+};
+
+static struct i2c_adapter stub_adapter = {
+	.owner		= THIS_MODULE,
+	.class		= I2C_CLASS_HWMON | I2C_CLASS_SPD,
+	.algo		= &smbus_algorithm,
+	.name		= "SMBus stub driver",
+};
+
+static int __init i2c_stub_init(void)
+{
+	int i, ret;
+
+	if (!chip_addr[0]) {
+		printk(KERN_ERR "i2c-stub: Please specify a chip address\n");
+		return -ENODEV;
+	}
+
+	for (i = 0; i < MAX_CHIPS && chip_addr[i]; i++) {
+		if (chip_addr[i] < 0x03 || chip_addr[i] > 0x77) {
+			printk(KERN_ERR "i2c-stub: Invalid chip address "
+			       "0x%02x\n", chip_addr[i]);
+			return -EINVAL;
+		}
+
+		printk(KERN_INFO "i2c-stub: Virtual chip at 0x%02x\n",
+		       chip_addr[i]);
+	}
+
+	/* Allocate memory for all chips at once */
+	stub_chips = kzalloc(i * sizeof(struct stub_chip), GFP_KERNEL);
+	if (!stub_chips) {
+		printk(KERN_ERR "i2c-stub: Out of memory\n");
+		return -ENOMEM;
+	}
+
+	ret = i2c_add_adapter(&stub_adapter);
+	if (ret)
+		kfree(stub_chips);
+	return ret;
+}
+
+static void __exit i2c_stub_exit(void)
+{
+	i2c_del_adapter(&stub_adapter);
+	kfree(stub_chips);
+}
+
+MODULE_AUTHOR("Mark M. Hoffman <mhoffman@lightlink.com>");
+MODULE_DESCRIPTION("I2C stub driver");
+MODULE_LICENSE("GPL");
+
+module_init(i2c_stub_init);
+module_exit(i2c_stub_exit);
+
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-taos-evm.c b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-taos-evm.c
new file mode 100644
index 0000000..26c352a
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-taos-evm.c
@@ -0,0 +1,331 @@
+/*
+ * Driver for the TAOS evaluation modules
+ * These devices include an I2C master which can be controlled over the
+ * serial port.
+ *
+ * Copyright (C) 2007 Jean Delvare <khali@linux-fr.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+#include <linux/serio.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+
+#define TAOS_BUFFER_SIZE	63
+
+#define TAOS_STATE_INIT		0
+#define TAOS_STATE_IDLE		1
+#define TAOS_STATE_EOFF		2
+#define TAOS_STATE_RECV		3
+
+#define TAOS_CMD_RESET		0x12
+#define TAOS_CMD_ECHO_ON	'+'
+#define TAOS_CMD_ECHO_OFF	'-'
+
+static DECLARE_WAIT_QUEUE_HEAD(wq);
+
+struct taos_data {
+	struct i2c_adapter adapter;
+	struct i2c_client *client;
+	int state;
+	u8 addr;		/* last used address */
+	unsigned char buffer[TAOS_BUFFER_SIZE];
+	unsigned int pos;	/* position inside the buffer */
+};
+
+/* TAOS TSL2550 EVM */
+static struct i2c_board_info tsl2550_info = {
+	I2C_BOARD_INFO("tsl2550", 0x39),
+};
+
+/* Instantiate i2c devices based on the adapter name */
+static struct i2c_client *taos_instantiate_device(struct i2c_adapter *adapter)
+{
+	if (!strncmp(adapter->name, "TAOS TSL2550 EVM", 16)) {
+		dev_info(&adapter->dev, "Instantiating device %s at 0x%02x\n",
+			tsl2550_info.type, tsl2550_info.addr);
+		return i2c_new_device(adapter, &tsl2550_info);
+	}
+
+	return NULL;
+}
+
+static int taos_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
+			   unsigned short flags, char read_write, u8 command,
+			   int size, union i2c_smbus_data *data)
+{
+	struct serio *serio = adapter->algo_data;
+	struct taos_data *taos = serio_get_drvdata(serio);
+	char *p;
+
+	/* Encode our transaction. "@" is for the device address, "$" for the
+	   SMBus command and "#" for the data. */
+	p = taos->buffer;
+
+	/* The device remembers the last used address, no need to send it
+	   again if it's the same */
+	if (addr != taos->addr)
+		p += sprintf(p, "@%02X", addr);
+
+	switch (size) {
+	case I2C_SMBUS_BYTE:
+		if (read_write == I2C_SMBUS_WRITE)
+			sprintf(p, "$#%02X", command);
+		else
+			sprintf(p, "$");
+		break;
+	case I2C_SMBUS_BYTE_DATA:
+		if (read_write == I2C_SMBUS_WRITE)
+			sprintf(p, "$%02X#%02X", command, data->byte);
+		else
+			sprintf(p, "$%02X", command);
+		break;
+	default:
+		dev_warn(&adapter->dev, "Unsupported transaction %d\n", size);
+		return -EOPNOTSUPP;
+	}
+
+	/* Send the transaction to the TAOS EVM */
+	dev_dbg(&adapter->dev, "Command buffer: %s\n", taos->buffer);
+	for (p = taos->buffer; *p; p++)
+		serio_write(serio, *p);
+
+	taos->addr = addr;
+
+	/* Start the transaction and read the answer */
+	taos->pos = 0;
+	taos->state = TAOS_STATE_RECV;
+	serio_write(serio, read_write == I2C_SMBUS_WRITE ? '>' : '<');
+	wait_event_interruptible_timeout(wq, taos->state == TAOS_STATE_IDLE,
+					 msecs_to_jiffies(150));
+	if (taos->state != TAOS_STATE_IDLE
+	 || taos->pos != 5) {
+		dev_err(&adapter->dev, "Transaction timeout (pos=%d)\n",
+			taos->pos);
+		return -EIO;
+	}
+	dev_dbg(&adapter->dev, "Answer buffer: %s\n", taos->buffer);
+
+	/* Interpret the returned string */
+	p = taos->buffer + 1;
+	p[3] = '\0';
+	if (!strcmp(p, "NAK"))
+		return -ENODEV;
+
+	if (read_write == I2C_SMBUS_WRITE) {
+		if (!strcmp(p, "ACK"))
+			return 0;
+	} else {
+		if (p[0] == 'x') {
+			data->byte = simple_strtol(p + 1, NULL, 16);
+			return 0;
+		}
+	}
+
+	return -EIO;
+}
+
+static u32 taos_smbus_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA;
+}
+
+static const struct i2c_algorithm taos_algorithm = {
+	.smbus_xfer	= taos_smbus_xfer,
+	.functionality	= taos_smbus_func,
+};
+
+static irqreturn_t taos_interrupt(struct serio *serio, unsigned char data,
+				  unsigned int flags)
+{
+	struct taos_data *taos = serio_get_drvdata(serio);
+
+	switch (taos->state) {
+	case TAOS_STATE_INIT:
+		taos->buffer[taos->pos++] = data;
+		if (data == ':'
+		 || taos->pos == TAOS_BUFFER_SIZE - 1) {
+			taos->buffer[taos->pos] = '\0';
+			taos->state = TAOS_STATE_IDLE;
+			wake_up_interruptible(&wq);
+		}
+		break;
+	case TAOS_STATE_EOFF:
+		taos->state = TAOS_STATE_IDLE;
+		wake_up_interruptible(&wq);
+		break;
+	case TAOS_STATE_RECV:
+		taos->buffer[taos->pos++] = data;
+		if (data == ']') {
+			taos->buffer[taos->pos] = '\0';
+			taos->state = TAOS_STATE_IDLE;
+			wake_up_interruptible(&wq);
+		}
+		break;
+	}
+
+	return IRQ_HANDLED;
+}
+
+/* Extract the adapter name from the buffer received after reset.
+   The buffer is modified and a pointer inside the buffer is returned. */
+static char *taos_adapter_name(char *buffer)
+{
+	char *start, *end;
+
+	start = strstr(buffer, "TAOS ");
+	if (!start)
+		return NULL;
+
+	end = strchr(start, '\r');
+	if (!end)
+		return NULL;
+	*end = '\0';
+
+	return start;
+}
+
+static int taos_connect(struct serio *serio, struct serio_driver *drv)
+{
+	struct taos_data *taos;
+	struct i2c_adapter *adapter;
+	char *name;
+	int err;
+
+	taos = kzalloc(sizeof(struct taos_data), GFP_KERNEL);
+	if (!taos) {
+		err = -ENOMEM;
+		goto exit;
+	}
+	taos->state = TAOS_STATE_INIT;
+	serio_set_drvdata(serio, taos);
+
+	err = serio_open(serio, drv);
+	if (err)
+		goto exit_kfree;
+
+	adapter = &taos->adapter;
+	adapter->owner = THIS_MODULE;
+	adapter->algo = &taos_algorithm;
+	adapter->algo_data = serio;
+	adapter->dev.parent = &serio->dev;
+
+	/* Reset the TAOS evaluation module to identify it */
+	serio_write(serio, TAOS_CMD_RESET);
+	wait_event_interruptible_timeout(wq, taos->state == TAOS_STATE_IDLE,
+					 msecs_to_jiffies(2000));
+
+	if (taos->state != TAOS_STATE_IDLE) {
+		err = -ENODEV;
+		dev_err(&serio->dev, "TAOS EVM reset failed (state=%d, "
+			"pos=%d)\n", taos->state, taos->pos);
+		goto exit_close;
+	}
+
+	name = taos_adapter_name(taos->buffer);
+	if (!name) {
+		err = -ENODEV;
+		dev_err(&serio->dev, "TAOS EVM identification failed\n");
+		goto exit_close;
+	}
+	strlcpy(adapter->name, name, sizeof(adapter->name));
+
+	/* Turn echo off for better performance */
+	taos->state = TAOS_STATE_EOFF;
+	serio_write(serio, TAOS_CMD_ECHO_OFF);
+
+	wait_event_interruptible_timeout(wq, taos->state == TAOS_STATE_IDLE,
+					 msecs_to_jiffies(250));
+	if (taos->state != TAOS_STATE_IDLE) {
+		err = -ENODEV;
+		dev_err(&serio->dev, "TAOS EVM echo off failed "
+			"(state=%d)\n", taos->state);
+		goto exit_close;
+	}
+
+	err = i2c_add_adapter(adapter);
+	if (err)
+		goto exit_close;
+	dev_info(&serio->dev, "Connected to TAOS EVM\n");
+
+	taos->client = taos_instantiate_device(adapter);
+	return 0;
+
+ exit_close:
+	serio_close(serio);
+ exit_kfree:
+	serio_set_drvdata(serio, NULL);
+	kfree(taos);
+ exit:
+	return err;
+}
+
+static void taos_disconnect(struct serio *serio)
+{
+	struct taos_data *taos = serio_get_drvdata(serio);
+
+	if (taos->client)
+		i2c_unregister_device(taos->client);
+	i2c_del_adapter(&taos->adapter);
+	serio_close(serio);
+	serio_set_drvdata(serio, NULL);
+	kfree(taos);
+
+	dev_info(&serio->dev, "Disconnected from TAOS EVM\n");
+}
+
+static struct serio_device_id taos_serio_ids[] = {
+	{
+		.type	= SERIO_RS232,
+		.proto	= SERIO_TAOSEVM,
+		.id	= SERIO_ANY,
+		.extra	= SERIO_ANY,
+	},
+	{ 0 }
+};
+MODULE_DEVICE_TABLE(serio, taos_serio_ids);
+
+static struct serio_driver taos_drv = {
+	.driver		= {
+		.name	= "taos-evm",
+	},
+	.description	= "TAOS evaluation module driver",
+	.id_table	= taos_serio_ids,
+	.connect	= taos_connect,
+	.disconnect	= taos_disconnect,
+	.interrupt	= taos_interrupt,
+};
+
+static int __init taos_init(void)
+{
+	return serio_register_driver(&taos_drv);
+}
+
+static void __exit taos_exit(void)
+{
+	serio_unregister_driver(&taos_drv);
+}
+
+MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
+MODULE_DESCRIPTION("TAOS evaluation module driver");
+MODULE_LICENSE("GPL");
+
+module_init(taos_init);
+module_exit(taos_exit);
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-tegra.c b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-tegra.c
new file mode 100644
index 0000000..d47ca36
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-tegra.c
@@ -0,0 +1,800 @@
+/*
+ * drivers/i2c/busses/i2c-tegra.c
+ *
+ * Copyright (C) 2010 Google, Inc.
+ * Author: Colin Cross <ccross@android.com>
+ *
+ * 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.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/i2c-tegra.h>
+#include <linux/of_i2c.h>
+#include <linux/module.h>
+
+#include <asm/unaligned.h>
+
+#include <mach/clk.h>
+
+#define TEGRA_I2C_TIMEOUT (msecs_to_jiffies(1000))
+#define BYTES_PER_FIFO_WORD 4
+
+#define I2C_CNFG				0x000
+#define I2C_CNFG_DEBOUNCE_CNT_SHIFT		12
+#define I2C_CNFG_PACKET_MODE_EN			(1<<10)
+#define I2C_CNFG_NEW_MASTER_FSM			(1<<11)
+#define I2C_STATUS				0x01C
+#define I2C_SL_CNFG				0x020
+#define I2C_SL_CNFG_NACK			(1<<1)
+#define I2C_SL_CNFG_NEWSL			(1<<2)
+#define I2C_SL_ADDR1				0x02c
+#define I2C_SL_ADDR2				0x030
+#define I2C_TX_FIFO				0x050
+#define I2C_RX_FIFO				0x054
+#define I2C_PACKET_TRANSFER_STATUS		0x058
+#define I2C_FIFO_CONTROL			0x05c
+#define I2C_FIFO_CONTROL_TX_FLUSH		(1<<1)
+#define I2C_FIFO_CONTROL_RX_FLUSH		(1<<0)
+#define I2C_FIFO_CONTROL_TX_TRIG_SHIFT		5
+#define I2C_FIFO_CONTROL_RX_TRIG_SHIFT		2
+#define I2C_FIFO_STATUS				0x060
+#define I2C_FIFO_STATUS_TX_MASK			0xF0
+#define I2C_FIFO_STATUS_TX_SHIFT		4
+#define I2C_FIFO_STATUS_RX_MASK			0x0F
+#define I2C_FIFO_STATUS_RX_SHIFT		0
+#define I2C_INT_MASK				0x064
+#define I2C_INT_STATUS				0x068
+#define I2C_INT_PACKET_XFER_COMPLETE		(1<<7)
+#define I2C_INT_ALL_PACKETS_XFER_COMPLETE	(1<<6)
+#define I2C_INT_TX_FIFO_OVERFLOW		(1<<5)
+#define I2C_INT_RX_FIFO_UNDERFLOW		(1<<4)
+#define I2C_INT_NO_ACK				(1<<3)
+#define I2C_INT_ARBITRATION_LOST		(1<<2)
+#define I2C_INT_TX_FIFO_DATA_REQ		(1<<1)
+#define I2C_INT_RX_FIFO_DATA_REQ		(1<<0)
+#define I2C_CLK_DIVISOR				0x06c
+
+#define DVC_CTRL_REG1				0x000
+#define DVC_CTRL_REG1_INTR_EN			(1<<10)
+#define DVC_CTRL_REG2				0x004
+#define DVC_CTRL_REG3				0x008
+#define DVC_CTRL_REG3_SW_PROG			(1<<26)
+#define DVC_CTRL_REG3_I2C_DONE_INTR_EN		(1<<30)
+#define DVC_STATUS				0x00c
+#define DVC_STATUS_I2C_DONE_INTR		(1<<30)
+
+#define I2C_ERR_NONE				0x00
+#define I2C_ERR_NO_ACK				0x01
+#define I2C_ERR_ARBITRATION_LOST		0x02
+#define I2C_ERR_UNKNOWN_INTERRUPT		0x04
+
+#define PACKET_HEADER0_HEADER_SIZE_SHIFT	28
+#define PACKET_HEADER0_PACKET_ID_SHIFT		16
+#define PACKET_HEADER0_CONT_ID_SHIFT		12
+#define PACKET_HEADER0_PROTOCOL_I2C		(1<<4)
+
+#define I2C_HEADER_HIGHSPEED_MODE		(1<<22)
+#define I2C_HEADER_CONT_ON_NAK			(1<<21)
+#define I2C_HEADER_SEND_START_BYTE		(1<<20)
+#define I2C_HEADER_READ				(1<<19)
+#define I2C_HEADER_10BIT_ADDR			(1<<18)
+#define I2C_HEADER_IE_ENABLE			(1<<17)
+#define I2C_HEADER_REPEAT_START			(1<<16)
+#define I2C_HEADER_MASTER_ADDR_SHIFT		12
+#define I2C_HEADER_SLAVE_ADDR_SHIFT		1
+
+/**
+ * struct tegra_i2c_dev	- per device i2c context
+ * @dev: device reference for power management
+ * @adapter: core i2c layer adapter information
+ * @clk: clock reference for i2c controller
+ * @i2c_clk: clock reference for i2c bus
+ * @iomem: memory resource for registers
+ * @base: ioremapped registers cookie
+ * @cont_id: i2c controller id, used for for packet header
+ * @irq: irq number of transfer complete interrupt
+ * @is_dvc: identifies the DVC i2c controller, has a different register layout
+ * @msg_complete: transfer completion notifier
+ * @msg_err: error code for completed message
+ * @msg_buf: pointer to current message data
+ * @msg_buf_remaining: size of unsent data in the message buffer
+ * @msg_read: identifies read transfers
+ * @bus_clk_rate: current i2c bus clock rate
+ * @is_suspended: prevents i2c controller accesses after suspend is called
+ */
+struct tegra_i2c_dev {
+	struct device *dev;
+	struct i2c_adapter adapter;
+	struct clk *clk;
+	struct clk *i2c_clk;
+	struct resource *iomem;
+	void __iomem *base;
+	int cont_id;
+	int irq;
+	bool irq_disabled;
+	int is_dvc;
+	struct completion msg_complete;
+	int msg_err;
+	u8 *msg_buf;
+	size_t msg_buf_remaining;
+	int msg_read;
+	unsigned long bus_clk_rate;
+	bool is_suspended;
+};
+
+static void dvc_writel(struct tegra_i2c_dev *i2c_dev, u32 val, unsigned long reg)
+{
+	writel(val, i2c_dev->base + reg);
+}
+
+static u32 dvc_readl(struct tegra_i2c_dev *i2c_dev, unsigned long reg)
+{
+	return readl(i2c_dev->base + reg);
+}
+
+/*
+ * i2c_writel and i2c_readl will offset the register if necessary to talk
+ * to the I2C block inside the DVC block
+ */
+static unsigned long tegra_i2c_reg_addr(struct tegra_i2c_dev *i2c_dev,
+	unsigned long reg)
+{
+	if (i2c_dev->is_dvc)
+		reg += (reg >= I2C_TX_FIFO) ? 0x10 : 0x40;
+	return reg;
+}
+
+static void i2c_writel(struct tegra_i2c_dev *i2c_dev, u32 val,
+	unsigned long reg)
+{
+	writel(val, i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, reg));
+}
+
+static u32 i2c_readl(struct tegra_i2c_dev *i2c_dev, unsigned long reg)
+{
+	return readl(i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, reg));
+}
+
+static void i2c_writesl(struct tegra_i2c_dev *i2c_dev, void *data,
+	unsigned long reg, int len)
+{
+	writesl(i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, reg), data, len);
+}
+
+static void i2c_readsl(struct tegra_i2c_dev *i2c_dev, void *data,
+	unsigned long reg, int len)
+{
+	readsl(i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, reg), data, len);
+}
+
+static void tegra_i2c_mask_irq(struct tegra_i2c_dev *i2c_dev, u32 mask)
+{
+	u32 int_mask = i2c_readl(i2c_dev, I2C_INT_MASK);
+	int_mask &= ~mask;
+	i2c_writel(i2c_dev, int_mask, I2C_INT_MASK);
+}
+
+static void tegra_i2c_unmask_irq(struct tegra_i2c_dev *i2c_dev, u32 mask)
+{
+	u32 int_mask = i2c_readl(i2c_dev, I2C_INT_MASK);
+	int_mask |= mask;
+	i2c_writel(i2c_dev, int_mask, I2C_INT_MASK);
+}
+
+static int tegra_i2c_flush_fifos(struct tegra_i2c_dev *i2c_dev)
+{
+	unsigned long timeout = jiffies + HZ;
+	u32 val = i2c_readl(i2c_dev, I2C_FIFO_CONTROL);
+	val |= I2C_FIFO_CONTROL_TX_FLUSH | I2C_FIFO_CONTROL_RX_FLUSH;
+	i2c_writel(i2c_dev, val, I2C_FIFO_CONTROL);
+
+	while (i2c_readl(i2c_dev, I2C_FIFO_CONTROL) &
+		(I2C_FIFO_CONTROL_TX_FLUSH | I2C_FIFO_CONTROL_RX_FLUSH)) {
+		if (time_after(jiffies, timeout)) {
+			dev_warn(i2c_dev->dev, "timeout waiting for fifo flush\n");
+			return -ETIMEDOUT;
+		}
+		msleep(1);
+	}
+	return 0;
+}
+
+static int tegra_i2c_empty_rx_fifo(struct tegra_i2c_dev *i2c_dev)
+{
+	u32 val;
+	int rx_fifo_avail;
+	u8 *buf = i2c_dev->msg_buf;
+	size_t buf_remaining = i2c_dev->msg_buf_remaining;
+	int words_to_transfer;
+
+	val = i2c_readl(i2c_dev, I2C_FIFO_STATUS);
+	rx_fifo_avail = (val & I2C_FIFO_STATUS_RX_MASK) >>
+		I2C_FIFO_STATUS_RX_SHIFT;
+
+	/* Rounds down to not include partial word at the end of buf */
+	words_to_transfer = buf_remaining / BYTES_PER_FIFO_WORD;
+	if (words_to_transfer > rx_fifo_avail)
+		words_to_transfer = rx_fifo_avail;
+
+	i2c_readsl(i2c_dev, buf, I2C_RX_FIFO, words_to_transfer);
+
+	buf += words_to_transfer * BYTES_PER_FIFO_WORD;
+	buf_remaining -= words_to_transfer * BYTES_PER_FIFO_WORD;
+	rx_fifo_avail -= words_to_transfer;
+
+	/*
+	 * If there is a partial word at the end of buf, handle it manually to
+	 * prevent overwriting past the end of buf
+	 */
+	if (rx_fifo_avail > 0 && buf_remaining > 0) {
+		BUG_ON(buf_remaining > 3);
+		val = i2c_readl(i2c_dev, I2C_RX_FIFO);
+		memcpy(buf, &val, buf_remaining);
+		buf_remaining = 0;
+		rx_fifo_avail--;
+	}
+
+	BUG_ON(rx_fifo_avail > 0 && buf_remaining > 0);
+	i2c_dev->msg_buf_remaining = buf_remaining;
+	i2c_dev->msg_buf = buf;
+	return 0;
+}
+
+static int tegra_i2c_fill_tx_fifo(struct tegra_i2c_dev *i2c_dev)
+{
+	u32 val;
+	int tx_fifo_avail;
+	u8 *buf = i2c_dev->msg_buf;
+	size_t buf_remaining = i2c_dev->msg_buf_remaining;
+	int words_to_transfer;
+
+	val = i2c_readl(i2c_dev, I2C_FIFO_STATUS);
+	tx_fifo_avail = (val & I2C_FIFO_STATUS_TX_MASK) >>
+		I2C_FIFO_STATUS_TX_SHIFT;
+
+	/* Rounds down to not include partial word at the end of buf */
+	words_to_transfer = buf_remaining / BYTES_PER_FIFO_WORD;
+
+	/* It's very common to have < 4 bytes, so optimize that case. */
+	if (words_to_transfer) {
+		if (words_to_transfer > tx_fifo_avail)
+			words_to_transfer = tx_fifo_avail;
+
+		/*
+		 * Update state before writing to FIFO.  If this casues us
+		 * to finish writing all bytes (AKA buf_remaining goes to 0) we
+		 * have a potential for an interrupt (PACKET_XFER_COMPLETE is
+		 * not maskable).  We need to make sure that the isr sees
+		 * buf_remaining as 0 and doesn't call us back re-entrantly.
+		 */
+		buf_remaining -= words_to_transfer * BYTES_PER_FIFO_WORD;
+		tx_fifo_avail -= words_to_transfer;
+		i2c_dev->msg_buf_remaining = buf_remaining;
+		i2c_dev->msg_buf = buf +
+			words_to_transfer * BYTES_PER_FIFO_WORD;
+		barrier();
+
+		i2c_writesl(i2c_dev, buf, I2C_TX_FIFO, words_to_transfer);
+
+		buf += words_to_transfer * BYTES_PER_FIFO_WORD;
+	}
+
+	/*
+	 * If there is a partial word at the end of buf, handle it manually to
+	 * prevent reading past the end of buf, which could cross a page
+	 * boundary and fault.
+	 */
+	if (tx_fifo_avail > 0 && buf_remaining > 0) {
+		BUG_ON(buf_remaining > 3);
+		memcpy(&val, buf, buf_remaining);
+
+		/* Again update before writing to FIFO to make sure isr sees. */
+		i2c_dev->msg_buf_remaining = 0;
+		i2c_dev->msg_buf = NULL;
+		barrier();
+
+		i2c_writel(i2c_dev, val, I2C_TX_FIFO);
+	}
+
+	return 0;
+}
+
+/*
+ * One of the Tegra I2C blocks is inside the DVC (Digital Voltage Controller)
+ * block.  This block is identical to the rest of the I2C blocks, except that
+ * it only supports master mode, it has registers moved around, and it needs
+ * some extra init to get it into I2C mode.  The register moves are handled
+ * by i2c_readl and i2c_writel
+ */
+static void tegra_dvc_init(struct tegra_i2c_dev *i2c_dev)
+{
+	u32 val = 0;
+	val = dvc_readl(i2c_dev, DVC_CTRL_REG3);
+	val |= DVC_CTRL_REG3_SW_PROG;
+	val |= DVC_CTRL_REG3_I2C_DONE_INTR_EN;
+	dvc_writel(i2c_dev, val, DVC_CTRL_REG3);
+
+	val = dvc_readl(i2c_dev, DVC_CTRL_REG1);
+	val |= DVC_CTRL_REG1_INTR_EN;
+	dvc_writel(i2c_dev, val, DVC_CTRL_REG1);
+}
+
+static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev)
+{
+	u32 val;
+	int err = 0;
+
+	err = clk_enable(i2c_dev->clk);
+	if (err < 0) {
+		dev_err(i2c_dev->dev, "Clock enable failed %d\n", err);
+		return err;
+	}
+
+	tegra_periph_reset_assert(i2c_dev->clk);
+	udelay(2);
+	tegra_periph_reset_deassert(i2c_dev->clk);
+
+	if (i2c_dev->is_dvc)
+		tegra_dvc_init(i2c_dev);
+
+	val = I2C_CNFG_NEW_MASTER_FSM | I2C_CNFG_PACKET_MODE_EN |
+		(0x2 << I2C_CNFG_DEBOUNCE_CNT_SHIFT);
+	i2c_writel(i2c_dev, val, I2C_CNFG);
+	i2c_writel(i2c_dev, 0, I2C_INT_MASK);
+	clk_set_rate(i2c_dev->clk, i2c_dev->bus_clk_rate * 8);
+
+	if (!i2c_dev->is_dvc) {
+		u32 sl_cfg = i2c_readl(i2c_dev, I2C_SL_CNFG);
+		sl_cfg |= I2C_SL_CNFG_NACK | I2C_SL_CNFG_NEWSL;
+		i2c_writel(i2c_dev, sl_cfg, I2C_SL_CNFG);
+		i2c_writel(i2c_dev, 0xfc, I2C_SL_ADDR1);
+		i2c_writel(i2c_dev, 0x00, I2C_SL_ADDR2);
+
+	}
+
+	val = 7 << I2C_FIFO_CONTROL_TX_TRIG_SHIFT |
+		0 << I2C_FIFO_CONTROL_RX_TRIG_SHIFT;
+	i2c_writel(i2c_dev, val, I2C_FIFO_CONTROL);
+
+	if (tegra_i2c_flush_fifos(i2c_dev))
+		err = -ETIMEDOUT;
+
+	clk_disable(i2c_dev->clk);
+
+	if (i2c_dev->irq_disabled) {
+		i2c_dev->irq_disabled = 0;
+		enable_irq(i2c_dev->irq);
+	}
+
+	return err;
+}
+
+static irqreturn_t tegra_i2c_isr(int irq, void *dev_id)
+{
+	u32 status;
+	const u32 status_err = I2C_INT_NO_ACK | I2C_INT_ARBITRATION_LOST;
+	struct tegra_i2c_dev *i2c_dev = dev_id;
+
+	status = i2c_readl(i2c_dev, I2C_INT_STATUS);
+
+	if (status == 0) {
+		dev_warn(i2c_dev->dev, "irq status 0 %08x %08x %08x\n",
+			 i2c_readl(i2c_dev, I2C_PACKET_TRANSFER_STATUS),
+			 i2c_readl(i2c_dev, I2C_STATUS),
+			 i2c_readl(i2c_dev, I2C_CNFG));
+		i2c_dev->msg_err |= I2C_ERR_UNKNOWN_INTERRUPT;
+
+		if (!i2c_dev->irq_disabled) {
+			disable_irq_nosync(i2c_dev->irq);
+			i2c_dev->irq_disabled = 1;
+		}
+		goto err;
+	}
+
+	if (unlikely(status & status_err)) {
+		if (status & I2C_INT_NO_ACK)
+			i2c_dev->msg_err |= I2C_ERR_NO_ACK;
+		if (status & I2C_INT_ARBITRATION_LOST)
+			i2c_dev->msg_err |= I2C_ERR_ARBITRATION_LOST;
+		goto err;
+	}
+
+	if (i2c_dev->msg_read && (status & I2C_INT_RX_FIFO_DATA_REQ)) {
+		if (i2c_dev->msg_buf_remaining)
+			tegra_i2c_empty_rx_fifo(i2c_dev);
+		else
+			BUG();
+	}
+
+	if (!i2c_dev->msg_read && (status & I2C_INT_TX_FIFO_DATA_REQ)) {
+		if (i2c_dev->msg_buf_remaining)
+			tegra_i2c_fill_tx_fifo(i2c_dev);
+		else
+			tegra_i2c_mask_irq(i2c_dev, I2C_INT_TX_FIFO_DATA_REQ);
+	}
+
+	i2c_writel(i2c_dev, status, I2C_INT_STATUS);
+	if (i2c_dev->is_dvc)
+		dvc_writel(i2c_dev, DVC_STATUS_I2C_DONE_INTR, DVC_STATUS);
+
+	if (status & I2C_INT_PACKET_XFER_COMPLETE) {
+		BUG_ON(i2c_dev->msg_buf_remaining);
+		complete(&i2c_dev->msg_complete);
+	}
+	return IRQ_HANDLED;
+err:
+	/* An error occurred, mask all interrupts */
+	tegra_i2c_mask_irq(i2c_dev, I2C_INT_NO_ACK | I2C_INT_ARBITRATION_LOST |
+		I2C_INT_PACKET_XFER_COMPLETE | I2C_INT_TX_FIFO_DATA_REQ |
+		I2C_INT_RX_FIFO_DATA_REQ);
+	i2c_writel(i2c_dev, status, I2C_INT_STATUS);
+	if (i2c_dev->is_dvc)
+		dvc_writel(i2c_dev, DVC_STATUS_I2C_DONE_INTR, DVC_STATUS);
+
+	complete(&i2c_dev->msg_complete);
+	return IRQ_HANDLED;
+}
+
+static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
+	struct i2c_msg *msg, int stop)
+{
+	u32 packet_header;
+	u32 int_mask;
+	int ret;
+
+	tegra_i2c_flush_fifos(i2c_dev);
+
+	if (msg->len == 0)
+		return -EINVAL;
+
+	i2c_dev->msg_buf = msg->buf;
+	i2c_dev->msg_buf_remaining = msg->len;
+	i2c_dev->msg_err = I2C_ERR_NONE;
+	i2c_dev->msg_read = (msg->flags & I2C_M_RD);
+	INIT_COMPLETION(i2c_dev->msg_complete);
+
+	packet_header = (0 << PACKET_HEADER0_HEADER_SIZE_SHIFT) |
+			PACKET_HEADER0_PROTOCOL_I2C |
+			(i2c_dev->cont_id << PACKET_HEADER0_CONT_ID_SHIFT) |
+			(1 << PACKET_HEADER0_PACKET_ID_SHIFT);
+	i2c_writel(i2c_dev, packet_header, I2C_TX_FIFO);
+
+	packet_header = msg->len - 1;
+	i2c_writel(i2c_dev, packet_header, I2C_TX_FIFO);
+
+	packet_header = msg->addr << I2C_HEADER_SLAVE_ADDR_SHIFT;
+	packet_header |= I2C_HEADER_IE_ENABLE;
+	if (!stop)
+		packet_header |= I2C_HEADER_REPEAT_START;
+	if (msg->flags & I2C_M_TEN)
+		packet_header |= I2C_HEADER_10BIT_ADDR;
+	if (msg->flags & I2C_M_IGNORE_NAK)
+		packet_header |= I2C_HEADER_CONT_ON_NAK;
+	if (msg->flags & I2C_M_RD)
+		packet_header |= I2C_HEADER_READ;
+	i2c_writel(i2c_dev, packet_header, I2C_TX_FIFO);
+
+	if (!(msg->flags & I2C_M_RD))
+		tegra_i2c_fill_tx_fifo(i2c_dev);
+
+	int_mask = I2C_INT_NO_ACK | I2C_INT_ARBITRATION_LOST;
+	if (msg->flags & I2C_M_RD)
+		int_mask |= I2C_INT_RX_FIFO_DATA_REQ;
+	else if (i2c_dev->msg_buf_remaining)
+		int_mask |= I2C_INT_TX_FIFO_DATA_REQ;
+	tegra_i2c_unmask_irq(i2c_dev, int_mask);
+	dev_dbg(i2c_dev->dev, "unmasked irq: %02x\n",
+		i2c_readl(i2c_dev, I2C_INT_MASK));
+
+	ret = wait_for_completion_timeout(&i2c_dev->msg_complete, TEGRA_I2C_TIMEOUT);
+	tegra_i2c_mask_irq(i2c_dev, int_mask);
+
+	if (WARN_ON(ret == 0)) {
+		dev_err(i2c_dev->dev, "i2c transfer timed out\n");
+
+		tegra_i2c_init(i2c_dev);
+		return -ETIMEDOUT;
+	}
+
+	dev_dbg(i2c_dev->dev, "transfer complete: %d %d %d\n",
+		ret, completion_done(&i2c_dev->msg_complete), i2c_dev->msg_err);
+
+	if (likely(i2c_dev->msg_err == I2C_ERR_NONE))
+		return 0;
+
+	/*
+	 * NACK interrupt is generated before the I2C controller generates the
+	 * STOP condition on the bus. So wait for 2 clock periods before resetting
+	 * the controller so that STOP condition has been delivered properly.
+	 */
+	if (i2c_dev->msg_err == I2C_ERR_NO_ACK)
+		udelay(DIV_ROUND_UP(2 * 1000000, i2c_dev->bus_clk_rate));
+
+	tegra_i2c_init(i2c_dev);
+	if (i2c_dev->msg_err == I2C_ERR_NO_ACK) {
+		if (msg->flags & I2C_M_IGNORE_NAK)
+			return 0;
+		return -EREMOTEIO;
+	}
+
+	return -EIO;
+}
+
+static int tegra_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
+	int num)
+{
+	struct tegra_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
+	int i;
+	int ret = 0;
+
+	if (i2c_dev->is_suspended)
+		return -EBUSY;
+
+	ret = clk_enable(i2c_dev->clk);
+	if (ret < 0) {
+		dev_err(i2c_dev->dev, "Clock enable failed %d\n", ret);
+		return ret;
+	}
+
+	for (i = 0; i < num; i++) {
+		int stop = (i == (num - 1)) ? 1  : 0;
+		ret = tegra_i2c_xfer_msg(i2c_dev, &msgs[i], stop);
+		if (ret)
+			break;
+	}
+	clk_disable(i2c_dev->clk);
+	return ret ?: i;
+}
+
+static u32 tegra_i2c_func(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm tegra_i2c_algo = {
+	.master_xfer	= tegra_i2c_xfer,
+	.functionality	= tegra_i2c_func,
+};
+
+static int __devinit tegra_i2c_probe(struct platform_device *pdev)
+{
+	struct tegra_i2c_dev *i2c_dev;
+	struct tegra_i2c_platform_data *pdata = pdev->dev.platform_data;
+	struct resource *res;
+	struct resource *iomem;
+	struct clk *clk;
+	struct clk *i2c_clk;
+	const unsigned int *prop;
+	void __iomem *base;
+	int irq;
+	int ret = 0;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "no mem resource\n");
+		return -EINVAL;
+	}
+	iomem = request_mem_region(res->start, resource_size(res), pdev->name);
+	if (!iomem) {
+		dev_err(&pdev->dev, "I2C region already claimed\n");
+		return -EBUSY;
+	}
+
+	base = ioremap(iomem->start, resource_size(iomem));
+	if (!base) {
+		dev_err(&pdev->dev, "Cannot ioremap I2C region\n");
+		return -ENOMEM;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "no irq resource\n");
+		ret = -EINVAL;
+		goto err_iounmap;
+	}
+	irq = res->start;
+
+	clk = clk_get(&pdev->dev, NULL);
+	if (IS_ERR(clk)) {
+		dev_err(&pdev->dev, "missing controller clock");
+		ret = PTR_ERR(clk);
+		goto err_release_region;
+	}
+
+	i2c_clk = clk_get(&pdev->dev, "i2c");
+	if (IS_ERR(i2c_clk)) {
+		dev_err(&pdev->dev, "missing bus clock");
+		ret = PTR_ERR(i2c_clk);
+		goto err_clk_put;
+	}
+
+	i2c_dev = kzalloc(sizeof(struct tegra_i2c_dev), GFP_KERNEL);
+	if (!i2c_dev) {
+		ret = -ENOMEM;
+		goto err_i2c_clk_put;
+	}
+
+	i2c_dev->base = base;
+	i2c_dev->clk = clk;
+	i2c_dev->i2c_clk = i2c_clk;
+	i2c_dev->iomem = iomem;
+	i2c_dev->adapter.algo = &tegra_i2c_algo;
+	i2c_dev->irq = irq;
+	i2c_dev->cont_id = pdev->id;
+	i2c_dev->dev = &pdev->dev;
+
+	i2c_dev->bus_clk_rate = 100000; /* default clock rate */
+	if (pdata) {
+		i2c_dev->bus_clk_rate = pdata->bus_clk_rate;
+
+	} else if (i2c_dev->dev->of_node) {    /* if there is a device tree node ... */
+		prop = of_get_property(i2c_dev->dev->of_node,
+				"clock-frequency", NULL);
+		if (prop)
+			i2c_dev->bus_clk_rate = be32_to_cpup(prop);
+	}
+
+	if (pdev->dev.of_node)
+		i2c_dev->is_dvc = of_device_is_compatible(pdev->dev.of_node,
+						"nvidia,tegra20-i2c-dvc");
+	else if (pdev->id == 3)
+		i2c_dev->is_dvc = 1;
+	init_completion(&i2c_dev->msg_complete);
+
+	platform_set_drvdata(pdev, i2c_dev);
+
+	ret = tegra_i2c_init(i2c_dev);
+	if (ret) {
+		dev_err(&pdev->dev, "Failed to initialize i2c controller");
+		goto err_free;
+	}
+
+	ret = request_irq(i2c_dev->irq, tegra_i2c_isr, 0, pdev->name, i2c_dev);
+	if (ret) {
+		dev_err(&pdev->dev, "Failed to request irq %i\n", i2c_dev->irq);
+		goto err_free;
+	}
+
+	clk_enable(i2c_dev->i2c_clk);
+
+	i2c_set_adapdata(&i2c_dev->adapter, i2c_dev);
+	i2c_dev->adapter.owner = THIS_MODULE;
+	i2c_dev->adapter.class = I2C_CLASS_HWMON;
+	strlcpy(i2c_dev->adapter.name, "Tegra I2C adapter",
+		sizeof(i2c_dev->adapter.name));
+	i2c_dev->adapter.algo = &tegra_i2c_algo;
+	i2c_dev->adapter.dev.parent = &pdev->dev;
+	i2c_dev->adapter.nr = pdev->id;
+	i2c_dev->adapter.dev.of_node = pdev->dev.of_node;
+
+	ret = i2c_add_numbered_adapter(&i2c_dev->adapter);
+	if (ret) {
+		dev_err(&pdev->dev, "Failed to add I2C adapter\n");
+		goto err_free_irq;
+	}
+
+	of_i2c_register_devices(&i2c_dev->adapter);
+
+	return 0;
+err_free_irq:
+	free_irq(i2c_dev->irq, i2c_dev);
+err_free:
+	kfree(i2c_dev);
+err_i2c_clk_put:
+	clk_put(i2c_clk);
+err_clk_put:
+	clk_put(clk);
+err_release_region:
+	release_mem_region(iomem->start, resource_size(iomem));
+err_iounmap:
+	iounmap(base);
+	return ret;
+}
+
+static int __devexit tegra_i2c_remove(struct platform_device *pdev)
+{
+	struct tegra_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
+	i2c_del_adapter(&i2c_dev->adapter);
+	free_irq(i2c_dev->irq, i2c_dev);
+	clk_put(i2c_dev->i2c_clk);
+	clk_put(i2c_dev->clk);
+	release_mem_region(i2c_dev->iomem->start,
+		resource_size(i2c_dev->iomem));
+	iounmap(i2c_dev->base);
+	kfree(i2c_dev);
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int tegra_i2c_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct tegra_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
+
+	i2c_lock_adapter(&i2c_dev->adapter);
+	i2c_dev->is_suspended = true;
+	i2c_unlock_adapter(&i2c_dev->adapter);
+
+	return 0;
+}
+
+static int tegra_i2c_resume(struct platform_device *pdev)
+{
+	struct tegra_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
+	int ret;
+
+	i2c_lock_adapter(&i2c_dev->adapter);
+
+	ret = tegra_i2c_init(i2c_dev);
+
+	if (ret) {
+		i2c_unlock_adapter(&i2c_dev->adapter);
+		return ret;
+	}
+
+	i2c_dev->is_suspended = false;
+
+	i2c_unlock_adapter(&i2c_dev->adapter);
+
+	return 0;
+}
+#endif
+
+#if defined(CONFIG_OF)
+/* Match table for of_platform binding */
+static const struct of_device_id tegra_i2c_of_match[] __devinitconst = {
+	{ .compatible = "nvidia,tegra20-i2c", },
+	{ .compatible = "nvidia,tegra20-i2c-dvc", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, tegra_i2c_of_match);
+#else
+#define tegra_i2c_of_match NULL
+#endif
+
+static struct platform_driver tegra_i2c_driver = {
+	.probe   = tegra_i2c_probe,
+	.remove  = __devexit_p(tegra_i2c_remove),
+#ifdef CONFIG_PM
+	.suspend = tegra_i2c_suspend,
+	.resume  = tegra_i2c_resume,
+#endif
+	.driver  = {
+		.name  = "tegra-i2c",
+		.owner = THIS_MODULE,
+		.of_match_table = tegra_i2c_of_match,
+	},
+};
+
+static int __init tegra_i2c_init_driver(void)
+{
+	return platform_driver_register(&tegra_i2c_driver);
+}
+
+static void __exit tegra_i2c_exit_driver(void)
+{
+	platform_driver_unregister(&tegra_i2c_driver);
+}
+
+subsys_initcall(tegra_i2c_init_driver);
+module_exit(tegra_i2c_exit_driver);
+
+MODULE_DESCRIPTION("nVidia Tegra2 I2C Bus Controller driver");
+MODULE_AUTHOR("Colin Cross");
+MODULE_LICENSE("GPL v2");
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-tiny-usb.c b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-tiny-usb.c
new file mode 100644
index 0000000..f07307f
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-tiny-usb.c
@@ -0,0 +1,271 @@
+/*
+ * driver for the i2c-tiny-usb adapter - 1.0
+ * http://www.harbaum.org/till/i2c_tiny_usb
+ *
+ * Copyright (C) 2006-2007 Till Harbaum (Till@Harbaum.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+/* include interfaces to usb layer */
+#include <linux/usb.h>
+
+/* include interface to i2c layer */
+#include <linux/i2c.h>
+
+/* commands via USB, must match command ids in the firmware */
+#define CMD_ECHO		0
+#define CMD_GET_FUNC		1
+#define CMD_SET_DELAY		2
+#define CMD_GET_STATUS		3
+
+#define CMD_I2C_IO		4
+#define CMD_I2C_IO_BEGIN	(1<<0)
+#define CMD_I2C_IO_END		(1<<1)
+
+/* i2c bit delay, default is 10us -> 100kHz max
+   (in practice, due to additional delays in the i2c bitbanging
+   code this results in a i2c clock of about 50kHz) */
+static unsigned short delay = 10;
+module_param(delay, ushort, 0);
+MODULE_PARM_DESC(delay, "bit delay in microseconds "
+		 "(default is 10us for 100kHz max)");
+
+static int usb_read(struct i2c_adapter *adapter, int cmd,
+		    int value, int index, void *data, int len);
+
+static int usb_write(struct i2c_adapter *adapter, int cmd,
+		     int value, int index, void *data, int len);
+
+/* ----- begin of i2c layer ---------------------------------------------- */
+
+#define STATUS_IDLE		0
+#define STATUS_ADDRESS_ACK	1
+#define STATUS_ADDRESS_NAK	2
+
+static int usb_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num)
+{
+	unsigned char status;
+	struct i2c_msg *pmsg;
+	int i;
+
+	dev_dbg(&adapter->dev, "master xfer %d messages:\n", num);
+
+	for (i = 0 ; i < num ; i++) {
+		int cmd = CMD_I2C_IO;
+
+		if (i == 0)
+			cmd |= CMD_I2C_IO_BEGIN;
+
+		if (i == num-1)
+			cmd |= CMD_I2C_IO_END;
+
+		pmsg = &msgs[i];
+
+		dev_dbg(&adapter->dev,
+			"  %d: %s (flags %d) %d bytes to 0x%02x\n",
+			i, pmsg->flags & I2C_M_RD ? "read" : "write",
+			pmsg->flags, pmsg->len, pmsg->addr);
+
+		/* and directly send the message */
+		if (pmsg->flags & I2C_M_RD) {
+			/* read data */
+			if (usb_read(adapter, cmd,
+				     pmsg->flags, pmsg->addr,
+				     pmsg->buf, pmsg->len) != pmsg->len) {
+				dev_err(&adapter->dev,
+					"failure reading data\n");
+				return -EREMOTEIO;
+			}
+		} else {
+			/* write data */
+			if (usb_write(adapter, cmd,
+				      pmsg->flags, pmsg->addr,
+				      pmsg->buf, pmsg->len) != pmsg->len) {
+				dev_err(&adapter->dev,
+					"failure writing data\n");
+				return -EREMOTEIO;
+			}
+		}
+
+		/* read status */
+		if (usb_read(adapter, CMD_GET_STATUS, 0, 0, &status, 1) != 1) {
+			dev_err(&adapter->dev, "failure reading status\n");
+			return -EREMOTEIO;
+		}
+
+		dev_dbg(&adapter->dev, "  status = %d\n", status);
+		if (status == STATUS_ADDRESS_NAK)
+			return -EREMOTEIO;
+	}
+
+	return i;
+}
+
+static u32 usb_func(struct i2c_adapter *adapter)
+{
+	__le32 func;
+
+	/* get functionality from adapter */
+	if (usb_read(adapter, CMD_GET_FUNC, 0, 0, &func, sizeof(func)) !=
+	    sizeof(func)) {
+		dev_err(&adapter->dev, "failure reading functionality\n");
+		return 0;
+	}
+
+	return le32_to_cpu(func);
+}
+
+/* This is the actual algorithm we define */
+static const struct i2c_algorithm usb_algorithm = {
+	.master_xfer	= usb_xfer,
+	.functionality	= usb_func,
+};
+
+/* ----- end of i2c layer ------------------------------------------------ */
+
+/* ----- begin of usb layer ---------------------------------------------- */
+
+/*
+ * Initially the usb i2c interface uses a vid/pid pair donated by
+ * Future Technology Devices International Ltd., later a pair was
+ * bought from EZPrototypes
+ */
+static const struct usb_device_id i2c_tiny_usb_table[] = {
+	{ USB_DEVICE(0x0403, 0xc631) },   /* FTDI */
+	{ USB_DEVICE(0x1c40, 0x0534) },   /* EZPrototypes */
+	{ }                               /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, i2c_tiny_usb_table);
+
+/* Structure to hold all of our device specific stuff */
+struct i2c_tiny_usb {
+	struct usb_device *usb_dev; /* the usb device for this device */
+	struct usb_interface *interface; /* the interface for this device */
+	struct i2c_adapter adapter; /* i2c related things */
+};
+
+static int usb_read(struct i2c_adapter *adapter, int cmd,
+		    int value, int index, void *data, int len)
+{
+	struct i2c_tiny_usb *dev = (struct i2c_tiny_usb *)adapter->algo_data;
+
+	/* do control transfer */
+	return usb_control_msg(dev->usb_dev, usb_rcvctrlpipe(dev->usb_dev, 0),
+			       cmd, USB_TYPE_VENDOR | USB_RECIP_INTERFACE |
+			       USB_DIR_IN, value, index, data, len, 2000);
+}
+
+static int usb_write(struct i2c_adapter *adapter, int cmd,
+		     int value, int index, void *data, int len)
+{
+	struct i2c_tiny_usb *dev = (struct i2c_tiny_usb *)adapter->algo_data;
+
+	/* do control transfer */
+	return usb_control_msg(dev->usb_dev, usb_sndctrlpipe(dev->usb_dev, 0),
+			       cmd, USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+			       value, index, data, len, 2000);
+}
+
+static void i2c_tiny_usb_free(struct i2c_tiny_usb *dev)
+{
+	usb_put_dev(dev->usb_dev);
+	kfree(dev);
+}
+
+static int i2c_tiny_usb_probe(struct usb_interface *interface,
+			      const struct usb_device_id *id)
+{
+	struct i2c_tiny_usb *dev;
+	int retval = -ENOMEM;
+	u16 version;
+
+	dev_dbg(&interface->dev, "probing usb device\n");
+
+	/* allocate memory for our device state and initialize it */
+	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+	if (dev == NULL) {
+		dev_err(&interface->dev, "Out of memory\n");
+		goto error;
+	}
+
+	dev->usb_dev = usb_get_dev(interface_to_usbdev(interface));
+	dev->interface = interface;
+
+	/* save our data pointer in this interface device */
+	usb_set_intfdata(interface, dev);
+
+	version = le16_to_cpu(dev->usb_dev->descriptor.bcdDevice);
+	dev_info(&interface->dev,
+		 "version %x.%02x found at bus %03d address %03d\n",
+		 version >> 8, version & 0xff,
+		 dev->usb_dev->bus->busnum, dev->usb_dev->devnum);
+
+	/* setup i2c adapter description */
+	dev->adapter.owner = THIS_MODULE;
+	dev->adapter.class = I2C_CLASS_HWMON;
+	dev->adapter.algo = &usb_algorithm;
+	dev->adapter.algo_data = dev;
+	snprintf(dev->adapter.name, sizeof(dev->adapter.name),
+		 "i2c-tiny-usb at bus %03d device %03d",
+		 dev->usb_dev->bus->busnum, dev->usb_dev->devnum);
+
+	if (usb_write(&dev->adapter, CMD_SET_DELAY, delay, 0, NULL, 0) != 0) {
+		dev_err(&dev->adapter.dev,
+			"failure setting delay to %dus\n", delay);
+		retval = -EIO;
+		goto error;
+	}
+
+	dev->adapter.dev.parent = &dev->interface->dev;
+
+	/* and finally attach to i2c layer */
+	i2c_add_adapter(&dev->adapter);
+
+	/* inform user about successful attachment to i2c layer */
+	dev_info(&dev->adapter.dev, "connected i2c-tiny-usb device\n");
+
+	return 0;
+
+ error:
+	if (dev)
+		i2c_tiny_usb_free(dev);
+
+	return retval;
+}
+
+static void i2c_tiny_usb_disconnect(struct usb_interface *interface)
+{
+	struct i2c_tiny_usb *dev = usb_get_intfdata(interface);
+
+	i2c_del_adapter(&dev->adapter);
+	usb_set_intfdata(interface, NULL);
+	i2c_tiny_usb_free(dev);
+
+	dev_dbg(&interface->dev, "disconnected\n");
+}
+
+static struct usb_driver i2c_tiny_usb_driver = {
+	.name		= "i2c-tiny-usb",
+	.probe		= i2c_tiny_usb_probe,
+	.disconnect	= i2c_tiny_usb_disconnect,
+	.id_table	= i2c_tiny_usb_table,
+};
+
+module_usb_driver(i2c_tiny_usb_driver);
+
+/* ----- end of usb layer ------------------------------------------------ */
+
+MODULE_AUTHOR("Till Harbaum <Till@Harbaum.org>");
+MODULE_DESCRIPTION("i2c-tiny-usb driver v1.0");
+MODULE_LICENSE("GPL");
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-versatile.c b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-versatile.c
new file mode 100644
index 0000000..f585aea
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-versatile.c
@@ -0,0 +1,170 @@
+/*
+ *  i2c-versatile.c
+ *
+ *  Copyright (C) 2006 ARM Ltd.
+ *  written by Russell King, Deep Blue Solutions Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/of_i2c.h>
+
+#define I2C_CONTROL	0x00
+#define I2C_CONTROLS	0x00
+#define I2C_CONTROLC	0x04
+#define SCL		(1 << 0)
+#define SDA		(1 << 1)
+
+struct i2c_versatile {
+	struct i2c_adapter	 adap;
+	struct i2c_algo_bit_data algo;
+	void __iomem		 *base;
+};
+
+static void i2c_versatile_setsda(void *data, int state)
+{
+	struct i2c_versatile *i2c = data;
+
+	writel(SDA, i2c->base + (state ? I2C_CONTROLS : I2C_CONTROLC));
+}
+
+static void i2c_versatile_setscl(void *data, int state)
+{
+	struct i2c_versatile *i2c = data;
+
+	writel(SCL, i2c->base + (state ? I2C_CONTROLS : I2C_CONTROLC));
+}
+
+static int i2c_versatile_getsda(void *data)
+{
+	struct i2c_versatile *i2c = data;
+	return !!(readl(i2c->base + I2C_CONTROL) & SDA);
+}
+
+static int i2c_versatile_getscl(void *data)
+{
+	struct i2c_versatile *i2c = data;
+	return !!(readl(i2c->base + I2C_CONTROL) & SCL);
+}
+
+static struct i2c_algo_bit_data i2c_versatile_algo = {
+	.setsda	= i2c_versatile_setsda,
+	.setscl = i2c_versatile_setscl,
+	.getsda	= i2c_versatile_getsda,
+	.getscl = i2c_versatile_getscl,
+	.udelay	= 30,
+	.timeout = HZ,
+};
+
+static int i2c_versatile_probe(struct platform_device *dev)
+{
+	struct i2c_versatile *i2c;
+	struct resource *r;
+	int ret;
+
+	r = platform_get_resource(dev, IORESOURCE_MEM, 0);
+	if (!r) {
+		ret = -EINVAL;
+		goto err_out;
+	}
+
+	if (!request_mem_region(r->start, resource_size(r), "versatile-i2c")) {
+		ret = -EBUSY;
+		goto err_out;
+	}
+
+	i2c = kzalloc(sizeof(struct i2c_versatile), GFP_KERNEL);
+	if (!i2c) {
+		ret = -ENOMEM;
+		goto err_release;
+	}
+
+	i2c->base = ioremap(r->start, resource_size(r));
+	if (!i2c->base) {
+		ret = -ENOMEM;
+		goto err_free;
+	}
+
+	writel(SCL | SDA, i2c->base + I2C_CONTROLS);
+
+	i2c->adap.owner = THIS_MODULE;
+	strlcpy(i2c->adap.name, "Versatile I2C adapter", sizeof(i2c->adap.name));
+	i2c->adap.algo_data = &i2c->algo;
+	i2c->adap.dev.parent = &dev->dev;
+	i2c->adap.dev.of_node = dev->dev.of_node;
+	i2c->algo = i2c_versatile_algo;
+	i2c->algo.data = i2c;
+
+	if (dev->id >= 0) {
+		/* static bus numbering */
+		i2c->adap.nr = dev->id;
+		ret = i2c_bit_add_numbered_bus(&i2c->adap);
+	} else
+		/* dynamic bus numbering */
+		ret = i2c_bit_add_bus(&i2c->adap);
+	if (ret >= 0) {
+		platform_set_drvdata(dev, i2c);
+		of_i2c_register_devices(&i2c->adap);
+		return 0;
+	}
+
+	iounmap(i2c->base);
+ err_free:
+	kfree(i2c);
+ err_release:
+	release_mem_region(r->start, resource_size(r));
+ err_out:
+	return ret;
+}
+
+static int i2c_versatile_remove(struct platform_device *dev)
+{
+	struct i2c_versatile *i2c = platform_get_drvdata(dev);
+
+	platform_set_drvdata(dev, NULL);
+
+	i2c_del_adapter(&i2c->adap);
+	return 0;
+}
+
+static const struct of_device_id i2c_versatile_match[] = {
+	{ .compatible = "arm,versatile-i2c", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, i2c_versatile_match);
+
+static struct platform_driver i2c_versatile_driver = {
+	.probe		= i2c_versatile_probe,
+	.remove		= i2c_versatile_remove,
+	.driver		= {
+		.name	= "versatile-i2c",
+		.owner	= THIS_MODULE,
+		.of_match_table = i2c_versatile_match,
+	},
+};
+
+static int __init i2c_versatile_init(void)
+{
+	return platform_driver_register(&i2c_versatile_driver);
+}
+
+static void __exit i2c_versatile_exit(void)
+{
+	platform_driver_unregister(&i2c_versatile_driver);
+}
+
+subsys_initcall(i2c_versatile_init);
+module_exit(i2c_versatile_exit);
+
+MODULE_DESCRIPTION("ARM Versatile I2C bus driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:versatile-i2c");
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-via.c b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-via.c
new file mode 100644
index 0000000..713d31a
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-via.c
@@ -0,0 +1,180 @@
+/*
+    i2c Support for Via Technologies 82C586B South Bridge
+
+    Copyright (c) 1998, 1999 Kyösti Mälkki <kmalkki@cc.hut.fi>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <linux/io.h>
+
+/* Power management registers */
+#define PM_CFG_REVID	0x08	/* silicon revision code */
+#define PM_CFG_IOBASE0	0x20
+#define PM_CFG_IOBASE1	0x48
+
+#define I2C_DIR		(pm_io_base+0x40)
+#define I2C_OUT		(pm_io_base+0x42)
+#define I2C_IN		(pm_io_base+0x44)
+#define I2C_SCL		0x02	/* clock bit in DIR/OUT/IN register */
+#define I2C_SDA		0x04
+
+/* io-region reservation */
+#define IOSPACE		0x06
+
+static struct pci_driver vt586b_driver;
+static u16 pm_io_base;
+
+/*
+   It does not appear from the datasheet that the GPIO pins are
+   open drain. So a we set a low value by setting the direction to
+   output and a high value by setting the direction to input and
+   relying on the required I2C pullup. The data value is initialized
+   to 0 in via_init() and never changed.
+*/
+static void bit_via_setscl(void *data, int state)
+{
+	outb(state ? inb(I2C_DIR) & ~I2C_SCL : inb(I2C_DIR) | I2C_SCL, I2C_DIR);
+}
+
+static void bit_via_setsda(void *data, int state)
+{
+	outb(state ? inb(I2C_DIR) & ~I2C_SDA : inb(I2C_DIR) | I2C_SDA, I2C_DIR);
+}
+
+static int bit_via_getscl(void *data)
+{
+	return (0 != (inb(I2C_IN) & I2C_SCL));
+}
+
+static int bit_via_getsda(void *data)
+{
+	return (0 != (inb(I2C_IN) & I2C_SDA));
+}
+
+
+static struct i2c_algo_bit_data bit_data = {
+	.setsda		= bit_via_setsda,
+	.setscl		= bit_via_setscl,
+	.getsda		= bit_via_getsda,
+	.getscl		= bit_via_getscl,
+	.udelay		= 5,
+	.timeout	= HZ
+};
+
+static struct i2c_adapter vt586b_adapter = {
+	.owner		= THIS_MODULE,
+	.class          = I2C_CLASS_HWMON | I2C_CLASS_SPD,
+	.name		= "VIA i2c",
+	.algo_data	= &bit_data,
+};
+
+
+static DEFINE_PCI_DEVICE_TABLE(vt586b_ids) = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_3) },
+	{ 0, }
+};
+
+MODULE_DEVICE_TABLE (pci, vt586b_ids);
+
+static int __devinit vt586b_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	u16 base;
+	u8 rev;
+	int res;
+
+	if (pm_io_base) {
+		dev_err(&dev->dev, "i2c-via: Will only support one host\n");
+		return -ENODEV;
+	}
+
+	pci_read_config_byte(dev, PM_CFG_REVID, &rev);
+
+	switch (rev) {
+	case 0x00:
+		base = PM_CFG_IOBASE0;
+		break;
+	case 0x01:
+	case 0x10:
+		base = PM_CFG_IOBASE1;
+		break;
+
+	default:
+		base = PM_CFG_IOBASE1;
+		/* later revision */
+	}
+
+	pci_read_config_word(dev, base, &pm_io_base);
+	pm_io_base &= (0xff << 8);
+
+	if (!request_region(I2C_DIR, IOSPACE, vt586b_driver.name)) {
+		dev_err(&dev->dev, "IO 0x%x-0x%x already in use\n", I2C_DIR, I2C_DIR + IOSPACE);
+		return -ENODEV;
+	}
+
+	outb(inb(I2C_DIR) & ~(I2C_SDA | I2C_SCL), I2C_DIR);
+	outb(inb(I2C_OUT) & ~(I2C_SDA | I2C_SCL), I2C_OUT);
+
+	/* set up the sysfs linkage to our parent device */
+	vt586b_adapter.dev.parent = &dev->dev;
+
+	res = i2c_bit_add_bus(&vt586b_adapter);
+	if ( res < 0 ) {
+		release_region(I2C_DIR, IOSPACE);
+		pm_io_base = 0;
+		return res;
+	}
+	return 0;
+}
+
+static void __devexit vt586b_remove(struct pci_dev *dev)
+{
+	i2c_del_adapter(&vt586b_adapter);
+	release_region(I2C_DIR, IOSPACE);
+	pm_io_base = 0;
+}
+
+
+static struct pci_driver vt586b_driver = {
+	.name		= "vt586b_smbus",
+	.id_table	= vt586b_ids,
+	.probe		= vt586b_probe,
+	.remove		= __devexit_p(vt586b_remove),
+};
+
+static int __init i2c_vt586b_init(void)
+{
+	return pci_register_driver(&vt586b_driver);
+}
+
+static void __exit i2c_vt586b_exit(void)
+{
+	pci_unregister_driver(&vt586b_driver);
+}
+
+
+MODULE_AUTHOR("Kyösti Mälkki <kmalkki@cc.hut.fi>");
+MODULE_DESCRIPTION("i2c for Via vt82c586b southbridge");
+MODULE_LICENSE("GPL");
+
+module_init(i2c_vt586b_init);
+module_exit(i2c_vt586b_exit);
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-viapro.c b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-viapro.c
new file mode 100644
index 0000000..333011c
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-viapro.c
@@ -0,0 +1,508 @@
+/*
+    Copyright (c) 1998 - 2002  Frodo Looijaard <frodol@dds.nl>,
+    Philip Edelbrock <phil@netroedge.com>, Kyösti Mälkki <kmalkki@cc.hut.fi>,
+    Mark D. Studebaker <mdsxyz123@yahoo.com>
+    Copyright (C) 2005 - 2008  Jean Delvare <khali@linux-fr.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/*
+   Supports the following VIA south bridges:
+
+   Chip name          PCI ID  REV     I2C block
+   VT82C596A          0x3050             no
+   VT82C596B          0x3051             no
+   VT82C686A          0x3057  0x30       no
+   VT82C686B          0x3057  0x40       yes
+   VT8231             0x8235             no?
+   VT8233             0x3074             yes
+   VT8233A            0x3147             yes?
+   VT8235             0x3177             yes
+   VT8237R            0x3227             yes
+   VT8237A            0x3337             yes
+   VT8237S            0x3372             yes
+   VT8251             0x3287             yes
+   CX700              0x8324             yes
+   VX800/VX820        0x8353             yes
+   VX855/VX875        0x8409             yes
+
+   Note: we assume there can only be one device, with one SMBus interface.
+*/
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/stddef.h>
+#include <linux/ioport.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/acpi.h>
+#include <linux/io.h>
+
+static struct pci_dev *vt596_pdev;
+
+#define SMBBA1		0x90
+#define SMBBA2		0x80
+#define SMBBA3		0xD0
+
+/* SMBus address offsets */
+static unsigned short vt596_smba;
+#define SMBHSTSTS	(vt596_smba + 0)
+#define SMBHSTCNT	(vt596_smba + 2)
+#define SMBHSTCMD	(vt596_smba + 3)
+#define SMBHSTADD	(vt596_smba + 4)
+#define SMBHSTDAT0	(vt596_smba + 5)
+#define SMBHSTDAT1	(vt596_smba + 6)
+#define SMBBLKDAT	(vt596_smba + 7)
+
+/* PCI Address Constants */
+
+/* SMBus data in configuration space can be found in two places,
+   We try to select the better one */
+
+static unsigned short SMBHSTCFG = 0xD2;
+
+/* Other settings */
+#define MAX_TIMEOUT	500
+
+/* VT82C596 constants */
+#define VT596_QUICK		0x00
+#define VT596_BYTE		0x04
+#define VT596_BYTE_DATA		0x08
+#define VT596_WORD_DATA		0x0C
+#define VT596_PROC_CALL		0x10
+#define VT596_BLOCK_DATA	0x14
+#define VT596_I2C_BLOCK_DATA	0x34
+
+
+/* If force is set to anything different from 0, we forcibly enable the
+   VT596. DANGEROUS! */
+static bool force;
+module_param(force, bool, 0);
+MODULE_PARM_DESC(force, "Forcibly enable the SMBus. DANGEROUS!");
+
+/* If force_addr is set to anything different from 0, we forcibly enable
+   the VT596 at the given address. VERY DANGEROUS! */
+static u16 force_addr;
+module_param(force_addr, ushort, 0);
+MODULE_PARM_DESC(force_addr,
+		 "Forcibly enable the SMBus at the given address. "
+		 "EXTREMELY DANGEROUS!");
+
+
+static struct pci_driver vt596_driver;
+static struct i2c_adapter vt596_adapter;
+
+#define FEATURE_I2CBLOCK	(1<<0)
+static unsigned int vt596_features;
+
+#ifdef DEBUG
+static void vt596_dump_regs(const char *msg, u8 size)
+{
+	dev_dbg(&vt596_adapter.dev, "%s: STS=%02x CNT=%02x CMD=%02x ADD=%02x "
+		"DAT=%02x,%02x\n", msg, inb_p(SMBHSTSTS), inb_p(SMBHSTCNT),
+		inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0),
+		inb_p(SMBHSTDAT1));
+
+	if (size == VT596_BLOCK_DATA
+	 || size == VT596_I2C_BLOCK_DATA) {
+		int i;
+
+		dev_dbg(&vt596_adapter.dev, "BLK=");
+		for (i = 0; i < I2C_SMBUS_BLOCK_MAX / 2; i++)
+			printk("%02x,", inb_p(SMBBLKDAT));
+		printk("\n");
+		dev_dbg(&vt596_adapter.dev, "    ");
+		for (; i < I2C_SMBUS_BLOCK_MAX - 1; i++)
+			printk("%02x,", inb_p(SMBBLKDAT));
+		printk("%02x\n", inb_p(SMBBLKDAT));
+	}
+}
+#else
+static inline void vt596_dump_regs(const char *msg, u8 size) { }
+#endif
+
+/* Return -1 on error, 0 on success */
+static int vt596_transaction(u8 size)
+{
+	int temp;
+	int result = 0;
+	int timeout = 0;
+
+	vt596_dump_regs("Transaction (pre)", size);
+
+	/* Make sure the SMBus host is ready to start transmitting */
+	if ((temp = inb_p(SMBHSTSTS)) & 0x1F) {
+		dev_dbg(&vt596_adapter.dev, "SMBus busy (0x%02x). "
+			"Resetting...\n", temp);
+
+		outb_p(temp, SMBHSTSTS);
+		if ((temp = inb_p(SMBHSTSTS)) & 0x1F) {
+			dev_err(&vt596_adapter.dev, "SMBus reset failed! "
+				"(0x%02x)\n", temp);
+			return -EBUSY;
+		}
+	}
+
+	/* Start the transaction by setting bit 6 */
+	outb_p(0x40 | size, SMBHSTCNT);
+
+	/* We will always wait for a fraction of a second */
+	do {
+		msleep(1);
+		temp = inb_p(SMBHSTSTS);
+	} while ((temp & 0x01) && (++timeout < MAX_TIMEOUT));
+
+	/* If the SMBus is still busy, we give up */
+	if (timeout == MAX_TIMEOUT) {
+		result = -ETIMEDOUT;
+		dev_err(&vt596_adapter.dev, "SMBus timeout!\n");
+	}
+
+	if (temp & 0x10) {
+		result = -EIO;
+		dev_err(&vt596_adapter.dev, "Transaction failed (0x%02x)\n",
+			size);
+	}
+
+	if (temp & 0x08) {
+		result = -EIO;
+		dev_err(&vt596_adapter.dev, "SMBus collision!\n");
+	}
+
+	if (temp & 0x04) {
+		result = -ENXIO;
+		dev_dbg(&vt596_adapter.dev, "No response\n");
+	}
+
+	/* Resetting status register */
+	if (temp & 0x1F)
+		outb_p(temp, SMBHSTSTS);
+
+	vt596_dump_regs("Transaction (post)", size);
+
+	return result;
+}
+
+/* Return negative errno on error, 0 on success */
+static s32 vt596_access(struct i2c_adapter *adap, u16 addr,
+		unsigned short flags, char read_write, u8 command,
+		int size, union i2c_smbus_data *data)
+{
+	int i;
+	int status;
+
+	switch (size) {
+	case I2C_SMBUS_QUICK:
+		size = VT596_QUICK;
+		break;
+	case I2C_SMBUS_BYTE:
+		if (read_write == I2C_SMBUS_WRITE)
+			outb_p(command, SMBHSTCMD);
+		size = VT596_BYTE;
+		break;
+	case I2C_SMBUS_BYTE_DATA:
+		outb_p(command, SMBHSTCMD);
+		if (read_write == I2C_SMBUS_WRITE)
+			outb_p(data->byte, SMBHSTDAT0);
+		size = VT596_BYTE_DATA;
+		break;
+	case I2C_SMBUS_WORD_DATA:
+		outb_p(command, SMBHSTCMD);
+		if (read_write == I2C_SMBUS_WRITE) {
+			outb_p(data->word & 0xff, SMBHSTDAT0);
+			outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1);
+		}
+		size = VT596_WORD_DATA;
+		break;
+	case I2C_SMBUS_PROC_CALL:
+		outb_p(command, SMBHSTCMD);
+		outb_p(data->word & 0xff, SMBHSTDAT0);
+		outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1);
+		size = VT596_PROC_CALL;
+		break;
+	case I2C_SMBUS_I2C_BLOCK_DATA:
+		if (!(vt596_features & FEATURE_I2CBLOCK))
+			goto exit_unsupported;
+		if (read_write == I2C_SMBUS_READ)
+			outb_p(data->block[0], SMBHSTDAT0);
+		/* Fall through */
+	case I2C_SMBUS_BLOCK_DATA:
+		outb_p(command, SMBHSTCMD);
+		if (read_write == I2C_SMBUS_WRITE) {
+			u8 len = data->block[0];
+			if (len > I2C_SMBUS_BLOCK_MAX)
+				len = I2C_SMBUS_BLOCK_MAX;
+			outb_p(len, SMBHSTDAT0);
+			inb_p(SMBHSTCNT);	/* Reset SMBBLKDAT */
+			for (i = 1; i <= len; i++)
+				outb_p(data->block[i], SMBBLKDAT);
+		}
+		size = (size == I2C_SMBUS_I2C_BLOCK_DATA) ?
+		       VT596_I2C_BLOCK_DATA : VT596_BLOCK_DATA;
+		break;
+	default:
+		goto exit_unsupported;
+	}
+
+	outb_p(((addr & 0x7f) << 1) | read_write, SMBHSTADD);
+
+	status = vt596_transaction(size);
+	if (status)
+		return status;
+
+	if (size == VT596_PROC_CALL)
+		read_write = I2C_SMBUS_READ;
+
+	if ((read_write == I2C_SMBUS_WRITE) || (size == VT596_QUICK))
+		return 0;
+
+	switch (size) {
+	case VT596_BYTE:
+	case VT596_BYTE_DATA:
+		data->byte = inb_p(SMBHSTDAT0);
+		break;
+	case VT596_WORD_DATA:
+	case VT596_PROC_CALL:
+		data->word = inb_p(SMBHSTDAT0) + (inb_p(SMBHSTDAT1) << 8);
+		break;
+	case VT596_I2C_BLOCK_DATA:
+	case VT596_BLOCK_DATA:
+		data->block[0] = inb_p(SMBHSTDAT0);
+		if (data->block[0] > I2C_SMBUS_BLOCK_MAX)
+			data->block[0] = I2C_SMBUS_BLOCK_MAX;
+		inb_p(SMBHSTCNT);	/* Reset SMBBLKDAT */
+		for (i = 1; i <= data->block[0]; i++)
+			data->block[i] = inb_p(SMBBLKDAT);
+		break;
+	}
+	return 0;
+
+exit_unsupported:
+	dev_warn(&vt596_adapter.dev, "Unsupported transaction %d\n",
+		 size);
+	return -EOPNOTSUPP;
+}
+
+static u32 vt596_func(struct i2c_adapter *adapter)
+{
+	u32 func = I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+	    I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+	    I2C_SMBUS_PROC_CALL | I2C_FUNC_SMBUS_BLOCK_DATA;
+
+	if (vt596_features & FEATURE_I2CBLOCK)
+		func |= I2C_FUNC_SMBUS_I2C_BLOCK;
+	return func;
+}
+
+static const struct i2c_algorithm smbus_algorithm = {
+	.smbus_xfer	= vt596_access,
+	.functionality	= vt596_func,
+};
+
+static struct i2c_adapter vt596_adapter = {
+	.owner		= THIS_MODULE,
+	.class		= I2C_CLASS_HWMON | I2C_CLASS_SPD,
+	.algo		= &smbus_algorithm,
+};
+
+static int __devinit vt596_probe(struct pci_dev *pdev,
+				 const struct pci_device_id *id)
+{
+	unsigned char temp;
+	int error;
+
+	/* Determine the address of the SMBus areas */
+	if (force_addr) {
+		vt596_smba = force_addr & 0xfff0;
+		force = 0;
+		goto found;
+	}
+
+	if ((pci_read_config_word(pdev, id->driver_data, &vt596_smba)) ||
+	    !(vt596_smba & 0x0001)) {
+		/* try 2nd address and config reg. for 596 */
+		if (id->device == PCI_DEVICE_ID_VIA_82C596_3 &&
+		    !pci_read_config_word(pdev, SMBBA2, &vt596_smba) &&
+		    (vt596_smba & 0x0001)) {
+			SMBHSTCFG = 0x84;
+		} else {
+			/* no matches at all */
+			dev_err(&pdev->dev, "Cannot configure "
+				"SMBus I/O Base address\n");
+			return -ENODEV;
+		}
+	}
+
+	vt596_smba &= 0xfff0;
+	if (vt596_smba == 0) {
+		dev_err(&pdev->dev, "SMBus base address "
+			"uninitialized - upgrade BIOS or use "
+			"force_addr=0xaddr\n");
+		return -ENODEV;
+	}
+
+found:
+	error = acpi_check_region(vt596_smba, 8, vt596_driver.name);
+	if (error)
+		return -ENODEV;
+
+	if (!request_region(vt596_smba, 8, vt596_driver.name)) {
+		dev_err(&pdev->dev, "SMBus region 0x%x already in use!\n",
+			vt596_smba);
+		return -ENODEV;
+	}
+
+	pci_read_config_byte(pdev, SMBHSTCFG, &temp);
+	/* If force_addr is set, we program the new address here. Just to make
+	   sure, we disable the VT596 first. */
+	if (force_addr) {
+		pci_write_config_byte(pdev, SMBHSTCFG, temp & 0xfe);
+		pci_write_config_word(pdev, id->driver_data, vt596_smba);
+		pci_write_config_byte(pdev, SMBHSTCFG, temp | 0x01);
+		dev_warn(&pdev->dev, "WARNING: SMBus interface set to new "
+			 "address 0x%04x!\n", vt596_smba);
+	} else if (!(temp & 0x01)) {
+		if (force) {
+			/* NOTE: This assumes I/O space and other allocations
+			 * WERE done by the Bios!  Don't complain if your
+			 * hardware does weird things after enabling this.
+			 * :') Check for Bios updates before resorting to
+			 * this.
+			 */
+			pci_write_config_byte(pdev, SMBHSTCFG, temp | 0x01);
+			dev_info(&pdev->dev, "Enabling SMBus device\n");
+		} else {
+			dev_err(&pdev->dev, "SMBUS: Error: Host SMBus "
+				"controller not enabled! - upgrade BIOS or "
+				"use force=1\n");
+			error = -ENODEV;
+			goto release_region;
+		}
+	}
+
+	dev_dbg(&pdev->dev, "VT596_smba = 0x%X\n", vt596_smba);
+
+	switch (pdev->device) {
+	case PCI_DEVICE_ID_VIA_CX700:
+	case PCI_DEVICE_ID_VIA_VX800:
+	case PCI_DEVICE_ID_VIA_VX855:
+	case PCI_DEVICE_ID_VIA_8251:
+	case PCI_DEVICE_ID_VIA_8237:
+	case PCI_DEVICE_ID_VIA_8237A:
+	case PCI_DEVICE_ID_VIA_8237S:
+	case PCI_DEVICE_ID_VIA_8235:
+	case PCI_DEVICE_ID_VIA_8233A:
+	case PCI_DEVICE_ID_VIA_8233_0:
+		vt596_features |= FEATURE_I2CBLOCK;
+		break;
+	case PCI_DEVICE_ID_VIA_82C686_4:
+		/* The VT82C686B (rev 0x40) does support I2C block
+		   transactions, but the VT82C686A (rev 0x30) doesn't */
+		if (pdev->revision >= 0x40)
+			vt596_features |= FEATURE_I2CBLOCK;
+		break;
+	}
+
+	vt596_adapter.dev.parent = &pdev->dev;
+	snprintf(vt596_adapter.name, sizeof(vt596_adapter.name),
+		 "SMBus Via Pro adapter at %04x", vt596_smba);
+
+	vt596_pdev = pci_dev_get(pdev);
+	error = i2c_add_adapter(&vt596_adapter);
+	if (error) {
+		pci_dev_put(vt596_pdev);
+		vt596_pdev = NULL;
+		goto release_region;
+	}
+
+	/* Always return failure here.  This is to allow other drivers to bind
+	 * to this pci device.  We don't really want to have control over the
+	 * pci device, we only wanted to read as few register values from it.
+	 */
+	return -ENODEV;
+
+release_region:
+	release_region(vt596_smba, 8);
+	return error;
+}
+
+static DEFINE_PCI_DEVICE_TABLE(vt596_ids) = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C596_3),
+	  .driver_data = SMBBA1 },
+	{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C596B_3),
+	  .driver_data = SMBBA1 },
+	{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4),
+	  .driver_data = SMBBA1 },
+	{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8233_0),
+	  .driver_data = SMBBA3 },
+	{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8233A),
+	  .driver_data = SMBBA3 },
+	{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8235),
+	  .driver_data = SMBBA3 },
+	{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237),
+	  .driver_data = SMBBA3 },
+	{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237A),
+	  .driver_data = SMBBA3 },
+	{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237S),
+	  .driver_data = SMBBA3 },
+	{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8231_4),
+	  .driver_data = SMBBA1 },
+	{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8251),
+	  .driver_data = SMBBA3 },
+	{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_CX700),
+	  .driver_data = SMBBA3 },
+	{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VX800),
+	  .driver_data = SMBBA3 },
+	{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VX855),
+	  .driver_data = SMBBA3 },
+	{ 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, vt596_ids);
+
+static struct pci_driver vt596_driver = {
+	.name		= "vt596_smbus",
+	.id_table	= vt596_ids,
+	.probe		= vt596_probe,
+};
+
+static int __init i2c_vt596_init(void)
+{
+	return pci_register_driver(&vt596_driver);
+}
+
+
+static void __exit i2c_vt596_exit(void)
+{
+	pci_unregister_driver(&vt596_driver);
+	if (vt596_pdev != NULL) {
+		i2c_del_adapter(&vt596_adapter);
+		release_region(vt596_smba, 8);
+		pci_dev_put(vt596_pdev);
+		vt596_pdev = NULL;
+	}
+}
+
+MODULE_AUTHOR("Kyosti Malkki <kmalkki@cc.hut.fi>, "
+	      "Mark D. Studebaker <mdsxyz123@yahoo.com> and "
+	      "Jean Delvare <khali@linux-fr.org>");
+MODULE_DESCRIPTION("vt82c596 SMBus driver");
+MODULE_LICENSE("GPL");
+
+module_init(i2c_vt596_init);
+module_exit(i2c_vt596_exit);
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-xiic.c b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-xiic.c
new file mode 100644
index 0000000..d70106e
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-xiic.c
@@ -0,0 +1,810 @@
+/*
+ * i2c-xiic.c
+ * Copyright (c) 2002-2007 Xilinx Inc.
+ * Copyright (c) 2009-2010 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * This code was implemented by Mocean Laboratories AB when porting linux
+ * to the automotive development board Russellville. The copyright holder
+ * as seen in the header is Intel corporation.
+ * Mocean Laboratories forked off the GNU/Linux platform work into a
+ * separate company called Pelagicore AB, which committed the code to the
+ * kernel.
+ */
+
+/* Supports:
+ * Xilinx IIC
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/wait.h>
+#include <linux/i2c-xiic.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+
+#define DRIVER_NAME "xiic-i2c"
+
+enum xilinx_i2c_state {
+	STATE_DONE,
+	STATE_ERROR,
+	STATE_START
+};
+
+/**
+ * struct xiic_i2c - Internal representation of the XIIC I2C bus
+ * @base:	Memory base of the HW registers
+ * @wait:	Wait queue for callers
+ * @adap:	Kernel adapter representation
+ * @tx_msg:	Messages from above to be sent
+ * @lock:	Mutual exclusion
+ * @tx_pos:	Current pos in TX message
+ * @nmsgs:	Number of messages in tx_msg
+ * @state:	See STATE_
+ * @rx_msg:	Current RX message
+ * @rx_pos:	Position within current RX message
+ */
+struct xiic_i2c {
+	void __iomem		*base;
+	wait_queue_head_t	wait;
+	struct i2c_adapter	adap;
+	struct i2c_msg		*tx_msg;
+	spinlock_t		lock;
+	unsigned int 		tx_pos;
+	unsigned int		nmsgs;
+	enum xilinx_i2c_state	state;
+	struct i2c_msg		*rx_msg;
+	int			rx_pos;
+};
+
+
+#define XIIC_MSB_OFFSET 0
+#define XIIC_REG_OFFSET (0x100+XIIC_MSB_OFFSET)
+
+/*
+ * Register offsets in bytes from RegisterBase. Three is added to the
+ * base offset to access LSB (IBM style) of the word
+ */
+#define XIIC_CR_REG_OFFSET   (0x00+XIIC_REG_OFFSET)	/* Control Register   */
+#define XIIC_SR_REG_OFFSET   (0x04+XIIC_REG_OFFSET)	/* Status Register    */
+#define XIIC_DTR_REG_OFFSET  (0x08+XIIC_REG_OFFSET)	/* Data Tx Register   */
+#define XIIC_DRR_REG_OFFSET  (0x0C+XIIC_REG_OFFSET)	/* Data Rx Register   */
+#define XIIC_ADR_REG_OFFSET  (0x10+XIIC_REG_OFFSET)	/* Address Register   */
+#define XIIC_TFO_REG_OFFSET  (0x14+XIIC_REG_OFFSET)	/* Tx FIFO Occupancy  */
+#define XIIC_RFO_REG_OFFSET  (0x18+XIIC_REG_OFFSET)	/* Rx FIFO Occupancy  */
+#define XIIC_TBA_REG_OFFSET  (0x1C+XIIC_REG_OFFSET)	/* 10 Bit Address reg */
+#define XIIC_RFD_REG_OFFSET  (0x20+XIIC_REG_OFFSET)	/* Rx FIFO Depth reg  */
+#define XIIC_GPO_REG_OFFSET  (0x24+XIIC_REG_OFFSET)	/* Output Register    */
+
+/* Control Register masks */
+#define XIIC_CR_ENABLE_DEVICE_MASK        0x01	/* Device enable = 1      */
+#define XIIC_CR_TX_FIFO_RESET_MASK        0x02	/* Transmit FIFO reset=1  */
+#define XIIC_CR_MSMS_MASK                 0x04	/* Master starts Txing=1  */
+#define XIIC_CR_DIR_IS_TX_MASK            0x08	/* Dir of tx. Txing=1     */
+#define XIIC_CR_NO_ACK_MASK               0x10	/* Tx Ack. NO ack = 1     */
+#define XIIC_CR_REPEATED_START_MASK       0x20	/* Repeated start = 1     */
+#define XIIC_CR_GENERAL_CALL_MASK         0x40	/* Gen Call enabled = 1   */
+
+/* Status Register masks */
+#define XIIC_SR_GEN_CALL_MASK             0x01	/* 1=a mstr issued a GC   */
+#define XIIC_SR_ADDR_AS_SLAVE_MASK        0x02	/* 1=when addr as slave   */
+#define XIIC_SR_BUS_BUSY_MASK             0x04	/* 1 = bus is busy        */
+#define XIIC_SR_MSTR_RDING_SLAVE_MASK     0x08	/* 1=Dir: mstr <-- slave  */
+#define XIIC_SR_TX_FIFO_FULL_MASK         0x10	/* 1 = Tx FIFO full       */
+#define XIIC_SR_RX_FIFO_FULL_MASK         0x20	/* 1 = Rx FIFO full       */
+#define XIIC_SR_RX_FIFO_EMPTY_MASK        0x40	/* 1 = Rx FIFO empty      */
+#define XIIC_SR_TX_FIFO_EMPTY_MASK        0x80	/* 1 = Tx FIFO empty      */
+
+/* Interrupt Status Register masks    Interrupt occurs when...       */
+#define XIIC_INTR_ARB_LOST_MASK           0x01	/* 1 = arbitration lost   */
+#define XIIC_INTR_TX_ERROR_MASK           0x02	/* 1=Tx error/msg complete */
+#define XIIC_INTR_TX_EMPTY_MASK           0x04	/* 1 = Tx FIFO/reg empty  */
+#define XIIC_INTR_RX_FULL_MASK            0x08	/* 1=Rx FIFO/reg=OCY level */
+#define XIIC_INTR_BNB_MASK                0x10	/* 1 = Bus not busy       */
+#define XIIC_INTR_AAS_MASK                0x20	/* 1 = when addr as slave */
+#define XIIC_INTR_NAAS_MASK               0x40	/* 1 = not addr as slave  */
+#define XIIC_INTR_TX_HALF_MASK            0x80	/* 1 = TX FIFO half empty */
+
+/* The following constants specify the depth of the FIFOs */
+#define IIC_RX_FIFO_DEPTH         16	/* Rx fifo capacity               */
+#define IIC_TX_FIFO_DEPTH         16	/* Tx fifo capacity               */
+
+/* The following constants specify groups of interrupts that are typically
+ * enabled or disables at the same time
+ */
+#define XIIC_TX_INTERRUPTS                           \
+(XIIC_INTR_TX_ERROR_MASK | XIIC_INTR_TX_EMPTY_MASK | XIIC_INTR_TX_HALF_MASK)
+
+#define XIIC_TX_RX_INTERRUPTS (XIIC_INTR_RX_FULL_MASK | XIIC_TX_INTERRUPTS)
+
+/* The following constants are used with the following macros to specify the
+ * operation, a read or write operation.
+ */
+#define XIIC_READ_OPERATION  1
+#define XIIC_WRITE_OPERATION 0
+
+/*
+ * Tx Fifo upper bit masks.
+ */
+#define XIIC_TX_DYN_START_MASK            0x0100 /* 1 = Set dynamic start */
+#define XIIC_TX_DYN_STOP_MASK             0x0200 /* 1 = Set dynamic stop */
+
+/*
+ * The following constants define the register offsets for the Interrupt
+ * registers. There are some holes in the memory map for reserved addresses
+ * to allow other registers to be added and still match the memory map of the
+ * interrupt controller registers
+ */
+#define XIIC_DGIER_OFFSET    0x1C /* Device Global Interrupt Enable Register */
+#define XIIC_IISR_OFFSET     0x20 /* Interrupt Status Register */
+#define XIIC_IIER_OFFSET     0x28 /* Interrupt Enable Register */
+#define XIIC_RESETR_OFFSET   0x40 /* Reset Register */
+
+#define XIIC_RESET_MASK             0xAUL
+
+/*
+ * The following constant is used for the device global interrupt enable
+ * register, to enable all interrupts for the device, this is the only bit
+ * in the register
+ */
+#define XIIC_GINTR_ENABLE_MASK      0x80000000UL
+
+#define xiic_tx_space(i2c) ((i2c)->tx_msg->len - (i2c)->tx_pos)
+#define xiic_rx_space(i2c) ((i2c)->rx_msg->len - (i2c)->rx_pos)
+
+static void xiic_start_xfer(struct xiic_i2c *i2c);
+static void __xiic_start_xfer(struct xiic_i2c *i2c);
+
+static inline void xiic_setreg8(struct xiic_i2c *i2c, int reg, u8 value)
+{
+	iowrite8(value, i2c->base + reg);
+}
+
+static inline u8 xiic_getreg8(struct xiic_i2c *i2c, int reg)
+{
+	return ioread8(i2c->base + reg);
+}
+
+static inline void xiic_setreg16(struct xiic_i2c *i2c, int reg, u16 value)
+{
+	iowrite16(value, i2c->base + reg);
+}
+
+static inline void xiic_setreg32(struct xiic_i2c *i2c, int reg, int value)
+{
+	iowrite32(value, i2c->base + reg);
+}
+
+static inline int xiic_getreg32(struct xiic_i2c *i2c, int reg)
+{
+	return ioread32(i2c->base + reg);
+}
+
+static inline void xiic_irq_dis(struct xiic_i2c *i2c, u32 mask)
+{
+	u32 ier = xiic_getreg32(i2c, XIIC_IIER_OFFSET);
+	xiic_setreg32(i2c, XIIC_IIER_OFFSET, ier & ~mask);
+}
+
+static inline void xiic_irq_en(struct xiic_i2c *i2c, u32 mask)
+{
+	u32 ier = xiic_getreg32(i2c, XIIC_IIER_OFFSET);
+	xiic_setreg32(i2c, XIIC_IIER_OFFSET, ier | mask);
+}
+
+static inline void xiic_irq_clr(struct xiic_i2c *i2c, u32 mask)
+{
+	u32 isr = xiic_getreg32(i2c, XIIC_IISR_OFFSET);
+	xiic_setreg32(i2c, XIIC_IISR_OFFSET, isr & mask);
+}
+
+static inline void xiic_irq_clr_en(struct xiic_i2c *i2c, u32 mask)
+{
+	xiic_irq_clr(i2c, mask);
+	xiic_irq_en(i2c, mask);
+}
+
+static void xiic_clear_rx_fifo(struct xiic_i2c *i2c)
+{
+	u8 sr;
+	for (sr = xiic_getreg8(i2c, XIIC_SR_REG_OFFSET);
+		!(sr & XIIC_SR_RX_FIFO_EMPTY_MASK);
+		sr = xiic_getreg8(i2c, XIIC_SR_REG_OFFSET))
+		xiic_getreg8(i2c, XIIC_DRR_REG_OFFSET);
+}
+
+static void xiic_reinit(struct xiic_i2c *i2c)
+{
+	xiic_setreg32(i2c, XIIC_RESETR_OFFSET, XIIC_RESET_MASK);
+
+	/* Set receive Fifo depth to maximum (zero based). */
+	xiic_setreg8(i2c, XIIC_RFD_REG_OFFSET, IIC_RX_FIFO_DEPTH - 1);
+
+	/* Reset Tx Fifo. */
+	xiic_setreg8(i2c, XIIC_CR_REG_OFFSET, XIIC_CR_TX_FIFO_RESET_MASK);
+
+	/* Enable IIC Device, remove Tx Fifo reset & disable general call. */
+	xiic_setreg8(i2c, XIIC_CR_REG_OFFSET, XIIC_CR_ENABLE_DEVICE_MASK);
+
+	/* make sure RX fifo is empty */
+	xiic_clear_rx_fifo(i2c);
+
+	/* Enable interrupts */
+	xiic_setreg32(i2c, XIIC_DGIER_OFFSET, XIIC_GINTR_ENABLE_MASK);
+
+	xiic_irq_clr_en(i2c, XIIC_INTR_AAS_MASK | XIIC_INTR_ARB_LOST_MASK);
+}
+
+static void xiic_deinit(struct xiic_i2c *i2c)
+{
+	u8 cr;
+
+	xiic_setreg32(i2c, XIIC_RESETR_OFFSET, XIIC_RESET_MASK);
+
+	/* Disable IIC Device. */
+	cr = xiic_getreg8(i2c, XIIC_CR_REG_OFFSET);
+	xiic_setreg8(i2c, XIIC_CR_REG_OFFSET, cr & ~XIIC_CR_ENABLE_DEVICE_MASK);
+}
+
+static void xiic_read_rx(struct xiic_i2c *i2c)
+{
+	u8 bytes_in_fifo;
+	int i;
+
+	bytes_in_fifo = xiic_getreg8(i2c, XIIC_RFO_REG_OFFSET) + 1;
+
+	dev_dbg(i2c->adap.dev.parent, "%s entry, bytes in fifo: %d, msg: %d"
+		", SR: 0x%x, CR: 0x%x\n",
+		__func__, bytes_in_fifo, xiic_rx_space(i2c),
+		xiic_getreg8(i2c, XIIC_SR_REG_OFFSET),
+		xiic_getreg8(i2c, XIIC_CR_REG_OFFSET));
+
+	if (bytes_in_fifo > xiic_rx_space(i2c))
+		bytes_in_fifo = xiic_rx_space(i2c);
+
+	for (i = 0; i < bytes_in_fifo; i++)
+		i2c->rx_msg->buf[i2c->rx_pos++] =
+			xiic_getreg8(i2c, XIIC_DRR_REG_OFFSET);
+
+	xiic_setreg8(i2c, XIIC_RFD_REG_OFFSET,
+		(xiic_rx_space(i2c) > IIC_RX_FIFO_DEPTH) ?
+		IIC_RX_FIFO_DEPTH - 1 :  xiic_rx_space(i2c) - 1);
+}
+
+static int xiic_tx_fifo_space(struct xiic_i2c *i2c)
+{
+	/* return the actual space left in the FIFO */
+	return IIC_TX_FIFO_DEPTH - xiic_getreg8(i2c, XIIC_TFO_REG_OFFSET) - 1;
+}
+
+static void xiic_fill_tx_fifo(struct xiic_i2c *i2c)
+{
+	u8 fifo_space = xiic_tx_fifo_space(i2c);
+	int len = xiic_tx_space(i2c);
+
+	len = (len > fifo_space) ? fifo_space : len;
+
+	dev_dbg(i2c->adap.dev.parent, "%s entry, len: %d, fifo space: %d\n",
+		__func__, len, fifo_space);
+
+	while (len--) {
+		u16 data = i2c->tx_msg->buf[i2c->tx_pos++];
+		if ((xiic_tx_space(i2c) == 0) && (i2c->nmsgs == 1)) {
+			/* last message in transfer -> STOP */
+			data |= XIIC_TX_DYN_STOP_MASK;
+			dev_dbg(i2c->adap.dev.parent, "%s TX STOP\n", __func__);
+		}
+		xiic_setreg16(i2c, XIIC_DTR_REG_OFFSET, data);
+	}
+}
+
+static void xiic_wakeup(struct xiic_i2c *i2c, int code)
+{
+	i2c->tx_msg = NULL;
+	i2c->rx_msg = NULL;
+	i2c->nmsgs = 0;
+	i2c->state = code;
+	wake_up(&i2c->wait);
+}
+
+static void xiic_process(struct xiic_i2c *i2c)
+{
+	u32 pend, isr, ier;
+	u32 clr = 0;
+
+	/* Get the interrupt Status from the IPIF. There is no clearing of
+	 * interrupts in the IPIF. Interrupts must be cleared at the source.
+	 * To find which interrupts are pending; AND interrupts pending with
+	 * interrupts masked.
+	 */
+	isr = xiic_getreg32(i2c, XIIC_IISR_OFFSET);
+	ier = xiic_getreg32(i2c, XIIC_IIER_OFFSET);
+	pend = isr & ier;
+
+	dev_dbg(i2c->adap.dev.parent, "%s entry, IER: 0x%x, ISR: 0x%x, "
+		"pend: 0x%x, SR: 0x%x, msg: %p, nmsgs: %d\n",
+		__func__, ier, isr, pend, xiic_getreg8(i2c, XIIC_SR_REG_OFFSET),
+		i2c->tx_msg, i2c->nmsgs);
+
+	/* Do not processes a devices interrupts if the device has no
+	 * interrupts pending
+	 */
+	if (!pend)
+		return;
+
+	/* Service requesting interrupt */
+	if ((pend & XIIC_INTR_ARB_LOST_MASK) ||
+		((pend & XIIC_INTR_TX_ERROR_MASK) &&
+		!(pend & XIIC_INTR_RX_FULL_MASK))) {
+		/* bus arbritration lost, or...
+		 * Transmit error _OR_ RX completed
+		 * if this happens when RX_FULL is not set
+		 * this is probably a TX error
+		 */
+
+		dev_dbg(i2c->adap.dev.parent, "%s error\n", __func__);
+
+		/* dynamic mode seem to suffer from problems if we just flushes
+		 * fifos and the next message is a TX with len 0 (only addr)
+		 * reset the IP instead of just flush fifos
+		 */
+		xiic_reinit(i2c);
+
+		if (i2c->tx_msg)
+			xiic_wakeup(i2c, STATE_ERROR);
+
+	} else if (pend & XIIC_INTR_RX_FULL_MASK) {
+		/* Receive register/FIFO is full */
+
+		clr = XIIC_INTR_RX_FULL_MASK;
+		if (!i2c->rx_msg) {
+			dev_dbg(i2c->adap.dev.parent,
+				"%s unexpexted RX IRQ\n", __func__);
+			xiic_clear_rx_fifo(i2c);
+			goto out;
+		}
+
+		xiic_read_rx(i2c);
+		if (xiic_rx_space(i2c) == 0) {
+			/* this is the last part of the message */
+			i2c->rx_msg = NULL;
+
+			/* also clear TX error if there (RX complete) */
+			clr |= (isr & XIIC_INTR_TX_ERROR_MASK);
+
+			dev_dbg(i2c->adap.dev.parent,
+				"%s end of message, nmsgs: %d\n",
+				__func__, i2c->nmsgs);
+
+			/* send next message if this wasn't the last,
+			 * otherwise the transfer will be finialise when
+			 * receiving the bus not busy interrupt
+			 */
+			if (i2c->nmsgs > 1) {
+				i2c->nmsgs--;
+				i2c->tx_msg++;
+				dev_dbg(i2c->adap.dev.parent,
+					"%s will start next...\n", __func__);
+
+				__xiic_start_xfer(i2c);
+			}
+		}
+	} else if (pend & XIIC_INTR_BNB_MASK) {
+		/* IIC bus has transitioned to not busy */
+		clr = XIIC_INTR_BNB_MASK;
+
+		/* The bus is not busy, disable BusNotBusy interrupt */
+		xiic_irq_dis(i2c, XIIC_INTR_BNB_MASK);
+
+		if (!i2c->tx_msg)
+			goto out;
+
+		if ((i2c->nmsgs == 1) && !i2c->rx_msg &&
+			xiic_tx_space(i2c) == 0)
+			xiic_wakeup(i2c, STATE_DONE);
+		else
+			xiic_wakeup(i2c, STATE_ERROR);
+
+	} else if (pend & (XIIC_INTR_TX_EMPTY_MASK | XIIC_INTR_TX_HALF_MASK)) {
+		/* Transmit register/FIFO is empty or ½ empty */
+
+		clr = pend &
+			(XIIC_INTR_TX_EMPTY_MASK | XIIC_INTR_TX_HALF_MASK);
+
+		if (!i2c->tx_msg) {
+			dev_dbg(i2c->adap.dev.parent,
+				"%s unexpexted TX IRQ\n", __func__);
+			goto out;
+		}
+
+		xiic_fill_tx_fifo(i2c);
+
+		/* current message sent and there is space in the fifo */
+		if (!xiic_tx_space(i2c) && xiic_tx_fifo_space(i2c) >= 2) {
+			dev_dbg(i2c->adap.dev.parent,
+				"%s end of message sent, nmsgs: %d\n",
+				__func__, i2c->nmsgs);
+			if (i2c->nmsgs > 1) {
+				i2c->nmsgs--;
+				i2c->tx_msg++;
+				__xiic_start_xfer(i2c);
+			} else {
+				xiic_irq_dis(i2c, XIIC_INTR_TX_HALF_MASK);
+
+				dev_dbg(i2c->adap.dev.parent,
+					"%s Got TX IRQ but no more to do...\n",
+					__func__);
+			}
+		} else if (!xiic_tx_space(i2c) && (i2c->nmsgs == 1))
+			/* current frame is sent and is last,
+			 * make sure to disable tx half
+			 */
+			xiic_irq_dis(i2c, XIIC_INTR_TX_HALF_MASK);
+	} else {
+		/* got IRQ which is not acked */
+		dev_err(i2c->adap.dev.parent, "%s Got unexpected IRQ\n",
+			__func__);
+		clr = pend;
+	}
+out:
+	dev_dbg(i2c->adap.dev.parent, "%s clr: 0x%x\n", __func__, clr);
+
+	xiic_setreg32(i2c, XIIC_IISR_OFFSET, clr);
+}
+
+static int xiic_bus_busy(struct xiic_i2c *i2c)
+{
+	u8 sr = xiic_getreg8(i2c, XIIC_SR_REG_OFFSET);
+
+	return (sr & XIIC_SR_BUS_BUSY_MASK) ? -EBUSY : 0;
+}
+
+static int xiic_busy(struct xiic_i2c *i2c)
+{
+	int tries = 3;
+	int err;
+
+	if (i2c->tx_msg)
+		return -EBUSY;
+
+	/* for instance if previous transfer was terminated due to TX error
+	 * it might be that the bus is on it's way to become available
+	 * give it at most 3 ms to wake
+	 */
+	err = xiic_bus_busy(i2c);
+	while (err && tries--) {
+		mdelay(1);
+		err = xiic_bus_busy(i2c);
+	}
+
+	return err;
+}
+
+static void xiic_start_recv(struct xiic_i2c *i2c)
+{
+	u8 rx_watermark;
+	struct i2c_msg *msg = i2c->rx_msg = i2c->tx_msg;
+
+	/* Clear and enable Rx full interrupt. */
+	xiic_irq_clr_en(i2c, XIIC_INTR_RX_FULL_MASK | XIIC_INTR_TX_ERROR_MASK);
+
+	/* we want to get all but last byte, because the TX_ERROR IRQ is used
+	 * to inidicate error ACK on the address, and negative ack on the last
+	 * received byte, so to not mix them receive all but last.
+	 * In the case where there is only one byte to receive
+	 * we can check if ERROR and RX full is set at the same time
+	 */
+	rx_watermark = msg->len;
+	if (rx_watermark > IIC_RX_FIFO_DEPTH)
+		rx_watermark = IIC_RX_FIFO_DEPTH;
+	xiic_setreg8(i2c, XIIC_RFD_REG_OFFSET, rx_watermark - 1);
+
+	if (!(msg->flags & I2C_M_NOSTART))
+		/* write the address */
+		xiic_setreg16(i2c, XIIC_DTR_REG_OFFSET,
+			(msg->addr << 1) | XIIC_READ_OPERATION |
+			XIIC_TX_DYN_START_MASK);
+
+	xiic_irq_clr_en(i2c, XIIC_INTR_BNB_MASK);
+
+	xiic_setreg16(i2c, XIIC_DTR_REG_OFFSET,
+		msg->len | ((i2c->nmsgs == 1) ? XIIC_TX_DYN_STOP_MASK : 0));
+	if (i2c->nmsgs == 1)
+		/* very last, enable bus not busy as well */
+		xiic_irq_clr_en(i2c, XIIC_INTR_BNB_MASK);
+
+	/* the message is tx:ed */
+	i2c->tx_pos = msg->len;
+}
+
+static void xiic_start_send(struct xiic_i2c *i2c)
+{
+	struct i2c_msg *msg = i2c->tx_msg;
+
+	xiic_irq_clr(i2c, XIIC_INTR_TX_ERROR_MASK);
+
+	dev_dbg(i2c->adap.dev.parent, "%s entry, msg: %p, len: %d, "
+		"ISR: 0x%x, CR: 0x%x\n",
+		__func__, msg, msg->len, xiic_getreg32(i2c, XIIC_IISR_OFFSET),
+		xiic_getreg8(i2c, XIIC_CR_REG_OFFSET));
+
+	if (!(msg->flags & I2C_M_NOSTART)) {
+		/* write the address */
+		u16 data = ((msg->addr << 1) & 0xfe) | XIIC_WRITE_OPERATION |
+			XIIC_TX_DYN_START_MASK;
+		if ((i2c->nmsgs == 1) && msg->len == 0)
+			/* no data and last message -> add STOP */
+			data |= XIIC_TX_DYN_STOP_MASK;
+
+		xiic_setreg16(i2c, XIIC_DTR_REG_OFFSET, data);
+	}
+
+	xiic_fill_tx_fifo(i2c);
+
+	/* Clear any pending Tx empty, Tx Error and then enable them. */
+	xiic_irq_clr_en(i2c, XIIC_INTR_TX_EMPTY_MASK | XIIC_INTR_TX_ERROR_MASK |
+		XIIC_INTR_BNB_MASK);
+}
+
+static irqreturn_t xiic_isr(int irq, void *dev_id)
+{
+	struct xiic_i2c *i2c = dev_id;
+
+	spin_lock(&i2c->lock);
+	/* disable interrupts globally */
+	xiic_setreg32(i2c, XIIC_DGIER_OFFSET, 0);
+
+	dev_dbg(i2c->adap.dev.parent, "%s entry\n", __func__);
+
+	xiic_process(i2c);
+
+	xiic_setreg32(i2c, XIIC_DGIER_OFFSET, XIIC_GINTR_ENABLE_MASK);
+	spin_unlock(&i2c->lock);
+
+	return IRQ_HANDLED;
+}
+
+static void __xiic_start_xfer(struct xiic_i2c *i2c)
+{
+	int first = 1;
+	int fifo_space = xiic_tx_fifo_space(i2c);
+	dev_dbg(i2c->adap.dev.parent, "%s entry, msg: %p, fifos space: %d\n",
+		__func__, i2c->tx_msg, fifo_space);
+
+	if (!i2c->tx_msg)
+		return;
+
+	i2c->rx_pos = 0;
+	i2c->tx_pos = 0;
+	i2c->state = STATE_START;
+	while ((fifo_space >= 2) && (first || (i2c->nmsgs > 1))) {
+		if (!first) {
+			i2c->nmsgs--;
+			i2c->tx_msg++;
+			i2c->tx_pos = 0;
+		} else
+			first = 0;
+
+		if (i2c->tx_msg->flags & I2C_M_RD) {
+			/* we dont date putting several reads in the FIFO */
+			xiic_start_recv(i2c);
+			return;
+		} else {
+			xiic_start_send(i2c);
+			if (xiic_tx_space(i2c) != 0) {
+				/* the message could not be completely sent */
+				break;
+			}
+		}
+
+		fifo_space = xiic_tx_fifo_space(i2c);
+	}
+
+	/* there are more messages or the current one could not be completely
+	 * put into the FIFO, also enable the half empty interrupt
+	 */
+	if (i2c->nmsgs > 1 || xiic_tx_space(i2c))
+		xiic_irq_clr_en(i2c, XIIC_INTR_TX_HALF_MASK);
+
+}
+
+static void xiic_start_xfer(struct xiic_i2c *i2c)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&i2c->lock, flags);
+	xiic_reinit(i2c);
+	/* disable interrupts globally */
+	xiic_setreg32(i2c, XIIC_DGIER_OFFSET, 0);
+	spin_unlock_irqrestore(&i2c->lock, flags);
+
+	__xiic_start_xfer(i2c);
+	xiic_setreg32(i2c, XIIC_DGIER_OFFSET, XIIC_GINTR_ENABLE_MASK);
+}
+
+static int xiic_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+{
+	struct xiic_i2c *i2c = i2c_get_adapdata(adap);
+	int err;
+
+	dev_dbg(adap->dev.parent, "%s entry SR: 0x%x\n", __func__,
+		xiic_getreg8(i2c, XIIC_SR_REG_OFFSET));
+
+	err = xiic_busy(i2c);
+	if (err)
+		return err;
+
+	i2c->tx_msg = msgs;
+	i2c->nmsgs = num;
+
+	xiic_start_xfer(i2c);
+
+	if (wait_event_timeout(i2c->wait, (i2c->state == STATE_ERROR) ||
+		(i2c->state == STATE_DONE), HZ))
+		return (i2c->state == STATE_DONE) ? num : -EIO;
+	else {
+		i2c->tx_msg = NULL;
+		i2c->rx_msg = NULL;
+		i2c->nmsgs = 0;
+		return -ETIMEDOUT;
+	}
+}
+
+static u32 xiic_func(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm xiic_algorithm = {
+	.master_xfer	= xiic_xfer,
+	.functionality	= xiic_func,
+};
+
+static struct i2c_adapter xiic_adapter = {
+	.owner		= THIS_MODULE,
+	.name		= DRIVER_NAME,
+	.class		= I2C_CLASS_HWMON | I2C_CLASS_SPD,
+	.algo		= &xiic_algorithm,
+};
+
+
+static int __devinit xiic_i2c_probe(struct platform_device *pdev)
+{
+	struct xiic_i2c *i2c;
+	struct xiic_i2c_platform_data *pdata;
+	struct resource *res;
+	int ret, irq;
+	u8 i;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		goto resource_missing;
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0)
+		goto resource_missing;
+
+	pdata = (struct xiic_i2c_platform_data *) pdev->dev.platform_data;
+	if (!pdata)
+		return -EINVAL;
+
+	i2c = kzalloc(sizeof(*i2c), GFP_KERNEL);
+	if (!i2c)
+		return -ENOMEM;
+
+	if (!request_mem_region(res->start, resource_size(res), pdev->name)) {
+		dev_err(&pdev->dev, "Memory region busy\n");
+		ret = -EBUSY;
+		goto request_mem_failed;
+	}
+
+	i2c->base = ioremap(res->start, resource_size(res));
+	if (!i2c->base) {
+		dev_err(&pdev->dev, "Unable to map registers\n");
+		ret = -EIO;
+		goto map_failed;
+	}
+
+	/* hook up driver to tree */
+	platform_set_drvdata(pdev, i2c);
+	i2c->adap = xiic_adapter;
+	i2c_set_adapdata(&i2c->adap, i2c);
+	i2c->adap.dev.parent = &pdev->dev;
+
+	xiic_reinit(i2c);
+
+	spin_lock_init(&i2c->lock);
+	init_waitqueue_head(&i2c->wait);
+	ret = request_irq(irq, xiic_isr, 0, pdev->name, i2c);
+	if (ret) {
+		dev_err(&pdev->dev, "Cannot claim IRQ\n");
+		goto request_irq_failed;
+	}
+
+	/* add i2c adapter to i2c tree */
+	ret = i2c_add_adapter(&i2c->adap);
+	if (ret) {
+		dev_err(&pdev->dev, "Failed to add adapter\n");
+		goto add_adapter_failed;
+	}
+
+	/* add in known devices to the bus */
+	for (i = 0; i < pdata->num_devices; i++)
+		i2c_new_device(&i2c->adap, pdata->devices + i);
+
+	return 0;
+
+add_adapter_failed:
+	free_irq(irq, i2c);
+request_irq_failed:
+	xiic_deinit(i2c);
+	iounmap(i2c->base);
+map_failed:
+	release_mem_region(res->start, resource_size(res));
+request_mem_failed:
+	kfree(i2c);
+
+	return ret;
+resource_missing:
+	dev_err(&pdev->dev, "IRQ or Memory resource is missing\n");
+	return -ENOENT;
+}
+
+static int __devexit xiic_i2c_remove(struct platform_device* pdev)
+{
+	struct xiic_i2c *i2c = platform_get_drvdata(pdev);
+	struct resource *res;
+
+	/* remove adapter & data */
+	i2c_del_adapter(&i2c->adap);
+
+	xiic_deinit(i2c);
+
+	platform_set_drvdata(pdev, NULL);
+
+	free_irq(platform_get_irq(pdev, 0), i2c);
+
+	iounmap(i2c->base);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (res)
+		release_mem_region(res->start, resource_size(res));
+
+	kfree(i2c);
+
+	return 0;
+}
+
+static struct platform_driver xiic_i2c_driver = {
+	.probe   = xiic_i2c_probe,
+	.remove  = __devexit_p(xiic_i2c_remove),
+	.driver  = {
+		.owner = THIS_MODULE,
+		.name = DRIVER_NAME,
+	},
+};
+
+module_platform_driver(xiic_i2c_driver);
+
+MODULE_AUTHOR("info@mocean-labs.com");
+MODULE_DESCRIPTION("Xilinx I2C bus driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:"DRIVER_NAME);
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-xlr.c b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-xlr.c
new file mode 100644
index 0000000..96d3fab
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-xlr.c
@@ -0,0 +1,278 @@
+/*
+ * Copyright 2011, Netlogic Microsystems Inc.
+ * Copyright 2004, Matt Porter <mporter@kernel.crashing.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/i2c.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+
+/* XLR I2C REGISTERS */
+#define XLR_I2C_CFG		0x00
+#define XLR_I2C_CLKDIV		0x01
+#define XLR_I2C_DEVADDR		0x02
+#define XLR_I2C_ADDR		0x03
+#define XLR_I2C_DATAOUT		0x04
+#define XLR_I2C_DATAIN		0x05
+#define XLR_I2C_STATUS		0x06
+#define XLR_I2C_STARTXFR	0x07
+#define XLR_I2C_BYTECNT		0x08
+#define XLR_I2C_HDSTATIM	0x09
+
+/* XLR I2C REGISTERS FLAGS */
+#define XLR_I2C_BUS_BUSY	0x01
+#define XLR_I2C_SDOEMPTY	0x02
+#define XLR_I2C_RXRDY		0x04
+#define XLR_I2C_ACK_ERR		0x08
+#define XLR_I2C_ARB_STARTERR	0x30
+
+/* Register Values */
+#define XLR_I2C_CFG_ADDR	0xF8
+#define XLR_I2C_CFG_NOADDR	0xFA
+#define XLR_I2C_STARTXFR_ND	0x02    /* No Data */
+#define XLR_I2C_STARTXFR_RD	0x01    /* Read */
+#define XLR_I2C_STARTXFR_WR	0x00    /* Write */
+
+#define XLR_I2C_TIMEOUT		10	/* timeout per byte in msec */
+
+/*
+ * On XLR/XLS, we need to use __raw_ IO to read the I2C registers
+ * because they are in the big-endian MMIO area on the SoC.
+ *
+ * The readl/writel implementation on XLR/XLS byteswaps, because
+ * those are for its little-endian PCI space (see arch/mips/Kconfig).
+ */
+static inline void xlr_i2c_wreg(u32 __iomem *base, unsigned int reg, u32 val)
+{
+	__raw_writel(val, base + reg);
+}
+
+static inline u32 xlr_i2c_rdreg(u32 __iomem *base, unsigned int reg)
+{
+	return __raw_readl(base + reg);
+}
+
+struct xlr_i2c_private {
+	struct i2c_adapter adap;
+	u32 __iomem *iobase;
+};
+
+static int xlr_i2c_tx(struct xlr_i2c_private *priv,  u16 len,
+	u8 *buf, u16 addr)
+{
+	struct i2c_adapter *adap = &priv->adap;
+	unsigned long timeout, stoptime, checktime;
+	u32 i2c_status;
+	int pos, timedout;
+	u8 offset, byte;
+
+	offset = buf[0];
+	xlr_i2c_wreg(priv->iobase, XLR_I2C_ADDR, offset);
+	xlr_i2c_wreg(priv->iobase, XLR_I2C_DEVADDR, addr);
+	xlr_i2c_wreg(priv->iobase, XLR_I2C_CFG, XLR_I2C_CFG_ADDR);
+	xlr_i2c_wreg(priv->iobase, XLR_I2C_BYTECNT, len - 1);
+
+	timeout = msecs_to_jiffies(XLR_I2C_TIMEOUT);
+	stoptime = jiffies + timeout;
+	timedout = 0;
+	pos = 1;
+retry:
+	if (len == 1) {
+		xlr_i2c_wreg(priv->iobase, XLR_I2C_STARTXFR,
+				XLR_I2C_STARTXFR_ND);
+	} else {
+		xlr_i2c_wreg(priv->iobase, XLR_I2C_DATAOUT, buf[pos]);
+		xlr_i2c_wreg(priv->iobase, XLR_I2C_STARTXFR,
+				XLR_I2C_STARTXFR_WR);
+	}
+
+	while (!timedout) {
+		checktime = jiffies;
+		i2c_status = xlr_i2c_rdreg(priv->iobase, XLR_I2C_STATUS);
+
+		if (i2c_status & XLR_I2C_SDOEMPTY) {
+			pos++;
+			/* need to do a empty dataout after the last byte */
+			byte = (pos < len) ? buf[pos] : 0;
+			xlr_i2c_wreg(priv->iobase, XLR_I2C_DATAOUT, byte);
+
+			/* reset timeout on successful xmit */
+			stoptime = jiffies + timeout;
+		}
+		timedout = time_after(checktime, stoptime);
+
+		if (i2c_status & XLR_I2C_ARB_STARTERR) {
+			if (timedout)
+				break;
+			goto retry;
+		}
+
+		if (i2c_status & XLR_I2C_ACK_ERR)
+			return -EIO;
+
+		if ((i2c_status & XLR_I2C_BUS_BUSY) == 0 && pos >= len)
+			return 0;
+	}
+	dev_err(&adap->dev, "I2C transmit timeout\n");
+	return -ETIMEDOUT;
+}
+
+static int xlr_i2c_rx(struct xlr_i2c_private *priv, u16 len, u8 *buf, u16 addr)
+{
+	struct i2c_adapter *adap = &priv->adap;
+	u32 i2c_status;
+	unsigned long timeout, stoptime, checktime;
+	int nbytes, timedout;
+	u8 byte;
+
+	xlr_i2c_wreg(priv->iobase, XLR_I2C_CFG, XLR_I2C_CFG_NOADDR);
+	xlr_i2c_wreg(priv->iobase, XLR_I2C_BYTECNT, len);
+	xlr_i2c_wreg(priv->iobase, XLR_I2C_DEVADDR, addr);
+
+	timeout = msecs_to_jiffies(XLR_I2C_TIMEOUT);
+	stoptime = jiffies + timeout;
+	timedout = 0;
+	nbytes = 0;
+retry:
+	xlr_i2c_wreg(priv->iobase, XLR_I2C_STARTXFR, XLR_I2C_STARTXFR_RD);
+
+	while (!timedout) {
+		checktime = jiffies;
+		i2c_status = xlr_i2c_rdreg(priv->iobase, XLR_I2C_STATUS);
+		if (i2c_status & XLR_I2C_RXRDY) {
+			if (nbytes > len)
+				return -EIO;	/* should not happen */
+
+			/* we need to do a dummy datain when nbytes == len */
+			byte = xlr_i2c_rdreg(priv->iobase, XLR_I2C_DATAIN);
+			if (nbytes < len)
+				buf[nbytes] = byte;
+			nbytes++;
+
+			/* reset timeout on successful read */
+			stoptime = jiffies + timeout;
+		}
+
+		timedout = time_after(checktime, stoptime);
+		if (i2c_status & XLR_I2C_ARB_STARTERR) {
+			if (timedout)
+				break;
+			goto retry;
+		}
+
+		if (i2c_status & XLR_I2C_ACK_ERR)
+			return -EIO;
+
+		if ((i2c_status & XLR_I2C_BUS_BUSY) == 0)
+			return 0;
+	}
+
+	dev_err(&adap->dev, "I2C receive timeout\n");
+	return -ETIMEDOUT;
+}
+
+static int xlr_i2c_xfer(struct i2c_adapter *adap,
+	struct i2c_msg *msgs, int num)
+{
+	struct i2c_msg *msg;
+	int i;
+	int ret = 0;
+	struct xlr_i2c_private *priv = i2c_get_adapdata(adap);
+
+	for (i = 0; ret == 0 && i < num; i++) {
+		msg = &msgs[i];
+		if (msg->flags & I2C_M_RD)
+			ret = xlr_i2c_rx(priv, msg->len, &msg->buf[0],
+					msg->addr);
+		else
+			ret = xlr_i2c_tx(priv, msg->len, &msg->buf[0],
+					msg->addr);
+	}
+
+	return (ret != 0) ? ret : num;
+}
+
+static u32 xlr_func(struct i2c_adapter *adap)
+{
+	/* Emulate SMBUS over I2C */
+	return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm xlr_i2c_algo = {
+	.master_xfer	= xlr_i2c_xfer,
+	.functionality	= xlr_func,
+};
+
+static int __devinit xlr_i2c_probe(struct platform_device *pdev)
+{
+	struct xlr_i2c_private  *priv;
+	struct resource *res;
+	int ret;
+
+	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	priv->iobase = devm_request_and_ioremap(&pdev->dev, res);
+	if (!priv->iobase) {
+		dev_err(&pdev->dev, "devm_request_and_ioremap failed\n");
+		return -EBUSY;
+	}
+
+	priv->adap.dev.parent = &pdev->dev;
+	priv->adap.owner	= THIS_MODULE;
+	priv->adap.algo_data	= priv;
+	priv->adap.algo		= &xlr_i2c_algo;
+	priv->adap.nr		= pdev->id;
+	priv->adap.class	= I2C_CLASS_HWMON;
+	snprintf(priv->adap.name, sizeof(priv->adap.name), "xlr-i2c");
+
+	i2c_set_adapdata(&priv->adap, priv);
+	ret = i2c_add_numbered_adapter(&priv->adap);
+	if (ret < 0) {
+		dev_err(&priv->adap.dev, "Failed to add i2c bus.\n");
+		return ret;
+	}
+
+	platform_set_drvdata(pdev, priv);
+	dev_info(&priv->adap.dev, "Added I2C Bus.\n");
+	return 0;
+}
+
+static int __devexit xlr_i2c_remove(struct platform_device *pdev)
+{
+	struct xlr_i2c_private *priv;
+
+	priv = platform_get_drvdata(pdev);
+	i2c_del_adapter(&priv->adap);
+	platform_set_drvdata(pdev, NULL);
+	return 0;
+}
+
+static struct platform_driver xlr_i2c_driver = {
+	.probe  = xlr_i2c_probe,
+	.remove = __devexit_p(xlr_i2c_remove),
+	.driver = {
+		.name   = "xlr-i2cbus",
+		.owner  = THIS_MODULE,
+	},
+};
+
+module_platform_driver(xlr_i2c_driver);
+
+MODULE_AUTHOR("Ganesan Ramalingam <ganesanr@netlogicmicro.com>");
+MODULE_DESCRIPTION("XLR/XLS SoC I2C Controller driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:xlr-i2cbus");
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-zx29-noirq.c b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-zx29-noirq.c
new file mode 100644
index 0000000..e70e91a
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-zx29-noirq.c
@@ -0,0 +1,195 @@
+#include <linux/kernel.h>

+#include <linux/module.h>

+

+#include <linux/i2c.h>

+#include <linux/init.h>

+#include <linux/time.h>

+#include <linux/interrupt.h>

+#include <linux/delay.h>

+#include <linux/errno.h>

+#include <linux/err.h>

+#include <linux/platform_device.h>

+#include <linux/clk.h>

+#include <linux/slab.h>

+#include <linux/io.h>

+#include <linux/of_gpio.h>

+#include <linux/clk/zx29-clk.h>

+

+

+#include <asm/irq.h>

+#include <mach/i2c_private.h>

+#include <mach/spinlock.h>

+

+

+#define I2C_FIFO_DEPTH   32

+

+#define MAX_BUS_CLK   	400000

+#define MIN_BUS_CLK   	100000

+

+#define I2C_WCLK_FREQ	(26*1000*1000)

+

+

+

+#define i2c_if_tx_fifo_empty(d) ((zx_read_reg(d->regs+I2C_TXF_STATUS) & WFIFO_EMPTY)>>1)

+#define i2c_if_rx_fifo_full(d) (zx_read_reg(d->regs+I2C_RXF_STATUS) & RFIFO_FULL)

+

+static int zx29_i2c_init(struct zx29_i2c *i2c)

+{

+	unsigned int bus_clk;

+	unsigned int pdiv;

+

+

+	/*reset*/

+	zx29_i2c_reset_fifo(i2c);

+	udelay(1);

+

+	/*calculate bus clock division, fix input clock is 26M*/

+	bus_clk = MIN_BUS_CLK/1000;  /*in KHz*/

+	pdiv = ((I2C_WCLK_FREQ/1000)/4)/bus_clk - 1;

+#if 0

+    i2c->clkrate = (I2C_WCLK_FREQ/4)/(pdiv+1);   /*actul bus clock rate*/

+

+	if ((i2c->clkrate >MAX_BUS_CLK)||(i2c->clkrate < MIN_BUS_CLK)){

+		printk(KERN_ERR"bus clock rate error!\n");

+		BUG();

+	}

+#endif

+

+	i2c_set_clk_div(i2c, pdiv);

+

+	/*master mode, disable interrupt, clear interrupt*/

+	i2c_set_cmd(i2c, 0x1);

+

+	return 0;

+}

+

+static void zx29_i2c_start(struct zx29_i2c *i2c, struct i2c_msg *msg)

+{

+	unsigned int  addr = msg->addr;

+	unsigned long ctrl = 0;

+	unsigned int  addr_mode = 0;

+

+	/*set slave device address*/

+	addr_mode = msg->flags & I2C_M_TEN;

+

+	i2c_set_addr(i2c, addr, addr_mode);

+

+	/*set cmd register for rx or tx*/

+	ctrl = i2c_get_cmd(i2c);

+	if (msg->flags & I2C_M_RD) {

+		ctrl |= CMD_I2C_RW;

+	}

+	else{

+		ctrl &= ~CMD_I2C_RW;

+	}

+

+	if (addr_mode){

+		/*10 bit address mode :clear interrupt conditions, set master mode,set 10bit address mode  and start*/

+		ctrl |= CMD_I2C_START|CMD_I2C_MODE|CMD_TENBIT_MODE;

+	}

+	else{

+    	/*7 bit address mode:clear interrupt conditions, set master mode  and start*/

+		ctrl &= ~CMD_TENBIT_MODE;

+		ctrl |= CMD_I2C_START|CMD_I2C_MODE;

+	}

+

+	i2c_set_cmd(i2c, ctrl);

+}

+

+static int zx29_i2c_read(struct zx29_i2c *i2c, struct i2c_msg *msg)

+{

+	u8 *buf = msg->buf;

+	u16 len_rx = 0;

+	unsigned int ret=0;

+	u8 val, msg_ptr = 0;

+

+	if ((msg->len > 0) && (msg->len <= I2C_FIFO_DEPTH))

+		len_rx = msg->len;

+	else

+		return -EINVAL;

+

+	while((ret=i2c_get_bus_status(i2c)));

+

+	zx29_i2c_init(i2c);		//zx29_i2c_reset_fifo(i2c);

+

+	i2c_set_rx_fifo_depth(i2c, len_rx-1);

+

+	zx29_i2c_start(i2c, msg);

+

+	while(!i2c_if_rx_fifo_full(i2c));

+

+	while (len_rx--) {

+		val = (u8)i2c_read_data(i2c);

+		*(buf + msg_ptr) = val;

+		msg_ptr++;

+	}

+

+	return 0;

+}

+

+static int zx29_i2c_write(struct zx29_i2c *i2c, struct i2c_msg *msg)

+{

+	u8 val, msg_ptr = 0;

+	u8 *buf = msg->buf;

+	u16 len_tx = 0;

+	unsigned int ret=0;

+

+	if ((msg->len > 0) && (msg->len <= I2C_FIFO_DEPTH))

+		len_tx = msg->len;

+	else

+		return -EINVAL;

+

+	while((ret=i2c_get_bus_status(i2c)));

+

+	zx29_i2c_init(i2c);		//zx29_i2c_reset_fifo(i2c);

+

+	i2c_set_tx_fifo_depth(i2c, len_tx-1);

+

+	/*write data to fifo*/

+	while(len_tx--){

+		val = *(buf + msg_ptr);

+		i2c_write_data(i2c, val);

+		msg_ptr++;

+	}

+	barrier();

+

+	zx29_i2c_start(i2c, msg);

+

+	while(!i2c_if_tx_fifo_empty(i2c));

+

+	return 0;

+}

+

+static int zx29_i2c_doxfer(struct zx29_i2c *i2c, struct i2c_msg *msg)

+{

+	int ret;

+

+	if (msg->flags & I2C_M_RD) {

+        ret = zx29_i2c_read(i2c, msg);

+	} else {

+		ret = zx29_i2c_write(i2c, msg);

+	}

+

+	return ret;

+}

+

+int zx29_i2c_xfer_PSM(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)

+{

+	struct zx29_i2c *i2c = (struct zx29_i2c *)adap->algo_data;

+	int ret = 0;

+	int i;

+

+	if (msgs->len == 0)

+		return -EINVAL;

+

+//	i2c->msg_num = num;

+

+	for (i = 0; i < num; i++) {

+		ret = zx29_i2c_doxfer(i2c, &msgs[i]);

+//			i2c->msg_idx=i;

+		if (ret)

+			break;

+	}

+

+	return ret ?: i;

+}
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-zx29.c b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-zx29.c
new file mode 100644
index 0000000..73e12ac
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/i2c-zx29.c
@@ -0,0 +1,1051 @@
+/* linux/drivers/i2c/busses/i2c-zx29.c
+ *
+ * Copyright (C) 2015 Sanechips-TSP
+ *
+ * ----------NOTICE-------------
+ * ZX29 serials I2C Controller driver used by zx297520, this driver
+ * do not support slave mode. bus clock rate should between 400KHz--100KHz.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/time.h>
+#include <linux/hrtimer.h>
+#include <linux/ktime.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+//#include <linux/of_i2c.h>
+#include <linux/of_gpio.h>
+#include <linux/clk/zx29-clk.h>
+
+
+#include <asm/irq.h>
+#include <mach/i2c_private.h>
+#include <mach/spinlock.h>
+#include <linux/soc/zte/pm/drv_idle.h>
+
+/*#define DEBUG_I2C_ADAPTER*/
+
+#ifdef DEBUG_I2C_ADAPTER
+#define drv_printk(fmt, arg...)  printk(KERN_DEBUG fmt, ##arg)
+#pragma GCC optimize("O0")
+#else
+#define drv_printk(fmt, arg...)
+#endif
+
+#define I2C_PSM_CONTROL         (1)
+#define I2C_LONG_TRANSFER		(1)
+
+#define I2C_FIFO_DEPTH   32
+#define I2C_TIMEOUT 	(msecs_to_jiffies(1000))
+#define MAX_BUS_CLK   	400000
+#define MIN_BUS_CLK   	100000
+
+#define I2C_WCLK_FREQ	(26*1000*1000)
+
+#if I2C_PSM_CONTROL
+static volatile unsigned int i2c_active_count = 0;
+#endif
+
+#if I2C_LONG_TRANSFER
+/* functions for hrtimer */
+
+static enum hrtimer_restart zx29_i2c_timer_callback(struct hrtimer *timer)
+{
+    struct zx29_i2c *i2c;
+    enum hrtimer_restart ret = HRTIMER_NORESTART;
+
+    i2c = container_of(timer, struct zx29_i2c, hr_timer);
+
+    if ((i2c->state == STATE_READ) && (i2c->buf_remaining > I2C_FIFO_DEPTH)) {
+    	unsigned int len_rx = 0;
+        unsigned int len_diff = 0;
+    	u8 *buf = i2c->msg->buf;
+    	u8 val = 0;
+
+    	len_rx = i2c_get_rx_fifo_length(i2c);
+        len_diff = i2c->buf_remaining - I2C_FIFO_DEPTH;
+        if (len_rx < len_diff) {
+            ret = HRTIMER_RESTART;
+			hrtimer_forward_now(timer, i2c->ktime);
+        } else {
+            len_rx = len_diff;
+        }
+
+    	i2c->buf_remaining -= len_rx;
+
+    	/*read data from fifo*/
+    	while (len_rx--) {
+    		val = (u8)i2c_read_data(i2c);
+    		*(buf + i2c->msg_ptr) = val;
+    		i2c->msg_ptr++;
+    	}
+    } else if ((i2c->state == STATE_WRITE) && (i2c->buf_remaining > 0)) {
+    	unsigned int len_tx = 0;
+        unsigned int len_diff = 0;
+    	u8 *buf = i2c->msg->buf;
+    	u8 val = 0;
+
+    	len_tx = i2c_get_tx_fifo_length(i2c);
+        len_tx = I2C_FIFO_DEPTH - len_tx;
+        len_diff = i2c->buf_remaining;
+        if (len_tx < len_diff) {
+            ret = HRTIMER_RESTART;
+			hrtimer_forward_now(timer, i2c->ktime);
+        } else {
+            len_tx = len_diff;
+        }
+
+    	i2c->buf_remaining -= len_tx;
+
+    	/* write data to fifo */
+    	while (len_tx--) {
+    		val = *(buf + i2c->msg_ptr);
+    		i2c_write_data(i2c, val);
+    		i2c->msg_ptr++;
+    	}
+    }
+
+    return ret;
+}
+
+static void zx29_i2c_start_timer( struct zx29_i2c *i2c )
+{
+    unsigned long delay_in_us = (9*I2C_FIFO_DEPTH/2)*1000*1000 / i2c->clkrate;
+
+    i2c->ktime = ktime_set(0, delay_in_us * 1000);
+
+    hrtimer_init( &i2c->hr_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL );
+
+    i2c->hr_timer.function = zx29_i2c_timer_callback;
+
+    hrtimer_start( &i2c->hr_timer, i2c->ktime, HRTIMER_MODE_REL );
+}
+
+static void zx29_i2c_stop_timer( struct zx29_i2c *i2c )
+{
+    int ret;
+
+    ret = hrtimer_cancel(&i2c->hr_timer);
+    if(ret){
+		pr_info("%s return %d\n", __FUNCTION__, ret);
+    }
+
+    return;
+}
+#endif
+
+/* functions for hrtimer end */
+
+#if I2C_PSM_CONTROL
+static void zx29_i2c_set_active(struct wake_lock *lock)
+{
+	unsigned long flags;
+
+	local_irq_save(flags);
+
+    if(i2c_active_count == 0)
+    {
+        zx_cpuidle_set_busy(IDLE_FLAG_I2C);
+    }
+    i2c_active_count++;
+
+	local_irq_restore(flags);
+
+    wake_lock(lock);
+}
+
+static void zx29_i2c_set_idle(struct wake_lock *lock)
+{
+	unsigned long flags;
+
+	local_irq_save(flags);
+
+    i2c_active_count--;
+    if(i2c_active_count == 0)
+    {
+        zx_cpuidle_set_free(IDLE_FLAG_I2C);
+    }
+
+	local_irq_restore(flags);
+
+    wake_unlock(lock);
+}
+#endif
+
+#ifdef CONFIG_SYSFS
+static ssize_t zx29_i2c_sysfs_show(struct device *dev,
+		struct device_attribute *attr, char *buf);
+static ssize_t zx29_i2c_sysfs_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count);
+
+
+DEVICE_ATTR(clk_rate, S_IWUSR | S_IRUGO, zx29_i2c_sysfs_show, zx29_i2c_sysfs_store);
+
+static struct attribute * zx29_i2c_sysfs_attrs[] = {
+	&dev_attr_clk_rate.attr,
+	NULL
+};
+
+static const struct attribute_group zx29_i2c_sysfs_attr_group = {
+	.attrs = zx29_i2c_sysfs_attrs,
+};
+
+static int zx29_i2c_sysfs_create_group(struct zx29_i2c *i2c)
+{
+	return sysfs_create_group(&i2c->dev->kobj, &zx29_i2c_sysfs_attr_group);
+}
+
+static void zx29_i2c_sysfs_remove_group(struct zx29_i2c *i2c)
+{
+	sysfs_remove_group(&i2c->dev->kobj, &zx29_i2c_sysfs_attr_group);
+}
+
+static ssize_t zx29_i2c_sysfs_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct zx29_i2c *i2c = dev_get_drvdata(dev);
+	
+	if (!i2c)
+		return -EINVAL;
+
+	return scnprintf(buf, PAGE_SIZE, "%ld\n", i2c->clkrate);
+}
+
+static ssize_t zx29_i2c_sysfs_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct zx29_i2c *i2c = dev_get_drvdata(dev);
+	unsigned long clock_rate = 0;
+
+	if(strict_strtoul(buf, 0, &clock_rate))
+		return -EINVAL;
+	if((clock_rate < MIN_BUS_CLK) || (clock_rate > MAX_BUS_CLK) || (NULL == i2c))
+		return -EINVAL;
+
+	i2c_lock_adapter(&i2c->adap);
+	i2c->clkrate = clock_rate;
+	i2c_unlock_adapter(&i2c->adap);
+
+	pr_info("new i2c%d scl rate: %ld\n", i2c->id, i2c->clkrate);
+
+	return count;
+}
+#else
+static int zx29_i2c_sysfs_create_group(struct zx29_i2c *i2c)
+{
+	return 0;
+}
+
+static void zx29_i2c_sysfs_remove_group(struct zx29_i2c *i2c)
+{
+	return;
+}
+#endif
+
+static emsf_lock_id i2c_get_sflock(unsigned int i2c_id)
+{
+ 	emsf_lock_id	softLock = I2C2_SFLOCK;
+
+	switch(i2c_id)
+	{
+		case 0:			//pmic i2c
+			softLock = I2C2_SFLOCK;
+			break;
+		case 1:
+			softLock = I2C1_SFLOCK;
+			break;
+		default:
+			BUG();
+	}
+
+	return softLock;
+}
+
+/*
+  * zx29_i2c_init
+  *
+  * initialise the controller, set frequency
+  */
+static int zx29_i2c_init(struct zx29_i2c *i2c)
+{
+	unsigned int bus_clk;
+	unsigned int pdiv;
+ 	emsf_lock_id	softLock = i2c_get_sflock(i2c->id);
+	unsigned long actual_clk = 0;
+
+	soft_spin_lock(softLock);
+
+	/*reset*/
+	zx29_i2c_reset_fifo(i2c);
+	udelay(1);
+
+	/*calculate bus clock division, fix input clock is 26M*/
+	bus_clk=i2c->clkrate/1000;  /*in KHz*/
+	pdiv=((I2C_WCLK_FREQ/1000)/4)/bus_clk - 1;
+    if(((I2C_WCLK_FREQ/1000)/4) % bus_clk != 0){
+        pdiv++;
+    }
+
+    actual_clk = (I2C_WCLK_FREQ/4)/(pdiv+1);   /*actul bus clock rate*/
+	if ((actual_clk > MAX_BUS_CLK) || (actual_clk < MIN_BUS_CLK)){
+		pr_warn("bus clock rate error %ld!\n", actual_clk);
+		BUG();
+	}
+	i2c_set_clk_div(i2c, pdiv);
+
+	/*master mode, disable interrupt, clear interrupt*/
+	i2c_set_cmd(i2c, 0x1);
+
+    soft_spin_unlock(softLock);
+
+    i2c->state = STATE_IDLE;
+
+	return 0;
+}
+
+/*
+ *zx29_i2c_start
+ * put the start of a message onto the bus
+ */
+static void zx29_i2c_start(struct zx29_i2c *i2c, uint8_t fmt)
+{
+	unsigned int  addr = i2c->msg->addr;
+	unsigned long ctrl = 0;
+	unsigned int  addr_mode = 0;
+
+	/*set slave device address*/
+	addr_mode = i2c->msg->flags & I2C_M_TEN;
+
+	i2c_set_addr(i2c, addr, addr_mode);
+
+	i2c_clr_irq_ack(i2c);
+
+	/*set cmd register for rx or tx*/
+	ctrl = i2c_get_cmd(i2c);
+	ctrl &= ~CMD_I2C_FMT_MSK;
+	ctrl |= fmt;
+
+	if (addr_mode){
+		/*10 bit address mode :clear interrupt conditions, set master mode,set 10bit address mode  and start*/
+		ctrl |= CMD_I2C_START|CMD_I2C_MODE|CMD_TENBIT_MODE;
+	}
+	else{
+    	/*7 bit address mode:clear interrupt conditions, set master mode  and start*/
+		ctrl &= ~CMD_TENBIT_MODE;
+		ctrl |= CMD_I2C_START|CMD_I2C_MODE;
+	}
+
+	i2c_set_cmd(i2c, ctrl);
+}
+
+
+/*
+ * zx29_i2c_stop
+ */
+
+static inline void zx29_i2c_stop(struct zx29_i2c *i2c)
+{
+	//unsigned long ctrl = ioread32(i2c->regs + I2C_CMD);
+
+	/* stop the transfer ,clear interrupt conditions */
+	//ctrl |= CMD_I2C_STOP|CMD_IRQ_ACK;
+	//iowrite32(ctrl, i2c->regs + I2C_CMD);
+
+	i2c->state = STATE_STOP;
+}
+
+/*
+ * check i2c busy or not
+ */
+static inline int zx29_i2c_is_busy(struct zx29_i2c *i2c)
+{
+	unsigned int time_out=0xff;
+
+	while(time_out--){
+		if(i2c_get_bus_status(i2c)==0)
+			return 0;
+		else
+			udelay(1);
+	}
+	return -ETIMEDOUT;
+}
+
+/*
+ * i2c fifo write
+ */
+static void zx29_i2c_prepare_write(struct zx29_i2c *i2c)
+{
+	u8 val=0;
+	u8 *buf=i2c->msg->buf;
+	u16 len =i2c->buf_remaining;
+	u16 len_tx = 0;
+	unsigned int ret=0;
+
+    /*this step must be done. because FIFO empty interrupt does not mean bus is idle*/
+	ret=zx29_i2c_is_busy(i2c);
+	if(ret)
+		BUG();
+
+    zx29_i2c_reset_tx_fifo(i2c);
+
+	if(len > I2C_FIFO_DEPTH)
+		len_tx = I2C_FIFO_DEPTH;
+	else
+		len_tx = len;
+	i2c->buf_remaining -= len_tx;
+
+	i2c_set_tx_fifo_depth(i2c, len_tx-1);
+
+	/*write data to fifo*/
+	while(len_tx--){
+		val = *(buf + i2c->msg_ptr);
+		i2c_write_data(i2c, val);
+		i2c->msg_ptr++;
+	}
+	barrier();
+
+//    zx29_i2c_start(i2c);
+}
+
+/*
+ * i2c start read
+ */
+static void zx29_i2c_prepare_read(struct zx29_i2c *i2c)
+{
+	u16 len =i2c->buf_remaining;
+	u16 len_rx = 0;
+	unsigned int ret=0;
+
+    /*i2c  can only be operated when bus is idle*/
+	ret=zx29_i2c_is_busy(i2c);
+	if(ret)
+		BUG();
+
+    zx29_i2c_reset_rx_fifo(i2c);
+
+	if(len > I2C_FIFO_DEPTH)
+		len_rx = I2C_FIFO_DEPTH;
+	else
+		len_rx = len;
+
+	i2c_set_rx_fifo_depth(i2c, len_rx-1);
+
+//    zx29_i2c_start(i2c);
+}
+
+/*
+ * i2c fifo read
+ */
+static void zx29_i2c_read_fifo(struct zx29_i2c *i2c)
+{
+	unsigned int len_rx=0;
+	u8 *buf=i2c->msg->buf;
+	u8 val=0;
+
+	len_rx = i2c_get_rx_fifo_length(i2c);
+
+	i2c->buf_remaining -= len_rx;
+
+	/*read data from fifo*/
+	while(len_rx--){
+		val =(u8) i2c_read_data(i2c);
+		*(buf + i2c->msg_ptr) = val;
+		i2c->msg_ptr++;
+	}
+ }
+
+/* zx29_i2c_irq
+ *
+ * top level IRQ servicing routine
+ */
+static irqreturn_t zx29_i2c_irq(int irqno, void *dev_id)
+{
+	struct zx29_i2c *i2c = dev_id;
+	unsigned long status;
+
+	status = i2c_get_irq_status(i2c);
+	i2c->reg_status = (i2c->reg_status << 8) | status;
+
+	/*
+	 * if state is idle or stop, maybe other core on 7510 platform  trigger interrupt
+	 * it will be looked as spurious interrupt, nothing need to be done
+	 */
+	if ((i2c->state == STATE_IDLE) || (i2c->state == STATE_STOP))
+		return IRQ_HANDLED;
+
+    if (status & (IRQ_ERR_DEVICE | IRQ_ERR_DATA | IRQ_TRANS_DONE)) {
+		i2c_disable_irq(i2c);
+		disable_irq_nosync(i2c->irq);
+
+	 	up(&i2c->msg_complete);
+
+		return IRQ_HANDLED;
+    }
+
+    if (status & IRQ_TIME_OUT) {
+		i2c_clr_irq_ack(i2c);
+		return IRQ_HANDLED;
+    }
+
+	return IRQ_HANDLED;
+}
+
+
+/* zx29_i2c_get_bus
+ *
+ * get the i2c bus for a master transaction
+*/
+static int zx29_i2c_get_bus(struct zx29_i2c *i2c)
+{
+	int timeout = 400;
+
+	while (timeout-- > 0) {
+
+		if (!i2c_get_bus_status(i2c))
+			return 0;
+
+		msleep(1);
+	}
+
+	return -ETIMEDOUT;
+}
+
+/* zx29_i2c_doxfer
+ *
+ * this starts an i2c transfer
+ */
+static int zx29_i2c_doxfer(struct zx29_i2c *i2c, struct i2c_msg *msgs, bool cmb_rw)
+{
+	int ret;
+
+	if (i2c->suspended)
+		return -EIO;
+
+	i2c->msg     = msgs;
+	i2c->msg_ptr = 0;
+	i2c->buf_remaining = msgs->len;
+//	i2c->msg_idx = 0;
+
+//	init_completion(&(i2c->msg_complete));
+	if (unlikely(i2c->msg_complete.count)) {
+		pr_err("i2c sem %d\n", i2c->msg_complete.count);
+	}
+	i2c->reg_status = 0;
+    i2c_clr_irq_ack(i2c);
+	i2c_enable_irq(i2c);
+    enable_irq(i2c->irq);
+
+	if (cmb_rw) {
+		zx29_i2c_prepare_write(i2c);
+
+		i2c->msg     = &msgs[1];
+		i2c->msg_ptr = 0;
+		i2c->buf_remaining = msgs[1].len;
+
+		i2c->state = STATE_READ;
+		memset(msgs[1].buf, 0, msgs[1].len);
+        zx29_i2c_prepare_read(i2c);
+
+		zx29_i2c_start(i2c, CMD_I2C_FMT_CMB);
+	} else if (i2c->msg->flags & I2C_M_RD) {
+		i2c->state = STATE_READ;
+		memset(msgs->buf, 0, msgs->len);
+        zx29_i2c_prepare_read(i2c);
+		zx29_i2c_start(i2c, CMD_I2C_FMT_RD);
+	} else {
+		i2c->state = STATE_WRITE;
+		zx29_i2c_prepare_write(i2c);
+		zx29_i2c_start(i2c, CMD_I2C_FMT_WR);
+	}
+
+#if I2C_LONG_TRANSFER
+    if (i2c->msg->len > I2C_FIFO_DEPTH) {
+        zx29_i2c_start_timer(i2c);
+    }
+#endif
+
+    /* waiting for tranfer finished */
+	ret = down_timeout(&i2c->msg_complete, I2C_TIMEOUT);
+
+#if I2C_LONG_TRANSFER
+    if (i2c->msg->len > I2C_FIFO_DEPTH) {
+        zx29_i2c_stop_timer(i2c);
+    }
+#endif
+
+	if (ret < 0) {
+		i2c_disable_irq(i2c);
+	    disable_irq_nosync(i2c->irq);
+
+		pr_err("i2c transfer timeout\n");
+
+		zx29_i2c_stop(i2c);
+		zx29_i2c_init(i2c);
+
+		return -ETIMEDOUT;
+	}
+
+	if (i2c->state == STATE_READ) {
+		zx29_i2c_read_fifo(i2c);
+	}
+
+	/* slave no ack on address phase or data phase */
+    if (i2c_get_irq_status(i2c) & (IRQ_ERR_DEVICE | IRQ_ERR_DATA)) {
+		pr_err("NACK by slave 0x%X, status %X\n", i2c->msg->addr, i2c_get_irq_status(i2c));
+
+		while (~ i2c_get_irq_status(i2c) & IRQ_TRANS_DONE);
+		i2c_clr_irq_ack(i2c);
+
+		zx29_i2c_init(i2c);
+
+		return -ECOMM;
+    }
+
+	i2c_clr_irq_ack(i2c);
+	i2c->state = STATE_IDLE;
+
+#if I2C_LONG_TRANSFER
+	if(i2c->buf_remaining) {
+		pr_err("%s: %d/%d isn't transferred\n", __FUNCTION__, i2c->buf_remaining, i2c->msg->len);
+		return -EAGAIN;
+	}
+#endif
+
+	return 0;
+}
+
+/* zx29_i2c_xfer
+ *
+ * first port of call from the i2c bus code when an message needs
+ * transferring across the i2c bus.
+*/
+static int zx29_i2c_xfer(struct i2c_adapter *adap,
+			struct i2c_msg *msgs, int num)
+{
+	struct zx29_i2c *i2c = (struct zx29_i2c *)adap->algo_data;
+	int ret;
+	int i = 0;
+	bool combie_rw_applicable;
+	unsigned int  pdiv;
+	emsf_lock_id	softLock = i2c_get_sflock(i2c->id);
+
+	if (i2c->suspended)
+		return -EIO;
+
+	if (msgs->len == 0)
+		return -EINVAL;
+
+#if I2C_PSM_CONTROL
+    zx29_i2c_set_active(&i2c->psm_lock);
+#endif
+
+    soft_spin_lock(softLock);
+
+#ifdef CONFIG_ARCH_ZX297502
+	clk_enable(i2c->clk);
+#endif
+
+	ret = zx29_i2c_get_bus(i2c);
+	if (ret != 0) {
+		dev_err(i2c->dev, "cannot get bus (error %d)\n", ret);
+
+        //soft_spin_unlock(I2C_SFLOCK);   /* zhouqi */
+
+		ret = -EAGAIN;
+		goto exit;
+	}
+
+	/* calculate bus clock division, fixed input clock is 26M */
+	pdiv = (I2C_WCLK_FREQ / 4 / i2c->clkrate) - 1;
+    if((I2C_WCLK_FREQ / 4) % i2c->clkrate != 0)
+        pdiv++;
+	i2c_set_clk_div(i2c, pdiv);
+
+//	i2c->msg_num = num;
+	/* check whether combined rw is applicable */
+	if ((num == 2) && (msgs[0].addr == msgs[1].addr)) {
+		combie_rw_applicable = ((msgs[0].flags & I2C_M_TEN) == (msgs[1].flags & I2C_M_TEN)) \
+								&& (~msgs[0].flags & I2C_M_RD) \
+								&& (msgs[1].flags & I2C_M_RD) \
+								&& (msgs[0].len <= I2C_FIFO_DEPTH);
+	} else
+		combie_rw_applicable = 0;
+
+	if (combie_rw_applicable) {
+		ret = zx29_i2c_doxfer(i2c, msgs, 1);
+	} else for (i = 0; i < num; i++) {
+		ret = zx29_i2c_doxfer(i2c, &msgs[i], 0);
+//			i2c->msg_idx=i;
+		if (ret) {
+			//printk(KERN_INFO "%s err code=%d\n", __FUNCTION__, ret);
+			break;
+		}
+    }
+
+exit:
+#ifdef CONFIG_ARCH_ZX297502
+	clk_disable(i2c->clk);
+#endif
+
+    soft_spin_unlock(softLock);
+
+#if I2C_PSM_CONTROL
+    zx29_i2c_set_idle(&i2c->psm_lock);
+#endif
+
+	return ret ? ret : num;
+}
+
+/* declare our i2c functionality */
+static u32 zx29_i2c_func(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK)| I2C_FUNC_10BIT_ADDR;
+}
+
+/* i2c bus registration info */
+static const struct i2c_algorithm zx29_i2c_algorithm = {
+	.master_xfer		= zx29_i2c_xfer,
+	.functionality		= zx29_i2c_func,
+};
+
+#ifdef CONFIG_OF
+/* zx29_i2c_parse_dt
+ *
+ * Parse the device tree node and retreive the platform data.
+*/
+static void
+zx29_i2c_parse_dt(struct device_node *np, struct zx29_i2c *i2c)
+{
+	struct zx29_i2c_platform_data *pdata = i2c->pdata;
+
+	if (!np)
+		return;
+	of_property_read_u32(np, "Sanechips-tsp,i2c-slave-addr", &pdata->slave_addr);
+	of_property_read_u32(np, "Sanechips-tsp,i2c-max-bus-freq",(u32 *)&pdata->max_bus_clk);
+}
+#else
+static void
+zx29_i2c_parse_dt(struct device_node *np, struct zx29_i2c *i2c)
+{
+	return;
+}
+#endif
+
+static int i2c_init_clks(struct platform_device *pdev, struct zx29_i2c *i2c)
+{
+	/* find the clock and enable it */
+	i2c->clk = clk_get(&pdev->dev, "work_clk");
+	if (IS_ERR(i2c->clk)) {
+		dev_err(&pdev->dev, "cannot get work clock\n");
+		return -ENOENT;
+	}
+
+	/* set i2c work clock at 26MHz/1 */
+	clk_set_rate(i2c->clk, I2C_WCLK_FREQ);
+	clk_enable(i2c->clk);
+
+	i2c->pclk = clk_get(&pdev->dev, "apb_clk");
+	if (IS_ERR(i2c->pclk)) {
+		dev_err(&pdev->dev, "cannot get apb clock\n");
+		return -ENOENT;
+	}
+	clk_enable(i2c->pclk);
+
+	clk_set_auto_gate(i2c->clk, true);
+	clk_set_auto_gate(i2c->pclk, true);
+
+	return 0;
+}
+
+/* zx29_i2c_probe
+ *
+ * called by the bus driver when a suitable device is found
+*/
+static int zx29_i2c_probe(struct platform_device *pdev)
+{
+	struct zx29_i2c *i2c=NULL;
+	struct zx29_i2c_platform_data *pdata = NULL;
+	struct resource *res=NULL;
+	void __iomem *base=NULL;
+	const unsigned int *prop=NULL;
+	int ret=0;
+    emsf_lock_id softLock;
+
+	/* irq&register */
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "no memory resource\n");
+		ret = -EINVAL;
+		goto err_iomap;
+	}
+	base = (void __iomem *)(res->start);
+
+	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "no irq resource\n");
+		ret = -EINVAL;
+		goto err_iomap;
+	}
+
+    i2c = devm_kzalloc(&pdev->dev, sizeof(struct zx29_i2c), GFP_KERNEL);
+	if (!i2c) {
+		dev_err(&pdev->dev, "no memory for state\n");
+        ret = -ENOMEM;
+		goto err_iomap;
+	}
+
+	if (!pdev->dev.of_node) {
+	  	pdata = pdev->dev.platform_data;
+	  	if (!pdata) {
+	  		dev_err(&pdev->dev, "no platform data\n");
+	  		return -EINVAL;
+		}
+    }
+
+	snprintf(i2c->name, sizeof(i2c->name), "zx29-i2c%d", pdev->id);
+	i2c->pdata	= pdata;
+    i2c->id 	= pdev->id;
+	i2c->regs	= base;
+	i2c->irq	= res->start;
+	i2c->dev 	= &pdev->dev;
+	i2c->state 	= STATE_IDLE;
+
+    i2c->clkrate = MIN_BUS_CLK; /* default clock rate */
+	if (pdata) {
+		i2c->clkrate = pdata->bus_clk_rate;
+	}
+	else if (i2c->dev->of_node) {    /* if there is a device tree node ... */
+		prop = of_get_property(i2c->dev->of_node,
+				"clock-frequency", NULL);
+		if (prop)
+			i2c->clkrate = be32_to_cpup(prop);
+	}
+
+	spin_lock_init(&i2c->lock);
+
+	sema_init(&i2c->msg_complete, 0);
+
+    softLock = i2c_get_sflock(i2c->id);
+    soft_spin_lock(softLock);
+
+	i2c_config_pins(i2c);
+
+	ret = i2c_init_clks(pdev, i2c);
+	if(ret < 0)
+	{
+        soft_spin_unlock(softLock);
+		goto err_free;
+	}
+
+	/* initialise the i2c controller */
+	ret = zx29_i2c_init(i2c);
+	if (ret != 0){
+        soft_spin_unlock(softLock);
+        goto err_free;
+	}
+
+    i2c_disable_irq(i2c);
+	/* find the IRQ for this unit (note, this relies on the init call to
+	 * ensure no current IRQs pending
+	 */
+	ret = devm_request_irq(&pdev->dev, i2c->irq, zx29_i2c_irq,
+							IRQF_TRIGGER_HIGH | IRQF_NO_THREAD | IRQF_ONESHOT,
+							dev_name(&pdev->dev), i2c);
+	if (ret != 0) {
+		dev_err(&pdev->dev, "cannot claim IRQ %d\n", i2c->irq);
+        soft_spin_unlock(softLock);
+        goto err_clk;
+	}
+    disable_irq_nosync(i2c->irq);
+
+    soft_spin_unlock(softLock);
+
+	/* Note, previous versions of the driver used i2c_add_adapter()
+	 * to add the bus at any number. We now pass the bus number via
+	 * the platform data, so if unset it will now default to always
+	 * being bus 0.
+	 */
+	zx29_i2c_parse_dt(pdev->dev.of_node, i2c);
+	strlcpy(i2c->adap.name, "zx29-i2c", sizeof(i2c->adap.name));
+	i2c->adap.owner   = THIS_MODULE;
+	i2c->adap.algo    = &zx29_i2c_algorithm;
+	i2c->adap.retries = 3;
+	i2c->adap.class   = I2C_CLASS_HWMON | I2C_CLASS_SPD;
+	i2c->adap.algo_data = i2c;
+	i2c->adap.dev.parent = &pdev->dev;
+	i2c->adap.nr = pdev->id;
+	i2c->adap.dev.of_node = pdev->dev.of_node;
+
+#if I2C_PSM_CONTROL
+    wake_lock_init(&i2c->psm_lock, WAKE_LOCK_SUSPEND, i2c->name);
+#endif
+
+	ret = i2c_add_numbered_adapter(&i2c->adap);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "failed to add bus to i2c core\n");
+		goto err_irq;
+	}
+
+//	of_i2c_register_devices(&i2c->adap);
+	platform_set_drvdata(pdev, i2c);
+
+	zx29_i2c_sysfs_create_group(i2c);
+
+	dev_info(&pdev->dev, "%s: ZX29 I2C adapter\n", dev_name(&i2c->adap.dev));
+
+#ifdef CONFIG_ARCH_ZX297502
+	clk_disable(i2c->clk);
+#endif
+	return 0;
+
+ /*err_cpufreq:
+	zx29_i2c_deregister_cpufreq(i2c);*/
+
+err_irq:
+#if I2C_PSM_CONTROL
+    wake_lock_destroy(&i2c->psm_lock);
+#endif
+	devm_free_irq(&pdev->dev, i2c->irq, i2c);
+
+err_clk:
+	clk_disable(i2c->clk);
+	clk_put(i2c->clk);
+	clk_disable(i2c->pclk);
+	clk_put(i2c->pclk);
+
+
+err_free:
+    kfree(i2c);
+
+err_iomap:
+//	iounmap(base);
+
+	return ret;
+}
+
+/* zx29_i2c_remove
+ *
+ * called when device is removed from the bus
+*/
+static int zx29_i2c_remove(struct platform_device *pdev)
+{
+	struct zx29_i2c *i2c = platform_get_drvdata(pdev);
+
+	zx29_i2c_sysfs_remove_group(i2c);
+
+	i2c_del_adapter(&i2c->adap);
+
+	clk_disable(i2c->clk);
+	clk_put(i2c->clk);
+	clk_disable(i2c->pclk);
+	clk_put(i2c->pclk);
+
+#if I2C_PSM_CONTROL
+    wake_lock_destroy(&i2c->psm_lock);
+#endif
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int zx29_i2c_suspend(struct platform_device *pdev, pm_message_t state)
+{
+
+#ifdef CONFIG_ARCH_ZX297502
+	struct zx29_i2c *i2c = platform_get_drvdata(pdev);
+
+    i2c_lock_adapter(&i2c->adap);
+	i2c->suspended = 1;
+	i2c_unlock_adapter(&i2c->adap);
+#endif
+
+	return 0;
+}
+
+static int zx29_i2c_resume(struct platform_device *pdev)
+{
+
+#ifdef CONFIG_ARCH_ZX297502
+	struct zx29_i2c *i2c = platform_get_drvdata(pdev);
+
+    i2c_lock_adapter(&i2c->adap);
+	clk_enable(i2c->clk);
+	zx29_i2c_init(i2c);
+	clk_disable(i2c->clk);
+	i2c->suspended = 0;
+    i2c_unlock_adapter(&i2c->adap);
+#endif
+
+	return 0;
+}
+#endif
+
+
+#ifdef CONFIG_OF
+static const struct of_device_id zx29_i2c_match[] = {
+	{ .compatible = "Sanechips-TSP, zx29_i2c0" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, zx29_i2c_match);
+#else
+#define zx29_i2c_match NULL
+#endif
+
+static struct platform_driver zx29_i2c_driver = {
+	.probe		= zx29_i2c_probe,
+	.remove		= zx29_i2c_remove,
+#ifdef CONFIG_PM
+	.suspend    = zx29_i2c_suspend,
+	.resume     = zx29_i2c_resume,
+#endif
+	.driver		= {
+		.owner	= THIS_MODULE,
+		.name	= "zx29_i2c",
+		.of_match_table = zx29_i2c_match,
+	},
+};
+
+static int __init i2c_adap_zx29_init(void)
+{
+	int ret;
+
+	ret=platform_driver_register(&zx29_i2c_driver);
+	if (ret<0) {
+		pr_err("zx29 i2c driver register fail\n");
+	}
+	return ret;
+}
+subsys_initcall(i2c_adap_zx29_init);
+
+static void __exit i2c_adap_zx29_exit(void)
+{
+	platform_driver_unregister(&zx29_i2c_driver);
+}
+module_exit(i2c_adap_zx29_exit);
+
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/busses/scx200_acb.c b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/scx200_acb.c
new file mode 100644
index 0000000..2eacb77
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/scx200_acb.c
@@ -0,0 +1,618 @@
+/*
+    Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com>
+
+    National Semiconductor SCx200 ACCESS.bus support
+    Also supports the AMD CS5535 and AMD CS5536
+
+    Based on i2c-keywest.c which is:
+        Copyright (c) 2001 Benjamin Herrenschmidt <benh@kernel.crashing.org>
+        Copyright (c) 2000 Philip Edelbrock <phil@stimpy.netroedge.com>
+
+    This program is free software; you can redistribute it and/or
+    modify it under the terms of the GNU General Public License as
+    published by the Free Software Foundation; either version 2 of the
+    License, or (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+
+#include <linux/scx200.h>
+
+#define NAME "scx200_acb"
+
+MODULE_AUTHOR("Christer Weinigel <wingel@nano-system.com>");
+MODULE_DESCRIPTION("NatSemi SCx200 ACCESS.bus Driver");
+MODULE_ALIAS("platform:cs5535-smb");
+MODULE_LICENSE("GPL");
+
+#define MAX_DEVICES 4
+static int base[MAX_DEVICES] = { 0x820, 0x840 };
+module_param_array(base, int, NULL, 0);
+MODULE_PARM_DESC(base, "Base addresses for the ACCESS.bus controllers");
+
+#define POLL_TIMEOUT	(HZ/5)
+
+enum scx200_acb_state {
+	state_idle,
+	state_address,
+	state_command,
+	state_repeat_start,
+	state_quick,
+	state_read,
+	state_write,
+};
+
+static const char *scx200_acb_state_name[] = {
+	"idle",
+	"address",
+	"command",
+	"repeat_start",
+	"quick",
+	"read",
+	"write",
+};
+
+/* Physical interface */
+struct scx200_acb_iface {
+	struct scx200_acb_iface *next;
+	struct i2c_adapter adapter;
+	unsigned base;
+	struct mutex mutex;
+
+	/* State machine data */
+	enum scx200_acb_state state;
+	int result;
+	u8 address_byte;
+	u8 command;
+	u8 *ptr;
+	char needs_reset;
+	unsigned len;
+};
+
+/* Register Definitions */
+#define ACBSDA		(iface->base + 0)
+#define ACBST		(iface->base + 1)
+#define    ACBST_SDAST		0x40 /* SDA Status */
+#define    ACBST_BER		0x20
+#define    ACBST_NEGACK		0x10 /* Negative Acknowledge */
+#define    ACBST_STASTR		0x08 /* Stall After Start */
+#define    ACBST_MASTER		0x02
+#define ACBCST		(iface->base + 2)
+#define    ACBCST_BB		0x02
+#define ACBCTL1		(iface->base + 3)
+#define    ACBCTL1_STASTRE	0x80
+#define    ACBCTL1_NMINTE	0x40
+#define    ACBCTL1_ACK		0x10
+#define    ACBCTL1_STOP		0x02
+#define    ACBCTL1_START	0x01
+#define ACBADDR		(iface->base + 4)
+#define ACBCTL2		(iface->base + 5)
+#define    ACBCTL2_ENABLE	0x01
+
+/************************************************************************/
+
+static void scx200_acb_machine(struct scx200_acb_iface *iface, u8 status)
+{
+	const char *errmsg;
+
+	dev_dbg(&iface->adapter.dev, "state %s, status = 0x%02x\n",
+		scx200_acb_state_name[iface->state], status);
+
+	if (status & ACBST_BER) {
+		errmsg = "bus error";
+		goto error;
+	}
+	if (!(status & ACBST_MASTER)) {
+		errmsg = "not master";
+		goto error;
+	}
+	if (status & ACBST_NEGACK) {
+		dev_dbg(&iface->adapter.dev, "negative ack in state %s\n",
+			scx200_acb_state_name[iface->state]);
+
+		iface->state = state_idle;
+		iface->result = -ENXIO;
+
+		outb(inb(ACBCTL1) | ACBCTL1_STOP, ACBCTL1);
+		outb(ACBST_STASTR | ACBST_NEGACK, ACBST);
+
+		/* Reset the status register */
+		outb(0, ACBST);
+		return;
+	}
+
+	switch (iface->state) {
+	case state_idle:
+		dev_warn(&iface->adapter.dev, "interrupt in idle state\n");
+		break;
+
+	case state_address:
+		/* Do a pointer write first */
+		outb(iface->address_byte & ~1, ACBSDA);
+
+		iface->state = state_command;
+		break;
+
+	case state_command:
+		outb(iface->command, ACBSDA);
+
+		if (iface->address_byte & 1)
+			iface->state = state_repeat_start;
+		else
+			iface->state = state_write;
+		break;
+
+	case state_repeat_start:
+		outb(inb(ACBCTL1) | ACBCTL1_START, ACBCTL1);
+		/* fallthrough */
+
+	case state_quick:
+		if (iface->address_byte & 1) {
+			if (iface->len == 1)
+				outb(inb(ACBCTL1) | ACBCTL1_ACK, ACBCTL1);
+			else
+				outb(inb(ACBCTL1) & ~ACBCTL1_ACK, ACBCTL1);
+			outb(iface->address_byte, ACBSDA);
+
+			iface->state = state_read;
+		} else {
+			outb(iface->address_byte, ACBSDA);
+
+			iface->state = state_write;
+		}
+		break;
+
+	case state_read:
+		/* Set ACK if _next_ byte will be the last one */
+		if (iface->len == 2)
+			outb(inb(ACBCTL1) | ACBCTL1_ACK, ACBCTL1);
+		else
+			outb(inb(ACBCTL1) & ~ACBCTL1_ACK, ACBCTL1);
+
+		if (iface->len == 1) {
+			iface->result = 0;
+			iface->state = state_idle;
+			outb(inb(ACBCTL1) | ACBCTL1_STOP, ACBCTL1);
+		}
+
+		*iface->ptr++ = inb(ACBSDA);
+		--iface->len;
+
+		break;
+
+	case state_write:
+		if (iface->len == 0) {
+			iface->result = 0;
+			iface->state = state_idle;
+			outb(inb(ACBCTL1) | ACBCTL1_STOP, ACBCTL1);
+			break;
+		}
+
+		outb(*iface->ptr++, ACBSDA);
+		--iface->len;
+
+		break;
+	}
+
+	return;
+
+ error:
+	dev_err(&iface->adapter.dev,
+		"%s in state %s (addr=0x%02x, len=%d, status=0x%02x)\n", errmsg,
+		scx200_acb_state_name[iface->state], iface->address_byte,
+		iface->len, status);
+
+	iface->state = state_idle;
+	iface->result = -EIO;
+	iface->needs_reset = 1;
+}
+
+static void scx200_acb_poll(struct scx200_acb_iface *iface)
+{
+	u8 status;
+	unsigned long timeout;
+
+	timeout = jiffies + POLL_TIMEOUT;
+	while (1) {
+		status = inb(ACBST);
+
+		/* Reset the status register to avoid the hang */
+		outb(0, ACBST);
+
+		if ((status & (ACBST_SDAST|ACBST_BER|ACBST_NEGACK)) != 0) {
+			scx200_acb_machine(iface, status);
+			return;
+		}
+		if (time_after(jiffies, timeout))
+			break;
+		cpu_relax();
+		cond_resched();
+	}
+
+	dev_err(&iface->adapter.dev, "timeout in state %s\n",
+		scx200_acb_state_name[iface->state]);
+
+	iface->state = state_idle;
+	iface->result = -EIO;
+	iface->needs_reset = 1;
+}
+
+static void scx200_acb_reset(struct scx200_acb_iface *iface)
+{
+	/* Disable the ACCESS.bus device and Configure the SCL
+	   frequency: 16 clock cycles */
+	outb(0x70, ACBCTL2);
+	/* Polling mode */
+	outb(0, ACBCTL1);
+	/* Disable slave address */
+	outb(0, ACBADDR);
+	/* Enable the ACCESS.bus device */
+	outb(inb(ACBCTL2) | ACBCTL2_ENABLE, ACBCTL2);
+	/* Free STALL after START */
+	outb(inb(ACBCTL1) & ~(ACBCTL1_STASTRE | ACBCTL1_NMINTE), ACBCTL1);
+	/* Send a STOP */
+	outb(inb(ACBCTL1) | ACBCTL1_STOP, ACBCTL1);
+	/* Clear BER, NEGACK and STASTR bits */
+	outb(ACBST_BER | ACBST_NEGACK | ACBST_STASTR, ACBST);
+	/* Clear BB bit */
+	outb(inb(ACBCST) | ACBCST_BB, ACBCST);
+}
+
+static s32 scx200_acb_smbus_xfer(struct i2c_adapter *adapter,
+				 u16 address, unsigned short flags,
+				 char rw, u8 command, int size,
+				 union i2c_smbus_data *data)
+{
+	struct scx200_acb_iface *iface = i2c_get_adapdata(adapter);
+	int len;
+	u8 *buffer;
+	u16 cur_word;
+	int rc;
+
+	switch (size) {
+	case I2C_SMBUS_QUICK:
+		len = 0;
+		buffer = NULL;
+		break;
+
+	case I2C_SMBUS_BYTE:
+		len = 1;
+		buffer = rw ? &data->byte : &command;
+		break;
+
+	case I2C_SMBUS_BYTE_DATA:
+		len = 1;
+		buffer = &data->byte;
+		break;
+
+	case I2C_SMBUS_WORD_DATA:
+		len = 2;
+		cur_word = cpu_to_le16(data->word);
+		buffer = (u8 *)&cur_word;
+		break;
+
+	case I2C_SMBUS_I2C_BLOCK_DATA:
+		len = data->block[0];
+		if (len == 0 || len > I2C_SMBUS_BLOCK_MAX)
+			return -EINVAL;
+		buffer = &data->block[1];
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	dev_dbg(&adapter->dev,
+		"size=%d, address=0x%x, command=0x%x, len=%d, read=%d\n",
+		size, address, command, len, rw);
+
+	if (!len && rw == I2C_SMBUS_READ) {
+		dev_dbg(&adapter->dev, "zero length read\n");
+		return -EINVAL;
+	}
+
+	mutex_lock(&iface->mutex);
+
+	iface->address_byte = (address << 1) | rw;
+	iface->command = command;
+	iface->ptr = buffer;
+	iface->len = len;
+	iface->result = -EINVAL;
+	iface->needs_reset = 0;
+
+	outb(inb(ACBCTL1) | ACBCTL1_START, ACBCTL1);
+
+	if (size == I2C_SMBUS_QUICK || size == I2C_SMBUS_BYTE)
+		iface->state = state_quick;
+	else
+		iface->state = state_address;
+
+	while (iface->state != state_idle)
+		scx200_acb_poll(iface);
+
+	if (iface->needs_reset)
+		scx200_acb_reset(iface);
+
+	rc = iface->result;
+
+	mutex_unlock(&iface->mutex);
+
+	if (rc == 0 && size == I2C_SMBUS_WORD_DATA && rw == I2C_SMBUS_READ)
+		data->word = le16_to_cpu(cur_word);
+
+#ifdef DEBUG
+	dev_dbg(&adapter->dev, "transfer done, result: %d", rc);
+	if (buffer) {
+		int i;
+		printk(" data:");
+		for (i = 0; i < len; ++i)
+			printk(" %02x", buffer[i]);
+	}
+	printk("\n");
+#endif
+
+	return rc;
+}
+
+static u32 scx200_acb_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+	       I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+	       I2C_FUNC_SMBUS_I2C_BLOCK;
+}
+
+/* For now, we only handle combined mode (smbus) */
+static const struct i2c_algorithm scx200_acb_algorithm = {
+	.smbus_xfer	= scx200_acb_smbus_xfer,
+	.functionality	= scx200_acb_func,
+};
+
+static struct scx200_acb_iface *scx200_acb_list;
+static DEFINE_MUTEX(scx200_acb_list_mutex);
+
+static __devinit int scx200_acb_probe(struct scx200_acb_iface *iface)
+{
+	u8 val;
+
+	/* Disable the ACCESS.bus device and Configure the SCL
+	   frequency: 16 clock cycles */
+	outb(0x70, ACBCTL2);
+
+	if (inb(ACBCTL2) != 0x70) {
+		pr_debug(NAME ": ACBCTL2 readback failed\n");
+		return -ENXIO;
+	}
+
+	outb(inb(ACBCTL1) | ACBCTL1_NMINTE, ACBCTL1);
+
+	val = inb(ACBCTL1);
+	if (val) {
+		pr_debug(NAME ": disabled, but ACBCTL1=0x%02x\n",
+			val);
+		return -ENXIO;
+	}
+
+	outb(inb(ACBCTL2) | ACBCTL2_ENABLE, ACBCTL2);
+
+	outb(inb(ACBCTL1) | ACBCTL1_NMINTE, ACBCTL1);
+
+	val = inb(ACBCTL1);
+	if ((val & ACBCTL1_NMINTE) != ACBCTL1_NMINTE) {
+		pr_debug(NAME ": enabled, but NMINTE won't be set, "
+			 "ACBCTL1=0x%02x\n", val);
+		return -ENXIO;
+	}
+
+	return 0;
+}
+
+static __devinit struct scx200_acb_iface *scx200_create_iface(const char *text,
+		struct device *dev, int index)
+{
+	struct scx200_acb_iface *iface;
+	struct i2c_adapter *adapter;
+
+	iface = kzalloc(sizeof(*iface), GFP_KERNEL);
+	if (!iface) {
+		printk(KERN_ERR NAME ": can't allocate memory\n");
+		return NULL;
+	}
+
+	adapter = &iface->adapter;
+	i2c_set_adapdata(adapter, iface);
+	snprintf(adapter->name, sizeof(adapter->name), "%s ACB%d", text, index);
+	adapter->owner = THIS_MODULE;
+	adapter->algo = &scx200_acb_algorithm;
+	adapter->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
+	adapter->dev.parent = dev;
+
+	mutex_init(&iface->mutex);
+
+	return iface;
+}
+
+static int __devinit scx200_acb_create(struct scx200_acb_iface *iface)
+{
+	struct i2c_adapter *adapter;
+	int rc;
+
+	adapter = &iface->adapter;
+
+	rc = scx200_acb_probe(iface);
+	if (rc) {
+		printk(KERN_WARNING NAME ": probe failed\n");
+		return rc;
+	}
+
+	scx200_acb_reset(iface);
+
+	if (i2c_add_adapter(adapter) < 0) {
+		printk(KERN_ERR NAME ": failed to register\n");
+		return -ENODEV;
+	}
+
+	if (!adapter->dev.parent) {
+		/* If there's no dev, we're tracking (ISA) ifaces manually */
+		mutex_lock(&scx200_acb_list_mutex);
+		iface->next = scx200_acb_list;
+		scx200_acb_list = iface;
+		mutex_unlock(&scx200_acb_list_mutex);
+	}
+
+	return 0;
+}
+
+static struct scx200_acb_iface * __devinit scx200_create_dev(const char *text,
+		unsigned long base, int index, struct device *dev)
+{
+	struct scx200_acb_iface *iface;
+	int rc;
+
+	iface = scx200_create_iface(text, dev, index);
+
+	if (iface == NULL)
+		return NULL;
+
+	if (!request_region(base, 8, iface->adapter.name)) {
+		printk(KERN_ERR NAME ": can't allocate io 0x%lx-0x%lx\n",
+		       base, base + 8 - 1);
+		goto errout_free;
+	}
+
+	iface->base = base;
+	rc = scx200_acb_create(iface);
+
+	if (rc == 0)
+		return iface;
+
+	release_region(base, 8);
+ errout_free:
+	kfree(iface);
+	return NULL;
+}
+
+static int __devinit scx200_probe(struct platform_device *pdev)
+{
+	struct scx200_acb_iface *iface;
+	struct resource *res;
+
+	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "can't fetch device resource info\n");
+		return -ENODEV;
+	}
+
+	iface = scx200_create_dev("CS5535", res->start, 0, &pdev->dev);
+	if (!iface)
+		return -EIO;
+
+	dev_info(&pdev->dev, "SCx200 device '%s' registered\n",
+			iface->adapter.name);
+	platform_set_drvdata(pdev, iface);
+
+	return 0;
+}
+
+static void __devexit scx200_cleanup_iface(struct scx200_acb_iface *iface)
+{
+	i2c_del_adapter(&iface->adapter);
+	release_region(iface->base, 8);
+	kfree(iface);
+}
+
+static int __devexit scx200_remove(struct platform_device *pdev)
+{
+	struct scx200_acb_iface *iface;
+
+	iface = platform_get_drvdata(pdev);
+	platform_set_drvdata(pdev, NULL);
+	scx200_cleanup_iface(iface);
+
+	return 0;
+}
+
+static struct platform_driver scx200_pci_driver = {
+	.driver = {
+		.name = "cs5535-smb",
+		.owner = THIS_MODULE,
+	},
+	.probe = scx200_probe,
+	.remove = __devexit_p(scx200_remove),
+};
+
+static DEFINE_PCI_DEVICE_TABLE(scx200_isa) = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_BRIDGE) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SC1100_BRIDGE) },
+	{ 0, }
+};
+
+static __init void scx200_scan_isa(void)
+{
+	int i;
+
+	if (!pci_dev_present(scx200_isa))
+		return;
+
+	for (i = 0; i < MAX_DEVICES; ++i) {
+		if (base[i] == 0)
+			continue;
+
+		/* XXX: should we care about failures? */
+		scx200_create_dev("SCx200", base[i], i, NULL);
+	}
+}
+
+static int __init scx200_acb_init(void)
+{
+	pr_debug(NAME ": NatSemi SCx200 ACCESS.bus Driver\n");
+
+	/* First scan for ISA-based devices */
+	scx200_scan_isa();	/* XXX: should we care about errors? */
+
+	/* If at least one bus was created, init must succeed */
+	if (scx200_acb_list)
+		return 0;
+
+	/* No ISA devices; register the platform driver for PCI-based devices */
+	return platform_driver_register(&scx200_pci_driver);
+}
+
+static void __exit scx200_acb_cleanup(void)
+{
+	struct scx200_acb_iface *iface;
+
+	platform_driver_unregister(&scx200_pci_driver);
+
+	mutex_lock(&scx200_acb_list_mutex);
+	while ((iface = scx200_acb_list) != NULL) {
+		scx200_acb_list = iface->next;
+		mutex_unlock(&scx200_acb_list_mutex);
+
+		scx200_cleanup_iface(iface);
+
+		mutex_lock(&scx200_acb_list_mutex);
+	}
+	mutex_unlock(&scx200_acb_list_mutex);
+}
+
+module_init(scx200_acb_init);
+module_exit(scx200_acb_cleanup);
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/busses/scx200_i2c.c b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/scx200_i2c.c
new file mode 100644
index 0000000..7ee0d50
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/busses/scx200_i2c.c
@@ -0,0 +1,131 @@
+/* linux/drivers/i2c/busses/scx200_i2c.c
+
+   Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com>
+
+   National Semiconductor SCx200 I2C bus on GPIO pins
+
+   Based on i2c-velleman.c Copyright (C) 1995-96, 2000 Simon G. Vogl
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.		     
+*/
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <linux/io.h>
+
+#include <linux/scx200_gpio.h>
+
+#define NAME "scx200_i2c"
+
+MODULE_AUTHOR("Christer Weinigel <wingel@nano-system.com>");
+MODULE_DESCRIPTION("NatSemi SCx200 I2C Driver");
+MODULE_LICENSE("GPL");
+
+static int scl = CONFIG_SCx200_I2C_SCL;
+static int sda = CONFIG_SCx200_I2C_SDA;
+
+module_param(scl, int, 0);
+MODULE_PARM_DESC(scl, "GPIO line for SCL");
+module_param(sda, int, 0);
+MODULE_PARM_DESC(sda, "GPIO line for SDA");
+
+static void scx200_i2c_setscl(void *data, int state)
+{
+	scx200_gpio_set(scl, state);
+}
+
+static void scx200_i2c_setsda(void *data, int state)
+{
+	scx200_gpio_set(sda, state);
+} 
+
+static int scx200_i2c_getscl(void *data)
+{
+	return scx200_gpio_get(scl);
+}
+
+static int scx200_i2c_getsda(void *data)
+{
+	return scx200_gpio_get(sda);
+}
+
+/* ------------------------------------------------------------------------
+ * Encapsulate the above functions in the correct operations structure.
+ * This is only done when more than one hardware adapter is supported.
+ */
+
+static struct i2c_algo_bit_data scx200_i2c_data = {
+	.setsda		= scx200_i2c_setsda,
+	.setscl		= scx200_i2c_setscl,
+	.getsda		= scx200_i2c_getsda,
+	.getscl		= scx200_i2c_getscl,
+	.udelay		= 10,
+	.timeout	= HZ,
+};
+
+static struct i2c_adapter scx200_i2c_ops = {
+	.owner		   = THIS_MODULE,
+	.class             = I2C_CLASS_HWMON | I2C_CLASS_SPD,
+	.algo_data	   = &scx200_i2c_data,
+	.name	= "NatSemi SCx200 I2C",
+};
+
+static int scx200_i2c_init(void)
+{
+	pr_debug(NAME ": NatSemi SCx200 I2C Driver\n");
+
+	if (!scx200_gpio_present()) {
+		printk(KERN_ERR NAME ": no SCx200 gpio pins available\n");
+		return -ENODEV;
+	}
+
+	pr_debug(NAME ": SCL=GPIO%02u, SDA=GPIO%02u\n", scl, sda);
+
+	if (scl == -1 || sda == -1 || scl == sda) {
+		printk(KERN_ERR NAME ": scl and sda must be specified\n");
+		return -EINVAL;
+	}
+
+	/* Configure GPIOs as open collector outputs */
+	scx200_gpio_configure(scl, ~2, 5);
+	scx200_gpio_configure(sda, ~2, 5);
+
+	if (i2c_bit_add_bus(&scx200_i2c_ops) < 0) {
+		printk(KERN_ERR NAME ": adapter %s registration failed\n", 
+		       scx200_i2c_ops.name);
+		return -ENODEV;
+	}
+	
+	return 0;
+}
+
+static void scx200_i2c_cleanup(void)
+{
+	i2c_del_adapter(&scx200_i2c_ops);
+}
+
+module_init(scx200_i2c_init);
+module_exit(scx200_i2c_cleanup);
+
+/*
+    Local variables:
+        compile-command: "make -k -C ../.. SUBDIRS=drivers/i2c modules"
+        c-basic-offset: 8
+    End:
+*/
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/i2c-boardinfo.c b/ap/os/linux/linux-3.4.x/drivers/i2c/i2c-boardinfo.c
new file mode 100644
index 0000000..f24cc64
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/i2c-boardinfo.c
@@ -0,0 +1,94 @@
+/*
+ * i2c-boardinfo.c - collect pre-declarations of I2C devices
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301 USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/export.h>
+#include <linux/rwsem.h>
+
+#include "i2c-core.h"
+
+
+/* These symbols are exported ONLY FOR the i2c core.
+ * No other users will be supported.
+ */
+DECLARE_RWSEM(__i2c_board_lock);
+EXPORT_SYMBOL_GPL(__i2c_board_lock);
+
+LIST_HEAD(__i2c_board_list);
+EXPORT_SYMBOL_GPL(__i2c_board_list);
+
+int __i2c_first_dynamic_bus_num;
+EXPORT_SYMBOL_GPL(__i2c_first_dynamic_bus_num);
+
+
+/**
+ * i2c_register_board_info - statically declare I2C devices
+ * @busnum: identifies the bus to which these devices belong
+ * @info: vector of i2c device descriptors
+ * @len: how many descriptors in the vector; may be zero to reserve
+ *	the specified bus number.
+ *
+ * Systems using the Linux I2C driver stack can declare tables of board info
+ * while they initialize.  This should be done in board-specific init code
+ * near arch_initcall() time, or equivalent, before any I2C adapter driver is
+ * registered.  For example, mainboard init code could define several devices,
+ * as could the init code for each daughtercard in a board stack.
+ *
+ * The I2C devices will be created later, after the adapter for the relevant
+ * bus has been registered.  After that moment, standard driver model tools
+ * are used to bind "new style" I2C drivers to the devices.  The bus number
+ * for any device declared using this routine is not available for dynamic
+ * allocation.
+ *
+ * The board info passed can safely be __initdata, but be careful of embedded
+ * pointers (for platform_data, functions, etc) since that won't be copied.
+ */
+int __init
+i2c_register_board_info(int busnum,
+	struct i2c_board_info const *info, unsigned len)
+{
+	int status;
+
+	down_write(&__i2c_board_lock);
+
+	/* dynamic bus numbers will be assigned after the last static one */
+	if (busnum >= __i2c_first_dynamic_bus_num)
+		__i2c_first_dynamic_bus_num = busnum + 1;
+
+	for (status = 0; len; len--, info++) {
+		struct i2c_devinfo	*devinfo;
+
+		devinfo = kzalloc(sizeof(*devinfo), GFP_KERNEL);
+		if (!devinfo) {
+			pr_debug("i2c-core: can't register boardinfo!\n");
+			status = -ENOMEM;
+			break;
+		}
+
+		devinfo->busnum = busnum;
+		devinfo->board_info = *info;
+		list_add_tail(&devinfo->list, &__i2c_board_list);
+	}
+
+	up_write(&__i2c_board_lock);
+
+	return status;
+}
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/i2c-core.c b/ap/os/linux/linux-3.4.x/drivers/i2c/i2c-core.c
new file mode 100644
index 0000000..6e25e25
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/i2c-core.c
@@ -0,0 +1,2136 @@
+/* i2c-core.c - a device driver for the iic-bus interface		     */
+/* ------------------------------------------------------------------------- */
+/*   Copyright (C) 1995-99 Simon G. Vogl
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+    MA 02110-1301 USA.							     */
+/* ------------------------------------------------------------------------- */
+
+/* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi>.
+   All SMBus-related things are written by Frodo Looijaard <frodol@dds.nl>
+   SMBus 2.0 support by Mark Studebaker <mdsxyz123@yahoo.com> and
+   Jean Delvare <khali@linux-fr.org>
+   Mux support by Rodolfo Giometti <giometti@enneenne.com> and
+   Michael Lawnick <michael.lawnick.ext@nsn.com> */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/idr.h>
+#include <linux/mutex.h>
+#include <linux/of_device.h>
+#include <linux/completion.h>
+#include <linux/hardirq.h>
+#include <linux/irqflags.h>
+#include <linux/rwsem.h>
+#include <linux/pm_runtime.h>
+#include <asm/uaccess.h>
+
+#include "i2c-core.h"
+
+
+/* core_lock protects i2c_adapter_idr, and guarantees
+   that device detection, deletion of detected devices, and attach_adapter
+   and detach_adapter calls are serialized */
+static DEFINE_MUTEX(core_lock);
+static DEFINE_IDR(i2c_adapter_idr);
+
+static struct device_type i2c_client_type;
+static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver);
+
+/* ------------------------------------------------------------------------- */
+
+static const struct i2c_device_id *i2c_match_id(const struct i2c_device_id *id,
+						const struct i2c_client *client)
+{
+	while (id->name[0]) {
+		if (strcmp(client->name, id->name) == 0)
+			return id;
+		id++;
+	}
+	return NULL;
+}
+
+static int i2c_device_match(struct device *dev, struct device_driver *drv)
+{
+	struct i2c_client	*client = i2c_verify_client(dev);
+	struct i2c_driver	*driver;
+
+	if (!client)
+		return 0;
+
+	/* Attempt an OF style match */
+	if (of_driver_match_device(dev, drv))
+		return 1;
+
+	driver = to_i2c_driver(drv);
+	/* match on an id table if there is one */
+	if (driver->id_table)
+		return i2c_match_id(driver->id_table, client) != NULL;
+
+	return 0;
+}
+
+#ifdef	CONFIG_HOTPLUG
+
+/* uevent helps with hotplug: modprobe -q $(MODALIAS) */
+static int i2c_device_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+	struct i2c_client	*client = to_i2c_client(dev);
+
+	if (add_uevent_var(env, "MODALIAS=%s%s",
+			   I2C_MODULE_PREFIX, client->name))
+		return -ENOMEM;
+	dev_dbg(dev, "uevent\n");
+	return 0;
+}
+
+#else
+#define i2c_device_uevent	NULL
+#endif	/* CONFIG_HOTPLUG */
+
+static int i2c_device_probe(struct device *dev)
+{
+	struct i2c_client	*client = i2c_verify_client(dev);
+	struct i2c_driver	*driver;
+	int status;
+
+	if (!client)
+		return 0;
+
+	driver = to_i2c_driver(dev->driver);
+	if (!driver->probe || !driver->id_table)
+		return -ENODEV;
+	client->driver = driver;
+	if (!device_can_wakeup(&client->dev))
+		device_init_wakeup(&client->dev,
+					client->flags & I2C_CLIENT_WAKE);
+	dev_dbg(dev, "probe\n");
+
+	status = driver->probe(client, i2c_match_id(driver->id_table, client));
+	if (status) {
+		client->driver = NULL;
+		i2c_set_clientdata(client, NULL);
+	}
+	return status;
+}
+
+static int i2c_device_remove(struct device *dev)
+{
+	struct i2c_client	*client = i2c_verify_client(dev);
+	struct i2c_driver	*driver;
+	int			status;
+
+	if (!client || !dev->driver)
+		return 0;
+
+	driver = to_i2c_driver(dev->driver);
+	if (driver->remove) {
+		dev_dbg(dev, "remove\n");
+		status = driver->remove(client);
+	} else {
+		dev->driver = NULL;
+		status = 0;
+	}
+	if (status == 0) {
+		client->driver = NULL;
+		i2c_set_clientdata(client, NULL);
+	}
+	return status;
+}
+
+static void i2c_device_shutdown(struct device *dev)
+{
+	struct i2c_client *client = i2c_verify_client(dev);
+	struct i2c_driver *driver;
+
+	if (!client || !dev->driver)
+		return;
+	driver = to_i2c_driver(dev->driver);
+	if (driver->shutdown)
+		driver->shutdown(client);
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int i2c_legacy_suspend(struct device *dev, pm_message_t mesg)
+{
+	struct i2c_client *client = i2c_verify_client(dev);
+	struct i2c_driver *driver;
+
+	if (!client || !dev->driver)
+		return 0;
+	driver = to_i2c_driver(dev->driver);
+	if (!driver->suspend)
+		return 0;
+	return driver->suspend(client, mesg);
+}
+
+static int i2c_legacy_resume(struct device *dev)
+{
+	struct i2c_client *client = i2c_verify_client(dev);
+	struct i2c_driver *driver;
+
+	if (!client || !dev->driver)
+		return 0;
+	driver = to_i2c_driver(dev->driver);
+	if (!driver->resume)
+		return 0;
+	return driver->resume(client);
+}
+
+static int i2c_device_pm_suspend(struct device *dev)
+{
+	const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
+
+	if (pm)
+		return pm_generic_suspend(dev);
+	else
+		return i2c_legacy_suspend(dev, PMSG_SUSPEND);
+}
+
+static int i2c_device_pm_resume(struct device *dev)
+{
+	const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
+
+	if (pm)
+		return pm_generic_resume(dev);
+	else
+		return i2c_legacy_resume(dev);
+}
+
+static int i2c_device_pm_freeze(struct device *dev)
+{
+	const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
+
+	if (pm)
+		return pm_generic_freeze(dev);
+	else
+		return i2c_legacy_suspend(dev, PMSG_FREEZE);
+}
+
+static int i2c_device_pm_thaw(struct device *dev)
+{
+	const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
+
+	if (pm)
+		return pm_generic_thaw(dev);
+	else
+		return i2c_legacy_resume(dev);
+}
+
+static int i2c_device_pm_poweroff(struct device *dev)
+{
+	const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
+
+	if (pm)
+		return pm_generic_poweroff(dev);
+	else
+		return i2c_legacy_suspend(dev, PMSG_HIBERNATE);
+}
+
+static int i2c_device_pm_restore(struct device *dev)
+{
+	const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
+
+	if (pm)
+		return pm_generic_restore(dev);
+	else
+		return i2c_legacy_resume(dev);
+}
+#else /* !CONFIG_PM_SLEEP */
+#define i2c_device_pm_suspend	NULL
+#define i2c_device_pm_resume	NULL
+#define i2c_device_pm_freeze	NULL
+#define i2c_device_pm_thaw	NULL
+#define i2c_device_pm_poweroff	NULL
+#define i2c_device_pm_restore	NULL
+#endif /* !CONFIG_PM_SLEEP */
+
+static void i2c_client_dev_release(struct device *dev)
+{
+	kfree(to_i2c_client(dev));
+}
+
+static ssize_t
+show_name(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	return sprintf(buf, "%s\n", dev->type == &i2c_client_type ?
+		       to_i2c_client(dev)->name : to_i2c_adapter(dev)->name);
+}
+
+static ssize_t
+show_modalias(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	return sprintf(buf, "%s%s\n", I2C_MODULE_PREFIX, client->name);
+}
+
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+static DEVICE_ATTR(modalias, S_IRUGO, show_modalias, NULL);
+
+static struct attribute *i2c_dev_attrs[] = {
+	&dev_attr_name.attr,
+	/* modalias helps coldplug:  modprobe $(cat .../modalias) */
+	&dev_attr_modalias.attr,
+	NULL
+};
+
+static struct attribute_group i2c_dev_attr_group = {
+	.attrs		= i2c_dev_attrs,
+};
+
+static const struct attribute_group *i2c_dev_attr_groups[] = {
+	&i2c_dev_attr_group,
+	NULL
+};
+
+static const struct dev_pm_ops i2c_device_pm_ops = {
+	.suspend = i2c_device_pm_suspend,
+	.resume = i2c_device_pm_resume,
+	.freeze = i2c_device_pm_freeze,
+	.thaw = i2c_device_pm_thaw,
+	.poweroff = i2c_device_pm_poweroff,
+	.restore = i2c_device_pm_restore,
+	SET_RUNTIME_PM_OPS(
+		pm_generic_runtime_suspend,
+		pm_generic_runtime_resume,
+		pm_generic_runtime_idle
+	)
+};
+
+struct bus_type i2c_bus_type = {
+	.name		= "i2c",
+	.match		= i2c_device_match,
+	.probe		= i2c_device_probe,
+	.remove		= i2c_device_remove,
+	.shutdown	= i2c_device_shutdown,
+	.pm		= &i2c_device_pm_ops,
+};
+EXPORT_SYMBOL_GPL(i2c_bus_type);
+
+static struct device_type i2c_client_type = {
+	.groups		= i2c_dev_attr_groups,
+	.uevent		= i2c_device_uevent,
+	.release	= i2c_client_dev_release,
+};
+
+
+/**
+ * i2c_verify_client - return parameter as i2c_client, or NULL
+ * @dev: device, probably from some driver model iterator
+ *
+ * When traversing the driver model tree, perhaps using driver model
+ * iterators like @device_for_each_child(), you can't assume very much
+ * about the nodes you find.  Use this function to avoid oopses caused
+ * by wrongly treating some non-I2C device as an i2c_client.
+ */
+struct i2c_client *i2c_verify_client(struct device *dev)
+{
+	return (dev->type == &i2c_client_type)
+			? to_i2c_client(dev)
+			: NULL;
+}
+EXPORT_SYMBOL(i2c_verify_client);
+
+
+/* This is a permissive address validity check, I2C address map constraints
+ * are purposely not enforced, except for the general call address. */
+static int i2c_check_client_addr_validity(const struct i2c_client *client)
+{
+	if (client->flags & I2C_CLIENT_TEN) {
+		/* 10-bit address, all values are valid */
+		if (client->addr > 0x3ff)
+			return -EINVAL;
+	} else {
+		/* 7-bit address, reject the general call address */
+		if (client->addr == 0x00 || client->addr > 0x7f)
+			return -EINVAL;
+	}
+	return 0;
+}
+
+/* And this is a strict address validity check, used when probing. If a
+ * device uses a reserved address, then it shouldn't be probed. 7-bit
+ * addressing is assumed, 10-bit address devices are rare and should be
+ * explicitly enumerated. */
+static int i2c_check_addr_validity(unsigned short addr)
+{
+	/*
+	 * Reserved addresses per I2C specification:
+	 *  0x00       General call address / START byte
+	 *  0x01       CBUS address
+	 *  0x02       Reserved for different bus format
+	 *  0x03       Reserved for future purposes
+	 *  0x04-0x07  Hs-mode master code
+	 *  0x78-0x7b  10-bit slave addressing
+	 *  0x7c-0x7f  Reserved for future purposes
+	 */
+	if (addr < 0x08 || addr > 0x77)
+		return -EINVAL;
+	return 0;
+}
+
+static int __i2c_check_addr_busy(struct device *dev, void *addrp)
+{
+	struct i2c_client	*client = i2c_verify_client(dev);
+	int			addr = *(int *)addrp;
+
+	if (client && client->addr == addr)
+		return -EBUSY;
+	return 0;
+}
+
+/* walk up mux tree */
+static int i2c_check_mux_parents(struct i2c_adapter *adapter, int addr)
+{
+	struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter);
+	int result;
+
+	result = device_for_each_child(&adapter->dev, &addr,
+					__i2c_check_addr_busy);
+
+	if (!result && parent)
+		result = i2c_check_mux_parents(parent, addr);
+
+	return result;
+}
+
+/* recurse down mux tree */
+static int i2c_check_mux_children(struct device *dev, void *addrp)
+{
+	int result;
+
+	if (dev->type == &i2c_adapter_type)
+		result = device_for_each_child(dev, addrp,
+						i2c_check_mux_children);
+	else
+		result = __i2c_check_addr_busy(dev, addrp);
+
+	return result;
+}
+
+static int i2c_check_addr_busy(struct i2c_adapter *adapter, int addr)
+{
+	struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter);
+	int result = 0;
+
+	if (parent)
+		result = i2c_check_mux_parents(parent, addr);
+
+	if (!result)
+		result = device_for_each_child(&adapter->dev, &addr,
+						i2c_check_mux_children);
+
+	return result;
+}
+
+/**
+ * i2c_lock_adapter - Get exclusive access to an I2C bus segment
+ * @adapter: Target I2C bus segment
+ */
+void i2c_lock_adapter(struct i2c_adapter *adapter)
+{
+	struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter);
+
+	if (parent)
+		i2c_lock_adapter(parent);
+	else
+		rt_mutex_lock(&adapter->bus_lock);
+}
+EXPORT_SYMBOL_GPL(i2c_lock_adapter);
+
+/**
+ * i2c_trylock_adapter - Try to get exclusive access to an I2C bus segment
+ * @adapter: Target I2C bus segment
+ */
+static int i2c_trylock_adapter(struct i2c_adapter *adapter)
+{
+	struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter);
+
+	if (parent)
+		return i2c_trylock_adapter(parent);
+	else
+		return rt_mutex_trylock(&adapter->bus_lock);
+}
+
+/**
+ * i2c_unlock_adapter - Release exclusive access to an I2C bus segment
+ * @adapter: Target I2C bus segment
+ */
+void i2c_unlock_adapter(struct i2c_adapter *adapter)
+{
+	struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter);
+
+	if (parent)
+		i2c_unlock_adapter(parent);
+	else
+		rt_mutex_unlock(&adapter->bus_lock);
+}
+EXPORT_SYMBOL_GPL(i2c_unlock_adapter);
+
+/**
+ * i2c_new_device - instantiate an i2c device
+ * @adap: the adapter managing the device
+ * @info: describes one I2C device; bus_num is ignored
+ * Context: can sleep
+ *
+ * Create an i2c device. Binding is handled through driver model
+ * probe()/remove() methods.  A driver may be bound to this device when we
+ * return from this function, or any later moment (e.g. maybe hotplugging will
+ * load the driver module).  This call is not appropriate for use by mainboard
+ * initialization logic, which usually runs during an arch_initcall() long
+ * before any i2c_adapter could exist.
+ *
+ * This returns the new i2c client, which may be saved for later use with
+ * i2c_unregister_device(); or NULL to indicate an error.
+ */
+struct i2c_client *
+i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)
+{
+	struct i2c_client	*client;
+	int			status;
+
+	client = kzalloc(sizeof *client, GFP_KERNEL);
+	if (!client)
+		return NULL;
+
+	client->adapter = adap;
+
+	client->dev.platform_data = info->platform_data;
+
+	if (info->archdata)
+		client->dev.archdata = *info->archdata;
+
+	client->flags = info->flags;
+	client->addr = info->addr;
+	client->irq = info->irq;
+
+	strlcpy(client->name, info->type, sizeof(client->name));
+
+	/* Check for address validity */
+	status = i2c_check_client_addr_validity(client);
+	if (status) {
+		dev_err(&adap->dev, "Invalid %d-bit I2C address 0x%02hx\n",
+			client->flags & I2C_CLIENT_TEN ? 10 : 7, client->addr);
+		goto out_err_silent;
+	}
+
+	/* Check for address business */
+	status = i2c_check_addr_busy(adap, client->addr);
+	if (status)
+		goto out_err;
+
+	client->dev.parent = &client->adapter->dev;
+	client->dev.bus = &i2c_bus_type;
+	client->dev.type = &i2c_client_type;
+	client->dev.of_node = info->of_node;
+
+	/* For 10-bit clients, add an arbitrary offset to avoid collisions */
+	dev_set_name(&client->dev, "%d-%04x", i2c_adapter_id(adap),
+		     client->addr | ((client->flags & I2C_CLIENT_TEN)
+				     ? 0xa000 : 0));
+	status = device_register(&client->dev);
+	if (status)
+		goto out_err;
+
+	dev_dbg(&adap->dev, "client [%s] registered with bus id %s\n",
+		client->name, dev_name(&client->dev));
+
+	return client;
+
+out_err:
+	dev_err(&adap->dev, "Failed to register i2c client %s at 0x%02x "
+		"(%d)\n", client->name, client->addr, status);
+out_err_silent:
+	kfree(client);
+	return NULL;
+}
+EXPORT_SYMBOL_GPL(i2c_new_device);
+
+
+/**
+ * i2c_unregister_device - reverse effect of i2c_new_device()
+ * @client: value returned from i2c_new_device()
+ * Context: can sleep
+ */
+void i2c_unregister_device(struct i2c_client *client)
+{
+	device_unregister(&client->dev);
+}
+EXPORT_SYMBOL_GPL(i2c_unregister_device);
+
+
+static const struct i2c_device_id dummy_id[] = {
+	{ "dummy", 0 },
+	{ },
+};
+
+static int dummy_probe(struct i2c_client *client,
+		       const struct i2c_device_id *id)
+{
+	return 0;
+}
+
+static int dummy_remove(struct i2c_client *client)
+{
+	return 0;
+}
+
+static struct i2c_driver dummy_driver = {
+	.driver.name	= "dummy",
+	.probe		= dummy_probe,
+	.remove		= dummy_remove,
+	.id_table	= dummy_id,
+};
+
+/**
+ * i2c_new_dummy - return a new i2c device bound to a dummy driver
+ * @adapter: the adapter managing the device
+ * @address: seven bit address to be used
+ * Context: can sleep
+ *
+ * This returns an I2C client bound to the "dummy" driver, intended for use
+ * with devices that consume multiple addresses.  Examples of such chips
+ * include various EEPROMS (like 24c04 and 24c08 models).
+ *
+ * These dummy devices have two main uses.  First, most I2C and SMBus calls
+ * except i2c_transfer() need a client handle; the dummy will be that handle.
+ * And second, this prevents the specified address from being bound to a
+ * different driver.
+ *
+ * This returns the new i2c client, which should be saved for later use with
+ * i2c_unregister_device(); or NULL to indicate an error.
+ */
+struct i2c_client *i2c_new_dummy(struct i2c_adapter *adapter, u16 address)
+{
+	struct i2c_board_info info = {
+		I2C_BOARD_INFO("dummy", address),
+	};
+
+	return i2c_new_device(adapter, &info);
+}
+EXPORT_SYMBOL_GPL(i2c_new_dummy);
+
+/* ------------------------------------------------------------------------- */
+
+/* I2C bus adapters -- one roots each I2C or SMBUS segment */
+
+static void i2c_adapter_dev_release(struct device *dev)
+{
+	struct i2c_adapter *adap = to_i2c_adapter(dev);
+	complete(&adap->dev_released);
+}
+
+/*
+ * Let users instantiate I2C devices through sysfs. This can be used when
+ * platform initialization code doesn't contain the proper data for
+ * whatever reason. Also useful for drivers that do device detection and
+ * detection fails, either because the device uses an unexpected address,
+ * or this is a compatible device with different ID register values.
+ *
+ * Parameter checking may look overzealous, but we really don't want
+ * the user to provide incorrect parameters.
+ */
+static ssize_t
+i2c_sysfs_new_device(struct device *dev, struct device_attribute *attr,
+		     const char *buf, size_t count)
+{
+	struct i2c_adapter *adap = to_i2c_adapter(dev);
+	struct i2c_board_info info;
+	struct i2c_client *client;
+	char *blank, end;
+	int res;
+
+	memset(&info, 0, sizeof(struct i2c_board_info));
+
+	blank = strchr(buf, ' ');
+	if (!blank) {
+		dev_err(dev, "%s: Missing parameters\n", "new_device");
+		return -EINVAL;
+	}
+	if (blank - buf > I2C_NAME_SIZE - 1) {
+		dev_err(dev, "%s: Invalid device name\n", "new_device");
+		return -EINVAL;
+	}
+	memcpy(info.type, buf, blank - buf);
+
+	/* Parse remaining parameters, reject extra parameters */
+	res = sscanf(++blank, "%hu%c", &info.addr, &end);
+	if (res < 1) {
+		dev_err(dev, "%s: Can't parse I2C address\n", "new_device");
+		return -EINVAL;
+	}
+	if (res > 1  && end != '\n') {
+		dev_err(dev, "%s: Extra parameters\n", "new_device");
+		return -EINVAL;
+	}
+
+	client = i2c_new_device(adap, &info);
+	if (!client)
+		return -EINVAL;
+
+	/* Keep track of the added device */
+	mutex_lock(&adap->userspace_clients_lock);
+	list_add_tail(&client->detected, &adap->userspace_clients);
+	mutex_unlock(&adap->userspace_clients_lock);
+	dev_info(dev, "%s: Instantiated device %s at 0x%02hx\n", "new_device",
+		 info.type, info.addr);
+
+	return count;
+}
+
+/*
+ * And of course let the users delete the devices they instantiated, if
+ * they got it wrong. This interface can only be used to delete devices
+ * instantiated by i2c_sysfs_new_device above. This guarantees that we
+ * don't delete devices to which some kernel code still has references.
+ *
+ * Parameter checking may look overzealous, but we really don't want
+ * the user to delete the wrong device.
+ */
+static ssize_t
+i2c_sysfs_delete_device(struct device *dev, struct device_attribute *attr,
+			const char *buf, size_t count)
+{
+	struct i2c_adapter *adap = to_i2c_adapter(dev);
+	struct i2c_client *client, *next;
+	unsigned short addr;
+	char end;
+	int res;
+
+	/* Parse parameters, reject extra parameters */
+	res = sscanf(buf, "%hu%c", &addr, &end);
+	if (res < 1) {
+		dev_err(dev, "%s: Can't parse I2C address\n", "delete_device");
+		return -EINVAL;
+	}
+	if (res > 1  && end != '\n') {
+		dev_err(dev, "%s: Extra parameters\n", "delete_device");
+		return -EINVAL;
+	}
+
+	/* Make sure the device was added through sysfs */
+	res = -ENOENT;
+	mutex_lock(&adap->userspace_clients_lock);
+	list_for_each_entry_safe(client, next, &adap->userspace_clients,
+				 detected) {
+		if (client->addr == addr) {
+			dev_info(dev, "%s: Deleting device %s at 0x%02hx\n",
+				 "delete_device", client->name, client->addr);
+
+			list_del(&client->detected);
+			i2c_unregister_device(client);
+			res = count;
+			break;
+		}
+	}
+	mutex_unlock(&adap->userspace_clients_lock);
+
+	if (res < 0)
+		dev_err(dev, "%s: Can't find device in list\n",
+			"delete_device");
+	return res;
+}
+
+static DEVICE_ATTR(new_device, S_IWUSR, NULL, i2c_sysfs_new_device);
+static DEVICE_ATTR(delete_device, S_IWUSR, NULL, i2c_sysfs_delete_device);
+
+static struct attribute *i2c_adapter_attrs[] = {
+	&dev_attr_name.attr,
+	&dev_attr_new_device.attr,
+	&dev_attr_delete_device.attr,
+	NULL
+};
+
+static struct attribute_group i2c_adapter_attr_group = {
+	.attrs		= i2c_adapter_attrs,
+};
+
+static const struct attribute_group *i2c_adapter_attr_groups[] = {
+	&i2c_adapter_attr_group,
+	NULL
+};
+
+struct device_type i2c_adapter_type = {
+	.groups		= i2c_adapter_attr_groups,
+	.release	= i2c_adapter_dev_release,
+};
+EXPORT_SYMBOL_GPL(i2c_adapter_type);
+
+#ifdef CONFIG_I2C_COMPAT
+static struct class_compat *i2c_adapter_compat_class;
+#endif
+
+static void i2c_scan_static_board_info(struct i2c_adapter *adapter)
+{
+	struct i2c_devinfo	*devinfo;
+
+	down_read(&__i2c_board_lock);
+	list_for_each_entry(devinfo, &__i2c_board_list, list) {
+		if (devinfo->busnum == adapter->nr
+				&& !i2c_new_device(adapter,
+						&devinfo->board_info))
+			dev_err(&adapter->dev,
+				"Can't create device at 0x%02x\n",
+				devinfo->board_info.addr);
+	}
+	up_read(&__i2c_board_lock);
+}
+
+static int i2c_do_add_adapter(struct i2c_driver *driver,
+			      struct i2c_adapter *adap)
+{
+	/* Detect supported devices on that bus, and instantiate them */
+	i2c_detect(adap, driver);
+
+	/* Let legacy drivers scan this bus for matching devices */
+	if (driver->attach_adapter) {
+		dev_warn(&adap->dev, "%s: attach_adapter method is deprecated\n",
+			 driver->driver.name);
+		dev_warn(&adap->dev, "Please use another way to instantiate "
+			 "your i2c_client\n");
+		/* We ignore the return code; if it fails, too bad */
+		driver->attach_adapter(adap);
+	}
+	return 0;
+}
+
+static int __process_new_adapter(struct device_driver *d, void *data)
+{
+	return i2c_do_add_adapter(to_i2c_driver(d), data);
+}
+
+static int i2c_register_adapter(struct i2c_adapter *adap)
+{
+	int res = 0;
+
+	/* Can't register until after driver model init */
+	if (unlikely(WARN_ON(!i2c_bus_type.p))) {
+		res = -EAGAIN;
+		goto out_list;
+	}
+
+	/* Sanity checks */
+	if (unlikely(adap->name[0] == '\0')) {
+		pr_err("i2c-core: Attempt to register an adapter with "
+		       "no name!\n");
+		return -EINVAL;
+	}
+	if (unlikely(!adap->algo)) {
+		pr_err("i2c-core: Attempt to register adapter '%s' with "
+		       "no algo!\n", adap->name);
+		return -EINVAL;
+	}
+
+	rt_mutex_init(&adap->bus_lock);
+	mutex_init(&adap->userspace_clients_lock);
+	INIT_LIST_HEAD(&adap->userspace_clients);
+
+	/* Set default timeout to 1 second if not already set */
+	if (adap->timeout == 0)
+		adap->timeout = HZ;
+
+	dev_set_name(&adap->dev, "i2c-%d", adap->nr);
+	adap->dev.bus = &i2c_bus_type;
+	adap->dev.type = &i2c_adapter_type;
+	res = device_register(&adap->dev);
+	if (res)
+		goto out_list;
+
+	dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name);
+
+#ifdef CONFIG_I2C_COMPAT
+	res = class_compat_create_link(i2c_adapter_compat_class, &adap->dev,
+				       adap->dev.parent);
+	if (res)
+		dev_warn(&adap->dev,
+			 "Failed to create compatibility class link\n");
+#endif
+
+	/* create pre-declared device nodes */
+	if (adap->nr < __i2c_first_dynamic_bus_num)
+		i2c_scan_static_board_info(adap);
+
+	/* Notify drivers */
+	mutex_lock(&core_lock);
+	bus_for_each_drv(&i2c_bus_type, NULL, adap, __process_new_adapter);
+	mutex_unlock(&core_lock);
+
+	return 0;
+
+out_list:
+	mutex_lock(&core_lock);
+	idr_remove(&i2c_adapter_idr, adap->nr);
+	mutex_unlock(&core_lock);
+	return res;
+}
+
+/**
+ * i2c_add_adapter - declare i2c adapter, use dynamic bus number
+ * @adapter: the adapter to add
+ * Context: can sleep
+ *
+ * This routine is used to declare an I2C adapter when its bus number
+ * doesn't matter.  Examples: for I2C adapters dynamically added by
+ * USB links or PCI plugin cards.
+ *
+ * When this returns zero, a new bus number was allocated and stored
+ * in adap->nr, and the specified adapter became available for clients.
+ * Otherwise, a negative errno value is returned.
+ */
+int i2c_add_adapter(struct i2c_adapter *adapter)
+{
+	int	id, res = 0;
+
+retry:
+	if (idr_pre_get(&i2c_adapter_idr, GFP_KERNEL) == 0)
+		return -ENOMEM;
+
+	mutex_lock(&core_lock);
+	/* "above" here means "above or equal to", sigh */
+	res = idr_get_new_above(&i2c_adapter_idr, adapter,
+				__i2c_first_dynamic_bus_num, &id);
+	mutex_unlock(&core_lock);
+
+	if (res < 0) {
+		if (res == -EAGAIN)
+			goto retry;
+		return res;
+	}
+
+	adapter->nr = id;
+	return i2c_register_adapter(adapter);
+}
+EXPORT_SYMBOL(i2c_add_adapter);
+
+/**
+ * i2c_add_numbered_adapter - declare i2c adapter, use static bus number
+ * @adap: the adapter to register (with adap->nr initialized)
+ * Context: can sleep
+ *
+ * This routine is used to declare an I2C adapter when its bus number
+ * matters.  For example, use it for I2C adapters from system-on-chip CPUs,
+ * or otherwise built in to the system's mainboard, and where i2c_board_info
+ * is used to properly configure I2C devices.
+ *
+ * If the requested bus number is set to -1, then this function will behave
+ * identically to i2c_add_adapter, and will dynamically assign a bus number.
+ *
+ * If no devices have pre-been declared for this bus, then be sure to
+ * register the adapter before any dynamically allocated ones.  Otherwise
+ * the required bus ID may not be available.
+ *
+ * When this returns zero, the specified adapter became available for
+ * clients using the bus number provided in adap->nr.  Also, the table
+ * of I2C devices pre-declared using i2c_register_board_info() is scanned,
+ * and the appropriate driver model device nodes are created.  Otherwise, a
+ * negative errno value is returned.
+ */
+int i2c_add_numbered_adapter(struct i2c_adapter *adap)
+{
+	int	id;
+	int	status;
+
+	if (adap->nr == -1) /* -1 means dynamically assign bus id */
+		return i2c_add_adapter(adap);
+	if (adap->nr & ~MAX_ID_MASK)
+		return -EINVAL;
+
+retry:
+	if (idr_pre_get(&i2c_adapter_idr, GFP_KERNEL) == 0)
+		return -ENOMEM;
+
+	mutex_lock(&core_lock);
+	/* "above" here means "above or equal to", sigh;
+	 * we need the "equal to" result to force the result
+	 */
+	status = idr_get_new_above(&i2c_adapter_idr, adap, adap->nr, &id);
+	if (status == 0 && id != adap->nr) {
+		status = -EBUSY;
+		idr_remove(&i2c_adapter_idr, id);
+	}
+	mutex_unlock(&core_lock);
+	if (status == -EAGAIN)
+		goto retry;
+
+	if (status == 0)
+		status = i2c_register_adapter(adap);
+	return status;
+}
+EXPORT_SYMBOL_GPL(i2c_add_numbered_adapter);
+
+static int i2c_do_del_adapter(struct i2c_driver *driver,
+			      struct i2c_adapter *adapter)
+{
+	struct i2c_client *client, *_n;
+	int res;
+
+	/* Remove the devices we created ourselves as the result of hardware
+	 * probing (using a driver's detect method) */
+	list_for_each_entry_safe(client, _n, &driver->clients, detected) {
+		if (client->adapter == adapter) {
+			dev_dbg(&adapter->dev, "Removing %s at 0x%x\n",
+				client->name, client->addr);
+			list_del(&client->detected);
+			i2c_unregister_device(client);
+		}
+	}
+
+	if (!driver->detach_adapter)
+		return 0;
+	dev_warn(&adapter->dev, "%s: detach_adapter method is deprecated\n",
+		 driver->driver.name);
+	res = driver->detach_adapter(adapter);
+	if (res)
+		dev_err(&adapter->dev, "detach_adapter failed (%d) "
+			"for driver [%s]\n", res, driver->driver.name);
+	return res;
+}
+
+static int __unregister_client(struct device *dev, void *dummy)
+{
+	struct i2c_client *client = i2c_verify_client(dev);
+	if (client && strcmp(client->name, "dummy"))
+		i2c_unregister_device(client);
+	return 0;
+}
+
+static int __unregister_dummy(struct device *dev, void *dummy)
+{
+	struct i2c_client *client = i2c_verify_client(dev);
+	if (client)
+		i2c_unregister_device(client);
+	return 0;
+}
+
+static int __process_removed_adapter(struct device_driver *d, void *data)
+{
+	return i2c_do_del_adapter(to_i2c_driver(d), data);
+}
+
+/**
+ * i2c_del_adapter - unregister I2C adapter
+ * @adap: the adapter being unregistered
+ * Context: can sleep
+ *
+ * This unregisters an I2C adapter which was previously registered
+ * by @i2c_add_adapter or @i2c_add_numbered_adapter.
+ */
+int i2c_del_adapter(struct i2c_adapter *adap)
+{
+	int res = 0;
+	struct i2c_adapter *found;
+	struct i2c_client *client, *next;
+
+	/* First make sure that this adapter was ever added */
+	mutex_lock(&core_lock);
+	found = idr_find(&i2c_adapter_idr, adap->nr);
+	mutex_unlock(&core_lock);
+	if (found != adap) {
+		pr_debug("i2c-core: attempting to delete unregistered "
+			 "adapter [%s]\n", adap->name);
+		return -EINVAL;
+	}
+
+	/* Tell drivers about this removal */
+	mutex_lock(&core_lock);
+	res = bus_for_each_drv(&i2c_bus_type, NULL, adap,
+			       __process_removed_adapter);
+	mutex_unlock(&core_lock);
+	if (res)
+		return res;
+
+	/* Remove devices instantiated from sysfs */
+	mutex_lock(&adap->userspace_clients_lock);
+	list_for_each_entry_safe(client, next, &adap->userspace_clients,
+				 detected) {
+		dev_dbg(&adap->dev, "Removing %s at 0x%x\n", client->name,
+			client->addr);
+		list_del(&client->detected);
+		i2c_unregister_device(client);
+	}
+	mutex_unlock(&adap->userspace_clients_lock);
+
+	/* Detach any active clients. This can't fail, thus we do not
+	 * check the returned value. This is a two-pass process, because
+	 * we can't remove the dummy devices during the first pass: they
+	 * could have been instantiated by real devices wishing to clean
+	 * them up properly, so we give them a chance to do that first. */
+	res = device_for_each_child(&adap->dev, NULL, __unregister_client);
+	res = device_for_each_child(&adap->dev, NULL, __unregister_dummy);
+
+#ifdef CONFIG_I2C_COMPAT
+	class_compat_remove_link(i2c_adapter_compat_class, &adap->dev,
+				 adap->dev.parent);
+#endif
+
+	/* device name is gone after device_unregister */
+	dev_dbg(&adap->dev, "adapter [%s] unregistered\n", adap->name);
+
+	/* clean up the sysfs representation */
+	init_completion(&adap->dev_released);
+	device_unregister(&adap->dev);
+
+	/* wait for sysfs to drop all references */
+	wait_for_completion(&adap->dev_released);
+
+	/* free bus id */
+	mutex_lock(&core_lock);
+	idr_remove(&i2c_adapter_idr, adap->nr);
+	mutex_unlock(&core_lock);
+
+	/* Clear the device structure in case this adapter is ever going to be
+	   added again */
+	memset(&adap->dev, 0, sizeof(adap->dev));
+
+	return 0;
+}
+EXPORT_SYMBOL(i2c_del_adapter);
+
+
+/* ------------------------------------------------------------------------- */
+
+int i2c_for_each_dev(void *data, int (*fn)(struct device *, void *))
+{
+	int res;
+
+	mutex_lock(&core_lock);
+	res = bus_for_each_dev(&i2c_bus_type, NULL, data, fn);
+	mutex_unlock(&core_lock);
+
+	return res;
+}
+EXPORT_SYMBOL_GPL(i2c_for_each_dev);
+
+static int __process_new_driver(struct device *dev, void *data)
+{
+	if (dev->type != &i2c_adapter_type)
+		return 0;
+	return i2c_do_add_adapter(data, to_i2c_adapter(dev));
+}
+
+/*
+ * An i2c_driver is used with one or more i2c_client (device) nodes to access
+ * i2c slave chips, on a bus instance associated with some i2c_adapter.
+ */
+
+int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
+{
+	int res;
+
+	/* Can't register until after driver model init */
+	if (unlikely(WARN_ON(!i2c_bus_type.p)))
+		return -EAGAIN;
+
+	/* add the driver to the list of i2c drivers in the driver core */
+	driver->driver.owner = owner;
+	driver->driver.bus = &i2c_bus_type;
+
+	/* When registration returns, the driver core
+	 * will have called probe() for all matching-but-unbound devices.
+	 */
+	res = driver_register(&driver->driver);
+	if (res)
+		return res;
+
+	/* Drivers should switch to dev_pm_ops instead. */
+	if (driver->suspend)
+		pr_warn("i2c-core: driver [%s] using legacy suspend method\n",
+			driver->driver.name);
+	if (driver->resume)
+		pr_warn("i2c-core: driver [%s] using legacy resume method\n",
+			driver->driver.name);
+
+	pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name);
+
+	INIT_LIST_HEAD(&driver->clients);
+	/* Walk the adapters that are already present */
+	i2c_for_each_dev(driver, __process_new_driver);
+
+	return 0;
+}
+EXPORT_SYMBOL(i2c_register_driver);
+
+static int __process_removed_driver(struct device *dev, void *data)
+{
+	if (dev->type != &i2c_adapter_type)
+		return 0;
+	return i2c_do_del_adapter(data, to_i2c_adapter(dev));
+}
+
+/**
+ * i2c_del_driver - unregister I2C driver
+ * @driver: the driver being unregistered
+ * Context: can sleep
+ */
+void i2c_del_driver(struct i2c_driver *driver)
+{
+	i2c_for_each_dev(driver, __process_removed_driver);
+
+	driver_unregister(&driver->driver);
+	pr_debug("i2c-core: driver [%s] unregistered\n", driver->driver.name);
+}
+EXPORT_SYMBOL(i2c_del_driver);
+
+/* ------------------------------------------------------------------------- */
+
+/**
+ * i2c_use_client - increments the reference count of the i2c client structure
+ * @client: the client being referenced
+ *
+ * Each live reference to a client should be refcounted. The driver model does
+ * that automatically as part of driver binding, so that most drivers don't
+ * need to do this explicitly: they hold a reference until they're unbound
+ * from the device.
+ *
+ * A pointer to the client with the incremented reference counter is returned.
+ */
+struct i2c_client *i2c_use_client(struct i2c_client *client)
+{
+	if (client && get_device(&client->dev))
+		return client;
+	return NULL;
+}
+EXPORT_SYMBOL(i2c_use_client);
+
+/**
+ * i2c_release_client - release a use of the i2c client structure
+ * @client: the client being no longer referenced
+ *
+ * Must be called when a user of a client is finished with it.
+ */
+void i2c_release_client(struct i2c_client *client)
+{
+	if (client)
+		put_device(&client->dev);
+}
+EXPORT_SYMBOL(i2c_release_client);
+
+struct i2c_cmd_arg {
+	unsigned	cmd;
+	void		*arg;
+};
+
+static int i2c_cmd(struct device *dev, void *_arg)
+{
+	struct i2c_client	*client = i2c_verify_client(dev);
+	struct i2c_cmd_arg	*arg = _arg;
+
+	if (client && client->driver && client->driver->command)
+		client->driver->command(client, arg->cmd, arg->arg);
+	return 0;
+}
+
+void i2c_clients_command(struct i2c_adapter *adap, unsigned int cmd, void *arg)
+{
+	struct i2c_cmd_arg	cmd_arg;
+
+	cmd_arg.cmd = cmd;
+	cmd_arg.arg = arg;
+	device_for_each_child(&adap->dev, &cmd_arg, i2c_cmd);
+}
+EXPORT_SYMBOL(i2c_clients_command);
+
+static int __init i2c_init(void)
+{
+	int retval;
+
+	retval = bus_register(&i2c_bus_type);
+	if (retval)
+		return retval;
+#ifdef CONFIG_I2C_COMPAT
+	i2c_adapter_compat_class = class_compat_register("i2c-adapter");
+	if (!i2c_adapter_compat_class) {
+		retval = -ENOMEM;
+		goto bus_err;
+	}
+#endif
+	retval = i2c_add_driver(&dummy_driver);
+	if (retval)
+		goto class_err;
+	return 0;
+
+class_err:
+#ifdef CONFIG_I2C_COMPAT
+	class_compat_unregister(i2c_adapter_compat_class);
+bus_err:
+#endif
+	bus_unregister(&i2c_bus_type);
+	return retval;
+}
+
+static void __exit i2c_exit(void)
+{
+	i2c_del_driver(&dummy_driver);
+#ifdef CONFIG_I2C_COMPAT
+	class_compat_unregister(i2c_adapter_compat_class);
+#endif
+	bus_unregister(&i2c_bus_type);
+}
+
+/* We must initialize early, because some subsystems register i2c drivers
+ * in subsys_initcall() code, but are linked (and initialized) before i2c.
+ */
+postcore_initcall(i2c_init);
+module_exit(i2c_exit);
+
+/* ----------------------------------------------------
+ * the functional interface to the i2c busses.
+ * ----------------------------------------------------
+ */
+
+/**
+ * i2c_transfer - execute a single or combined I2C message
+ * @adap: Handle to I2C bus
+ * @msgs: One or more messages to execute before STOP is issued to
+ *	terminate the operation; each message begins with a START.
+ * @num: Number of messages to be executed.
+ *
+ * Returns negative errno, else the number of messages executed.
+ *
+ * Note that there is no requirement that each message be sent to
+ * the same slave address, although that is the most common model.
+ */
+int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+{
+	unsigned long orig_jiffies;
+	int ret, try;
+
+	/* REVISIT the fault reporting model here is weak:
+	 *
+	 *  - When we get an error after receiving N bytes from a slave,
+	 *    there is no way to report "N".
+	 *
+	 *  - When we get a NAK after transmitting N bytes to a slave,
+	 *    there is no way to report "N" ... or to let the master
+	 *    continue executing the rest of this combined message, if
+	 *    that's the appropriate response.
+	 *
+	 *  - When for example "num" is two and we successfully complete
+	 *    the first message but get an error part way through the
+	 *    second, it's unclear whether that should be reported as
+	 *    one (discarding status on the second message) or errno
+	 *    (discarding status on the first one).
+	 */
+
+	if (adap->algo->master_xfer) {
+#ifdef DEBUG
+		for (ret = 0; ret < num; ret++) {
+			dev_dbg(&adap->dev, "master_xfer[%d] %c, addr=0x%02x, "
+				"len=%d%s\n", ret, (msgs[ret].flags & I2C_M_RD)
+				? 'R' : 'W', msgs[ret].addr, msgs[ret].len,
+				(msgs[ret].flags & I2C_M_RECV_LEN) ? "+" : "");
+		}
+#endif
+
+		if (in_atomic() || irqs_disabled()) {
+			ret = i2c_trylock_adapter(adap);
+			if (!ret)
+				/* I2C activity is ongoing. */
+				return -EAGAIN;
+		} else {
+			i2c_lock_adapter(adap);
+		}
+
+		/* Retry automatically on arbitration loss */
+		orig_jiffies = jiffies;
+		for (ret = 0, try = 0; try <= adap->retries; try++) {
+			ret = adap->algo->master_xfer(adap, msgs, num);
+			if (ret != -EAGAIN)
+				break;
+			if (time_after(jiffies, orig_jiffies + adap->timeout))
+				break;
+		}
+		i2c_unlock_adapter(adap);
+
+		return ret;
+	} else {
+		dev_dbg(&adap->dev, "I2C level transfers not supported\n");
+		return -EOPNOTSUPP;
+	}
+}
+EXPORT_SYMBOL(i2c_transfer);
+
+/**
+ * i2c_master_send - issue a single I2C message in master transmit mode
+ * @client: Handle to slave device
+ * @buf: Data that will be written to the slave
+ * @count: How many bytes to write, must be less than 64k since msg.len is u16
+ *
+ * Returns negative errno, or else the number of bytes written.
+ */
+int i2c_master_send(const struct i2c_client *client, const char *buf, int count)
+{
+	int ret;
+	struct i2c_adapter *adap = client->adapter;
+	struct i2c_msg msg;
+
+	msg.addr = client->addr;
+	msg.flags = client->flags & I2C_M_TEN;
+	msg.len = count;
+	msg.buf = (char *)buf;
+
+	ret = i2c_transfer(adap, &msg, 1);
+
+	/*
+	 * If everything went ok (i.e. 1 msg transmitted), return #bytes
+	 * transmitted, else error code.
+	 */
+	return (ret == 1) ? count : ret;
+}
+EXPORT_SYMBOL(i2c_master_send);
+
+/**
+ * i2c_master_recv - issue a single I2C message in master receive mode
+ * @client: Handle to slave device
+ * @buf: Where to store data read from slave
+ * @count: How many bytes to read, must be less than 64k since msg.len is u16
+ *
+ * Returns negative errno, or else the number of bytes read.
+ */
+int i2c_master_recv(const struct i2c_client *client, char *buf, int count)
+{
+	struct i2c_adapter *adap = client->adapter;
+	struct i2c_msg msg;
+	int ret;
+
+	msg.addr = client->addr;
+	msg.flags = client->flags & I2C_M_TEN;
+	msg.flags |= I2C_M_RD;
+	msg.len = count;
+	msg.buf = buf;
+
+	ret = i2c_transfer(adap, &msg, 1);
+
+	/*
+	 * If everything went ok (i.e. 1 msg received), return #bytes received,
+	 * else error code.
+	 */
+	return (ret == 1) ? count : ret;
+}
+EXPORT_SYMBOL(i2c_master_recv);
+
+/* ----------------------------------------------------
+ * the i2c address scanning function
+ * Will not work for 10-bit addresses!
+ * ----------------------------------------------------
+ */
+
+/*
+ * Legacy default probe function, mostly relevant for SMBus. The default
+ * probe method is a quick write, but it is known to corrupt the 24RF08
+ * EEPROMs due to a state machine bug, and could also irreversibly
+ * write-protect some EEPROMs, so for address ranges 0x30-0x37 and 0x50-0x5f,
+ * we use a short byte read instead. Also, some bus drivers don't implement
+ * quick write, so we fallback to a byte read in that case too.
+ * On x86, there is another special case for FSC hardware monitoring chips,
+ * which want regular byte reads (address 0x73.) Fortunately, these are the
+ * only known chips using this I2C address on PC hardware.
+ * Returns 1 if probe succeeded, 0 if not.
+ */
+static int i2c_default_probe(struct i2c_adapter *adap, unsigned short addr)
+{
+	int err;
+	union i2c_smbus_data dummy;
+
+#ifdef CONFIG_X86
+	if (addr == 0x73 && (adap->class & I2C_CLASS_HWMON)
+	 && i2c_check_functionality(adap, I2C_FUNC_SMBUS_READ_BYTE_DATA))
+		err = i2c_smbus_xfer(adap, addr, 0, I2C_SMBUS_READ, 0,
+				     I2C_SMBUS_BYTE_DATA, &dummy);
+	else
+#endif
+	if (!((addr & ~0x07) == 0x30 || (addr & ~0x0f) == 0x50)
+	 && i2c_check_functionality(adap, I2C_FUNC_SMBUS_QUICK))
+		err = i2c_smbus_xfer(adap, addr, 0, I2C_SMBUS_WRITE, 0,
+				     I2C_SMBUS_QUICK, NULL);
+	else if (i2c_check_functionality(adap, I2C_FUNC_SMBUS_READ_BYTE))
+		err = i2c_smbus_xfer(adap, addr, 0, I2C_SMBUS_READ, 0,
+				     I2C_SMBUS_BYTE, &dummy);
+	else {
+		dev_warn(&adap->dev, "No suitable probing method supported\n");
+		err = -EOPNOTSUPP;
+	}
+
+	return err >= 0;
+}
+
+static int i2c_detect_address(struct i2c_client *temp_client,
+			      struct i2c_driver *driver)
+{
+	struct i2c_board_info info;
+	struct i2c_adapter *adapter = temp_client->adapter;
+	int addr = temp_client->addr;
+	int err;
+
+	/* Make sure the address is valid */
+	err = i2c_check_addr_validity(addr);
+	if (err) {
+		dev_warn(&adapter->dev, "Invalid probe address 0x%02x\n",
+			 addr);
+		return err;
+	}
+
+	/* Skip if already in use */
+	if (i2c_check_addr_busy(adapter, addr))
+		return 0;
+
+	/* Make sure there is something at this address */
+	if (!i2c_default_probe(adapter, addr))
+		return 0;
+
+	/* Finally call the custom detection function */
+	memset(&info, 0, sizeof(struct i2c_board_info));
+	info.addr = addr;
+	err = driver->detect(temp_client, &info);
+	if (err) {
+		/* -ENODEV is returned if the detection fails. We catch it
+		   here as this isn't an error. */
+		return err == -ENODEV ? 0 : err;
+	}
+
+	/* Consistency check */
+	if (info.type[0] == '\0') {
+		dev_err(&adapter->dev, "%s detection function provided "
+			"no name for 0x%x\n", driver->driver.name,
+			addr);
+	} else {
+		struct i2c_client *client;
+
+		/* Detection succeeded, instantiate the device */
+		dev_dbg(&adapter->dev, "Creating %s at 0x%02x\n",
+			info.type, info.addr);
+		client = i2c_new_device(adapter, &info);
+		if (client)
+			list_add_tail(&client->detected, &driver->clients);
+		else
+			dev_err(&adapter->dev, "Failed creating %s at 0x%02x\n",
+				info.type, info.addr);
+	}
+	return 0;
+}
+
+static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver)
+{
+	const unsigned short *address_list;
+	struct i2c_client *temp_client;
+	int i, err = 0;
+	int adap_id = i2c_adapter_id(adapter);
+
+	address_list = driver->address_list;
+	if (!driver->detect || !address_list)
+		return 0;
+
+	/* Stop here if the classes do not match */
+	if (!(adapter->class & driver->class))
+		return 0;
+
+	/* Set up a temporary client to help detect callback */
+	temp_client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
+	if (!temp_client)
+		return -ENOMEM;
+	temp_client->adapter = adapter;
+
+	for (i = 0; address_list[i] != I2C_CLIENT_END; i += 1) {
+		dev_dbg(&adapter->dev, "found normal entry for adapter %d, "
+			"addr 0x%02x\n", adap_id, address_list[i]);
+		temp_client->addr = address_list[i];
+		err = i2c_detect_address(temp_client, driver);
+		if (unlikely(err))
+			break;
+	}
+
+	kfree(temp_client);
+	return err;
+}
+
+int i2c_probe_func_quick_read(struct i2c_adapter *adap, unsigned short addr)
+{
+	return i2c_smbus_xfer(adap, addr, 0, I2C_SMBUS_READ, 0,
+			      I2C_SMBUS_QUICK, NULL) >= 0;
+}
+EXPORT_SYMBOL_GPL(i2c_probe_func_quick_read);
+
+struct i2c_client *
+i2c_new_probed_device(struct i2c_adapter *adap,
+		      struct i2c_board_info *info,
+		      unsigned short const *addr_list,
+		      int (*probe)(struct i2c_adapter *, unsigned short addr))
+{
+	int i;
+
+	if (!probe)
+		probe = i2c_default_probe;
+
+	for (i = 0; addr_list[i] != I2C_CLIENT_END; i++) {
+		/* Check address validity */
+		if (i2c_check_addr_validity(addr_list[i]) < 0) {
+			dev_warn(&adap->dev, "Invalid 7-bit address "
+				 "0x%02x\n", addr_list[i]);
+			continue;
+		}
+
+		/* Check address availability */
+		if (i2c_check_addr_busy(adap, addr_list[i])) {
+			dev_dbg(&adap->dev, "Address 0x%02x already in "
+				"use, not probing\n", addr_list[i]);
+			continue;
+		}
+
+		/* Test address responsiveness */
+		if (probe(adap, addr_list[i]))
+			break;
+	}
+
+	if (addr_list[i] == I2C_CLIENT_END) {
+		dev_dbg(&adap->dev, "Probing failed, no device found\n");
+		return NULL;
+	}
+
+	info->addr = addr_list[i];
+	return i2c_new_device(adap, info);
+}
+EXPORT_SYMBOL_GPL(i2c_new_probed_device);
+
+struct i2c_adapter *i2c_get_adapter(int nr)
+{
+	struct i2c_adapter *adapter;
+
+	mutex_lock(&core_lock);
+	adapter = idr_find(&i2c_adapter_idr, nr);
+	if (adapter && !try_module_get(adapter->owner))
+		adapter = NULL;
+
+	mutex_unlock(&core_lock);
+	return adapter;
+}
+EXPORT_SYMBOL(i2c_get_adapter);
+
+void i2c_put_adapter(struct i2c_adapter *adap)
+{
+	module_put(adap->owner);
+}
+EXPORT_SYMBOL(i2c_put_adapter);
+
+/* The SMBus parts */
+
+#define POLY    (0x1070U << 3)
+static u8 crc8(u16 data)
+{
+	int i;
+
+	for (i = 0; i < 8; i++) {
+		if (data & 0x8000)
+			data = data ^ POLY;
+		data = data << 1;
+	}
+	return (u8)(data >> 8);
+}
+
+/* Incremental CRC8 over count bytes in the array pointed to by p */
+static u8 i2c_smbus_pec(u8 crc, u8 *p, size_t count)
+{
+	int i;
+
+	for (i = 0; i < count; i++)
+		crc = crc8((crc ^ p[i]) << 8);
+	return crc;
+}
+
+/* Assume a 7-bit address, which is reasonable for SMBus */
+static u8 i2c_smbus_msg_pec(u8 pec, struct i2c_msg *msg)
+{
+	/* The address will be sent first */
+	u8 addr = (msg->addr << 1) | !!(msg->flags & I2C_M_RD);
+	pec = i2c_smbus_pec(pec, &addr, 1);
+
+	/* The data buffer follows */
+	return i2c_smbus_pec(pec, msg->buf, msg->len);
+}
+
+/* Used for write only transactions */
+static inline void i2c_smbus_add_pec(struct i2c_msg *msg)
+{
+	msg->buf[msg->len] = i2c_smbus_msg_pec(0, msg);
+	msg->len++;
+}
+
+/* Return <0 on CRC error
+   If there was a write before this read (most cases) we need to take the
+   partial CRC from the write part into account.
+   Note that this function does modify the message (we need to decrease the
+   message length to hide the CRC byte from the caller). */
+static int i2c_smbus_check_pec(u8 cpec, struct i2c_msg *msg)
+{
+	u8 rpec = msg->buf[--msg->len];
+	cpec = i2c_smbus_msg_pec(cpec, msg);
+
+	if (rpec != cpec) {
+		pr_debug("i2c-core: Bad PEC 0x%02x vs. 0x%02x\n",
+			rpec, cpec);
+		return -EBADMSG;
+	}
+	return 0;
+}
+
+/**
+ * i2c_smbus_read_byte - SMBus "receive byte" protocol
+ * @client: Handle to slave device
+ *
+ * This executes the SMBus "receive byte" protocol, returning negative errno
+ * else the byte received from the device.
+ */
+s32 i2c_smbus_read_byte(const struct i2c_client *client)
+{
+	union i2c_smbus_data data;
+	int status;
+
+	status = i2c_smbus_xfer(client->adapter, client->addr, client->flags,
+				I2C_SMBUS_READ, 0,
+				I2C_SMBUS_BYTE, &data);
+	return (status < 0) ? status : data.byte;
+}
+EXPORT_SYMBOL(i2c_smbus_read_byte);
+
+/**
+ * i2c_smbus_write_byte - SMBus "send byte" protocol
+ * @client: Handle to slave device
+ * @value: Byte to be sent
+ *
+ * This executes the SMBus "send byte" protocol, returning negative errno
+ * else zero on success.
+ */
+s32 i2c_smbus_write_byte(const struct i2c_client *client, u8 value)
+{
+	return i2c_smbus_xfer(client->adapter, client->addr, client->flags,
+	                      I2C_SMBUS_WRITE, value, I2C_SMBUS_BYTE, NULL);
+}
+EXPORT_SYMBOL(i2c_smbus_write_byte);
+
+/**
+ * i2c_smbus_read_byte_data - SMBus "read byte" protocol
+ * @client: Handle to slave device
+ * @command: Byte interpreted by slave
+ *
+ * This executes the SMBus "read byte" protocol, returning negative errno
+ * else a data byte received from the device.
+ */
+s32 i2c_smbus_read_byte_data(const struct i2c_client *client, u8 command)
+{
+	union i2c_smbus_data data;
+	int status;
+
+	status = i2c_smbus_xfer(client->adapter, client->addr, client->flags,
+				I2C_SMBUS_READ, command,
+				I2C_SMBUS_BYTE_DATA, &data);
+	return (status < 0) ? status : data.byte;
+}
+EXPORT_SYMBOL(i2c_smbus_read_byte_data);
+
+/**
+ * i2c_smbus_write_byte_data - SMBus "write byte" protocol
+ * @client: Handle to slave device
+ * @command: Byte interpreted by slave
+ * @value: Byte being written
+ *
+ * This executes the SMBus "write byte" protocol, returning negative errno
+ * else zero on success.
+ */
+s32 i2c_smbus_write_byte_data(const struct i2c_client *client, u8 command,
+			      u8 value)
+{
+	union i2c_smbus_data data;
+	data.byte = value;
+	return i2c_smbus_xfer(client->adapter, client->addr, client->flags,
+			      I2C_SMBUS_WRITE, command,
+			      I2C_SMBUS_BYTE_DATA, &data);
+}
+EXPORT_SYMBOL(i2c_smbus_write_byte_data);
+
+/**
+ * i2c_smbus_read_word_data - SMBus "read word" protocol
+ * @client: Handle to slave device
+ * @command: Byte interpreted by slave
+ *
+ * This executes the SMBus "read word" protocol, returning negative errno
+ * else a 16-bit unsigned "word" received from the device.
+ */
+s32 i2c_smbus_read_word_data(const struct i2c_client *client, u8 command)
+{
+	union i2c_smbus_data data;
+	int status;
+
+	status = i2c_smbus_xfer(client->adapter, client->addr, client->flags,
+				I2C_SMBUS_READ, command,
+				I2C_SMBUS_WORD_DATA, &data);
+	return (status < 0) ? status : data.word;
+}
+EXPORT_SYMBOL(i2c_smbus_read_word_data);
+
+/**
+ * i2c_smbus_write_word_data - SMBus "write word" protocol
+ * @client: Handle to slave device
+ * @command: Byte interpreted by slave
+ * @value: 16-bit "word" being written
+ *
+ * This executes the SMBus "write word" protocol, returning negative errno
+ * else zero on success.
+ */
+s32 i2c_smbus_write_word_data(const struct i2c_client *client, u8 command,
+			      u16 value)
+{
+	union i2c_smbus_data data;
+	data.word = value;
+	return i2c_smbus_xfer(client->adapter, client->addr, client->flags,
+			      I2C_SMBUS_WRITE, command,
+			      I2C_SMBUS_WORD_DATA, &data);
+}
+EXPORT_SYMBOL(i2c_smbus_write_word_data);
+
+/**
+ * i2c_smbus_process_call - SMBus "process call" protocol
+ * @client: Handle to slave device
+ * @command: Byte interpreted by slave
+ * @value: 16-bit "word" being written
+ *
+ * This executes the SMBus "process call" protocol, returning negative errno
+ * else a 16-bit unsigned "word" received from the device.
+ */
+s32 i2c_smbus_process_call(const struct i2c_client *client, u8 command,
+			   u16 value)
+{
+	union i2c_smbus_data data;
+	int status;
+	data.word = value;
+
+	status = i2c_smbus_xfer(client->adapter, client->addr, client->flags,
+				I2C_SMBUS_WRITE, command,
+				I2C_SMBUS_PROC_CALL, &data);
+	return (status < 0) ? status : data.word;
+}
+EXPORT_SYMBOL(i2c_smbus_process_call);
+
+/**
+ * i2c_smbus_read_block_data - SMBus "block read" protocol
+ * @client: Handle to slave device
+ * @command: Byte interpreted by slave
+ * @values: Byte array into which data will be read; big enough to hold
+ *	the data returned by the slave.  SMBus allows at most 32 bytes.
+ *
+ * This executes the SMBus "block read" protocol, returning negative errno
+ * else the number of data bytes in the slave's response.
+ *
+ * Note that using this function requires that the client's adapter support
+ * the I2C_FUNC_SMBUS_READ_BLOCK_DATA functionality.  Not all adapter drivers
+ * support this; its emulation through I2C messaging relies on a specific
+ * mechanism (I2C_M_RECV_LEN) which may not be implemented.
+ */
+s32 i2c_smbus_read_block_data(const struct i2c_client *client, u8 command,
+			      u8 *values)
+{
+	union i2c_smbus_data data;
+	int status;
+
+	status = i2c_smbus_xfer(client->adapter, client->addr, client->flags,
+				I2C_SMBUS_READ, command,
+				I2C_SMBUS_BLOCK_DATA, &data);
+	if (status)
+		return status;
+
+	memcpy(values, &data.block[1], data.block[0]);
+	return data.block[0];
+}
+EXPORT_SYMBOL(i2c_smbus_read_block_data);
+
+/**
+ * i2c_smbus_write_block_data - SMBus "block write" protocol
+ * @client: Handle to slave device
+ * @command: Byte interpreted by slave
+ * @length: Size of data block; SMBus allows at most 32 bytes
+ * @values: Byte array which will be written.
+ *
+ * This executes the SMBus "block write" protocol, returning negative errno
+ * else zero on success.
+ */
+s32 i2c_smbus_write_block_data(const struct i2c_client *client, u8 command,
+			       u8 length, const u8 *values)
+{
+	union i2c_smbus_data data;
+
+	if (length > I2C_SMBUS_BLOCK_MAX)
+		length = I2C_SMBUS_BLOCK_MAX;
+	data.block[0] = length;
+	memcpy(&data.block[1], values, length);
+	return i2c_smbus_xfer(client->adapter, client->addr, client->flags,
+			      I2C_SMBUS_WRITE, command,
+			      I2C_SMBUS_BLOCK_DATA, &data);
+}
+EXPORT_SYMBOL(i2c_smbus_write_block_data);
+
+/* Returns the number of read bytes */
+s32 i2c_smbus_read_i2c_block_data(const struct i2c_client *client, u8 command,
+				  u8 length, u8 *values)
+{
+	union i2c_smbus_data data;
+	int status;
+
+	if (length > I2C_SMBUS_BLOCK_MAX)
+		length = I2C_SMBUS_BLOCK_MAX;
+	data.block[0] = length;
+	status = i2c_smbus_xfer(client->adapter, client->addr, client->flags,
+				I2C_SMBUS_READ, command,
+				I2C_SMBUS_I2C_BLOCK_DATA, &data);
+	if (status < 0)
+		return status;
+
+	memcpy(values, &data.block[1], data.block[0]);
+	return data.block[0];
+}
+EXPORT_SYMBOL(i2c_smbus_read_i2c_block_data);
+
+s32 i2c_smbus_write_i2c_block_data(const struct i2c_client *client, u8 command,
+				   u8 length, const u8 *values)
+{
+	union i2c_smbus_data data;
+
+	if (length > I2C_SMBUS_BLOCK_MAX)
+		length = I2C_SMBUS_BLOCK_MAX;
+	data.block[0] = length;
+	memcpy(data.block + 1, values, length);
+	return i2c_smbus_xfer(client->adapter, client->addr, client->flags,
+			      I2C_SMBUS_WRITE, command,
+			      I2C_SMBUS_I2C_BLOCK_DATA, &data);
+}
+EXPORT_SYMBOL(i2c_smbus_write_i2c_block_data);
+
+/* Simulate a SMBus command using the i2c protocol
+   No checking of parameters is done!  */
+static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr,
+				   unsigned short flags,
+				   char read_write, u8 command, int size,
+				   union i2c_smbus_data *data)
+{
+	/* So we need to generate a series of msgs. In the case of writing, we
+	  need to use only one message; when reading, we need two. We initialize
+	  most things with sane defaults, to keep the code below somewhat
+	  simpler. */
+	unsigned char msgbuf0[I2C_SMBUS_BLOCK_MAX+3];
+	unsigned char msgbuf1[I2C_SMBUS_BLOCK_MAX+2];
+	int num = read_write == I2C_SMBUS_READ ? 2 : 1;
+	struct i2c_msg msg[2] = { { addr, flags, 1, msgbuf0 },
+	                          { addr, flags | I2C_M_RD, 0, msgbuf1 }
+	                        };
+	int i;
+	u8 partial_pec = 0;
+	int status;
+
+	msgbuf0[0] = command;
+	switch (size) {
+	case I2C_SMBUS_QUICK:
+		msg[0].len = 0;
+		/* Special case: The read/write field is used as data */
+		msg[0].flags = flags | (read_write == I2C_SMBUS_READ ?
+					I2C_M_RD : 0);
+		num = 1;
+		break;
+	case I2C_SMBUS_BYTE:
+		if (read_write == I2C_SMBUS_READ) {
+			/* Special case: only a read! */
+			msg[0].flags = I2C_M_RD | flags;
+			num = 1;
+		}
+		break;
+	case I2C_SMBUS_BYTE_DATA:
+		if (read_write == I2C_SMBUS_READ)
+			msg[1].len = 1;
+		else {
+			msg[0].len = 2;
+			msgbuf0[1] = data->byte;
+		}
+		break;
+	case I2C_SMBUS_WORD_DATA:
+		if (read_write == I2C_SMBUS_READ)
+			msg[1].len = 2;
+		else {
+			msg[0].len = 3;
+			msgbuf0[1] = data->word & 0xff;
+			msgbuf0[2] = data->word >> 8;
+		}
+		break;
+	case I2C_SMBUS_PROC_CALL:
+		num = 2; /* Special case */
+		read_write = I2C_SMBUS_READ;
+		msg[0].len = 3;
+		msg[1].len = 2;
+		msgbuf0[1] = data->word & 0xff;
+		msgbuf0[2] = data->word >> 8;
+		break;
+	case I2C_SMBUS_BLOCK_DATA:
+		if (read_write == I2C_SMBUS_READ) {
+			msg[1].flags |= I2C_M_RECV_LEN;
+			msg[1].len = 1; /* block length will be added by
+					   the underlying bus driver */
+		} else {
+			msg[0].len = data->block[0] + 2;
+			if (msg[0].len > I2C_SMBUS_BLOCK_MAX + 2) {
+				dev_err(&adapter->dev,
+					"Invalid block write size %d\n",
+					data->block[0]);
+				return -EINVAL;
+			}
+			for (i = 1; i < msg[0].len; i++)
+				msgbuf0[i] = data->block[i-1];
+		}
+		break;
+	case I2C_SMBUS_BLOCK_PROC_CALL:
+		num = 2; /* Another special case */
+		read_write = I2C_SMBUS_READ;
+		if (data->block[0] > I2C_SMBUS_BLOCK_MAX) {
+			dev_err(&adapter->dev,
+				"Invalid block write size %d\n",
+				data->block[0]);
+			return -EINVAL;
+		}
+		msg[0].len = data->block[0] + 2;
+		for (i = 1; i < msg[0].len; i++)
+			msgbuf0[i] = data->block[i-1];
+		msg[1].flags |= I2C_M_RECV_LEN;
+		msg[1].len = 1; /* block length will be added by
+				   the underlying bus driver */
+		break;
+	case I2C_SMBUS_I2C_BLOCK_DATA:
+		if (read_write == I2C_SMBUS_READ) {
+			msg[1].len = data->block[0];
+		} else {
+			msg[0].len = data->block[0] + 1;
+			if (msg[0].len > I2C_SMBUS_BLOCK_MAX + 1) {
+				dev_err(&adapter->dev,
+					"Invalid block write size %d\n",
+					data->block[0]);
+				return -EINVAL;
+			}
+			for (i = 1; i <= data->block[0]; i++)
+				msgbuf0[i] = data->block[i];
+		}
+		break;
+	default:
+		dev_err(&adapter->dev, "Unsupported transaction %d\n", size);
+		return -EOPNOTSUPP;
+	}
+
+	i = ((flags & I2C_CLIENT_PEC) && size != I2C_SMBUS_QUICK
+				      && size != I2C_SMBUS_I2C_BLOCK_DATA);
+	if (i) {
+		/* Compute PEC if first message is a write */
+		if (!(msg[0].flags & I2C_M_RD)) {
+			if (num == 1) /* Write only */
+				i2c_smbus_add_pec(&msg[0]);
+			else /* Write followed by read */
+				partial_pec = i2c_smbus_msg_pec(0, &msg[0]);
+		}
+		/* Ask for PEC if last message is a read */
+		if (msg[num-1].flags & I2C_M_RD)
+			msg[num-1].len++;
+	}
+
+	status = i2c_transfer(adapter, msg, num);
+	if (status < 0)
+		return status;
+
+	/* Check PEC if last message is a read */
+	if (i && (msg[num-1].flags & I2C_M_RD)) {
+		status = i2c_smbus_check_pec(partial_pec, &msg[num-1]);
+		if (status < 0)
+			return status;
+	}
+
+	if (read_write == I2C_SMBUS_READ)
+		switch (size) {
+		case I2C_SMBUS_BYTE:
+			data->byte = msgbuf0[0];
+			break;
+		case I2C_SMBUS_BYTE_DATA:
+			data->byte = msgbuf1[0];
+			break;
+		case I2C_SMBUS_WORD_DATA:
+		case I2C_SMBUS_PROC_CALL:
+			data->word = msgbuf1[0] | (msgbuf1[1] << 8);
+			break;
+		case I2C_SMBUS_I2C_BLOCK_DATA:
+			for (i = 0; i < data->block[0]; i++)
+				data->block[i+1] = msgbuf1[i];
+			break;
+		case I2C_SMBUS_BLOCK_DATA:
+		case I2C_SMBUS_BLOCK_PROC_CALL:
+			for (i = 0; i < msgbuf1[0] + 1; i++)
+				data->block[i] = msgbuf1[i];
+			break;
+		}
+	return 0;
+}
+
+/**
+ * i2c_smbus_xfer - execute SMBus protocol operations
+ * @adapter: Handle to I2C bus
+ * @addr: Address of SMBus slave on that bus
+ * @flags: I2C_CLIENT_* flags (usually zero or I2C_CLIENT_PEC)
+ * @read_write: I2C_SMBUS_READ or I2C_SMBUS_WRITE
+ * @command: Byte interpreted by slave, for protocols which use such bytes
+ * @protocol: SMBus protocol operation to execute, such as I2C_SMBUS_PROC_CALL
+ * @data: Data to be read or written
+ *
+ * This executes an SMBus protocol operation, and returns a negative
+ * errno code else zero on success.
+ */
+s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags,
+		   char read_write, u8 command, int protocol,
+		   union i2c_smbus_data *data)
+{
+	unsigned long orig_jiffies;
+	int try;
+	s32 res;
+
+	flags &= I2C_M_TEN | I2C_CLIENT_PEC;
+
+	if (adapter->algo->smbus_xfer) {
+		i2c_lock_adapter(adapter);
+
+		/* Retry automatically on arbitration loss */
+		orig_jiffies = jiffies;
+		for (res = 0, try = 0; try <= adapter->retries; try++) {
+			res = adapter->algo->smbus_xfer(adapter, addr, flags,
+							read_write, command,
+							protocol, data);
+			if (res != -EAGAIN)
+				break;
+			if (time_after(jiffies,
+				       orig_jiffies + adapter->timeout))
+				break;
+		}
+		i2c_unlock_adapter(adapter);
+	} else
+		res = i2c_smbus_xfer_emulated(adapter, addr, flags, read_write,
+					      command, protocol, data);
+
+	return res;
+}
+EXPORT_SYMBOL(i2c_smbus_xfer);
+
+MODULE_AUTHOR("Simon G. Vogl <simon@tk.uni-linz.ac.at>");
+MODULE_DESCRIPTION("I2C-Bus main module");
+MODULE_LICENSE("GPL");
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/i2c-core.h b/ap/os/linux/linux-3.4.x/drivers/i2c/i2c-core.h
new file mode 100644
index 0000000..18a8fd2
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/i2c-core.h
@@ -0,0 +1,34 @@
+/*
+ * i2c-core.h - interfaces internal to the I2C framework
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301 USA.
+ */
+
+#include <linux/rwsem.h>
+
+struct i2c_devinfo {
+	struct list_head	list;
+	int			busnum;
+	struct i2c_board_info	board_info;
+};
+
+/* board_lock protects board_list and first_dynamic_bus_num.
+ * only i2c core components are allowed to use these symbols.
+ */
+extern struct rw_semaphore	__i2c_board_lock;
+extern struct list_head	__i2c_board_list;
+extern int		__i2c_first_dynamic_bus_num;
+
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/i2c-dev.c b/ap/os/linux/linux-3.4.x/drivers/i2c/i2c-dev.c
new file mode 100644
index 0000000..4504832
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/i2c-dev.c
@@ -0,0 +1,652 @@
+/*
+    i2c-dev.c - i2c-bus driver, char device interface
+
+    Copyright (C) 1995-97 Simon G. Vogl
+    Copyright (C) 1998-99 Frodo Looijaard <frodol@dds.nl>
+    Copyright (C) 2003 Greg Kroah-Hartman <greg@kroah.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+    MA 02110-1301 USA.
+*/
+
+/* Note that this is a complete rewrite of Simon Vogl's i2c-dev module.
+   But I have used so much of his original code and ideas that it seems
+   only fair to recognize him as co-author -- Frodo */
+
+/* The I2C_RDWR ioctl code is written by Kolja Waschk <waschk@telos.de> */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/notifier.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+#include <linux/jiffies.h>
+#include <linux/uaccess.h>
+
+/*
+ * An i2c_dev represents an i2c_adapter ... an I2C or SMBus master, not a
+ * slave (i2c_client) with which messages will be exchanged.  It's coupled
+ * with a character special file which is accessed by user mode drivers.
+ *
+ * The list of i2c_dev structures is parallel to the i2c_adapter lists
+ * maintained by the driver model, and is updated using bus notifications.
+ */
+struct i2c_dev {
+	struct list_head list;
+	struct i2c_adapter *adap;
+	struct device *dev;
+};
+
+#define I2C_MINORS	256
+static LIST_HEAD(i2c_dev_list);
+static DEFINE_SPINLOCK(i2c_dev_list_lock);
+
+static struct i2c_dev *i2c_dev_get_by_minor(unsigned index)
+{
+	struct i2c_dev *i2c_dev;
+
+	spin_lock(&i2c_dev_list_lock);
+	list_for_each_entry(i2c_dev, &i2c_dev_list, list) {
+		if (i2c_dev->adap->nr == index)
+			goto found;
+	}
+	i2c_dev = NULL;
+found:
+	spin_unlock(&i2c_dev_list_lock);
+	return i2c_dev;
+}
+
+static struct i2c_dev *get_free_i2c_dev(struct i2c_adapter *adap)
+{
+	struct i2c_dev *i2c_dev;
+
+	if (adap->nr >= I2C_MINORS) {
+		printk(KERN_ERR "i2c-dev: Out of device minors (%d)\n",
+		       adap->nr);
+		return ERR_PTR(-ENODEV);
+	}
+
+	i2c_dev = kzalloc(sizeof(*i2c_dev), GFP_KERNEL);
+	if (!i2c_dev)
+		return ERR_PTR(-ENOMEM);
+	i2c_dev->adap = adap;
+
+	spin_lock(&i2c_dev_list_lock);
+	list_add_tail(&i2c_dev->list, &i2c_dev_list);
+	spin_unlock(&i2c_dev_list_lock);
+	return i2c_dev;
+}
+
+static void return_i2c_dev(struct i2c_dev *i2c_dev)
+{
+	spin_lock(&i2c_dev_list_lock);
+	list_del(&i2c_dev->list);
+	spin_unlock(&i2c_dev_list_lock);
+	kfree(i2c_dev);
+}
+
+static ssize_t show_adapter_name(struct device *dev,
+				 struct device_attribute *attr, char *buf)
+{
+	struct i2c_dev *i2c_dev = i2c_dev_get_by_minor(MINOR(dev->devt));
+
+	if (!i2c_dev)
+		return -ENODEV;
+	return sprintf(buf, "%s\n", i2c_dev->adap->name);
+}
+static DEVICE_ATTR(name, S_IRUGO, show_adapter_name, NULL);
+
+/* ------------------------------------------------------------------------- */
+
+/*
+ * After opening an instance of this character special file, a file
+ * descriptor starts out associated only with an i2c_adapter (and bus).
+ *
+ * Using the I2C_RDWR ioctl(), you can then *immediately* issue i2c_msg
+ * traffic to any devices on the bus used by that adapter.  That's because
+ * the i2c_msg vectors embed all the addressing information they need, and
+ * are submitted directly to an i2c_adapter.  However, SMBus-only adapters
+ * don't support that interface.
+ *
+ * To use read()/write() system calls on that file descriptor, or to use
+ * SMBus interfaces (and work with SMBus-only hosts!), you must first issue
+ * an I2C_SLAVE (or I2C_SLAVE_FORCE) ioctl.  That configures an anonymous
+ * (never registered) i2c_client so it holds the addressing information
+ * needed by those system calls and by this SMBus interface.
+ */
+
+static ssize_t i2cdev_read(struct file *file, char __user *buf, size_t count,
+		loff_t *offset)
+{
+	char *tmp;
+	int ret;
+
+	struct i2c_client *client = file->private_data;
+
+	if (count > 8192)
+		count = 8192;
+
+	tmp = kmalloc(count, GFP_KERNEL);
+	if (tmp == NULL)
+		return -ENOMEM;
+
+	pr_debug("i2c-dev: i2c-%d reading %zu bytes.\n",
+		iminor(file->f_path.dentry->d_inode), count);
+
+	ret = i2c_master_recv(client, tmp, count);
+	if (ret >= 0)
+		ret = copy_to_user(buf, tmp, count) ? -EFAULT : ret;
+	kfree(tmp);
+	return ret;
+}
+
+static ssize_t i2cdev_write(struct file *file, const char __user *buf,
+		size_t count, loff_t *offset)
+{
+	int ret;
+	char *tmp;
+	struct i2c_client *client = file->private_data;
+
+	if (count > 8192)
+		count = 8192;
+
+	tmp = memdup_user(buf, count);
+	if (IS_ERR(tmp))
+		return PTR_ERR(tmp);
+
+	pr_debug("i2c-dev: i2c-%d writing %zu bytes.\n",
+		iminor(file->f_path.dentry->d_inode), count);
+
+	ret = i2c_master_send(client, tmp, count);
+	kfree(tmp);
+	return ret;
+}
+
+static int i2cdev_check(struct device *dev, void *addrp)
+{
+	struct i2c_client *client = i2c_verify_client(dev);
+
+	if (!client || client->addr != *(unsigned int *)addrp)
+		return 0;
+
+	return dev->driver ? -EBUSY : 0;
+}
+
+/* walk up mux tree */
+static int i2cdev_check_mux_parents(struct i2c_adapter *adapter, int addr)
+{
+	struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter);
+	int result;
+
+	result = device_for_each_child(&adapter->dev, &addr, i2cdev_check);
+	if (!result && parent)
+		result = i2cdev_check_mux_parents(parent, addr);
+
+	return result;
+}
+
+/* recurse down mux tree */
+static int i2cdev_check_mux_children(struct device *dev, void *addrp)
+{
+	int result;
+
+	if (dev->type == &i2c_adapter_type)
+		result = device_for_each_child(dev, addrp,
+						i2cdev_check_mux_children);
+	else
+		result = i2cdev_check(dev, addrp);
+
+	return result;
+}
+
+/* This address checking function differs from the one in i2c-core
+   in that it considers an address with a registered device, but no
+   driver bound to it, as NOT busy. */
+static int i2cdev_check_addr(struct i2c_adapter *adapter, unsigned int addr)
+{
+	struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter);
+	int result = 0;
+
+	if (parent)
+		result = i2cdev_check_mux_parents(parent, addr);
+
+	if (!result)
+		result = device_for_each_child(&adapter->dev, &addr,
+						i2cdev_check_mux_children);
+
+	return result;
+}
+
+static noinline int i2cdev_ioctl_rdrw(struct i2c_client *client,
+		unsigned long arg)
+{
+	struct i2c_rdwr_ioctl_data rdwr_arg;
+	struct i2c_msg *rdwr_pa;
+	u8 __user **data_ptrs;
+	int i, res;
+
+	if (copy_from_user(&rdwr_arg,
+			   (struct i2c_rdwr_ioctl_data __user *)arg,
+			   sizeof(rdwr_arg)))
+		return -EFAULT;
+
+	/* Put an arbitrary limit on the number of messages that can
+	 * be sent at once */
+	if (rdwr_arg.nmsgs > I2C_RDRW_IOCTL_MAX_MSGS)
+		return -EINVAL;
+
+	rdwr_pa = memdup_user(rdwr_arg.msgs,
+			      rdwr_arg.nmsgs * sizeof(struct i2c_msg));
+	if (IS_ERR(rdwr_pa))
+		return PTR_ERR(rdwr_pa);
+
+	data_ptrs = kmalloc(rdwr_arg.nmsgs * sizeof(u8 __user *), GFP_KERNEL);
+	if (data_ptrs == NULL) {
+		kfree(rdwr_pa);
+		return -ENOMEM;
+	}
+
+	res = 0;
+	for (i = 0; i < rdwr_arg.nmsgs; i++) {
+		/* Limit the size of the message to a sane amount;
+		 * and don't let length change either. */
+		if ((rdwr_pa[i].len > 8192) ||
+		    (rdwr_pa[i].flags & I2C_M_RECV_LEN)) {
+			res = -EINVAL;
+			break;
+		}
+		data_ptrs[i] = (u8 __user *)rdwr_pa[i].buf;
+		rdwr_pa[i].buf = memdup_user(data_ptrs[i], rdwr_pa[i].len);
+		if (IS_ERR(rdwr_pa[i].buf)) {
+			res = PTR_ERR(rdwr_pa[i].buf);
+			break;
+		}
+	}
+	if (res < 0) {
+		int j;
+		for (j = 0; j < i; ++j)
+			kfree(rdwr_pa[j].buf);
+		kfree(data_ptrs);
+		kfree(rdwr_pa);
+		return res;
+	}
+
+	res = i2c_transfer(client->adapter, rdwr_pa, rdwr_arg.nmsgs);
+	while (i-- > 0) {
+		if (res >= 0 && (rdwr_pa[i].flags & I2C_M_RD)) {
+			if (copy_to_user(data_ptrs[i], rdwr_pa[i].buf,
+					 rdwr_pa[i].len))
+				res = -EFAULT;
+		}
+		kfree(rdwr_pa[i].buf);
+	}
+	kfree(data_ptrs);
+	kfree(rdwr_pa);
+	return res;
+}
+
+static noinline int i2cdev_ioctl_smbus(struct i2c_client *client,
+		unsigned long arg)
+{
+	struct i2c_smbus_ioctl_data data_arg;
+	union i2c_smbus_data temp;
+	int datasize, res;
+
+	if (copy_from_user(&data_arg,
+			   (struct i2c_smbus_ioctl_data __user *) arg,
+			   sizeof(struct i2c_smbus_ioctl_data)))
+		return -EFAULT;
+	if ((data_arg.size != I2C_SMBUS_BYTE) &&
+	    (data_arg.size != I2C_SMBUS_QUICK) &&
+	    (data_arg.size != I2C_SMBUS_BYTE_DATA) &&
+	    (data_arg.size != I2C_SMBUS_WORD_DATA) &&
+	    (data_arg.size != I2C_SMBUS_PROC_CALL) &&
+	    (data_arg.size != I2C_SMBUS_BLOCK_DATA) &&
+	    (data_arg.size != I2C_SMBUS_I2C_BLOCK_BROKEN) &&
+	    (data_arg.size != I2C_SMBUS_I2C_BLOCK_DATA) &&
+	    (data_arg.size != I2C_SMBUS_BLOCK_PROC_CALL)) {
+		dev_dbg(&client->adapter->dev,
+			"size out of range (%x) in ioctl I2C_SMBUS.\n",
+			data_arg.size);
+		return -EINVAL;
+	}
+	/* Note that I2C_SMBUS_READ and I2C_SMBUS_WRITE are 0 and 1,
+	   so the check is valid if size==I2C_SMBUS_QUICK too. */
+	if ((data_arg.read_write != I2C_SMBUS_READ) &&
+	    (data_arg.read_write != I2C_SMBUS_WRITE)) {
+		dev_dbg(&client->adapter->dev,
+			"read_write out of range (%x) in ioctl I2C_SMBUS.\n",
+			data_arg.read_write);
+		return -EINVAL;
+	}
+
+	/* Note that command values are always valid! */
+
+	if ((data_arg.size == I2C_SMBUS_QUICK) ||
+	    ((data_arg.size == I2C_SMBUS_BYTE) &&
+	    (data_arg.read_write == I2C_SMBUS_WRITE)))
+		/* These are special: we do not use data */
+		return i2c_smbus_xfer(client->adapter, client->addr,
+				      client->flags, data_arg.read_write,
+				      data_arg.command, data_arg.size, NULL);
+
+	if (data_arg.data == NULL) {
+		dev_dbg(&client->adapter->dev,
+			"data is NULL pointer in ioctl I2C_SMBUS.\n");
+		return -EINVAL;
+	}
+
+	if ((data_arg.size == I2C_SMBUS_BYTE_DATA) ||
+	    (data_arg.size == I2C_SMBUS_BYTE))
+		datasize = sizeof(data_arg.data->byte);
+	else if ((data_arg.size == I2C_SMBUS_WORD_DATA) ||
+		 (data_arg.size == I2C_SMBUS_PROC_CALL))
+		datasize = sizeof(data_arg.data->word);
+	else /* size == smbus block, i2c block, or block proc. call */
+		datasize = sizeof(data_arg.data->block);
+
+	if ((data_arg.size == I2C_SMBUS_PROC_CALL) ||
+	    (data_arg.size == I2C_SMBUS_BLOCK_PROC_CALL) ||
+	    (data_arg.size == I2C_SMBUS_I2C_BLOCK_DATA) ||
+	    (data_arg.read_write == I2C_SMBUS_WRITE)) {
+		if (copy_from_user(&temp, data_arg.data, datasize))
+			return -EFAULT;
+	}
+	if (data_arg.size == I2C_SMBUS_I2C_BLOCK_BROKEN) {
+		/* Convert old I2C block commands to the new
+		   convention. This preserves binary compatibility. */
+		data_arg.size = I2C_SMBUS_I2C_BLOCK_DATA;
+		if (data_arg.read_write == I2C_SMBUS_READ)
+			temp.block[0] = I2C_SMBUS_BLOCK_MAX;
+	}
+	res = i2c_smbus_xfer(client->adapter, client->addr, client->flags,
+	      data_arg.read_write, data_arg.command, data_arg.size, &temp);
+	if (!res && ((data_arg.size == I2C_SMBUS_PROC_CALL) ||
+		     (data_arg.size == I2C_SMBUS_BLOCK_PROC_CALL) ||
+		     (data_arg.read_write == I2C_SMBUS_READ))) {
+		if (copy_to_user(data_arg.data, &temp, datasize))
+			return -EFAULT;
+	}
+	return res;
+}
+
+static long i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct i2c_client *client = file->private_data;
+	unsigned long funcs;
+
+	dev_dbg(&client->adapter->dev, "ioctl, cmd=0x%02x, arg=0x%02lx\n",
+		cmd, arg);
+
+	switch (cmd) {
+	case I2C_SLAVE:
+	case I2C_SLAVE_FORCE:
+		/* NOTE:  devices set up to work with "new style" drivers
+		 * can't use I2C_SLAVE, even when the device node is not
+		 * bound to a driver.  Only I2C_SLAVE_FORCE will work.
+		 *
+		 * Setting the PEC flag here won't affect kernel drivers,
+		 * which will be using the i2c_client node registered with
+		 * the driver model core.  Likewise, when that client has
+		 * the PEC flag already set, the i2c-dev driver won't see
+		 * (or use) this setting.
+		 */
+		if ((arg > 0x3ff) ||
+		    (((client->flags & I2C_M_TEN) == 0) && arg > 0x7f))
+			return -EINVAL;
+		if (cmd == I2C_SLAVE && i2cdev_check_addr(client->adapter, arg))
+			return -EBUSY;
+		/* REVISIT: address could become busy later */
+		client->addr = arg;
+		return 0;
+	case I2C_TENBIT:
+		if (arg)
+			client->flags |= I2C_M_TEN;
+		else
+			client->flags &= ~I2C_M_TEN;
+		return 0;
+	case I2C_PEC:
+		if (arg)
+			client->flags |= I2C_CLIENT_PEC;
+		else
+			client->flags &= ~I2C_CLIENT_PEC;
+		return 0;
+	case I2C_FUNCS:
+		funcs = i2c_get_functionality(client->adapter);
+		return put_user(funcs, (unsigned long __user *)arg);
+
+	case I2C_RDWR:
+		return i2cdev_ioctl_rdrw(client, arg);
+
+	case I2C_SMBUS:
+		return i2cdev_ioctl_smbus(client, arg);
+
+	case I2C_RETRIES:
+		client->adapter->retries = arg;
+		break;
+	case I2C_TIMEOUT:
+		/* For historical reasons, user-space sets the timeout
+		 * value in units of 10 ms.
+		 */
+		client->adapter->timeout = msecs_to_jiffies(arg * 10);
+		break;
+	default:
+		/* NOTE:  returning a fault code here could cause trouble
+		 * in buggy userspace code.  Some old kernel bugs returned
+		 * zero in this case, and userspace code might accidentally
+		 * have depended on that bug.
+		 */
+		return -ENOTTY;
+	}
+	return 0;
+}
+
+static int i2cdev_open(struct inode *inode, struct file *file)
+{
+	unsigned int minor = iminor(inode);
+	struct i2c_client *client;
+	struct i2c_adapter *adap;
+	struct i2c_dev *i2c_dev;
+
+	i2c_dev = i2c_dev_get_by_minor(minor);
+	if (!i2c_dev)
+		return -ENODEV;
+
+	adap = i2c_get_adapter(i2c_dev->adap->nr);
+	if (!adap)
+		return -ENODEV;
+
+	/* This creates an anonymous i2c_client, which may later be
+	 * pointed to some address using I2C_SLAVE or I2C_SLAVE_FORCE.
+	 *
+	 * This client is ** NEVER REGISTERED ** with the driver model
+	 * or I2C core code!!  It just holds private copies of addressing
+	 * information and maybe a PEC flag.
+	 */
+	client = kzalloc(sizeof(*client), GFP_KERNEL);
+	if (!client) {
+		i2c_put_adapter(adap);
+		return -ENOMEM;
+	}
+	snprintf(client->name, I2C_NAME_SIZE, "i2c-dev %d", adap->nr);
+
+	client->adapter = adap;
+	file->private_data = client;
+
+	return 0;
+}
+
+static int i2cdev_release(struct inode *inode, struct file *file)
+{
+	struct i2c_client *client = file->private_data;
+
+	i2c_put_adapter(client->adapter);
+	kfree(client);
+	file->private_data = NULL;
+
+	return 0;
+}
+
+static const struct file_operations i2cdev_fops = {
+	.owner		= THIS_MODULE,
+	.llseek		= no_llseek,
+	.read		= i2cdev_read,
+	.write		= i2cdev_write,
+	.unlocked_ioctl	= i2cdev_ioctl,
+	.open		= i2cdev_open,
+	.release	= i2cdev_release,
+};
+
+/* ------------------------------------------------------------------------- */
+
+static struct class *i2c_dev_class;
+
+static int i2cdev_attach_adapter(struct device *dev, void *dummy)
+{
+	struct i2c_adapter *adap;
+	struct i2c_dev *i2c_dev;
+	int res;
+
+	if (dev->type != &i2c_adapter_type)
+		return 0;
+	adap = to_i2c_adapter(dev);
+
+	i2c_dev = get_free_i2c_dev(adap);
+	if (IS_ERR(i2c_dev))
+		return PTR_ERR(i2c_dev);
+
+	/* register this i2c device with the driver core */
+	i2c_dev->dev = device_create(i2c_dev_class, &adap->dev,
+				     MKDEV(I2C_MAJOR, adap->nr), NULL,
+				     "i2c-%d", adap->nr);
+	if (IS_ERR(i2c_dev->dev)) {
+		res = PTR_ERR(i2c_dev->dev);
+		goto error;
+	}
+	res = device_create_file(i2c_dev->dev, &dev_attr_name);
+	if (res)
+		goto error_destroy;
+
+	pr_debug("i2c-dev: adapter [%s] registered as minor %d\n",
+		 adap->name, adap->nr);
+	return 0;
+error_destroy:
+	device_destroy(i2c_dev_class, MKDEV(I2C_MAJOR, adap->nr));
+error:
+	return_i2c_dev(i2c_dev);
+	return res;
+}
+
+static int i2cdev_detach_adapter(struct device *dev, void *dummy)
+{
+	struct i2c_adapter *adap;
+	struct i2c_dev *i2c_dev;
+
+	if (dev->type != &i2c_adapter_type)
+		return 0;
+	adap = to_i2c_adapter(dev);
+
+	i2c_dev = i2c_dev_get_by_minor(adap->nr);
+	if (!i2c_dev) /* attach_adapter must have failed */
+		return 0;
+
+	device_remove_file(i2c_dev->dev, &dev_attr_name);
+	return_i2c_dev(i2c_dev);
+	device_destroy(i2c_dev_class, MKDEV(I2C_MAJOR, adap->nr));
+
+	pr_debug("i2c-dev: adapter [%s] unregistered\n", adap->name);
+	return 0;
+}
+
+static int i2cdev_notifier_call(struct notifier_block *nb, unsigned long action,
+			 void *data)
+{
+	struct device *dev = data;
+
+	switch (action) {
+	case BUS_NOTIFY_ADD_DEVICE:
+		return i2cdev_attach_adapter(dev, NULL);
+	case BUS_NOTIFY_DEL_DEVICE:
+		return i2cdev_detach_adapter(dev, NULL);
+	}
+
+	return 0;
+}
+
+static struct notifier_block i2cdev_notifier = {
+	.notifier_call = i2cdev_notifier_call,
+};
+
+/* ------------------------------------------------------------------------- */
+
+/*
+ * module load/unload record keeping
+ */
+
+static int __init i2c_dev_init(void)
+{
+	int res;
+
+	printk(KERN_INFO "i2c /dev entries driver\n");
+
+	res = register_chrdev(I2C_MAJOR, "i2c", &i2cdev_fops);
+	if (res)
+		goto out;
+
+	i2c_dev_class = class_create(THIS_MODULE, "i2c-dev");
+	if (IS_ERR(i2c_dev_class)) {
+		res = PTR_ERR(i2c_dev_class);
+		goto out_unreg_chrdev;
+	}
+
+	/* Keep track of adapters which will be added or removed later */
+	res = bus_register_notifier(&i2c_bus_type, &i2cdev_notifier);
+	if (res)
+		goto out_unreg_class;
+
+	/* Bind to already existing adapters right away */
+	i2c_for_each_dev(NULL, i2cdev_attach_adapter);
+
+	return 0;
+
+out_unreg_class:
+	class_destroy(i2c_dev_class);
+out_unreg_chrdev:
+	unregister_chrdev(I2C_MAJOR, "i2c");
+out:
+	printk(KERN_ERR "%s: Driver Initialisation failed\n", __FILE__);
+	return res;
+}
+
+static void __exit i2c_dev_exit(void)
+{
+	bus_unregister_notifier(&i2c_bus_type, &i2cdev_notifier);
+	i2c_for_each_dev(NULL, i2cdev_detach_adapter);
+	class_destroy(i2c_dev_class);
+	unregister_chrdev(I2C_MAJOR, "i2c");
+}
+
+MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl> and "
+		"Simon G. Vogl <simon@tk.uni-linz.ac.at>");
+MODULE_DESCRIPTION("I2C /dev entries driver");
+MODULE_LICENSE("GPL");
+
+module_init(i2c_dev_init);
+module_exit(i2c_dev_exit);
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/i2c-mux.c b/ap/os/linux/linux-3.4.x/drivers/i2c/i2c-mux.c
new file mode 100644
index 0000000..d7a4833
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/i2c-mux.c
@@ -0,0 +1,164 @@
+/*
+ * Multiplexed I2C bus driver.
+ *
+ * Copyright (c) 2008-2009 Rodolfo Giometti <giometti@linux.it>
+ * Copyright (c) 2008-2009 Eurotech S.p.A. <info@eurotech.it>
+ * Copyright (c) 2009-2010 NSN GmbH & Co KG <michael.lawnick.ext@nsn.com>
+ *
+ * Simplifies access to complex multiplexed I2C bus topologies, by presenting
+ * each multiplexed bus segment as an additional I2C adapter.
+ * Supports multi-level mux'ing (mux behind a mux).
+ *
+ * Based on:
+ *	i2c-virt.c from Kumar Gala <galak@kernel.crashing.org>
+ *	i2c-virtual.c from Ken Harrenstien, Copyright (c) 2004 Google, Inc.
+ *	i2c-virtual.c from Brian Kuschak <bkuschak@yahoo.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/i2c-mux.h>
+
+/* multiplexer per channel data */
+struct i2c_mux_priv {
+	struct i2c_adapter adap;
+	struct i2c_algorithm algo;
+
+	struct i2c_adapter *parent;
+	void *mux_dev;	/* the mux chip/device */
+	u32  chan_id;	/* the channel id */
+
+	int (*select)(struct i2c_adapter *, void *mux_dev, u32 chan_id);
+	int (*deselect)(struct i2c_adapter *, void *mux_dev, u32 chan_id);
+};
+
+static int i2c_mux_master_xfer(struct i2c_adapter *adap,
+			       struct i2c_msg msgs[], int num)
+{
+	struct i2c_mux_priv *priv = adap->algo_data;
+	struct i2c_adapter *parent = priv->parent;
+	int ret;
+
+	/* Switch to the right mux port and perform the transfer. */
+
+	ret = priv->select(parent, priv->mux_dev, priv->chan_id);
+	if (ret >= 0)
+		ret = parent->algo->master_xfer(parent, msgs, num);
+	if (priv->deselect)
+		priv->deselect(parent, priv->mux_dev, priv->chan_id);
+
+	return ret;
+}
+
+static int i2c_mux_smbus_xfer(struct i2c_adapter *adap,
+			      u16 addr, unsigned short flags,
+			      char read_write, u8 command,
+			      int size, union i2c_smbus_data *data)
+{
+	struct i2c_mux_priv *priv = adap->algo_data;
+	struct i2c_adapter *parent = priv->parent;
+	int ret;
+
+	/* Select the right mux port and perform the transfer. */
+
+	ret = priv->select(parent, priv->mux_dev, priv->chan_id);
+	if (ret >= 0)
+		ret = parent->algo->smbus_xfer(parent, addr, flags,
+					read_write, command, size, data);
+	if (priv->deselect)
+		priv->deselect(parent, priv->mux_dev, priv->chan_id);
+
+	return ret;
+}
+
+/* Return the parent's functionality */
+static u32 i2c_mux_functionality(struct i2c_adapter *adap)
+{
+	struct i2c_mux_priv *priv = adap->algo_data;
+	struct i2c_adapter *parent = priv->parent;
+
+	return parent->algo->functionality(parent);
+}
+
+struct i2c_adapter *i2c_add_mux_adapter(struct i2c_adapter *parent,
+				void *mux_dev, u32 force_nr, u32 chan_id,
+				int (*select) (struct i2c_adapter *,
+					       void *, u32),
+				int (*deselect) (struct i2c_adapter *,
+						 void *, u32))
+{
+	struct i2c_mux_priv *priv;
+	int ret;
+
+	priv = kzalloc(sizeof(struct i2c_mux_priv), GFP_KERNEL);
+	if (!priv)
+		return NULL;
+
+	/* Set up private adapter data */
+	priv->parent = parent;
+	priv->mux_dev = mux_dev;
+	priv->chan_id = chan_id;
+	priv->select = select;
+	priv->deselect = deselect;
+
+	/* Need to do algo dynamically because we don't know ahead
+	 * of time what sort of physical adapter we'll be dealing with.
+	 */
+	if (parent->algo->master_xfer)
+		priv->algo.master_xfer = i2c_mux_master_xfer;
+	if (parent->algo->smbus_xfer)
+		priv->algo.smbus_xfer = i2c_mux_smbus_xfer;
+	priv->algo.functionality = i2c_mux_functionality;
+
+	/* Now fill out new adapter structure */
+	snprintf(priv->adap.name, sizeof(priv->adap.name),
+		 "i2c-%d-mux (chan_id %d)", i2c_adapter_id(parent), chan_id);
+	priv->adap.owner = THIS_MODULE;
+	priv->adap.algo = &priv->algo;
+	priv->adap.algo_data = priv;
+	priv->adap.dev.parent = &parent->dev;
+
+	if (force_nr) {
+		priv->adap.nr = force_nr;
+		ret = i2c_add_numbered_adapter(&priv->adap);
+	} else {
+		ret = i2c_add_adapter(&priv->adap);
+	}
+	if (ret < 0) {
+		dev_err(&parent->dev,
+			"failed to add mux-adapter (error=%d)\n",
+			ret);
+		kfree(priv);
+		return NULL;
+	}
+
+	dev_info(&parent->dev, "Added multiplexed i2c bus %d\n",
+		 i2c_adapter_id(&priv->adap));
+
+	return &priv->adap;
+}
+EXPORT_SYMBOL_GPL(i2c_add_mux_adapter);
+
+int i2c_del_mux_adapter(struct i2c_adapter *adap)
+{
+	struct i2c_mux_priv *priv = adap->algo_data;
+	int ret;
+
+	ret = i2c_del_adapter(adap);
+	if (ret < 0)
+		return ret;
+	kfree(priv);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(i2c_del_mux_adapter);
+
+MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>");
+MODULE_DESCRIPTION("I2C driver for multiplexed I2C busses");
+MODULE_LICENSE("GPL v2");
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/i2c-smbus.c b/ap/os/linux/linux-3.4.x/drivers/i2c/i2c-smbus.c
new file mode 100644
index 0000000..9836d08
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/i2c-smbus.c
@@ -0,0 +1,263 @@
+/*
+ * i2c-smbus.c - SMBus extensions to the I2C protocol
+ *
+ * Copyright (C) 2008 David Brownell
+ * Copyright (C) 2010 Jean Delvare <khali@linux-fr.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301 USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/i2c.h>
+#include <linux/i2c-smbus.h>
+#include <linux/slab.h>
+
+struct i2c_smbus_alert {
+	unsigned int		alert_edge_triggered:1;
+	int			irq;
+	struct work_struct	alert;
+	struct i2c_client	*ara;		/* Alert response address */
+};
+
+struct alert_data {
+	unsigned short		addr;
+	u8			flag:1;
+};
+
+/* If this is the alerting device, notify its driver */
+static int smbus_do_alert(struct device *dev, void *addrp)
+{
+	struct i2c_client *client = i2c_verify_client(dev);
+	struct alert_data *data = addrp;
+
+	if (!client || client->addr != data->addr)
+		return 0;
+	if (client->flags & I2C_CLIENT_TEN)
+		return 0;
+
+	/*
+	 * Drivers should either disable alerts, or provide at least
+	 * a minimal handler.  Lock so client->driver won't change.
+	 */
+	device_lock(dev);
+	if (client->driver) {
+		if (client->driver->alert)
+			client->driver->alert(client, data->flag);
+		else
+			dev_warn(&client->dev, "no driver alert()!\n");
+	} else
+		dev_dbg(&client->dev, "alert with no driver\n");
+	device_unlock(dev);
+
+	/* Stop iterating after we find the device */
+	return -EBUSY;
+}
+
+/*
+ * The alert IRQ handler needs to hand work off to a task which can issue
+ * SMBus calls, because those sleeping calls can't be made in IRQ context.
+ */
+static void smbus_alert(struct work_struct *work)
+{
+	struct i2c_smbus_alert *alert;
+	struct i2c_client *ara;
+	unsigned short prev_addr = 0;	/* Not a valid address */
+
+	alert = container_of(work, struct i2c_smbus_alert, alert);
+	ara = alert->ara;
+
+	for (;;) {
+		s32 status;
+		struct alert_data data;
+
+		/*
+		 * Devices with pending alerts reply in address order, low
+		 * to high, because of slave transmit arbitration.  After
+		 * responding, an SMBus device stops asserting SMBALERT#.
+		 *
+		 * Note that SMBus 2.0 reserves 10-bit addresess for future
+		 * use.  We neither handle them, nor try to use PEC here.
+		 */
+		status = i2c_smbus_read_byte(ara);
+		if (status < 0)
+			break;
+
+		data.flag = status & 1;
+		data.addr = status >> 1;
+
+		if (data.addr == prev_addr) {
+			dev_warn(&ara->dev, "Duplicate SMBALERT# from dev "
+				"0x%02x, skipping\n", data.addr);
+			break;
+		}
+		dev_dbg(&ara->dev, "SMBALERT# from dev 0x%02x, flag %d\n",
+			data.addr, data.flag);
+
+		/* Notify driver for the device which issued the alert */
+		device_for_each_child(&ara->adapter->dev, &data,
+				      smbus_do_alert);
+		prev_addr = data.addr;
+	}
+
+	/* We handled all alerts; re-enable level-triggered IRQs */
+	if (!alert->alert_edge_triggered)
+		enable_irq(alert->irq);
+}
+
+static irqreturn_t smbalert_irq(int irq, void *d)
+{
+	struct i2c_smbus_alert *alert = d;
+
+	/* Disable level-triggered IRQs until we handle them */
+	if (!alert->alert_edge_triggered)
+		disable_irq_nosync(irq);
+
+	schedule_work(&alert->alert);
+	return IRQ_HANDLED;
+}
+
+/* Setup SMBALERT# infrastructure */
+static int smbalert_probe(struct i2c_client *ara,
+			  const struct i2c_device_id *id)
+{
+	struct i2c_smbus_alert_setup *setup = ara->dev.platform_data;
+	struct i2c_smbus_alert *alert;
+	struct i2c_adapter *adapter = ara->adapter;
+	int res;
+
+	alert = kzalloc(sizeof(struct i2c_smbus_alert), GFP_KERNEL);
+	if (!alert)
+		return -ENOMEM;
+
+	alert->alert_edge_triggered = setup->alert_edge_triggered;
+	alert->irq = setup->irq;
+	INIT_WORK(&alert->alert, smbus_alert);
+	alert->ara = ara;
+
+	if (setup->irq > 0) {
+		res = devm_request_irq(&ara->dev, setup->irq, smbalert_irq,
+				       0, "smbus_alert", alert);
+		if (res) {
+			kfree(alert);
+			return res;
+		}
+	}
+
+	i2c_set_clientdata(ara, alert);
+	dev_info(&adapter->dev, "supports SMBALERT#, %s trigger\n",
+		 setup->alert_edge_triggered ? "edge" : "level");
+
+	return 0;
+}
+
+/* IRQ resource is managed so it is freed automatically */
+static int smbalert_remove(struct i2c_client *ara)
+{
+	struct i2c_smbus_alert *alert = i2c_get_clientdata(ara);
+
+	cancel_work_sync(&alert->alert);
+
+	kfree(alert);
+	return 0;
+}
+
+static const struct i2c_device_id smbalert_ids[] = {
+	{ "smbus_alert", 0 },
+	{ /* LIST END */ }
+};
+MODULE_DEVICE_TABLE(i2c, smbalert_ids);
+
+static struct i2c_driver smbalert_driver = {
+	.driver = {
+		.name	= "smbus_alert",
+	},
+	.probe		= smbalert_probe,
+	.remove		= smbalert_remove,
+	.id_table	= smbalert_ids,
+};
+
+/**
+ * i2c_setup_smbus_alert - Setup SMBus alert support
+ * @adapter: the target adapter
+ * @setup: setup data for the SMBus alert handler
+ * Context: can sleep
+ *
+ * Setup handling of the SMBus alert protocol on a given I2C bus segment.
+ *
+ * Handling can be done either through our IRQ handler, or by the
+ * adapter (from its handler, periodic polling, or whatever).
+ *
+ * NOTE that if we manage the IRQ, we *MUST* know if it's level or
+ * edge triggered in order to hand it to the workqueue correctly.
+ * If triggering the alert seems to wedge the system, you probably
+ * should have said it's level triggered.
+ *
+ * This returns the ara client, which should be saved for later use with
+ * i2c_handle_smbus_alert() and ultimately i2c_unregister_device(); or NULL
+ * to indicate an error.
+ */
+struct i2c_client *i2c_setup_smbus_alert(struct i2c_adapter *adapter,
+					 struct i2c_smbus_alert_setup *setup)
+{
+	struct i2c_board_info ara_board_info = {
+		I2C_BOARD_INFO("smbus_alert", 0x0c),
+		.platform_data = setup,
+	};
+
+	return i2c_new_device(adapter, &ara_board_info);
+}
+EXPORT_SYMBOL_GPL(i2c_setup_smbus_alert);
+
+/**
+ * i2c_handle_smbus_alert - Handle an SMBus alert
+ * @ara: the ARA client on the relevant adapter
+ * Context: can't sleep
+ *
+ * Helper function to be called from an I2C bus driver's interrupt
+ * handler. It will schedule the alert work, in turn calling the
+ * corresponding I2C device driver's alert function.
+ *
+ * It is assumed that ara is a valid i2c client previously returned by
+ * i2c_setup_smbus_alert().
+ */
+int i2c_handle_smbus_alert(struct i2c_client *ara)
+{
+	struct i2c_smbus_alert *alert = i2c_get_clientdata(ara);
+
+	return schedule_work(&alert->alert);
+}
+EXPORT_SYMBOL_GPL(i2c_handle_smbus_alert);
+
+static int __init i2c_smbus_init(void)
+{
+	return i2c_add_driver(&smbalert_driver);
+}
+
+static void __exit i2c_smbus_exit(void)
+{
+	i2c_del_driver(&smbalert_driver);
+}
+
+module_init(i2c_smbus_init);
+module_exit(i2c_smbus_exit);
+
+MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
+MODULE_DESCRIPTION("SMBus protocol extensions support");
+MODULE_LICENSE("GPL");
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/muxes/Kconfig b/ap/os/linux/linux-3.4.x/drivers/i2c/muxes/Kconfig
new file mode 100644
index 0000000..90b7a01
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/muxes/Kconfig
@@ -0,0 +1,40 @@
+#
+# Multiplexer I2C chip drivers configuration
+#
+
+menu "Multiplexer I2C Chip support"
+	depends on I2C_MUX
+
+config I2C_MUX_GPIO
+	tristate "GPIO-based I2C multiplexer"
+	depends on GENERIC_GPIO
+	help
+	  If you say yes to this option, support will be included for a
+	  GPIO based I2C multiplexer. This driver provides access to
+	  I2C busses connected through a MUX, which is controlled
+	  through GPIO pins.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called gpio-i2cmux.
+
+config I2C_MUX_PCA9541
+	tristate "NXP PCA9541 I2C Master Selector"
+	depends on EXPERIMENTAL
+	help
+	  If you say yes here you get support for the NXP PCA9541
+	  I2C Master Selector.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called pca9541.
+
+config I2C_MUX_PCA954x
+	tristate "Philips PCA954x I2C Mux/switches"
+	depends on EXPERIMENTAL
+	help
+	  If you say yes here you get support for the Philips PCA954x
+	  I2C mux/switch devices.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called pca954x.
+
+endmenu
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/muxes/Makefile b/ap/os/linux/linux-3.4.x/drivers/i2c/muxes/Makefile
new file mode 100644
index 0000000..4640436
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/muxes/Makefile
@@ -0,0 +1,8 @@
+#
+# Makefile for multiplexer I2C chip drivers.
+
+obj-$(CONFIG_I2C_MUX_GPIO)	+= gpio-i2cmux.o
+obj-$(CONFIG_I2C_MUX_PCA9541)	+= pca9541.o
+obj-$(CONFIG_I2C_MUX_PCA954x)	+= pca954x.o
+
+ccflags-$(CONFIG_I2C_DEBUG_BUS) := -DDEBUG
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/muxes/gpio-i2cmux.c b/ap/os/linux/linux-3.4.x/drivers/i2c/muxes/gpio-i2cmux.c
new file mode 100644
index 0000000..e5fa695
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/muxes/gpio-i2cmux.c
@@ -0,0 +1,173 @@
+/*
+ * I2C multiplexer using GPIO API
+ *
+ * Peter Korsgaard <peter.korsgaard@barco.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/i2c.h>
+#include <linux/i2c-mux.h>
+#include <linux/gpio-i2cmux.h>
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+
+struct gpiomux {
+	struct i2c_adapter *parent;
+	struct i2c_adapter **adap; /* child busses */
+	struct gpio_i2cmux_platform_data data;
+};
+
+static void gpiomux_set(const struct gpiomux *mux, unsigned val)
+{
+	int i;
+
+	for (i = 0; i < mux->data.n_gpios; i++)
+		gpio_set_value(mux->data.gpios[i], val & (1 << i));
+}
+
+static int gpiomux_select(struct i2c_adapter *adap, void *data, u32 chan)
+{
+	struct gpiomux *mux = data;
+
+	gpiomux_set(mux, mux->data.values[chan]);
+
+	return 0;
+}
+
+static int gpiomux_deselect(struct i2c_adapter *adap, void *data, u32 chan)
+{
+	struct gpiomux *mux = data;
+
+	gpiomux_set(mux, mux->data.idle);
+
+	return 0;
+}
+
+static int __devinit gpiomux_probe(struct platform_device *pdev)
+{
+	struct gpiomux *mux;
+	struct gpio_i2cmux_platform_data *pdata;
+	struct i2c_adapter *parent;
+	int (*deselect) (struct i2c_adapter *, void *, u32);
+	unsigned initial_state;
+	int i, ret;
+
+	pdata = pdev->dev.platform_data;
+	if (!pdata) {
+		dev_err(&pdev->dev, "Missing platform data\n");
+		return -ENODEV;
+	}
+
+	parent = i2c_get_adapter(pdata->parent);
+	if (!parent) {
+		dev_err(&pdev->dev, "Parent adapter (%d) not found\n",
+			pdata->parent);
+		return -ENODEV;
+	}
+
+	mux = kzalloc(sizeof(*mux), GFP_KERNEL);
+	if (!mux) {
+		ret = -ENOMEM;
+		goto alloc_failed;
+	}
+
+	mux->parent = parent;
+	mux->data = *pdata;
+	mux->adap = kzalloc(sizeof(struct i2c_adapter *) * pdata->n_values,
+			    GFP_KERNEL);
+	if (!mux->adap) {
+		ret = -ENOMEM;
+		goto alloc_failed2;
+	}
+
+	if (pdata->idle != GPIO_I2CMUX_NO_IDLE) {
+		initial_state = pdata->idle;
+		deselect = gpiomux_deselect;
+	} else {
+		initial_state = pdata->values[0];
+		deselect = NULL;
+	}
+
+	for (i = 0; i < pdata->n_gpios; i++) {
+		ret = gpio_request(pdata->gpios[i], "gpio-i2cmux");
+		if (ret)
+			goto err_request_gpio;
+		gpio_direction_output(pdata->gpios[i],
+				      initial_state & (1 << i));
+	}
+
+	for (i = 0; i < pdata->n_values; i++) {
+		u32 nr = pdata->base_nr ? (pdata->base_nr + i) : 0;
+
+		mux->adap[i] = i2c_add_mux_adapter(parent, mux, nr, i,
+						   gpiomux_select, deselect);
+		if (!mux->adap[i]) {
+			ret = -ENODEV;
+			dev_err(&pdev->dev, "Failed to add adapter %d\n", i);
+			goto add_adapter_failed;
+		}
+	}
+
+	dev_info(&pdev->dev, "%d port mux on %s adapter\n",
+		 pdata->n_values, parent->name);
+
+	platform_set_drvdata(pdev, mux);
+
+	return 0;
+
+add_adapter_failed:
+	for (; i > 0; i--)
+		i2c_del_mux_adapter(mux->adap[i - 1]);
+	i = pdata->n_gpios;
+err_request_gpio:
+	for (; i > 0; i--)
+		gpio_free(pdata->gpios[i - 1]);
+	kfree(mux->adap);
+alloc_failed2:
+	kfree(mux);
+alloc_failed:
+	i2c_put_adapter(parent);
+
+	return ret;
+}
+
+static int __devexit gpiomux_remove(struct platform_device *pdev)
+{
+	struct gpiomux *mux = platform_get_drvdata(pdev);
+	int i;
+
+	for (i = 0; i < mux->data.n_values; i++)
+		i2c_del_mux_adapter(mux->adap[i]);
+
+	for (i = 0; i < mux->data.n_gpios; i++)
+		gpio_free(mux->data.gpios[i]);
+
+	platform_set_drvdata(pdev, NULL);
+	i2c_put_adapter(mux->parent);
+	kfree(mux->adap);
+	kfree(mux);
+
+	return 0;
+}
+
+static struct platform_driver gpiomux_driver = {
+	.probe	= gpiomux_probe,
+	.remove	= __devexit_p(gpiomux_remove),
+	.driver	= {
+		.owner	= THIS_MODULE,
+		.name	= "gpio-i2cmux",
+	},
+};
+
+module_platform_driver(gpiomux_driver);
+
+MODULE_DESCRIPTION("GPIO-based I2C multiplexer driver");
+MODULE_AUTHOR("Peter Korsgaard <peter.korsgaard@barco.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:gpio-i2cmux");
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/muxes/pca9541.c b/ap/os/linux/linux-3.4.x/drivers/i2c/muxes/pca9541.c
new file mode 100644
index 0000000..e0df9b6
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/muxes/pca9541.c
@@ -0,0 +1,400 @@
+/*
+ * I2C multiplexer driver for PCA9541 bus master selector
+ *
+ * Copyright (c) 2010 Ericsson AB.
+ *
+ * Author: Guenter Roeck <guenter.roeck@ericsson.com>
+ *
+ * Derived from:
+ *  pca954x.c
+ *
+ *  Copyright (c) 2008-2009 Rodolfo Giometti <giometti@linux.it>
+ *  Copyright (c) 2008-2009 Eurotech S.p.A. <info@eurotech.it>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/jiffies.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/i2c-mux.h>
+
+#include <linux/i2c/pca954x.h>
+
+/*
+ * The PCA9541 is a bus master selector. It supports two I2C masters connected
+ * to a single slave bus.
+ *
+ * Before each bus transaction, a master has to acquire bus ownership. After the
+ * transaction is complete, bus ownership has to be released. This fits well
+ * into the I2C multiplexer framework, which provides select and release
+ * functions for this purpose. For this reason, this driver is modeled as
+ * single-channel I2C bus multiplexer.
+ *
+ * This driver assumes that the two bus masters are controlled by two different
+ * hosts. If a single host controls both masters, platform code has to ensure
+ * that only one of the masters is instantiated at any given time.
+ */
+
+#define PCA9541_CONTROL		0x01
+#define PCA9541_ISTAT		0x02
+
+#define PCA9541_CTL_MYBUS	(1 << 0)
+#define PCA9541_CTL_NMYBUS	(1 << 1)
+#define PCA9541_CTL_BUSON	(1 << 2)
+#define PCA9541_CTL_NBUSON	(1 << 3)
+#define PCA9541_CTL_BUSINIT	(1 << 4)
+#define PCA9541_CTL_TESTON	(1 << 6)
+#define PCA9541_CTL_NTESTON	(1 << 7)
+
+#define PCA9541_ISTAT_INTIN	(1 << 0)
+#define PCA9541_ISTAT_BUSINIT	(1 << 1)
+#define PCA9541_ISTAT_BUSOK	(1 << 2)
+#define PCA9541_ISTAT_BUSLOST	(1 << 3)
+#define PCA9541_ISTAT_MYTEST	(1 << 6)
+#define PCA9541_ISTAT_NMYTEST	(1 << 7)
+
+#define BUSON		(PCA9541_CTL_BUSON | PCA9541_CTL_NBUSON)
+#define MYBUS		(PCA9541_CTL_MYBUS | PCA9541_CTL_NMYBUS)
+#define mybus(x)	(!((x) & MYBUS) || ((x) & MYBUS) == MYBUS)
+#define busoff(x)	(!((x) & BUSON) || ((x) & BUSON) == BUSON)
+
+/* arbitration timeouts, in jiffies */
+#define ARB_TIMEOUT	(HZ / 8)	/* 125 ms until forcing bus ownership */
+#define ARB2_TIMEOUT	(HZ / 4)	/* 250 ms until acquisition failure */
+
+/* arbitration retry delays, in us */
+#define SELECT_DELAY_SHORT	50
+#define SELECT_DELAY_LONG	1000
+
+struct pca9541 {
+	struct i2c_adapter *mux_adap;
+	unsigned long select_timeout;
+	unsigned long arb_timeout;
+};
+
+static const struct i2c_device_id pca9541_id[] = {
+	{"pca9541", 0},
+	{}
+};
+
+MODULE_DEVICE_TABLE(i2c, pca9541_id);
+
+/*
+ * Write to chip register. Don't use i2c_transfer()/i2c_smbus_xfer()
+ * as they will try to lock the adapter a second time.
+ */
+static int pca9541_reg_write(struct i2c_client *client, u8 command, u8 val)
+{
+	struct i2c_adapter *adap = client->adapter;
+	int ret;
+
+	if (adap->algo->master_xfer) {
+		struct i2c_msg msg;
+		char buf[2];
+
+		msg.addr = client->addr;
+		msg.flags = 0;
+		msg.len = 2;
+		buf[0] = command;
+		buf[1] = val;
+		msg.buf = buf;
+		ret = adap->algo->master_xfer(adap, &msg, 1);
+	} else {
+		union i2c_smbus_data data;
+
+		data.byte = val;
+		ret = adap->algo->smbus_xfer(adap, client->addr,
+					     client->flags,
+					     I2C_SMBUS_WRITE,
+					     command,
+					     I2C_SMBUS_BYTE_DATA, &data);
+	}
+
+	return ret;
+}
+
+/*
+ * Read from chip register. Don't use i2c_transfer()/i2c_smbus_xfer()
+ * as they will try to lock adapter a second time.
+ */
+static int pca9541_reg_read(struct i2c_client *client, u8 command)
+{
+	struct i2c_adapter *adap = client->adapter;
+	int ret;
+	u8 val;
+
+	if (adap->algo->master_xfer) {
+		struct i2c_msg msg[2] = {
+			{
+				.addr = client->addr,
+				.flags = 0,
+				.len = 1,
+				.buf = &command
+			},
+			{
+				.addr = client->addr,
+				.flags = I2C_M_RD,
+				.len = 1,
+				.buf = &val
+			}
+		};
+		ret = adap->algo->master_xfer(adap, msg, 2);
+		if (ret == 2)
+			ret = val;
+		else if (ret >= 0)
+			ret = -EIO;
+	} else {
+		union i2c_smbus_data data;
+
+		ret = adap->algo->smbus_xfer(adap, client->addr,
+					     client->flags,
+					     I2C_SMBUS_READ,
+					     command,
+					     I2C_SMBUS_BYTE_DATA, &data);
+		if (!ret)
+			ret = data.byte;
+	}
+	return ret;
+}
+
+/*
+ * Arbitration management functions
+ */
+
+/* Release bus. Also reset NTESTON and BUSINIT if it was set. */
+static void pca9541_release_bus(struct i2c_client *client)
+{
+	int reg;
+
+	reg = pca9541_reg_read(client, PCA9541_CONTROL);
+	if (reg >= 0 && !busoff(reg) && mybus(reg))
+		pca9541_reg_write(client, PCA9541_CONTROL,
+				  (reg & PCA9541_CTL_NBUSON) >> 1);
+}
+
+/*
+ * Arbitration is defined as a two-step process. A bus master can only activate
+ * the slave bus if it owns it; otherwise it has to request ownership first.
+ * This multi-step process ensures that access contention is resolved
+ * gracefully.
+ *
+ * Bus	Ownership	Other master	Action
+ * state		requested access
+ * ----------------------------------------------------
+ * off	-		yes		wait for arbitration timeout or
+ *					for other master to drop request
+ * off	no		no		take ownership
+ * off	yes		no		turn on bus
+ * on	yes		-		done
+ * on	no		-		wait for arbitration timeout or
+ *					for other master to release bus
+ *
+ * The main contention point occurs if the slave bus is off and both masters
+ * request ownership at the same time. In this case, one master will turn on
+ * the slave bus, believing that it owns it. The other master will request
+ * bus ownership. Result is that the bus is turned on, and master which did
+ * _not_ own the slave bus before ends up owning it.
+ */
+
+/* Control commands per PCA9541 datasheet */
+static const u8 pca9541_control[16] = {
+	4, 0, 1, 5, 4, 4, 5, 5, 0, 0, 1, 1, 0, 4, 5, 1
+};
+
+/*
+ * Channel arbitration
+ *
+ * Return values:
+ *  <0: error
+ *  0 : bus not acquired
+ *  1 : bus acquired
+ */
+static int pca9541_arbitrate(struct i2c_client *client)
+{
+	struct pca9541 *data = i2c_get_clientdata(client);
+	int reg;
+
+	reg = pca9541_reg_read(client, PCA9541_CONTROL);
+	if (reg < 0)
+		return reg;
+
+	if (busoff(reg)) {
+		int istat;
+		/*
+		 * Bus is off. Request ownership or turn it on unless
+		 * other master requested ownership.
+		 */
+		istat = pca9541_reg_read(client, PCA9541_ISTAT);
+		if (!(istat & PCA9541_ISTAT_NMYTEST)
+		    || time_is_before_eq_jiffies(data->arb_timeout)) {
+			/*
+			 * Other master did not request ownership,
+			 * or arbitration timeout expired. Take the bus.
+			 */
+			pca9541_reg_write(client,
+					  PCA9541_CONTROL,
+					  pca9541_control[reg & 0x0f]
+					  | PCA9541_CTL_NTESTON);
+			data->select_timeout = SELECT_DELAY_SHORT;
+		} else {
+			/*
+			 * Other master requested ownership.
+			 * Set extra long timeout to give it time to acquire it.
+			 */
+			data->select_timeout = SELECT_DELAY_LONG * 2;
+		}
+	} else if (mybus(reg)) {
+		/*
+		 * Bus is on, and we own it. We are done with acquisition.
+		 * Reset NTESTON and BUSINIT, then return success.
+		 */
+		if (reg & (PCA9541_CTL_NTESTON | PCA9541_CTL_BUSINIT))
+			pca9541_reg_write(client,
+					  PCA9541_CONTROL,
+					  reg & ~(PCA9541_CTL_NTESTON
+						  | PCA9541_CTL_BUSINIT));
+		return 1;
+	} else {
+		/*
+		 * Other master owns the bus.
+		 * If arbitration timeout has expired, force ownership.
+		 * Otherwise request it.
+		 */
+		data->select_timeout = SELECT_DELAY_LONG;
+		if (time_is_before_eq_jiffies(data->arb_timeout)) {
+			/* Time is up, take the bus and reset it. */
+			pca9541_reg_write(client,
+					  PCA9541_CONTROL,
+					  pca9541_control[reg & 0x0f]
+					  | PCA9541_CTL_BUSINIT
+					  | PCA9541_CTL_NTESTON);
+		} else {
+			/* Request bus ownership if needed */
+			if (!(reg & PCA9541_CTL_NTESTON))
+				pca9541_reg_write(client,
+						  PCA9541_CONTROL,
+						  reg | PCA9541_CTL_NTESTON);
+		}
+	}
+	return 0;
+}
+
+static int pca9541_select_chan(struct i2c_adapter *adap, void *client, u32 chan)
+{
+	struct pca9541 *data = i2c_get_clientdata(client);
+	int ret;
+	unsigned long timeout = jiffies + ARB2_TIMEOUT;
+		/* give up after this time */
+
+	data->arb_timeout = jiffies + ARB_TIMEOUT;
+		/* force bus ownership after this time */
+
+	do {
+		ret = pca9541_arbitrate(client);
+		if (ret)
+			return ret < 0 ? ret : 0;
+
+		if (data->select_timeout == SELECT_DELAY_SHORT)
+			udelay(data->select_timeout);
+		else
+			msleep(data->select_timeout / 1000);
+	} while (time_is_after_eq_jiffies(timeout));
+
+	return -ETIMEDOUT;
+}
+
+static int pca9541_release_chan(struct i2c_adapter *adap,
+				void *client, u32 chan)
+{
+	pca9541_release_bus(client);
+	return 0;
+}
+
+/*
+ * I2C init/probing/exit functions
+ */
+static int pca9541_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	struct i2c_adapter *adap = client->adapter;
+	struct pca954x_platform_data *pdata = client->dev.platform_data;
+	struct pca9541 *data;
+	int force;
+	int ret = -ENODEV;
+
+	if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE_DATA))
+		goto err;
+
+	data = kzalloc(sizeof(struct pca9541), GFP_KERNEL);
+	if (!data) {
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	i2c_set_clientdata(client, data);
+
+	/*
+	 * I2C accesses are unprotected here.
+	 * We have to lock the adapter before releasing the bus.
+	 */
+	i2c_lock_adapter(adap);
+	pca9541_release_bus(client);
+	i2c_unlock_adapter(adap);
+
+	/* Create mux adapter */
+
+	force = 0;
+	if (pdata)
+		force = pdata->modes[0].adap_id;
+	data->mux_adap = i2c_add_mux_adapter(adap, client, force, 0,
+					     pca9541_select_chan,
+					     pca9541_release_chan);
+
+	if (data->mux_adap == NULL) {
+		dev_err(&client->dev, "failed to register master selector\n");
+		goto exit_free;
+	}
+
+	dev_info(&client->dev, "registered master selector for I2C %s\n",
+		 client->name);
+
+	return 0;
+
+exit_free:
+	kfree(data);
+err:
+	return ret;
+}
+
+static int pca9541_remove(struct i2c_client *client)
+{
+	struct pca9541 *data = i2c_get_clientdata(client);
+
+	i2c_del_mux_adapter(data->mux_adap);
+
+	kfree(data);
+	return 0;
+}
+
+static struct i2c_driver pca9541_driver = {
+	.driver = {
+		   .name = "pca9541",
+		   .owner = THIS_MODULE,
+		   },
+	.probe = pca9541_probe,
+	.remove = pca9541_remove,
+	.id_table = pca9541_id,
+};
+
+module_i2c_driver(pca9541_driver);
+
+MODULE_AUTHOR("Guenter Roeck <guenter.roeck@ericsson.com>");
+MODULE_DESCRIPTION("PCA9541 I2C master selector driver");
+MODULE_LICENSE("GPL v2");
diff --git a/ap/os/linux/linux-3.4.x/drivers/i2c/muxes/pca954x.c b/ap/os/linux/linux-3.4.x/drivers/i2c/muxes/pca954x.c
new file mode 100644
index 0000000..0e37ef2
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/i2c/muxes/pca954x.c
@@ -0,0 +1,291 @@
+/*
+ * I2C multiplexer
+ *
+ * Copyright (c) 2008-2009 Rodolfo Giometti <giometti@linux.it>
+ * Copyright (c) 2008-2009 Eurotech S.p.A. <info@eurotech.it>
+ *
+ * This module supports the PCA954x series of I2C multiplexer/switch chips
+ * made by Philips Semiconductors.
+ * This includes the:
+ *	 PCA9540, PCA9542, PCA9543, PCA9544, PCA9545, PCA9546, PCA9547
+ *	 and PCA9548.
+ *
+ * These chips are all controlled via the I2C bus itself, and all have a
+ * single 8-bit register. The upstream "parent" bus fans out to two,
+ * four, or eight downstream busses or channels; which of these
+ * are selected is determined by the chip type and register contents. A
+ * mux can select only one sub-bus at a time; a switch can select any
+ * combination simultaneously.
+ *
+ * Based on:
+ *	pca954x.c from Kumar Gala <galak@kernel.crashing.org>
+ * Copyright (C) 2006
+ *
+ * Based on:
+ *	pca954x.c from Ken Harrenstien
+ * Copyright (C) 2004 Google, Inc. (Ken Harrenstien)
+ *
+ * Based on:
+ *	i2c-virtual_cb.c from Brian Kuschak <bkuschak@yahoo.com>
+ * and
+ *	pca9540.c from Jean Delvare <khali@linux-fr.org>.
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/i2c-mux.h>
+
+#include <linux/i2c/pca954x.h>
+
+#define PCA954X_MAX_NCHANS 8
+
+enum pca_type {
+	pca_9540,
+	pca_9542,
+	pca_9543,
+	pca_9544,
+	pca_9545,
+	pca_9546,
+	pca_9547,
+	pca_9548,
+};
+
+struct pca954x {
+	enum pca_type type;
+	struct i2c_adapter *virt_adaps[PCA954X_MAX_NCHANS];
+
+	u8 last_chan;		/* last register value */
+};
+
+struct chip_desc {
+	u8 nchans;
+	u8 enable;	/* used for muxes only */
+	enum muxtype {
+		pca954x_ismux = 0,
+		pca954x_isswi
+	} muxtype;
+};
+
+/* Provide specs for the PCA954x types we know about */
+static const struct chip_desc chips[] = {
+	[pca_9540] = {
+		.nchans = 2,
+		.enable = 0x4,
+		.muxtype = pca954x_ismux,
+	},
+	[pca_9543] = {
+		.nchans = 2,
+		.muxtype = pca954x_isswi,
+	},
+	[pca_9544] = {
+		.nchans = 4,
+		.enable = 0x4,
+		.muxtype = pca954x_ismux,
+	},
+	[pca_9545] = {
+		.nchans = 4,
+		.muxtype = pca954x_isswi,
+	},
+	[pca_9547] = {
+		.nchans = 8,
+		.enable = 0x8,
+		.muxtype = pca954x_ismux,
+	},
+	[pca_9548] = {
+		.nchans = 8,
+		.muxtype = pca954x_isswi,
+	},
+};
+
+static const struct i2c_device_id pca954x_id[] = {
+	{ "pca9540", pca_9540 },
+	{ "pca9542", pca_9540 },
+	{ "pca9543", pca_9543 },
+	{ "pca9544", pca_9544 },
+	{ "pca9545", pca_9545 },
+	{ "pca9546", pca_9545 },
+	{ "pca9547", pca_9547 },
+	{ "pca9548", pca_9548 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, pca954x_id);
+
+/* Write to mux register. Don't use i2c_transfer()/i2c_smbus_xfer()
+   for this as they will try to lock adapter a second time */
+static int pca954x_reg_write(struct i2c_adapter *adap,
+			     struct i2c_client *client, u8 val)
+{
+	int ret = -ENODEV;
+
+	if (adap->algo->master_xfer) {
+		struct i2c_msg msg;
+		char buf[1];
+
+		msg.addr = client->addr;
+		msg.flags = 0;
+		msg.len = 1;
+		buf[0] = val;
+		msg.buf = buf;
+		ret = adap->algo->master_xfer(adap, &msg, 1);
+	} else {
+		union i2c_smbus_data data;
+		ret = adap->algo->smbus_xfer(adap, client->addr,
+					     client->flags,
+					     I2C_SMBUS_WRITE,
+					     val, I2C_SMBUS_BYTE, &data);
+	}
+
+	return ret;
+}
+
+static int pca954x_select_chan(struct i2c_adapter *adap,
+			       void *client, u32 chan)
+{
+	struct pca954x *data = i2c_get_clientdata(client);
+	const struct chip_desc *chip = &chips[data->type];
+	u8 regval;
+	int ret = 0;
+
+	/* we make switches look like muxes, not sure how to be smarter */
+	if (chip->muxtype == pca954x_ismux)
+		regval = chan | chip->enable;
+	else
+		regval = 1 << chan;
+
+	/* Only select the channel if its different from the last channel */
+	if (data->last_chan != regval) {
+		ret = pca954x_reg_write(adap, client, regval);
+		data->last_chan = regval;
+	}
+
+	return ret;
+}
+
+static int pca954x_deselect_mux(struct i2c_adapter *adap,
+				void *client, u32 chan)
+{
+	struct pca954x *data = i2c_get_clientdata(client);
+
+	/* Deselect active channel */
+	data->last_chan = 0;
+	return pca954x_reg_write(adap, client, data->last_chan);
+}
+
+/*
+ * I2C init/probing/exit functions
+ */
+static int pca954x_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent);
+	struct pca954x_platform_data *pdata = client->dev.platform_data;
+	int num, force;
+	struct pca954x *data;
+	int ret = -ENODEV;
+
+	if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE))
+		goto err;
+
+	data = kzalloc(sizeof(struct pca954x), GFP_KERNEL);
+	if (!data) {
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	i2c_set_clientdata(client, data);
+
+	/* Write the mux register at addr to verify
+	 * that the mux is in fact present. This also
+	 * initializes the mux to disconnected state.
+	 */
+	if (i2c_smbus_write_byte(client, 0) < 0) {
+		dev_warn(&client->dev, "probe failed\n");
+		goto exit_free;
+	}
+
+	data->type = id->driver_data;
+	data->last_chan = 0;		   /* force the first selection */
+
+	/* Now create an adapter for each channel */
+	for (num = 0; num < chips[data->type].nchans; num++) {
+		force = 0;			  /* dynamic adap number */
+		if (pdata) {
+			if (num < pdata->num_modes)
+				/* force static number */
+				force = pdata->modes[num].adap_id;
+			else
+				/* discard unconfigured channels */
+				break;
+		}
+
+		data->virt_adaps[num] =
+			i2c_add_mux_adapter(adap, client,
+				force, num, pca954x_select_chan,
+				(pdata && pdata->modes[num].deselect_on_exit)
+					? pca954x_deselect_mux : NULL);
+
+		if (data->virt_adaps[num] == NULL) {
+			ret = -ENODEV;
+			dev_err(&client->dev,
+				"failed to register multiplexed adapter"
+				" %d as bus %d\n", num, force);
+			goto virt_reg_failed;
+		}
+	}
+
+	dev_info(&client->dev,
+		 "registered %d multiplexed busses for I2C %s %s\n",
+		 num, chips[data->type].muxtype == pca954x_ismux
+				? "mux" : "switch", client->name);
+
+	return 0;
+
+virt_reg_failed:
+	for (num--; num >= 0; num--)
+		i2c_del_mux_adapter(data->virt_adaps[num]);
+exit_free:
+	kfree(data);
+err:
+	return ret;
+}
+
+static int pca954x_remove(struct i2c_client *client)
+{
+	struct pca954x *data = i2c_get_clientdata(client);
+	const struct chip_desc *chip = &chips[data->type];
+	int i, err;
+
+	for (i = 0; i < chip->nchans; ++i)
+		if (data->virt_adaps[i]) {
+			err = i2c_del_mux_adapter(data->virt_adaps[i]);
+			if (err)
+				return err;
+			data->virt_adaps[i] = NULL;
+		}
+
+	kfree(data);
+	return 0;
+}
+
+static struct i2c_driver pca954x_driver = {
+	.driver		= {
+		.name	= "pca954x",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= pca954x_probe,
+	.remove		= pca954x_remove,
+	.id_table	= pca954x_id,
+};
+
+module_i2c_driver(pca954x_driver);
+
+MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>");
+MODULE_DESCRIPTION("PCA954x I2C mux/switch driver");
+MODULE_LICENSE("GPL v2");