| /* |
| * 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, ®_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"); |