mirror of
https://github.com/saymrwulf/xous-core.git
synced 2026-11-04 04:27:34 +00:00
add axp2101 driver skeleton
This commit is contained in:
parent
12cfb40546
commit
be56097fe4
1 changed files with 308 additions and 0 deletions
308
libs/cramium-hal/src/axp2101.rs
Normal file
308
libs/cramium-hal/src/axp2101.rs
Normal file
|
|
@ -0,0 +1,308 @@
|
|||
use crate::udma::i2c;
|
||||
|
||||
pub const AXP2101_DEV: u8 = 0x34;
|
||||
|
||||
const REG_DCDC_ENA: usize = 0x80;
|
||||
const REG_DCDC1_V: usize = 0x82;
|
||||
const REG_DCDC2_V: usize = 0x83;
|
||||
const REG_DCDC3_V: usize = 0x84;
|
||||
const REG_DCDC4_V: usize = 0x85;
|
||||
#[allow(dead_code)]
|
||||
const REG_DCDC5_V: usize = 0x86;
|
||||
const REG_LDO1_ENA: usize = 0x90;
|
||||
const REG_LDO2_ENA: usize = 0x91;
|
||||
#[allow(dead_code)]
|
||||
const REG_ALDO1_V: usize = 0x92;
|
||||
#[allow(dead_code)]
|
||||
const REG_ALDO2_V: usize = 0x93;
|
||||
#[allow(dead_code)]
|
||||
const REG_ALDO3_V: usize = 0x94;
|
||||
#[allow(dead_code)]
|
||||
const REG_ALDO4_V: usize = 0x95;
|
||||
#[allow(dead_code)]
|
||||
const REG_BLDO1_V: usize = 0x96;
|
||||
#[allow(dead_code)]
|
||||
const REG_BLDO2_V: usize = 0x97;
|
||||
#[allow(dead_code)]
|
||||
const REG_CPUSLDO_V: usize = 0x98;
|
||||
#[allow(dead_code)]
|
||||
const REG_DLDO1_V: usize = 0x99;
|
||||
#[allow(dead_code)]
|
||||
const REG_DLDO2_V: usize = 0x9A;
|
||||
|
||||
#[repr(u8)]
|
||||
#[derive(PartialEq, Eq, Clone, Copy)]
|
||||
pub enum WhichLdo {
|
||||
Aldo1 = 0,
|
||||
Aldo2 = 1,
|
||||
Aldo3 = 2,
|
||||
Aldo4 = 3,
|
||||
Bldo1 = 4,
|
||||
Bldo2 = 5,
|
||||
Cpusldo1 = 6,
|
||||
Dldo1 = 7,
|
||||
Dldo2 = 8,
|
||||
}
|
||||
impl Into<f32> for WhichLdo {
|
||||
fn into(self) -> f32 {
|
||||
match self {
|
||||
Self::Cpusldo1 | Self::Dldo1 => 0.050,
|
||||
_ => 0.100,
|
||||
}
|
||||
}
|
||||
}
|
||||
impl From<usize> for WhichLdo {
|
||||
fn from(value: usize) -> Self {
|
||||
match value {
|
||||
0 => Self::Aldo1,
|
||||
1 => Self::Aldo2,
|
||||
2 => Self::Aldo3,
|
||||
3 => Self::Aldo4,
|
||||
4 => Self::Bldo1,
|
||||
5 => Self::Bldo2,
|
||||
6 => Self::Cpusldo1,
|
||||
7 => Self::Dldo1,
|
||||
8 => Self::Dldo2,
|
||||
_ => panic!("bad WhichLdo"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(usize)]
|
||||
#[derive(PartialEq, Eq, Copy, Clone)]
|
||||
pub enum WhichDcDc {
|
||||
Dcdc1 = 0,
|
||||
Dcdc2 = 1,
|
||||
Dcdc3 = 2,
|
||||
Dcdc4 = 3,
|
||||
Dcdc5 = 4,
|
||||
}
|
||||
impl From<usize> for WhichDcDc {
|
||||
fn from(value: usize) -> Self {
|
||||
match value {
|
||||
0 => Self::Dcdc1,
|
||||
1 => Self::Dcdc2,
|
||||
2 => Self::Dcdc3,
|
||||
3 => Self::Dcdc4,
|
||||
4 => Self::Dcdc5,
|
||||
_ => panic!("bad WhichDcDc"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Axp2101 {
|
||||
pub dcdc_ena: [bool; 4],
|
||||
pub fast_ramp: bool,
|
||||
pub force_ccm: bool,
|
||||
pub dcdc_v_dvm: [(f32, bool); 4],
|
||||
pub ldo_ena: [bool; 9],
|
||||
pub ldo_v: [f32; 9],
|
||||
}
|
||||
|
||||
impl Axp2101 {
|
||||
pub fn new(i2c: &mut dyn i2c::I2cApi) -> Axp2101 {
|
||||
let mut s = Axp2101 {
|
||||
dcdc_ena: [false; 4],
|
||||
fast_ramp: false,
|
||||
force_ccm: false,
|
||||
dcdc_v_dvm: [(0.0, false); 4],
|
||||
ldo_ena: [false; 9],
|
||||
ldo_v: [0.0; 9],
|
||||
};
|
||||
s.update(i2c);
|
||||
s
|
||||
}
|
||||
|
||||
pub fn update(&mut self, i2c: &mut dyn i2c::I2cApi) {
|
||||
let mut buf = [0u8; 0xb0];
|
||||
i2c.i2c_read(AXP2101_DEV, 0x0, &mut buf, false).expect("couldn't access AXP2101");
|
||||
|
||||
(self.dcdc_ena, self.fast_ramp, self.force_ccm) = parse_dcdc_ena(buf[REG_DCDC_ENA]);
|
||||
self.dcdc_v_dvm = [
|
||||
parse_dcdc(buf[REG_DCDC1_V], WhichDcDc::Dcdc1),
|
||||
parse_dcdc(buf[REG_DCDC2_V], WhichDcDc::Dcdc2),
|
||||
parse_dcdc(buf[REG_DCDC3_V], WhichDcDc::Dcdc3),
|
||||
parse_dcdc(buf[REG_DCDC4_V], WhichDcDc::Dcdc4),
|
||||
];
|
||||
for (i, ena) in self.ldo_ena.iter_mut().enumerate() {
|
||||
if i < 8 {
|
||||
*ena = (buf[REG_LDO1_ENA] >> i) & 1 != 0;
|
||||
} else {
|
||||
*ena = (buf[REG_LDO2_ENA] & 1) != 0;
|
||||
}
|
||||
}
|
||||
for (i, v) in self.ldo_v.iter_mut().enumerate() {
|
||||
*v = parse_ldo(buf[REG_ALDO1_V + i], WhichLdo::from(i));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_dcdc(
|
||||
&mut self,
|
||||
i2c: &mut dyn i2c::I2cApi,
|
||||
setting: Option<(f32, bool)>,
|
||||
which: WhichDcDc,
|
||||
) -> Result<(), xous::Error> {
|
||||
if let Some((voltage, dvm)) = setting {
|
||||
match encode_dcdc(voltage, dvm, which) {
|
||||
Some(code) => {
|
||||
self.dcdc_v_dvm[which as usize] = (voltage, dvm);
|
||||
self.dcdc_ena[which as usize] = true;
|
||||
i2c.i2c_write(AXP2101_DEV, (REG_DCDC1_V + which as usize) as u8, &[code]).map(|_| ())?;
|
||||
i2c.i2c_write(AXP2101_DEV, REG_DCDC_ENA as u8, &[self.encode_dcdc_ena()]).map(|_| ())
|
||||
}
|
||||
None => Err(xous::Error::InvalidLimit),
|
||||
}
|
||||
} else {
|
||||
self.dcdc_ena[which as usize] = false;
|
||||
i2c.i2c_write(AXP2101_DEV, REG_DCDC_ENA as u8, &[self.encode_dcdc_ena()]).map(|_| ())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_ldo(
|
||||
&mut self,
|
||||
i2c: &mut dyn i2c::I2cApi,
|
||||
setting: Option<f32>,
|
||||
which: WhichLdo,
|
||||
) -> Result<(), xous::Error> {
|
||||
if let Some(voltage) = setting {
|
||||
match encode_ldo(voltage, which) {
|
||||
Some(code) => {
|
||||
self.ldo_v[which as usize] = voltage;
|
||||
self.ldo_ena[which as usize] = true;
|
||||
let ctl = self.encode_ldo_ena();
|
||||
i2c.i2c_write(AXP2101_DEV, (REG_ALDO1_V + which as usize) as u8, &[code]).map(|_| ())?;
|
||||
i2c.i2c_write(AXP2101_DEV, REG_LDO1_ENA as u8, &ctl).map(|_| ())
|
||||
}
|
||||
None => Err(xous::Error::InvalidLimit),
|
||||
}
|
||||
} else {
|
||||
self.ldo_ena[which as usize] = false;
|
||||
let ctl = self.encode_ldo_ena();
|
||||
i2c.i2c_write(AXP2101_DEV, REG_LDO1_ENA as u8, &ctl).map(|_| ())
|
||||
}
|
||||
}
|
||||
|
||||
fn encode_dcdc_ena(&self) -> u8 {
|
||||
let mut code = 0;
|
||||
for (i, &ena) in self.dcdc_ena.iter().enumerate() {
|
||||
if ena {
|
||||
code |= 1 << i;
|
||||
}
|
||||
}
|
||||
if self.fast_ramp {
|
||||
code |= 1 << 5;
|
||||
}
|
||||
if self.force_ccm {
|
||||
code |= 1 << 6;
|
||||
}
|
||||
code
|
||||
}
|
||||
|
||||
fn encode_ldo_ena(&self) -> [u8; 2] {
|
||||
let mut ctl = [0u8; 2];
|
||||
for (i, &ena) in self.ldo_ena.iter().enumerate() {
|
||||
if i < 8 {
|
||||
if ena {
|
||||
ctl[0] |= 1 << i;
|
||||
}
|
||||
} else {
|
||||
if ena {
|
||||
ctl[1] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
ctl
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_dcdc_ena(d: u8) -> ([bool; 4], bool, bool) {
|
||||
let mut enable = [false; 4];
|
||||
let mut fast_ramp = false;
|
||||
let mut force_ccm = false;
|
||||
|
||||
for (i, ena) in enable.iter_mut().enumerate() {
|
||||
if ((d >> i) & 1) == 1 {
|
||||
*ena = true;
|
||||
}
|
||||
}
|
||||
if ((d >> 5) & 1) == 1 {
|
||||
fast_ramp = true;
|
||||
}
|
||||
if ((d >> 6) & 1) == 1 {
|
||||
force_ccm = true;
|
||||
}
|
||||
(enable, fast_ramp, force_ccm)
|
||||
}
|
||||
|
||||
pub fn encode_dcdc(v: f32, dvm: bool, which: WhichDcDc) -> Option<u8> {
|
||||
match which {
|
||||
WhichDcDc::Dcdc1 => {
|
||||
if v < 1.5 || v > 3.4 {
|
||||
None
|
||||
} else {
|
||||
let code = (v - 1.5) / 0.100;
|
||||
return Some(code as u8 | if dvm { 0x80 } else { 0x0 });
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
if which == WhichDcDc::Dcdc2 || which == WhichDcDc::Dcdc3 {
|
||||
if v < 0.5 || v > 1.54 {
|
||||
return None;
|
||||
}
|
||||
} else if which == WhichDcDc::Dcdc4 {
|
||||
if v < 0.5 || v > 1.84 {
|
||||
return None;
|
||||
}
|
||||
} else {
|
||||
// we haven't coded the DCDC5 path yet
|
||||
return None;
|
||||
}
|
||||
if v < 1.22 {
|
||||
let code = (v - 0.5) / 0.010;
|
||||
Some(code as u8)
|
||||
} else {
|
||||
// high side already bounds checked above
|
||||
let code = (v - 1.22) / 0.020;
|
||||
Some(code as u8 + 70)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_dcdc(d: u8, which: WhichDcDc) -> (f32, bool) {
|
||||
match which {
|
||||
WhichDcDc::Dcdc1 => {
|
||||
let step = 0.10f32;
|
||||
let dvm = (d & 0x80) != 0;
|
||||
let voltage = ((d & 0x3F) as f32) * step + 1.5;
|
||||
(voltage, dvm)
|
||||
}
|
||||
_ => {
|
||||
let step = if (d & 0x7F) <= 71 { 0.010f32 } else { 0.020f32 };
|
||||
let dvm = (d & 0x80) != 0;
|
||||
let voltage = ((d & 0x7F) as f32) * step + 0.5;
|
||||
(voltage, dvm)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_ldo(code: u8, ldo: WhichLdo) -> f32 {
|
||||
let step: f32 = ldo.into();
|
||||
0.5f32 + (code as f32) * step
|
||||
}
|
||||
|
||||
// returns a tuple of (code, register)
|
||||
pub fn encode_ldo(v: f32, ldo: WhichLdo) -> Option<u8> {
|
||||
let step: f32 = ldo.into();
|
||||
if step == 0.10 {
|
||||
if v < 0.5 || v > 3.5 {
|
||||
return None;
|
||||
}
|
||||
} else if step == 0.050 {
|
||||
if v < 0.5 || v > 1.4 {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
Some(((v - 0.5) / step) as u8)
|
||||
}
|
||||
Loading…
Reference in a new issue