From: 黄涛 Date: Mon, 6 Jan 2014 04:45:00 +0000 (+0800) Subject: i2c: rockchip: support check idle X-Git-Tag: firefly_0821_release~6417 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=e32d0895ccf215831b5d6ea9ab298e92bd522599;p=firefly-linux-kernel-4.4.55.git i2c: rockchip: support check idle --- diff --git a/arch/arm/boot/dts/rk3188-pinctrl.dtsi b/arch/arm/boot/dts/rk3188-pinctrl.dtsi index 0a0eaf12d6a8..4a6819fb7c7a 100755 --- a/arch/arm/boot/dts/rk3188-pinctrl.dtsi +++ b/arch/arm/boot/dts/rk3188-pinctrl.dtsi @@ -199,6 +199,11 @@ rockchip,drive = ; //rockchip,tristate = ; }; + + i2c0_gpio: i2c0-gpio { + rockchip,pins = , ; + rockchip,drive = ; + }; }; gpio1_i2c1 { @@ -217,6 +222,11 @@ rockchip,drive = ; //rockchip,tristate = ; }; + + i2c1_gpio: i2c1-gpio { + rockchip,pins = , ; + rockchip,drive = ; + }; }; gpio1_i2c2 { @@ -235,6 +245,11 @@ rockchip,drive = ; //rockchip,tristate = ; }; + + i2c2_gpio: i2c2-gpio { + rockchip,pins = , ; + rockchip,drive = ; + }; }; gpio1_i2c3 { @@ -253,6 +268,11 @@ rockchip,drive = ; //rockchip,tristate = ; }; + + i2c3_gpio: i2c3-gpio { + rockchip,pins = , ; + rockchip,drive = ; + }; }; gpio1_i2c4 { @@ -271,6 +291,11 @@ rockchip,drive = ; //rockchip,tristate = ; }; + + i2c4_gpio: i2c4-gpio { + rockchip,pins = , ; + rockchip,drive = ; + }; }; gpio1_spi0 { diff --git a/arch/arm/boot/dts/rk3188.dtsi b/arch/arm/boot/dts/rk3188.dtsi index f2c72a5873b7..e811e255d421 100755 --- a/arch/arm/boot/dts/rk3188.dtsi +++ b/arch/arm/boot/dts/rk3188.dtsi @@ -247,8 +247,12 @@ interrupts = ; #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"; }; @@ -258,8 +262,12 @@ interrupts = ; #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"; }; @@ -269,8 +277,12 @@ interrupts = ; #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"; }; @@ -280,8 +292,12 @@ interrupts = ; #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"; }; @@ -291,18 +307,18 @@ interrupts = ; #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>; }; - }; - - - diff --git a/drivers/i2c/busses/i2c-rockchip.c b/drivers/i2c/busses/i2c-rockchip.c index aceeb67dc4ff..3dd6e02f758a 100644 --- a/drivers/i2c/busses/i2c-rockchip.c +++ b/drivers/i2c/busses/i2c-rockchip.c @@ -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 #include #include +#include #include #include #include @@ -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<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; }