Merge "power: smb-lib: Add support to detect weak charger"

This commit is contained in:
Linux Build Service Account 2017-06-22 14:00:18 -07:00 committed by Gerrit - the friendly Code Review server
commit 1cbfeeaf0d
5 changed files with 102 additions and 19 deletions

View file

@ -266,6 +266,10 @@ module_param_named(
debug_mask, __debug_mask, int, S_IRUSR | S_IWUSR
);
static int __weak_chg_icl_ua = 500000;
module_param_named(
weak_chg_icl_ua, __weak_chg_icl_ua, int, S_IRUSR | S_IWUSR);
#define MICRO_1P5A 1500000
#define MICRO_P1A 100000
#define OTG_DEFAULT_DEGLITCH_TIME_MS 50
@ -2109,7 +2113,7 @@ static struct smb_irq_info smb2_irqs[] = {
[SWITCH_POWER_OK_IRQ] = {
.name = "switcher-power-ok",
.handler = smblib_handle_switcher_power_ok,
.storm_data = {true, 1000, 3},
.storm_data = {true, 1000, 8},
},
};
@ -2303,6 +2307,7 @@ static int smb2_probe(struct platform_device *pdev)
chg->dev = &pdev->dev;
chg->param = v1_params;
chg->debug_mask = &__debug_mask;
chg->weak_chg_icl_ua = &__weak_chg_icl_ua;
chg->mode = PARALLEL_MASTER;
chg->irq_info = smb2_irqs;
chg->name = "PMI";

View file

@ -630,6 +630,8 @@ int smblib_mapping_cc_delta_from_field_value(struct smb_chg_param *param,
static void smblib_uusb_removal(struct smb_charger *chg)
{
int rc;
struct smb_irq_data *data;
struct storm_watch *wdata;
cancel_delayed_work_sync(&chg->pl_enable_work);
@ -641,8 +643,16 @@ static void smblib_uusb_removal(struct smb_charger *chg)
rc);
}
if (chg->wa_flags & BOOST_BACK_WA)
vote(chg->usb_icl_votable, BOOST_BACK_VOTER, false, 0);
if (chg->wa_flags & BOOST_BACK_WA) {
data = chg->irq_info[SWITCH_POWER_OK_IRQ].irq_data;
if (data) {
wdata = &data->storm_data;
update_storm_count(wdata, WEAK_CHG_STORM_COUNT);
vote(chg->usb_icl_votable, BOOST_BACK_VOTER, false, 0);
vote(chg->usb_icl_votable, WEAK_CHARGER_VOTER,
false, 0);
}
}
vote(chg->pl_disable_votable, PL_DELAY_VOTER, true, 0);
vote(chg->awake_votable, PL_DELAY_VOTER, false, 0);
@ -3138,6 +3148,8 @@ void smblib_usb_plugin_hard_reset_locked(struct smb_charger *chg)
int rc;
u8 stat;
bool vbus_rising;
struct smb_irq_data *data;
struct storm_watch *wdata;
rc = smblib_read(chg, USBIN_BASE + INT_RT_STS_OFFSET, &stat);
if (rc < 0) {
@ -3151,8 +3163,18 @@ void smblib_usb_plugin_hard_reset_locked(struct smb_charger *chg)
smblib_cc2_sink_removal_exit(chg);
} else {
smblib_cc2_sink_removal_enter(chg);
if (chg->wa_flags & BOOST_BACK_WA)
vote(chg->usb_icl_votable, BOOST_BACK_VOTER, false, 0);
if (chg->wa_flags & BOOST_BACK_WA) {
data = chg->irq_info[SWITCH_POWER_OK_IRQ].irq_data;
if (data) {
wdata = &data->storm_data;
update_storm_count(wdata,
WEAK_CHG_STORM_COUNT);
vote(chg->usb_icl_votable, BOOST_BACK_VOTER,
false, 0);
vote(chg->usb_icl_votable, WEAK_CHARGER_VOTER,
false, 0);
}
}
}
power_supply_changed(chg->usb_psy);
@ -3166,6 +3188,8 @@ void smblib_usb_plugin_locked(struct smb_charger *chg)
int rc;
u8 stat;
bool vbus_rising;
struct smb_irq_data *data;
struct storm_watch *wdata;
rc = smblib_read(chg, USBIN_BASE + INT_RT_STS_OFFSET, &stat);
if (rc < 0) {
@ -3202,8 +3226,18 @@ void smblib_usb_plugin_locked(struct smb_charger *chg)
schedule_delayed_work(&chg->pl_enable_work,
msecs_to_jiffies(PL_DELAY_MS));
} else {
if (chg->wa_flags & BOOST_BACK_WA)
vote(chg->usb_icl_votable, BOOST_BACK_VOTER, false, 0);
if (chg->wa_flags & BOOST_BACK_WA) {
data = chg->irq_info[SWITCH_POWER_OK_IRQ].irq_data;
if (data) {
wdata = &data->storm_data;
update_storm_count(wdata,
WEAK_CHG_STORM_COUNT);
vote(chg->usb_icl_votable, BOOST_BACK_VOTER,
false, 0);
vote(chg->usb_icl_votable, WEAK_CHARGER_VOTER,
false, 0);
}
}
if (chg->dpdm_reg && regulator_is_enabled(chg->dpdm_reg)) {
smblib_dbg(chg, PR_MISC, "disabling DPDM regulator\n");
@ -3582,6 +3616,8 @@ static void typec_sink_removal(struct smb_charger *chg)
static void smblib_handle_typec_removal(struct smb_charger *chg)
{
int rc;
struct smb_irq_data *data;
struct storm_watch *wdata;
chg->cc2_detach_wa_active = false;
@ -3593,8 +3629,16 @@ static void smblib_handle_typec_removal(struct smb_charger *chg)
rc);
}
if (chg->wa_flags & BOOST_BACK_WA)
vote(chg->usb_icl_votable, BOOST_BACK_VOTER, false, 0);
if (chg->wa_flags & BOOST_BACK_WA) {
data = chg->irq_info[SWITCH_POWER_OK_IRQ].irq_data;
if (data) {
wdata = &data->storm_data;
update_storm_count(wdata, WEAK_CHG_STORM_COUNT);
vote(chg->usb_icl_votable, BOOST_BACK_VOTER, false, 0);
vote(chg->usb_icl_votable, WEAK_CHARGER_VOTER,
false, 0);
}
}
/* reset APSD voters */
vote(chg->apsd_disable_votable, PD_HARD_RESET_VOTER, false, 0);
@ -3826,10 +3870,13 @@ static void smblib_bb_removal_work(struct work_struct *work)
}
#define BOOST_BACK_UNVOTE_DELAY_MS 750
#define BOOST_BACK_STORM_COUNT 3
#define WEAK_CHG_STORM_COUNT 8
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;
struct storm_watch *wdata = &irq_data->storm_data;
int rc, usb_icl;
u8 stat;
@ -3851,16 +3898,32 @@ irqreturn_t smblib_handle_switcher_power_ok(int irq, void *data)
return IRQ_HANDLED;
if (is_storming(&irq_data->storm_data)) {
smblib_err(chg, "Reverse boost detected: voting 0mA to suspend input\n");
vote(chg->usb_icl_votable, BOOST_BACK_VOTER, true, 0);
vote(chg->awake_votable, BOOST_BACK_VOTER, true, 0);
/*
* Remove the boost-back vote after a delay, to avoid
* permanently suspending the input if the boost-back condition
* is unintentionally hit.
*/
schedule_delayed_work(&chg->bb_removal_work,
msecs_to_jiffies(BOOST_BACK_UNVOTE_DELAY_MS));
/* This could be a weak charger reduce ICL */
if (!is_client_vote_enabled(chg->usb_icl_votable,
WEAK_CHARGER_VOTER)) {
smblib_err(chg,
"Weak charger detected: voting %dmA ICL\n",
*chg->weak_chg_icl_ua / 1000);
vote(chg->usb_icl_votable, WEAK_CHARGER_VOTER,
true, *chg->weak_chg_icl_ua);
/*
* reset storm data and set the storm threshold
* to 3 for reverse boost detection.
*/
update_storm_count(wdata, BOOST_BACK_STORM_COUNT);
} else {
smblib_err(chg,
"Reverse boost detected: voting 0mA to suspend input\n");
vote(chg->usb_icl_votable, BOOST_BACK_VOTER, true, 0);
vote(chg->awake_votable, BOOST_BACK_VOTER, true, 0);
/*
* Remove the boost-back vote after a delay, to avoid
* permanently suspending the input if the boost-back
* condition is unintentionally hit.
*/
schedule_delayed_work(&chg->bb_removal_work,
msecs_to_jiffies(BOOST_BACK_UNVOTE_DELAY_MS));
}
}
return IRQ_HANDLED;

