On Monday 30 June 2014 8:16:01 am Nic Roets wrote:
> The patch I tried (dated 2012) did not include the platform support:

I was just going to suggest that in reply to you earlier message.

This is the current version of the patch for kernel v3.15-rc7; It has all
the clocks and what not needed for more recent kernels.

if this doesnt work I'd be very interested in seeing the details of your
setup.


---
 arch/m68k/include/asm/m5206sim.h     |    8 +
 arch/m68k/include/asm/m520xsim.h     |    7 +
 arch/m68k/include/asm/m523xsim.h     |   10 +-
 arch/m68k/include/asm/m527xsim.h     |    8 +
 arch/m68k/include/asm/m528xsim.h     |    9 +
 arch/m68k/include/asm/m5307sim.h     |    9 +-
 arch/m68k/include/asm/m53xxsim.h     |    7 +
 arch/m68k/include/asm/m5407sim.h     |    8 +
 arch/m68k/include/asm/m54xxsim.h     |   10 +
 arch/m68k/include/asm/mcfi2c.h       |   15 +
 arch/m68k/platform/coldfire/device.c |  193 +++++++++++++
 arch/m68k/platform/coldfire/m5206.c  |   12 +
 arch/m68k/platform/coldfire/m520x.c  |   18 +-
 arch/m68k/platform/coldfire/m523x.c  |   18 ++
 arch/m68k/platform/coldfire/m5249.c  |   25 ++
 arch/m68k/platform/coldfire/m525x.c  |    6 +-
 arch/m68k/platform/coldfire/m527x.c  |   28 ++
 arch/m68k/platform/coldfire/m528x.c  |   18 ++
 arch/m68k/platform/coldfire/m5307.c  |   14 +
 arch/m68k/platform/coldfire/m53xx.c  |   15 +-
 arch/m68k/platform/coldfire/m5407.c  |   14 +
 arch/m68k/platform/coldfire/m54xx.c  |   17 ++
 drivers/i2c/busses/Kconfig           |   10 +
 drivers/i2c/busses/Makefile          |    1 +
 drivers/i2c/busses/i2c-coldfire.c    |  496 ++++++++++++++++++++++++++++++++++
 25 files changed, 971 insertions(+), 5 deletions(-)

diff --git a/arch/m68k/include/asm/m5206sim.h b/arch/m68k/include/asm/m5206sim.h
index 4cf864f..0ddf3ef 100644
--- a/arch/m68k/include/asm/m5206sim.h
+++ b/arch/m68k/include/asm/m5206sim.h
@@ -110,6 +110,7 @@
 /*
  *     Define system peripheral IRQ usage.
  */
+#define        MCF_IRQ_I2C0            29              /* I2C, Level 5 */
 #define        MCF_IRQ_TIMER           30              /* Timer0, Level 6 */
 #define        MCF_IRQ_PROFILER        31              /* Timer1, Level 7 */
 #define        MCF_IRQ_UART0           73              /* UART0 */
@@ -138,6 +139,7 @@
 #define        MCFSIM_SWDICR           MCFSIM_ICR8     /* Watchdog timer ICR */
 #define        MCFSIM_TIMER1ICR        MCFSIM_ICR9     /* Timer 1 ICR */
 #define        MCFSIM_TIMER2ICR        MCFSIM_ICR10    /* Timer 2 ICR */
+#define        MCFSIM_I2CICR           MCFSIM_ICR11    /* I2C ICR */
 #define        MCFSIM_UART1ICR         MCFSIM_ICR12    /* UART 1 ICR */
 #define        MCFSIM_UART2ICR         MCFSIM_ICR13    /* UART 2 ICR */
 #ifdef CONFIG_M5206e
@@ -145,5 +147,11 @@
 #define        MCFSIM_DMA2ICR          MCFSIM_ICR15    /* DMA 2 ICR */
 #endif
 
+/*
+ * I2C Controller
+*/
+#define MCFI2C_BASE0           (MCF_MBAR + 0x1e0)
+#define MCFI2C_SIZE0           0x40
+
 /****************************************************************************/
 #endif /* m5206sim_h */
diff --git a/arch/m68k/include/asm/m520xsim.h b/arch/m68k/include/asm/m520xsim.h
index db3f8ee..505a614 100644
--- a/arch/m68k/include/asm/m520xsim.h
+++ b/arch/m68k/include/asm/m520xsim.h
@@ -50,6 +50,7 @@
 #define MCFINT_UART0        26          /* Interrupt number for UART0 */
 #define MCFINT_UART1        27          /* Interrupt number for UART1 */
 #define MCFINT_UART2        28          /* Interrupt number for UART2 */
+#define MCFINT_I2C0         30          /* Interrupt number for I2C */
 #define MCFINT_QSPI         31          /* Interrupt number for QSPI */
 #define MCFINT_FECRX0      36          /* Interrupt number for FEC RX */
 #define MCFINT_FECTX0      40          /* Interrupt number for FEC RX */
@@ -67,6 +68,7 @@
 #define        MCF_IRQ_QSPI        (MCFINT_VECBASE + MCFINT_QSPI)
 #define MCF_IRQ_PIT1        (MCFINT_VECBASE + MCFINT_PIT1)
 
+#define MCF_IRQ_I2C0        (MCFINT_VECBASE + MCFINT_I2C0)
 /*
  *  SDRAM configuration registers.
  */
@@ -199,6 +201,11 @@
 #define MCFPM_PPMHR0           0xfc040030
 #define MCFPM_PPMLR0           0xfc040034
 #define MCFPM_LPCR             0xfc0a0007
+/*
+ * I2C module.
+*/
+#define MCFI2C_BASE0           0xFC058000
+#define MCFI2C_SIZE0           0x40
 
 /****************************************************************************/
 #endif  /* m520xsim_h */
diff --git a/arch/m68k/include/asm/m523xsim.h b/arch/m68k/include/asm/m523xsim.h
index 5e06b4e..50f6c3f 100644
--- a/arch/m68k/include/asm/m523xsim.h
+++ b/arch/m68k/include/asm/m523xsim.h
@@ -37,7 +37,8 @@
 #define        MCFINT_UART0            13              /* Interrupt number for 
UART0 */
 #define        MCFINT_UART1            14              /* Interrupt number for 
UART1 */
 #define        MCFINT_UART2            15              /* Interrupt number for 
UART2 */
-#define MCFINT_QSPI            18              /* Interrupt number for QSPI */
+#define        MCFINT_I2C0             17              /* Interrupt number for 
I2C */
+#define        MCFINT_QSPI             18              /* Interrupt number for 
QSPI */
 #define        MCFINT_FECRX0           23              /* Interrupt number for 
FEC */
 #define        MCFINT_FECTX0           27              /* Interrupt number for 
FEC */
 #define        MCFINT_FECENTC0         29              /* Interrupt number for 
FEC */
@@ -53,6 +54,7 @@
 
 #define        MCF_IRQ_QSPI            (MCFINT_VECBASE + MCFINT_QSPI)
 #define MCF_IRQ_PIT1           (MCFINT_VECBASE + MCFINT_PIT1)
+#define        MCF_IRQ_I2C0            (MCFINT_VECBASE + MCFINT_I2C0)
 
 /*
  *     SDRAM configuration registers.
@@ -208,5 +210,11 @@
 #define        MCFDMA_BASE2            (MCF_IPSBAR + 0x180)
 #define        MCFDMA_BASE3            (MCF_IPSBAR + 0x1C0)
 
+/*
+ * I2C module.
+*/
+#define        MCFI2C_BASE0            (MCF_IPSBAR + 0x300)
+#define        MCFI2C_SIZE0            0x40
+
 /****************************************************************************/
 #endif /* m523xsim_h */
diff --git a/arch/m68k/include/asm/m527xsim.h b/arch/m68k/include/asm/m527xsim.h
index 1bebbe7..a3a5d83 100644
--- a/arch/m68k/include/asm/m527xsim.h
+++ b/arch/m68k/include/asm/m527xsim.h
@@ -37,6 +37,7 @@
 #define        MCFINT_UART0            13              /* Interrupt number for 
UART0 */
 #define        MCFINT_UART1            14              /* Interrupt number for 
UART1 */
 #define        MCFINT_UART2            15              /* Interrupt number for 
UART2 */
+#define        MCFINT_I2C0             17              /* Interrupt number for 
I2C */
 #define        MCFINT_QSPI             18              /* Interrupt number for 
QSPI */
 #define        MCFINT_FECRX0           23              /* Interrupt number for 
FEC0 */
 #define        MCFINT_FECTX0           27              /* Interrupt number for 
FEC0 */
@@ -61,6 +62,7 @@
 
 #define        MCF_IRQ_QSPI            (MCFINT_VECBASE + MCFINT_QSPI)
 #define MCF_IRQ_PIT1           (MCFINT_VECBASE + MCFINT_PIT1)
