Skip to contentSkip to conversation

m68k: add coldfire mcf5307 i2c support

PATCH Superseded Angelo Dureghello 2 participants 3 messages Oct 2, 2016 – Oct 5, 2016

Subsystems (3)

v1 of 3 Superseded Latest is v3 →

lore
Share & tools
lore
#0 lore raw

PATCH 2/2 m68k: add coldfire mcf5307 i2c support

Add Steven King i2c driver for Coldfire, and reviewed to build and run properly with the actual kernel version.

---
 arch/m68k/coldfire/device.c      | 191 ++++++++++++++++
 arch/m68k/coldfire/m5307.c       |  12 +
 arch/m68k/include/asm/m5307sim.h |   8 +
 arch/m68k/include/asm/mcfi2c.h   |  29 +++
 drivers/i2c/busses/Kconfig       |  12 +
 drivers/i2c/busses/Makefile      |   1 +
 drivers/i2c/busses/i2c-mcf.c     | 463 +++++++++++++++++++++++++++++++++++++++
 7 files changed, 716 insertions(+)
 create mode 100644 arch/m68k/include/asm/mcfi2c.h
 create mode 100644 drivers/i2c/busses/i2c-mcf.c
arch/m68k/coldfire/device.c +191 -0
index a0fc0c1..a1ed057 100644
@@ -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,178 @@ 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,
 #if IS_ENABLED(CONFIG_FEC)
@@ -338,6 +511,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
 };
 
 /*
arch/m68k/coldfire/m5307.c +12 -0
index 2da1d14..159485e 100644
@@ -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,9 +44,19 @@ 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)
@@ -73,6 +84,7 @@ void __init config_BSP(char *commandp, int size)
 	 */
 	wdebug(MCFDEBUG_CSR, MCFDEBUG_CSR_PSTCLK);
 #endif
+	m5307_i2c_init();
 }
 
 /***************************************************************************/
arch/m68k/include/asm/m5307sim.h +8 -0
index 5d0bb7e..608e04c 100644
@@ -131,6 +131,12 @@
 #define MCFGPIO_IRQ_MAX		-1
 #define MCFGPIO_IRQ_VECBASE	-1
 
+/*
+ * I2C module.
+ */
+#define MCFI2C_BASE0		(MCF_MBAR + 0x280)
+#define MCFI2C_SIZE0		0x40
+
 
 /* Definition offset address for CS2-7  -- old mask 5307 */
 
@@ -148,6 +154,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 */
@@ -174,6 +181,7 @@
 /*
  *	Define system peripheral IRQ usage.
  */
+#define MCF_IRQ_I2C0		29		/* I2C */
 #define	MCF_IRQ_TIMER		30		/* Timer0, Level 6 */
 #define	MCF_IRQ_PROFILER	31		/* Timer1, Level 7 */
 #define	MCF_IRQ_UART0		73		/* UART0 */
arch/m68k/include/asm/mcfi2c.h new file +29 -0
new file mode 100644
index 0000000..a0c69e1
@@ -0,0 +1,29 @@
+/*
+ * Definitions for Coldfire I2C interface
+ */
+#ifndef mcfi2c_h
+#define mcfi2c_h
+
+#if defined(CONFIG_M5206) || defined(CONFIG_M5206e)
+#define MCFI2C_IOBASE  (MCF_MBAR + 0x1e0)
+#elif defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x)
+#define MCFI2C_IOBASE  (MCF_IPSBAR + 0x300)
+#elif defined(CONFIG_M5249) || defined(CONFIG_M5307) || defined(CONFIG_M5407)
+#define MCFI2C_IOBASE  (MCF_MBAR + 0x280)
+#ifdef CONFIG_M5249
+#define MCFI2C_IOBASE2 (MCF_MBAR2 + 0x440)
+#endif
+#elif defined(CONFIG_M520x) || defined(CONFIG_M532x) || defined(CONFIG_M5445x)
+#define MCFI2C_IOBASE  0xFC058000
+#endif
+#define MCFI2C_IOSIZE   0x40
+
+/*
+ * 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 */
drivers/i2c/busses/Kconfig +12 -0
index 5c3993b..5c3e326 100644
@@ -597,6 +597,18 @@ config I2C_IMX
 	  This driver can also be built as a module.  If so, the module
 	  will be called i2c-imx.
 
