diff options
author | Colin Cross <ccross@android.com> | 2010-07-23 12:55:12 -0700 |
---|---|---|
committer | Colin Cross <ccross@android.com> | 2010-10-06 16:26:45 -0700 |
commit | 1908b3377de876b3c6725173877fab33e09e0739 (patch) | |
tree | 8d2c2cede36a5e0579d6821b6bad1245ca70933d /drivers/i2c | |
parent | 80f33a8c5ada9411d598f07cb79a7360e0ebc108 (diff) |
i2c: tegra: Prevent i2c transactions after suspend
The cpufreq driver suspends very late, and may cause an i2c
transaction when the clk api calls the dvfs api, which calls
the regulator api, which calls i2c. Return an error if an
i2c transaction is requested after suspend has been called.
Change-Id: I4d92eb9c1f558758097e2dafda6fc02addf4e185
Signed-off-by: Colin Cross <ccross@android.com>
Diffstat (limited to 'drivers/i2c')
-rw-r--r-- | drivers/i2c/busses/i2c-tegra.c | 35 |
1 files changed, 32 insertions, 3 deletions
diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index 2586117e7c75..69e8cdd46173 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -109,6 +109,7 @@ struct tegra_i2c_dev { int msg_read; int msg_transfer_complete; unsigned long bus_clk_rate; + bool is_suspended; }; static void dvc_writel(struct tegra_i2c_dev *i2c_dev, u32 val, unsigned long reg) @@ -439,7 +440,7 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev, tegra_i2c_mask_irq(i2c_dev, int_mask); dev_dbg(i2c_dev->dev, "after transfer: %08x fifo %02x\n", i2c_readl(i2c_dev, I2C_PACKET_TRANSFER_STATUS), i2c_readl(i2c_dev, I2C_FIFO_STATUS)); - if (ret == 0) { + if (WARN_ON(ret == 0)) { dev_err(i2c_dev->dev, "i2c transfer timed out\n"); tegra_i2c_init(i2c_dev); @@ -466,6 +467,10 @@ static int tegra_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int n struct tegra_i2c_dev *i2c_dev = i2c_get_adapdata(adap); int i; int ret = 0; + + if(i2c_dev->is_suspended) + return -EBUSY; + clk_enable(i2c_dev->clk); for (i = 0; i < num; i++) { int stop = (i == (num - 1)) ? 1 : 0; @@ -617,23 +622,47 @@ static int tegra_i2c_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM static int tegra_i2c_suspend(struct platform_device *pdev, pm_message_t state) { - /* FIXME to be implemented */ + struct tegra_i2c_dev *i2c_dev = platform_get_drvdata(pdev); + + i2c_lock_adapter(&i2c_dev->adapter); + i2c_dev->is_suspended = true; + i2c_unlock_adapter(&i2c_dev->adapter); + return 0; } static int tegra_i2c_resume(struct platform_device *pdev) { - /* FIXME to be implemented */ + struct tegra_i2c_dev *i2c_dev = platform_get_drvdata(pdev); + int ret; + + i2c_lock_adapter(&i2c_dev->adapter); + + ret = tegra_i2c_init(i2c_dev); + + if (ret) { + i2c_unlock_adapter(&i2c_dev->adapter); + return ret; + } + + i2c_dev->is_suspended = false; + + i2c_unlock_adapter(&i2c_dev->adapter); + return 0; } +#endif static struct platform_driver tegra_i2c_driver = { .probe = tegra_i2c_probe, .remove = tegra_i2c_remove, +#ifdef CONFIG_PM .suspend = tegra_i2c_suspend, .resume = tegra_i2c_resume, +#endif .driver = { .name = "tegra-i2c", |