| /* |
| * 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)); |
| } |
| } |