+config I2C_COLDFIRE
+	tristate "Freescale Coldfire I2C driver"
+	depends on M5206 || M5206e || M520x || M523x || M5249 || \
+		   M527x || M528x || M5307 || M532x || M5407
+	help
+	  This driver supports the I2C interface availible on some Freescale
+	  Coldfire processors (M520x, M523x, M5249, M5271, M5275, M528x,
+	  M5307, M532x, M5407).
+
+	  This driver can be built as a module.  If so, the module
+	  will be called i2c-mcf.
+
 config I2C_IOP3XX
 	tristate "Intel IOPx3xx and IXP4xx on-chip I2C interface"
 	depends on ARCH_IOP32X || ARCH_IOP33X || ARCH_IXP4XX || ARCH_IOP13XX
drivers/i2c/busses/Makefile +1 -0
index 37f2819..17ad0c8 100644
@@ -96,6 +96,7 @@ obj-$(CONFIG_I2C_XILINX)	+= i2c-xiic.o
 obj-$(CONFIG_I2C_XLR)		+= i2c-xlr.o
 obj-$(CONFIG_I2C_XLP9XX)	+= i2c-xlp9xx.o
 obj-$(CONFIG_I2C_RCAR)		+= i2c-rcar.o
+obj-$(CONFIG_I2C_COLDFIRE)      += i2c-mcf.o
 
 # External I2C/SMBus adapter drivers
 obj-$(CONFIG_I2C_DIOLAN_U2C)	+= i2c-diolan-u2c.o
drivers/i2c/busses/i2c-mcf.c new file +463 -0

463 lines not on this page · raw message

Signature · 1 line
2.8.1
maintainer
#1 lore raw

Hi Angelo,

Quoted 2 lines · Angelo Dureghello

Add Steven King i2c driver for Coldfire, and reviewed to build and run properly with the actual kernel version.

This won't be able to be merged in this form.
I can take the m68k/coldfire specific parts - but the i2c driver would need to go via the i2c maintainers (so you would need a patch to be sent and reveiwed on the i2c email list).

I would prefer to merge the existing ColdFire i2c platform support I have for all platforms in any case.

Regards
Greg

Quoted 842 lines
---
 arch/m68k/coldfire/device.c      | 191 ++++++++++++++++
 arch/m68k/coldfire/m5307.c       |  12 +
 arch/m68k/include/asm/m5307sim.h |   8 +
 arch/m68k/include/asm/mcfi2c.h   |  29 +++
 drivers/i2c/busses/Kconfig       |  12 +
 drivers/i2c/busses/Makefile      |   1 +
 drivers/i2c/busses/i2c-mcf.c     | 463 +++++++++++++++++++++++++++++++++++++++
 7 files changed, 716 insertions(+)
 create mode 100644 arch/m68k/include/asm/mcfi2c.h
 create mode 100644 drivers/i2c/busses/i2c-mcf.c
arch/m68k/coldfire/device.c +191 -0
index a0fc0c1..a1ed057 100644
@@ -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,178 @@ 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,
 #if IS_ENABLED(CONFIG_FEC)
@@ -338,6 +511,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
 };
 
 /*
arch/m68k/coldfire/m5307.c +12 -0
index 2da1d14..159485e 100644
@@ -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,9 +44,19 @@ 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)
@@ -73,6 +84,7 @@ void __init config_BSP(char *commandp, int size)
 	 */
 	wdebug(MCFDEBUG_CSR, MCFDEBUG_CSR_PSTCLK);
 #endif
+	m5307_i2c_init();
 }
 
 /***************************************************************************/
arch/m68k/include/asm/m5307sim.h +8 -0
index 5d0bb7e..608e04c 100644
@@ -131,6 +131,12 @@
 #define MCFGPIO_IRQ_MAX		-1
 #define MCFGPIO_IRQ_VECBASE	-1
 
+/*
+ * I2C module.
+ */
+#define MCFI2C_BASE0		(MCF_MBAR + 0x280)
+#define MCFI2C_SIZE0		0x40
+
 
 /* Definition offset address for CS2-7  -- old mask 5307 */
 
@@ -148,6 +154,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 */
@@ -174,6 +181,7 @@
 /*
  *	Define system peripheral IRQ usage.
  */
