Files
yggdrasil/kernel/src/device/gpio.rs
T

131 lines
3.2 KiB
Rust

//! GPIO drivers
use abi::error::Error;
use alloc::{boxed::Box, string::String, sync::Arc, vec::Vec};
use device_api::{
device::{Device, DeviceInitContext},
gpio::{GpioPinLevel, PinHandle},
};
use device_tree::driver::{device_tree_driver, DeviceTreeGpioPins, Node, ProbeContext};
use libk::event::GpioEvent;
struct LedPin {
name: String,
handle: PinHandle,
}
struct KeyPin {
name: String,
handle: PinHandle,
}
trait Pin: Sized + Send + Sync + 'static {
fn from_device_tree(node: &Arc<Node>) -> Option<Self>;
fn configure(&self) -> Result<(), Error>;
fn name(&self) -> &str;
}
struct PinGroup<P: Pin> {
name: String,
pins: Vec<P>,
}
impl<P: Pin> PinGroup<P> {
fn from_device_tree(node: &Arc<Node>) -> Option<Arc<dyn Device>> {
let pins = node
.children()
.filter_map(P::from_device_tree)
.collect::<Vec<_>>();
if pins.is_empty() {
return None;
}
let name = node.name().unwrap_or("pin-group");
Some(Arc::new(Self {
pins,
name: name.into(),
}))
}
}
impl<P: Pin> Device for PinGroup<P> {
unsafe fn init(self: Arc<Self>, _cx: DeviceInitContext) -> Result<(), Error> {
for pin in self.pins.iter() {
if let Err(error) = pin.configure() {
log::error!("gpio {} setup error: {:?}", pin.name(), error);
}
}
Ok(())
}
fn display_name(&self) -> &str {
&self.name
}
}
impl Pin for LedPin {
fn from_device_tree(node: &Arc<Node>) -> Option<Self> {
let handle = node.gpio(
&DeviceTreeGpioPins {
input: false,
output: true,
initial_level: GpioPinLevel::Low,
},
0,
)?;
let name = node.name().unwrap_or("gpio-led").into();
Some(Self { name, handle })
}
fn configure(&self) -> Result<(), Error> {
self.handle.configure()
}
fn name(&self) -> &str {
&self.name
}
}
impl Pin for KeyPin {
fn from_device_tree(node: &Arc<Node>) -> Option<Self> {
let handle = node.gpio(
&DeviceTreeGpioPins {
input: true,
output: false,
initial_level: GpioPinLevel::Low,
},
0,
)?;
let name = node.name().unwrap_or("gpio-key").into();
Some(Self { name, handle })
}
fn configure(&self) -> Result<(), Error> {
let name = self.name.clone();
self.handle.configure_with_interrupt(Box::new(move || {
log::info!("GPIO key {name:?} triggered");
}))
}
fn name(&self) -> &str {
&self.name
}
}
device_tree_driver! {
compatible: ["gpio-leds"],
driver: {
fn probe(&self, node: &Arc<Node>, _context: &mut ProbeContext) -> Option<Arc<dyn Device>> {
PinGroup::<LedPin>::from_device_tree(node)
}
}
}
device_tree_driver! {
compatible: ["gpio-keys"],
driver: {
fn probe(&self, node: &Arc<Node>, _context: &mut ProbeContext) -> Option<Arc<dyn Device>> {
PinGroup::<KeyPin>::from_device_tree(node)
}
}
}