summaryrefslogtreecommitdiff
path: root/drivers/i2c/busses/i2c-tegra.c
diff options
context:
space:
mode:
authorBitan Biswas <bbiswas@nvidia.com>2019-06-06 22:37:47 -0700
committerWolfram Sang <wsa@the-dreams.de>2019-06-14 23:24:34 +0200
commitacc8abcb2a9ca26318d86f53addf952dea930ab7 (patch)
treed1a1f32c30e154d2bcb1816e1bc0ea9948e3d61a /drivers/i2c/busses/i2c-tegra.c
parent76cc9f0efd952d376e93e79b1f19fd6fdb8291bc (diff)
i2c: tegra: Add suspend-resume support
Post suspend I2C registers have power on reset values. Before any transfer initialize I2C registers to prevent I2C transfer timeout and implement suspend and resume callbacks needed. Fix below errors post suspend: 1) Tegra I2C transfer timeout during jetson tx2 resume: [ 27.520613] pca953x 1-0074: calling pca953x_resume+0x0/0x1b0 @ 2939, parent: i2c-1 [ 27.633623] tegra-i2c 3160000.i2c: i2c transfer timed out [ 27.639162] pca953x 1-0074: Unable to sync registers 0x3-0x5. -110 [ 27.645336] pca953x 1-0074: Failed to sync GPIO dir registers: -110 [ 27.651596] PM: dpm_run_callback(): pca953x_resume+0x0/0x1b0 returns -110 [ 27.658375] pca953x 1-0074: pca953x_resume+0x0/0x1b0 returned -110 after 127152 usecs [ 27.666194] PM: Device 1-0074 failed to resume: error -110 2) Tegra I2C transfer timeout error on jetson Xavier post resume. Remove i2c bus lock-unlock calls in resume callback as i2c_mark_adapter_* (suspended-resumed) help ensure i2c core calls from client are not executed before i2c-tegra resume. Signed-off-by: Bitan Biswas <bbiswas@nvidia.com> Reviewed-by: Dmitry Osipenko <digetx@gmail.com> Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
Diffstat (limited to 'drivers/i2c/busses/i2c-tegra.c')
-rw-r--r--drivers/i2c/busses/i2c-tegra.c24
1 files changed, 24 insertions, 0 deletions
diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
index 30daf7341e83..1ed15af46542 100644
--- a/drivers/i2c/busses/i2c-tegra.c
+++ b/drivers/i2c/busses/i2c-tegra.c
@@ -1681,7 +1681,31 @@ static int tegra_i2c_remove(struct platform_device *pdev)
}
#ifdef CONFIG_PM_SLEEP
+static int tegra_i2c_suspend(struct device *dev)
+{
+ struct tegra_i2c_dev *i2c_dev = dev_get_drvdata(dev);
+
+ i2c_mark_adapter_suspended(&i2c_dev->adapter);
+
+ return 0;
+}
+
+static int tegra_i2c_resume(struct device *dev)
+{
+ struct tegra_i2c_dev *i2c_dev = dev_get_drvdata(dev);
+ int err;
+
+ err = tegra_i2c_init(i2c_dev, false);
+ if (err)
+ return err;
+
+ i2c_mark_adapter_resumed(&i2c_dev->adapter);
+
+ return 0;
+}
+
static const struct dev_pm_ops tegra_i2c_pm = {
+ SET_SYSTEM_SLEEP_PM_OPS(tegra_i2c_suspend, tegra_i2c_resume)
SET_RUNTIME_PM_OPS(tegra_i2c_runtime_suspend, tegra_i2c_runtime_resume,
NULL)
};