Skip to content

Commit 0eafc58

Browse files
jhovoldBenjamin Tissoires
authored andcommitted
HID: i2c-hid: elan: fix reset suspend current leakage
The Elan eKTH5015M touch controller found on the Lenovo ThinkPad X13s shares the VCC33 supply with other peripherals that may remain powered during suspend (e.g. when enabled as wakeup sources). The reset line is also wired so that it can be left deasserted when the supply is off. This is important as it avoids holding the controller in reset for extended periods of time when it remains powered, which can lead to increased power consumption, and also avoids leaking current through the X13s reset circuitry during suspend (and after driver unbind). Use the new 'no-reset-on-power-off' devicetree property to determine when reset needs to be asserted on power down. Notably this also avoids wasting power on machine variants without a touchscreen for which the driver would otherwise exit probe with reset asserted. Fixes: bd3cba0 ("HID: i2c-hid: elan: Add support for Elan eKTH6915 i2c-hid touchscreens") Cc: <[email protected]> # 6.0 Cc: Douglas Anderson <[email protected]> Tested-by: Steev Klimaszewski <[email protected]> Signed-off-by: Johan Hovold <[email protected]> Reviewed-by: Douglas Anderson <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Benjamin Tissoires <[email protected]>
1 parent e538d4b commit 0eafc58

File tree

1 file changed

+47
-12
lines changed

1 file changed

+47
-12
lines changed

drivers/hid/i2c-hid/i2c-hid-of-elan.c

Lines changed: 47 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ struct i2c_hid_of_elan {
3131
struct regulator *vcc33;
3232
struct regulator *vccio;
3333
struct gpio_desc *reset_gpio;
34+
bool no_reset_on_power_off;
3435
const struct elan_i2c_hid_chip_data *chip_data;
3536
};
3637

@@ -40,17 +41,17 @@ static int elan_i2c_hid_power_up(struct i2chid_ops *ops)
4041
container_of(ops, struct i2c_hid_of_elan, ops);
4142
int ret;
4243

44+
gpiod_set_value_cansleep(ihid_elan->reset_gpio, 1);
45+
4346
if (ihid_elan->vcc33) {
4447
ret = regulator_enable(ihid_elan->vcc33);
4548
if (ret)
46-
return ret;
49+
goto err_deassert_reset;
4750
}
4851

4952
ret = regulator_enable(ihid_elan->vccio);
50-
if (ret) {
51-
regulator_disable(ihid_elan->vcc33);
52-
return ret;
53-
}
53+
if (ret)
54+
goto err_disable_vcc33;
5455

5556
if (ihid_elan->chip_data->post_power_delay_ms)
5657
msleep(ihid_elan->chip_data->post_power_delay_ms);
@@ -60,14 +61,30 @@ static int elan_i2c_hid_power_up(struct i2chid_ops *ops)
6061
msleep(ihid_elan->chip_data->post_gpio_reset_on_delay_ms);
6162

6263
return 0;
64+
65+
err_disable_vcc33:
66+
if (ihid_elan->vcc33)
67+
regulator_disable(ihid_elan->vcc33);
68+
err_deassert_reset:
69+
if (ihid_elan->no_reset_on_power_off)
70+
gpiod_set_value_cansleep(ihid_elan->reset_gpio, 0);
71+
72+
return ret;
6373
}
6474

6575
static void elan_i2c_hid_power_down(struct i2chid_ops *ops)
6676
{
6777
struct i2c_hid_of_elan *ihid_elan =
6878
container_of(ops, struct i2c_hid_of_elan, ops);
6979

70-
gpiod_set_value_cansleep(ihid_elan->reset_gpio, 1);
80+
/*
81+
* Do not assert reset when the hardware allows for it to remain
82+
* deasserted regardless of the state of the (shared) power supply to
83+
* avoid wasting power when the supply is left on.
84+
*/
85+
if (!ihid_elan->no_reset_on_power_off)
86+
gpiod_set_value_cansleep(ihid_elan->reset_gpio, 1);
87+
7188
if (ihid_elan->chip_data->post_gpio_reset_off_delay_ms)
7289
msleep(ihid_elan->chip_data->post_gpio_reset_off_delay_ms);
7390

@@ -79,6 +96,7 @@ static void elan_i2c_hid_power_down(struct i2chid_ops *ops)
7996
static int i2c_hid_of_elan_probe(struct i2c_client *client)
8097
{
8198
struct i2c_hid_of_elan *ihid_elan;
99+
int ret;
82100

83101
ihid_elan = devm_kzalloc(&client->dev, sizeof(*ihid_elan), GFP_KERNEL);
84102
if (!ihid_elan)
@@ -93,21 +111,38 @@ static int i2c_hid_of_elan_probe(struct i2c_client *client)
93111
if (IS_ERR(ihid_elan->reset_gpio))
94112
return PTR_ERR(ihid_elan->reset_gpio);
95113

114+
ihid_elan->no_reset_on_power_off = of_property_read_bool(client->dev.of_node,
115+
"no-reset-on-power-off");
116+
96117
ihid_elan->vccio = devm_regulator_get(&client->dev, "vccio");
97-
if (IS_ERR(ihid_elan->vccio))
98-
return PTR_ERR(ihid_elan->vccio);
118+
if (IS_ERR(ihid_elan->vccio)) {
119+
ret = PTR_ERR(ihid_elan->vccio);
120+
goto err_deassert_reset;
121+
}
99122

100123
ihid_elan->chip_data = device_get_match_data(&client->dev);
101124

102125
if (ihid_elan->chip_data->main_supply_name) {
103126
ihid_elan->vcc33 = devm_regulator_get(&client->dev,
104127
ihid_elan->chip_data->main_supply_name);
105-
if (IS_ERR(ihid_elan->vcc33))
106-
return PTR_ERR(ihid_elan->vcc33);
128+
if (IS_ERR(ihid_elan->vcc33)) {
129+
ret = PTR_ERR(ihid_elan->vcc33);
130+
goto err_deassert_reset;
131+
}
107132
}
108133

109-
return i2c_hid_core_probe(client, &ihid_elan->ops,
110-
ihid_elan->chip_data->hid_descriptor_address, 0);
134+
ret = i2c_hid_core_probe(client, &ihid_elan->ops,
135+
ihid_elan->chip_data->hid_descriptor_address, 0);
136+
if (ret)
137+
goto err_deassert_reset;
138+
139+
return 0;
140+
141+
err_deassert_reset:
142+
if (ihid_elan->no_reset_on_power_off)
143+
gpiod_set_value_cansleep(ihid_elan->reset_gpio, 0);
144+
145+
return ret;
111146
}
112147

113148
static const struct elan_i2c_hid_chip_data elan_ekth6915_chip_data = {

0 commit comments

Comments
 (0)