Skip to content

Commit 557e05f

Browse files
diandersbentiss
authored andcommitted
HID: i2c-hid: goodix: Stop tying the reset line to the regulator
In commit 18eeef4 ("HID: i2c-hid: goodix: Tie the reset line to true state of the regulator"), we started tying the reset line of Goodix touchscreens to the regulator. The primary motivation for that patch was some pre-production hardware (specifically sc7180-trogdor-homestar) where it was proposed to hook the touchscreen's main 3.3V power rail to an always-on supply. In such a case, when we turned "off" the touchscreen in Linux it was bad to assert the "reset" GPIO because that was causing a power drain. The patch accomplished that goal and did it in a general sort of way that didn't require special properties to be added in the device tree for homestar. It turns out that the design of using an always-on power rail for the touchscreen was rejected soon after the patch was written and long before sc7180-trogdor-homestar went into production. The final design of homestar actually fully separates the rail for the touchscreen and the display panel and both can be powered off and on. That means that the original motivation for the feature is gone. There are 3 other users of the goodix i2c-hid driver in mainline. I'll first talk about 2 of the other users in mainline: coachz and mrbland. On both coachz and mrbland the touchscreen power and panel power _are_ shared. That means that the patch to tie the reset line to the true state of the regulator _is_ doing something on those boards. Specifically, the patch reduced power consumption by tens of mA in the case where we turned the touchscreen off but left the panel on. Other than saving a small bit of power, the patch wasn't truly necessary. That being said, even though a small bit of power was saved in the state of "panel on + touchscreen off", that's not actually a state we ever expect to be in, except perhaps for very short periods of time at boot or during suspend/resume. Thus, the patch is truly not necessary. It should be further noted that, as documented in the original patch, the current code still didn't optimize power for every corner case of the "shared rail" situation. The last user in mainline was very recently added: evoker. Evoker is actually the motivation for me removing this bit of code. It turns out that for evoker we need to manage a second power rail for IO to the touchscreen. Trying to fit the management of this IO rail into the regulator notifiers turns out to be extremely hard. To avoid lockdep splats you shouldn't enable/disable other regulators in regulator notifiers and trying to find a way around this was going to be fairly difficult. Given the lack of any true motivation to tie the reset line to the regulator, lets go back to the simpler days and remove the code. This is, effectively, a revert of commit bdbc65e ("HID: i2c-hid: goodix: Fix a lockdep splat"), commit 25ddd7c ("HID: i2c-hid: goodix: Use the devm variant of regulator_register_notifier()"), and commit 18eeef4 ("HID: i2c-hid: goodix: Tie the reset line to true state of the regulator"). Signed-off-by: Douglas Anderson <[email protected]> Reviewed-by: Matthias Kaehlcke <[email protected]> Reviewed-by: Dmitry Torokhov <[email protected]> Link: https://lore.kernel.org/r/20230206184744.4.I085b32b6140c7d1ac4e7e97b712bff9dd5962b62@changeid Signed-off-by: Benjamin Tissoires <[email protected]>
1 parent 4122abf commit 557e05f

File tree

1 file changed

+13
-75
lines changed

1 file changed

+13
-75
lines changed

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

Lines changed: 13 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -26,71 +26,43 @@ struct i2c_hid_of_goodix {
2626
struct i2chid_ops ops;
2727

2828
struct regulator *vdd;
29-
struct notifier_block nb;
3029
struct gpio_desc *reset_gpio;
3130
const struct goodix_i2c_hid_timing_data *timings;
3231
};
3332

34-
static void goodix_i2c_hid_deassert_reset(struct i2c_hid_of_goodix *ihid_goodix,
35-
bool regulator_just_turned_on)
33+
static int goodix_i2c_hid_power_up(struct i2chid_ops *ops)
3634
{
37-
if (regulator_just_turned_on && ihid_goodix->timings->post_power_delay_ms)
35+
struct i2c_hid_of_goodix *ihid_goodix =
36+
container_of(ops, struct i2c_hid_of_goodix, ops);
37+
int ret;
38+
39+
ret = regulator_enable(ihid_goodix->vdd);
40+
if (ret)
41+
return ret;
42+
43+
if (ihid_goodix->timings->post_power_delay_ms)
3844
msleep(ihid_goodix->timings->post_power_delay_ms);
3945

4046
gpiod_set_value_cansleep(ihid_goodix->reset_gpio, 0);
4147
if (ihid_goodix->timings->post_gpio_reset_delay_ms)
4248
msleep(ihid_goodix->timings->post_gpio_reset_delay_ms);
43-
}
44-
45-
static int goodix_i2c_hid_power_up(struct i2chid_ops *ops)
46-
{
47-
struct i2c_hid_of_goodix *ihid_goodix =
48-
container_of(ops, struct i2c_hid_of_goodix, ops);
4949

50-
return regulator_enable(ihid_goodix->vdd);
50+
return 0;
5151
}
5252

