blob: a821c1bc858f9d1e2678dadc2a7f842d676730f7 [file] [log] [blame]
/*
* Copyright (c) 2019, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <common/debug.h>
#include <drivers/delay_timer.h>
#include <rtc.h>
static void RTC_Config_Interface(uint32_t addr, uint16_t data,
uint16_t MASK, uint16_t SHIFT)
{
uint16_t pmic_reg = 0;
pmic_reg = RTC_Read(addr);
pmic_reg &= ~(MASK << SHIFT);
pmic_reg |= (data << SHIFT);
RTC_Write(addr, pmic_reg);
}
static void rtc_disable_2sec_reboot(void)
{
uint16_t reboot;
reboot = (RTC_Read(RTC_AL_SEC) & ~RTC_BBPU_2SEC_EN) &
~RTC_BBPU_AUTO_PDN_SEL;
RTC_Write(RTC_AL_SEC, reboot);
RTC_Write_Trigger();
}
static void rtc_xosc_write(uint16_t val, bool reload)
{
uint16_t bbpu;
RTC_Write(RTC_OSC32CON, RTC_OSC32CON_UNLOCK1);
rtc_busy_wait();
RTC_Write(RTC_OSC32CON, RTC_OSC32CON_UNLOCK2);
rtc_busy_wait();
RTC_Write(RTC_OSC32CON, val);
rtc_busy_wait();
if (reload) {
bbpu = RTC_Read(RTC_BBPU) | RTC_BBPU_KEY | RTC_BBPU_RELOAD;
RTC_Write(RTC_BBPU, bbpu);
RTC_Write_Trigger();
}
}
static void rtc_enable_k_eosc(void)
{
uint16_t osc32;
uint16_t rtc_eosc_cali_td = 8; /* eosc cali period time */
/* Truning on eosc cali mode clock */
RTC_Config_Interface(PMIC_RG_TOP_CON, 1,
PMIC_RG_SRCLKEN_IN0_HW_MODE_MASK,
PMIC_RG_SRCLKEN_IN0_HW_MODE_SHIFT);
RTC_Config_Interface(PMIC_RG_TOP_CON, 1,
PMIC_RG_SRCLKEN_IN1_HW_MODE_MASK,
PMIC_RG_SRCLKEN_IN1_HW_MODE_SHIFT);
RTC_Config_Interface(PMIC_RG_SCK_TOP_CKPDN_CON0, 0,
PMIC_RG_RTC_EOSC32_CK_PDN_MASK,
PMIC_RG_RTC_EOSC32_CK_PDN_SHIFT);
switch (rtc_eosc_cali_td) {
case 1:
RTC_Config_Interface(PMIC_RG_EOSC_CALI_CON0, 0x3,
PMIC_RG_EOSC_CALI_TD_MASK, PMIC_RG_EOSC_CALI_TD_SHIFT);
break;
case 2:
RTC_Config_Interface(PMIC_RG_EOSC_CALI_CON0, 0x4,
PMIC_RG_EOSC_CALI_TD_MASK, PMIC_RG_EOSC_CALI_TD_SHIFT);
break;
case 4:
RTC_Config_Interface(PMIC_RG_EOSC_CALI_CON0, 0x5,
PMIC_RG_EOSC_CALI_TD_MASK, PMIC_RG_EOSC_CALI_TD_SHIFT);
break;
case 16:
RTC_Config_Interface(PMIC_RG_EOSC_CALI_CON0, 0x7,
PMIC_RG_EOSC_CALI_TD_MASK, PMIC_RG_EOSC_CALI_TD_SHIFT);
break;
default:
RTC_Config_Interface(PMIC_RG_EOSC_CALI_CON0, 0x6,
PMIC_RG_EOSC_CALI_TD_MASK, PMIC_RG_EOSC_CALI_TD_SHIFT);
break;
}
/* Switch the DCXO from 32k-less mode to RTC mode,
* otherwise, EOSC cali will fail
*/
/* RTC mode will have only OFF mode and FPM */
RTC_Config_Interface(PMIC_RG_DCXO_CW02, 0, PMIC_RG_XO_EN32K_MAN_MASK,
PMIC_RG_XO_EN32K_MAN_SHIFT);
RTC_Write(RTC_BBPU,
RTC_Read(RTC_BBPU) | RTC_BBPU_KEY | RTC_BBPU_RELOAD);
RTC_Write_Trigger();
/* Enable K EOSC mode for normal power off and then plug out battery */
RTC_Write(RTC_AL_YEA, ((RTC_Read(RTC_AL_YEA) | RTC_K_EOSC_RSV_0)
& (~RTC_K_EOSC_RSV_1)) | RTC_K_EOSC_RSV_2);
RTC_Write_Trigger();
osc32 = RTC_Read(RTC_OSC32CON);
rtc_xosc_write(osc32 | RTC_EMBCK_SRC_SEL, true);
INFO("[RTC] RTC_enable_k_eosc\n");
}
void rtc_power_off_sequence(void)
{
uint16_t bbpu;
rtc_disable_2sec_reboot();
rtc_enable_k_eosc();
/* clear alarm */
bbpu = RTC_BBPU_KEY | RTC_BBPU_CLR | RTC_BBPU_PWREN;
if (Writeif_unlock()) {
RTC_Write(RTC_BBPU, bbpu);
RTC_Write(RTC_AL_MASK, RTC_AL_MASK_DOW);
RTC_Write_Trigger();
mdelay(1);
bbpu = RTC_Read(RTC_BBPU) | RTC_BBPU_KEY | RTC_BBPU_RELOAD;
RTC_Write(RTC_BBPU, bbpu);
RTC_Write_Trigger();
INFO("[RTC] BBPU=0x%x, IRQ_EN=0x%x, AL_MSK=0x%x, AL_SEC=0x%x\n",
RTC_Read(RTC_BBPU), RTC_Read(RTC_IRQ_EN),
RTC_Read(RTC_AL_MASK), RTC_Read(RTC_AL_SEC));
}
}