• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2024 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 #pragma once
15 
16 #include "fsl_clock.h"
17 #include "fsl_power.h"
18 #include "pw_clock_tree/clock_tree.h"
19 
20 namespace pw::clock_tree {
21 
22 /// Class implementing an FRO clock source.
23 class ClockMcuxpressoFro final
24     : public ClockSource<ElementNonBlockingCannotFail> {
25  public:
26   /// Constructor specifying the FRO divider output to manage.
ClockMcuxpressoFro(clock_fro_output_en_t fro_output)27   constexpr ClockMcuxpressoFro(clock_fro_output_en_t fro_output)
28       : fro_output_(fro_output) {}
29 
30  private:
31   /// Enable this FRO divider.
DoEnable()32   Status DoEnable() final {
33     CLOCK_EnableFroClk(CLKCTL0->FRODIVOEN | fro_output_);
34     return OkStatus();
35   }
36 
37   /// Disable this FRO divider.
DoDisable()38   Status DoDisable() final {
39     CLOCK_EnableFroClk(CLKCTL0->FRODIVOEN & ~fro_output_);
40     return OkStatus();
41   }
42 
43   /// FRO divider.
44   const uint32_t fro_output_;
45 };
46 
47 /// Class implementing the low power oscillator clock source.
48 class ClockMcuxpressoLpOsc final
49     : public ClockSource<ElementNonBlockingCannotFail> {
50  private:
51   /// Enable low power oscillator.
DoEnable()52   Status DoEnable() final {
53     POWER_DisablePD(kPDRUNCFG_PD_LPOSC); /* Power on LPOSC (1MHz) */
54     // POWER_ApplyPD() is not necessary for LPOSC_PD.
55     CLOCK_EnableLpOscClk(); /* Wait until LPOSC stable */
56     return OkStatus();
57   }
58 
59   /// Disable low power oscillator.
DoDisable()60   Status DoDisable() final {
61     POWER_EnablePD(kPDRUNCFG_PD_LPOSC); /* Power down LPOSC (1MHz). */
62     // POWER_ApplyPD() is not necessary for LPOSC_PD.
63     return OkStatus();
64   }
65 };
66 
67 /// Class template implementing the MCLK IN clock source.
68 ///
69 /// Template argument `ElementType` can be of class `ElementBlocking` or
70 /// `ElementNonBlockingCannotFail`.
71 template <typename ElementType>
72 class ClockMcuxpressoMclk final : public DependentElement<ElementType> {
73  public:
74   /// Constructor specifying the MCLK IN clock frequency in Hz and
75   /// the dependent clock tree element to enable the MCLK clock source.
ClockMcuxpressoMclk(ElementType & source,uint32_t frequency)76   constexpr ClockMcuxpressoMclk(ElementType& source, uint32_t frequency)
77       : DependentElement<ElementType>(source), frequency_(frequency) {}
78 
79  private:
80   /// Set MCLK IN clock frequency.
DoEnable()81   Status DoEnable() final {
82     CLOCK_SetMclkFreq(frequency_); /* Sets external MCLKIN freq */
83     return OkStatus();
84   }
85 
86   /// Set MCLK IN clock frequency to 0 Hz.
DoDisable()87   Status DoDisable() final {
88     CLOCK_SetMclkFreq(0); /* Sets external MCLKIN freq */
89     return OkStatus();
90   }
91 
92   /// MCLK IN frequency.
93   uint32_t frequency_;
94 };
95 
96 /// Alias for a blocking MCLK IN clock tree element.
97 using ClockMcuxpressoMclkBlocking = ClockMcuxpressoMclk<ElementBlocking>;
98 
99 /// Alias for a non-blocking MCLK IN clock tree element where updates cannot
100 /// fail.
101 using ClockMcuxpressoMclkNonBlocking =
102     ClockMcuxpressoMclk<ElementNonBlockingCannotFail>;
103 
104 /// Class template implementing the CLK IN pin clock source and selecting
105 /// it as an input source for OSC Clock source.
106 ///
107 /// Template argument `ElementType` can be of class `ElementBlocking` or
108 /// `ElementNonBlockingCannotFail`.
109 template <typename ElementType>
110 class ClockMcuxpressoClkIn final : public DependentElement<ElementType> {
111  public:
112   /// Constructor specifying the CLK IN pin clock frequency in Hz and
113   /// the dependent clock tree element to enable the CLK IN pin clock source.
ClockMcuxpressoClkIn(ElementType & source,uint32_t frequency)114   constexpr ClockMcuxpressoClkIn(ElementType& source, uint32_t frequency)
115       : DependentElement<ElementType>(source), frequency_(frequency) {}
116 
117  private:
118   /// Set CLK IN clock frequency.
DoEnable()119   Status DoEnable() final {
120     CLOCK_SetClkinFreq(
121         frequency_); /*!< Sets CLK_IN pin clock frequency in Hz */
122 
123     // OSC clock source selector ClkIn.
124     const uint8_t kCLOCK_OscClkIn = CLKCTL0_SYSOSCBYPASS_SEL(1);
125     CLKCTL0->SYSOSCBYPASS = kCLOCK_OscClkIn;
126     return OkStatus();
127   }
128 
129   /// Set CLK IN clock frequency to 0 Hz.
DoDisable()130   Status DoDisable() final {
131     CLOCK_SetClkinFreq(0); /*!< Sets CLK_IN pin clock frequency in Hz */
132 
133     // OSC clock source selector None, which gates output to reduce power.
134     const uint8_t kCLOCK_OscNone = CLKCTL0_SYSOSCBYPASS_SEL(7);
135     CLKCTL0->SYSOSCBYPASS = kCLOCK_OscNone;
136     return OkStatus();
137   }
138 
139   /// CLK IN frequency.
140   uint32_t frequency_;
141 };
142 
143 /// Alias for a blocking CLK IN pin clock tree element.
144 using ClockMcuxpressoClkInBlocking = ClockMcuxpressoClkIn<ElementBlocking>;
145 
146 /// Alias for a non-blocking CLK IN pin clock tree element where updates cannot
147 /// fail.
148 using ClockMcuxpressoClkInNonBlocking =
149     ClockMcuxpressoClkIn<ElementNonBlockingCannotFail>;
150 
151 /// Class template implementing the FRG clock tree element.
152 ///
153 /// Template argument `ElementType` can be of class `ElementBlocking` or
154 /// `ElementNonBlockingCannotFail`.
155 template <typename ElementType>
156 class ClockMcuxpressoFrg final : public DependentElement<ElementType> {
157  public:
158   /// Constructor specifying the source clock and FRG configuration.
ClockMcuxpressoFrg(ElementType & source,const clock_frg_clk_config_t & config)159   constexpr ClockMcuxpressoFrg(ElementType& source,
160                                const clock_frg_clk_config_t& config)
161       : DependentElement<ElementType>(source), config_(config) {}
162 
163  private:
164   // FRG clock source selector None, which gates output to reduce power.
165   // The None source selector is not defined in the SDK.
166   const uint8_t kCLOCK_FrgNone = 7;
167 
168   /// Enable FRG configuration.
DoEnable()169   Status DoEnable() final {
170     CLOCK_SetFRGClock(&config_);
171     return OkStatus();
172   }
173 
174   /// Disable FRG configuration.
DoDisable()175   Status DoDisable() final {
176     clock_frg_clk_config_t disable_config = config_;
177     static_assert(sizeof(disable_config.sfg_clock_src) ==
178                   sizeof(kCLOCK_FrgNone));
179     disable_config.sfg_clock_src =
180         static_cast<decltype(disable_config.sfg_clock_src)>(kCLOCK_FrgNone);
181     CLOCK_SetFRGClock(&disable_config);
182     return OkStatus();
183   }
184 
185   /// FRG clock configuration to enable FRG component.
186   const clock_frg_clk_config_t& config_;
187 };
188 
189 /// Alias for a blocking FRG clock tree element.
190 using ClockMcuxpressoFrgBlocking = ClockMcuxpressoFrg<ElementBlocking>;
191 
192 /// Alias for a non-blocking FRG clock tree element where updates cannot fail.
193 using ClockMcuxpressoFrgNonBlocking =
194     ClockMcuxpressoFrg<ElementNonBlockingCannotFail>;
195 
196 /// Class template implementing the clock selector element.
197 ///
198 /// Template argument `ElementType` can be of class `ElementBlocking` or
199 /// `ElementNonBlockingCannotFail`.
200 template <typename ElementType>
201 class ClockMcuxpressoSelector : public DependentElement<ElementType> {
202  public:
203   /// Constructor specifying the source clock and the selector value
204   /// when the selector should get enabled, and the selector value when
205   /// the selector should get disabled to save power.
ClockMcuxpressoSelector(ElementType & source,clock_attach_id_t selector_enable,clock_attach_id_t selector_disable)206   constexpr ClockMcuxpressoSelector(ElementType& source,
207                                     clock_attach_id_t selector_enable,
208                                     clock_attach_id_t selector_disable)
209       : DependentElement<ElementType>(source),
210         selector_enable_(selector_enable),
211         selector_disable_(selector_disable) {}
212 
213  private:
214   /// Enable selector.
DoEnable()215   Status DoEnable() final {
216     CLOCK_AttachClk(selector_enable_);
217     return OkStatus();
218   }
219 
220   /// Disable selector.
DoDisable()221   Status DoDisable() final {
222     CLOCK_AttachClk(selector_disable_);
223     return OkStatus();
224   }
225 
226   /// Enable selector value.
227   clock_attach_id_t selector_enable_;
228   /// Disable selector value.
229   clock_attach_id_t selector_disable_;
230 };
231 
232 /// Alias for a blocking clock selector clock tree element.
233 using ClockMcuxpressoSelectorBlocking =
234     ClockMcuxpressoSelector<ElementBlocking>;
235 
236 /// Alias for a non-blocking clock selector clock tree element where updates
237 /// cannot fail.
238 using ClockMcuxpressoSelectorNonBlocking =
239     ClockMcuxpressoSelector<ElementNonBlockingCannotFail>;
240 
241 /// Class template implementing the clock divider element.
242 ///
243 /// Template argument `ElementType` can be of class `ElementBlocking` or
244 /// `ElementNonBlockingCannotFail`.
245 template <typename ElementType>
246 class ClockMcuxpressoDivider final : public ClockDividerElement<ElementType> {
247  public:
248   /// Constructor specifying the source clock, the name of the divder and
249   /// the divider setting.
ClockMcuxpressoDivider(ElementType & source,clock_div_name_t divider_name,uint32_t divider)250   constexpr ClockMcuxpressoDivider(ElementType& source,
251                                    clock_div_name_t divider_name,
252                                    uint32_t divider)
253       : ClockDividerElement<ElementType>(source, divider),
254         divider_name_(divider_name) {}
255 
256  private:
257   /// Set the divider configuration.
DoEnable()258   Status DoEnable() final {
259     CLOCK_SetClkDiv(divider_name_, this->divider());
260     return OkStatus();
261   }
262 
263   /// Name of divider.
264   clock_div_name_t divider_name_;
265 };
266 
267 /// Alias for a blocking clock divider clock tree element.
268 using ClockMcuxpressoDividerBlocking = ClockMcuxpressoDivider<ElementBlocking>;
269 
270 /// Alias for a non-blocking clock divider clock tree element where updates
271 /// cannot fail.
272 using ClockMcuxpressoDividerNonBlocking =
273     ClockMcuxpressoDivider<ElementNonBlockingCannotFail>;
274 
275 /// Class template implementing the audio pll clock element.
276 ///
277 /// The Audio PLL can either operate in the enabled mode where the PLL
278 /// and the phase fractional divider are enabled, or it can operate in
279 /// bypass mode, where both PLL and phase fractional divider are
280 /// clock gated.
281 /// When the Audio PLL clock tree gets disabled, both PLL and phase fractional
282 /// divider will be clock gated.
283 ///
284 /// Template argument `ElementType` can be of class `ElementBlocking` or
285 /// `ElementNonBlockingCannotFail`.
286 template <typename ElementType>
287 class ClockMcuxpressoAudioPll : public DependentElement<ElementType> {
288  public:
289   /// Constructor specifying the configuration for the enabled Audio PLL.
ClockMcuxpressoAudioPll(ElementType & source,const clock_audio_pll_config_t & config,uint8_t audio_pfd_divider)290   constexpr ClockMcuxpressoAudioPll(ElementType& source,
291                                     const clock_audio_pll_config_t& config,
292                                     uint8_t audio_pfd_divider)
293       : DependentElement<ElementType>(source),
294         config_(&config),
295         audio_pfd_divider_(audio_pfd_divider) {}
296 
297   /// Constructor to place the Audio PLL into bypass mode.
ClockMcuxpressoAudioPll(ElementType & source,audio_pll_src_t bypass_source)298   constexpr ClockMcuxpressoAudioPll(ElementType& source,
299                                     audio_pll_src_t bypass_source)
300       : DependentElement<ElementType>(source), bypass_source_(bypass_source) {}
301 
302  private:
303   /// Configures and enables the audio PLL if `config_` is set, otherwise places
304   /// the audio PLL in bypass mode.
DoEnable()305   Status DoEnable() override {
306     // If `config_` is specified, the PLL should be enabled and the phase
307     // fractional divider PFD0 needs to get configured, otherwise the PLL
308     // operates in bypass mode.
309     if (config_ != nullptr) {
310       // Configure Audio PLL clock source.
311       CLOCK_InitAudioPll(config_);
312       CLOCK_InitAudioPfd(kCLOCK_Pfd0, audio_pfd_divider_);
313     } else {
314       // PLL operates in bypass mode.
315       CLKCTL1->AUDIOPLL0CLKSEL = bypass_source_;
316       CLKCTL1->AUDIOPLL0CTL0 |= CLKCTL1_AUDIOPLL0CTL0_BYPASS_MASK;
317     }
318     return OkStatus();
319   }
320 
321   /// Disables the audio PLL logic.
DoDisable()322   Status DoDisable() override {
323     if (config_ != nullptr) {
324       // Clock gate the phase fractional divider PFD0.
325       CLOCK_DeinitAudioPfd(kCLOCK_Pfd0);
326     }
327 
328     // Power down Audio PLL
329     CLOCK_DeinitAudioPll();
330 
331     // Clock gate audio PLL clock selector.
332     CLKCTL1->AUDIOPLL0CLKSEL = kCLOCK_AudioPllNone;
333     return OkStatus();
334   }
335 
336   /// Optional audio PLL configuration.
337   const clock_audio_pll_config_t* config_ = nullptr;
338 
339   /// Optional audio kCLOCK_Pfd0 clock divider value.
340   const uint8_t audio_pfd_divider_ = 0;
341 
342   /// Optional audio PLL bypass clock source.
343   const audio_pll_src_t bypass_source_ = kCLOCK_AudioPllNone;
344 };
345 
346 /// Alias for a blocking audio PLL clock tree element.
347 using ClockMcuxpressoAudioPllBlocking =
348     ClockMcuxpressoAudioPll<ElementBlocking>;
349 
350 /// Alias for a non-blocking audio PLL clock tree element where updates
351 /// cannot fail.
352 using ClockMcuxpressoAudioPllNonBlocking =
353     ClockMcuxpressoAudioPll<ElementNonBlockingCannotFail>;
354 
355 }  // namespace pw::clock_tree
356