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