i2c: rockchip: support check idle
author黄涛 <huangtao@rock-chips.com>
Mon, 6 Jan 2014 04:45:00 +0000 (12:45 +0800)
committer黄涛 <huangtao@rock-chips.com>
Mon, 6 Jan 2014 04:45:00 +0000 (12:45 +0800)
arch/arm/boot/dts/rk3188-pinctrl.dtsi
arch/arm/boot/dts/rk3188.dtsi
drivers/i2c/busses/i2c-rockchip.c

index 0a0eaf12d6a855e5820afc1ca422e21923554744..4a6819fb7c7aaa13666e740b25de2725542bae20 100755 (executable)
                                rockchip,drive = <VALUE_DRV_DEFAULT>;
                                //rockchip,tristate = <VALUE_TRI_DEFAULT>;
                        };
+
+                       i2c0_gpio: i2c0-gpio {
+                               rockchip,pins = <FUNC_TO_GPIO(I2C0_SDA)>, <FUNC_TO_GPIO(I2C0_SCL)>;
+                               rockchip,drive = <VALUE_DRV_DEFAULT>;
+                       };
                };
 
                gpio1_i2c1 {
                                rockchip,drive = <VALUE_DRV_DEFAULT>;
                                //rockchip,tristate = <VALUE_TRI_DEFAULT>;
                        };
+
+                       i2c1_gpio: i2c1-gpio {
+                               rockchip,pins = <FUNC_TO_GPIO(I2C1_SDA)>, <FUNC_TO_GPIO(I2C1_SCL)>;
+                               rockchip,drive = <VALUE_DRV_DEFAULT>;
+                       };
                };
 
                gpio1_i2c2 {
                                rockchip,drive = <VALUE_DRV_DEFAULT>;
                                //rockchip,tristate = <VALUE_TRI_DEFAULT>;
                        };
+
+                       i2c2_gpio: i2c2-gpio {
+                               rockchip,pins = <FUNC_TO_GPIO(I2C2_SDA)>, <FUNC_TO_GPIO(I2C2_SCL)>;
+                               rockchip,drive = <VALUE_DRV_DEFAULT>;
+                       };
                };
 
                gpio1_i2c3 {
                                rockchip,drive = <VALUE_DRV_DEFAULT>;
                                //rockchip,tristate = <VALUE_TRI_DEFAULT>;
                        };
+
+                       i2c3_gpio: i2c3-gpio {
+                               rockchip,pins = <FUNC_TO_GPIO(I2C3_SDA)>, <FUNC_TO_GPIO(I2C3_SCL)>;
+                               rockchip,drive = <VALUE_DRV_DEFAULT>;
+                       };
                };
 
                gpio1_i2c4 {
                                rockchip,drive = <VALUE_DRV_DEFAULT>;
                                //rockchip,tristate = <VALUE_TRI_DEFAULT>;
                        };
+
+                       i2c4_gpio: i2c4-gpio {
+                               rockchip,pins = <FUNC_TO_GPIO(I2C4_SDA)>, <FUNC_TO_GPIO(I2C4_SCL)>;
+                               rockchip,drive = <VALUE_DRV_DEFAULT>;
+                       };
                };
 
                gpio1_spi0 {
index f2c72a5873b7854a79f44c5d9ac01891ce04d439..e811e255d42115b45c4bb4817d31ec728ffe6d58 100755 (executable)
                interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>;
                #address-cells = <1>;
                #size-cells = <0>;
-               pinctrl-names = "default";
+               pinctrl-names = "default", "gpio";
                pinctrl-0 = <&i2c0_sda &i2c0_scl>;
+               pinctrl-1 = <&i2c0_gpio>;
+               gpios = <&gpio1 GPIO_D0 GPIO_ACTIVE_LOW>, <&gpio1 GPIO_D1 GPIO_ACTIVE_LOW>;
+               clocks = <&clk_gates8 4>;
+               rockchip,check-idle = <1>;
                status = "disabled";
        };
 
                interrupts = <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>;
                #address-cells = <1>;
                #size-cells = <0>;
