Add reset GPIO support to the generic i2c-hid-of driver This is necessary to make the Wacom digitizer on the Lenovo Yoga Book 1 (yb1-x90f/l) work and this will also allow consolidating the 2 specialized i2c-hid-of-elan.c and i2c-hid-of-goodix.c drivers into the generic i2c-hid-of driver. For now the new "post-reset-deassert-delay-ms" property is only used on x86/ACPI (non devicetree) devs. IOW it is not used in actual devicetree files and the same goes for the reset GPIO. The devicetree-bindings maintainers have requested properties like these to not be added to the devicetree-bindings, so the new property + GPIO are deliberately not added to the existing devicetree-bindings. Signed-off-by: Hans de Goede <hdegoede@xxxxxxxxxx> --- Chanhes in v2: - Add a comment to the "post-reset-deassert-delay-ms" property reading, that it is a kernel internal (non public) property used between x86 platform code and the i2c-hid driver. --- drivers/hid/i2c-hid/i2c-hid-of.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/drivers/hid/i2c-hid/i2c-hid-of.c b/drivers/hid/i2c-hid/i2c-hid-of.c index 385f7460e03c..855f53092f4e 100644 --- a/drivers/hid/i2c-hid/i2c-hid-of.c +++ b/drivers/hid/i2c-hid/i2c-hid-of.c @@ -21,6 +21,7 @@ #include <linux/delay.h> #include <linux/device.h> +#include <linux/gpio/consumer.h> #include <linux/hid.h> #include <linux/i2c.h> #include <linux/kernel.h> @@ -35,8 +36,10 @@ struct i2c_hid_of { struct i2chid_ops ops; struct i2c_client *client; + struct gpio_desc *reset_gpio; struct regulator_bulk_data supplies[2]; int post_power_delay_ms; + int post_reset_delay_ms; }; static int i2c_hid_of_power_up(struct i2chid_ops *ops) @@ -55,6 +58,10 @@ static int i2c_hid_of_power_up(struct i2chid_ops *ops) if (ihid_of->post_power_delay_ms) msleep(ihid_of->post_power_delay_ms); + gpiod_set_value_cansleep(ihid_of->reset_gpio, 0); + if (ihid_of->post_reset_delay_ms) + msleep(ihid_of->post_reset_delay_ms); + return 0; } @@ -62,6 +69,7 @@ static void i2c_hid_of_power_down(struct i2chid_ops *ops) { struct i2c_hid_of *ihid_of = container_of(ops, struct i2c_hid_of, ops); + gpiod_set_value_cansleep(ihid_of->reset_gpio, 1); regulator_bulk_disable(ARRAY_SIZE(ihid_of->supplies), ihid_of->supplies); } @@ -96,6 +104,19 @@ static int i2c_hid_of_probe(struct i2c_client *client) if (!device_property_read_u32(dev, "post-power-on-delay-ms", &val)) ihid_of->post_power_delay_ms = val; + /* + * Note this is a kernel internal device-property set by x86 platform code, + * this MUST not be used in devicetree files without first adding it to + * the DT bindings. + */ + if (!device_property_read_u32(dev, "post-reset-deassert-delay-ms", &val)) + ihid_of->post_reset_delay_ms = val; + + /* Start out with reset asserted */ + ihid_of->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(ihid_of->reset_gpio)) + return PTR_ERR(ihid_of->reset_gpio); + ihid_of->supplies[0].supply = "vdd"; ihid_of->supplies[1].supply = "vddl"; ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ihid_of->supplies), -- 2.39.1