summaryrefslogtreecommitdiff
path: root/drivers/i2c
diff options
context:
space:
mode:
authorPeter De Schrijver <pdeschrijver@nvidia.com>2011-12-20 14:03:00 +0200
committerVarun Wadekar <vwadekar@nvidia.com>2011-12-23 03:34:49 -0800
commitfc56d07f59a3cafa33c31bf90a50af04a0235cf8 (patch)
tree6937cbfba4cba31c0ee43218240639b615b4cdf8 /drivers/i2c
parent9cfa02e6af2d69681b369a584e311237184eaa6b (diff)
i2c: tegra: use PM runtime framework
Convert tegra i2c driver to use PM runtime framework. changes since last version: fix hang when using resume_noirq Change-Id: I1cce314ef4c06dbc7f1b3ddbdd1ad50255aa8b02 Signed-off-by: Peter De Schrijver <pdeschrijver@nvidia.com> Reviewed-on: http://git-master/r/71192 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Varun Wadekar <vwadekar@nvidia.com>
Diffstat (limited to 'drivers/i2c')
-rw-r--r--drivers/i2c/busses/i2c-tegra.c72
1 files changed, 47 insertions, 25 deletions
diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
index 2cbee05c3897..2d058369a6fd 100644
--- a/drivers/i2c/busses/i2c-tegra.c
+++ b/drivers/i2c/busses/i2c-tegra.c
@@ -33,6 +33,7 @@
#include <linux/i2c-tegra.h>
#include <linux/of_i2c.h>
#include <linux/spinlock.h>
+#include <linux/pm_runtime.h>
#include <asm/unaligned.h>
@@ -112,8 +113,6 @@
#define SL_ADDR1(addr) (addr & 0xff)
#define SL_ADDR2(addr) ((addr >> 8) & 0xff)
-
-
struct tegra_i2c_dev;
struct tegra_i2c_bus {
@@ -396,8 +395,7 @@ 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);
+ pm_runtime_get_sync(i2c_dev->dev);
/* Interrupt generated before sending stop signal so
* wait for some time so that stop signal can be send proerly */
@@ -435,8 +433,7 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev)
if (tegra_i2c_flush_fifos(i2c_dev))
err = -ETIMEDOUT;
- if (!i2c_dev->is_clkon_always)
- clk_disable(i2c_dev->clk);
+ pm_runtime_put_sync(i2c_dev->dev);
if (i2c_dev->irq_disabled) {
i2c_dev->irq_disabled = 0;
@@ -693,8 +690,10 @@ static int tegra_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
int ret = 0;
unsigned long flags;
- if (i2c_dev->is_suspended)
- return -EBUSY;
+ if (i2c_dev->is_suspended) {
+ tegra_i2c_init(i2c_dev);
+ i2c_dev->is_suspended = false;
+ }
rt_mutex_lock(&i2c_dev->dev_lock);
@@ -715,8 +714,7 @@ static int tegra_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
i2c_dev->msgs = msgs;
i2c_dev->msgs_num = num;
- if (!i2c_dev->is_clkon_always)
- clk_enable(i2c_dev->clk);
+ pm_runtime_get_sync(i2c_dev->dev);
spin_lock_irqsave(&i2c_dev->clk_lock, flags);
i2c_dev->controller_enabled = true;
@@ -733,8 +731,7 @@ static int tegra_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
i2c_dev->controller_enabled = false;
spin_unlock_irqrestore(&i2c_dev->clk_lock, flags);
- if (!i2c_dev->is_clkon_always)
- clk_disable(i2c_dev->clk);
+ pm_runtime_put_sync(i2c_dev->dev);
rt_mutex_unlock(&i2c_dev->dev_lock);
@@ -856,8 +853,8 @@ 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);
+ pm_runtime_enable(i2c_dev->dev);
+ pm_runtime_irq_safe(i2c_dev->dev);
ret = tegra_i2c_init(i2c_dev);
if (ret) {
@@ -865,6 +862,9 @@ static int tegra_i2c_probe(struct platform_device *pdev)
goto err_free;
}
+ if (i2c_dev->is_clkon_always)
+ pm_runtime_forbid(i2c_dev->dev);
+
ret = request_irq(i2c_dev->irq, tegra_i2c_isr, 0, pdev->name, i2c_dev);
if (ret) {
dev_err(&pdev->dev, "Failed to request irq %i\n", i2c_dev->irq);
@@ -935,7 +935,9 @@ 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);
+ pm_runtime_allow(i2c_dev->dev);
+
+ pm_runtime_disable(i2c_dev->dev);
free_irq(i2c_dev->irq, i2c_dev);
clk_put(i2c_dev->clk);
@@ -956,7 +958,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);
+ pm_runtime_allow(i2c_dev->dev);
rt_mutex_unlock(&i2c_dev->dev_lock);
@@ -971,19 +973,36 @@ 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);
+ if (i2c_dev->is_clkon_always) {
+ pm_runtime_forbid(i2c_dev->dev);
+ ret = tegra_i2c_init(i2c_dev);
+ if (ret) {
+ rt_mutex_unlock(&i2c_dev->dev_lock);
+ return ret;
+ }
+ i2c_dev->is_suspended = false;
+ }
+ rt_mutex_unlock(&i2c_dev->dev_lock);
- ret = tegra_i2c_init(i2c_dev);
+ return 0;
+}
- if (ret) {
- rt_mutex_unlock(&i2c_dev->dev_lock);
- return ret;
- }
+static int tegra_i2c_runtime_idle(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct tegra_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
- i2c_dev->is_suspended = false;
+ clk_disable(i2c_dev->clk);
- rt_mutex_unlock(&i2c_dev->dev_lock);
+ return 0;
+}
+
+static int tegra_i2c_runtime_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct tegra_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
+
+ clk_enable(i2c_dev->clk);
return 0;
}
@@ -991,7 +1010,10 @@ static int tegra_i2c_resume_noirq(struct device *dev)
static const struct dev_pm_ops tegra_i2c_dev_pm_ops = {
.suspend_noirq = tegra_i2c_suspend_noirq,
.resume_noirq = tegra_i2c_resume_noirq,
+ .runtime_idle = tegra_i2c_runtime_idle,
+ .runtime_resume = tegra_i2c_runtime_resume,
};
+
#define TEGRA_I2C_DEV_PM_OPS (&tegra_i2c_dev_pm_ops)
#else
#define TEGRA_I2C_DEV_PM_OPS NULL