From 69d321dceeeb492e645d100906f54ac492330089 Mon Sep 17 00:00:00 2001 From: Abhijeet Dharmapurikar Date: Thu, 23 Mar 2017 14:04:05 -0700 Subject: [PATCH 1/4] qcom: battery: remove ICL_REDUCTION support Make battery library to directly update the split current of the main charger via power_supply framework's set_property API using CURRENT_MAX property. ICL_REDUCTION property is no longer required. Note that we are not doing initial ICL vote for USBIN USBIN, instead when time comes to split aicl, we will read the input current limit and if nothing is set, check what the hw determined as the max limit and use that. For a PD charger case where the apsd result will be unknown, the current limit is expected to be set by the time aicl settled is called. The 30 second delaying of parallel enabling, should give PD engine ample time to set the current limits. While at it clean up the way settled current change is tracked. Create a variable that specifically indicates the total settled current seen last time settled current was adjusted. This makes compare to an updated settled current value easy. CRs-Fixed: 2014572 Change-Id: I040b65e6380f2c12350ea44bf32e6981ff126f18 Signed-off-by: Ashay Jaiswal Signed-off-by: Abhijeet Dharmapurikar --- drivers/power/supply/qcom/battery.c | 58 ++++++++++++++++------- drivers/power/supply/qcom/qpnp-smb2.c | 11 ++--- drivers/power/supply/qcom/smb-lib.c | 66 +++++---------------------- drivers/power/supply/qcom/smb-lib.h | 4 +- 4 files changed, 58 insertions(+), 81 deletions(-) diff --git a/drivers/power/supply/qcom/battery.c b/drivers/power/supply/qcom/battery.c index 99a5f48ad5db..4d18a48f56ee 100644 --- a/drivers/power/supply/qcom/battery.c +++ b/drivers/power/supply/qcom/battery.c @@ -56,8 +56,9 @@ struct pl_data { struct power_supply *main_psy; struct power_supply *pl_psy; struct power_supply *batt_psy; + struct power_supply *usb_psy; int charge_type; - int main_settled_ua; + int total_settled_ua; int pl_settled_ua; struct class qcom_batt_class; struct wakeup_source *pl_ws; @@ -93,15 +94,10 @@ enum { ********/ static void split_settled(struct pl_data *chip) { - int slave_icl_pct; + int slave_icl_pct, total_current_ua; int slave_ua = 0, main_settled_ua = 0; union power_supply_propval pval = {0, }; - int rc; - - /* TODO some parallel chargers do not have a fine ICL resolution. For - * them implement a psy interface which returns the closest lower ICL - * for desired split - */ + int rc, total_settled_ua = 0; if ((chip->pl_mode != POWER_SUPPLY_PL_USBIN_USBIN) && (chip->pl_mode != POWER_SUPPLY_PL_USBIN_USBIN_EXT)) @@ -123,12 +119,31 @@ static void split_settled(struct pl_data *chip) slave_icl_pct = max(0, chip->slave_pct - 10); slave_ua = ((main_settled_ua + chip->pl_settled_ua) * slave_icl_pct) / 100; + total_settled_ua = main_settled_ua + chip->pl_settled_ua; } - /* ICL_REDUCTION on main could be 0mA when pl is disabled */ - pval.intval = slave_ua; + total_current_ua = get_effective_result_locked(chip->usb_icl_votable); + if (total_current_ua < 0) { + if (!chip->usb_psy) + chip->usb_psy = power_supply_get_by_name("usb"); + if (!chip->usb_psy) { + pr_err("Couldn't get usbpsy while splitting settled\n"); + return; + } + /* no client is voting, so get the total current from charger */ + rc = power_supply_get_property(chip->usb_psy, + POWER_SUPPLY_PROP_HW_CURRENT_MAX, &pval); + if (rc < 0) { + pr_err("Couldn't get max current rc=%d\n", rc); + return; + } + total_current_ua = pval.intval; + } + + pval.intval = total_current_ua - slave_ua; + /* Set ICL on main charger */ rc = power_supply_set_property(chip->main_psy, - POWER_SUPPLY_PROP_ICL_REDUCTION, &pval); + POWER_SUPPLY_PROP_CURRENT_MAX, &pval); if (rc < 0) { pr_err("Couldn't change slave suspend state rc=%d\n", rc); return; @@ -143,10 +158,12 @@ static void split_settled(struct pl_data *chip) return; } - /* main_settled_ua represents the total capability of adapter */ - if (!chip->main_settled_ua) - chip->main_settled_ua = main_settled_ua; + chip->total_settled_ua = total_settled_ua; chip->pl_settled_ua = slave_ua; + + pl_dbg(chip, PR_PARALLEL, + "Split total_current_ua=%d main_settled_ua=%d slave_ua=%d\n", + total_current_ua, main_settled_ua, slave_ua); } static ssize_t version_show(struct class *c, struct class_attribute *attr, @@ -528,7 +545,7 @@ static int pl_disable_vote_callback(struct votable *votable, int rc; chip->taper_pct = 100; - chip->main_settled_ua = 0; + chip->total_settled_ua = 0; chip->pl_settled_ua = 0; if (!pl_disable) { /* enable */ @@ -733,6 +750,7 @@ static void handle_main_charge_type(struct pl_data *chip) static void handle_settled_icl_change(struct pl_data *chip) { union power_supply_propval pval = {0, }; + int new_total_settled_ua; int rc; if (get_effective_result(chip->pl_disable_votable)) @@ -752,9 +770,15 @@ static void handle_settled_icl_change(struct pl_data *chip) return; } + new_total_settled_ua = pval.intval + chip->pl_settled_ua; + pl_dbg(chip, PR_PARALLEL, + "total_settled_ua=%d settled_ua=%d new_total_settled_ua=%d\n", + chip->total_settled_ua, pval.intval, + new_total_settled_ua); + /* If ICL change is small skip splitting */ - if (abs((chip->main_settled_ua - chip->pl_settled_ua) - - pval.intval) > MIN_ICL_CHANGE_DELTA_UA) + if (abs(new_total_settled_ua - chip->total_settled_ua) + > MIN_ICL_CHANGE_DELTA_UA) split_settled(chip); } else { rerun_election(chip->fcc_votable); diff --git a/drivers/power/supply/qcom/qpnp-smb2.c b/drivers/power/supply/qcom/qpnp-smb2.c index 77e21a7976ff..f9f1b28baa58 100644 --- a/drivers/power/supply/qcom/qpnp-smb2.c +++ b/drivers/power/supply/qcom/qpnp-smb2.c @@ -414,6 +414,7 @@ static enum power_supply_property smb2_usb_props[] = { POWER_SUPPLY_PROP_BOOST_CURRENT, POWER_SUPPLY_PROP_PE_START, POWER_SUPPLY_PROP_CTM_CURRENT_MAX, + POWER_SUPPLY_PROP_HW_CURRENT_MAX, }; static int smb2_usb_get_prop(struct power_supply *psy, @@ -502,6 +503,9 @@ static int smb2_usb_get_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_CTM_CURRENT_MAX: val->intval = get_client_vote(chg->usb_icl_votable, CTM_VOTER); break; + case POWER_SUPPLY_PROP_HW_CURRENT_MAX: + rc = smblib_get_charge_current(chg, &val->intval); + break; default: pr_err("get prop %d is not supported in usb\n", psp); rc = -EINVAL; @@ -610,7 +614,6 @@ static int smb2_init_usb_psy(struct smb2 *chip) static enum power_supply_property smb2_usb_main_props[] = { POWER_SUPPLY_PROP_VOLTAGE_MAX, - POWER_SUPPLY_PROP_ICL_REDUCTION, POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, POWER_SUPPLY_PROP_TYPE, POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED, @@ -635,9 +638,6 @@ static int smb2_usb_main_get_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_VOLTAGE_MAX: rc = smblib_get_charge_param(chg, &chg->param.fv, &val->intval); break; - case POWER_SUPPLY_PROP_ICL_REDUCTION: - val->intval = chg->icl_reduction_ua; - break; case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX: rc = smblib_get_charge_param(chg, &chg->param.fcc, &val->intval); @@ -681,9 +681,6 @@ static int smb2_usb_main_set_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_VOLTAGE_MAX: rc = smblib_set_charge_param(chg, &chg->param.fv, val->intval); break; - case POWER_SUPPLY_PROP_ICL_REDUCTION: - rc = smblib_set_icl_reduction(chg, val->intval); - break; case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX: rc = smblib_set_charge_param(chg, &chg->param.fcc, val->intval); break; diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c index 5e1300ce1897..cf16d9082466 100644 --- a/drivers/power/supply/qcom/smb-lib.c +++ b/drivers/power/supply/qcom/smb-lib.c @@ -696,13 +696,6 @@ static void smblib_uusb_removal(struct smb_charger *chg) if (rc < 0) smblib_err(chg, "Couldn't un-vote DCP from USB ICL rc=%d\n", rc); - - /* clear USB ICL vote for PL_USBIN_USBIN_VOTER */ - rc = vote(chg->usb_icl_votable, PL_USBIN_USBIN_VOTER, false, 0); - if (rc < 0) - smblib_err(chg, - "Couldn't un-vote PL_USBIN_USBIN from USB ICL rc=%d\n", - rc); } void smblib_suspend_on_debug_battery(struct smb_charger *chg) @@ -871,8 +864,7 @@ int smblib_set_icl_current(struct smb_charger *chg, int icl_ua) goto enable_icl_changed_interrupt; } } else { - rc = smblib_set_charge_param(chg, &chg->param.usb_icl, - icl_ua - chg->icl_reduction_ua); + rc = smblib_set_charge_param(chg, &chg->param.usb_icl, icl_ua); if (rc < 0) { smblib_err(chg, "Couldn't set HC ICL rc=%d\n", rc); goto enable_icl_changed_interrupt; @@ -890,7 +882,7 @@ override_suspend_config: /* 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) + && icl_ua == 1500000) /* * For std cable with type = CDP override only if * current is not 1500mA @@ -2605,13 +2597,6 @@ int smblib_set_prop_pd_active(struct smb_charger *chg, "Couldn't un-vote DCP from USB ICL rc=%d\n", rc); - /* clear USB ICL vote for PL_USBIN_USBIN_VOTER */ - rc = vote(chg->usb_icl_votable, PL_USBIN_USBIN_VOTER, false, 0); - if (rc < 0) - smblib_err(chg, - "Couldn't un-vote PL_USBIN_USBIN from USB ICL rc=%d\n", - rc); - /* remove USB_PSY_VOTER */ rc = vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0); if (rc < 0) { @@ -2866,15 +2851,21 @@ int smblib_get_prop_fcc_delta(struct smb_charger *chg, #define TYPEC_DEFAULT_CURRENT_MA 900000 #define TYPEC_MEDIUM_CURRENT_MA 1500000 #define TYPEC_HIGH_CURRENT_MA 3000000 -static int smblib_get_charge_current(struct smb_charger *chg, +int smblib_get_charge_current(struct smb_charger *chg, int *total_current_ua) { const struct apsd_result *apsd_result = smblib_update_usb_type(chg); union power_supply_propval val = {0, }; - int rc, typec_source_rd, current_ua; + int rc = 0, typec_source_rd, current_ua; bool non_compliant; u8 stat5; + if (chg->pd_active) { + *total_current_ua = + get_client_vote_locked(chg->usb_icl_votable, PD_VOTER); + return rc; + } + rc = smblib_read(chg, TYPE_C_STATUS_5_REG, &stat5); if (rc < 0) { smblib_err(chg, "Couldn't read TYPE_C_STATUS_5 rc=%d\n", rc); @@ -2949,39 +2940,12 @@ static int smblib_get_charge_current(struct smb_charger *chg, return 0; } -int smblib_set_icl_reduction(struct smb_charger *chg, int reduction_ua) -{ - int current_ua, rc; - - if (reduction_ua == 0) { - vote(chg->usb_icl_votable, PL_USBIN_USBIN_VOTER, false, 0); - } else { - /* - * No usb_icl voter means we are defaulting to hw chosen - * max limit. We need a vote from s/w to enforce the reduction. - */ - if (get_effective_result(chg->usb_icl_votable) == -EINVAL) { - rc = smblib_get_charge_current(chg, ¤t_ua); - if (rc < 0) { - pr_err("Failed to get ICL rc=%d\n", rc); - return rc; - } - vote(chg->usb_icl_votable, PL_USBIN_USBIN_VOTER, true, - current_ua); - } - } - - chg->icl_reduction_ua = reduction_ua; - - return rerun_election(chg->usb_icl_votable); -} - /************************ * PARALLEL PSY GETTERS * ************************/ int smblib_get_prop_slave_current_now(struct smb_charger *chg, - union power_supply_propval *pval) + union power_supply_propval *pval) { if (IS_ERR_OR_NULL(chg->iio.batt_i_chan)) chg->iio.batt_i_chan = iio_channel_get(chg->dev, "batt_i"); @@ -3044,7 +3008,7 @@ irqreturn_t smblib_handle_chg_state_change(int irq, void *data) rc = smblib_read(chg, BATTERY_CHARGER_STATUS_1_REG, &stat); if (rc < 0) { smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_1 rc=%d\n", - rc); + rc); return IRQ_HANDLED; } @@ -3584,12 +3548,6 @@ static void typec_source_removal(struct smb_charger *chg) smblib_err(chg, "Couldn't un-vote DCP from USB ICL rc=%d\n", rc); - /* clear USB ICL vote for PL_USBIN_USBIN_VOTER */ - rc = vote(chg->usb_icl_votable, PL_USBIN_USBIN_VOTER, false, 0); - if (rc < 0) - smblib_err(chg, - "Couldn't un-vote PL_USBIN_USBIN from USB ICL rc=%d\n", - rc); } static void typec_source_insertion(struct smb_charger *chg) diff --git a/drivers/power/supply/qcom/smb-lib.h b/drivers/power/supply/qcom/smb-lib.h index 2b09a5bbd1a1..49b9d3da783c 100644 --- a/drivers/power/supply/qcom/smb-lib.h +++ b/drivers/power/supply/qcom/smb-lib.h @@ -322,8 +322,6 @@ struct smb_charger { /* extcon for VBUS / ID notification to USB for uUSB */ struct extcon_dev *extcon; - int icl_reduction_ua; - /* qnovo */ int qnovo_fcc_ua; int qnovo_fv_uv; @@ -489,10 +487,10 @@ int smblib_rerun_apsd_if_required(struct smb_charger *chg); int smblib_get_prop_fcc_delta(struct smb_charger *chg, union power_supply_propval *val); int smblib_icl_override(struct smb_charger *chg, bool override); -int smblib_set_icl_reduction(struct smb_charger *chg, int reduction_ua); int smblib_dp_dm(struct smb_charger *chg, int val); int smblib_rerun_aicl(struct smb_charger *chg); int smblib_set_icl_current(struct smb_charger *chg, int icl_ua); +int smblib_get_charge_current(struct smb_charger *chg, int *total_current_ua); int smblib_init(struct smb_charger *chg); int smblib_deinit(struct smb_charger *chg); From 347cdf228abe816a694204fa15b80dba2436073d Mon Sep 17 00:00:00 2001 From: Abhijeet Dharmapurikar Date: Thu, 23 Mar 2017 14:07:07 -0700 Subject: [PATCH 2/4] qcom: battery: update parallel algorithm for ICL change Update the parallel algorithm for ICL change request. Following steps are performed for every ICL change: - disable parallel charger using ICL_CHANGE_VOTER - update the new ICL and re-run AICL. - re-enable parallel charger by removing vote of ICL_CHANGE_VOTER. While at it, update the 'smblib_get_prop_usb_online' function to use voter library's locked API to get the usb_icl_vote, this fixes the lockup that happens when charging is enabled/disabled from usb_icl_votable's callback function. CRs-Fixed: 2014572 Change-Id: I7deb6a50d67471ab1aa5e1db6fff880574b4bafb Signed-off-by: Ashay Jaiswal Signed-off-by: Abhijeet Dharmapurikar --- drivers/power/supply/qcom/battery.c | 42 ++++++++++++++++++++++++++--- drivers/power/supply/qcom/smb-lib.c | 2 +- 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/drivers/power/supply/qcom/battery.c b/drivers/power/supply/qcom/battery.c index 4d18a48f56ee..53e6a4138f04 100644 --- a/drivers/power/supply/qcom/battery.c +++ b/drivers/power/supply/qcom/battery.c @@ -13,6 +13,7 @@ #define pr_fmt(fmt) "QCOM-BATT: %s: " fmt, __func__ #include +#include #include #include #include @@ -36,6 +37,7 @@ #define PL_HW_ABSENT_VOTER "PL_HW_ABSENT_VOTER" #define PL_VOTER "PL_VOTER" #define RESTRICT_CHG_VOTER "RESTRICT_CHG_VOTER" +#define ICL_CHANGE_VOTER "ICL_CHANGE_VOTER" struct pl_data { int pl_mode; @@ -505,9 +507,11 @@ static int pl_fv_vote_callback(struct votable *votable, void *data, return 0; } +#define ICL_STEP_UV 25000 static int usb_icl_vote_callback(struct votable *votable, void *data, int icl_ua, const char *client) { + int rc; struct pl_data *chip = data; union power_supply_propval pval = {0, }; @@ -517,9 +521,41 @@ static int usb_icl_vote_callback(struct votable *votable, void *data, if (client == NULL) icl_ua = INT_MAX; - pval.intval = icl_ua; - return power_supply_set_property(chip->main_psy, - POWER_SUPPLY_PROP_INPUT_CURRENT_MAX, &pval); + /* + * Disable parallel for new ICL vote - the call to split_settled will + * ensure that all the input current limit gets assigned to the main + * charger. + */ + vote(chip->pl_disable_votable, ICL_CHANGE_VOTER, true, 0); + + /* rerun AICL */ + /* get the settled current */ + rc = power_supply_get_property(chip->main_psy, + POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED, + &pval); + if (rc < 0) { + pr_err("Couldn't get aicl settled value rc=%d\n", rc); + return rc; + } + + /* rerun AICL if new ICL is above settled ICL */ + if (icl_ua > pval.intval) { + /* set a lower ICL */ + pval.intval = max(pval.intval - ICL_STEP_UV, ICL_STEP_UV); + power_supply_set_property(chip->main_psy, + POWER_SUPPLY_PROP_CURRENT_MAX, + &pval); + /* wait for ICL change */ + msleep(100); + + pval.intval = icl_ua; + power_supply_set_property(chip->main_psy, + POWER_SUPPLY_PROP_CURRENT_MAX, + &pval); + /* wait for ICL change */ + msleep(100); + } + vote(chip->pl_disable_votable, ICL_CHANGE_VOTER, false, 0); return 0; } diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c index cf16d9082466..3d6503c42e2f 100644 --- a/drivers/power/supply/qcom/smb-lib.c +++ b/drivers/power/supply/qcom/smb-lib.c @@ -2019,7 +2019,7 @@ int smblib_get_prop_usb_online(struct smb_charger *chg, int rc = 0; u8 stat; - if (get_client_vote(chg->usb_icl_votable, USER_VOTER) == 0) { + if (get_client_vote_locked(chg->usb_icl_votable, USER_VOTER) == 0) { val->intval = false; return rc; } From eb367740c8f2db8aec2d55b8be29c3caf2d926ed Mon Sep 17 00:00:00 2001 From: Ashay Jaiswal Date: Tue, 28 Mar 2017 17:19:47 +0530 Subject: [PATCH 3/4] qcom: smb2: disable parallel in restricted/thermal conditions Add voting to disable parallel charger in case of restricted charging and when system temperature level changes from normal. Parallel charger gets re-enabled once thermal condition/FCC restrictions are removed. CRs-Fixed: 2014572 Change-Id: Ic26b3d93f2f3d582a2eb3c7b9ea0d27bbad24a50 Signed-off-by: Ashay Jaiswal --- drivers/power/supply/qcom/battery.c | 4 ++++ drivers/power/supply/qcom/smb-lib.c | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/drivers/power/supply/qcom/battery.c b/drivers/power/supply/qcom/battery.c index 53e6a4138f04..914a6e4eae64 100644 --- a/drivers/power/supply/qcom/battery.c +++ b/drivers/power/supply/qcom/battery.c @@ -233,6 +233,10 @@ static ssize_t restrict_chg_store(struct class *c, struct class_attribute *attr, chip->restricted_charging_enabled = !!val; + /* disable parallel charger in case of restricted charging */ + vote(chip->pl_disable_votable, RESTRICT_CHG_VOTER, + chip->restricted_charging_enabled, 0); + vote(chip->fcc_votable, RESTRICT_CHG_VOTER, chip->restricted_charging_enabled, chip->restricted_current); diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c index 3d6503c42e2f..c9df25586da9 100644 --- a/drivers/power/supply/qcom/smb-lib.c +++ b/drivers/power/supply/qcom/smb-lib.c @@ -1785,6 +1785,10 @@ int smblib_set_prop_system_temp_level(struct smb_charger *chg, return -EINVAL; chg->system_temp_level = val->intval; + /* disable parallel charge in case of system temp level */ + vote(chg->pl_disable_votable, THERMAL_DAEMON_VOTER, + chg->system_temp_level ? true : false, 0); + if (chg->system_temp_level == chg->thermal_levels) return vote(chg->chg_disable_votable, THERMAL_DAEMON_VOTER, true, 0); From 0b6793543b1036bf6d49c5274ae307507154a750 Mon Sep 17 00:00:00 2001 From: Ashay Jaiswal Date: Tue, 4 Apr 2017 16:57:57 +0530 Subject: [PATCH 4/4] qcom: smb1351: update CHARGING_ENABLE reporting logic In case of parallel charging mode "parallel_charger_suspended" variable tracks the charging enable state, update CHARGING_ENABLE reporting to use the same. CRs-Fixed: 2014572 Change-Id: Ib7246f407ad103343b7587b9de3ac938fb63767d Signed-off-by: Ashay Jaiswal --- drivers/power/supply/qcom/smb1351-charger.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/power/supply/qcom/smb1351-charger.c b/drivers/power/supply/qcom/smb1351-charger.c index 8467d167512f..7014fd706d9e 100644 --- a/drivers/power/supply/qcom/smb1351-charger.c +++ b/drivers/power/supply/qcom/smb1351-charger.c @@ -1655,7 +1655,7 @@ static int smb1351_parallel_get_property(struct power_supply *psy, switch (prop) { case POWER_SUPPLY_PROP_CHARGING_ENABLED: - val->intval = !chip->usb_suspended_status; + val->intval = !chip->parallel_charger_suspended; break; case POWER_SUPPLY_PROP_CURRENT_MAX: if (!chip->parallel_charger_suspended)