4 * \brief Chip-specific DFLL definitions
\r
6 * Copyright (c) 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
43 #ifndef CHIP_DFLL_H_INCLUDED
\r
44 #define CHIP_DFLL_H_INCLUDED
\r
51 * \weakgroup dfll_group
\r
56 #define DFLL_MIN_HZ 20000000UL
\r
57 #define DFLL_MAX_HZ 150000000UL
\r
58 #define DFLL_MIN_KHZ (DFLL_MIN_HZ / 1000)
\r
59 #define DFLL_MAX_KHZ (DFLL_MAX_HZ / 1000)
\r
61 #define DFLL_COARSE_MAX (255)
\r
62 #define DFLL_FINE_MAX (511)
\r
63 #define DFLL_FINE_HALF (255)
\r
65 #define DFLL_CALIB_VALUE (0x0B)
\r
67 #define DFLL_RANGE0 (0)
\r
68 #define DFLL_RANGE1 (1)
\r
69 #define DFLL_RANGE2 (2)
\r
70 #define DFLL_RANGE3 (3)
\r
71 #define DFLL_MAX_RANGE1 (110000000)
\r
72 #define DFLL_MAX_RANGE2 (55000000)
\r
73 #define DFLL_MAX_RANGE3 (30000000)
\r
75 #ifndef __ASSEMBLY__
\r
77 #include "compiler.h"
\r
81 typedef enum genclk_source dfll_refclk_t;
\r
83 struct dfll_config {
\r
84 struct genclk_config ref_cfg; //!< Reference clock
\r
85 uint32_t conf; //!< DFLLnCONF
\r
86 uint32_t mul; //!< DFLLnMUL
\r
87 uint32_t step; //!< DFLLnSTEP
\r
88 uint32_t ssg; //!< DFLLnSSG
\r
89 uint32_t val; //!< DFLLnVAL
\r
90 uint8_t freq_range; //!< Frequency Range
\r
93 static inline void dfll_config_set_max_step(struct dfll_config *cfg,
\r
94 uint16_t coarse, uint16_t fine)
\r
96 cfg->step = (SCIF_DFLL0STEP_CSTEP(coarse)
\r
97 | SCIF_DFLL0STEP_FSTEP(fine));
\r
100 static inline void dfll_priv_set_frequency_range(struct dfll_config *cfg,
\r
103 if (freq < DFLL_MAX_RANGE3){
\r
104 cfg->freq_range = DFLL_RANGE3;
\r
106 else if (freq < DFLL_MAX_RANGE2){
\r
107 cfg->freq_range = DFLL_RANGE2;
\r
109 else if (freq < DFLL_MAX_RANGE1){
\r
110 cfg->freq_range = DFLL_RANGE1;
\r
113 cfg->freq_range = DFLL_RANGE0;
\r
115 cfg->conf &= ~SCIF_DFLL0CONF_RANGE_Msk;
\r
116 cfg->conf |=SCIF_DFLL0CONF_RANGE(cfg->freq_range);
\r
119 static inline void dfll_config_init_open_loop_mode(struct dfll_config *cfg)
\r
121 genclk_config_defaults(&cfg->ref_cfg, 0);
\r
122 // Do a sync before reading a dfll conf register
\r
123 SCIF->SCIF_DFLL0SYNC = SCIF_DFLL0SYNC_SYNC;
\r
124 while (!(SCIF->SCIF_PCLKSR & SCIF_PCLKSR_DFLL0RDY));
\r
125 cfg->conf = SCIF->SCIF_DFLL0CONF;
\r
126 // Select Open Loop Mode
\r
127 cfg->conf &= ~SCIF_DFLL0CONF_MODE;
\r
128 // Clear DFLL Frequency Range
\r
129 cfg->freq_range = 0;
\r
130 cfg->conf &= ~SCIF_DFLL0CONF_RANGE_Msk;
\r
131 cfg->conf |= SCIF_DFLL0CONF_RANGE(cfg->freq_range);
\r
139 #ifdef CONFIG_DFLL0_FREQ
\r
140 static inline void dfll_config_init_closed_loop_mode(struct dfll_config *cfg,
\r
141 dfll_refclk_t refclk, uint16_t divide, uint16_t mul)
\r
144 * Set up generic clock source with specified reference clock
\r
147 genclk_config_defaults(&cfg->ref_cfg, 0);
\r
148 genclk_config_set_source(&cfg->ref_cfg, refclk);
\r
149 genclk_config_set_divider(&cfg->ref_cfg, divide);
\r
151 // Do a sync before reading a dfll conf register
\r
152 SCIF->SCIF_DFLL0SYNC = SCIF_DFLL0SYNC_SYNC;
\r
153 while (!(SCIF->SCIF_PCLKSR & SCIF_PCLKSR_DFLL0RDY));
\r
154 cfg->conf = SCIF->SCIF_DFLL0CONF;
\r
155 // Select Closed Loop Mode
\r
156 cfg->conf |= SCIF_DFLL0CONF_MODE;
\r
157 // Write DFLL Frequency Range
\r
158 dfll_priv_set_frequency_range(cfg, CONFIG_DFLL0_FREQ);
\r
163 * Initial step length of 4. If this is set too high, the DFLL
\r
164 * may fail to lock.
\r
166 dfll_config_set_max_step(cfg, 4, 4);
\r
171 static inline uint32_t dfll_priv_get_source_hz(dfll_refclk_t src)
\r
174 * Only handle the cases that actually make sense as a DFLL
\r
175 * source. The DFLL itself is obviously not one of those cases.
\r
178 case GENCLK_SRC_RCSYS:
\r
179 return OSC_RCSYS_NOMINAL_HZ;
\r
181 #ifdef BOARD_OSC32_HZ
\r
182 case GENCLK_SRC_OSC32K:
\r
183 return BOARD_OSC32_HZ;
\r
186 #ifdef BOARD_OSC0_HZ
\r
187 case GENCLK_SRC_OSC0:
\r
188 return BOARD_OSC0_HZ;
\r
191 case GENCLK_SRC_RC80M:
\r
192 return OSC_RC80M_NOMINAL_HZ;
\r
194 case GENCLK_SRC_RC32K:
\r
195 return OSC_RC32K_NOMINAL_HZ;
\r
198 /* unhandled_case(src) */
\r
203 #define dfll_config_defaults(cfg, dfll_id) \
\r
204 dfll_config_init_closed_loop_mode(cfg, \
\r
205 CONFIG_DFLL##dfll_id##_SOURCE, \
\r
206 CONFIG_DFLL##dfll_id##_DIV, \
\r
207 CONFIG_DFLL##dfll_id##_MUL)
\r
209 #define dfll_get_default_rate(dfll_id) \
\r
210 ((dfll_priv_get_source_hz(CONFIG_DFLL##dfll_id##_SOURCE) \
\r
211 * CONFIG_DFLL##dfll_id##_MUL) \
\r
212 / CONFIG_DFLL##dfll_id##_DIV)
\r
214 static inline void dfll_config_set_initial_tuning(struct dfll_config *cfg,
\r
215 uint16_t coarse, uint16_t fine)
\r
217 cfg->val = (SCIF_DFLL0VAL_COARSE(coarse)
\r
218 | SCIF_DFLL0VAL_FINE(fine));
\r
222 * \brief Tune the DFLL configuration for a specific target frequency
\r
224 * This will set the initial coarse and fine DFLL tuning to match the
\r
225 * given target frequency. In open loop mode, this will cause the DFLL
\r
226 * to run close to the specified frequency, though it may not match
\r
227 * exactly. In closed loop mode, the DFLL will automatically tune itself
\r
228 * to the target frequency regardless of the initial tuning, but this
\r
229 * function may be used to set a starting point close to the desired
\r
230 * frequency in order to reduce the startup time.
\r
232 * \par Calculating the DFLL frequency
\r
235 f_{DFLL} &=& \left[f_{min} + \left(f_{max} - f_{min}\right)
\r
236 \frac{\mathrm{COARSE}}{\mathrm{COARSE}_{max}}\right]
\r
237 \left(1 + x \frac{\mathrm{FINE}
\r
238 - \mathrm{FINE}_{half}}{\mathrm{FINE}_{max}}\right)
\r
239 = f_{coarse} \left(1 + x
\r
240 \frac{\mathrm{FINE}
\r
241 - \mathrm{FINE}_{half}}{\mathrm{FINE}_{max}}\right) \\
\r
242 \mathrm{COARSE} &=& \frac{\left(f_{DFLL} - f_{min}\right)}
\r
243 {f_{max} - f_{min}} \mathrm{COARSE}_{max} \\
\r
244 f_{coarse} &=& f_{min} + \left(f_{max} - f_{min}\right)
\r
245 \frac{\mathrm{COARSE}}{\mathrm{COARSE}_{max}} \\
\r
246 \mathrm{FINE} &=& \left(10 \frac{f_{DFLL} - f_{coarse}}
\r
247 {f_{coarse}} + \mathrm{FINE}_{half}\right) / 4
\r
250 * \param cfg The DFLL configuration to be tuned.
\r
251 * \param target_hz Target frequency in Hz.
\r
253 static inline void dfll_config_tune_for_target_hz(struct dfll_config *cfg,
\r
254 uint32_t target_hz)
\r
256 uint32_t target_khz;
\r
257 uint32_t coarse_khz;
\r
258 uint32_t delta_khz;
\r
262 target_khz = target_hz / 1000;
\r
263 coarse = ((target_khz - DFLL_MIN_KHZ) * DFLL_COARSE_MAX)
\r
264 / (DFLL_MAX_KHZ - DFLL_MIN_KHZ);
\r
265 coarse_khz = DFLL_MIN_KHZ + (((DFLL_MAX_KHZ - DFLL_MIN_KHZ)
\r
266 / DFLL_COARSE_MAX) * coarse);
\r
267 delta_khz = target_khz - coarse_khz;
\r
268 fine = (((delta_khz * DFLL_FINE_MAX) * 2) / coarse_khz) * 5;
\r
269 fine += DFLL_FINE_HALF;
\r
272 dfll_config_set_initial_tuning(cfg, coarse, fine);
\r
273 dfll_priv_set_frequency_range(cfg, target_hz);
\r
276 static inline void dfll_config_enable_ssg(struct dfll_config *cfg,
\r
277 uint16_t amplitude, uint16_t step_size)
\r
279 cfg->ssg = (SCIF_DFLL0SSG_EN
\r
280 | SCIF_DFLL0SSG_AMPLITUDE(amplitude)
\r
281 | SCIF_DFLL0SSG_STEPSIZE(step_size));
\r
284 static inline void dfll_config_disable_ssg(struct dfll_config *cfg)
\r
289 extern void dfll_enable_open_loop(const struct dfll_config *cfg,
\r
291 extern void dfll_disable_open_loop(uint32_t dfll_id);
\r
292 extern void dfll_enable_closed_loop(const struct dfll_config *cfg,
\r
294 extern void dfll_disable_closed_loop(uint32_t dfll_id);
\r
295 #ifndef CHIP_GENCLK_H_INCLUDED
\r
296 // This function already has a prototype in genclk.h.
\r
297 extern void dfll_enable_config_defaults(uint32_t dfll_id);
\r
300 static inline bool dfll_is_coarse_locked(uint32_t dfll_id)
\r
303 return !!(SCIF->SCIF_PCLKSR & SCIF_PCLKSR_DFLL0LOCKC);
\r
306 static inline bool dfll_is_fine_locked(uint32_t dfll_id)
\r
309 return !!(SCIF->SCIF_PCLKSR & SCIF_PCLKSR_DFLL0LOCKF);
\r
312 static inline bool dfll_is_accurate_locked(uint32_t dfll_id)
\r
316 return (dfll_is_coarse_locked(dfll_id) &&
\r
317 dfll_is_fine_locked(dfll_id));
\r
320 static inline void dfll_enable_source(dfll_refclk_t src)
\r
323 case GENCLK_SRC_RCSYS:
\r
324 /* Nothing to do */
\r
327 #ifdef BOARD_OSC32_HZ
\r
328 case GENCLK_SRC_OSC32K:
\r
329 if (!osc_is_ready(OSC_ID_OSC32)) {
\r
330 osc_enable(OSC_ID_OSC32);
\r
331 osc_wait_ready(OSC_ID_OSC32);
\r
336 #ifdef BOARD_OSC0_HZ
\r
337 case GENCLK_SRC_OSC0:
\r
338 if (!osc_is_ready(OSC_ID_OSC0)) {
\r
339 osc_enable(OSC_ID_OSC0);
\r
340 osc_wait_ready(OSC_ID_OSC0);
\r
345 case GENCLK_SRC_RC80M:
\r
346 if (!osc_is_ready(OSC_ID_RC80M)) {
\r
347 osc_enable(OSC_ID_RC80M);
\r
348 osc_wait_ready(OSC_ID_RC80M);
\r
352 case GENCLK_SRC_RC32K:
\r
353 if (!osc_is_ready(OSC_ID_RC32K)) {
\r
354 osc_enable(OSC_ID_RC32K);
\r
355 osc_wait_ready(OSC_ID_RC32K);
\r
365 #endif /* __ASSEMBLY__ */
\r
373 #endif /* CHIP_DFLL_H_INCLUDED */
\r