m68k: add coldfire mcf5307 i2c support
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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
Greg Ungerer
maintainerHi 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
Signed-off-by Angelo Dureghello <[email protected]>--- 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.carch/m68k/coldfire/device.c +191
-0@@ -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@@ -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@@ -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@@ -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@@ -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_IOP13XXdrivers/i2c/busses/Makefile +1
-0@@ -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.odrivers/i2c/busses/i2c-mcf.c new file +463
-0@@ -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 ); +
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
Signed-off-by Angelo Dureghello <[email protected]>--- 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.carch/m68k/coldfire/device.c +191
-0@@ -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@@ -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@@ -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@@ -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@@ -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_IOP13XXdrivers/i2c/busses/Makefile +1
-0@@ -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.odrivers/i2c/busses/i2c-mcf.c new file +453
-0@@ -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