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