smb-lib: do not disable parallel based only on main's settled current
Currently main charger ends up voting to disable parallel(USBIN_I_VOTER)
if the settled current is less than 1.4Amps. It could be that the
parallel path is drawing some current and the draw is higher than
1.4Amps.
Move this disabling to battery, where the parallel charger's input current
is taken in to consideration.
Also while voting to disable, make sure that the main's input is limited.
If there is more room for ICL to increase that means more power could be
drawn from the charger and so we must keep the parallel charging enabled.
If the ICL ceiling itself if 1.4Amps then disable parallel charging,
because even if ICL has room to increase it wont cross 1.4Amps.
The main's input limited state is set while AICL steps up - this
ensures that we keep parallel disabled while AICL is running and settled
is less than 1.4Amps.
When the charger is removed, the main's input limited status is unset,
however we want to keep the parallel charger disabled. In such situations
the main's settled current is 0mA - use this to vote for disabling
parallel charging.
For any ICL change vote request:
Disable parallel using USBIN_I_VOTER if requested current is less than
1.4Amps and to un-vote (i.e. when ICL vote is higher than 1.4Amps) rely
on event from AICL done or status_change delayed work.
Note that USBIN_I_VOTER is effective only for non-QC chargers. For QC
chargers USBIN_V_VOTER continues to keep charging enabled since parallel
need not be disabled is a lower current is requested with a QC charger.
Change-Id: I61d7cd161a87de2904470b2d870058a0fe199116
Signed-off-by: Abhijeet Dharmapurikar <adharmap@codeaurora.org>
diff --git a/drivers/power/supply/qcom/battery.c b/drivers/power/supply/qcom/battery.c
index 4ecf9a5..bf5f952 100644
--- a/drivers/power/supply/qcom/battery.c
+++ b/drivers/power/supply/qcom/battery.c
@@ -39,6 +39,8 @@
#define PL_VOTER "PL_VOTER"
#define RESTRICT_CHG_VOTER "RESTRICT_CHG_VOTER"
#define ICL_CHANGE_VOTER "ICL_CHANGE_VOTER"
+#define PL_INDIRECT_VOTER "PL_INDIRECT_VOTER"
+#define USBIN_I_VOTER "USBIN_I_VOTER"
struct pl_data {
int pl_mode;
@@ -53,7 +55,8 @@
struct votable *pl_awake_votable;
struct votable *hvdcp_hw_inov_dis_votable;
struct votable *usb_icl_votable;
- struct work_struct status_change_work;
+ struct votable *pl_enable_votable_indirect;
+ struct delayed_work status_change_work;
struct work_struct pl_disable_forever_work;
struct delayed_work pl_taper_work;
struct power_supply *main_psy;
@@ -491,6 +494,7 @@
}
#define ICL_STEP_UA 25000
+#define PL_DELAY_MS 3000
static int usb_icl_vote_callback(struct votable *votable, void *data,
int icl_ua, const char *client)
{
@@ -512,6 +516,21 @@
*/
vote(chip->pl_disable_votable, ICL_CHANGE_VOTER, true, 0);
+ /*
+ * if (ICL < 1400)
+ * disable parallel charger using USBIN_I_VOTER
+ * else
+ * instead of re-enabling here rely on status_changed_work
+ * (triggered via AICL completed or scheduled from here to
+ * unvote USBIN_I_VOTER) the status_changed_work enables
+ * USBIN_I_VOTER based on settled current.
+ */
+ if (icl_ua <= 1400000)
+ vote(chip->pl_enable_votable_indirect, USBIN_I_VOTER, false, 0);
+ else
+ schedule_delayed_work(&chip->status_change_work,
+ msecs_to_jiffies(PL_DELAY_MS));
+
/* rerun AICL */
/* get the settled current */
rc = power_supply_get_property(chip->main_psy,
@@ -643,6 +662,16 @@
return 0;
}
+static int pl_enable_indirect_vote_callback(struct votable *votable,
+ void *data, int pl_enable, const char *client)
+{
+ struct pl_data *chip = data;
+
+ vote(chip->pl_disable_votable, PL_INDIRECT_VOTER, !pl_enable, 0);
+
+ return 0;
+}
+
static int pl_awake_vote_callback(struct votable *votable,
void *data, int awake, const char *client)
{
@@ -775,6 +804,42 @@
union power_supply_propval pval = {0, };
int new_total_settled_ua;
int rc;
+ int main_settled_ua;
+ int main_limited;
+ int total_current_ua;
+
+ total_current_ua = get_effective_result_locked(chip->usb_icl_votable);
+
+ /*
+ * call aicl split only when USBIN_USBIN and enabled
+ * and if aicl changed
+ */
+ 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;
+ }
+ main_settled_ua = pval.intval;
+
+ rc = power_supply_get_property(chip->batt_psy,
+ POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED,
+ &pval);
+ if (rc < 0) {
+ pr_err("Couldn't get aicl settled value rc=%d\n", rc);
+ return;
+ }
+ main_limited = pval.intval;
+
+ if ((main_limited && (main_settled_ua + chip->pl_settled_ua) < 1400000)
+ || (main_settled_ua == 0)
+ || ((total_current_ua >= 0) &&
+ (total_current_ua <= 1400000)))
+ vote(chip->pl_enable_votable_indirect, USBIN_I_VOTER, false, 0);
+ else
+ vote(chip->pl_enable_votable_indirect, USBIN_I_VOTER, true, 0);
+
if (get_effective_result(chip->pl_disable_votable))
return;
@@ -783,17 +848,10 @@
|| chip->pl_mode == POWER_SUPPLY_PL_USBIN_USBIN_EXT) {
/*
* call aicl split only when USBIN_USBIN and enabled
- * and if aicl changed
+ * and if settled current has changed by more than 300mA
*/
- 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;
- }
- new_total_settled_ua = pval.intval + chip->pl_settled_ua;
+ new_total_settled_ua = main_settled_ua + 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,
@@ -840,7 +898,7 @@
static void status_change_work(struct work_struct *work)
{
struct pl_data *chip = container_of(work,
- struct pl_data, status_change_work);
+ struct pl_data, status_change_work.work);
if (!chip->main_psy && is_main_available(chip)) {
/*
@@ -878,7 +936,7 @@
if ((strcmp(psy->desc->name, "parallel") == 0)
|| (strcmp(psy->desc->name, "battery") == 0)
|| (strcmp(psy->desc->name, "main") == 0))
- schedule_work(&chip->status_change_work);
+ schedule_delayed_work(&chip->status_change_work, 0);
return NOTIFY_OK;
}
@@ -899,7 +957,7 @@
static int pl_determine_initial_status(struct pl_data *chip)
{
- status_change_work(&chip->status_change_work);
+ status_change_work(&chip->status_change_work.work);
return 0;
}
@@ -968,7 +1026,18 @@
goto destroy_votable;
}
- INIT_WORK(&chip->status_change_work, status_change_work);
+ chip->pl_enable_votable_indirect = create_votable("PL_ENABLE_INDIRECT",
+ VOTE_SET_ANY,
+ pl_enable_indirect_vote_callback,
+ chip);
+ if (IS_ERR(chip->pl_enable_votable_indirect)) {
+ rc = PTR_ERR(chip->pl_enable_votable_indirect);
+ return rc;
+ }
+
+ vote(chip->pl_disable_votable, PL_INDIRECT_VOTER, true, 0);
+
+ INIT_DELAYED_WORK(&chip->status_change_work, status_change_work);
INIT_DELAYED_WORK(&chip->pl_taper_work, pl_taper_work);
INIT_WORK(&chip->pl_disable_forever_work, pl_disable_forever_work);
@@ -1001,6 +1070,7 @@
unreg_notifier:
power_supply_unreg_notifier(&chip->nb);
destroy_votable:
+ destroy_votable(chip->pl_enable_votable_indirect);
destroy_votable(chip->pl_awake_votable);
destroy_votable(chip->pl_disable_votable);
destroy_votable(chip->fv_votable);
@@ -1020,11 +1090,12 @@
if (chip == NULL)
return;
- cancel_work_sync(&chip->status_change_work);
+ cancel_delayed_work_sync(&chip->status_change_work);
cancel_delayed_work_sync(&chip->pl_taper_work);
cancel_work_sync(&chip->pl_disable_forever_work);
power_supply_unreg_notifier(&chip->nb);
+ destroy_votable(chip->pl_enable_votable_indirect);
destroy_votable(chip->pl_awake_votable);
destroy_votable(chip->pl_disable_votable);
destroy_votable(chip->fv_votable);
diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c
index 9880598..45bf783 100644
--- a/drivers/power/supply/qcom/smb-lib.c
+++ b/drivers/power/supply/qcom/smb-lib.c
@@ -1046,16 +1046,6 @@
return 0;
}
-static int smblib_pl_enable_indirect_vote_callback(struct votable *votable,
- void *data, int chg_enable, const char *client)
-{
- struct smb_charger *chg = data;
-
- vote(chg->pl_disable_votable, PL_INDIRECT_VOTER, !chg_enable, 0);
-
- return 0;
-}
-
static int smblib_hvdcp_enable_vote_callback(struct votable *votable,
void *data,
int hvdcp_enable, const char *client)
@@ -4185,8 +4175,6 @@
}
power_supply_changed(chg->usb_main_psy);
- vote(chg->pl_enable_votable_indirect, USBIN_I_VOTER,
- settled_ua >= USB_WEAK_INPUT_UA, 0);
smblib_dbg(chg, PR_INTERRUPT, "icl_settled=%d\n", settled_ua);
}
@@ -4282,7 +4270,16 @@
smblib_err(chg, "Couldn't find votable PL_DISABLE rc=%d\n", rc);
return rc;
}
- vote(chg->pl_disable_votable, PL_INDIRECT_VOTER, true, 0);
+
+ chg->pl_enable_votable_indirect = find_votable("PL_ENABLE_INDIRECT");
+ if (chg->pl_enable_votable_indirect == NULL) {
+ rc = -EINVAL;
+ smblib_err(chg,
+ "Couldn't find votable PL_ENABLE_INDIRECT rc=%d\n",
+ rc);
+ return rc;
+ }
+
vote(chg->pl_disable_votable, PL_DELAY_VOTER, true, 0);
chg->dc_suspend_votable = create_votable("DC_SUSPEND", VOTE_SET_ANY,
@@ -4332,14 +4329,6 @@
return rc;
}
- chg->pl_enable_votable_indirect = create_votable("PL_ENABLE_INDIRECT",
- VOTE_SET_ANY,
- smblib_pl_enable_indirect_vote_callback,
- chg);
- if (IS_ERR(chg->pl_enable_votable_indirect)) {
- rc = PTR_ERR(chg->pl_enable_votable_indirect);
- return rc;
- }
chg->hvdcp_disable_votable_indirect = create_votable(
"HVDCP_DISABLE_INDIRECT",
@@ -4415,8 +4404,6 @@
destroy_votable(chg->awake_votable);
if (chg->chg_disable_votable)
destroy_votable(chg->chg_disable_votable);
- if (chg->pl_enable_votable_indirect)
- destroy_votable(chg->pl_enable_votable_indirect);
if (chg->apsd_disable_votable)
destroy_votable(chg->apsd_disable_votable);
if (chg->hvdcp_hw_inov_dis_votable)
diff --git a/drivers/power/supply/qcom/smb-lib.h b/drivers/power/supply/qcom/smb-lib.h
index 883f520..0c8e661 100644
--- a/drivers/power/supply/qcom/smb-lib.h
+++ b/drivers/power/supply/qcom/smb-lib.h
@@ -36,9 +36,7 @@
#define PL_USBIN_USBIN_VOTER "PL_USBIN_USBIN_VOTER"
#define USB_PSY_VOTER "USB_PSY_VOTER"
#define PL_TAPER_WORK_RUNNING_VOTER "PL_TAPER_WORK_RUNNING_VOTER"
-#define PL_INDIRECT_VOTER "PL_INDIRECT_VOTER"
#define PL_QNOVO_VOTER "PL_QNOVO_VOTER"
-#define USBIN_I_VOTER "USBIN_I_VOTER"
#define USBIN_V_VOTER "USBIN_V_VOTER"
#define CHG_STATE_VOTER "CHG_STATE_VOTER"
#define TYPEC_SRC_VOTER "TYPEC_SRC_VOTER"
@@ -65,6 +63,7 @@
#define QNOVO_VOTER "QNOVO_VOTER"
#define BATT_PROFILE_VOTER "BATT_PROFILE_VOTER"
#define OTG_DELAY_VOTER "OTG_DELAY_VOTER"
+#define USBIN_I_VOTER "USBIN_I_VOTER"
#define VCONN_MAX_ATTEMPTS 3
#define OTG_MAX_ATTEMPTS 3