summaryrefslogtreecommitdiff
path: root/drivers/i2c
diff options
context:
space:
mode:
authorColin Cross <ccross@android.com>2010-07-23 12:55:12 -0700
committerColin Cross <ccross@android.com>2010-10-06 16:26:45 -0700
commit1908b3377de876b3c6725173877fab33e09e0739 (patch)
tree8d2c2cede36a5e0579d6821b6bad1245ca70933d /drivers/i2c
parent80f33a8c5ada9411d598f07cb79a7360e0ebc108 (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.c35
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",