diff --git a/arch/arm/plat-omap/Makefile b/arch/arm/plat-omap/Makefile
index 2549129aabc67f23f1d4d5851e8d8631cbddbd11..ce17df31b845b0543e43229faa6b6e5186de8c6a 100644
--- a/arch/arm/plat-omap/Makefile
+++ b/arch/arm/plat-omap/Makefile
@@ -19,3 +19,4 @@ obj-$(CONFIG_CPU_FREQ) += cpu-omap.o
 obj-$(CONFIG_OMAP_DM_TIMER) += dmtimer.o
 obj-$(CONFIG_OMAP_DEBUG_DEVICES) += debug-devices.o
 obj-$(CONFIG_OMAP_DEBUG_LEDS) += debug-leds.o
+obj-$(CONFIG_I2C_OMAP) += i2c.o
diff --git a/arch/arm/plat-omap/i2c.c b/arch/arm/plat-omap/i2c.c
new file mode 100644
index 0000000000000000000000000000000000000000..7990ab185bb1f7eeed556e0d533ed7429551323b
--- /dev/null
+++ b/arch/arm/plat-omap/i2c.c
@@ -0,0 +1,148 @@
+/*
+ * linux/arch/arm/plat-omap/i2c.c
+ *
+ * Helper module for board specific I2C bus registration
+ *
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * Contact: Jarkko Nikula <jarkko.nikula@nokia.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., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <asm/mach-types.h>
+#include <asm/arch/mux.h>
+
+#define OMAP_I2C_SIZE		0x3f
+#define OMAP1_I2C_BASE		0xfffb3800
+#define OMAP2_I2C_BASE1		0x48070000
+#define OMAP2_I2C_BASE2		0x48072000
+#define OMAP2_I2C_BASE3		0x48060000
+
+static const char name[] = "i2c_omap";
+
+#define I2C_RESOURCE_BUILDER(base, irq)			\
+	{						\
+		.start	= (base),			\
+		.end	= (base) + OMAP_I2C_SIZE,	\
+		.flags	= IORESOURCE_MEM,		\
+	},						\
+	{						\
+		.start	= (irq),			\
+		.flags	= IORESOURCE_IRQ,		\
+	},
+
+static struct resource i2c_resources[][2] = {
+	{ I2C_RESOURCE_BUILDER(0, 0) },
+#if	defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
+	{ I2C_RESOURCE_BUILDER(OMAP2_I2C_BASE2, INT_24XX_I2C2_IRQ) },
+#endif
+#if	defined(CONFIG_ARCH_OMAP34XX)
+	{ I2C_RESOURCE_BUILDER(OMAP2_I2C_BASE3, INT_34XX_I2C3_IRQ) },
+#endif
+};
+
+#define I2C_DEV_BUILDER(bus_id, res, data)		\
+	{						\
+		.id	= (bus_id),			\
+		.name	= name,				\
+		.num_resources	= ARRAY_SIZE(res),	\
+		.resource	= (res),		\
+		.dev		= {			\
+			.platform_data	= (data),	\
+		},					\
+	}
+
+static u32 i2c_rate[ARRAY_SIZE(i2c_resources)];
+static struct platform_device omap_i2c_devices[] = {
+	I2C_DEV_BUILDER(1, i2c_resources[0], &i2c_rate[0]),
+#if	defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
+	I2C_DEV_BUILDER(2, i2c_resources[1], &i2c_rate[1]),
+#endif
+#if	defined(CONFIG_ARCH_OMAP34XX)
+	I2C_DEV_BUILDER(3, i2c_resources[2], &i2c_rate[2]),
+#endif
+};
+
+static void __init omap_i2c_mux_pins(int bus_id)
+{
+	/* TODO: Muxing for OMAP3 */
+	switch (bus_id) {
+	case 1:
+		if (cpu_class_is_omap1()) {
+			omap_cfg_reg(I2C_SCL);
+			omap_cfg_reg(I2C_SDA);
+		} else if (cpu_is_omap24xx()) {
+			omap_cfg_reg(M19_24XX_I2C1_SCL);
+			omap_cfg_reg(L15_24XX_I2C1_SDA);
+		}
+		break;
+	case 2:
+		if (cpu_is_omap24xx()) {
+			omap_cfg_reg(J15_24XX_I2C2_SCL);
+			omap_cfg_reg(H19_24XX_I2C2_SDA);
+		}
+		break;
+	}
+}
+
+int __init omap_register_i2c_bus(int bus_id, u32 clkrate,
+			  struct i2c_board_info const *info,
+			  unsigned len)
+{
+	int ports, err;
+	struct platform_device *pdev;
+	struct resource *res;
+	resource_size_t base, irq;
+
+	if (cpu_class_is_omap1())
+		ports = 1;
+	else if (cpu_is_omap24xx())
+		ports = 2;
+	else if (cpu_is_omap34xx())
+		ports = 3;
+
+	BUG_ON(bus_id < 1 || bus_id > ports);
+
+	if (info) {
+		err = i2c_register_board_info(bus_id, info, len);
+		if (err)
+			return err;
+	}
+
+	pdev = &omap_i2c_devices[bus_id - 1];
+	*(u32 *)pdev->dev.platform_data = clkrate;
+
+	if (bus_id == 1) {
+		res = pdev->resource;
+		if (cpu_class_is_omap1()) {
+			base = OMAP1_I2C_BASE;
+			irq = INT_I2C;
+		} else {
+			base = OMAP2_I2C_BASE1;
+			irq = INT_24XX_I2C1_IRQ;
+		}
+		res[0].start = base;
+		res[0].end = base + OMAP_I2C_SIZE;
+		res[1].start = irq;
+	}
+
+	omap_i2c_mux_pins(bus_id);
+	return platform_device_register(pdev);
+}
diff --git a/include/asm-arm/arch-omap/common.h b/include/asm-arm/arch-omap/common.h
index 08d58abd82182a1fdd307f1a7ed94a256f86c35d..442aecbb8f44b23f3392906b9c790dc5e651f626 100644
--- a/include/asm-arm/arch-omap/common.h
+++ b/include/asm-arm/arch-omap/common.h
@@ -27,10 +27,21 @@
 #ifndef __ARCH_ARM_MACH_OMAP_COMMON_H
 #define __ARCH_ARM_MACH_OMAP_COMMON_H
 
