1 //*****************************************************************************
2 //
3 //  am_hal_clkgen.c
4 //! @file
5 //!
6 //! @brief Functions for interfacing with the CLKGEN.
7 //!
8 //! @addtogroup clkgen2 Clock Generator (CLKGEN)
9 //! @ingroup apollo2hal
10 //! @{
11 //
12 //*****************************************************************************
13 
14 //*****************************************************************************
15 //
16 // Copyright (c) 2017, Ambiq Micro
17 // All rights reserved.
18 //
19 // Redistribution and use in source and binary forms, with or without
20 // modification, are permitted provided that the following conditions are met:
21 //
22 // 1. Redistributions of source code must retain the above copyright notice,
23 // this list of conditions and the following disclaimer.
24 //
25 // 2. Redistributions in binary form must reproduce the above copyright
26 // notice, this list of conditions and the following disclaimer in the
27 // documentation and/or other materials provided with the distribution.
28 //
29 // 3. Neither the name of the copyright holder nor the names of its
30 // contributors may be used to endorse or promote products derived from this
31 // software without specific prior written permission.
32 //
33 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
34 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
35 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
36 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
37 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
38 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
39 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
40 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
41 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
42 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
43 // POSSIBILITY OF SUCH DAMAGE.
44 //
45 // This is part of revision 1.2.11 of the AmbiqSuite Development Package.
46 //
47 //*****************************************************************************
48 
49 #include <stdint.h>
50 #include <stdbool.h>
51 #include "am_mcu_apollo.h"
52 
53 //*****************************************************************************
54 //
55 // CLKGEN HFADJ register
56 //
57 //*****************************************************************************
58 #define AM_REG_CLKGEN_HFADJ_HFXTADJ_DEFAULT         0x5B8
59 
60 //*****************************************************************************
61 //
62 //! @brief Select the clock divisor for the main system clock.
63 //!
64 //! @param ui32ClockSetting - The divisor value for the system clock.
65 //!
66 //! This function can be used to select the frequency of the main system clock.
67 //! The \e ui32ClockSetting parameter should be set to one of the following
68 //! values:
69 //!
70 //!     AM_HAL_CLKGEN_SYSCLK_MAX
71 //!     AM_HAL_CLKGEN_SYSCLK_48MHZ
72 //!
73 //! @return None.
74 //
75 //*****************************************************************************
76 void
am_hal_clkgen_sysclk_select(uint32_t ui32ClockSetting)77 am_hal_clkgen_sysclk_select(uint32_t ui32ClockSetting)
78 {
79     am_hal_debug_assert_msg(ui32ClockSetting == AM_HAL_CLKGEN_SYSCLK_48MHZ,
80         "am_hal_clkgen_sysclk_select(): invalid clock setting.");
81 
82     //
83     // Unlock the clock control register.
84     //
85     AM_REG(CLKGEN, CLKKEY) = AM_REG_CLKGEN_CLKKEY_KEYVAL;
86 
87     //
88     // Set the HFRC divisor to the user-selected value.
89     //
90     AM_REG(CLKGEN, CCTRL) = ui32ClockSetting;
91 
92     //
93     // Lock the clock configuration registers.
94     //
95     AM_REG(CLKGEN, CLKKEY) = 0;
96 }
97 
98 //*****************************************************************************
99 //
100 //! @brief Get the current system clock frequency.
101 //!
102 //! This function can be used to determine the frequency of the main system
103 //! clock. The return value is the system clock frequency measured in hertz.
104 //!
105 //! @return System clock frequency in Hz
106 //
107 //*****************************************************************************
108 uint32_t
am_hal_clkgen_sysclk_get(void)109 am_hal_clkgen_sysclk_get(void)
110 {
111     uint32_t ui32ClockSetting;
112 
113     //
114     // Read the value of the clock divider.
115     //
116     ui32ClockSetting = AM_REG(CLKGEN, CCTRL) & AM_REG_CLKGEN_CCTRL_CORESEL_M;
117 
118     switch ( ui32ClockSetting )
119     {
120         case AM_REG_CLKGEN_CCTRL_CORESEL_HFRC:
121             return 48000000;
122         case AM_REG_CLKGEN_CCTRL_CORESEL_HFRC_DIV2:
123             return 24000000;
124         default:
125             return 0xFFFFFFFF;
126     }
127 }
128 
129 //*****************************************************************************
130 //
131 //! @brief Enable selected CLKGEN Interrupts.
132 //!
133 //! Use this function to enable the interrupts.
134 //!
135 //! @param ui32Interrupt - Use the macro bit fields provided in am_hal_clkgen.h
136 //!
137 //! @return None
138 //
139 //*****************************************************************************
140 void
am_hal_clkgen_int_enable(uint32_t ui32Interrupt)141 am_hal_clkgen_int_enable(uint32_t ui32Interrupt)
142 {
143     //
144     // Enable the interrupts.
145     //
146     AM_REG(CLKGEN, INTEN) |= ui32Interrupt;
147 }
148 
149 //*****************************************************************************
150 //
151 //! @brief Return enabled CLKGEN Interrupts.
152 //!
153 //! Use this function to get all enabled CLKGEN interrupts.
154 //!
155 //! @return enabled CLKGEN interrupts.
156 //
157 //*****************************************************************************
158 uint32_t
am_hal_clkgen_int_enable_get(void)159 am_hal_clkgen_int_enable_get(void)
160 {
161     //
162     // Return the enabled interrupts.
163     //
164     return AM_REG(CLKGEN, INTEN);
165 }
166 
167 //*****************************************************************************
168 //
169 //! @brief Disable selected CLKGEN Interrupts.
170 //!
171 //! Use this function to disable the CLKGEN interrupts.
172 //!
173 //! @param ui32Interrupt - Use the macro bit fields provided in am_hal_clkgen.h
174 //!
175 //! @return None
176 //
177 //*****************************************************************************
178 void
am_hal_clkgen_int_disable(uint32_t ui32Interrupt)179 am_hal_clkgen_int_disable(uint32_t ui32Interrupt)
180 {
181     //
182     // Disable the interrupts.
183     //
184     AM_REG(CLKGEN, INTEN) &= ~ui32Interrupt;
185 }
186 
187 //*****************************************************************************
188 //
189 //! @brief Sets the interrupt status.
190 //!
191 //! @param ui32IntFlags interrupts to be enabled.
192 //!
193 //! This function sets the interrupts.
194 //!
195 //! Valid values for ui32IntFlags are:
196 //!
197 //!     AM_HAL_CLKGEN_INT_RTC_ALARM
198 //!     AM_HAL_CLKGEN_INT_XT_FAIL
199 //!     AM_HAL_CLKGEN_INT_AUTOCAL_COMPLETE
200 //!     AM_HAL_CLKGEN_INT AUTOCAL_FAIL
201 //!
202 //! @return None.
203 //
204 //*****************************************************************************
205 void
am_hal_clkgen_int_set(uint32_t ui32Interrupt)206 am_hal_clkgen_int_set(uint32_t ui32Interrupt)
207 {
208     //
209     // Set the interrupt status.
210     //
211     AM_REG(CLKGEN, INTSET) = ui32Interrupt;
212 }
213 
214 //*****************************************************************************
215 //
216 //! @brief Gets the interrupt configuration.
217 //!
218 //! @param bEnabledOnly - return the status of only the enabled interrupts.
219 //!
220 //! This function gets the currently configured interrupts.
221 //!
222 //! @return the configured interrupts.
223 //!
224 //! Possible values for the return are:
225 //!
226 //!     AM_HAL_CLKGEN_INT_RTC_ALARM
227 //!     AM_HAL_CLKGEN_INT_XT_FAIL
228 //!     AM_HAL_CLKGEN_INT_AUTOCAL_COMPLETE
229 //!     AM_HAL_CLKGEN_INT AUTOCAL_FAIL
230 //
231 //*****************************************************************************
232 uint32_t
am_hal_clkgen_int_status_get(bool bEnabledOnly)233 am_hal_clkgen_int_status_get(bool bEnabledOnly)
234 {
235     //
236     // Return the status.
237     //
238     if ( bEnabledOnly )
239     {
240         uint32_t u32RetVal = AM_REG(CLKGEN, INTSTAT);
241         u32RetVal &= AM_REG(CLKGEN, INTEN);
242         return u32RetVal;
243     }
244     else
245     {
246         return AM_REG(CLKGEN, INTSTAT);
247     }
248 }
249 
250 //*****************************************************************************
251 //
252 //! @brief Clears the interrupts.
253 //!
254 //! @param ui32IntFlags interrupts to be cleared.
255 //!
256 //! This function clears the interrupts.
257 //!
258 //! Valid values for ui32IntFlags are:
259 //!
260 //!     AM_HAL_CLKGEN_INT_RTC_ALARM
261 //!     AM_HAL_CLKGEN_INT_XT_FAIL
262 //!     AM_HAL_CLKGEN_INT_AUTOCAL_COMPLETE
263 //!     AM_HAL_CLKGEN_INT AUTOCAL_FAIL
264 //!
265 //! @return None.
266 //
267 //*****************************************************************************
268 void
am_hal_clkgen_int_clear(uint32_t ui32Interrupt)269 am_hal_clkgen_int_clear(uint32_t ui32Interrupt)
270 {
271     //
272     // Clear the interrupts.
273     //
274     AM_REG(CLKGEN, INTCLR) = ui32Interrupt;
275 }
276 
277 //*****************************************************************************
278 //
279 //! @brief Starts the desired oscillator(s) (OSC).
280 //!
281 //! @param ui32OscFlags oscillator(s) to start.
282 //!
283 //! This function starts the desired oscillator(s) (OSC).
284 //!
285 //! Valid values for ui32OscFlags are:
286 //!
287 //!     AM_HAL_CLKGEN_OSC_LFRC
288 //!     AM_HAL_CLKGEN_OSC_XT
289 //!
290 //! @return None.
291 //
292 //*****************************************************************************
293 void
am_hal_clkgen_osc_start(uint32_t ui32OscFlags)294 am_hal_clkgen_osc_start(uint32_t ui32OscFlags)
295 {
296     if ( ui32OscFlags & (AM_HAL_CLKGEN_OSC_LFRC | AM_HAL_CLKGEN_OSC_XT) )
297     {
298         //
299         // Start the oscillator(s).
300         // Note that these bits are cleared in order to enable the oscillator.
301         //
302         AM_REG(CLKGEN, OCTRL) &= ~ui32OscFlags;
303     }
304 }
305 
306 //*****************************************************************************
307 //
308 //! @brief Stops the desired oscillator(s) (OSC).
309 //!
310 //! @param ui32OscFlags oscillator(s) to stop.
311 //!
312 //! This function stops the desired oscillator(s) (OSC).
313 //!
314 //! Valid values for ui32OscFlags are:
315 //!
316 //!     AM_HAL_CLKGEN_OSC_LFRC
317 //!     AM_HAL_CLKGEN_OSC_XT
318 //!
319 //! @return None.
320 //
321 //*****************************************************************************
322 void
am_hal_clkgen_osc_stop(uint32_t ui32OscFlags)323 am_hal_clkgen_osc_stop(uint32_t ui32OscFlags)
324 {
325     if ( ui32OscFlags & (AM_HAL_CLKGEN_OSC_LFRC | AM_HAL_CLKGEN_OSC_XT) )
326     {
327         //
328         // Stop the oscillator(s).
329         // Note that these bits are set in order to stop the oscillator.
330         //
331         AM_REG(CLKGEN, OCTRL) |= ui32OscFlags;
332     }
333 }
334 
335 //*****************************************************************************
336 //
337 //! @brief Enables the clock out signal.
338 //!
339 //! @param ui32Signal desired location for the clock out signal.
340 //!
341 //! This function enables the clock out signal. See am_hal_clkgen.h for
342 //! available signals.
343 //!
344 //! e.g. AM_HAL_CLKGEN_CLKOUT_CKSEL_HFRC
345 //!      AM_HAL_CLKGEN_CLKOUT_CKSEL_HFRC_DIV4
346 //!      AM_HAL_CLKGEN_CLKOUT_CKSEL_LFRC
347 //!
348 //! @return None.
349 //
350 //*****************************************************************************
351 void
am_hal_clkgen_clkout_enable(uint32_t ui32Signal)352 am_hal_clkgen_clkout_enable(uint32_t ui32Signal)
353 {
354     //
355     // Enable the clock out on desired signal.
356     //
357     AM_REG(CLKGEN, CLKOUT) = AM_REG_CLKGEN_CLKOUT_CKEN_M | ui32Signal;
358 }
359 
360 //*****************************************************************************
361 //
362 //! @brief Disables the clock out signal.
363 //!
364 //! This function disables the clock out signal.
365 //!
366 //! @return None.
367 //
368 //*****************************************************************************
369 void
am_hal_clkgen_clkout_disable(void)370 am_hal_clkgen_clkout_disable(void)
371 {
372     //
373     // Disable the clock out.
374     //
375     AM_REG(CLKGEN, CLKOUT) = 0;
376 }
377 
378 //*****************************************************************************
379 //
380 //! @brief Enable UART system clock.
381 //!
382 //! This function enables or disables the UART system clock.
383 //!
384 //! @param ui32Module is 0 or 1 for Apollo2.
385 //! @param ui32UartEn is one of the following.
386 //!     AM_HAL_CLKGEN_UARTEN_DIS
387 //!     AM_HAL_CLKGEN_UARTEN_EN
388 //!     AM_HAL_CLKGEN_UARTEN_REDUCE_FREQ
389 //!     AM_HAL_CLKGEN_UARTEN_EN_POWER_SAV
390 //!
391 //! @return None.
392 //
393 //*****************************************************************************
394 void
am_hal_clkgen_uarten_set(uint32_t ui32Module,uint32_t ui32UartEn)395 am_hal_clkgen_uarten_set(uint32_t ui32Module, uint32_t ui32UartEn)
396 {
397     uint32_t ui32Mask;
398 
399     if ( (ui32Module >= AM_REG_UART_NUM_MODULES)        ||
400          (ui32UartEn > AM_HAL_CLKGEN_UARTEN_EN_POWER_SAV) )
401     {
402         return;
403     }
404 
405     ui32UartEn <<= (ui32Module * AM_HAL_CLKGEN_UARTEN_UARTENn_S(ui32Module));
406     ui32Mask = ~(AM_HAL_CLKGEN_UARTEN_UARTENn_M(ui32Module));
407 
408     //
409     // Begin critical section.
410     //
411     AM_CRITICAL_BEGIN_ASM
412 
413     //
414     // Set the UART clock
415     //
416     AM_REG(CLKGEN, UARTEN) &= ui32Mask;
417     AM_REG(CLKGEN, UARTEN) |= ui32UartEn;
418 
419     //
420     // Begin critical section.
421     //
422     AM_CRITICAL_END_ASM
423 }
424 
425 //*****************************************************************************
426 //
427 //! @brief Enables HFRC auto-adjustment at the specified interval.
428 //!
429 //! @param ui32Warmup - How long to give the HFRC to stabilize during each
430 //! calibration attempt.
431 //! @param ui32Frequency - How often the auto-adjustment should happen.
432 //!
433 //! This function enables HFRC auto-adjustment from an external crystal
434 //! oscillator even when the crystal is not normally being used.
435 //!
436 //! ui32Warmup should be one of the following values:
437 //!
438 //!     AM_REG_CLKGEN_HFADJ_HFWARMUP_1SEC
439 //!     AM_REG_CLKGEN_HFADJ_HFWARMUP_2SEC
440 //!
441 //! ui32Frequency should be one of the following values:
442 //!
443 //!     AM_REG_CLKGEN_HFADJ_HFADJCK_4SEC
444 //!     AM_REG_CLKGEN_HFADJ_HFADJCK_16SEC
445 //!     AM_REG_CLKGEN_HFADJ_HFADJCK_32SEC
446 //!     AM_REG_CLKGEN_HFADJ_HFADJCK_64SEC
447 //!     AM_REG_CLKGEN_HFADJ_HFADJCK_128SEC
448 //!     AM_REG_CLKGEN_HFADJ_HFADJCK_256SEC
449 //!     AM_REG_CLKGEN_HFADJ_HFADJCK_512SEC
450 //!     AM_REG_CLKGEN_HFADJ_HFADJCK_1024SEC
451 //!
452 //! @return None.
453 //
454 //*****************************************************************************
455 void
am_hal_clkgen_hfrc_adjust_enable(uint32_t ui32Warmup,uint32_t ui32Frequency)456 am_hal_clkgen_hfrc_adjust_enable(uint32_t ui32Warmup, uint32_t ui32Frequency)
457 {
458     //
459     // Set the HFRC Auto-adjust register for the user's chosen settings. Assume
460     // that the HFRC should be calibrated to 48 MHz and that the crystal is
461     // running at 32.768 kHz.
462     //
463     AM_REG(CLKGEN, HFADJ) =
464          AM_REG_CLKGEN_HFADJ_HFADJ_GAIN_Gain_of_1_in_2                      |
465          ui32Warmup                                                         |
466          AM_REG_CLKGEN_HFADJ_HFXTADJ(AM_REG_CLKGEN_HFADJ_HFXTADJ_DEFAULT)   |
467          ui32Frequency                                                      |
468          AM_REG_CLKGEN_HFADJ_HFADJEN_EN;
469 }
470 
471 //*****************************************************************************
472 //
473 //! @brief Disables HFRC auto-adjustment.
474 //!
475 //! This function disables HFRC auto-adjustment.
476 //!
477 //! @return None.
478 //
479 //*****************************************************************************
480 void
am_hal_clkgen_hfrc_adjust_disable(void)481 am_hal_clkgen_hfrc_adjust_disable(void)
482 {
483     //
484     // Disable the clock out.
485     //
486     AM_REG(CLKGEN, HFADJ) =
487         AM_REG_CLKGEN_HFADJ_HFADJ_GAIN_Gain_of_1_in_2                       |
488         AM_REG_CLKGEN_HFADJ_HFWARMUP_1SEC                                   |
489         AM_REG_CLKGEN_HFADJ_HFXTADJ(AM_REG_CLKGEN_HFADJ_HFXTADJ_DEFAULT)    |
490         AM_REG_CLKGEN_HFADJ_HFADJCK_4SEC                                    |
491         AM_REG_CLKGEN_HFADJ_HFADJEN_DIS;
492 }
493 
494 //*****************************************************************************
495 //
496 // End Doxygen group.
497 //! @}
498 //
499 //*****************************************************************************
500