Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 32 additions & 6 deletions src/fw/board/boards/board_asterix.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
#include "drivers/nrf5/i2c_hal_definitions.h"
#include "drivers/nrf5/spi_definitions.h"
#include "drivers/nrf5/uart_definitions.h"
#include "drivers/pmic/npm1300.h"
#include "drivers/pwm.h"
#include "drivers/qspi_definitions.h"
#include "drivers/rtc.h"
Expand Down Expand Up @@ -207,12 +206,39 @@ IRQ_MAP_NRFX(PWM0, nrfx_pwm_0_irq_handler);

IRQ_MAP_NRFX(RTC1, rtc_irq_handler);

enum {
ASTERIX_NPM1300_CHARGE_CURRENT_MA = 128,
ASTERIX_NPM1300_DISCHARGE_LIMIT_MA = 200,
ASTERIX_NPM1300_THERMISTOR_BETA = 3380,
};

const Npm1300Config NPM1300_CONFIG = {
// 128mA = ~1C (rapid charge)
.chg_current_ma = 128,
.dischg_limit_ma = 200,
.term_current_pct = 10,
.thermistor_beta = 3380,
.chg_current_ma = ASTERIX_NPM1300_CHARGE_CURRENT_MA, // ~1C rapid charge
.dischg_limit_ma = ASTERIX_NPM1300_DISCHARGE_LIMIT_MA, // ~1.6C burst, HW protection floor
.term_current_pct = NPM1300_TERM_CURRENT_10_PERCENT, // 12.8mA
.thermistor_beta = ASTERIX_NPM1300_THERMISTOR_BETA, // 10kΩ
.vterm_setting = NPM1300_VTERM_4V20,

// Buck1 (1.8V)
.buck1_enable = true,
.buck1_voltage_sel = NPM1300_VOLTAGE_SEL_1V8,

// Buck2 (3.0V)
.buck2_enable = true,
.buck2_voltage_sel = NPM1300_VOLTAGE_SEL_3V0,
.buck_sw_ctrl_sel = NPM1300_BUCK_SW_CTRL_SEL_BUCK1_BUCK2,
.configure_buck_sw_ctrl = false, // Already configured by Erratum 27 workaround

// LDSW1 disabled (not used)
.ldsw1_enable = false,
.ldsw1_voltage_sel = NPM1300_VOLTAGE_SEL_DISABLED,

// LDSW2 (1.8V LDO)
.ldsw2_enable = true,
.ldsw2_mode = NPM1300_LDO2_MODE_LDO,
.ldsw2_voltage_sel = NPM1300_VOLTAGE_SEL_1V8,

.apply_erratum_27_workaround = true,
};

