blob: e0f28d59c6ae1929dc7d281827352abff6be078b [file] [log] [blame]
/*
* Copyright (C) 2018 MediaTek, Inc.
* Author: Wilma Wu <wilma.wu@mediatek.com>
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/rtc.h>
#include <linux/sched/clock.h>
#include <linux/spinlock.h>
#include <linux/types.h>
#include <linux/irqdomain.h>
#include <linux/platform_device.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/io.h>
#include <linux/mfd/mt6358/core.h>
#if defined(CONFIG_MTK_PMIC_CHIP_MT6358)
#include <linux/mfd/mt6358/registers.h>
#elif defined(CONFIG_MTK_PMIC_CHIP_MT6359)
#include <linux/mfd/mt6359/registers.h>
#elif defined(CONFIG_MTK_PMIC_CHIP_MT6389)
#include <linux/mfd/mt6389/registers.h>
#endif
#ifdef pr_fmt
#undef pr_fmt
#endif
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
/* we map HW YEA 0 (2000) to 1968 not 1970 because 2000 is the leap year */
#define RTC_MIN_YEAR 1968
/*
* Reset to default date if RTC time is over 2038/1/19 3:14:7
* Year (YEA) : 1970 ~ 2037
* Month (MTH) : 1 ~ 12
* Day of Month (DOM): 1 ~ 31
*/
#define RTC_DEFAULT_YEA 2010
#define RTC_DEFAULT_MTH 1
#define RTC_DEFAULT_DOM 1
/* Min, Hour, Dom... register offset to RTC_TC_SEC */
#define RTC_OFFSET_SEC 0
#define RTC_OFFSET_MIN 1
#define RTC_OFFSET_HOUR 2
#define RTC_OFFSET_DOM 3
#define RTC_OFFSET_DOW 4
#define RTC_OFFSET_MTH 5
#define RTC_OFFSET_YEAR 6
#define RTC_OFFSET_COUNT 7
#define RTC_DSN_ID 0x580
#define RTC_BBPU 0x8
#define RTC_IRQ_STA 0xa
#define RTC_IRQ_EN 0xc
#define RTC_CII_EN 0xe
#define RTC_AL_MASK 0x10
#define RTC_TC_SEC 0x12
#define RTC_TC_MIN 0x14
#define RTC_TC_HOU 0x16
#define RTC_TC_DOM 0x18
#define RTC_TC_DOW 0x1a
#define RTC_TC_MTH 0x1c
#define RTC_TC_YEA 0x1e
#define RTC_AL_SEC 0x20
#define RTC_AL_MIN 0x22
#define RTC_AL_HOU 0x24
#define RTC_AL_DOM 0x26
#define RTC_AL_DOW 0x28
#define RTC_AL_MTH 0x2a
#define RTC_AL_YEA 0x2c
#define RTC_PDN1 0x34
#define RTC_PDN2 0x36
#define RTC_SPAR0 0x38
#define RTC_SPAR1 0x3a
#define RTC_WRTGR 0x42
#define RTC_OSC32CON 0x2e
#define RTC_POWERKEY1 0x30
#define RTC_POWERKEY2 0x32
#define RTC_PROT 0x3c
#define RTC_DIFF 0x3e
#define RTC_CALI 0x40
#define RTC_CON 0x44
#define RTC_AL_SEC_MASK 0x3f
#define RTC_AL_MIN_MASK 0x3f
#define RTC_AL_HOU_MASK 0x1f
#define RTC_AL_DOM_MASK 0x1f
#define RTC_AL_DOW_MASK 0x7
#define RTC_AL_MTH_MASK 0xf
#define RTC_AL_YEA_MASK 0x7f
#define RTC_PWRON_SEC_MASK 0x3f
#define RTC_PWRON_MIN_MASK 0x3f
#define RTC_PWRON_HOU_MASK 0x7c0
#define RTC_PWRON_DOM_MASK 0xf800
#define RTC_PWRON_MTH_MASK 0xf
#define RTC_PWRON_YEA_MASK 0x7f00
#define RTC_PWRON_SEC_SHIFT 0x0
#define RTC_PWRON_MIN_SHIFT 0x0
#define RTC_PWRON_HOU_SHIFT 0x6
#define RTC_PWRON_DOM_SHIFT 0xb
#define RTC_PWRON_MTH_SHIFT 0x0
#define RTC_PWRON_YEA_SHIFT 0x8
#define RTC_IRQ_EN_AL BIT(0)
/* RTC_BBPU bit field */
#define PMIC_SPAR_SW_SHIFT 1
#define PMIC_RESET_SPAR_SHIFT 2
#define PMIC_RESET_ALARM_SHIFT 3
#define RTC_BBPU_KEY 0x4300
#define RTC_BBPU_CBUSY BIT(6)
#define RTC_BBPU_RELOAD BIT(5)
#define RTC_BBPU_RESET_SPAR BIT(PMIC_RESET_SPAR_SHIFT)
#define RTC_BBPU_RESET_ALARM BIT(PMIC_RESET_ALARM_SHIFT)
#define RTC_BBPU_CLR BIT(1)
#define RTC_BBPU_SPAR_SW BIT(PMIC_SPAR_SW_SHIFT)
#define RTC_BBPU_PWREN BIT(0)
#define RTC_AL_MASK_DOW BIT(4)
#define RTC_GPIO_USER_MASK 0x1f00
#define RTC_PDN1_PWRON_TIME BIT(7)
#define RTC_PDN2_PWRON_LOGO BIT(15)
#define RTC_CON_F32KOB BIT(5)
#define RTC_POWERKEY1_KEY 0xa357
#define RTC_POWERKEY2_KEY 0x67d2
#define RTC_OSC32CON_UNLOCK1 0x1a57
#define RTC_OSC32CON_UNLOCK2 0x2b68
#define RTC_EMBCK_SRC_SEL BIT(8)
#define RTC_K_EOSC_RSV_0 BIT(8)
#define RTC_K_EOSC_RSV_1 BIT(9)
#define RTC_K_EOSC_RSV_2 BIT(10)
#define RTC_BBPU_2SEC_EN BIT(8)
#define RTC_BBPU_AUTO_PDN_SEL BIT(6)
#define RTC_EMBCK_SEL_K_EOSC BIT(MT6389_RTC_EMBCK_SEL_MODE_SHIFT)
#define RTC_EMBCK_SEL_OPTION BIT(MT6389_RTC_EMBCK_SEL_OPTION_SHIFT)
#define RTC_GPS_CKOUT_EN BIT(MT6389_RTC_GPS_CKOUT_EN_SHIFT)
#define RTC_EOSC32_VCT_EN BIT(MT6389_RTC_EOSC32_VCT_EN_SHIFT)
#define RTC_EOSC32_CHOP_EN BIT(MT6389_RTC_EOSC32_CHOP_EN_SHIFT)
#define RTC_GP_OSC32_CON (2U << MT6389_RTC_GP_OSC32_CON_SHIFT)
#define RTC_REG_XOSC32_ENB BIT(MT6389_RTC_REG_XOSC32_ENB_SHIFT)
#define OSC32CON_ANALOG_SETTING (RTC_GP_OSC32_CON | RTC_EOSC32_CHOP_EN | \
RTC_EOSC32_VCT_EN | \
RTC_GPS_CKOUT_EN | RTC_EMBCK_SEL_OPTION | \
RTC_EMBCK_SEL_K_EOSC)
#define RTC_EOSC32_LPEN BIT(MT6389_EOSC32_LPEN_SHIFT)
#define RTC_XOSC32_LPEN BIT(MT6389_XOSC32_LPEN_SHIFT)
#define RTC_CON_LPRST BIT(MT6389_LPRST_SHIFT)
/* 1: GPO mode, 0: GPI mode */
#define RTC_CON_GOE BIT(MT6389_GOE_SHIFT)
#define RTC_CON_GPEN BIT(MT6389_GPEN_SHIFT)
#define RTC_CON_GPU BIT(MT6389_GPU_SHIFT)
#define RTC_CON_LPSTA_RAW BIT(MT6389_LPSTA_RAW_SHIFT)
#define RTC_PROT_UNLOCK1 0x586a
#define RTC_PROT_UNLOCK2 0x9136
#define RTC_EOSC_CALI_TD_01_SEC 0x3
#define RTC_EOSC_CALI_TD_02_SEC 0x4
#define RTC_EOSC_CALI_TD_04_SEC 0x5
#define RTC_EOSC_CALI_TD_08_SEC 0x6
#define RTC_EOSC_CALI_TD_16_SEC 0x7
#define RTC_LPD_OPT_F32K_CK_ALIVE (3U << MT6389_RTC_LPD_OPT_SHIFT)
#define RTC_K_EOSC32_VTCXO_ON_SEL BIT(MT6389_K_EOSC32_VTCXO_ON_SEL_SHIFT)
#define RTC_SPAR0_32K_LESS BIT(6)
#define RTC_LPD_OPT_MASK (MT6389_RTC_LPD_OPT_MASK << \
MT6389_RTC_LPD_OPT_SHIFT)
#define RG_75K_32K_SEL MT6389_TOP_CKSEL_CON0_SET_ADDR
#define RTC_75K_TO_32K BIT(MT6389_RG_RTC_32K1V8_SEL_SHIFT)
#define RTC_LPD_OPT_EOSC_LPD BIT(MT6389_RTC_LPD_OPT_SHIFT)
#define RG_FQMTR_RST MT6389_RG_FQMTR_RST_ADDR
#define RG_FQMTR_TCKSEL MT6389_FQMTR_TCKSEL_ADDR
#define RG_FQMTR_WINSET MT6389_FQMTR_WINSET_ADDR
#define RG_FQMTR_BUSY MT6389_FQMTR_BUSY_ADDR
#define RG_FQMTR_DCXO26M_EN MT6389_FQMTR_DCXO26M_EN_ADDR
#define RG_FQMTR_DATA MT6389_FQMTR_DATA_ADDR
#define RG_FQMTR_32K_CLK_PDN_SET MT6389_TOP_CKPDN_CON0_SET_ADDR
#define RG_FQMTR_32K_CLK_PDN_CLR MT6389_TOP_CKPDN_CON0_CLR_ADDR
#define RG_FQMTR_32K_CLK_PDN_MASK MT6389_RG_FQMTR_32K_CK_PDN_MASK
#define RG_FQMTR_32K_CLK_PDN_SHIFT MT6389_RG_FQMTR_32K_CK_PDN_SHIFT
#define FQMTR_CLK_CK_PDN_SET MT6389_TOP_CKPDN_CON0_SET_ADDR
#define FQMTR_CLK_CK_PDN_CLR MT6389_TOP_CKPDN_CON0_CLR_ADDR
#define FQMTR_CLK_CK_PDN_MASK MT6389_RG_FQMTR_CK_PDN_MASK
#define FQMTR_CLK_CK_PDN_SHIFT MT6389_RG_FQMTR_CK_PDN_SHIFT
#define RG_FQMTR_CKSEL MT6389_RG_FQMTR_CK_CKSEL_ADDR
#define RG_FQMTR_CKSEL_SET MT6389_TOP_CKSEL_CON0_SET_ADDR
#define RG_FQMTR_CKSEL_CLR MT6389_TOP_CKSEL_CON0_CLR_ADDR
#define RG_FQMTR_CKSEL_MASK MT6389_RG_FQMTR_CK_CKSEL_MASK
#define RG_FQMTR_CKSEL_SHIFT MT6389_RG_FQMTR_CK_CKSEL_SHIFT
#define RG_FQMTR_TCKSEL_MASK MT6389_FQMTR_TCKSEL_MASK
#define RG_FQMTR_TCKSEL_SHIFT MT6389_FQMTR_TCKSEL_SHIFT
#define FQMTR_FIX_CLK_26M (0 << RG_FQMTR_CKSEL_SHIFT)
#define FQMTR_FIX_CLK_XOSC_32K_DET (1 << RG_FQMTR_CKSEL_SHIFT)
#define FQMTR_FIX_CLK_EOSC_32K (2 << RG_FQMTR_CKSEL_SHIFT)
#define FQMTR_FIX_CLK_RTC_32K (3 << RG_FQMTR_CKSEL_SHIFT)
#define FQMTR_FIX_CLK_SMPS_CK (4 << RG_FQMTR_CKSEL_SHIFT)
#define FQMTR_FIX_CLK_TCK_SEC (5 << RG_FQMTR_CKSEL_SHIFT)
#define FQMTR_FIX_CLK_PMU_75K (6 << RG_FQMTR_CKSEL_SHIFT)
#define FQMTR_RST (1U << MT6389_RG_FQMTR_RST_SHIFT)
#define FQMTR_EN (1U << MT6389_FQMTR_EN_SHIFT)
#define FQMTR_BUSY (1U << MT6389_FQMTR_BUSY_SHIFT)
#define FQMTR_DCXO26M_EN (1U << MT6389_FQMTR_DCXO26M_EN_SHIFT)
#define FQMTR_XOSC32_CK 0
#define FQMTR_DCXO_F32K_CK 1
#define FQMTR_EOSC32_CK 2
#define FQMTR_XOSC32_CK_DETECTON 3
#define FQMTR_FQM26M_CK 4
#define FQMTR_FQM32K_CK 5
#define FQMTR_TEST_CK 6
#define FQMTR_WINSET 0x0000
#define RTC_FQMTR_LOW_BASE (794 - 2)
#define RTC_FQMTR_HIGH_BASE (794 + 2)
#define RTC_XOSCCALI_START 0x0000
#define RTC_XOSCCALI_END 0x001f
/* 0 (32k crystal exist) 1 (32k crystal doesn't exist) */
#define RTC_XOSC32_ENB (MT6389_RTC_XOSC32_ENB_MASK << \
MT6389_RTC_XOSC32_ENB_SHIFT)
#define RTC_BBPU_2SEC_STAT_CLEAR (MT6389_BBPU_2SEC_STAT_CLEAR_MASK << \
MT6389_BBPU_2SEC_STAT_CLEAR_SHIFT)
/* Default 4'b0111, 2nd step suggest to set to 4'b0000
* EOSC_CALI = charging cap calibration
*/
#define RTC_XOSCCALI_MASK (MT6389_XOSCCALI_MASK << MT6389_XOSCCALI_SHIFT)
#define IPIMB
enum rtc_spare_enum {
RTC_FGSOC = 0,
RTC_ANDROID,
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_FG_INIT,
RTC_SPAR_NUM
};
enum rtc_reg_set {
RTC_REG,
RTC_MASK,
RTC_SHIFT
};
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}
};
/*
* 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 : reserved bit
* bit 9 : reserved bit
* bit 10 : reserved bit
* bit 11 : reserved bit
* bit 12 : reserved 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 : POWER DROP AUTO BOOT 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 : Low power detected in preloader
* bit 8 - 15: reserved bits
*/
/*
* RTC_SPAR1:
* bit 0 - 5 : MIN in power-on time
* bit 6 - 10 : HOU in power-on time
* bit 11 - 15: DOM in power-on time
*/
/*
* RTC_NEW_SPARE0: RTC_AL_HOU bit8~15
* bit 8 ~ 14 : Fuel Gauge
* bit 15 : reserved bits
*/
/*
* RTC_NEW_SPARE1: RTC_AL_DOM bit8~15
* bit 8 ~ 15 : reserved bits
*/
/*
* RTC_NEW_SPARE2: RTC_AL_DOW bit8~15
* bit 8 ~ 15 : reserved bits
*/
/*
* RTC_NEW_SPARE3: RTC_AL_MTH bit8~15
* bit 8 ~ 15 : reserved bits
*/
static u16 rtc_alarm_reg[RTC_OFFSET_COUNT][3] = {
{RTC_AL_SEC, RTC_AL_SEC_MASK, 0},
{RTC_AL_MIN, RTC_AL_MIN_MASK, 0},
{RTC_AL_HOU, RTC_AL_HOU_MASK, 0},
{RTC_AL_DOM, RTC_AL_DOM_MASK, 0},
{RTC_AL_DOW, RTC_AL_DOW_MASK, 0},
{RTC_AL_MTH, RTC_AL_MTH_MASK, 0},
{RTC_AL_YEA, RTC_AL_YEA_MASK, 0},
};
static u16 rtc_pwron_reg[RTC_OFFSET_COUNT][3] = {
{RTC_SPAR0, RTC_PWRON_SEC_MASK, RTC_PWRON_SEC_SHIFT},
{RTC_SPAR1, RTC_PWRON_MIN_MASK, RTC_PWRON_MIN_SHIFT},
{RTC_SPAR1, RTC_PWRON_HOU_MASK, RTC_PWRON_HOU_SHIFT},
{RTC_SPAR1, RTC_PWRON_DOM_MASK, RTC_PWRON_DOM_SHIFT},
{0, 0, 0},
{RTC_PDN2, RTC_PWRON_MTH_MASK, RTC_PWRON_MTH_SHIFT},
{RTC_PDN2, RTC_PWRON_YEA_MASK, RTC_PWRON_YEA_SHIFT},
};
struct mt6358_misc {
struct device *dev;
spinlock_t lock;
struct regmap *regmap;
u32 addr_base;
};
static struct mt6358_misc *rtc_misc;
#ifdef IPIMB
struct regmap *pmic_regmap;
#endif
static int rtc_eosc_cali_td = 8;
static int dcxo_switch;
static int eosc_k;
static int support_xosc;
module_param(rtc_eosc_cali_td, int, 0664);
static int rtc_read(unsigned int reg, unsigned int *val)
{
return regmap_read(rtc_misc->regmap, rtc_misc->addr_base + reg, val);
}
static int rtc_write(unsigned int reg, unsigned int val)
{
return regmap_write(rtc_misc->regmap, rtc_misc->addr_base + reg, val);
}
static int rtc_update_bits(unsigned int reg, unsigned int mask,
unsigned int val)
{
return regmap_update_bits(rtc_misc->regmap,
rtc_misc->addr_base + reg, mask, val);
}
static int rtc_field_read(unsigned int reg,
unsigned int mask, unsigned int shift,
unsigned int *val)
{
int ret;
unsigned int reg_val;
ret = rtc_read(reg, &reg_val);
if (ret != 0)
return ret;
reg_val &= mask;
reg_val >>= shift;
*val = reg_val;
return ret;
}
static int rtc_busy_wait(void)
{
unsigned long long timeout = sched_clock() + 500000000;
int ret;
unsigned int bbpu;
u32 pwrkey1, pwrkey2, sec;
do {
ret = rtc_read(RTC_BBPU, &bbpu);
if (ret < 0)
break;
if ((bbpu & RTC_BBPU_CBUSY) == 0)
break;
else if (sched_clock() > timeout) {
rtc_read(RTC_BBPU, &bbpu);
rtc_read(RTC_POWERKEY1, &pwrkey1);
rtc_read(RTC_POWERKEY2, &pwrkey2);
rtc_read(RTC_TC_SEC, &sec);
pr_err("%s, wait cbusy timeout, %x, %x, %x, %d\n",
__func__, bbpu, pwrkey1, pwrkey2, sec);
ret = -ETIMEDOUT;
break;
}
} while (1);
return ret;
}
static int rtc_write_trigger(void)
{
int ret;
ret = rtc_write(RTC_WRTGR, 1);
if (ret < 0)
return ret;
return !rtc_busy_wait();
}
static int mtk_rtc_get_spare_register(enum rtc_spare_enum cmd)
{
unsigned int tmp_val = 0;
int ret = -EINVAL;
if (cmd >= 0 && cmd < RTC_SPAR_NUM) {
ret = rtc_field_read(rtc_spare_reg[cmd][RTC_REG],
rtc_spare_reg[cmd][RTC_MASK]
<< rtc_spare_reg[cmd][RTC_SHIFT],
rtc_spare_reg[cmd][RTC_SHIFT], &tmp_val);
if (ret < 0)
goto exit;
pr_notice("%s: cmd[%d], get rg[0x%x, 0x%x , %d] = 0x%x\n",
__func__, cmd,
rtc_spare_reg[cmd][RTC_REG],
rtc_spare_reg[cmd][RTC_MASK],
rtc_spare_reg[cmd][RTC_SHIFT], tmp_val);
return tmp_val;
}
exit:
return ret;
}
static void mtk_rtc_set_spare_register(enum rtc_spare_enum cmd, u16 val)
{
u32 tmp_val = 0;
int ret;
if (cmd >= 0 && cmd < RTC_SPAR_NUM) {
pr_notice("%s: cmd[%d], set rg[0x%x, 0x%x , %d] = 0x%x\n",
__func__, cmd,
rtc_spare_reg[cmd][RTC_REG],
rtc_spare_reg[cmd][RTC_MASK],
rtc_spare_reg[cmd][RTC_SHIFT], val);
tmp_val = ((val & rtc_spare_reg[cmd][RTC_MASK])
<< rtc_spare_reg[cmd][RTC_SHIFT]);
ret = rtc_update_bits(rtc_spare_reg[cmd][RTC_REG],
rtc_spare_reg[cmd][RTC_MASK]
<< rtc_spare_reg[cmd][RTC_SHIFT],
tmp_val);
if (ret < 0)
goto exit;
ret = rtc_write_trigger();
if (ret < 0)
goto exit;
}
return;
exit:
pr_err("%s error\n", __func__);
}
int get_rtc_spare_fg_value(void)
{
/* RTC_AL_HOU bit8~14 */
u16 temp;
unsigned long flags;
spin_lock_irqsave(&rtc_misc->lock, flags);
temp = mtk_rtc_get_spare_register(RTC_FGSOC);
spin_unlock_irqrestore(&rtc_misc->lock, flags);
return temp;
}
int set_rtc_spare_fg_value(int val)
{
/* RTC_AL_HOU bit8~14 */
unsigned long flags;
spin_lock_irqsave(&rtc_misc->lock, flags);
mtk_rtc_set_spare_register(RTC_FGSOC, val);
spin_unlock_irqrestore(&rtc_misc->lock, flags);
return 0;
}
int get_rtc_spare0_fg_value(void)
{
u16 temp;
unsigned long flags;
spin_lock_irqsave(&rtc_misc->lock, flags);
temp = mtk_rtc_get_spare_register(RTC_FG_INIT);
spin_unlock_irqrestore(&rtc_misc->lock, flags);
return temp;
}
int set_rtc_spare0_fg_value(int val)
{
unsigned long flags;
spin_lock_irqsave(&rtc_misc->lock, flags);
mtk_rtc_set_spare_register(RTC_FG_INIT, val);
spin_unlock_irqrestore(&rtc_misc->lock, flags);
return 0;
}
bool crystal_exist_status(void)
{
unsigned long flags;
u16 ret;
spin_lock_irqsave(&rtc_misc->lock, flags);
ret = mtk_rtc_get_spare_register(RTC_32K_LESS);
spin_unlock_irqrestore(&rtc_misc->lock, flags);
if (ret)
return true;
else
return false;
}
EXPORT_SYMBOL(crystal_exist_status);
static void mtk_rtc_clear_pwron_alarm(void)
{
u16 data[RTC_OFFSET_COUNT];
int ret, i;
pr_notice("%s\n", __func__);
data[RTC_OFFSET_SEC] = 0;
data[RTC_OFFSET_MIN] = 0;
data[RTC_OFFSET_HOUR] = 0;
data[RTC_OFFSET_DOM] = ((RTC_DEFAULT_DOM << RTC_PWRON_DOM_SHIFT) &
RTC_PWRON_DOM_MASK);
data[RTC_OFFSET_MTH] = ((RTC_DEFAULT_MTH << RTC_PWRON_MTH_SHIFT) &
RTC_PWRON_MTH_MASK);
data[RTC_OFFSET_YEAR] = (((RTC_DEFAULT_YEA - RTC_MIN_YEAR) <<
RTC_PWRON_YEA_SHIFT)
& RTC_PWRON_YEA_MASK);
for (i = RTC_OFFSET_SEC; i < RTC_OFFSET_COUNT; i++) {
if (i == RTC_OFFSET_DOW)
continue;
ret = rtc_update_bits(rtc_pwron_reg[i][RTC_REG],
rtc_pwron_reg[i][RTC_MASK], data[i]);
if (ret < 0)
goto exit;
ret = rtc_write_trigger();
if (ret < 0)
goto exit;
}
ret = rtc_update_bits(RTC_PDN1, RTC_PDN1_PWRON_TIME, 0);
if (ret < 0)
goto exit;
ret = rtc_update_bits(RTC_PDN2, RTC_PDN2_PWRON_LOGO, 0);
if (ret < 0)
goto exit;
ret = rtc_write_trigger();
if (ret < 0)
goto exit;
return;
exit:
pr_err("%s error\n", __func__);
}
static void mtk_rtc_clear_alarm(void)
{
unsigned int irqsta;
u16 data[RTC_OFFSET_COUNT];
int i, ret;
ret = rtc_update_bits(RTC_IRQ_EN, RTC_IRQ_EN_AL, 0);
if (ret < 0)
goto exit;
ret = rtc_write_trigger();
if (ret < 0)
goto exit;
ret = rtc_read(RTC_IRQ_STA, &irqsta); /* read clear */
if (ret < 0)
goto exit;
data[RTC_OFFSET_SEC] = 0;
data[RTC_OFFSET_MIN] = 0;
data[RTC_OFFSET_HOUR] = 0;
data[RTC_OFFSET_DOM] = RTC_DEFAULT_DOM & RTC_AL_DOM_MASK;
data[RTC_OFFSET_MTH] = RTC_DEFAULT_MTH & RTC_AL_MTH_MASK;
data[RTC_OFFSET_YEAR] = ((RTC_DEFAULT_YEA - RTC_MIN_YEAR) &
RTC_AL_YEA_MASK);
for (i = RTC_OFFSET_SEC; i < RTC_OFFSET_COUNT; i++) {
if (i == RTC_OFFSET_DOW)
continue;
ret = rtc_update_bits(rtc_alarm_reg[i][RTC_REG],
rtc_alarm_reg[i][RTC_MASK], data[i]);
if (ret < 0)
goto exit;
}
ret = rtc_write_trigger();
if (ret < 0)
goto exit;
return;
exit:
pr_err("%s error\n", __func__);
}
void rtc_mark_recovery(void)
{
unsigned long flags;
pr_notice("%s\n", __func__);
spin_lock_irqsave(&rtc_misc->lock, flags);
mtk_rtc_set_spare_register(RTC_FAC_RESET, 0x1);
/* Clear alarm setting when doing factory recovery. */
mtk_rtc_clear_pwron_alarm();
mtk_rtc_clear_alarm();
spin_unlock_irqrestore(&rtc_misc->lock, flags);
}
void rtc_mark_kpoc(void)
{
unsigned long flags;
pr_notice("%s\n", __func__);
spin_lock_irqsave(&rtc_misc->lock, flags);
mtk_rtc_set_spare_register(RTC_KPOC, 0x1);
spin_unlock_irqrestore(&rtc_misc->lock, flags);
}
void rtc_mark_fast(void)
{
unsigned long flags;
pr_notice("%s\n", __func__);
spin_lock_irqsave(&rtc_misc->lock, flags);
mtk_rtc_set_spare_register(RTC_FAST_BOOT, 0x1);
spin_unlock_irqrestore(&rtc_misc->lock, flags);
}
static int pmic_read_interface(unsigned int RegNum, unsigned int *val,
unsigned int MASK, unsigned int SHIFT)
{
int ret = 0;
#ifdef IPIMB
ret = regmap_read(pmic_regmap, RegNum, val);
#else
ret = regmap_read(rtc_misc->regmap, RegNum, val);
#endif
if (ret) {
pr_notice("[%s]ret=%d Reg=0x%x val=0x%x MASK=0x%x SHIFT=%d\n",
__func__, ret, RegNum, val, MASK, SHIFT);
return ret;
}
*val = (*val >> SHIFT) & MASK;
return ret;
}
static int upmu_get_reg_value(unsigned int reg, unsigned int *reg_val)
{
int ret = 0;
ret = pmic_read_interface(reg, reg_val, 0xFFFF, 0x0);
return ret;
}
static int pmic_config_interface(unsigned int RegNum, unsigned int val,
unsigned int MASK, unsigned int SHIFT)
{
int ret = 0;
#ifdef IPIMB
ret = regmap_update_bits(pmic_regmap, RegNum,
(MASK << SHIFT), (val << SHIFT));
#else
ret = regmap_update_bits(rtc_misc->regmap, RegNum,
(MASK << SHIFT), (val << SHIFT));
#endif
if (ret) {
pr_notice("[%s]ret=%d Reg=0x%x val=0x%x MASK=0x%x SHIFT=%d\n",
__func__, ret, RegNum, val, MASK, SHIFT);
return ret;
}
return ret;
}
static int upmu_set_reg_value(unsigned int reg, unsigned int reg_val)
{
unsigned int ret = 0;
ret = pmic_config_interface(reg, reg_val, 0xFFFF, 0x0);
return ret;
}
static void mtk_rtc_enable_k_eosc(void)
{
pr_notice("%s\n", __func__);
/* Truning on eosc cali mode clock */
pmic_config_interface(MT6389_SCK_TOP_CKPDN_CON0_CLR_ADDR, 1,
MT6389_RG_RTC_EOSC32_CK_PDN_MASK,
MT6389_RG_RTC_EOSC32_CK_PDN_SHIFT);
if (rtc_eosc_cali_td != 8) {
pr_notice("%s: rtc_eosc_cali_td = %d\n",
__func__, rtc_eosc_cali_td);
switch (rtc_eosc_cali_td) {
case 1:
pmic_config_interface(MT6389_EOSC_CALI_TD_ADDR, 0x3,
MT6389_EOSC_CALI_TD_MASK,
MT6389_EOSC_CALI_TD_SHIFT);
break;
case 2:
pmic_config_interface(MT6389_EOSC_CALI_TD_ADDR, 0x4,
MT6389_EOSC_CALI_TD_MASK,
MT6389_EOSC_CALI_TD_SHIFT);
break;
case 4:
pmic_config_interface(MT6389_EOSC_CALI_TD_ADDR, 0x5,
MT6389_EOSC_CALI_TD_MASK,
MT6389_EOSC_CALI_TD_SHIFT);
break;
case 16:
pmic_config_interface(MT6389_EOSC_CALI_TD_ADDR, 0x7,
MT6389_EOSC_CALI_TD_MASK,
MT6389_EOSC_CALI_TD_SHIFT);
break;
default:
pmic_config_interface(MT6389_EOSC_CALI_TD_ADDR, 0x6,
MT6389_EOSC_CALI_TD_MASK,
MT6389_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
*/
if (dcxo_switch) {
pr_notice("%s: dcxo_switch\n", __func__);
pmic_config_interface(MT6389_XO_EN32K_MAN_ADDR, 0,
MT6389_XO_EN32K_MAN_MASK,
MT6389_XO_EN32K_MAN_SHIFT);
}
}
static void mtk_rtc_spar_alarm_clear_wait(void)
{
unsigned long long timeout = sched_clock() + 500000000;
u32 bbpu;
int ret;
do {
ret = rtc_read(RTC_BBPU, &bbpu);
if (ret < 0)
break;
if ((bbpu & RTC_BBPU_CLR) == 0)
break;
else if (sched_clock() > timeout) {
pr_err("%s, spar/alarm clear time out,\n", __func__);
break;
}
} while (1);
}
void mt_power_off(void)
{
unsigned long flags;
u32 pdn1 = 0, al_mask = 0, irq_en = 0;
int ret;
pr_notice("%s\n", __func__);
dump_stack();
spin_lock_irqsave(&rtc_misc->lock, flags);
#ifndef CONFIG_MTK_PMIC_CHIP_MT6389
ret = rtc_field_read(RTC_PDN1, RTC_GPIO_USER_MASK,
RTC_GPIO_USER_WIFI, &pdn1);
if (ret < 0)
goto exit;
/* disable 32K export if there are no RTC_GPIO users */
if (!pdn1) {
ret = rtc_update_bits(RTC_CON, RTC_CON_F32KOB, RTC_CON_F32KOB);
if (ret < 0)
goto exit;
ret = rtc_write_trigger();
if (ret < 0)
goto exit;
}
#endif
/* lpsd */
pr_notice("clear lpsd solution\n");
ret = rtc_write(RTC_BBPU, RTC_BBPU_KEY | RTC_BBPU_CLR | RTC_BBPU_PWREN);
if (ret < 0)
goto exit;
ret = rtc_write(RTC_AL_MASK, RTC_AL_MASK_DOW); /* mask DOW */
if (ret < 0)
goto exit;
ret = rtc_write_trigger();
if (ret < 0)
goto exit;
mtk_rtc_spar_alarm_clear_wait();
ret = rtc_update_bits(RTC_BBPU,
(RTC_BBPU_KEY | RTC_BBPU_RELOAD),
(RTC_BBPU_KEY | RTC_BBPU_RELOAD));
if (ret < 0)
goto exit;
ret = rtc_write_trigger();
if (ret < 0)
goto exit;
ret = rtc_read(RTC_AL_MASK, &al_mask);
if (ret < 0)
goto exit;
ret = rtc_read(RTC_IRQ_EN, &irq_en);
if (ret < 0)
goto exit;
pr_notice("%s: RTC_AL_MASK= 0x%x RTC_IRQ_EN= 0x%x\n",
__func__, al_mask, irq_en);
spin_unlock_irqrestore(&rtc_misc->lock, flags);
//wk_pmic_enable_sdn_delay();
pmic_config_interface(MT6389_TMA_KEY_ADDR, 0x9CA7,
MT6389_TMA_KEY_MASK, MT6389_TMA_KEY_SHIFT);
pmic_config_interface(MT6389_RG_SDN_DLY_ENB_ADDR, 0,
MT6389_RG_SDN_DLY_ENB_MASK,
MT6389_RG_SDN_DLY_ENB_SHIFT);
pmic_config_interface(MT6389_TMA_KEY_ADDR, 0,
MT6389_TMA_KEY_MASK, MT6389_TMA_KEY_SHIFT);
#ifndef CONFIG_MTK_PMIC_CHIP_MT6389
pmic_config_interface(MT6389_RG_PWRHOLD_ADDR, 0,
MT6389_RG_PWRHOLD_MASK, MT6389_RG_PWRHOLD_SHIFT);
#endif
return;
exit:
spin_unlock_irqrestore(&rtc_misc->lock, flags);
pr_err("%s error\n", __func__);
}
static void mtk_rtc_lpsd_restore_al_mask(void)
{
int ret;
u32 val;
ret = rtc_update_bits(RTC_BBPU,
(RTC_BBPU_KEY | RTC_BBPU_RELOAD),
(RTC_BBPU_KEY | RTC_BBPU_RELOAD));
if (ret < 0)
goto exit;
ret = rtc_write_trigger();
if (ret < 0)
goto exit;
ret = rtc_read(RTC_AL_MASK, &val);
if (ret < 0)
goto exit;
pr_notice("%s: 1st RTC_AL_MASK = 0x%x\n", __func__, val);
/* mask DOW */
ret = rtc_write(RTC_AL_MASK, RTC_AL_MASK_DOW);
if (ret < 0)
goto exit;
ret = rtc_write_trigger();
if (ret < 0)
goto exit;
ret = rtc_read(RTC_AL_MASK, &val);
if (ret < 0)
goto exit;
pr_notice("%s: 2nd RTC_AL_MASK = 0x%x\n", __func__, val);
return;
exit:
pr_err("%s error\n", __func__);
}
static void mt6358_misc_shutdown(struct platform_device *pdev)
{
if (eosc_k)
mtk_rtc_enable_k_eosc();
}
static bool rtc_gpio_init(void)
{
u16 con;
int ret;
u32 val;
/* GPI mode and pull enable + pull down */
ret = rtc_read(RTC_CON, &val);
if (ret < 0)
goto exit;
con = val & (RTC_CON_LPSTA_RAW | RTC_CON_LPRST |
RTC_XOSC32_LPEN | RTC_EOSC32_LPEN);
con &= ~RTC_CON_GPU;
con &= ~RTC_CON_F32KOB; //for avoid leak current
con |= RTC_CON_GPEN | RTC_CON_GOE;
rtc_write(RTC_CON, con);
if (rtc_write_trigger())
return true;
else
return false;
exit:
pr_err("%s error\n", __func__);
return false;
}
void rtc_reload(void)
{
u16 bbpu;
int ret;
u32 val;
ret = rtc_read(RTC_BBPU, &val);
if (ret < 0)
goto exit;
bbpu = val | RTC_BBPU_KEY | RTC_BBPU_RELOAD;
rtc_write(RTC_BBPU, bbpu);
rtc_write_trigger();
return;
exit:
pr_err("%s error\n", __func__);
}
void rtc_xosc_write(u16 val)
{
int ret;
rtc_write(RTC_OSC32CON, RTC_OSC32CON_UNLOCK1);
mdelay(1);
rtc_write(RTC_OSC32CON, RTC_OSC32CON_UNLOCK2);
mdelay(1);
rtc_write(RTC_OSC32CON, val);
mdelay(1);
pr_notice("[RTC] xosc write val=%x\n", val);
}
void rtc_switch_mode(bool XOSC, bool recovery)
{
u16 osc32con;
if (XOSC) {
/* Since HW XTAL_DET is removed, there is a register for
* switch the external crystal or the embedded clock
*/
/* 0: with the external xtal */
pmic_config_interface(MT6389_SCK_TOP_XTAL_SEL_ADDR, 0,
MT6389_SCK_TOP_XTAL_SEL_MASK,
MT6389_SCK_TOP_XTAL_SEL_SHIFT);
osc32con = OSC32CON_ANALOG_SETTING;
/* assume crystal exist mode + XOSCCALI = 0x7 */
rtc_xosc_write(osc32con | 0x7);
if (recovery)
mdelay(1500);
} else {
/* 1: without the external xtal */
pmic_config_interface(MT6389_SCK_TOP_XTAL_SEL_ADDR, 1,
MT6389_SCK_TOP_XTAL_SEL_MASK,
MT6389_SCK_TOP_XTAL_SEL_SHIFT);
if (recovery)
mdelay(100);
osc32con = OSC32CON_ANALOG_SETTING | RTC_REG_XOSC32_ENB;
/*crystal not exist + eosc cali = 0xF */
rtc_xosc_write(osc32con);
mdelay(10);
}
}
void rtc_switch_to_xosc_recv_mode(void)
{
rtc_switch_mode(true, true);
}
void rtc_switch_to_dcxo_recv_mode(void)
{
rtc_switch_mode(false, true);
}
static u16 get_frequency_meter(u16 cali, u16 measureSrc, u16 window_size)
{
u16 data;
int ret;
u32 val;
unsigned long long timeout = sched_clock() + 500000000;
if (cali != 0) {
u16 osc32con;
rtc_reload();
ret = rtc_read(RTC_OSC32CON, &val);
if (ret < 0)
goto exit;
osc32con = val & 0xFFE0;
rtc_xosc_write(osc32con | (cali & RTC_XOSCCALI_MASK));
}
pmic_config_interface(FQMTR_CLK_CK_PDN_CLR, 1, FQMTR_CLK_CK_PDN_MASK,
FQMTR_CLK_CK_PDN_SHIFT);
pmic_config_interface(RG_FQMTR_32K_CLK_PDN_CLR, 1,
RG_FQMTR_32K_CLK_PDN_MASK,
RG_FQMTR_32K_CLK_PDN_SHIFT);
pmic_config_interface(MT6389_RG_BANK_FQMTR_RST_ADDR, 1,
MT6389_RG_BANK_FQMTR_RST_MASK,
MT6389_RG_BANK_FQMTR_RST_SHIFT);
udelay(20);
pmic_config_interface(MT6389_RG_BANK_FQMTR_RST_ADDR, 0,
MT6389_RG_BANK_FQMTR_RST_MASK,
MT6389_RG_BANK_FQMTR_RST_SHIFT);
pmic_config_interface(MT6389_FQMTR_DCXO26M_EN_ADDR, 1,
MT6389_FQMTR_DCXO26M_EN_MASK,
MT6389_FQMTR_DCXO26M_EN_SHIFT);
//set freq. meter window value (0=1X32K(fix clock))
upmu_set_reg_value(RG_FQMTR_WINSET, window_size);
//enable freq. meter, set measure clock to 26Mhz
upmu_set_reg_value(RG_FQMTR_TCKSEL, FQMTR_DCXO26M_EN | measureSrc);
mdelay(1);
ret = upmu_get_reg_value(RG_FQMTR_TCKSEL, &val);
if (ret < 0)
goto exit;
upmu_set_reg_value(RG_FQMTR_TCKSEL, val | FQMTR_EN);
mdelay(1);
// FQMTR read until ready
do {
if (sched_clock() > timeout) {
pr_err("[RTC] get frequency time out\n");
break;
}
mdelay(1);
ret = upmu_get_reg_value(RG_FQMTR_BUSY, &val);
if (ret < 0)
goto exit;
} while ((FQMTR_BUSY & val) == FQMTR_BUSY);
ret = upmu_get_reg_value(RG_FQMTR_DATA, &val);
if (ret < 0)
goto exit;
data = val; //read data should be closed to 26M/32k = 794
pmic_config_interface(MT6389_FQMTR_DCXO26M_EN_ADDR, 0,
MT6389_FQMTR_DCXO26M_EN_MASK,
MT6389_FQMTR_DCXO26M_EN_SHIFT);
ret = upmu_get_reg_value(RG_FQMTR_TCKSEL, &val);
if (ret < 0)
goto exit;
//enable freq. meter, set measure clock to 26Mhz
upmu_set_reg_value(RG_FQMTR_TCKSEL, val & ~(FQMTR_DCXO26M_EN));
mdelay(1);
ret = upmu_get_reg_value(RG_FQMTR_TCKSEL, &val);
if (ret < 0)
goto exit;
//enable freq. meter, set measure clock to 26Mhz
upmu_set_reg_value(RG_FQMTR_TCKSEL, val & ~(FQMTR_EN));
pr_notice("[RTC] %s: input=0x%x, output=%d\n", __func__, cali, data);
pmic_config_interface(FQMTR_CLK_CK_PDN_SET, 1, FQMTR_CLK_CK_PDN_MASK,
FQMTR_CLK_CK_PDN_SHIFT);
pmic_config_interface(RG_FQMTR_32K_CLK_PDN_SET, 1,
RG_FQMTR_32K_CLK_PDN_MASK,
RG_FQMTR_32K_CLK_PDN_SHIFT);
return data;
exit:
pr_err("%s error\n", __func__);
return 0;
}
void rtc_measure_four_clock(u16 *result)
{
u16 window_size;
u16 regval;
int ret;
u32 val;
ret = upmu_get_reg_value(RG_FQMTR_CKSEL, &val);
if (ret < 0)
goto exit;
regval = val & (~(RG_FQMTR_CKSEL_MASK << RG_FQMTR_CKSEL_SHIFT));
//select 26M as fixed clock
upmu_set_reg_value(RG_FQMTR_CKSEL, regval | FQMTR_FIX_CLK_26M);
window_size = 4;
mdelay(1);
//select 26M as target clock
result[0] = get_frequency_meter(0, FQMTR_FQM26M_CK, window_size);
ret = upmu_get_reg_value(RG_FQMTR_CKSEL, &val);
if (ret < 0)
goto exit;
regval = val & (~(RG_FQMTR_CKSEL_MASK << RG_FQMTR_CKSEL_SHIFT));
//select XOSC_DET as fixed clock
upmu_set_reg_value(RG_FQMTR_CKSEL, regval | FQMTR_FIX_CLK_XOSC_32K_DET);
window_size = 4;
mdelay(1);
//select 26M as target clock
result[1] = get_frequency_meter(0, FQMTR_FQM26M_CK, window_size);
ret = upmu_get_reg_value(RG_FQMTR_CKSEL, &val);
if (ret < 0)
goto exit;
regval = val & (~(RG_FQMTR_CKSEL_MASK << RG_FQMTR_CKSEL_SHIFT));
//select 26M as fixed clock
upmu_set_reg_value(RG_FQMTR_CKSEL, regval | FQMTR_FIX_CLK_26M);
window_size = 3970; // (26M / 32K) * 5
mdelay(1);
//select xosc_32 as target clock
result[2] = get_frequency_meter(0, FQMTR_XOSC32_CK, window_size);
//select DCXO_32 as target clock
result[2] = get_frequency_meter(0, FQMTR_DCXO_F32K_CK, window_size);
ret = upmu_get_reg_value(RG_FQMTR_CKSEL, &val);
if (ret < 0)
goto exit;
regval = val & (~(RG_FQMTR_CKSEL_MASK << RG_FQMTR_CKSEL_SHIFT));
//select EOSC_32 as fixed clock
upmu_set_reg_value(RG_FQMTR_CKSEL, regval | FQMTR_FIX_CLK_EOSC_32K);
window_size = 4;
mdelay(1);
//select 26M as target clock
result[3] = get_frequency_meter(0, FQMTR_FQM26M_CK, window_size);
return;
exit:
pr_err("%s error\n", __func__);
}
static bool rtc_xosc_check_clock(u16 *result)
{
///// fix me loose range for frequency meter result////
if ((result[0] >= 3 && result[0] <= 7) &&
(result[1] > 1500 && result[1] < 6000) &&
(result[2] == 0) && (result[3] == 0))
return true;
else
return false;
}
static bool rtc_eosc_check_clock(u16 *result)
{
if ((result[0] >= 3 && result[0] <= 7) &&
(result[1] < 500) &&
(result[2] > 2 && result[2] < 9) &&
(result[3] > 300 && result[3] < 10400))
return true;
else
return false;
}
bool Writeif_unlock(void)
{
rtc_write(RTC_PROT, RTC_PROT_UNLOCK1);
if (!rtc_write_trigger())
return false;
rtc_write(RTC_PROT, RTC_PROT_UNLOCK2);
if (!rtc_write_trigger())
return false;
return true;
}
int eosc_cali(void)
{
u32 val, diff1, diff2, eosc_freq, regval;
int middle;
int i, left, right;
int ret;
ret = upmu_get_reg_value(RG_FQMTR_CKSEL, &val);
if (ret < 0)
goto exit;
regval = val & (~(RG_FQMTR_CKSEL_MASK << RG_FQMTR_CKSEL_SHIFT));
//select EOSC_32 as fixed clock
upmu_set_reg_value(RG_FQMTR_CKSEL, regval | FQMTR_FIX_CLK_EOSC_32K);
left = RTC_XOSCCALI_START;
right = RTC_XOSCCALI_END;
while (left <= right) {
middle = (right + left) / 2;
if (middle == left)
break;
//select 26M as target clock
val = get_frequency_meter(middle,
FQMTR_FQM26M_CK, 0);
pr_notice("[RTC] EOSC_Cali: val=0x%x\n", val);
if ((val >= RTC_FQMTR_LOW_BASE) && (val <= RTC_FQMTR_HIGH_BASE))
break;
if (val > RTC_FQMTR_HIGH_BASE)
right = middle;
else
left = middle;
}
if ((val >= RTC_FQMTR_LOW_BASE) && (val <= RTC_FQMTR_HIGH_BASE))
return middle;
val = get_frequency_meter(left, FQMTR_FQM26M_CK, 0);
if (val > RTC_FQMTR_LOW_BASE)
diff1 = val - RTC_FQMTR_LOW_BASE;
else
diff1 = RTC_FQMTR_LOW_BASE - val;
val = get_frequency_meter(right, FQMTR_FQM26M_CK, 0);
if (val > RTC_FQMTR_LOW_BASE)
diff2 = val - RTC_FQMTR_LOW_BASE;
else
diff2 = RTC_FQMTR_LOW_BASE - val;
if (diff1 < diff2)
return left;
else
return right;
exit:
pr_err("%s error\n", __func__);
return 0;
}
static bool eosc_init(void)
{
u16 osc32con, val = 0;
val = eosc_cali();
pr_notice("EOSC cali val = 0x%x\n", val);
//EMB_HW_Mode
osc32con = OSC32CON_ANALOG_SETTING | RTC_REG_XOSC32_ENB;
val = (val & 0x001f) | osc32con;
pr_notice("EOSC cali val = 0x%x\n", val);
rtc_xosc_write(val);
return true;
}
static bool rtc_hw_init(void)
{
int ret;
u32 val;
unsigned long long timeout = sched_clock() + 500000000;
ret = rtc_read(RTC_BBPU, &val);
if (ret < 0)
goto exit;
rtc_write(RTC_BBPU,
val | RTC_BBPU_KEY | RTC_BBPU_RESET_ALARM |
RTC_BBPU_RESET_SPAR &
(~RTC_BBPU_SPAR_SW));
rtc_write_trigger();
do {
rtc_reload();
ret = rtc_read(RTC_BBPU, &val);
if (ret < 0)
goto exit;
} while (((val & RTC_BBPU_RESET_ALARM) || (val & RTC_BBPU_RESET_SPAR))
&& sched_clock() < timeout);
if ((val & RTC_BBPU_RESET_ALARM) || (val & RTC_BBPU_RESET_SPAR)) {
pr_err("[RTC] hw_init timeout\n");
return false;
}
return true;
exit:
pr_err("%s error\n", __func__);
return false;
}
static bool rtc_lpd_init(void)
{
u16 con;
int ret;
u32 val;
ret = rtc_read(RTC_CON, &val);
if (ret < 0)
goto exit;
con = val | RTC_XOSC32_LPEN;
con &= ~RTC_CON_LPRST;
rtc_write(RTC_CON, con);
if (!rtc_write_trigger())
return false;
con |= RTC_CON_LPRST;
rtc_write(RTC_CON, con);
if (!rtc_write_trigger())
return false;
con &= ~RTC_CON_LPRST;
rtc_write(RTC_CON, con);
if (!rtc_write_trigger())
return false;
ret = rtc_read(RTC_CON, &val);
if (ret < 0)
goto exit;
con = val | RTC_EOSC32_LPEN;
con &= ~RTC_CON_LPRST;
rtc_write(RTC_CON, con);
if (!rtc_write_trigger())
return false;
con |= RTC_CON_LPRST;
rtc_write(RTC_CON, con);
if (!rtc_write_trigger())
return false;
con &= ~RTC_CON_LPRST;
rtc_write(RTC_CON, con);
if (!rtc_write_trigger())
return false;
ret = rtc_read(RTC_CON, &val);
if (ret < 0)
goto exit;
pr_notice("[RTC] %s RTC_CON=0x%x\n", __func__, val);
ret = rtc_read(RTC_SPAR0, &val);
if (ret < 0)
goto exit;
//bit 7 for low power detected in preloader
rtc_write(RTC_SPAR0, val | 0x0080);
if (!rtc_write_trigger())
return false;
return true;
exit:
pr_err("%s error\n", __func__);
return false;
}
static bool rtc_2sec_stat_clear(void)
{
int ret;
u32 val;
pr_notice("[RTC] %s\n", __func__);
ret = rtc_read(RTC_AL_SEC, &val);
if (ret < 0)
goto exit;
rtc_write(RTC_AL_SEC, val & ~RTC_BBPU_2SEC_STAT_CLEAR);
if (!rtc_write_trigger())
return false;
ret = rtc_read(RTC_AL_SEC, &val);
if (ret < 0)
goto exit;
rtc_write(RTC_AL_SEC, val | RTC_BBPU_2SEC_STAT_CLEAR);
if (!rtc_write_trigger())
return false;
ret = rtc_read(RTC_AL_SEC, &val);
if (ret < 0)
goto exit;
rtc_write(RTC_AL_SEC, val & ~RTC_BBPU_2SEC_STAT_CLEAR);
if (!rtc_write_trigger())
return false;
return true;
exit:
pr_err("%s error\n", __func__);
return false;
}
static bool rtc_android_init(void)
{
u16 reboot;
int ret;
u32 val;
rtc_write(RTC_IRQ_EN, 0);
rtc_write(RTC_CII_EN, 0);
rtc_write(RTC_AL_MASK, 0);
ret = rtc_read(RTC_AL_YEA, &val);
if (ret < 0)
goto exit;
rtc_write(RTC_AL_YEA,
(val & (~RTC_AL_YEA_MASK)) |
((1970 - RTC_MIN_YEAR) & RTC_AL_YEA_MASK));
rtc_write(RTC_AL_MTH, 1);
rtc_write(RTC_AL_DOM, 1); /* NEW_SPARE1[0] = 0 */
/* RG_EOSC_CALI_TD = 8 sec */
rtc_write(RTC_AL_DOW, RTC_EOSC_CALI_TD_08_SEC <<
MT6389_RG_EOSC_CALI_TD_SHIFT | 1);
rtc_write(RTC_AL_HOU, 0);
rtc_write(RTC_AL_MIN, 0);
ret = rtc_read(RTC_AL_SEC, &val);
if (ret < 0)
goto exit;
rtc_write(RTC_AL_SEC, val & (~RTC_AL_SEC_MASK));
rtc_write(RTC_PDN1, 0); /* set Debug bit */
rtc_write(RTC_PDN2, 0);
rtc_write(RTC_SPAR0, 0);
rtc_write(RTC_SPAR1, 0);
rtc_write(RTC_DIFF, 0);
rtc_write(RTC_CALI, 0);
ret = rtc_read(RTC_AL_SEC, &val);
if (ret < 0)
goto exit;
reboot = (val & ~RTC_BBPU_2SEC_EN) & ~RTC_BBPU_AUTO_PDN_SEL;
rtc_write(RTC_AL_SEC, reboot);
if (!rtc_2sec_stat_clear())
return false;
if (!rtc_write_trigger())
return false;
/* read clear */
ret = rtc_read(RTC_AL_SEC, &val);
if (ret < 0)
goto exit;
/* init time counters after resetting RTC_DIFF and RTC_CALI */
rtc_write(RTC_TC_YEA, 2010 - RTC_MIN_YEAR);
rtc_write(RTC_TC_MTH, 1);
rtc_write(RTC_TC_DOM, 1);
rtc_write(RTC_TC_DOW, 1);
rtc_write(RTC_TC_HOU, 0);
rtc_write(RTC_TC_MIN, 0);
rtc_write(RTC_TC_SEC, 0);
if (!rtc_write_trigger())
return false;
return true;
exit:
pr_err("%s error\n", __func__);
return false;
}
static bool rtc_first_boot_init(void)
{
int ret;
u32 val;
u16 result[4];
pr_notice("[RTC] %s\n", __func__);
pmic_config_interface(MT6389_XO_EN32K_MAN_ADDR, 0,
MT6389_XO_EN32K_MAN_MASK,
MT6389_XO_EN32K_MAN_SHIFT);
pmic_config_interface(MT6389_XO_XMODE_M_ADDR, 1, MT6389_XO_XMODE_M_MASK,
MT6389_XO_XMODE_M_SHIFT);
/* always try xosc fisrt */
/* switch to XOSC */
if (support_xosc) {
rtc_switch_to_xosc_recv_mode();
rtc_measure_four_clock(result);
}
if (!support_xosc || !rtc_xosc_check_clock(result)) {
/* switch to DCXO if XOSC detect failed */
rtc_switch_to_dcxo_recv_mode();
rtc_measure_four_clock(result);
if (!rtc_eosc_check_clock(result)) {
pr_err("32k detection failed\n");
return false;
}
}
if (!Writeif_unlock()) {
pr_err("[RTC] Writeif_unlock fail1\n");
return false;
}
rtc_reload();
if (!rtc_gpio_init())
return false;
/* write powerkeys */
ret = rtc_read(RTC_AL_SEC, &val);
if (ret < 0)
goto exit;
rtc_write(RTC_AL_SEC, val & (~RTC_K_EOSC32_VTCXO_ON_SEL));
rtc_write(RTC_POWERKEY1, RTC_POWERKEY1_KEY);
rtc_write(RTC_POWERKEY2, RTC_POWERKEY2_KEY);
if (!rtc_write_trigger()) {
pr_err("[RTC] first_boot_init rtc_write_trigger fail1\n");
return false;
}
//disable both XOSC & EOSC LPD
ret = rtc_read(RTC_AL_SEC, &val);
if (ret < 0)
goto exit;
rtc_write(RTC_AL_SEC, val | RTC_LPD_OPT_F32K_CK_ALIVE);
if (!rtc_write_trigger()) {
pr_err("[RTC] %s rtc_write_trigger fail2\n", __func__);
return false;
}
if (!rtc_lpd_init())
return false;
//write POWERKEY again to unlock RTC
rtc_write(RTC_POWERKEY1, RTC_POWERKEY1_KEY);
rtc_write(RTC_POWERKEY2, RTC_POWERKEY2_KEY);
if (!rtc_write_trigger()) {
pr_err("[RTC] %s rtc_write_trigger fail3\n", __func__);
return false;
}
//Enable EOSC LPD
ret = rtc_read(RTC_AL_SEC, &val);
if (ret < 0)
goto exit;
rtc_write(RTC_AL_SEC, (val & (~RTC_LPD_OPT_MASK)) |
RTC_LPD_OPT_EOSC_LPD);
rtc_write_trigger();
if (!eosc_init()) {
pr_err("[RTC] %s eosc_init fail\n", __func__);
return false;
}
if (!rtc_lpd_init()) {
pr_err("[RTC] %s rtc_lpd_init fail\n", __func__);
return false;
}
if (!rtc_hw_init()) {
pr_err("[RTC] %s rtc_hw_init fail\n", __func__);
return false;
}
if (!rtc_android_init()) {
pr_err("[RTC] %s rtc_android_init fail\n", __func__);
return false;
}
return true;
exit:
pr_err("%s error\n", __func__);
return false;
}
static bool rtc_get_xosc_mode(void)
{
u16 xosc_mode;
int ret;
u32 val;
ret =
pmic_read_interface(MT6389_SCK_TOP_XTAL_SEL_ADDR,
&val, MT6389_SCK_TOP_XTAL_SEL_MASK,
MT6389_SCK_TOP_XTAL_SEL_SHIFT);
if (ret < 0)
goto exit;
if (val)
xosc_mode = 0; /* 32k */
else
xosc_mode = 1; /* 32k-less */
return xosc_mode;
exit:
pr_err("%s error\n", __func__);
return false;
}
void rtc_init(void)
{
u16 spar0;
int ret;
u32 val1, val2, val3;
pmic_config_interface(MT6389_TOP_CKPDN_CON0_CLR_ADDR, 1,
MT6389_RG_FQMTR_CK_PDN_MASK,
MT6389_RG_FQMTR_CK_PDN_SHIFT);
pmic_config_interface(MT6389_TOP_CKPDN_CON0_CLR_ADDR, 1,
MT6389_RG_FQMTR_32K_CK_PDN_MASK,
MT6389_RG_FQMTR_32K_CK_PDN_SHIFT);
ret = rtc_read(RTC_POWERKEY1, &val1);
if (ret < 0)
goto exit;
ret = rtc_read(RTC_POWERKEY2, &val2);
if (ret < 0)
goto exit;
ret = rtc_read(RTC_CON, &val3);
if (ret < 0)
goto exit;
pr_notice("%s#1 powerkey1 = 0x%x, powerkey2 = 0x%x, %s LPD\n",
__func__, val1, val2,
(val3 & RTC_CON_LPSTA_RAW) ? "with" : "without");
ret = rtc_read(RTC_BBPU, &val1);
if (ret < 0)
goto exit;
ret = rtc_read(RTC_CON, &val2);
if (ret < 0)
goto exit;
ret = rtc_read(RTC_OSC32CON, &val3);
if (ret < 0)
goto exit;
pr_notice("bbpu = 0x%x, con = 0x%x, osc32con = 0x%x\n",
val1, val2, val3);
// switch from 32k to 128/4k
pmic_config_interface(MT6389_TOP_CKSEL_CON0_CLR_ADDR, 1,
MT6389_RG_RTC_32K1V8_SEL_MASK,
MT6389_RG_RTC_32K1V8_SEL_SHIFT);
// always do first boot init
if (!rtc_first_boot_init())
goto exit;
// switch from 128/4k to 32k
pmic_config_interface(MT6389_TOP_CKSEL_CON0_SET_ADDR, 1,
MT6389_RG_RTC_32K1V8_SEL_MASK,
MT6389_RG_RTC_32K1V8_SEL_SHIFT);
rtc_reload();
/* HW K EOSC mode whatever power off (including plug out battery) */
ret = rtc_read(RTC_AL_YEA, &val1);
if (ret < 0)
goto exit;
rtc_write(RTC_AL_YEA,
(val1 | RTC_K_EOSC_RSV_0) &
(~RTC_K_EOSC_RSV_1) & (~RTC_K_EOSC_RSV_2));
pmic_config_interface(MT6389_TOP_CKPDN_CON0_CLR_ADDR, 1,
MT6389_RG_FQMTR_CK_PDN_MASK,
MT6389_RG_FQMTR_CK_PDN_SHIFT);
/* Truning off eosc cali mode clock */
pmic_config_interface(MT6389_SCK_TOP_CKPDN_CON0_SET_ADDR, 1,
MT6389_RG_RTC_EOSC32_CK_PDN_MASK,
MT6389_RG_RTC_EOSC32_CK_PDN_SHIFT);
//set register to let MD know 32k status
ret = rtc_read(RTC_SPAR0, &val1);
if (ret < 0)
goto exit;
if (rtc_get_xosc_mode()) {
rtc_write(RTC_SPAR0, (val1 | RTC_SPAR0_32K_LESS));
pr_notice("RTC/32k mode\n");
} else {
rtc_write(RTC_SPAR0, (val1 & ~RTC_SPAR0_32K_LESS));
pr_notice("32k-less mode\n");
}
rtc_write_trigger();
return;
exit:
pr_err("%s error\n", __func__);
}
static int mt6358_misc_probe(struct platform_device *pdev)
{
struct mt6358_chip *mt6358_chip = dev_get_drvdata(pdev->dev.parent);
struct mt6358_misc *misc;
unsigned long flags;
misc = devm_kzalloc(&pdev->dev, sizeof(struct mt6358_misc), GFP_KERNEL);
if (!misc)
return -ENOMEM;
#ifdef IPIMB
pmic_regmap = mt6358_chip->regmap;
misc->regmap = dev_get_regmap(pdev->dev.parent->parent, NULL);
#else
misc->regmap = mt6358_chip->regmap;
#endif
if (!misc->regmap) {
pr_notice("get regmap failed\n");
return -ENODEV;
}
misc->dev = &pdev->dev;
spin_lock_init(&misc->lock);
rtc_misc = misc;
platform_set_drvdata(pdev, misc);
if (of_property_read_u32(pdev->dev.of_node,
"base", &rtc_misc->addr_base))
rtc_misc->addr_base = RTC_DSN_ID;
pr_notice("%s: rtc_misc->addr_base =0x%x\n",
__func__, rtc_misc->addr_base);
if (of_property_read_bool(pdev->dev.of_node, "apply-lpsd-solution")) {
spin_lock_irqsave(&misc->lock, flags);
mtk_rtc_lpsd_restore_al_mask();
spin_unlock_irqrestore(&misc->lock, flags);
pm_power_off = mt_power_off;
}
if (of_property_read_bool(pdev->dev.of_node, "dcxo-switch"))
dcxo_switch = 1;
if (of_property_read_bool(pdev->dev.of_node, "eosc-k"))
eosc_k = 1;
if (of_property_read_bool(pdev->dev.of_node, "support_xosc"))
support_xosc = 1;
rtc_init();
pr_notice("%s done\n", __func__);
return 0;
}
static const struct of_device_id mt6358_misc_of_match[] = {
{.compatible = "mediatek,mt6358-misc",},
{.compatible = "mediatek,mt6359-misc",},
{.compatible = "mediatek,mt6389-misc",},
{}
};
MODULE_DEVICE_TABLE(of, mt6358_misc_of_match);
static struct platform_driver mt6358_misc_driver = {
.driver = {
.name = "mt6358-misc",
.of_match_table = mt6358_misc_of_match,
},
.probe = mt6358_misc_probe,
.shutdown = mt6358_misc_shutdown,
};
module_platform_driver(mt6358_misc_driver);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Wilma Wu <wilma.wu@mediatek.com>");
MODULE_DESCRIPTION("Misc Driver for MediaTek MT6358 PMIC");