Merge "power: qpnp-charger: add battery presence detection selector"
diff --git a/Documentation/devicetree/bindings/power/qpnp-charger.txt b/Documentation/devicetree/bindings/power/qpnp-charger.txt
index fced0d7..359ee6c 100644
--- a/Documentation/devicetree/bindings/power/qpnp-charger.txt
+++ b/Documentation/devicetree/bindings/power/qpnp-charger.txt
@@ -56,6 +56,13 @@
 - qcom,warm-bat-mv:			Warm temperature battery target voltage.
 - qcom,cool-bat-mv:			Cool temperature battery target voltage.
 - qcom,tchg-mins:			Maximum total software initialized charge time.
+- qcom,bpd-detection:			Select a battery presence detection scheme by
+					specifying either "bpd_thm", "bpd_id" or
+					"bpd_thm_id". "bpd_thm" selects the temperature
+					pin, "bpd_id" uses the id pin for battery presence
+					detection, "bpd_thm_id" selects both.
+					If the property is not set the hw default will
+					be used.
 
 Sub node required structure:
 - A qcom,chg node must be a child of an SPMI node that has specified
diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c
index 3d8a75d..5a0441b 100644
--- a/drivers/power/qpnp-charger.c
+++ b/drivers/power/qpnp-charger.c
@@ -91,6 +91,7 @@
 #define BUCK_TEST_SMBC_MODES			0xE6
 #define SEC_ACCESS				0xD0
 #define BAT_IF_VREF_BAT_THM_CTRL		0x4A
+#define BAT_IF_BPD_CTRL				0x48
 
 #define REG_OFFSET_PERP_SUBTYPE			0x05
 /* SMBB peripheral subtype values */
@@ -126,7 +127,11 @@
 #define USB_VALID_DEB_20MS		0x03
 #define BUCK_VBAT_REG_NODE_SEL_BIT	BIT(0)
 #define VREF_BATT_THERM_FORCE_ON	0xC0
+#define BAT_IF_BPD_CTRL_SEL		0x03
 #define VREF_BAT_THM_ENABLED_FSM	0x80
+#define REV_BST_DETECTED		BIT(0)
+#define BAT_THM_EN			BIT(1)
+#define BAT_ID_EN			BIT(0)
 
 /* Interrupt definitions */
 /* smbb_chg_interrupts */
@@ -253,6 +258,7 @@
 	bool				batt_present;
 	bool				charging_disabled;
 	bool				use_default_batt_values;
+	unsigned int			bpd_detection;
 	unsigned int			max_bat_chg_current;
 	unsigned int			warm_bat_chg_ma;
 	unsigned int			cool_bat_chg_ma;
@@ -291,6 +297,25 @@
 	{}
 };
 
+#define BPD_MAX		3
+
+static const char *bpd_list[BPD_MAX] = {
+	"bpd_thm",
+	"bpd_id",
+	"bpd_thm_id",
+};
+
+static inline int
+get_bpd(const char *name)
+{
+	int i = 0;
+	for (i = 0 ; i < BPD_MAX; i++) {
+		if (strcmp(name, bpd_list[i]) == 0)
+			return i;
+	}
+	return -EINVAL;
+}
+
 static int
 qpnp_chg_read(struct qpnp_chg_chip *chip, u8 *val,
 			u16 base, int count)
@@ -1853,7 +1878,7 @@
 				struct spmi_resource *spmi_resource)
 {
 	int rc = 0;
-	u8 reg;
+	u8 reg = 0;
 
 	switch (subtype) {
 	case SMBB_CHGR_SUBTYPE:
@@ -1932,6 +1957,20 @@
 	case SMBB_BAT_IF_SUBTYPE:
 	case SMBBP_BAT_IF_SUBTYPE:
 	case SMBCL_BAT_IF_SUBTYPE:
+		/* Select battery presence detection */
+		if (chip->bpd_detection == 1)
+			reg = BAT_ID_EN;
+		else if (chip->bpd_detection == 2)
+			reg = BAT_ID_EN | BAT_THM_EN;
+
+		rc = qpnp_chg_masked_write(chip,
+			chip->bat_if_base + BAT_IF_BPD_CTRL,
+			BAT_IF_BPD_CTRL_SEL,
+			reg, 1);
+		if (rc) {
+			pr_debug("failed to chose BPD rc=%d\n", rc);
+			return rc;
+		}
 		/* Force on VREF_BAT_THM */
 		rc = qpnp_chg_masked_write(chip,
 			chip->bat_if_base + BAT_IF_VREF_BAT_THM_CTRL,
@@ -2031,6 +2070,7 @@
 qpnp_charger_read_dt_props(struct qpnp_chg_chip *chip)
 {
 	int rc = 0;
+	const char *bpd;
 
 	OF_PROP_READ(chip, max_voltage_mv, "vddmax-mv", rc, 0);
 	OF_PROP_READ(chip, min_voltage_mv, "vinmin-mv", rc, 0);
@@ -2050,6 +2090,18 @@
 	if (rc)
 		return rc;
 
+	rc = of_property_read_string(chip->spmi->dev.of_node,
+		"qcom,bpd-detection", &bpd);
+	if (rc) {
+		pr_debug("no bpd-detection specified, ignored\n");
+	} else {
+		chip->bpd_detection = get_bpd(bpd);
+		if (chip->bpd_detection < 0) {
+			pr_err("failed to determine bpd schema %d\n", rc);
+			return rc;
+		}
+	}
+
 	/* Look up JEITA compliance parameters if cool and warm temp provided */
 	if (chip->cool_bat_decidegc && chip->warm_bat_decidegc) {
 		rc = qpnp_adc_tm_is_ready();
@@ -2361,8 +2413,9 @@
 	if (qpnp_chg_is_usb_chg_plugged_in(chip))
 		power_supply_set_online(chip->usb_psy, 1);
 
-	pr_info("success chg_dis = %d, usb = %d, dc = %d b_health = %d batt_present = %d\n",
+	pr_info("success chg_dis = %d, bpd = %d, usb = %d, dc = %d b_health = %d batt_present = %d\n",
 			chip->charging_disabled,
+			chip->bpd_detection,
 			qpnp_chg_is_usb_chg_plugged_in(chip),
 			qpnp_chg_is_dc_chg_plugged_in(chip),
 			get_prop_batt_present(chip),