+#define MCF_IRQ_I2C0		29		/* I2C */
 #define	MCF_IRQ_TIMER		30		/* Timer0, Level 6 */
 #define	MCF_IRQ_PROFILER	31		/* Timer1, Level 7 */
 #define	MCF_IRQ_UART0		73		/* UART0 */
arch/m68k/include/asm/mcfi2c.h new file +29 -0
new file mode 100644
index 0000000..a0c69e1
@@ -0,0 +1,29 @@
+/*
+ * Definitions for Coldfire I2C interface
+ */
+#ifndef mcfi2c_h
+#define mcfi2c_h
+
+#if defined(CONFIG_M5206) || defined(CONFIG_M5206e)
+#define MCFI2C_IOBASE  (MCF_MBAR + 0x1e0)
+#elif defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x)
+#define MCFI2C_IOBASE  (MCF_IPSBAR + 0x300)
+#elif defined(CONFIG_M5249) || defined(CONFIG_M5307) || defined(CONFIG_M5407)
+#define MCFI2C_IOBASE  (MCF_MBAR + 0x280)
+#ifdef CONFIG_M5249
+#define MCFI2C_IOBASE2 (MCF_MBAR2 + 0x440)
+#endif
+#elif defined(CONFIG_M520x) || defined(CONFIG_M532x) || defined(CONFIG_M5445x)
+#define MCFI2C_IOBASE  0xFC058000
+#endif
+#define MCFI2C_IOSIZE   0x40
+
+/*
+ * 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 */
drivers/i2c/busses/Kconfig +12 -0
index 5c3993b..5c3e326 100644
@@ -597,6 +597,18 @@ config I2C_IMX
 	  This driver can also be built as a module.  If so, the module
 	  will be called i2c-imx.
 
+config I2C_COLDFIRE
+	tristate "Freescale Coldfire I2C driver"
+	depends on M5206 || M5206e || M520x || M523x || M5249 || \
+		   M527x || M528x || M5307 || M532x || M5407
+	help
+	  This driver supports the I2C interface availible on some Freescale
+	  Coldfire processors (M520x, M523x, M5249, M5271, M5275, M528x,
+	  M5307, M532x, M5407).
+
+	  This driver can be built as a module.  If so, the module
+	  will be called i2c-mcf.
+
 config I2C_IOP3XX
 	tristate "Intel IOPx3xx and IXP4xx on-chip I2C interface"
 	depends on ARCH_IOP32X || ARCH_IOP33X || ARCH_IXP4XX || ARCH_IOP13XX
drivers/i2c/busses/Makefile +1 -0
index 37f2819..17ad0c8 100644
@@ -96,6 +96,7 @@ obj-$(CONFIG_I2C_XILINX)	+= i2c-xiic.o
 obj-$(CONFIG_I2C_XLR)		+= i2c-xlr.o
 obj-$(CONFIG_I2C_XLP9XX)	+= i2c-xlp9xx.o
 obj-$(CONFIG_I2C_RCAR)		+= i2c-rcar.o
+obj-$(CONFIG_I2C_COLDFIRE)      += i2c-mcf.o
 
 # External I2C/SMBus adapter drivers
 obj-$(CONFIG_I2C_DIOLAN_U2C)	+= i2c-diolan-u2c.o
