/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (C) 2021 MediaTek Inc. */ #ifdef pr_fmt #undef pr_fmt #endif #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include #include #include #include #include #include #include #include #include #include #include #include #include #include "mtk_rtc_hw.h" #include #include #include "include/pmic.h" #define hal_rtc_xinfo(fmt, args...) \ pr_notice(fmt, ##args) /*TODO extern bool pmic_chrdet_status(void);*/ /* * RTC_FGSOC = 0, * RTC_ANDROID, * RTC_RECOVERY, * RTC_FAC_RESET, * RTC_BYPASS_PWR, * RTC_PWRON_TIME, * RTC_FAST_BOOT, * RTC_KPOC, * RTC_DEBUG, * RTC_PWRON_AL, * RTC_UART, * RTC_AUTOBOOT, * RTC_PWRON_LOGO, * RTC_32K_LESS, * RTC_LP_DET, * RTC_SPAR_NUM * */ /* * RTC_PDN1: * bit 0 - 3 : Android bits * bit 4 - 5 : Recovery bits (0x10: factory data reset) * bit 6 : Bypass PWRKEY bit * bit 7 : Power-On Time bit * bit 8 : RTC_GPIO_USER_WIFI bit * bit 9 : RTC_GPIO_USER_GPS bit * bit 10 : RTC_GPIO_USER_BT bit * bit 11 : RTC_GPIO_USER_FM bit * bit 12 : RTC_GPIO_USER_PMIC bit * bit 13 : Fast Boot * bit 14 : Kernel Power Off Charging * bit 15 : Debug bit */ /* * RTC_PDN2: * bit 0 - 3 : MTH in power-on time * bit 4 : Power-On Alarm bit * bit 5 - 6 : UART bits * bit 7 : autoboot bit * bit 8 - 14: YEA in power-on time * bit 15 : Power-On Logo bit */ /* * RTC_SPAR0: * bit 0 - 5 : SEC in power-on time * bit 6 : 32K less bit. True:with 32K, False:Without 32K * bit 7 - 15: reserved bits */ u16 rtc_spare_reg[RTC_SPAR_NUM][3] = { {RTC_AL_MTH, 0xff, 8}, {RTC_PDN1, 0xf, 0}, {RTC_PDN1, 0x3, 4}, {RTC_PDN1, 0x1, 6}, {RTC_PDN1, 0x1, 7}, {RTC_PDN1, 0x1, 13}, {RTC_PDN1, 0x1, 14}, {RTC_PDN1, 0x1, 15}, {RTC_PDN2, 0x1, 4}, {RTC_PDN2, 0x3, 5}, {RTC_PDN2, 0x1, 7}, {RTC_PDN2, 0x1, 15}, {RTC_SPAR0, 0x1, 6}, {RTC_SPAR0, 0x1, 7}, {RTC_AL_HOU, 0xff, 8} }; static int rtc_eosc_cali_td = 8; module_param(rtc_eosc_cali_td, int, 0664); void hal_rtc_set_abb_32k(u16 enable) { hal_rtc_xinfo("ABB 32k not support\n"); } u16 hal_rtc_get_gpio_32k_status(void) { u16 con; con = rtc_read(RTC_CON); hal_rtc_xinfo("RTC_GPIO 32k status(RTC_CON=0x%x)\n", con); if (con & RTC_CON_F32KOB) return 0; else return 1; } void hal_rtc_set_gpio_32k_status(u16 user, bool enable) { u16 con, pdn1; if (enable) { pdn1 = rtc_read(RTC_PDN1); } else { pdn1 = rtc_read(RTC_PDN1) & ~(1U << user); rtc_write(RTC_PDN1, pdn1); rtc_write_trigger(); } con = rtc_read(RTC_CON); if (enable) { con &= ~RTC_CON_F32KOB; } else { if (!(pdn1 & RTC_GPIO_USER_MASK)) { /* no users */ con |= RTC_CON_F32KOB; } } rtc_write(RTC_CON, con); rtc_write_trigger(); if (enable) { pdn1 |= (1U << user); rtc_write(RTC_PDN1, pdn1); rtc_write_trigger(); } hal_rtc_xinfo("RTC_GPIO user %d enable = %d 32k (0x%x), RTC_CON = %x\n", user, enable, pdn1, rtc_read(RTC_CON)); } void rtc_spar_alarm_clear_wait(void) { unsigned long long timeout = sched_clock() + 500000000; do { if ((rtc_read(RTC_BBPU) & RTC_BBPU_CLR) == 0) break; else if (sched_clock() > timeout) { pr_notice("%s, spar/alarm clear time out, %x,\n", __func__, rtc_read(RTC_BBPU)); break; } } while (1); } void rtc_enable_k_eosc(void) { u16 osc32; /* Truning on eosc cali mode clock */ pmic_config_interface_nolock(PMIC_SCK_TOP_CKPDN_CON0_CLR_ADDR, 1, PMIC_RG_RTC_EOSC32_CK_PDN_MASK, PMIC_RG_RTC_EOSC32_CK_PDN_SHIFT); pmic_config_interface_nolock(PMIC_RG_SRCLKEN_IN0_HW_MODE_ADDR, 1, PMIC_RG_SRCLKEN_IN0_HW_MODE_MASK, PMIC_RG_SRCLKEN_IN0_HW_MODE_SHIFT); pmic_config_interface_nolock(PMIC_RG_SRCLKEN_IN1_HW_MODE_ADDR, 1, PMIC_RG_SRCLKEN_IN1_HW_MODE_MASK, PMIC_RG_SRCLKEN_IN1_HW_MODE_SHIFT); pmic_config_interface_nolock(PMIC_RG_RTC_EOSC32_CK_PDN_ADDR, 0, PMIC_RG_RTC_EOSC32_CK_PDN_MASK, PMIC_RG_RTC_EOSC32_CK_PDN_SHIFT); switch (rtc_eosc_cali_td) { case 1: pmic_config_interface_nolock(PMIC_EOSC_CALI_TD_ADDR, 0x3, PMIC_EOSC_CALI_TD_MASK, PMIC_EOSC_CALI_TD_SHIFT); break; case 2: pmic_config_interface_nolock(PMIC_EOSC_CALI_TD_ADDR, 0x4, PMIC_EOSC_CALI_TD_MASK, PMIC_EOSC_CALI_TD_SHIFT); break; case 4: pmic_config_interface_nolock(PMIC_EOSC_CALI_TD_ADDR, 0x5, PMIC_EOSC_CALI_TD_MASK, PMIC_EOSC_CALI_TD_SHIFT); break; case 16: pmic_config_interface_nolock(PMIC_EOSC_CALI_TD_ADDR, 0x7, PMIC_EOSC_CALI_TD_MASK, PMIC_EOSC_CALI_TD_SHIFT); break; default: pmic_config_interface_nolock(PMIC_EOSC_CALI_TD_ADDR, 0x6, PMIC_EOSC_CALI_TD_MASK, PMIC_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 */ pmic_config_interface_nolock(PMIC_XO_EN32K_MAN_ADDR, 0, PMIC_XO_EN32K_MAN_MASK, PMIC_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); hal_rtc_xinfo("RTC_enable_k_eosc\n"); } void rtc_disable_2sec_reboot(void) { u16 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(); } void rtc_bbpu_pwrdown(bool auto_boot) { PMIC_POWER_HOLD(0); } void hal_rtc_bbpu_pwdn(bool charger_status) { u16 con, bbpu; rtc_disable_2sec_reboot(); rtc_enable_k_eosc(); /* disable 32K export if there are no RTC_GPIO users */ if (!(rtc_read(RTC_PDN1) & RTC_GPIO_USER_MASK)) { con = rtc_read(RTC_CON) | RTC_CON_F32KOB; rtc_write(RTC_CON, con); rtc_write_trigger(); } /* lpsd */ pr_notice("clear lpsd solution\n"); bbpu = RTC_BBPU_KEY | RTC_BBPU_CLR | RTC_BBPU_PWREN; rtc_write(RTC_BBPU, bbpu); rtc_write(RTC_AL_MASK, RTC_AL_MASK_DOW); /* mask DOW */ rtc_write_trigger(); rtc_spar_alarm_clear_wait(); wk_pmic_enable_sdn_delay(); rtc_write(RTC_BBPU, rtc_read(RTC_BBPU) | RTC_BBPU_KEY | RTC_BBPU_RELOAD); rtc_write_trigger(); pr_notice("RTC_AL_MASK= 0x%x RTC_IRQ_EN= 0x%x\n", rtc_read(RTC_AL_MASK), rtc_read(RTC_IRQ_EN)); /* lpsd */ rtc_bbpu_pwrdown(true); } void hal_rtc_get_pwron_alarm(struct rtc_time *tm, struct rtc_wkalrm *alm) { u16 pdn1, pdn2; pdn1 = rtc_read(RTC_PDN1); pdn2 = rtc_read(RTC_PDN2); alm->enabled = (pdn1 & RTC_PDN1_PWRON_TIME ? (pdn2 & RTC_PDN2_PWRON_LOGO ? 3 : 2) : 0); /* return Power-On Alarm bit */ alm->pending = !!(pdn2 & RTC_PDN2_PWRON_ALARM); hal_rtc_get_alarm_time(tm); } bool hal_rtc_is_lp_irq(void) { u16 irqsta; irqsta = rtc_read(RTC_IRQ_STA); /* read clear */ if (unlikely(!(irqsta & RTC_IRQ_STA_AL))) { #ifndef USER_BUILD_KERNEL if (irqsta & RTC_IRQ_STA_LP) rtc_lp_exception(); #endif return true; } return false; } bool hal_rtc_is_pwron_alarm(struct rtc_time *nowtm, struct rtc_time *tm) { u16 pdn1; pdn1 = rtc_read(RTC_PDN1); hal_rtc_xinfo("pdn1 = 0x%4x\n", pdn1); if (pdn1 & RTC_PDN1_PWRON_TIME) { /* power-on time is available */ hal_rtc_xinfo("pdn1 = 0x%4x\n", pdn1); hal_rtc_get_tick_time(nowtm); hal_rtc_xinfo("pdn1 = 0x%4x\n", pdn1); /* SEC has carried */ if (rtc_read(RTC_TC_SEC) < nowtm->tm_sec) hal_rtc_get_tick_time(nowtm); hal_rtc_get_pwron_alarm_time(tm); return true; } return false; } void hal_rtc_get_alarm(struct rtc_time *tm, struct rtc_wkalrm *alm) { u16 irqen, pdn2; irqen = rtc_read(RTC_IRQ_EN); hal_rtc_get_alarm_time(tm); pdn2 = rtc_read(RTC_PDN2); alm->enabled = !!(irqen & RTC_IRQ_EN_AL); /* return Power-On Alarm bit */ alm->pending = !!(pdn2 & RTC_PDN2_PWRON_ALARM); } void hal_rtc_set_alarm(struct rtc_time *tm) { u16 irqen; hal_rtc_set_alarm_time(tm); irqen = rtc_read(RTC_IRQ_EN) | RTC_IRQ_EN_ONESHOT_AL; rtc_write(RTC_IRQ_EN, irqen); rtc_write_trigger(); } void hal_rtc_clear_alarm(struct rtc_time *tm) { u16 irqsta, irqen, pdn2; irqen = rtc_read(RTC_IRQ_EN) & ~RTC_IRQ_EN_AL; pdn2 = rtc_read(RTC_PDN2) & ~RTC_PDN2_PWRON_ALARM; rtc_write(RTC_IRQ_EN, irqen); rtc_write(RTC_PDN2, pdn2); rtc_write_trigger(); irqsta = rtc_read(RTC_IRQ_STA); /* read clear */ hal_rtc_set_alarm_time(tm); } void hal_rtc_set_lp_irq(void) { u16 irqen; #ifndef USER_BUILD_KERNEL irqen = rtc_read(RTC_IRQ_EN) | RTC_IRQ_EN_LP; #else irqen = rtc_read(RTC_IRQ_EN) & ~RTC_IRQ_EN_LP; #endif rtc_write(RTC_IRQ_EN, irqen); rtc_write_trigger(); } void hal_rtc_save_pwron_time(bool enable, struct rtc_time *tm, bool logo) { u16 pdn1, pdn2; hal_rtc_set_pwron_alarm_time(tm); if (logo) pdn2 = rtc_read(RTC_PDN2) | RTC_PDN2_PWRON_LOGO; else pdn2 = rtc_read(RTC_PDN2) & ~RTC_PDN2_PWRON_LOGO; rtc_write(RTC_PDN2, pdn2); if (enable) pdn1 = rtc_read(RTC_PDN1) | RTC_PDN1_PWRON_TIME; else pdn1 = rtc_read(RTC_PDN1) & ~RTC_PDN1_PWRON_TIME; rtc_write(RTC_PDN1, pdn1); rtc_write_trigger(); } void rtc_clock_enable(int enable) { if (enable) { pmic_config_interface_nolock(PMIC_SCK_TOP_CKPDN_CON0_CLR_ADDR, 1, PMIC_RG_RTC_MCLK_PDN_MASK, PMIC_RG_RTC_MCLK_PDN_SHIFT); pmic_config_interface_nolock(PMIC_SCK_TOP_CKPDN_CON0_CLR_ADDR, 1, PMIC_RG_RTC_32K_CK_PDN_MASK, PMIC_RG_RTC_32K_CK_PDN_SHIFT); } else { pmic_config_interface_nolock(PMIC_SCK_TOP_CKPDN_CON0_SET_ADDR, 1, PMIC_RG_RTC_MCLK_PDN_MASK, PMIC_RG_RTC_MCLK_PDN_SHIFT); pmic_config_interface_nolock(PMIC_SCK_TOP_CKPDN_CON0_SET_ADDR, 1, PMIC_RG_RTC_32K_CK_PDN_MASK, PMIC_RG_RTC_32K_CK_PDN_SHIFT); } } void rtc_lpsd_restore_al_mask(void) { pr_notice("%s\n", __func__); rtc_write(RTC_BBPU, rtc_read(RTC_BBPU) | RTC_BBPU_KEY | RTC_BBPU_RELOAD); rtc_write_trigger(); pr_notice("1st RTC_AL_MASK = 0x%x\n", rtc_read(RTC_AL_MASK)); /* mask DOW */ rtc_write(RTC_AL_MASK, RTC_AL_MASK_DOW); rtc_write_trigger(); pr_notice("2nd RTC_AL_MASK = 0x%x\n", rtc_read(RTC_AL_MASK)); }