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); }