Loading drivers/power/qpnp-fg.c +307 −1 Original line number Diff line number Diff line Loading @@ -337,7 +337,8 @@ module_param_named( struct fg_irq { int irq; unsigned long disabled; bool disabled; bool wakeup; }; enum fg_soc_irq { Loading Loading @@ -521,6 +522,8 @@ struct fg_chip { bool charging_disabled; bool use_vbat_low_empty_soc; bool fg_shutdown; bool use_soft_jeita_irq; bool allow_false_negative_isense; struct delayed_work update_jeita_setting; struct delayed_work update_sram_data; struct delayed_work update_temp_work; Loading @@ -545,6 +548,7 @@ struct fg_chip { int prev_status; int health; enum fg_batt_aging_mode batt_aging_mode; struct alarm hard_jeita_alarm; /* capacity learning */ struct fg_learning_data learning_data; struct alarm fg_cap_learning_alarm; Loading @@ -565,6 +569,8 @@ struct fg_chip { bool jeita_hysteresis_support; bool batt_hot; bool batt_cold; bool batt_warm; bool batt_cool; int cold_hysteresis; int hot_hysteresis; /* ESR pulse tuning */ Loading Loading @@ -2286,6 +2292,25 @@ static int set_prop_sense_type(struct fg_chip *chip, int ext_sense_type) return 0; } #define IGNORE_FALSE_NEGATIVE_ISENSE_BIT BIT(3) static int set_prop_ignore_false_negative_isense(struct fg_chip *chip, bool ignore) { int rc; rc = fg_mem_masked_write(chip, EXTERNAL_SENSE_SELECT, IGNORE_FALSE_NEGATIVE_ISENSE_BIT, ignore ? IGNORE_FALSE_NEGATIVE_ISENSE_BIT : 0, EXTERNAL_SENSE_OFFSET); if (rc) { pr_err("failed to %s isense false negative ignore rc=%d\n", ignore ? "enable" : "disable", rc); return rc; } return 0; } #define EXPONENT_MASK 0xF800 #define MANTISSA_MASK 0x3FF #define SIGN BIT(10) Loading Loading @@ -3220,6 +3245,8 @@ static enum power_supply_property fg_power_props[] = { POWER_SUPPLY_PROP_CYCLE_COUNT_ID, POWER_SUPPLY_PROP_HI_POWER, POWER_SUPPLY_PROP_SOC_REPORTING_READY, POWER_SUPPLY_PROP_IGNORE_FALSE_NEGATIVE_ISENSE, POWER_SUPPLY_PROP_ENABLE_JEITA_DETECTION, }; static int fg_power_get_property(struct power_supply *psy, Loading Loading @@ -3250,6 +3277,12 @@ static int fg_power_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_CURRENT_NOW: val->intval = get_sram_prop_now(chip, FG_DATA_CURRENT); break; case POWER_SUPPLY_PROP_IGNORE_FALSE_NEGATIVE_ISENSE: val->intval = !chip->allow_false_negative_isense; break; case POWER_SUPPLY_PROP_ENABLE_JEITA_DETECTION: val->intval = chip->use_soft_jeita_irq; break; case POWER_SUPPLY_PROP_VOLTAGE_NOW: val->intval = get_sram_prop_now(chip, FG_DATA_VOLTAGE); break; Loading Loading @@ -4252,6 +4285,67 @@ static int fg_power_set_property(struct power_supply *psy, if (val->intval) update_sram_data(chip, &unused); break; case POWER_SUPPLY_PROP_IGNORE_FALSE_NEGATIVE_ISENSE: rc = set_prop_ignore_false_negative_isense(chip, !!val->intval); if (rc) pr_err("set_prop_ignore_false_negative_isense failed, rc=%d\n", rc); else chip->allow_false_negative_isense = !val->intval; break; case POWER_SUPPLY_PROP_ENABLE_JEITA_DETECTION: if (chip->use_soft_jeita_irq == !!val->intval) { pr_debug("JEITA irq %s, ignore!\n", chip->use_soft_jeita_irq ? "enabled" : "disabled"); break; } chip->use_soft_jeita_irq = !!val->intval; if (chip->use_soft_jeita_irq) { if (chip->batt_irq[JEITA_SOFT_COLD].disabled) { enable_irq( chip->batt_irq[JEITA_SOFT_COLD].irq); chip->batt_irq[JEITA_SOFT_COLD].disabled = false; } if (!chip->batt_irq[JEITA_SOFT_COLD].wakeup) { enable_irq_wake( chip->batt_irq[JEITA_SOFT_COLD].irq); chip->batt_irq[JEITA_SOFT_COLD].wakeup = true; } if (chip->batt_irq[JEITA_SOFT_HOT].disabled) { enable_irq( chip->batt_irq[JEITA_SOFT_HOT].irq); chip->batt_irq[JEITA_SOFT_HOT].disabled = false; } if (!chip->batt_irq[JEITA_SOFT_HOT].wakeup) { enable_irq_wake( chip->batt_irq[JEITA_SOFT_HOT].irq); chip->batt_irq[JEITA_SOFT_HOT].wakeup = true; } } else { if (chip->batt_irq[JEITA_SOFT_COLD].wakeup) { disable_irq_wake( chip->batt_irq[JEITA_SOFT_COLD].irq); chip->batt_irq[JEITA_SOFT_COLD].wakeup = false; } if (!chip->batt_irq[JEITA_SOFT_COLD].disabled) { disable_irq_nosync( chip->batt_irq[JEITA_SOFT_COLD].irq); chip->batt_irq[JEITA_SOFT_COLD].disabled = true; } if (chip->batt_irq[JEITA_SOFT_HOT].wakeup) { disable_irq_wake( chip->batt_irq[JEITA_SOFT_HOT].irq); chip->batt_irq[JEITA_SOFT_HOT].wakeup = false; } if (!chip->batt_irq[JEITA_SOFT_HOT].disabled) { disable_irq_nosync( chip->batt_irq[JEITA_SOFT_HOT].irq); chip->batt_irq[JEITA_SOFT_HOT].disabled = true; } } break; case POWER_SUPPLY_PROP_STATUS: chip->prev_status = chip->status; chip->status = val->intval; Loading Loading @@ -4535,6 +4629,168 @@ static void cc_soc_store_work(struct work_struct *work) fg_relax(&chip->cc_soc_wakeup_source); } #define HARD_JEITA_ALARM_CHECK_NS 10000000000 static enum alarmtimer_restart fg_hard_jeita_alarm_cb(struct alarm *alarm, ktime_t now) { struct fg_chip *chip = container_of(alarm, struct fg_chip, hard_jeita_alarm); int rc, health = POWER_SUPPLY_HEALTH_UNKNOWN; u8 regval; bool batt_hot, batt_cold; union power_supply_propval val = {0, }; if (!is_usb_present(chip)) { pr_debug("USB plugged out, stop the timer!\n"); return ALARMTIMER_NORESTART; } rc = fg_read(chip, ®val, BATT_INFO_STS(chip->batt_base), 1); if (rc) { pr_err("read batt_sts failed, rc=%d\n", rc); goto recheck; } batt_hot = !!(regval & JEITA_HARD_HOT_RT_STS); batt_cold = !!(regval & JEITA_HARD_COLD_RT_STS); if (batt_hot && batt_cold) { pr_debug("Hot && cold can't co-exist\n"); goto recheck; } if ((batt_hot == chip->batt_hot) && (batt_cold == chip->batt_cold)) { pr_debug("battery JEITA state not changed, ignore\n"); goto recheck; } if (batt_cold != chip->batt_cold) { /* cool --> cold */ if (chip->batt_cool) { chip->batt_cool = false; chip->batt_cold = true; health = POWER_SUPPLY_HEALTH_COLD; } else if (chip->batt_cold) { /* cold --> cool */ chip->batt_cool = true; chip->batt_cold = false; health = POWER_SUPPLY_HEALTH_COOL; } } if (batt_hot != chip->batt_hot) { /* warm --> hot */ if (chip->batt_warm) { chip->batt_warm = false; chip->batt_hot = true; health = POWER_SUPPLY_HEALTH_OVERHEAT; } else if (chip->batt_hot) { /* hot --> warm */ chip->batt_hot = false; chip->batt_warm = true; health = POWER_SUPPLY_HEALTH_WARM; } } if (health != POWER_SUPPLY_HEALTH_UNKNOWN) { pr_debug("FG report battery health: %d\n", health); val.intval = health; rc = chip->batt_psy->set_property(chip->batt_psy, POWER_SUPPLY_PROP_HEALTH, &val); if (rc) pr_err("Set batt_psy health: %d failed\n", health); } recheck: alarm_forward_now(alarm, ns_to_ktime(HARD_JEITA_ALARM_CHECK_NS)); return ALARMTIMER_RESTART; } #define BATT_SOFT_COLD_STS BIT(0) #define BATT_SOFT_HOT_STS BIT(1) static irqreturn_t fg_jeita_soft_hot_irq_handler(int irq, void *_chip) { int rc; struct fg_chip *chip = _chip; u8 regval; bool batt_warm; union power_supply_propval val = {0, }; rc = fg_read(chip, ®val, INT_RT_STS(chip->batt_base), 1); if (rc) { pr_err("spmi read failed: addr=%03X, rc=%d\n", INT_RT_STS(chip->batt_base), rc); return IRQ_HANDLED; } batt_warm = !!(regval & BATT_SOFT_HOT_STS); if (chip->batt_warm == batt_warm) { pr_debug("warm state not change, ignore!\n"); return IRQ_HANDLED; } chip->batt_warm = batt_warm; if (batt_warm) { val.intval = POWER_SUPPLY_HEALTH_WARM; chip->batt_psy->set_property(chip->batt_psy, POWER_SUPPLY_PROP_HEALTH, &val); /* kick the alarm timer for hard hot polling */ rc = alarm_start_relative(&chip->hard_jeita_alarm, ns_to_ktime(HARD_JEITA_ALARM_CHECK_NS)); if (rc) pr_err("start alarm for hard HOT detection failed, rc=%d\n", rc); } else { val.intval = POWER_SUPPLY_HEALTH_GOOD; chip->batt_psy->set_property(chip->batt_psy, POWER_SUPPLY_PROP_HEALTH, &val); /* cancel the alarm timer */ alarm_try_to_cancel(&chip->hard_jeita_alarm); } return IRQ_HANDLED; } static irqreturn_t fg_jeita_soft_cold_irq_handler(int irq, void *_chip) { int rc; struct fg_chip *chip = _chip; u8 regval; bool batt_cool; union power_supply_propval val = {0, }; rc = fg_read(chip, ®val, INT_RT_STS(chip->batt_base), 1); if (rc) { pr_err("spmi read failed: addr=%03X, rc=%d\n", INT_RT_STS(chip->batt_base), rc); return IRQ_HANDLED; } batt_cool = !!(regval & BATT_SOFT_COLD_STS); if (chip->batt_cool == batt_cool) { pr_debug("cool state not change, ignore\n"); return IRQ_HANDLED; } chip->batt_cool = batt_cool; if (batt_cool) { val.intval = POWER_SUPPLY_HEALTH_COOL; chip->batt_psy->set_property(chip->batt_psy, POWER_SUPPLY_PROP_HEALTH, &val); /* kick the alarm timer for hard cold polling */ rc = alarm_start_relative(&chip->hard_jeita_alarm, ns_to_ktime(HARD_JEITA_ALARM_CHECK_NS)); if (rc) pr_err("start alarm for hard COLD detection failed, rc=%d\n", rc); } else { val.intval = POWER_SUPPLY_HEALTH_GOOD; chip->batt_psy->set_property(chip->batt_psy, POWER_SUPPLY_PROP_HEALTH, &val); /* cancel the alarm timer */ alarm_try_to_cancel(&chip->hard_jeita_alarm); } return IRQ_HANDLED; } #define SOC_FIRST_EST_DONE BIT(5) static bool is_first_est_done(struct fg_chip *chip) { Loading Loading @@ -6690,6 +6946,53 @@ static int fg_init_irqs(struct fg_chip *chip) } break; case FG_BATT: chip->batt_irq[JEITA_SOFT_COLD].irq = spmi_get_irq_byname(chip->spmi, spmi_resource, "soft-cold"); if (chip->batt_irq[JEITA_SOFT_COLD].irq < 0) { pr_err("Unable to get soft-cold irq\n"); rc = -EINVAL; return rc; } rc = devm_request_threaded_irq(chip->dev, chip->batt_irq[JEITA_SOFT_COLD].irq, NULL, fg_jeita_soft_cold_irq_handler, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "soft-cold", chip); if (rc < 0) { pr_err("Can't request %d soft-cold: %d\n", chip->batt_irq[JEITA_SOFT_COLD].irq, rc); return rc; } disable_irq(chip->batt_irq[JEITA_SOFT_COLD].irq); chip->batt_irq[JEITA_SOFT_COLD].disabled = true; chip->batt_irq[JEITA_SOFT_HOT].irq = spmi_get_irq_byname(chip->spmi, spmi_resource, "soft-hot"); if (chip->batt_irq[JEITA_SOFT_HOT].irq < 0) { pr_err("Unable to get soft-hot irq\n"); rc = -EINVAL; return rc; } rc = devm_request_threaded_irq(chip->dev, chip->batt_irq[JEITA_SOFT_HOT].irq, NULL, fg_jeita_soft_hot_irq_handler, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "soft-hot", chip); if (rc < 0) { pr_err("Can't request %d soft-hot: %d\n", chip->batt_irq[JEITA_SOFT_HOT].irq, rc); return rc; } disable_irq(chip->batt_irq[JEITA_SOFT_HOT].irq); chip->batt_irq[JEITA_SOFT_HOT].disabled = true; chip->batt_irq[BATT_MISSING].irq = spmi_get_irq_byname( chip->spmi, spmi_resource, "batt-missing"); Loading Loading @@ -6760,6 +7063,7 @@ static void fg_cancel_all_works(struct fg_chip *chip) cancel_delayed_work_sync(&chip->check_empty_work); cancel_delayed_work_sync(&chip->batt_profile_init); alarm_try_to_cancel(&chip->fg_cap_learning_alarm); alarm_try_to_cancel(&chip->hard_jeita_alarm); if (!chip->ima_error_handling) cancel_work_sync(&chip->ima_error_recovery_work); cancel_work_sync(&chip->rslow_comp_work); Loading Loading @@ -8065,6 +8369,8 @@ static int fg_probe(struct spmi_device *spmi) INIT_WORK(&chip->cc_soc_store_work, cc_soc_store_work); alarm_init(&chip->fg_cap_learning_alarm, ALARM_BOOTTIME, fg_cap_learning_alarm_cb); alarm_init(&chip->hard_jeita_alarm, ALARM_BOOTTIME, fg_hard_jeita_alarm_cb); init_completion(&chip->sram_access_granted); init_completion(&chip->sram_access_revoked); complete_all(&chip->sram_access_revoked); Loading Loading
drivers/power/qpnp-fg.c +307 −1 Original line number Diff line number Diff line Loading @@ -337,7 +337,8 @@ module_param_named( struct fg_irq { int irq; unsigned long disabled; bool disabled; bool wakeup; }; enum fg_soc_irq { Loading Loading @@ -521,6 +522,8 @@ struct fg_chip { bool charging_disabled; bool use_vbat_low_empty_soc; bool fg_shutdown; bool use_soft_jeita_irq; bool allow_false_negative_isense; struct delayed_work update_jeita_setting; struct delayed_work update_sram_data; struct delayed_work update_temp_work; Loading @@ -545,6 +548,7 @@ struct fg_chip { int prev_status; int health; enum fg_batt_aging_mode batt_aging_mode; struct alarm hard_jeita_alarm; /* capacity learning */ struct fg_learning_data learning_data; struct alarm fg_cap_learning_alarm; Loading @@ -565,6 +569,8 @@ struct fg_chip { bool jeita_hysteresis_support; bool batt_hot; bool batt_cold; bool batt_warm; bool batt_cool; int cold_hysteresis; int hot_hysteresis; /* ESR pulse tuning */ Loading Loading @@ -2286,6 +2292,25 @@ static int set_prop_sense_type(struct fg_chip *chip, int ext_sense_type) return 0; } #define IGNORE_FALSE_NEGATIVE_ISENSE_BIT BIT(3) static int set_prop_ignore_false_negative_isense(struct fg_chip *chip, bool ignore) { int rc; rc = fg_mem_masked_write(chip, EXTERNAL_SENSE_SELECT, IGNORE_FALSE_NEGATIVE_ISENSE_BIT, ignore ? IGNORE_FALSE_NEGATIVE_ISENSE_BIT : 0, EXTERNAL_SENSE_OFFSET); if (rc) { pr_err("failed to %s isense false negative ignore rc=%d\n", ignore ? "enable" : "disable", rc); return rc; } return 0; } #define EXPONENT_MASK 0xF800 #define MANTISSA_MASK 0x3FF #define SIGN BIT(10) Loading Loading @@ -3220,6 +3245,8 @@ static enum power_supply_property fg_power_props[] = { POWER_SUPPLY_PROP_CYCLE_COUNT_ID, POWER_SUPPLY_PROP_HI_POWER, POWER_SUPPLY_PROP_SOC_REPORTING_READY, POWER_SUPPLY_PROP_IGNORE_FALSE_NEGATIVE_ISENSE, POWER_SUPPLY_PROP_ENABLE_JEITA_DETECTION, }; static int fg_power_get_property(struct power_supply *psy, Loading Loading @@ -3250,6 +3277,12 @@ static int fg_power_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_CURRENT_NOW: val->intval = get_sram_prop_now(chip, FG_DATA_CURRENT); break; case POWER_SUPPLY_PROP_IGNORE_FALSE_NEGATIVE_ISENSE: val->intval = !chip->allow_false_negative_isense; break; case POWER_SUPPLY_PROP_ENABLE_JEITA_DETECTION: val->intval = chip->use_soft_jeita_irq; break; case POWER_SUPPLY_PROP_VOLTAGE_NOW: val->intval = get_sram_prop_now(chip, FG_DATA_VOLTAGE); break; Loading Loading @@ -4252,6 +4285,67 @@ static int fg_power_set_property(struct power_supply *psy, if (val->intval) update_sram_data(chip, &unused); break; case POWER_SUPPLY_PROP_IGNORE_FALSE_NEGATIVE_ISENSE: rc = set_prop_ignore_false_negative_isense(chip, !!val->intval); if (rc) pr_err("set_prop_ignore_false_negative_isense failed, rc=%d\n", rc); else chip->allow_false_negative_isense = !val->intval; break; case POWER_SUPPLY_PROP_ENABLE_JEITA_DETECTION: if (chip->use_soft_jeita_irq == !!val->intval) { pr_debug("JEITA irq %s, ignore!\n", chip->use_soft_jeita_irq ? "enabled" : "disabled"); break; } chip->use_soft_jeita_irq = !!val->intval; if (chip->use_soft_jeita_irq) { if (chip->batt_irq[JEITA_SOFT_COLD].disabled) { enable_irq( chip->batt_irq[JEITA_SOFT_COLD].irq); chip->batt_irq[JEITA_SOFT_COLD].disabled = false; } if (!chip->batt_irq[JEITA_SOFT_COLD].wakeup) { enable_irq_wake( chip->batt_irq[JEITA_SOFT_COLD].irq); chip->batt_irq[JEITA_SOFT_COLD].wakeup = true; } if (chip->batt_irq[JEITA_SOFT_HOT].disabled) { enable_irq( chip->batt_irq[JEITA_SOFT_HOT].irq); chip->batt_irq[JEITA_SOFT_HOT].disabled = false; } if (!chip->batt_irq[JEITA_SOFT_HOT].wakeup) { enable_irq_wake( chip->batt_irq[JEITA_SOFT_HOT].irq); chip->batt_irq[JEITA_SOFT_HOT].wakeup = true; } } else { if (chip->batt_irq[JEITA_SOFT_COLD].wakeup) { disable_irq_wake( chip->batt_irq[JEITA_SOFT_COLD].irq); chip->batt_irq[JEITA_SOFT_COLD].wakeup = false; } if (!chip->batt_irq[JEITA_SOFT_COLD].disabled) { disable_irq_nosync( chip->batt_irq[JEITA_SOFT_COLD].irq); chip->batt_irq[JEITA_SOFT_COLD].disabled = true; } if (chip->batt_irq[JEITA_SOFT_HOT].wakeup) { disable_irq_wake( chip->batt_irq[JEITA_SOFT_HOT].irq); chip->batt_irq[JEITA_SOFT_HOT].wakeup = false; } if (!chip->batt_irq[JEITA_SOFT_HOT].disabled) { disable_irq_nosync( chip->batt_irq[JEITA_SOFT_HOT].irq); chip->batt_irq[JEITA_SOFT_HOT].disabled = true; } } break; case POWER_SUPPLY_PROP_STATUS: chip->prev_status = chip->status; chip->status = val->intval; Loading Loading @@ -4535,6 +4629,168 @@ static void cc_soc_store_work(struct work_struct *work) fg_relax(&chip->cc_soc_wakeup_source); } #define HARD_JEITA_ALARM_CHECK_NS 10000000000 static enum alarmtimer_restart fg_hard_jeita_alarm_cb(struct alarm *alarm, ktime_t now) { struct fg_chip *chip = container_of(alarm, struct fg_chip, hard_jeita_alarm); int rc, health = POWER_SUPPLY_HEALTH_UNKNOWN; u8 regval; bool batt_hot, batt_cold; union power_supply_propval val = {0, }; if (!is_usb_present(chip)) { pr_debug("USB plugged out, stop the timer!\n"); return ALARMTIMER_NORESTART; } rc = fg_read(chip, ®val, BATT_INFO_STS(chip->batt_base), 1); if (rc) { pr_err("read batt_sts failed, rc=%d\n", rc); goto recheck; } batt_hot = !!(regval & JEITA_HARD_HOT_RT_STS); batt_cold = !!(regval & JEITA_HARD_COLD_RT_STS); if (batt_hot && batt_cold) { pr_debug("Hot && cold can't co-exist\n"); goto recheck; } if ((batt_hot == chip->batt_hot) && (batt_cold == chip->batt_cold)) { pr_debug("battery JEITA state not changed, ignore\n"); goto recheck; } if (batt_cold != chip->batt_cold) { /* cool --> cold */ if (chip->batt_cool) { chip->batt_cool = false; chip->batt_cold = true; health = POWER_SUPPLY_HEALTH_COLD; } else if (chip->batt_cold) { /* cold --> cool */ chip->batt_cool = true; chip->batt_cold = false; health = POWER_SUPPLY_HEALTH_COOL; } } if (batt_hot != chip->batt_hot) { /* warm --> hot */ if (chip->batt_warm) { chip->batt_warm = false; chip->batt_hot = true; health = POWER_SUPPLY_HEALTH_OVERHEAT; } else if (chip->batt_hot) { /* hot --> warm */ chip->batt_hot = false; chip->batt_warm = true; health = POWER_SUPPLY_HEALTH_WARM; } } if (health != POWER_SUPPLY_HEALTH_UNKNOWN) { pr_debug("FG report battery health: %d\n", health); val.intval = health; rc = chip->batt_psy->set_property(chip->batt_psy, POWER_SUPPLY_PROP_HEALTH, &val); if (rc) pr_err("Set batt_psy health: %d failed\n", health); } recheck: alarm_forward_now(alarm, ns_to_ktime(HARD_JEITA_ALARM_CHECK_NS)); return ALARMTIMER_RESTART; } #define BATT_SOFT_COLD_STS BIT(0) #define BATT_SOFT_HOT_STS BIT(1) static irqreturn_t fg_jeita_soft_hot_irq_handler(int irq, void *_chip) { int rc; struct fg_chip *chip = _chip; u8 regval; bool batt_warm; union power_supply_propval val = {0, }; rc = fg_read(chip, ®val, INT_RT_STS(chip->batt_base), 1); if (rc) { pr_err("spmi read failed: addr=%03X, rc=%d\n", INT_RT_STS(chip->batt_base), rc); return IRQ_HANDLED; } batt_warm = !!(regval & BATT_SOFT_HOT_STS); if (chip->batt_warm == batt_warm) { pr_debug("warm state not change, ignore!\n"); return IRQ_HANDLED; } chip->batt_warm = batt_warm; if (batt_warm) { val.intval = POWER_SUPPLY_HEALTH_WARM; chip->batt_psy->set_property(chip->batt_psy, POWER_SUPPLY_PROP_HEALTH, &val); /* kick the alarm timer for hard hot polling */ rc = alarm_start_relative(&chip->hard_jeita_alarm, ns_to_ktime(HARD_JEITA_ALARM_CHECK_NS)); if (rc) pr_err("start alarm for hard HOT detection failed, rc=%d\n", rc); } else { val.intval = POWER_SUPPLY_HEALTH_GOOD; chip->batt_psy->set_property(chip->batt_psy, POWER_SUPPLY_PROP_HEALTH, &val); /* cancel the alarm timer */ alarm_try_to_cancel(&chip->hard_jeita_alarm); } return IRQ_HANDLED; } static irqreturn_t fg_jeita_soft_cold_irq_handler(int irq, void *_chip) { int rc; struct fg_chip *chip = _chip; u8 regval; bool batt_cool; union power_supply_propval val = {0, }; rc = fg_read(chip, ®val, INT_RT_STS(chip->batt_base), 1); if (rc) { pr_err("spmi read failed: addr=%03X, rc=%d\n", INT_RT_STS(chip->batt_base), rc); return IRQ_HANDLED; } batt_cool = !!(regval & BATT_SOFT_COLD_STS); if (chip->batt_cool == batt_cool) { pr_debug("cool state not change, ignore\n"); return IRQ_HANDLED; } chip->batt_cool = batt_cool; if (batt_cool) { val.intval = POWER_SUPPLY_HEALTH_COOL; chip->batt_psy->set_property(chip->batt_psy, POWER_SUPPLY_PROP_HEALTH, &val); /* kick the alarm timer for hard cold polling */ rc = alarm_start_relative(&chip->hard_jeita_alarm, ns_to_ktime(HARD_JEITA_ALARM_CHECK_NS)); if (rc) pr_err("start alarm for hard COLD detection failed, rc=%d\n", rc); } else { val.intval = POWER_SUPPLY_HEALTH_GOOD; chip->batt_psy->set_property(chip->batt_psy, POWER_SUPPLY_PROP_HEALTH, &val); /* cancel the alarm timer */ alarm_try_to_cancel(&chip->hard_jeita_alarm); } return IRQ_HANDLED; } #define SOC_FIRST_EST_DONE BIT(5) static bool is_first_est_done(struct fg_chip *chip) { Loading Loading @@ -6690,6 +6946,53 @@ static int fg_init_irqs(struct fg_chip *chip) } break; case FG_BATT: chip->batt_irq[JEITA_SOFT_COLD].irq = spmi_get_irq_byname(chip->spmi, spmi_resource, "soft-cold"); if (chip->batt_irq[JEITA_SOFT_COLD].irq < 0) { pr_err("Unable to get soft-cold irq\n"); rc = -EINVAL; return rc; } rc = devm_request_threaded_irq(chip->dev, chip->batt_irq[JEITA_SOFT_COLD].irq, NULL, fg_jeita_soft_cold_irq_handler, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "soft-cold", chip); if (rc < 0) { pr_err("Can't request %d soft-cold: %d\n", chip->batt_irq[JEITA_SOFT_COLD].irq, rc); return rc; } disable_irq(chip->batt_irq[JEITA_SOFT_COLD].irq); chip->batt_irq[JEITA_SOFT_COLD].disabled = true; chip->batt_irq[JEITA_SOFT_HOT].irq = spmi_get_irq_byname(chip->spmi, spmi_resource, "soft-hot"); if (chip->batt_irq[JEITA_SOFT_HOT].irq < 0) { pr_err("Unable to get soft-hot irq\n"); rc = -EINVAL; return rc; } rc = devm_request_threaded_irq(chip->dev, chip->batt_irq[JEITA_SOFT_HOT].irq, NULL, fg_jeita_soft_hot_irq_handler, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "soft-hot", chip); if (rc < 0) { pr_err("Can't request %d soft-hot: %d\n", chip->batt_irq[JEITA_SOFT_HOT].irq, rc); return rc; } disable_irq(chip->batt_irq[JEITA_SOFT_HOT].irq); chip->batt_irq[JEITA_SOFT_HOT].disabled = true; chip->batt_irq[BATT_MISSING].irq = spmi_get_irq_byname( chip->spmi, spmi_resource, "batt-missing"); Loading Loading @@ -6760,6 +7063,7 @@ static void fg_cancel_all_works(struct fg_chip *chip) cancel_delayed_work_sync(&chip->check_empty_work); cancel_delayed_work_sync(&chip->batt_profile_init); alarm_try_to_cancel(&chip->fg_cap_learning_alarm); alarm_try_to_cancel(&chip->hard_jeita_alarm); if (!chip->ima_error_handling) cancel_work_sync(&chip->ima_error_recovery_work); cancel_work_sync(&chip->rslow_comp_work); Loading Loading @@ -8065,6 +8369,8 @@ static int fg_probe(struct spmi_device *spmi) INIT_WORK(&chip->cc_soc_store_work, cc_soc_store_work); alarm_init(&chip->fg_cap_learning_alarm, ALARM_BOOTTIME, fg_cap_learning_alarm_cb); alarm_init(&chip->hard_jeita_alarm, ALARM_BOOTTIME, fg_hard_jeita_alarm_cb); init_completion(&chip->sram_access_granted); init_completion(&chip->sram_access_revoked); complete_all(&chip->sram_access_revoked); Loading