diff mbox series

[v2,4/4] i2c: muxes: pca954x: Add regulator support

Message ID 20220108185759.2086347-5-patrick.rudolph@9elements.com
State Superseded
Headers show
Series Add support for Maxim MAX735x/MAX736x variants | expand

Commit Message

Patrick Rudolph Jan. 8, 2022, 6:57 p.m. UTC
Add an optional vdd regulator and enable it when found for devices
that are powered off by default.

Signed-off-by: Patrick Rudolph <patrick.rudolph@9elements.com>
---
 drivers/i2c/muxes/i2c-mux-pca954x.c | 32 ++++++++++++++++++++++++-----
 1 file changed, 27 insertions(+), 5 deletions(-)

Comments

Wolfram Sang Jan. 12, 2022, 9:31 a.m. UTC | #1
On Sat, Jan 08, 2022 at 07:57:58PM +0100, Patrick Rudolph wrote:
> Add an optional vdd regulator and enable it when found for devices
> that are powered off by default.
> 
> Signed-off-by: Patrick Rudolph <patrick.rudolph@9elements.com>

regulator support was recently added to the I2C core but had to be
reverted because of side effects [1]. I think you could make use of it
if it gets readded?

[1] a19f75de73c2 ("Revert "i2c: core: support bus regulator controlling in adapter"")
Patrick Rudolph Jan. 20, 2022, 7:22 a.m. UTC | #2
Hi Wolfram,
I don't think that it's possible to use the generic vbus-supply.
In my case the complete chip, not only the bus, is powered by a regulator.
In addition it looks like this works only for platform drivers where
you can set the bus_regulator
before the i2c core probe function is invoked.

Regards,
Patrick Rudolph



On Wed, Jan 12, 2022 at 10:31 AM Wolfram Sang <wsa@kernel.org> wrote:
>
> On Sat, Jan 08, 2022 at 07:57:58PM +0100, Patrick Rudolph wrote:
> > Add an optional vdd regulator and enable it when found for devices
> > that are powered off by default.
> >
> > Signed-off-by: Patrick Rudolph <patrick.rudolph@9elements.com>
>
> regulator support was recently added to the I2C core but had to be
> reverted because of side effects [1]. I think you could make use of it
> if it gets readded?
>
> [1] a19f75de73c2 ("Revert "i2c: core: support bus regulator controlling in adapter"")
>
diff mbox series

Patch

diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c
index 33b9a6a1fffa..086647193ea9 100644
--- a/drivers/i2c/muxes/i2c-mux-pca954x.c
+++ b/drivers/i2c/muxes/i2c-mux-pca954x.c
@@ -49,6 +49,7 @@ 
 #include <linux/module.h>
 #include <linux/pm.h>
 #include <linux/property.h>
+#include <linux/regulator/consumer.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 #include <dt-bindings/mux/mux.h>
@@ -119,6 +120,7 @@  struct pca954x {
 	struct irq_domain *irq;
 	unsigned int irq_mask;
 	raw_spinlock_t lock;
+	struct regulator *supply;
 };
 
 /* Provide specs for the PCA954x and MAX735x types we know about */
@@ -459,6 +461,9 @@  static void pca954x_cleanup(struct i2c_mux_core *muxc)
 	struct pca954x *data = i2c_mux_priv(muxc);
 	int c, irq;
 
+	if (!IS_ERR_OR_NULL(data->supply))
+		regulator_disable(data->supply);
+
 	if (data->irq) {
 		for (c = 0; c < data->chip->nchans; c++) {
 			irq = irq_find_mapping(data->irq, c);
@@ -513,15 +518,30 @@  static int pca954x_probe(struct i2c_client *client,
 			     pca954x_select_chan, pca954x_deselect_mux);
 	if (!muxc)
 		return -ENOMEM;
+
 	data = i2c_mux_priv(muxc);
 
 	i2c_set_clientdata(client, muxc);
 	data->client = client;
 
+	data->supply = devm_regulator_get_optional(dev, "vdd");
+	if (IS_ERR(data->supply)) {
+		if ((PTR_ERR(data->supply) == -EPROBE_DEFER))
+			return -EPROBE_DEFER;
+	} else {
+		ret = regulator_enable(data->supply);
+		if (ret) {
+			dev_err(dev, "Failed to enable regulator vdd: %d\n", ret);
+			return ret;
+		}
+	}
+
 	/* Reset the mux if a reset GPIO is specified. */
 	gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
-	if (IS_ERR(gpio))
-		return PTR_ERR(gpio);
+	if (IS_ERR(gpio)) {
+		ret = PTR_ERR(gpio);
+		goto fail_cleanup;
+	}
 	if (gpio) {
 		udelay(1);
 		gpiod_set_value_cansleep(gpio, 0);
@@ -538,7 +558,7 @@  static int pca954x_probe(struct i2c_client *client,
 
 		ret = i2c_get_device_id(client, &id);
 		if (ret && ret != -EOPNOTSUPP)
-			return ret;
+			goto fail_cleanup;
 
 		if (!ret &&
 		    (id.manufacturer_id != data->chip->id.manufacturer_id ||
@@ -546,7 +566,8 @@  static int pca954x_probe(struct i2c_client *client,
 			dev_warn(dev, "unexpected device id %03x-%03x-%x\n",
 				 id.manufacturer_id, id.part_id,
 				 id.die_revision);
-			return -ENODEV;
+			ret = -ENODEV;
+			goto fail_cleanup;
 		}
 	}
 
@@ -565,7 +586,8 @@  static int pca954x_probe(struct i2c_client *client,
 	ret = pca954x_init(client, data);
 	if (ret < 0) {
 		dev_warn(dev, "probe failed\n");
-		return -ENODEV;
+		ret = -ENODEV;
+		goto fail_cleanup;
 	}
 
 	ret = pca954x_irq_setup(muxc);