From 9ca853a25d0776ebb64f2178e899bb33f75c7ce7 Mon Sep 17 00:00:00 2001 From: kfx Date: Fri, 28 Jun 2013 10:38:35 +0800 Subject: [PATCH] i2c: 'fixed bug: set scl clk' and 'warning if scl is hold by slave' --- drivers/i2c/busses/i2c-rk30-adapter.c | 31 +++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) mode change 100755 => 100644 drivers/i2c/busses/i2c-rk30-adapter.c diff --git a/drivers/i2c/busses/i2c-rk30-adapter.c b/drivers/i2c/busses/i2c-rk30-adapter.c old mode 100755 new mode 100644 index 21503f5c172f..44b2f3eca852 --- a/drivers/i2c/busses/i2c-rk30-adapter.c +++ b/drivers/i2c/busses/i2c-rk30-adapter.c @@ -76,6 +76,8 @@ enum{ #define I2C_STARTIPD (1 << 4) #define I2C_STOPIPD (1 << 5) #define I2C_NAKRCVIPD (1 << 6) + +#define I2C_HOLD_SCL (1 << 7) #define I2C_IPD_ALL_CLEAN 0x7f /* finished count */ @@ -209,22 +211,36 @@ static inline void rk30_i2c_enable_irq(struct rk30_i2c *i2c) { i2c_writel(IRQ_MST_ENABLE, i2c->regs + I2C_IEN); } - -/* SCL Divisor = 8 * (CLKDIVL + CLKDIVH) +static void rk30_get_div(int div, int *divh, int *divl) +{ + if(div % 2 == 0){ + *divh = div/2; + *divl = div/2; + }else{ + *divh = rk30_ceil(div, 2); + *divl = div/2; + } +} +/* SCL Divisor = 8 * (CLKDIVL+1 + CLKDIVH+1) * SCL = i2c_rate/ SCLK Divisor */ static void rk30_i2c_set_clk(struct rk30_i2c *i2c, unsigned long scl_rate) { unsigned long i2c_rate = clk_get_rate(i2c->clk); - unsigned int div, divl, divh; + int div, divl, divh; if((scl_rate == i2c->scl_rate) && (i2c_rate == i2c->i2c_rate)) return; i2c->i2c_rate = i2c_rate; i2c->scl_rate = scl_rate; - div = rk30_ceil(i2c_rate, scl_rate * 8); - divh = divl = rk30_ceil(div, 2); + div = rk30_ceil(i2c_rate, (scl_rate * 8)) - 2; + if(unlikely(div < 0)){ + dev_warn(i2c->dev, "Divisor(%d) is negative, set divl = divh = 0\n", div); + divh =divl = 0; + }else{ + rk30_get_div(div, &divh, &divl); + } i2c_writel(I2C_CLKDIV_VAL(divl, divh), i2c->regs + I2C_CLKDIV); i2c_dbg(i2c->dev, "set clk(I2C_CLKDIV: 0x%08x)\n", i2c_readl(i2c->regs + I2C_CLKDIV)); return; @@ -572,11 +588,14 @@ static int rk30_i2c_doxfer(struct rk30_i2c *i2c, spin_unlock_irqrestore(&i2c->lock, flags); if (timeout == 0){ + unsigned int ipd = i2c_readl(i2c->regs + I2C_IPD); if(error < 0) i2c_dbg(i2c->dev, "error = %d\n", error); else if((i2c->complete_what !=COMPLETE_READ && i2c->complete_what != COMPLETE_WRITE)){ + if(ipd & I2C_HOLD_SCL) + dev_err(i2c->dev, "SCL was hold by slave\n"); dev_err(i2c->dev, "Addr[0x%04x] wait event timeout, state: %d, is_busy: %d, error: %d, complete_what: 0x%x, ipd: 0x%x\n", - msgs[0].addr, i2c->state, i2c->is_busy, error, i2c->complete_what, i2c_readl(i2c->regs + I2C_IPD)); + msgs[0].addr, i2c->state, i2c->is_busy, error, i2c->complete_what, ipd); //rk30_show_regs(i2c); error = -ETIMEDOUT; if(in_atomic()) -- 2.34.1