drivers/i2c/busses/i2c-mcf.c new file +463 -0
new file mode 100644
index 0000000..320531c
@@ -0,0 +1,463 @@
+/*
+ * Freescale/Motorola Coldfire I2C driver.
+ *
+ * Copyright 2010 Steven King <[email protected]>
+ *
+ * Updated by Angelo Dureghello <[email protected]> Sep 2016
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+#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 <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;
+};
+
+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;
+
+	/* clear interrupt */
+	mcfi2c_wr_sr(mcfi2c, 0);
+	complete(&mcfi2c->completion);
+
+	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 void mcfi2c_wait_for_bus_idle(struct mcfi2c *mcfi2c)
+{
+	if (mcfi2c_rd_sr(mcfi2c) & MCFI2C_SR_IBB) {
+		unsigned long timeout = jiffies + HZ / 2;
+
+		do {
+			cond_resched();
+			if (time_after(jiffies, timeout)) {
+				mcfi2c_reset(mcfi2c);
+				break;
+			}
+		} while (mcfi2c_rd_sr(mcfi2c) & MCFI2C_SR_IBB);
+	}
+}
+
+static int mcfi2c_wait_for_bus_busy(struct mcfi2c *mcfi2c)
+{
+	u8 sr;
+
+	while (!((sr = mcfi2c_rd_sr(mcfi2c)) & MCFI2C_SR_IBB))
+		if (sr & MCFI2C_SR_IAL) {
+			mcfi2c_reset(mcfi2c);
+			return -EIO;
+		}
+
+	return 0;
+}
+
+static int mcfi2c_xmit(struct mcfi2c *mcfi2c, u16 addr, u16 flags, u8 *buf,
+			u16 len, int timeout, int more)
+{
+	if (!(mcfi2c_rd_cr(mcfi2c) & MCFI2C_CR_MSTA)) {
+		mcfi2c_wait_for_bus_idle(mcfi2c);
+
+		reinit_completion(&mcfi2c->completion);
+		mcfi2c_start(mcfi2c);
+
+		if (mcfi2c_wait_for_bus_busy(mcfi2c))
+			return -EIO;
+	}
+
+	mcfi2c_wr_dr(mcfi2c, (addr << 1) | (flags & I2C_M_RD));
+
+	while (wait_for_completion_timeout(&mcfi2c->completion, timeout)) {
+		u8 sr = mcfi2c_rd_sr(mcfi2c);
+
+		if (sr & MCFI2C_SR_IAL) {
+			mcfi2c_wr_sr(mcfi2c, ~MCFI2C_SR_IAL);
+			return -EIO;
+		} else if (mcfi2c_rd_cr(mcfi2c) & MCFI2C_CR_MTX) {
+			if (sr & MCFI2C_SR_RXAK) {
+				mcfi2c_stop(mcfi2c);
+				return -EIO;
+			} else if (flags & I2C_M_RD) {
+				if (len > 1)
+					mcfi2c_tx_ack(mcfi2c);
+				else
+					mcfi2c_tx_nak(mcfi2c);
+				/* dummy read */
+				mcfi2c_rd_dr(mcfi2c);
+			} else if (len--) {
+				mcfi2c_wr_dr(mcfi2c, *buf++);
+			} else {
+				if (more)
+					mcfi2c_repeat_start(mcfi2c);
+				else
+					mcfi2c_stop(mcfi2c);
+				return 0;
+			}
+		} else if (--len) {
+			if (!(len > 1))
+				mcfi2c_tx_nak(mcfi2c);
+			*buf++ = mcfi2c_rd_dr(mcfi2c);
+		} else {
+			if (more)
+				mcfi2c_repeat_start(mcfi2c);
+			else
+				mcfi2c_stop(mcfi2c);
+			*buf++ = mcfi2c_rd_dr(mcfi2c);
+			return 0;
+		}
+	}
+
+	mcfi2c_stop(mcfi2c);
+
+	return -ETIMEDOUT;
+}
+
+static int mcfi2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
+			int num)
+{
+	struct mcfi2c *mcfi2c = i2c_get_adapdata(adapter);
+	int cnt = 0;
+	int status;
+	int retries;
+
+	while (num--) {
+		retries = adapter->retries;
+		if (msgs->flags & ~I2C_M_RD)
+			return -EINVAL;
+
+		do {
+			status = mcfi2c_xmit(mcfi2c, msgs->addr, msgs->flags,
+						msgs->buf, msgs->len,
+						adapter->timeout, num);
+		} while (status && retries--);
+
+		if (status)
+			return status;
+		++cnt;
+		++msgs;
+	}
+
+	return 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)
+		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, "i2c_clk");
+	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);
+
+	/* 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;
+	}
+	dev_info(&pdev->dev, "Coldfire I2C bus driver\n");
+
+	return 0;
+
+fail4:
+	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
+static int mcfi2c_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_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;
+}
+
+static const struct dev_pm_ops mcfi2c_dev_pm_ops = {
+	.suspend        = mcfi2c_suspend,
+	.resume         = mcfi2c_resume,
+};
+
+#define MCFI2C_DEV_PM_OPS (&mcfi2c_dev_pm_ops)
+#else
+#define MCFI2C_DEV_PM_OPS NULL
+#endif
+
+static struct platform_driver mcfi2c_driver = {
+	.driver.name    = DRIVER_NAME,
+	.driver.owner   = THIS_MODULE,
+	.driver.pm      = MCFI2C_DEV_PM_OPS,
+	.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 <[email protected]>");
+MODULE_DESCRIPTION("I2C-Bus support for Freescale Coldfire processors");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRIVER_NAME);
+
#2 lore raw

Hi Greg,
thanks for the review,

Quoted 6 lines · Greg Ungerer

Hi Angelo,

Quoted 2 lines · Angelo Dureghello

Add Steven King i2c driver for Coldfire, and reviewed to build and run properly with the actual kernel version.

Quoted 9 lines

This won't be able to be merged in this form.
I can take the m68k/coldfire specific parts - but the i2c driver would need to go via the i2c maintainers (so you would need a patch to be sent and reveiwed on the i2c email list).

I would prefer to merge the existing ColdFire i2c platform support I have for all platforms in any case.

mainly, i can test things to work properly only on mcf5307, even i f i am developing some other coldfire boards, they are not still ready.
Ok i leave i2c/rtc entirely out for now. But i promise to work on it step by step to have it accepted if board part is accepted, so at least i have a starting point.

Quoted 4 lines

Regards
Greg

Best regards,
Angelo Dureghello

Quoted 848 lines
Quoted 833 lines
---
 arch/m68k/coldfire/device.c      | 191 ++++++++++++++++
 arch/m68k/coldfire/m5307.c       |  12 +
 arch/m68k/include/asm/m5307sim.h |   8 +
 arch/m68k/include/asm/mcfi2c.h   |  29 +++
 drivers/i2c/busses/Kconfig       |  12 +
 drivers/i2c/busses/Makefile      |   1 +
 drivers/i2c/busses/i2c-mcf.c     | 463 +++++++++++++++++++++++++++++++++++++++
 7 files changed, 716 insertions(+)
 create mode 100644 arch/m68k/include/asm/mcfi2c.h
 create mode 100644 drivers/i2c/busses/i2c-mcf.c
arch/m68k/coldfire/device.c +191 -0
index a0fc0c1..a1ed057 100644
@@ -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,178 @@ 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,
 #if IS_ENABLED(CONFIG_FEC)
@@ -338,6 +511,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
 };
 
 /*
arch/m68k/coldfire/m5307.c +12 -0
index 2da1d14..159485e 100644
@@ -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,9 +44,19 @@ 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)
@@ -73,6 +84,7 @@ void __init config_BSP(char *commandp, int size)
      */
     wdebug(MCFDEBUG_CSR, MCFDEBUG_CSR_PSTCLK);
 #endif
