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