opentitanlib/transport/dediprog/
gpio.rs

1// Copyright lowRISC contributors (OpenTitan project).
2// Licensed under the Apache License, Version 2.0, see LICENSE for details.
3// SPDX-License-Identifier: Apache-2.0
4
5use std::cell::RefCell;
6use std::collections::HashMap;
7use std::rc::Rc;
8use std::sync::LazyLock;
9
10use anyhow::{Result, ensure};
11
12use crate::collection;
13use crate::io::gpio::{GpioError, GpioPin, PinMode, PullMode};
14use crate::transport::dediprog::Inner;
15use crate::util::parse_int::ParseInt;
16
17pub struct DediprogPin {
18    inner: Rc<RefCell<Inner>>,
19    index: u8,
20}
21
22impl DediprogPin {
23    const LAST_PIN_NUM: u8 = 15;
24
25    pub fn open(inner: Rc<RefCell<Inner>>, pinname: &str) -> Result<Self> {
26        Ok(Self {
27            inner,
28            index: Self::pin_name_to_number(pinname)?,
29        })
30    }
31
32    /// Given a dediprog pin name, return its pin number.
33    pub fn pin_name_to_number(pinname: &str) -> Result<u8> {
34        // If the pinname is an integer, use it; otherwise try to see if it
35        // is a symbolic name of a pin.
36        if let Ok(pinnum) = u8::from_str(pinname) {
37            ensure!(
38                pinnum <= Self::LAST_PIN_NUM,
39                GpioError::InvalidPinNumber(pinnum)
40            );
41            return Ok(pinnum);
42        }
43        let pinname = pinname.to_uppercase();
44        let pn = pinname.as_str();
45        PIN_NAMES
46            .get(pn)
47            .copied()
48            .ok_or_else(|| GpioError::InvalidPinName(pinname).into())
49    }
50}
51
52impl GpioPin for DediprogPin {
53    fn read(&self) -> Result<bool> {
54        Ok(self.inner.borrow().gpio_levels & (1 << self.index) != 0)
55    }
56
57    fn write(&self, value: bool) -> Result<()> {
58        let mut inner = self.inner.borrow_mut();
59        if value {
60            inner.gpio_levels |= 1u16 << self.index
61        } else {
62            inner.gpio_levels &= !(1u16 << self.index)
63        }
64        inner.set_gpio_levels()
65    }
66
67    fn set_mode(&self, mode: PinMode) -> Result<()> {
68        match mode {
69            PinMode::PushPull => Ok(()),
70            _ => Err(GpioError::UnsupportedPinMode(mode).into()),
71        }
72    }
73
74    fn set_pull_mode(&self, mode: PullMode) -> Result<()> {
75        match mode {
76            PullMode::None => Ok(()),
77            _ => Err(GpioError::UnsupportedPullMode(mode).into()),
78        }
79    }
80}
81
82static PIN_NAMES: LazyLock<HashMap<&'static str, u8>> = LazyLock::new(|| {
83    collection! {
84        "IO2" => 0,
85        "IO1" => 1,
86        "IO3" => 2,
87        "IO4" => 3,
88        "PASS_LED" => 8,
89        "BUSY_LED" => 9,
90        "ERROR_LED" => 10,
91    }
92});