+    m5307_i2c_init();
 }
 
 /***************************************************************************/
arch/m68k/include/asm/m5307sim.h +8 -0
index 5d0bb7e..608e04c 100644
@@ -131,6 +131,12 @@
 #define MCFGPIO_IRQ_MAX        -1
 #define MCFGPIO_IRQ_VECBASE    -1
 
+/*
+ * I2C module.
+ */
+#define MCFI2C_BASE0        (MCF_MBAR + 0x280)
+#define MCFI2C_SIZE0        0x40
+
 
 /* Definition offset address for CS2-7  -- old mask 5307 */
 
@@ -148,6 +154,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 */
@@ -174,6 +181,7 @@
 /*
  *    Define system peripheral IRQ usage.
  */
+#define MCF_IRQ_I2C0        29        /* I2C */
 #define    MCF_IRQ_TIMER        30        /* Timer0, Level 6 */
 #define    MCF_IRQ_PROFILER    31        /* Timer1, Level 7 */
 #define    MCF_IRQ_UART0        73        /* UART0 */
arch/m68k/include/asm/mcfi2c.h new file +29 -0
new file mode 100644
index 0000000..a0c69e1
@@ -0,0 +1,29 @@
+/*
+ * Definitions for Coldfire I2C interface
+ */
+#ifndef mcfi2c_h
+#define mcfi2c_h
+
+#if defined(CONFIG_M5206) || defined(CONFIG_M5206e)
+#define MCFI2C_IOBASE  (MCF_MBAR + 0x1e0)
+#elif defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x)
+#define MCFI2C_IOBASE  (MCF_IPSBAR + 0x300)
+#elif defined(CONFIG_M5249) || defined(CONFIG_M5307) || defined(CONFIG_M5407)
+#define MCFI2C_IOBASE  (MCF_MBAR + 0x280)
+#ifdef CONFIG_M5249
+#define MCFI2C_IOBASE2 (MCF_MBAR2 + 0x440)
+#endif
+#elif defined(CONFIG_M520x) || defined(CONFIG_M532x) || defined(CONFIG_M5445x)
+#define MCFI2C_IOBASE  0xFC058000
+#endif
+#define MCFI2C_IOSIZE   0x40
+
+/*
+ * 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 */
drivers/i2c/busses/Kconfig +12 -0
index 5c3993b..5c3e326 100644
@@ -597,6 +597,18 @@ config I2C_IMX
       This driver can also be built as a module.  If so, the module
       will be called i2c-imx.
 
