131 lines
3.2 KiB
Rust
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)
|
|
}
|
|
}
|
|
}
|