summaryrefslogtreecommitdiff
path: root/drivers/i2c
diff options
context:
space:
mode:
authorLaxman Dewangan <ldewangan@nvidia.com>2012-02-18 21:37:47 +0530
committerSimone Willett <swillett@nvidia.com>2012-02-22 10:14:49 -0800
commiteecc9e8b5739e7d148eed9b75623b513024cd3ff (patch)
tree39b06e932413a11d45896a6adc4aad3e6ad4f7d9 /drivers/i2c
parent01510d204c65269918bcef8656e1b94e130a532c (diff)
i2c: tegra: clock control for fast clock
I2c controller requires the clock for fast clock as a second clock source. This clock should be on during normal function of i2c controller. Making sure that i2c driver get this clock and hold the clock enable during data transfer. bug 933653 Change-Id: I676eee1f8a0e1dff81b17259abcd9644bcb0b394 Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com> Reviewed-on: http://git-master/r/78996 Reviewed-by: Aleksandr Frid <afrid@nvidia.com>
Diffstat (limited to 'drivers/i2c')
-rw-r--r--drivers/i2c/busses/i2c-tegra.c77
1 files changed, 57 insertions, 20 deletions
diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
index e23d431b7907..101ec4787396 100644
--- a/drivers/i2c/busses/i2c-tegra.c
+++ b/drivers/i2c/busses/i2c-tegra.c
@@ -147,7 +147,8 @@ struct tegra_i2c_bus {
*/
struct tegra_i2c_dev {
struct device *dev;
- struct clk *clk;
+ struct clk *div_clk;
+ struct clk *fast_clk;
struct resource *iomem;
struct rt_mutex dev_lock;
spinlock_t clk_lock;
@@ -393,21 +394,45 @@ static void tegra_i2c_slave_init(struct tegra_i2c_dev *i2c_dev)
}
}
+static inline int tegra_i2c_clock_enable(struct tegra_i2c_dev *i2c_dev)
+{
+ int ret;
+ ret = clk_enable(i2c_dev->fast_clk);
+ if (ret < 0) {
+ dev_err(i2c_dev->dev,
+ "Error in enabling fast clock err %d\n", ret);
+ return ret;
+ }
+ ret = clk_enable(i2c_dev->div_clk);
+ if (ret < 0) {
+ dev_err(i2c_dev->dev,
+ "Error in enabling div clock err %d\n", ret);
+ clk_disable(i2c_dev->fast_clk);
+ }
+ return ret;
+}
+
+static inline void tegra_i2c_clock_disable(struct tegra_i2c_dev *i2c_dev)
+{
+ clk_disable(i2c_dev->div_clk);
+ clk_disable(i2c_dev->fast_clk);
+}
+
static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev)
{
u32 val;
int err = 0;
if (!i2c_dev->is_clkon_always)
- clk_enable(i2c_dev->clk);
+ tegra_i2c_clock_enable(i2c_dev);
/* Interrupt generated before sending stop signal so
* wait for some time so that stop signal can be send proerly */
udelay(100);
- tegra_periph_reset_assert(i2c_dev->clk);
+ tegra_periph_reset_assert(i2c_dev->div_clk);
udelay(2);
- tegra_periph_reset_deassert(i2c_dev->clk);
+ tegra_periph_reset_deassert(i2c_dev->div_clk);
if (i2c_dev->is_dvc)
tegra_dvc_init(i2c_dev);
@@ -416,7 +441,7 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev)
(0x2 << I2C_CNFG_DEBOUNCE_CNT_SHIFT);
i2c_writel(i2c_dev, val, I2C_CNFG);
i2c_writel(i2c_dev, 0, I2C_INT_MASK);
- clk_set_rate(i2c_dev->clk, i2c_dev->last_bus_clk_rate * 8);
+ clk_set_rate(i2c_dev->div_clk, i2c_dev->last_bus_clk_rate * 8);
i2c_writel(i2c_dev, 0x3, I2C_CLK_DIVISOR);
if (!i2c_dev->is_dvc) {
@@ -439,7 +464,7 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev)
err = -ETIMEDOUT;
if (!i2c_dev->is_clkon_always)
- clk_disable(i2c_dev->clk);
+ tegra_i2c_clock_disable(i2c_dev);
if (i2c_dev->irq_disabled) {
i2c_dev->irq_disabled = 0;
@@ -716,7 +741,7 @@ static int tegra_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
}
if (i2c_dev->last_bus_clk_rate != i2c_bus->bus_clk_rate) {
- clk_set_rate(i2c_dev->clk, i2c_bus->bus_clk_rate * 8);
+ clk_set_rate(i2c_dev->div_clk, i2c_bus->bus_clk_rate * 8);
i2c_dev->last_bus_clk_rate = i2c_bus->bus_clk_rate;
}
@@ -724,7 +749,7 @@ static int tegra_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
i2c_dev->msgs_num = num;
if (!i2c_dev->is_clkon_always)
- clk_enable(i2c_dev->clk);
+ tegra_i2c_clock_enable(i2c_dev);
spin_lock_irqsave(&i2c_dev->clk_lock, flags);
i2c_dev->controller_enabled = true;
@@ -742,7 +767,7 @@ static int tegra_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
spin_unlock_irqrestore(&i2c_dev->clk_lock, flags);
if (!i2c_dev->is_clkon_always)
- clk_disable(i2c_dev->clk);
+ tegra_i2c_clock_disable(i2c_dev);
rt_mutex_unlock(&i2c_dev->dev_lock);
@@ -768,7 +793,8 @@ static int tegra_i2c_probe(struct platform_device *pdev)
struct tegra_i2c_platform_data *plat = pdev->dev.platform_data;
struct resource *res;
struct resource *iomem;
- struct clk *clk;
+ struct clk *div_clk;
+ struct clk *fast_clk = NULL;
const unsigned int *prop;
void *base;
int irq;
@@ -814,13 +840,20 @@ static int tegra_i2c_probe(struct platform_device *pdev)
}
irq = res->start;
- clk = clk_get(&pdev->dev, "i2c-div");
- if (IS_ERR(clk)) {
+ div_clk = clk_get(&pdev->dev, "i2c-div");
+ if (IS_ERR(div_clk)) {
dev_err(&pdev->dev, "missing controller clock");
- ret = PTR_ERR(clk);
+ ret = PTR_ERR(div_clk);
goto err_release_region;
}
+ fast_clk = clk_get(&pdev->dev, "i2c-fast");
+ if (IS_ERR(fast_clk)) {
+ dev_err(&pdev->dev, "missing controller fast clock");
+ ret = PTR_ERR(fast_clk);
+ goto fast_clk_err;
+ }
+
i2c_dev = kzalloc(sizeof(struct tegra_i2c_dev) +
(nbus-1) * sizeof(struct tegra_i2c_bus), GFP_KERNEL);
if (!i2c_dev) {
@@ -829,7 +862,8 @@ static int tegra_i2c_probe(struct platform_device *pdev)
}
i2c_dev->base = base;
- i2c_dev->clk = clk;
+ i2c_dev->div_clk = div_clk;
+ i2c_dev->fast_clk = fast_clk;
i2c_dev->iomem = iomem;
i2c_dev->irq = irq;
i2c_dev->cont_id = pdev->id;
@@ -868,7 +902,7 @@ static int tegra_i2c_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, i2c_dev);
if (i2c_dev->is_clkon_always)
- clk_enable(i2c_dev->clk);
+ tegra_i2c_clock_enable(i2c_dev);
ret = tegra_i2c_init(i2c_dev);
if (ret) {
@@ -931,7 +965,9 @@ err_del_bus:
err_free:
kfree(i2c_dev);
err_clk_put:
- clk_put(clk);
+ clk_put(fast_clk);
+fast_clk_err:
+ clk_put(div_clk);
err_release_region:
release_mem_region(iomem->start, resource_size(iomem));
err_iounmap:
@@ -946,10 +982,11 @@ static int tegra_i2c_remove(struct platform_device *pdev)
i2c_del_adapter(&i2c_dev->busses[i2c_dev->bus_count].adapter);
if (i2c_dev->is_clkon_always)
- clk_disable(i2c_dev->clk);
+ tegra_i2c_clock_disable(i2c_dev);
free_irq(i2c_dev->irq, i2c_dev);
- clk_put(i2c_dev->clk);
+ clk_put(i2c_dev->div_clk);
+ clk_put(i2c_dev->fast_clk);
release_mem_region(i2c_dev->iomem->start,
resource_size(i2c_dev->iomem));
iounmap(i2c_dev->base);
@@ -967,7 +1004,7 @@ static int tegra_i2c_suspend_noirq(struct device *dev)
i2c_dev->is_suspended = true;
if (i2c_dev->is_clkon_always)
- clk_disable(i2c_dev->clk);
+ tegra_i2c_clock_disable(i2c_dev);
rt_mutex_unlock(&i2c_dev->dev_lock);
@@ -983,7 +1020,7 @@ static int tegra_i2c_resume_noirq(struct device *dev)
rt_mutex_lock(&i2c_dev->dev_lock);
if (i2c_dev->is_clkon_always)
- clk_enable(i2c_dev->clk);
+ tegra_i2c_clock_enable(i2c_dev);
ret = tegra_i2c_init(i2c_dev);