forked from M-Labs/artiq
firmware: I2C I/O expander support
This commit is contained in:
parent
ef4e5bc69b
commit
4982fde898
|
@ -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;
|
pub mod i2c;
|
||||||
#[cfg(soc_platform = "kasli")]
|
#[cfg(soc_platform = "kasli")]
|
||||||
pub mod i2c_eeprom;
|
pub mod i2c_eeprom;
|
||||||
|
#[cfg(all(soc_platform = "kasli", hw_rev = "v2.0"))]
|
||||||
|
pub mod io_expander;
|
||||||
#[cfg(all(has_ethmac, feature = "smoltcp"))]
|
#[cfg(all(has_ethmac, feature = "smoltcp"))]
|
||||||
pub mod net_settings;
|
pub mod net_settings;
|
||||||
#[cfg(has_slave_fpga_cfg)]
|
#[cfg(has_slave_fpga_cfg)]
|
||||||
|
|
|
@ -99,6 +99,15 @@ fn startup() {
|
||||||
setup_log_levels();
|
setup_log_levels();
|
||||||
#[cfg(has_i2c)]
|
#[cfg(has_i2c)]
|
||||||
board_misoc::i2c::init().expect("I2C initialization failed");
|
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();
|
rtio_clocking::init();
|
||||||
|
|
||||||
let mut net_device = unsafe { ethmac::EthernetDevice::new() };
|
let mut net_device = unsafe { ethmac::EthernetDevice::new() };
|
||||||
|
@ -210,6 +219,12 @@ fn startup() {
|
||||||
if let Some(_net_stats_diff) = net_stats.update() {
|
if let Some(_net_stats_diff) = net_stats.update() {
|
||||||
debug!("ethernet mac:{}", ethmac::EthernetStatistics::new());
|
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!("software ident {}", csr::CONFIG_IDENTIFIER_STR);
|
||||||
info!("gateware ident {}", ident::read(&mut [0; 64]));
|
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");
|
io_expander0 = board_misoc::io_expander::IoExpander::new(0);
|
||||||
si5324::setup(&SI5324_SETTINGS, si5324::Input::Ckin1).expect("cannot initialize Si5324");
|
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)]
|
#[cfg(has_wrpll)]
|
||||||
wrpll::init();
|
wrpll::init();
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
csr::drtio_transceiver::stable_clkin_write(1);
|
csr::drtio_transceiver::stable_clkin_write(1);
|
||||||
}
|
}
|
||||||
|
@ -507,6 +517,11 @@ pub extern fn main() -> i32 {
|
||||||
for mut rep in repeaters.iter_mut() {
|
for mut rep in repeaters.iter_mut() {
|
||||||
rep.service(&routing_table, rank);
|
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);
|
hardware_tick(&mut hardware_tick_ts);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -531,6 +546,11 @@ pub extern fn main() -> i32 {
|
||||||
for mut rep in repeaters.iter_mut() {
|
for mut rep in repeaters.iter_mut() {
|
||||||
rep.service(&routing_table, rank);
|
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);
|
hardware_tick(&mut hardware_tick_ts);
|
||||||
if drtiosat_tsc_loaded() {
|
if drtiosat_tsc_loaded() {
|
||||||
info!("TSC loaded from uplink");
|
info!("TSC loaded from uplink");
|
||||||
|
|
Loading…
Reference in New Issue