use thiserror_no_std::Error;
use crate::io::shared_i2c::SharedI2cBus;
const REG_PWR_STATUS: u8 = 0x00;
const REG_ADC_EN: u8 = 0x30; const REG_LDO_EN: u8 = 0x90;
const REG_DLDO1_VOL: u8 = 0x99;
const REG_VBAT_H: u8 = 0x34;
const DLDO1_VOL_MIN_MV: u16 = 500;
const DLDO1_VOL_STEP_MV: u16 = 100;
const DLDO1_EN_BIT: u8 = 0x80; const VBUS_PRESENT_BIT: u8 = 0x08; const VBAT_ADC_EN_BIT: u8 = 0x01;
#[derive(Debug, Error)]
pub enum Axp2101Error {
#[error("I2C error: {0:?}")]
I2cError(#[from] esp_hal::i2c::master::Error),
#[error("Voltage out of range")]
VoltageOutOfRange,
}
pub struct Axp2101Driver {
i2c: &'static SharedI2cBus,
address: u8,
}
impl Axp2101Driver {
pub fn new(i2c: &'static SharedI2cBus, address: u8) -> Self {
Self { i2c, address }
}
async fn read_reg(&mut self, reg: u8) -> Result<u8, Axp2101Error> {
let mut buf = [0u8; 1];
self.i2c
.lock()
.await
.write_read_async(self.address, &[reg], &mut buf)
.await?;
debug!("AXP2101 rd 0x{:02x} = 0x{:02x}", reg, buf[0]);
Ok(buf[0])
}
async fn write_reg(&mut self, reg: u8, value: u8) -> Result<(), Axp2101Error> {
debug!("AXP2101 wr 0x{:02x} = 0x{:02x}", reg, value);
self.i2c
.lock()
.await
.write_async(self.address, &[reg, value])
.await?;
Ok(())
}
pub async fn set_dldo1(&mut self, enabled: bool, mv: u16) -> Result<(), Axp2101Error> {
if mv < DLDO1_VOL_MIN_MV || mv > 3400 || (mv - DLDO1_VOL_MIN_MV) % DLDO1_VOL_STEP_MV != 0 {
return Err(Axp2101Error::VoltageOutOfRange);
}
let vol_val = ((mv - DLDO1_VOL_MIN_MV) / DLDO1_VOL_STEP_MV) as u8;
debug!(
"AXP2101 DLDO1 enabled={} {}mV (reg_val={})",
enabled, mv, vol_val
);
self.write_reg(REG_DLDO1_VOL, vol_val).await?;
let en_reg = self.read_reg(REG_LDO_EN).await?;
let en_val = if enabled {
en_reg | DLDO1_EN_BIT
} else {
en_reg & !DLDO1_EN_BIT
};
self.write_reg(REG_LDO_EN, en_val).await?;
Ok(())
}
pub async fn enable_battery_adc(&mut self) -> Result<(), Axp2101Error> {
let en = self.read_reg(REG_ADC_EN).await?;
self.write_reg(REG_ADC_EN, en | VBAT_ADC_EN_BIT).await?;
Ok(())
}
pub async fn battery_voltage_mv(&mut self) -> Result<u16, Axp2101Error> {
let hi = self.read_reg(REG_VBAT_H).await?;
let mut lo_buf = [0u8; 1];
self.i2c
.lock()
.await
.write_read_async(self.address, &[REG_VBAT_H + 1], &mut lo_buf)
.await?;
debug!("AXP2101 rd 0x{:02x} = 0x{:02x}", REG_VBAT_H + 1, lo_buf[0]);
let raw = ((hi as u16 & 0x3F) << 8) | lo_buf[0] as u16;
Ok(raw)
}
pub async fn vbus_present(&mut self) -> Result<bool, Axp2101Error> {
let status = self.read_reg(REG_PWR_STATUS).await?;
Ok(status & VBUS_PRESENT_BIT != 0)
}
}