diff --git a/drivers/input/touchscreen/ft5x06_ts.c b/drivers/input/touchscreen/ft5x06_ts.c index 48ceadaafd81..e1de4663c0f2 100644 --- a/drivers/input/touchscreen/ft5x06_ts.c +++ b/drivers/input/touchscreen/ft5x06_ts.c @@ -405,6 +405,79 @@ static irqreturn_t ft5x06_ts_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } +static int ft5x06_gpio_configure(struct ft5x06_ts_data *data, bool on) +{ + int err = 0; + + if (on) { + if (gpio_is_valid(data->pdata->irq_gpio)) { + err = gpio_request(data->pdata->irq_gpio, + "ft5x06_irq_gpio"); + if (err) { + dev_err(&data->client->dev, + "irq gpio request failed"); + goto err_irq_gpio_req; + } + + err = gpio_direction_input(data->pdata->irq_gpio); + if (err) { + dev_err(&data->client->dev, + "set_direction for irq gpio failed\n"); + goto err_irq_gpio_dir; + } + } + + if (gpio_is_valid(data->pdata->reset_gpio)) { + err = gpio_request(data->pdata->reset_gpio, + "ft5x06_reset_gpio"); + if (err) { + dev_err(&data->client->dev, + "reset gpio request failed"); + goto err_irq_gpio_dir; + } + + err = gpio_direction_output(data->pdata->reset_gpio, 0); + if (err) { + dev_err(&data->client->dev, + "set_direction for reset gpio failed\n"); + goto err_reset_gpio_dir; + } + msleep(data->pdata->hard_rst_dly); + gpio_set_value_cansleep(data->pdata->reset_gpio, 1); + } + + return 0; + } + if (gpio_is_valid(data->pdata->irq_gpio)) + gpio_free(data->pdata->irq_gpio); + if (gpio_is_valid(data->pdata->reset_gpio)) { + /* + * This is intended to save leakage current + * only. Even if the call(gpio_direction_input) + * fails, only leakage current will be more but + * functionality will not be affected. + */ + err = gpio_direction_input(data->pdata->reset_gpio); + if (err) { + dev_err(&data->client->dev, + "unable to set direction for gpio [%d]\n", + data->pdata->irq_gpio); + } + gpio_free(data->pdata->reset_gpio); + } + + return 0; + +err_reset_gpio_dir: + if (gpio_is_valid(data->pdata->reset_gpio)) + gpio_free(data->pdata->reset_gpio); +err_irq_gpio_dir: + if (gpio_is_valid(data->pdata->irq_gpio)) + gpio_free(data->pdata->irq_gpio); +err_irq_gpio_req: + return err; +} + static int ft5x06_power_on(struct ft5x06_ts_data *data, bool on) { int rc; @@ -618,10 +691,40 @@ static int ft5x06_ts_suspend(struct device *dev) } } + if (data->ts_pinctrl) { + err = pinctrl_select_state(data->ts_pinctrl, + data->pinctrl_state_suspend); + if (err < 0) + dev_err(dev, "Cannot get suspend pinctrl state\n"); + } + + err = ft5x06_gpio_configure(data, false); + if (err < 0) { + dev_err(&data->client->dev, + "failed to put gpios in suspend state\n"); + goto gpio_configure_fail; + } + data->suspended = true; return 0; +gpio_configure_fail: + if (data->ts_pinctrl) { + err = pinctrl_select_state(data->ts_pinctrl, + data->pinctrl_state_active); + if (err < 0) + dev_err(dev, "Cannot get active pinctrl state\n"); + } + if (data->pdata->power_on) { + err = data->pdata->power_on(true); + if (err) + dev_err(dev, "power on failed"); + } else { + err = ft5x06_power_on(data, true); + if (err) + dev_err(dev, "power on failed"); + } pwr_off_fail: if (gpio_is_valid(data->pdata->reset_gpio)) { gpio_set_value_cansleep(data->pdata->reset_gpio, 0); @@ -656,6 +759,20 @@ static int ft5x06_ts_resume(struct device *dev) } } + if (data->ts_pinctrl) { + err = pinctrl_select_state(data->ts_pinctrl, + data->pinctrl_state_active); + if (err < 0) + dev_err(dev, "Cannot get active pinctrl state\n"); + } + + err = ft5x06_gpio_configure(data, true); + if (err < 0) { + dev_err(&data->client->dev, + "failed to put gpios in resue state\n"); + goto err_gpio_configuration; + } + if (gpio_is_valid(data->pdata->reset_gpio)) { gpio_set_value_cansleep(data->pdata->reset_gpio, 0); msleep(data->pdata->hard_rst_dly); @@ -669,6 +786,24 @@ static int ft5x06_ts_resume(struct device *dev) data->suspended = false; return 0; + +err_gpio_configuration: + if (data->ts_pinctrl) { + err = pinctrl_select_state(data->ts_pinctrl, + data->pinctrl_state_suspend); + if (err < 0) + dev_err(dev, "Cannot get suspend pinctrl state\n"); + } + if (data->pdata->power_on) { + err = data->pdata->power_on(false); + if (err) + dev_err(dev, "power off failed"); + } else { + err = ft5x06_power_on(data, false); + if (err) + dev_err(dev, "power off failed"); + } + return err; } static const struct dev_pm_ops ft5x06_ts_pm_ops = { @@ -1604,46 +1739,24 @@ static int ft5x06_ts_probe(struct i2c_client *client, err = ft5x06_ts_pinctrl_init(data); if (!err && data->ts_pinctrl) { + /* + * Pinctrl handle is optional. If pinctrl handle is found + * let pins to be configured in active state. If not + * found continue further without error. + */ err = pinctrl_select_state(data->ts_pinctrl, data->pinctrl_state_active); if (err < 0) { dev_err(&client->dev, "failed to select pin to active state"); - goto pinctrl_deinit; - } - } else { - goto pwr_off; - } - - if (gpio_is_valid(pdata->irq_gpio)) { - err = gpio_request(pdata->irq_gpio, "ft5x06_irq_gpio"); - if (err) { - dev_err(&client->dev, "irq gpio request failed"); - goto err_gpio_req; - } - err = gpio_direction_input(pdata->irq_gpio); - if (err) { - dev_err(&client->dev, - "set_direction for irq gpio failed\n"); - goto free_irq_gpio; } } - if (gpio_is_valid(pdata->reset_gpio)) { - err = gpio_request(pdata->reset_gpio, "ft5x06_reset_gpio"); - if (err) { - dev_err(&client->dev, "reset gpio request failed"); - goto free_irq_gpio; - } - - err = gpio_direction_output(pdata->reset_gpio, 0); - if (err) { - dev_err(&client->dev, - "set_direction for reset gpio failed\n"); - goto free_reset_gpio; - } - msleep(data->pdata->hard_rst_dly); - gpio_set_value_cansleep(data->pdata->reset_gpio, 1); + err = ft5x06_gpio_configure(data, true); + if (err < 0) { + dev_err(&client->dev, + "Failed to configure the gpios\n"); + goto err_gpio_req; } /* make sure CTP already finish startup process */ @@ -1654,14 +1767,14 @@ static int ft5x06_ts_probe(struct i2c_client *client, err = ft5x06_i2c_read(client, ®_addr, 1, ®_value, 1); if (err < 0) { dev_err(&client->dev, "version read failed"); - goto free_reset_gpio; + goto free_gpio; } dev_info(&client->dev, "Device ID = 0x%x\n", reg_value); if ((pdata->family_id != reg_value) && (!pdata->ignore_id_check)) { dev_err(&client->dev, "%s:Unsupported controller\n", __func__); - goto free_reset_gpio; + goto free_gpio; } data->family_id = pdata->family_id; @@ -1672,7 +1785,7 @@ static int ft5x06_ts_probe(struct i2c_client *client, client->dev.driver->name, data); if (err) { dev_err(&client->dev, "request irq failed\n"); - goto free_reset_gpio; + goto free_gpio; } err = device_create_file(&client->dev, &dev_attr_fw_name); @@ -1789,14 +1902,12 @@ free_fw_name_sys: device_remove_file(&client->dev, &dev_attr_fw_name); irq_free: free_irq(client->irq, data); -free_reset_gpio: +free_gpio: if (gpio_is_valid(pdata->reset_gpio)) gpio_free(pdata->reset_gpio); -free_irq_gpio: if (gpio_is_valid(pdata->irq_gpio)) gpio_free(pdata->irq_gpio); err_gpio_req: -pinctrl_deinit: if (data->ts_pinctrl) { if (IS_ERR_OR_NULL(data->pinctrl_state_release)) { devm_pinctrl_put(data->ts_pinctrl); @@ -1808,7 +1919,6 @@ pinctrl_deinit: pr_err("failed to select relase pinctrl state\n"); } } -pwr_off: if (pdata->power_on) pdata->power_on(false); else