-               pinctrl-names = "default";
+               pinctrl-names = "default", "gpio";
                pinctrl-0 = <&i2c1_sda &i2c1_scl>;
+               pinctrl-1 = <&i2c1_gpio>;
+               gpios = <&gpio1 GPIO_D2 GPIO_ACTIVE_LOW>, <&gpio1 GPIO_D3 GPIO_ACTIVE_LOW>;
+               clocks = <&clk_gates8 5>;
+               rockchip,check-idle = <1>;
                status = "disabled";
        };
 
                interrupts = <GIC_SPI 42 IRQ_TYPE_LEVEL_HIGH>;
                #address-cells = <1>;
                #size-cells = <0>;
-               pinctrl-names = "default";
+               pinctrl-names = "default", "gpio";
                pinctrl-0 = <&i2c2_sda &i2c2_scl>;
+               pinctrl-1 = <&i2c2_gpio>;
+               gpios = <&gpio1 GPIO_D4 GPIO_ACTIVE_LOW>, <&gpio1 GPIO_D5 GPIO_ACTIVE_LOW>;
+               clocks = <&clk_gates8 6>;
+               rockchip,check-idle = <1>;
                status = "disabled";
        };
 
                interrupts = <GIC_SPI 43 IRQ_TYPE_LEVEL_HIGH>;
                #address-cells = <1>;
                #size-cells = <0>;
-               pinctrl-names = "default";
+               pinctrl-names = "default", "gpio";
                pinctrl-0 = <&i2c3_sda &i2c3_scl>;
+               pinctrl-1 = <&i2c3_gpio>;
+               gpios = <&gpio3 GPIO_B6 GPIO_ACTIVE_LOW>, <&gpio3 GPIO_B7 GPIO_ACTIVE_LOW>;
+               clocks = <&clk_gates8 7>;
+               rockchip,check-idle = <1>;
                status = "disabled";
        };
 
                interrupts = <GIC_SPI 52 IRQ_TYPE_LEVEL_HIGH>;
                #address-cells = <1>;
                #size-cells = <0>;
-               pinctrl-names = "default";
+               pinctrl-names = "default", "gpio";
                pinctrl-0 = <&i2c4_sda &i2c4_scl>;
+               pinctrl-1 = <&i2c4_gpio>;
+               gpios = <&gpio1 GPIO_D6 GPIO_ACTIVE_LOW>, <&gpio1 GPIO_D7 GPIO_ACTIVE_LOW>;
+               clocks = <&clk_gates8 8>;
+               rockchip,check-idle = <1>;
                status = "disabled";
        };
-       
+
        clocks-init{
                compatible = "rockchip,clocks-init";
                rockchip,clocks-init-rate =<&clk_cpll 768000000>,<&clk_gpll 594000000>;
                rockchip,clocks-init-parent =<&aclk_peri_mux &clk_gpll>,<&aclk_cpu &clk_gpll>;
        };
-       
 };
-
-
-
index aceeb67dc4ff940ce17cfb5599d48383342a333c..3dd6e02f758aa0fcc3ecbb05c1739926a5b1b6aa 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012, 2013 ROCKCHIP, Inc.
+ * Copyright (C) 2012-2014 ROCKCHIP, Inc.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -18,6 +18,7 @@
 #include <linux/module.h>
 #include <linux/wakelock.h>
 #include <linux/i2c.h>
+#include <linux/of_gpio.h>
 #include <linux/of_i2c.h>
 #include <linux/init.h>
 #include <linux/time.h>
@@ -41,8 +42,6 @@
 #define i2c_dbg(dev, format, arg...)
 #endif
 