+config I2C_COLDFIRE
+    tristate "Freescale Coldfire I2C driver"
+    depends on M5206 || M5206e || M520x || M523x || M5249 || \
+           M527x || M528x || M5307 || M532x || M5407
+    help
+      This driver supports the I2C interface availible on some Freescale
+      Coldfire processors (M520x, M523x, M5249, M5271, M5275, M528x,
+      M5307, M532x, M5407).
+
+      This driver can be built as a module.  If so, the module
+      will be called i2c-mcf.
+
 config I2C_IOP3XX
     tristate "Intel IOPx3xx and IXP4xx on-chip I2C interface"
     depends on ARCH_IOP32X || ARCH_IOP33X || ARCH_IXP4XX || ARCH_IOP13XX
drivers/i2c/busses/Makefile +1 -0
index 37f2819..17ad0c8 100644
@@ -96,6 +96,7 @@ obj-$(CONFIG_I2C_XILINX)    += i2c-xiic.o
 obj-$(CONFIG_I2C_XLR)        += i2c-xlr.o
 obj-$(CONFIG_I2C_XLP9XX)    += i2c-xlp9xx.o
 obj-$(CONFIG_I2C_RCAR)        += i2c-rcar.o
+obj-$(CONFIG_I2C_COLDFIRE)      += i2c-mcf.o
 
 # External I2C/SMBus adapter drivers
 obj-$(CONFIG_I2C_DIOLAN_U2C)    += i2c-diolan-u2c.o
