diff --git a/sw/host/opentitanlib/BUILD b/sw/host/opentitanlib/BUILD index c2026992fcef4..a70dab0def813 100644 --- a/sw/host/opentitanlib/BUILD +++ b/sw/host/opentitanlib/BUILD @@ -183,6 +183,7 @@ rust_library( "src/transport/dediprog/spi.rs", "src/transport/errors.rs", "src/transport/ftdi/chip.rs", + "src/transport/ftdi/gpio.rs", "src/transport/ftdi/mod.rs", "src/transport/hyperdebug/c2d2.rs", "src/transport/hyperdebug/dfu.rs", diff --git a/sw/host/opentitanlib/src/transport/ftdi/gpio.rs b/sw/host/opentitanlib/src/transport/ftdi/gpio.rs new file mode 100644 index 0000000000000..47acb3ca7b1c8 --- /dev/null +++ b/sw/host/opentitanlib/src/transport/ftdi/gpio.rs @@ -0,0 +1,83 @@ +// Copyright lowRISC contributors (OpenTitan project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +use anyhow::Result; +use std::cell::RefCell; +use std::collections::HashMap; +use std::rc::Rc; + +use embedded_hal::digital::OutputPin; +use ftdi_embedded_hal as ftdi_hal; + +use crate::io::gpio::{GpioError, GpioPin, PinMode, PullMode}; +use crate::transport::ftdi::Chip; + +pub struct Pin { + pin: Rc>>, + pinname: String, +} + +impl Pin { + pub fn open( + ftdi_interfaces: &HashMap>, + pinname: String, + ) -> Result { + let pinname = pinname.to_lowercase(); + let (interface, pin) = pinname.split_at(1); + let interface = match interface { + "a" => ftdi::Interface::A, + "b" => ftdi::Interface::B, + "c" => ftdi::Interface::C, + "d" => ftdi::Interface::D, + &_ => panic!("{}", pinname.clone()), + }; + + let hal = ftdi_interfaces + .get(&interface) + .ok_or_else(|| GpioError::InvalidPinName(pinname.clone()))?; + let pin = match pin { + "dbus0" => hal.ad0(), + "dbus1" => hal.ad1(), + "dbus2" => hal.ad2(), + "dbus3" => hal.ad3(), + "dbus4" => hal.ad4(), + "dbus5" => hal.ad5(), + "dbus6" => hal.ad6(), + "dbus7" => hal.ad7(), + _ => return Err(GpioError::InvalidPinName(pinname).into()), + }?; + + Ok(Self { + pin: Rc::new(RefCell::new(pin)), + pinname, + }) + } +} + +impl GpioPin for Pin { + fn read(&self) -> Result { + Ok(false) + } + + fn write(&self, value: bool) -> Result<()> { + if value { + self.pin.borrow_mut().set_high()?; + } else { + self.pin.borrow_mut().set_low()?; + } + Ok(()) + } + + fn set_mode(&self, _mode: PinMode) -> Result<()> { + Ok(()) + } + + fn set_pull_mode(&self, _mode: PullMode) -> Result<()> { + Ok(()) + } + + fn get_internal_pin_name(&self) -> Option<&str> { + Some(&self.pinname) + } +} diff --git a/sw/host/opentitanlib/src/transport/ftdi/mod.rs b/sw/host/opentitanlib/src/transport/ftdi/mod.rs index c5c36d70fbc30..9b06eca70d3a5 100644 --- a/sw/host/opentitanlib/src/transport/ftdi/mod.rs +++ b/sw/host/opentitanlib/src/transport/ftdi/mod.rs @@ -25,6 +25,7 @@ use chip::Chip; use ftdi_embedded_hal as ftdi_hal; pub mod chip; +pub mod gpio; #[derive(Default)] struct Inner { @@ -101,7 +102,17 @@ impl Transport for Ftdi { } fn gpio_pin(&self, pinname: &str) -> Result> { - Err(TransportError::UnsupportedOperation.into()) + let mut inner = self.inner.borrow_mut(); + Ok(match inner.gpio.entry(pinname.to_string()) { + Entry::Vacant(v) => { + let u = v.insert(Rc::new(gpio::Pin::open::( + &self.ftdi_interfaces, + pinname.to_string(), + )?)); + Rc::clone(u) + } + Entry::Occupied(o) => Rc::clone(o.get()), + }) } fn spi(&self, _instance: &str) -> Result> {