Skip to content

Commit 6ef9233

Browse files
author
Jiri Kosina
committed
Merge branch 'for-5.15/goodix' into for-linus
- power management improvement for Goodix driver
2 parents dab6e4f + 25ddd7c commit 6ef9233

1 file changed

Lines changed: 79 additions & 13 deletions

File tree

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

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

2828
struct regulator *vdd;
29+
struct notifier_block nb;
30+
struct mutex regulator_mutex;
2931
struct gpio_desc *reset_gpio;
3032
const struct goodix_i2c_hid_timing_data *timings;
3133
};
3234

33-
static int goodix_i2c_hid_power_up(struct i2chid_ops *ops)
35+
static void goodix_i2c_hid_deassert_reset(struct i2c_hid_of_goodix *ihid_goodix,
36+
bool regulator_just_turned_on)
3437
{
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)
38+
if (regulator_just_turned_on && ihid_goodix->timings->post_power_delay_ms)
4439
msleep(ihid_goodix->timings->post_power_delay_ms);
4540

4641
gpiod_set_value_cansleep(ihid_goodix->reset_gpio, 0);
4742
if (ihid_goodix->timings->post_gpio_reset_delay_ms)
4843
msleep(ihid_goodix->timings->post_gpio_reset_delay_ms);
44+
}
4945

50-
return 0;
46+
static int goodix_i2c_hid_power_up(struct i2chid_ops *ops)
47+
{
48+
struct i2c_hid_of_goodix *ihid_goodix =
49+
container_of(ops, struct i2c_hid_of_goodix, ops);
50+
51+
return regulator_enable(ihid_goodix->vdd);
5152
}
5253

5354
static void goodix_i2c_hid_power_down(struct i2chid_ops *ops)
5455
{
5556
struct i2c_hid_of_goodix *ihid_goodix =
5657
container_of(ops, struct i2c_hid_of_goodix, ops);
5758

58-
gpiod_set_value_cansleep(ihid_goodix->reset_gpio, 1);
5959
regulator_disable(ihid_goodix->vdd);
6060
}
6161

62+
static int ihid_goodix_vdd_notify(struct notifier_block *nb,
63+
unsigned long event,
64+
void *ignored)
65+
{
66+
struct i2c_hid_of_goodix *ihid_goodix =
67+
container_of(nb, struct i2c_hid_of_goodix, nb);
68+
int ret = NOTIFY_OK;
69+
70+
mutex_lock(&ihid_goodix->regulator_mutex);
71+
72+
switch (event) {
73+
case REGULATOR_EVENT_PRE_DISABLE:
74+
gpiod_set_value_cansleep(ihid_goodix->reset_gpio, 1);
75+
break;
76+
77+
case REGULATOR_EVENT_ENABLE:
78+
goodix_i2c_hid_deassert_reset(ihid_goodix, true);
79+
break;
80+
81+
case REGULATOR_EVENT_ABORT_DISABLE:
82+
goodix_i2c_hid_deassert_reset(ihid_goodix, false);
83+
break;
84+
85+
default:
86+
ret = NOTIFY_DONE;
87+
break;
88+
}
89+
90+
mutex_unlock(&ihid_goodix->regulator_mutex);
91+
92+
return ret;
93+
}
94+
6295
static int i2c_hid_of_goodix_probe(struct i2c_client *client,
6396
const struct i2c_device_id *id)
6497
{
6598
struct i2c_hid_of_goodix *ihid_goodix;
66-
99+
int ret;
67100
ihid_goodix = devm_kzalloc(&client->dev, sizeof(*ihid_goodix),
68101
GFP_KERNEL);
69102
if (!ihid_goodix)
70103
return -ENOMEM;
71104

105+
mutex_init(&ihid_goodix->regulator_mutex);
106+
72107
ihid_goodix->ops.power_up = goodix_i2c_hid_power_up;
73108
ihid_goodix->ops.power_down = goodix_i2c_hid_power_down;
74109

@@ -84,6 +119,37 @@ static int i2c_hid_of_goodix_probe(struct i2c_client *client,
84119

85120
ihid_goodix->timings = device_get_match_data(&client->dev);
86121

122+
/*
123+
* We need to control the "reset" line in lockstep with the regulator
124+
* actually turning on an off instead of just when we make the request.
125+
* This matters if the regulator is shared with another consumer.
126+
* - If the regulator is off then we must assert reset. The reset
127+
* line is active low and on some boards it could cause a current
128+
* leak if left high.
129+
* - If the regulator is on then we don't want reset asserted for very
130+
* long. Holding the controller in reset apparently draws extra
131+
* power.
132+
*/
133+
mutex_lock(&ihid_goodix->regulator_mutex);
134+
ihid_goodix->nb.notifier_call = ihid_goodix_vdd_notify;
135+
ret = devm_regulator_register_notifier(ihid_goodix->vdd, &ihid_goodix->nb);
136+
if (ret) {
137+
mutex_unlock(&ihid_goodix->regulator_mutex);
138+
return dev_err_probe(&client->dev, ret,
139+
"regulator notifier request failed\n");
140+
}
141+
142+
/*
143+
* If someone else is holding the regulator on (or the regulator is
144+
* an always-on one) we might never be told to deassert reset. Do it
145+
* now. Here we'll assume that someone else might have _just
146+
* barely_ turned the regulator on so we'll do the full
147+
* "post_power_delay" just in case.
148+
*/
149+
if (ihid_goodix->reset_gpio && regulator_is_enabled(ihid_goodix->vdd))
150+
goodix_i2c_hid_deassert_reset(ihid_goodix, true);
151+
mutex_unlock(&ihid_goodix->regulator_mutex);
152+
87153
return i2c_hid_core_probe(client, &ihid_goodix->ops, 0x0001);
88154
}
89155

0 commit comments

Comments
 (0)