Skip to content

Commit

Permalink
Add PCA9545 driver, use on Gimlet + Sidecar
Browse files Browse the repository at this point in the history
  • Loading branch information
mkeeter committed Jan 14, 2025
1 parent aa66dcd commit 98c0e37
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 10 deletions.
8 changes: 4 additions & 4 deletions app/gimlet/rev-b.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ scl.pin = 10
sda.pin = 11
af = 4
[[config.i2c.controllers.ports.B.muxes]]
driver = "pca9548"
driver = "pca9545"
address = 0x73

#
Expand All @@ -38,15 +38,15 @@ af = 4
# Shark fin muxes
#
[[config.i2c.controllers.ports.F.muxes]]
driver = "pca9548"
driver = "pca9545"
address = 0x70

[[config.i2c.controllers.ports.F.muxes]]
driver = "pca9548"
driver = "pca9545"
address = 0x71

[[config.i2c.controllers.ports.F.muxes]]
driver = "pca9548"
driver = "pca9545"
address = 0x72

[[config.i2c.devices]]
Expand Down
8 changes: 4 additions & 4 deletions app/gimlet/rev-d.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ sda.pin = 11
af = 4

[[config.i2c.controllers.ports.B.muxes]]
driver = "pca9548"
driver = "pca9545"
address = 0x73
nreset = { port = "E", pin = 15 } # SP_TO_I2C_SW_M2_A2_V3P3

Expand All @@ -44,17 +44,17 @@ af = 4
# Shark fin muxes
#
[[config.i2c.controllers.ports.F.muxes]]
driver = "pca9548"
driver = "pca9545"
address = 0x70
nreset = { port = "E", pin = 12 } # SP_TO_I2C_SW_CEMABCD_A2_V3P3

[[config.i2c.controllers.ports.F.muxes]]
driver = "pca9548"
driver = "pca9545"
address = 0x71
nreset = { port = "E", pin = 14 } # SP_TO_I2C_SW_CEMEFGH_A2_V3P3

[[config.i2c.controllers.ports.F.muxes]]
driver = "pca9548"
driver = "pca9545"
address = 0x72
nreset = { port = "E" , pin = 13 } # SP_TO_I2C_SW_CEMIJ_FRU_A2_V3P3

Expand Down
4 changes: 2 additions & 2 deletions app/sidecar/base.toml
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,7 @@ description = "Northeast Corridor 0"
scl = { gpio_port = "B", pin = 6 }
sda = { gpio_port = "B", pin = 7 }
af = 4
muxes = [ { driver = "pca9548", address = 0x70 } ]
muxes = [ { driver = "pca9545", address = 0x70 } ]

#
# I2C_NORTH_EAST1_SCL
Expand Down Expand Up @@ -428,7 +428,7 @@ description = "Northwest Corridor 1"
scl.pin = 7
sda.pin = 8
af = 4
muxes = [ { driver = "pca9548", address = 0x70 } ]
muxes = [ { driver = "pca9545", address = 0x70 } ]

#
# I2C4: South bend
Expand Down
1 change: 1 addition & 0 deletions drv/stm32xx-i2c/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ pub type Isr = device::i2c1::isr::R;

pub mod ltc4306;
pub mod max7358;
pub mod pca9545;
pub mod pca9548;

use ringbuf::*;
Expand Down
86 changes: 86 additions & 0 deletions drv/stm32xx-i2c/src/pca9545.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

//! Driver for the PCA9545 I2C mux
use crate::*;
use bitfield::bitfield;
use drv_i2c_api::{ResponseCode, Segment};

pub struct Pca9545;

bitfield! {
#[derive(Copy, Clone, Eq, PartialEq)]
pub struct ControlRegister(u8);
channel3_enabled, set_channel3_enabled: 3;
channel2_enabled, set_channel2_enabled: 2;
channel1_enabled, set_channel1_enabled: 1;
channel0_enabled, set_channel0_enabled: 0;
}

impl I2cMuxDriver for Pca9545 {
fn configure(
&self,
mux: &I2cMux<'_>,
_controller: &I2cController<'_>,
gpio: &sys_api::Sys,
_ctrl: &I2cControl,
) -> Result<(), drv_i2c_api::ResponseCode> {
mux.configure(gpio)
}

fn enable_segment(
&self,
mux: &I2cMux<'_>,
controller: &I2cController<'_>,
segment: Option<Segment>,
ctrl: &I2cControl,
) -> Result<(), ResponseCode> {
let mut reg = ControlRegister(0);

if let Some(segment) = segment {
match segment {
Segment::S1 => {
reg.set_channel0_enabled(true);
}
Segment::S2 => {
reg.set_channel1_enabled(true);
}
Segment::S3 => {
reg.set_channel2_enabled(true);
}
Segment::S4 => {
reg.set_channel3_enabled(true);
}
_ => {
return Err(ResponseCode::SegmentNotFound);
}
}
}

//
// This part has but one register -- any write is to the control
// register.
//
match controller.write_read(
mux.address,
1,
|_| Some(reg.0),
ReadLength::Fixed(0),
|_, _| Some(()),
ctrl,
) {
Err(code) => Err(mux.error_code(code)),
_ => Ok(()),
}
}

fn reset(
&self,
mux: &I2cMux<'_>,
gpio: &sys_api::Sys,
) -> Result<(), drv_i2c_api::ResponseCode> {
mux.reset(gpio)
}
}

0 comments on commit 98c0e37

Please sign in to comment.