4 * \brief Chip-specific PLL definitions.
\r
6 * Copyright (c) 2011-2012 Atmel Corporation. All rights reserved.
\r
12 * Redistribution and use in source and binary forms, with or without
\r
13 * modification, are permitted provided that the following conditions are met:
\r
15 * 1. Redistributions of source code must retain the above copyright notice,
\r
16 * this list of conditions and the following disclaimer.
\r
18 * 2. Redistributions in binary form must reproduce the above copyright notice,
\r
19 * this list of conditions and the following disclaimer in the documentation
\r
20 * and/or other materials provided with the distribution.
\r
22 * 3. The name of Atmel may not be used to endorse or promote products derived
\r
23 * from this software without specific prior written permission.
\r
25 * 4. This software may only be redistributed and used in connection with an
\r
26 * Atmel microcontroller product.
\r
28 * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
\r
29 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
\r
30 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
\r
31 * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
\r
32 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
\r
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
\r
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
\r
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
\r
36 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
\r
37 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
\r
38 * POSSIBILITY OF SUCH DAMAGE.
\r
44 #ifndef CHIP_PLL_H_INCLUDED
\r
45 #define CHIP_PLL_H_INCLUDED
\r
58 * \weakgroup pll_group
\r
62 #define PLL_OUTPUT_MIN_HZ 60000000
\r
63 #define PLL_OUTPUT_MAX_HZ 130000000
\r
65 #define PLL_INPUT_MIN_HZ 3500000
\r
66 #define PLL_INPUT_MAX_HZ 20000000
\r
72 #define PLL_COUNT 0x3fU
\r
75 PLL_SRC_MAINCK_4M_RC = OSC_MAINCK_4M_RC, //!< Internal 4MHz RC oscillator.
\r
76 PLL_SRC_MAINCK_8M_RC = OSC_MAINCK_8M_RC, //!< Internal 8MHz RC oscillator.
\r
77 PLL_SRC_MAINCK_12M_RC = OSC_MAINCK_12M_RC, //!< Internal 12MHz RC oscillator.
\r
78 PLL_SRC_MAINCK_XTAL = OSC_MAINCK_XTAL, //!< External crystal oscillator.
\r
79 PLL_SRC_MAINCK_BYPASS = OSC_MAINCK_BYPASS, //!< External bypass oscillator.
\r
80 PLL_NR_SOURCES, //!< Number of PLL sources.
\r
87 #define pll_get_default_rate(pll_id) \
\r
88 ((osc_get_rate(CONFIG_PLL##pll_id##_SOURCE) \
\r
89 * CONFIG_PLL##pll_id##_MUL) \
\r
90 / CONFIG_PLL##pll_id##_DIV)
\r
93 * \note The SAM3S PLL hardware interprets mul as mul+1. For readability the hardware mul+1
\r
94 * is hidden in this implementation. Use mul as mul effective value.
\r
96 static inline void pll_config_init(struct pll_config *p_cfg,
\r
97 enum pll_source e_src, uint32_t ul_div, uint32_t ul_mul)
\r
101 Assert(e_src < PLL_NR_SOURCES);
\r
103 /* Calculate internal VCO frequency */
\r
104 vco_hz = osc_get_rate(e_src) / ul_div;
\r
105 Assert(vco_hz >= PLL_INPUT_MIN_HZ);
\r
106 Assert(vco_hz <= PLL_INPUT_MAX_HZ);
\r
109 Assert(vco_hz >= PLL_OUTPUT_MIN_HZ);
\r
110 Assert(vco_hz <= PLL_OUTPUT_MAX_HZ);
\r
112 /* PMC hardware will automatically make it mul+1 */
\r
113 p_cfg->ctrl = CKGR_PLLAR_MULA(ul_mul - 1) | CKGR_PLLAR_DIVA(ul_div) | CKGR_PLLAR_PLLACOUNT(PLL_COUNT);
\r
116 #define pll_config_defaults(cfg, pll_id) \
\r
117 pll_config_init(cfg, \
\r
118 CONFIG_PLL##pll_id##_SOURCE, \
\r
119 CONFIG_PLL##pll_id##_DIV, \
\r
120 CONFIG_PLL##pll_id##_MUL)
\r
122 static inline void pll_config_read(struct pll_config *p_cfg, uint32_t ul_pll_id)
\r
124 Assert(ul_pll_id < NR_PLLS);
\r
126 if (ul_pll_id == PLLA_ID)
\r
127 p_cfg->ctrl = PMC->CKGR_PLLAR;
\r
129 p_cfg->ctrl = PMC->CKGR_PLLBR;
\r
132 static inline void pll_config_write(const struct pll_config *p_cfg, uint32_t ul_pll_id)
\r
134 Assert(ul_pll_id < NR_PLLS);
\r
136 if (ul_pll_id == PLLA_ID) {
\r
137 pmc_disable_pllack(); // Always stop PLL first!
\r
138 PMC->CKGR_PLLAR = CKGR_PLLAR_ONE | p_cfg->ctrl;
\r
140 pmc_disable_pllbck();
\r
141 PMC->CKGR_PLLBR = p_cfg->ctrl;
\r
145 static inline void pll_enable(const struct pll_config *p_cfg, uint32_t ul_pll_id)
\r
147 Assert(ul_pll_id < NR_PLLS);
\r
149 if (ul_pll_id == PLLA_ID) {
\r
150 pmc_disable_pllack(); // Always stop PLL first!
\r
151 PMC->CKGR_PLLAR = CKGR_PLLAR_ONE | p_cfg->ctrl;
\r
153 pmc_disable_pllbck();
\r
154 PMC->CKGR_PLLBR = p_cfg->ctrl;
\r
159 * \note This will only disable the selected PLL, not the underlying oscillator (mainck).
\r
161 static inline void pll_disable(uint32_t ul_pll_id)
\r
163 Assert(ul_pll_id < NR_PLLS);
\r
165 if (ul_pll_id == PLLA_ID)
\r
166 pmc_disable_pllack();
\r
168 pmc_disable_pllbck();
\r
171 static inline uint32_t pll_is_locked(uint32_t ul_pll_id)
\r
173 Assert(ul_pll_id < NR_PLLS);
\r
175 if (ul_pll_id == PLLA_ID)
\r
176 return pmc_is_locked_pllack();
\r
178 return pmc_is_locked_pllbck();
\r
181 static inline void pll_enable_source(enum pll_source e_src)
\r
184 case PLL_SRC_MAINCK_4M_RC:
\r
185 case PLL_SRC_MAINCK_8M_RC:
\r
186 case PLL_SRC_MAINCK_12M_RC:
\r
187 case PLL_SRC_MAINCK_XTAL:
\r
188 case PLL_SRC_MAINCK_BYPASS:
\r
190 osc_wait_ready(e_src);
\r
199 static inline void pll_enable_config_defaults(unsigned int ul_pll_id)
\r
201 struct pll_config pllcfg;
\r
203 if (pll_is_locked(ul_pll_id)) {
\r
204 return; // Pll already running
\r
206 switch (ul_pll_id) {
\r
207 #ifdef CONFIG_PLL0_SOURCE
\r
209 pll_enable_source(CONFIG_PLL0_SOURCE);
\r
210 pll_config_init(&pllcfg,
\r
211 CONFIG_PLL0_SOURCE,
\r
216 #ifdef CONFIG_PLL1_SOURCE
\r
218 pll_enable_source(CONFIG_PLL1_SOURCE);
\r
219 pll_config_init(&pllcfg,
\r
220 CONFIG_PLL1_SOURCE,
\r
229 pll_enable(&pllcfg, ul_pll_id);
\r
230 while (!pll_is_locked(ul_pll_id));
\r
243 #endif /* CHIP_PLL_H_INCLUDED */
\r