5353
static void goodix_i2c_hid_power_down(struct i2chid_ops *ops)
5454
{
5555
struct i2c_hid_of_goodix *ihid_goodix =
5656
container_of(ops, struct i2c_hid_of_goodix, ops);
5757

58+
gpiod_set_value_cansleep(ihid_goodix->reset_gpio, 1);
5859
regulator_disable(ihid_goodix->vdd);
5960
}
6061

61-
static int ihid_goodix_vdd_notify(struct notifier_block *nb,
62-
unsigned long event,
63-
void *ignored)
64-
{
65-
struct i2c_hid_of_goodix *ihid_goodix =
66-
container_of(nb, struct i2c_hid_of_goodix, nb);
67-
int ret = NOTIFY_OK;
68-
69-
switch (event) {
70-
case REGULATOR_EVENT_PRE_DISABLE:
71-
gpiod_set_value_cansleep(ihid_goodix->reset_gpio, 1);
72-
break;
73-
74-
case REGULATOR_EVENT_ENABLE:
75-
goodix_i2c_hid_deassert_reset(ihid_goodix, true);
76-
break;
77-
78-
case REGULATOR_EVENT_ABORT_DISABLE:
79-
goodix_i2c_hid_deassert_reset(ihid_goodix, false);
80-
break;
81-
82-
default:
83-
ret = NOTIFY_DONE;
84-
break;
85-
}
86-
87-
return ret;
88-
}
89-
9062
static int i2c_hid_of_goodix_probe(struct i2c_client *client)
9163
{
9264
struct i2c_hid_of_goodix *ihid_goodix;
93-
int ret;
65+
9466
ihid_goodix = devm_kzalloc(&client->dev, sizeof(*ihid_goodix),
9567
GFP_KERNEL);
9668
if (!ihid_goodix)
@@ -111,40 +83,6 @@ static int i2c_hid_of_goodix_probe(struct i2c_client *client)
11183

11284
ihid_goodix->timings = device_get_match_data(&client->dev);
11385

114-
/*
115-
* We need to control the "reset" line in lockstep with the regulator
116-
* actually turning on an off instead of just when we make the request.
117-
* This matters if the regulator is shared with another consumer.
118-
* - If the regulator is off then we must assert reset. The reset
119-
* line is active low and on some boards it could cause a current
120-
* leak if left high.
121-
* - If the regulator is on then we don't want reset asserted for very
122-
* long. Holding the controller in reset apparently draws extra
123-
* power.
124-
*/
125-
ihid_goodix->nb.notifier_call = ihid_goodix_vdd_notify;
126-
ret = devm_regulator_register_notifier(ihid_goodix->vdd, &ihid_goodix->nb);
127-
if (ret)
128-
return dev_err_probe(&client->dev, ret,
129-
"regulator notifier request failed\n");
130-
131-
/*
132-
* If someone else is holding the regulator on (or the regulator is
133-
* an always-on one) we might never be told to deassert reset. Do it
134-
* now... and temporarily bump the regulator reference count just to
135-
* make sure it is impossible for this to race with our own notifier!
136-
* We also assume that someone else might have _just barely_ turned
137-
* the regulator on so we'll do the full "post_power_delay" just in
138-
* case.
139-
*/
140-
if (ihid_goodix->reset_gpio && regulator_is_enabled(ihid_goodix->vdd)) {
141-
ret = regulator_enable(ihid_goodix->vdd);
142-
if (ret)
143-
return ret;
144-
goodix_i2c_hid_deassert_reset(ihid_goodix, true);
145-
regulator_disable(ihid_goodix->vdd);
146-
}
147-
14886
return i2c_hid_core_probe(client, &ihid_goodix->ops, 0x0001, 0);
14987
}
15088

0 commit comments

Comments
 (0)