update i2c add i2c poll mode
authorlhh <lhh@rock-chips.com>
Tue, 13 Jul 2010 07:04:12 +0000 (15:04 +0800)
committerlhh <lhh@rock-chips.com>
Tue, 13 Jul 2010 07:04:12 +0000 (15:04 +0800)
arch/arm/mach-rk2818/board-midsdk.c
arch/arm/mach-rk2818/include/mach/board.h
drivers/i2c/busses/i2c-rk2818.c

index af1554f20631660848251f681b00f855add5462b..aad050d66561e4418ddce4d25110b8611bd211be 100644 (file)
@@ -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,
 };
 
index 961df8660295393fc660e2e0e140e238c7705894..0de9068242b5d91940bf8e944c26b7bf9686a6d2 100644 (file)
@@ -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);
 };
 
index f7f3f65e92821f4d897a4d9d71cfc215d480d20e..29a7f7c896a43b9d2eeb70e8751a0d60ff8ba3b8 100755 (executable)
@@ -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<<I2CCDVR_EXP_BITS;   
        writel(tmp, i2c->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);