>From 7781ff0b5033436c1d2740570364b1739017e03d Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 11 Dec 2018 19:19:17 +0100 Subject: [PATCH 1/2] i2c: add I2C_AQ_RUNTIME_PM adapter quirk flag Add a new I2C_AQ_RUNTIME_PM adapter quirk flag, when this flag is set then the i2c-core will all pm_runtime_get_sync() before calling an adapter's master_xfer function and call pm_runtime_mark_last_busy() + pm_runtime_put_autosuspend() after the master_xfer function. Moving these runtime pm calls into the core for adapters which use them is necessary for the WARN_ON(adap->is_suspended) to not trigger when runtime-suspend is used. Another approach would be to only call i2c_mark_adapter_suspended() from the adapter's regular suspend/resume callbacks and not from the runtime-resume ones, but that would circumvent the check also on system suspend when using DPM_FLAG_SMART_PREPARE or DPM_FLAG_SMART_SUSPEND. Note that of the 20 adapter drivers which call pm_runtime_get_sync() from there master_xfer function, 16 call pm_runtime_put_autosuspend() when done. i2c-nomadik.c and i2c-sh_mobile.c use pm_runtime_put_sync() and i2c-tegra.c and i2c-rcar.c use pm_runtime_put(), so these will need to be modified to use these new flag, or they will need another flag for their special case. Signed-off-by: Hans de Goede --- drivers/i2c/i2c-core-base.c | 16 ++++++++++++++-- include/linux/i2c.h | 2 ++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c index 5b2078a902f8..acff1e4c09d9 100644 --- a/drivers/i2c/i2c-core-base.c +++ b/drivers/i2c/i2c-core-base.c @@ -1866,12 +1866,18 @@ int __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) if (WARN_ON(!msgs || num < 1)) return -EINVAL; - if (WARN_ON(adap->is_suspended)) - return -ESHUTDOWN; if (adap->quirks && i2c_check_for_quirks(adap, msgs, num)) return -EOPNOTSUPP; + if (adap->quirks && (adap->quirks->flags & I2C_AQ_RUNTIME_PM)) + pm_runtime_get_sync(adap->dev.parent); + + if (WARN_ON(adap->is_suspended)) { + ret = -ESHUTDOWN; + goto out; + } + /* * i2c_trace_msg_key gets enabled when tracepoint i2c_transfer gets * enabled. This is an efficient way of keeping the for-loop from @@ -1904,6 +1910,12 @@ int __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) trace_i2c_result(adap, num, ret); } +out: + if (adap->quirks && (adap->quirks->flags & I2C_AQ_RUNTIME_PM)) { + pm_runtime_mark_last_busy(adap->dev.parent); + pm_runtime_put_autosuspend(adap->dev.parent); + } + return ret; } EXPORT_SYMBOL(__i2c_transfer); diff --git a/include/linux/i2c.h b/include/linux/i2c.h index 9852038ee3a7..96b9cac6c01e 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -661,6 +661,8 @@ struct i2c_adapter_quirks { #define I2C_AQ_NO_ZERO_LEN_READ BIT(5) #define I2C_AQ_NO_ZERO_LEN_WRITE BIT(6) #define I2C_AQ_NO_ZERO_LEN (I2C_AQ_NO_ZERO_LEN_READ | I2C_AQ_NO_ZERO_LEN_WRITE) +/* core must call pm_runtime_get_sync / put_autosuspend around master_xfer */ +#define I2C_AQ_RUNTIME_PM BIT(7) /* * i2c_adapter is the structure used to identify a physical i2c bus along -- 2.19.2