i2c: mxc: refactor i2c driver and support dm
Subsystems (3)
PATCH v2 1/1 i2c: mxc: refactor i2c driver and support dm
1. Introduce a new structure struct mxc_i2c_bus, this structure will used for non-DM and DM.
1. Remove struct mxc_i2c_regs structure, but use register offset to access registers based on base entry of struct mxc_i2c_bus.
2. Remove most #ifdef I2C_QUIRK_REG. Using driver_data to contain platform flags. A new flag is introduced, I2C_QUIRK_FLAG.
3. Most functions use struct mxc_i2c_bus as one of the parameters.
4. Support DM
5. Make most functions common to DM and non-DM, try to avoid duplicated code.
6. struct i2c_parms and struct sram_data are removed, since we move to use struct mxc_i2c_regs.
7. Remove bus_i2c_read bus_i2c_write prototype in header file
8. The frist paramter of bus_i2c_init is modified to i2c index, since bus_i2c_init is a must now, so it is also implemented for DM part.
---
Changes v2:
This patch is a big change from v1 patch.
1. Refactor driver, remove register access based on structure, but use 'base + offset'
2. Introduce mxc_i2c_bus structure
3. Introduce I2C_QUIRK_FLAG and remove most I2C_QUIRK_REG and use driver_data to contain the flags for different platforms
4. Avoid duplicated code between DM and non-DM part
5. The function name i2c_init_transfer is not changed.
6. Remove bus_i2c_read/write prototype from header file
7. change bus_i2c_init's first parameter to i2c index
8. Rename patch name, since refactor non-DM part.
arch/arm/imx-common/i2c-mxv7.c | 3 +- arch/arm/include/asm/imx-common/mxc_i2c.h | 6 +- drivers/i2c/mxc_i2c.c | 585 ++++++++++++++++++++---------- 3 files changed, 402 insertions(+), 192 deletions(-)
arch/arm/imx-common/i2c-mxv7.c +1 -2
@@ -99,8 +99,7 @@ int setup_i2c(unsigned i2c_index, int speed, int slave_addr,if (ret) goto err_idle; -bus_i2c_init (i2c_bases[i2c_index], speed, slave_addr, - force_idle_bus, p); +bus_i2c_init (i2c_index, speed, slave_addr, force_idle_bus, p);return 0 ;
arch/arm/include/asm/imx-common/mxc_i2c.h +1 -5
@@ -54,10 +54,6 @@ struct i2c_pads_info {int setup_i2c (unsigned i2c_index,int speed,int slave_addr,struct i2c_pads_info *p); -void bus_i2c_init (void *base,int speed,int slave_addr, +void bus_i2c_init (int index,int speed,int slave_addr,int (*idle_bus_fn)(void *p),void *p); -int bus_i2c_read (void *base,uchar chip,uint addr,int alen,uchar *buf, -int len); -int bus_i2c_write (void *base,uchar chip,uint addr,int alen, -const uchar *buf,int len);#endif
drivers/i2c/mxc_i2c.c +400 -185
792 lines not on this page · raw message
Signature · 1 line
1.8.4
PATCH v2 1/1 i2c: mxc: refactor i2c driver and support dm
Please ignore this version, since bus_i2c_init is not good for DM, I'll implement a weak function for this.
Quoted 866 lines · Peng Fan
1. Introduce a new structure
struct mxc_i2c_bus, this structure will used for non-DM and DM.
1. Removestruct mxc_i2c_regsstructure, but use register offset to access registers based onbaseentry ofstruct mxc_i2c_bus.
2. Remove most#ifdef I2C_QUIRK_REG. Usingdriver_datato contain platform flags. A new flag is introduced,I2C_QUIRK_FLAG.
3. Most functions usestruct mxc_i2c_busas one of the parameters.
4. Support DM
5. Make most functions common to DM and non-DM, try to avoid duplicated code.
6. structi2c_parmsand structsram_dataare removed, since we move to use structmxc_i2c_regs.
7. Removebus_i2c_readbus_i2c_writeprototype in header file
8. The frist paramter ofbus_i2c_initis modified to i2c index, sincebus_i2c_initis a must now, so it is also implemented for DM part.Signed-off-by Peng Fan <[email protected]>---
Changes v2:
This patch is a big change from v1 patch.
1. Refactor driver, remove register access based on structure, but use 'base + offset'
2. Introducemxc_i2c_busstructure
3. IntroduceI2C_QUIRK_FLAGand remove mostI2C_QUIRK_REGand usedriver_datato contain the flags for different platforms
4. Avoid duplicated code between DM and non-DM part
5. The function namei2c_init_transferis not changed.
6. Remove bus_i2c_read/write prototype from header file
7. change bus_i2c_init's first parameter to i2c index
8. Rename patch name, since refactor non-DM part.arch/arm/imx-common/i2c-mxv7.c | 3 +- arch/arm/include/asm/imx-common/mxc_i2c.h | 6 +- drivers/i2c/mxc_i2c.c | 585 ++++++++++++++++++++---------- 3 files changed, 402 insertions(+), 192 deletions(-)arch/arm/imx-common/i2c-mxv7.c +1
-2@@ -99,8 +99,7 @@ int setup_i2c(unsigned i2c_index, int speed, int slave_addr,if (ret) goto err_idle; -bus_i2c_init (i2c_bases[i2c_index], speed, slave_addr, - force_idle_bus, p); +bus_i2c_init (i2c_index, speed, slave_addr, force_idle_bus, p);return 0 ;arch/arm/include/asm/imx-common/mxc_i2c.h +1
-5@@ -54,10 +54,6 @@ struct i2c_pads_info {int setup_i2c (unsigned i2c_index,int speed,int slave_addr,struct i2c_pads_info *p); -void bus_i2c_init (void *base,int speed,int slave_addr, +void bus_i2c_init (int index,int speed,int slave_addr,int (*idle_bus_fn)(void *p),void *p); -int bus_i2c_read (void *base,uchar chip,uint addr,int alen,uchar *buf, -int len); -int bus_i2c_write (void *base,uchar chip,uint addr,int alen, -const uchar *buf,int len);#endif drivers/i2c/mxc_i2c.c +390
-185@@ -21,26 +21,21 @@#include <asm/io.h> #include <i2c.h> #include <watchdog.h> +#include <dm.h> +#include <fdtdec.h> DECLARE_GLOBAL_DATA_PTR ; -#ifdef I2C_QUIRK_REG -struct mxc_i2c_regs { -uint8_t iadr; -uint8_t ifdr; -uint8_t i2cr; -uint8_t i2sr; -uint8_t i2dr; -}; -#else -struct mxc_i2c_regs { -uint32_t iadr; -uint32_t ifdr; -uint32_t i2cr; -uint32_t i2sr; -uint32_t i2dr; -}; -#endif +#define I2C_QUIRK_FLAG (1 << 0) + +#define IMX_I2C_REGSHIFT 2 +#define VF610_I2C_REGSHIFT 0 +/* Register index */ +#define IADR 0 +#define IFDR 1 +#define I2CR 2 +#define I2SR 3 +#define I2DR 4#define I2CR_IIEN (1 << 6)#define I2CR_MSTA (1 << 5)@@ -68,6 +63,23 @@ struct mxc_i2c_regs {#error "define CONFIG_SYS_I2C_BASE to use the mxc_i2c driver"#endif +/* +* Information about i2c controller +* struct mxc_i2c_bus - information about the i2c[x] bus +* @base: Address of I2C bus controller +* @speed: Speed of I2C bus +* @driver_data: Flags for different platforms, such as I2C_QUIRK_FLAG. +* @idle_bus_fn: function to force bus idle +* @idle_bus_data: parameter for idle_bus_fun +*/ +struct mxc_i2c_bus { +ulong base; +ulong driver_data; +int speed; +int (*idle_bus_fn)(void *p); +void *idle_bus_data; +}; +#ifdef I2C_QUIRK_REG static u16 i2c_clk_div[60 ][2 ] = { { 20, 0x00 }, { 22, 0x01 }, { 24, 0x02 }, { 26, 0x03 },@@ -104,7 +116,6 @@ static u16 i2c_clk_div[50][2] = { };#endif -#ifndef CONFIG_SYS_MXC_I2C1_SPEED #define CONFIG_SYS_MXC_I2C1_SPEED 100000#endif @@ -125,11 +136,10 @@ static u16 i2c_clk_div[50][2] = {#define CONFIG_SYS_MXC_I2C3_SLAVE 0#endif -/* * Calculate and set proper clock divider */ -static uint8_t i2c_imx_get_clk (unsigned int rate) +static uint8_t i2c_imx_get_clk (struct mxc_i2c_bus *i2c_bus,unsigned int rate) {unsigned int i2c_clk_rate;unsigned int div;@@ -162,18 +172,20 @@ static uint8_t i2c_imx_get_clk(unsigned int rate)/* * Set I2C Bus speed */ -static int bus_i2c_set_bus_speed (void *base,int speed) +static int bus_i2c_set_bus_speed (struct mxc_i2c_bus *i2c_bus,int speed) { -struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)base; -u8 clk_idx =i2c_imx_get_clk (speed); +ulong base = i2c_bus->base; +bool quirk = i2c_bus->driver_data &I2C_QUIRK_FLAG ? true : false; +u8 clk_idx =i2c_imx_get_clk (i2c_bus, speed);u8 idx = i2c_clk_div[clk_idx][1 ]; +int reg_shift = quirk ?VF610_I2C_REGSHIFT :IMX_I2C_REGSHIFT ;/* Store divider value */ -writeb (idx, &i2c_regs->ifdr); +writeb (idx, base + (IFDR << reg_shift));/* Reset module */ -writeb (I2CR_IDIS , &i2c_regs->i2cr); -writeb (0 , &i2c_regs->i2sr); +writeb (I2CR_IDIS , base + (I2CR << reg_shift)); +writeb (0 , base + (I2SR << reg_shift));return 0 ; }@@ -181,21 +193,26 @@ static int bus_i2c_set_bus_speed(void *base, int speed)#define ST_BUS_BUSY (I2SR_IBB | (I2SR_IBB << 8))#define ST_IIF (I2SR_IIF | (I2SR_IIF << 8)) -static int wait_for_sr_state (struct mxc_i2c_regs *i2c_regs,unsigned state) +static int wait_for_sr_state (struct mxc_i2c_bus *i2c_bus,unsigned state) {unsigned sr;ulong elapsed; +bool quirk = i2c_bus->driver_data &I2C_QUIRK_FLAG ? true : false; +int reg_shift = quirk ?VF610_I2C_REGSHIFT :IMX_I2C_REGSHIFT ; +ulong base = i2c_bus->base;ulong start_time =get_timer (0 );for (;;) { - sr =readb (&i2c_regs->i2sr); + sr =readb (base + (I2SR << reg_shift));if (sr &I2SR_IAL ) { -#ifdef I2C_QUIRK_REG -writeb (sr |I2SR_IAL , &i2c_regs->i2sr); -#else -writeb (sr & ~I2SR_IAL , &i2c_regs->i2sr); -#endif +if (quirk) +writeb (sr |I2SR_IAL , base + + (I2SR << reg_shift)); +else +writeb (sr & ~I2SR_IAL , base + + (I2SR << reg_shift));printf ("%s: Arbitration lost sr=%x cr=%x state=%x\n" , - __func__, sr,readb (&i2c_regs->i2cr), state); + __func__, sr,readb (base + (I2CR << reg_shift)), + state);return -ERESTART ; }if ((sr & (state >>8 )) == (unsigned char )state)@@ -206,17 +223,21 @@ static int wait_for_sr_state(struct mxc_i2c_regs *i2c_regs, unsigned state)break ; }printf ("%s: failed sr=%x cr=%x state=%x\n" , __func__, - sr,readb (&i2c_regs->i2cr), state); + sr,readb (base + (I2CR << reg_shift)), state);return -ETIMEDOUT ; } -static int tx_byte (struct mxc_i2c_regs *i2c_regs,u8 byte) +static int tx_byte (struct mxc_i2c_bus *i2c_bus,u8 byte) {int ret; +int reg_shift = i2c_bus->driver_data &I2C_QUIRK_FLAG ? +VF610_I2C_REGSHIFT :IMX_I2C_REGSHIFT ; +ulong base = i2c_bus->base; -writeb (I2SR_IIF_CLEAR , &i2c_regs->i2sr); -writeb (byte, &i2c_regs->i2dr); - ret =wait_for_sr_state (i2c_regs,ST_IIF ); +writeb (I2SR_IIF_CLEAR , base + (I2SR << reg_shift)); +writeb (byte, base + (I2DR << reg_shift)); + + ret =wait_for_sr_state (i2c_bus,ST_IIF );if (ret <0 )return ret;if (ret &I2SR_RX_NO_AK )@@ -225,16 +246,28 @@ static int tx_byte(struct mxc_i2c_regs *i2c_regs, u8 byte) }/* +* Stub implementations for outer i2c slave operations. +*/ +void __i2c_force_reset_slave (void ) +{ +} +void i2c_force_reset_slave (void ) + __attribute__((weak,alias ("__i2c_force_reset_slave" ))); + +/* * Stop I2C transaction */ -static void i2c_imx_stop (struct mxc_i2c_regs *i2c_regs) +static void i2c_imx_stop (struct mxc_i2c_bus *i2c_bus) {int ret; -unsigned int temp =readb (&i2c_regs->i2cr); +int reg_shift = i2c_bus->driver_data &I2C_QUIRK_FLAG ? +VF610_I2C_REGSHIFT :IMX_I2C_REGSHIFT ; +ulong base = i2c_bus->base; +unsigned int temp =readb (base + (I2CR << reg_shift)); temp &= ~(I2CR_MSTA |I2CR_MTX ); -writeb (temp, &i2c_regs->i2cr); - ret =wait_for_sr_state (i2c_regs,ST_BUS_IDLE ); +writeb (temp, base + (I2CR << reg_shift)); + ret =wait_for_sr_state (i2c_bus,ST_BUS_IDLE );if (ret <0 )printf ("%s:trigger stop failed\n" , __func__); }@@ -243,66 +276,82 @@ static void i2c_imx_stop(struct mxc_i2c_regs *i2c_regs)* Send start signal, chip address and * write register address */ -static int i2c_init_transfer_ (struct mxc_i2c_regs *i2c_regs, -uchar chip,uint addr,int alen) +static int i2c_init_transfer_ (struct mxc_i2c_bus *i2c_bus,u8 chip, +u32 addr,int alen) {unsigned int temp;int ret; +bool quirk = i2c_bus->driver_data &I2C_QUIRK_FLAG ? true : false; +ulong base = i2c_bus->base; +int reg_shift = quirk ?VF610_I2C_REGSHIFT :IMX_I2C_REGSHIFT ; + +/* Reset i2c slave */ +i2c_force_reset_slave ();/* Enable I2C controller */ -#ifdef I2C_QUIRK_REG -if (readb (&i2c_regs->i2cr) &I2CR_IDIS ) { -#else -if (!(readb (&i2c_regs->i2cr) &I2CR_IEN )) { -#endif -writeb (I2CR_IEN , &i2c_regs->i2cr); +if (quirk) + ret =readb (base + (I2CR << reg_shift)) &I2CR_IDIS ; +else + ret = !(readb (base + (I2CR << reg_shift)) &I2CR_IEN ); + +if (ret) { +writeb (I2CR_IEN , base + (I2CR << reg_shift));/* Wait for controller to be stable */ udelay (50 ); } -if (readb (&i2c_regs->iadr) == (chip <<1 )) -writeb ((chip <<1 ) ^2 , &i2c_regs->iadr); -writeb (I2SR_IIF_CLEAR , &i2c_regs->i2sr); - ret =wait_for_sr_state (i2c_regs,ST_BUS_IDLE ); + +if (readb (base + (IADR << reg_shift)) == (chip <<1 )) +writeb ((chip <<1 ) ^2 , base + (IADR << reg_shift)); +writeb (I2SR_IIF_CLEAR , base + (I2SR << reg_shift)); + ret =wait_for_sr_state (i2c_bus,ST_BUS_IDLE );if (ret <0 )return ret;/* Start I2C transaction */ - temp =readb (&i2c_regs->i2cr); + temp =readb (base + (I2CR << reg_shift)); temp |=I2CR_MSTA ; -writeb (temp, &i2c_regs->i2cr); +writeb (temp, base + (I2CR << reg_shift)); - ret =wait_for_sr_state (i2c_regs,ST_BUS_BUSY ); + ret =wait_for_sr_state (i2c_bus,ST_BUS_BUSY );if (ret <0 )return ret; temp |=I2CR_MTX |I2CR_TX_NO_AK ; -writeb (temp, &i2c_regs->i2cr); +writeb (temp, base + (I2CR << reg_shift));/* write slave address */ - ret =tx_byte (i2c_regs, chip <<1 ); + ret =tx_byte (i2c_bus, chip <<1 );if (ret <0 )return ret;while (alen--) { - ret =tx_byte (i2c_regs, (addr >> (alen *8 )) &0xff ); + ret =tx_byte (i2c_bus, (addr >> (alen *8 )) &0xff );if (ret <0 )return ret; }return 0 ; } -static int i2c_idle_bus (void *base); +static int i2c_idle_bus (struct mxc_i2c_bus *i2c_bus) +{ +if (i2c_bus && i2c_bus->idle_bus_fn) +return i2c_bus->idle_bus_fn (i2c_bus->idle_bus_data); +return 0 ; +} -static int i2c_init_transfer (struct mxc_i2c_regs *i2c_regs, -uchar chip,uint addr,int alen) + +static int i2c_init_transfer (struct mxc_i2c_bus *i2c_bus,u8 chip, +u32 addr,int alen) {int retry;int ret; +int reg_shift = i2c_bus->driver_data &I2C_QUIRK_FLAG ? +VF610_I2C_REGSHIFT :IMX_I2C_REGSHIFT ;for (retry =0 ; retry <3 ; retry++) { - ret =i2c_init_transfer_ (i2c_regs, chip, addr, alen); + ret =i2c_init_transfer_ (i2c_bus, chip, addr, alen);if (ret >=0 )return 0 ; -i2c_imx_stop (i2c_regs); +i2c_imx_stop (i2c_bus);if (ret == -ENODEV )return ret;@@ -310,54 +359,67 @@ static int i2c_init_transfer(struct mxc_i2c_regs *i2c_regs, retry);if (ret != -ERESTART )/* Disable controller */ -writeb (I2CR_IDIS , &i2c_regs->i2cr); +writeb (I2CR_IDIS , i2c_bus->base + (I2CR << reg_shift));udelay (100 ); -if (i2c_idle_bus (i2c_regs) <0 ) +if (i2c_idle_bus (i2c_bus) <0 )break ; } -printf ("%s: give up i2c_regs=%p\n" , __func__, i2c_regs); +printf ("%s: give up i2c_regs=0x%lx\n" , __func__, i2c_bus->base);return ret; } -/* -* Read data from I2C device -*/ -int bus_i2c_read (void *base,uchar chip,uint addr,int alen,uchar *buf, -int len) + +static int i2c_write_data (struct mxc_i2c_bus *i2c_bus,u8 chip,const u8 *buf, +int len) +{ +int i, ret =0 ; + +debug ("i2c_write_data: chip=0x%x, len=0x%x\n" , chip, len); +debug ("write_data: " ); +/* use rc for counter */ +for (i =0 ; i < len; ++i) +debug (" 0x%02x" , buf[i]); +debug ("\n" ); + +for (i =0 ; i < len; i++) { + ret =tx_byte (i2c_bus, buf[i]); +if (ret <0 ) { +debug ("i2c_write_data(): rc=%d\n" , ret); +break ; + } + } + +return ret; +} + +static int i2c_read_data (struct mxc_i2c_bus *i2c_bus,uchar chip,uchar *buf, +int len) {int ret;unsigned int temp;int i; -struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)base; +int reg_shift = i2c_bus->driver_data &I2C_QUIRK_FLAG ? +VF610_I2C_REGSHIFT :IMX_I2C_REGSHIFT ; +ulong base = i2c_bus->base; - ret =i2c_init_transfer (i2c_regs, chip, addr, alen); -if (ret <0 ) -return ret; - - temp =readb (&i2c_regs->i2cr); - temp |=I2CR_RSTA ; -writeb (temp, &i2c_regs->i2cr); - - ret =tx_byte (i2c_regs, (chip <<1 ) |1 ); -if (ret <0 ) { -i2c_imx_stop (i2c_regs); -return ret; - } +debug ("i2c_read_data: chip=0x%x, len=0x%x\n" , chip, len);/* setup bus to read data */ - temp =readb (&i2c_regs->i2cr); + temp =readb (base + (I2CR << reg_shift)); temp &= ~(I2CR_MTX |I2CR_TX_NO_AK );if (len ==1 ) temp |=I2CR_TX_NO_AK ; -writeb (temp, &i2c_regs->i2cr); -writeb (I2SR_IIF_CLEAR , &i2c_regs->i2sr); -readb (&i2c_regs->i2dr);/* dummy read to clear ICF */ +writeb (temp, base + (I2CR << reg_shift)); +writeb (I2SR_IIF_CLEAR , base + (I2SR << reg_shift)); +/* dummy read to clear ICF */ +readb (base + (I2DR << reg_shift));/* read data */ for (i =0 ; i < len; i++) { - ret =wait_for_sr_state (i2c_regs,ST_IIF ); + ret =wait_for_sr_state (i2c_bus,ST_IIF );if (ret <0 ) { -i2c_imx_stop (i2c_regs); +debug ("i2c_read_data(): ret=%d\n" , ret); +i2c_imx_stop (i2c_bus);return ret; }@@ -366,105 +428,111 @@ int bus_i2c_read(void *base, uchar chip, uint addr, int alen, uchar *buf, * controller from generating another clock cycle */ if (i == (len - 1)) { -i2c_imx_stop (i2c_regs); + i2c_imx_stop(i2c_bus); } else if (i == (len - 2)) { - temp =readb (&i2c_regs->i2cr); + temp = readb(base + (I2CR << reg_shift)); temp |= I2CR_TX_NO_AK; -writeb (temp, &i2c_regs->i2cr); + writeb(temp, base + (I2CR << reg_shift)); } -writeb (I2SR_IIF_CLEAR , &i2c_regs->i2sr); - buf[i] =readb (&i2c_regs->i2dr); + writeb(I2SR_IIF_CLEAR, base + (I2SR << reg_shift)); + buf[i] = readb(base + (I2DR << reg_shift)); } -i2c_imx_stop (i2c_regs); + + /* reuse ret for counter*/ + for (ret = 0; ret < len; ++ret) + debug(" 0x%02x", buf[ret]); + debug("\n"); + + i2c_imx_stop(i2c_bus); return 0; } +#ifndef CONFIG_DM_I2C /* -* Write data to I2C device + * Read data from I2C device */ -int bus_i2c_write (void *base,uchar chip,uint addr,int alen, -const uchar *buf,int len) +static int bus_i2c_read(struct mxc_i2c_bus *i2c_bus, u8 chip, u32 addr, + int alen, u8 *buf, int len) { -int ret; -int i; -struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)base; + int ret = 0; + u32 temp; + int reg_shift = i2c_bus->driver_data & I2C_QUIRK_FLAG ? + VF610_I2C_REGSHIFT : IMX_I2C_REGSHIFT; + ulong base = i2c_bus->base; - ret =i2c_init_transfer (i2c_regs, chip, addr, alen); + ret = i2c_init_transfer(i2c_bus, chip, addr, alen); if (ret < 0) return ret; -for (i =0 ; i < len; i++) { - ret =tx_byte (i2c_regs, buf[i]); -if (ret <0 ) -break ; + temp = readb(base + (I2CR << reg_shift)); + temp |= I2CR_RSTA; + writeb(temp, base + (I2CR << reg_shift)); + + ret = tx_byte(i2c_bus, (chip << 1) | 1); + if (ret < 0) { + i2c_imx_stop(i2c_bus); + return ret; } -i2c_imx_stop (i2c_regs); + + ret = i2c_read_data(i2c_bus, chip, buf, len); + + i2c_imx_stop(i2c_bus); return ret; } -static void * const i2c_bases[] = { +/* + * Write data to I2C device + */ +static int bus_i2c_write(struct mxc_i2c_bus *i2c_bus, u8 chip, u32 addr, + int alen, const u8 *buf, int len) +{ + int ret = 0; + + ret = i2c_init_transfer(i2c_bus, chip, addr, alen); + if (ret < 0) + return ret; + + ret = i2c_write_data(i2c_bus, chip, buf, len); + + i2c_imx_stop(i2c_bus); + + return ret; +} + +static struct mxc_i2c_bus mxc_i2c_buses[] = { #if defined(CONFIG_MX25) - (void *)IMX_I2C_BASE , - (void *)IMX_I2C2_BASE , - (void *)IMX_I2C3_BASE + { IMX_I2C_BASE, 0 }, + { IMX_I2C2_BASE, 0 }, + { IMX_I2C3_BASE, 0 }, #elif defined(CONFIG_MX27) - (void *)IMX_I2C1_BASE , - (void *)IMX_I2C2_BASE + { IMX_I2C1_BASE, 0 }, + { IMX_I2C2_BASE, 0 }, #elif defined(CONFIG_MX31) || defined(CONFIG_MX35) || \ defined(CONFIG_MX51) || defined(CONFIG_MX53) || \ - defined(CONFIG_MX6 ) || defined(CONFIG_LS102XA ) - (void *)I2C1_BASE_ADDR , - (void *)I2C2_BASE_ADDR , - (void *)I2C3_BASE_ADDR + defined(CONFIG_MX6) + { I2C1_BASE_ADDR, 0 }, + { I2C2_BASE_ADDR, 0 }, + { I2C3_BASE_ADDR, 0 }, +#elif defined(CONFIG_LS102XA) + { I2C1_BASE_ADDR, I2C_QUIRK_FLAG }, + { I2C2_BASE_ADDR, I2C_QUIRK_FLAG }, + { I2C3_BASE_ADDR, I2C_QUIRK_FLAG }, #elif defined(CONFIG_VF610) - (void *)I2C0_BASE_ADDR + { I2C0_BASE_ADDR, I2C_QUIRK_FLAG }, #elif defined(CONFIG_FSL_LSCH3) - (void *)I2C1_BASE_ADDR , - (void *)I2C2_BASE_ADDR , - (void *)I2C3_BASE_ADDR , - (void *)I2C4_BASE_ADDR + { I2C1_BASE_ADDR, I2C_QUIRK_FLAG }, + { I2C2_BASE_ADDR, I2C_QUIRK_FLAG }, + { I2C3_BASE_ADDR, I2C_QUIRK_FLAG }, + { I2C4_BASE_ADDR, I2C_QUIRK_FLAG }, #else #error "architecture not supported" #endif + { } }; -struct i2c_parms { -void *base; -void *idle_bus_data; -int (*idle_bus_fn)(void *p); -}; - -struct sram_data { -unsigned curr_i2c_bus; -struct i2c_parms i2c_data[ARRAY_SIZE (i2c_bases)]; -}; - -void *i2c_get_base (struct i2c_adapter *adap) +struct mxc_i2c_bus *i2c_get_base(struct i2c_adapter *adap) { -return i2c_bases[adap->hwadapnr]; -} - -static struct i2c_parms *i2c_get_parms (void *base) -{ -struct sram_data *srdata = (void *)gd->srdata; -int i =0 ; -struct i2c_parms *p = srdata->i2c_data; -while (i <ARRAY_SIZE (srdata->i2c_data)) { -if (p->base == base) -return p; - p++; - i++; - } -printf ("Invalid I2C base: %p\n" , base); -return NULL ; -} - -static int i2c_idle_bus (void *base) -{ -struct i2c_parms *p =i2c_get_parms (base); -if (p && p->idle_bus_fn) -return p->idle_bus_fn (p->idle_bus_data); -return 0 ; + return &mxc_i2c_buses[adap->hwadapnr]; } static int mxc_i2c_read(struct i2c_adapter *adap, uint8_t chip,@@ -489,29 +557,18 @@ static int mxc_i2c_probe(struct i2c_adapter *adap, uint8_t chip)return bus_i2c_write (i2c_get_base (adap), chip,0 ,0 ,NULL ,0 ); } -void bus_i2c_init (void *base,int speed,int unused, -int (*idle_bus_fn)(void *p),void *idle_bus_data) +void bus_i2c_init (int index,int speed,int unused, +int (*idle_bus_fn)(void *p),void *idle_bus_data) { -struct sram_data *srdata = (void *)gd->srdata; -int i =0 ; -struct i2c_parms *p = srdata->i2c_data; -if (!base) +if (index >=ARRAY_SIZE (mxc_i2c_buses)) { +debug ("Error i2c index\n" );return ; -for (;;) { -if (!p->base || (p->base == base)) { - p->base = base; -if (idle_bus_fn) { - p->idle_bus_fn = idle_bus_fn; - p->idle_bus_data = idle_bus_data; - } -break ; - } - p++; - i++; -if (i >=ARRAY_SIZE (srdata->i2c_data)) -return ; } -bus_i2c_set_bus_speed (base, speed); + + mxc_i2c_buses[index].idle_bus_fn = idle_bus_fn; + mxc_i2c_buses[index].idle_bus_data = idle_bus_data; + +bus_i2c_set_bus_speed (&mxc_i2c_buses[index], speed); }/* @@ -519,13 +576,13 @@ void bus_i2c_init(void *base, int speed, int unused,*/ static void mxc_i2c_init (struct i2c_adapter *adap,int speed,int slaveaddr) { -bus_i2c_init (i2c_get_base (adap), speed, slaveaddr,NULL ,NULL ); +bus_i2c_init (adap->hwadapnr, speed, slaveaddr,NULL ,NULL ); }/* * Set I2C Speed */ -static uint mxc_i2c_set_bus_speed (struct i2c_adapter *adap,uint speed) +static u32 mxc_i2c_set_bus_speed (struct i2c_adapter *adap,uint speed) {return bus_i2c_set_bus_speed (i2c_get_base (adap), speed); }@@ -552,3 +609,161 @@ U_BOOT_I2C_ADAP_COMPLETE(mxc2, mxc_i2c_init, mxc_i2c_probe, CONFIG_SYS_MXC_I2C3_SPEED, CONFIG_SYS_MXC_I2C3_SLAVE, 2)#endif + +#else + +static int mxc_i2c_set_bus_speed (struct udevice *bus,unsigned int speed) +{ +struct mxc_i2c_bus *i2c_bus =dev_get_priv (bus); + +return bus_i2c_set_bus_speed (i2c_bus, speed); +} + +static int mxc_i2c_probe (struct udevice *bus) +{ +struct mxc_i2c_bus *i2c_bus =dev_get_priv (bus); +fdt_addr_t addr; + + i2c_bus->driver_data =dev_get_driver_data (bus); + + addr =dev_get_addr (bus); +if (addr ==FDT_ADDR_T_NONE ) +return -ENODEV ; + + i2c_bus->base = addr; + +/* +* Pinmux settings are in board file now, until pinmux is supported, +* we can set pinmux here in probe function. +*/ + +debug ("i2c : controller bus %d at %lu , speed %d: " , + bus->seq, i2c_bus->base, + i2c_bus->speed); + +return 0 ; +} + +/* +* This function is for setup_i2c.We need idle_bus_fn and pinmux setting. +* When something wrong happens during data transfer, we can use gpio +* mode to force i2c bus idle. +* This way not friend to DM. Since arch/arm/imx-common/i2c-mxv7.c is used +* for all i.MX platforms, it is not easy to refactor it for DM. So, +* implement bus_i2c_init here temporarily. +* +* In future, when we can remove setup_i2c from board file, bus_i2c_init +* can be removed. +*/ +void bus_i2c_init (int busnum,int speed,int slave,int (*idle_bus_fn)(void *p), +void *idle_bus_data) +{ +struct udevice *bus; +struct mxc_i2c_bus *i2c_bus; +int ret; + + ret =uclass_get_device_by_seq (UCLASS_I2C , busnum, &bus); +if (ret) { +debug ("Cannot find I2C bus %d\n" , busnum); +return ; + } + + i2c_bus =dev_get_priv (bus); + + i2c_bus->idle_bus_fn = idle_bus_fn; + i2c_bus->idle_bus_data = idle_bus_data; + +return ; +} + +static int mxc_i2c_probe_chip (struct udevice *bus,u32 chip_addr, +u32 chip_flags) +{ +int ret; +struct mxc_i2c_bus *i2c_bus =dev_get_priv (bus); + + ret =i2c_init_transfer (i2c_bus, chip_addr,0 ,0 ); +if (ret <0 ) { +debug ("%s failed, ret = %d\n" , __func__, ret); +return ret; + } + +i2c_imx_stop (i2c_bus); + +return 0 ; +} + +static int mxc_i2c_xfer (struct udevice *bus,struct i2c_msg *msg,int nmsgs) +{ +struct mxc_i2c_bus *i2c_bus =dev_get_priv (bus); +int ret =0 ; +ulong base = i2c_bus->base; +int reg_shift = i2c_bus->driver_data &I2C_QUIRK_FLAG ? +VF610_I2C_REGSHIFT :IMX_I2C_REGSHIFT ; + +/* +* Here the 3rd parameter addr and the 4th one alen are set to 0, +* because here we only want to send out chip address. The register +* address is wrapped in msg. +*/ + ret =i2c_init_transfer (i2c_bus, msg->addr,0 ,0 ); +if (ret <0 ) { +debug ("i2c_init_transfer error: %d\n" , ret); +return ret; + } + +for (; nmsgs >0 ; nmsgs--, msg++) { +bool next_is_read = nmsgs >1 && (msg[1 ].flags &I2C_M_RD ); +debug ("i2c_xfer: chip=0x%x, len=0x%x\n" , msg->addr, msg->len); +if (msg->flags &I2C_M_RD ) + ret =i2c_read_data (i2c_bus, msg->addr, msg->buf, + msg->len); +else { + ret =i2c_write_data (i2c_bus, msg->addr, msg->buf, + msg->len); +if (ret) +break ; +if (next_is_read) { +/* Reuse ret */ + ret =readb (base + (I2CR << reg_shift)); + ret |=I2CR_RSTA ; +writeb (ret, base + (I2CR << reg_shift)); + + ret =tx_byte (i2c_bus, (msg->addr <<1 ) |1 ); +if (ret <0 ) { +i2c_imx_stop (i2c_bus); +break ; + } + } + } + } + +if (ret) +debug ("i2c_write: error sending\n" ); + +i2c_imx_stop (i2c_bus); + +return ret; +} + +static const struct dm_i2c_ops mxc_i2c_ops = { + .xfer = mxc_i2c_xfer, + .probe_chip = mxc_i2c_probe_chip, + .set_bus_speed = mxc_i2c_set_bus_speed, +}; + +static const struct udevice_id mxc_i2c_ids[] = { + { .compatible ="fsl,imx21-i2c" , }, + { .compatible ="fsl,vf610-i2c" , .data =I2C_QUIRK_FLAG , }, + {} +};
drivers/i2c/mxc_i2c.c U_BOOT_I2C_ADAP_COMPLETE(mxc2, mxc_i2c_init, mxc_i2c_probe, · line 769
Quoted 10 lines
drivers/i2c/mxc_i2c.c +10
-0+ +U_BOOT_DRIVER (i2c_mxc) = { + .name ="i2c_mxc" , + .id =UCLASS_I2C , + .of_match = mxc_i2c_ids, + .probe = mxc_i2c_probe, + .priv_auto_alloc_size =sizeof (struct mxc_i2c_bus ), + .ops = &mxc_i2c_ops, +}; +#endif
Regards,
Peng.