Merge "power: smb5-lib: Disable charging on detecting a debug battery"
diff --git a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb5.txt b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb5.txt
index 8f8c87e..b7e6a31b 100644
--- a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb5.txt
+++ b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb5.txt
@@ -109,10 +109,18 @@
- qcom,auto-recharge-soc
Usage: optional
- Value type: <empty>
- Definition: Specifies if automatic recharge needs to be based off battery
- SOC. If this property is not specified, then auto recharge will
- be based off battery voltage.
+ Value type: <u32>
+ Definition: Specifies the SOC threshold at which the charger will
+ restart charging after termination. The value specified
+ ranges from 0 - 100. The feature is enabled if this
+ property is specified with a valid SOC value.
+
+- qcom,auto-recharge-vbat-mv
+ Usage: optional
+ Value type: <u32>
+ Definition: Specifies the battery voltage threshold at which the charger
+ will restart charging after termination. The value specified
+ is in milli-volts.
- qcom,suspend-input-on-debug-batt
Usage: optional
diff --git a/drivers/power/supply/qcom/qpnp-smb5.c b/drivers/power/supply/qcom/qpnp-smb5.c
index b3f66d5..0e6adff 100644
--- a/drivers/power/supply/qcom/qpnp-smb5.c
+++ b/drivers/power/supply/qcom/qpnp-smb5.c
@@ -158,7 +158,8 @@
int chg_inhibit_thr_mv;
bool no_battery;
bool hvdcp_disable;
- bool auto_recharge_soc;
+ int auto_recharge_soc;
+ int auto_recharge_vbat_mv;
int wd_bark_time;
int batt_profile_fcc_ua;
int batt_profile_fv_uv;
@@ -329,8 +330,23 @@
return -EINVAL;
}
- chip->dt.auto_recharge_soc = of_property_read_bool(node,
- "qcom,auto-recharge-soc");
+ chip->dt.auto_recharge_soc = -EINVAL;
+ rc = of_property_read_u32(node, "qcom,auto-recharge-soc",
+ &chip->dt.auto_recharge_soc);
+ if (!rc && (chip->dt.auto_recharge_soc < 0 ||
+ chip->dt.auto_recharge_soc > 100)) {
+ pr_err("qcom,auto-recharge-soc is incorrect\n");
+ return -EINVAL;
+ }
+ chg->auto_recharge_soc = chip->dt.auto_recharge_soc;
+
+ chip->dt.auto_recharge_vbat_mv = -EINVAL;
+ rc = of_property_read_u32(node, "qcom,auto-recharge-vbat-mv",
+ &chip->dt.auto_recharge_vbat_mv);
+ if (!rc && (chip->dt.auto_recharge_vbat_mv < 0)) {
+ pr_err("qcom,auto-recharge-vbat-mv is incorrect\n");
+ return -EINVAL;
+ }
chg->dcp_icl_ua = chip->dt.usb_icl_ua;
@@ -956,6 +972,7 @@
POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX,
POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT,
POWER_SUPPLY_PROP_CHARGE_COUNTER,
+ POWER_SUPPLY_PROP_RECHARGE_SOC,
};
static int smb5_batt_get_prop(struct power_supply *psy,
@@ -1045,6 +1062,9 @@
case POWER_SUPPLY_PROP_CHARGE_COUNTER:
rc = smblib_get_prop_batt_charge_counter(chg, val);
break;
+ case POWER_SUPPLY_PROP_RECHARGE_SOC:
+ val->intval = chg->auto_recharge_soc;
+ break;
default:
pr_err("batt power supply prop %d not supported\n", psp);
return -EINVAL;
@@ -1555,15 +1575,66 @@
return rc;
}
- rc = smblib_masked_write(chg, CHGR_CFG2_REG,
- SOC_BASED_RECHG_BIT,
- chip->dt.auto_recharge_soc ? SOC_BASED_RECHG_BIT : 0);
+ rc = smblib_masked_write(chg, CHGR_CFG2_REG, RECHG_MASK,
+ (chip->dt.auto_recharge_vbat_mv != -EINVAL) ?
+ VBAT_BASED_RECHG_BIT : 0);
if (rc < 0) {
- dev_err(chg->dev, "Couldn't configure FG_UPDATE_CFG2_SEL_REG rc=%d\n",
+ dev_err(chg->dev, "Couldn't configure VBAT-rechg CHG_CFG2_REG rc=%d\n",
rc);
return rc;
}
+ /* program the auto-recharge VBAT threshold */
+ if (chip->dt.auto_recharge_vbat_mv != -EINVAL) {
+ u32 temp = VBAT_TO_VRAW_ADC(chip->dt.auto_recharge_vbat_mv);
+
+ temp = ((temp & 0xFF00) >> 8) | ((temp & 0xFF) << 8);
+ rc = smblib_batch_write(chg,
+ CHGR_ADC_RECHARGE_THRESHOLD_MSB_REG, (u8 *)&temp, 2);
+ if (rc < 0) {
+ dev_err(chg->dev, "Couldn't configure ADC_RECHARGE_THRESHOLD REG rc=%d\n",
+ rc);
+ return rc;
+ }
+ /* Program the sample count for VBAT based recharge to 3 */
+ rc = smblib_masked_write(chg, CHGR_NO_SAMPLE_TERM_RCHG_CFG_REG,
+ NO_OF_SAMPLE_FOR_RCHG,
+ 2 << NO_OF_SAMPLE_FOR_RCHG_SHIFT);
+ if (rc < 0) {
+ dev_err(chg->dev, "Couldn't configure CHGR_NO_SAMPLE_FOR_TERM_RCHG_CFG rc=%d\n",
+ rc);
+ return rc;
+ }
+ }
+
+ rc = smblib_masked_write(chg, CHGR_CFG2_REG, RECHG_MASK,
+ (chip->dt.auto_recharge_soc != -EINVAL) ?
+ SOC_BASED_RECHG_BIT : VBAT_BASED_RECHG_BIT);
+ if (rc < 0) {
+ dev_err(chg->dev, "Couldn't configure SOC-rechg CHG_CFG2_REG rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ /* program the auto-recharge threshold */
+ if (chip->dt.auto_recharge_soc != -EINVAL) {
+ rc = smblib_write(chg, CHARGE_RCHG_SOC_THRESHOLD_CFG_REG,
+ (chip->dt.auto_recharge_soc * 255) / 100);
+ if (rc < 0) {
+ dev_err(chg->dev, "Couldn't configure CHG_RCHG_SOC_REG rc=%d\n",
+ rc);
+ return rc;
+ }
+ /* Program the sample count for SOC based recharge to 1 */
+ rc = smblib_masked_write(chg, CHGR_NO_SAMPLE_TERM_RCHG_CFG_REG,
+ NO_OF_SAMPLE_FOR_RCHG, 0);
+ if (rc < 0) {
+ dev_err(chg->dev, "Couldn't configure CHGR_NO_SAMPLE_FOR_TERM_RCHG_CFG rc=%d\n",
+ rc);
+ return rc;
+ }
+ }
+
if (chg->sw_jeita_enabled) {
rc = smblib_disable_hw_jeita(chg, true);
if (rc < 0) {
diff --git a/drivers/power/supply/qcom/smb5-lib.c b/drivers/power/supply/qcom/smb5-lib.c
index dbadd95..46cedb3 100644
--- a/drivers/power/supply/qcom/smb5-lib.c
+++ b/drivers/power/supply/qcom/smb5-lib.c
@@ -62,11 +62,15 @@
return regmap_write(chg->regmap, addr, val);
}
+int smblib_batch_write(struct smb_charger *chg, u16 addr, u8 *val,
+ int count)
+{
+ return regmap_bulk_write(chg->regmap, addr, val, count);
+}
+
int smblib_masked_write(struct smb_charger *chg, u16 addr, u8 mask, u8 val)
{
-
return regmap_update_bits(chg->regmap, addr, mask, val);
-
}
int smblib_get_jeita_cc_delta(struct smb_charger *chg, int *cc_delta_ua)
@@ -707,20 +711,21 @@
int rc;
union power_supply_propval val;
- if (!chg->suspend_input_on_debug_batt)
- return;
-
rc = power_supply_get_property(chg->bms_psy,
POWER_SUPPLY_PROP_DEBUG_BATTERY, &val);
if (rc < 0) {
smblib_err(chg, "Couldn't get debug battery prop rc=%d\n", rc);
return;
}
-
- vote(chg->usb_icl_votable, DEBUG_BOARD_VOTER, val.intval, 0);
- vote(chg->dc_suspend_votable, DEBUG_BOARD_VOTER, val.intval, 0);
- if (val.intval)
- pr_info("Input suspended: Fake battery\n");
+ if (chg->suspend_input_on_debug_batt) {
+ vote(chg->usb_icl_votable, DEBUG_BOARD_VOTER, val.intval, 0);
+ vote(chg->dc_suspend_votable, DEBUG_BOARD_VOTER, val.intval, 0);
+ if (val.intval)
+ pr_info("Input suspended: Fake battery\n");
+ } else {
+ vote(chg->chg_disable_votable, DEBUG_BOARD_VOTER,
+ val.intval, 0);
+ }
}
int smblib_rerun_apsd_if_required(struct smb_charger *chg)
diff --git a/drivers/power/supply/qcom/smb5-lib.h b/drivers/power/supply/qcom/smb5-lib.h
index d7b9a17..335764e 100644
--- a/drivers/power/supply/qcom/smb5-lib.h
+++ b/drivers/power/supply/qcom/smb5-lib.h
@@ -70,6 +70,8 @@
#define BOOST_BACK_STORM_COUNT 3
#define WEAK_CHG_STORM_COUNT 8
+#define VBAT_TO_VRAW_ADC(v) div_u64((u64)v * 1000000UL, 194637UL)
+
enum smb_mode {
PARALLEL_MASTER = 0,
PARALLEL_SLAVE,
@@ -344,6 +346,7 @@
bool use_extcon;
bool otg_present;
int hw_max_icl_ua;
+ int auto_recharge_soc;
/* workaround flag */
u32 wa_flags;
@@ -372,6 +375,8 @@
int smblib_read(struct smb_charger *chg, u16 addr, u8 *val);
int smblib_masked_write(struct smb_charger *chg, u16 addr, u8 mask, u8 val);
int smblib_write(struct smb_charger *chg, u16 addr, u8 val);
+int smblib_batch_write(struct smb_charger *chg, u16 addr, u8 *val, int count);
+int smblib_batch_read(struct smb_charger *chg, u16 addr, u8 *val, int count);
int smblib_get_charge_param(struct smb_charger *chg,
struct smb_chg_param *param, int *val_u);
diff --git a/drivers/power/supply/qcom/smb5-reg.h b/drivers/power/supply/qcom/smb5-reg.h
index 9a418c8..afc45ab 100644
--- a/drivers/power/supply/qcom/smb5-reg.h
+++ b/drivers/power/supply/qcom/smb5-reg.h
@@ -66,11 +66,17 @@
#define CHARGING_ENABLE_CMD_BIT BIT(0)
#define CHGR_CFG2_REG (CHGR_BASE + 0x51)
-#define SOC_BASED_RECHG_BIT BIT(1)
+#define RECHG_MASK GENMASK(2, 1)
+#define VBAT_BASED_RECHG_BIT BIT(2)
+#define SOC_BASED_RECHG_BIT GENMASK(2, 1)
#define CHARGER_INHIBIT_BIT BIT(0)
#define CHGR_FAST_CHARGE_CURRENT_CFG_REG (CHGR_BASE + 0x61)
+#define CHGR_NO_SAMPLE_TERM_RCHG_CFG_REG (CHGR_BASE + 0x6B)
+#define NO_OF_SAMPLE_FOR_RCHG_SHIFT 2
+#define NO_OF_SAMPLE_FOR_RCHG GENMASK(3, 2)
+
#define CHGR_FLOAT_VOLTAGE_CFG_REG (CHGR_BASE + 0x70)
#define CHARGE_INHIBIT_THRESHOLD_CFG_REG (CHGR_BASE + 0x72)
@@ -80,6 +86,12 @@
#define INHIBIT_ANALOG_VFLT_MINUS_200MV 2
#define INHIBIT_ANALOG_VFLT_MINUS_300MV 3
+#define CHARGE_RCHG_SOC_THRESHOLD_CFG_REG (CHGR_BASE + 0x7D)
+
+#define CHGR_ADC_RECHARGE_THRESHOLD_MSB_REG (CHGR_BASE + 0x7E)
+
+#define CHGR_ADC_RECHARGE_THRESHOLD_LSB_REG (CHGR_BASE + 0x7F)
+
#define JEITA_EN_CFG_REG (CHGR_BASE + 0x90)
#define JEITA_EN_HOT_SL_FCV_BIT BIT(3)
#define JEITA_EN_COLD_SL_FCV_BIT BIT(2)