suggestion: add power off command #6

Closed
opened 2026-10-04 23:05:50 +02:00 by adam · 2 comments
Owner

Hibernate is not that low power: the battery still runs down. I asked claude about this, here's what I got:

True power-off is possible — via the BQ25896 BATFET

The T-Deck Pro's "hibernate" today is ESP32 deep sleep (esp_deep_sleep_start()). The CPU halts, but the BQ25896 battery charger's internal BATFET (battery FET) stays ON, keeping the battery connected to VSYS. The
BQ25896 + BQ27220 fuel gauge together draw ~200–500 µA quiescent — enough to drain the battery over days.

The BQ25896 has a ship mode register bit designed exactly for this: writing 1 to bit 5 of REG09 (the BATFET_DIS bit) opens the FET, fully disconnecting the battery from VSYS. The ESP32 and all peripherals lose all
power immediately. The only way back is plugging in USB-C — the charger detects VBUS and re-enables the BATFET, booting the device normally. Exactly what you've seen in other firmwares.

What to change

In TDeckBoard.h, the current powerOff() only calls btStop() and returns. It needs to end with a BQ25896 ship-mode write:

  // BQ25896 REG09, bit 5 = BATFET_DIS                                                                                                                                                                                  
  // Disconnects battery from VSYS entirely. Wakes on USB-C plug-in.                                                                                                                                                    
  void powerOff() override {                                                                                                                                                                                            
      btStop();                                                                                                                                                                                                         
      // Read current REG09, set BATFET_DIS bit                                                                                                                                                                         
      Wire.beginTransmission(I2C_ADDR_BQ25896);                                                                                                                                                                         
      Wire.write(0x09);
      Wire.endTransmission(false);                                                                                                                                                                                      
      Wire.requestFrom((uint8_t)I2C_ADDR_BQ25896, (uint8_t)1);                                                                                                                                                          
      uint8_t reg09 = Wire.read();
      Wire.beginTransmission(I2C_ADDR_BQ25896);                                                                                                                                                                         
      Wire.write(0x09);
      Wire.write(reg09 | 0x20);   // BATFET_DIS = bit 5                                                                                                                                                                 
      Wire.endTransmission();                                                                                                                                                                                           
      // Power cuts here. This line is never reached.
  }                                                                                                                                                                                                                     

One thing to confirm from the schematic: whether the BQ25896's ILIM/PMON pin is wired to a user-accessible button. If it is, setting BATFET_RST_EN (REG09 bit 3) alongside BATFET_DIS would let a long button press
also wake the device, not just USB-C. On the T-Deck Pro it's likely not exposed that way, so USB-C-only wake is the safe default.

So maybe we could have both power-off and hibernate features, ideally?

Hibernate is not that low power: the battery still runs down. I asked claude about this, here's what I got: > True power-off is possible — via the BQ25896 BATFET > The T-Deck Pro's "hibernate" today is ESP32 deep sleep (esp_deep_sleep_start()). The CPU halts, but the BQ25896 battery charger's internal BATFET (battery FET) stays ON, keeping the battery connected to VSYS. The > BQ25896 + BQ27220 fuel gauge together draw ~200–500 µA quiescent — enough to drain the battery over days. > The BQ25896 has a ship mode register bit designed exactly for this: writing 1 to bit 5 of REG09 (the BATFET_DIS bit) opens the FET, fully disconnecting the battery from VSYS. The ESP32 and all peripherals lose all > power immediately. The only way back is plugging in USB-C — the charger detects VBUS and re-enables the BATFET, booting the device normally. Exactly what you've seen in other firmwares. > What to change > In TDeckBoard.h, the current powerOff() only calls btStop() and returns. It needs to end with a BQ25896 ship-mode write: ``` // BQ25896 REG09, bit 5 = BATFET_DIS // Disconnects battery from VSYS entirely. Wakes on USB-C plug-in. void powerOff() override { btStop(); // Read current REG09, set BATFET_DIS bit Wire.beginTransmission(I2C_ADDR_BQ25896); Wire.write(0x09); Wire.endTransmission(false); Wire.requestFrom((uint8_t)I2C_ADDR_BQ25896, (uint8_t)1); uint8_t reg09 = Wire.read(); Wire.beginTransmission(I2C_ADDR_BQ25896); Wire.write(0x09); Wire.write(reg09 | 0x20); // BATFET_DIS = bit 5 Wire.endTransmission(); // Power cuts here. This line is never reached. } ``` > One thing to confirm from the schematic: whether the BQ25896's ILIM/PMON pin is wired to a user-accessible button. If it is, setting BATFET_RST_EN (REG09 bit 3) alongside BATFET_DIS would let a long button press > also wake the device, not just USB-C. On the T-Deck Pro it's likely not exposed that way, so USB-C-only wake is the safe default. So maybe we could have both power-off and hibernate features, ideally? <!-- github-sync-id:4370142987 -->
adam closed this issue 2026-10-04 23:05:50 +02:00
Author
Owner
Check out https://github.com/pelgraine/Meck/releases/tag/v1.8 and https://github.com/pelgraine/Meck/commit/c2bfc3c98593d4cc238ca4f25c781bb05b80bbba for details. Thanks for the suggestion! <!-- github-comment-id:4366060967 -->
Author
Owner

That works, thanks.

That works, thanks. <!-- github-comment-id:4376973039 -->
Sign in to join this conversation.
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: adam/Meck#6