1 /** 2 * \file 3 * 4 * \brief Sleep mode access 5 * 6 * Copyright (c) 2012-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 <compiler.h> 48 #include "sleep.h" 49 50 /* SAM3 and SAM4 series */ 51 #if (SAM3S || SAM3N || SAM3XA || SAM3U || SAM4S || SAM4E || SAM4N || SAM4C || \ 52 SAM4CM || SAMG || SAM4CP || SAMV71 || SAMV70 || SAMS70 || SAME70) 53 # include "pmc.h" 54 # include "board.h" 55 56 /* Checking board configuration of main clock xtal statup time */ 57 #if !defined(BOARD_OSC_STARTUP_US) 58 # warning The board main clock xtal statup time has not been defined. Using default settings. 59 # define BOARD_OSC_STARTUP_US (15625UL) 60 #endif 61 62 #if !defined(EFC0) 63 # define EFC0 EFC 64 #endif 65 66 /** 67 * Save clock settings and shutdown PLLs 68 */ 69 __always_inline static void pmc_save_clock_settings( 70 uint32_t *p_osc_setting, 71 uint32_t *p_pll0_setting, 72 uint32_t *p_pll1_setting, 73 uint32_t *p_mck_setting, 74 uint32_t *p_fmr_setting, 75 #if defined(EFC1) 76 uint32_t *p_fmr_setting1, 77 #endif 78 const bool disable_xtal) 79 { 80 uint32_t mor = PMC->CKGR_MOR; 81 uint32_t mckr = PMC->PMC_MCKR; 82 uint32_t fmr = EFC0->EEFC_FMR; 83 # if defined(EFC1) 84 uint32_t fmr1 = EFC1->EEFC_FMR; 85 # endif 86 87 if (p_osc_setting) { 88 *p_osc_setting = mor; 89 } 90 if (p_pll0_setting) { 91 *p_pll0_setting = PMC->CKGR_PLLAR; 92 } 93 if (p_pll1_setting) { 94 #if (SAM3S || SAM4S || SAM4C || SAM4CM || SAM4CP) 95 *p_pll1_setting = PMC->CKGR_PLLBR; 96 #elif (SAM3U || SAM3XA) 97 *p_pll1_setting = PMC->CKGR_UCKR; 98 #else 99 *p_pll1_setting = 0; 100 #endif 101 } 102 if (p_mck_setting) { 103 *p_mck_setting = mckr; 104 } 105 if (p_fmr_setting) { 106 *p_fmr_setting = fmr; 107 } 108 #if defined(EFC1) 109 if (p_fmr_setting1) { 110 *p_fmr_setting1 = fmr1; 111 } 112 #endif 113 114 /* Enable FAST RC */ 115 PMC->CKGR_MOR = CKGR_MOR_KEY_PASSWD | mor | CKGR_MOR_MOSCRCEN; 116 /* if MCK source is PLL, switch to mainck */ 117 if ((mckr & PMC_MCKR_CSS_Msk) > PMC_MCKR_CSS_MAIN_CLK) { 118 /* MCK -> MAINCK */ 119 mckr = (mckr & (~PMC_MCKR_CSS_Msk)) | PMC_MCKR_CSS_MAIN_CLK; 120 PMC->PMC_MCKR = mckr; 121 while(!(PMC->PMC_SR & PMC_SR_MCKRDY)); 122 } 123 /* MCK prescale -> 1 */ 124 if (mckr & PMC_MCKR_PRES_Msk) { 125 mckr = (mckr & (~PMC_MCKR_PRES_Msk)); 126 PMC->PMC_MCKR = mckr; 127 while(!(PMC->PMC_SR & PMC_SR_MCKRDY)); 128 } 129 /* Disable PLLs */ 130 pmc_disable_pllack(); 131 #if (SAM3S || SAM4S || SAM4C || SAM4CM || SAM4CP) 132 pmc_disable_pllbck(); 133 #elif (SAM3U || SAM3XA) 134 pmc_disable_upll_clock(); 135 #endif 136 137 /* Prepare for entering WAIT mode */ 138 /* Wait fast RC ready */ 139 while (!(PMC->PMC_SR & PMC_SR_MOSCRCS)); 140 141 /* Switch mainck to FAST RC */ 142 #if SAMG 143 /** 144 * For the sleepwalking feature, we need an accurate RC clock. Only 24M and 145 * 16M are trimmed in production. Here we select the 24M. 146 * And so wait state need to be 1. 147 */ 148 EFC0->EEFC_FMR = (fmr & (~EEFC_FMR_FWS_Msk)) | EEFC_FMR_FWS(1); 149 150 PMC->CKGR_MOR = (PMC->CKGR_MOR & ~CKGR_MOR_MOSCSEL) | CKGR_MOR_MOSCRCF_24_MHz | 151 CKGR_MOR_KEY_PASSWD; 152 #else 153 PMC->CKGR_MOR = (PMC->CKGR_MOR & ~CKGR_MOR_MOSCSEL) | 154 CKGR_MOR_KEY_PASSWD; 155 #endif 156 while (!(PMC->PMC_SR & PMC_SR_MOSCSELS)); 157 158 #if (!SAMG) 159 /* FWS update */ 160 EFC0->EEFC_FMR = fmr & (~EEFC_FMR_FWS_Msk); 161 #if defined(EFC1) 162 EFC1->EEFC_FMR = fmr1 & (~EEFC_FMR_FWS_Msk); 163 #endif 164 #endif 165 166 /* Disable XTALs */ 167 if (disable_xtal) { 168 PMC->CKGR_MOR = (PMC->CKGR_MOR & ~CKGR_MOR_MOSCXTEN) | 169 CKGR_MOR_KEY_PASSWD; 170 } 171 } 172 173 /** 174 * Restore clock settings 175 */ 176 __always_inline static void pmc_restore_clock_setting( 177 const uint32_t osc_setting, 178 const uint32_t pll0_setting, 179 const uint32_t pll1_setting, 180 const uint32_t mck_setting, 181 const uint32_t fmr_setting 182 #if defined(EFC1) 183 , const uint32_t fmr_setting1 184 #endif 185 ) 186 { 187 uint32_t mckr; 188 uint32_t pll_sr = 0; 189 190 /* Switch mainck to external xtal */ 191 if (CKGR_MOR_MOSCXTBY == (osc_setting & CKGR_MOR_MOSCXTBY)) { 192 /* Bypass mode */ 193 PMC->CKGR_MOR = (PMC->CKGR_MOR & ~CKGR_MOR_MOSCXTEN) | 194 CKGR_MOR_KEY_PASSWD | CKGR_MOR_MOSCXTBY | 195 CKGR_MOR_MOSCSEL; 196 PMC->CKGR_MOR = (PMC->CKGR_MOR & ~CKGR_MOR_MOSCRCEN & 197 ~CKGR_MOR_MOSCRCF_Msk) 198 | CKGR_MOR_KEY_PASSWD; 199 } else if (CKGR_MOR_MOSCXTEN == (osc_setting & CKGR_MOR_MOSCXTEN)) { 200 /* Enable External XTAL */ 201 if (!(PMC->CKGR_MOR & CKGR_MOR_MOSCXTEN)) { 202 PMC->CKGR_MOR = (PMC->CKGR_MOR & ~CKGR_MOR_MOSCXTBY) | 203 CKGR_MOR_KEY_PASSWD | CKGR_MOR_MOSCXTEN; 204 /* Wait the Xtal to stabilize */ 205 while (!(PMC->PMC_SR & PMC_SR_MOSCXTS)); 206 } 207 /* Select External XTAL */ 208 if (!(PMC->CKGR_MOR & CKGR_MOR_MOSCSEL)) { 209 PMC->CKGR_MOR |= CKGR_MOR_KEY_PASSWD | CKGR_MOR_MOSCSEL; 210 while (!(PMC->PMC_SR & PMC_SR_MOSCSELS)); 211 } 212 /* Disable Fast RC */ 213 PMC->CKGR_MOR = (PMC->CKGR_MOR & ~CKGR_MOR_MOSCRCEN & 214 ~CKGR_MOR_MOSCRCF_Msk) 215 | CKGR_MOR_KEY_PASSWD; 216 } 217 218 if (pll0_setting & CKGR_PLLAR_MULA_Msk) { 219 #if (SAM4C || SAM4CM || SAMG || SAM4CP) 220 PMC->CKGR_PLLAR = pll0_setting; 221 #else 222 PMC->CKGR_PLLAR = CKGR_PLLAR_ONE | pll0_setting; 223 #endif 224 pll_sr |= PMC_SR_LOCKA; 225 } 226 #if (SAM3S || SAM4S || SAM4C || SAM4CM || SAM4CP) 227 if (pll1_setting & CKGR_PLLBR_MULB_Msk) { 228 PMC->CKGR_PLLBR = pll1_setting; 229 pll_sr |= PMC_SR_LOCKB; 230 } 231 #elif (SAM3U || SAM3XA) 232 if (pll1_setting & CKGR_UCKR_UPLLEN) { 233 PMC->CKGR_UCKR = pll1_setting; 234 pll_sr |= PMC_SR_LOCKU; 235 } 236 #else 237 UNUSED(pll1_setting); 238 #endif 239 /* Wait MCK source ready */ 240 switch(mck_setting & PMC_MCKR_CSS_Msk) { 241 case PMC_MCKR_CSS_PLLA_CLK: 242 while (!(PMC->PMC_SR & PMC_SR_LOCKA)); 243 break; 244 #if (SAM3S || SAM4S || SAM4C || SAM4CM || SAM4CP) 245 case PMC_MCKR_CSS_PLLB_CLK: 246 while (!(PMC->PMC_SR & PMC_SR_LOCKB)); 247 break; 248 #elif (SAM3U || SAM3XA) 249 case PMC_MCKR_CSS_UPLL_CLK: 250 while (!(PMC->PMC_SR & PMC_SR_LOCKU)); 251 break; 252 #endif 253 } 254 255 /* Switch to faster clock */ 256 mckr = PMC->PMC_MCKR; 257 258 /* Set PRES */ 259 PMC->PMC_MCKR = (mckr & ~PMC_MCKR_PRES_Msk) 260 | (mck_setting & PMC_MCKR_PRES_Msk); 261 while (!(PMC->PMC_SR & PMC_SR_MCKRDY)); 262 263 /* Restore flash wait states */ 264 EFC0->EEFC_FMR = fmr_setting; 265 #if defined(EFC1) 266 EFC1->EEFC_FMR = fmr_setting1; 267 #endif 268 269 /* Set CSS and others */ 270 PMC->PMC_MCKR = mck_setting; 271 while (!(PMC->PMC_SR & PMC_SR_MCKRDY)); 272 273 /* Waiting all restored PLLs ready */ 274 while (!(PMC->PMC_SR & pll_sr)); 275 } 276 277 /** If clocks are switched for some sleep mode */ 278 static volatile bool b_is_sleep_clock_used = false; 279 /** Callback invoked once when clocks are restored */ 280 static pmc_callback_wakeup_clocks_restored_t callback_clocks_restored = NULL; 281 282 void pmc_sleep(int sleep_mode) 283 { 284 switch (sleep_mode) { 285 #if (!(SAMG51 || SAMG53 || SAMG54)) 286 case SAM_PM_SMODE_SLEEP_WFI: 287 case SAM_PM_SMODE_SLEEP_WFE: 288 #if (SAM4S || SAM4E || SAM4N || SAM4C || SAM4CM || SAM4CP || SAMG55 || SAMV71 || SAMV70 || SAMS70 || SAME70) 289 SCB->SCR &= (uint32_t)~SCR_SLEEPDEEP; 290 cpu_irq_enable(); 291 __WFI(); 292 break; 293 #else 294 PMC->PMC_FSMR &= (uint32_t)~PMC_FSMR_LPM; 295 SCB->SCR &= (uint32_t)~SCR_SLEEPDEEP; 296 cpu_irq_enable(); 297 if (sleep_mode == SAM_PM_SMODE_SLEEP_WFI) 298 __WFI(); 299 else 300 __WFE(); 301 break; 302 #endif 303 #endif 304 305 case SAM_PM_SMODE_WAIT_FAST: 306 case SAM_PM_SMODE_WAIT: { 307 uint32_t mor, pllr0, pllr1, mckr; 308 uint32_t fmr; 309 #if defined(EFC1) 310 uint32_t fmr1; 311 #endif 312 #if (SAM4S || SAM4E || SAM4N || SAM4C || SAM4CM || SAM4CP || SAMG55 || SAMV71 || SAMV70 || SAMS70 || SAME70) 313 (sleep_mode == SAM_PM_SMODE_WAIT_FAST) ? 314 pmc_set_flash_in_wait_mode(PMC_FSMR_FLPM_FLASH_STANDBY) : 315 pmc_set_flash_in_wait_mode(PMC_FSMR_FLPM_FLASH_DEEP_POWERDOWN); 316 #endif 317 cpu_irq_disable(); 318 b_is_sleep_clock_used = true; 319 320 #if (SAM4C || SAM4CM || SAM4CP) 321 /* Backup the sub-system 1 status and stop sub-system 1 */ 322 uint32_t cpclk_backup = PMC->PMC_SCSR & 323 (PMC_SCSR_CPCK | PMC_SCSR_CPBMCK); 324 PMC->PMC_SCDR = cpclk_backup | PMC_SCDR_CPKEY_PASSWD; 325 #endif 326 pmc_save_clock_settings(&mor, &pllr0, &pllr1, &mckr, &fmr, 327 #if defined(EFC1) 328 &fmr1, 329 #endif 330 (sleep_mode == SAM_PM_SMODE_WAIT)); 331 332 /* Enter wait mode */ 333 cpu_irq_enable(); 334 335 pmc_enable_waitmode(); 336 337 cpu_irq_disable(); 338 pmc_restore_clock_setting(mor, pllr0, pllr1, mckr, fmr 339 #if defined(EFC1) 340 , fmr1 341 #endif 342 ); 343 344 #if (SAM4C || SAM4CM || SAM4CP) 345 /* Restore the sub-system 1 */ 346 PMC->PMC_SCER = cpclk_backup | PMC_SCER_CPKEY_PASSWD; 347 #endif 348 b_is_sleep_clock_used = false; 349 if (callback_clocks_restored) { 350 callback_clocks_restored(); 351 callback_clocks_restored = NULL; 352 } 353 cpu_irq_enable(); 354 355 break; 356 } 357 #if (!(SAMG51 || SAMG53 || SAMG54)) 358 case SAM_PM_SMODE_BACKUP: 359 SCB->SCR |= SCR_SLEEPDEEP; 360 #if (SAM4S || SAM4E || SAM4N || SAM4C || SAM4CM || SAM4CP || SAMG55 || SAMV71 || SAMV70 || SAMS70 || SAME70) 361 SUPC->SUPC_CR = SUPC_CR_KEY_PASSWD | SUPC_CR_VROFF_STOP_VREG; 362 cpu_irq_enable(); 363 __WFI() ; 364 #else 365 cpu_irq_enable(); 366 __WFE() ; 367 #endif 368 break; 369 #endif 370 } 371 } 372 373 bool pmc_is_wakeup_clocks_restored(void) 374 { 375 return !b_is_sleep_clock_used; 376 } 377 378 void pmc_wait_wakeup_clocks_restore( 379 pmc_callback_wakeup_clocks_restored_t callback) 380 { 381 if (b_is_sleep_clock_used) { 382 cpu_irq_disable(); 383 callback_clocks_restored = callback; 384 } else if (callback) { 385 callback(); 386 } 387 } 388 389 #endif 390