diff options
author | Ashay Jaiswal <ashayj@codeaurora.org> | 2017-06-14 16:04:45 +0530 |
---|---|---|
committer | Ashay Jaiswal <ashayj@codeaurora.org> | 2017-06-21 19:22:08 +0530 |
commit | 7a071fadb175463dcd24cb1de3f4e6078d5dfb2d (patch) | |
tree | 57c14492185c1c1a4b827c271d7d181c534274c2 /drivers | |
parent | f11fd649ff6594a4614894ae710784b22e7d1289 (diff) |
power: smb-lib: Add support to detect weak charger
A weak charger might trigger switcher_power_ok interrupt storm
which gets incorrectly detected as a boost_back condition and
input gets suspended. Add a logic to distinguish a weak charger
and the boost_back condition by first reducing the ICL current
to a lower value (500mA by default) on detecting a
switcher_power_ok storm. If the switcher_ok storm disappears
then its indeed a weak charger and if the storm continues its
possibly a boost_back condition.
Change-Id: I46b406e403aa16a502e6da149b180545848fc906
Signed-off-by: Ashay Jaiswal <ashayj@codeaurora.org>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/power/supply/qcom/qpnp-smb2.c | 7 | ||||
-rw-r--r-- | drivers/power/supply/qcom/smb-lib.c | 99 | ||||
-rw-r--r-- | drivers/power/supply/qcom/smb-lib.h | 4 | ||||
-rw-r--r-- | drivers/power/supply/qcom/storm-watch.c | 10 | ||||
-rw-r--r-- | drivers/power/supply/qcom/storm-watch.h | 1 |
5 files changed, 102 insertions, 19 deletions
diff --git a/drivers/power/supply/qcom/qpnp-smb2.c b/drivers/power/supply/qcom/qpnp-smb2.c index 803851d2b3ef..49cd7aa6fdac 100644 --- a/drivers/power/supply/qcom/qpnp-smb2.c +++ b/drivers/power/supply/qcom/qpnp-smb2.c @@ -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"; diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c index 49a5a17a521b..22944f122c44 100644 --- a/drivers/power/supply/qcom/smb-lib.c +++ b/drivers/power/supply/qcom/smb-lib.c @@ -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; diff --git a/drivers/power/supply/qcom/smb-lib.h b/drivers/power/supply/qcom/smb-lib.h index a428b35f9493..c97b84c34084 100644 --- a/drivers/power/supply/qcom/smb-lib.h +++ b/drivers/power/supply/qcom/smb-lib.h @@ -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; diff --git a/drivers/power/supply/qcom/storm-watch.c b/drivers/power/supply/qcom/storm-watch.c index 5275079c53e0..21ac669f2ec9 100644 --- a/drivers/power/supply/qcom/storm-watch.c +++ b/drivers/power/supply/qcom/storm-watch.c @@ -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); +} diff --git a/drivers/power/supply/qcom/storm-watch.h b/drivers/power/supply/qcom/storm-watch.h index ff05c4a661c3..5275d73613d4 100644 --- a/drivers/power/supply/qcom/storm-watch.h +++ b/drivers/power/supply/qcom/storm-watch.h @@ -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 |