From 1e2e9b8b6439f9decf8effc104fa9f47e61786ed Mon Sep 17 00:00:00 2001 From: Konstantin Makariev Date: Fri, 16 Aug 2019 15:41:02 -0500 Subject: [PATCH] sec_mmi: multiple suspend/resume scenarios Added multiple suspend/resume scenarios to the driver. First option is to perform HW reset on resume. It implies that touch IC will be put to sleep mode when suspended. Device tree property sec,reset-on-resume controls it. Second option is to turn power supplies off when suspended. Device tree property sec,power-off-suspend controls it. Second option takes precedence over first one when both enabled in device tree. Change-Id: I93a99152397ea15f46a01c2f1a0ca8bd68c9f732 Signed-off-by: Konstantin Makariev Reviewed-on: https://gerrit.mot.com/1405038 SLTApproved: Slta Waiver SME-Granted: SME Approvals Granted Tested-by: Jira Key Reviewed-by: Konstantin Makariev Submit-Approved: Jira Key --- drivers/input/touchscreen/sec_mmi/sec_mmi.h | 2 + drivers/input/touchscreen/sec_mmi/sec_ts.c | 36 +++-- drivers/input/touchscreen/sec_mmi/sec_ts.h | 2 + .../input/touchscreen/sec_mmi/sec_ts_mmi.c | 138 ++++++++++++++---- 4 files changed, 135 insertions(+), 43 deletions(-) diff --git a/drivers/input/touchscreen/sec_mmi/sec_mmi.h b/drivers/input/touchscreen/sec_mmi/sec_mmi.h index cb2f92da878e..d11733043ddf 100644 --- a/drivers/input/touchscreen/sec_mmi/sec_mmi.h +++ b/drivers/input/touchscreen/sec_mmi/sec_mmi.h @@ -27,6 +27,8 @@ struct sec_mmi_data { atomic_t touch_stopped; + bool power_off_suspend; + bool hw_reset; bool usb_detection; struct work_struct ps_notify_work; struct notifier_block ps_notif; diff --git a/drivers/input/touchscreen/sec_mmi/sec_ts.c b/drivers/input/touchscreen/sec_mmi/sec_ts.c index 9684507441ef..3d912db2232f 100644 --- a/drivers/input/touchscreen/sec_mmi/sec_ts.c +++ b/drivers/input/touchscreen/sec_mmi/sec_ts.c @@ -927,26 +927,26 @@ int get_tsp_status(void) } EXPORT_SYMBOL(get_tsp_status); -void sec_ts_set_charger(bool enable) +void sec_ts_set_charger(struct sec_ts_data *ts, bool enable) { - return; -#if 0 int ret; - u8 noise_mode_on[] = {0x01}; - u8 noise_mode_off[] = {0x00}; + u8 charger_in[] = {0x02}; + u8 charger_out[] = {0x01}; if (enable) { - input_info(true, &ts->client->dev, "sec_ts_set_charger : charger CONNECTED!!\n"); - ret = sec_ts_i2c_write(ts, SEC_TS_CMD_NOISE_MODE, noise_mode_on, sizeof(noise_mode_on)); - if (ret < 0) - input_err(true, &ts->client->dev, "sec_ts_set_charger: fail to write NOISE_ON\n"); + input_info(true, &ts->client->dev, + "sec_ts_set_charger : charger CONNECTED!!\n"); + ret = sec_ts_i2c_write(ts, SET_TS_CMD_SET_CHARGER_MODE, + charger_in, sizeof(charger_in)); } else { - input_info(true, &ts->client->dev, "sec_ts_set_charger : charger DISCONNECTED!!\n"); - ret = sec_ts_i2c_write(ts, SEC_TS_CMD_NOISE_MODE, noise_mode_off, sizeof(noise_mode_off)); - if (ret < 0) - input_err(true, &ts->client->dev, "sec_ts_set_charger: fail to write NOISE_OFF\n"); + input_info(true, &ts->client->dev, + "sec_ts_set_charger : charger DISCONNECTED!!\n"); + ret = sec_ts_i2c_write(ts, SET_TS_CMD_SET_CHARGER_MODE, + charger_out, sizeof(charger_out)); } -#endif + if (ret < 0) + input_err(true, &ts->client->dev, + "sec_ts_set_charger: fail to write\n"); } EXPORT_SYMBOL(sec_ts_set_charger); @@ -1077,7 +1077,7 @@ void sec_ts_set_grip_type(struct sec_ts_data *ts, u8 set_type) /* for debugging--------------------------------------------------------------------------------------*/ -static int sec_ts_pinctrl_configure(struct sec_ts_data *ts, bool enable) +int sec_ts_pinctrl_configure(struct sec_ts_data *ts, bool enable) { struct pinctrl_state *state; @@ -1087,6 +1087,11 @@ static int sec_ts_pinctrl_configure(struct sec_ts_data *ts, bool enable) state = pinctrl_lookup_state(ts->plat_data->pinctrl, "on_state"); if (IS_ERR(ts->plat_data->pinctrl)) input_err(true, &ts->client->dev, "%s: could not get active pinstate\n", __func__); + if (gpio_is_valid(ts->plat_data->rst_gpio)) { + /* pinctrl is not setting RESET gpio high by default */ + /* due to compatibility issues with Synaptics driver */ + gpio_set_value(ts->plat_data->rst_gpio, 1); + } } else { state = pinctrl_lookup_state(ts->plat_data->pinctrl, "off_state"); if (IS_ERR(ts->plat_data->pinctrl)) @@ -1196,7 +1201,6 @@ static int sec_ts_parse_dt(struct i2c_client *client) input_err(true, &client->dev, "%s: Unable to request tsp_rst [%d]\n", __func__, pdata->rst_gpio); return -EINVAL; } - gpio_set_value(pdata->rst_gpio, 1); } else input_info(true, &client->dev, "%s: has no rst gpio\n", __func__); diff --git a/drivers/input/touchscreen/sec_mmi/sec_ts.h b/drivers/input/touchscreen/sec_mmi/sec_ts.h index 070b3418500c..28eddf497b18 100644 --- a/drivers/input/touchscreen/sec_mmi/sec_ts.h +++ b/drivers/input/touchscreen/sec_mmi/sec_ts.h @@ -788,6 +788,7 @@ typedef struct { u32 reserved; } fw_chunk; +int sec_ts_pinctrl_configure(struct sec_ts_data *ts, bool enable); int sec_ts_power(void *data, bool on); int sec_ts_stop_device(struct sec_ts_data *ts); int sec_ts_start_device(struct sec_ts_data *ts); @@ -824,6 +825,7 @@ void sec_ts_run_rawdata_all(struct sec_ts_data *ts, bool full_read); void sec_ts_reinit(struct sec_ts_data *ts); void sec_ts_sense_on(struct sec_ts_data *ts); void sec_ts_irq_enable(struct sec_ts_data *ts, bool on); +void sec_ts_set_charger(struct sec_ts_data *ts, bool enable); void sec_ts_lv1_params(u8 cmd, int size); ssize_t sec_ts_reg_store(struct device *dev, diff --git a/drivers/input/touchscreen/sec_mmi/sec_ts_mmi.c b/drivers/input/touchscreen/sec_mmi/sec_ts_mmi.c index 1b326cf76bc6..ab70fbfe4915 100644 --- a/drivers/input/touchscreen/sec_mmi/sec_ts_mmi.c +++ b/drivers/input/touchscreen/sec_mmi/sec_ts_mmi.c @@ -263,18 +263,21 @@ static void sec_mmi_ps_work(struct work_struct *work) struct sec_mmi_data *data = container_of(work, struct sec_mmi_data, ps_notify_work); struct sec_ts_data *ts = data->ts_ptr; + u8 cval = 0; u8 mode = 1; int ret; /* plugged in USB should change value to 2 */ if (data->ps_is_present) mode++; - ret = ts->sec_ts_i2c_write(ts, SET_TS_CMD_SET_CHARGER_MODE, - &mode, sizeof(mode)); + ret = ts->sec_ts_i2c_read(ts, SET_TS_CMD_SET_CHARGER_MODE, + &cval, sizeof(cval)); if (ret < 0) { - dev_err(DEV_TS, "%s: failed to set charger mode %d\n", - __func__, mode); + dev_err(DEV_TS, "%s: failed to read charger mode\n", __func__); } + + if (cval != mode) + sec_ts_set_charger(ts, data->ps_is_present); } static int sec_mmi_ps_notify_callback(struct notifier_block *self, @@ -298,11 +301,12 @@ static int sec_mmi_ps_notify_callback(struct notifier_block *self, return ret; } + dev_dbg(DEV_MMI, "%s: event=%lu, usb status: cur=%d, prev=%d\n", + __func__, event, present, data->ps_is_present); + if (data->ps_is_present != present) { data->ps_is_present = present; schedule_work(&data->ps_notify_work); - dev_dbg(DEV_MMI, "%s: usb status changed: %d\n", - __func__, data->ps_is_present); } return 0; @@ -330,6 +334,20 @@ static int sec_mmi_dt(struct sec_mmi_data *data) data->usb_detection = true; } + if (of_property_read_bool(np, "sec,reset-on-resume")) { + dev_info(DEV_MMI, "%s: using hw reset on resume\n", __func__); + data->hw_reset = true; + } + + if (of_property_read_bool(np, "sec,power-off-suspend")) { + dev_info(DEV_MMI, "%s: using power off in suspend\n", __func__); + data->power_off_suspend = true; + if (data->hw_reset) { + data->hw_reset = false; + dev_info(DEV_MMI, "%s: unset hw reset on resume!!!\n", __func__); + } + } + np = of_find_node_by_name(NULL, "chosen"); if (np) { const char *supplier; @@ -417,13 +435,16 @@ static void sec_mmi_ic_reset(struct sec_mmi_data *data, int mode) !gpio_get_value(ts->plat_data->rst_gpio)) return; - mutex_lock(&ts->modechange); __pm_stay_awake(&ts->wakelock); + mutex_lock(&ts->modechange); + /* disable irq to ensure getting boot complete */ + sec_ts_irq_enable(ts, false); if (mode) { gpio_set_value(ts->plat_data->rst_gpio, 0); usleep_range(10, 10); gpio_set_value(ts->plat_data->rst_gpio, 1); + dev_dbg(DEV_MMI, "%s: reset line toggled\n", __func__); } else { int ret; @@ -433,6 +454,7 @@ static void sec_mmi_ic_reset(struct sec_mmi_data *data, int mode) } sec_ts_wait_for_ready(ts, SEC_TS_ACK_BOOT_COMPLETE); + sec_ts_irq_enable(ts, true); mutex_unlock(&ts->modechange); __pm_relax(&ts->wakelock); @@ -482,9 +504,23 @@ static void sec_mmi_work(struct work_struct *w) } if (ts->fw_invalid == false) { + struct power_supply *psy; + sec_mmi_fw_read_id(data); sec_ts_integrity_check(ts); + psy = power_supply_get_by_name("usb"); + if (psy) { + int rc; + rc = sec_mmi_ps_get_state(psy, &data->ps_is_present); + if (rc) { + dev_err(DEV_MMI, "%s: failed to get usb status\n", __func__); + } + + if (data->ps_is_present) + sec_ts_set_charger(ts, data->ps_is_present); + } + sec_ts_sense_on(ts); dev_dbg(DEV_MMI, "%s: sensing turned on\n", __func__); } @@ -498,12 +534,40 @@ static void sec_mmi_queued_resume(struct work_struct *w) container_of(dw, struct sec_mmi_data, resume_work); struct sec_ts_data *ts = data->ts_ptr; unsigned char buffer = 0; + bool wait4_boot_complete = true; + bool update_charger = true; int ret; if (atomic_cmpxchg(&data->touch_stopped, 1, 0) == 0) return; - sec_ts_set_lowpowermode(ts, TO_TOUCH_MODE); + if (data->hw_reset) { + dev_dbg(DEV_MMI, "%s: doing hw reset...\n", __func__); + data->reset(ts->mmi_ptr, 1); + } else if (data->power_off_suspend) { + sec_ts_wait_for_ready(ts, SEC_TS_ACK_BOOT_COMPLETE); + } else { + sec_ts_set_lowpowermode(ts, TO_TOUCH_MODE); + wait4_boot_complete = false; + update_charger = false; + } + + if (wait4_boot_complete) { + if (data->power_off_suspend) + sec_ts_irq_enable(ts, true); + + /* Sense_on */ + dev_dbg(DEV_MMI, "%s: sending sense_on...\n", __func__); + ret = ts->sec_ts_i2c_write(ts, SEC_TS_CMD_SENSE_ON, NULL, 0); + if (ret < 0) + dev_err(DEV_MMI, + "%s: failed sense_on (%d)\n", __func__, ret); + } + + /* make sure charger mode is properly set after reset */ + if (update_charger) + schedule_work(&data->ps_notify_work); + if (ts->lowpower_mode) complete_all(&ts->resume_done); @@ -516,7 +580,7 @@ static void sec_mmi_queued_resume(struct work_struct *w) ts->fw_invalid = buffer == SEC_TS_STATUS_BOOT_MODE; - dev_info(DEV_MMI, "%s: touch resumed\n", __func__); + dev_info(DEV_MMI, "%s: done\n", __func__); } static int inline sec_mmi_display_on(struct sec_mmi_data *data) @@ -534,13 +598,18 @@ static int inline sec_mmi_display_off(struct sec_mmi_data *data) return 0; /* complete critical work */ sec_mmi_wait4idle(data); - sec_ts_set_lowpowermode(ts, TO_SLEEP_MODE); + + if (data->power_off_suspend) + sec_ts_irq_enable(ts, false); + else + sec_ts_set_lowpowermode(ts, TO_SLEEP_MODE); + cancel_delayed_work_sync(&data->resume_work); if (ts->lowpower_mode) reinit_completion(&ts->resume_done); - dev_info(DEV_MMI, "%s: touch suspended\n", __func__); + dev_info(DEV_MMI, "%s: done\n", __func__); return 0; } @@ -560,6 +629,7 @@ static int sec_mmi_panel_cb(struct notifier_block *nb, if ((event == MSM_DRM_EARLY_EVENT_BLANK || event == MSM_DRM_EVENT_BLANK) && evdata && evdata->data && data) { + struct sec_ts_data *ts = data->ts_ptr; int *blank = evdata->data; dev_dbg(DEV_MMI, "%s: drm notification: event = %lu blank = %d\n", @@ -567,12 +637,36 @@ static int sec_mmi_panel_cb(struct notifier_block *nb, /* entering suspend upon early blank event */ /* to ensure shared power supply is still on */ /* for in-cell design touch solutions */ - if (event == MSM_DRM_EARLY_EVENT_BLANK) { - if (*blank != MSM_DRM_BLANK_POWERDOWN) - return 0; - sec_mmi_display_off(data); - } else if (*blank == MSM_DRM_BLANK_UNBLANK) { - sec_mmi_display_on(data); + switch (event) { + case MSM_DRM_EARLY_EVENT_BLANK: + if (*blank == MSM_DRM_BLANK_POWERDOWN) { + /* put in reset first */ + if (data->power_off_suspend) + sec_ts_pinctrl_configure(ts, false); + + sec_mmi_display_off(data); + + } else if (data->power_off_suspend) { + /* powering on early */ + sec_ts_power((void *)ts, true); + dev_dbg(DEV_MMI, "%s: touch powered on\n", __func__); + } + break; + + case MSM_DRM_EVENT_BLANK: + if (*blank == MSM_DRM_BLANK_UNBLANK) { + /* out of reset to allow wait for boot complete */ + if (data->power_off_suspend) + sec_ts_pinctrl_configure(ts, true); + + sec_mmi_display_on(data); + + } else if (data->power_off_suspend) { + /* then proceed with de-powering */ + sec_ts_power((void *)ts, false); + dev_dbg(DEV_MMI, "%s: touch powered off\n", __func__); + } + break; } } @@ -589,16 +683,6 @@ static int sec_mmi_register_notifiers( rc = msm_drm_register_client(&data->panel_nb); if (data->usb_detection) { - struct power_supply *psy; - - psy = power_supply_get_by_name("usb"); - if (psy) { - rc = sec_mmi_ps_get_state(psy, &data->ps_is_present); - if (rc) { - dev_err(DEV_MMI, "%s: failed to get usb status\n", __func__); - } - } - data->ps_notif.notifier_call = sec_mmi_ps_notify_callback; rc = power_supply_reg_notifier(&data->ps_notif); }