drivers/i2c/busses/i2c-mcf.c new file +453 -0
new file mode 100644
index 0000000..320531c
@@ -0,0 +1,463 @@
+/*
+ * Freescale/Motorola Coldfire I2C driver.
+ *
+ * Copyright 2010 Steven King <[email protected]>
+ *
+ * Updated by Angelo Dureghello <[email protected]> Sep 2016
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+#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 <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;
+};
+
+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;
+
+    /* clear interrupt */
+    mcfi2c_wr_sr(mcfi2c, 0);
+    complete(&mcfi2c->completion);
+
+    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 void mcfi2c_wait_for_bus_idle(struct mcfi2c *mcfi2c)
+{
+    if (mcfi2c_rd_sr(mcfi2c) & MCFI2C_SR_IBB) {
+        unsigned long timeout = jiffies + HZ / 2;
+
+        do {
+            cond_resched();
+            if (time_after(jiffies, timeout)) {
+                mcfi2c_reset(mcfi2c);
+                break;
+            }
+        } while (mcfi2c_rd_sr(mcfi2c) & MCFI2C_SR_IBB);
+    }
+}
+
+static int mcfi2c_wait_for_bus_busy(struct mcfi2c *mcfi2c)
+{
+    u8 sr;
+
+    while (!((sr = mcfi2c_rd_sr(mcfi2c)) & MCFI2C_SR_IBB))
+        if (sr & MCFI2C_SR_IAL) {
+            mcfi2c_reset(mcfi2c);
+            return -EIO;
+        }
+
+    return 0;
+}
+
+static int mcfi2c_xmit(struct mcfi2c *mcfi2c, u16 addr, u16 flags, u8 *buf,
+            u16 len, int timeout, int more)
+{
+    if (!(mcfi2c_rd_cr(mcfi2c) & MCFI2C_CR_MSTA)) {
+        mcfi2c_wait_for_bus_idle(mcfi2c);
+
+        reinit_completion(&mcfi2c->completion);
+        mcfi2c_start(mcfi2c);
+
+        if (mcfi2c_wait_for_bus_busy(mcfi2c))
+            return -EIO;
+    }
+
+    mcfi2c_wr_dr(mcfi2c, (addr << 1) | (flags & I2C_M_RD));
+
+    while (wait_for_completion_timeout(&mcfi2c->completion, timeout)) {
+        u8 sr = mcfi2c_rd_sr(mcfi2c);
+
+        if (sr & MCFI2C_SR_IAL) {
+            mcfi2c_wr_sr(mcfi2c, ~MCFI2C_SR_IAL);
+            return -EIO;
+        } else if (mcfi2c_rd_cr(mcfi2c) & MCFI2C_CR_MTX) {
+            if (sr & MCFI2C_SR_RXAK) {
+                mcfi2c_stop(mcfi2c);
+                return -EIO;
+            } else if (flags & I2C_M_RD) {
+                if (len > 1)
+                    mcfi2c_tx_ack(mcfi2c);
+                else
+                    mcfi2c_tx_nak(mcfi2c);
+                /* dummy read */
+                mcfi2c_rd_dr(mcfi2c);
+            } else if (len--) {
+                mcfi2c_wr_dr(mcfi2c, *buf++);
+            } else {
+                if (more)
+                    mcfi2c_repeat_start(mcfi2c);
+                else
+                    mcfi2c_stop(mcfi2c);
+                return 0;
+            }
+        } else if (--len) {
+            if (!(len > 1))
+                mcfi2c_tx_nak(mcfi2c);
+            *buf++ = mcfi2c_rd_dr(mcfi2c);
+        } else {
+            if (more)
+                mcfi2c_repeat_start(mcfi2c);
+            else
+                mcfi2c_stop(mcfi2c);
+            *buf++ = mcfi2c_rd_dr(mcfi2c);
+            return 0;
+        }
+    }
+
+    mcfi2c_stop(mcfi2c);
+
+    return -ETIMEDOUT;
+}
+
+static int mcfi2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
+            int num)
+{
+    struct mcfi2c *mcfi2c = i2c_get_adapdata(adapter);
+    int cnt = 0;
+    int status;
+    int retries;
+
+    while (num--) {
+        retries = adapter->retries;
+        if (msgs->flags & ~I2C_M_RD)
+            return -EINVAL;
+
+        do {
+            status = mcfi2c_xmit(mcfi2c, msgs->addr, msgs->flags,
+                        msgs->buf, msgs->len,
+                        adapter->timeout, num);
+        } while (status && retries--);
+
+        if (status)
+            return status;
+        ++cnt;
+        ++msgs;
+    }
+
+    return 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)
+        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, "i2c_clk");
+    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);
+
+    /* 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;
+    }
+    dev_info(&pdev->dev, "Coldfire I2C bus driver\n");
+
+    return 0;
+
+fail4:
+    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
+static int mcfi2c_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_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;
+}
+
+static const struct dev_pm_ops mcfi2c_dev_pm_ops = {
+    .suspend        = mcfi2c_suspend,
+    .resume         = mcfi2c_resume,
+};
+
+#define MCFI2C_DEV_PM_OPS (&mcfi2c_dev_pm_ops)
+#else
+#define MCFI2C_DEV_PM_OPS NULL
+#endif
+
+static struct platform_driver mcfi2c_driver = {
+    .driver.name    = DRIVER_NAME,
+    .driver.owner   = THIS_MODULE,
+    .driver.pm      = MCFI2C_DEV_PM_OPS,
+    .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)

drivers/i2c/busses/i2c-mcf.c line 463

Quoted 10 lines
drivers/i2c/busses/i2c-mcf.c new file +10 -0
+{
+    platform_driver_unregister(&mcfi2c_driver);
+}
+module_exit(mcfi2c_exit);
+
+MODULE_AUTHOR("Steven King <[email protected]>");
+MODULE_DESCRIPTION("I2C-Bus support for Freescale Coldfire processors");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRIVER_NAME);
+

--
To unsubscribe from this list: send the line "unsubscribe linux-m68k" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html