Loading drivers/power/qpnp-linear-charger.c +87 −17 Original line number Diff line number Diff line Loading @@ -122,6 +122,7 @@ struct qpnp_lbc_irq { int irq; unsigned long disabled; bool is_wake; }; enum { Loading Loading @@ -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 Loading Loading @@ -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; Loading @@ -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) { Loading Loading @@ -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; Loading Loading @@ -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); Loading Loading @@ -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"); Loading Loading @@ -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. Loading @@ -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; Loading @@ -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; } Loading Loading @@ -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) Loading @@ -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); Loading Loading @@ -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); Loading Loading
drivers/power/qpnp-linear-charger.c +87 −17 Original line number Diff line number Diff line Loading @@ -122,6 +122,7 @@ struct qpnp_lbc_irq { int irq; unsigned long disabled; bool is_wake; }; enum { Loading Loading @@ -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 Loading Loading @@ -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; Loading @@ -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) { Loading Loading @@ -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; Loading Loading @@ -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); Loading Loading @@ -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"); Loading Loading @@ -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. Loading @@ -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; Loading @@ -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; } Loading Loading @@ -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) Loading @@ -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); Loading Loading @@ -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); Loading