+#define        MCF_IRQ_I2C0            (MCFINT_VECBASE + MCFINT_I2C0)
 
 /*
  *     SDRAM configuration registers.
@@ -351,5 +353,11 @@
 #define        MCF_RCR_SWRESET         0x80            /* Software reset bit */
 #define        MCF_RCR_FRCSTOUT        0x40            /* Force external reset 
*/
 
+/*
+ * I2C module.
+*/
+#define        MCFI2C_BASE0            (MCF_IPSBAR + 0x300)
+#define        MCFI2C_SIZE0            0x40
+
 /****************************************************************************/
 #endif /* m527xsim_h */
diff --git a/arch/m68k/include/asm/m528xsim.h b/arch/m68k/include/asm/m528xsim.h
index cf68ca0..df223e6 100644
--- a/arch/m68k/include/asm/m528xsim.h
+++ b/arch/m68k/include/asm/m528xsim.h
@@ -37,6 +37,7 @@
 #define        MCFINT_UART0            13              /* Interrupt number for 
UART0 */
 #define        MCFINT_UART1            14              /* Interrupt number for 
UART1 */
 #define        MCFINT_UART2            15              /* Interrupt number for 
UART2 */
+#define        MCFINT_I2C0             17              /* Interrupt number for 
I2C */
 #define        MCFINT_QSPI             18              /* Interrupt number for 
QSPI */
 #define        MCFINT_FECRX0           23              /* Interrupt number for 
FEC */
 #define        MCFINT_FECTX0           27              /* Interrupt number for 
FEC */
@@ -53,6 +54,8 @@
 
 #define        MCF_IRQ_QSPI            (MCFINT_VECBASE + MCFINT_QSPI)
 #define MCF_IRQ_PIT1           (MCFINT_VECBASE + MCFINT_PIT1)
+#define        MCF_IRQ_I2C0            (MCFINT_VECBASE + MCFINT_I2C0)
+
 /*
  *     SDRAM configuration registers.
  */
@@ -242,5 +245,11 @@
 #define        MCF_RCR_SWRESET         0x80            /* Software reset bit */
 #define        MCF_RCR_FRCSTOUT        0x40            /* Force external reset 
*/
 
+/*
+ * I2C module
+*/
+#define        MCFI2C_BASE0            (MCF_IPSBAR + 0x300)
+#define        MCFI2C_SIZE0            0x40
+
 /****************************************************************************/
 #endif /* m528xsim_h */
diff --git a/arch/m68k/include/asm/m5307sim.h b/arch/m68k/include/asm/m5307sim.h
index 5d0bb7e..baa9304 100644
--- a/arch/m68k/include/asm/m5307sim.h
+++ b/arch/m68k/include/asm/m5307sim.h
@@ -148,6 +148,7 @@
 #define        MCFSIM_SWDICR           MCFSIM_ICR0     /* Watchdog timer ICR */
 #define        MCFSIM_TIMER1ICR        MCFSIM_ICR1     /* Timer 1 ICR */
 #define        MCFSIM_TIMER2ICR        MCFSIM_ICR2     /* Timer 2 ICR */
+#define        MCFSIM_I2CICR           MCFSIM_ICR3     /* I2C ICR */
 #define        MCFSIM_UART1ICR         MCFSIM_ICR4     /* UART 1 ICR */
 #define        MCFSIM_UART2ICR         MCFSIM_ICR5     /* UART 2 ICR */
 #define        MCFSIM_DMA0ICR          MCFSIM_ICR6     /* DMA 0 ICR */
@@ -155,7 +156,6 @@
 #define        MCFSIM_DMA2ICR          MCFSIM_ICR8     /* DMA 2 ICR */
 #define        MCFSIM_DMA3ICR          MCFSIM_ICR9     /* DMA 3 ICR */
 
-
 /*
  *     Some symbol defines for the Parallel Port Pin Assignment Register
  */
@@ -174,10 +174,17 @@
 /*
  *     Define system peripheral IRQ usage.
  */
+#define        MCF_IRQ_I2C0            29              /* I2C, Level 5 */
 #define        MCF_IRQ_TIMER           30              /* Timer0, Level 6 */
 #define        MCF_IRQ_PROFILER        31              /* Timer1, Level 7 */
 #define        MCF_IRQ_UART0           73              /* UART0 */
 #define        MCF_IRQ_UART1           74              /* UART1 */
 
+/*
+ * I2C module
+*/
+#define        MCFI2C_BASE0            (MCF_MBAR + 0x280)
+#define        MCFI2C_SIZE0            0x40
+
 /****************************************************************************/
 #endif /* m5307sim_h */
diff --git a/arch/m68k/include/asm/m53xxsim.h b/arch/m68k/include/asm/m53xxsim.h
index faa1a21..c35ca07 100644
--- a/arch/m68k/include/asm/m53xxsim.h
+++ b/arch/m68k/include/asm/m53xxsim.h
@@ -19,6 +19,7 @@
 #define MCFINT_UART0        26          /* Interrupt number for UART0 */
 #define MCFINT_UART1        27          /* Interrupt number for UART1 */
 #define MCFINT_UART2        28          /* Interrupt number for UART2 */
+#define MCFINT_I2C0         30         /* Interrupt number for I2C */
 #define MCFINT_QSPI         31          /* Interrupt number for QSPI */
 #define MCFINT_FECRX0      36          /* Interrupt number for FEC */
 #define MCFINT_FECTX0      40          /* Interrupt number for FEC */
@@ -32,6 +33,7 @@
 #define MCF_IRQ_FECTX0     (MCFINT_VECBASE + MCFINT_FECTX0)
 #define MCF_IRQ_FECENTC0    (MCFINT_VECBASE + MCFINT_FECENTC0)
 
+#define        MCF_IRQ_I2C0        (MCFINT_VECBASE + MCFINT_I2C0)
 #define        MCF_IRQ_QSPI        (MCFINT_VECBASE + MCFINT_QSPI)
 
 #define MCF_WTM_WCR            0xFC098000
@@ -1237,5 +1239,10 @@
 #define MCFEPORT_EPPDR                (0xFC094005)
 #define MCFEPORT_EPFR                 (0xFC094006)
 
+/*
+ * I2C Module
+ */
+#define        MCFI2C_BASE0                    (0xFc058000)
+#define        MCFI2C_SIZE0                    0x40
 /********************************************************************/
 #endif /* m53xxsim_h */
diff --git a/arch/m68k/include/asm/m5407sim.h b/arch/m68k/include/asm/m5407sim.h
index a7550bc..018c535 100644
--- a/arch/m68k/include/asm/m5407sim.h
+++ b/arch/m68k/include/asm/m5407sim.h
@@ -112,6 +112,7 @@
 #define        MCFSIM_SWDICR           MCFSIM_ICR0     /* Watchdog timer ICR */
 #define        MCFSIM_TIMER1ICR        MCFSIM_ICR1     /* Timer 1 ICR */
 #define        MCFSIM_TIMER2ICR        MCFSIM_ICR2     /* Timer 2 ICR */
+#define        MCFSIM_I2CICR           MCFSIM_ICR3     /* I2C ICR */
 #define        MCFSIM_UART1ICR         MCFSIM_ICR4     /* UART 1 ICR */
 #define        MCFSIM_UART2ICR         MCFSIM_ICR5     /* UART 2 ICR */
 #define        MCFSIM_DMA0ICR          MCFSIM_ICR6     /* DMA 0 ICR */
@@ -137,10 +138,17 @@
 /*
  *     Define system peripheral IRQ usage.
  */
+#define        MCF_IRQ_I2C0            29              /* I2C, Level 5 */
 #define        MCF_IRQ_TIMER           30              /* Timer0, Level 6 */
 #define        MCF_IRQ_PROFILER        31              /* Timer1, Level 7 */
 #define        MCF_IRQ_UART0           73              /* UART0 */
 #define        MCF_IRQ_UART1           74              /* UART1 */
 
+/*
+ * I2C module
+*/
+#define        MCFI2C_BASE0            (MCF_MBAR + 0x280)
+#define        MCFI2C_SIZE0            0x40
+
 /****************************************************************************/
 #endif /* m5407sim_h */
diff --git a/arch/m68k/include/asm/m54xxsim.h b/arch/m68k/include/asm/m54xxsim.h
index d3bd838..5edaf22 100644
--- a/arch/m68k/include/asm/m54xxsim.h
+++ b/arch/m68k/include/asm/m54xxsim.h
@@ -41,6 +41,7 @@
  */
 #define MCF_IRQ_TIMER          (MCFINT_VECBASE + 54)   /* Slice Timer 0 */
 #define MCF_IRQ_PROFILER       (MCFINT_VECBASE + 53)   /* Slice Timer 1 */
