diff --git a/arch/arm/mach-s3c2410/mach-bast.c b/arch/arm/mach-s3c2410/mach-bast.c
index 01bd76725b920040a6b7ea1687d1c84770f32f54..4389c160f7d08f920d884b3f974ea2474d44fa09 100644
--- a/arch/arm/mach-s3c2410/mach-bast.c
+++ b/arch/arm/mach-s3c2410/mach-bast.c
@@ -409,8 +409,7 @@ static struct platform_device bast_sio = {
 static struct s3c2410_platform_i2c __initdata bast_i2c_info = {
 	.flags		= 0,
 	.slave_addr	= 0x10,
-	.bus_freq	= 100*1000,
-	.max_freq	= 130*1000,
+	.frequency	= 100*1000,
 };
 
 /* Asix AX88796 10/100 ethernet controller */
diff --git a/arch/arm/mach-s3c2410/mach-n30.c b/arch/arm/mach-s3c2410/mach-n30.c
index 05a5e877b49b73b7ccfa20734544b8f1f089e2c7..2b83f87077100b310f8a9502663c75451bacaca0 100644
--- a/arch/arm/mach-s3c2410/mach-n30.c
+++ b/arch/arm/mach-s3c2410/mach-n30.c
@@ -340,8 +340,7 @@ static struct platform_device *n35_devices[] __initdata = {
 static struct s3c2410_platform_i2c n30_i2ccfg = {
 	.flags		= 0,
 	.slave_addr	= 0x10,
-	.bus_freq	= 10*1000,
-	.max_freq	= 10*1000,
+	.frequency	= 10*1000,
 };
 
 /* Lots of hardcoded stuff, but it sets up the hardware in a useful
diff --git a/arch/arm/mach-s3c2412/mach-jive.c b/arch/arm/mach-s3c2412/mach-jive.c
index 72c266aee1410ab73ab085b65c1dbec1c00919aa..332bd3263eafd18134791a95b6fd041b564370e6 100644
--- a/arch/arm/mach-s3c2412/mach-jive.c
+++ b/arch/arm/mach-s3c2412/mach-jive.c
@@ -453,8 +453,7 @@ static struct spi_board_info __initdata jive_spi_devs[] = {
 /* I2C bus and device configuration. */
 
 static struct s3c2410_platform_i2c jive_i2c_cfg __initdata = {
-	.max_freq	= 80 * 1000,
-	.bus_freq	= 50 * 1000,
+	.frequency	= 80 * 1000,
 	.flags		= S3C_IICFLG_FILTER,
 	.sda_delay	= 2,
 };
diff --git a/arch/arm/plat-mxc/include/mach/i2c.h b/arch/arm/plat-mxc/include/mach/i2c.h
new file mode 100644
index 0000000000000000000000000000000000000000..4a5dc5c6d8e8121e4af007d71bf9a0b989fdd8c0
--- /dev/null
+++ b/arch/arm/plat-mxc/include/mach/i2c.h
@@ -0,0 +1,25 @@
+/*
+ * i2c.h - i.MX I2C driver header file
+ *
+ * Copyright (c) 2008, Darius Augulis <augulis.darius@gmail.com>
+ *
+ * This file is released under the GPLv2
+ */
+
+#ifndef __ASM_ARCH_I2C_H_
+#define __ASM_ARCH_I2C_H_
+
+/**
+ * struct imxi2c_platform_data - structure of platform data for MXC I2C driver
+ * @init:	Initialise gpio's and other board specific things
+ * @exit:	Free everything initialised by @init
+ * @bitrate:	Bus speed measured in Hz
+ *
+ **/
+struct imxi2c_platform_data {
+	int (*init)(struct device *dev);
+	void (*exit)(struct device *dev);
+	int bitrate;
+};
+
+#endif /* __ASM_ARCH_I2C_H_ */
diff --git a/arch/arm/plat-s3c/dev-i2c0.c b/arch/arm/plat-s3c/dev-i2c0.c
index fe327074037ea05d4d996cbe52be7ab9a2deae78..428372868fbba66408c1fc2d290de9d138399397 100644
--- a/arch/arm/plat-s3c/dev-i2c0.c
+++ b/arch/arm/plat-s3c/dev-i2c0.c
@@ -1,6 +1,6 @@
 /* linux/arch/arm/plat-s3c/dev-i2c0.c
  *
- * Copyright 2008 Simtec Electronics
+ * Copyright 2008,2009 Simtec Electronics
  *	Ben Dooks <ben@simtec.co.uk>
  *	http://armlinux.simtec.co.uk/
  *
@@ -50,9 +50,8 @@ struct platform_device s3c_device_i2c0 = {
 static struct s3c2410_platform_i2c default_i2c_data0 __initdata = {
 	.flags		= 0,
 	.slave_addr	= 0x10,
-	.bus_freq	= 100*1000,
-	.max_freq	= 400*1000,
-	.sda_delay	= S3C2410_IICLC_SDA_DELAY5 | S3C2410_IICLC_FILTER_ON,
+	.frequency	= 100*1000,
+	.sda_delay	= 100,
 };
 
 void __init s3c_i2c0_set_platdata(struct s3c2410_platform_i2c *pd)
diff --git a/arch/arm/plat-s3c/dev-i2c1.c b/arch/arm/plat-s3c/dev-i2c1.c
index 2387fbf57af6da984b49dce28fcf08a55a6afee5..8349c462788c9e2f41eb0977b2f491f79bbb6f9a 100644
--- a/arch/arm/plat-s3c/dev-i2c1.c
+++ b/arch/arm/plat-s3c/dev-i2c1.c
@@ -1,6 +1,6 @@
 /* linux/arch/arm/plat-s3c/dev-i2c1.c
  *
- * Copyright 2008 Simtec Electronics
+ * Copyright 2008,2009 Simtec Electronics
  *	Ben Dooks <ben@simtec.co.uk>
  *	http://armlinux.simtec.co.uk/
  *
@@ -47,9 +47,8 @@ static struct s3c2410_platform_i2c default_i2c_data1 __initdata = {
 	.flags		= 0,
 	.bus_num	= 1,
 	.slave_addr	= 0x10,
-	.bus_freq	= 100*1000,
-	.max_freq	= 400*1000,
-	.sda_delay	= S3C2410_IICLC_SDA_DELAY5 | S3C2410_IICLC_FILTER_ON,
+	.frequency	= 100*1000,
+	.sda_delay	= 100,
 };
 
 void __init s3c_i2c1_set_platdata(struct s3c2410_platform_i2c *pd)
diff --git a/arch/arm/plat-s3c/include/plat/iic.h b/arch/arm/plat-s3c/include/plat/iic.h
index dc1dfcb9bc6c63034e0a42750ab334ed72ed06d0..67450f115748641da0f8b889d4d19da185b13cd4 100644
--- a/arch/arm/plat-s3c/include/plat/iic.h
+++ b/arch/arm/plat-s3c/include/plat/iic.h
@@ -1,9 +1,9 @@
-/* arch/arm/mach-s3c2410/include/mach/iic.h
+/* arch/arm/plat-s3c/include/plat/iic.h
  *
- * Copyright (c) 2004 Simtec Electronics
+ * Copyright 2004,2009 Simtec Electronics
  *	Ben Dooks <ben@simtec.co.uk>
  *
- * S3C2410 - I2C Controller platfrom_device info
+ * S3C - I2C Controller platform_device info
  *
  * 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
@@ -15,19 +15,24 @@
 
 #define S3C_IICFLG_FILTER	(1<<0)	/* enable s3c2440 filter */
 
-/* Notes:
- *	1) All frequencies are expressed in Hz
- *	2) A value of zero is `do not care`
-*/
-
+/**
+ *	struct s3c2410_platform_i2c - Platform data for s3c I2C.
+ *	@bus_num: The bus number to use (if possible).
+ *	@flags: Any flags for the I2C bus (E.g. S3C_IICFLK_FILTER).
+ *	@slave_addr: The I2C address for the slave device (if enabled).
+ *	@frequency: The desired frequency in Hz of the bus.  This is
+ *                  guaranteed to not be exceeded.  If the caller does
+ *                  not care, use zero and the driver will select a
+ *                  useful default.
+ *	@sda_delay: The delay (in ns) applied to SDA edges.
+ *	@cfg_gpio: A callback to configure the pins for I2C operation.
+ */
 struct s3c2410_platform_i2c {
-	int		bus_num;	/* bus number to use */
+	int		bus_num;
 	unsigned int	flags;
-	unsigned int	slave_addr;	/* slave address for controller */
-	unsigned long	bus_freq;	/* standard bus frequency */
-	unsigned long	max_freq;	/* max frequency for the bus */
-	unsigned long	min_freq;	/* min frequency for the bus */
-	unsigned int	sda_delay;	/* pclks (s3c2440 only) */
+	unsigned int	slave_addr;
+	unsigned long	frequency;
+	unsigned int	sda_delay;
 
 	void	(*cfg_gpio)(struct platform_device *dev);
 };
diff --git a/arch/powerpc/boot/dts/socrates.dts b/arch/powerpc/boot/dts/socrates.dts
index 04c398862e03fb8a5b2268c4c6c1112cd93ef12f..7a6ae75a1e573a14afac948038fa469a662b012f 100644
--- a/arch/powerpc/boot/dts/socrates.dts
+++ b/arch/powerpc/boot/dts/socrates.dts
@@ -79,11 +79,11 @@ i2c@3000 {
 			#address-cells = <1>;
 			#size-cells = <0>;
 			cell-index = <0>;
-			compatible = "fsl-i2c";
+			compatible = "fsl,mpc8544-i2c", "fsl-i2c";
 			reg = <0x3000 0x100>;
 			interrupts = <43 2>;
 			interrupt-parent = <&mpic>;
-			dfsrr;
+			fsl,preserve-clocking;
 
 			dtt@28 {
 				compatible = "winbond,w83782d";
@@ -111,11 +111,11 @@ i2c@3100 {
 			#address-cells = <1>;
 			#size-cells = <0>;
 			cell-index = <1>;
-			compatible = "fsl-i2c";
+			compatible = "fsl,mpc8544-i2c", "fsl-i2c";
 			reg = <0x3100 0x100>;
 			interrupts = <43 2>;
 			interrupt-parent = <&mpic>;
-			dfsrr;
+			fsl,preserve-clocking;
 		};
 
 		enet0: ethernet@24000 {
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index da809ad0996aaa1ea010a13900fa466be9e92ec0..94eae5c3cbc7d3417d2273569f89164d45efea5b 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -356,6 +356,16 @@ config I2C_IBM_IIC
 	  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_IOP3XX
 	tristate "Intel IOPx3xx and IXP4xx on-chip I2C interface"
 	depends on ARCH_IOP32X || ARCH_IOP33X || ARCH_IXP4XX || ARCH_IOP13XX
@@ -462,6 +472,16 @@ config I2C_S3C2410
 	  Say Y here to include support for I2C controller in the
 	  Samsung S3C2410 based System-on-Chip devices.
 
+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
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 0c2c4b26cdf1ff4d5bac686a40a4a306bf0e730f..776acb6403a783bed7bcab070ae93d7384221c50 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -33,6 +33,7 @@ obj-$(CONFIG_I2C_DAVINCI)	+= i2c-davinci.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_IOP3XX)	+= i2c-iop3xx.o
 obj-$(CONFIG_I2C_IXP2000)	+= i2c-ixp2000.o
 obj-$(CONFIG_I2C_MPC)		+= i2c-mpc.o
@@ -43,6 +44,7 @@ obj-$(CONFIG_I2C_PASEMI)	+= i2c-pasemi.o
 obj-$(CONFIG_I2C_PNX)		+= i2c-pnx.o
 obj-$(CONFIG_I2C_PXA)		+= i2c-pxa.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
diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c
new file mode 100644
index 0000000000000000000000000000000000000000..0b486a63460d1aabd2df1b11702a906b79778d63
--- /dev/null
+++ b/drivers/i2c/busses/i2c-imx.c
@@ -0,0 +1,624 @@
+/*
+ *	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 <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;
+};
+
+/** Functions for IMX I2C adapter driver ***************************************
+*******************************************************************************/
+
+static int i2c_imx_bus_busy(struct imx_i2c_struct *i2c_imx)
+{
+	unsigned long orig_jiffies = jiffies;
+
+	dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__);
+
+	/* wait for bus not busy */
+	while (readb(i2c_imx->base + IMX_I2C_I2SR) & I2SR_IBB) {
+		if (signal_pending(current)) {
+			dev_dbg(&i2c_imx->adapter.dev,
+				"<%s> I2C Interrupted\n", __func__);
+			return -EINTR;
+		}
+		if (time_after(jiffies, orig_jiffies + HZ / 1000)) {
+			dev_dbg(&i2c_imx->adapter.dev,
+				"<%s> I2C bus is busy\n", __func__);
+			return -EIO;
+		}
+		schedule();
+	}
+
+	return 0;
+}
+
+static int i2c_imx_trx_complete(struct imx_i2c_struct *i2c_imx)
+{
+	int result;
+
+	result = wait_event_interruptible_timeout(i2c_imx->queue,
+		i2c_imx->i2csr & I2SR_IIF, HZ / 10);
+
+	if (unlikely(result < 0)) {
+		dev_dbg(&i2c_imx->adapter.dev, "<%s> result < 0\n", __func__);
+		return result;
+	} else 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 void i2c_imx_start(struct imx_i2c_struct *i2c_imx)
+{
+	unsigned int temp = 0;
+
+	dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__);
+
+	/* Enable I2C controller */
+	writeb(I2CR_IEN, i2c_imx->base + IMX_I2C_I2CR);
+	/* Start I2C transaction */
+	temp = readb(i2c_imx->base + IMX_I2C_I2CR);
+	temp |= I2CR_MSTA;
+	writeb(temp, i2c_imx->base + IMX_I2C_I2CR);
+	temp |= I2CR_IIEN | I2CR_MTX | I2CR_TXAK;
+	writeb(temp, i2c_imx->base + IMX_I2C_I2CR);
+}
+
+static void i2c_imx_stop(struct imx_i2c_struct *i2c_imx)
+{
+	unsigned int temp = 0;
+
+	/* Stop I2C transaction */
+	dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__);
+	temp = readb(i2c_imx->base + IMX_I2C_I2CR);
+	temp &= ~I2CR_MSTA;
+	writeb(temp, i2c_imx->base + IMX_I2C_I2CR);
+	/* setup chip registers to defaults */
+	writeb(I2CR_IEN, i2c_imx->base + IMX_I2C_I2CR);
+	writeb(0, i2c_imx->base + IMX_I2C_I2SR);
+	/*
+	 * 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);
+	/* Disable I2C controller */
+	writeb(0, i2c_imx->base + IMX_I2C_I2CR);
+}
+
+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++);
+
+	/* Write divider value to register */
+	writeb(i2c_clk_div[i][1], i2c_imx->base + IMX_I2C_IFDR);
+
+	/*
+	 * 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_interruptible(&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)) {
+			dev_dbg(&i2c_imx->adapter.dev,
+				"<%s> clear MSTA\n", __func__);
+			temp = readb(i2c_imx->base + IMX_I2C_I2CR);
+			temp &= ~I2CR_MSTA;
+			writeb(temp, i2c_imx->base + IMX_I2C_I2CR);
+		} 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__);
+
+	/* Check if i2c bus is not busy */
+	result = i2c_imx_bus_busy(i2c_imx);
+	if (result)
+		goto fail0;
+
+	/* Start I2C transfer */
+	i2c_imx_start(i2c_imx);
+
+	/* 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);
+		}
+		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]);
+	}
+
+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;
+	void __iomem *base;
+	resource_size_t res_size;
+	int irq;
+	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;
+	}
+
+	pdata = pdev->dev.platform_data;
+
+	if (pdata && pdata->init) {
+		ret = pdata->init(&pdev->dev);
+		if (ret)
+			return ret;
+	}
+
+	res_size = resource_size(res);
+	base = ioremap(res->start, res_size);
+	if (!base) {
+		dev_err(&pdev->dev, "ioremap failed\n");
+		ret = -EIO;
+		goto fail0;
+	}
+
+	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 fail1;
+	}
+
+	if (!request_mem_region(res->start, res_size, DRIVER_NAME)) {
+		ret = -EBUSY;
+		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->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;
+	}
+	clk_enable(i2c_imx->clk);
+
+	/* 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 */
+	if (pdata && pdata->bitrate)
+		i2c_imx_set_clk(i2c_imx, pdata->bitrate);
+	else
+		i2c_imx_set_clk(i2c_imx, IMX_I2C_BIT_RATE);
+
+	/* 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;
+	}
+
+	/* 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_disable(i2c_imx->clk);
+	clk_put(i2c_imx->clk);
+fail3:
+	release_mem_region(i2c_imx->res->start, resource_size(res));
+fail2:
+	kfree(i2c_imx);
+fail1:
+	iounmap(base);
+fail0:
+	if (pdata && pdata->exit)
+		pdata->exit(&pdev->dev);
+	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);
+	struct imxi2c_platform_data *pdata = pdev->dev.platform_data;
+
+	/* 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);
+
+	/* Shut down hardware */
+	if (pdata && pdata->exit)
+		pdata->exit(&pdev->dev);
+
+	/* Disable I2C clock */
+	clk_disable(i2c_imx->clk);
+	clk_put(i2c_imx->clk);
+
+	release_mem_region(i2c_imx->res->start, resource_size(i2c_imx->res));
+	iounmap(i2c_imx->base);
+	kfree(i2c_imx);
+	return 0;
+}
+
+static struct platform_driver i2c_imx_driver = {
+	.probe		= i2c_imx_probe,
+	.remove		= __exit_p(i2c_imx_remove),
+	.driver	= {
+		.name	= DRIVER_NAME,
+		.owner	= THIS_MODULE,
+	}
+};
+
+static int __init i2c_adap_imx_init(void)
+{
+	return platform_driver_probe(&i2c_imx_driver, i2c_imx_probe);
+}
+
+static void __exit i2c_adap_imx_exit(void)
+{
+	platform_driver_unregister(&i2c_imx_driver);
+}
+
+module_init(i2c_adap_imx_init);
+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/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c
index 26bf3701058648ad338847631122101eb37c691f..4af5c09f0e8fe3def51810746652f6d70da52717 100644
--- a/drivers/i2c/busses/i2c-mpc.c
+++ b/drivers/i2c/busses/i2c-mpc.c
@@ -20,18 +20,21 @@
 #include <linux/of_platform.h>
 #include <linux/of_i2c.h>
 