-//#define I2C_CHECK_IDLE
-
 enum {
        I2C_IDLE = 0,
        I2C_SDA_LOW,
@@ -107,9 +106,9 @@ struct rockchip_i2c {
        unsigned int            mode;
        unsigned int            count;
 
-       int                     sda_mode, scl_mode;
-
-       struct wake_lock        idlelock[5];
+       unsigned int            check_idle;
+       int                     sda_gpio, scl_gpio;
+       struct pinctrl_state    *gpio_state;
 };
 
 #define COMPLETE_READ      (1<<STATE_START | 1<<STATE_READ  | 1<<STATE_STOP)
@@ -210,38 +209,21 @@ static void rockchip_show_regs(struct rockchip_i2c *i2c)
                dev_info(i2c->dev, "I2C_RXDATA%d: 0x%08x\n", i, i2c_readl(i2c->regs + I2C_RXDATA_BASE + i * 4));
 }
 
-#ifdef I2C_CHECK_IDLE
 static int rockchip_i2c_check_idle(struct rockchip_i2c *i2c)
 {
-       int ret = 0;
-       int sda_io, scl_io;
+       int ret = I2C_IDLE;
        int sda_lev, scl_lev;
 
-       sda_io = iomux_mode_to_gpio(i2c->sda_mode);
-       scl_io = iomux_mode_to_gpio(i2c->scl_mode);
-
-       ret = gpio_request(sda_io, NULL);
-       if (unlikely(ret < 0)) {
-               dev_err(i2c->dev, "Failed to request gpio: SDA_GPIO\n");
-               return ret;
-       }
-       ret = gpio_request(scl_io, NULL);
-       if (unlikely(ret < 0)) {
-               dev_err(i2c->dev, "Failed to request gpio: SCL_GPIO\n");
-               gpio_free(sda_io);
+       if (!gpio_is_valid(i2c->sda_gpio))
                return ret;
-       }
-       gpio_direction_input(sda_io);
-       gpio_direction_input(scl_io);
 
-       sda_lev = gpio_get_value(sda_io);
-       scl_lev = gpio_get_value(scl_io);
+       if (pinctrl_select_state(i2c->dev->pins->p, i2c->gpio_state))
+               return ret;
 
-       gpio_free(sda_io);
-       gpio_free(scl_io);
+       sda_lev = gpio_get_value(i2c->sda_gpio);
+       scl_lev = gpio_get_value(i2c->scl_gpio);
 
-       iomux_set(i2c->sda_mode);
-       iomux_set(i2c->scl_mode);
+       pinctrl_select_state(i2c->dev->pins->p, i2c->dev->pins->default_state);
 
        if (sda_lev == 1 && scl_lev == 1)
                return I2C_IDLE;
@@ -252,7 +234,6 @@ static int rockchip_i2c_check_idle(struct rockchip_i2c *i2c)
        else
                return BOTH_LOW;
 }
-#endif
 
 static inline void rockchip_i2c_enable(struct rockchip_i2c *i2c, unsigned int lastnak)
 {
@@ -338,9 +319,6 @@ static void rockchip_i2c_set_clk(struct rockchip_i2c *i2c, unsigned long scl_rat
        unsigned long i2c_rate = clk_get_rate(i2c->clk);
        int div, divl, divh;
 
-       if (!i2c_rate)
-               i2c_rate = 9375000;
-
        if ((scl_rate == i2c->scl_rate) && (i2c_rate == i2c->i2c_rate))
                return;
        i2c->i2c_rate = i2c_rate;
@@ -354,15 +332,14 @@ static void rockchip_i2c_set_clk(struct rockchip_i2c *i2c, unsigned long scl_rat
        }
        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));
