lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Wed, 15 Nov 2023 16:57:53 +1300
From:   Chris Packham <chris.packham@...iedtelesis.co.nz>
To:     wsa@...nel.org, andi.shyti@...nel.org, robh+dt@...nel.org,
        krzysztof.kozlowski+dt@...aro.org, conor+dt@...nel.org,
        gregory.clement@...tlin.com
Cc:     linux-i2c@...r.kernel.org, devicetree@...r.kernel.org,
        linux-kernel@...r.kernel.org,
        Chris Packham <chris.packham@...iedtelesis.co.nz>
Subject: [PATCH v6 2/2] i2c: add an optional bus-reset-gpios property

Some hardware designs have a GPIO used to control the reset of all the
devices on and I2C bus. It's not possible for every child node to
declare a reset-gpios property as only the first device probed would be
able to successfully request it. Represent this kind of hardware design
by associating the bus-reset-gpios with the parent I2C bus. The reset
line will be released prior to the child I2C devices being probed.

Signed-off-by: Chris Packham <chris.packham@...iedtelesis.co.nz>
---

Notes:
    Changes in v6:
    - Retarget changes at the i2c core instead of an individual driver
    Changes in v5:
    - Rename reset-gpios and reset-duration-us to bus-reset-gpios and
      bus-reset-duration-us as requested by Wolfram
    Changes in v4:
    - Add missing gpio/consumer.h
    - use fsleep() for enforcing reset-duration
    Changes in v3:
    - Rename reset-delay to reset-duration
    - Use reset-duration-us property to control the reset pulse rather than
      delaying after the reset
    Changes in v2:
    - Add a property to cover the length of delay after releasing the reset
      GPIO
    - Use dev_err_probe() when requesing the GPIO fails

 drivers/i2c/i2c-core-base.c | 39 +++++++++++++++++++++++++++++++++++++
 include/linux/i2c.h         |  3 +++
 2 files changed, 42 insertions(+)

diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c
index 60746652fd52..d7f53272487b 100644
--- a/drivers/i2c/i2c-core-base.c
+++ b/drivers/i2c/i2c-core-base.c
@@ -1468,6 +1468,39 @@ int i2c_handle_smbus_host_notify(struct i2c_adapter *adap, unsigned short addr)
 }
 EXPORT_SYMBOL_GPL(i2c_handle_smbus_host_notify);
 
+static int i2c_setup_bus_reset_gpio(struct i2c_adapter *adap)
+{
+	int res;
+
+	adap->reset_gpios = devm_gpiod_get_array_optional(&adap->dev, "bus-reset", GPIOD_OUT_HIGH);
+	if (IS_ERR(adap->reset_gpios))
+		return dev_err_probe(&adap->dev, PTR_ERR(adap->reset_gpios),
+				     "Cannot get reset gpio\n");
+	res = device_property_read_u32(&adap->dev, "bus-reset-duration-us", &adap->reset_duration);
+	if (res)
+		adap->reset_duration = 1;
+
+	return 0;
+}
+
+static void i2c_deassert_bus_reset_gpio(struct i2c_adapter *adap)
+{
+	unsigned long *values;
+
+	if (!adap->reset_gpios)
+		return;
+
+	values = bitmap_zalloc(adap->reset_gpios->ndescs, GFP_KERNEL);
+	if (!values)
+		return;
+
+	gpiod_set_array_value_cansleep(adap->reset_gpios->ndescs,
+			adap->reset_gpios->desc, adap->reset_gpios->info,
+			values);
+
+	bitmap_free(values);
+}
+
 static int i2c_register_adapter(struct i2c_adapter *adap)
 {
 	int res = -EINVAL;
@@ -1521,6 +1554,10 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
 	if (res)
 		goto out_reg;
 
+	res = i2c_setup_bus_reset_gpio(adap);
+	if (res)
+		goto out_reg;
+
 	device_enable_async_suspend(&adap->dev);
 	pm_runtime_no_callbacks(&adap->dev);
 	pm_suspend_ignore_children(&adap->dev, true);
@@ -1539,6 +1576,8 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
 		dev_warn(&adap->dev,
 			 "Failed to create compatibility class link\n");
 #endif
+	/* bring downstream devices out of reset */
+	i2c_deassert_bus_reset_gpio(adap);
 
 	/* create pre-declared device nodes */
 	of_i2c_register_devices(adap);
diff --git a/include/linux/i2c.h b/include/linux/i2c.h
index 0dae9db27538..1110a49dcdaf 100644
--- a/include/linux/i2c.h
+++ b/include/linux/i2c.h
@@ -746,6 +746,9 @@ struct i2c_adapter {
 
 	struct irq_domain *host_notify_domain;
 	struct regulator *bus_regulator;
+
+	struct gpio_descs *reset_gpios;
+	u32 reset_duration;
 };
 #define to_i2c_adapter(d) container_of(d, struct i2c_adapter, dev)
 
-- 
2.42.0

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