mbox series

[0/1] Input: rmi_i2c: introduce reset GPIO handling

Message ID 20250210050220.634497-1-felix@kaechele.ca
Headers show
Series Input: rmi_i2c: introduce reset GPIO handling | expand

Message

Felix Kaechele Feb. 10, 2025, 5:02 a.m. UTC
This patch adds handling of the GPIO reset line on Synaptics hardware
using the rmi4 driver.

The syna,reset-delay-ms device tree property is already documented in
the bindings but was seemingly never implemented in the kernel driver.
This property can be found being used in some downstream dts files,
mostly for Qualcomm-based smartphones.

Adding support to the mainline driver makes devices that require
asserting the reset pin work properly.

Cc: Barnabás Czémán <barnabas.czeman@mainlining.org>

Felix Kaechele (1):
  Input: rmi_i2c: introduce reset GPIO handling

 drivers/input/rmi4/rmi_driver.c |  1 -
 drivers/input/rmi4/rmi_driver.h |  2 ++
 drivers/input/rmi4/rmi_i2c.c    | 23 +++++++++++++++++++++++
 3 files changed, 25 insertions(+), 1 deletion(-)


base-commit: a7550ff59edfc768a8600c1e5c24c304208696a5

Comments

Barnabás Czémán Feb. 10, 2025, 5:48 a.m. UTC | #1
On February 10, 2025 6:02:09 AM GMT+01:00, Felix Kaechele <felix@kaechele.ca> wrote:
>Implement reset GPIO handling logic for the rmi_i2c driver. This logic
>is required for some mobile devices to successfully initialize the touch
>controller.
>
>The timings for the assertion of the reset GPIO were derived from the
>GPLv2+ licensed synaptics-dsx-v2.1 vendor driver release and research I
>conducted into downstream device tree sources. Values of 10ms to 20ms
>are commonly found.
>
>Tested-On: Motorola Moto G5 Plus (XT1685 "potter")
>
>Signed-off-by: Felix Kaechele <felix@kaechele.ca>
>---
> drivers/input/rmi4/rmi_driver.c |  1 -
> drivers/input/rmi4/rmi_driver.h |  2 ++
> drivers/input/rmi4/rmi_i2c.c    | 23 +++++++++++++++++++++++
> 3 files changed, 25 insertions(+), 1 deletion(-)

Tested-by: Barnabás Czémán <barnabas.czeman@mainlining.org>

>
>diff --git a/drivers/input/rmi4/rmi_driver.c b/drivers/input/rmi4/rmi_driver.c
>index 2168b6cd7167..ff6aed6a11c1 100644
>--- a/drivers/input/rmi4/rmi_driver.c
>+++ b/drivers/input/rmi4/rmi_driver.c
>@@ -30,7 +30,6 @@
> #define RMI4_PAGE_MASK 0xFF00
> 
> #define RMI_DEVICE_RESET_CMD	0x01
>-#define DEFAULT_RESET_DELAY_MS	100
> 
> void rmi_free_function_list(struct rmi_device *rmi_dev)
> {
>diff --git a/drivers/input/rmi4/rmi_driver.h b/drivers/input/rmi4/rmi_driver.h
>index 3bfe9013043e..e01453bd680f 100644
>--- a/drivers/input/rmi4/rmi_driver.h
>+++ b/drivers/input/rmi4/rmi_driver.h
>@@ -16,6 +16,8 @@
> #define SYNAPTICS_INPUT_DEVICE_NAME "Synaptics RMI4 Touch Sensor"
> #define SYNAPTICS_VENDOR_ID 0x06cb
> 
>+#define DEFAULT_RESET_DELAY_MS	100
>+
> #define GROUP(_attrs) { \
> 	.attrs = _attrs,  \
> }
>diff --git a/drivers/input/rmi4/rmi_i2c.c b/drivers/input/rmi4/rmi_i2c.c
>index 3c0c5fd44702..beff566ca2c8 100644
>--- a/drivers/input/rmi4/rmi_i2c.c
>+++ b/drivers/input/rmi4/rmi_i2c.c
>@@ -4,6 +4,7 @@
>  * Copyright (c) 2011 Unixphere
>  */
> 
>+#include <linux/gpio/consumer.h>
> #include <linux/i2c.h>
> #include <linux/rmi.h>
> #include <linux/of.h>
>@@ -26,7 +27,9 @@
>  * @tx_buf_size: Size of the buffer
>  *
>  * @supplies: Array of voltage regulators
>+ * @reset_gpio: Reference to the reset GPIO
>  * @startup_delay: Milliseconds to pause after powering up the regulators
>+ * @reset_delay: Milliseconds to pause after resetting the device
>  */
> struct rmi_i2c_xport {
> 	struct rmi_transport_dev xport;
>@@ -39,7 +42,9 @@ struct rmi_i2c_xport {
> 	size_t tx_buf_size;
> 
> 	struct regulator_bulk_data supplies[2];
>+	struct gpio_desc *reset_gpio;
> 	u32 startup_delay;
>+	u32 reset_delay;
> };
> 
> #define RMI_PAGE_SELECT_REGISTER 0xff
>@@ -227,6 +232,15 @@ static int rmi_i2c_probe(struct i2c_client *client)
> 		return -ENODEV;
> 	}
> 
>+	rmi_i2c->reset_gpio = devm_gpiod_get_optional(&client->dev, "reset",
>+						      GPIOD_OUT_HIGH);
>+	if (IS_ERR(rmi_i2c->reset_gpio)) {
>+		error = PTR_ERR(rmi_i2c->reset_gpio);
>+		dev_err(&client->dev, "failed to get reset GPIO: %d\n", error);
>+		return error;
>+	}
>+	gpiod_set_consumer_name(rmi_i2c->reset_gpio, "rmi4 reset");
>+
> 	rmi_i2c->supplies[0].supply = "vdd";
> 	rmi_i2c->supplies[1].supply = "vio";
> 	error = devm_regulator_bulk_get(&client->dev,
>@@ -251,6 +265,15 @@ static int rmi_i2c_probe(struct i2c_client *client)
> 
> 	msleep(rmi_i2c->startup_delay);
> 
>+	if (rmi_i2c->reset_gpio) {
>+		of_property_read_u32(client->dev.of_node, "syna,reset-delay-ms",
>+				     &rmi_i2c->reset_delay);
>+		gpiod_set_value_cansleep(rmi_i2c->reset_gpio, 1);
>+		usleep_range(10000, 20000);
>+		gpiod_set_value_cansleep(rmi_i2c->reset_gpio, 0);
>+		msleep(rmi_i2c->reset_delay ?: DEFAULT_RESET_DELAY_MS);
>+	}
>+
> 	rmi_i2c->client = client;
> 	mutex_init(&rmi_i2c->page_mutex);
>