X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=cpu%2Fmpc8260%2Fi2c.c;h=d2bdcc2d827f99e1560a334f996a9f1f860c79ba;hb=f9edcc10e6cb497dd7dcbaf691cfd1859abae27a;hp=8bfa2e8e74e26eeb699bb929e512ec716583317f;hpb=c609719b8d1b2dca590e0ed499016d041203e403;p=oweals%2Fu-boot.git diff --git a/cpu/mpc8260/i2c.c b/cpu/mpc8260/i2c.c index 8bfa2e8e74..d2bdcc2d82 100644 --- a/cpu/mpc8260/i2c.c +++ b/cpu/mpc8260/i2c.c @@ -34,6 +34,12 @@ /* define to enable debug messages */ #undef DEBUG_I2C +DECLARE_GLOBAL_DATA_PTR; + +#if defined(CONFIG_I2C_MULTI_BUS) +static unsigned int i2c_bus_num __attribute__ ((section (".data"))) = 0; +#endif /* CONFIG_I2C_MULTI_BUS */ + /* uSec to wait between polls of the i2c */ #define DELAY_US 100 /* uSec to wait for the CPM to start processing the buffer */ @@ -48,17 +54,14 @@ /*----------------------------------------------------------------------- * Set default values */ -#ifndef CFG_I2C_SPEED -#define CFG_I2C_SPEED 50000 +#ifndef CONFIG_SYS_I2C_SPEED +#define CONFIG_SYS_I2C_SPEED 50000 #endif -#ifndef CFG_I2C_SLAVE -#define CFG_I2C_SLAVE 0xFE -#endif /*----------------------------------------------------------------------- */ -typedef void (*i2c_ecb_t)(int, int); /* error callback function */ +typedef void (*i2c_ecb_t)(int, int, void *); /* error callback function */ /* This structure keeps track of the bd and buffer space usage. */ typedef struct i2c_state { @@ -69,6 +72,7 @@ typedef struct i2c_state { int tx_space; /* number of Tx bytes left */ unsigned char *tx_buf; /* pointer to free Tx area */ i2c_ecb_t err_cb; /* error callback function */ + void *cb_data; /* private data to be passed */ } i2c_state_t; /* flags for i2c_send() and i2c_receive() */ @@ -77,14 +81,15 @@ typedef struct i2c_state { #define I2CF_STOP_COND 0x04 /* tx: generate stop condition */ /* return codes */ -#define I2CERR_NO_BUFFERS 0x01 /* no more BDs or buffer space */ -#define I2CERR_MSG_TOO_LONG 0x02 /* tried to send/receive to much data */ -#define I2CERR_TIMEOUT 0x03 /* timeout in i2c_doio() */ -#define I2CERR_QUEUE_EMPTY 0x04 /* i2c_doio called without send/receive */ +#define I2CERR_NO_BUFFERS 1 /* no more BDs or buffer space */ +#define I2CERR_MSG_TOO_LONG 2 /* tried to send/receive to much data */ +#define I2CERR_TIMEOUT 3 /* timeout in i2c_doio() */ +#define I2CERR_QUEUE_EMPTY 4 /* i2c_doio called without send/receive */ +#define I2CERR_IO_ERROR 5 /* had an error during comms */ /* error callback flags */ #define I2CECB_RX_ERR 0x10 /* this is a receive error */ -#define I2CECB_RX_ERR_OV 0x02 /* receive overrun error */ +#define I2CECB_RX_OV 0x02 /* receive overrun error */ #define I2CECB_RX_MASK 0x0f /* mask for error bits */ #define I2CECB_TX_ERR 0x20 /* this is a transmit error */ #define I2CECB_TX_CL 0x01 /* transmit collision error */ @@ -147,7 +152,7 @@ i2c_roundrate(int hz, int speed, int filter, int modval, PRINTD(("\t\tmoddiv=%d, brgdiv=%d\n", moddiv, brgdiv)); - *brgval = (brgdiv / 2) - 3 - (2*filter); + *brgval = ((brgdiv + 1) / 2) - 3 - (2*filter); if ((*brgval < 0) || (*brgval > 255)) { PRINTD(("\t\trejected brgval=%d\n", *brgval)); @@ -156,7 +161,7 @@ i2c_roundrate(int hz, int speed, int filter, int modval, brgdiv = 2 * (*brgval + 3 + (2 * filter)); div = moddiv * brgdiv ; - *totspeed = (hz + div - 1) / div; + *totspeed = hz / div; PRINTD(("\t\taccepted brgval=%d, totspeed=%d\n", *brgval, *totspeed)); @@ -168,7 +173,7 @@ i2c_roundrate(int hz, int speed, int filter, int modval, */ static int i2c_setrate(int hz, int speed) { - immap_t *immap = (immap_t *)CFG_IMMR ; + immap_t *immap = (immap_t *)CONFIG_SYS_IMMR ; volatile i2c8260_t *i2c = (i2c8260_t *)&immap->im_i2c; int brgval, modval, /* 0-3 */ @@ -187,10 +192,10 @@ static int i2c_setrate(int hz, int speed) if ((diff >= 0) && (diff < bestspeed_diff)) { - bestspeed_diff = diff ; - bestspeed_modval = modval; - bestspeed_brgval = brgval; - bestspeed_filter = filter; + bestspeed_diff = diff ; + bestspeed_modval = modval; + bestspeed_brgval = brgval; + bestspeed_filter = filter; } } } @@ -211,9 +216,7 @@ static int i2c_setrate(int hz, int speed) void i2c_init(int speed, int slaveadd) { - DECLARE_GLOBAL_DATA_PTR; - - volatile immap_t *immap = (immap_t *)CFG_IMMR ; + volatile immap_t *immap = (immap_t *)CONFIG_SYS_IMMR ; volatile cpm8260_t *cp = (cpm8260_t *)&immap->im_cpm; volatile i2c8260_t *i2c = (i2c8260_t *)&immap->im_i2c; volatile iic_t *iip; @@ -221,6 +224,13 @@ void i2c_init(int speed, int slaveadd) volatile I2C_BD *rxbd, *txbd; uint dpaddr; +#ifdef CONFIG_SYS_I2C_INIT_BOARD + /* call board specific i2c bus reset routine before accessing the */ + /* environment, which might be in a chip on that bus. For details */ + /* about this problem see doc/I2C_Edge_Conditions. */ + i2c_init_board(); +#endif + dpaddr = *((unsigned short*)(&immap->im_dprambase[PROFF_I2C_BASE])); if (dpaddr == 0) { /* need to allocate dual port ram */ @@ -233,7 +243,7 @@ void i2c_init(int speed, int slaveadd) /* * initialise data in dual port ram: * - * dpaddr -> parameter ram (64 bytes) + * dpaddr -> parameter ram (64 bytes) * rbase -> rx BD (NUM_RX_BDS * sizeof(I2C_BD) bytes) * tbase -> tx BD (NUM_TX_BDS * sizeof(I2C_BD) bytes) * tx buffer (MAX_TX_SPACE bytes) @@ -257,7 +267,7 @@ void i2c_init(int speed, int slaveadd) * divide BRGCLK by 1) */ PRINTD(("[I2C] Setting rate...\n")); - i2c_setrate (gd->brg_clk, CFG_I2C_SPEED) ; + i2c_setrate (gd->brg_clk, CONFIG_SYS_I2C_SPEED) ; /* Set I2C controller in master mode */ i2c->i2c_i2com = 0x01; @@ -296,7 +306,7 @@ void i2c_init(int speed, int slaveadd) static void i2c_newio(i2c_state_t *state) { - volatile immap_t *immap = (immap_t *)CFG_IMMR ; + volatile immap_t *immap = (immap_t *)CONFIG_SYS_IMMR ; volatile iic_t *iip; uint dpaddr; @@ -311,6 +321,7 @@ void i2c_newio(i2c_state_t *state) state->tx_space = MAX_TX_SPACE; state->tx_buf = (uchar*)state->txbd + NUM_TX_BDS * sizeof(I2C_BD); state->err_cb = NULL; + state->cb_data = NULL; PRINTD(("[I2C] rxbd = %08x\n", (int)state->rxbd)); PRINTD(("[I2C] txbd = %08x\n", (int)state->txbd)); @@ -480,18 +491,15 @@ int i2c_receive(i2c_state_t *state, static int i2c_doio(i2c_state_t *state) { - volatile immap_t *immap = (immap_t *)CFG_IMMR ; + volatile immap_t *immap = (immap_t *)CONFIG_SYS_IMMR ; volatile iic_t *iip; volatile i2c8260_t *i2c = (i2c8260_t *)&immap->im_i2c; volatile I2C_BD *txbd, *rxbd; - int j; - int timeout; + int n, i, b, rxcnt = 0, rxtimeo = 0, txcnt = 0, txtimeo = 0, rc = 0; uint dpaddr; PRINTD(("[I2C] i2c_doio\n")); - timeout = TOUT_LOOP * 256; /* arbitrarily long */ - if (state->tx_idx <= 0 && state->rx_idx <= 0) { PRINTD(("[I2C] No I/O is queued\n")); return I2CERR_QUEUE_EMPTY; @@ -511,14 +519,20 @@ int i2c_doio(i2c_state_t *state) /* Loop until transmit & receive completed */ - txbd = ((I2C_BD*)state->txbd) - 1; - j = 0; - if (state->tx_idx > 0) { - timeout = TOUT_LOOP * txbd->length; + if ((n = state->tx_idx) > 0) { + + txbd = ((I2C_BD*)state->txbd) - n; + for (i = 0; i < n; i++) { + txtimeo += TOUT_LOOP * txbd->length; + txbd++; + } + + txbd--; /* wait until last in list is done */ PRINTD(("[I2C] Transmitting...(txbd=0x%08lx)\n", (ulong)txbd)); + udelay(START_DELAY_US); /* give it time to start */ - while((txbd->status & BD_SC_READY) && (j++ < timeout)) { + while((txbd->status & BD_SC_READY) && (++txcnt < txtimeo)) { udelay(DELAY_US); if (ctrlc()) return (-1); @@ -526,13 +540,20 @@ int i2c_doio(i2c_state_t *state) } } - rxbd = ((I2C_BD*)state->rxbd) - 1; - j = 0; - if ((state->rx_idx > 0) && (j < timeout)) { - timeout = TOUT_LOOP * rxbd->length; + if (txcnt < txtimeo && (n = state->rx_idx) > 0) { + + rxbd = ((I2C_BD*)state->rxbd) - n; + for (i = 0; i < n; i++) { + rxtimeo += TOUT_LOOP * rxbd->length; + rxbd++; + } + + rxbd--; /* wait until last in list is done */ + PRINTD(("[I2C] Receiving...(rxbd=0x%08lx)\n", (ulong)rxbd)); + udelay(START_DELAY_US); /* give it time to start */ - while((rxbd->status & BD_SC_EMPTY) && (j++ < timeout)) { + while((rxbd->status & BD_SC_EMPTY) && (++rxcnt < rxtimeo)) { udelay(DELAY_US); if (ctrlc()) return (-1); @@ -543,76 +564,91 @@ int i2c_doio(i2c_state_t *state) /* Turn off I2C */ i2c->i2c_i2mod &= ~0x01; - if (state->err_cb != NULL) { - int n, i, b; - - /* - * if we have an error callback function, look at the - * error bits in the bd status and pass them back - */ - - if ((n = state->tx_idx) > 0) { - for (i = 0; i < n; i++) { - txbd = ((I2C_BD*)state->txbd) - (n - i); - if ((b = txbd->status & BD_I2C_TX_ERR) != 0) - (*state->err_cb)(I2CECB_TX_ERR|b, i); + if ((n = state->tx_idx) > 0) { + for (i = 0; i < n; i++) { + txbd = ((I2C_BD*)state->txbd) - (n - i); + if ((b = txbd->status & BD_I2C_TX_ERR) != 0) { + if (state->err_cb != NULL) + (*state->err_cb)(I2CECB_TX_ERR|b, i, + state->cb_data); + if (rc == 0) + rc = I2CERR_IO_ERROR; } } + } - if ((n = state->rx_idx) > 0) { - for (i = 0; i < n; i++) { - rxbd = ((I2C_BD*)state->rxbd) - (n - i); - if ((b = rxbd->status & BD_I2C_RX_ERR) != 0) - (*state->err_cb)(I2CECB_RX_ERR|b, i); + if ((n = state->rx_idx) > 0) { + for (i = 0; i < n; i++) { + rxbd = ((I2C_BD*)state->rxbd) - (n - i); + if ((b = rxbd->status & BD_I2C_RX_ERR) != 0) { + if (state->err_cb != NULL) + (*state->err_cb)(I2CECB_RX_ERR|b, i, + state->cb_data); + if (rc == 0) + rc = I2CERR_IO_ERROR; } } - - if (j >= timeout) - (*state->err_cb)(I2CECB_TIMEOUT, 0); } - /* sort out errors and return appropriate good/error status */ - if(j >= timeout) - return(I2CERR_TIMEOUT); - if((txbd->status & BD_I2C_TX_ERR) != 0) - return(I2CECB_TX_ERR | (txbd->status & I2CECB_TX_MASK)); - if((rxbd->status & BD_I2C_RX_ERR) != 0) - return(I2CECB_RX_ERR | (rxbd->status & I2CECB_RX_MASK)); + if ((txtimeo > 0 && txcnt >= txtimeo) || \ + (rxtimeo > 0 && rxcnt >= rxtimeo)) { + if (state->err_cb != NULL) + (*state->err_cb)(I2CECB_TIMEOUT, -1, state->cb_data); + if (rc == 0) + rc = I2CERR_TIMEOUT; + } - return(0); + return (rc); } -static int had_tx_nak; - static void -i2c_test_callback(int flags, int xnum) +i2c_probe_callback(int flags, int xnum, void *data) { - if ((flags & I2CECB_TX_ERR) && (flags & I2CECB_TX_NAK)) - had_tx_nak = 1; + /* + * the only acceptable errors are a transmit NAK or a receive + * overrun - tx NAK means the device does not exist, rx OV + * means the device must have responded to the slave address + * even though the transfer failed + */ + if (flags == (I2CECB_TX_ERR|I2CECB_TX_NAK)) + *(int *)data |= 1; + if (flags == (I2CECB_RX_ERR|I2CECB_RX_OV)) + *(int *)data |= 2; } -int i2c_probe(uchar chip) +int +i2c_probe(uchar chip) { i2c_state_t state; - int rc; + int rc, err_flag; uchar buf[1]; i2c_newio(&state); - state.err_cb = i2c_test_callback; - had_tx_nak = 0; + state.err_cb = i2c_probe_callback; + state.cb_data = (void *) &err_flag; + err_flag = 0; rc = i2c_receive(&state, chip, 0, I2CF_START_COND|I2CF_STOP_COND, 1, buf); if (rc != 0) - return (rc); + return (rc); /* probe failed */ rc = i2c_doio(&state); - if ((rc != 0) && (rc != I2CERR_TIMEOUT)) - return (rc); + if (rc == 0) + return (0); /* device exists - read succeeded */ + + if (rc == I2CERR_TIMEOUT) + return (-1); /* device does not exist - timeout */ + + if (rc != I2CERR_IO_ERROR || err_flag == 0) + return (rc); /* probe failed */ - return (had_tx_nak); + if (err_flag & 1) + return (-1); /* device does not exist - had transmit NAK */ + + return (0); /* device exists - had receive overrun */ } @@ -628,19 +664,19 @@ i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len) xaddr[2] = (addr >> 8) & 0xFF; xaddr[3] = addr & 0xFF; -#ifdef CFG_I2C_EEPROM_ADDR_OVERFLOW +#ifdef CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW /* * EEPROM chips that implement "address overflow" are ones * like Catalyst 24WC04/08/16 which has 9/10/11 bits of address * and the extra bits end up in the "chip address" bit slots. * This makes a 24WC08 (1Kbyte) chip look like four 256 byte * chips. - * + * * Note that we consider the length of the address field to still * be one byte because the extra address bits are hidden in the * chip address. */ - chip |= ((addr >> (alen * 8)) & CFG_I2C_EEPROM_ADDR_OVERFLOW); + chip |= ((addr >> (alen * 8)) & CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW); #endif i2c_newio(&state); @@ -677,19 +713,19 @@ i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len) xaddr[2] = (addr >> 8) & 0xFF; xaddr[3] = addr & 0xFF; -#ifdef CFG_I2C_EEPROM_ADDR_OVERFLOW +#ifdef CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW /* * EEPROM chips that implement "address overflow" are ones * like Catalyst 24WC04/08/16 which has 9/10/11 bits of address * and the extra bits end up in the "chip address" bit slots. * This makes a 24WC08 (1Kbyte) chip look like four 256 byte * chips. - * + * * Note that we consider the length of the address field to still * be one byte because the extra address bits are hidden in the * chip address. */ - chip |= ((addr >> (alen * 8)) & CFG_I2C_EEPROM_ADDR_OVERFLOW); + chip |= ((addr >> (alen * 8)) & CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW); #endif i2c_newio(&state); @@ -714,20 +750,36 @@ i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len) return 0; } -uchar -i2c_reg_read(uchar chip, uchar reg) +#if defined(CONFIG_I2C_MULTI_BUS) +/* + * Functions for multiple I2C bus handling + */ +unsigned int i2c_get_bus_num(void) { - char buf; - - i2c_read(chip, reg, 1, &buf, 1); - - return (buf); + return i2c_bus_num; } -void -i2c_reg_write(uchar chip, uchar reg, uchar val) +int i2c_set_bus_num(unsigned int bus) { - i2c_write(chip, reg, 1, &val, 1); +#if defined(CONFIG_I2C_MUX) + if (bus < CONFIG_SYS_MAX_I2C_BUS) { + i2c_bus_num = bus; + } else { + int ret; + + ret = i2x_mux_select_mux(bus); + if (ret == 0) + i2c_bus_num = bus; + else + return ret; + } +#else + if (bus >= CONFIG_SYS_MAX_I2C_BUS) + return -1; + i2c_bus_num = bus; +#endif + return 0; } +#endif /* CONFIG_I2C_MULTI_BUS */ #endif /* CONFIG_HARD_I2C */