Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add IMX3112 mux and APML devices to Grapefruit #1977

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions app/grapefruit/app.toml
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,11 @@ sda.pin = 11
scl.pin = 10
af = 4

[[config.i2c.controllers.ports.B.muxes]]
driver = "imx3112"
address = 0x70
# U6 on AMD Ruby schematic

[config.i2c.controllers.ports.F]
name = "pcie"
sda.pin = 0
Expand Down Expand Up @@ -528,6 +533,26 @@ sensors = { temperature = 1 }
description = "LM75 (H)"
refdes = "U104"

[[config.i2c.devices]]
bus = "apml"
address = 0x3c
device = "sbrmi"
name = "RMI"
mux = 1
segment = 1
description = "CPU via SB-RMI"

[[config.i2c.devices]]
bus = "apml"
address = 0x4c
device = "sbtsi"
name = "CPU"
mux = 1
segment = 1
description = "CPU temperature sensor"
sensors = { temperature = 1 }


################################################################################

[config.spi.spi2]
Expand Down
136 changes: 136 additions & 0 deletions drv/stm32xx-i2c/src/imx3112.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
// 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 IMX3112 I2C mux

use crate::*;
use drv_i2c_api::{ResponseCode, Segment};

use bitfield::bitfield;

#[allow(dead_code)]
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum Register {
DeviceTypeLo = 0x0,
DeviceTypeHi = 0x1,
DeviceRevision = 0x2,
VendorIdLo = 0x3,
VendorIdHi = 0x4,
LocalInterfaceCfg = 0xe,
PullupResistorConfig = 0xf,
DeviceCfg = 0x12,
ClearTempSensorAlarm = 0x13,
ClearEccError = 0x14,
TempSensorCfg = 0x1a,
InterruptCfg = 0x1b,
TempHiLimitCfgLo = 0x1c,
TempHiLimitCfgHi = 0x1d,
TempLoLimitCfgLo = 0x1e,
TempLoLimitCfgHi = 0x1f,
TempCritHiLimitCfgLo = 0x20,
TempCritHiLimitCfgHi = 0x21,
TempCritLoLimitCfgLo = 0x22,
TempCritLoLimitCfgHi = 0x23,
DeviceStatus = 0x30,
CurrentTemperatureLo = 0x31,
CurrentTemperatureHi = 0x32,
TemperatureStatus = 0x33,
ErrorStatus = 0x34,
MuxConfig = 0x40,
MuxSelect = 0x41,
}

bitfield! {
#[derive(Copy, Clone, Eq, PartialEq)]
pub struct LocalInterfaceConfigRegister(u8);
external_pullup, set_external_pullup: 5;
ldo_voltage, set_ldo_voltage: 4, 3, 2;
}

bitfield! {
#[derive(Copy, Clone, Eq, PartialEq)]
pub struct MuxSelectRegister(u8);
channel1_enabled, set_channel1_enabled: 7;
channel0_enabled, set_channel0_enabled: 6;
}

pub struct Imx3112;

fn write_reg_u8(
mux: &I2cMux<'_>,
controller: &I2cController<'_>,
reg: Register,
val: u8,
ctrl: &I2cControl,
) -> Result<(), ResponseCode> {
controller
.write_read(
mux.address,
2,
|pos| Some(if pos == 0 { reg as u8 } else { val }),
ReadLength::Fixed(0),
|_, _| Some(()),
ctrl,
)
.map_err(|e| mux.error_code(e))
}

impl I2cMuxDriver for Imx3112 {
fn configure(
&self,
mux: &I2cMux<'_>,
controller: &I2cController<'_>,
gpio: &sys_api::Sys,
ctrl: &I2cControl,
) -> Result<(), drv_i2c_api::ResponseCode> {
// Configure the mux to use external pull-ups
mux.configure(gpio)?;

let mut cfg = LocalInterfaceConfigRegister(0);
cfg.set_external_pullup(true);
write_reg_u8(
mux,
controller,
Register::LocalInterfaceCfg,
cfg.0,
ctrl,
)?;
let mut reg = MuxSelectRegister(0);
reg.set_channel0_enabled(true);
write_reg_u8(mux, controller, Register::MuxConfig, 0, ctrl)?;
write_reg_u8(mux, controller, Register::MuxSelect, reg.0, ctrl)?;
write_reg_u8(mux, controller, Register::MuxConfig, reg.0, ctrl)?;

Ok(())
}

fn enable_segment(
&self,
mux: &I2cMux<'_>,
controller: &I2cController<'_>,
segment: Option<Segment>,
ctrl: &I2cControl,
) -> Result<(), ResponseCode> {
let mut reg = MuxSelectRegister(0);
match segment {
Some(Segment::S1) => reg.set_channel0_enabled(true),
Some(Segment::S2) => reg.set_channel1_enabled(true),
None => (),
_ => return Err(ResponseCode::SegmentNotFound),
}
// Enable only our desired output
write_reg_u8(mux, controller, Register::MuxConfig, reg.0, ctrl)?;
// Select our desired output
write_reg_u8(mux, controller, Register::MuxSelect, reg.0, ctrl)?;
Ok(())
}

fn reset(
&self,
mux: &I2cMux<'_>,
gpio: &sys_api::Sys,
) -> Result<(), drv_i2c_api::ResponseCode> {
mux.reset(gpio)
}
}
1 change: 1 addition & 0 deletions drv/stm32xx-i2c/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ pub type RegisterBlock = device::i2c1::RegisterBlock;
))]
pub type Isr = device::i2c1::isr::R;

pub mod imx3112;
pub mod ltc4306;
pub mod max7358;
pub mod pca9545;
Expand Down
9 changes: 7 additions & 2 deletions task/thermal/src/bsp/grapefruit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use i2c_config::sensors;
// Constants!

// Air temperature sensors, which aren't used in the control loop
const NUM_TEMPERATURE_SENSORS: usize = 0;
const NUM_TEMPERATURE_SENSORS: usize = 1;

// Temperature inputs (I2C devices), which are used in the control loop.
pub const NUM_TEMPERATURE_INPUTS: usize = 1;
Expand Down Expand Up @@ -135,4 +135,9 @@ const INPUTS: [InputChannel; NUM_TEMPERATURE_INPUTS] = [InputChannel::new(
ChannelType::MustBePresent,
)];

const MISC_SENSORS: [TemperatureSensor; NUM_TEMPERATURE_SENSORS] = [];
const MISC_SENSORS: [TemperatureSensor; NUM_TEMPERATURE_SENSORS] =
[TemperatureSensor::new(
Device::CPU,
devices::sbtsi_cpu,
sensors::SBTSI_CPU_TEMPERATURE_SENSOR,
)];
Loading