forked from Minki/linux
Input: edt-ft5x06 - add support for iovcc-supply
At the moment, the edt-ft5x06 driver can control a single regulator ("vcc"). However, some FocalTech touch controllers have an additional IOVCC pin that should be supplied with the digital I/O voltage. The I/O voltage might be provided by another regulator that should also be kept on. Otherwise, the touchscreen can randomly stop functioning if the regulator is turned off because no other components still require it. Implement (optional) support for also enabling an "iovcc-supply". The datasheet specifies a delay of ~ 10us before enabling VDD/VCC after IOVCC is enabled, so make sure to enable IOVCC first. Signed-off-by: Stephan Gerhold <stephan@gerhold.net> Link: https://lore.kernel.org/r/20210510193108.50178-2-stephan@gerhold.net Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
This commit is contained in:
parent
77191c8d6c
commit
df4c40f484
@ -104,6 +104,7 @@ struct edt_ft5x06_ts_data {
|
||||
u16 num_x;
|
||||
u16 num_y;
|
||||
struct regulator *vcc;
|
||||
struct regulator *iovcc;
|
||||
|
||||
struct gpio_desc *reset_gpio;
|
||||
struct gpio_desc *wake_gpio;
|
||||
@ -1062,11 +1063,12 @@ static void edt_ft5x06_ts_set_regs(struct edt_ft5x06_ts_data *tsdata)
|
||||
}
|
||||
}
|
||||
|
||||
static void edt_ft5x06_disable_regulator(void *arg)
|
||||
static void edt_ft5x06_disable_regulators(void *arg)
|
||||
{
|
||||
struct edt_ft5x06_ts_data *data = arg;
|
||||
|
||||
regulator_disable(data->vcc);
|
||||
regulator_disable(data->iovcc);
|
||||
}
|
||||
|
||||
static int edt_ft5x06_ts_probe(struct i2c_client *client,
|
||||
@ -1107,14 +1109,33 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,
|
||||
return error;
|
||||
}
|
||||
|
||||
tsdata->iovcc = devm_regulator_get(&client->dev, "iovcc");
|
||||
if (IS_ERR(tsdata->iovcc)) {
|
||||
error = PTR_ERR(tsdata->iovcc);
|
||||
if (error != -EPROBE_DEFER)
|
||||
dev_err(&client->dev,
|
||||
"failed to request iovcc regulator: %d\n", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
error = regulator_enable(tsdata->iovcc);
|
||||
if (error < 0) {
|
||||
dev_err(&client->dev, "failed to enable iovcc: %d\n", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
/* Delay enabling VCC for > 10us (T_ivd) after IOVCC */
|
||||
usleep_range(10, 100);
|
||||
|
||||
error = regulator_enable(tsdata->vcc);
|
||||
if (error < 0) {
|
||||
dev_err(&client->dev, "failed to enable vcc: %d\n", error);
|
||||
regulator_disable(tsdata->iovcc);
|
||||
return error;
|
||||
}
|
||||
|
||||
error = devm_add_action_or_reset(&client->dev,
|
||||
edt_ft5x06_disable_regulator,
|
||||
edt_ft5x06_disable_regulators,
|
||||
tsdata);
|
||||
if (error)
|
||||
return error;
|
||||
@ -1289,6 +1310,9 @@ static int __maybe_unused edt_ft5x06_ts_suspend(struct device *dev)
|
||||
ret = regulator_disable(tsdata->vcc);
|
||||
if (ret)
|
||||
dev_warn(dev, "Failed to disable vcc\n");
|
||||
ret = regulator_disable(tsdata->iovcc);
|
||||
if (ret)
|
||||
dev_warn(dev, "Failed to disable iovcc\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1319,9 +1343,19 @@ static int __maybe_unused edt_ft5x06_ts_resume(struct device *dev)
|
||||
gpiod_set_value_cansleep(reset_gpio, 1);
|
||||
usleep_range(5000, 6000);
|
||||
|
||||
ret = regulator_enable(tsdata->iovcc);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to enable iovcc\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Delay enabling VCC for > 10us (T_ivd) after IOVCC */
|
||||
usleep_range(10, 100);
|
||||
|
||||
ret = regulator_enable(tsdata->vcc);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to enable vcc\n");
|
||||
regulator_disable(tsdata->iovcc);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user