summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorAbhijeet Dharmapurikar <adharmap@codeaurora.org>2017-02-06 18:39:19 -0800
committerAshay Jaiswal <ashayj@codeaurora.org>2017-02-10 09:57:37 +0530
commit07b6e5b98f730ea7f2285fbbc4a94a57ddf82e50 (patch)
tree63111504c8a1bea65e01535a8b204014bffb1aeb /drivers
parent059118476764090b5fc6ee4bdfb5491f6571cb34 (diff)
smb-lib: manage override in icl_callback
Currently we have only one path - the pd active setting path - where ICL_OVERRIDE gets set. With the upcoming changes to manage connector temperature mitigation and usbin-usbin parallel charger, the ICL_OVERRIDE is needed to be set from these usecases. So instead of creating a voter for ICL_OVERRIDE and putting the onus on callsites to set it before calling their icl settings, it is best to handle it in icl_callback. Update the icl_callback to manage override and suspend in this way. - Presence of voter signifies that the driver wants to enforce a value different than the hw default. Force an icl override. - No voters signifies that the hw defaults are good, undo an override. - For USB types that command a limit aka SDP and CDP, never override. - never suspend if there are no clients. Change-Id: I3ed01237b0bb2c028bec572d2905cabb03ce50a3 Signed-off-by: Abhijeet Dharmapurikar <adharmap@codeaurora.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/power/supply/qcom/qpnp-smb2.c9
-rw-r--r--drivers/power/supply/qcom/smb-lib.c116
-rw-r--r--drivers/power/supply/qcom/smb-lib.h1
3 files changed, 70 insertions, 56 deletions
diff --git a/drivers/power/supply/qcom/qpnp-smb2.c b/drivers/power/supply/qcom/qpnp-smb2.c
index 46e920d1076d..16b7dd8c2ccd 100644
--- a/drivers/power/supply/qcom/qpnp-smb2.c
+++ b/drivers/power/supply/qcom/qpnp-smb2.c
@@ -1351,12 +1351,9 @@ static int smb2_init_hw(struct smb2 *chip)
smblib_rerun_apsd_if_required(chg);
/* clear the ICL override if it is set */
- if (stat & ICL_OVERRIDE_LATCH_BIT) {
- rc = smblib_write(chg, CMD_APSD_REG, ICL_OVERRIDE_BIT);
- if (rc < 0) {
- pr_err("Couldn't disable ICL override rc=%d\n", rc);
- return rc;
- }
+ if (smblib_icl_override(chg, false) < 0) {
+ pr_err("Couldn't disable ICL override rc=%d\n", rc);
+ return rc;
}
/* votes must be cast before configuring software control */
diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c
index 5c5ad200b3e0..dd8cd54b190b 100644
--- a/drivers/power/supply/qcom/smb-lib.c
+++ b/drivers/power/supply/qcom/smb-lib.c
@@ -151,6 +151,31 @@ static int smblib_get_jeita_cc_delta(struct smb_charger *chg, int *cc_delta_ua)
return 0;
}
+int smblib_icl_override(struct smb_charger *chg, bool override)
+{
+ int rc;
+ bool override_status;
+ u8 stat;
+
+ rc = smblib_read(chg, APSD_RESULT_STATUS_REG, &stat);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't read APSD_RESULT_STATUS_REG rc=%d\n",
+ rc);
+ return rc;
+ }
+ override_status = (bool)(stat & ICL_OVERRIDE_LATCH_BIT);
+
+ if (override != override_status) {
+ rc = smblib_masked_write(chg, CMD_APSD_REG,
+ ICL_OVERRIDE_BIT, ICL_OVERRIDE_BIT);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't override ICL rc=%d\n", rc);
+ return rc;
+ }
+ }
+ return 0;
+}
+
/********************
* REGISTER GETTERS *
********************/
@@ -728,19 +753,33 @@ static int smblib_usb_icl_vote_callback(struct votable *votable, void *data,
{
struct smb_charger *chg = data;
int rc = 0;
- bool suspend = (icl_ua < USBIN_25MA);
+ 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) {
- 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);
- return rc;
+ if (client) {
+ 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);
+ return rc;
+ }
}
-
goto out;
}
@@ -769,10 +808,14 @@ static int smblib_usb_icl_vote_callback(struct votable *votable, void *data,
}
out:
+ if (override)
+ icl_options |= USBIN_MODE_CHG_BIT;
+
rc = smblib_masked_write(chg, USBIN_ICL_OPTIONS_REG,
- CFG_USB3P0_SEL_BIT | USB51_MODE_BIT, icl_options);
+ CFG_USB3P0_SEL_BIT | USB51_MODE_BIT | USBIN_MODE_CHG_BIT,
+ icl_options);
if (rc < 0) {
- smblib_err(chg, "Couldn't set ICL opetions rc=%d\n", rc);
+ smblib_err(chg, "Couldn't set ICL options rc=%d\n", rc);
return rc;
}
@@ -783,6 +826,12 @@ out:
return rc;
}
+ rc = smblib_icl_override(chg, override);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't set ICL override rc=%d\n", rc);
+ return rc;
+ }
+
return rc;
}
@@ -2162,38 +2211,6 @@ int smblib_set_prop_pd_active(struct smb_charger *chg,
smblib_err(chg, "Couldn't unvote USB_PSY rc=%d\n", rc);
return rc;
}
-
- rc = smblib_masked_write(chg, USBIN_ICL_OPTIONS_REG,
- USBIN_MODE_CHG_BIT, USBIN_MODE_CHG_BIT);
- if (rc < 0) {
- smblib_err(chg,
- "Couldn't change USB mode rc=%d\n", rc);
- return rc;
- }
-
- rc = smblib_masked_write(chg, CMD_APSD_REG,
- ICL_OVERRIDE_BIT, ICL_OVERRIDE_BIT);
- if (rc < 0) {
- smblib_err(chg,
- "Couldn't override APSD rc=%d\n", rc);
- return rc;
- }
- } else {
- rc = smblib_masked_write(chg, CMD_APSD_REG,
- ICL_OVERRIDE_BIT, 0);
- if (rc < 0) {
- smblib_err(chg,
- "Couldn't override APSD rc=%d\n", rc);
- return rc;
- }
-
- rc = smblib_masked_write(chg, USBIN_ICL_OPTIONS_REG,
- USBIN_MODE_CHG_BIT, 0);
- if (rc < 0) {
- smblib_err(chg,
- "Couldn't change USB mode rc=%d\n", rc);
- return rc;
- }
}
/* CC pin selection s/w override in PD session; h/w otherwise. */
@@ -2803,17 +2820,16 @@ static void smblib_handle_hvdcp_check_timeout(struct smb_charger *chg,
if (get_effective_result(chg->pd_disallowed_votable_indirect))
/* could be a legacy cable, try doing hvdcp */
try_rerun_apsd_for_hvdcp(chg);
+
+ /*
+ * HVDCP detection timeout done
+ * If adapter is not QC2.0/QC3.0 - it is a plain old DCP.
+ */
+ if (!qc_charger && (apsd_result->bit & DCP_CHARGER_BIT))
+ /* enforce DCP ICL if specified */
+ vote(chg->usb_icl_votable, DCP_VOTER,
+ chg->dcp_icl_ua != -EINVAL, chg->dcp_icl_ua);
}
- /*
- * HVDCP detection timeout done
- * If adapter is not QC2.0/QC3.0 - it is a plain old DCP.
- * Otherwise if adapter is QC2.0/QC3.0 wait for authentication
- * to complete.
- */
- if (!qc_charger && (apsd_result->bit & DCP_CHARGER_BIT))
- /* enforce DCP ICL if specified */
- vote(chg->usb_icl_votable, DCP_VOTER,
- chg->dcp_icl_ua != -EINVAL, chg->dcp_icl_ua);
smblib_dbg(chg, PR_INTERRUPT, "IRQ: smblib_handle_hvdcp_check_timeout %s\n",
rising ? "rising" : "falling");
diff --git a/drivers/power/supply/qcom/smb-lib.h b/drivers/power/supply/qcom/smb-lib.h
index 5bb42f2ce7d9..1a5254d98737 100644
--- a/drivers/power/supply/qcom/smb-lib.h
+++ b/drivers/power/supply/qcom/smb-lib.h
@@ -405,6 +405,7 @@ void smblib_suspend_on_debug_battery(struct smb_charger *chg);
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_init(struct smb_charger *chg);
int smblib_deinit(struct smb_charger *chg);