* Tony Lindgren <tony@xxxxxxxxxxx> [180926 16:04]: > * Keerthy <j-keerthy@xxxxxx> [180926 04:12]: > > So the below patch is solving the problem only for the first iteration > > but i see the problem recurring from second iteration of suspend. > > > > I tried the above cycle multiple times on am437x-gp-evm. I believe > > we are one step closer still not completely fixed. > > OK thanks, that's interesting, I'll take a look. Good to hear > that is the reason for pixcir issues though :) Heh ooops the previous i2c-omap patch I posted does unpaired runtime_pm calls.. The put must be left out omap_i2c_resume(). Below is a better patch, seems to work for me multiple times now. Regards, Tony 8< --------------------------- diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -208,6 +208,8 @@ struct omap_i2c_dev { * if set, should be trsh+1 */ u32 rev; + unsigned int is_suspended:1; + unsigned int needs_resume:1; unsigned b_hw:1; /* bad h/w fixes */ unsigned bb_valid:1; /* true when BB-bit reflects * the I2C bus state @@ -1498,8 +1500,7 @@ static int omap_i2c_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM -static int omap_i2c_runtime_suspend(struct device *dev) +static int __maybe_unused omap_i2c_runtime_suspend(struct device *dev) { struct omap_i2c_dev *omap = dev_get_drvdata(dev); @@ -1521,11 +1522,12 @@ static int omap_i2c_runtime_suspend(struct device *dev) } pinctrl_pm_select_sleep_state(dev); + omap->is_suspended = true; return 0; } -static int omap_i2c_runtime_resume(struct device *dev) +static int __maybe_unused omap_i2c_runtime_resume(struct device *dev) { struct omap_i2c_dev *omap = dev_get_drvdata(dev); @@ -1535,6 +1537,51 @@ static int omap_i2c_runtime_resume(struct device *dev) return 0; __omap_i2c_init(omap); + omap->is_suspended = false; + + return 0; +} + +static int __maybe_unused omap_i2c_suspend(struct device *dev) +{ + struct omap_i2c_dev *ddata = dev_get_drvdata(dev); + int error; + + /* Is device still enabled because of autosuspend? */ + if (ddata->is_suspended) + return 0; + + /* Paired with call in omap_i2c_resume() */ + error = pm_runtime_put_sync_suspend(dev); + if (error < 0) { + dev_err(dev, "%s failed: %i\n", __func__, error); + + return error; + } + + ddata->needs_resume = true; + + return 0; +} + +static int __maybe_unused omap_i2c_resume(struct device *dev) +{ + struct omap_i2c_dev *ddata = dev_get_drvdata(dev); + int error; + + if (!ddata->needs_resume) + return 0; + + /* Paired with call in omap_i2c_suspend() */ + error = pm_runtime_get_sync(dev); + if (error < 0) { + dev_err(dev, "%s failed: %i\n", __func__, error); + pm_runtime_put_noidle(dev); + + return error; + } + + ddata->needs_resume = false; return 0; } @@ -1542,18 +1589,15 @@ static int omap_i2c_runtime_resume(struct device *dev) static const struct dev_pm_ops omap_i2c_pm_ops = { SET_RUNTIME_PM_OPS(omap_i2c_runtime_suspend, omap_i2c_runtime_resume, NULL) + SET_SYSTEM_SLEEP_PM_OPS(omap_i2c_suspend, omap_i2c_resume) }; -#define OMAP_I2C_PM_OPS (&omap_i2c_pm_ops) -#else -#define OMAP_I2C_PM_OPS NULL -#endif /* CONFIG_PM */ static struct platform_driver omap_i2c_driver = { .probe = omap_i2c_probe, .remove = omap_i2c_remove, .driver = { .name = "omap_i2c", - .pm = OMAP_I2C_PM_OPS, + .pm = &omap_i2c_pm_ops, .of_match_table = of_match_ptr(omap_i2c_of_match), }, }; -- 2.19.0