Merge "smb-lib: fix icl changed interrupt storm"

This commit is contained in:
Linux Build Service Account 2017-02-15 17:01:06 -08:00 committed by Gerrit - the friendly Code Review server
commit be873ee554
4 changed files with 103 additions and 88 deletions

View file

@ -1382,7 +1382,8 @@ static int smb2_init_hw(struct smb2 *chip)
} }
/* votes must be cast before configuring software control */ /* votes must be cast before configuring software control */
vote(chg->usb_suspend_votable, /* vote 0mA on usb_icl for non battery platforms */
vote(chg->usb_icl_votable,
DEFAULT_VOTER, chip->dt.no_battery, 0); DEFAULT_VOTER, chip->dt.no_battery, 0);
vote(chg->dc_suspend_votable, vote(chg->dc_suspend_votable,
DEFAULT_VOTER, chip->dt.no_battery, 0); DEFAULT_VOTER, chip->dt.no_battery, 0);

View file

@ -698,7 +698,7 @@ void smblib_suspend_on_debug_battery(struct smb_charger *chg)
return; return;
} }
vote(chg->usb_suspend_votable, DEBUG_BOARD_VOTER, val.intval, 0); vote(chg->usb_icl_votable, DEBUG_BOARD_VOTER, val.intval, 0);
vote(chg->dc_suspend_votable, DEBUG_BOARD_VOTER, val.intval, 0); vote(chg->dc_suspend_votable, DEBUG_BOARD_VOTER, val.intval, 0);
if (val.intval) if (val.intval)
pr_info("Input suspended: Fake battery\n"); pr_info("Input suspended: Fake battery\n");
@ -741,18 +741,6 @@ int smblib_rerun_apsd_if_required(struct smb_charger *chg)
* VOTABLE CALLBACKS * * VOTABLE CALLBACKS *
*********************/ *********************/
static int smblib_usb_suspend_vote_callback(struct votable *votable, void *data,
int suspend, const char *client)
{
struct smb_charger *chg = data;
/* 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,
int suspend, const char *client) int suspend, const char *client)
{ {
@ -770,44 +758,12 @@ static int smblib_dc_suspend_vote_callback(struct votable *votable, void *data,
#define USBIN_150MA 150000 #define USBIN_150MA 150000
#define USBIN_500MA 500000 #define USBIN_500MA 500000
#define USBIN_900MA 900000 #define USBIN_900MA 900000
static int smblib_usb_icl_vote_callback(struct votable *votable, void *data,
int icl_ua, const char *client)
static int set_sdp_current(struct smb_charger *chg, int icl_ua)
{ {
struct smb_charger *chg = data; int rc;
int rc = 0; u8 icl_options;
bool suspend, override;
u8 icl_options = 0;
override = true;
/* remove override if no voters or type = SDP or CDP */
if (client == NULL
|| chg->usb_psy_desc.type == POWER_SUPPLY_TYPE_USB
|| chg->usb_psy_desc.type == POWER_SUPPLY_TYPE_USB_CDP)
override = false;
suspend = false;
if (client && (icl_ua < USBIN_25MA))
suspend = true;
if (suspend)
goto out;
if (chg->usb_psy_desc.type != POWER_SUPPLY_TYPE_USB) {
if (client) {
rc = smblib_set_charge_param(chg, &chg->param.usb_icl,
icl_ua - chg->icl_reduction_ua);
if (rc < 0) {
smblib_err(chg, "Couldn't set HC ICL rc=%d\n",
rc);
return rc;
}
}
smblib_dbg(chg, PR_PARALLEL,
"icl_ua=%d icl_reduction=%d\n",
icl_ua, chg->icl_reduction_ua);
goto out;
}
/* power source is SDP */ /* power source is SDP */
switch (icl_ua) { switch (icl_ua) {
@ -829,35 +785,97 @@ static int smblib_usb_icl_vote_callback(struct votable *votable, void *data,
break; break;
default: default:
smblib_err(chg, "ICL %duA isn't supported for SDP\n", icl_ua); smblib_err(chg, "ICL %duA isn't supported for SDP\n", icl_ua);
icl_options = 0; return -EINVAL;
break;
} }
out:
if (override)
icl_options |= USBIN_MODE_CHG_BIT;
rc = smblib_masked_write(chg, USBIN_ICL_OPTIONS_REG, rc = smblib_masked_write(chg, USBIN_ICL_OPTIONS_REG,
CFG_USB3P0_SEL_BIT | USB51_MODE_BIT | USBIN_MODE_CHG_BIT, CFG_USB3P0_SEL_BIT | USB51_MODE_BIT, icl_options);
icl_options);
if (rc < 0) { if (rc < 0) {
smblib_err(chg, "Couldn't set ICL options rc=%d\n", rc); smblib_err(chg, "Couldn't set ICL options rc=%d\n", rc);
return rc; return rc;
} }
rc = vote(chg->usb_suspend_votable, PD_VOTER, suspend, 0);
if (rc < 0) {
smblib_err(chg, "Couldn't %s input rc=%d\n",
suspend ? "suspend" : "resume", rc);
return rc; return rc;
}
static int smblib_usb_icl_vote_callback(struct votable *votable, void *data,
int icl_ua, const char *client)
{
struct smb_charger *chg = data;
int rc = 0;
bool override;
union power_supply_propval pval;
/* suspend and return if 25mA or less is requested */
if (client && (icl_ua < USBIN_25MA))
return smblib_set_usb_suspend(chg, true);
disable_irq_nosync(chg->irq_info[USBIN_ICL_CHANGE_IRQ].irq);
if (!client)
goto override_suspend_config;
rc = smblib_get_prop_typec_mode(chg, &pval);
if (rc < 0) {
smblib_err(chg, "Couldn't get typeC mode rc = %d\n", rc);
goto enable_icl_changed_interrupt;
} }
/* configure current */
if (pval.intval == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT
&& (chg->usb_psy_desc.type == POWER_SUPPLY_TYPE_USB)) {
rc = set_sdp_current(chg, icl_ua);
if (rc < 0) {
smblib_err(chg, "Couldn't set SDP ICL rc=%d\n", rc);
goto enable_icl_changed_interrupt;
}
} else {
rc = smblib_set_charge_param(chg, &chg->param.usb_icl,
icl_ua - chg->icl_reduction_ua);
if (rc < 0) {
smblib_err(chg, "Couldn't set HC ICL rc=%d\n", rc);
goto enable_icl_changed_interrupt;
}
}
override_suspend_config:
/* determine if override needs to be enforced */
override = true;
if (client == NULL) {
/* remove override if no voters - hw defaults is desired */
override = false;
} else if (pval.intval == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT) {
if (chg->usb_psy_desc.type == POWER_SUPPLY_TYPE_USB)
/* For std cable with type = SDP never override */
override = false;
else if (chg->usb_psy_desc.type == POWER_SUPPLY_TYPE_USB_CDP
&& icl_ua - chg->icl_reduction_ua == 1500000)
/*
* For std cable with type = CDP override only if
* current is not 1500mA
*/
override = false;
}
/* enforce override */
rc = smblib_masked_write(chg, USBIN_ICL_OPTIONS_REG,
USBIN_MODE_CHG_BIT, override ? USBIN_MODE_CHG_BIT : 0);
rc = smblib_icl_override(chg, override); rc = smblib_icl_override(chg, override);
if (rc < 0) { if (rc < 0) {
smblib_err(chg, "Couldn't set ICL override rc=%d\n", rc); smblib_err(chg, "Couldn't set ICL override rc=%d\n", rc);
return rc; goto enable_icl_changed_interrupt;
} }
/* unsuspend after configuring current and override */
rc = smblib_set_usb_suspend(chg, false);
if (rc < 0) {
smblib_err(chg, "Couldn't resume input rc=%d\n", rc);
goto enable_icl_changed_interrupt;
}
enable_icl_changed_interrupt:
enable_irq(chg->irq_info[USBIN_ICL_CHANGE_IRQ].irq);
return rc; return rc;
} }
@ -1269,8 +1287,9 @@ int smblib_vbus_regulator_is_enabled(struct regulator_dev *rdev)
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)
{ {
val->intval = get_client_vote(chg->usb_suspend_votable, USER_VOTER) && val->intval
get_client_vote(chg->dc_suspend_votable, USER_VOTER); = (get_client_vote(chg->usb_icl_votable, USER_VOTER) == 0)
&& get_client_vote(chg->dc_suspend_votable, USER_VOTER);
return 0; return 0;
} }
@ -1567,7 +1586,8 @@ int smblib_set_prop_input_suspend(struct smb_charger *chg,
{ {
int rc; int rc;
rc = vote(chg->usb_suspend_votable, USER_VOTER, (bool)val->intval, 0); /* vote 0mA when suspended */
rc = vote(chg->usb_icl_votable, USER_VOTER, (bool)val->intval, 0);
if (rc < 0) { if (rc < 0) {
smblib_err(chg, "Couldn't vote to %s USB rc=%d\n", smblib_err(chg, "Couldn't vote to %s USB rc=%d\n",
(bool)val->intval ? "suspend" : "resume", rc); (bool)val->intval ? "suspend" : "resume", rc);
@ -1713,7 +1733,7 @@ int smblib_get_prop_usb_online(struct smb_charger *chg,
int rc = 0; int rc = 0;
u8 stat; u8 stat;
if (get_client_vote(chg->usb_suspend_votable, USER_VOTER)) { if (get_client_vote(chg->usb_icl_votable, USER_VOTER) == 0) {
val->intval = false; val->intval = false;
return rc; return rc;
} }
@ -2866,8 +2886,7 @@ irqreturn_t smblib_handle_usb_plugin(int irq, void *data)
} }
} else { } else {
if (chg->wa_flags & BOOST_BACK_WA) if (chg->wa_flags & BOOST_BACK_WA)
vote(chg->usb_suspend_votable, vote(chg->usb_icl_votable, BOOST_BACK_VOTER, false, 0);
BOOST_BACK_VOTER, false, 0);
if (chg->dpdm_reg && regulator_is_enabled(chg->dpdm_reg)) { 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");
@ -3145,6 +3164,13 @@ irqreturn_t smblib_handle_usb_source_change(int irq, void *data)
power_supply_changed(chg->usb_psy); power_supply_changed(chg->usb_psy);
rc = smblib_read(chg, APSD_STATUS_REG, &stat);
if (rc < 0) {
smblib_err(chg, "Couldn't read APSD_STATUS rc=%d\n", rc);
return IRQ_HANDLED;
}
smblib_dbg(chg, PR_REGISTER, "APSD_STATUS = 0x%02x\n", stat);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
@ -3240,12 +3266,13 @@ static void smblib_handle_typec_removal(struct smb_charger *chg)
chg->vconn_attempts = 0; chg->vconn_attempts = 0;
chg->otg_attempts = 0; chg->otg_attempts = 0;
typec_source_removal(chg);
typec_sink_removal(chg);
chg->usb_ever_removed = true; chg->usb_ever_removed = true;
smblib_update_usb_type(chg); smblib_update_usb_type(chg);
typec_source_removal(chg);
typec_sink_removal(chg);
} }
static void smblib_handle_typec_insertion(struct smb_charger *chg, static void smblib_handle_typec_insertion(struct smb_charger *chg,
@ -3428,15 +3455,15 @@ irqreturn_t smblib_handle_switcher_power_ok(int irq, void *data)
} }
if ((stat & USE_USBIN_BIT) && if ((stat & USE_USBIN_BIT) &&
get_effective_result(chg->usb_suspend_votable)) get_effective_result(chg->usb_icl_votable) < USBIN_25MA)
return IRQ_HANDLED; return IRQ_HANDLED;
if (stat & USE_DCIN_BIT) if (stat & USE_DCIN_BIT)
return IRQ_HANDLED; return IRQ_HANDLED;
if (is_storming(&irq_data->storm_data)) { if (is_storming(&irq_data->storm_data)) {
smblib_err(chg, "Reverse boost detected: suspending input\n"); smblib_err(chg, "Reverse boost detected: voting 0mA to suspend input\n");
vote(chg->usb_suspend_votable, BOOST_BACK_VOTER, true, 0); vote(chg->usb_icl_votable, BOOST_BACK_VOTER, true, 0);
} }
return IRQ_HANDLED; return IRQ_HANDLED;
@ -3785,14 +3812,6 @@ static int smblib_create_votables(struct smb_charger *chg)
vote(chg->pl_disable_votable, PL_INDIRECT_VOTER, true, 0); vote(chg->pl_disable_votable, PL_INDIRECT_VOTER, true, 0);
vote(chg->pl_disable_votable, PL_DELAY_HVDCP_VOTER, true, 0); vote(chg->pl_disable_votable, PL_DELAY_HVDCP_VOTER, true, 0);
chg->usb_suspend_votable = create_votable("USB_SUSPEND", VOTE_SET_ANY,
smblib_usb_suspend_vote_callback,
chg);
if (IS_ERR(chg->usb_suspend_votable)) {
rc = PTR_ERR(chg->usb_suspend_votable);
return rc;
}
chg->dc_suspend_votable = create_votable("DC_SUSPEND", VOTE_SET_ANY, chg->dc_suspend_votable = create_votable("DC_SUSPEND", VOTE_SET_ANY,
smblib_dc_suspend_vote_callback, smblib_dc_suspend_vote_callback,
chg); chg);
@ -3890,8 +3909,6 @@ static int smblib_create_votables(struct smb_charger *chg)
static void smblib_destroy_votables(struct smb_charger *chg) static void smblib_destroy_votables(struct smb_charger *chg)
{ {
if (chg->usb_suspend_votable)
destroy_votable(chg->usb_suspend_votable);
if (chg->dc_suspend_votable) if (chg->dc_suspend_votable)
destroy_votable(chg->dc_suspend_votable); destroy_votable(chg->dc_suspend_votable);
if (chg->usb_icl_votable) if (chg->usb_icl_votable)

View file

@ -252,7 +252,6 @@ struct smb_charger {
struct regulator *dpdm_reg; struct regulator *dpdm_reg;
/* votables */ /* votables */
struct votable *usb_suspend_votable;
struct votable *dc_suspend_votable; struct votable *dc_suspend_votable;
struct votable *fcc_votable; struct votable *fcc_votable;
struct votable *fv_votable; struct votable *fv_votable;

View file

@ -827,8 +827,6 @@ static int smb138x_init_hw(struct smb138x *chip)
int rc = 0; int rc = 0;
/* votes must be cast before configuring software control */ /* votes must be cast before configuring software control */
vote(chg->usb_suspend_votable,
DEFAULT_VOTER, chip->dt.suspend_input, 0);
vote(chg->dc_suspend_votable, vote(chg->dc_suspend_votable,
DEFAULT_VOTER, chip->dt.suspend_input, 0); DEFAULT_VOTER, chip->dt.suspend_input, 0);
vote(chg->fcc_votable, vote(chg->fcc_votable,