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