summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorNicholas Troast <ntroast@codeaurora.org>2016-09-16 11:07:45 -0700
committerNicholas Troast <ntroast@codeaurora.org>2016-11-07 11:37:08 -0800
commit2dad6f26dc9039672ba600d237cb7172c426dc94 (patch)
treee19831c382b923118734f37904dbef9599f9b9b8 /drivers
parentce610f2fc934e89c706a8030b25ce48accced28a (diff)
qpnp-smb2: fix reverse boost when input is removed
When any input is removed it is likely that reverse boost can happen. Detect reverse boost by checking if the switcher-power-ok interrupt triggers 3 times within 1 second. If detected then suspend all input. Once VBUS falls the input can be resumed for the next insertion. Change-Id: I3dbe4fe426111023b60eefd968c426be7d6057b9 Signed-off-by: Nicholas Troast <ntroast@codeaurora.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/power/qcom-charger/qpnp-smb2.c4
-rw-r--r--drivers/power/qcom-charger/smb-lib.c59
-rw-r--r--drivers/power/qcom-charger/smb-lib.h3
3 files changed, 56 insertions, 10 deletions
diff --git a/drivers/power/qcom-charger/qpnp-smb2.c b/drivers/power/qcom-charger/qpnp-smb2.c
index f9d76c56aa2e..0e2f5afb9416 100644
--- a/drivers/power/qcom-charger/qpnp-smb2.c
+++ b/drivers/power/qcom-charger/qpnp-smb2.c
@@ -1241,6 +1241,7 @@ static int smb2_setup_wa_flags(struct smb2 *chip)
switch (pmic_rev_id->pmic_subtype) {
case PMICOBALT_SUBTYPE:
+ chip->chg.wa_flags |= BOOST_BACK_WA;
if (pmic_rev_id->rev4 == PMICOBALT_V1P1_REV4) /* PMI rev 1.1 */
chg->wa_flags |= QC_CHARGER_DETECTION_WA_BIT;
break;
@@ -1451,7 +1452,8 @@ static struct smb2_irq_info smb2_irqs[] = {
},
{
.name = "switcher-power-ok",
- .handler = smblib_handle_debug,
+ .handler = smblib_handle_switcher_power_ok,
+ .storm_data = {true, 1000, 3},
},
};
diff --git a/drivers/power/qcom-charger/smb-lib.c b/drivers/power/qcom-charger/smb-lib.c
index 198e77469bbe..7a542c59f496 100644
--- a/drivers/power/qcom-charger/smb-lib.c
+++ b/drivers/power/qcom-charger/smb-lib.c
@@ -596,7 +596,11 @@ static int smblib_usb_suspend_vote_callback(struct votable *votable, void *data,
{
struct smb_charger *chg = data;
- return smblib_set_usb_suspend(chg, suspend);
+ /* resume input if suspend is invalid */
+ if (suspend < 0)
+ suspend = 0;
+
+ return smblib_set_usb_suspend(chg, (bool)suspend);
}
static int smblib_dc_suspend_vote_callback(struct votable *votable, void *data,
@@ -604,10 +608,11 @@ static int smblib_dc_suspend_vote_callback(struct votable *votable, void *data,
{
struct smb_charger *chg = data;
+ /* resume input if suspend is invalid */
if (suspend < 0)
- suspend = false;
+ suspend = 0;
- return smblib_set_dc_suspend(chg, suspend);
+ return smblib_set_dc_suspend(chg, (bool)suspend);
}
static int smblib_fcc_max_vote_callback(struct votable *votable, void *data,
@@ -2230,11 +2235,8 @@ irqreturn_t smblib_handle_usb_plugin(int irq, void *data)
}
}
- if (!chg->dpdm_reg)
- goto skip_dpdm_float;
-
if (chg->vbus_present) {
- if (!regulator_is_enabled(chg->dpdm_reg)) {
+ if (chg->dpdm_reg && !regulator_is_enabled(chg->dpdm_reg)) {
smblib_dbg(chg, PR_MISC, "enabling DPDM regulator\n");
rc = regulator_enable(chg->dpdm_reg);
if (rc < 0)
@@ -2242,7 +2244,14 @@ irqreturn_t smblib_handle_usb_plugin(int irq, void *data)
rc);
}
} else {
- if (regulator_is_enabled(chg->dpdm_reg)) {
+ if (chg->wa_flags & BOOST_BACK_WA) {
+ vote(chg->usb_suspend_votable,
+ BOOST_BACK_VOTER, false, 0);
+ vote(chg->dc_suspend_votable,
+ BOOST_BACK_VOTER, false, 0);
+ }
+
+ if (chg->dpdm_reg && regulator_is_enabled(chg->dpdm_reg)) {
smblib_dbg(chg, PR_MISC, "disabling DPDM regulator\n");
rc = regulator_disable(chg->dpdm_reg);
if (rc < 0)
@@ -2251,7 +2260,6 @@ irqreturn_t smblib_handle_usb_plugin(int irq, void *data)
}
}
-skip_dpdm_float:
power_supply_changed(chg->usb_psy);
smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s %s\n",
irq_data->name, chg->vbus_present ? "attached" : "detached");
@@ -2683,6 +2691,39 @@ irqreturn_t smblib_handle_high_duty_cycle(int irq, void *data)
return IRQ_HANDLED;
}
+irqreturn_t smblib_handle_switcher_power_ok(int irq, void *data)
+{
+ struct smb_irq_data *irq_data = data;
+ struct smb_charger *chg = irq_data->parent_data;
+ int rc;
+ u8 stat;
+
+ if (!(chg->wa_flags & BOOST_BACK_WA))
+ return IRQ_HANDLED;
+
+ rc = smblib_read(chg, POWER_PATH_STATUS_REG, &stat);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't read POWER_PATH_STATUS rc=%d\n", rc);
+ return IRQ_HANDLED;
+ }
+
+ if ((stat & USE_USBIN_BIT) &&
+ get_effective_result(chg->usb_suspend_votable))
+ return IRQ_HANDLED;
+
+ if ((stat & USE_DCIN_BIT) &&
+ get_effective_result(chg->dc_suspend_votable))
+ return IRQ_HANDLED;
+
+ if (is_storming(&irq_data->storm_data)) {
+ smblib_dbg(chg, PR_MISC, "reverse boost detected; suspending input\n");
+ vote(chg->usb_suspend_votable, BOOST_BACK_VOTER, true, 0);
+ vote(chg->dc_suspend_votable, BOOST_BACK_VOTER, true, 0);
+ }
+
+ return IRQ_HANDLED;
+}
+
/***************
* Work Queues *
***************/
diff --git a/drivers/power/qcom-charger/smb-lib.h b/drivers/power/qcom-charger/smb-lib.h
index 4be06ffcfb25..61168f7f71e6 100644
--- a/drivers/power/qcom-charger/smb-lib.h
+++ b/drivers/power/qcom-charger/smb-lib.h
@@ -46,6 +46,7 @@ enum print_reason {
#define VBUS_CC_SHORT_VOTER "VBUS_CC_SHORT_VOTER"
#define LEGACY_CABLE_VOTER "LEGACY_CABLE_VOTER"
#define PD_INACTIVE_VOTER "PD_INACTIVE_VOTER"
+#define BOOST_BACK_VOTER "BOOST_BACK_VOTER"
enum smb_mode {
PARALLEL_MASTER = 0,
@@ -55,6 +56,7 @@ enum smb_mode {
enum {
QC_CHARGER_DETECTION_WA_BIT = BIT(0),
+ BOOST_BACK_WA = BIT(1),
};
struct smb_regulator {
@@ -240,6 +242,7 @@ irqreturn_t smblib_handle_icl_change(int irq, void *data);
irqreturn_t smblib_handle_usb_typec_change(int irq, void *data);
irqreturn_t smblib_handle_dc_plugin(int irq, void *data);
irqreturn_t smblib_handle_high_duty_cycle(int irq, void *data);
+irqreturn_t smblib_handle_switcher_power_ok(int irq, void *data);
int smblib_get_prop_input_suspend(struct smb_charger *chg,
union power_supply_propval *val);