-       dev_info(i2c->dev, "set clk(I2C_CLKDIV: 0x%08x)\n", i2c_readl(i2c->regs + I2C_CLKDIV));
 }
 
 static void rockchip_i2c_init_hw(struct rockchip_i2c *i2c, unsigned long scl_rate)
 {
        i2c->scl_rate = 0;
-       clk_enable(i2c->clk);
+       clk_prepare_enable(i2c->clk);
        rockchip_i2c_set_clk(i2c, scl_rate);
-       clk_disable(i2c->clk);
+       clk_disable_unprepare(i2c->clk);
 }
 
 /* returns TRUE if we this is the last byte in the current message */
@@ -742,27 +719,27 @@ static int rockchip_i2c_doxfer(struct rockchip_i2c *i2c,
 static int rockchip_i2c_xfer(struct i2c_adapter *adap,
                        struct i2c_msg *msgs, int num)
 {
-#ifdef I2C_CHECK_IDLE
-       int state, retry = 10;
-#endif
        int ret;
        struct rockchip_i2c *i2c = i2c_get_adapdata(adap);
        unsigned long scl_rate = i2c->scl_rate;
 
-       clk_enable(i2c->clk);
-#ifdef I2C_CHECK_IDLE
-       int state, retry = 10;
-       while (retry-- && ((state = rockchip_i2c_check_idle(i2c)) != I2C_IDLE)) {
-               if (in_atomic())
-                       mdelay(10);
-               else
-                       msleep(10);
-       }
-       if (retry == 0) {
-               dev_err(i2c->dev, "i2c is not in idle(state = %d)\n", state);
-               return -EIO;
+       clk_prepare_enable(i2c->clk);
+       if (i2c->check_idle) {
+               int state, retry = 10;
+               while (retry--) {
+                       state = rockchip_i2c_check_idle(i2c);
+                       if (state == I2C_IDLE)
+                               break;
+                       if (in_atomic())
+                               mdelay(10);
+                       else
+                               msleep(10);
+               }
+               if (retry == 0) {
+                       dev_err(i2c->dev, "i2c is not in idle(state = %d)\n", state);
+                       return -EIO;
+               }
        }
-#endif
 
 #ifdef CONFIG_I2C_ROCKCHIP_COMPAT
        if (msgs[0].scl_rate <= 400000 && msgs[0].scl_rate >= 10000)
@@ -784,7 +761,7 @@ static int rockchip_i2c_xfer(struct i2c_adapter *adap,
        ret = rockchip_i2c_doxfer(i2c, msgs, num);
        i2c_dbg(i2c->dev, "i2c transfer stop: addr: 0x%04x, state: %d, ret: %d\n", msgs[0].addr, ret, i2c->state);
 
-       clk_disable(i2c->clk);
+       clk_disable_unprepare(i2c->clk);
        return (ret < 0) ? ret : num;
 }
 
@@ -801,8 +778,6 @@ static const struct i2c_algorithm rockchip_i2c_algorithm = {
        .functionality          = rockchip_i2c_func,
 };
 
-static int i2c_max_adap;
-
 /* rockchip_i2c_probe
  *
  * called by the bus driver when a suitable device is found
@@ -849,6 +824,39 @@ static int rockchip_i2c_probe(struct platform_device *pdev)
        i2c_dbg(&pdev->dev, "registers %p (%p, %p)\n",
                i2c->regs, i2c->ioarea, res);
 
+       i2c->check_idle = true;
+       of_property_read_u32(np, "rockchip,check-idle", &i2c->check_idle);
+       if (i2c->check_idle) {
+               i2c->sda_gpio = of_get_gpio(np, 0);
+               if (!gpio_is_valid(i2c->sda_gpio)) {
+                       dev_err(&pdev->dev, "sda gpio is invalid\n");
+                       return -EINVAL;
+               }
+               ret = devm_gpio_request(&pdev->dev, i2c->sda_gpio, dev_name(&i2c->adap.dev));
+               if (ret) {
+                       dev_err(&pdev->dev, "failed to request sda gpio\n");
+                       return ret;
+               }
+               i2c->scl_gpio = of_get_gpio(np, 1);
+               if (!gpio_is_valid(i2c->scl_gpio)) {
+                       dev_err(&pdev->dev, "scl gpio is invalid\n");
+                       return -EINVAL;
+               }
+               ret = devm_gpio_request(&pdev->dev, i2c->scl_gpio, dev_name(&i2c->adap.dev));
+               if (ret) {
+                       dev_err(&pdev->dev, "failed to request scl gpio\n");
+                       return ret;
+               }
+               i2c->gpio_state = pinctrl_lookup_state(i2c->dev->pins->p, "gpio");
+               if (IS_ERR(i2c->gpio_state)) {
+                       dev_err(&pdev->dev, "no gpio pinctrl state\n");
+                       return PTR_ERR(i2c->gpio_state);
+               }
+               gpio_direction_input(i2c->sda_gpio);
+               gpio_direction_input(i2c->scl_gpio);
+               pinctrl_select_state(i2c->dev->pins->p, i2c->dev->pins->default_state);
+       }
+
        /* setup info block for the i2c core */
        ret = i2c_add_adapter(&i2c->adap);
        if (ret < 0) {
@@ -856,6 +864,17 @@ static int rockchip_i2c_probe(struct platform_device *pdev)
                return ret;
        }
 
+       platform_set_drvdata(pdev, i2c);
+
+       /* find the clock and enable it */
+       i2c->clk = devm_clk_get(&pdev->dev, NULL);
+       if (IS_ERR(i2c->clk)) {
+               dev_err(&pdev->dev, "cannot get clock\n");
+               return PTR_ERR(i2c->clk);
+       }
+
+       i2c_dbg(&pdev->dev, "clock source %p\n", i2c->clk);
+
        /* find the IRQ for this unit (note, this relies on the init call to
         * ensure no current IRQs pending
         */
@@ -872,20 +891,8 @@ static int rockchip_i2c_probe(struct platform_device *pdev)
                return ret;
        }
 
-       /* find the clock and enable it */
-       i2c->clk = clk_get(&pdev->dev, "i2c");
-       if (IS_ERR(i2c->clk)) {
-               dev_err(&pdev->dev, "cannot get clock\n");
-               i2c->clk = NULL;
-//             return PTR_ERR(i2c->clk);
-       }
-
-       i2c_dbg(&pdev->dev, "clock source %p\n", i2c->clk);
-
-       platform_set_drvdata(pdev, i2c);
-
+       clk_prepare_enable(i2c->clk); // FIXME: enable i2c clock temporarily
        rockchip_i2c_init_hw(i2c, 100 * 1000);
-       i2c_max_adap++;
        dev_info(&pdev->dev, "%s: Rockchip I2C adapter\n", dev_name(&i2c->adap.dev));
 
        of_i2c_register_devices(&i2c->adap);
@@ -903,7 +910,6 @@ static int rockchip_i2c_remove(struct platform_device *pdev)
        struct rockchip_i2c *i2c = platform_get_drvdata(pdev);
 
        i2c_del_adapter(&i2c->adap);
-       clk_put(i2c->clk);
 
        return 0;
 }
@@ -915,6 +921,7 @@ static int rockchip_i2c_suspend_noirq(struct device *dev)
        struct rockchip_i2c *i2c = platform_get_drvdata(pdev);
 
        i2c->suspended = 1;
+       pinctrl_pm_select_sleep_state(dev);
 
        return 0;
 }
@@ -924,8 +931,9 @@ static int rockchip_i2c_resume_noirq(struct device *dev)
        struct platform_device *pdev = to_platform_device(dev);
        struct rockchip_i2c *i2c = platform_get_drvdata(pdev);
 
-       i2c->suspended = 0;
+       pinctrl_pm_select_default_state(dev);
        rockchip_i2c_init_hw(i2c, i2c->scl_rate);
+       i2c->suspended = 0;
 
        return 0;
 }