4 * \brief Sleep mode access
\r
6 * Copyright (c) 2012 Atmel Corporation. All rights reserved.
\r
10 * Redistribution and use in source and binary forms, with or without
\r
11 * modification, are permitted provided that the following conditions are met:
\r
13 * 1. Redistributions of source code must retain the above copyright notice,
\r
14 * this list of conditions and the following disclaimer.
\r
16 * 2. Redistributions in binary form must reproduce the above copyright notice,
\r
17 * this list of conditions and the following disclaimer in the documentation
\r
18 * and/or other materials provided with the distribution.
\r
20 * 3. The name of Atmel may not be used to endorse or promote products derived
\r
21 * from this software without specific prior written permission.
\r
23 * 4. This software may only be redistributed and used in connection with an
\r
24 * Atmel microcontroller product.
\r
26 * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
\r
27 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
\r
28 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
\r
29 * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
\r
30 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
\r
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
\r
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
\r
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
\r
34 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
\r
35 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
\r
36 * POSSIBILITY OF SUCH DAMAGE.
\r
49 #include <compiler.h>
\r
52 * \defgroup sleep_group Power Manager (PM)
\r
54 * This is a stub on the SAM Power Manager Control (PMC) for the sleepmgr service.
\r
56 * \note To minimize the code overhead, these functions do not feature
\r
57 * interrupt-protected access since they are likely to be called inside
\r
58 * interrupt handlers or in applications where such protection is not
\r
59 * necessary. If such protection is needed, it must be ensured by the calling
\r
65 #if defined(__DOXYGEN__)
\r
67 * \brief Sets the MCU in the specified sleep mode
\r
68 * \param sleep_mode Sleep mode to set.
\r
72 #if (SAM3S || SAM3N || SAM3XA || SAM3U || SAM4S) // SAM3 and SAM4 series
\r
75 # define SAM_PM_SMODE_ACTIVE 0
\r
76 # define SAM_PM_SMODE_SLEEP_WFE 1
\r
77 # define SAM_PM_SMODE_SLEEP_WFI 2
\r
78 # define SAM_PM_SMODE_WAIT 3
\r
79 # define SAM_PM_SMODE_BACKUP 4
\r
81 /* (SCR) Sleep deep bit */
\r
82 #define SCR_SLEEPDEEP (0x1 << 2)
\r
85 * Save clock settings and shutdown PLLs
\r
87 static inline void pmc_save_clock_settings(
\r
88 uint32_t *p_osc_setting,
\r
89 uint32_t *p_pll0_setting,
\r
90 uint32_t *p_pll1_setting,
\r
91 uint32_t *p_mck_setting)
\r
93 if (p_osc_setting) {
\r
94 *p_osc_setting = PMC->CKGR_MOR;
\r
96 if (p_pll0_setting) {
\r
97 *p_pll0_setting = PMC->CKGR_PLLAR;
\r
99 if (p_pll1_setting) {
\r
101 *p_pll1_setting = PMC->CKGR_PLLBR;
\r
102 #elif SAM3U||SAM3XA
\r
103 *p_pll1_setting = PMC->CKGR_UCKR;
\r
105 *p_pll1_setting = 0;
\r
108 if (p_mck_setting) {
\r
109 *p_mck_setting = PMC->PMC_MCKR;
\r
112 // Switch MCK to Main clock (internal or external 12MHz) for fast wakeup
\r
113 // If MAIN_CLK is already the source, just skip
\r
114 if ((PMC->PMC_MCKR & PMC_MCKR_CSS_Msk) == PMC_MCKR_CSS_MAIN_CLK) {
\r
117 // If we have to enable the MAIN_CLK
\r
118 if ((PMC->PMC_SR & PMC_SR_MOSCXTS) == 0) {
\r
119 // Intend to use internal RC as source of MAIN_CLK
\r
120 pmc_osc_enable_fastrc(CKGR_MOR_MOSCRCF_12_MHz);
\r
121 pmc_switch_mainck_to_fastrc(CKGR_MOR_MOSCRCF_12_MHz);
\r
123 pmc_switch_mck_to_mainck(PMC_MCKR_PRES_CLK_1);
\r
127 * Restore clock settings
\r
129 static inline void pmc_restore_clock_setting(
\r
130 uint32_t osc_setting,
\r
131 uint32_t pll0_setting,
\r
132 uint32_t pll1_setting,
\r
133 uint32_t mck_setting)
\r
136 if ((pll0_setting & CKGR_PLLAR_MULA_Msk) &&
\r
137 pll0_setting != PMC->CKGR_PLLAR) {
\r
138 PMC->CKGR_PLLAR = 0;
\r
139 PMC->CKGR_PLLAR = CKGR_PLLAR_ONE | pll0_setting;
\r
140 while (!(PMC->PMC_SR & PMC_SR_LOCKA));
\r
143 if ((pll1_setting & CKGR_PLLBR_MULB_Msk) &&
\r
144 pll1_setting != PMC->CKGR_PLLBR) {
\r
145 PMC->CKGR_PLLBR = 0;
\r
146 PMC->CKGR_PLLBR = pll1_setting ;
\r
147 while (!(PMC->PMC_SR & PMC_SR_LOCKB));
\r
149 #elif SAM3U||SAM3XA
\r
150 if ((pll1_setting & CKGR_UCKR_UPLLEN) &&
\r
151 pll1_setting != PMC->CKGR_UCKR) {
\r
152 PMC->CKGR_UCKR = 0;
\r
153 PMC->CKGR_UCKR = pll1_setting;
\r
154 while (!(PMC->PMC_SR & PMC_SR_LOCKU));
\r
157 /* Switch to faster clock */
\r
158 mckr = PMC->PMC_MCKR;
\r
160 PMC->PMC_MCKR = (mckr & ~PMC_MCKR_PRES_Msk)
\r
161 | (mck_setting & PMC_MCKR_PRES_Msk);
\r
162 while (!(PMC->PMC_SR & PMC_SR_MCKRDY));
\r
163 // Set CSS and others
\r
164 PMC->PMC_MCKR = mck_setting;
\r
165 while (!(PMC->PMC_SR & PMC_SR_MCKRDY));
\r
166 /* Shutdown fastrc */
\r
167 if (0 == (osc_setting & CKGR_MOR_MOSCRCEN)) {
\r
168 pmc_osc_disable_fastrc();
\r
172 static inline void pmc_sleep(int sleep_mode)
\r
174 switch (sleep_mode) {
\r
175 case SAM_PM_SMODE_SLEEP_WFI:
\r
176 case SAM_PM_SMODE_SLEEP_WFE:
\r
177 PMC->PMC_FSMR &= (uint32_t)~PMC_FSMR_LPM;
\r
178 SCB->SCR &= (uint32_t)~SCR_SLEEPDEEP;
\r
180 if (sleep_mode == SAM_PM_SMODE_SLEEP_WFI)
\r
186 case SAM_PM_SMODE_WAIT: {
\r
187 uint32_t mor, pllr0, pllr1, mckr;
\r
188 pmc_save_clock_settings(&mor, &pllr0, &pllr1, &mckr);
\r
190 PMC->PMC_FSMR |= PMC_FSMR_LPM;
\r
191 SCB->SCR &= (uint32_t)~SCR_SLEEPDEEP ;
\r
196 pmc_restore_clock_setting(mor, pllr0, pllr1, mckr);
\r
201 case SAM_PM_SMODE_BACKUP:
\r
202 SCB->SCR |= SCR_SLEEPDEEP ;
\r
217 #endif /* SLEEP_H */
\r