power: qpnp-charger: avoid ARB during JEITA
To avoid a possible accidental reverse boost condition
imposed by setting VDDMAX < VBAT, introduce the following
new flow for JEITA.
Once warm or cool temperature zones are entered, only
adjust VBATDET:
* If VBAT is less than VBATDET the fast charge interrupt
will be triggered and subsequently the appropriate
VDDMAX and IBATMAX adjustments will be made.
* If VBAT is exceeding VBATDET, charging will be stopped
and only resumed via the VBATDET_LO threshold. Once
charging resumes the appropriate VDDMAX IBATMAX adjustments
will be made.
Signed-off-by: David Keitel <dkeitel@codeaurora.org>
CRs-Fixed: 605333
Change-Id: I13f3bad10f8478efd0ed4ff4c9ae6988ca6baafe
diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c
index 18c8ccb..2dc77e6 100644
--- a/drivers/power/qpnp-charger.c
+++ b/drivers/power/qpnp-charger.c
@@ -116,6 +116,7 @@
#define BOOST_ILIM 0x78
#define USB_SPARE 0xDF
#define DC_COMP_OVR1 0xE9
+#define CHGR_COMP_OVR1 0xEE
#define REG_OFFSET_PERP_SUBTYPE 0x05
@@ -388,6 +389,8 @@
bool power_stage_workaround_enable;
};
+static void
+qpnp_chg_set_appropriate_battery_current(struct qpnp_chg_chip *chip);
static struct of_device_id qpnp_charger_match_table[] = {
{ .compatible = QPNP_CHARGER_DEV_NAME, },
@@ -1857,6 +1860,29 @@
return (chgr_sts & FAST_CHG_ON_IRQ) ? 1 : 0;
}
+#define VBATDET_BYPASS 0x01
+static int
+bypass_vbatdet_comp(struct qpnp_chg_chip *chip, bool bypass)
+{
+ int rc;
+
+ pr_debug("bypass %d\n", bypass);
+ rc = qpnp_chg_masked_write(chip,
+ chip->chgr_base + SEC_ACCESS,
+ 0xA5,
+ 0xA5, 1);
+ rc |= qpnp_chg_masked_write(chip,
+ chip->chgr_base + CHGR_COMP_OVR1,
+ 0xFF,
+ bypass ? VBATDET_BYPASS : 0, 1);
+ if (rc) {
+ pr_err("Failed to bypass vbatdet comp rc = %d\n", rc);
+ return rc;
+ }
+
+ return rc;
+}
+
static irqreturn_t
qpnp_chg_chgr_chg_fastchg_irq_handler(int irq, void *_chip)
{
@@ -1884,6 +1910,11 @@
if (fastchg_on) {
chip->chg_done = false;
+ bypass_vbatdet_comp(chip, 1);
+ if (chip->bat_is_warm || chip->bat_is_cool) {
+ qpnp_chg_set_appropriate_vddmax(chip);
+ qpnp_chg_set_appropriate_battery_current(chip);
+ }
if (chip->resuming_charging) {
chip->resuming_charging = false;
@@ -1900,6 +1931,8 @@
} else {
if (chip->parallel_ovp_mode)
switch_parallel_ovp_mode(chip, 0);
+ if (!chip->bat_is_warm && !chip->bat_is_cool)
+ bypass_vbatdet_comp(chip, 0);
}
}
@@ -2770,6 +2803,25 @@
return 0;
}
+static void
+qpnp_chg_set_appropriate_battery_current(struct qpnp_chg_chip *chip)
+{
+ unsigned int chg_current = chip->max_bat_chg_current;
+
+ if (chip->bat_is_cool)
+ chg_current = min(chg_current, chip->cool_bat_chg_ma);
+
+ if (chip->bat_is_warm)
+ chg_current = min(chg_current, chip->warm_bat_chg_ma);
+
+ if (chip->therm_lvl_sel != 0 && chip->thermal_mitigation)
+ chg_current = min(chg_current,
+ chip->thermal_mitigation[chip->therm_lvl_sel]);
+
+ pr_debug("setting %d mA\n", chg_current);
+ qpnp_chg_ibatmax_set(chip, chg_current);
+}
+
static int
qpnp_chg_vddsafe_set(struct qpnp_chg_chip *chip, int voltage)
{
@@ -2978,25 +3030,6 @@
}
static void
-qpnp_chg_set_appropriate_battery_current(struct qpnp_chg_chip *chip)
-{
- unsigned int chg_current = chip->max_bat_chg_current;
-
- if (chip->bat_is_cool)
- chg_current = min(chg_current, chip->cool_bat_chg_ma);
-
- if (chip->bat_is_warm)
- chg_current = min(chg_current, chip->warm_bat_chg_ma);
-
- if (chip->therm_lvl_sel != 0 && chip->thermal_mitigation)
- chg_current = min(chg_current,
- chip->thermal_mitigation[chip->therm_lvl_sel]);
-
- pr_debug("setting %d mA\n", chg_current);
- qpnp_chg_ibatmax_set(chip, chg_current);
-}
-
-static void
qpnp_batt_system_temp_level_set(struct qpnp_chg_chip *chip, int lvl_sel)
{
if (lvl_sel >= 0 && lvl_sel < chip->thermal_levels) {
@@ -3570,9 +3603,6 @@
chip->bat_is_cool = bat_cool;
chip->bat_is_warm = bat_warm;
- if (bat_cool || bat_warm)
- chip->resuming_charging = false;
-
/**
* set appropriate voltages and currents.
*
@@ -3580,9 +3610,25 @@
* driver will not resume with SoC. Only vbatdet is used to
* determine resume of charging.
*/
- qpnp_chg_set_appropriate_vddmax(chip);
- qpnp_chg_set_appropriate_battery_current(chip);
- qpnp_chg_set_appropriate_vbatdet(chip);
+ if (bat_cool || bat_warm) {
+ chip->resuming_charging = false;
+ qpnp_chg_set_appropriate_vbatdet(chip);
+
+ /* To avoid ARB, only vbatdet is configured in
+ * warm/cold zones. Once vbat < vbatdet the
+ * appropriate vddmax/ibatmax adjustments will
+ * be made in the fast charge interrupt. */
+ bypass_vbatdet_comp(chip, 1);
+ qpnp_chg_charge_en(chip, !chip->charging_disabled);
+ qpnp_chg_charge_en(chip, chip->charging_disabled);
+ qpnp_chg_charge_en(chip, !chip->charging_disabled);
+ } else {
+ bypass_vbatdet_comp(chip, 0);
+ /* restore normal parameters */
+ qpnp_chg_set_appropriate_vbatdet(chip);
+ qpnp_chg_set_appropriate_vddmax(chip);
+ qpnp_chg_set_appropriate_battery_current(chip);
+ }
}
pr_debug("warm %d, cool %d, low = %d deciDegC, high = %d deciDegC\n",