xref: /btstack/port/samv71-xplained-atwilc3000/ASF/sam/drivers/pmc/sleep.c (revision 1b2596b5303dd8caeea8565532c93cca8dab8cc4)
1*1b2596b5SMatthias Ringwald /**
2*1b2596b5SMatthias Ringwald  * \file
3*1b2596b5SMatthias Ringwald  *
4*1b2596b5SMatthias Ringwald  * \brief Sleep mode access
5*1b2596b5SMatthias Ringwald  *
6*1b2596b5SMatthias Ringwald  * Copyright (c) 2012-2015 Atmel Corporation. All rights reserved.
7*1b2596b5SMatthias Ringwald  *
8*1b2596b5SMatthias Ringwald  * \asf_license_start
9*1b2596b5SMatthias Ringwald  *
10*1b2596b5SMatthias Ringwald  * \page License
11*1b2596b5SMatthias Ringwald  *
12*1b2596b5SMatthias Ringwald  * Redistribution and use in source and binary forms, with or without
13*1b2596b5SMatthias Ringwald  * modification, are permitted provided that the following conditions are met:
14*1b2596b5SMatthias Ringwald  *
15*1b2596b5SMatthias Ringwald  * 1. Redistributions of source code must retain the above copyright notice,
16*1b2596b5SMatthias Ringwald  *    this list of conditions and the following disclaimer.
17*1b2596b5SMatthias Ringwald  *
18*1b2596b5SMatthias Ringwald  * 2. Redistributions in binary form must reproduce the above copyright notice,
19*1b2596b5SMatthias Ringwald  *    this list of conditions and the following disclaimer in the documentation
20*1b2596b5SMatthias Ringwald  *    and/or other materials provided with the distribution.
21*1b2596b5SMatthias Ringwald  *
22*1b2596b5SMatthias Ringwald  * 3. The name of Atmel may not be used to endorse or promote products derived
23*1b2596b5SMatthias Ringwald  *    from this software without specific prior written permission.
24*1b2596b5SMatthias Ringwald  *
25*1b2596b5SMatthias Ringwald  * 4. This software may only be redistributed and used in connection with an
26*1b2596b5SMatthias Ringwald  *    Atmel microcontroller product.
27*1b2596b5SMatthias Ringwald  *
28*1b2596b5SMatthias Ringwald  * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
29*1b2596b5SMatthias Ringwald  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
30*1b2596b5SMatthias Ringwald  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
31*1b2596b5SMatthias Ringwald  * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
32*1b2596b5SMatthias Ringwald  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33*1b2596b5SMatthias Ringwald  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34*1b2596b5SMatthias Ringwald  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35*1b2596b5SMatthias Ringwald  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
36*1b2596b5SMatthias Ringwald  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
37*1b2596b5SMatthias Ringwald  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38*1b2596b5SMatthias Ringwald  * POSSIBILITY OF SUCH DAMAGE.
39*1b2596b5SMatthias Ringwald  *
40*1b2596b5SMatthias Ringwald  * \asf_license_stop
41*1b2596b5SMatthias Ringwald  *
42*1b2596b5SMatthias Ringwald  */
43*1b2596b5SMatthias Ringwald /*
44*1b2596b5SMatthias Ringwald  * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
45*1b2596b5SMatthias Ringwald  */
46*1b2596b5SMatthias Ringwald 
47*1b2596b5SMatthias Ringwald #include <compiler.h>
48*1b2596b5SMatthias Ringwald #include "sleep.h"
49*1b2596b5SMatthias Ringwald 
50*1b2596b5SMatthias Ringwald /* SAM3 and SAM4 series */
51*1b2596b5SMatthias Ringwald #if (SAM3S || SAM3N || SAM3XA || SAM3U || SAM4S || SAM4E || SAM4N || SAM4C || \
52*1b2596b5SMatthias Ringwald 		SAM4CM || SAMG || SAM4CP || SAMV71 || SAMV70 || SAMS70 || SAME70)
53*1b2596b5SMatthias Ringwald # include "pmc.h"
54*1b2596b5SMatthias Ringwald # include "board.h"
55*1b2596b5SMatthias Ringwald 
56*1b2596b5SMatthias Ringwald /* Checking board configuration of main clock xtal statup time */
57*1b2596b5SMatthias Ringwald #if !defined(BOARD_OSC_STARTUP_US)
58*1b2596b5SMatthias Ringwald # warning The board main clock xtal statup time has not been defined. Using default settings.
59*1b2596b5SMatthias Ringwald # define BOARD_OSC_STARTUP_US    (15625UL)
60*1b2596b5SMatthias Ringwald #endif
61*1b2596b5SMatthias Ringwald 
62*1b2596b5SMatthias Ringwald #if !defined(EFC0)
63*1b2596b5SMatthias Ringwald # define EFC0 EFC
64*1b2596b5SMatthias Ringwald #endif
65*1b2596b5SMatthias Ringwald 
66*1b2596b5SMatthias Ringwald /**
67*1b2596b5SMatthias Ringwald  * Save clock settings and shutdown PLLs
68*1b2596b5SMatthias Ringwald  */
pmc_save_clock_settings(uint32_t * p_osc_setting,uint32_t * p_pll0_setting,uint32_t * p_pll1_setting,uint32_t * p_mck_setting,uint32_t * p_fmr_setting,uint32_t * p_fmr_setting1,const bool disable_xtal)69*1b2596b5SMatthias Ringwald __always_inline static void pmc_save_clock_settings(
70*1b2596b5SMatthias Ringwald 		uint32_t *p_osc_setting,
71*1b2596b5SMatthias Ringwald 		uint32_t *p_pll0_setting,
72*1b2596b5SMatthias Ringwald 		uint32_t *p_pll1_setting,
73*1b2596b5SMatthias Ringwald 		uint32_t *p_mck_setting,
74*1b2596b5SMatthias Ringwald 		uint32_t *p_fmr_setting,
75*1b2596b5SMatthias Ringwald #if defined(EFC1)
76*1b2596b5SMatthias Ringwald 		uint32_t *p_fmr_setting1,
77*1b2596b5SMatthias Ringwald #endif
78*1b2596b5SMatthias Ringwald 		const bool disable_xtal)
79*1b2596b5SMatthias Ringwald {
80*1b2596b5SMatthias Ringwald 	uint32_t mor  = PMC->CKGR_MOR;
81*1b2596b5SMatthias Ringwald 	uint32_t mckr = PMC->PMC_MCKR;
82*1b2596b5SMatthias Ringwald 	uint32_t fmr  = EFC0->EEFC_FMR;
83*1b2596b5SMatthias Ringwald # if defined(EFC1)
84*1b2596b5SMatthias Ringwald 	uint32_t fmr1 = EFC1->EEFC_FMR;
85*1b2596b5SMatthias Ringwald # endif
86*1b2596b5SMatthias Ringwald 
87*1b2596b5SMatthias Ringwald 	if (p_osc_setting) {
88*1b2596b5SMatthias Ringwald 		*p_osc_setting = mor;
89*1b2596b5SMatthias Ringwald 	}
90*1b2596b5SMatthias Ringwald 	if (p_pll0_setting) {
91*1b2596b5SMatthias Ringwald 		*p_pll0_setting = PMC->CKGR_PLLAR;
92*1b2596b5SMatthias Ringwald 	}
93*1b2596b5SMatthias Ringwald 	if (p_pll1_setting) {
94*1b2596b5SMatthias Ringwald #if (SAM3S || SAM4S || SAM4C || SAM4CM || SAM4CP)
95*1b2596b5SMatthias Ringwald 		*p_pll1_setting = PMC->CKGR_PLLBR;
96*1b2596b5SMatthias Ringwald #elif (SAM3U || SAM3XA)
97*1b2596b5SMatthias Ringwald 		*p_pll1_setting = PMC->CKGR_UCKR;
98*1b2596b5SMatthias Ringwald #else
99*1b2596b5SMatthias Ringwald 		*p_pll1_setting = 0;
100*1b2596b5SMatthias Ringwald #endif
101*1b2596b5SMatthias Ringwald 	}
102*1b2596b5SMatthias Ringwald 	if (p_mck_setting) {
103*1b2596b5SMatthias Ringwald 		*p_mck_setting  = mckr;
104*1b2596b5SMatthias Ringwald 	}
105*1b2596b5SMatthias Ringwald 	if (p_fmr_setting) {
106*1b2596b5SMatthias Ringwald 		*p_fmr_setting  = fmr;
107*1b2596b5SMatthias Ringwald 	}
108*1b2596b5SMatthias Ringwald #if defined(EFC1)
109*1b2596b5SMatthias Ringwald 	if (p_fmr_setting1) {
110*1b2596b5SMatthias Ringwald 		*p_fmr_setting1 = fmr1;
111*1b2596b5SMatthias Ringwald 	}
112*1b2596b5SMatthias Ringwald #endif
113*1b2596b5SMatthias Ringwald 
114*1b2596b5SMatthias Ringwald 	/* Enable FAST RC */
115*1b2596b5SMatthias Ringwald 	PMC->CKGR_MOR = CKGR_MOR_KEY_PASSWD | mor | CKGR_MOR_MOSCRCEN;
116*1b2596b5SMatthias Ringwald 	/* if MCK source is PLL, switch to mainck */
117*1b2596b5SMatthias Ringwald 	if ((mckr & PMC_MCKR_CSS_Msk) > PMC_MCKR_CSS_MAIN_CLK) {
118*1b2596b5SMatthias Ringwald 		/* MCK -> MAINCK */
119*1b2596b5SMatthias Ringwald 		mckr = (mckr & (~PMC_MCKR_CSS_Msk)) | PMC_MCKR_CSS_MAIN_CLK;
120*1b2596b5SMatthias Ringwald 		PMC->PMC_MCKR = mckr;
121*1b2596b5SMatthias Ringwald 		while(!(PMC->PMC_SR & PMC_SR_MCKRDY));
122*1b2596b5SMatthias Ringwald 	}
123*1b2596b5SMatthias Ringwald 	/* MCK prescale -> 1 */
124*1b2596b5SMatthias Ringwald 	if (mckr & PMC_MCKR_PRES_Msk) {
125*1b2596b5SMatthias Ringwald 		mckr = (mckr & (~PMC_MCKR_PRES_Msk));
126*1b2596b5SMatthias Ringwald 		PMC->PMC_MCKR = mckr;
127*1b2596b5SMatthias Ringwald 		while(!(PMC->PMC_SR & PMC_SR_MCKRDY));
128*1b2596b5SMatthias Ringwald 	}
129*1b2596b5SMatthias Ringwald 	/* Disable PLLs */
130*1b2596b5SMatthias Ringwald 	pmc_disable_pllack();
131*1b2596b5SMatthias Ringwald #if (SAM3S || SAM4S || SAM4C || SAM4CM || SAM4CP)
132*1b2596b5SMatthias Ringwald 	pmc_disable_pllbck();
133*1b2596b5SMatthias Ringwald #elif (SAM3U || SAM3XA)
134*1b2596b5SMatthias Ringwald 	pmc_disable_upll_clock();
135*1b2596b5SMatthias Ringwald #endif
136*1b2596b5SMatthias Ringwald 
137*1b2596b5SMatthias Ringwald 	/* Prepare for entering WAIT mode */
138*1b2596b5SMatthias Ringwald 	/* Wait fast RC ready */
139*1b2596b5SMatthias Ringwald 	while (!(PMC->PMC_SR & PMC_SR_MOSCRCS));
140*1b2596b5SMatthias Ringwald 
141*1b2596b5SMatthias Ringwald 	/* Switch mainck to FAST RC */
142*1b2596b5SMatthias Ringwald #if SAMG
143*1b2596b5SMatthias Ringwald 	/**
144*1b2596b5SMatthias Ringwald 	 * For the sleepwalking feature, we need an accurate RC clock. Only 24M and
145*1b2596b5SMatthias Ringwald 	 * 16M are trimmed in production. Here we select the 24M.
146*1b2596b5SMatthias Ringwald 	 * And so wait state need to be 1.
147*1b2596b5SMatthias Ringwald 	 */
148*1b2596b5SMatthias Ringwald 	EFC0->EEFC_FMR = (fmr & (~EEFC_FMR_FWS_Msk)) | EEFC_FMR_FWS(1);
149*1b2596b5SMatthias Ringwald 
150*1b2596b5SMatthias Ringwald 	PMC->CKGR_MOR = (PMC->CKGR_MOR & ~CKGR_MOR_MOSCSEL) | CKGR_MOR_MOSCRCF_24_MHz |
151*1b2596b5SMatthias Ringwald 			CKGR_MOR_KEY_PASSWD;
152*1b2596b5SMatthias Ringwald #else
153*1b2596b5SMatthias Ringwald 	PMC->CKGR_MOR = (PMC->CKGR_MOR & ~CKGR_MOR_MOSCSEL) |
154*1b2596b5SMatthias Ringwald 			CKGR_MOR_KEY_PASSWD;
155*1b2596b5SMatthias Ringwald #endif
156*1b2596b5SMatthias Ringwald 	while (!(PMC->PMC_SR & PMC_SR_MOSCSELS));
157*1b2596b5SMatthias Ringwald 
158*1b2596b5SMatthias Ringwald #if (!SAMG)
159*1b2596b5SMatthias Ringwald 	/* FWS update */
160*1b2596b5SMatthias Ringwald 	EFC0->EEFC_FMR = fmr & (~EEFC_FMR_FWS_Msk);
161*1b2596b5SMatthias Ringwald #if defined(EFC1)
162*1b2596b5SMatthias Ringwald 	EFC1->EEFC_FMR = fmr1 & (~EEFC_FMR_FWS_Msk);
163*1b2596b5SMatthias Ringwald #endif
164*1b2596b5SMatthias Ringwald #endif
165*1b2596b5SMatthias Ringwald 
166*1b2596b5SMatthias Ringwald 	/* Disable XTALs */
167*1b2596b5SMatthias Ringwald 	if (disable_xtal) {
168*1b2596b5SMatthias Ringwald 		PMC->CKGR_MOR = (PMC->CKGR_MOR & ~CKGR_MOR_MOSCXTEN) |
169*1b2596b5SMatthias Ringwald 				CKGR_MOR_KEY_PASSWD;
170*1b2596b5SMatthias Ringwald 	}
171*1b2596b5SMatthias Ringwald }
172*1b2596b5SMatthias Ringwald 
173*1b2596b5SMatthias Ringwald /**
174*1b2596b5SMatthias Ringwald  * Restore clock settings
175*1b2596b5SMatthias Ringwald  */
pmc_restore_clock_setting(const uint32_t osc_setting,const uint32_t pll0_setting,const uint32_t pll1_setting,const uint32_t mck_setting,const uint32_t fmr_setting,const uint32_t fmr_setting1)176*1b2596b5SMatthias Ringwald __always_inline static void pmc_restore_clock_setting(
177*1b2596b5SMatthias Ringwald 		const uint32_t osc_setting,
178*1b2596b5SMatthias Ringwald 		const uint32_t pll0_setting,
179*1b2596b5SMatthias Ringwald 		const uint32_t pll1_setting,
180*1b2596b5SMatthias Ringwald 		const uint32_t mck_setting,
181*1b2596b5SMatthias Ringwald 		const uint32_t fmr_setting
182*1b2596b5SMatthias Ringwald #if defined(EFC1)
183*1b2596b5SMatthias Ringwald 		, const uint32_t fmr_setting1
184*1b2596b5SMatthias Ringwald #endif
185*1b2596b5SMatthias Ringwald 		)
186*1b2596b5SMatthias Ringwald {
187*1b2596b5SMatthias Ringwald 	uint32_t mckr;
188*1b2596b5SMatthias Ringwald 	uint32_t pll_sr = 0;
189*1b2596b5SMatthias Ringwald 
190*1b2596b5SMatthias Ringwald 	/* Switch mainck to external xtal */
191*1b2596b5SMatthias Ringwald 	if (CKGR_MOR_MOSCXTBY == (osc_setting & CKGR_MOR_MOSCXTBY)) {
192*1b2596b5SMatthias Ringwald 		/* Bypass mode */
193*1b2596b5SMatthias Ringwald 		PMC->CKGR_MOR = (PMC->CKGR_MOR & ~CKGR_MOR_MOSCXTEN) |
194*1b2596b5SMatthias Ringwald 				CKGR_MOR_KEY_PASSWD | CKGR_MOR_MOSCXTBY |
195*1b2596b5SMatthias Ringwald 				CKGR_MOR_MOSCSEL;
196*1b2596b5SMatthias Ringwald 		PMC->CKGR_MOR = (PMC->CKGR_MOR & ~CKGR_MOR_MOSCRCEN &
197*1b2596b5SMatthias Ringwald 					~CKGR_MOR_MOSCRCF_Msk)
198*1b2596b5SMatthias Ringwald 				| CKGR_MOR_KEY_PASSWD;
199*1b2596b5SMatthias Ringwald 	} else if (CKGR_MOR_MOSCXTEN == (osc_setting & CKGR_MOR_MOSCXTEN)) {
200*1b2596b5SMatthias Ringwald 		/* Enable External XTAL */
201*1b2596b5SMatthias Ringwald 		if (!(PMC->CKGR_MOR & CKGR_MOR_MOSCXTEN)) {
202*1b2596b5SMatthias Ringwald 			PMC->CKGR_MOR = (PMC->CKGR_MOR & ~CKGR_MOR_MOSCXTBY) |
203*1b2596b5SMatthias Ringwald 					CKGR_MOR_KEY_PASSWD | CKGR_MOR_MOSCXTEN;
204*1b2596b5SMatthias Ringwald 			/* Wait the Xtal to stabilize */
205*1b2596b5SMatthias Ringwald 			while (!(PMC->PMC_SR & PMC_SR_MOSCXTS));
206*1b2596b5SMatthias Ringwald 		}
207*1b2596b5SMatthias Ringwald 		/* Select External XTAL */
208*1b2596b5SMatthias Ringwald 		if (!(PMC->CKGR_MOR & CKGR_MOR_MOSCSEL)) {
209*1b2596b5SMatthias Ringwald 			PMC->CKGR_MOR |= CKGR_MOR_KEY_PASSWD | CKGR_MOR_MOSCSEL;
210*1b2596b5SMatthias Ringwald 			while (!(PMC->PMC_SR & PMC_SR_MOSCSELS));
211*1b2596b5SMatthias Ringwald 		}
212*1b2596b5SMatthias Ringwald 		/* Disable Fast RC */
213*1b2596b5SMatthias Ringwald 		PMC->CKGR_MOR = (PMC->CKGR_MOR & ~CKGR_MOR_MOSCRCEN &
214*1b2596b5SMatthias Ringwald 						~CKGR_MOR_MOSCRCF_Msk)
215*1b2596b5SMatthias Ringwald 					| CKGR_MOR_KEY_PASSWD;
216*1b2596b5SMatthias Ringwald 	}
217*1b2596b5SMatthias Ringwald 
218*1b2596b5SMatthias Ringwald 	if (pll0_setting & CKGR_PLLAR_MULA_Msk) {
219*1b2596b5SMatthias Ringwald #if (SAM4C || SAM4CM || SAMG || SAM4CP)
220*1b2596b5SMatthias Ringwald 		PMC->CKGR_PLLAR = pll0_setting;
221*1b2596b5SMatthias Ringwald #else
222*1b2596b5SMatthias Ringwald 		PMC->CKGR_PLLAR = CKGR_PLLAR_ONE | pll0_setting;
223*1b2596b5SMatthias Ringwald #endif
224*1b2596b5SMatthias Ringwald 		pll_sr |= PMC_SR_LOCKA;
225*1b2596b5SMatthias Ringwald 	}
226*1b2596b5SMatthias Ringwald #if (SAM3S || SAM4S || SAM4C || SAM4CM || SAM4CP)
227*1b2596b5SMatthias Ringwald 	if (pll1_setting & CKGR_PLLBR_MULB_Msk) {
228*1b2596b5SMatthias Ringwald 		PMC->CKGR_PLLBR = pll1_setting;
229*1b2596b5SMatthias Ringwald 		pll_sr |= PMC_SR_LOCKB;
230*1b2596b5SMatthias Ringwald 	}
231*1b2596b5SMatthias Ringwald #elif (SAM3U || SAM3XA)
232*1b2596b5SMatthias Ringwald 	if (pll1_setting & CKGR_UCKR_UPLLEN) {
233*1b2596b5SMatthias Ringwald 		PMC->CKGR_UCKR = pll1_setting;
234*1b2596b5SMatthias Ringwald 		pll_sr |= PMC_SR_LOCKU;
235*1b2596b5SMatthias Ringwald 	}
236*1b2596b5SMatthias Ringwald #else
237*1b2596b5SMatthias Ringwald 	UNUSED(pll1_setting);
238*1b2596b5SMatthias Ringwald #endif
239*1b2596b5SMatthias Ringwald 	/* Wait MCK source ready */
240*1b2596b5SMatthias Ringwald 	switch(mck_setting & PMC_MCKR_CSS_Msk) {
241*1b2596b5SMatthias Ringwald 	case PMC_MCKR_CSS_PLLA_CLK:
242*1b2596b5SMatthias Ringwald 		while (!(PMC->PMC_SR & PMC_SR_LOCKA));
243*1b2596b5SMatthias Ringwald 		break;
244*1b2596b5SMatthias Ringwald #if (SAM3S || SAM4S || SAM4C || SAM4CM || SAM4CP)
245*1b2596b5SMatthias Ringwald 	case PMC_MCKR_CSS_PLLB_CLK:
246*1b2596b5SMatthias Ringwald 		while (!(PMC->PMC_SR & PMC_SR_LOCKB));
247*1b2596b5SMatthias Ringwald 		break;
248*1b2596b5SMatthias Ringwald #elif (SAM3U || SAM3XA)
249*1b2596b5SMatthias Ringwald 	case PMC_MCKR_CSS_UPLL_CLK:
250*1b2596b5SMatthias Ringwald 		while (!(PMC->PMC_SR & PMC_SR_LOCKU));
251*1b2596b5SMatthias Ringwald 		break;
252*1b2596b5SMatthias Ringwald #endif
253*1b2596b5SMatthias Ringwald 	}
254*1b2596b5SMatthias Ringwald 
255*1b2596b5SMatthias Ringwald 	/* Switch to faster clock */
256*1b2596b5SMatthias Ringwald 	mckr = PMC->PMC_MCKR;
257*1b2596b5SMatthias Ringwald 
258*1b2596b5SMatthias Ringwald 	/* Set PRES */
259*1b2596b5SMatthias Ringwald 	PMC->PMC_MCKR = (mckr & ~PMC_MCKR_PRES_Msk)
260*1b2596b5SMatthias Ringwald 		| (mck_setting & PMC_MCKR_PRES_Msk);
261*1b2596b5SMatthias Ringwald 	while (!(PMC->PMC_SR & PMC_SR_MCKRDY));
262*1b2596b5SMatthias Ringwald 
263*1b2596b5SMatthias Ringwald 	/* Restore flash wait states */
264*1b2596b5SMatthias Ringwald 	EFC0->EEFC_FMR = fmr_setting;
265*1b2596b5SMatthias Ringwald #if defined(EFC1)
266*1b2596b5SMatthias Ringwald 	EFC1->EEFC_FMR = fmr_setting1;
267*1b2596b5SMatthias Ringwald #endif
268*1b2596b5SMatthias Ringwald 
269*1b2596b5SMatthias Ringwald 	/* Set CSS and others */
270*1b2596b5SMatthias Ringwald 	PMC->PMC_MCKR = mck_setting;
271*1b2596b5SMatthias Ringwald 	while (!(PMC->PMC_SR & PMC_SR_MCKRDY));
272*1b2596b5SMatthias Ringwald 
273*1b2596b5SMatthias Ringwald 	/* Waiting all restored PLLs ready */
274*1b2596b5SMatthias Ringwald 	while (!(PMC->PMC_SR & pll_sr));
275*1b2596b5SMatthias Ringwald }
276*1b2596b5SMatthias Ringwald 
277*1b2596b5SMatthias Ringwald /** If clocks are switched for some sleep mode */
278*1b2596b5SMatthias Ringwald static volatile bool b_is_sleep_clock_used = false;
279*1b2596b5SMatthias Ringwald /** Callback invoked once when clocks are restored */
280*1b2596b5SMatthias Ringwald static pmc_callback_wakeup_clocks_restored_t callback_clocks_restored = NULL;
281*1b2596b5SMatthias Ringwald 
pmc_sleep(int sleep_mode)282*1b2596b5SMatthias Ringwald void pmc_sleep(int sleep_mode)
283*1b2596b5SMatthias Ringwald {
284*1b2596b5SMatthias Ringwald 	switch (sleep_mode) {
285*1b2596b5SMatthias Ringwald #if (!(SAMG51 || SAMG53 || SAMG54))
286*1b2596b5SMatthias Ringwald 	case SAM_PM_SMODE_SLEEP_WFI:
287*1b2596b5SMatthias Ringwald 	case SAM_PM_SMODE_SLEEP_WFE:
288*1b2596b5SMatthias Ringwald #if (SAM4S || SAM4E || SAM4N || SAM4C || SAM4CM || SAM4CP || SAMG55 || SAMV71 || SAMV70 || SAMS70 || SAME70)
289*1b2596b5SMatthias Ringwald 		SCB->SCR &= (uint32_t)~SCR_SLEEPDEEP;
290*1b2596b5SMatthias Ringwald 		cpu_irq_enable();
291*1b2596b5SMatthias Ringwald 		__WFI();
292*1b2596b5SMatthias Ringwald 		break;
293*1b2596b5SMatthias Ringwald #else
294*1b2596b5SMatthias Ringwald 		PMC->PMC_FSMR &= (uint32_t)~PMC_FSMR_LPM;
295*1b2596b5SMatthias Ringwald 		SCB->SCR &= (uint32_t)~SCR_SLEEPDEEP;
296*1b2596b5SMatthias Ringwald 		cpu_irq_enable();
297*1b2596b5SMatthias Ringwald 		if (sleep_mode == SAM_PM_SMODE_SLEEP_WFI)
298*1b2596b5SMatthias Ringwald 			__WFI();
299*1b2596b5SMatthias Ringwald 		else
300*1b2596b5SMatthias Ringwald 			__WFE();
301*1b2596b5SMatthias Ringwald 		break;
302*1b2596b5SMatthias Ringwald #endif
303*1b2596b5SMatthias Ringwald #endif
304*1b2596b5SMatthias Ringwald 
305*1b2596b5SMatthias Ringwald 	case SAM_PM_SMODE_WAIT_FAST:
306*1b2596b5SMatthias Ringwald 	case SAM_PM_SMODE_WAIT: {
307*1b2596b5SMatthias Ringwald 		uint32_t mor, pllr0, pllr1, mckr;
308*1b2596b5SMatthias Ringwald 		uint32_t fmr;
309*1b2596b5SMatthias Ringwald #if defined(EFC1)
310*1b2596b5SMatthias Ringwald 		uint32_t fmr1;
311*1b2596b5SMatthias Ringwald #endif
312*1b2596b5SMatthias Ringwald #if (SAM4S || SAM4E || SAM4N || SAM4C || SAM4CM || SAM4CP || SAMG55 || SAMV71 || SAMV70 || SAMS70 || SAME70)
313*1b2596b5SMatthias Ringwald 		(sleep_mode == SAM_PM_SMODE_WAIT_FAST) ?
314*1b2596b5SMatthias Ringwald 				pmc_set_flash_in_wait_mode(PMC_FSMR_FLPM_FLASH_STANDBY) :
315*1b2596b5SMatthias Ringwald 				pmc_set_flash_in_wait_mode(PMC_FSMR_FLPM_FLASH_DEEP_POWERDOWN);
316*1b2596b5SMatthias Ringwald #endif
317*1b2596b5SMatthias Ringwald 		cpu_irq_disable();
318*1b2596b5SMatthias Ringwald 		b_is_sleep_clock_used = true;
319*1b2596b5SMatthias Ringwald 
320*1b2596b5SMatthias Ringwald #if (SAM4C || SAM4CM || SAM4CP)
321*1b2596b5SMatthias Ringwald 		/* Backup the sub-system 1 status and stop sub-system 1 */
322*1b2596b5SMatthias Ringwald 		uint32_t cpclk_backup = PMC->PMC_SCSR &
323*1b2596b5SMatthias Ringwald 				(PMC_SCSR_CPCK | PMC_SCSR_CPBMCK);
324*1b2596b5SMatthias Ringwald 		PMC->PMC_SCDR = cpclk_backup | PMC_SCDR_CPKEY_PASSWD;
325*1b2596b5SMatthias Ringwald #endif
326*1b2596b5SMatthias Ringwald 		pmc_save_clock_settings(&mor, &pllr0, &pllr1, &mckr, &fmr,
327*1b2596b5SMatthias Ringwald #if defined(EFC1)
328*1b2596b5SMatthias Ringwald 				&fmr1,
329*1b2596b5SMatthias Ringwald #endif
330*1b2596b5SMatthias Ringwald 				(sleep_mode == SAM_PM_SMODE_WAIT));
331*1b2596b5SMatthias Ringwald 
332*1b2596b5SMatthias Ringwald 		/* Enter wait mode */
333*1b2596b5SMatthias Ringwald 		cpu_irq_enable();
334*1b2596b5SMatthias Ringwald 
335*1b2596b5SMatthias Ringwald 		pmc_enable_waitmode();
336*1b2596b5SMatthias Ringwald 
337*1b2596b5SMatthias Ringwald 		cpu_irq_disable();
338*1b2596b5SMatthias Ringwald 		pmc_restore_clock_setting(mor, pllr0, pllr1, mckr, fmr
339*1b2596b5SMatthias Ringwald #if defined(EFC1)
340*1b2596b5SMatthias Ringwald 				, fmr1
341*1b2596b5SMatthias Ringwald #endif
342*1b2596b5SMatthias Ringwald 				);
343*1b2596b5SMatthias Ringwald 
344*1b2596b5SMatthias Ringwald #if (SAM4C || SAM4CM || SAM4CP)
345*1b2596b5SMatthias Ringwald 		/* Restore the sub-system 1 */
346*1b2596b5SMatthias Ringwald 		PMC->PMC_SCER = cpclk_backup | PMC_SCER_CPKEY_PASSWD;
347*1b2596b5SMatthias Ringwald #endif
348*1b2596b5SMatthias Ringwald 		b_is_sleep_clock_used = false;
349*1b2596b5SMatthias Ringwald 		if (callback_clocks_restored) {
350*1b2596b5SMatthias Ringwald 			callback_clocks_restored();
351*1b2596b5SMatthias Ringwald 			callback_clocks_restored = NULL;
352*1b2596b5SMatthias Ringwald 		}
353*1b2596b5SMatthias Ringwald 		cpu_irq_enable();
354*1b2596b5SMatthias Ringwald 
355*1b2596b5SMatthias Ringwald 		break;
356*1b2596b5SMatthias Ringwald 	}
357*1b2596b5SMatthias Ringwald #if (!(SAMG51 || SAMG53 || SAMG54))
358*1b2596b5SMatthias Ringwald 	case SAM_PM_SMODE_BACKUP:
359*1b2596b5SMatthias Ringwald 		SCB->SCR |= SCR_SLEEPDEEP;
360*1b2596b5SMatthias Ringwald #if (SAM4S || SAM4E || SAM4N || SAM4C || SAM4CM || SAM4CP || SAMG55 || SAMV71 || SAMV70 || SAMS70 || SAME70)
361*1b2596b5SMatthias Ringwald 		SUPC->SUPC_CR = SUPC_CR_KEY_PASSWD | SUPC_CR_VROFF_STOP_VREG;
362*1b2596b5SMatthias Ringwald 		cpu_irq_enable();
363*1b2596b5SMatthias Ringwald 		__WFI() ;
364*1b2596b5SMatthias Ringwald #else
365*1b2596b5SMatthias Ringwald 		cpu_irq_enable();
366*1b2596b5SMatthias Ringwald 		__WFE() ;
367*1b2596b5SMatthias Ringwald #endif
368*1b2596b5SMatthias Ringwald 		break;
369*1b2596b5SMatthias Ringwald #endif
370*1b2596b5SMatthias Ringwald 	}
371*1b2596b5SMatthias Ringwald }
372*1b2596b5SMatthias Ringwald 
pmc_is_wakeup_clocks_restored(void)373*1b2596b5SMatthias Ringwald bool pmc_is_wakeup_clocks_restored(void)
374*1b2596b5SMatthias Ringwald {
375*1b2596b5SMatthias Ringwald 	return !b_is_sleep_clock_used;
376*1b2596b5SMatthias Ringwald }
377*1b2596b5SMatthias Ringwald 
pmc_wait_wakeup_clocks_restore(pmc_callback_wakeup_clocks_restored_t callback)378*1b2596b5SMatthias Ringwald void pmc_wait_wakeup_clocks_restore(
379*1b2596b5SMatthias Ringwald 		pmc_callback_wakeup_clocks_restored_t callback)
380*1b2596b5SMatthias Ringwald {
381*1b2596b5SMatthias Ringwald 	if (b_is_sleep_clock_used) {
382*1b2596b5SMatthias Ringwald 		cpu_irq_disable();
383*1b2596b5SMatthias Ringwald 		callback_clocks_restored = callback;
384*1b2596b5SMatthias Ringwald 	} else if (callback) {
385*1b2596b5SMatthias Ringwald 		callback();
386*1b2596b5SMatthias Ringwald 	}
387*1b2596b5SMatthias Ringwald }
388*1b2596b5SMatthias Ringwald 
389*1b2596b5SMatthias Ringwald #endif
390