forked from M-Labs/artiq
firmware: I2C I/O expander support
This commit is contained in:
parent
ef4e5bc69b
commit
4982fde898
101
artiq/firmware/libboard_misoc/io_expander.rs
Normal file
101
artiq/firmware/libboard_misoc/io_expander.rs
Normal file
@ -0,0 +1,101 @@
|
||||
use i2c;
|
||||
|
||||
pub struct IoExpander {
|
||||
busno: u8,
|
||||
port: u8,
|
||||
address: u8,
|
||||
virtual_led_mapping: &'static [(u8, u8, u8)],
|
||||
out_current: [u8; 2],
|
||||
out_target: [u8; 2],
|
||||
}
|
||||
|
||||
impl IoExpander {
|
||||
#[cfg(all(soc_platform = "kasli", hw_rev = "v2.0"))]
|
||||
pub fn new(index: u8) -> Self {
|
||||
const VIRTUAL_LED_MAPPING0: [(u8, u8, u8); 2] = [(0, 0, 6), (1, 1, 6)];
|
||||
const VIRTUAL_LED_MAPPING1: [(u8, u8, u8); 2] = [(2, 0, 6), (3, 1, 6)];
|
||||
// Both expanders on SHARED I2C bus
|
||||
match index {
|
||||
0 => IoExpander {
|
||||
busno: 0,
|
||||
port: 11,
|
||||
address: 0x40,
|
||||
virtual_led_mapping: &VIRTUAL_LED_MAPPING0,
|
||||
out_current: [0; 2],
|
||||
out_target: [0; 2],
|
||||
},
|
||||
1 => IoExpander {
|
||||
busno: 0,
|
||||
port: 11,
|
||||
address: 0x42,
|
||||
virtual_led_mapping: &VIRTUAL_LED_MAPPING1,
|
||||
out_current: [0; 2],
|
||||
out_target: [0; 2],
|
||||
},
|
||||
_ => panic!("incorrect I/O expander index"),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(soc_platform = "kasli")]
|
||||
fn select(&self) -> Result<(), &'static str> {
|
||||
let mask: u16 = 1 << self.port;
|
||||
i2c::pca9548_select(self.busno, 0x70, mask as u8)?;
|
||||
i2c::pca9548_select(self.busno, 0x71, (mask >> 8) as u8)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write(&self, addr: u8, value: u8) -> Result<(), &'static str> {
|
||||
i2c::start(self.busno)?;
|
||||
i2c::write(self.busno, self.address)?;
|
||||
i2c::write(self.busno, addr)?;
|
||||
i2c::write(self.busno, value)?;
|
||||
i2c::stop(self.busno)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn init(&mut self) -> Result<(), &'static str> {
|
||||
self.select()?;
|
||||
|
||||
let mut iodir = [0xffu8; 2];
|
||||
for (_led, port, bit) in self.virtual_led_mapping.iter() {
|
||||
iodir[*port as usize] &= !(1 << *bit);
|
||||
}
|
||||
self.write(0x00, iodir[0])?;
|
||||
self.write(0x01, iodir[1])?;
|
||||
|
||||
self.out_current[0] = 0x00;
|
||||
self.write(0x12, 0x00)?;
|
||||
self.out_current[1] = 0x00;
|
||||
self.write(0x13, 0x00)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn set(&mut self, port: u8, bit: u8, high: bool) {
|
||||
if high {
|
||||
self.out_target[port as usize] |= 1 << bit;
|
||||
} else {
|
||||
self.out_target[port as usize] &= !(1 << bit);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn service(&mut self) -> Result<(), &'static str> {
|
||||
for (led, port, bit) in self.virtual_led_mapping.iter() {
|
||||
// TODO: get level from gateware
|
||||
self.set(*port, *bit, false);
|
||||
}
|
||||
|
||||
if self.out_target != self.out_current {
|
||||
self.select()?;
|
||||
if self.out_target[0] != self.out_current[0] {
|
||||
self.write(0x12, self.out_target[0])?;
|
||||
self.out_current[0] = self.out_target[0];
|
||||
}
|
||||
if self.out_target[1] != self.out_current[1] {
|
||||
self.write(0x13, self.out_target[1])?;
|
||||
self.out_current[1] = self.out_target[1];
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
@ -37,6 +37,8 @@ pub mod ethmac;
|
||||
pub mod i2c;
|
||||
#[cfg(soc_platform = "kasli")]
|
||||
pub mod i2c_eeprom;
|
||||
#[cfg(all(soc_platform = "kasli", hw_rev = "v2.0"))]
|
||||
pub mod io_expander;
|
||||
#[cfg(all(has_ethmac, feature = "smoltcp"))]
|
||||
pub mod net_settings;
|
||||
#[cfg(has_slave_fpga_cfg)]
|
||||
|
@ -99,6 +99,15 @@ fn startup() {
|
||||
setup_log_levels();
|
||||
#[cfg(has_i2c)]
|
||||
board_misoc::i2c::init().expect("I2C initialization failed");
|
||||
#[cfg(all(soc_platform = "kasli", hw_rev = "v2.0"))]
|
||||
let (mut io_expander0, mut io_expander1);
|
||||
#[cfg(all(soc_platform = "kasli", hw_rev = "v2.0"))]
|
||||
{
|
||||
io_expander0 = board_misoc::io_expander::IoExpander::new(0);
|
||||
io_expander1 = board_misoc::io_expander::IoExpander::new(1);
|
||||
io_expander0.init().expect("I2C I/O expander #0 initialization failed");
|
||||
io_expander1.init().expect("I2C I/O expander #1 initialization failed");
|
||||
}
|
||||
rtio_clocking::init();
|
||||
|
||||
let mut net_device = unsafe { ethmac::EthernetDevice::new() };
|
||||
@ -210,6 +219,12 @@ fn startup() {
|
||||
if let Some(_net_stats_diff) = net_stats.update() {
|
||||
debug!("ethernet mac:{}", ethmac::EthernetStatistics::new());
|
||||
}
|
||||
|
||||
#[cfg(all(soc_platform = "kasli", hw_rev = "v2.0"))]
|
||||
{
|
||||
io_expander0.service().expect("I2C I/O expander #0 service failed");
|
||||
io_expander1.service().expect("I2C I/O expander #1 service failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -454,13 +454,23 @@ pub extern fn main() -> i32 {
|
||||
info!("software ident {}", csr::CONFIG_IDENTIFIER_STR);
|
||||
info!("gateware ident {}", ident::read(&mut [0; 64]));
|
||||
|
||||
#[cfg(has_si5324)]
|
||||
#[cfg(has_i2c)]
|
||||
i2c::init().expect("I2C initialization failed");
|
||||
#[cfg(all(soc_platform = "kasli", hw_rev = "v2.0"))]
|
||||
let (mut io_expander0, mut io_expander1);
|
||||
#[cfg(all(soc_platform = "kasli", hw_rev = "v2.0"))]
|
||||
{
|
||||
i2c::init().expect("I2C initialization failed");
|
||||
si5324::setup(&SI5324_SETTINGS, si5324::Input::Ckin1).expect("cannot initialize Si5324");
|
||||
io_expander0 = board_misoc::io_expander::IoExpander::new(0);
|
||||
io_expander1 = board_misoc::io_expander::IoExpander::new(1);
|
||||
io_expander0.init().expect("I2C I/O expander #0 initialization failed");
|
||||
io_expander1.init().expect("I2C I/O expander #1 initialization failed");
|
||||
}
|
||||
|
||||
#[cfg(has_si5324)]
|
||||
si5324::setup(&SI5324_SETTINGS, si5324::Input::Ckin1).expect("cannot initialize Si5324");
|
||||
#[cfg(has_wrpll)]
|
||||
wrpll::init();
|
||||
|
||||
unsafe {
|
||||
csr::drtio_transceiver::stable_clkin_write(1);
|
||||
}
|
||||
@ -507,6 +517,11 @@ pub extern fn main() -> i32 {
|
||||
for mut rep in repeaters.iter_mut() {
|
||||
rep.service(&routing_table, rank);
|
||||
}
|
||||
#[cfg(all(soc_platform = "kasli", hw_rev = "v2.0"))]
|
||||
{
|
||||
io_expander0.service().expect("I2C I/O expander #0 service failed");
|
||||
io_expander1.service().expect("I2C I/O expander #1 service failed");
|
||||
}
|
||||
hardware_tick(&mut hardware_tick_ts);
|
||||
}
|
||||
|
||||
@ -531,6 +546,11 @@ pub extern fn main() -> i32 {
|
||||
for mut rep in repeaters.iter_mut() {
|
||||
rep.service(&routing_table, rank);
|
||||
}
|
||||
#[cfg(all(soc_platform = "kasli", hw_rev = "v2.0"))]
|
||||
{
|
||||
io_expander0.service().expect("I2C I/O expander #0 service failed");
|
||||
io_expander1.service().expect("I2C I/O expander #1 service failed");
|
||||
}
|
||||
hardware_tick(&mut hardware_tick_ts);
|
||||
if drtiosat_tsc_loaded() {
|
||||
info!("TSC loaded from uplink");
|
||||
|
Loading…
Reference in New Issue
Block a user