1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2025-03-30 15:05:43 +00:00

feat(core): add npm1300 buck regulator control

[no changelog]
This commit is contained in:
cepetr 2024-12-10 09:53:59 +01:00 committed by cepetr
parent 27b27df17d
commit 9d2d96f832
2 changed files with 99 additions and 6 deletions

View File

@ -38,7 +38,7 @@
#define NPM1300_I2C_ERROR_LIMIT 3 #define NPM1300_I2C_ERROR_LIMIT 3
// Delay inserted between the ADC trigger and the readout [ms] // Delay inserted between the ADC trigger and the readout [ms]
#define NPM1300_ADC_READOUT_DELAY 300 #define NPM1300_ADC_READOUT_DELAY 80
// NPM1300 FSM states // NPM1300 FSM states
typedef enum { typedef enum {
@ -46,6 +46,8 @@ typedef enum {
NPM1300_STATE_CHARGING_ENABLE, NPM1300_STATE_CHARGING_ENABLE,
NPM1300_STATE_CHARGING_DISABLE, NPM1300_STATE_CHARGING_DISABLE,
NPM1300_STATE_CHARGING_LIMIT, NPM1300_STATE_CHARGING_LIMIT,
NPM1300_STATE_BUCK_MODE_SET,
NPM1300_STATE_ENTER_SHIPMODE,
NPM1300_STATE_ADC_TRIGGER, NPM1300_STATE_ADC_TRIGGER,
NPM1300_STATE_ADC_WAIT, NPM1300_STATE_ADC_WAIT,
NPM1300_STATE_ADC_READOUT, NPM1300_STATE_ADC_READOUT,
@ -60,6 +62,7 @@ typedef struct {
uint8_t adc_gp1_result_lsbs; uint8_t adc_gp1_result_lsbs;
uint8_t adc_vbat2_result_msb; uint8_t adc_vbat2_result_msb;
uint8_t adc_ibat_meas_status; uint8_t adc_ibat_meas_status;
uint8_t buck_status;
} npm1300_adc_regs_t; } npm1300_adc_regs_t;
@ -107,6 +110,14 @@ typedef struct {
bool charging; bool charging;
bool charging_requested; bool charging_requested;
// Buck voltage regulator mode
npm1300_buck_mode_t buck_mode; // written value
npm1300_buck_mode_t buck_mode_requested; // requested value
npm1300_buck_mode_t buck_mode_set; // value beeing written
// Enter ship mode
bool shipmode_requested;
// Request flags for ADC measurements // Request flags for ADC measurements
bool adc_trigger_requested; bool adc_trigger_requested;
bool adc_readout_requested; bool adc_readout_requested;
@ -215,6 +226,12 @@ static bool npm1300_initialize(i2c_bus_t* bus, uint16_t i_charge,
{NPM1300_TASKLDSW1CLR, 0x01}, {NPM1300_TASKLDSW1CLR, 0x01},
{NPM1300_TASKLDSW2CLR, 0x01}, {NPM1300_TASKLDSW2CLR, 0x01},
// BUCK regulators // BUCK regulators
// 2.7V, use sw settigns
{NPM1300_BUCK1NORMVOUT, 17},
{NPM1300_BUCKSWCTRLSEL, 1},
// Buck auto mode, Pull downs disabled
{NPM1300_BUCKCTRL0, 0}, // Auto mode
//
// TODO // TODO
// ADC settings // ADC settings
{NPM1300_ADCNTCRSEL, NPM1300_ADCNTCRSEL_10K}, {NPM1300_ADCNTCRSEL, NPM1300_ADCNTCRSEL_10K},
@ -293,6 +310,10 @@ bool npm1300_init(void) {
drv->i_charge_set = drv->i_charge; drv->i_charge_set = drv->i_charge;
drv->i_charge_requested = drv->i_charge; drv->i_charge_requested = drv->i_charge;
drv->buck_mode_requested = NPM1300_BUCK_MODE_AUTO;
drv->buck_mode_set = NPM1300_BUCK_MODE_AUTO;
drv->buck_mode = NPM1300_BUCK_MODE_AUTO;
drv->i2c_bus = i2c_bus_open(NPM1300_I2C_INSTANCE); drv->i2c_bus = i2c_bus_open(NPM1300_I2C_INSTANCE);
if (drv->i2c_bus == NULL) { if (drv->i2c_bus == NULL) {
goto cleanup; goto cleanup;
@ -329,14 +350,17 @@ void npm1300_deinit(void) {
memset(drv, 0, sizeof(npm1300_driver_t)); memset(drv, 0, sizeof(npm1300_driver_t));
} }
bool npm1300_shipmode(void) { bool npm1300_enter_shipmode(void) {
npm1300_driver_t* drv = &g_npm1300_driver; npm1300_driver_t* drv = &g_npm1300_driver;
if (!drv->initialized) { if (!drv->initialized) {
return false; return false;
} }
// TODO irq_key_t irq_key = irq_lock();
drv->shipmode_requested = true;
npm1300_fsm_continue(drv);
irq_unlock(irq_key);
return true; return true;
} }
@ -387,6 +411,21 @@ bool npm1300_set_charging(bool enable) {
return true; return true;
} }
bool npm1300_set_buck_mode(npm1300_buck_mode_t buck_mode) {
npm1300_driver_t* drv = &g_npm1300_driver;
if (!drv->initialized) {
return false;
}
irq_key_t irq_key = irq_lock();
drv->buck_mode_requested = buck_mode;
npm1300_fsm_continue(drv);
irq_unlock(irq_key);
return true;
}
uint8_t npm1300_restart_cause(void) { uint8_t npm1300_restart_cause(void) {
npm1300_driver_t* drv = &g_npm1300_driver; npm1300_driver_t* drv = &g_npm1300_driver;
@ -537,6 +576,7 @@ static void npm1300_calculate_report(npm1300_driver_t* drv,
// Populate measurement and status flags from the raw data // Populate measurement and status flags from the raw data
report->ibat_meas_status = r->adc_ibat_meas_status; report->ibat_meas_status = r->adc_ibat_meas_status;
report->buck_status = r->buck_status;
} }
// I2C operation for writing constant value to the npm1300 register // I2C operation for writing constant value to the npm1300 register
@ -587,6 +627,25 @@ static const i2c_op_t npm1300_ops_charging_limit[] = {
NPM_WRITE_FIELD(NPM1300_BCHGISETLSB, chlimit_regs.bchg_iset_lsb), NPM_WRITE_FIELD(NPM1300_BCHGISETLSB, chlimit_regs.bchg_iset_lsb),
}; };
static const i2c_op_t npm1300_ops_buck_auto[] = {
NPM_WRITE_CONST(NPM1300_BUCKCTRL0, 0),
NPM_WRITE_CONST(NPM1300_BUCK1PWMCLR, 1),
};
static const i2c_op_t npm1300_ops_buck_pwm[] = {
NPM_WRITE_CONST(NPM1300_BUCKCTRL0, 0),
NPM_WRITE_CONST(NPM1300_BUCK1PWMSET, 1),
};
static const i2c_op_t npm1300_ops_buck_pfm[] = {
NPM_WRITE_CONST(NPM1300_BUCK1PWMCLR, 1),
NPM_WRITE_CONST(NPM1300_BUCKCTRL0, 1), // Auto mode
};
static const i2c_op_t npm1300_ops_enter_shipmode[] = {
NPM_WRITE_CONST(NPM1300_TASKENTERSHIPMODE, 1),
};
// I2C operations for setting of the charging limit from // I2C operations for setting of the charging limit from
// `g_npm1300_driver.chlimit_regs` structure together with // `g_npm1300_driver.chlimit_regs` structure together with
// disabling and re-enabling of the charging // disabling and re-enabling of the charging
@ -608,8 +667,6 @@ static const i2c_op_t npm1300_ops_adc_trigger[] = {
// I2C operations for readout of the ADC values into the // I2C operations for readout of the ADC values into the
// `g_npm1300_driver.adc_regs` structure // `g_npm1300_driver.adc_regs` structure
static const i2c_op_t npm1300_ops_adc_readout[] = { static const i2c_op_t npm1300_ops_adc_readout[] = {
NPM_WRITE_CONST(NPM1300_TASKUPDATEILIMSW,
NPM1300_TASKUPDATEILIM_SELVBUSILIM0),
NPM_READ_FIELD(NPM1300_ADCGP0RESULTLSBS, adc_regs.adc_gp0_result_lsbs), NPM_READ_FIELD(NPM1300_ADCGP0RESULTLSBS, adc_regs.adc_gp0_result_lsbs),
NPM_READ_FIELD(NPM1300_ADCVBATRESULTMSB, adc_regs.adc_vbat_result_msb), NPM_READ_FIELD(NPM1300_ADCVBATRESULTMSB, adc_regs.adc_vbat_result_msb),
NPM_READ_FIELD(NPM1300_ADCNTCRESULTMSB, adc_regs.adc_nt_result_msb), NPM_READ_FIELD(NPM1300_ADCNTCRESULTMSB, adc_regs.adc_nt_result_msb),
@ -618,6 +675,7 @@ static const i2c_op_t npm1300_ops_adc_readout[] = {
NPM_READ_FIELD(NPM1300_ADCGP1RESULTLSBS, adc_regs.adc_gp1_result_lsbs), NPM_READ_FIELD(NPM1300_ADCGP1RESULTLSBS, adc_regs.adc_gp1_result_lsbs),
NPM_READ_FIELD(NPM1300_ADCVBAT2RESULTMSB, adc_regs.adc_vbat2_result_msb), 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_ADCIBATMEASSTATUS, adc_regs.adc_ibat_meas_status),
NPM_READ_FIELD(NPM1300_BUCKSTATUS, adc_regs.buck_status),
}; };
#define npm1300_i2c_submit(drv, ops) \ #define npm1300_i2c_submit(drv, ops) \
@ -707,6 +765,15 @@ static void npm1300_i2c_callback(void* context, i2c_packet_t* packet) {
drv->state = NPM1300_STATE_IDLE; drv->state = NPM1300_STATE_IDLE;
break; break;
case NPM1300_STATE_BUCK_MODE_SET:
drv->buck_mode = drv->buck_mode_set;
drv->state = NPM1300_STATE_IDLE;
break;
case NPM1300_STATE_ENTER_SHIPMODE:
drv->state = NPM1300_STATE_IDLE;
break;
case NPM1300_STATE_ADC_TRIGGER: case NPM1300_STATE_ADC_TRIGGER:
drv->adc_trigger_requested = false; drv->adc_trigger_requested = false;
systimer_set(drv->timer, NPM1300_ADC_READOUT_DELAY); systimer_set(drv->timer, NPM1300_ADC_READOUT_DELAY);
@ -778,6 +845,16 @@ static void npm1300_fsm_continue(npm1300_driver_t* drv) {
npm1300_i2c_submit(drv, npm1300_ops_charging_disable); npm1300_i2c_submit(drv, npm1300_ops_charging_disable);
drv->state = NPM1300_STATE_CHARGING_DISABLE; drv->state = NPM1300_STATE_CHARGING_DISABLE;
} }
} else if (drv->buck_mode != drv->buck_mode_requested) {
drv->buck_mode_set = drv->buck_mode_requested;
if (drv->buck_mode_set == NPM1300_BUCK_MODE_PWM) {
npm1300_i2c_submit(drv, npm1300_ops_buck_pwm);
} else if (drv->buck_mode_set == NPM1300_BUCK_MODE_PFM) {
npm1300_i2c_submit(drv, npm1300_ops_buck_pfm);
} else {
npm1300_i2c_submit(drv, npm1300_ops_buck_auto);
}
drv->state = NPM1300_STATE_BUCK_MODE_SET;
} else if (drv->adc_readout_requested) { } else if (drv->adc_readout_requested) {
// Read ADC values // Read ADC values
npm1300_i2c_submit(drv, npm1300_ops_adc_readout); npm1300_i2c_submit(drv, npm1300_ops_adc_readout);
@ -786,6 +863,10 @@ static void npm1300_fsm_continue(npm1300_driver_t* drv) {
// Trigger ADC conversion // Trigger ADC conversion
npm1300_i2c_submit(drv, npm1300_ops_adc_trigger); npm1300_i2c_submit(drv, npm1300_ops_adc_trigger);
drv->state = NPM1300_STATE_ADC_TRIGGER; drv->state = NPM1300_STATE_ADC_TRIGGER;
} else if (drv->shipmode_requested) {
npm1300_i2c_submit(drv, npm1300_ops_enter_shipmode);
drv->shipmode_requested = false;
drv->state = NPM1300_STATE_ENTER_SHIPMODE;
} }
} }

View File

@ -45,6 +45,9 @@ typedef struct {
// IBAT_MEAS_STATUS register value // IBAT_MEAS_STATUS register value
// (for debugging purposes, see the NPM1300 datasheet) // (for debugging purposes, see the NPM1300 datasheet)
uint8_t ibat_meas_status; uint8_t ibat_meas_status;
// BUCKSTATUS register value
// (for debugging purposes, see the NPM1300 datasheet)
uint8_t buck_status;
} npm1300_report_t; } npm1300_report_t;
@ -61,7 +64,7 @@ void npm1300_deinit(void);
uint8_t npm1300_restart_cause(void); uint8_t npm1300_restart_cause(void);
// Switches the device to the ship mode // Switches the device to the ship mode
bool npm1300_shipmode(void); bool npm1300_enter_shipmode(void);
// Starts the asynchronous measurement // Starts the asynchronous measurement
// //
@ -98,4 +101,13 @@ bool npm1300_set_charging_limit(int i_charge);
// Gets the charging current limit [mA]. // Gets the charging current limit [mA].
int npm1300_get_charging_limit(void); int npm1300_get_charging_limit(void);
typedef enum {
NPM1300_BUCK_MODE_AUTO,
NPM1300_BUCK_MODE_PWM,
NPM1300_BUCK_MODE_PFM,
} npm1300_buck_mode_t;
// Set the buck voltage regulator mode
bool npm1300_set_buck_mode(npm1300_buck_mode_t buck_mode);
#endif // TREZORHAL_NPM1300_H #endif // TREZORHAL_NPM1300_H