Message ID | 20210507131406.2224177-1-hsinyi@chromium.org |
---|---|
Headers | show |
Series | add power control in i2c | expand |
On 07/05/2021 15:14, Hsin-Yi Wang wrote: > From: Bibby Hsieh <bibby.hsieh@mediatek.com> > > Although in the most platforms, the bus power of i2c > are alway on, some platforms disable the i2c bus power > in order to meet low power request. > > We can control bulk regulator if it is provided in i2c > adapter device. > > Signed-off-by: Bibby Hsieh <bibby.hsieh@mediatek.com> > Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com> > Signed-off-by: Hsin-Yi Wang <hsinyi@chromium.org> Reviewed-by: Matthias Brugger <matthias.bgg@gmail.com> > --- > drivers/i2c/i2c-core-base.c | 95 +++++++++++++++++++++++++++++++++++++ > include/linux/i2c.h | 2 + > 2 files changed, 97 insertions(+) > > diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c > index 5a97e4a02fa2..23bc7c269184 100644 > --- a/drivers/i2c/i2c-core-base.c > +++ b/drivers/i2c/i2c-core-base.c > @@ -461,12 +461,14 @@ static int i2c_smbus_host_notify_to_irq(const struct i2c_client *client) > static int i2c_device_probe(struct device *dev) > { > struct i2c_client *client = i2c_verify_client(dev); > + struct i2c_adapter *adap; > struct i2c_driver *driver; > int status; > > if (!client) > return 0; > > + adap = client->adapter; > client->irq = client->init_irq; > > if (!client->irq) { > @@ -532,6 +534,14 @@ static int i2c_device_probe(struct device *dev) > > dev_dbg(dev, "probe\n"); > > + if (adap->bus_regulator) { > + status = regulator_enable(adap->bus_regulator); > + if (status < 0) { > + dev_err(&adap->dev, "Failed to enable bus regulator\n"); > + goto err_clear_wakeup_irq; > + } > + } > + > status = of_clk_set_defaults(dev->of_node, false); > if (status < 0) > goto err_clear_wakeup_irq; > @@ -589,8 +599,10 @@ static int i2c_device_probe(struct device *dev) > static int i2c_device_remove(struct device *dev) > { > struct i2c_client *client = to_i2c_client(dev); > + struct i2c_adapter *adap; > struct i2c_driver *driver; > > + adap = client->adapter; > driver = to_i2c_driver(dev->driver); > if (driver->remove) { > int status; > @@ -605,6 +617,8 @@ static int i2c_device_remove(struct device *dev) > devres_release_group(&client->dev, client->devres_group_id); > > dev_pm_domain_detach(&client->dev, true); > + if (!pm_runtime_status_suspended(&client->dev) && adap->bus_regulator) > + regulator_disable(adap->bus_regulator); > > dev_pm_clear_wake_irq(&client->dev); > device_init_wakeup(&client->dev, false); > @@ -617,6 +631,86 @@ static int i2c_device_remove(struct device *dev) > return 0; > } > > +#ifdef CONFIG_PM_SLEEP > +static int i2c_resume_early(struct device *dev) > +{ > + struct i2c_client *client = i2c_verify_client(dev); > + int err; > + > + if (!client) > + return 0; > + > + if (pm_runtime_status_suspended(&client->dev) && > + client->adapter->bus_regulator) { > + err = regulator_enable(client->adapter->bus_regulator); > + if (err) > + return err; > + } > + > + return pm_generic_resume_early(&client->dev); > +} > + > +static int i2c_suspend_late(struct device *dev) > +{ > + struct i2c_client *client = i2c_verify_client(dev); > + int err; > + > + if (!client) > + return 0; > + > + err = pm_generic_suspend_late(&client->dev); > + if (err) > + return err; > + > + if (!pm_runtime_status_suspended(&client->dev) && > + client->adapter->bus_regulator) > + return regulator_disable(client->adapter->bus_regulator); > + > + return 0; > +} > +#endif > + > +#ifdef CONFIG_PM > +static int i2c_runtime_resume(struct device *dev) > +{ > + struct i2c_client *client = i2c_verify_client(dev); > + int err; > + > + if (!client) > + return 0; > + > + if (client->adapter->bus_regulator) { > + err = regulator_enable(client->adapter->bus_regulator); > + if (err) > + return err; > + } > + > + return pm_generic_runtime_resume(&client->dev); > +} > + > +static int i2c_runtime_suspend(struct device *dev) > +{ > + struct i2c_client *client = i2c_verify_client(dev); > + int err; > + > + if (!client) > + return 0; > + > + err = pm_generic_runtime_suspend(&client->dev); > + if (err) > + return err; > + > + if (client->adapter->bus_regulator) > + return regulator_disable(client->adapter->bus_regulator); > + return 0; > +} > +#endif > + > +static const struct dev_pm_ops i2c_device_pm = { > + SET_LATE_SYSTEM_SLEEP_PM_OPS(i2c_suspend_late, i2c_resume_early) > + SET_RUNTIME_PM_OPS(i2c_runtime_suspend, i2c_runtime_resume, NULL) > +}; > + > static void i2c_device_shutdown(struct device *dev) > { > struct i2c_client *client = i2c_verify_client(dev); > @@ -674,6 +768,7 @@ struct bus_type i2c_bus_type = { > .probe = i2c_device_probe, > .remove = i2c_device_remove, > .shutdown = i2c_device_shutdown, > + .pm = &i2c_device_pm, > }; > EXPORT_SYMBOL_GPL(i2c_bus_type); > > diff --git a/include/linux/i2c.h b/include/linux/i2c.h > index e8f2ac8c9c3d..953a4eecb88f 100644 > --- a/include/linux/i2c.h > +++ b/include/linux/i2c.h > @@ -15,6 +15,7 @@ > #include <linux/device.h> /* for struct device */ > #include <linux/sched.h> /* for completion */ > #include <linux/mutex.h> > +#include <linux/regulator/consumer.h> > #include <linux/rtmutex.h> > #include <linux/irqdomain.h> /* for Host Notify IRQ */ > #include <linux/of.h> /* for struct device_node */ > @@ -729,6 +730,7 @@ struct i2c_adapter { > const struct i2c_adapter_quirks *quirks; > > struct irq_domain *host_notify_domain; > + struct regulator *bus_regulator; > }; > #define to_i2c_adapter(d) container_of(d, struct i2c_adapter, dev) > >
On 07/05/2021 15:14, Hsin-Yi Wang wrote: > Add vbus-supply which provides power to SCL/SDA. Pass this regulator > into core so it can be turned on/off for low power mode support. > > Signed-off-by: Hsin-Yi Wang <hsinyi@chromium.org> Reviewed-by: Matthias Brugger <matthias.bgg@gmail.com> > --- > drivers/i2c/busses/i2c-mt65xx.c | 7 +++++++ > 1 file changed, 7 insertions(+) > > diff --git a/drivers/i2c/busses/i2c-mt65xx.c b/drivers/i2c/busses/i2c-mt65xx.c > index 5ddfa4e56ee2..22d1d14b5de5 100644 > --- a/drivers/i2c/busses/i2c-mt65xx.c > +++ b/drivers/i2c/busses/i2c-mt65xx.c > @@ -1220,6 +1220,13 @@ static int mtk_i2c_probe(struct platform_device *pdev) > i2c->adap.quirks = i2c->dev_comp->quirks; > i2c->adap.timeout = 2 * HZ; > i2c->adap.retries = 1; > + i2c->adap.bus_regulator = devm_regulator_get_optional(&pdev->dev, "vbus"); > + if (IS_ERR(i2c->adap.bus_regulator)) { > + if (PTR_ERR(i2c->adap.bus_regulator) == -ENODEV) > + i2c->adap.bus_regulator = NULL; > + else > + return PTR_ERR(i2c->adap.bus_regulator); > + } > > ret = mtk_i2c_parse_dt(pdev->dev.of_node, i2c); > if (ret) >
On Fri, 2021-05-07 at 21:14 +0800, Hsin-Yi Wang wrote: > Add vbus-supply which provides power to SCL/SDA. Pass this regulator > into core so it can be turned on/off for low power mode support. > > Signed-off-by: Hsin-Yi Wang <hsinyi@chromium.org> Reviewed-by: Qii Wang <qii.wang@mediatek.com> > --- > drivers/i2c/busses/i2c-mt65xx.c | 7 +++++++ > 1 file changed, 7 insertions(+) > > diff --git a/drivers/i2c/busses/i2c-mt65xx.c b/drivers/i2c/busses/i2c-mt65xx.c > index 5ddfa4e56ee2..22d1d14b5de5 100644 > --- a/drivers/i2c/busses/i2c-mt65xx.c > +++ b/drivers/i2c/busses/i2c-mt65xx.c > @@ -1220,6 +1220,13 @@ static int mtk_i2c_probe(struct platform_device *pdev) > i2c->adap.quirks = i2c->dev_comp->quirks; > i2c->adap.timeout = 2 * HZ; > i2c->adap.retries = 1; > + i2c->adap.bus_regulator = devm_regulator_get_optional(&pdev->dev, "vbus"); > + if (IS_ERR(i2c->adap.bus_regulator)) { > + if (PTR_ERR(i2c->adap.bus_regulator) == -ENODEV) > + i2c->adap.bus_regulator = NULL; > + else > + return PTR_ERR(i2c->adap.bus_regulator); > + } > > ret = mtk_i2c_parse_dt(pdev->dev.of_node, i2c); > if (ret)
On Fri, May 7, 2021 at 9:14 PM Hsin-Yi Wang <hsinyi@chromium.org> wrote: > > Although in the most platforms, the power of eeprom > and i2c are alway on, some platforms disable the > eeprom and i2c power in order to meet low power request. > > This patch add the pm_runtime ops to control power to > support all platforms. > Hi maintainers, Gentle ping on the thread. (the 4th patch is already picked) Thanks. > Changes since v20: > - fix regulator check logic in suspend/resume. > > Changes since v19: > - resend v19 with fix tag added. > > Changes since v18: > - Fix a function name conflict with drivers/gpu/drm/i915/selftests/i915_gem.c > > Changes since v17: > - Add a patch to fix unbalanced regulator disabling. > - Add dts patch. > > Changes since v16: > - request regulator in device instead of in the core. > - control regulator only if it's provided. > > Changes since v15: > - Squash the fix[1] for v15. > [1] https://patchwork.ozlabs.org/project/linux-i2c/patch/20200522101327.13456-1-m.szyprowski@samsung.com/ > > Changes since v14: > - change the return value in normal condition > - access the variable after NULL pointer checking > - add ack tag > > Changes since v13: > - fixup some logic error > > Changes since v12: > - rebase onto v5.7-rc1 > - change the property description in binding > > Changes since v11: > - use suspend_late/resume_early instead of suspend/resume > - rebase onto v5.6-rc1 > > Changes since v10: > - fixup some worng codes > > Changes since v9: > - fixup build error > - remove redundant code > > Changes since v8: > - fixup some wrong code > - remove redundant message > > [... snip ...] > > > Bibby Hsieh (1): > i2c: core: support bus regulator controlling in adapter > > Hsin-Yi Wang (4): > dt-binding: i2c: mt65xx: add vbus-supply property > i2c: mediatek: mt65xx: add optional vbus-supply > misc: eeprom: at24: check suspend status before disable regulator > arm64: dts: mt8183: add supply name for eeprom > > .../devicetree/bindings/i2c/i2c-mt65xx.txt | 1 + > .../dts/mediatek/mt8183-kukui-kakadu.dtsi | 4 + > .../dts/mediatek/mt8183-kukui-kodama.dtsi | 4 + > .../boot/dts/mediatek/mt8183-kukui-krane.dtsi | 4 + > drivers/i2c/busses/i2c-mt65xx.c | 7 ++ > drivers/i2c/i2c-core-base.c | 95 +++++++++++++++++++ > drivers/misc/eeprom/at24.c | 6 +- > include/linux/i2c.h | 2 + > 8 files changed, 121 insertions(+), 2 deletions(-) > > -- > 2.31.1.607.g51e8a6a459-goog >