mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-12-11 17:08:15 +00:00
feat(core): introduce npm1300 driver
[no changelog]
This commit is contained in:
parent
748a19ac5d
commit
e46c2eace2
792
core/embed/sys/powerctl/npm1300/npm1300.c
Normal file
792
core/embed/sys/powerctl/npm1300/npm1300.c
Normal file
@ -0,0 +1,792 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <trezor_bsp.h>
|
||||
#include <trezor_rtl.h>
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include <io/i2c_bus.h>
|
||||
#include <sys/irq.h>
|
||||
#include <sys/systimer.h>
|
||||
|
||||
#include "npm1300.h"
|
||||
#include "npm1300_defs.h"
|
||||
|
||||
#ifdef KERNEL_MODE
|
||||
|
||||
// Default timeout for all I2C operations
|
||||
#define NPM1300_I2C_TIMEOUT 10
|
||||
|
||||
// Maximum number of consecutive I2C errors after we report a fatal error
|
||||
#define NPM1300_I2C_ERROR_LIMIT 3
|
||||
|
||||
// Delay inserted between the ADC trigger and the readout [ms]
|
||||
#define NPM1300_ADC_READOUT_DELAY 300
|
||||
|
||||
// NPM1300 FSM states
|
||||
typedef enum {
|
||||
NPM1300_STATE_IDLE = 0,
|
||||
NPM1300_STATE_CHARGING_ENABLE,
|
||||
NPM1300_STATE_CHARGING_DISABLE,
|
||||
NPM1300_STATE_CHARGING_LIMIT,
|
||||
NPM1300_STATE_ADC_TRIGGER,
|
||||
NPM1300_STATE_ADC_WAIT,
|
||||
NPM1300_STATE_ADC_READOUT,
|
||||
} npm1300_fsm_state_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t adc_gp0_result_lsbs;
|
||||
uint8_t adc_vbat_result_msb;
|
||||
uint8_t adc_nt_result_msb;
|
||||
uint8_t adc_temp_result_msb;
|
||||
uint8_t adc_vsys_result_msb;
|
||||
uint8_t adc_gp1_result_lsbs;
|
||||
uint8_t adc_vbat2_result_msb;
|
||||
uint8_t adc_ibat_meas_status;
|
||||
|
||||
} npm1300_adc_regs_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t bchg_iset_msb;
|
||||
uint8_t bchg_iset_lsb;
|
||||
|
||||
} npm1300_chlimit_regs_t;
|
||||
|
||||
// NPM1300 PMIC driver state
|
||||
typedef struct {
|
||||
// Set if the PMIC driver is initialized
|
||||
bool initialized;
|
||||
|
||||
// I2C bus where the PMIC is connected
|
||||
i2c_bus_t* i2c_bus;
|
||||
// Number of consecutive I2C errors
|
||||
int i2c_errors;
|
||||
// Storage for the pending I2C packet
|
||||
i2c_packet_t pending_i2c_packet;
|
||||
|
||||
// Timer used for waiting for the ADC conversion
|
||||
systimer_t* timer;
|
||||
|
||||
// Content of RTSCAUSE register read during driver initialization
|
||||
uint8_t restart_cause;
|
||||
|
||||
// Current state of the FSM
|
||||
npm1300_fsm_state_t state;
|
||||
|
||||
// ADC register (global buffer used for ADC measurements)
|
||||
npm1300_adc_regs_t adc_regs;
|
||||
// Charging limit registers (global buffer used for charging limit)
|
||||
npm1300_chlimit_regs_t chlimit_regs;
|
||||
|
||||
// Discharge current limit [mA]
|
||||
uint16_t i_limit;
|
||||
|
||||
// Charge current limit [mA]
|
||||
uint16_t i_charge; // written value
|
||||
uint16_t i_charge_requested; // requested value
|
||||
uint16_t i_charge_set; // value beeing written
|
||||
|
||||
// Set if the charging is enabled
|
||||
bool charging;
|
||||
bool charging_requested;
|
||||
|
||||
// Request flags for ADC measurements
|
||||
bool adc_trigger_requested;
|
||||
bool adc_readout_requested;
|
||||
|
||||
// Report callback used for asynchronous measurements
|
||||
npm1300_report_callback_t report_callback;
|
||||
void* report_callback_context;
|
||||
|
||||
} npm1300_driver_t;
|
||||
|
||||
// PMIC driver instance
|
||||
npm1300_driver_t g_npm1300_driver = {
|
||||
.initialized = false,
|
||||
};
|
||||
|
||||
// forward declarations
|
||||
static void npm1300_timer_callback(void* context);
|
||||
static void npm1300_i2c_callback(void* context, i2c_packet_t* packet);
|
||||
static void npm1300_fsm_continue(npm1300_driver_t* drv);
|
||||
|
||||
// Writes a value to the NPM1300 register
|
||||
//
|
||||
// This function is used only during driver initialization because
|
||||
// it's synchronous and blocks the execution.
|
||||
static bool npm1300_set_reg(i2c_bus_t* bus, uint16_t addr, uint8_t value) {
|
||||
i2c_op_t ops[] = {
|
||||
{
|
||||
.flags = I2C_FLAG_TX | I2C_FLAG_EMBED,
|
||||
.size = 3,
|
||||
.data = {addr >> 8, addr & 0xFF, value},
|
||||
},
|
||||
};
|
||||
|
||||
i2c_packet_t pkt = {
|
||||
.address = NPM1300_I2C_ADDRESS,
|
||||
.timeout = NPM1300_I2C_TIMEOUT,
|
||||
.op_count = ARRAY_LENGTH(ops),
|
||||
.ops = ops,
|
||||
};
|
||||
|
||||
if (I2C_STATUS_OK != i2c_bus_submit_and_wait(bus, &pkt)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Reads a value from the NPM1300 register
|
||||
//
|
||||
// This function is used only during driver initialization because
|
||||
// it's synchronous and blocks the execution.
|
||||
static bool npm1300_get_reg(i2c_bus_t* bus, uint16_t addr, uint8_t* data) {
|
||||
i2c_op_t ops[] = {
|
||||
{
|
||||
.flags = I2C_FLAG_TX | I2C_FLAG_EMBED,
|
||||
.size = 2,
|
||||
.data = {addr >> 8, addr & 0xFF},
|
||||
},
|
||||
{
|
||||
.flags = I2C_FLAG_RX,
|
||||
.size = sizeof(*data),
|
||||
.ptr = data,
|
||||
},
|
||||
};
|
||||
|
||||
i2c_packet_t pkt = {
|
||||
.address = NPM1300_I2C_ADDRESS,
|
||||
.timeout = NPM1300_I2C_TIMEOUT,
|
||||
.op_count = ARRAY_LENGTH(ops),
|
||||
.ops = ops,
|
||||
};
|
||||
|
||||
if (I2C_STATUS_OK != i2c_bus_submit_and_wait(bus, &pkt)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Initializes the NPM1300 driver to the default state
|
||||
static bool npm1300_initialize(i2c_bus_t* bus, uint16_t i_charge,
|
||||
uint16_t i_limit) {
|
||||
uint16_t bchg_iset = i_charge / 2; // 2mA steps
|
||||
uint16_t bchg_iset_discharge = (i_limit * 100) / 323; // 3.23mA steps
|
||||
uint16_t die_temp_stop = 360; // 110°C
|
||||
uint16_t die_temp_resume = 372; // 100°C
|
||||
uint16_t ntc_cold = 749; // 0°C
|
||||
uint16_t ntc_cool = 658; // 10°C
|
||||
uint16_t ntc_warm = 337; // 45°C
|
||||
uint16_t ntc_hot = 237; // 60°C
|
||||
|
||||
struct {
|
||||
uint16_t addr;
|
||||
uint8_t value;
|
||||
} table[] = {
|
||||
{NPM1300_SCRATCH0, 0x00},
|
||||
{NPM1300_SCRATCH1, 0x00},
|
||||
// SYSREG
|
||||
{NPM1300_VBUSINILIM0, NPM1300_VBUSINILIM0_500MA},
|
||||
{NPM1300_VBUSINILIMSTARTUP, NPM1300_VBUSINILIM0_500MA},
|
||||
{NPM1300_VBUSSUSPEND, 0x00},
|
||||
{NPM1300_TASKUPDATEILIMSW, NPM1300_TASKUPDATEILIM_SELVBUSILIM0},
|
||||
// LOADSW/LDO
|
||||
{NPM1300_LDSW1GPISEL, 0x00},
|
||||
{NPM1300_LDSW2GPISEL, 0x00},
|
||||
{NPM1300_TASKLDSW1CLR, 0x01},
|
||||
{NPM1300_TASKLDSW2CLR, 0x01},
|
||||
// BUCK regulators
|
||||
// TODO
|
||||
// ADC settings
|
||||
{NPM1300_ADCNTCRSEL, NPM1300_ADCNTCRSEL_10K},
|
||||
{NPM1300_ADCCONFIG, 0x00},
|
||||
{NPM1300_ADCIBATMEASEN, NPM1300_ADCIBATMEASEN_IBATMEASENABLE},
|
||||
// Charger settings
|
||||
{NPM1300_BCHGVTERM, NPM1300_BCHGVTERM_3V65},
|
||||
{NPM1300_BCHGVTERMR, NPM1300_BCHGVTERM_3V60},
|
||||
{NPM1300_BCHGVTRICKLESEL, NPM1300_BCHGVTRICKLESEL_2V5},
|
||||
{NPM1300_BCHGITERMSEL, NPM1300_BCHGITERMSEL_SEL10},
|
||||
{NPM1300_BCHGISETMSB, bchg_iset >> 1},
|
||||
{NPM1300_BCHGISETLSB, bchg_iset & 1},
|
||||
{NPM1300_BCHGISETDISCHARGEMSB, bchg_iset_discharge >> 1},
|
||||
{NPM1300_BCHGISETDISCHARGELSB, bchg_iset_discharge & 1},
|
||||
{NPM1300_BCHGDISABLECLR, NPM1300_BCHGDISABLECLR_USENTC},
|
||||
{NPM1300_BCHGDISABLECLR, NPM1300_BCHGDISABLECLR_ENABLERCHRG},
|
||||
{NPM1300_BCHGCONFIG, 0},
|
||||
// Disable charging
|
||||
{NPM1300_BCHGENABLECLR, NPM1300_BCHGENABLECLR_DISABLECHG},
|
||||
// NTC thresholds
|
||||
{NPM1300_NTCCOLD, ntc_cold >> 2},
|
||||
{NPM1300_NTCCOLDLSB, ntc_cold & 0x3},
|
||||
{NPM1300_NTCCOOL, ntc_cool >> 2},
|
||||
{NPM1300_NTCCOOLLSB, ntc_cool & 0x3},
|
||||
{NPM1300_NTCWARM, ntc_warm >> 2},
|
||||
{NPM1300_NTCWARMLSB, ntc_warm & 0x3},
|
||||
{NPM1300_NTCHOT, ntc_hot >> 2},
|
||||
{NPM1300_NTCHOTLSB, ntc_hot & 0x3},
|
||||
// Die tempererature thresholds
|
||||
{NPM1300_DIETEMPSTOP, die_temp_stop >> 2},
|
||||
{NPM1300_DIETEMPSTOPLSB, die_temp_stop & 0x03},
|
||||
{NPM1300_DIETEMPRESUME, die_temp_resume >> 2},
|
||||
{NPM1300_DIETEMPRESUMELSB, die_temp_resume & 0x03},
|
||||
// LEDS
|
||||
{NPM1300_LEDDRV0MODESEL, NPM1300_LEDDRVMODESEL_ERROR},
|
||||
{NPM1300_LEDDRV1MODESEL, NPM1300_LEDDRVMODESEL_CHARGING},
|
||||
{NPM1300_LEDDRV2MODESEL, NPM1300_LEDDRVMODESEL_NOTUSED},
|
||||
// GPIO
|
||||
{NPM1300_GPIOMODE0, NPM1300_GPIOMODE_GPIINPUT},
|
||||
{NPM1300_GPIOMODE1, NPM1300_GPIOMODE_GPIINPUT},
|
||||
{NPM1300_GPIOMODE2, NPM1300_GPIOMODE_GPIINPUT},
|
||||
{NPM1300_GPIOMODE3, NPM1300_GPIOMODE_GPIINPUT},
|
||||
{NPM1300_GPIOMODE4, NPM1300_GPIOMODE_GPIINPUT},
|
||||
// POF
|
||||
{NPM1300_POFCONFIG, 0x00},
|
||||
// TIMER
|
||||
{NPM1300_TIMERCLR, 0x01},
|
||||
// Ship and hibernate mode
|
||||
// {NPM1300_SHPHLDCONFIG, .. },
|
||||
// {NPM1300_TASKSHPHLDCFGSTROBE, 0x01},
|
||||
|
||||
// TODO automatic temp measurement during charging
|
||||
};
|
||||
|
||||
for (int i = 0; i < sizeof(table) / sizeof(table[0]); i++) {
|
||||
if (!npm1300_set_reg(bus, table[i].addr, table[i].value)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool npm1300_init(void) {
|
||||
npm1300_driver_t* drv = &g_npm1300_driver;
|
||||
|
||||
if (drv->initialized) {
|
||||
return true;
|
||||
}
|
||||
|
||||
memset(drv, 0, sizeof(npm1300_driver_t));
|
||||
|
||||
drv->i_charge = NPM1300_CHARGING_LIMIT_DEFAULT; // mA
|
||||
drv->i_limit = 500; // mA (268mA-1340mA)
|
||||
|
||||
drv->i_charge_set = drv->i_charge;
|
||||
drv->i_charge_requested = drv->i_charge;
|
||||
|
||||
drv->i2c_bus = i2c_bus_open(NPM1300_I2C_INSTANCE);
|
||||
if (drv->i2c_bus == NULL) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
drv->timer = systimer_create(npm1300_timer_callback, drv);
|
||||
if (drv->timer == NULL) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (!npm1300_get_reg(drv->i2c_bus, NPM1300_RSTCAUSE, &drv->restart_cause)) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (!npm1300_initialize(drv->i2c_bus, drv->i_charge, drv->i_limit)) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
drv->initialized = true;
|
||||
|
||||
return true;
|
||||
|
||||
cleanup:
|
||||
npm1300_deinit();
|
||||
return false;
|
||||
}
|
||||
|
||||
void npm1300_deinit(void) {
|
||||
npm1300_driver_t* drv = &g_npm1300_driver;
|
||||
|
||||
i2c_bus_close(drv->i2c_bus);
|
||||
systimer_delete(drv->timer);
|
||||
|
||||
memset(drv, 0, sizeof(npm1300_driver_t));
|
||||
}
|
||||
|
||||
bool npm1300_shipmode(void) {
|
||||
npm1300_driver_t* drv = &g_npm1300_driver;
|
||||
|
||||
if (!drv->initialized) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int npm1300_get_charging_limit(void) {
|
||||
npm1300_driver_t* drv = &g_npm1300_driver;
|
||||
|
||||
if (!drv->initialized) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return drv->i_charge_requested;
|
||||
}
|
||||
|
||||
bool npm1300_set_charging_limit(int i_charge) {
|
||||
npm1300_driver_t* drv = &g_npm1300_driver;
|
||||
|
||||
if (!drv->initialized) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (i_charge < NPM1300_CHARGING_LIMIT_MIN ||
|
||||
i_charge > NPM1300_CHARGING_LIMIT_MAX) {
|
||||
// The value is out of range
|
||||
return false;
|
||||
}
|
||||
|
||||
irq_key_t irq_key = irq_lock();
|
||||
drv->i_charge_requested = i_charge;
|
||||
npm1300_fsm_continue(drv);
|
||||
irq_unlock(irq_key);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool npm1300_set_charging(bool enable) {
|
||||
npm1300_driver_t* drv = &g_npm1300_driver;
|
||||
|
||||
if (!drv->initialized) {
|
||||
return false;
|
||||
}
|
||||
|
||||
irq_key_t irq_key = irq_lock();
|
||||
drv->charging_requested = enable;
|
||||
npm1300_fsm_continue(drv);
|
||||
irq_unlock(irq_key);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8_t npm1300_restart_cause(void) {
|
||||
npm1300_driver_t* drv = &g_npm1300_driver;
|
||||
|
||||
if (!drv->initialized) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return drv->restart_cause;
|
||||
}
|
||||
|
||||
bool npm1300_measure(npm1300_report_callback_t callback, void* context) {
|
||||
npm1300_driver_t* drv = &g_npm1300_driver;
|
||||
|
||||
if (!drv->initialized) {
|
||||
return false;
|
||||
}
|
||||
|
||||
irq_key_t irq_key = irq_lock();
|
||||
|
||||
if (drv->report_callback != NULL && callback != NULL) {
|
||||
// Cannot start another measurement while the previous one is in progress
|
||||
irq_unlock(irq_key);
|
||||
return false;
|
||||
}
|
||||
|
||||
drv->report_callback = callback;
|
||||
drv->report_callback_context = context;
|
||||
|
||||
if (drv->report_callback != NULL) {
|
||||
drv->adc_trigger_requested = true;
|
||||
npm1300_fsm_continue(drv);
|
||||
}
|
||||
|
||||
irq_unlock(irq_key);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Synchronous measurement context structure
|
||||
// (used internally within the `npm1300_measure_sync` function)
|
||||
typedef struct {
|
||||
// Set when the measurement is done
|
||||
volatile bool done;
|
||||
// Report structure where the measurement is stored
|
||||
npm1300_report_t* report;
|
||||
} npm1300_sync_measure_t;
|
||||
|
||||
// Callback for the synchronous measurement
|
||||
static void npm1300_sync_measure_callback(void* context,
|
||||
npm1300_report_t* report) {
|
||||
npm1300_sync_measure_t* ctx = (npm1300_sync_measure_t*)context;
|
||||
*ctx->report = *report;
|
||||
ctx->done = true;
|
||||
}
|
||||
|
||||
bool npm1300_measure_sync(npm1300_report_t* report) {
|
||||
npm1300_sync_measure_t measure = {
|
||||
.done = false,
|
||||
.report = report,
|
||||
};
|
||||
|
||||
// Start asynchronous measurement
|
||||
if (!npm1300_measure(npm1300_sync_measure_callback, &measure)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Wait for the measurement to finish
|
||||
while (!measure.done) {
|
||||
__WFI();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Prepares PMIC report from the last readout of the ADC values
|
||||
// stored in `drv->adc_regs`
|
||||
//
|
||||
// This function is called in the irq context.
|
||||
static void npm1300_calculate_report(npm1300_driver_t* drv,
|
||||
npm1300_report_t* report) {
|
||||
memset(report, 0, sizeof(npm1300_report_t));
|
||||
|
||||
npm1300_adc_regs_t* r = &drv->adc_regs;
|
||||
|
||||
// Gather measured values from the ADC registers
|
||||
|
||||
uint16_t vbat_adc =
|
||||
(r->adc_vbat_result_msb << 2) + (r->adc_gp0_result_lsbs & 0x03);
|
||||
|
||||
uint16_t ntc_adc =
|
||||
(r->adc_nt_result_msb << 2) + ((r->adc_gp0_result_lsbs >> 2) & 0x3);
|
||||
|
||||
uint16_t die_adc =
|
||||
(r->adc_temp_result_msb << 2) + ((r->adc_gp0_result_lsbs >> 4) & 0x3);
|
||||
|
||||
uint16_t vsys_adc =
|
||||
(r->adc_vsys_result_msb << 2) + ((r->adc_gp0_result_lsbs >> 6) & 0x03);
|
||||
|
||||
uint16_t ibat_adc =
|
||||
(r->adc_vbat2_result_msb << 2) + ((r->adc_gp1_result_lsbs >> 4) & 0x03);
|
||||
|
||||
// IBAT_MEAS_STATUS register isn't well documented in the NPM1300 datasheet.
|
||||
// The following is based partially on observation.
|
||||
//
|
||||
// 00100 - discharge
|
||||
// 01000 - usb powered, not charging
|
||||
// 01100 - charge trickle
|
||||
// 01110 - charge cool
|
||||
// 01111 - charge normal
|
||||
// 1XXXX - invalid value, start measure again
|
||||
|
||||
// bool ibat_invalid = (ibat_meas_status & 0x10) != 0;
|
||||
bool ibat_discharging = ((r->adc_ibat_meas_status >> 2) & 0x03) == 1;
|
||||
bool ibat_charging = ((r->adc_ibat_meas_status >> 2) & 0x03) == 3;
|
||||
|
||||
// Calculate the battery current based on the ADC reading and operating state.
|
||||
// If discharging, use the discharge current limit (i_limit).
|
||||
// If charging, use the charge current limit (i_charge).
|
||||
// See the NPM1300 datasheet for details.
|
||||
if (ibat_discharging) {
|
||||
report->ibat = ((int)ibat_adc * drv->i_limit) / 1250.0;
|
||||
} else if (ibat_charging) {
|
||||
report->ibat = -((int)ibat_adc * drv->i_charge) / 800.0;
|
||||
} else {
|
||||
report->ibat = 0;
|
||||
}
|
||||
|
||||
// Calculate the battery voltage (VBAT) from the ADC value.
|
||||
// VBAT is scaled by the voltage divider ratio and ADC resolution.
|
||||
report->vbat = (vbat_adc * 5.0) / 1023.0;
|
||||
|
||||
// Calculate the temperature from the NTC (thermistor).
|
||||
// Beta value for the thermistor is specified as 3380.
|
||||
// The equation is derived from the NPM1300 datasheet.
|
||||
float beta = 3380;
|
||||
report->ntc_temp =
|
||||
1 / (1 / 298.15 - (1 / beta) * logf(1024.0 / ntc_adc - 1)) - 298.15 +
|
||||
25.0;
|
||||
|
||||
// Calculate the die temperature from the die ADC reading.
|
||||
// The equation is derived from the NPM1300 datasheet.
|
||||
report->die_temp = 394.67 - 0.7926 * die_adc;
|
||||
|
||||
// Calculate the system voltage (VSYS) from the ADC value.
|
||||
// VSYS is scaled based on the system voltage divider ratio and ADC
|
||||
// resolution.
|
||||
report->vsys = (vsys_adc * 6.375) / 1023.0;
|
||||
|
||||
// Populate measurement and status flags from the raw data
|
||||
report->ibat_meas_status = r->adc_ibat_meas_status;
|
||||
}
|
||||
|
||||
// I2C operation for writing constant value to the npm1300 register
|
||||
#define NPM_WRITE_CONST(reg, value) \
|
||||
{ \
|
||||
.flags = I2C_FLAG_TX | I2C_FLAG_EMBED | I2C_FLAG_START, .size = 3, \
|
||||
.data = {(reg) >> 8, (reg) & 0xFF, (value)}, \
|
||||
}
|
||||
|
||||
// I2C operations for the value of specified uint8_t field
|
||||
// in `g_npm1300_driver` structure into npm1300 register
|
||||
#define NPM_WRITE_FIELD(reg, field) \
|
||||
{ \
|
||||
.flags = I2C_FLAG_TX | I2C_FLAG_EMBED | I2C_FLAG_START, \
|
||||
.size = 2, \
|
||||
.data = {(reg) >> 8, (reg) & 0xFF}, \
|
||||
}, \
|
||||
{ \
|
||||
.flags = I2C_FLAG_TX, .size = 1, .ptr = &g_npm1300_driver.field, \
|
||||
}
|
||||
|
||||
// I2C operations for reading npm1300 register into the specified
|
||||
// field in `g_npm1300_driver` structure
|
||||
#define NPM_READ_FIELD(reg, field) \
|
||||
{ \
|
||||
.flags = I2C_FLAG_TX | I2C_FLAG_EMBED | I2C_FLAG_START, \
|
||||
.size = 2, \
|
||||
.data = {(reg) >> 8, (reg) & 0xFF}, \
|
||||
}, \
|
||||
{ \
|
||||
.flags = I2C_FLAG_RX, .size = 1, .ptr = &g_npm1300_driver.field, \
|
||||
}
|
||||
|
||||
// I2C operations for enabling of the charging
|
||||
static const i2c_op_t npm1300_ops_charging_enable[] = {
|
||||
NPM_WRITE_CONST(NPM1300_BCHGENABLESET, NPM1300_BCHGENABLESET_ENABLECHG),
|
||||
};
|
||||
|
||||
// I2C operations for disabling of the charging
|
||||
static const i2c_op_t npm1300_ops_charging_disable[] = {
|
||||
NPM_WRITE_CONST(NPM1300_BCHGENABLECLR, NPM1300_BCHGENABLECLR_DISABLECHG),
|
||||
};
|
||||
|
||||
// I2C operations for setting of the charging limit from
|
||||
// `g_npm1300_driver.chlimit_regs` structure
|
||||
static const i2c_op_t npm1300_ops_charging_limit[] = {
|
||||
NPM_WRITE_FIELD(NPM1300_BCHGISETMSB, chlimit_regs.bchg_iset_msb),
|
||||
NPM_WRITE_FIELD(NPM1300_BCHGISETLSB, chlimit_regs.bchg_iset_lsb),
|
||||
};
|
||||
|
||||
// I2C operations for setting of the charging limit from
|
||||
// `g_npm1300_driver.chlimit_regs` structure together with
|
||||
// disabling and re-enabling of the charging
|
||||
static const i2c_op_t npm1300_ops_charging_limit_reenable[] = {
|
||||
NPM_WRITE_CONST(NPM1300_BCHGENABLECLR, NPM1300_BCHGENABLECLR_DISABLECHG),
|
||||
NPM_WRITE_FIELD(NPM1300_BCHGISETMSB, chlimit_regs.bchg_iset_msb),
|
||||
NPM_WRITE_FIELD(NPM1300_BCHGISETLSB, chlimit_regs.bchg_iset_lsb),
|
||||
NPM_WRITE_CONST(NPM1300_BCHGENABLESET, NPM1300_BCHGENABLESET_ENABLECHG),
|
||||
};
|
||||
|
||||
// I2C operations for triggering of the ADC measurements
|
||||
static const i2c_op_t npm1300_ops_adc_trigger[] = {
|
||||
NPM_WRITE_CONST(NPM1300_TASKVBATMEASURE, 1),
|
||||
NPM_WRITE_CONST(NPM1300_TASKVSYSMEASURE, 1),
|
||||
NPM_WRITE_CONST(NPM1300_TASKNTCMEASURE, 1),
|
||||
NPM_WRITE_CONST(NPM1300_TASKTEMPMEASURE, 1),
|
||||
};
|
||||
|
||||
// I2C operations for readout of the ADC values into the
|
||||
// `g_npm1300_driver.adc_regs` structure
|
||||
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_ADCVBATRESULTMSB, adc_regs.adc_vbat_result_msb),
|
||||
NPM_READ_FIELD(NPM1300_ADCNTCRESULTMSB, adc_regs.adc_nt_result_msb),
|
||||
NPM_READ_FIELD(NPM1300_ADCTEMPRESULTMSB, adc_regs.adc_temp_result_msb),
|
||||
NPM_READ_FIELD(NPM1300_ADCVSYSRESULTMSB, adc_regs.adc_vsys_result_msb),
|
||||
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_ADCIBATMEASSTATUS, adc_regs.adc_ibat_meas_status),
|
||||
};
|
||||
|
||||
#define npm1300_i2c_submit(drv, ops) \
|
||||
_npm1300_i2c_submit(drv, ops, ARRAY_LENGTH(ops))
|
||||
|
||||
// helper function for submitting I2C operations
|
||||
static void _npm1300_i2c_submit(npm1300_driver_t* drv, const i2c_op_t* ops,
|
||||
size_t op_count) {
|
||||
i2c_packet_t* pkt = &drv->pending_i2c_packet;
|
||||
|
||||
memset(pkt, 0, sizeof(i2c_packet_t));
|
||||
pkt->address = NPM1300_I2C_ADDRESS;
|
||||
pkt->context = drv;
|
||||
pkt->callback = npm1300_i2c_callback;
|
||||
pkt->timeout = NPM1300_I2C_TIMEOUT;
|
||||
pkt->ops = (i2c_op_t*)ops;
|
||||
pkt->op_count = op_count;
|
||||
|
||||
i2c_status_t status = i2c_bus_submit(drv->i2c_bus, pkt);
|
||||
|
||||
if (status != I2C_STATUS_OK) {
|
||||
// This should never happen
|
||||
error_shutdown("npm1300 I2C submit error");
|
||||
}
|
||||
}
|
||||
|
||||
// npm1300 driver timer callback invoked when `drv->timer` expires.
|
||||
//
|
||||
// This function is called in the irq context.
|
||||
static void npm1300_timer_callback(void* context) {
|
||||
npm1300_driver_t* drv = (npm1300_driver_t*)context;
|
||||
|
||||
switch (drv->state) {
|
||||
case NPM1300_STATE_ADC_WAIT:
|
||||
// The ADC conversion is done, read the values
|
||||
drv->adc_readout_requested = true;
|
||||
drv->state = NPM1300_STATE_IDLE;
|
||||
break;
|
||||
|
||||
default:
|
||||
// we should never get here
|
||||
drv->state = NPM1300_STATE_IDLE;
|
||||
break;
|
||||
}
|
||||
|
||||
npm1300_fsm_continue(drv);
|
||||
}
|
||||
|
||||
// npm1300 driver I2C completion callback invoked when
|
||||
// `drv->pending_i2c_packet` is completed
|
||||
//
|
||||
// This function is called in the irq context.
|
||||
static void npm1300_i2c_callback(void* context, i2c_packet_t* packet) {
|
||||
npm1300_driver_t* drv = (npm1300_driver_t*)context;
|
||||
|
||||
if (packet->status != I2C_STATUS_OK) {
|
||||
drv->i2c_errors++;
|
||||
|
||||
if (drv->i2c_errors > NPM1300_I2C_ERROR_LIMIT) {
|
||||
error_shutdown("npm1300 I2C error");
|
||||
}
|
||||
|
||||
drv->state = NPM1300_STATE_IDLE;
|
||||
|
||||
// I2C operation will be retried until it succeeds or
|
||||
// the error limit is reached
|
||||
npm1300_fsm_continue(drv);
|
||||
return;
|
||||
}
|
||||
|
||||
// If the I2C operation was successful, reset the error counter
|
||||
drv->i2c_errors = 0;
|
||||
|
||||
switch (drv->state) {
|
||||
case NPM1300_STATE_CHARGING_ENABLE:
|
||||
drv->charging = true;
|
||||
drv->state = NPM1300_STATE_IDLE;
|
||||
break;
|
||||
|
||||
case NPM1300_STATE_CHARGING_DISABLE:
|
||||
drv->charging = false;
|
||||
drv->state = NPM1300_STATE_IDLE;
|
||||
break;
|
||||
|
||||
case NPM1300_STATE_CHARGING_LIMIT:
|
||||
drv->i_charge = drv->i_charge_set;
|
||||
drv->state = NPM1300_STATE_IDLE;
|
||||
break;
|
||||
|
||||
case NPM1300_STATE_ADC_TRIGGER:
|
||||
drv->adc_trigger_requested = false;
|
||||
systimer_set(drv->timer, NPM1300_ADC_READOUT_DELAY);
|
||||
drv->state = NPM1300_STATE_ADC_WAIT;
|
||||
break;
|
||||
|
||||
case NPM1300_STATE_ADC_READOUT:
|
||||
drv->adc_readout_requested = false;
|
||||
|
||||
npm1300_report_t report;
|
||||
npm1300_calculate_report(drv, &report);
|
||||
|
||||
// Invoke report callback
|
||||
npm1300_report_callback_t report_callback = drv->report_callback;
|
||||
void* report_callback_context = drv->report_callback_context;
|
||||
|
||||
// Clear the report callback before invoking it
|
||||
// to allow the new measurement to be scheduled in the callback
|
||||
drv->report_callback = NULL;
|
||||
drv->report_callback_context = NULL;
|
||||
|
||||
if (report_callback != NULL) {
|
||||
report_callback(report_callback_context, &report);
|
||||
}
|
||||
|
||||
drv->state = NPM1300_STATE_IDLE;
|
||||
break;
|
||||
|
||||
default:
|
||||
// we should never get here
|
||||
drv->state = NPM1300_STATE_IDLE;
|
||||
break;
|
||||
}
|
||||
|
||||
npm1300_fsm_continue(drv);
|
||||
}
|
||||
|
||||
// npm1300 driver FSM continuation function that decides what to do next
|
||||
//
|
||||
// This function is called in the irq context or when interrupts are disabled.
|
||||
static void npm1300_fsm_continue(npm1300_driver_t* drv) {
|
||||
if (drv->state != NPM1300_STATE_IDLE) {
|
||||
return;
|
||||
}
|
||||
|
||||
// The order of the following conditions defines the priority
|
||||
|
||||
if (drv->i_charge != drv->i_charge_requested) {
|
||||
// Change charging limit
|
||||
uint16_t bchg_iset = drv->i_charge / 2; // 2mA steps
|
||||
drv->chlimit_regs.bchg_iset_msb = bchg_iset >> 1;
|
||||
drv->chlimit_regs.bchg_iset_lsb = bchg_iset & 1;
|
||||
drv->i_charge_set = drv->i_charge_requested;
|
||||
|
||||
if (drv->charging) {
|
||||
// When charging is enabled, we need to disable it first
|
||||
// and then re-enable it after changing the limit
|
||||
npm1300_i2c_submit(drv, npm1300_ops_charging_limit_reenable);
|
||||
} else {
|
||||
npm1300_i2c_submit(drv, npm1300_ops_charging_limit);
|
||||
}
|
||||
drv->state = NPM1300_STATE_CHARGING_LIMIT;
|
||||
} else if (drv->charging != drv->charging_requested) {
|
||||
// Change charging state
|
||||
if (drv->charging_requested) {
|
||||
npm1300_i2c_submit(drv, npm1300_ops_charging_enable);
|
||||
drv->state = NPM1300_STATE_CHARGING_ENABLE;
|
||||
} else {
|
||||
npm1300_i2c_submit(drv, npm1300_ops_charging_disable);
|
||||
drv->state = NPM1300_STATE_CHARGING_DISABLE;
|
||||
}
|
||||
} else if (drv->adc_readout_requested) {
|
||||
// Read ADC values
|
||||
npm1300_i2c_submit(drv, npm1300_ops_adc_readout);
|
||||
drv->state = NPM1300_STATE_ADC_READOUT;
|
||||
} else if (drv->adc_trigger_requested) {
|
||||
// Trigger ADC conversion
|
||||
npm1300_i2c_submit(drv, npm1300_ops_adc_trigger);
|
||||
drv->state = NPM1300_STATE_ADC_TRIGGER;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // KERNEL_MODE
|
101
core/embed/sys/powerctl/npm1300/npm1300.h
Normal file
101
core/embed/sys/powerctl/npm1300/npm1300.h
Normal file
@ -0,0 +1,101 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef TREZORHAL_NPM1300_H
|
||||
#define TREZORHAL_NPM1300_H
|
||||
|
||||
#include <trezor_types.h>
|
||||
|
||||
// Charging current limits
|
||||
// - range of np1300 is 32-800mA
|
||||
// - used battery limit is 180mA
|
||||
#define NPM1300_CHARGING_LIMIT_MIN 32 // mA
|
||||
#define NPM1300_CHARGING_LIMIT_MAX 800 // mA // !@# TODO: set to 180mA
|
||||
#define NPM1300_CHARGING_LIMIT_DEFAULT 180 // mA
|
||||
|
||||
typedef struct {
|
||||
// Battery voltage [V]
|
||||
float vbat;
|
||||
// System voltage [V]
|
||||
float vsys;
|
||||
// Battery current [mA]
|
||||
// - positive value means discharging
|
||||
// - negative value means charging
|
||||
float ibat;
|
||||
// NTC temperature [°C]
|
||||
float ntc_temp;
|
||||
// Die temperature [°C]
|
||||
float die_temp;
|
||||
// IBAT_MEAS_STATUS register value
|
||||
// (for debugging purposes, see the NPM1300 datasheet)
|
||||
uint8_t ibat_meas_status;
|
||||
|
||||
} npm1300_report_t;
|
||||
|
||||
typedef void (*npm1300_report_callback_t)(void* context,
|
||||
npm1300_report_t* report);
|
||||
|
||||
// Initializes NPM1300 PMIC driver
|
||||
bool npm1300_init(void);
|
||||
|
||||
// Deinitializes NPM1300 PMIC driver
|
||||
void npm1300_deinit(void);
|
||||
|
||||
// Gets the cause of the last restart
|
||||
uint8_t npm1300_restart_cause(void);
|
||||
|
||||
// Switches the device to the ship mode
|
||||
bool npm1300_shipmode(void);
|
||||
|
||||
// Starts the asynchronous measurement
|
||||
//
|
||||
// The measurement is started as soon as possible and finished in
|
||||
// hundreds of milliseconds. The result is reported using the callback.
|
||||
//
|
||||
// The function returns `false` if the measurement cannot be started
|
||||
// (e.g. because the previous measurement is still in progress or
|
||||
// the the driver is not initialized).
|
||||
bool npm1300_measure(npm1300_report_callback_t callback, void* context);
|
||||
|
||||
// Synchroneous version of the `pmic_measure` function.
|
||||
//
|
||||
// Use only for testing purposes, as it blocks the execution until
|
||||
// the measurement is done.
|
||||
//
|
||||
// Returns `true` if the measurement was successful and the report
|
||||
// is stored in the `report` structure.
|
||||
bool npm1300_measure_sync(npm1300_report_t* report);
|
||||
|
||||
// Enables or disables the charging.
|
||||
//
|
||||
// The function returns `false` if the operation cannot be performed.
|
||||
bool npm1300_set_charging(bool enable);
|
||||
|
||||
// Sets the charging current limit [mA].
|
||||
//
|
||||
// The current value must be in the range defined by the
|
||||
// `NPM1300_CHARGING_LIMIT_MIN` and `NPM1300_CHARGING_LIMIT_MAX` constants.
|
||||
//
|
||||
// The function returns `false` if the operation cannot be performed.
|
||||
bool npm1300_set_charging_limit(int i_charge);
|
||||
|
||||
// Gets the charging current limit [mA].
|
||||
int npm1300_get_charging_limit(void);
|
||||
|
||||
#endif // TREZORHAL_NPM1300_H
|
320
core/embed/sys/powerctl/npm1300/npm1300_defs.h
Normal file
320
core/embed/sys/powerctl/npm1300/npm1300_defs.h
Normal file
@ -0,0 +1,320 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef TREZORHAL_NPM1300_DEFS_H
|
||||
#define TREZORHAL_NPM1300_DEFS_H
|
||||
|
||||
// I2C address of the NPM1300 on the I2C bus.
|
||||
#define NPM1300_I2C_ADDRESS 0x6B
|
||||
|
||||
// Event and interrupt registers
|
||||
|
||||
#define NPM1300_TASKSWRESET 0x0001
|
||||
#define NPM1300_EVENTSADCSET 0x0002
|
||||
#define NPM1300_EVENTSADCCLR 0x0003
|
||||
#define NPM1300_INTENEVENTSADCSET 0x0004
|
||||
#define NPM1300_INTENEVENTSADCCLR 0x0005
|
||||
#define NPM1300_EVENTSBCHARGER0SET 0x0006
|
||||
#define NPM1300_EVENTSBCHARGER0CLR 0x0007
|
||||
#define NPM1300_INTENEVENTSBCHARGER0SET 0x0008
|
||||
#define NPM1300_INTENEVENTSBCHARGER0CLR 0x0009
|
||||
#define NPM1300_EVENTSBCHARGER1SET 0x000A
|
||||
#define NPM1300_EVENTSBCHARGER1CLR 0x000B
|
||||
#define NPM1300_INTENEVENTSBCHARGER1SET 0x000C
|
||||
#define NPM1300_INTENEVENTSBCHARGER1CLR 0x000D
|
||||
#define NPM1300_EVENTSBCHARGER2SET 0x000E
|
||||
#define NPM1300_EVENTSBCHARGER2CLR 0x000F
|
||||
#define NPM1300_INTENEVENTSBCHARGER2SET 0x0010
|
||||
#define NPM1300_INTENEVENTSBCHARGER2CLR 0x0011
|
||||
#define NPM1300_EVENTSSHPHLDSET 0x0012
|
||||
#define NPM1300_EVENTSSHPHLDCLR 0x0013
|
||||
#define NPM1300_INTENEVENTSSHPHLDSET 0x0014
|
||||
#define NPM1300_INTENEVENTSSHPHLDCLR 0x0015
|
||||
#define NPM1300_EVENTSVBUSIN0SET 0x0016
|
||||
#define NPM1300_EVENTSVBUSIN0CLR 0x0017
|
||||
#define NPM1300_INTENEVENTSVBUSIN0SET 0x0018
|
||||
#define NPM1300_INTENEVENTSVBUSIN0CLR 0x0019
|
||||
#define NPM1300_EVENTSVBUSIN1SET 0x001A
|
||||
#define NPM1300_EVENTSVBUSIN1CLR 0x001B
|
||||
#define NPM1300_INTENEVENTSVBUSIN1SET 0x001C
|
||||
#define NPM1300_INTENEVENTSVBUSIN1CLR 0x001D
|
||||
#define NPM1300_EVENTSGPIOSET 0x0022
|
||||
#define NPM1300_EVENTSGPIOCLR 0x0023
|
||||
#define NPM1300_INTENEVENTSGPIOSET 0x0024
|
||||
#define NPM1300_INTENEVENTSGPIOCLR 0x0025
|
||||
|
||||
// SYSREG registers
|
||||
|
||||
#define NPM1300_TASKUPDATEILIMSW 0x0200
|
||||
#define NPM1300_VBUSINILIM0 0x0201
|
||||
#define NPM1300_VBUSINILIMSTARTUP 0x0202
|
||||
#define NPM1300_VBUSSUSPEND 0x0203
|
||||
#define NPM1300_USBCDETECTSTATUS 0x0205
|
||||
#define NPM1300_VBUSINSTATUS 0x0207
|
||||
|
||||
// Charger registers
|
||||
|
||||
#define NPM1300_TASKRELEASEERR 0x0300
|
||||
#define NPM1300_TASKCLEARCHGERR 0x0301
|
||||
#define NPM1300_TASKCLEARSAFETYTIMER 0x0302
|
||||
#define NPM1300_BCHGENABLESET 0x0304
|
||||
#define NPM1300_BCHGENABLECLR 0x0305
|
||||
#define NPM1300_BCHGDISABLESET 0x0306
|
||||
#define NPM1300_BCHGDISABLECLR 0x0307
|
||||
#define NPM1300_BCHGISETMSB 0x0308
|
||||
#define NPM1300_BCHGISETLSB 0x0309
|
||||
#define NPM1300_BCHGISETDISCHARGEMSB 0x030A
|
||||
#define NPM1300_BCHGISETDISCHARGELSB 0x030B
|
||||
#define NPM1300_BCHGVTERM 0x030C
|
||||
#define NPM1300_BCHGVTERMR 0x030D
|
||||
#define NPM1300_BCHGVTRICKLESEL 0x030E
|
||||
#define NPM1300_BCHGITERMSEL 0x030F
|
||||
#define NPM1300_NTCCOLD 0x0310
|
||||
#define NPM1300_NTCCOLDLSB 0x0311
|
||||
#define NPM1300_NTCCOOL 0x0312
|
||||
#define NPM1300_NTCCOOLLSB 0x0313
|
||||
#define NPM1300_NTCWARM 0x0314
|
||||
#define NPM1300_NTCWARMLSB 0x0315
|
||||
#define NPM1300_NTCHOT 0x0316
|
||||
#define NPM1300_NTCHOTLSB 0x0317
|
||||
#define NPM1300_DIETEMPSTOP 0x0318
|
||||
#define NPM1300_DIETEMPSTOPLSB 0x0319
|
||||
#define NPM1300_DIETEMPRESUME 0x031A
|
||||
#define NPM1300_DIETEMPRESUMELSB 0x031B
|
||||
#define NPM1300_BCHGILIMSTATUS 0x032D
|
||||
#define NPM1300_NTCSTATUS 0x0332
|
||||
#define NPM1300_DIETEMPSTATUS 0x0333
|
||||
#define NPM1300_BCHGCHARGESTATUS 0x0334
|
||||
#define NPM1300_BCHGERRREASON 0x0336
|
||||
#define NPM1300_BCHGERRSENSOR 0x0337
|
||||
#define NPM1300_BCHGCONFIG 0x033C
|
||||
|
||||
// Buck regulator registers
|
||||
|
||||
#define NPM1300_BUCK1ENASET 0x0400
|
||||
#define NPM1300_BUCK1ENACLR 0x0401
|
||||
#define NPM1300_BUCK2ENASET 0x0402
|
||||
#define NPM1300_BUCK2ENACLR 0x0403
|
||||
#define NPM1300_BUCK1PWMSET 0x0404
|
||||
#define NPM1300_BUCK1PWMCLR 0x0405
|
||||
#define NPM1300_BUCK2PWMSET 0x0406
|
||||
#define NPM1300_BUCK2PWMCLR 0x0407
|
||||
#define NPM1300_BUCK1NORMVOUT 0x0408
|
||||
#define NPM1300_BUCK1RETVOUT 0x0409
|
||||
#define NPM1300_BUCK2NORMVOUT 0x040A
|
||||
#define NPM1300_BUCK2RETVOUT 0x040B
|
||||
#define NPM1300_BUCKENCTRL 0x040C
|
||||
#define NPM1300_BUCKVRETCTRL 0x040D
|
||||
#define NPM1300_BUCKPWMCTRL 0x040E
|
||||
#define NPM1300_BUCKSWCTRLSEL 0x040F
|
||||
#define NPM1300_BUCK1VOUTSTATUS 0x0410
|
||||
#define NPM1300_BUCK2VOUTSTATUS 0x0411
|
||||
#define NPM1300_BUCKCTRL0 0x0415
|
||||
#define NPM1300_BUCKSTATUS 0x0434
|
||||
|
||||
// System monitor registers
|
||||
|
||||
#define NPM1300_TASKVBATMEASURE 0x0500
|
||||
#define NPM1300_TASKNTCMEASURE 0x0501
|
||||
#define NPM1300_TASKTEMPMEASURE 0x0502
|
||||
#define NPM1300_TASKVSYSMEASURE 0x0503
|
||||
#define NPM1300_TASKIBATMEASURE 0x0506
|
||||
#define NPM1300_TASKVBUS7MEASURE 0x0507
|
||||
#define NPM1300_TASKDELAYEDVBATMEASURE 0x0508
|
||||
#define NPM1300_ADCCONFIG 0x0509
|
||||
#define NPM1300_ADCNTCRSEL 0x050A
|
||||
#define NPM1300_ADCAUTOTIMCONF 0x050B
|
||||
#define NPM1300_TASKAUTOTIMUPDATE 0x050C
|
||||
#define NPM1300_ADCDELTIMCONF 0x050D
|
||||
#define NPM1300_ADCIBATMEASSTATUS 0x0510
|
||||
#define NPM1300_ADCVBATRESULTMSB 0x0511
|
||||
#define NPM1300_ADCNTCRESULTMSB 0x0512
|
||||
#define NPM1300_ADCTEMPRESULTMSB 0x0513
|
||||
#define NPM1300_ADCVSYSRESULTMSB 0x0514
|
||||
#define NPM1300_ADCGP0RESULTLSBS 0x0515
|
||||
#define NPM1300_ADCVBAT0RESULTMSB 0x0516
|
||||
#define NPM1300_ADCVBAT1RESULTMSB 0x0517
|
||||
#define NPM1300_ADCVBAT2RESULTMSB 0x0518
|
||||
#define NPM1300_ADCVBAT3RESULTMSB 0x0519
|
||||
#define NPM1300_ADCGP1RESULTLSBS 0x051A
|
||||
#define NPM1300_ADCIBATMEASEN 0x0524
|
||||
|
||||
// GPIO registers
|
||||
|
||||
#define NPM1300_GPIOMODE0 0x0600
|
||||
#define NPM1300_GPIOMODE1 0x0601
|
||||
#define NPM1300_GPIOMODE2 0x0602
|
||||
#define NPM1300_GPIOMODE3 0x0603
|
||||
#define NPM1300_GPIOMODE4 0x0604
|
||||
#define NPM1300_GPIODRIVE0 0x0605
|
||||
#define NPM1300_GPIODRIVE1 0x0606
|
||||
#define NPM1300_GPIODRIVE2 0x0607
|
||||
#define NPM1300_GPIODRIVE3 0x0608
|
||||
#define NPM1300_GPIODRIVE4 0x0609
|
||||
#define NPM1300_GPIOPUEN0 0x060A
|
||||
#define NPM1300_GPIOPUEN1 0x060B
|
||||
#define NPM1300_GPIOPUEN2 0x060C
|
||||
#define NPM1300_GPIOPUEN3 0x060D
|
||||
#define NPM1300_GPIOPUEN4 0x060E
|
||||
#define NPM1300_GPIOPDEN0 0x060F
|
||||
#define NPM1300_GPIOPDEN1 0x0610
|
||||
#define NPM1300_GPIOPDEN2 0x0611
|
||||
#define NPM1300_GPIOPDEN3 0x0612
|
||||
#define NPM1300_GPIOPDEN4 0x0613
|
||||
#define NPM1300_GPIOOPENDRAIN0 0x0614
|
||||
#define NPM1300_GPIOOPENDRAIN1 0x0615
|
||||
#define NPM1300_GPIOOPENDRAIN2 0x0616
|
||||
#define NPM1300_GPIOOPENDRAIN3 0x0617
|
||||
#define NPM1300_GPIOOPENDRAIN4 0x0618
|
||||
#define NPM1300_GPIODEBOUNCE0 0x0619
|
||||
#define NPM1300_GPIODEBOUNCE1 0x061A
|
||||
#define NPM1300_GPIODEBOUNCE2 0x061B
|
||||
#define NPM1300_GPIODEBOUNCE3 0x061C
|
||||
#define NPM1300_GPIODEBOUNCE4 0x061D
|
||||
#define NPM1300_GPIOSTATUS 0x061E
|
||||
|
||||
// Timer registers
|
||||
|
||||
#define NPM1300_TIMERSET 0x0700
|
||||
#define NPM1300_TIMERCLR 0x0701
|
||||
#define NPM1300_TIMERTARGETSTROBE 0x0703
|
||||
#define NPM1300_WATCHDOGKICK 0x0704
|
||||
#define NPM1300_TIMERCONFIG 0x0705
|
||||
#define NPM1300_TIMERSTATUS 0x0706
|
||||
#define NPM1300_TIMERHIBYTE 0x0708
|
||||
#define NPM1300_TIMERMIDBYTE 0x0709
|
||||
#define NPM1300_TIMERLOBYTE 0x070A
|
||||
|
||||
// LOADSW/LDO registers
|
||||
|
||||
#define NPM1300_TASKLDSW1SET 0x0800
|
||||
#define NPM1300_TASKLDSW1CLR 0x0801
|
||||
#define NPM1300_TASKLDSW2SET 0x0802
|
||||
#define NPM1300_TASKLDSW2CLR 0x0803
|
||||
#define NPM1300_LDSWSTATUS 0x0804
|
||||
#define NPM1300_LDSW1GPISEL 0x0805
|
||||
#define NPM1300_LDSW2GPISEL 0x0806
|
||||
#define NPM1300_LDSWCONFIG 0x0807
|
||||
#define NPM1300_LDSW1LDOSEL 0x0808
|
||||
#define NPM1300_LDSW2LDOSEL 0x0809
|
||||
#define NPM1300_LDSW1VOUTSEL 0x080C
|
||||
#define NPM1300_LDSW2VOUTSEL 0x080D
|
||||
|
||||
// POF registers
|
||||
|
||||
#define NPM1300_POFCONFIG 0x0900
|
||||
|
||||
// LED registers
|
||||
|
||||
#define NPM1300_LEDDRV0MODESEL 0x0A00
|
||||
#define NPM1300_LEDDRV1MODESEL 0x0A01
|
||||
#define NPM1300_LEDDRV2MODESEL 0x0A02
|
||||
#define NPM1300_LEDDRV0SET 0x0A03
|
||||
#define NPM1300_LEDDRV0CLR 0x0A04
|
||||
#define NPM1300_LEDDRV1SET 0x0A05
|
||||
#define NPM1300_LEDDRV1CLR 0x0A06
|
||||
#define NPM1300_LEDDRV2SET 0x0A07
|
||||
#define NPM1300_LEDDRV2CLR 0x0A08
|
||||
|
||||
// Reset and hibernation mode registers
|
||||
|
||||
#define NPM1300_TASKENTERHIBERNATE 0x0B00
|
||||
#define NPM1300_TASKSHPHLDCFGSTROBE 0x0B01
|
||||
#define NPM1300_TASKENTERSHIPMODE 0x0B02
|
||||
#define NPM1300_TASKRESETCFG 0x0B03
|
||||
#define NPM1300_SHPHLDCONFIG 0x0B04
|
||||
#define NPM1300_SHPHLDSTATUS 0x0B05
|
||||
#define NPM1300_LPRESETCONFIG 0x0B06
|
||||
|
||||
// Reset and error registers
|
||||
|
||||
#define NPM1300_TASKCLRERRLOG 0x0E00
|
||||
#define NPM1300_SCRATCH0 0x0E01
|
||||
#define NPM1300_SCRATCH1 0x0E02
|
||||
#define NPM1300_RSTCAUSE 0x0E03
|
||||
#define NPM1300_CHARGERERRREASON 0x0E04
|
||||
#define NPM1300_CHARGERERRSENSOR 0x0E05
|
||||
|
||||
// ------------------------------------------------------
|
||||
|
||||
// TASKSWRESET
|
||||
#define NPM1300_TASKSWRESET_TRIGGER 0x01
|
||||
|
||||
// TASKUPDATEILIM
|
||||
#define NPM1300_TASKUPDATEILIM_SELVBUSILIM0 1
|
||||
|
||||
// VBUSINILIM0
|
||||
#define NPM1300_VBUSINILIM0_500MA 5 // Default
|
||||
|
||||
// BCHGENABLESET
|
||||
#define NPM1300_BCHGENABLESET_ENABLECHG 0x01
|
||||
|
||||
// BCHGENABLECLR
|
||||
#define NPM1300_BCHGENABLECLR_DISABLECHG 0x01
|
||||
|
||||
// BGCDISABLECLR
|
||||
#define NPM1300_BCHGDISABLECLR_ENABLERCHRG 0x01
|
||||
#define NPM1300_BCHGDISABLECLR_USENTC 0x02
|
||||
|
||||
// BCHGVTERM, BCHGVTERMR
|
||||
#define NPM1300_BCHGVTERM_3V60 2 // Default
|
||||
#define NPM1300_BCHGVTERM_3V65 3
|
||||
|
||||
// ADCCONFIG
|
||||
#define NPM1300_ADCCONFIG_AUTOENABLE 0x01
|
||||
#define NPM1300_ADCCONFIG_BURSTMODE 0x02
|
||||
|
||||
// ADCNTCRSEL
|
||||
#define NPM1300_ADCNTCRSEL_HI_Z 0
|
||||
#define NPM1300_ADCNTCRSEL_10K 1 // Default
|
||||
#define NPM1300_ADCNTCRSEL_47K 2
|
||||
#define NPM1300_ADCNTCRSEL_100K 3
|
||||
|
||||
// ADCIBATMEASEN
|
||||
#define NPM1300_ADCIBATMEASEN_IBATMEASENABLE 0x01
|
||||
|
||||
// BCHGVTRICKLESEL
|
||||
#define NPM1300_BCHGVTRICKLESEL_2V9 0 // Default
|
||||
#define NPM1300_BCHGVTRICKLESEL_2V5 1
|
||||
|
||||
// BCHGITERMSEL
|
||||
#define NPM1300_BCHGITERMSEL_SEL10 0 // Default
|
||||
#define NPM1300_BCHGITERMSEL_SEL20 1
|
||||
|
||||
// LEDDRVxMODESEL
|
||||
|
||||
#define NPM1300_LEDDRVMODESEL_ERROR 0x00
|
||||
#define NPM1300_LEDDRVMODESEL_CHARGING 0x01
|
||||
#define NPM1300_LEDDRVMODESEL_HOST 0x02
|
||||
#define NPM1300_LEDDRVMODESEL_NOTUSED 0x03
|
||||
|
||||
// GPIOMODEx
|
||||
|
||||
#define NPM1300_GPIOMODE_GPIINPUT 0x00
|
||||
#define NPM1300_GPIOMODE_GPILOGIC1 0x01
|
||||
#define NPM1300_GPIOMODE_GPILOGIC0 0x02
|
||||
#define NPM1300_GPIOMODE_GPIEVENTRISE 0x03
|
||||
#define NPM1300_GPIOMODE_GPIEVENTFALL 0x04
|
||||
#define NPM1300_GPIOMODE_GPOIRQ 0x05
|
||||
#define NPM1300_GPIOMODE_GPORESET 0x06
|
||||
#define NPM1300_GPIOMODE_GPOPLW 0x07
|
||||
#define NPM1300_GPIOMODE_GPOLOGIC1 0x08
|
||||
#define NPM1300_GPIOMODE_GPOLOGIC9 0x09
|
||||
|
||||
#endif // TREZORHAL_NPM1300_DEFS_H
|
@ -147,6 +147,8 @@ def configure(
|
||||
("USE_RESET_TO_BOOT", "1"),
|
||||
]
|
||||
|
||||
sources += ["embed/sys/powerctl/npm1300/npm1300.c"]
|
||||
|
||||
env.get("ENV")["LINKER_SCRIPT"] = linker_script
|
||||
|
||||
defs = env.get("CPPDEFINES_IMPLICIT")
|
||||
|
Loading…
Reference in New Issue
Block a user