Skip to content

Commit c0cd2d8

Browse files
jhovoldgregkh
authored andcommitted
HID: i2c-hid: elan: fix reset suspend current leakage
[ Upstream commit 0eafc58 ] 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]> Signed-off-by: Sasha Levin <[email protected]>
1 parent 274ecd4 commit c0cd2d8

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

@@ -80,6 +97,7 @@ static int i2c_hid_of_elan_probe(struct i2c_client *client,
8097
const struct i2c_device_id *id)
8198
{
8299
struct i2c_hid_of_elan *ihid_elan;
100+
int ret;
83101

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

115+
ihid_elan->no_reset_on_power_off = of_property_read_bool(client->dev.of_node,
116+
"no-reset-on-power-off");
117+
97118
ihid_elan->vccio = devm_regulator_get(&client->dev, "vccio");
98-
if (IS_ERR(ihid_elan->vccio))
99-
return PTR_ERR(ihid_elan->vccio);
119+
if (IS_ERR(ihid_elan->vccio)) {
120+
ret = PTR_ERR(ihid_elan->vccio);
121+
goto err_deassert_reset;
122+
}
100123

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

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

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

114149
static const struct elan_i2c_hid_chip_data elan_ekth6915_chip_data = {

0 commit comments

Comments
 (0)