void board_early_init(void) {
Expand Down
44 changes: 37 additions & 7 deletions src/fw/board/boards/board_getafix.c
Original file line number Diff line number Diff line change
Expand Up @@ -460,14 +460,44 @@ const BoardConfigActuator BOARD_CONFIG_VIBE = {
.ctl = {hwp_gpio1, 20, false},
};

enum {
GETAFIX_NPM1300_CHARGE_CURRENT_MA = 70,
GETAFIX_NPM1300_DISCHARGE_LIMIT_MA = 200,
GETAFIX_NPM1300_THERMISTOR_BETA = 3380,
GETAFIX_NPM1300_VBUS_CURRENT_LIMIT_MA = 500,
GETAFIX_NPM1300_VBUS_STARTUP_CURRENT_MA = GETAFIX_NPM1300_VBUS_CURRENT_LIMIT_MA,
};

const Npm1300Config NPM1300_CONFIG = {
// 70mA = 1C (max limit from datasheet)
.chg_current_ma = 70,
.dischg_limit_ma = 200,
.term_current_pct = 10,
.thermistor_beta = 3380,
.vbus_current_lim0 = 500,
.vbus_current_startup = 500,
.chg_current_ma = GETAFIX_NPM1300_CHARGE_CURRENT_MA, // 1C, max per datasheet
.dischg_limit_ma = GETAFIX_NPM1300_DISCHARGE_LIMIT_MA, // ~2.8C burst, HW protection floor
.term_current_pct = NPM1300_TERM_CURRENT_10_PERCENT, // 7mA
.thermistor_beta = GETAFIX_NPM1300_THERMISTOR_BETA, // 10kΩ
.vbus_current_lim0 = GETAFIX_NPM1300_VBUS_CURRENT_LIMIT_MA, // USB 2.0 max
.vbus_current_startup = GETAFIX_NPM1300_VBUS_STARTUP_CURRENT_MA, // Match steady-state
.vterm_setting = NPM1300_VTERM_4V45,

// Buck1 disabled after switching to SW control via Erratum 27 workaround
.buck1_enable = false,
.buck1_voltage_sel = NPM1300_VOLTAGE_SEL_1V8,

// Buck2 disabled
.buck2_enable = false,
.buck2_voltage_sel = NPM1300_VOLTAGE_SEL_DISABLED,
.buck_sw_ctrl_sel = NPM1300_BUCK_SW_CTRL_SEL_BUCK1,
.configure_buck_sw_ctrl = false, // Already configured by Erratum 27 workaround

// LDSW1 (1.8V LDO)
.ldsw1_enable = true,
.ldsw1_mode = NPM1300_LDO2_MODE_LDO,
.ldsw1_voltage_sel = NPM1300_VOLTAGE_SEL_1V8,

// LDSW2 (3.3V LDSW for PDM, initially disabled)
.ldsw2_enable = false,
.ldsw2_mode = NPM1300_LDO2_MODE_LDSW,
.ldsw2_voltage_sel = NPM1300_VOLTAGE_SEL_DISABLED,

.apply_erratum_27_workaround = true,
};

const BoardConfigPower BOARD_CONFIG_POWER = {
Expand Down
44 changes: 37 additions & 7 deletions src/fw/board/boards/board_obelix.c
Original file line number Diff line number Diff line change
Expand Up @@ -580,15 +580,45 @@ const BoardConfigActuator BOARD_CONFIG_VIBE = {
.ctl = {hwp_gpio1, 1, false},
};

enum {
OBELIX_NPM1300_CHARGE_CURRENT_MA = 190,
OBELIX_NPM1300_DISCHARGE_LIMIT_MA = 200,
OBELIX_NPM1300_THERMISTOR_BETA = 3380,
OBELIX_NPM1300_VBUS_CURRENT_LIMIT_MA = 500,
OBELIX_NPM1300_VBUS_STARTUP_CURRENT_MA = OBELIX_NPM1300_VBUS_CURRENT_LIMIT_MA,
};

// TODO(OBELIX): Adjust to final battery parameters
const Npm1300Config NPM1300_CONFIG = {
// 190mA = 1C (rapid charge, max limit from datasheet)
.chg_current_ma = 190,
.dischg_limit_ma = 200,
.term_current_pct = 10,
.thermistor_beta = 3380,
.vbus_current_lim0 = 500,
.vbus_current_startup = 500,
.chg_current_ma = OBELIX_NPM1300_CHARGE_CURRENT_MA, // 1C rapid charge, max per datasheet
.dischg_limit_ma = OBELIX_NPM1300_DISCHARGE_LIMIT_MA, // ~1.05C burst, HW protection floor
.term_current_pct = NPM1300_TERM_CURRENT_10_PERCENT, // 19mA
.thermistor_beta = OBELIX_NPM1300_THERMISTOR_BETA, // 10kΩ
.vbus_current_lim0 = OBELIX_NPM1300_VBUS_CURRENT_LIMIT_MA, // USB 2.0 max
.vbus_current_startup = OBELIX_NPM1300_VBUS_STARTUP_CURRENT_MA, // Match steady-state
.vterm_setting = NPM1300_VTERM_4V35,

// Buck1 disabled after switching to SW control via Erratum 27 workaround
.buck1_enable = false,
.buck1_voltage_sel = NPM1300_VOLTAGE_SEL_1V8, // 1.8V (don't-care, disabled)
// Buck2 disabled (unused?)
.buck2_enable = false,
.buck2_voltage_sel = NPM1300_VOLTAGE_SEL_DISABLED,
.buck_sw_ctrl_sel = NPM1300_BUCK_SW_CTRL_SEL_BUCK1,

.configure_buck_sw_ctrl = false, // Already configured by Erratum 27 workaround

// LDSW1 enabled: 1.8V LDO
.ldsw1_enable = true,
.ldsw1_mode = NPM1300_LDO2_MODE_LDO,
.ldsw1_voltage_sel = NPM1300_VOLTAGE_SEL_1V8,

// LDSW2 disabled: 3.3V LDO configured but disabled
.ldsw2_enable = false,
.ldsw2_mode = NPM1300_LDO2_MODE_LDO,
.ldsw2_voltage_sel = NPM1300_VOLTAGE_SEL_3V3,

.apply_erratum_27_workaround = true,
};

static const I2CSlavePort s_i2c_w1160 = {
Expand Down
141 changes: 76 additions & 65 deletions src/fw/drivers/pmic/npm1300.c
Original file line number Diff line number Diff line change
Expand Up @@ -270,46 +270,80 @@ bool pmic_init(void) {

s_debounce_charger_timer = new_timer_create();

// TODO(NPM1300): This needs to be configurable at board level
#if PLATFORM_ASTERIX
// Anomaly 27: set BUCK1/BUCK2 to SW control with workaround
ok &= prv_buck_set_sw_ctrl(PmicRegisters_BUCK_BUCK1NORMVOUT,
PmicRegisters_BUCK_BUCK1VOUTSTATUS,
PmicRegisters_BUCK_BUCKSWCTRLSEL__BUCK1SWCTRLSEL_SWCTRL,
8 /* 1.8V */);
ok &= prv_buck_set_sw_ctrl(PmicRegisters_BUCK_BUCK2NORMVOUT,
PmicRegisters_BUCK_BUCK2VOUTSTATUS,
PmicRegisters_BUCK_BUCKSWCTRLSEL__BUCK2SWCTRLSEL_SWCTRL,
20 /* 3.0V */);

if (!prv_read_register(PmicRegisters_LDSW_LDSWSTATUS, &val)) {
PBL_LOG_ERR("failed to read LDSWSTATUS");
return false;
prv_read_register(PmicRegisters_BUCK_BUCK1NORMVOUT, &val);
PBL_LOG_DBG("found the nPM1300, BUCK1NORMVOUT = 0x%x", val);

if (NPM1300_CONFIG.apply_erratum_27_workaround) {
if ((NPM1300_CONFIG.buck_sw_ctrl_sel & NPM1300_BUCK_SW_CTRL_SEL_BUCK1) != 0 &&
NPM1300_CONFIG.buck1_voltage_sel != NPM1300_VOLTAGE_SEL_DISABLED) {
ok &= prv_buck_set_sw_ctrl(PmicRegisters_BUCK_BUCK1NORMVOUT,
PmicRegisters_BUCK_BUCK1VOUTSTATUS,
NPM1300_BUCK_SW_CTRL_SEL_BUCK1,
NPM1300_CONFIG.buck1_voltage_sel);
}

if ((NPM1300_CONFIG.buck_sw_ctrl_sel & NPM1300_BUCK_SW_CTRL_SEL_BUCK2) != 0 &&
NPM1300_CONFIG.buck2_voltage_sel != NPM1300_VOLTAGE_SEL_DISABLED) {
ok &= prv_buck_set_sw_ctrl(PmicRegisters_BUCK_BUCK2NORMVOUT,
PmicRegisters_BUCK_BUCK2VOUTSTATUS,
NPM1300_BUCK_SW_CTRL_SEL_BUCK2,
NPM1300_CONFIG.buck2_voltage_sel);
}
}

// Configure Bucks
if (NPM1300_CONFIG.buck1_voltage_sel != NPM1300_VOLTAGE_SEL_DISABLED) {
ok &= prv_write_register(PmicRegisters_BUCK_BUCK1NORMVOUT, NPM1300_CONFIG.buck1_voltage_sel);
}

if (!NPM1300_CONFIG.buck1_enable) {
// Disable if not enabled (matching original Obelix behavior)
ok &= prv_write_register(PmicRegisters_BUCK_BUCK1ENACLR, 1);
}

if ((val & PmicRegisters_LDSW_LDSWSTATUS__LDSW2PWRUPLDO) == 0U) {
ok &= prv_write_register(PmicRegisters_LDSW_TASKLDSW2CLR, 0x01);
ok &= prv_write_register(PmicRegisters_LDSW_LDSW2VOUTSEL, 8 /* 1.8V */);
ok &= prv_write_register(PmicRegisters_LDSW_LDSW2LDOSEL, 1 /* LDO */);
ok &= prv_write_register(PmicRegisters_LDSW_TASKLDSW2SET, 0x01);
if (NPM1300_CONFIG.buck2_voltage_sel != NPM1300_VOLTAGE_SEL_DISABLED &&
NPM1300_CONFIG.buck2_enable) {
ok &= prv_write_register(PmicRegisters_BUCK_BUCK2NORMVOUT, NPM1300_CONFIG.buck2_voltage_sel);
}

if (NPM1300_CONFIG.configure_buck_sw_ctrl) {
ok &= prv_write_register(PmicRegisters_BUCK_BUCKSWCTRLSEL, NPM1300_CONFIG.buck_sw_ctrl_sel);
}

// Configure LDSW1
if (NPM1300_CONFIG.ldsw1_enable) {
ok &= prv_write_register(PmicRegisters_LDSW_LDSW1LDOSEL, NPM1300_CONFIG.ldsw1_mode);
ok &= prv_write_register(PmicRegisters_LDSW_LDSW1VOUTSEL, NPM1300_CONFIG.ldsw1_voltage_sel);
ok &= prv_write_register(PmicRegisters_LDSW_TASKLDSW1SET, 1);
} else {
ok &= prv_write_register(PmicRegisters_LDSW_LDSW2VOUTSEL, 8 /* 1.8V */);
}
#endif

// FIXME(OBELIX,GETAFIX): Needs to be configurable at board level
#if PLATFORM_OBELIX || PLATFORM_GETAFIX
// Anomaly 27: set BUCK1 to SW control with workaround, then disable it
ok &= prv_buck_set_sw_ctrl(PmicRegisters_BUCK_BUCK1NORMVOUT,
PmicRegisters_BUCK_BUCK1VOUTSTATUS,
PmicRegisters_BUCK_BUCKSWCTRLSEL__BUCK1SWCTRLSEL_SWCTRL,
8 /* 1.8V */);
ok &= prv_write_register(PmicRegisters_BUCK_BUCK1ENACLR, 1);
//enable 1.8V@LDO1
ok &= prv_write_register(PmicRegisters_LDSW_LDSW1LDOSEL, 1); //LDO
ok &= prv_write_register(PmicRegisters_LDSW_LDSW1VOUTSEL, 8); //1.8V
ok &= prv_write_register(PmicRegisters_LDSW_TASKLDSW1SET, 1); //enable
#endif
ok &= prv_write_register(PmicRegisters_LDSW_TASKLDSW1CLR, 1);
}

// Configure LDSW2
if (NPM1300_CONFIG.ldsw2_enable) {
// Asterix logic checks if already powered up to avoid glitching/resetting if already on
uint8_t status = 0;
if (!prv_read_register(PmicRegisters_LDSW_LDSWSTATUS, &status)) {
PBL_LOG_ERR("failed to read LDSWSTATUS");
return false;
}
if ((status & PmicRegisters_LDSW_LDSWSTATUS__LDSW2PWRUPLDO) == 0) {
// Not powered up, perform full setup
ok &= prv_write_register(PmicRegisters_LDSW_TASKLDSW2CLR, 1);
ok &= prv_write_register(PmicRegisters_LDSW_LDSW2LDOSEL, NPM1300_CONFIG.ldsw2_mode);
ok &= prv_write_register(PmicRegisters_LDSW_LDSW2VOUTSEL, NPM1300_CONFIG.ldsw2_voltage_sel);
ok &= prv_write_register(PmicRegisters_LDSW_TASKLDSW2SET, 1);
} else {
// Already powered up, just update voltage
ok &= prv_write_register(PmicRegisters_LDSW_LDSW2VOUTSEL, NPM1300_CONFIG.ldsw2_voltage_sel);
}
} else {
ok &= prv_write_register(PmicRegisters_LDSW_LDSW2LDOSEL, NPM1300_CONFIG.ldsw2_mode);
if (NPM1300_CONFIG.ldsw2_voltage_sel != NPM1300_VOLTAGE_SEL_DISABLED) {
ok &= prv_write_register(PmicRegisters_LDSW_LDSW2VOUTSEL, NPM1300_CONFIG.ldsw2_voltage_sel);
}
ok &= prv_write_register(PmicRegisters_LDSW_TASKLDSW2CLR, 1);
}

ok &= prv_write_register(PmicRegisters_MAIN_EVENTSBCHARGER1CLR, PmicRegisters_MAIN_EVENTSBCHARGER1__EVENTCHGCOMPLETED);
ok &= prv_write_register(PmicRegisters_MAIN_INTENEVENTSBCHARGER1SET, PmicRegisters_MAIN_EVENTSBCHARGER1__EVENTCHGCOMPLETED);
Expand All @@ -335,35 +369,12 @@ bool pmic_init(void) {
ok &= prv_write_register(PmicRegisters_BCHARGER_TASKCLEARCHGERR, 1);
ok &= prv_write_register(PmicRegisters_BCHARGER_TASKRELEASEERROR, 1);

// FIXME: this needs to be configurable at board level
#if PLATFORM_OBELIX
ok &= prv_write_register(PmicRegisters_ADC_ADCNTCRSEL, PmicRegisters_ADC_ADCNTCRSEL__ADCNTCRSEL_10K);

ok &= prv_write_register(PmicRegisters_BCHARGER_BCHGVTERM, PmicRegisters_BCHARGER_BCHGVTERM__BCHGVTERMNORM_4V35);
ok &= prv_write_register(PmicRegisters_BCHARGER_BCHGVTERMR, PmicRegisters_BCHARGER_BCHGVTERMR__BCHGVTERMREDUCED_4V00);
#elif PLATFORM_GETAFIX
ok &= prv_write_register(PmicRegisters_ADC_ADCNTCRSEL, PmicRegisters_ADC_ADCNTCRSEL__ADCNTCRSEL_10K);

ok &= prv_write_register(PmicRegisters_BCHARGER_BCHGVTERM, PmicRegisters_BCHARGER_BCHGVTERM__BCHGVTERMNORM_4V45);
ok &= prv_write_register(PmicRegisters_BCHARGER_BCHGVTERMR, PmicRegisters_BCHARGER_BCHGVTERMR__BCHGVTERMREDUCED_4V00);
#elif PLATFORM_ASTERIX
ok &= prv_write_register(PmicRegisters_ADC_ADCNTCRSEL, PmicRegisters_ADC_ADCNTCRSEL__ADCNTCRSEL_10K);

ok &= prv_write_register(PmicRegisters_BCHARGER_BCHGVTERM, PmicRegisters_BCHARGER_BCHGVTERM__BCHGVTERMNORM_4V20);
ok &= prv_write_register(PmicRegisters_BCHARGER_BCHGVTERMR, PmicRegisters_BCHARGER_BCHGVTERMR__BCHGVTERMREDUCED_4V00);
#endif

// FIXME: this needs to be configurable at board level
#if PLATFORM_OBELIX
//3.3V @ LDO2
ok &= prv_write_register(PmicRegisters_LDSW_LDSW2LDOSEL, PmicRegisters_LDSW_LDSW2LDOSEL__LDO_MODE);
ok &= prv_write_register(PmicRegisters_LDSW_LDSW2VOUTSEL, PmicRegisters_LDSW_LDSW2VOUTSEL__3V3);
ok &= prv_write_register(PmicRegisters_LDSW_TASKLDSW2CLR, 1);
#elif PLATFORM_GETAFIX
// LDSW2 (3.3V for PDM)
ok &= prv_write_register(PmicRegisters_LDSW_LDSW2LDOSEL, PmicRegisters_LDSW_LDSW2LDOSEL__LDSW_MODE);
ok &= prv_write_register(PmicRegisters_LDSW_TASKLDSW2CLR, 1);
#endif
ok &= prv_write_register(PmicRegisters_BCHARGER_BCHGVTERM, NPM1300_CONFIG.vterm_setting);
ok &= prv_write_register(PmicRegisters_BCHARGER_BCHGVTERMR,
PmicRegisters_BCHARGER_BCHGVTERMR__BCHGVTERMREDUCED_4V00);

val = (uint8_t)(NPM1300_CONFIG.chg_current_ma / 4U);
ok &= prv_write_register(PmicRegisters_BCHARGER_BCHGISETMSB, val);
Expand All @@ -377,10 +388,10 @@ bool pmic_init(void) {
NPM1300_CONFIG.vbus_current_startup/NPM1300_VBUS_CURRENT_DIVISOR);
}

if (NPM1300_CONFIG.term_current_pct == 10U) {
if (NPM1300_CONFIG.term_current_pct == NPM1300_TERM_CURRENT_10_PERCENT) {
ok &= prv_write_register(PmicRegisters_BCHARGER_BCHGITERMSEL,
PmicRegisters_BCHARGER_BCHGITERMSEL__SEL10);
} else if(NPM1300_CONFIG.term_current_pct == 20U) {
} else if (NPM1300_CONFIG.term_current_pct == NPM1300_TERM_CURRENT_20_PERCENT) {
ok &= prv_write_register(PmicRegisters_BCHARGER_BCHGITERMSEL,
PmicRegisters_BCHARGER_BCHGITERMSEL__SEL20);
} else {
Expand Down
Loading