From fc56d07f59a3cafa33c31bf90a50af04a0235cf8 Mon Sep 17 00:00:00 2001 From: Peter De Schrijver Date: Tue, 20 Dec 2011 14:03:00 +0200 Subject: 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 Reviewed-on: http://git-master/r/71192 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Varun Wadekar --- drivers/i2c/busses/i2c-tegra.c | 72 +++++++++++++++++++++++++++--------------- 1 file changed, 47 insertions(+), 25 deletions(-) (limited to 'drivers/i2c') 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 #include #include +#include #include @@ -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 -- cgit v1.2.3