/*
|
* 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)
|
|
struct SLEEP_TIMER_HANDLE_T sleep_timer_handle = {
|
.mode = SLEEP_TIMER_MODE_ONESHOT,
|
.enable = 0,
|
.int_en = true,
|
.time = 32768,
|
.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;
|
sleep_timer_handle.enable = 1;
|
|
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);
|
}
|
sleep_timer_handle.enable = 0;
|
}
|
|
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 xtal_38m4_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");
|
}
|
}
|