+#define MCF_IRQ_I2C0           (MCFINT_VECBASE + 40)
 #define MCF_IRQ_UART0          (MCFINT_VECBASE + 35)
 #define MCF_IRQ_UART1          (MCFINT_VECBASE + 34)
 #define MCF_IRQ_UART2          (MCFINT_VECBASE + 33)
@@ -97,4 +98,13 @@
 #define MCF_PAR_PSC_RTS_RTS    (0x30)
 #define MCF_PAR_PSC_CANRX      (0x40)
 
+#define MCF_PAR_FECI2CIRQ      (MCF_MBAR + 0x00000a44) /* FEC/I2C/IRQ */
+#define MCF_PAR_FECI2CIRQ_SDA  (1 << 3)
+#define MCF_PAR_FECI2CIRQ_SCL  (1 << 2)
+/*
+ * I2C module.
+*/
+#define MCFI2C_BASE0           (MCF_MBAR + 0x8f00)
+#define MCFI2C_SIZE0           0x40
+
 #endif /* m54xxsim_h */
diff --git a/arch/m68k/include/asm/mcfi2c.h b/arch/m68k/include/asm/mcfi2c.h
new file mode 100644
index 0000000..24b0453
--- /dev/null
+++ b/arch/m68k/include/asm/mcfi2c.h
@@ -0,0 +1,15 @@
+/*
+ * Definitions for Coldfire I2C interface
+*/
+#ifndef mcfi2c_h
+#define mcfi2c_h
+
+/**
+ * struct mcfi2c_platform_data - platform data for the coldfire i2c driver
+ * @bitrate: bitrate to use for this i2c controller.
+*/
+struct mcfi2c_platform_data {
+       u32     bitrate;
+};
+
+#endif /* mcfi2c_h */
diff --git a/arch/m68k/platform/coldfire/device.c 
b/arch/m68k/platform/coldfire/device.c
index 71ea4c0..7d20603 100644
--- a/arch/m68k/platform/coldfire/device.c
+++ b/arch/m68k/platform/coldfire/device.c
@@ -19,6 +19,7 @@
 #include <asm/mcfsim.h>
 #include <asm/mcfuart.h>
 #include <asm/mcfqspi.h>
+#include <asm/mcfi2c.h>
 
 /*
  *     All current ColdFire parts contain from 2, 3, 4 or 10 UARTS.
@@ -327,6 +328,180 @@ static struct platform_device mcf_qspi = {
 };
 #endif /* IS_ENABLED(CONFIG_SPI_COLDFIRE_QSPI) */
 
