Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 456c3527 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "power: qpnp-linear-charger: Fix interrupt storm due to VBAT_DET irq"

parents f61592d4 30bb37f3
Loading
Loading
Loading
Loading
+87 −17
Original line number Diff line number Diff line
@@ -122,6 +122,7 @@
struct qpnp_lbc_irq {
	int		irq;
	unsigned long	disabled;
	bool            is_wake;
};

enum {
@@ -283,6 +284,7 @@ struct vddtrim_map vddtrim_map[] = {
 * @hw_access_lock:		lock to serialize access to charger registers
 * @ibat_change_lock:		lock to serialize ibat change requests from
 *				USB and thermal.
 * @irq_lock			lock to serialize enabling/disabling of irq
 * @supported_feature_flag	bitmask for all supported features
 * @vddtrim_alarm		alarm to schedule trim work at regular
 *				interval
@@ -352,6 +354,7 @@ struct qpnp_lbc_chip {
	struct mutex			chg_enable_lock;
	spinlock_t			ibat_change_lock;
	spinlock_t			hw_access_lock;
	spinlock_t			irq_lock;
	struct power_supply		*usb_psy;
	struct power_supply		*bms_psy;
	struct power_supply		batt_psy;
@@ -360,6 +363,36 @@ struct qpnp_lbc_chip {
	struct qpnp_adc_tm_chip		*adc_tm_dev;
};

static void qpnp_lbc_enable_irq(struct qpnp_lbc_chip *chip,
					struct qpnp_lbc_irq *irq)
{
	unsigned long flags;

	spin_lock_irqsave(&chip->irq_lock, flags);
	if (__test_and_clear_bit(0, &irq->disabled)) {
		pr_debug("number = %d\n", irq->irq);
		enable_irq(irq->irq);
		if (irq->is_wake)
			enable_irq_wake(irq->irq);
	}
	spin_unlock_irqrestore(&chip->irq_lock, flags);
}

static void qpnp_lbc_disable_irq(struct qpnp_lbc_chip *chip,
					struct qpnp_lbc_irq *irq)
{
	unsigned long flags;

	spin_lock_irqsave(&chip->irq_lock, flags);
	if (!__test_and_set_bit(0, &irq->disabled)) {
		pr_debug("number = %d\n", irq->irq);
		disable_irq_nosync(irq->irq);
		if (irq->is_wake)
			disable_irq_wake(irq->irq);
	}
	spin_unlock_irqrestore(&chip->irq_lock, flags);
}

static int __qpnp_lbc_read(struct spmi_device *spmi, u16 base,
			u8 *val, int count)
{
@@ -1398,6 +1431,15 @@ static int qpnp_batt_power_set_property(struct power_supply *psy,
						rc);
			else
				chip->chg_done = true;

			/*
			 * Enable VBAT_DET based charging:
			 * To enable charging when VBAT falls below VBAT_DET
			 * and device stays suspended after EOC.
			 */
			qpnp_lbc_enable_irq(chip,
					&chip->irqs[CHG_VBAT_DET_LO]);

			mutex_unlock(&chip->chg_enable_lock);
		}
		break;
@@ -1608,17 +1650,21 @@ static int qpnp_lbc_chg_init(struct qpnp_lbc_chip *chip)
	}

	/*
	 * Disable iterm comparator of linear charger to disable charger
	 * detecting end of charge condition based on DT configuration
	 * and float charge configuration.
	 * Override VBAT_DET comparator to enable charging
	 * irrespective of VBAT above VBAT_DET.
	 */
	if (!chip->cfg_charger_detect_eoc || chip->cfg_float_charge) {
		if (chip->cfg_float_charge)
	rc = qpnp_lbc_vbatdet_override(chip, OVERRIDE_0);
	if (rc) {
		pr_err("Failed to override comp rc=%d\n", rc);
		return rc;
	}

	/*
	 * Disable iterm comparator of linear charger to disable charger
	 * detecting end of charge condition based on DT configuration
	 * and float charge configuration.
	 */
	if (!chip->cfg_charger_detect_eoc || chip->cfg_float_charge) {
		rc = qpnp_lbc_masked_write(chip,
				chip->chgr_base + CHG_IBATTERM_EN_REG,
				IBAT_TERM_EN_MASK, 0);
@@ -1922,7 +1968,18 @@ static irqreturn_t qpnp_lbc_usbin_valid_irq_handler(int irq, void *_chip)
			spin_unlock_irqrestore(&chip->ibat_change_lock,
								flags);
		} else {
			qpnp_lbc_charger_enable(chip, CURRENT, 1);
			/*
			 * Override VBAT_DET comparator to start charging
			 * even if VBAT > VBAT_DET.
			 */
			qpnp_lbc_vbatdet_override(chip, OVERRIDE_0);

			/*
			 * Enable SOC based charging to make sure
			 * charging gets enabled on USB insertion
			 * irrespective of battery SOC above resume_soc.
			 */
			qpnp_lbc_charger_enable(chip, SOC, 1);
		}

		pr_debug("Updating usb_psy PRESENT property\n");
@@ -2041,7 +2098,9 @@ static irqreturn_t qpnp_lbc_fastchg_irq_handler(int irq, void *_chip)
	if (chip->fastchg_on ^ fastchg_on) {
		chip->fastchg_on = fastchg_on;
		if (fastchg_on) {
			mutex_lock(&chip->chg_enable_lock);
			chip->chg_done = false;
			mutex_unlock(&chip->chg_enable_lock);
			/*
			 * Start alarm timer to periodically calculate
			 * and update VDD_MAX trim value.
@@ -2058,7 +2117,6 @@ static irqreturn_t qpnp_lbc_fastchg_irq_handler(int irq, void *_chip)
			pr_debug("power supply changed batt_psy\n");
			power_supply_changed(&chip->batt_psy);
		}

	}

	return IRQ_HANDLED;
@@ -2084,18 +2142,26 @@ static irqreturn_t qpnp_lbc_vbatdet_lo_irq_handler(int irq, void *_chip)

	pr_debug("vbatdet-lo triggered\n");

	/* Battery has fallen below the vbatdet threshold and it is
	/*
	 * Disable vbatdet irq to prevent interrupt storm when VBAT is
	 * close to VBAT_DET.
	 */
	qpnp_lbc_disable_irq(chip, &chip->irqs[CHG_VBAT_DET_LO]);

	/*
	 * Override VBAT_DET comparator to 0 to fix comparator toggling
	 * near VBAT_DET threshold.
	 */
	qpnp_lbc_vbatdet_override(chip, OVERRIDE_0);

	/*
	 * Battery has fallen below the vbatdet threshold and it is
	 * time to resume charging.
	 */
	rc = qpnp_lbc_charger_enable(chip, SOC, 1);
	if (rc)
		pr_err("Failed to enable charging\n");

	if (chip->bat_if_base && !rc) {
		pr_debug("power supply changed batt_psy\n");
		power_supply_changed(&chip->batt_psy);
	}

	return IRQ_HANDLED;
}

@@ -2164,8 +2230,10 @@ do { \
								rc);	\
		} else {						\
			rc = 0;						\
			if (wake)					\
			if (wake) {					\
				enable_irq_wake(chip->irqs[idx].irq);	\
				chip->irqs[idx].is_wake = true;		\
			}						\
		}							\
	}								\
} while (0)
@@ -2191,8 +2259,9 @@ static int qpnp_lbc_request_irqs(struct qpnp_lbc_chip *chip)
	SPMI_REQUEST_IRQ(chip, CHG_FAILED, rc, chg_failed, 0,
			IRQF_TRIGGER_RISING, 1);

	SPMI_REQUEST_IRQ(chip, CHG_FAST_CHG, rc, fastchg, 0,
			IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, 0);
	SPMI_REQUEST_IRQ(chip, CHG_FAST_CHG, rc, fastchg, 1,
			IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING
			| IRQF_ONESHOT, 1);

	SPMI_REQUEST_IRQ(chip, CHG_DONE, rc, chg_done, 0,
			IRQF_TRIGGER_RISING, 0);
@@ -2374,6 +2443,7 @@ static int qpnp_lbc_probe(struct spmi_device *spmi)
	mutex_init(&chip->chg_enable_lock);
	spin_lock_init(&chip->hw_access_lock);
	spin_lock_init(&chip->ibat_change_lock);
	spin_lock_init(&chip->irq_lock);
	INIT_WORK(&chip->vddtrim_work, qpnp_lbc_vddtrim_work_fn);
	alarm_init(&chip->vddtrim_alarm, ALARM_REALTIME, vddtrim_callback);