From eaea3c248f9745aa75b1883f99c8e1fcf2bdbfff Mon Sep 17 00:00:00 2001 From: Akhil R Date: Fri, 9 Aug 2024 10:37:13 +0530 Subject: [PATCH] NVIDIA: SAUCE: i2c: tegra: resume explicitly if pm_runtime is disabled BugLink: https://bugs.launchpad.net/bugs/2080908 This is a WAR to handle NOIRQ suspend/resume in I2C client devices. runtime_pm is disabled during system suspend and enabled on resume. Some client devices trigger I2C transfers before the I2C driver has resumed completely which causes the I2C transfers to fail. Do runtime_resume explicitly then so that I2C can work. http://nvbugs/4765610 Signed-off-by: Akhil R Signed-off-by: Laxman Dewangan Acked-by: Noah Wager Acked-by: Jacob Martin Signed-off-by: Noah Wager --- drivers/i2c/busses/i2c-tegra.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index 59d0e4f6094f..28cf1a9f7a7b 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -313,6 +313,9 @@ static u32 dvc_readl(struct tegra_i2c_dev *i2c_dev, unsigned int reg) return readl_relaxed(i2c_dev->base + reg); } +static int tegra_i2c_runtime_resume(struct device *dev); +static int tegra_i2c_runtime_suspend(struct device *dev); + /* * If necessary, i2c_writel() and i2c_readl() will offset the register * in order to talk to the I2C block inside the DVC block. @@ -1427,10 +1430,16 @@ static int tegra_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], struct tegra_i2c_dev *i2c_dev = i2c_get_adapdata(adap); int i, ret; - ret = pm_runtime_get_sync(i2c_dev->dev); + if (pm_runtime_enabled(i2c_dev->dev)) + ret = pm_runtime_get_sync(i2c_dev->dev); + else + ret = tegra_i2c_runtime_resume(i2c_dev->dev); + if (ret < 0) { + if (pm_runtime_enabled(i2c_dev->dev)) + pm_runtime_put_noidle(i2c_dev->dev); + dev_err(i2c_dev->dev, "runtime resume failed %d\n", ret); - pm_runtime_put_noidle(i2c_dev->dev); return ret; } @@ -1458,7 +1467,10 @@ static int tegra_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], break; } - pm_runtime_put(i2c_dev->dev); + if (pm_runtime_enabled(i2c_dev->dev)) + pm_runtime_put(i2c_dev->dev); + else + tegra_i2c_runtime_suspend(i2c_dev->dev); return ret ?: i; }