aboutsummaryrefslogtreecommitdiff
path: root/embassy-imxrt/src/flexcomm/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'embassy-imxrt/src/flexcomm/mod.rs')
-rw-r--r--embassy-imxrt/src/flexcomm/mod.rs252
1 files changed, 252 insertions, 0 deletions
diff --git a/embassy-imxrt/src/flexcomm/mod.rs b/embassy-imxrt/src/flexcomm/mod.rs
new file mode 100644
index 000000000..4473c9a77
--- /dev/null
+++ b/embassy-imxrt/src/flexcomm/mod.rs
@@ -0,0 +1,252 @@
1//! Implements Flexcomm interface wrapper for easier usage across modules
2
3pub mod uart;
4
5use paste::paste;
6
7use crate::clocks::{enable_and_reset, SysconPeripheral};
8use crate::peripherals::{
9 FLEXCOMM0, FLEXCOMM1, FLEXCOMM14, FLEXCOMM15, FLEXCOMM2, FLEXCOMM3, FLEXCOMM4, FLEXCOMM5, FLEXCOMM6, FLEXCOMM7,
10};
11use crate::{pac, PeripheralType};
12
13/// clock selection option
14#[derive(Copy, Clone, Debug)]
15pub enum Clock {
16 /// SFRO
17 Sfro,
18
19 /// FFRO
20 Ffro,
21
22 /// `AUDIO_PLL`
23 AudioPll,
24
25 /// MASTER
26 Master,
27
28 /// FCn_FRG with Main clock source
29 FcnFrgMain,
30
31 /// FCn_FRG with Pll clock source
32 FcnFrgPll,
33
34 /// FCn_FRG with Sfro clock source
35 FcnFrgSfro,
36
37 /// FCn_FRG with Ffro clock source
38 FcnFrgFfro,
39
40 /// disabled
41 None,
42}
43
44/// do not allow implementation of trait outside this mod
45mod sealed {
46 /// trait does not get re-exported outside flexcomm mod, allowing us to safely expose only desired APIs
47 pub trait Sealed {}
48}
49
50/// primary low-level flexcomm interface
51pub(crate) trait FlexcommLowLevel: sealed::Sealed + PeripheralType + SysconPeripheral + 'static + Send {
52 // fetch the flexcomm register block for direct manipulation
53 fn reg() -> &'static pac::flexcomm0::RegisterBlock;
54
55 // set the clock select for this flexcomm instance and remove from reset
56 fn enable(clk: Clock);
57}
58
59macro_rules! impl_flexcomm {
60 ($($idx:expr),*) => {
61 $(
62 paste!{
63 impl sealed::Sealed for crate::peripherals::[<FLEXCOMM $idx>] {}
64
65 impl FlexcommLowLevel for crate::peripherals::[<FLEXCOMM $idx>] {
66 fn reg() -> &'static crate::pac::flexcomm0::RegisterBlock {
67 // SAFETY: safe from single executor, enforce
68 // via peripheral reference lifetime tracking
69 unsafe {
70 &*crate::pac::[<Flexcomm $idx>]::ptr()
71 }
72 }
73
74 fn enable(clk: Clock) {
75 // SAFETY: safe from single executor
76 let clkctl1 = unsafe { crate::pac::Clkctl1::steal() };
77
78 clkctl1.flexcomm($idx).fcfclksel().write(|w| match clk {
79 Clock::Sfro => w.sel().sfro_clk(),
80 Clock::Ffro => w.sel().ffro_clk(),
81 Clock::AudioPll => w.sel().audio_pll_clk(),
82 Clock::Master => w.sel().master_clk(),
83 Clock::FcnFrgMain => w.sel().fcn_frg_clk(),
84 Clock::FcnFrgPll => w.sel().fcn_frg_clk(),
85 Clock::FcnFrgSfro => w.sel().fcn_frg_clk(),
86 Clock::FcnFrgFfro => w.sel().fcn_frg_clk(),
87 Clock::None => w.sel().none(), // no clock? throw an error?
88 });
89
90 clkctl1.flexcomm($idx).frgclksel().write(|w| match clk {
91 Clock::FcnFrgMain => w.sel().main_clk(),
92 Clock::FcnFrgPll => w.sel().frg_pll_clk(),
93 Clock::FcnFrgSfro => w.sel().sfro_clk(),
94 Clock::FcnFrgFfro => w.sel().ffro_clk(),
95 _ => w.sel().none(), // not using frg ...
96 });
97
98 // todo: add support for frg div/mult
99 clkctl1
100 .flexcomm($idx)
101 .frgctl()
102 .write(|w|
103 // SAFETY: unsafe only used for .bits() call
104 unsafe { w.mult().bits(0) });
105
106 enable_and_reset::<[<FLEXCOMM $idx>]>();
107 }
108 }
109 }
110 )*
111 }
112}
113
114impl_flexcomm!(0, 1, 2, 3, 4, 5, 6, 7);
115
116// TODO: FLEXCOMM 14 is untested. Enable SPI support on FLEXCOMM14
117// Add special case FLEXCOMM14
118impl sealed::Sealed for crate::peripherals::FLEXCOMM14 {}
119
120impl FlexcommLowLevel for crate::peripherals::FLEXCOMM14 {
121 fn reg() -> &'static crate::pac::flexcomm0::RegisterBlock {
122 // SAFETY: safe from single executor, enforce
123 // via peripheral reference lifetime tracking
124 unsafe { &*crate::pac::Flexcomm14::ptr() }
125 }
126
127 fn enable(clk: Clock) {
128 // SAFETY: safe from single executor
129 let clkctl1 = unsafe { crate::pac::Clkctl1::steal() };
130
131 clkctl1.fc14fclksel().write(|w| match clk {
132 Clock::Sfro => w.sel().sfro_clk(),
133 Clock::Ffro => w.sel().ffro_clk(),
134 Clock::AudioPll => w.sel().audio_pll_clk(),
135 Clock::Master => w.sel().master_clk(),
136 Clock::FcnFrgMain => w.sel().fcn_frg_clk(),
137 Clock::FcnFrgPll => w.sel().fcn_frg_clk(),
138 Clock::FcnFrgSfro => w.sel().fcn_frg_clk(),
139 Clock::FcnFrgFfro => w.sel().fcn_frg_clk(),
140 Clock::None => w.sel().none(), // no clock? throw an error?
141 });
142
143 clkctl1.frg14clksel().write(|w| match clk {
144 Clock::FcnFrgMain => w.sel().main_clk(),
145 Clock::FcnFrgPll => w.sel().frg_pll_clk(),
146 Clock::FcnFrgSfro => w.sel().sfro_clk(),
147 Clock::FcnFrgFfro => w.sel().ffro_clk(),
148 _ => w.sel().none(), // not using frg ...
149 });
150
151 // todo: add support for frg div/mult
152 clkctl1.frg14ctl().write(|w|
153 // SAFETY: unsafe only used for .bits() call
154 unsafe { w.mult().bits(0) });
155
156 enable_and_reset::<FLEXCOMM14>();
157 }
158}
159
160// Add special case FLEXCOMM15
161impl sealed::Sealed for crate::peripherals::FLEXCOMM15 {}
162
163impl FlexcommLowLevel for crate::peripherals::FLEXCOMM15 {
164 fn reg() -> &'static crate::pac::flexcomm0::RegisterBlock {
165 // SAFETY: safe from single executor, enforce
166 // via peripheral reference lifetime tracking
167 unsafe { &*crate::pac::Flexcomm15::ptr() }
168 }
169
170 fn enable(clk: Clock) {
171 // SAFETY: safe from single executor
172 let clkctl1 = unsafe { crate::pac::Clkctl1::steal() };
173
174 clkctl1.fc15fclksel().write(|w| match clk {
175 Clock::Sfro => w.sel().sfro_clk(),
176 Clock::Ffro => w.sel().ffro_clk(),
177 Clock::AudioPll => w.sel().audio_pll_clk(),
178 Clock::Master => w.sel().master_clk(),
179 Clock::FcnFrgMain => w.sel().fcn_frg_clk(),
180 Clock::FcnFrgPll => w.sel().fcn_frg_clk(),
181 Clock::FcnFrgSfro => w.sel().fcn_frg_clk(),
182 Clock::FcnFrgFfro => w.sel().fcn_frg_clk(),
183 Clock::None => w.sel().none(), // no clock? throw an error?
184 });
185 clkctl1.frg15clksel().write(|w| match clk {
186 Clock::FcnFrgMain => w.sel().main_clk(),
187 Clock::FcnFrgPll => w.sel().frg_pll_clk(),
188 Clock::FcnFrgSfro => w.sel().sfro_clk(),
189 Clock::FcnFrgFfro => w.sel().ffro_clk(),
190 _ => w.sel().none(), // not using frg ...
191 });
192 // todo: add support for frg div/mult
193 clkctl1.frg15ctl().write(|w|
194 // SAFETY: unsafe only used for .bits() call
195 unsafe { w.mult().bits(0) });
196
197 enable_and_reset::<FLEXCOMM15>();
198 }
199}
200
201macro_rules! into_mode {
202 ($mode:ident, $($fc:ident),*) => {
203 paste! {
204 /// Sealed Mode trait
205 trait [<SealedInto $mode:camel>]: FlexcommLowLevel {}
206
207 /// Select mode of operation
208 #[allow(private_bounds)]
209 pub trait [<Into $mode:camel>]: [<SealedInto $mode:camel>] {
210 /// Set mode of operation
211 fn [<into_ $mode>]() {
212 Self::reg().pselid().write(|w| w.persel().[<$mode>]());
213 }
214 }
215 }
216
217 $(
218 paste!{
219 impl [<SealedInto $mode:camel>] for crate::peripherals::$fc {}
220 impl [<Into $mode:camel>] for crate::peripherals::$fc {}
221 }
222 )*
223 }
224}
225
226into_mode!(usart, FLEXCOMM0, FLEXCOMM1, FLEXCOMM2, FLEXCOMM3, FLEXCOMM4, FLEXCOMM5, FLEXCOMM6, FLEXCOMM7);
227into_mode!(spi, FLEXCOMM0, FLEXCOMM1, FLEXCOMM2, FLEXCOMM3, FLEXCOMM4, FLEXCOMM5, FLEXCOMM6, FLEXCOMM7, FLEXCOMM14);
228into_mode!(i2c, FLEXCOMM0, FLEXCOMM1, FLEXCOMM2, FLEXCOMM3, FLEXCOMM4, FLEXCOMM5, FLEXCOMM6, FLEXCOMM7, FLEXCOMM15);
229
230into_mode!(
231 i2s_transmit,
232 FLEXCOMM0,
233 FLEXCOMM1,
234 FLEXCOMM2,
235 FLEXCOMM3,
236 FLEXCOMM4,
237 FLEXCOMM5,
238 FLEXCOMM6,
239 FLEXCOMM7
240);
241
242into_mode!(
243 i2s_receive,
244 FLEXCOMM0,
245 FLEXCOMM1,
246 FLEXCOMM2,
247 FLEXCOMM3,
248 FLEXCOMM4,
249 FLEXCOMM5,
250 FLEXCOMM6,
251 FLEXCOMM7
252);