Skip to main content

core_s3/
aw9523b.rs

1//! AW9523B I/O expander support used by CoreS3 board power/reset paths.
2
3use embedded_hal::i2c::I2c;
4
5use crate::devices;
6
7const REG_INPUT_P0: u8 = 0x00;
8const REG_INPUT_P1: u8 = 0x01;
9const REG_OUTPUT_P0: u8 = 0x02;
10const REG_OUTPUT_P1: u8 = 0x03;
11const REG_CONFIG_P0: u8 = 0x04;
12const REG_CONFIG_P1: u8 = 0x05;
13const REG_GLOBAL_CONTROL: u8 = 0x11;
14const REG_LED_MODE_P0: u8 = 0x12;
15const REG_LED_MODE_P1: u8 = 0x13;
16
17#[cfg_attr(feature = "defmt", derive(defmt::Format))]
18#[derive(Clone, Copy, Debug, Eq, PartialEq)]
19pub enum Port {
20    P0,
21    P1,
22}
23
24#[cfg_attr(feature = "defmt", derive(defmt::Format))]
25#[derive(Clone, Copy, Debug, Eq, PartialEq)]
26pub struct ExpanderPin {
27    pub port: Port,
28    pub index: u8,
29}
30
31impl ExpanderPin {
32    pub const LCD_RESET: Self = Self {
33        port: Port::P1,
34        index: 1,
35    };
36}
37
38pub struct Aw9523b<I2C> {
39    i2c: I2C,
40    address: u8,
41}
42
43impl<I2C> Aw9523b<I2C> {
44    pub const fn new(i2c: I2C) -> Self {
45        Self {
46            i2c,
47            address: devices::i2c::AW9523B_GPIO_EXPANDER,
48        }
49    }
50
51    pub fn release(self) -> I2C {
52        self.i2c
53    }
54}
55
56impl<I2C, Error> Aw9523b<I2C>
57where
58    I2C: I2c<Error = Error>,
59{
60    pub fn init_core_s3_defaults(&mut self) -> Result<(), Error> {
61        self.write_bit(REG_OUTPUT_P0, 0, true)?;
62        self.write_bit(REG_OUTPUT_P0, 2, true)?;
63        self.write_bit(REG_OUTPUT_P1, 0, true)?;
64        self.write_bit(REG_OUTPUT_P1, 1, true)?;
65        self.write_register(REG_CONFIG_P0, 0b0001_1000)?;
66        self.write_register(REG_CONFIG_P1, 0b0000_1100)?;
67        self.write_register(REG_GLOBAL_CONTROL, 0b0001_0000)?;
68        self.write_register(REG_LED_MODE_P0, 0xFF)?;
69        self.write_register(REG_LED_MODE_P1, 0xFF)
70    }
71
72    pub fn set_output(&mut self, pin: ExpanderPin, high: bool) -> Result<(), Error> {
73        let reg = output_register(pin.port);
74        self.write_bit(reg, pin.index, high)
75    }
76
77    pub fn read_input_port(&mut self, port: Port) -> Result<u8, Error> {
78        self.read_register(match port {
79            Port::P0 => REG_INPUT_P0,
80            Port::P1 => REG_INPUT_P1,
81        })
82    }
83
84    pub fn read_register(&mut self, register: u8) -> Result<u8, Error> {
85        let mut value = [0u8];
86        self.i2c.write_read(self.address, &[register], &mut value)?;
87        Ok(value[0])
88    }
89
90    pub fn write_register(&mut self, register: u8, value: u8) -> Result<(), Error> {
91        self.i2c.write(self.address, &[register, value])
92    }
93
94    pub fn write_bit(&mut self, register: u8, bit: u8, value: bool) -> Result<(), Error> {
95        let current = self.read_register(register)?;
96        let mask = 1u8 << bit;
97        let next = if value {
98            current | mask
99        } else {
100            current & !mask
101        };
102        self.write_register(register, next)
103    }
104}
105
106const fn output_register(port: Port) -> u8 {
107    match port {
108        Port::P0 => REG_OUTPUT_P0,
109        Port::P1 => REG_OUTPUT_P1,
110    }
111}