use core::ops::Deref;
use alloc::{borrow::ToOwned, string::String, vec::Vec};
use fdt_raw::Phandle;
use super::NodeView;
use crate::{NodeGeneric, NodeGenericMut, Property, ViewMutOp, ViewOp};
#[derive(Clone, Debug, PartialEq)]
pub enum ClockType {
Fixed(FixedClock),
Normal,
}
#[derive(Clone, Debug, PartialEq)]
pub struct FixedClock {
pub name: Option<String>,
pub frequency: u32,
pub accuracy: Option<u32>,
}
#[derive(Clone, Debug)]
pub struct ClockRef {
pub name: Option<String>,
pub phandle: Phandle,
pub cells: u32,
pub specifier: Vec<u32>,
}
impl ClockRef {
pub fn new(phandle: Phandle, cells: u32, specifier: Vec<u32>) -> Self {
Self {
name: None,
phandle,
cells,
specifier,
}
}
pub fn with_name(
name: Option<String>,
phandle: Phandle,
cells: u32,
specifier: Vec<u32>,
) -> Self {
Self {
name,
phandle,
cells,
specifier,
}
}
pub fn select(&self) -> Option<u32> {
if self.cells > 0 {
self.specifier.first().copied()
} else {
None
}
}
}
#[derive(Clone, Copy)]
pub struct ClockNodeView<'a> {
pub(super) inner: NodeGeneric<'a>,
}
impl<'a> Deref for ClockNodeView<'a> {
type Target = NodeGeneric<'a>;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl<'a> ViewOp<'a> for ClockNodeView<'a> {
fn as_view(&self) -> NodeView<'a> {
self.inner.as_view()
}
}
impl<'a> ClockNodeView<'a> {
pub(crate) fn try_from_view(view: NodeView<'a>) -> Option<Self> {
if view.as_node().is_clock() {
Some(Self {
inner: NodeGeneric { inner: view },
})
} else {
None
}
}
pub fn clock_cells(&self) -> u32 {
self.as_view()
.as_node()
.get_property("#clock-cells")
.and_then(|prop| prop.get_u32())
.unwrap_or(0)
}
pub fn clock_output_names(&self) -> Vec<String> {
self.as_view()
.as_node()
.get_property("clock-output-names")
.map(|prop| prop.as_str_iter().map(|s| s.to_owned()).collect())
.unwrap_or_default()
}
pub fn output_name(&self, index: usize) -> Option<String> {
self.clock_output_names().get(index).cloned()
}
pub fn clock_type(&self) -> ClockType {
let node = self.as_view().as_node();
let is_fixed = node
.get_property("compatible")
.and_then(|prop| prop.as_str_iter().find(|&c| c == "fixed-clock"))
.is_some();
if is_fixed {
let frequency = node
.get_property("clock-frequency")
.and_then(|prop| prop.get_u32())
.unwrap_or(0);
let accuracy = node
.get_property("clock-accuracy")
.and_then(|prop| prop.get_u32());
let name = self.clock_output_names().first().cloned();
ClockType::Fixed(FixedClock {
name,
frequency,
accuracy,
})
} else {
ClockType::Normal
}
}
}
pub struct ClockNodeViewMut<'a> {
pub(super) inner: NodeGenericMut<'a>,
}
impl<'a> Deref for ClockNodeViewMut<'a> {
type Target = NodeGenericMut<'a>;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl<'a> ViewOp<'a> for ClockNodeViewMut<'a> {
fn as_view(&self) -> NodeView<'a> {
self.inner.as_view()
}
}
impl<'a> ViewMutOp<'a> for ClockNodeViewMut<'a> {
fn new(node: NodeGenericMut<'a>) -> Self {
let mut s = Self { inner: node };
let n = s.inner.inner.as_node_mut();
n.set_property(Property::new("#clock-cells", (0u32).to_be_bytes().to_vec()));
s
}
}
impl<'a> ClockNodeViewMut<'a> {
pub(crate) fn try_from_view(view: NodeView<'a>) -> Option<Self> {
if view.as_node().is_clock() {
Some(Self {
inner: NodeGenericMut { inner: view },
})
} else {
None
}
}
}