summaryrefslogtreecommitdiff
path: root/drivers/power
diff options
context:
space:
mode:
authorAbhijeet Dharmapurikar <adharmap@codeaurora.org>2016-10-10 16:43:43 -0700
committerAbhijeet Dharmapurikar <adharmap@codeaurora.org>2016-10-17 11:54:06 -0700
commit665d020cda7c25577c52b0d979b010dc96c09867 (patch)
treec283b1f8711fa4768c2c8772936cfe1367a5578e /drivers/power
parent9fde5f583073dd842d7beff5702e0b34c6bb7920 (diff)
qpnp-smb2: Disable hvdcp based on user configuration
Some platforms do not support HVDCP charging. Provide means to disable them. Provide a votable for disabling HVDCP in preparation to handle VBUS and CC line shorted situation. Note that when hvdcp is disabled, we only disable voltage negotiations i.e. qc 2.0 detection remains enabled since it does not need voltage to change. Change-Id: Id7eaa46f08ac451a918a550f7837efbef78ab6f6 Signed-off-by: Abhijeet Dharmapurikar <adharmap@codeaurora.org>
Diffstat (limited to 'drivers/power')
-rw-r--r--drivers/power/qcom-charger/qpnp-smb2.c6
-rw-r--r--drivers/power/qcom-charger/smb-lib.c125
-rw-r--r--drivers/power/qcom-charger/smb-lib.h1
3 files changed, 114 insertions, 18 deletions
diff --git a/drivers/power/qcom-charger/qpnp-smb2.c b/drivers/power/qcom-charger/qpnp-smb2.c
index 2b2847230b9f..9340b98dc883 100644
--- a/drivers/power/qcom-charger/qpnp-smb2.c
+++ b/drivers/power/qcom-charger/qpnp-smb2.c
@@ -218,6 +218,7 @@ struct smb_dt_props {
s32 step_cc_delta[STEP_CHARGING_MAX_STEPS];
struct device_node *revid_dev_node;
int float_option;
+ bool hvdcp_disable;
};
struct smb2 {
@@ -329,6 +330,9 @@ static int smb2_parse_dt(struct smb2 *chip)
return -EINVAL;
}
+ chip->dt.hvdcp_disable = of_property_read_bool(node,
+ "qcom,hvdcp-disable");
+
return 0;
}
@@ -1031,6 +1035,8 @@ static int smb2_init_hw(struct smb2 *chip)
DEFAULT_VOTER, true, chip->dt.usb_icl_ua);
vote(chg->dc_icl_votable,
DEFAULT_VOTER, true, chip->dt.dc_icl_ua);
+ vote(chg->hvdcp_disable_votable, DEFAULT_VOTER,
+ chip->dt.hvdcp_disable, 0);
/* Configure charge enable for software control; active high */
rc = smblib_masked_write(chg, CHGR_CFG2_REG,
diff --git a/drivers/power/qcom-charger/smb-lib.c b/drivers/power/qcom-charger/smb-lib.c
index d6479d62e498..b9f8202e0a9e 100644
--- a/drivers/power/qcom-charger/smb-lib.c
+++ b/drivers/power/qcom-charger/smb-lib.c
@@ -208,47 +208,97 @@ struct apsd_result {
const enum power_supply_type pst;
};
+enum {
+ UNKNOWN,
+ SDP,
+ CDP,
+ DCP,
+ OCP,
+ FLOAT,
+ HVDCP2,
+ HVDCP3,
+ MAX_TYPES
+};
+
static const struct apsd_result const smblib_apsd_results[] = {
- {"UNKNOWN", 0, POWER_SUPPLY_TYPE_UNKNOWN},
- {"SDP", SDP_CHARGER_BIT, POWER_SUPPLY_TYPE_USB},
- {"CDP", CDP_CHARGER_BIT, POWER_SUPPLY_TYPE_USB_CDP},
- {"DCP", DCP_CHARGER_BIT, POWER_SUPPLY_TYPE_USB_DCP},
- {"OCP", OCP_CHARGER_BIT, POWER_SUPPLY_TYPE_USB_DCP},
- {"FLOAT", FLOAT_CHARGER_BIT, POWER_SUPPLY_TYPE_USB_DCP},
- {"HVDCP2", DCP_CHARGER_BIT | QC_2P0_BIT, POWER_SUPPLY_TYPE_USB_HVDCP},
- {"HVDCP3", DCP_CHARGER_BIT | QC_3P0_BIT, POWER_SUPPLY_TYPE_USB_HVDCP_3},
+ [UNKNOWN] = {
+ .name = "UNKNOWN",
+ .bit = 0,
+ .pst = POWER_SUPPLY_TYPE_UNKNOWN
+ },
+ [SDP] = {
+ .name = "SDP",
+ .bit = SDP_CHARGER_BIT,
+ .pst = POWER_SUPPLY_TYPE_USB
+ },
+ [CDP] = {
+ .name = "CDP",
+ .bit = CDP_CHARGER_BIT,
+ .pst = POWER_SUPPLY_TYPE_USB_CDP
+ },
+ [DCP] = {
+ .name = "DCP",
+ .bit = DCP_CHARGER_BIT,
+ .pst = POWER_SUPPLY_TYPE_USB_DCP
+ },
+ [OCP] = {
+ .name = "OCP",
+ .bit = OCP_CHARGER_BIT,
+ .pst = POWER_SUPPLY_TYPE_USB_DCP
+ },
+ [FLOAT] = {
+ .name = "FLOAT",
+ .bit = FLOAT_CHARGER_BIT,
+ .pst = POWER_SUPPLY_TYPE_USB_DCP
+ },
+ [HVDCP2] = {
+ .name = "HVDCP2",
+ .bit = DCP_CHARGER_BIT | QC_2P0_BIT,
+ .pst = POWER_SUPPLY_TYPE_USB_HVDCP
+ },
+ [HVDCP3] = {
+ .name = "HVDCP3",
+ .bit = DCP_CHARGER_BIT | QC_3P0_BIT,
+ .pst = POWER_SUPPLY_TYPE_USB_HVDCP_3,
+ },
};
static const struct apsd_result *smblib_get_apsd_result(struct smb_charger *chg)
{
int rc, i;
- u8 stat;
+ u8 apsd_stat, stat;
+ const struct apsd_result *result = &smblib_apsd_results[UNKNOWN];
- rc = smblib_read(chg, APSD_STATUS_REG, &stat);
+ rc = smblib_read(chg, APSD_STATUS_REG, &apsd_stat);
if (rc < 0) {
dev_err(chg->dev, "Couldn't read APSD_STATUS rc=%d\n", rc);
- return &smblib_apsd_results[0];
+ return result;
}
- smblib_dbg(chg, PR_REGISTER, "APSD_STATUS = 0x%02x\n", stat);
+ smblib_dbg(chg, PR_REGISTER, "APSD_STATUS = 0x%02x\n", apsd_stat);
- if (!(stat & APSD_DTC_STATUS_DONE_BIT))
- return &smblib_apsd_results[0];
+ if (!(apsd_stat & APSD_DTC_STATUS_DONE_BIT))
+ return result;
rc = smblib_read(chg, APSD_RESULT_STATUS_REG, &stat);
if (rc < 0) {
dev_err(chg->dev, "Couldn't read APSD_RESULT_STATUS rc=%d\n",
rc);
- return &smblib_apsd_results[0];
+ return result;
}
stat &= APSD_RESULT_STATUS_MASK;
for (i = 0; i < ARRAY_SIZE(smblib_apsd_results); i++) {
if (smblib_apsd_results[i].bit == stat)
- return &smblib_apsd_results[i];
+ result = &smblib_apsd_results[i];
+ }
+
+ if (apsd_stat & QC_CHARGER_BIT) {
+ /* since its a qc_charger, either return HVDCP3 or HVDCP2 */
+ if (result != &smblib_apsd_results[HVDCP3])
+ result = &smblib_apsd_results[HVDCP2];
}
- dev_err(chg->dev, "Couldn't find an APSD result for 0x%02x\n", stat);
- return &smblib_apsd_results[0];
+ return result;
}
@@ -794,6 +844,37 @@ static int smblib_pl_enable_indirect_vote_callback(struct votable *votable,
return 0;
}
+static int smblib_hvdcp_disable_vote_callback(struct votable *votable,
+ void *data,
+ int hvdcp_disable, const char *client)
+{
+ struct smb_charger *chg = data;
+ int rc;
+ u8 val = HVDCP_AUTH_ALG_EN_CFG_BIT
+ | HVDCP_AUTONOMOUS_MODE_EN_CFG_BIT | HVDCP_EN_BIT;
+
+ /*
+ * Disable the autonomous bit and auth bit for disabling hvdcp.
+ * This ensures only qc 2.0 detection runs but no vbus
+ * negotiation happens.
+ */
+ if (hvdcp_disable)
+ val = HVDCP_EN_BIT;
+
+ rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
+ HVDCP_EN_BIT
+ | HVDCP_AUTONOMOUS_MODE_EN_CFG_BIT
+ | HVDCP_AUTH_ALG_EN_CFG_BIT,
+ val);
+ if (rc < 0) {
+ dev_err(chg->dev, "Couldn't %s hvdcp rc=%d\n",
+ hvdcp_disable ? "disable" : "enable", rc);
+ return rc;
+ }
+
+ return 0;
+}
+
/*****************
* OTG REGULATOR *
*****************/
@@ -2455,6 +2536,14 @@ static int smblib_create_votables(struct smb_charger *chg)
return rc;
}
+ chg->hvdcp_disable_votable = create_votable("HVDCP_DISABLE",
+ VOTE_SET_ANY,
+ smblib_hvdcp_disable_vote_callback,
+ chg);
+ if (IS_ERR(chg->hvdcp_disable_votable)) {
+ rc = PTR_ERR(chg->hvdcp_disable_votable);
+ return rc;
+ }
return rc;
}
diff --git a/drivers/power/qcom-charger/smb-lib.h b/drivers/power/qcom-charger/smb-lib.h
index 00975e6c1285..e2a525a525b1 100644
--- a/drivers/power/qcom-charger/smb-lib.h
+++ b/drivers/power/qcom-charger/smb-lib.h
@@ -149,6 +149,7 @@ struct smb_charger {
struct votable *pl_disable_votable;
struct votable *chg_disable_votable;
struct votable *pl_enable_votable_indirect;
+ struct votable *hvdcp_disable_votable;
/* work */
struct work_struct bms_update_work;