diff options
author | Abhijeet Dharmapurikar <adharmap@codeaurora.org> | 2017-04-17 12:15:19 -0700 |
---|---|---|
committer | Abhijeet Dharmapurikar <adharmap@codeaurora.org> | 2017-04-17 17:35:46 -0700 |
commit | fd0747e34a4fddf2ed14ddc1d9b83d637924504f (patch) | |
tree | 5f418c7d94b5dc7268468a2221e91d6ffed46a64 /drivers | |
parent | 9b1513098b1ea710c5eb0ea9635b35580a9a243f (diff) |
power: qcom: lock USB removal
During USB removal a lot of cleanup happens; votables are reset, flags
are cleared, etc. After the cleanup is finished there is a chance that
USB power supply consumers may set properties before getting the USB
removal notification. This can lead to many problems where ICL limits
are set based on the previous insertion, or APSD is disabled due to a
late setting of PD_ACTIVE.
Introduce a lock which prevents USB power supply consumers from setting
properties when USB has been removed. This lock will ensure that the
next insertion starts with a clean slate.
CRs-Fixed: 2020132
Change-Id: I05a4145289b6097e41afc30aa09782722fa03fb6
Signed-off-by: Nicholas Troast <ntroast@codeaurora.org>
Signed-off-by: Abhijeet Dharmapurikar <adharmap@codeaurora.org>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/power/supply/qcom/qpnp-smb2.c | 8 | ||||
-rw-r--r-- | drivers/power/supply/qcom/smb-lib.c | 76 | ||||
-rw-r--r-- | drivers/power/supply/qcom/smb-lib.h | 1 |
3 files changed, 57 insertions, 28 deletions
diff --git a/drivers/power/supply/qcom/qpnp-smb2.c b/drivers/power/supply/qcom/qpnp-smb2.c index c7d6937bcc49..aa51b67acf72 100644 --- a/drivers/power/supply/qcom/qpnp-smb2.c +++ b/drivers/power/supply/qcom/qpnp-smb2.c @@ -540,6 +540,12 @@ static int smb2_usb_set_prop(struct power_supply *psy, struct smb_charger *chg = &chip->chg; int rc = 0; + mutex_lock(&chg->lock); + if (!chg->typec_present) { + rc = -EINVAL; + goto unlock; + } + switch (psp) { case POWER_SUPPLY_PROP_VOLTAGE_MIN: rc = smblib_set_prop_usb_voltage_min(chg, val); @@ -578,6 +584,8 @@ static int smb2_usb_set_prop(struct power_supply *psy, break; } +unlock: + mutex_unlock(&chg->lock); return rc; } diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c index f17ccc91e38c..c9fcb2be8569 100644 --- a/drivers/power/supply/qcom/smb-lib.c +++ b/drivers/power/supply/qcom/smb-lib.c @@ -3104,7 +3104,11 @@ irqreturn_t smblib_handle_usbin_uv(int irq, void *data) static void smblib_micro_usb_plugin(struct smb_charger *chg, bool vbus_rising) { - if (!vbus_rising) { + if (vbus_rising) { + /* use the typec flag even though its not typec */ + chg->typec_present = 1; + } else { + chg->typec_present = 0; smblib_update_usb_type(chg); extcon_set_cable_state_(chg->extcon, EXTCON_USB, false); smblib_uusb_removal(chg); @@ -3120,18 +3124,16 @@ static void smblib_typec_usb_plugin(struct smb_charger *chg, bool vbus_rising) } #define PL_DELAY_MS 30000 -irqreturn_t smblib_handle_usb_plugin(int irq, void *data) +void smblib_usb_plugin_locked(struct smb_charger *chg) { - struct smb_irq_data *irq_data = data; - struct smb_charger *chg = irq_data->parent_data; int rc; u8 stat; bool vbus_rising; rc = smblib_read(chg, USBIN_BASE + INT_RT_STS_OFFSET, &stat); if (rc < 0) { - dev_err(chg->dev, "Couldn't read USB_INT_RT_STS rc=%d\n", rc); - return IRQ_HANDLED; + smblib_err(chg, "Couldn't read USB_INT_RT_STS rc=%d\n", rc); + return; } vbus_rising = (bool)(stat & USBIN_PLUGIN_RT_STS_BIT); @@ -3181,8 +3183,18 @@ irqreturn_t smblib_handle_usb_plugin(int irq, void *data) smblib_typec_usb_plugin(chg, vbus_rising); power_supply_changed(chg->usb_psy); - smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s %s\n", - irq_data->name, vbus_rising ? "attached" : "detached"); + smblib_dbg(chg, PR_INTERRUPT, "IRQ: usbin-plugin %s\n", + vbus_rising ? "attached" : "detached"); +} + +irqreturn_t smblib_handle_usb_plugin(int irq, void *data) +{ + struct smb_irq_data *irq_data = data; + struct smb_charger *chg = irq_data->parent_data; + + mutex_lock(&chg->lock); + smblib_usb_plugin_locked(chg); + mutex_unlock(&chg->lock); return IRQ_HANDLED; } @@ -3717,46 +3729,33 @@ irqreturn_t smblib_handle_usb_typec_change_for_uusb(struct smb_charger *chg) return IRQ_HANDLED; } -irqreturn_t smblib_handle_usb_typec_change(int irq, void *data) +static void smblib_usb_typec_change(struct smb_charger *chg) { - struct smb_irq_data *irq_data = data; - struct smb_charger *chg = irq_data->parent_data; int rc; u8 stat4, stat5; bool debounce_done, sink_attached, legacy_cable; - if (chg->micro_usb_mode) - return smblib_handle_usb_typec_change_for_uusb(chg); - rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat4); if (rc < 0) { smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc); - return IRQ_HANDLED; + return; } rc = smblib_read(chg, TYPE_C_STATUS_5_REG, &stat5); if (rc < 0) { smblib_err(chg, "Couldn't read TYPE_C_STATUS_5 rc=%d\n", rc); - return IRQ_HANDLED; + return; } debounce_done = (bool)(stat4 & TYPEC_DEBOUNCE_DONE_STATUS_BIT); sink_attached = (bool)(stat4 & UFP_DFP_MODE_STATUS_BIT); legacy_cable = (bool)(stat5 & TYPEC_LEGACY_CABLE_STATUS_BIT); - if (chg->cc2_detach_wa_active) { - smblib_dbg(chg, PR_INTERRUPT, "Ignoring cc2_wrkarnd=%d dd=%d\n", - chg->cc2_detach_wa_active, - debounce_done); - return IRQ_HANDLED; - } - smblib_handle_typec_debounce_done(chg, debounce_done, sink_attached, legacy_cable); if (stat4 & TYPEC_VBUS_ERROR_STATUS_BIT) - smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s vbus-error\n", - irq_data->name); + smblib_dbg(chg, PR_INTERRUPT, "IRQ: vbus-error\n"); if (stat4 & TYPEC_VCONN_OVERCURR_STATUS_BIT) schedule_work(&chg->vconn_oc_work); @@ -3764,6 +3763,26 @@ irqreturn_t smblib_handle_usb_typec_change(int irq, void *data) power_supply_changed(chg->usb_psy); smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_4 = 0x%02x\n", stat4); smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_5 = 0x%02x\n", stat5); +} + +irqreturn_t smblib_handle_usb_typec_change(int irq, void *data) +{ + struct smb_irq_data *irq_data = data; + struct smb_charger *chg = irq_data->parent_data; + + if (chg->micro_usb_mode) { + smblib_handle_usb_typec_change_for_uusb(chg); + return IRQ_HANDLED; + } + + if (chg->cc2_detach_wa_active) { + smblib_dbg(chg, PR_INTERRUPT, "Ignoring cc2_wa_active\n"); + return IRQ_HANDLED; + } + + mutex_lock(&chg->lock); + smblib_usb_typec_change(chg); + mutex_unlock(&chg->lock); return IRQ_HANDLED; } @@ -3889,7 +3908,6 @@ static void rdstd_cc2_detach_work(struct work_struct *work) { int rc; u8 stat4, stat5; - struct smb_irq_data irq_data = {NULL, "cc2-removal-workaround"}; struct smb_charger *chg = container_of(work, struct smb_charger, rdstd_cc2_detach_work); @@ -3952,8 +3970,9 @@ static void rdstd_cc2_detach_work(struct work_struct *work) rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG, EXIT_SNK_BASED_ON_CC_BIT, 0); smblib_reg_block_restore(chg, cc2_detach_settings); - irq_data.parent_data = chg; - smblib_handle_usb_typec_change(0, &irq_data); + mutex_lock(&chg->lock); + smblib_usb_typec_change(chg); + mutex_unlock(&chg->lock); return; rerun: @@ -4353,6 +4372,7 @@ int smblib_init(struct smb_charger *chg) { int rc = 0; + mutex_init(&chg->lock); mutex_init(&chg->write_lock); mutex_init(&chg->otg_oc_lock); INIT_WORK(&chg->bms_update_work, bms_update_work); diff --git a/drivers/power/supply/qcom/smb-lib.h b/drivers/power/supply/qcom/smb-lib.h index 002d58b8c33c..877f62a77d1a 100644 --- a/drivers/power/supply/qcom/smb-lib.h +++ b/drivers/power/supply/qcom/smb-lib.h @@ -229,6 +229,7 @@ struct smb_charger { int smb_version; /* locks */ + struct mutex lock; struct mutex write_lock; struct mutex ps_change_lock; struct mutex otg_oc_lock; |