From e347ef6e9c465bdb9428619cf3d440c712e397b6 Mon Sep 17 00:00:00 2001 From: Konstantin Makariev Date: Wed, 24 Jun 2020 13:04:13 -0500 Subject: [PATCH] synaptics_mmi_class: handle delayed init When Synaptics touch belongs to secondary display and splash screen option enabled, driver depends on DRM display notification to follow with HW init. In this case suspend/resule and irq enable/disable methods can be called by class driver un-initialized causing kernel to panic. Added atomic flag to indicate device queried successfully to prevent un-initialized methods execution. Change-Id: I3debfb80eac129f550acdd2fc104eacc32f499a2 Signed-off-by: Konstantin Makariev Reviewed-on: https://gerrit.mot.com/1641558 SLTApproved: Slta Waiver SME-Granted: SME Approvals Granted Tested-by: Jira Key Reviewed-by: Ryan Lattrel Reviewed-by: Konstantin Makariev Submit-Approved: Jira Key --- .../synaptics_mmi_class/synaptics_dsx_i2c.c | 12 ++++++++++ .../synaptics_mmi_class/synaptics_dsx_i2c.h | 1 + .../synaptics_mmi_class/synaptics_mmi_class.c | 23 +++++++++++++++++-- 3 files changed, 34 insertions(+), 2 deletions(-) diff --git a/drivers/input/touchscreen/synaptics_mmi_class/synaptics_dsx_i2c.c b/drivers/input/touchscreen/synaptics_mmi_class/synaptics_dsx_i2c.c index 1b635ab9dd76..f4379c113299 100644 --- a/drivers/input/touchscreen/synaptics_mmi_class/synaptics_dsx_i2c.c +++ b/drivers/input/touchscreen/synaptics_mmi_class/synaptics_dsx_i2c.c @@ -5788,6 +5788,8 @@ skip_f12_single_i2c_setup: synaptics_rmi4_scan_f01_reg_info(rmi4_data); } + atomic_set(&rmi4_data->query_done, 1); + return 0; } @@ -6894,6 +6896,11 @@ int synaptics_rmi4_suspend(struct device *dev) *platform_data = &rmi4_data->board; static char ud_stats[PAGE_SIZE]; + if (atomic_read(&rmi4_data->query_done) == 0) { + pr_warn("called before ic queried\n"); + return 0; + } + if (atomic_cmpxchg(&rmi4_data->touch_stopped, 0, 1) == 1) return 0; @@ -6958,6 +6965,11 @@ int synaptics_rmi4_resume(struct device *dev) struct synaptics_dsx_platform_data *platform_data = &rmi4_data->board; + if (atomic_read(&rmi4_data->query_done) == 0) { + pr_warn("called before ic queried\n"); + return 0; + } + if (atomic_cmpxchg(&rmi4_data->touch_stopped, 1, 0) == 0) return 0; diff --git a/drivers/input/touchscreen/synaptics_mmi_class/synaptics_dsx_i2c.h b/drivers/input/touchscreen/synaptics_mmi_class/synaptics_dsx_i2c.h index 47ee9968ae8d..7ca5fe6e4e57 100644 --- a/drivers/input/touchscreen/synaptics_mmi_class/synaptics_dsx_i2c.h +++ b/drivers/input/touchscreen/synaptics_mmi_class/synaptics_dsx_i2c.h @@ -546,6 +546,7 @@ struct synaptics_rmi4_data { int sensor_max_y; bool irq_enabled; atomic_t touch_stopped; + atomic_t query_done; bool splash_screen_mode; bool flash_enabled; bool ic_on; diff --git a/drivers/input/touchscreen/synaptics_mmi_class/synaptics_mmi_class.c b/drivers/input/touchscreen/synaptics_mmi_class/synaptics_mmi_class.c index c6367cbdc26b..611098ea0928 100644 --- a/drivers/input/touchscreen/synaptics_mmi_class/synaptics_mmi_class.c +++ b/drivers/input/touchscreen/synaptics_mmi_class/synaptics_mmi_class.c @@ -115,6 +115,8 @@ static int synaptics_mmi_drv_irq(struct device *dev, int state) ASSERT_PTR(ts); dev_dbg(dev, "%s\n", __func__); + if (atomic_read(&ts->query_done) != 1) + return -EBUSY; switch (state) { case 0: /* Disable irq */ synaptics_rmi4_irq_enable(ts, false); @@ -137,6 +139,8 @@ static int synaptics_mmi_reset(struct device *dev, int type) ASSERT_PTR(ts); dev_dbg(dev, "%s\n", __func__); + if (atomic_read(&ts->query_done) != 1) + return -EBUSY; ret = synaptics_dsx_ic_reset(ts, type); if (ret > 0) dev_dbg(dev,"%s: successful reset took %dms\n", __func__, ret); @@ -152,6 +156,8 @@ static int synaptics_mmi_panel_state(struct device *dev, struct synaptics_rmi4_data *ts = dev_get_drvdata(dev); ASSERT_PTR(ts); dev_dbg(dev, "%s: panel state change: %d->%d\n", __func__, from, to); + if (atomic_read(&ts->query_done) != 1) + return -EBUSY; switch (to) { case TS_MMI_PM_GESTURE: case TS_MMI_PM_DEEPSLEEP: @@ -171,6 +177,8 @@ static int synaptics_mmi_post_resume(struct device *dev) struct synaptics_rmi4_data *ts = dev_get_drvdata(dev); ASSERT_PTR(ts); dev_dbg(dev, "%s\n", __func__); + if (atomic_read(&ts->query_done) != 1) + return -EBUSY; synaptics_rmi4_resume(dev); return 0; } @@ -183,7 +191,12 @@ static int synaptics_mmi_fw_update(struct device *dev, char *fwname) ASSERT_PTR(ts); dev_dbg(dev, "%s\n", __func__); fwu = ts->fwu_data; - return (fwu && fwu->firmware_update) ? fwu->firmware_update(dev, name) : -ENOSYS; + if (!fwu || !fwu->firmware_update) + return -ENOSYS; + if (atomic_read(&ts->query_done) != 1) + return -EBUSY; + atomic_set(&ts->query_done, 0); + return fwu->firmware_update(dev, name); } static int synaptics_mmi_fw_erase(struct device *dev) @@ -193,7 +206,11 @@ static int synaptics_mmi_fw_erase(struct device *dev) ASSERT_PTR(ts); dev_dbg(dev, "%s\n", __func__); fwu = ts->fwu_data; - return (fwu && fwu->firmware_erase) ? fwu->firmware_erase(dev) : -ENOSYS; + if (!fwu || !fwu->firmware_erase) + return -ENOSYS; + if (atomic_read(&ts->query_done) != 1) + return -EBUSY; + return fwu->firmware_erase(dev); } static int synaptics_mmi_charger_mode(struct device *dev, int mode) @@ -201,6 +218,8 @@ static int synaptics_mmi_charger_mode(struct device *dev, int mode) struct synaptics_rmi4_data *ts = dev_get_drvdata(dev); ASSERT_PTR(ts); dev_dbg(dev, "%s\n", __func__); + if (atomic_read(&ts->query_done) != 1) + return -EBUSY; synaptics_dsx_charger_mode(ts, mode); return 0; }