From 383f9ddb1da6be30f24a69415d6c4c296a3b4fa6 Mon Sep 17 00:00:00 2001 From: lhh Date: Tue, 13 Jul 2010 15:04:12 +0800 Subject: [PATCH] update i2c add i2c poll mode --- arch/arm/mach-rk2818/board-midsdk.c | 2 + arch/arm/mach-rk2818/include/mach/board.h | 3 + drivers/i2c/busses/i2c-rk2818.c | 124 +++++++++++++--------- 3 files changed, 81 insertions(+), 48 deletions(-) diff --git a/arch/arm/mach-rk2818/board-midsdk.c b/arch/arm/mach-rk2818/board-midsdk.c index af1554f20631..aad050d66561 100644 --- a/arch/arm/mach-rk2818/board-midsdk.c +++ b/arch/arm/mach-rk2818/board-midsdk.c @@ -271,6 +271,7 @@ struct rk2818_i2c_platform_data default_i2c0_data = { .flags = 0, .slave_addr = 0xff, .scl_rate = 400*1000, + .mode = I2C_MODE_IRQ, //I2C_MODE_POLL .cfg_gpio = rk2818_i2c0_cfg_gpio, }; struct rk2818_i2c_platform_data default_i2c1_data = { @@ -282,6 +283,7 @@ struct rk2818_i2c_platform_data default_i2c1_data = { .flags = 0, .slave_addr = 0xff, .scl_rate = 400*1000, + .mode = I2C_MODE_IRQ, //I2C_MODE_POLL .cfg_gpio = rk2818_i2c1_cfg_gpio, }; diff --git a/arch/arm/mach-rk2818/include/mach/board.h b/arch/arm/mach-rk2818/include/mach/board.h index 961df8660295..0de9068242b5 100644 --- a/arch/arm/mach-rk2818/include/mach/board.h +++ b/arch/arm/mach-rk2818/include/mach/board.h @@ -37,6 +37,9 @@ struct rk2818_i2c_platform_data { unsigned int flags; unsigned int slave_addr; unsigned long scl_rate; +#define I2C_MODE_IRQ 0 +#define I2C_MODE_POLL 1 + unsigned int mode:1; void (*cfg_gpio)(struct platform_device *dev); }; diff --git a/drivers/i2c/busses/i2c-rk2818.c b/drivers/i2c/busses/i2c-rk2818.c index f7f3f65e9282..29a7f7c896a4 100755 --- a/drivers/i2c/busses/i2c-rk2818.c +++ b/drivers/i2c/busses/i2c-rk2818.c @@ -63,6 +63,8 @@ struct rk2818_i2c_data { unsigned long scl_rate; struct clk *clk; + unsigned int mode; + unsigned int irq; spinlock_t cmd_lock; @@ -95,30 +97,29 @@ static inline void rk2818_i2c_enable_irqs(struct rk2818_i2c_data *i2c) } /* scl = pclk/(5 *(rem+1) * 2^(exp+1)) */ -static unsigned long rk2818_i2c_calcdivisor(unsigned long pclk, +static void rk2818_i2c_calcdivisor(unsigned long pclk, unsigned long scl_rate, unsigned long *real_rate, unsigned int *rem, unsigned int *exp) { - unsigned int calc_rem = pclk / (5 * scl_rate); - unsigned int calc_exp; + unsigned int calc_rem = 0; + unsigned int calc_exp = 0; for(calc_exp = 0; calc_exp < I2CCDVR_EXP_MAX; calc_exp++) { + calc_rem = pclk / (5 * scl_rate * (1 <<(calc_exp +1))); if(calc_rem < I2CCDVR_REM_MAX) - { - calc_exp--; break; - } - calc_rem = calc_rem >> 1; } - if(calc_rem >= I2CCDVR_REM_MAX) - return -1; + if(calc_rem >= I2CCDVR_REM_MAX || calc_exp >= I2CCDVR_EXP_MAX) + { + calc_rem = I2CCDVR_REM_MAX - 1; + calc_exp = I2CCDVR_EXP_MAX - 1; + } *rem = calc_rem; *exp = calc_exp; - *real_rate = pclk/(5 * (calc_rem + 1) * (1 <<(calc_exp +1))); - return 0; + return; } /* set i2c bus scl rate */ static unsigned long rk2818_i2c_clockrate(struct rk2818_i2c_data *i2c) @@ -126,45 +127,37 @@ static unsigned long rk2818_i2c_clockrate(struct rk2818_i2c_data *i2c) struct rk2818_i2c_platform_data *pdata = i2c->dev->platform_data; unsigned int rem = 0, exp = 0; unsigned long scl_rate, real_rate = 0, tmp, pclk; - int ret = 0; struct clk *arm_pclk; arm_pclk = clk_get_parent(i2c->clk); if(IS_ERR(arm_pclk)) { dev_err(i2c->dev, "cannot get pclk\n"); - ret = -ENOENT; + return -ENOENT; } pclk = clk_get_rate(arm_pclk); - dev_dbg(i2c->dev, "pdata desired clkrate %lu\n", pdata->scl_rate); + scl_rate = (i2c->scl_rate) ? i2c->scl_rate : ((pdata->scl_rate)? pdata->scl_rate:100000); - scl_rate = pdata->scl_rate ? pdata->scl_rate : 100000; - - ret = rk2818_i2c_calcdivisor(pclk, scl_rate, &real_rate, &rem, &exp); - - if (ret < 0) - { - dev_err(i2c->dev, - "Unable to achieve desired clkrate %luHz.", scl_rate); - return -EINVAL; - } - + rk2818_i2c_calcdivisor(pclk, scl_rate, &real_rate, &rem, &exp); tmp = readl(i2c->regs + I2C_OPR); tmp |= exp; tmp |= rem<regs + I2C_OPR); - dev_dbg(i2c->dev, " Scl real rate is %lu\n", real_rate); - - return ret; + if(real_rate > 400000) + dev_info(i2c->dev, "WARN: PCLK %luKhz, I2C set rate %luKhz, and real rate is %luKhz > 400Khz\n", + pclk/1000, scl_rate/1000, real_rate/1000); + else + dev_dbg(i2c->dev, " OK: PCLK %luKhz, I2C set rate %luKhz, real rate is %luKhz\n", + pclk/1000, scl_rate/1000, real_rate/1000); + return 0; } static int rk2818_event_occurred(struct rk2818_i2c_data *i2c) { - unsigned long isr, lsr; + unsigned long isr; isr = readl(i2c->regs + I2C_ISR); - lsr = readl(i2c->regs + I2C_LSR); if(isr & I2C_ISR_ARBITR_LOSE) { isr &= ~I2C_ISR_ARBITR_LOSE; @@ -195,7 +188,6 @@ static int rk2818_event_occurred(struct rk2818_i2c_data *i2c) break; } i2c->cmd_err = RK2818_ERROR_UNKNOWN; - dev_err(i2c->dev,"Unhandled interrupt!\n"); return 0; } @@ -203,20 +195,38 @@ static irqreturn_t rk2818_i2c_irq(int irq, void *data) { struct rk2818_i2c_data *i2c = (struct rk2818_i2c_data *)data; int res; + rk2818_i2c_disable_irqs(i2c); spin_lock(&i2c->cmd_lock); res = rk2818_event_occurred(i2c); if(res || i2c->cmd_err != RK2818_ERROR_NONE) complete(&i2c->cmd_complete); spin_unlock(&i2c->cmd_lock); - return IRQ_HANDLED; } +static int wait_for_completion_poll_timeout(struct rk2818_i2c_data *i2c) +{ + unsigned long timeout = jiffies + RK2818_I2C_TIMEOUT; + unsigned int time = 10; + int res; + while(!time_after(jiffies, timeout)) + { + dev_dbg(i2c->dev, "%s: time = %d\n", __func__, time); + res = rk2818_event_occurred(i2c); + if(res || i2c->cmd_err != RK2818_ERROR_NONE) + return 1; + udelay(time); + time *= 2; + } + return 0; + +} static int rk2818_wait_event(struct rk2818_i2c_data *i2c, enum rk2818_event mr_event) { int ret = 0; + if(unlikely(irqs_disabled())) { dev_err(i2c->dev, "irqs are disabled on this system!\n"); @@ -231,9 +241,16 @@ static int rk2818_wait_event(struct rk2818_i2c_data *i2c, spin_unlock_irq(&i2c->cmd_lock); rk2818_i2c_enable_irqs(i2c); - ret = wait_for_completion_interruptible_timeout(&i2c->cmd_complete, + if(i2c->mode == I2C_MODE_IRQ) + { + ret = wait_for_completion_interruptible_timeout(&i2c->cmd_complete, RK2818_I2C_TIMEOUT); - + } + else + { + ret = wait_for_completion_poll_timeout(i2c); + dev_dbg(i2c->dev, "%s: ret = %d\n", __func__, ret); + } if(ret < 0) { dev_err(i2c->dev, "wait_for_completion_interruptible_timeout(): " @@ -349,9 +366,6 @@ static int rk2818_xfer_msg(struct i2c_adapter *adap, } clk_enable(i2c->clk); - if(msg->scl_rate) - i2c->scl_rate = msg->scl_rate; - rk2818_i2c_clockrate(i2c); ret = rk2818_send_address(i2c, msg); if(ret != 0) @@ -445,7 +459,16 @@ static int rk2818_i2c_xfer(struct i2c_adapter *adap, if(i2c->suspended ==1) return -EIO; - i2c->scl_rate = msgs[0].scl_rate; + if(msgs[0].scl_rate <= 400000 && msgs[0].scl_rate > 0) + { + i2c->scl_rate = msgs[0].scl_rate; + } + else + { + dev_info(i2c->dev, "Scl_rate(%uKhz) is failed to change[0 -- 400Khz], current rate(%luKhz)\n", + msgs[0].scl_rate/1000, i2c->scl_rate/1000); + } + ret = rk2818_i2c_init_hw(i2c); if(ret < 0) return ret; @@ -578,6 +601,8 @@ static int rk2818_i2c_probe(struct platform_device *pdev) dev_err(&pdev->dev, "no memory for state\n"); return -ENOMEM; } + i2c->mode = pdata->mode; + i2c->scl_rate = (pdata->scl_rate) ? pdata->scl_rate : 100000; strlcpy(i2c->adap.name, DRV_NAME, sizeof(i2c->adap.name)); i2c->adap.owner = THIS_MODULE; @@ -640,15 +665,16 @@ static int rk2818_i2c_probe(struct platform_device *pdev) dev_err(&pdev->dev, "cannot find IRQ\n"); goto err_iomap; } + if(i2c->mode == I2C_MODE_IRQ) + { + ret = request_irq(i2c->irq, rk2818_i2c_irq, IRQF_DISABLED, + dev_name(&pdev->dev), i2c); - ret = request_irq(i2c->irq, rk2818_i2c_irq, IRQF_DISABLED, - dev_name(&pdev->dev), i2c); - - if (ret != 0) { - dev_err(&pdev->dev, "cannot claim IRQ %d\n", i2c->irq); - goto err_iomap; + if (ret != 0) { + dev_err(&pdev->dev, "cannot claim IRQ %d\n", i2c->irq); + goto err_iomap; + } } - ret = rk2818_i2c_register_cpufreq(i2c); if (ret < 0) { dev_err(&pdev->dev, "failed to register cpufreq notifier\n"); @@ -664,14 +690,15 @@ static int rk2818_i2c_probe(struct platform_device *pdev) platform_set_drvdata(pdev, i2c); - dev_dbg(&pdev->dev, "%s: RK2818 I2C adapter\n", dev_name(&i2c->adap.dev)); + dev_info(&pdev->dev, "%s: RK2818 I2C adapter\n", dev_name(&i2c->adap.dev)); return 0; err_cpufreq: rk2818_i2c_unregister_cpufreq(i2c); err_irq: - free_irq(i2c->irq, i2c); + if(i2c->mode == I2C_MODE_IRQ) + free_irq(i2c->irq, i2c); err_iomap: iounmap(i2c->regs); @@ -697,7 +724,8 @@ static int rk2818_i2c_remove(struct platform_device *pdev) rk2818_i2c_unregister_cpufreq(i2c); i2c_del_adapter(&i2c->adap); - free_irq(i2c->irq, i2c); + if(i2c->mode == I2C_MODE_IRQ) + free_irq(i2c->irq, i2c); clk_disable(i2c->clk); clk_put(i2c->clk); -- 2.34.1