1 /* ----------------------------------------------------------------------------
\r
2 * SAM Software Package License
\r
3 * ----------------------------------------------------------------------------
\r
4 * Copyright (c) 2015, Atmel Corporation
\r
6 * All rights reserved.
\r
8 * Redistribution and use in source and binary forms, with or without
\r
9 * modification, are permitted provided that the following conditions are met:
\r
11 * - Redistributions of source code must retain the above copyright notice,
\r
12 * this list of conditions and the disclaimer below.
\r
14 * Atmel's name may not be used to endorse or promote products derived from
\r
15 * this software without specific prior written permission.
\r
17 * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
\r
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
\r
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
\r
20 * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
\r
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
\r
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
\r
23 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
\r
24 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
\r
25 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
\r
26 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\r
27 * ----------------------------------------------------------------------------
\r
30 /** \addtogroup pmc_module Working with PMC
\r
32 * The PMC driver provides the Interface for configuration the Power Management
\r
37 * <li> Enable & disable peripherals using pmc_enable_peripheral() and
\r
38 * pmc_enable_all_peripherals() or pmc_disable_peripheral() and
\r
39 * pmc_disable_all_peripherals().
\r
40 * <li> Get & set maximum frequency clock for giving peripheral using
\r
41 * pmc_get_peri_max_freq() and pmc_set_peri_max_clock().
\r
42 * <li> Get Peripheral Status for the given peripheral using pmc_is_periph_enabled()
\r
43 * <li> Select clocks's source using pmc_select_external_crystal(),
\r
44 * pmc_select_internal_crystal(), pmc_select_external_osc() and pmc_select_internal_osc().
\r
45 * <li> Switch MCK using pmc_switch_mck_to_pll(), pmc_switch_mck_to_main() and
\r
46 * pmc_switch_mck_to_slck().
\r
47 * <li> Config PLL using pmc_set_pll_a() and pmc_disable_pll_a().
\r
50 * For more accurate information, please look at the PMC section of the
\r
63 * Implementation of PIO (Parallel Input/Output) controller.
\r
66 /*----------------------------------------------------------------------------
\r
68 *----------------------------------------------------------------------------*/
\r
72 #include "peripherals/pmc.h"
\r
76 /*----------------------------------------------------------------------------
\r
78 *----------------------------------------------------------------------------*/
\r
80 static uint32_t _pmc_mck = 0;
\r
82 /*----------------------------------------------------------------------------
\r
84 *----------------------------------------------------------------------------*/
\r
86 static void _pmc_compute_mck(void)
\r
89 uint32_t mckr = PMC->PMC_MCKR;
\r
91 uint32_t css = mckr & PMC_MCKR_CSS_Msk;
\r
93 case PMC_MCKR_CSS_SLOW_CLK:
\r
94 clk = pmc_get_slow_clock();
\r
96 case PMC_MCKR_CSS_MAIN_CLK:
\r
97 clk = pmc_get_main_clock();
\r
99 case PMC_MCKR_CSS_PLLA_CLK:
\r
100 clk = pmc_get_plla_clock();
\r
102 case PMC_MCKR_CSS_UPLL_CLK:
\r
103 clk = pmc_get_upll_clock();
\r
106 /* should never get here... */
\r
110 uint32_t pres = mckr & PMC_MCKR_PRES_Msk;
\r
112 case PMC_MCKR_PRES_CLOCK:
\r
114 case PMC_MCKR_PRES_CLOCK_DIV2:
\r
117 case PMC_MCKR_PRES_CLOCK_DIV4:
\r
120 case PMC_MCKR_PRES_CLOCK_DIV8:
\r
123 case PMC_MCKR_PRES_CLOCK_DIV16:
\r
126 case PMC_MCKR_PRES_CLOCK_DIV32:
\r
129 case PMC_MCKR_PRES_CLOCK_DIV64:
\r
133 /* should never get here... */
\r
137 uint32_t mdiv = mckr & PMC_MCKR_MDIV_Msk;
\r
139 case PMC_MCKR_MDIV_EQ_PCK:
\r
141 case PMC_MCKR_MDIV_PCK_DIV2:
\r
142 clk >>= 1; // divide by 2
\r
144 case PMC_MCKR_MDIV_PCK_DIV4:
\r
145 clk >>= 2; // divide by 4
\r
147 case PMC_MCKR_MDIV_PCK_DIV3:
\r
148 clk /= 3; // divide by 3
\r
151 /* should never get here... */
\r
158 static uint32_t _pmc_get_pck_clock(uint32_t index)
\r
161 uint32_t pck = PMC->PMC_PCK[index];
\r
163 switch (pck & PMC_PCK_CSS_Msk) {
\r
164 case PMC_PCK_CSS_SLOW_CLK:
\r
165 clk = pmc_get_slow_clock();
\r
167 case PMC_PCK_CSS_MAIN_CLK:
\r
168 clk = pmc_get_main_clock();
\r
170 case PMC_PCK_CSS_PLLA_CLK:
\r
171 clk = pmc_get_plla_clock();
\r
173 case PMC_PCK_CSS_UPLL_CLK:
\r
174 clk = pmc_get_upll_clock();
\r
176 case PMC_PCK_CSS_MCK_CLK:
\r
177 clk = pmc_get_master_clock();
\r
179 #ifdef CONFIG_HAVE_PMC_AUDIO_CLOCK
\r
180 case PMC_PCK_CSS_AUDIO_CLK:
\r
181 clk = pmc_get_audio_pmc_clock();
\r
186 uint32_t prescaler = (pck & PMC_PCK_PRES_Msk) >> PMC_PCK_PRES_Pos;
\r
187 return clk / (prescaler + 1);
\r
190 static bool _pmc_get_system_clock_bits(enum _pmc_system_clock clock,
\r
191 uint32_t *scer, uint32_t* scdr, uint32_t *scsr)
\r
197 #ifdef PMC_SCDR_PCK
\r
198 case PMC_SYSTEM_CLOCK_PCK:
\r
204 case PMC_SYSTEM_CLOCK_DDR:
\r
205 e = PMC_SCER_DDRCK;
\r
206 d = PMC_SCDR_DDRCK;
\r
207 s = PMC_SCSR_DDRCK;
\r
209 case PMC_SYSTEM_CLOCK_LCD:
\r
210 e = PMC_SCER_LCDCK;
\r
211 d = PMC_SCDR_LCDCK;
\r
212 s = PMC_SCSR_LCDCK;
\r
214 #ifdef PMC_SCER_SMDCK
\r
215 case PMC_SYSTEM_CLOCK_SMD:
\r
216 e = PMC_SCER_SMDCK;
\r
217 d = PMC_SCDR_SMDCK;
\r
218 s = PMC_SCSR_SMDCK;
\r
221 case PMC_SYSTEM_CLOCK_UHP:
\r
226 case PMC_SYSTEM_CLOCK_UDP:
\r
231 case PMC_SYSTEM_CLOCK_PCK0:
\r
236 case PMC_SYSTEM_CLOCK_PCK1:
\r
241 case PMC_SYSTEM_CLOCK_PCK2:
\r
246 #ifdef PMC_SCER_ISCCK
\r
247 case PMC_SYSTEM_CLOCK_ISC:
\r
248 e = PMC_SCER_ISCCK;
\r
249 d = PMC_SCDR_ISCCK;
\r
250 s = PMC_SCSR_ISCCK;
\r
281 /*----------------------------------------------------------------------------
\r
282 * Exported functions (General)
\r
283 *----------------------------------------------------------------------------*/
\r
285 uint32_t pmc_get_master_clock(void)
\r
288 _pmc_compute_mck();
\r
293 uint32_t pmc_get_slow_clock(void)
\r
295 if (SCKC->SCKC_CR & SCKC_CR_OSCSEL)
\r
296 return SLOW_CLOCK_INT_OSC; /* on-chip slow clock RC */
\r
298 return BOARD_SLOW_CLOCK_EXT_OSC; /* external crystal */
\r
301 uint32_t pmc_get_main_clock(void)
\r
303 if (PMC->CKGR_MOR & CKGR_MOR_MOSCSEL)
\r
304 return MAIN_CLOCK_INT_OSC; /* on-chip main clock RC */
\r
306 return BOARD_MAIN_CLOCK_EXT_OSC; /* external crystal */
\r
309 uint32_t pmc_get_plla_clock(void)
\r
311 uint32_t pllaclk, pllar, pllmula, plldiva;
\r
313 if (PMC->CKGR_MOR & CKGR_MOR_MOSCSEL)
\r
314 pllaclk = MAIN_CLOCK_INT_OSC; /* on-chip main clock RC */
\r
316 pllaclk = BOARD_MAIN_CLOCK_EXT_OSC; /* external crystal */
\r
318 pllar = PMC->CKGR_PLLAR;
\r
319 pllmula = (pllar & CKGR_PLLAR_MULA_Msk) >> CKGR_PLLAR_MULA_Pos;
\r
320 plldiva = (pllar & CKGR_PLLAR_DIVA_Msk) >> CKGR_PLLAR_DIVA_Pos;
\r
321 if (plldiva == 0 || pllmula == 0) {
\r
324 pllaclk = pllaclk * (pllmula + 1) / plldiva;
\r
325 if (PMC->PMC_MCKR & PMC_MCKR_PLLADIV2)
\r
332 uint32_t pmc_get_processor_clock(void)
\r
334 uint32_t procclk, mdiv;
\r
336 procclk = pmc_get_master_clock();
\r
338 mdiv = PMC->PMC_MCKR & PMC_MCKR_MDIV_Msk;
\r
340 case PMC_MCKR_MDIV_EQ_PCK:
\r
342 case PMC_MCKR_MDIV_PCK_DIV2:
\r
343 procclk <<= 1; // multiply by 2
\r
345 case PMC_MCKR_MDIV_PCK_DIV3:
\r
346 procclk *= 3; // multiply by 3
\r
348 case PMC_MCKR_MDIV_PCK_DIV4:
\r
349 procclk <<= 2; // multiply by 4
\r
352 /* should never get here... */
\r
359 void pmc_select_external_crystal(void)
\r
361 int return_to_sclock = 0;
\r
363 if (PMC->PMC_MCKR == PMC_MCKR_CSS(PMC_MCKR_CSS_SLOW_CLK)) {
\r
364 pmc_switch_mck_to_main();
\r
365 return_to_sclock = 1;
\r
368 /* switch from internal RC 32kHz to external OSC 32 kHz */
\r
369 SCKC->SCKC_CR = (SCKC->SCKC_CR & ~SCKC_CR_OSCSEL) | SCKC_CR_OSCSEL_XTAL;
\r
371 /* Wait 5 slow clock cycles for internal resynchronization */
\r
372 volatile int count;
\r
373 for (count = 0; count < 0x1000; count++);
\r
375 /* Switch to slow clock again if needed */
\r
376 if (return_to_sclock)
\r
377 pmc_switch_mck_to_slck();
\r
380 void pmc_select_internal_crystal(void)
\r
382 int return_to_sclock = 0;
\r
384 if (PMC->PMC_MCKR == PMC_MCKR_CSS(PMC_MCKR_CSS_SLOW_CLK)) {
\r
385 pmc_switch_mck_to_main();
\r
386 return_to_sclock = 1;
\r
389 /* switch from extenal OSC 32kHz to internal RC 32 kHz */
\r
390 /* switch slow clock source to internal OSC 32 kHz */
\r
391 SCKC->SCKC_CR = (SCKC->SCKC_CR & ~SCKC_CR_OSCSEL) | SCKC_CR_OSCSEL_RC;
\r
393 /* Wait 5 slow clock cycles for internal resynchronization */
\r
394 volatile int count;
\r
395 for (count = 0; count < 0x1000; count++);
\r
397 /* Switch to slow clock again if needed */
\r
398 if (return_to_sclock)
\r
399 pmc_switch_mck_to_slck();
\r
402 void pmc_select_external_osc(void)
\r
404 /* Enable external osc 12 MHz when needed */
\r
405 if ((PMC->CKGR_MOR & CKGR_MOR_MOSCXTEN) != CKGR_MOR_MOSCXTEN) {
\r
406 PMC->CKGR_MOR |= CKGR_MOR_MOSCXTST(18) | CKGR_MOR_MOSCXTEN | CKGR_MOR_KEY_PASSWD;
\r
407 /* Wait Main Oscillator ready */
\r
408 while(!(PMC->PMC_SR & PMC_SR_MOSCXTS));
\r
411 /* Return if external osc had been selected */
\r
412 if ((PMC->CKGR_MOR & CKGR_MOR_MOSCSEL) == CKGR_MOR_MOSCSEL)
\r
415 /* switch MAIN clock to external OSC 12 MHz */
\r
416 PMC->CKGR_MOR |= CKGR_MOR_MOSCSEL | CKGR_MOR_KEY_PASSWD;
\r
418 /* wait for the command to be taken into account */
\r
419 while ((PMC->CKGR_MOR & CKGR_MOR_MOSCSEL) != CKGR_MOR_MOSCSEL);
\r
421 /* wait MAIN clock status change for external OSC 12 MHz selection */
\r
422 while (!(PMC->PMC_SR & PMC_SR_MOSCSELS));
\r
424 /* disable internal RC 12 MHz to save power */
\r
425 pmc_disable_internal_osc();
\r
428 void pmc_disable_external_osc(void)
\r
430 /* disable external OSC 12 MHz */
\r
431 PMC->CKGR_MOR = (PMC->CKGR_MOR & ~CKGR_MOR_MOSCXTEN) | CKGR_MOR_KEY_PASSWD;
\r
434 void pmc_select_internal_osc(void)
\r
436 #ifdef CKGR_MOR_MOSCRCEN
\r
437 /* Enable internal RC 12 MHz when needed */
\r
438 if ((PMC->CKGR_MOR & CKGR_MOR_MOSCRCEN) != CKGR_MOR_MOSCRCEN) {
\r
439 PMC->CKGR_MOR |= CKGR_MOR_MOSCRCEN | CKGR_MOR_KEY_PASSWD;
\r
440 /* Wait internal 12 MHz RC Startup Time for clock stabilization */
\r
441 while (!(PMC->PMC_SR & PMC_SR_MOSCRCS));
\r
445 /* switch MAIN clock to internal RC 12 MHz */
\r
446 PMC->CKGR_MOR = (PMC->CKGR_MOR & ~CKGR_MOR_MOSCSEL) | CKGR_MOR_KEY_PASSWD;
\r
448 /* in case where MCK is running on MAIN CLK */
\r
449 while (!(PMC->PMC_SR & PMC_SR_MCKRDY));
\r
451 /* disable external OSC 12 MHz to save power*/
\r
452 pmc_disable_external_osc();
\r
455 void pmc_disable_internal_osc(void)
\r
457 #ifdef CKGR_MOR_MOSCRCEN
\r
458 /* disable internal RC 12 MHz */
\r
459 PMC->CKGR_MOR = (PMC->CKGR_MOR & ~CKGR_MOR_MOSCRCEN) | CKGR_MOR_KEY_PASSWD;
\r
463 void pmc_switch_mck_to_pll(void)
\r
465 /* Select PLL as input clock for PCK and MCK */
\r
466 PMC->PMC_MCKR = (PMC->PMC_MCKR & ~PMC_MCKR_CSS_Msk) | PMC_MCKR_CSS_PLLA_CLK;
\r
467 while (!(PMC->PMC_SR & PMC_SR_MCKRDY));
\r
472 void pmc_switch_mck_to_upll(void)
\r
474 /* Select UPLL as input clock for PCK and MCK */
\r
475 PMC->PMC_MCKR = (PMC->PMC_MCKR & ~PMC_MCKR_CSS_Msk) | PMC_MCKR_CSS_UPLL_CLK;
\r
476 while (!(PMC->PMC_SR & PMC_SR_MCKRDY));
\r
481 void pmc_switch_mck_to_main(void)
\r
483 /* Select Main Oscillator as input clock for PCK and MCK */
\r
484 PMC->PMC_MCKR = (PMC->PMC_MCKR & ~PMC_MCKR_CSS_Msk) | PMC_PCK_CSS_MAIN_CLK;
\r
485 while (!(PMC->PMC_SR & PMC_SR_MCKRDY));
\r
490 void pmc_switch_mck_to_slck(void)
\r
492 /* Select Slow Clock as input clock for PCK and MCK */
\r
493 PMC->PMC_MCKR = (PMC->PMC_MCKR & ~PMC_MCKR_CSS_Msk) | PMC_PCK_CSS_SLOW_CLK;
\r
494 while (!(PMC->PMC_SR & PMC_SR_MCKRDY));
\r
499 void pmc_set_mck_prescaler(uint32_t prescaler)
\r
501 /* Change MCK Prescaler divider in PMC_MCKR register */
\r
502 PMC->PMC_MCKR = (PMC->PMC_MCKR & ~PMC_MCKR_PRES_Msk) | prescaler;
\r
503 while (!(PMC->PMC_SR & PMC_SR_MCKRDY));
\r
506 void pmc_set_mck_plla_div(uint32_t divider)
\r
508 if ((PMC->PMC_MCKR & PMC_MCKR_PLLADIV2) == PMC_MCKR_PLLADIV2) {
\r
509 if (divider == 0) {
\r
510 PMC->PMC_MCKR = (PMC->PMC_MCKR & ~PMC_MCKR_PLLADIV2);
\r
513 if (divider == PMC_MCKR_PLLADIV2) {
\r
514 PMC->PMC_MCKR = (PMC->PMC_MCKR | PMC_MCKR_PLLADIV2);
\r
517 while (!(PMC->PMC_SR & PMC_SR_MCKRDY));
\r
520 void pmc_set_mck_h32mxdiv(uint32_t divider)
\r
522 if ((PMC->PMC_MCKR & PMC_MCKR_H32MXDIV) == PMC_MCKR_H32MXDIV_H32MXDIV2) {
\r
523 if (divider == PMC_MCKR_H32MXDIV_H32MXDIV1) {
\r
524 PMC->PMC_MCKR = (PMC->PMC_MCKR & ~PMC_MCKR_H32MXDIV);
\r
527 if (divider == PMC_MCKR_H32MXDIV_H32MXDIV2) {
\r
528 PMC->PMC_MCKR = (PMC->PMC_MCKR | PMC_MCKR_H32MXDIV_H32MXDIV2);
\r
531 while (!(PMC->PMC_SR & PMC_SR_MCKRDY));
\r
534 void pmc_set_mck_divider(uint32_t divider)
\r
536 /* change MCK Prescaler divider in PMC_MCKR register */
\r
537 PMC->PMC_MCKR = (PMC->PMC_MCKR & ~PMC_MCKR_MDIV_Msk) | divider;
\r
538 while (!(PMC->PMC_SR & PMC_SR_MCKRDY));
\r
541 void pmc_set_plla(uint32_t pll, uint32_t cpcr)
\r
543 PMC->CKGR_PLLAR = pll;
\r
544 PMC->PMC_PLLICPR = cpcr;
\r
546 if ((pll & CKGR_PLLAR_DIVA_Msk) != CKGR_PLLAR_DIVA_0) {
\r
547 while (!(PMC->PMC_SR & PMC_SR_LOCKA));
\r
551 void pmc_disable_plla(void)
\r
553 PMC->CKGR_PLLAR = (PMC->CKGR_PLLAR & ~CKGR_PLLAR_MULA_Msk) | CKGR_PLLAR_MULA(0);
\r
556 void pmc_enable_system_clock(enum _pmc_system_clock clock)
\r
558 uint32_t scer, scsr;
\r
559 if (!_pmc_get_system_clock_bits(clock, &scer, NULL, &scsr))
\r
562 PMC->PMC_SCER |= scer;
\r
563 while (!(PMC->PMC_SCSR & scsr));
\r
566 void pmc_disable_system_clock(enum _pmc_system_clock clock)
\r
568 uint32_t scdr, scsr;
\r
569 if (!_pmc_get_system_clock_bits(clock, NULL, &scdr, &scsr))
\r
572 PMC->PMC_SCDR |= scdr;
\r
573 while (PMC->PMC_SCSR & scsr);
\r
576 #ifdef CONFIG_HAVE_PMC_FAST_STARTUP
\r
577 void pmc_set_fast_startup_mode(uint32_t startup_mode)
\r
579 PMC->PMC_FSMR = startup_mode;
\r
582 void pmc_set_fast_startup_polarity(uint32_t high_level, uint32_t low_level)
\r
584 PMC->PMC_FSPR &= ~low_level;
\r
585 PMC->PMC_FSPR |= high_level;
\r
587 #endif /* CONFIG_HAVE_PMC_FAST_STARTUP */
\r
589 void pmc_set_custom_pck_mck(struct pck_mck_cfg *cfg)
\r
591 pmc_switch_mck_to_slck();
\r
594 pmc_select_external_osc();
\r
596 pmc_select_internal_osc();
\r
598 pmc_switch_mck_to_main();
\r
601 pmc_select_external_crystal();
\r
603 pmc_select_internal_crystal();
\r
605 pmc_set_mck_prescaler(cfg->pck_pres);
\r
606 pmc_set_mck_divider(cfg->mck_div);
\r
608 pmc_set_mck_plla_div(cfg->plla_div2 ? PMC_MCKR_PLLADIV2 : 0);
\r
609 if (cfg->plla_mul > 0) {
\r
610 pmc_disable_plla();
\r
611 uint32_t tmp = CKGR_PLLAR_ONE |
\r
612 CKGR_PLLAR_PLLACOUNT(0x3F) |
\r
613 CKGR_PLLAR_OUTA(0x0) |
\r
614 CKGR_PLLAR_MULA(cfg->plla_mul) |
\r
615 CKGR_PLLAR_DIVA(cfg->plla_div);
\r
616 pmc_set_plla(tmp, PMC_PLLICPR_IPLL_PLLA(0x3));
\r
618 pmc_disable_plla();
\r
621 if (cfg->h32mxdiv2)
\r
622 pmc_set_mck_h32mxdiv(PMC_MCKR_H32MXDIV_H32MXDIV2);
\r
624 pmc_set_mck_h32mxdiv(PMC_MCKR_H32MXDIV_H32MXDIV1);
\r
626 switch (cfg->pck_input) {
\r
627 case PMC_MCKR_CSS_PLLA_CLK:
\r
628 pmc_switch_mck_to_pll();
\r
631 case PMC_MCKR_CSS_UPLL_CLK:
\r
632 pmc_switch_mck_to_upll();
\r
635 case PMC_MCKR_CSS_SLOW_CLK:
\r
636 pmc_switch_mck_to_slck();
\r
637 pmc_disable_internal_osc();
\r
638 pmc_disable_external_osc();
\r
643 /*----------------------------------------------------------------------------
\r
644 * Exported functions (Peripherals)
\r
645 *----------------------------------------------------------------------------*/
\r
647 void pmc_enable_peripheral(uint32_t id)
\r
649 assert(id > 1 && id < ID_PERIPH_COUNT);
\r
651 PMC->PMC_PCR = PMC_PCR_PID(id);
\r
652 volatile uint32_t pcr = PMC->PMC_PCR;
\r
654 PMC->PMC_PCR = pcr | PMC_PCR_CMD | PMC_PCR_EN;
\r
657 void pmc_disable_peripheral(uint32_t id)
\r
659 assert(id > 1 && id < ID_PERIPH_COUNT);
\r
661 PMC->PMC_PCR = PMC_PCR_PID(id);
\r
662 volatile uint32_t pcr = PMC->PMC_PCR;
\r
664 PMC->PMC_PCR = PMC_PCR_CMD | (pcr & ~PMC_PCR_EN);
\r
667 uint32_t pmc_is_peripheral_enabled(uint32_t id)
\r
669 assert(id > 1 && id < ID_PERIPH_COUNT);
\r
671 PMC->PMC_PCR = PMC_PCR_PID(id);
\r
672 volatile uint32_t pcr = PMC->PMC_PCR;
\r
674 return !!(pcr & PMC_PCR_EN);
\r
677 uint32_t pmc_get_peripheral_clock(uint32_t id)
\r
679 assert(id > 1 && id < ID_PERIPH_COUNT);
\r
681 uint32_t div = get_peripheral_clock_divider(id);
\r
683 return pmc_get_master_clock() / div;
\r
688 void pmc_disable_all_peripherals(void)
\r
691 for (i = 2; i < ID_PERIPH_COUNT; i++)
\r
692 pmc_disable_peripheral(i);
\r
695 /*----------------------------------------------------------------------------
\r
696 * Exported functions (PCK0-2)
\r
697 *----------------------------------------------------------------------------*/
\r
699 void pmc_configure_pck0(uint32_t clock_source, uint32_t prescaler)
\r
701 pmc_disable_pck0();
\r
702 PMC->PMC_PCK[0] = (clock_source & PMC_PCK_CSS_Msk) | PMC_PCK_PRES(prescaler);
\r
705 void pmc_enable_pck0(void)
\r
707 PMC->PMC_SCER = PMC_SCER_PCK0;
\r
708 while (!(PMC->PMC_SR & PMC_SR_PCKRDY0));
\r
711 void pmc_disable_pck0(void)
\r
713 PMC->PMC_SCDR = PMC_SCDR_PCK0;
\r
714 while (PMC->PMC_SCSR & PMC_SCSR_PCK0);
\r
717 uint32_t pmc_get_pck0_clock(void)
\r
719 return _pmc_get_pck_clock(0);
\r
722 void pmc_configure_pck1(uint32_t clock_source, uint32_t prescaler)
\r
724 pmc_disable_pck1();
\r
725 PMC->PMC_PCK[1] = (clock_source & PMC_PCK_CSS_Msk) | PMC_PCK_PRES(prescaler);
\r
728 void pmc_enable_pck1(void)
\r
730 PMC->PMC_SCER = PMC_SCER_PCK1;
\r
731 while (!(PMC->PMC_SR & PMC_SR_PCKRDY1));
\r
734 void pmc_disable_pck1(void)
\r
736 PMC->PMC_SCDR = PMC_SCDR_PCK1;
\r
737 while (PMC->PMC_SCSR & PMC_SCSR_PCK1);
\r
740 uint32_t pmc_get_pck1_clock(void)
\r
742 return _pmc_get_pck_clock(1);
\r
745 void pmc_configure_pck2(uint32_t clock_source, uint32_t prescaler)
\r
747 pmc_disable_pck2();
\r
748 PMC->PMC_PCK[2] = (clock_source & PMC_PCK_CSS_Msk) | PMC_PCK_PRES(prescaler);
\r
751 void pmc_enable_pck2(void)
\r
753 PMC->PMC_SCER = PMC_SCER_PCK2;
\r
754 while (!(PMC->PMC_SR & PMC_SR_PCKRDY2));
\r
757 void pmc_disable_pck2(void)
\r
759 PMC->PMC_SCDR = PMC_SCDR_PCK2;
\r
760 while (PMC->PMC_SCSR & PMC_SCSR_PCK2);
\r
763 uint32_t pmc_get_pck2_clock(void)
\r
765 return _pmc_get_pck_clock(2);
\r
768 /*----------------------------------------------------------------------------
\r
769 * Exported functions (UPLL)
\r
770 *----------------------------------------------------------------------------*/
\r
772 void pmc_enable_upll_clock(void)
\r
774 /* enable 480Mhz UPLL */
\r
775 PMC->CKGR_UCKR = CKGR_UCKR_UPLLEN | CKGR_UCKR_UPLLCOUNT(0x3)
\r
776 | CKGR_UCKR_BIASCOUNT(0x1);
\r
778 /* wait until UPLL is locked */
\r
779 while (!(PMC->PMC_SR & PMC_SR_LOCKU));
\r
782 void pmc_disable_upll_clock(void)
\r
784 PMC->CKGR_UCKR &= ~CKGR_UCKR_UPLLEN;
\r
787 uint32_t pmc_get_upll_clock(void)
\r
789 #ifdef SFR_UTMICKTRIM_FREQ_Msk
\r
790 uint32_t clktrim = SFR->SFR_UTMICKTRIM & SFR_UTMICKTRIM_FREQ_Msk;
\r
792 case SFR_UTMICKTRIM_FREQ_16:
\r
793 return 30 * BOARD_MAIN_CLOCK_EXT_OSC;
\r
794 case SFR_UTMICKTRIM_FREQ_24:
\r
795 return 20 * BOARD_MAIN_CLOCK_EXT_OSC;
\r
797 return 40 * BOARD_MAIN_CLOCK_EXT_OSC;
\r
800 return 40 * BOARD_MAIN_CLOCK_EXT_OSC;
\r
804 void pmc_enable_upll_bias(void)
\r
806 PMC->CKGR_UCKR |= CKGR_UCKR_BIASEN;
\r
809 void pmc_disable_upll_bias(void)
\r
811 PMC->CKGR_UCKR &= ~CKGR_UCKR_BIASEN;
\r
814 /*----------------------------------------------------------------------------
\r
815 * Exported functions (Generated clocks)
\r
816 *----------------------------------------------------------------------------*/
\r
818 #ifdef CONFIG_HAVE_PMC_GENERATED_CLOCKS
\r
819 void pmc_configure_gck(uint32_t id, uint32_t clock_source, uint32_t div)
\r
821 assert(id > 1 && id < ID_PERIPH_COUNT);
\r
822 assert(!(clock_source & ~PMC_PCR_GCKCSS_Msk));
\r
823 assert(!(div << PMC_PCR_GCKDIV_Pos & ~PMC_PCR_GCKDIV_Msk));
\r
825 pmc_disable_gck(id);
\r
826 PMC->PMC_PCR = PMC_PCR_PID(id);
\r
827 volatile uint32_t pcr = PMC->PMC_PCR;
\r
828 PMC->PMC_PCR = pcr | (clock_source & PMC_PCR_GCKCSS_Msk) | PMC_PCR_CMD
\r
829 | PMC_PCR_GCKDIV(div);
\r
832 void pmc_enable_gck(uint32_t id)
\r
834 assert(id > 1 && id < ID_PERIPH_COUNT);
\r
836 PMC->PMC_PCR = PMC_PCR_PID(id);
\r
837 volatile uint32_t pcr = PMC->PMC_PCR;
\r
838 PMC->PMC_PCR = pcr | PMC_PCR_CMD | PMC_PCR_GCKEN;
\r
839 while (!(PMC->PMC_SR & PMC_SR_GCKRDY));
\r
842 void pmc_disable_gck(uint32_t id)
\r
844 assert(id > 1 && id < ID_PERIPH_COUNT);
\r
846 PMC->PMC_PCR = PMC_PCR_PID(id);
\r
847 volatile uint32_t pcr = PMC->PMC_PCR;
\r
848 PMC->PMC_PCR = PMC_PCR_CMD | (pcr & ~PMC_PCR_GCKEN);
\r
851 uint32_t pmc_get_gck_clock(uint32_t id)
\r
854 assert(id > 1 && id < ID_PERIPH_COUNT);
\r
856 PMC->PMC_PCR = PMC_PCR_PID(id);
\r
857 volatile uint32_t pcr = PMC->PMC_PCR;
\r
859 switch (pcr & PMC_PCR_GCKCSS_Msk) {
\r
860 case PMC_PCR_GCKCSS_SLOW_CLK:
\r
861 clk = pmc_get_slow_clock();
\r
863 case PMC_PCR_GCKCSS_MAIN_CLK:
\r
864 clk = pmc_get_main_clock();
\r
866 case PMC_PCR_GCKCSS_PLLA_CLK:
\r
867 clk = pmc_get_plla_clock();
\r
869 case PMC_PCR_GCKCSS_UPLL_CLK:
\r
870 clk = pmc_get_upll_clock();
\r
872 case PMC_PCR_GCKCSS_MCK_CLK:
\r
873 clk = pmc_get_master_clock();
\r
875 #ifdef CONFIG_HAVE_PMC_AUDIO_CLOCK
\r
876 case PMC_PCR_GCKCSS_AUDIO_CLK:
\r
877 clk = pmc_get_audio_pmc_clock();
\r
882 uint32_t div = (pcr & PMC_PCR_GCKDIV_Msk) >> PMC_PCR_GCKDIV_Pos;
\r
883 return ROUND_INT_DIV(clk, div + 1);
\r
885 #endif /* CONFIG_HAVE_PMC_GENERATED_CLOCKS */
\r
887 /*----------------------------------------------------------------------------
\r
888 * Exported functions (Audio PLL)
\r
889 *----------------------------------------------------------------------------*/
\r
891 #ifdef CONFIG_HAVE_PMC_AUDIO_CLOCK
\r
892 void pmc_configure_audio(struct _pmc_audio_cfg *cfg)
\r
894 /* reset audio clock */
\r
895 PMC->PMC_AUDIO_PLL0 &= ~PMC_AUDIO_PLL0_RESETN;
\r
896 PMC->PMC_AUDIO_PLL0 |= PMC_AUDIO_PLL0_RESETN;
\r
898 /* configure values */
\r
899 uint32_t pll0 = PMC->PMC_AUDIO_PLL0;
\r
900 pll0 &= ~PMC_AUDIO_PLL0_ND_Msk;
\r
901 pll0 |= cfg->nd << PMC_AUDIO_PLL0_ND_Pos;
\r
902 pll0 &= ~PMC_AUDIO_PLL0_QDPMC_Msk;
\r
903 pll0 |= cfg->qdpmc << PMC_AUDIO_PLL0_QDPMC_Pos;
\r
904 PMC->PMC_AUDIO_PLL0 = pll0;
\r
905 uint32_t pll1 = PMC->PMC_AUDIO_PLL1;
\r
906 pll1 &= ~PMC_AUDIO_PLL1_DIV_Msk;
\r
907 pll1 |= cfg->div << PMC_AUDIO_PLL1_DIV_Pos;
\r
908 pll1 &= ~PMC_AUDIO_PLL1_FRACR_Msk;
\r
909 pll1 |= cfg->fracr << PMC_AUDIO_PLL1_FRACR_Pos;
\r
910 pll1 &= ~PMC_AUDIO_PLL1_QDAUDIO_Msk;
\r
911 pll1 |= cfg->qdaudio << PMC_AUDIO_PLL1_QDAUDIO_Pos;
\r
912 PMC->PMC_AUDIO_PLL1 = pll1;
\r
915 void pmc_enable_audio(bool pmc_clock, bool pad_clock)
\r
917 uint32_t bits = PMC_AUDIO_PLL0_PLLEN | PMC_AUDIO_PLL0_RESETN;
\r
918 uint32_t nbits = 0;
\r
921 bits |= PMC_AUDIO_PLL0_PADEN;
\r
923 nbits |= PMC_AUDIO_PLL0_PADEN;
\r
926 bits |= PMC_AUDIO_PLL0_PMCEN;
\r
928 nbits |= PMC_AUDIO_PLL0_PMCEN;
\r
930 PMC->PMC_AUDIO_PLL0 = (PMC->PMC_AUDIO_PLL0 & ~nbits) | bits;
\r
933 void pmc_disable_audio()
\r
935 uint32_t nbits = PMC_AUDIO_PLL0_PLLEN | PMC_AUDIO_PLL0_RESETN |
\r
936 PMC_AUDIO_PLL0_PADEN | PMC_AUDIO_PLL0_PMCEN;
\r
937 PMC->PMC_AUDIO_PLL0 &= ~nbits;
\r
940 uint32_t pmc_get_audio_pmc_clock(void)
\r
942 uint32_t pll0 = PMC->PMC_AUDIO_PLL0;
\r
943 uint32_t pll1 = PMC->PMC_AUDIO_PLL1;
\r
945 uint32_t nd = (pll0 & PMC_AUDIO_PLL0_ND_Msk) >> PMC_AUDIO_PLL0_ND_Pos;
\r
946 uint32_t fracr = (pll1 & PMC_AUDIO_PLL1_FRACR_Msk) >> PMC_AUDIO_PLL1_FRACR_Pos;
\r
947 uint32_t qdpmc = (pll0 & PMC_AUDIO_PLL0_QDPMC_Msk) >> PMC_AUDIO_PLL0_QDPMC_Pos;
\r
949 uint64_t clk = BOARD_MAIN_CLOCK_EXT_OSC;
\r
950 clk *= ((nd + 1) << 22) + fracr;
\r
953 return (uint32_t)clk;
\r
956 uint32_t pmc_get_audio_pad_clock(void)
\r
958 uint32_t pll0 = PMC->PMC_AUDIO_PLL0;
\r
959 uint32_t pll1 = PMC->PMC_AUDIO_PLL1;
\r
961 uint32_t nd = (pll0 & PMC_AUDIO_PLL0_ND_Msk) >> PMC_AUDIO_PLL0_ND_Pos;
\r
962 uint32_t fracr = (pll1 & PMC_AUDIO_PLL1_FRACR_Msk) >> PMC_AUDIO_PLL1_FRACR_Pos;
\r
963 uint32_t qdaudio = (pll1 & PMC_AUDIO_PLL1_QDAUDIO_Msk) >> PMC_AUDIO_PLL1_QDAUDIO_Pos;
\r
967 uint32_t div = (pll1 & PMC_AUDIO_PLL1_DIV_Msk) >> PMC_AUDIO_PLL1_DIV_Pos;
\r
968 if (div != 2 && div != 3)
\r
971 uint64_t clk = BOARD_MAIN_CLOCK_EXT_OSC;
\r
972 clk *= ((nd + 1) << 22) + fracr;
\r
974 clk /= div * qdaudio;
\r
975 return (uint32_t)clk;
\r
977 #endif /* CONFIG_HAVE_PMC_AUDIO_CLOCK */
\r