diff --git a/core/embed/sys/power_manager/inc/sys/pmic.h b/core/embed/sys/power_manager/inc/sys/pmic.h index 296023b3f9..d2b9905b22 100644 --- a/core/embed/sys/power_manager/inc/sys/pmic.h +++ b/core/embed/sys/power_manager/inc/sys/pmic.h @@ -47,6 +47,8 @@ typedef struct { // BUCKSTATUS register value // (for debugging purposes, see the datasheet) uint8_t charge_status; + uint8_t charge_err; + uint8_t charge_sensor_err; uint8_t buck_status; uint8_t usb_status; } pmic_report_t; @@ -135,3 +137,6 @@ typedef enum { // Set the buck voltage regulator mode bool pmic_set_buck_mode(pmic_buck_mode_t buck_mode); + +// Clears all battery charger errors. +bool pmic_clear_charger_errors(void); diff --git a/core/embed/sys/power_manager/npm1300/npm1300.c b/core/embed/sys/power_manager/npm1300/npm1300.c index 1e5a5755ae..f7d2f9e346 100644 --- a/core/embed/sys/power_manager/npm1300/npm1300.c +++ b/core/embed/sys/power_manager/npm1300/npm1300.c @@ -68,6 +68,8 @@ typedef struct { uint8_t adc_vbat2_result_msb; uint8_t adc_ibat_meas_status; uint8_t charging_status; + uint8_t charging_err; + uint8_t charging_sensor_err; uint8_t buck_status; uint8_t usb_status; } npm1300_adc_regs_t; @@ -706,6 +708,8 @@ static void npm1300_calculate_report(npm1300_driver_t* drv, report->buck_status = r->buck_status; report->usb_status = r->usb_status; report->charge_status = r->charging_status; + report->charge_err = r->charging_err; + report->charge_sensor_err = r->charging_sensor_err; } // I2C operation for writing constant value to the npm1300 register @@ -805,6 +809,8 @@ static const i2c_op_t npm1300_ops_adc_readout[] = { NPM_READ_FIELD(NPM1300_ADCVBAT2RESULTMSB, adc_regs.adc_vbat2_result_msb), NPM_READ_FIELD(NPM1300_ADCIBATMEASSTATUS, adc_regs.adc_ibat_meas_status), NPM_READ_FIELD(NPM1300_BCHGCHARGESTATUS, adc_regs.charging_status), + NPM_READ_FIELD(NPM1300_BCHGERRREASON, adc_regs.charging_err), + NPM_READ_FIELD(NPM1300_BCHGERRSENSOR, adc_regs.charging_sensor_err), NPM_READ_FIELD(NPM1300_BUCKSTATUS, adc_regs.buck_status), NPM_READ_FIELD(NPM1300_USBCDETECTSTATUS, adc_regs.usb_status), }; @@ -815,6 +821,12 @@ static const i2c_op_t npm1300_ops_clear_events[] = { NPM_WRITE_CONST(NPM1300_EVENTSVBUSIN0CLR, 0x3F), }; +// Clear charger errors and release charging from error state +static const i2c_op_t npm1300_ops_clear_charger_errors[] = { + NPM_WRITE_CONST(NPM1300_TASKCLEARCHGERR, 1), + NPM_WRITE_CONST(NPM1300_TASKRELEASEERR, 1), +}; + #define npm1300_i2c_submit(drv, ops) \ _npm1300_i2c_submit(drv, ops, ARRAY_LENGTH(ops)) @@ -839,6 +851,20 @@ static void _npm1300_i2c_submit(npm1300_driver_t* drv, const i2c_op_t* ops, } } +bool pmic_clear_charger_errors(void) { + npm1300_driver_t* drv = &g_npm1300_driver; + + if (!drv->initialized) { + return false; + } + + irq_key_t irq_key = irq_lock(); + npm1300_i2c_submit(drv, npm1300_ops_clear_charger_errors); + irq_unlock(irq_key); + + return true; +} + // npm1300 driver timer callback invoked when `drv->timer` expires. // // This function is called in the irq context. diff --git a/core/embed/sys/power_manager/stm32u5/power_monitoring.c b/core/embed/sys/power_manager/stm32u5/power_monitoring.c index 8ea3fc90ac..d7ab85187d 100644 --- a/core/embed/sys/power_manager/stm32u5/power_monitoring.c +++ b/core/embed/sys/power_manager/stm32u5/power_monitoring.c @@ -176,12 +176,6 @@ void pm_charging_controller(pm_driver_t* drv) { pm_temperature_controller(drv); - // Set charging target - if (drv->i_chg_target_ma != pmic_get_charging_limit()) { - // Set charging current limit - pmic_set_charging_limit(drv->i_chg_target_ma); - } - if (drv->soc_target == 100) { drv->soc_target_reached = false; } else { @@ -212,9 +206,20 @@ void pm_charging_controller(pm_driver_t* drv) { drv->i_chg_target_ma = 0; } + // Set charging target + if (drv->i_chg_target_ma != pmic_get_charging_limit()) { + // Set charging current limit + pmic_set_charging_limit(drv->i_chg_target_ma); + } + if (drv->i_chg_target_ma == 0) { pmic_set_charging(false); } else { + // Clear and release charger if it has any errors + if (drv->pmic_data.charge_err || drv->pmic_data.charge_sensor_err) { + pmic_clear_charger_errors(); + } + pmic_set_charging(true); } }