diff --git a/drivers/i2c/i2c-algo-mpc5xxx.c b/drivers/i2c/i2c-algo-mpc5xxx.c index 26292c7..4130aae 100644 --- a/drivers/i2c/i2c-algo-mpc5xxx.c +++ b/drivers/i2c/i2c-algo-mpc5xxx.c @@ -24,13 +24,20 @@ #include /* #define MPC5xxx_SCAN 1 */ -#define MPC5xxx_TIMEOUT 100 +#define MPC5xxx_TIMEOUT 1000 #define MPC5xxx_RETRIES 3 +#define MPC5xxx_SPEED_KBPS 25 -static int speed = 100; +#define DEB(x) if (dlevel>=1) x; +#define DEB2(x) if (dlevel>=2) x; -MODULE_PARM(speed, "i"); +static int speed = MPC5xxx_SPEED_KBPS; /* kbps */ +static int dlevel = 1; +MODULE_PARM(speed, "i"); +MODULE_PARM_DESC(speed, "bus clock (kbps)"); +MODULE_PARM(dlevel, "i"); +MODULE_PARM_DESC(dlevel, "debug level"); #ifdef CONFIG_MPC5xxx_I2C_INT DECLARE_WAIT_QUEUE_HEAD(i2c1_if_wq); @@ -48,6 +55,8 @@ static int i2c2_status = 0; static volatile u32 *micr = (u32 *)(MPC5xxx_I2C_MICR); #endif +static void mpc5xxx_init(struct i2c_algo_mpc5xxx_data *algo_data); + static int mpc5xxx_in(volatile u32 *reg) { return in_be32(reg) >> 24; @@ -75,6 +84,9 @@ static void i2c_start(struct i2c_algo_mpc5xxx_data *algo_data) mpc5xxx_out(®s->mcr, MPC5xxx_I2C_STA, MPC5xxx_I2C_STA); + /* clear pending interrupts */ + mpc5xxx_out(®s->msr, 0, MPC5xxx_I2C_IF); + return; } @@ -140,6 +152,22 @@ static void i2c2_interrupt(int irq, void *dev_id, struct pt_regs *pregs) } #endif +static void i2c_reset(struct i2c_algo_mpc5xxx_data *algo_data) +{ + struct mpc5xxx_i2c *regs = algo_data->regs; + + DEB(printk(KERN_DEBUG "i2c-algo-mpc5xxx.o: resetting bus\n")); + + /* Clear status, go slave */ + mpc5xxx_out(®s->msr, 0, 0); + i2c_stop(algo_data); + + udelay(10000 / speed); /* 0,1 ms @ 100 kbs */ + mpc5xxx_init(algo_data); + + return; +} + static int wait_for_bb(struct i2c_algo_mpc5xxx_data *algo_data) { struct mpc5xxx_i2c *regs = algo_data->regs; @@ -177,7 +205,15 @@ static int wait_for_bb(struct i2c_algo_mpc5xxx_data *algo_data) *pstat = 0; #else status = mpc5xxx_in(®s->msr); + + if(status & MPC5xxx_I2C_AL) { + DEB(printk(KERN_DEBUG "i2c-algo-mpc5xxx.o: AL set in wait_for_bb, status=0x%x\n", status)); + i2c_reset(algo_data); + return -1; + } + while ((time_before(jiffies,timeout)) && (status & MPC5xxx_I2C_BB)) { + udelay(10); status = mpc5xxx_in(®s->msr); } #endif @@ -220,13 +256,17 @@ static int wait_for_pin(struct i2c_algo_mpc5xxx_data *algo_data, *status = mpc5xxx_in(®s->msr); while ((time_before(jiffies,timeout)) && !(*status & MPC5xxx_I2C_IF)) { + udelay(10); *status = mpc5xxx_in(®s->msr); } #endif - if (!(*status & MPC5xxx_I2C_IF)) { - return -1; - } + if (!(*status & MPC5xxx_I2C_IF) || *status & MPC5xxx_I2C_AL) { + DEB(printk(KERN_DEBUG "i2c-algo-mpc5xxx.o: wait_for_pin: status=0x%x\n", + *status)); + i2c_reset(algo_data); + return -1; + } mpc5xxx_out(®s->msr, 0, MPC5xxx_I2C_IF); @@ -247,7 +287,8 @@ static int mpc5xxx_get_fdr(void) ulong ipb = CONFIG_PPC_5xxx_IPBFREQ; #endif ulong bestmatch = 0xffffffffUL; - int best_i = 0, best_j = 0, i, j; + int best_i = 3, best_j = 7; /* values for the slowest bus */ + int i, j; int SCL_Tap[] = { 9, 10, 12, 15, 5, 6, 7, 8}; struct {int scl2tap, tap2tap; } scltap[] = { {4, 1}, @@ -275,7 +316,7 @@ static int mpc5xxx_get_fdr(void) } } - divider = (best_i & 3) | ((best_i & 4) << 3) | (best_j << 2); + divider = (best_i & 3) | ((best_i & 4) << 5) | (best_j << 2); return divider; } @@ -373,12 +414,9 @@ static int mpc5xxx_sendbytes(struct i2c_adapter *adap, for (wrcount = 0; wrcount < count; ++wrcount) { mpc5xxx_out(®s->mdr, buf[wrcount], 0); - if (wait_for_pin(algo_data, &status)) { - i2c_stop(algo_data); - return -EREMOTEIO; - } - - if (status & MPC5xxx_I2C_RXAK) { + if (wait_for_pin(algo_data, &status) || + (status & MPC5xxx_I2C_RXAK) ) { + DEB(printk(KERN_DEBUG "i2c-algo-mpc5xxx.o: error in mpc5xxx_sendbytes, status=0x%x\n", status)); i2c_stop(algo_data); return -EREMOTEIO; } @@ -394,36 +432,33 @@ static int mpc5xxx_readbytes(struct i2c_adapter *adap, struct i2c_algo_mpc5xxx_data *algo_data = adap->algo_data; struct mpc5xxx_i2c *regs = algo_data->regs; int rdcount = 0; - int dummy = 1; int status; - int i; mpc5xxx_out(®s->mcr, 0, MPC5xxx_I2C_TX); - mpc5xxx_out(®s->mcr, 0, MPC5xxx_I2C_TXAK); - - for (i = 0; i < count; ++i) { - buf[rdcount] = mpc5xxx_in(®s->mdr); - - if (dummy) { - dummy = 0; - } else { - rdcount++; - } - if (i == count - 1) - mpc5xxx_out(®s->mcr, MPC5xxx_I2C_TXAK, MPC5xxx_I2C_TXAK); + if(count > 1) { + mpc5xxx_out(®s->mcr, 0, MPC5xxx_I2C_TXAK); + } else { + mpc5xxx_out(®s->mcr, ~0, MPC5xxx_I2C_TXAK); + } + if(count > 0) { + mpc5xxx_in(®s->mdr); + } + + for (rdcount = 0; rdcount < count; ++rdcount) { if (wait_for_pin(algo_data, &status)) { i2c_stop(algo_data); return -EREMOTEIO; } - } - - buf[rdcount++] = mpc5xxx_in(®s->mdr); - if (wait_for_pin(algo_data, &status)) { - i2c_stop(algo_data); - return -EREMOTEIO; + if (rdcount == count - 1) { + mpc5xxx_out(®s->mcr, ~0, MPC5xxx_I2C_TX); + } + else if (rdcount == count - 2) { + mpc5xxx_out(®s->mcr, ~0, MPC5xxx_I2C_TXAK); + } + buf[rdcount] = mpc5xxx_in(®s->mdr); } return rdcount; @@ -464,18 +499,23 @@ static int mpc5xxx_xfer(struct i2c_adapter *adap, for (i = 0; i < num; i++) { pmsg = &msgs[i]; - if (wait_for_bb(algo_data)) + if (wait_for_bb(algo_data)) { + DEB(printk(KERN_DEBUG "i2c-algo-mpc5xxx.o: wait_for_bb failed in mpc5xxx_xfer\n")); + i2c_reset(algo_data); return -EREMOTEIO; + } i2c_start(algo_data); mpc5xxx_do_address(algo_data, pmsg, adap->retries); if (wait_for_pin(algo_data, &status)) { + DEB(printk(KERN_DEBUG "i2c-algo-mpc5xxx.o: wait_for_pin failed in mpc5xxx_xfer, status=0x%x\n", status)); i2c_stop(algo_data); return -EREMOTEIO; } - if (status & MPC5xxx_I2C_RXAK) { + if (status & MPC5xxx_I2C_RXAK) { + DEB2(printk(KERN_DEBUG "i2c-algo-mpc5xxx.o: RXAK set in mpc5xxx_xfer, status=0x%x\n", status)); i2c_stop(algo_data); return -EREMOTEIO; }