1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements.  See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership.  The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License.  You may obtain a copy of the License at
9  *
10  *  http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied.  See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  */
19 
20 #include <stdbool.h>
21 #include <DA1469xAB.h>
22 #include <da1469x_config.h>
23 #include <da1469x_clock.h>
24 #include <da1469x_pd.h>
25 #include <da1469x_pdc.h>
26 #include <da1469x_sleep.h>
27 
28 static int pdc_idx_combo;
29 static bool wait_for_jtag;
30 static struct da1469x_sleep_config sleep_config;
31 static uint32_t sys_clock_selection;
32 
da1469x_is_wakeup_by_jtag(void)33 static bool da1469x_is_wakeup_by_jtag(void)
34 {
35     return (da1469x_pdc_is_pending(pdc_idx_combo) &&
36             !(NVIC->ISPR[0] & ((1 << CMAC2SYS_IRQn) | (1 << KEY_WKUP_GPIO_IRQn) |
37                                (1 << VBUS_IRQn))));
38 }
39 
da1469x_is_sleep_allowed(void)40 static bool da1469x_is_sleep_allowed(void)
41 {
42     if (wait_for_jtag) {
43         if (CRG_TOP->SYS_STAT_REG & CRG_TOP_SYS_STAT_REG_DBG_IS_ACTIVE_Msk) {
44             wait_for_jtag = false;
45         }
46         return false;
47     }
48 
49     /* We can enter extended sleep only if running from RCX or XTAL32K, debugger is
50      * not attached and there are no interrupts pending.
51      */
52     return (CRG_TOP->CLK_CTRL_REG & CRG_TOP_CLK_CTRL_REG_LP_CLK_SEL_Msk) &&
53            !(CRG_TOP->SYS_STAT_REG & CRG_TOP_SYS_STAT_REG_DBG_IS_ACTIVE_Msk) &&
54            !((NVIC->ISPR[0] & NVIC->ISER[0]) | (NVIC->ISPR[1] & NVIC->ISER[1]));
55 }
56 
da1469x_sleep(void)57 int da1469x_sleep(void)
58 {
59     int slept = 0;
60 
61     if (!da1469x_is_sleep_allowed()) {
62         __DMB();
63         __WFI();
64         return 0;
65     }
66 
67     /* PD_SYS will not be disabled here until we enter deep sleep - don't wait */
68     if (!da1469x_pd_release_nowait(MCU_PD_DOMAIN_SYS)) {
69         __DMB();
70         __WFI();
71     } else {
72         da1469x_pdc_ack_all_m33();
73         sys_clock_selection = CRG_TOP->CLK_CTRL_REG & CRG_TOP_CLK_CTRL_REG_SYS_CLK_SEL_Msk;
74         slept = da1469x_enter_sleep();
75         if (slept) {
76             /* Watchdog is always resumed when PD_SYS is turned off, need to
77              * freeze it again if there's no one to feed it.
78              */
79             GPREG->SET_FREEZE_REG = GPREG_SET_FREEZE_REG_FRZ_SYS_WDOG_Msk;
80             SYS_WDOG->WATCHDOG_REG = SYS_WDOG_WATCHDOG_REG_WDOG_VAL_Msk;
81 
82             da1469x_pd_acquire(MCU_PD_DOMAIN_SYS);
83             if (da1469x_is_wakeup_by_jtag()) {
84                 wait_for_jtag = 1;
85             }
86             if (sys_clock_selection != 1) {
87                 da1469x_clock_sys_xtal32m_wait_to_settle();
88                 /* PLL requires that the current system clock be XTAL32M. */
89                 da1469x_clock_sys_xtal32m_switch();
90             }
91             if (sys_clock_selection == 3 << CRG_TOP_CLK_CTRL_REG_SYS_CLK_SEL_Pos) {
92                 da1469x_clock_sys_pll_enable();
93                 da1469x_clock_sys_pll_switch();
94             }
95         }
96     }
97 
98     /*
99      * The SoC did not enter the normal sleep state. Acquire PD_SYS without
100      * applying preferred settings.
101      */
102     if (slept == 0) {
103         da1469x_pd_acquire_noconf(MCU_PD_DOMAIN_SYS);
104     }
105 
106     return slept;
107 }
108 
da1469x_sleep_config(const struct da1469x_sleep_config * config)109 void da1469x_sleep_config(const struct da1469x_sleep_config *config)
110 {
111     sleep_config = *config;
112 
113     pdc_idx_combo = da1469x_pdc_add(MCU_PDC_TRIGGER_COMBO, MCU_PDC_MASTER_M33,
114                                     sleep_config.enable_xtal_on_wakeup);
115     __ASSERT_NO_MSG(pdc_idx_combo >= 0);
116     da1469x_pdc_set(pdc_idx_combo);
117     da1469x_pdc_ack(pdc_idx_combo);
118 }
119