+#ifdef CONFIG_I2C_OMAP
+#include <linux/i2c.h>
+#endif
+
 struct sys_timer;
 
 extern void omap_map_common_io(void);
 extern struct sys_timer omap_timer;
 extern void omap_serial_init(void);
+#ifdef CONFIG_I2C_OMAP
+extern int omap_register_i2c_bus(int bus_id, u32 clkrate,
+				 struct i2c_board_info const *info,
+				 unsigned len);
+#else
+#define omap_register_i2c_bus(a, b, c, d)	0
+#endif
 
 #endif /* __ARCH_ARM_MACH_OMAP_COMMON_H */
diff --git a/include/asm-arm/arch-omap/irqs.h b/include/asm-arm/arch-omap/irqs.h
index 3ede58b51db28f36688e451d173b51b1fffc12ab..87973654e625d6c9c3fee9505f764c131b52d26e 100644
--- a/include/asm-arm/arch-omap/irqs.h
+++ b/include/asm-arm/arch-omap/irqs.h
@@ -263,6 +263,8 @@
 #define INT_24XX_GPTIMER10	46
 #define INT_24XX_GPTIMER11	47
 #define INT_24XX_GPTIMER12	48
+#define INT_24XX_I2C1_IRQ	56
+#define INT_24XX_I2C2_IRQ	57
 #define INT_24XX_MCBSP1_IRQ_TX	59
 #define INT_24XX_MCBSP1_IRQ_RX	60
 #define INT_24XX_MCBSP2_IRQ_TX	62