-#include <asm/io.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_FDR 	0x04
-#define MPC_I2C_CR	0x08
-#define MPC_I2C_SR	0x0c
-#define MPC_I2C_DR	0x10
+#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
@@ -50,15 +53,27 @@
 #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 flags;
 };
 
-static __inline__ void writeccr(struct mpc_i2c *i2c, u32 x)
+struct mpc_i2c_divider {
+	u16 divider;
+	u16 fdr;	/* including dfsrr */
+};
+
+struct mpc_i2c_match_data {
+	void (*setclock)(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);
 }
@@ -100,12 +115,11 @@ static int i2c_wait(struct mpc_i2c *i2c, unsigned timeout, int writing)
 	u32 x;
 	int result = 0;
 
-	if (i2c->irq == NO_IRQ)
-	{
+	if (i2c->irq == NO_IRQ) {
 		while (!(readb(i2c->base + MPC_I2C_SR) & CSR_MIF)) {
 			schedule();
 			if (time_after(jiffies, orig_jiffies + timeout)) {
-				pr_debug("I2C: timeout\n");
+				dev_dbg(i2c->dev, "timeout\n");
 				writeccr(i2c, 0);
 				result = -EIO;
 				break;
@@ -119,7 +133,7 @@ static int i2c_wait(struct mpc_i2c *i2c, unsigned timeout, int writing)
 			(i2c->interrupt & CSR_MIF), timeout);
 
 		if (unlikely(!(i2c->interrupt & CSR_MIF))) {
-			pr_debug("I2C: wait timeout\n");
+			dev_dbg(i2c->dev, "wait timeout\n");
 			writeccr(i2c, 0);
 			result = -ETIMEDOUT;
 		}
@@ -132,17 +146,17 @@ static int i2c_wait(struct mpc_i2c *i2c, unsigned timeout, int writing)
 		return result;
 
 	if (!(x & CSR_MCF)) {
-		pr_debug("I2C: unfinished\n");
+		dev_dbg(i2c->dev, "unfinished\n");
 		return -EIO;
 	}
 
 	if (x & CSR_MAL) {
-		pr_debug("I2C: MAL\n");
+		dev_dbg(i2c->dev, "MAL\n");
 		return -EIO;
 	}
 
 	if (writing && (x & CSR_RXAK)) {
-		pr_debug("I2C: No RXAK\n");
+		dev_dbg(i2c->dev, "No RXAK\n");
 		/* generate stop */
 		writeccr(i2c, CCR_MEN);
 		return -EIO;
@@ -150,18 +164,181 @@ static int i2c_wait(struct mpc_i2c *i2c, unsigned timeout, int writing)
 	return 0;
 }
 
-static void mpc_i2c_setclock(struct mpc_i2c *i2c)
+#ifdef CONFIG_PPC_52xx
+static const struct mpc_i2c_divider mpc_i2c_dividers_52xx[] = {
+	{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}
+};
+
+int mpc_i2c_get_fdr_52xx(struct device_node *node, u32 clock, int prescaler)
+{
+	const struct mpc52xx_i2c_divider *div = NULL;
+	unsigned int pvr = mfspr(SPRN_PVR);
+	u32 divider;
+	int i;
+
+	if (!clock)
+		return -EINVAL;
+
+	/* Determine divider value */
+	divider = mpc52xx_find_ipb_freq(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(mpc52xx_i2c_dividers); 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;
+	}
+
+	return div ? (int)div->fdr : -EINVAL;
+}
+
+static void mpc_i2c_setclock_52xx(struct device_node *node,
+				  struct mpc_i2c *i2c,
+				  u32 clock, u32 prescaler)
 {
-	/* Set clock and filters */
-	if (i2c->flags & FSL_I2C_DEV_SEPARATE_DFSRR) {
-		writeb(0x31, i2c->base + MPC_I2C_FDR);
-		writeb(0x10, i2c->base + MPC_I2C_DFSRR);
-	} else if (i2c->flags & FSL_I2C_DEV_CLOCK_5200)
-		writeb(0x3f, i2c->base + MPC_I2C_FDR);
-	else
-		writel(0x1031, i2c->base + MPC_I2C_FDR);
+	int fdr = mpc52xx_i2c_get_fdr(node, clock, prescaler);
+
+	if (fdr < 0)
+		fdr = 0x3f; /* backward compatibility */
+	writeb(fdr & 0xff, i2c->base + MPC_I2C_FDR);
+	dev_info(i2c->dev, "clock %d Hz (fdr=%d)\n", clock, fdr);
+}
+#else /* !CONFIG_PPC_52xx */
+static void mpc_i2c_setclock_52xx(struct device_node *node,
+				  struct mpc_i2c *i2c,
+				  u32 clock, u32 prescaler)
+{
+}
+#endif /* CONFIG_PPC_52xx*/
+
+#ifdef CONFIG_FSL_SOC
+static const struct mpc_i2c_divider mpc_i2c_dividers_8xxx[] = {
+	{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}
+};
+
+u32 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;
 }
 
+int mpc_i2c_get_fdr_8xxx(struct device_node *node, u32 clock, u32 prescaler)
+{
+	const struct mpc_i2c_divider *div = NULL;
+	u32 divider;
+	int i;
+
+	if (!clock)
+		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;
+	}
+
+	return div ? (int)div->fdr : -EINVAL;
+}
+
+static void mpc_i2c_setclock_8xxx(struct device_node *node,
+				  struct mpc_i2c *i2c,
+				  u32 clock, u32 prescaler)
+{
+	int fdr = mpc_i2c_get_fdr_8xxx(node, clock, prescaler);
+
+	if (fdr < 0)
+		fdr = 0x1031; /* backward compatibility */
+	writeb(fdr & 0xff, i2c->base + MPC_I2C_FDR);
+	writeb((fdr >> 8) & 0xff, i2c->base + MPC_I2C_DFSRR);
+	dev_info(i2c->dev, "clock %d Hz (dfsrr=%d fdr=%d)\n",
+		 clock, fdr >> 8, fdr & 0xff);
+}
+
+#else /* !CONFIG_FSL_SOC */
+static void mpc_i2c_setclock_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 */
@@ -176,7 +353,7 @@ static void mpc_i2c_stop(struct mpc_i2c *i2c)
 }
 
 static int mpc_write(struct mpc_i2c *i2c, int target,
-		     const u8 * data, int length, int restart)
+		     const u8 *data, int length, int restart)
 {
 	int i, result;
 	unsigned timeout = i2c->adap.timeout;
@@ -207,7 +384,7 @@ static int mpc_write(struct mpc_i2c *i2c, int target,
 }
 
 static int mpc_read(struct mpc_i2c *i2c, int target,
-		    u8 * data, int length, int restart)
+		    u8 *data, int length, int restart)
 {
 	unsigned timeout = i2c->adap.timeout;
 	int i, result;
@@ -264,12 +441,12 @@ static int mpc_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
 	/* Allow bus up to 1s to become not busy */
 	while (readb(i2c->base + MPC_I2C_SR) & CSR_MBB) {
 		if (signal_pending(current)) {
-			pr_debug("I2C: Interrupted\n");
+			dev_dbg(i2c->dev, "Interrupted\n");
 			writeccr(i2c, 0);
 			return -EINTR;
 		}
 		if (time_after(jiffies, orig_jiffies + HZ)) {
-			pr_debug("I2C: timeout\n");
+			dev_dbg(i2c->dev, "timeout\n");
 			if (readb(i2c->base + MPC_I2C_SR) ==
 			    (CSR_MCF | CSR_MBB | CSR_RXAK))
 				mpc_i2c_fixup(i2c);
@@ -280,9 +457,10 @@ static int mpc_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
 
 	for (i = 0; ret >= 0 && i < num; i++) {
 		pmsg = &msgs[i];
-		pr_debug("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);
+		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)
 			ret =
 			    mpc_read(i2c, pmsg->addr, pmsg->buf, pmsg->len, i);
@@ -311,27 +489,26 @@ static struct i2c_adapter mpc_ops = {
 	.timeout = HZ,
 };
 
-static int __devinit fsl_i2c_probe(struct of_device *op, const struct of_device_id *match)
+static int __devinit fsl_i2c_probe(struct of_device *op,
+				   const struct of_device_id *match)
 {
-	int result = 0;
 	struct mpc_i2c *i2c;
+	const u32 *prop;
+	u32 clock = 0;
+	int result = 0;
+	int plen;
 
 	i2c = kzalloc(sizeof(*i2c), GFP_KERNEL);
 	if (!i2c)
 		return -ENOMEM;
 
-	if (of_get_property(op->node, "dfsrr", NULL))
-		i2c->flags |= FSL_I2C_DEV_SEPARATE_DFSRR;
-
-	if (of_device_is_compatible(op->node, "fsl,mpc5200-i2c") ||
-			of_device_is_compatible(op->node, "mpc5200-i2c"))
-		i2c->flags |= FSL_I2C_DEV_CLOCK_5200;
+	i2c->dev = &op->dev; /* for debug and error output */
 
 	init_waitqueue_head(&i2c->queue);
 
 	i2c->base = of_iomap(op->node, 0);
 	if (!i2c->base) {
-		printk(KERN_ERR "i2c-mpc - failed to map controller\n");
+		dev_err(i2c->dev, "failed to map controller\n");
 		result = -ENOMEM;
 		goto fail_map;
 	}
@@ -341,12 +518,27 @@ static int __devinit fsl_i2c_probe(struct of_device *op, const struct of_device_
 		result = request_irq(i2c->irq, mpc_i2c_isr,
 				     IRQF_SHARED, "i2c-mpc", i2c);
 		if (result < 0) {
-			printk(KERN_ERR "i2c-mpc - failed to attach interrupt\n");
+			dev_err(i2c->dev, "failed to attach interrupt\n");
 			goto fail_request;
 		}
 	}
-	
-	mpc_i2c_setclock(i2c);
+
+	if (!of_get_property(op->node, "fsl,preserve-clocking", NULL)) {
+		prop = of_get_property(op->node, "clock-frequency", &plen);
+		if (prop && plen == sizeof(u32))
+			clock = *prop;
+
+		if (match->data) {
+			struct mpc_i2c_match_data *data =
+				(struct mpc_i2c_match_data *)match->data;
+			data->setclock(op->node, i2c, clock, data->prescaler);
+		} else {
+			/* Backwards compatibility */
+			if (of_get_property(op->node, "dfsrr", NULL))
+				mpc_i2c_setclock_8xxx(op->node, i2c,
+						      clock, 0);
+		}
+	}
 
 	dev_set_drvdata(&op->dev, i2c);
 
@@ -356,7 +548,7 @@ static int __devinit fsl_i2c_probe(struct of_device *op, const struct of_device_
 
 	result = i2c_add_adapter(&i2c->adap);
 	if (result < 0) {
-		printk(KERN_ERR "i2c-mpc - failed to add adapter\n");
+		dev_err(i2c->dev, "failed to add adapter\n");
 		goto fail_add;
 	}
 	of_register_i2c_devices(&i2c->adap, op->node);
@@ -368,7 +560,7 @@ static int __devinit fsl_i2c_probe(struct of_device *op, const struct of_device_
 	free_irq(i2c->irq, i2c);
  fail_request:
 	irq_dispose_mapping(i2c->irq);
- 	iounmap(i2c->base);
+	iounmap(i2c->base);
  fail_map:
 	kfree(i2c);
 	return result;
@@ -391,9 +583,43 @@ static int __devexit fsl_i2c_remove(struct of_device *op)
 };
 
 static const struct of_device_id mpc_i2c_of_match[] = {
-	{.compatible = "fsl-i2c",},
+	{.compatible = "mpc5200-i2c",
+	 .data = &(struct mpc_i2c_match_data) {
+			.setclock = mpc_i2c_setclock_52xx,
+		},
+	},
+	{.compatible = "fsl,mpc5200b-i2c",
+	 .data = &(struct mpc_i2c_match_data) {
+			.setclock = mpc_i2c_setclock_52xx,
+		},
+	},
+	{.compatible = "fsl,mpc5200-i2c",
+	 .data = &(struct mpc_i2c_match_data) {
+			.setclock = mpc_i2c_setclock_52xx,
+		},
+	},
+	{.compatible = "fsl,mpc8313-i2c",
+	 .data = &(struct mpc_i2c_match_data) {
+			.setclock = mpc_i2c_setclock_8xxx,
+		},
+	},
+	{.compatible = "fsl,mpc8543-i2c",
+	 .data = &(struct mpc_i2c_match_data) {
+			.setclock = mpc_i2c_setclock_8xxx,
+			.prescaler = 2,
+		},
+	},
+	{.compatible = "fsl,mpc8544-i2c",
+	 .data = &(struct mpc_i2c_match_data) {
+			.setclock = mpc_i2c_setclock_8xxx,
+			.prescaler = 3,
+		},
+	/* Backward compatibility */
+	},
+	{.compatible = "fsl-i2c", },
 	{},
 };
+
 MODULE_DEVICE_TABLE(of, mpc_i2c_of_match);
 
 
@@ -414,7 +640,7 @@ static int __init fsl_i2c_init(void)
 
 	rv = of_register_platform_driver(&mpc_i2c_driver);
 	if (rv)
-		printk(KERN_ERR DRV_NAME 
+		printk(KERN_ERR DRV_NAME
 		       " of_register_platform_driver failed (%i)\n", rv);
 	return rv;
 }
@@ -428,6 +654,6 @@ module_init(fsl_i2c_init);
 module_exit(fsl_i2c_exit);
 
 MODULE_AUTHOR("Adrian Cox <adrian@humboldt.co.uk>");
-MODULE_DESCRIPTION
-    ("I2C-Bus adapter for MPC107 bridge and MPC824x/85xx/52xx processors");
+MODULE_DESCRIPTION("I2C-Bus adapter for MPC107 bridge and "
+		   "MPC824x/85xx/52xx processors");
 MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c
index 5b7f95641ba48119d17fe71c7fc02b8c3b16fd2d..1691ef0f1ee1ee64dcd9352cf785849b26592623 100644
--- a/drivers/i2c/busses/i2c-s3c2410.c
+++ b/drivers/i2c/busses/i2c-s3c2410.c
@@ -1,6 +1,6 @@
 /* linux/drivers/i2c/busses/i2c-s3c2410.c
  *
- * Copyright (C) 2004,2005 Simtec Electronics
+ * Copyright (C) 2004,2005,2009 Simtec Electronics
  *	Ben Dooks <ben@simtec.co.uk>
  *
  * S3C2410 I2C Controller
@@ -590,18 +590,6 @@ static int s3c24xx_i2c_calcdivisor(unsigned long clkin, unsigned int wanted,
 	return clkin / (calc_divs * calc_div1);
 }
 
-/* freq_acceptable
- *
- * test wether a frequency is within the acceptable range of error
-*/
-
-static inline int freq_acceptable(unsigned int freq, unsigned int wanted)
-{
-	int diff = freq - wanted;
-
-	return diff >= -2 && diff <= 2;
-}
-
 /* s3c24xx_i2c_clockrate
  *
  * work out a divisor for the user requested frequency setting,
@@ -614,44 +602,28 @@ static int s3c24xx_i2c_clockrate(struct s3c24xx_i2c *i2c, unsigned int *got)
 	struct s3c2410_platform_i2c *pdata = i2c->dev->platform_data;
 	unsigned long clkin = clk_get_rate(i2c->clk);
 	unsigned int divs, div1;
+	unsigned long target_frequency;
 	u32 iiccon;
 	int freq;
-	int start, end;
 
 	i2c->clkrate = clkin;
 	clkin /= 1000;		/* clkin now in KHz */
 
-	dev_dbg(i2c->dev, "pdata %p, freq %lu %lu..%lu\n",
-		 pdata, pdata->bus_freq, pdata->min_freq, pdata->max_freq);
-
-	if (pdata->bus_freq != 0) {
-		freq = s3c24xx_i2c_calcdivisor(clkin, pdata->bus_freq/1000,
-					       &div1, &divs);
-		if (freq_acceptable(freq, pdata->bus_freq/1000))
-			goto found;
-	}
-
-	/* ok, we may have to search for something suitable... */
+	dev_dbg(i2c->dev, "pdata desired frequency %lu\n", pdata->frequency);
 
-	start = (pdata->max_freq == 0) ? pdata->bus_freq : pdata->max_freq;
-	end = pdata->min_freq;
+	target_frequency = pdata->frequency ? pdata->frequency : 100000;
 
-	start /= 1000;
-	end /= 1000;
+	target_frequency /= 1000; /* Target frequency now in KHz */
 
-	/* search loop... */
+	freq = s3c24xx_i2c_calcdivisor(clkin, target_frequency, &div1, &divs);
 
-	for (; start > end; start--) {
-		freq = s3c24xx_i2c_calcdivisor(clkin, start, &div1, &divs);
-		if (freq_acceptable(freq, start))
-			goto found;
+	if (freq > target_frequency) {
+		dev_err(i2c->dev,
+			"Unable to achieve desired frequency %luKHz."	\
+			" Lowest achievable %dKHz\n", target_frequency, freq);
+		return -EINVAL;
 	}
 
-	/* cannot find frequency spec */
-
-	return -EINVAL;
-
- found:
 	*got = freq;
 
 	iiccon = readl(i2c->regs + S3C2410_IICCON);
@@ -663,6 +635,23 @@ static int s3c24xx_i2c_clockrate(struct s3c24xx_i2c *i2c, unsigned int *got)
 
 	writel(iiccon, i2c->regs + S3C2410_IICCON);
 
+	if (s3c24xx_i2c_is2440(i2c)) {
+		unsigned long sda_delay;
+
+		if (pdata->sda_delay) {
+			sda_delay = (freq / 1000) * pdata->sda_delay;
+			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;
 }
 
@@ -769,11 +758,8 @@ static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c)
 
 	/* check for s3c2440 i2c controller  */
 
-	if (s3c24xx_i2c_is2440(i2c)) {
-		dev_dbg(i2c->dev, "S3C2440_IICLC=%08x\n", pdata->sda_delay);
-
-		writel(pdata->sda_delay, i2c->regs + S3C2440_IICLC);
-	}
+	if (s3c24xx_i2c_is2440(i2c))
+		writel(0x0, i2c->regs + S3C2440_IICLC);
 
 	return 0;
 }
@@ -1018,14 +1004,13 @@ static int __init i2c_adap_s3c_init(void)
 
 	return ret;
 }
+subsys_initcall(i2c_adap_s3c_init);
 
 static void __exit i2c_adap_s3c_exit(void)
 {
 	platform_driver_unregister(&s3c2410_i2c_driver);
 	platform_driver_unregister(&s3c2440_i2c_driver);
 }
-
-module_init(i2c_adap_s3c_init);
 module_exit(i2c_adap_s3c_exit);
 
 MODULE_DESCRIPTION("S3C24XX I2C Bus driver");
diff --git a/drivers/i2c/busses/i2c-s6000.c b/drivers/i2c/busses/i2c-s6000.c
new file mode 100644
index 0000000000000000000000000000000000000000..c91359f4965c0e3db5055c5cf44cf389fe0769e0
--- /dev/null
+++ b/drivers/i2c/busses/i2c-s6000.c
@@ -0,0 +1,407 @@
+/*
+ * 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 <asm/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: cant 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);
+	if (bus_num < 0)
+		rc = i2c_add_adapter(p_adap);
+	else
+		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/drivers/i2c/busses/i2c-s6000.h b/drivers/i2c/busses/i2c-s6000.h
new file mode 100644
index 0000000000000000000000000000000000000000..ff23b81ded44591ceb93cd861701bd2a632cc0ce
--- /dev/null
+++ b/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/include/linux/i2c/s6000.h b/include/linux/i2c/s6000.h
new file mode 100644
index 0000000000000000000000000000000000000000..d9b34bfdae7604c36fb57be28cc1eaf73e14d7c9
--- /dev/null
+++ b/include/linux/i2c/s6000.h
@@ -0,0 +1,10 @@
+#ifndef __LINUX_I2C_S6000_H
+#define __LINUX_I2C_S6000_H
+
+struct s6_i2c_platform_data {
+	const char *clock; /* the clock to use */
+	int bus_num; /* the bus number to register */
+};
+
+#endif
+