mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-09 12:17:12 +09:00
i2c: rockchip: support check idle
This commit is contained in:
@@ -199,6 +199,11 @@
|
||||
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 {
|
||||
@@ -217,6 +222,11 @@
|
||||
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 {
|
||||
@@ -235,6 +245,11 @@
|
||||
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 {
|
||||
@@ -253,6 +268,11 @@
|
||||
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 {
|
||||
@@ -271,6 +291,11 @@
|
||||
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 {
|
||||
|
||||
@@ -247,8 +247,12 @@
|
||||
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";
|
||||
};
|
||||
|
||||
@@ -258,8 +262,12 @@
|
||||
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";
|
||||
};
|
||||
|
||||
@@ -269,8 +277,12 @@
|
||||
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";
|
||||
};
|
||||
|
||||
@@ -280,8 +292,12 @@
|
||||
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";
|
||||
};
|
||||
|
||||
@@ -291,18 +307,18 @@
|
||||
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>;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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");
|
||||
if (!gpio_is_valid(i2c->sda_gpio))
|
||||
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 (pinctrl_select_state(i2c->dev->pins->p, i2c->gpio_state))
|
||||
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);
|
||||
sda_lev = gpio_get_value(i2c->sda_gpio);
|
||||
scl_lev = gpio_get_value(i2c->scl_gpio);
|
||||
|
||||
gpio_free(sda_io);
|
||||
gpio_free(scl_io);
|
||||
|
||||
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);
|
||||
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;
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user