View file

@ -64,9 +64,12 @@ enum print_reason {
#define BATT_PROFILE_VOTER "BATT_PROFILE_VOTER"
#define OTG_DELAY_VOTER "OTG_DELAY_VOTER"
#define USBIN_I_VOTER "USBIN_I_VOTER"
#define WEAK_CHARGER_VOTER "WEAK_CHARGER_VOTER"
#define VCONN_MAX_ATTEMPTS 3
#define OTG_MAX_ATTEMPTS 3
#define BOOST_BACK_STORM_COUNT 3
#define WEAK_CHG_STORM_COUNT 8
enum smb_mode {
PARALLEL_MASTER = 0,
@ -230,6 +233,7 @@ struct smb_charger {
struct smb_chg_freq chg_freq;
int smb_version;
int otg_delay_ms;
int *weak_chg_icl_ua;
/* locks */
struct mutex lock;

View file

@ -64,3 +64,13 @@ void reset_storm_count(struct storm_watch *data)
data->storm_count = 0;
mutex_unlock(&data->storm_lock);
}
void update_storm_count(struct storm_watch *data, int max_count)
{
if (!data)
return;
mutex_lock(&data->storm_lock);
data->max_storm_count = max_count;
mutex_unlock(&data->storm_lock);
}

View file

@ -37,4 +37,5 @@ struct storm_watch {
bool is_storming(struct storm_watch *data);
void reset_storm_count(struct storm_watch *data);
void update_storm_count(struct storm_watch *data, int max_count);
#endif