CDC Badge OS
Firmware for the CDC Badge v1.0 hardware security key
Loading...
Searching...
No Matches
BQ25895Power.cpp
Go to the documentation of this file.
1
8
10#include "cdc_hal/II2cBus.h"
11#include "cdc_hal/hw_config.h"
12#include "cdc_log.h"
13#include "esp_attr.h"
14#include "esp_timer.h"
15#include "driver/gpio.h"
16#include "freertos/FreeRTOS.h"
17#include "freertos/task.h"
18
19static const char* TAG = "BQ25895";
20
21namespace cdc::hal {
22
26static constexpr uint8_t BQ_REG_INPUT_CTRL = 0x00; // Input source control
27static constexpr uint8_t BQ_REG_ADC_CTRL = 0x02; // ADC control
28static constexpr uint8_t BQ_REG_CHG_CTRL = 0x03; // Charge control (SYS_MIN, OTG)
29static constexpr uint8_t BQ_REG_FAST_CHG = 0x04; // Fast charge current
30static constexpr uint8_t BQ_REG_TIMER = 0x07; // Charge timer
31static constexpr uint8_t BQ_REG_MISC = 0x09; // Misc (BATFET_DIS)
32static constexpr uint8_t BQ_REG_SYS_STATUS = 0x0B; // System status
33static constexpr uint8_t BQ_REG_FAULT = 0x0C; // Fault status
34static constexpr uint8_t BQ_REG_BATV = 0x0E; // Battery voltage ADC
35static constexpr uint8_t BQ_REG_SYSV = 0x0F; // System voltage ADC
36static constexpr uint8_t BQ_REG_TS = 0x10; // TS ADC
37static constexpr uint8_t BQ_REG_VBUS = 0x11; // VBUS voltage ADC
38static constexpr uint8_t BQ_REG_ICHG = 0x12; // Charge current ADC
39static constexpr uint8_t BQ_REG_VINDPM = 0x13; // VINDPM threshold
40static constexpr uint8_t BQ_REG_VENDOR = 0x14; // Vendor/Part info
41
45static constexpr uint8_t BQ_ICHG_STEP_MA = 64; // REG04[6:0] step size
46static constexpr uint16_t BQ_SYS_MIN_MV = 3300; // Minimum system voltage
47static constexpr uint16_t CHARGE_CURRENT_SLOW = 512; // Slow charge: 512mA
48static constexpr uint16_t CHARGE_CURRENT_FAST = 1000; // Fast charge: 1000mA
49static constexpr uint16_t CHARGE_CURRENT_MIN = 64;
50static constexpr uint16_t CHARGE_CURRENT_MAX = 1024; // Critical: max for 1200mAh LiPo
51
56static constexpr uint16_t BATTERY_MIN_MV = 2800; // Minimum usable voltage
57static constexpr uint16_t BATTERY_EMPTY_MV = 3200; // 0% calculation point
58static constexpr uint16_t BATTERY_FULL_MV = 4200; // 100% calculation point
59static constexpr uint16_t BATTERY_MAX_MV = 4250; // Maximum safe voltage
60static constexpr uint16_t BATTERY_USB_PASSTHRU_MIN_MV = 4000; // No-battery USB-passthrough range
61static constexpr uint16_t BATTERY_USB_PASSTHRU_MAX_MV = BATTERY_MAX_MV;
62
66static constexpr uint32_t kPowerButtonLongPressMs = 3000;
67
71static volatile bool charger_irq_pending = false;
72
78static void IRAM_ATTR charger_isr(void* arg) {
79 (void)arg;
81}
82
87public:
88 BQ25895Power() = default;
89
94 bool init() override;
95 bool start() override;
96 void stop() override;
97 core::ServiceState getState() const override { return state_; }
98 const char* getName() const override { return "power"; }
100
105 uint16_t getBatteryVoltage() const override;
106 uint8_t getBatteryPercent() const override;
107 bool isUsbConnected() const override;
108 PowerSource getPowerSource() const override;
109 ChargeStatus getChargeStatus() const override;
110 bool isBatteryLow() const override;
111 bool isBatteryCritical() const override;
112 bool isBatteryPresent() const override;
113 void setChargingEnabled(bool enabled) override;
114 void enterShipMode() override;
115 void setPreShipModeCallback(PreShipModeCallback cb) override { preShipModeCb_ = cb; }
116 void update() override;
117 void refresh() override;
118 void prepareForSleep() override;
119 void recoverFromSleep() override;
121
122private:
124 bool readReg(uint8_t reg, uint8_t* value) const;
125 bool writeReg(uint8_t reg, uint8_t value);
126 bool updateRegBits(uint8_t reg, uint8_t mask, uint8_t value, const char* label);
127
129 void readChargerStatus();
130 bool setChargeCurrentMa(uint16_t currentMa);
131
133
135 II2cBus* bus_ = nullptr;
136 I2cDeviceHandle device_ = nullptr;
137
139 void kickWatchdog();
140
142 uint16_t currentChargeMa_ = CHARGE_CURRENT_SLOW;
143 bool fastChargeEnabled_ = false;
144 uint32_t lastWdtKickMs_ = 0;
145
147 bool powerButtonHeld_ = false;
148 uint32_t powerButtonHoldStartMs_ = 0;
149
151 PreShipModeCallback preShipModeCb_ = nullptr;
152
154 mutable uint16_t cachedBatteryMv_ = 0;
155 mutable ChargeStatus cachedChargeStatus_ = ChargeStatus::NOT_CHARGING;
156 mutable bool cachedUsbConnected_ = false;
157 mutable bool cachedBatteryPresent_ = false;
158
160 ChargeStatus prevChargeStatus_ = ChargeStatus::NOT_CHARGING;
161 bool prevUsbConnected_ = false;
162 bool prevBatteryPresent_ = false;
163};
164
171bool BQ25895Power::readReg(uint8_t reg, uint8_t* value) const {
172 if (!device_ || !value) return false;
173 return bus_->readReg(device_, reg, value, 1) == ESP_OK;
174}
175
182bool BQ25895Power::writeReg(uint8_t reg, uint8_t value) {
183 if (!device_) return false;
184 return bus_->writeReg(device_, reg, &value, 1) == ESP_OK;
185}
186
195bool BQ25895Power::updateRegBits(uint8_t reg, uint8_t mask, uint8_t value, const char* label) {
196 uint8_t current = 0;
197 if (!readReg(reg, &current)) {
198 LOG_E(TAG, "Read failed: %s", label);
199 return false;
200 }
201
202 uint8_t newVal = (current & ~mask) | (value & mask);
203 if (newVal == current) {
204 LOG_D(TAG, "%s already set (0x%02X)", label, current);
205 return true;
206 }
207
208 if (!writeReg(reg, newVal)) {
209 LOG_E(TAG, "Write failed: %s", label);
210 return false;
211 }
212
213 LOG_D(TAG, "%s: 0x%02X -> 0x%02X", label, current, newVal);
214 return true;
215}
216
222 if (state_ != core::ServiceState::UNINITIALIZED) {
223 return state_ == core::ServiceState::INITIALIZED ||
225 }
226
227 LOG_I(TAG, "Initializing BQ25895 power management");
228
229 // Get I2C bus
230 bus_ = getI2cBus0();
231 if (!bus_ || bus_->getState() != core::ServiceState::INITIALIZED) {
232 LOG_E(TAG, "I2C bus not initialized");
234 return false;
235 }
236
237 // Add BQ25895 to I2C bus
238 if (bus_->addDevice(BQ25895_ADDR, &device_) != ESP_OK) {
239 LOG_E(TAG, "Failed to add BQ25895 to I2C0");
241 return false;
242 }
243
244 // Verify chip ID (REG14[5:3] should be 0b111 for BQ25895)
245 uint8_t vendor = 0;
246 if (!readReg(BQ_REG_VENDOR, &vendor)) {
247 LOG_E(TAG, "Failed to read vendor register");
249 return false;
250 }
251 uint8_t partNumber = (vendor >> 3) & 0x07;
252 if (partNumber != 7) {
253 LOG_E(TAG, "BQ25895 not detected (got part=%d)", partNumber);
255 return false;
256 }
257 LOG_I(TAG, "BQ25895 detected (REG14=0x%02X)", vendor);
258
259 // Apply safe defaults (charger has NO persistent storage!)
260
261 // 1) Disable ILIM pin (REG00[6]=0) - use internal limit
262 if (!updateRegBits(BQ_REG_INPUT_CTRL, (1 << 6), 0x00, "ILIM disable")) {
263 return false;
264 }
265
266 // 2) Set minimum system voltage to 3.3V (REG03[3:1])
267 // Formula: SYS_MIN = 3.0V + code*0.1V -> code = 3 for 3.3V
268 uint8_t sysMinCode = (BQ_SYS_MIN_MV - 3000) / 100;
269 if (!updateRegBits(BQ_REG_CHG_CTRL, 0x0E, (uint8_t)(sysMinCode << 1), "SYS_MIN=3.3V")) {
270 return false;
271 }
272
273 // 3) Disable OTG boost (REG03[5]=0)
274 if (!updateRegBits(BQ_REG_CHG_CTRL, (1 << 5), 0x00, "OTG disable")) {
275 return false;
276 }
277
278 // 4) Set initial charge current (default: slow charge 512mA)
279 if (!setChargeCurrentMa(CHARGE_CURRENT_SLOW)) {
280 return false;
281 }
282
283 // 5) Disable USB D+/D- detection (REG02[0]=0)
284 // This prevents the charger from pulling D+/D- during detection.
285 if (!updateRegBits(BQ_REG_ADC_CTRL, (1 << 0), 0x00, "DPDM disable")) {
286 return false;
287 }
288
289 // Configure charger IRQ (active-low, open-drain)
290 gpio_config_t io_conf = {};
291 io_conf.pin_bit_mask = (1ULL << CHG_IRQ_PIN);
292 io_conf.mode = GPIO_MODE_INPUT;
293 io_conf.pull_up_en = GPIO_PULLUP_ENABLE;
294 io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
295 io_conf.intr_type = GPIO_INTR_NEGEDGE;
296 gpio_config(&io_conf);
297
298 // Install ISR service (may already be installed by another driver)
299 esp_err_t err = gpio_install_isr_service(0);
300 if (err != ESP_OK && err != ESP_ERR_INVALID_STATE) {
301 LOG_E(TAG, "Failed to install ISR service: %s", esp_err_to_name(err));
303 return false;
304 }
305 gpio_isr_handler_add(CHG_IRQ_PIN, charger_isr, nullptr);
306
307 // Configure power/flash button as input (active-low), polled in update()
308 // for the ship-mode long-press.
309 gpio_config_t btn_conf = {};
310 btn_conf.pin_bit_mask = (1ULL << FLASH_BTN_PIN);
311 btn_conf.mode = GPIO_MODE_INPUT;
312 btn_conf.pull_up_en = GPIO_PULLUP_ENABLE;
313 btn_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
314 btn_conf.intr_type = GPIO_INTR_DISABLE;
315 gpio_config(&btn_conf);
316
317 // Read initial status (clears any stale IRQ flags)
318 readChargerStatus();
319
321 LOG_I(TAG, "BQ25895 initialized");
322 return true;
323}
324
330 if (state_ == core::ServiceState::INITIALIZED ||
331 state_ == core::ServiceState::STOPPED) {
333 return true;
334 }
335 return state_ == core::ServiceState::STARTED;
336}
337
342 if (state_ == core::ServiceState::STARTED) {
344 }
345}
346
350void BQ25895Power::readChargerStatus() {
351 uint8_t reg0b = 0, reg0c = 0;
352 uint8_t chrgStat = 0;
353
354 if (readReg(BQ_REG_SYS_STATUS, &reg0b)) {
355 chrgStat = (reg0b >> 3) & 0x03;
356 bool pgStat = (reg0b >> 2) & 0x01;
357 // REG0B[0] VSYS_STAT: 1 = chip in VSYSMIN regulation (battery missing or
358 // below VSYSMIN), 0 = battery is supplying VBAT >= VSYSMIN.
359 bool vsysMinRegulation = (reg0b & 0x01) != 0;
360
361 // Update cached status
362 cachedUsbConnected_ = pgStat;
363
364 switch (chrgStat) {
365 case 0: cachedChargeStatus_ = ChargeStatus::NOT_CHARGING; break;
366 case 1: cachedChargeStatus_ = ChargeStatus::PRE_CHARGE; break;
367 case 2: cachedChargeStatus_ = ChargeStatus::FAST_CHARGE; break;
368 case 3: cachedChargeStatus_ = ChargeStatus::CHARGE_DONE; break;
369 }
370
371 uint16_t vbat = getBatteryVoltage();
372 uint8_t ichgr = 0;
373 readReg(BQ_REG_ICHG, &ichgr);
374 // ICHGR = (REG12[6:0]) * 50mA
375
376 // Primary battery presence signal: VSYS_STAT bit.
377 // Active charging (pre/fast) also implies a battery (overrides VSYS_STAT
378 // during a charge cycle).
379 if (cachedChargeStatus_ == ChargeStatus::FAST_CHARGE ||
380 cachedChargeStatus_ == ChargeStatus::PRE_CHARGE) {
381 cachedBatteryPresent_ = true;
382 } else if (cachedUsbConnected_) {
383 // With USB powering the system the battery is present iff the chip
384 // is NOT in VSYSMIN regulation. CHARGE_DONE without battery keeps
385 // VSYS_STAT=1; CHARGE_DONE with full battery keeps VSYS_STAT=0.
386 cachedBatteryPresent_ = !vsysMinRegulation;
387 } else {
388 // On battery only (no USB): trust VBAT range and VSYS_STAT together.
389 cachedBatteryPresent_ = !vsysMinRegulation &&
390 (vbat >= BATTERY_MIN_MV && vbat <= BATTERY_MAX_MV);
391 }
392
393 // Correct "charge done" to "not charging" if no battery connected
394 if (cachedChargeStatus_ == ChargeStatus::CHARGE_DONE && !cachedBatteryPresent_) {
395 cachedChargeStatus_ = ChargeStatus::NOT_CHARGING;
396 }
397
398 // Only log on status change to avoid spam
399 bool statusChanged = (cachedChargeStatus_ != prevChargeStatus_) ||
400 (cachedUsbConnected_ != prevUsbConnected_) ||
401 (cachedBatteryPresent_ != prevBatteryPresent_);
402
403 if (statusChanged) {
404 const char* chrgText[] = {"Not charging", "Pre-charge", "Fast charging", "Charge done"};
405 uint16_t chargeMa = (ichgr & 0x7F) * 50;
406 if (!cachedBatteryPresent_ && cachedUsbConnected_) {
407 LOG_I(TAG, "USB connected, no battery (VBAT=%dmV, ICHG=%dmA)", vbat, chargeMa);
408 } else {
409 LOG_I(TAG, "Status: %s, USB=%d, VBAT=%dmV, ICHG=%dmA",
410 chrgText[static_cast<int>(cachedChargeStatus_)],
411 cachedUsbConnected_, vbat, chargeMa);
412 }
413
414 prevChargeStatus_ = cachedChargeStatus_;
415 prevUsbConnected_ = cachedUsbConnected_;
416 prevBatteryPresent_ = cachedBatteryPresent_;
417 }
418 }
419
420 if (readReg(BQ_REG_FAULT, &reg0c) && reg0c != 0x00) {
421 // Watchdog fault (0x80) when battery is full is expected behavior
422 if (reg0c == 0x80 && chrgStat == 3 && cachedBatteryPresent_) {
423 LOG_I(TAG, "Battery full");
424 } else if (reg0c == 0x80) {
425 // Watchdog expired after sleep - kick to resume charging
426 LOG_D(TAG, "WDT expired (post-sleep), kicking");
427 kickWatchdog();
428 } else {
429 // Real fault
430 LOG_W(TAG, "Fault: 0x%02X", reg0c);
431 cachedChargeStatus_ = ChargeStatus::FAULT;
432 }
433 }
434}
435
441bool BQ25895Power::setChargeCurrentMa(uint16_t currentMa) {
442 // Clamp to valid range
443 if (currentMa < CHARGE_CURRENT_MIN) currentMa = CHARGE_CURRENT_MIN;
444 if (currentMa > CHARGE_CURRENT_MAX) currentMa = CHARGE_CURRENT_MAX;
445
446 // Calculate register code: ICHG = code * 64mA
447 uint8_t code = (uint8_t)(currentMa / BQ_ICHG_STEP_MA);
448
449 // REG04[6:0] = charge current code
450 if (!updateRegBits(BQ_REG_FAST_CHG, 0x7F, code, "ICHG")) {
451 return false;
452 }
453
454 currentChargeMa_ = code * BQ_ICHG_STEP_MA;
455 LOG_I(TAG, "Charge current set to %dmA (code=%d)", currentChargeMa_, code);
456 return true;
457}
458
464 // Start ADC conversion if not running (REG02[7]=CONV_START)
465 uint8_t reg02 = 0;
466 if (readReg(BQ_REG_ADC_CTRL, &reg02) && !(reg02 & 0x80)) {
467 const_cast<BQ25895Power*>(this)->writeReg(BQ_REG_ADC_CTRL, reg02 | 0x80);
468 vTaskDelay(pdMS_TO_TICKS(10)); // Wait for ADC conversion
469 }
470
471 uint8_t batv = 0;
472 if (!readReg(BQ_REG_BATV, &batv)) {
473 return 0;
474 }
475
476 // Formula: VBAT = 2304mV + (BATV[6:0] * 20mV)
477 uint8_t code = batv & 0x7F;
478 cachedBatteryMv_ = 2304 + (code * 20);
479 return cachedBatteryMv_;
480}
481
487 uint16_t mv = getBatteryVoltage();
488 if (mv == 0) return 0;
489
490 // Linear approximation: BATTERY_EMPTY_MV=0%, BATTERY_FULL_MV=100%
491 if (mv <= BATTERY_EMPTY_MV) return 0;
492 if (mv >= BATTERY_FULL_MV) return 100;
493
494 return (uint8_t)(((uint32_t)(mv - BATTERY_EMPTY_MV) * 100) /
496}
497
503 // Use cached value (updated in update())
504 return cachedUsbConnected_;
505}
506
512 return cachedUsbConnected_ ? PowerSource::USB : PowerSource::BATTERY;
513}
514
520 return cachedChargeStatus_;
521}
522
528 return getBatteryPercent() < 20;
529}
530
536 return getBatteryPercent() < 5;
537}
538
544 return cachedBatteryPresent_;
545}
546
552 if (enabled) {
553 setChargeCurrentMa(fastChargeEnabled_ ? CHARGE_CURRENT_FAST : CHARGE_CURRENT_SLOW);
554 } else {
555 // Set minimum current to effectively disable
556 setChargeCurrentMa(CHARGE_CURRENT_MIN);
557 }
558 LOG_I(TAG, "Charging %s", enabled ? "enabled" : "disabled");
559}
560
565 // Show the ship-mode screen and let it fully render before cutting power.
566 if (preShipModeCb_) {
567 preShipModeCb_();
568 }
569
570 // Set BATFET_DIS (REG09[5]=1) to disconnect battery
571 // System will only run from USB after this.
572 // User must press PW ON / RESET to wake.
573 uint8_t current = 0;
574 if (!readReg(BQ_REG_MISC, &current)) {
575 LOG_E(TAG, "Failed to read REG09");
576 return;
577 }
578
579 if (!writeReg(BQ_REG_MISC, current | (1 << 5))) {
580 LOG_E(TAG, "Failed to set BATFET_DIS");
581 return;
582 }
583
584 LOG_I(TAG, "Entered shipping mode");
585}
586
590void BQ25895Power::kickWatchdog() {
591 // REG03[6] = 1 resets the I2C watchdog timer
592 // Silently kick without debug log (runs every 30s)
593 uint8_t current = 0;
594 if (readReg(BQ_REG_CHG_CTRL, &current)) {
595 writeReg(BQ_REG_CHG_CTRL, current | (1 << 6));
596 }
597}
598
603 // Proactive watchdog kick every 30s (WDT timeout is 40s)
604 uint32_t nowMs = (uint32_t)(esp_timer_get_time() / 1000);
605 if ((nowMs - lastWdtKickMs_) >= 30000) {
606 lastWdtKickMs_ = nowMs;
607 kickWatchdog();
608 }
609
610 // Power-button long-press enters ship mode (FLASH_BTN is active-low)
611 if (gpio_get_level(FLASH_BTN_PIN) == 0) {
612 if (!powerButtonHeld_) {
613 powerButtonHeld_ = true;
614 powerButtonHoldStartMs_ = nowMs;
615 } else if ((nowMs - powerButtonHoldStartMs_) >= kPowerButtonLongPressMs) {
616 powerButtonHeld_ = false;
617 LOG_W(TAG, "Power button long-press, entering ship mode");
619 }
620 } else {
621 powerButtonHeld_ = false;
622 }
623
624 // Handle charger IRQ
626 charger_irq_pending = false;
627 readChargerStatus();
628 }
629}
630
635 readChargerStatus();
636}
637
645 gpio_intr_disable(CHG_IRQ_PIN);
646}
647
655 gpio_intr_disable(CHG_IRQ_PIN);
656 charger_irq_pending = false;
657 readChargerStatus();
658 gpio_set_intr_type(CHG_IRQ_PIN, GPIO_INTR_NEGEDGE);
659 gpio_intr_enable(CHG_IRQ_PIN);
660}
661
666
674
675} // namespace cdc::hal
static const char * TAG
CDC Log: logging over TinyUSB CDC and UART.
#define LOG_W(tag, fmt,...)
Definition cdc_log.h:146
#define LOG_D(tag, fmt,...)
Definition cdc_log.h:148
#define LOG_I(tag, fmt,...)
Definition cdc_log.h:147
#define LOG_E(tag, fmt,...)
Definition cdc_log.h:145
PowerSource getPowerSource() const override
Returns current active power source.
ChargeStatus getChargeStatus() const override
Returns cached charge-state machine value.
void stop() override
Stops power manager service state.
uint8_t getBatteryPercent() const override
Estimates battery percentage from measured voltage.
bool isBatteryPresent() const override
Returns whether a battery is considered present.
void setPreShipModeCallback(PreShipModeCallback cb) override
bool init() override
Initializes charger hardware and applies safe boot defaults.
void refresh() override
Forces a synchronous re-read of charger status registers.
bool isBatteryLow() const override
Indicates low-battery threshold state.
void update() override
Periodic power-manager update handling watchdog and IRQ-driven refresh.
uint16_t getBatteryVoltage() const override
Returns measured battery voltage in millivolts.
bool isUsbConnected() const override
Returns cached USB power presence.
const char * getName() const override
bool isBatteryCritical() const override
Indicates critical-battery threshold state.
void setChargingEnabled(bool enabled) override
Enables or effectively disables charging current.
void enterShipMode() override
Requests battery ship mode via BATFET disconnect.
bool start() override
Starts power manager service state.
void recoverFromSleep() override
Restores charger IRQ handling and refreshes status after wakeup.
void prepareForSleep() override
Disables the charger IRQ before light sleep.
core::ServiceState getState() const override
virtual esp_err_t readReg(I2cDeviceHandle dev, uint8_t reg, uint8_t *data, size_t len)=0
virtual esp_err_t writeReg(I2cDeviceHandle dev, uint8_t reg, const uint8_t *data, size_t len)=0
#define CHG_IRQ_PIN
Definition hw_config.h:24
#define BQ25895_ADDR
Definition hw_config.h:22
#define FLASH_BTN_PIN
Definition hw_config.h:43
static constexpr uint8_t BQ_REG_VBUS
static constexpr uint8_t BQ_REG_ADC_CTRL
static constexpr uint32_t kPowerButtonLongPressMs
Hold duration on the power/flash button that triggers ship mode.
static BQ25895Power g_powerManager
Singleton power manager instance.
II2cBus * getI2cBus0()
Returns singleton instance of I2C bus 0.
Definition I2cBus.cpp:275
static constexpr uint16_t CHARGE_CURRENT_MIN
static constexpr uint8_t BQ_REG_SYSV
static constexpr uint16_t BATTERY_MIN_MV
Battery voltage thresholds for state estimation. LiPo battery characteristics (3.7V nominal,...
static constexpr uint8_t BQ_REG_FAULT
void * I2cDeviceHandle
Definition II2cBus.h:10
static constexpr uint8_t BQ_REG_SYS_STATUS
static constexpr uint16_t BATTERY_FULL_MV
static constexpr uint16_t BATTERY_USB_PASSTHRU_MIN_MV
static constexpr uint8_t BQ_ICHG_STEP_MA
Charge current and safety threshold constants.
static constexpr uint8_t BQ_REG_TS
static constexpr uint8_t BQ_REG_CHG_CTRL
static constexpr uint8_t BQ_REG_MISC
IPowerManager * getPowerManagerInstance()
Returns the singleton power manager instance.
static constexpr uint16_t BATTERY_MAX_MV
static constexpr uint16_t CHARGE_CURRENT_FAST
static constexpr uint16_t CHARGE_CURRENT_MAX
static constexpr uint8_t BQ_REG_INPUT_CTRL
BQ25895 register map constants.
static constexpr uint8_t BQ_REG_FAST_CHG
static constexpr uint16_t BATTERY_EMPTY_MV
static void charger_isr(void *arg)
GPIO interrupt handler for the charger IRQ pin.
static volatile bool charger_irq_pending
Charger IRQ flag set by ISR and consumed in update().
static constexpr uint16_t CHARGE_CURRENT_SLOW
static constexpr uint8_t BQ_REG_TIMER
static constexpr uint16_t BQ_SYS_MIN_MV
static constexpr uint8_t BQ_REG_ICHG
static constexpr uint8_t BQ_REG_VINDPM
static constexpr uint8_t BQ_REG_VENDOR
static constexpr uint16_t BATTERY_USB_PASSTHRU_MAX_MV
static constexpr uint8_t BQ_REG_BATV