]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/CORTEX_M4_ATSAM4L_Atmel_Studio/src/asf/common/services/clock/sam4l/dfll.h
Add SAM4L demo.
[freertos] / FreeRTOS / Demo / CORTEX_M4_ATSAM4L_Atmel_Studio / src / asf / common / services / clock / sam4l / dfll.h
1 /**\r
2  * \file\r
3  *\r
4  * \brief Chip-specific DFLL definitions\r
5  *\r
6  * Copyright (c) 2012 Atmel Corporation. All rights reserved.\r
7  *\r
8  * \asf_license_start\r
9  *\r
10  * \page License\r
11  *\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
14  *\r
15  * 1. Redistributions of source code must retain the above copyright notice,\r
16  *    this list of conditions and the following disclaimer.\r
17  *\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
21  *\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
24  *\r
25  * 4. This software may only be redistributed and used in connection with an\r
26  *    Atmel microcontroller product.\r
27  *\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
39  *\r
40  * \asf_license_stop\r
41  *\r
42  */\r
43 #ifndef CHIP_DFLL_H_INCLUDED\r
44 #define CHIP_DFLL_H_INCLUDED\r
45 \r
46 #ifdef __cplusplus\r
47 extern "C" {\r
48 #endif\r
49 \r
50 /**\r
51  * \weakgroup dfll_group\r
52  * @{\r
53  */\r
54 \r
55 #define NR_DFLLS          1\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
60 \r
61 #define DFLL_COARSE_MAX   (255)\r
62 #define DFLL_FINE_MAX     (511)\r
63 #define DFLL_FINE_HALF    (255)\r
64 \r
65 #define DFLL_CALIB_VALUE  (0x0B)\r
66 \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
74 \r
75 #ifndef __ASSEMBLY__\r
76 \r
77 #include "compiler.h"\r
78 #include <genclk.h>\r
79 #include <osc.h>\r
80 \r
81 typedef enum genclk_source dfll_refclk_t;\r
82 \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
91 };\r
92 \r
93 static inline void dfll_config_set_max_step(struct dfll_config *cfg,\r
94                 uint16_t coarse, uint16_t fine)\r
95 {\r
96         cfg->step = (SCIF_DFLL0STEP_CSTEP(coarse)\r
97                         | SCIF_DFLL0STEP_FSTEP(fine));\r
98 }\r
99 \r
100 static inline void dfll_priv_set_frequency_range(struct dfll_config *cfg,\r
101                 uint32_t freq)\r
102 {\r
103         if (freq < DFLL_MAX_RANGE3){\r
104                 cfg->freq_range = DFLL_RANGE3;\r
105         }\r
106         else if (freq < DFLL_MAX_RANGE2){\r
107                 cfg->freq_range = DFLL_RANGE2;\r
108         }\r
109         else if (freq < DFLL_MAX_RANGE1){\r
110                 cfg->freq_range = DFLL_RANGE1;\r
111         }\r
112         else {\r
113                 cfg->freq_range = DFLL_RANGE0;\r
114         }\r
115         cfg->conf &= ~SCIF_DFLL0CONF_RANGE_Msk;\r
116         cfg->conf |=SCIF_DFLL0CONF_RANGE(cfg->freq_range);\r
117 }\r
118 \r
119 static inline void dfll_config_init_open_loop_mode(struct dfll_config *cfg)\r
120 {\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
132 \r
133         cfg->mul = 0;\r
134         cfg->step = 0;\r
135         cfg->ssg = 0;\r
136         cfg->val = 0;\r
137 }\r
138 \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
142 {\r
143         /*\r
144          * Set up generic clock source with specified reference clock\r
145          * and divider.\r
146          */\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
150 \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
159 \r
160         cfg->mul = mul;\r
161         cfg->val = 0;\r
162         /*\r
163          * Initial step length of 4. If this is set too high, the DFLL\r
164          * may fail to lock.\r
165          */\r
166         dfll_config_set_max_step(cfg, 4, 4);\r
167         cfg->ssg = 0;\r
168 }\r
169 #endif\r
170 \r
171 static inline uint32_t dfll_priv_get_source_hz(dfll_refclk_t src)\r
172 {\r
173         /*\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
176          */\r
177         switch (src) {\r
178         case GENCLK_SRC_RCSYS:\r
179                 return OSC_RCSYS_NOMINAL_HZ;\r
180 \r
181 #ifdef BOARD_OSC32_HZ\r
182         case GENCLK_SRC_OSC32K:\r
183                 return BOARD_OSC32_HZ;\r
184 #endif\r
185 \r
186 #ifdef BOARD_OSC0_HZ\r
187         case GENCLK_SRC_OSC0:\r
188                 return BOARD_OSC0_HZ;\r
189 #endif\r
190 \r
191         case GENCLK_SRC_RC80M:\r
192                 return OSC_RC80M_NOMINAL_HZ;\r
193 \r
194         case GENCLK_SRC_RC32K:\r
195                 return OSC_RC32K_NOMINAL_HZ;\r
196 \r
197         default:\r
198                 /* unhandled_case(src) */\r
199                 return 0;\r
200         }\r
201 }\r
202 \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
208 \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
213 \r
214 static inline void dfll_config_set_initial_tuning(struct dfll_config *cfg,\r
215                 uint16_t coarse, uint16_t fine)\r
216 {\r
217         cfg->val = (SCIF_DFLL0VAL_COARSE(coarse)\r
218                         | SCIF_DFLL0VAL_FINE(fine));\r
219 }\r
220 \r
221 /**\r
222  * \brief Tune the DFLL configuration for a specific target frequency\r
223  *\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
231  *\r
232  * \par Calculating the DFLL frequency\r
233  *\r
234  * \f{eqnarray*}{\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
248    \f}\r
249  *\r
250  * \param cfg The DFLL configuration to be tuned.\r
251  * \param target_hz Target frequency in Hz.\r
252  */\r
253 static inline void dfll_config_tune_for_target_hz(struct dfll_config *cfg,\r
254                 uint32_t target_hz)\r
255 {\r
256         uint32_t target_khz;\r
257         uint32_t coarse_khz;\r
258         uint32_t delta_khz;\r
259         uint32_t coarse;\r
260         uint32_t fine;\r
261 \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
270         fine /= 4;\r
271 \r
272         dfll_config_set_initial_tuning(cfg, coarse, fine);\r
273         dfll_priv_set_frequency_range(cfg, target_hz);\r
274 }\r
275 \r
276 static inline void dfll_config_enable_ssg(struct dfll_config *cfg,\r
277                 uint16_t amplitude, uint16_t step_size)\r
278 {\r
279         cfg->ssg = (SCIF_DFLL0SSG_EN\r
280                         | SCIF_DFLL0SSG_AMPLITUDE(amplitude)\r
281                         | SCIF_DFLL0SSG_STEPSIZE(step_size));\r
282 }\r
283 \r
284 static inline void dfll_config_disable_ssg(struct dfll_config *cfg)\r
285 {\r
286         cfg->ssg = 0;\r
287 }\r
288 \r
289 extern void dfll_enable_open_loop(const struct dfll_config *cfg,\r
290                 uint32_t dfll_id);\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
293                 uint32_t dfll_id);\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
298 #endif\r
299 \r
300 static inline bool dfll_is_coarse_locked(uint32_t dfll_id)\r
301 {\r
302         UNUSED(dfll_id);\r
303         return !!(SCIF->SCIF_PCLKSR & SCIF_PCLKSR_DFLL0LOCKC);\r
304 }\r
305 \r
306 static inline bool dfll_is_fine_locked(uint32_t dfll_id)\r
307 {\r
308         UNUSED(dfll_id);\r
309         return !!(SCIF->SCIF_PCLKSR & SCIF_PCLKSR_DFLL0LOCKF);\r
310 }\r
311 \r
312 static inline bool dfll_is_accurate_locked(uint32_t dfll_id)\r
313 {\r
314         UNUSED(dfll_id);\r
315 \r
316         return (dfll_is_coarse_locked(dfll_id) &&\r
317                         dfll_is_fine_locked(dfll_id));\r
318 }\r
319 \r
320 static inline void dfll_enable_source(dfll_refclk_t src)\r
321 {\r
322         switch (src) {\r
323         case GENCLK_SRC_RCSYS:\r
324                 /* Nothing to do */\r
325                 break;\r
326 \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
332                 }\r
333                 break;\r
334 #endif\r
335 \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
341                 }\r
342                 break;\r
343 #endif\r
344 \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
349                 }\r
350                 break;\r
351 \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
356                 }\r
357                 break;\r
358 \r
359         default:\r
360                 Assert(false);\r
361                 break;\r
362         }\r
363 }\r
364 \r
365 #endif /* __ASSEMBLY__ */\r
366 \r
367 //! @}\r
368 \r
369 #ifdef __cplusplus\r
370 }\r
371 #endif\r
372 \r
373 #endif /* CHIP_DFLL_H_INCLUDED */\r