linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] i2c: mux: pca954x: Support multiple devices on a single reset line
@ 2021-05-05 21:59 Eddie James
  2021-05-06 22:08 ` Peter Rosin
  0 siblings, 1 reply; 3+ messages in thread
From: Eddie James @ 2021-05-05 21:59 UTC (permalink / raw)
  To: linux-i2c; +Cc: linux-kernel, peda, joel, Eddie James

Some systems connect several PCA954x devices to a single reset GPIO. For
these devices to get out of reset and probe successfully, only the first
device probed should change the GPIO. Add this functionality by checking
for EBUSY when getting the GPIO fails. Then, retry getting the GPIO with
the non-exclusive flag and wait for the reset line to drop. This prevents
the later probes from proceding while the device is still reset.

Signed-off-by: Eddie James <eajames@linux.ibm.com>
---
 drivers/i2c/muxes/i2c-mux-pca954x.c | 43 +++++++++++++++++++++++++++--
 1 file changed, 40 insertions(+), 3 deletions(-)

diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c
index 4ad665757dd8..840667a82f71 100644
--- a/drivers/i2c/muxes/i2c-mux-pca954x.c
+++ b/drivers/i2c/muxes/i2c-mux-pca954x.c
@@ -39,6 +39,7 @@
 #include <linux/i2c-mux.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
+#include <linux/ktime.h>
 #include <linux/module.h>
 #include <linux/pm.h>
 #include <linux/property.h>
@@ -414,6 +415,8 @@ static int pca954x_init(struct i2c_client *client, struct pca954x *data)
 static int pca954x_probe(struct i2c_client *client,
 			 const struct i2c_device_id *id)
 {
+	enum gpiod_flags flags = GPIOD_OUT_HIGH;
+	const char *reset_gpio_name = "reset";
 	struct i2c_adapter *adap = client->adapter;
 	struct device *dev = &client->dev;
 	struct gpio_desc *gpio;
@@ -435,9 +438,43 @@ static int pca954x_probe(struct i2c_client *client,
 	data->client = client;
 
 	/* 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);
+	gpio = devm_gpiod_get_optional(dev, reset_gpio_name, flags);
+	if (IS_ERR(gpio)) {
+		ret = PTR_ERR(gpio);
+		/*
+		 * In the case that multiple muxes share a single reset line,
+		 * only one should toggle the reset. The other muxes should
+		 * continue probing, waiting for the reset line to drop.
+		 */
+		if (ret == -EBUSY) {
+			ktime_t exp;
+
+			flags |= GPIOD_FLAGS_BIT_NONEXCLUSIVE;
+			gpio = gpiod_get(dev, reset_gpio_name, flags);
+			if (IS_ERR(gpio))
+				return PTR_ERR(gpio);
+
+			exp = ktime_add_us(ktime_get(), 1000);
+			do {
+				ret = gpiod_get_value_cansleep(gpio);
+				if (ret <= 0)
+					break;
+				usleep_range(5, 50);
+			} while (ktime_before(ktime_get(), exp));
+
+			gpiod_put(gpio);
+			if (ret) {
+				if (ret > 0)
+					ret = -ETIMEDOUT;
+
+				return ret;
+			}
+
+			gpio = NULL;
+		} else {
+			return ret;
+		}
+	}
 	if (gpio) {
 		udelay(1);
 		gpiod_set_value_cansleep(gpio, 0);
-- 
2.27.0


^ permalink raw reply related	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2021-07-27 16:00 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-05-05 21:59 [PATCH] i2c: mux: pca954x: Support multiple devices on a single reset line Eddie James
2021-05-06 22:08 ` Peter Rosin
2021-07-27 15:59   ` Eddie James

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).