/* * Copyright (c) 2019-2023 Beijing Hanwei Innovation Technology Ltd. Co. and * its subsidiaries and affiliates (collectly called MKSEMI). * * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form, except as embedded into an MKSEMI * integrated circuit in a product or a software update for such product, * must reproduce the above copyright notice, this list of conditions and * the following disclaimer in the documentation and/or other materials * provided with the distribution. * * 3. Neither the name of MKSEMI nor the names of its contributors may be used * to endorse or promote products derived from this software without * specific prior written permission. * * 4. This software, with or without modification, must only be used with a * MKSEMI integrated circuit. * * 5. Any software provided in binary form under this license must not be * reverse engineered, decompiled, modified and/or disassembled. * * THIS SOFTWARE IS PROVIDED BY MKSEMI "AS IS" AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL MKSEMI OR CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "mk_sleep_timer.h" #include "mk_trace.h" #include "mk_clock.h" #include "mk_power.h" #define SLEEP_TIMER_REG_STDR (RTC_BASE + 0x20) #define SLEEP_TIMER_REG_STCR (RTC_BASE + 0x2C) #define SLEEP_TIMER_INT_STATUS (0x80000000) #define SLEEP_TIMER_INT_CLR (0x00000004) static struct SLEEP_TIMER_HANDLE_T sleep_timer_handle = { .mode = SLEEP_TIMER_MODE_ONESHOT, .time = 32768, .int_en = true, .ppm = 0, .callback = NULL, }; void sleep_timer_open(bool int_en, enum SLEEP_TIMER_MODE_T mode, drv_callback_t callback) { // need open RTC clock clock_enable(CLOCK_RTC); // disable sleep timer and clear int status REG_WRITE(SLEEP_TIMER_REG_STCR, SLEEP_TIMER_MODE_STOP | SLEEP_TIMER_INT_CLR); sleep_timer_handle.callback = callback; sleep_timer_handle.int_en = int_en; sleep_timer_handle.mode = mode; if (sleep_timer_handle.int_en) { NVIC_SetPriority(SLEEP_TIMER_IRQn, IRQ_PRIORITY_NORMAL); NVIC_ClearPendingIRQ(SLEEP_TIMER_IRQn); NVIC_EnableIRQ(SLEEP_TIMER_IRQn); } // enable sleep timer as wakeup source power_wakeup_enable(POWER_WAKEUP_BY_SLEEP_TIMER, POWER_WAKEUP_LEVEL_NONE); } void sleep_timer_close(void) { // disable sleep timer and clear int status REG_WRITE(SLEEP_TIMER_REG_STCR, SLEEP_TIMER_MODE_STOP | SLEEP_TIMER_INT_CLR); if (sleep_timer_handle.int_en) { NVIC_DisableIRQ(SLEEP_TIMER_IRQn); NVIC_ClearPendingIRQ(SLEEP_TIMER_IRQn); } } void sleep_timer_start(uint32_t time) { sleep_timer_handle.time = (uint32_t)((int32_t)time + (int32_t)((int32_t)time * sleep_timer_handle.ppm / 1000000)); // disable sleep timer REG_WRITE(SLEEP_TIMER_REG_STCR, SLEEP_TIMER_MODE_STOP); // set sleep timer REG_WRITE(SLEEP_TIMER_REG_STDR, sleep_timer_handle.time); // enable sleep timer REG_WRITE(SLEEP_TIMER_REG_STCR, sleep_timer_handle.mode); } void sleep_timer_stop(void) { // disable sleep timer REG_WRITE(SLEEP_TIMER_REG_STCR, SLEEP_TIMER_MODE_STOP); } uint32_t high_xtal_off_time(void) { #ifdef UWB_EN uint32_t slp_cnt = REG_READ(0x40000074); return (uint32_t)((int32_t)slp_cnt - (int32_t)((int32_t)slp_cnt * sleep_timer_handle.ppm / 1000000)); #else return REG_READ(SLEEP_TIMER_REG_STDR); #endif } void sleep_timer_ppm_set(int32_t ppm) { sleep_timer_handle.ppm = ppm; } int32_t sleep_timer_ppm_get(void) { return sleep_timer_handle.ppm; } void SLEEP_TIMER_IRQHandler(void) { uint32_t int_stat = REG_READ(SLEEP_TIMER_REG_STCR); if (int_stat & SLEEP_TIMER_INT_STATUS) { // clear interrupt status if (sleep_timer_handle.mode == SLEEP_TIMER_MODE_ONESHOT) { REG_WRITE(SLEEP_TIMER_REG_STCR, SLEEP_TIMER_MODE_STOP | SLEEP_TIMER_INT_CLR); } else { REG_WRITE(SLEEP_TIMER_REG_STCR, sleep_timer_handle.mode | SLEEP_TIMER_INT_CLR); } if (sleep_timer_handle.callback != NULL) { sleep_timer_handle.callback(NULL, sleep_timer_handle.time); } } else { ASSERT(0, "Unexpected sleep interrupt"); } }