1 /** 2 * \file 3 * 4 * \brief Chip-specific system clock management functions. 5 * 6 * Copyright (c) 2015 Atmel Corporation. All rights reserved. 7 * 8 * \asf_license_start 9 * 10 * \page License 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions are met: 14 * 15 * 1. Redistributions of source code must retain the above copyright notice, 16 * this list of conditions and the following disclaimer. 17 * 18 * 2. Redistributions in binary form must reproduce the above copyright notice, 19 * this list of conditions and the following disclaimer in the documentation 20 * and/or other materials provided with the distribution. 21 * 22 * 3. The name of Atmel may not be used to endorse or promote products derived 23 * from this software without specific prior written permission. 24 * 25 * 4. This software may only be redistributed and used in connection with an 26 * Atmel microcontroller product. 27 * 28 * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED 29 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 30 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE 31 * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR 32 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 36 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 37 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 38 * POSSIBILITY OF SUCH DAMAGE. 39 * 40 * \asf_license_stop 41 * 42 */ 43 /* 44 * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a> 45 */ 46 47 #include <sysclk.h> 48 49 /// @cond 0 50 /**INDENT-OFF**/ 51 #ifdef __cplusplus 52 extern "C" { 53 #endif 54 /**INDENT-ON**/ 55 /// @endcond 56 57 /** 58 * \weakgroup sysclk_group 59 * @{ 60 */ 61 62 #if defined(CONFIG_SYSCLK_DEFAULT_RETURNS_SLOW_OSC) 63 /** 64 * \brief boolean signalling that the sysclk_init is done. 65 */ 66 uint32_t sysclk_initialized = 0; 67 #endif 68 69 /** 70 * \brief Set system clock prescaler configuration 71 * 72 * This function will change the system clock prescaler configuration to 73 * match the parameters. 74 * 75 * \note The parameters to this function are device-specific. 76 * 77 * \param ul_pres The CPU clock will be divided by \f$2^{mck\_pres}\f$ 78 */ 79 void sysclk_set_prescalers(uint32_t ul_pres) 80 { 81 pmc_mck_set_prescaler(ul_pres); 82 SystemCoreClockUpdate(); 83 } 84 85 /** 86 * \brief Change the source of the main system clock. 87 * 88 * \param ul_src The new system clock source. Must be one of the constants 89 * from the <em>System Clock Sources</em> section. 90 */ 91 void sysclk_set_source(uint32_t ul_src) 92 { 93 switch (ul_src) { 94 case SYSCLK_SRC_SLCK_RC: 95 case SYSCLK_SRC_SLCK_XTAL: 96 case SYSCLK_SRC_SLCK_BYPASS: 97 pmc_mck_set_source(PMC_MCKR_CSS_SLOW_CLK); 98 break; 99 100 case SYSCLK_SRC_MAINCK_4M_RC: 101 case SYSCLK_SRC_MAINCK_8M_RC: 102 case SYSCLK_SRC_MAINCK_12M_RC: 103 case SYSCLK_SRC_MAINCK_XTAL: 104 case SYSCLK_SRC_MAINCK_BYPASS: 105 pmc_mck_set_source(PMC_MCKR_CSS_MAIN_CLK); 106 break; 107 108 case SYSCLK_SRC_PLLACK: 109 pmc_mck_set_source(PMC_MCKR_CSS_PLLA_CLK); 110 break; 111 112 case SYSCLK_SRC_UPLLCK: 113 pmc_mck_set_source(PMC_MCKR_CSS_UPLL_CLK); 114 break; 115 } 116 117 SystemCoreClockUpdate(); 118 } 119 120 #if defined(CONFIG_USBCLK_SOURCE) || defined(__DOXYGEN__) 121 /** 122 * \brief Enable USB clock. 123 * 124 * \note The SAMV71 UDP hardware interprets div as div+1. For readability the hardware div+1 125 * is hidden in this implementation. Use div as div effective value. 126 * 127 * \param pll_id Source of the USB clock. 128 * \param div Actual clock divisor. Must be superior to 0. 129 */ 130 void sysclk_enable_usb(void) 131 { 132 Assert(CONFIG_USBCLK_DIV > 0); 133 134 #ifdef CONFIG_PLL0_SOURCE 135 if (CONFIG_USBCLK_SOURCE == USBCLK_SRC_PLL0) { 136 struct pll_config pllcfg; 137 138 pll_enable_source(CONFIG_PLL0_SOURCE); 139 pll_config_defaults(&pllcfg, 0); 140 pll_enable(&pllcfg, 0); 141 pll_wait_for_lock(0); 142 pmc_switch_udpck_to_pllack(CONFIG_USBCLK_DIV - 1); 143 pmc_enable_udpck(); 144 return; 145 } 146 #endif 147 148 if (CONFIG_USBCLK_SOURCE == USBCLK_SRC_UPLL) { 149 150 pmc_enable_upll_clock(); 151 pmc_switch_udpck_to_upllck(CONFIG_USBCLK_DIV - 1); 152 pmc_enable_udpck(); 153 return; 154 } 155 } 156 157 /** 158 * \brief Disable the USB clock. 159 * 160 * \note This implementation does not switch off the PLL, it just turns off the USB clock. 161 */ 162 void sysclk_disable_usb(void) 163 { 164 pmc_disable_udpck(); 165 } 166 #endif // CONFIG_USBCLK_SOURCE 167 168 void sysclk_init(void) 169 { 170 struct pll_config pllcfg; 171 172 /* Set flash wait state to max in case the below clock switching. */ 173 system_init_flash(CHIP_FREQ_CPU_MAX); 174 175 /* Config system clock setting */ 176 if (CONFIG_SYSCLK_SOURCE == SYSCLK_SRC_SLCK_RC) { 177 osc_enable(OSC_SLCK_32K_RC); 178 osc_wait_ready(OSC_SLCK_32K_RC); 179 pmc_switch_mck_to_sclk(CONFIG_SYSCLK_PRES); 180 } 181 182 else if (CONFIG_SYSCLK_SOURCE == SYSCLK_SRC_SLCK_XTAL) { 183 osc_enable(OSC_SLCK_32K_XTAL); 184 osc_wait_ready(OSC_SLCK_32K_XTAL); 185 pmc_switch_mck_to_sclk(CONFIG_SYSCLK_PRES); 186 } 187 188 else if (CONFIG_SYSCLK_SOURCE == SYSCLK_SRC_SLCK_BYPASS) { 189 osc_enable(OSC_SLCK_32K_BYPASS); 190 osc_wait_ready(OSC_SLCK_32K_BYPASS); 191 pmc_switch_mck_to_sclk(CONFIG_SYSCLK_PRES); 192 } 193 194 else if (CONFIG_SYSCLK_SOURCE == SYSCLK_SRC_MAINCK_4M_RC) { 195 /* Already running from SYSCLK_SRC_MAINCK_4M_RC */ 196 } 197 198 else if (CONFIG_SYSCLK_SOURCE == SYSCLK_SRC_MAINCK_8M_RC) { 199 osc_enable(OSC_MAINCK_8M_RC); 200 osc_wait_ready(OSC_MAINCK_8M_RC); 201 pmc_switch_mck_to_mainck(CONFIG_SYSCLK_PRES); 202 } 203 204 else if (CONFIG_SYSCLK_SOURCE == SYSCLK_SRC_MAINCK_12M_RC) { 205 osc_enable(OSC_MAINCK_12M_RC); 206 osc_wait_ready(OSC_MAINCK_12M_RC); 207 pmc_switch_mck_to_mainck(CONFIG_SYSCLK_PRES); 208 } 209 210 else if (CONFIG_SYSCLK_SOURCE == SYSCLK_SRC_MAINCK_XTAL) { 211 osc_enable(OSC_MAINCK_XTAL); 212 osc_wait_ready(OSC_MAINCK_XTAL); 213 pmc_switch_mck_to_mainck(CONFIG_SYSCLK_PRES); 214 } 215 216 else if (CONFIG_SYSCLK_SOURCE == SYSCLK_SRC_MAINCK_BYPASS) { 217 osc_enable(OSC_MAINCK_BYPASS); 218 osc_wait_ready(OSC_MAINCK_BYPASS); 219 pmc_switch_mck_to_mainck(CONFIG_SYSCLK_PRES); 220 } 221 222 #ifdef CONFIG_PLL0_SOURCE 223 else if (CONFIG_SYSCLK_SOURCE == SYSCLK_SRC_PLLACK) { 224 pll_enable_source(CONFIG_PLL0_SOURCE); 225 pll_config_defaults(&pllcfg, 0); 226 pll_enable(&pllcfg, 0); 227 pll_wait_for_lock(0); 228 pmc_mck_set_division(CONFIG_SYSCLK_DIV); 229 pmc_switch_mck_to_pllack(CONFIG_SYSCLK_PRES); 230 } 231 #endif 232 233 else if (CONFIG_SYSCLK_SOURCE == SYSCLK_SRC_UPLLCK) { 234 pll_enable_source(CONFIG_PLL1_SOURCE); 235 pll_config_defaults(&pllcfg, 1); 236 pll_enable(&pllcfg, 1); 237 pll_wait_for_lock(1); 238 pmc_mck_set_division(CONFIG_SYSCLK_DIV); 239 pmc_switch_mck_to_upllck(CONFIG_SYSCLK_PRES); 240 } 241 /* Update the SystemFrequency variable */ 242 SystemCoreClockUpdate(); 243 244 /* Set a flash wait state depending on the new cpu frequency */ 245 system_init_flash(sysclk_get_cpu_hz()); 246 247 #if (defined CONFIG_SYSCLK_DEFAULT_RETURNS_SLOW_OSC) 248 /* Signal that the internal frequencies are setup */ 249 sysclk_initialized = 1; 250 #endif 251 } 252 253 //! @} 254 255 /// @cond 0 256 /**INDENT-OFF**/ 257 #ifdef __cplusplus 258 } 259 #endif 260 /**INDENT-ON**/ 261 /// @endcond 262