Skip to main content

fdt_edit/node/view/
clock.rs

1//! Clock node view specialization.
2
3use core::ops::Deref;
4
5use alloc::{borrow::ToOwned, string::String, vec::Vec};
6use fdt_raw::Phandle;
7
8use super::NodeView;
9use crate::{NodeGeneric, NodeGenericMut, Property, ViewMutOp, ViewOp};
10
11// ---------------------------------------------------------------------------
12// Clock types
13// ---------------------------------------------------------------------------
14
15/// Clock provider type.
16#[derive(Clone, Debug, PartialEq)]
17pub enum ClockType {
18    /// Fixed clock
19    Fixed(FixedClock),
20    /// Normal clock provider
21    Normal,
22}
23
24/// Fixed clock provider.
25///
26/// Represents a fixed-rate clock that always operates at a constant frequency.
27#[derive(Clone, Debug, PartialEq)]
28pub struct FixedClock {
29    /// Optional name for the clock
30    pub name: Option<String>,
31    /// Clock frequency in Hz
32    pub frequency: u32,
33    /// Clock accuracy in ppb (parts per billion)
34    pub accuracy: Option<u32>,
35}
36
37/// Clock reference, used to parse clocks property.
38///
39/// According to the device tree specification, the clocks property format is:
40/// `clocks = <&clock_provider specifier [specifier ...]> [<&clock_provider2 ...>]`
41///
42/// Each clock reference consists of a phandle and several specifier cells,
43/// the number of specifiers is determined by the target clock provider's `#clock-cells` property.
44#[derive(Clone, Debug)]
45pub struct ClockRef {
46    /// Clock name, from clock-names property
47    pub name: Option<String>,
48    /// Phandle of the clock provider
49    pub phandle: Phandle,
50    /// #clock-cells value of the provider
51    pub cells: u32,
52    /// Clock selector (specifier), usually the first value is used to select clock output
53    /// Length is determined by provider's #clock-cells
54    pub specifier: Vec<u32>,
55}
56
57impl ClockRef {
58    /// Create a new clock reference
59    pub fn new(phandle: Phandle, cells: u32, specifier: Vec<u32>) -> Self {
60        Self {
61            name: None,
62            phandle,
63            cells,
64            specifier,
65        }
66    }
67
68    /// Create a named clock reference
69    pub fn with_name(
70        name: Option<String>,
71        phandle: Phandle,
72        cells: u32,
73        specifier: Vec<u32>,
74    ) -> Self {
75        Self {
76            name,
77            phandle,
78            cells,
79            specifier,
80        }
81    }
82
83    /// Get the first value of the selector (usually used to select clock output)
84    ///
85    /// Only returns a selector value when `cells > 0`,
86    /// because providers with `#clock-cells = 0` don't need a selector.
87    pub fn select(&self) -> Option<u32> {
88        if self.cells > 0 {
89            self.specifier.first().copied()
90        } else {
91            None
92        }
93    }
94}
95
96// ---------------------------------------------------------------------------
97// ClockNodeView
98// ---------------------------------------------------------------------------
99
100/// Specialized view for clock provider nodes.
101#[derive(Clone, Copy)]
102pub struct ClockNodeView<'a> {
103    pub(super) inner: NodeGeneric<'a>,
104}
105
106impl<'a> Deref for ClockNodeView<'a> {
107    type Target = NodeGeneric<'a>;
108
109    fn deref(&self) -> &Self::Target {
110        &self.inner
111    }
112}
113
114impl<'a> ViewOp<'a> for ClockNodeView<'a> {
115    fn as_view(&self) -> NodeView<'a> {
116        self.inner.as_view()
117    }
118}
119
120impl<'a> ClockNodeView<'a> {
121    pub(crate) fn try_from_view(view: NodeView<'a>) -> Option<Self> {
122        if view.as_node().is_clock() {
123            Some(Self {
124                inner: NodeGeneric { inner: view },
125            })
126        } else {
127            None
128        }
129    }
130
131    /// Get the value of the `#clock-cells` property.
132    pub fn clock_cells(&self) -> u32 {
133        self.as_view()
134            .as_node()
135            .get_property("#clock-cells")
136            .and_then(|prop| prop.get_u32())
137            .unwrap_or(0)
138    }
139
140    /// Get clock output names from the `clock-output-names` property.
141    pub fn clock_output_names(&self) -> Vec<String> {
142        self.as_view()
143            .as_node()
144            .get_property("clock-output-names")
145            .map(|prop| prop.as_str_iter().map(|s| s.to_owned()).collect())
146            .unwrap_or_default()
147    }
148
149    /// Get clock output name by index.
150    pub fn output_name(&self, index: usize) -> Option<String> {
151        self.clock_output_names().get(index).cloned()
152    }
153
154    /// Get the clock type (Fixed or Normal).
155    pub fn clock_type(&self) -> ClockType {
156        let node = self.as_view().as_node();
157
158        // Check if this is a fixed-clock
159        let is_fixed = node
160            .get_property("compatible")
161            .and_then(|prop| prop.as_str_iter().find(|&c| c == "fixed-clock"))
162            .is_some();
163
164        if is_fixed {
165            let frequency = node
166                .get_property("clock-frequency")
167                .and_then(|prop| prop.get_u32())
168                .unwrap_or(0);
169
170            let accuracy = node
171                .get_property("clock-accuracy")
172                .and_then(|prop| prop.get_u32());
173
174            let name = self.clock_output_names().first().cloned();
175
176            ClockType::Fixed(FixedClock {
177                name,
178                frequency,
179                accuracy,
180            })
181        } else {
182            ClockType::Normal
183        }
184    }
185}
186
187// ---------------------------------------------------------------------------
188// ClockNodeViewMut
189// ---------------------------------------------------------------------------
190
191/// Mutable view for clock provider nodes.
192pub struct ClockNodeViewMut<'a> {
193    pub(super) inner: NodeGenericMut<'a>,
194}
195
196impl<'a> Deref for ClockNodeViewMut<'a> {
197    type Target = NodeGenericMut<'a>;
198
199    fn deref(&self) -> &Self::Target {
200        &self.inner
201    }
202}
203
204impl<'a> ViewOp<'a> for ClockNodeViewMut<'a> {
205    fn as_view(&self) -> NodeView<'a> {
206        self.inner.as_view()
207    }
208}
209
210impl<'a> ViewMutOp<'a> for ClockNodeViewMut<'a> {
211    fn new(node: NodeGenericMut<'a>) -> Self {
212        let mut s = Self { inner: node };
213        let n = s.inner.inner.as_node_mut();
214        // Set #clock-cells property (default to 0)
215        n.set_property(Property::new("#clock-cells", (0u32).to_be_bytes().to_vec()));
216        s
217    }
218}
219
220impl<'a> ClockNodeViewMut<'a> {
221    pub(crate) fn try_from_view(view: NodeView<'a>) -> Option<Self> {
222        if view.as_node().is_clock() {
223            Some(Self {
224                inner: NodeGenericMut { inner: view },
225            })
226        } else {
227            None
228        }
229    }
230}