diff options
| author | Linux Build Service Account <lnxbuild@localhost> | 2016-10-27 15:49:02 -0700 |
|---|---|---|
| committer | Gerrit - the friendly Code Review server <code-review@localhost> | 2016-10-27 15:49:01 -0700 |
| commit | a893d7854bbedeedbe4599ffc6cbfa2b92ba087f (patch) | |
| tree | 58a6e98e074b781a905c5118ade89e5f69c7bca5 /drivers/input | |
| parent | 206ef38970a19ca50e7ff3952e81094e67e473c2 (diff) | |
| parent | c38f93d1100c099fcf968c21d291829c8d8db455 (diff) | |
Merge "input: misc: hbtp_input: Add support for multiple AFE"
Diffstat (limited to 'drivers/input')
| -rw-r--r-- | drivers/input/misc/hbtp_input.c | 674 |
1 files changed, 658 insertions, 16 deletions
diff --git a/drivers/input/misc/hbtp_input.c b/drivers/input/misc/hbtp_input.c index 519e3db4d73e..f94ecf02d9cb 100644 --- a/drivers/input/misc/hbtp_input.c +++ b/drivers/input/misc/hbtp_input.c @@ -23,6 +23,12 @@ #include <linux/regulator/consumer.h> #include <uapi/linux/hbtp_input.h> #include "../input-compat.h" +#include <linux/ktime.h> +#include <linux/uaccess.h> +#include <linux/gpio.h> +#include <linux/of_gpio.h> +#include <linux/delay.h> +#include <linux/completion.h> #if defined(CONFIG_FB) #include <linux/notifier.h> @@ -32,6 +38,10 @@ #define HBTP_INPUT_NAME "hbtp_input" #define DISP_COORDS_SIZE 2 +#define HBTP_PINCTRL_VALID_STATE_CNT (2) +#define HBTP_HOLD_DURATION_US (10) +#define HBTP_PINCTRL_DDIC_SEQ_NUM (4) + struct hbtp_data { struct platform_device *pdev; struct input_dev *input_dev; @@ -41,6 +51,20 @@ struct hbtp_data { #if defined(CONFIG_FB) struct notifier_block fb_notif; #endif + struct pinctrl *ts_pinctrl; + struct pinctrl_state *gpio_state_active; + struct pinctrl_state *gpio_state_suspend; + struct pinctrl_state *ddic_rst_state_active; + struct pinctrl_state *ddic_rst_state_suspend; + u32 ts_pinctrl_seq_delay; + u32 ddic_pinctrl_seq_delay[HBTP_PINCTRL_DDIC_SEQ_NUM]; + u32 fb_resume_seq_delay; + bool lcd_on; + bool power_suspended; + bool power_sync_enabled; + bool power_sig_enabled; + struct completion power_resume_sig; + struct completion power_suspend_sig; struct regulator *vcc_ana; struct regulator *vcc_dig; int afe_load_ua; @@ -59,31 +83,68 @@ struct hbtp_data { bool override_disp_coords; bool manage_afe_power_ana; bool manage_power_dig; + u32 power_on_delay; + u32 power_off_delay; + bool manage_pin_ctrl; }; static struct hbtp_data *hbtp; #if defined(CONFIG_FB) +static int hbtp_fb_suspend(struct hbtp_data *ts); +static int hbtp_fb_early_resume(struct hbtp_data *ts); +static int hbtp_fb_resume(struct hbtp_data *ts); +#endif + +#if defined(CONFIG_FB) static int fb_notifier_callback(struct notifier_block *self, unsigned long event, void *data) { int blank; struct fb_event *evdata = data; struct hbtp_data *hbtp_data = - container_of(self, struct hbtp_data, fb_notif); - char *envp[2] = {HBTP_EVENT_TYPE_DISPLAY, NULL}; + container_of(self, struct hbtp_data, fb_notif); - if (evdata && evdata->data && event == FB_EVENT_BLANK && - hbtp_data && hbtp_data->input_dev) { + if (evdata && evdata->data && hbtp_data && + (event == FB_EARLY_EVENT_BLANK || + event == FB_R_EARLY_EVENT_BLANK)) { blank = *(int *)(evdata->data); - if (blank == FB_BLANK_UNBLANK) - kobject_uevent_env(&hbtp_data->input_dev->dev.kobj, - KOBJ_ONLINE, envp); - else if (blank == FB_BLANK_POWERDOWN) - kobject_uevent_env(&hbtp_data->input_dev->dev.kobj, - KOBJ_OFFLINE, envp); + if (event == FB_EARLY_EVENT_BLANK) { + if (blank == FB_BLANK_UNBLANK) { + pr_debug("%s: receives EARLY_BLANK:UNBLANK\n", + __func__); + hbtp_data->lcd_on = true; + hbtp_fb_early_resume(hbtp_data); + } else if (blank == FB_BLANK_POWERDOWN) { + pr_debug("%s: receives EARLY_BLANK:POWERDOWN\n", + __func__); + hbtp_data->lcd_on = false; + } + } else if (event == FB_R_EARLY_EVENT_BLANK) { + if (blank == FB_BLANK_UNBLANK) { + pr_debug("%s: receives R_EARLY_BALNK:UNBLANK\n", + __func__); + hbtp_data->lcd_on = false; + hbtp_fb_suspend(hbtp_data); + } else if (blank == FB_BLANK_POWERDOWN) { + pr_debug("%s: receives R_EARLY_BALNK:POWERDOWN\n", + __func__); + hbtp_data->lcd_on = true; + } + } } + if (evdata && evdata->data && hbtp_data && + event == FB_EVENT_BLANK) { + blank = *(int *)(evdata->data); + if (blank == FB_BLANK_POWERDOWN) { + pr_debug("%s: receives BLANK:POWERDOWN\n", __func__); + hbtp_fb_suspend(hbtp_data); + } else if (blank == FB_BLANK_UNBLANK) { + pr_debug("%s: receives BLANK:UNBLANK\n", __func__); + hbtp_fb_resume(hbtp_data); + } + } return 0; } #endif @@ -111,6 +172,8 @@ static int hbtp_input_release(struct inode *inode, struct file *file) return -ENOTTY; } hbtp->count--; + if (hbtp->power_sig_enabled) + hbtp->power_sig_enabled = false; mutex_unlock(&hbtp->mutex); return 0; @@ -278,6 +341,14 @@ static int hbtp_pdev_power_on(struct hbtp_data *hbtp, bool on) return ret; } } + + if (hbtp->power_on_delay) { + pr_debug("%s: power-on-delay = %u\n", __func__, + hbtp->power_on_delay); + usleep_range(hbtp->power_on_delay, + hbtp->power_on_delay + HBTP_HOLD_DURATION_US); + } + if (hbtp->vcc_dig) { ret = reg_set_load_check(hbtp->vcc_dig, hbtp->dig_load_ua); @@ -299,17 +370,171 @@ static int hbtp_pdev_power_on(struct hbtp_data *hbtp, bool on) return 0; reg_off: - if (hbtp->vcc_ana) { - reg_set_load_check(hbtp->vcc_ana, 0); - regulator_disable(hbtp->vcc_ana); - } if (hbtp->vcc_dig) { reg_set_load_check(hbtp->vcc_dig, 0); regulator_disable(hbtp->vcc_dig); } + + if (hbtp->power_off_delay) { + pr_debug("%s: power-off-delay = %u\n", __func__, + hbtp->power_off_delay); + usleep_range(hbtp->power_off_delay, + hbtp->power_off_delay + HBTP_HOLD_DURATION_US); + } + + if (hbtp->vcc_ana) { + reg_set_load_check(hbtp->vcc_ana, 0); + regulator_disable(hbtp->vcc_ana); + } return 0; } +static int hbtp_gpio_select(struct hbtp_data *data, bool on) +{ + struct pinctrl_state *pins_state; + int ret = 0; + + pins_state = on ? data->gpio_state_active : data->gpio_state_suspend; + if (!IS_ERR_OR_NULL(pins_state)) { + ret = pinctrl_select_state(data->ts_pinctrl, pins_state); + if (ret) { + dev_err(&data->pdev->dev, + "can not set %s pins\n", + on ? "ts_active" : "ts_suspend"); + return ret; + } + + if (on) { + if (data->ts_pinctrl_seq_delay) { + usleep_range(data->ts_pinctrl_seq_delay, + data->ts_pinctrl_seq_delay + + HBTP_HOLD_DURATION_US); + dev_dbg(&data->pdev->dev, "ts_pinctrl_seq_delay = %u\n", + data->ts_pinctrl_seq_delay); + } + } + } else { + dev_warn(&data->pdev->dev, + "not a valid '%s' pinstate\n", + on ? "ts_active" : "ts_suspend"); + return ret; + } + + return ret; +} + +static int hbtp_ddic_rst_select(struct hbtp_data *data, bool on) +{ + struct pinctrl_state *active, *suspend; + int ret = 0; + + active = data->ddic_rst_state_active; + if (IS_ERR_OR_NULL(active)) { + dev_warn(&data->pdev->dev, + "not a valid ddic_rst_active pinstate\n"); + return ret; + } + + suspend = data->ddic_rst_state_suspend; + if (IS_ERR_OR_NULL(suspend)) { + dev_warn(&data->pdev->dev, + "not a valid ddic_rst_suspend pinstate\n"); + return ret; + } + + if (on) { + if (data->ddic_pinctrl_seq_delay[0]) { + usleep_range(data->ddic_pinctrl_seq_delay[0], + data->ddic_pinctrl_seq_delay[0] + + HBTP_HOLD_DURATION_US); + dev_dbg(&data->pdev->dev, "ddic_seq_delay[0] = %u\n", + data->ddic_pinctrl_seq_delay[0]); + } + + ret = pinctrl_select_state(data->ts_pinctrl, active); + if (ret) { + dev_err(&data->pdev->dev, + "can not set ddic_rst_active pins\n"); + return ret; + } + if (data->ddic_pinctrl_seq_delay[1]) { + usleep_range(data->ddic_pinctrl_seq_delay[1], + data->ddic_pinctrl_seq_delay[1] + + HBTP_HOLD_DURATION_US); + dev_dbg(&data->pdev->dev, "ddic_seq_delay[1] = %u\n", + data->ddic_pinctrl_seq_delay[1]); + } + ret = pinctrl_select_state(data->ts_pinctrl, suspend); + if (ret) { + dev_err(&data->pdev->dev, + "can not set ddic_rst_suspend pins\n"); + return ret; + } + + if (data->ddic_pinctrl_seq_delay[2]) { + usleep_range(data->ddic_pinctrl_seq_delay[2], + data->ddic_pinctrl_seq_delay[2] + + HBTP_HOLD_DURATION_US); + dev_dbg(&data->pdev->dev, "ddic_seq_delay[2] = %u\n", + data->ddic_pinctrl_seq_delay[2]); + } + + ret = pinctrl_select_state(data->ts_pinctrl, active); + if (ret) { + dev_err(&data->pdev->dev, + "can not set ddic_rst_active pins\n"); + return ret; + } + + if (data->ddic_pinctrl_seq_delay[3]) { + usleep_range(data->ddic_pinctrl_seq_delay[3], + data->ddic_pinctrl_seq_delay[3] + + HBTP_HOLD_DURATION_US); + dev_dbg(&data->pdev->dev, "ddic_seq_delay[3] = %u\n", + data->ddic_pinctrl_seq_delay[3]); + } + } else { + ret = pinctrl_select_state(data->ts_pinctrl, suspend); + if (ret) { + dev_err(&data->pdev->dev, + "can not set ddic_rst_suspend pins\n"); + return ret; + } + } + + return ret; +} + +static int hbtp_pinctrl_enable(struct hbtp_data *ts, bool on) +{ + int rc = 0; + + if (!ts->manage_pin_ctrl) { + pr_info("%s: pinctrl info is not available\n", __func__); + return 0; + } + + if (!on) + goto pinctrl_suspend; + + rc = hbtp_gpio_select(ts, true); + if (rc < 0) + return -EINVAL; + + rc = hbtp_ddic_rst_select(ts, true); + if (rc < 0) + goto err_ddic_rst_pinctrl_enable; + + return rc; + +pinctrl_suspend: + if (ts->ddic_rst_state_suspend) + hbtp_ddic_rst_select(ts, true); +err_ddic_rst_pinctrl_enable: + hbtp_gpio_select(ts, false); + return rc; +} + static long hbtp_input_ioctl_handler(struct file *file, unsigned int cmd, unsigned long arg, void __user *p) { @@ -318,6 +543,8 @@ static long hbtp_input_ioctl_handler(struct file *file, unsigned int cmd, struct hbtp_input_absinfo absinfo[ABS_MT_LAST - ABS_MT_FIRST + 1]; struct hbtp_input_key key_data; enum hbtp_afe_power_cmd power_cmd; + enum hbtp_afe_signal afe_signal; + enum hbtp_afe_power_ctrl afe_power_ctrl; switch (cmd) { case HBTP_SET_ABSPARAM: @@ -408,6 +635,112 @@ static long hbtp_input_ioctl_handler(struct file *file, unsigned int cmd, input_sync(hbtp->input_dev); break; + case HBTP_SET_SYNCSIGNAL: + if (!hbtp || !hbtp->input_dev) { + pr_err("%s: The input device hasn't been created\n", + __func__); + return -EFAULT; + } + + if (!hbtp->power_sig_enabled) { + pr_err("%s: power_signal is not enabled", __func__); + return -EPERM; + } + + if (copy_from_user(&afe_signal, (void *)arg, + sizeof(enum hbtp_afe_signal))) { + pr_err("%s: Error copying data\n", __func__); + return -EFAULT; + } + + pr_debug("%s: receives %d signal\n", __func__, afe_signal); + + switch (afe_signal) { + case HBTP_AFE_SIGNAL_ON_RESUME: + mutex_lock(&hbtp->mutex); + if (!hbtp->power_suspended) { + complete(&hbtp->power_resume_sig); + } else { + pr_err("%s: resume signal in wrong state\n", + __func__); + } + mutex_unlock(&hbtp->mutex); + break; + case HBTP_AFE_SIGNAL_ON_SUSPEND: + mutex_lock(&hbtp->mutex); + if (hbtp->power_suspended) { + complete(&hbtp->power_suspend_sig); + } else { + pr_err("%s: suspend signal in wrong state\n", + __func__); + } + mutex_unlock(&hbtp->mutex); + break; + default: + pr_err("%s: Unsupported command for afe signal, %d\n", + __func__, afe_signal); + return -EINVAL; + } + break; + case HBTP_SET_POWER_CTRL: + if (!hbtp || !hbtp->input_dev) { + pr_err("%s: The input device hasn't been created\n", + __func__); + return -EFAULT; + } + + if (copy_from_user(&afe_power_ctrl, (void *)arg, + sizeof(enum hbtp_afe_power_ctrl))) { + pr_err("%s: Error copying data\n", __func__); + return -EFAULT; + } + switch (afe_power_ctrl) { + case HBTP_AFE_POWER_ENABLE_SYNC: + pr_debug("%s: power_sync is enabled\n", __func__); + if (!hbtp->manage_pin_ctrl || !hbtp->manage_power_dig || + !hbtp->manage_afe_power_ana) { + pr_err("%s: power/pin is not available\n", + __func__); + return -EFAULT; + } + mutex_lock(&hbtp->mutex); + error = hbtp_pdev_power_on(hbtp, true); + if (error) { + mutex_unlock(&hbtp->mutex); + pr_err("%s: failed to power on\n", __func__); + return error; + } + error = hbtp_pinctrl_enable(hbtp, true); + if (error) { + mutex_unlock(&hbtp->mutex); + pr_err("%s: failed to enable pins\n", __func__); + hbtp_pdev_power_on(hbtp, false); + return error; + } + hbtp->power_sync_enabled = true; + mutex_unlock(&hbtp->mutex); + pr_debug("%s: power_sync option is enabled\n", + __func__); + break; + case HBTP_AFE_POWER_ENABLE_SYNC_SIGNAL: + if (!hbtp->power_sync_enabled) { + pr_err("%s: power_sync is not enabled\n", + __func__); + return -EFAULT; + } + mutex_lock(&hbtp->mutex); + init_completion(&hbtp->power_resume_sig); + init_completion(&hbtp->power_suspend_sig); + hbtp->power_sig_enabled = true; + mutex_unlock(&hbtp->mutex); + pr_err("%s: sync_signal option is enabled\n", __func__); + break; + default: + pr_err("%s: unsupported power ctrl, %d\n", + __func__, afe_power_ctrl); + return -EINVAL; + } + break; default: pr_err("%s: Unsupported ioctl command %u\n", __func__, cmd); error = -EINVAL; @@ -514,6 +847,25 @@ static int hbtp_parse_dt(struct device *dev) } } + if (hbtp->manage_power_dig && hbtp->manage_afe_power_ana) { + rc = of_property_read_u32(np, + "qcom,afe-power-on-delay-us", &temp_val); + if (!rc) + hbtp->power_on_delay = (u32)temp_val; + else + dev_info(dev, "Power-On Delay is not specified\n"); + + rc = of_property_read_u32(np, + "qcom,afe-power-off-delay-us", &temp_val); + if (!rc) + hbtp->power_off_delay = (u32)temp_val; + else + dev_info(dev, "Power-Off Delay is not specified\n"); + + dev_dbg(dev, "power-on-delay = %u, power-off-delay = %u\n", + hbtp->power_on_delay, hbtp->power_off_delay); + } + prop = of_find_property(np, "qcom,display-resolution", NULL); if (prop != NULL) { if (!prop->value) @@ -605,11 +957,292 @@ static int hbtp_parse_dt(struct device *dev) } #endif +static int hbtp_pinctrl_init(struct hbtp_data *data) +{ + const char *statename; + int rc; + int state_cnt, i; + struct device_node *np = data->pdev->dev.of_node; + bool pinctrl_state_act_found = false; + bool pinctrl_state_sus_found = false; + bool pinctrl_ddic_act_found = false; + bool pinctrl_ddic_sus_found = false; + int count = 0; + + data->ts_pinctrl = devm_pinctrl_get(&(data->pdev->dev)); + if (IS_ERR_OR_NULL(data->ts_pinctrl)) { + dev_err(&data->pdev->dev, + "Target does not use pinctrl\n"); + rc = PTR_ERR(data->ts_pinctrl); + data->ts_pinctrl = NULL; + return rc; + } + + state_cnt = of_property_count_strings(np, "pinctrl-names"); + if (state_cnt < HBTP_PINCTRL_VALID_STATE_CNT) { + /* + *if pinctrl names are not available then, + *power_sync can't be enabled + */ + dev_info(&data->pdev->dev, + "pinctrl names are not available\n"); + rc = -EINVAL; + goto error; + } + + for (i = 0; i < state_cnt; i++) { + rc = of_property_read_string_index(np, + "pinctrl-names", i, &statename); + if (rc) { + dev_err(&data->pdev->dev, + "failed to read pinctrl states by index\n"); + goto error; + } + + if (!strcmp(statename, "pmx_ts_active")) { + data->gpio_state_active + = pinctrl_lookup_state(data->ts_pinctrl, + statename); + if (IS_ERR_OR_NULL(data->gpio_state_active)) { + dev_err(&data->pdev->dev, + "Can not get ts default state\n"); + rc = PTR_ERR(data->gpio_state_active); + goto error; + } + pinctrl_state_act_found = true; + } else if (!strcmp(statename, "pmx_ts_suspend")) { + data->gpio_state_suspend + = pinctrl_lookup_state(data->ts_pinctrl, + statename); + if (IS_ERR_OR_NULL(data->gpio_state_suspend)) { + dev_err(&data->pdev->dev, + "Can not get ts sleep state\n"); + rc = PTR_ERR(data->gpio_state_suspend); + goto error; + } + pinctrl_state_sus_found = true; + } else if (!strcmp(statename, "ddic_rst_active")) { + data->ddic_rst_state_active + = pinctrl_lookup_state(data->ts_pinctrl, + statename); + if (IS_ERR(data->ddic_rst_state_active)) { + dev_err(&data->pdev->dev, + "Can not get DDIC rst act state\n"); + rc = PTR_ERR(data->ddic_rst_state_active); + goto error; + } + pinctrl_ddic_act_found = true; + } else if (!strcmp(statename, "ddic_rst_suspend")) { + data->ddic_rst_state_suspend + = pinctrl_lookup_state(data->ts_pinctrl, + statename); + if (IS_ERR(data->ddic_rst_state_suspend)) { + dev_err(&data->pdev->dev, + "Can not get DDIC rst sleep state\n"); + rc = PTR_ERR(data->ddic_rst_state_suspend); + goto error; + } + pinctrl_ddic_sus_found = true; + } else { + dev_err(&data->pdev->dev, "invalid pinctrl state\n"); + rc = -EINVAL; + goto error; + } + } + + if (!pinctrl_state_act_found || !pinctrl_state_sus_found) { + dev_err(&data->pdev->dev, + "missing required pinctrl states\n"); + rc = -EINVAL; + goto error; + } + + if (of_property_read_u32(np, "qcom,pmx-ts-on-seq-delay-us", + &data->ts_pinctrl_seq_delay)) { + dev_warn(&data->pdev->dev, "Can not find ts seq delay\n"); + } + + if (of_property_read_u32(np, "qcom,fb-resume-delay-us", + &data->fb_resume_seq_delay)) { + dev_warn(&data->pdev->dev, "Can not find fb resume seq delay\n"); + } + + if (pinctrl_ddic_act_found && pinctrl_ddic_sus_found) { + count = of_property_count_u32_elems(np, + "qcom,ddic-rst-on-seq-delay-us"); + if (count == HBTP_PINCTRL_DDIC_SEQ_NUM) { + of_property_read_u32_array(np, + "qcom,ddic-rst-on-seq-delay-us", + data->ddic_pinctrl_seq_delay, count); + } else { + dev_err(&data->pdev->dev, "count(%u) is not same as %u\n", + (u32)count, HBTP_PINCTRL_DDIC_SEQ_NUM); + } + } else { + dev_err(&data->pdev->dev, "ddic pinctrl act/sus not found\n"); + } + + data->manage_pin_ctrl = true; + return 0; + +error: + devm_pinctrl_put(data->ts_pinctrl); + data->ts_pinctrl = NULL; + return rc; +} + +static int hbtp_fb_suspend(struct hbtp_data *ts) +{ + int rc; + char *envp[2] = {HBTP_EVENT_TYPE_DISPLAY, NULL}; + + mutex_lock(&hbtp->mutex); + if (ts->pdev && ts->power_sync_enabled) { + pr_debug("%s: power_sync is enabled\n", __func__); + if (ts->power_suspended) { + mutex_unlock(&hbtp->mutex); + pr_err("%s: power is not resumed\n", __func__); + return 0; + } + rc = hbtp_pinctrl_enable(ts, false); + if (rc) { + pr_err("%s: failed to disable GPIO pins\n", __func__); + goto err_pin_disable; + } + + rc = hbtp_pdev_power_on(ts, false); + if (rc) { + pr_err("%s: failed to disable power\n", __func__); + goto err_power_disable; + } + ts->power_suspended = true; + } + + if (ts->input_dev) { + kobject_uevent_env(&ts->input_dev->dev.kobj, + KOBJ_OFFLINE, envp); + + if (ts->power_sig_enabled) { + pr_debug("%s: power_sig is enabled, wait for signal\n", + __func__); + mutex_unlock(&hbtp->mutex); + rc = wait_for_completion_interruptible( + &hbtp->power_suspend_sig); + if (rc != 0) { + pr_err("%s: wait for suspend is interrupted\n", + __func__); + } + mutex_lock(&hbtp->mutex); + pr_debug("%s: Wait is done for suspend\n", __func__); + } else { + pr_debug("%s: power_sig is NOT enabled", __func__); + } + } + + mutex_unlock(&hbtp->mutex); + return 0; +err_power_disable: + hbtp_pinctrl_enable(ts, true); +err_pin_disable: + mutex_unlock(&hbtp->mutex); + return rc; +} + +static int hbtp_fb_early_resume(struct hbtp_data *ts) +{ + char *envp[2] = {HBTP_EVENT_TYPE_DISPLAY, NULL}; + int rc; + + mutex_lock(&hbtp->mutex); + + pr_debug("%s: hbtp_fb_early_resume\n", __func__); + + if (ts->pdev && ts->power_sync_enabled) { + pr_debug("%s: power_sync is enabled\n", __func__); + if (!ts->power_suspended) { + pr_err("%s: power is not suspended\n", __func__); + mutex_unlock(&hbtp->mutex); + return 0; + } + rc = hbtp_pdev_power_on(ts, true); + if (rc) { + pr_err("%s: failed to enable panel power\n", __func__); + goto err_power_on; + } + + rc = hbtp_pinctrl_enable(ts, true); + + if (rc) { + pr_err("%s: failed to enable pin\n", __func__); + goto err_pin_enable; + } + + ts->power_suspended = false; + + if (ts->input_dev) { + + kobject_uevent_env(&ts->input_dev->dev.kobj, + KOBJ_ONLINE, envp); + + if (ts->power_sig_enabled) { + pr_err("%s: power_sig is enabled, wait for signal\n", + __func__); + mutex_unlock(&hbtp->mutex); + rc = wait_for_completion_interruptible( + &hbtp->power_resume_sig); + if (rc != 0) { + pr_err("%s: wait for resume is interrupted\n", + __func__); + } + mutex_lock(&hbtp->mutex); + pr_debug("%s: wait is done\n", __func__); + } else { + pr_debug("%s: power_sig is NOT enabled\n", + __func__); + } + + if (ts->fb_resume_seq_delay) { + usleep_range(ts->fb_resume_seq_delay, + ts->fb_resume_seq_delay + + HBTP_HOLD_DURATION_US); + pr_err("%s: fb_resume_seq_delay = %u\n", + __func__, ts->fb_resume_seq_delay); + } + } + } + mutex_unlock(&hbtp->mutex); + return 0; + +err_pin_enable: + hbtp_pdev_power_on(ts, false); +err_power_on: + mutex_unlock(&hbtp->mutex); + return rc; +} + +static int hbtp_fb_resume(struct hbtp_data *ts) +{ + char *envp[2] = {HBTP_EVENT_TYPE_DISPLAY, NULL}; + + mutex_lock(&hbtp->mutex); + if (!ts->power_sync_enabled) { + pr_debug("%s: power_sync is disabled, send uevent\n", __func__); + if (ts->input_dev) { + kobject_uevent_env(&ts->input_dev->dev.kobj, + KOBJ_ONLINE, envp); + } + } + mutex_unlock(&hbtp->mutex); + return 0; +} + static int hbtp_pdev_probe(struct platform_device *pdev) { int error; struct regulator *vcc_ana, *vcc_dig; + hbtp->pdev = pdev; + if (pdev->dev.of_node) { error = hbtp_parse_dt(&pdev->dev); if (error) { @@ -618,6 +1251,14 @@ static int hbtp_pdev_probe(struct platform_device *pdev) } } + platform_set_drvdata(pdev, hbtp); + + error = hbtp_pinctrl_init(hbtp); + if (error) { + pr_info("%s: pinctrl isn't available, rc=%d\n", __func__, + error); + } + if (hbtp->manage_afe_power_ana) { vcc_ana = regulator_get(&pdev->dev, "vcc_ana"); if (IS_ERR(vcc_ana)) { @@ -662,8 +1303,6 @@ static int hbtp_pdev_probe(struct platform_device *pdev) hbtp->vcc_dig = vcc_dig; } - hbtp->pdev = pdev; - return 0; } @@ -677,6 +1316,9 @@ static int hbtp_pdev_remove(struct platform_device *pdev) regulator_put(hbtp->vcc_dig); } + if (hbtp->ts_pinctrl) + devm_pinctrl_put(hbtp->ts_pinctrl); + return 0; } |