+#if IS_ENABLED(CONFIG_I2C_COLDFIRE)
+static struct resource mcf_i2c0_resources[] = {
+       {
+               .start          = MCFI2C_BASE0,
+               .end            = MCFI2C_BASE0 + MCFI2C_SIZE0 - 1,
+               .flags          = IORESOURCE_MEM,
+       },
+       {
+               .start          = MCF_IRQ_I2C0,
+               .end            = MCF_IRQ_I2C0,
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+static struct mcfi2c_platform_data mcf_i2c0_platform_data = {
+       .bitrate                = 100000,
+};
+
+static struct platform_device mcf_i2c0 = {
+       .name                   = "mcfi2c",
+       .id                     = 0,
+       .num_resources          = ARRAY_SIZE(mcf_i2c0_resources),
+       .resource               = mcf_i2c0_resources,
+       .dev.platform_data      = &mcf_i2c0_platform_data,
+};
+#ifdef MCFI2C_BASE1
+
+static struct resource mcf_i2c1_resources[] = {
+       {
+               .start          = MCFI2C_BASE1,
+               .end            = MCFI2C_BASE1 + MCFI2C_SIZE1 - 1,
+               .flags          = IORESOURCE_MEM,
+       },
+       {
+               .start          = MCF_IRQ_I2C1,
+               .end            = MCF_IRQ_I2C1,
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+static struct mcfi2c_platform_data mcf_i2c1_platform_data = {
+       .bitrate                = 100000,
+};
+
+static struct platform_device mcf_i2c1 = {
+       .name                   = "mcfi2c",
+       .id                     = 1,
+       .num_resources          = ARRAY_SIZE(mcf_i2c1_resources),
+       .resource               = mcf_i2c1_resources,
+       .dev.platform_data      = &mcf_i2c1_platform_data,
+};
+
+#endif /* MCFI2C_BASE1 */
+
+#ifdef MCFI2C_BASE2
+
+static struct resource mcf_i2c2_resources[] = {
+       {
+               .start          = MCFI2C_BASE2,
+               .end            = MCFI2C_BASE2 + MCFI2C_SIZE2 - 1,
+               .flags          = IORESOURCE_MEM,
+       },
+       {
+               .start          = MCF_IRQ_I2C2,
+               .end            = MCF_IRQ_I2C2,
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+static struct mcfi2c_platform_data mcf_i2c2_platform_data = {
+       .bitrate                = 100000,
+};
+
+static struct platform_device mcf_i2c2 = {
+       .name                   = "mcfi2c",
+       .id                     = 2,
+       .num_resources          = ARRAY_SIZE(mcf_i2c2_resources),
+       .resource               = mcf_i2c2_resources,
+       .dev.platform_data      = &mcf_i2c2_platform_data,
+};
+
+#endif /* MCFI2C_BASE2 */
+
+#ifdef MCFI2C_BASE3
+
+static struct resource mcf_i2c3_resources[] = {
+       {
+               .start          = MCFI2C_BASE3,
+               .end            = MCFI2C_BASE3 + MCFI2C_SIZE3 - 1,
+               .flags          = IORESOURCE_MEM,
+       },
+       {
+               .start          = MCF_IRQ_I2C3,
+               .end            = MCF_IRQ_I2C3,
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+static struct mcfi2c_platform_data mcf_i2c3_platform_data = {
+       .bitrate                = 100000,
+};
+
+static struct platform_device mcf_i2c3 = {
+       .name                   = "mcfi2c",
+       .id                     = 3,
+       .num_resources          = ARRAY_SIZE(mcf_i2c3_resources),
+       .resource               = mcf_i2c3_resources,
+       .dev.platform_data      = &mcf_i2c3_platform_data,
+};
+
+#endif /* MCFI2C_BASE3 */
+
+#ifdef MCFI2C_BASE4
+
+static struct resource mcf_i2c4_resources[] = {
+       {
+               .start          = MCFI2C_BASE4,
+               .end            = MCFI2C_BASE4 + MCFI2C_SIZE4 - 1,
+               .flags          = IORESOURCE_MEM,
+       },
+       {
+               .start          = MCF_IRQ_I2C4,
+               .end            = MCF_IRQ_I2C4,
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+static struct mcfi2c_platform_data mcf_i2c4_platform_data = {
+       .bitrate                = 100000,
+};
+
+static struct platform_device mcf_i2c4 = {
+       .name                   = "mcfi2c",
+       .id                     = 4,
+       .num_resources          = ARRAY_SIZE(mcf_i2c4_resources),
+       .resource               = mcf_i2c4_resources,
+       .dev.platform_data      = &mcf_i2c4_platform_data,
+};
+
+#endif /* MCFI2C_BASE4 */
+
+#ifdef MCFI2C_BASE5
+
+static struct resource mcf_i2c5_resources[] = {
+       {
+               .start          = MCFI2C_BASE5,
+               .end            = MCFI2C_BASE5 + MCFI2C_SIZE5 - 1,
+               .flags          = IORESOURCE_MEM,
+       },
+       {
+               .start          = MCF_IRQ_I2C5,
+               .end            = MCF_IRQ_I2C5,
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+static struct mcfi2c_platform_data mcf_i2c5_platform_data = {
+       .bitrate                = 100000,
+};
+
+static struct platform_device mcf_i2c5 = {
+       .name                   = "mcfi2c",
+       .id                     = 5,
+       .num_resources          = ARRAY_SIZE(mcf_i2c5_resources),
+       .resource               = mcf_i2c5_resources,
+       .dev.platform_data      = &mcf_i2c5_platform_data,
+};
+
+#endif /* MCFI2C_BASE5 */
+
+
+#endif /* IS_ENABLED(CONFIG_I2C_COLDFIRE) */
+
+
 static struct platform_device *mcf_devices[] __initdata = {
        &mcf_uart,
 #ifdef CONFIG_FEC
@@ -338,6 +513,24 @@ static struct platform_device *mcf_devices[] __initdata = {
 #if IS_ENABLED(CONFIG_SPI_COLDFIRE_QSPI)
        &mcf_qspi,
 #endif
+#if IS_ENABLED(CONFIG_I2C_COLDFIRE)
+       &mcf_i2c0,
+#ifdef MCFI2C_BASE1
+       &mcf_i2c1,
+#endif
+#ifdef MCFI2C_BASE2
+       &mcf_i2c2,
+#endif
+#ifdef MCFI2C_BASE3
+       &mcf_i2c3,
+#endif
+#ifdef MCFI2C_BASE4
+       &mcf_i2c4,
+#endif
+#ifdef MCFI2C_BASE5
+       &mcf_i2c5,
+#endif
+#endif
 };
 
 /*
diff --git a/arch/m68k/platform/coldfire/m5206.c 
b/arch/m68k/platform/coldfire/m5206.c
index 0e55f44..f3d6258 100644
--- a/arch/m68k/platform/coldfire/m5206.c
+++ b/arch/m68k/platform/coldfire/m5206.c
@@ -26,6 +26,7 @@ DEFINE_CLK(mcftmr0, "mcftmr.0", MCF_BUSCLK);
 DEFINE_CLK(mcftmr1, "mcftmr.1", MCF_BUSCLK);
 DEFINE_CLK(mcfuart0, "mcfuart.0", MCF_BUSCLK);
 DEFINE_CLK(mcfuart1, "mcfuart.1", MCF_BUSCLK);
+DEFINE_CLK(mcfi2c0, "mcfi2c.0", MCF_BUSCLK);
 
 struct clk *mcf_clks[] = {
        &clk_pll,
@@ -34,11 +35,21 @@ struct clk *mcf_clks[] = {
        &clk_mcftmr1,
        &clk_mcfuart0,
        &clk_mcfuart1,
+       &clk_mcfi2c0,
        NULL
 };
 
 /***************************************************************************/
 
+static void __init m5206_i2c_init(void)
+{
+#if IS_ENABLED(CONFIG_I2C_COLDFIRE)
+       writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL5 | MCFSIM_ICR_PRI0,
+              MCFSIM_I2CICR);
+       mcf_mapirq2imr(MCF_IRQ_I2C0, MCFINTC_I2C);
+#endif /* IS_ENABLED(CONFIG_I2C_COLDFIRE) */
+}
+
 void __init config_BSP(char *commandp, int size)
 {
 #if defined(CONFIG_NETtel)
@@ -53,6 +64,7 @@ void __init config_BSP(char *commandp, int size)
        mcf_mapirq2imr(25, MCFINTC_EINT1);
        mcf_mapirq2imr(28, MCFINTC_EINT4);
        mcf_mapirq2imr(31, MCFINTC_EINT7);
+       m5206_i2c_init();
 }
 
 /***************************************************************************/
diff --git a/arch/m68k/platform/coldfire/m520x.c 
b/arch/m68k/platform/coldfire/m520x.c
index ea1be0e..2becf2d 100644
--- a/arch/m68k/platform/coldfire/m520x.c
+++ b/arch/m68k/platform/coldfire/m520x.c
@@ -71,7 +71,7 @@ struct clk *mcf_clks[] = {
        &__clk_0_40, /* sys.0 */
        &__clk_0_41, /* gpio.0 */
        &__clk_0_42, /* sdram.0 */
-NULL,
+       NULL,
 };
 
 static struct clk * const enable_clks[] __initconst = {
@@ -135,6 +135,21 @@ static void __init m520x_qspi_init(void)
 
 /***************************************************************************/
 
+static void __init m520x_i2c_init(void)
+{
+#if IS_ENABLED(CONFIG_I2C_COLDFIRE)
+       u8 par;
+
+       /* setup Port FECI2C Pin Assignment Register for I2C */
+       /*  set PAR_SCL to SCL and PAR_SDA to SDA */
+       par = readb(MCF_GPIO_PAR_FECI2C);
+       par |= 0x0f;
+       writeb(par, MCF_GPIO_PAR_FECI2C);
+#endif /* IS_ENABLED(CONFIG_I2C_COLDFIRE) */
+}
+
+/***************************************************************************/
+
 static void __init m520x_uarts_init(void)
 {
        u16 par;
@@ -179,6 +194,7 @@ void __init config_BSP(char *commandp, int size)
 #if IS_ENABLED(CONFIG_SPI_COLDFIRE_QSPI)
        m520x_qspi_init();
 #endif
+       m520x_i2c_init();
 }
 
 /***************************************************************************/
diff --git a/arch/m68k/platform/coldfire/m523x.c 
b/arch/m68k/platform/coldfire/m523x.c
index 2b10e9f..0139703 100644
--- a/arch/m68k/platform/coldfire/m523x.c
+++ b/arch/m68k/platform/coldfire/m523x.c
@@ -33,6 +33,7 @@ DEFINE_CLK(mcfuart0, "mcfuart.0", MCF_BUSCLK);
 DEFINE_CLK(mcfuart1, "mcfuart.1", MCF_BUSCLK);
 DEFINE_CLK(mcfuart2, "mcfuart.2", MCF_BUSCLK);
 DEFINE_CLK(fec0, "fec.0", MCF_BUSCLK);
+DEFINE_CLK(mcfi2c0, "mcfi2c.0", MCF_BUSCLK);
 
 struct clk *mcf_clks[] = {
        &clk_pll,
@@ -45,6 +46,7 @@ struct clk *mcf_clks[] = {
        &clk_mcfuart1,
        &clk_mcfuart2,
        &clk_fec0,
+       &clk_mcfi2c0,
        NULL
 };
 
@@ -68,6 +70,21 @@ static void __init m523x_qspi_init(void)
 
 /***************************************************************************/
 
+static void __init m523x_i2c_init(void)
+{
+#if IS_ENABLED(CONFIG_I2C_COLDFIRE)
+       u8 par;
+
+       /* setup Port AS Pin Assignment Register for I2C */
+       /*  set PASPA0 to SCL and PASPA1 to SDA */
+       par = readb(MCFGPIO_PAR_FECI2C);
+       par |= 0x0f;
+       writeb(par, MCFGPIO_PAR_FECI2C);
+#endif /* IS_ENABLED(CONFIG_I2C_COLDFIRE) */
+}
+
+/***************************************************************************/
+
 static void __init m523x_fec_init(void)
 {
        /* Set multi-function pins to ethernet use */
@@ -83,6 +100,7 @@ void __init config_BSP(char *commandp, int size)
 #if IS_ENABLED(CONFIG_SPI_COLDFIRE_QSPI)
        m523x_qspi_init();
 #endif
+       m523x_i2c_init();
 }
 
 /***************************************************************************/
diff --git a/arch/m68k/platform/coldfire/m5249.c 
b/arch/m68k/platform/coldfire/m5249.c
index c80b5e5..eb4d9f5 100644
--- a/arch/m68k/platform/coldfire/m5249.c
+++ b/arch/m68k/platform/coldfire/m5249.c
@@ -26,6 +26,8 @@ DEFINE_CLK(mcftmr0, "mcftmr.0", MCF_BUSCLK);
 DEFINE_CLK(mcftmr1, "mcftmr.1", MCF_BUSCLK);
 DEFINE_CLK(mcfuart0, "mcfuart.0", MCF_BUSCLK);
 DEFINE_CLK(mcfuart1, "mcfuart.1", MCF_BUSCLK);
+DEFINE_CLK(mcfi2c0, "mcfi2c.0", MCF_BUSCLK);
+DEFINE_CLK(mcfi2c1, "mcfi2c.1", MCF_BUSCLK);
 
 struct clk *mcf_clks[] = {
        &clk_pll,
@@ -34,6 +36,8 @@ struct clk *mcf_clks[] = {
        &clk_mcftmr1,
        &clk_mcfuart0,
        &clk_mcfuart1,
+       &clk_mcfi2c0,
+       &clk_mcfi2c1,
        NULL
 };
 
@@ -85,6 +89,26 @@ static void __init m5249_qspi_init(void)
 
 /***************************************************************************/
 
+static void __init m5249_i2c_init(void)
+{
+#if IS_ENABLED(CONFIG_I2C_COLDFIRE)
+       u32 r;
+
+       /* first I2C controller uses regular irq setup */
+       writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL5 | MCFSIM_ICR_PRI0,
+              MCFSIM_I2CICR);
+       mcf_mapirq2imr(MCF_IRQ_I2C0, MCFINTC_I2C);
+
+       /* second I2C controller is completely different */
+       r = readl(MCFINTC2_INTPRI_REG(MCF_IRQ_I2C1));
+       r &= ~MCFINTC2_INTPRI_BITS(0xf, MCF_IRQ_I2C1);
+       r |= MCFINTC2_INTPRI_BITS(0x5, MCF_IRQ_I2C1);
+       writel(r, MCFINTC2_INTPRI_REG(MCF_IRQ_I2C1));
+#endif
+}
+
+/***************************************************************************/
+
 #ifdef CONFIG_M5249C3
 
 static void __init m5249_smc91x_init(void)
@@ -113,6 +137,7 @@ void __init config_BSP(char *commandp, int size)
 #if IS_ENABLED(CONFIG_SPI_COLDFIRE_QSPI)
        m5249_qspi_init();
 #endif
+       m5249_i2c_init();
 }
 
 /***************************************************************************/
diff --git a/arch/m68k/platform/coldfire/m525x.c 
b/arch/m68k/platform/coldfire/m525x.c
index 5b9f657..ce149e4 100644
--- a/arch/m68k/platform/coldfire/m525x.c
+++ b/arch/m68k/platform/coldfire/m525x.c
@@ -26,6 +26,8 @@ DEFINE_CLK(mcftmr0, "mcftmr.0", MCF_BUSCLK);
 DEFINE_CLK(mcftmr1, "mcftmr.1", MCF_BUSCLK);
 DEFINE_CLK(mcfuart0, "mcfuart.0", MCF_BUSCLK);
 DEFINE_CLK(mcfuart1, "mcfuart.1", MCF_BUSCLK);
+DEFINE_CLK(mcfi2c0, "mcfi2c.0", MCF_BUSCLK);
+DEFINE_CLK(mcfi2c1, "mcfi2c.1", MCF_BUSCLK);
 
 struct clk *mcf_clks[] = {
        &clk_pll,
@@ -34,6 +36,8 @@ struct clk *mcf_clks[] = {
        &clk_mcftmr1,
        &clk_mcfuart0,
        &clk_mcfuart1,
+       &clk_mcfi2c0,
+       &clk_mcfi2c1,
        NULL
 };
 
@@ -62,7 +66,7 @@ static void __init m525x_i2c_init(void)
 
        /* first I2C controller uses regular irq setup */
        writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL5 | MCFSIM_ICR_PRI0,
-               MCFSIM_I2CICR);
+              MCFSIM_I2CICR);
        mcf_mapirq2imr(MCF_IRQ_I2C0, MCFINTC_I2C);
 
        /* second I2C controller is completely different */
diff --git a/arch/m68k/platform/coldfire/m527x.c 
b/arch/m68k/platform/coldfire/m527x.c
index 6fbfe909..625cb9a 100644
--- a/arch/m68k/platform/coldfire/m527x.c
+++ b/arch/m68k/platform/coldfire/m527x.c
@@ -35,6 +35,7 @@ DEFINE_CLK(mcfuart1, "mcfuart.1", MCF_BUSCLK);
 DEFINE_CLK(mcfuart2, "mcfuart.2", MCF_BUSCLK);
 DEFINE_CLK(fec0, "fec.0", MCF_BUSCLK);
 DEFINE_CLK(fec1, "fec.1", MCF_BUSCLK);
+DEFINE_CLK(mcfi2c0, "mcfi2c.0", MCF_BUSCLK);
 
 struct clk *mcf_clks[] = {
        &clk_pll,
@@ -48,6 +49,7 @@ struct clk *mcf_clks[] = {
        &clk_mcfuart2,
        &clk_fec0,
        &clk_fec1,
+       &clk_mcfi2c0,
        NULL
 };
 
@@ -76,6 +78,31 @@ static void __init m527x_qspi_init(void)
 
 /***************************************************************************/
 
+static void __init m527x_i2c_init(void)
+{
+#if IS_ENABLED(CONFIG_I2C_COLDFIRE)
+#if defined(CONFIG_M5271)
+       u8 par;
+
+       /* setup Port FECI2C Pin Assignment Register for I2C */
+       /*  set PAR_SCL to SCL and PAR_SDA to SDA */
+       par = readb(MCFGPIO_PAR_FECI2C);
+       par |= 0x0f;
+       writeb(par, MCFGPIO_PAR_FECI2C);
+#elif defined(CONFIG_M5275)
+       u16 par;
+
+       /* setup Port FECI2C Pin Assignment Register for I2C */
+       /*  set PAR_SCL to SCL and PAR_SDA to SDA */
+       par = readw(MCFGPIO_PAR_FECI2C);
+       par |= 0x0f;
+       writew(par, MCFGPIO_PAR_FECI2C);
+#endif
+#endif /* IS_ENABLED(CONFIG_I2C_COLDFIRE) */
+}
+
+/***************************************************************************/
+
 static void __init m527x_uarts_init(void)
 {
        u16 sepmask;
@@ -123,6 +150,7 @@ void __init config_BSP(char *commandp, int size)
 #if IS_ENABLED(CONFIG_SPI_COLDFIRE_QSPI)
        m527x_qspi_init();
 #endif
+       m527x_i2c_init();
 }
 
 /***************************************************************************/
diff --git a/arch/m68k/platform/coldfire/m528x.c 
b/arch/m68k/platform/coldfire/m528x.c
index b03a9d2..e2f8b3e 100644
--- a/arch/m68k/platform/coldfire/m528x.c
+++ b/arch/m68k/platform/coldfire/m528x.c
@@ -35,6 +35,7 @@ DEFINE_CLK(mcfuart0, "mcfuart.0", MCF_BUSCLK);
 DEFINE_CLK(mcfuart1, "mcfuart.1", MCF_BUSCLK);
 DEFINE_CLK(mcfuart2, "mcfuart.2", MCF_BUSCLK);
 DEFINE_CLK(fec0, "fec.0", MCF_BUSCLK);
+DEFINE_CLK(mcfi2c0, "mcfi2c.0", MCF_BUSCLK);
 
 struct clk *mcf_clks[] = {
        &clk_pll,
@@ -47,6 +48,7 @@ struct clk *mcf_clks[] = {
        &clk_mcfuart1,
        &clk_mcfuart2,
        &clk_fec0,
+       &clk_mcfi2c0,
        NULL
 };
 
@@ -64,6 +66,21 @@ static void __init m528x_qspi_init(void)
 
 /***************************************************************************/
 
+static void __init m528x_i2c_init(void)
+{
+#if IS_ENABLED(CONFIG_I2C_COLDFIRE)
+       u16 paspar;
+
+       /* setup Port AS Pin Assignment Register for I2C */
+       /*  set PASPA0 to SCL and PASPA1 to SDA */
+       paspar = readw(MCFGPIO_PASPAR);
+       paspar |= 0xF;
+       writew(paspar, MCFGPIO_PASPAR);
+#endif /* IS_ENABLED(CONFIG_I2C_COLDFIRE) */
+}
+
+/***************************************************************************/
+
 static void __init m528x_uarts_init(void)
 {
        u8 port;
@@ -129,6 +146,7 @@ void __init config_BSP(char *commandp, int size)
 #if IS_ENABLED(CONFIG_SPI_COLDFIRE_QSPI)
        m528x_qspi_init();
 #endif
+       m528x_i2c_init();
 }
 
 /***************************************************************************/
diff --git a/arch/m68k/platform/coldfire/m5307.c 
b/arch/m68k/platform/coldfire/m5307.c
index 8874353..1f844ba 100644
--- a/arch/m68k/platform/coldfire/m5307.c
+++ b/arch/m68k/platform/coldfire/m5307.c
@@ -35,6 +35,7 @@ DEFINE_CLK(mcftmr0, "mcftmr.0", MCF_BUSCLK);
 DEFINE_CLK(mcftmr1, "mcftmr.1", MCF_BUSCLK);
 DEFINE_CLK(mcfuart0, "mcfuart.0", MCF_BUSCLK);
 DEFINE_CLK(mcfuart1, "mcfuart.1", MCF_BUSCLK);
+DEFINE_CLK(mcfi2c0, "mcfi2c.0", MCF_BUSCLK);
 
 struct clk *mcf_clks[] = {
        &clk_pll,
@@ -43,11 +44,23 @@ struct clk *mcf_clks[] = {
        &clk_mcftmr1,
        &clk_mcfuart0,
        &clk_mcfuart1,
+       &clk_mcfi2c0,
        NULL
 };
 
 /***************************************************************************/
 
+static void __init m5307_i2c_init(void)
+{
+#if IS_ENABLED(CONFIG_I2C_COLDFIRE)
+       writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL5 | MCFSIM_ICR_PRI0,
+              MCFSIM_I2CICR);
+       mcf_mapirq2imr(MCF_IRQ_I2C0, MCFINTC_I2C);
+#endif /* IS_ENABLED(CONFIG_I2C_COLDFIRE) */
+}
+
+/***************************************************************************/
+
 void __init config_BSP(char *commandp, int size)
 {
 #if defined(CONFIG_NETtel) || \
@@ -73,6 +86,7 @@ void __init config_BSP(char *commandp, int size)
         */
        wdebug(MCFDEBUG_CSR, MCFDEBUG_CSR_PSTCLK);
 #endif
+       m5307_i2c_init();
 }
 
 /***************************************************************************/
diff --git a/arch/m68k/platform/coldfire/m53xx.c 
b/arch/m68k/platform/coldfire/m53xx.c
index 5286f98..22c532b 100644
--- a/arch/m68k/platform/coldfire/m53xx.c
+++ b/arch/m68k/platform/coldfire/m53xx.c
@@ -178,6 +178,19 @@ static void __init m53xx_qspi_init(void)
 
 /***************************************************************************/
 
+static void __init m53xx_i2c_init(void)
+{
+#if IS_ENABLED(CONFIG_I2C_COLDFIRE)
+       /* setup Port AS Pin Assignment Register for I2C */
+       /*  set PASPA0 to SCL and PASPA1 to SDA */
+       u8 r = readb(MCFGPIO_PAR_FECI2C);
+       r |= 0x0f;
+       writeb(r, MCFGPIO_PAR_FECI2C);
+#endif /* IS_ENABLED(CONFIG_I2C_COLDFIRE) */
+}
+
+/***************************************************************************/
+
 static void __init m53xx_uarts_init(void)
 {
        /* UART GPIO initialization */
@@ -222,7 +235,7 @@ void __init config_BSP(char *commandp, int size)
 #if IS_ENABLED(CONFIG_SPI_COLDFIRE_QSPI)
        m53xx_qspi_init();
 #endif
-
+       m53xx_i2c_init();
 #ifdef CONFIG_BDM_DISABLE
        /*
         * Disable the BDM clocking.  This also turns off most of the rest of
diff --git a/arch/m68k/platform/coldfire/m5407.c 
b/arch/m68k/platform/coldfire/m5407.c
index 2fb3cdb..3588212 100644
--- a/arch/m68k/platform/coldfire/m5407.c
+++ b/arch/m68k/platform/coldfire/m5407.c
@@ -26,6 +26,7 @@ DEFINE_CLK(mcftmr0, "mcftmr.0", MCF_BUSCLK);
 DEFINE_CLK(mcftmr1, "mcftmr.1", MCF_BUSCLK);
 DEFINE_CLK(mcfuart0, "mcfuart.0", MCF_BUSCLK);
 DEFINE_CLK(mcfuart1, "mcfuart.1", MCF_BUSCLK);
+DEFINE_CLK(mcfi2c0, "mcfi2c.0", MCF_BUSCLK);
 
 struct clk *mcf_clks[] = {
        &clk_pll,
@@ -34,11 +35,23 @@ struct clk *mcf_clks[] = {
        &clk_mcftmr1,
        &clk_mcfuart0,
        &clk_mcfuart1,
+       &clk_mcfi2c0,
        NULL
 };
 
 /***************************************************************************/
 
+static void __init m5407_i2c_init(void)
+{
+#if IS_ENABLED(CONFIG_I2C_COLDFIRE)
+       writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL5 | MCFSIM_ICR_PRI0,
+              MCFSIM_I2CICR);
+       mcf_mapirq2imr(MCF_IRQ_I2C0, MCFINTC_I2C);
+#endif /* IS_ENABLED(CONFIG_I2C_COLDFIRE) */
+}
+
+/***************************************************************************/
+
 void __init config_BSP(char *commandp, int size)
 {
        mach_sched_init = hw_timer_init;
@@ -48,6 +61,7 @@ void __init config_BSP(char *commandp, int size)
        mcf_mapirq2imr(27, MCFINTC_EINT3);
        mcf_mapirq2imr(29, MCFINTC_EINT5);
        mcf_mapirq2imr(31, MCFINTC_EINT7);
+       m5407_i2c_init();
 }
 
 /***************************************************************************/
diff --git a/arch/m68k/platform/coldfire/m54xx.c 
b/arch/m68k/platform/coldfire/m54xx.c
index 952da53..67f047b 100644
--- a/arch/m68k/platform/coldfire/m54xx.c
+++ b/arch/m68k/platform/coldfire/m54xx.c
@@ -38,6 +38,7 @@ DEFINE_CLK(mcfuart0, "mcfuart.0", MCF_BUSCLK);
 DEFINE_CLK(mcfuart1, "mcfuart.1", MCF_BUSCLK);
 DEFINE_CLK(mcfuart2, "mcfuart.2", MCF_BUSCLK);
 DEFINE_CLK(mcfuart3, "mcfuart.3", MCF_BUSCLK);
+DEFINE_CLK(mcfi2c0, "mcfi2c.0", MCF_BUSCLK);
 
 struct clk *mcf_clks[] = {
        &clk_pll,
@@ -48,6 +49,7 @@ struct clk *mcf_clks[] = {
        &clk_mcfuart1,
        &clk_mcfuart2,
        &clk_mcfuart3,
+       &clk_mcfi2c0,
        NULL
 };
 
@@ -66,6 +68,20 @@ static void __init m54xx_uarts_init(void)
 
 /***************************************************************************/
 
+static void __init m54xx_i2c_init(void)
+{
+#if IS_ENABLED(CONFIG_I2C_COLDFIRE)
+       u32 r;
+
+       /* set the fec/i2c/irq pin assignment register for i2c */
+       r = readl(MCF_PAR_FECI2CIRQ);
+       r |= MCF_PAR_FECI2CIRQ_SDA | MCF_PAR_FECI2CIRQ_SCL;
+       writel(r, MCF_PAR_FECI2CIRQ);
+#endif /* IS_ENABLED(CONFIG_I2C_COLDFIRE) */
+}
+
+/***************************************************************************/
+
 static void mcf54xx_reset(void)
 {
        /* disable interrupts and enable the watchdog */
@@ -124,6 +140,7 @@ void __init config_BSP(char *commandp, int size)
        mach_reset = mcf54xx_reset;
        mach_sched_init = hw_timer_init;
        m54xx_uarts_init();
+       m54xx_i2c_init();
 }
 
 /***************************************************************************/
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index c94db1c..30d250c 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -393,6 +393,16 @@ config I2C_CBUS_GPIO
          This driver can also be built as a module.  If so, the module
          will be called i2c-cbus-gpio.
 
+config I2C_COLDFIRE
+       tristate "Freescale Coldfire I2C driver"
+       depends on !M5272
+       help
+         This driver supports the I2C interface availible on most Freescale
+         Coldfire processors.
+
+         This driver can be built as a module.  If so, the module
+         will be called i2c-coldfire.
+
 config I2C_CPM
        tristate "Freescale CPM1 or CPM2 (MPC8xx/826x)"
        depends on CPM1 || CPM2
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 18d18ff..e9e951e 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -35,6 +35,7 @@ obj-$(CONFIG_I2C_BCM2835)     += i2c-bcm2835.o
 obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o
 obj-$(CONFIG_I2C_CADENCE)      += i2c-cadence.o
 obj-$(CONFIG_I2C_CBUS_GPIO)    += i2c-cbus-gpio.o
+obj-$(CONFIG_I2C_COLDFIRE)     += i2c-coldfire.o
 obj-$(CONFIG_I2C_CPM)          += i2c-cpm.o
 obj-$(CONFIG_I2C_DAVINCI)      += i2c-davinci.o
 obj-$(CONFIG_I2C_DESIGNWARE_CORE)      += i2c-designware-core.o
diff --git a/drivers/i2c/busses/i2c-coldfire.c 
b/drivers/i2c/busses/i2c-coldfire.c
new file mode 100644
index 0000000..165a29e
--- /dev/null
+++ b/drivers/i2c/busses/i2c-coldfire.c
@@ -0,0 +1,496 @@
+/* Freescale/Motorola Coldfire I2C driver.
+ *
+ * Copyright 2010, 2012 Steven King <sfk...@fdwdc.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 St - Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/pm_runtime.h>
+#include <asm/mcfi2c.h>
+
+#define        DRIVER_NAME "mcfi2c"
+
+#define        MCFI2C_ADR                      0x00
+#define        MCFI2C_FDR                      0x04
+#define        MCFI2C_CR                       0x08
+#define                MCFI2C_CR_IEN           0x80
+#define                MCFI2C_CR_IIEN          0x40
+#define                MCFI2C_CR_MSTA          0x20
+#define                MCFI2C_CR_MTX           0x10
+#define                MCFI2C_CR_TXAK          0x08
+#define                MCFI2C_CR_RSTA          0x04
+#define        MCFI2C_DR                       0x10
+#define        MCFI2C_SR                       0x0C
+#define                MCFI2C_SR_ICF           0x80
+#define                MCFI2C_SR_IAAS          0x40
+#define                MCFI2C_SR_IBB           0x20
+#define                MCFI2C_SR_IAL           0x10
+#define                MCFI2C_SR_SRW           0x04
+#define                MCFI2C_SR_IIF           0x02
+#define                MCFI2C_SR_RXAK          0x01
+
+#define        DEFAULT_I2C_BUS_SPEED           100000
+
+struct mcfi2c {
+       struct i2c_adapter      adapter;
+       void __iomem            *iobase;
+       int                     irq;
+       struct clk              *clk;
+       struct completion       completion;
+
+       u8                      *buf;
+       u16                     flags;
+       u16                     len;
+       int                     more;
+       int                     status;
+};
+
+static u8 mcfi2c_rd_cr(struct mcfi2c *mcfi2c)
+{
+       return readb(mcfi2c->iobase + MCFI2C_CR);
+}
+
+static void mcfi2c_wr_cr(struct mcfi2c *mcfi2c, u8 val)
+{
+       writeb(val, mcfi2c->iobase + MCFI2C_CR);
+}
+
+static u8 mcfi2c_rd_sr(struct mcfi2c *mcfi2c)
+{
+       return readb(mcfi2c->iobase + MCFI2C_SR);
+}
+
+static void mcfi2c_wr_sr(struct mcfi2c *mcfi2c, u8 val)
+{
+       writeb(val, mcfi2c->iobase + MCFI2C_SR);
+}
+
+static u8 mcfi2c_rd_dr(struct mcfi2c *mcfi2c)
+{
+       return readb(mcfi2c->iobase + MCFI2C_DR);
+}
+
+static void mcfi2c_wr_dr(struct mcfi2c *mcfi2c, u8 val)
+{
+       writeb(val, mcfi2c->iobase + MCFI2C_DR);
+}
+
+static void mcfi2c_start(struct mcfi2c *mcfi2c)
+{
+       mcfi2c_wr_cr(mcfi2c, MCFI2C_CR_IEN | MCFI2C_CR_IIEN | MCFI2C_CR_MSTA |
+                    MCFI2C_CR_MTX);
+}
+
+static void mcfi2c_repeat_start(struct mcfi2c *mcfi2c)
+{
+       mcfi2c_wr_cr(mcfi2c, MCFI2C_CR_IEN | MCFI2C_CR_IIEN | MCFI2C_CR_MSTA |
+                    MCFI2C_CR_MTX | MCFI2C_CR_RSTA);
+}
+
+static void mcfi2c_stop(struct mcfi2c *mcfi2c)
+{
+       mcfi2c_wr_cr(mcfi2c, MCFI2C_CR_IEN);
+}
+
+static void mcfi2c_tx_ack(struct mcfi2c *mcfi2c)
+{
+       mcfi2c_wr_cr(mcfi2c, MCFI2C_CR_IEN | MCFI2C_CR_IIEN | MCFI2C_CR_MSTA);
+}
+
+static void mcfi2c_tx_nak(struct mcfi2c *mcfi2c)
+{
+       mcfi2c_wr_cr(mcfi2c, MCFI2C_CR_IEN | MCFI2C_CR_IIEN | MCFI2C_CR_MSTA |
+                    MCFI2C_CR_TXAK);
+}
+
+static irqreturn_t mcfi2c_irq_handler(int this_irq, void *dev_id)
+{
+       struct mcfi2c *mcfi2c = dev_id;
+       u8 sr;
+
+       if (pm_runtime_suspended(&mcfi2c->adapter.dev))
+               return IRQ_NONE;
+
+       /* clear interrupt */
+       mcfi2c_wr_sr(mcfi2c, 0);
+
+       sr = mcfi2c_rd_sr(mcfi2c);
+       if (sr & MCFI2C_SR_IAL) {
+               mcfi2c_wr_sr(mcfi2c, ~MCFI2C_SR_IAL);
+               mcfi2c->status = -EAGAIN;
+       } else {
+               if (mcfi2c_rd_cr(mcfi2c) & MCFI2C_CR_MTX) {
+                       if (sr & MCFI2C_SR_RXAK) {
+                               mcfi2c_stop(mcfi2c);
+                               mcfi2c->status = -EIO;
+                       } else if (mcfi2c->flags & I2C_M_RD) {
+                               if (mcfi2c->len > 1)
+                                       mcfi2c_tx_ack(mcfi2c);
+                               else
+                                       mcfi2c_tx_nak(mcfi2c);
+                               /* dummy read */
+                               mcfi2c_rd_dr(mcfi2c);
+                               goto not_complete;
+
+                       } else if (mcfi2c->len--) {
+                               mcfi2c_wr_dr(mcfi2c, *(mcfi2c->buf++));
+                               goto not_complete;
+                       } else {
+                               if (mcfi2c->more)
+                                       mcfi2c_repeat_start(mcfi2c);
+                               else
+                                       mcfi2c_stop(mcfi2c);
+                       }
+               } else {
+                       if (--mcfi2c->len) {
+                               if (!(mcfi2c->len > 1))
+                                       mcfi2c_tx_nak(mcfi2c);
+                               *(mcfi2c->buf++) = mcfi2c_rd_dr(mcfi2c);
+                               goto not_complete;
+                       } else {
+                               if (mcfi2c->more)
+                                       mcfi2c_repeat_start(mcfi2c);
+                               else
+                                       mcfi2c_stop(mcfi2c);
+                               *(mcfi2c->buf++) = mcfi2c_rd_dr(mcfi2c);
+                       }
+               }
+       }
+       complete(&mcfi2c->completion);
+not_complete:
+       return IRQ_HANDLED;
+}
+
+static void mcfi2c_reset(struct mcfi2c *mcfi2c)
+{
+       mcfi2c_wr_cr(mcfi2c, 0);
+       mcfi2c_wr_cr(mcfi2c, MCFI2C_CR_IEN | MCFI2C_CR_MSTA);
+       mcfi2c_rd_dr(mcfi2c);
+       mcfi2c_wr_sr(mcfi2c, 0);
+       mcfi2c_wr_cr(mcfi2c, 0);
+       mcfi2c_wr_cr(mcfi2c, MCFI2C_CR_IEN);
+}
+
+static int mcfi2c_wait_for_bus_idle(struct mcfi2c *mcfi2c)
+{
+       unsigned long timeout = jiffies + HZ / 2;
+       while (mcfi2c_rd_sr(mcfi2c) & MCFI2C_SR_IBB) {
+               if (time_after(jiffies, timeout))
+                       return -EAGAIN; /* bus is busy, try again */
+               cond_resched();
+       }
+       return 0;
+}
+
+static int mcfi2c_wait_for_bus_busy(struct mcfi2c *mcfi2c)
+{
+       unsigned long timeout = jiffies + HZ / 10;
+       u8 sr;
+       while (!((sr = mcfi2c_rd_sr(mcfi2c)) & MCFI2C_SR_IBB)) {
+               if (sr & MCFI2C_SR_IAL)
+                       return -EAGAIN; /* lost arbitration, try again */
+               if (time_after(jiffies, timeout)) {
+                       /* if we dont get bus busy and dont get an arbitration
+                        * loss, then the bus is probably glitched, see if we
+                        * can recover.
+                       */
+                       dev_dbg(&mcfi2c->adapter.dev,
+                               "unable to send START, trying to reset the 
bus\n");
+                       mcfi2c_reset(mcfi2c);
+                       return -EAGAIN;
+               }
+               cond_resched();
+       }
+       return 0;
+}
+
+static int mcfi2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
+               int num)
+{
+       struct mcfi2c *mcfi2c = i2c_get_adapdata(adapter);
+       int cnt = 0;
+
+       pm_runtime_get_sync(&adapter->dev);
+
+       while (num--) {
+               if (msgs->flags & ~I2C_M_RD) {
+                       mcfi2c->status = -EINVAL;
+                       goto done;
+               }
+               mcfi2c->flags = msgs->flags;
+               mcfi2c->buf = msgs->buf;
+               mcfi2c->len = msgs->len;
+               mcfi2c->more = num;
+               mcfi2c->status = 0;
+
+               if (!(mcfi2c_rd_cr(mcfi2c) & MCFI2C_CR_MSTA)) {
+                       mcfi2c->status = mcfi2c_wait_for_bus_idle(mcfi2c);
+                       if (mcfi2c->status)
+                               continue;
+
+                       init_completion(&mcfi2c->completion);
+                       mcfi2c_start(mcfi2c);
+
+                       mcfi2c->status = mcfi2c_wait_for_bus_busy(mcfi2c);
+                       if (mcfi2c->status)
+                               continue;
+               }
+
+               mcfi2c_wr_dr(mcfi2c, (msgs->addr << 1) |
+                               (msgs->flags & I2C_M_RD));
+               if (!wait_for_completion_timeout(&mcfi2c->completion,
+                                       adapter->timeout * msgs->len)) {
+                       mcfi2c->status = -ETIMEDOUT;
+                       mcfi2c_stop(mcfi2c);
+               }
+
+               if (mcfi2c->status)
+                       goto done;
+               ++cnt;
+               ++msgs;
+       }
+done:
+       pm_runtime_put(&adapter->dev);
+
+       return mcfi2c->status ?: cnt;
+}
+
+static u32 mcfi2c_func(struct i2c_adapter *adapter)
+{
+       return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm mcfi2c_algo = {
+       .master_xfer    = mcfi2c_xfer,
+       .functionality  = mcfi2c_func,
+};
+
+static const u16 mcfi2c_fdr[] = {
+         28,   30,   34,   40,   44,   48,   56,   68,
+         80,   88,  104,  128,  144,  160,  192,  240,
+        288,  320,  384,  480,  576,  640,  768,  960,
+       1152, 1280, 1536, 1920, 2304, 2560, 3072, 3840,
+         20,   22,   24,   26,   28,   32,   36,   40,
+         48,   56,   64,   72,   80,   96,  112,  128,
+        160,  192,  224,  256,  320,  384,  448,  512,
+        640,  768,  896, 1024, 1280, 1536, 1792, 2048
+};
+
+static u8 mcfi2c_calc_fdr(struct mcfi2c *mcfi2c,
+                                   struct mcfi2c_platform_data *pdata)
+{
+       u32 bitrate = (pdata && pdata->bitrate) ?
+                       pdata->bitrate : DEFAULT_I2C_BUS_SPEED;
+       int div = clk_get_rate(mcfi2c->clk)/bitrate;
+       int r = 0, i = 0;
+
+       do
+               if (abs(mcfi2c_fdr[i] - div) < abs(mcfi2c_fdr[r] - div))
+                       r = i;
+       while (++i < ARRAY_SIZE(mcfi2c_fdr));
+
+       return r;
+}
+
+static int mcfi2c_probe(struct platform_device *pdev)
+{
+       struct mcfi2c *mcfi2c;
+       struct resource *res;
+       int status;
+
+       mcfi2c = kzalloc(sizeof(*mcfi2c), GFP_KERNEL);
+       if (!mcfi2c) {
+               dev_dbg(&pdev->dev, "kzalloc failed\n");
+
+               return -ENOMEM;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_dbg(&pdev->dev, "platform_get_resource failed\n");
+               status = -ENXIO;
+               goto fail0;
+       }
+
+       if (!request_mem_region(res->start, resource_size(res), pdev->name)) {
+               dev_dbg(&pdev->dev, "request_mem_region failed\n");
+               status = -EBUSY;
+               goto fail0;
+       }
+
+       mcfi2c->iobase = ioremap(res->start, resource_size(res));
+       if (!mcfi2c->iobase) {
+               dev_dbg(&pdev->dev, "ioremap failed\n");
+               status = -ENOMEM;
+               goto fail1;
+       }
+
+       mcfi2c->irq = platform_get_irq(pdev, 0);
+       if (mcfi2c->irq < 0) {
+               dev_dbg(&pdev->dev, "platform_get_irq failed\n");
+               status = -ENXIO;
+               goto fail2;
+       }
+       status = request_irq(mcfi2c->irq, mcfi2c_irq_handler, 0, pdev->name,
+                       mcfi2c);
+       if (status) {
+               dev_dbg(&pdev->dev, "request_irq failed\n");
+               goto fail2;
+       }
+
+       mcfi2c->clk = clk_get(&pdev->dev, NULL);
+       if (IS_ERR(mcfi2c->clk)) {
+               dev_dbg(&pdev->dev, "clk_get failed\n");
+               status = PTR_ERR(mcfi2c->clk);
+               goto fail3;
+       }
+       clk_enable(mcfi2c->clk);
+
+       platform_set_drvdata(pdev, mcfi2c);
+
+       init_completion(&mcfi2c->completion);
+
+       writeb(mcfi2c_calc_fdr(mcfi2c, pdev->dev.platform_data),
+              mcfi2c->iobase + MCFI2C_FDR);
+
+       writeb(0x00, mcfi2c->iobase + MCFI2C_ADR);
+
+       mcfi2c_wr_cr(mcfi2c, MCFI2C_CR_IEN);
+
+       pm_runtime_enable(&pdev->dev);
+       pm_runtime_get_sync(&pdev->dev);
+
+       /* if the bus busy (IBB) is set, reset the controller */
+       if (mcfi2c_rd_sr(mcfi2c) & MCFI2C_SR_IBB)
+               mcfi2c_reset(mcfi2c);
+
+       mcfi2c->adapter.algo            = &mcfi2c_algo;
+       mcfi2c->adapter.class           = I2C_CLASS_HWMON | I2C_CLASS_SPD;
+       mcfi2c->adapter.dev.parent      = &pdev->dev;
+       mcfi2c->adapter.nr              = pdev->id;
+       mcfi2c->adapter.retries         = 2;
+       snprintf(mcfi2c->adapter.name, sizeof(mcfi2c->adapter.name),
+                       DRIVER_NAME ".%d", pdev->id);
+
+       i2c_set_adapdata(&mcfi2c->adapter, mcfi2c);
+
+       status = i2c_add_numbered_adapter(&mcfi2c->adapter);
+       if (status < 0) {
+               dev_dbg(&pdev->dev, "i2c_add_numbered_adapter failed\n");
+               goto fail4;
+       }
+
+       pm_runtime_put(&pdev->dev);
+
+       dev_info(&pdev->dev, "Coldfire I2C bus driver\n");
+
+       return 0;
+
+fail4:
+       pm_runtime_put(&pdev->dev);
+
+       clk_disable(mcfi2c->clk);
+       clk_put(mcfi2c->clk);
+fail3:
+       free_irq(mcfi2c->irq, mcfi2c);
+fail2:
+       iounmap(mcfi2c->iobase);
+fail1:
+       release_mem_region(res->start, resource_size(res));
+fail0:
+       kfree(mcfi2c);
+
+       return status;
+}
+
+static int mcfi2c_remove(struct platform_device *pdev)
+{
+       struct mcfi2c *mcfi2c = platform_get_drvdata(pdev);
+       struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+       /* disable the hardware */
+       mcfi2c_wr_cr(mcfi2c, 0);
+
+       platform_set_drvdata(pdev, NULL);
+       i2c_del_adapter(&mcfi2c->adapter);
+       clk_disable(mcfi2c->clk);
+       clk_put(mcfi2c->clk);
+       free_irq(mcfi2c->irq, mcfi2c);
+       iounmap(mcfi2c->iobase);
+       release_mem_region(res->start, resource_size(res));
+       kfree(mcfi2c);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM_RUNTIME
+static int mcfi2c_runtime_suspend(struct device *dev)
+{
+       struct mcfi2c *mcfi2c = platform_get_drvdata(to_platform_device(dev));
+
+       mcfi2c_wr_cr(mcfi2c, 0);
+       clk_disable(mcfi2c->clk);
+
+       return 0;
+}
+
+static int mcfi2c_runtime_resume(struct device *dev)
+{
+       struct mcfi2c *mcfi2c = platform_get_drvdata(to_platform_device(dev));
+
+       clk_enable(mcfi2c->clk);
+       mcfi2c_wr_cr(mcfi2c, MCFI2C_CR_IEN);
+
+       return 0;
+}
+#endif
+
+static const struct dev_pm_ops mcfi2c_pm = {
+       SET_RUNTIME_PM_OPS(mcfi2c_runtime_suspend, mcfi2c_runtime_resume, NULL)
+};
+
+static struct platform_driver mcfi2c_driver = {
+       .driver.name    = DRIVER_NAME,
+       .driver.owner   = THIS_MODULE,
+       .driver.pm      = &mcfi2c_pm,
+       .remove         = mcfi2c_remove,
+};
+
+static int __init mcfi2c_init(void)
+{
+       return platform_driver_probe(&mcfi2c_driver, mcfi2c_probe);
+}
+module_init(mcfi2c_init);
+
+static void __exit mcfi2c_exit(void)
+{
+       platform_driver_unregister(&mcfi2c_driver);
+}
+module_exit(mcfi2c_exit);
+
+MODULE_AUTHOR("Steven King <sfk...@fdwdc.com>");
+MODULE_DESCRIPTION("I2C-Bus support for Freescale Coldfire processors");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRIVER_NAME);





_______________________________________________
uClinux-dev mailing list
uClinux-dev@uclinux.org
http://mailman.uclinux.org/mailman/listinfo/uclinux-dev
This message was resent by uclinux-dev@uclinux.org
To unsubscribe see:
http://mailman.uclinux.org/mailman/options/uclinux-dev

Reply via email to