summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorAbhijeet Dharmapurikar <adharmap@codeaurora.org>2017-04-17 12:15:19 -0700
committerAbhijeet Dharmapurikar <adharmap@codeaurora.org>2017-04-17 17:35:46 -0700
commitfd0747e34a4fddf2ed14ddc1d9b83d637924504f (patch)
tree5f418c7d94b5dc7268468a2221e91d6ffed46a64 /drivers
parent9b1513098b1ea710c5eb0ea9635b35580a9a243f (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.c8
-rw-r--r--drivers/power/supply/qcom/smb-lib.c76
-rw-r--r--drivers/power/supply/qcom/smb-lib.h1
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;