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>
This commit is contained in:
parent
ce610f2fc9
commit
2dad6f26dc
3 changed files with 56 additions and 10 deletions
|
@ -1241,6 +1241,7 @@ static int smb2_setup_wa_flags(struct smb2 *chip)
|
||||||
|
|
||||||
switch (pmic_rev_id->pmic_subtype) {
|
switch (pmic_rev_id->pmic_subtype) {
|
||||||
case PMICOBALT_SUBTYPE:
|
case PMICOBALT_SUBTYPE:
|
||||||
|
chip->chg.wa_flags |= BOOST_BACK_WA;
|
||||||
if (pmic_rev_id->rev4 == PMICOBALT_V1P1_REV4) /* PMI rev 1.1 */
|
if (pmic_rev_id->rev4 == PMICOBALT_V1P1_REV4) /* PMI rev 1.1 */
|
||||||
chg->wa_flags |= QC_CHARGER_DETECTION_WA_BIT;
|
chg->wa_flags |= QC_CHARGER_DETECTION_WA_BIT;
|
||||||
break;
|
break;
|
||||||
|
@ -1451,7 +1452,8 @@ static struct smb2_irq_info smb2_irqs[] = {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.name = "switcher-power-ok",
|
.name = "switcher-power-ok",
|
||||||
.handler = smblib_handle_debug,
|
.handler = smblib_handle_switcher_power_ok,
|
||||||
|
.storm_data = {true, 1000, 3},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -596,7 +596,11 @@ static int smblib_usb_suspend_vote_callback(struct votable *votable, void *data,
|
||||||
{
|
{
|
||||||
struct smb_charger *chg = 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,
|
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;
|
struct smb_charger *chg = data;
|
||||||
|
|
||||||
|
/* resume input if suspend is invalid */
|
||||||
if (suspend < 0)
|
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,
|
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 (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");
|
smblib_dbg(chg, PR_MISC, "enabling DPDM regulator\n");
|
||||||
rc = regulator_enable(chg->dpdm_reg);
|
rc = regulator_enable(chg->dpdm_reg);
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
|
@ -2242,7 +2244,14 @@ irqreturn_t smblib_handle_usb_plugin(int irq, void *data)
|
||||||
rc);
|
rc);
|
||||||
}
|
}
|
||||||
} else {
|
} 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");
|
smblib_dbg(chg, PR_MISC, "disabling DPDM regulator\n");
|
||||||
rc = regulator_disable(chg->dpdm_reg);
|
rc = regulator_disable(chg->dpdm_reg);
|
||||||
if (rc < 0)
|
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);
|
power_supply_changed(chg->usb_psy);
|
||||||
smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s %s\n",
|
smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s %s\n",
|
||||||
irq_data->name, chg->vbus_present ? "attached" : "detached");
|
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;
|
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 *
|
* Work Queues *
|
||||||
***************/
|
***************/
|
||||||
|
|
|
@ -46,6 +46,7 @@ enum print_reason {
|
||||||
#define VBUS_CC_SHORT_VOTER "VBUS_CC_SHORT_VOTER"
|
#define VBUS_CC_SHORT_VOTER "VBUS_CC_SHORT_VOTER"
|
||||||
#define LEGACY_CABLE_VOTER "LEGACY_CABLE_VOTER"
|
#define LEGACY_CABLE_VOTER "LEGACY_CABLE_VOTER"
|
||||||
#define PD_INACTIVE_VOTER "PD_INACTIVE_VOTER"
|
#define PD_INACTIVE_VOTER "PD_INACTIVE_VOTER"
|
||||||
|
#define BOOST_BACK_VOTER "BOOST_BACK_VOTER"
|
||||||
|
|
||||||
enum smb_mode {
|
enum smb_mode {
|
||||||
PARALLEL_MASTER = 0,
|
PARALLEL_MASTER = 0,
|
||||||
|
@ -55,6 +56,7 @@ enum smb_mode {
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
QC_CHARGER_DETECTION_WA_BIT = BIT(0),
|
QC_CHARGER_DETECTION_WA_BIT = BIT(0),
|
||||||
|
BOOST_BACK_WA = BIT(1),
|
||||||
};
|
};
|
||||||
|
|
||||||
struct smb_regulator {
|
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_usb_typec_change(int irq, void *data);
|
||||||
irqreturn_t smblib_handle_dc_plugin(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_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,
|
int smblib_get_prop_input_suspend(struct smb_charger *chg,
|
||||||
union power_supply_propval *val);
|
union power_supply_propval *val);
|
||||||
|
|
Loading…
Add table
Reference in a new issue