diff mbox series

[1/1] rtc: mediatek: Add mt6685 RTC driver

Message ID 20241031135807.31605-1-ot_shunxi.zhang@mediatek.com (mailing list archive)
State New
Headers show
Series [1/1] rtc: mediatek: Add mt6685 RTC driver | expand

Commit Message

shunxi zhang Oct. 31, 2024, 1:58 p.m. UTC
From: Shunxi Zhang <ot_shunxi.zhang@mediatek.com>

Signed-off-by: Shunxi Zhang <ot_shunxi.zhang@mediatek.com>
---
 drivers/rtc/Kconfig                  |   10 +
 drivers/rtc/Makefile                 |    1 +
 drivers/rtc/rtc-mt6685.c             | 1456 ++++++++++++++++++++++++++
 include/linux/mfd/mt6685-audclk.h    |   11 +
 include/linux/mfd/mt6685/core.h      |   22 +
 include/linux/mfd/mt6685/registers.h |  921 ++++++++++++++++
 include/linux/mfd/mt6685/rtc.h       |  318 ++++++
 7 files changed, 2739 insertions(+)
 create mode 100644 drivers/rtc/rtc-mt6685.c
 create mode 100644 include/linux/mfd/mt6685-audclk.h
 create mode 100644 include/linux/mfd/mt6685/core.h
 create mode 100644 include/linux/mfd/mt6685/registers.h
 create mode 100644 include/linux/mfd/mt6685/rtc.h

Comments

Krzysztof Kozlowski Oct. 31, 2024, 3:58 p.m. UTC | #1
On 31/10/2024 14:58, shunxi zhang wrote:
> From: Shunxi Zhang <ot_shunxi.zhang@mediatek.com>
> 

Missing commit msg.

> Signed-off-by: Shunxi Zhang <ot_shunxi.zhang@mediatek.com>
> ---
>  drivers/rtc/Kconfig                  |   10 +
>  drivers/rtc/Makefile                 |    1 +
>  drivers/rtc/rtc-mt6685.c             | 1456 ++++++++++++++++++++++++++
>  include/linux/mfd/mt6685-audclk.h    |   11 +
>  include/linux/mfd/mt6685/core.h      |   22 +
>  include/linux/mfd/mt6685/registers.h |  921 ++++++++++++++++
>  include/linux/mfd/mt6685/rtc.h       |  318 ++++++

Two separate drivers should not be in one commit.

>  7 files changed, 2739 insertions(+)
>  create mode 100644 drivers/rtc/rtc-mt6685.c
>  create mode 100644 include/linux/mfd/mt6685-audclk.h
>  create mode 100644 include/linux/mfd/mt6685/core.h
>  create mode 100644 include/linux/mfd/mt6685/registers.h
>  create mode 100644 include/linux/mfd/mt6685/rtc.h
> 
> diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
> index 66eb1122248b..7af04dfac978 100644
> --- a/drivers/rtc/Kconfig
> +++ b/drivers/rtc/Kconfig
> @@ -1898,6 +1898,16 @@ config RTC_DRV_MT6397
>  
>  	  If you want to use MediaTek(R) RTC interface, select Y or M here.
>  
> +config RTC_DRV_MT6685
> +	tristate "Mediatek Real Time Clock driver"
> +	depends on MFD_MT6685 || (COMPILE_TEST && IRQ_DOMAIN)
> +	help
> +	  This selects the Mediatek(R) RTC driver. RTC is part of Mediatek
> +	  MT6685. You should enable MT6685 MFD before select
> +	  Mediatek(R) RTC driver.
> +
> +	  If you want to use Mediatek(R) RTC interface, select Y or M here.
> +
>  config RTC_DRV_MT7622
>  	tristate "MediaTek SoC based RTC"
>  	depends on ARCH_MEDIATEK || COMPILE_TEST
> diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
> index f62340ecc534..ec982192526d 100644
> --- a/drivers/rtc/Makefile
> +++ b/drivers/rtc/Makefile
> @@ -110,6 +110,7 @@ obj-$(CONFIG_RTC_DRV_SSD202D)	+= rtc-ssd202d.o
>  obj-$(CONFIG_RTC_DRV_MSM6242)	+= rtc-msm6242.o
>  obj-$(CONFIG_RTC_DRV_MT2712)	+= rtc-mt2712.o
>  obj-$(CONFIG_RTC_DRV_MT6397)	+= rtc-mt6397.o
> +obj-$(CONFIG_RTC_DRV_MT6685)	+= rtc-mt6685.o
>  obj-$(CONFIG_RTC_DRV_MT7622)	+= rtc-mt7622.o
>  obj-$(CONFIG_RTC_DRV_MV)	+= rtc-mv.o
>  obj-$(CONFIG_RTC_DRV_MXC)	+= rtc-mxc.o
> diff --git a/drivers/rtc/rtc-mt6685.c b/drivers/rtc/rtc-mt6685.c

Why this cannot be part of existing MT drivers?

> new file mode 100644
> index 000000000000..a3aa747a788a
> --- /dev/null
> +++ b/drivers/rtc/rtc-mt6685.c
> @@ -0,0 +1,1456 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2020 MediaTek Inc.
> + * Author: Amber Lin <Mw.lin@mediatek.com>
> + */
> +
> +#include <linux/err.h>
> +#include <linux/interrupt.h>
> +#include <linux/module.h>
> +#include <linux/mutex.h>
> +#include <linux/of_device.h>
> +#include <linux/of_irq.h>
> +#include <linux/platform_device.h>
> +#include <linux/regmap.h>
> +#include <linux/rtc.h>
> +#include <linux/mfd/mt6685/rtc.h>
> +#include <linux/mfd/mt6685/core.h>
> +#include <linux/mfd/mt6685/registers.h>
> +#include <linux/nvmem-provider.h>
> +#include <linux/sched/clock.h>
> +#include <linux/spmi.h>
> +
> +#if IS_ENABLED(CONFIG_MTK_AEE_FEATURE)

There is no such stuff. Don't send us downstream code.

> +#include <mt-plat/aee.h>
> +#endif
> +
> +#ifdef SUPPORT_PWR_OFF_ALARM

???

> +#include <linux/notifier.h>
> +#include <linux/suspend.h>
> +#include <linux/completion.h>
> +#include <linux/workqueue.h>
> +#include <linux/jiffies.h>
> +#include <linux/cpumask.h>
> +#include <linux/reboot.h>

Drop all unrelated, unused headers.

> +#endif
> +
> +/*debug information*/
> +static int rtc_show_time;
> +static int rtc_show_alarm;
> +
> +module_param(rtc_show_time, int, 0644);
> +module_param(rtc_show_alarm, int, 0644);

Drop all four. What's the purpose?

> +
> +static int mtk_rtc_write_trigger(struct mt6685_rtc *rtc);
> +
> +static int counter;

Drop.


> +
> +static void power_on_mclk(struct mt6685_rtc *rtc)
> +{
> +	mutex_lock(&rtc->clk_lock);
> +	/*Power on RTC MCLK and 32k clk before write RTC register*/

This code has quite poor quality. I think you just send whatever you had
downstream. Code has multiple trivial issues which should be easily
pointed out by your internal review. Also multiple issues which we
already fixed in upstream and you are supposed to take *upstream*
driver, not downstream, and customize it. Please clean it up and consult
internal review before sending such stuff upstream.


> +	regmap_write(rtc->regmap, RG_RTC_32K_CK_PDN_CLR, RG_RTC_32K_CK_PDN_MASK);
> +	regmap_write(rtc->regmap, RG_RTC_MCLK_PDN_CLR, RG_RTC_MCLK_PDN_MASK);
> +	counter++;
> +	mdelay(1);
> +	mutex_unlock(&rtc->clk_lock);
> +}
> +
> +static void power_down_mclk(struct mt6685_rtc *rtc)
> +{
> +	mutex_lock(&rtc->clk_lock);
> +	counter--;
> +	if (counter < 0) {
> +		//dump_stack();
> +		pr_info("mclk_counter[%d]\n", counter);

Oh man... So many wrong things. This applies to entire code:
1. Drop dead code. All dead code.

2. Do not use pr_xxx but dev_xxx

3. Drop all such useless printks because your driver is supposed to be
silent.

4. Implement proper clock handling instead of reimplementing it yourself
with some counters.

...

> +
> +static const struct reg_field mt6685_cali_reg_fields[CALI_FILED_MAX] = {
> +	[EOSC_CALI_TD]		= REG_FIELD(EOSC_CALI_TD_MT6685, 0, 2),
> +};
> +
> +static int rtc_eosc_cali_td;
> +module_param(rtc_eosc_cali_td, int, 0644);

Why do you put module params in multiple places? This is supposed to be
in one, top level place, so we see all such interfaces.

Anyway, drop.


> +
> +static void mtk_rtc_enable_k_eosc(struct device *dev)
> +{
> +	struct mt6685_rtc *rtc = dev_get_drvdata(dev);
> +	u32 td;
> +
> +	power_on_mclk(rtc);

This code is really suspicious.

> +
> +	if (!rtc->cali_is_supported) {
> +		power_down_mclk(rtc);
> +		return;
> +	}
> +
> +	if (rtc_eosc_cali_td) {
> +		dev_notice(dev, "%s: rtc_eosc_cali_td = %d\n",
> +			   __func__, rtc_eosc_cali_td);

No, drop.

> +		switch (rtc_eosc_cali_td) {
> +		case 1:
> +			td = EOSC_CALI_TD_01_SEC;
> +			break;
> +		case 2:
> +			td = EOSC_CALI_TD_02_SEC;
> +			break;
> +		case 4:
> +			td = EOSC_CALI_TD_04_SEC;
> +			break;
> +		case 16:
> +			td = EOSC_CALI_TD_16_SEC;
> +			break;
> +		default:
> +			td = EOSC_CALI_TD_08_SEC;
> +			break;
> +		}
> +
> +		rtc_field_write(rtc, &rtc->data->cali_reg_fields[EOSC_CALI_TD], td);
> +	}
> +	power_down_mclk(rtc);
> +}
> +
> +#ifdef SUPPORT_PWR_OFF_ALARM

Is this some sort of joke? There is no such thing.


> +
> +static u32 bootmode = NORMAL_BOOT;
> +static struct wakeup_source *mt6685_rtc_suspend_lock;
> +#if IS_ENABLED(CONFIG_PM)
> +static bool rtc_pm_notifier_registered;
> +static unsigned long rtc_pm_status;
> +#endif
> +static bool kpoc_alarm;
> +
> +#if IS_ENABLED(CONFIG_PM)
> +
> +#define PM_DUMMY 0xFFFF

NAK to all above.

> +
> +static int rtc_pm_event(struct notifier_block *notifier, unsigned long pm_event,
> +			void *unused)
> +{
> +	struct mt6685_rtc *rtc = container_of(notifier,
> +		struct mt6685_rtc, pm_nb);
> +
> +	switch (pm_event) {
> +	case PM_SUSPEND_PREPARE:
> +		rtc_pm_status = PM_SUSPEND_PREPARE;
> +		return NOTIFY_DONE;
> +	case PM_POST_SUSPEND:
> +		rtc_pm_status = PM_POST_SUSPEND;
> +		break;
> +	default:
> +		rtc_pm_status = PM_DUMMY;
> +		break;
> +	}
> +
> +	if (kpoc_alarm) {
> +		dev_notice(rtc->rtc_dev->dev.parent,
> +			   "%s trigger reboot\n", __func__);
> +		complete(&rtc->comp);
> +		kpoc_alarm = false;
> +	}
> +	return NOTIFY_DONE;
> +}
> +#endif /* CONFIG_PM */
> +
> +static void rtc_mark_kpoc(struct mt6685_rtc *rtc)
> +{
> +	power_on_mclk(rtc);
> +	mutex_lock(&rtc->lock);
> +	rtc_field_write(rtc, &rtc->data->spare_reg_fields[SPARE_KPOC], 1);
> +	mutex_unlock(&rtc->lock);
> +	power_down_mclk(rtc);
> +}
> +
> +static void mtk_rtc_work_queue(struct work_struct *work)
> +{
> +	struct mt6685_rtc *rtc = container_of(work, struct mt6685_rtc, work);
> +	unsigned long ret;
> +	unsigned int msecs;
> +
> +	ret = wait_for_completion_timeout(&rtc->comp, msecs_to_jiffies(30000));
> +	if (!ret) {
> +		dev_notice(rtc->rtc_dev->dev.parent, "%s timeout\n", __func__);
> +		WARN_ON(1);
> +	} else {
> +		msecs = jiffies_to_msecs(ret);
> +		dev_notice(rtc->rtc_dev->dev.parent,
> +			   "%s timeleft= %d\n", __func__, msecs);
> +		rtc_mark_kpoc(rtc);
> +		kernel_restart("kpoc");
> +	}
> +}
> +
> +static void mtk_rtc_reboot(struct mt6685_rtc *rtc)
> +{
> +	__pm_stay_awake(mt6685_rtc_suspend_lock);
> +
> +	init_completion(&rtc->comp);
> +	schedule_work_on(cpumask_first(cpu_online_mask), &rtc->work);
> +
> +#if IS_ENABLED(CONFIG_PM)
> +	if (!rtc_pm_notifier_registered)
> +		goto reboot;
> +
> +	if (rtc_pm_status != PM_SUSPEND_PREPARE)
> +		goto reboot;
> +#endif
> +
> +	kpoc_alarm = true;
> +
> +	dev_notice(rtc->rtc_dev->dev.parent, "%s:wait\n", __func__);
> +	return;
> +
> +#if IS_ENABLED(CONFIG_PM)
> +reboot:
> +	dev_notice(rtc->rtc_dev->dev.parent, "%s:trigger\n", __func__);
> +	complete(&rtc->comp);
> +#endif
> +}
> +
> +static void mtk_rtc_update_pwron_alarm_flag(struct mt6685_rtc *rtc)
> +{
> +	int ret;
> +
> +	power_on_mclk(rtc);
> +
> +	ret = rtc_update_bits(rtc,
> +			      rtc->addr_base + RTC_PDN1,
> +			      RTC_PDN1_PWRON_TIME, 0);
> +	if (ret < 0)
> +		goto exit;
> +
> +	ret =  rtc_update_bits(rtc,
> +			       rtc->addr_base + RTC_PDN2,
> +			       RTC_PDN2_PWRON_ALARM, RTC_PDN2_PWRON_ALARM);
> +	if (ret < 0)
> +		goto exit;
> +
> +	mtk_rtc_write_trigger(rtc);
> +	power_down_mclk(rtc);
> +	dev_notice(rtc->rtc_dev->dev.parent, "%s info\n", __func__);

NAK

> +	return;
> +
> +exit:
> +	power_down_mclk(rtc);
> +	dev_err(rtc->rtc_dev->dev.parent, "%s error\n", __func__);

NAK, what error? Be descriptive.


> +}
> +
> +static int mtk_rtc_restore_alarm(struct mt6685_rtc *rtc, struct rtc_time *tm)
> +{
> +	int ret;
> +	u16 data[RTC_OFFSET_COUNT] = { 0 };
> +
> +	power_on_mclk(rtc);
> +
> +	ret = rtc_bulk_read(rtc, rtc->addr_base + RTC_AL_SEC,
> +			    data, RTC_OFFSET_COUNT * 2);
> +	if (ret < 0)
> +		goto exit;
> +
> +	data[RTC_OFFSET_SEC] = ((data[RTC_OFFSET_SEC] & ~(RTC_AL_SEC_MASK)) |
> +				(tm->tm_sec & RTC_AL_SEC_MASK));
> +	data[RTC_OFFSET_MIN] = ((data[RTC_OFFSET_MIN] & ~(RTC_AL_MIN_MASK)) |
> +				(tm->tm_min & RTC_AL_MIN_MASK));
> +	data[RTC_OFFSET_HOUR] = ((data[RTC_OFFSET_HOUR] & ~(RTC_AL_HOU_MASK)) |
> +				(tm->tm_hour & RTC_AL_HOU_MASK));
> +	data[RTC_OFFSET_DOM] = ((data[RTC_OFFSET_DOM] & ~(RTC_AL_DOM_MASK)) |
> +				(tm->tm_mday & RTC_AL_DOM_MASK));
> +	data[RTC_OFFSET_MTH] = ((data[RTC_OFFSET_MTH] & ~(RTC_AL_MTH_MASK)) |
> +				(tm->tm_mon & RTC_AL_MTH_MASK));
> +	data[RTC_OFFSET_YEAR] = ((data[RTC_OFFSET_YEAR] & ~(RTC_AL_YEA_MASK)) |
> +				(tm->tm_year & RTC_AL_YEA_MASK));
> +
> +	dev_notice(rtc->rtc_dev->dev.parent,
> +		   "restore al time = %04d/%02d/%02d %02d:%02d:%02d\n",
> +		   tm->tm_year + RTC_MIN_YEAR, tm->tm_mon, tm->tm_mday,
> +		   tm->tm_hour, tm->tm_min, tm->tm_sec);
> +
> +	ret = rtc_bulk_write(rtc, rtc->addr_base + RTC_AL_SEC,
> +			     data, RTC_OFFSET_COUNT * 2);
> +	if (ret < 0)
> +		goto exit;
> +
> +	ret = rtc_write(rtc, rtc->addr_base + RTC_AL_MASK,
> +			RTC_AL_MASK_DOW);
> +	if (ret < 0)
> +		goto exit;
> +
> +	ret =  rtc_update_bits(rtc,
> +			       rtc->addr_base + RTC_IRQ_EN,
> +			       RTC_IRQ_EN_AL, RTC_IRQ_EN_AL);
> +	if (ret < 0)
> +		goto exit;
> +
> +	mtk_rtc_write_trigger(rtc);
> +	power_down_mclk(rtc);
> +	return ret;
> +
> +exit:
> +	power_down_mclk(rtc);
> +	dev_err(rtc->rtc_dev->dev.parent, "%s error\n", __func__);

Again, be descriptive.

> +	return ret;
> +}
> +
> +static bool mtk_rtc_is_pwron_alarm(struct mt6685_rtc *rtc,
> +				   struct rtc_time *nowtm, struct rtc_time *tm)
> +{
> +	u32 pdn1 = 0, spar1 = 0, pdn2 = 0, spar0 = 0;
> +	int ret, sec = 0;
> +	u16 data[RTC_OFFSET_COUNT] = { 0 };
> +
> +	ret = rtc_read(rtc, rtc->addr_base + RTC_PDN1, &pdn1);
> +	if (ret < 0)
> +		goto exit;
> +
> +	dev_notice(rtc->rtc_dev->dev.parent, "pdn1 = 0x%x\n", pdn1);

NAK


...


> +
> +				dev_info(rtc->rtc_dev->dev.parent,
> +					 "[HWID 0x%x, MCLK 0x%x, prot key 0x%x] %s write %d, latest %d\n",
> +					 hwid, mclk, prot_key, rtc_time_reg_name[i],
> +					 data[i], latest[i]);
> +			}

NAK

> +		}
> +
> +		if (write_fail > 0)
> +			mdelay(2);
> +		else
> +			break;
> +	}
> +
> +	if (write_fail > 0)
> +		return false;
> +
> +	return true;
> +}
> +
> +static int mtk_rtc_set_time(struct device *dev, struct rtc_time *tm)
> +{
> +	struct mt6685_rtc *rtc = dev_get_drvdata(dev);
> +	int ret, result = 0;
> +	u16 data[RTC_OFFSET_COUNT];
> +
> +	power_on_mclk(rtc);
> +
> +	dev_notice(rtc->rtc_dev->dev.parent,
> +		   "set tc time = %04d/%02d/%02d %02d:%02d:%02d\n",
> +		   tm->tm_year + RTC_BASE_YEAR, tm->tm_mon + 1, tm->tm_mday,
> +		   tm->tm_hour, tm->tm_min, tm->tm_sec);
> +
> +	tm->tm_year -= RTC_MIN_YEAR_OFFSET;
> +	tm->tm_mon++;
> +
> +	data[RTC_OFFSET_SEC] = tm->tm_sec;
> +	data[RTC_OFFSET_MIN] = tm->tm_min;
> +	data[RTC_OFFSET_HOUR] = tm->tm_hour;
> +	data[RTC_OFFSET_DOM] = tm->tm_mday;
> +	data[RTC_OFFSET_MTH] = tm->tm_mon;
> +	data[RTC_OFFSET_YEAR] = tm->tm_year;
> +
> +	mutex_lock(&rtc->lock);
> +	ret = rtc_bulk_write(rtc, rtc->addr_base + RTC_TC_SEC,
> +			     data, RTC_OFFSET_COUNT * 2);
> +	if (ret < 0)
> +		goto exit;
> +
> +	/* Time register write to hardware after call trigger function */
> +	ret = mtk_rtc_write_trigger(rtc);
> +	if (ret < 0)
> +		goto exit;
> +
> +	result = mtk_rtc_check_set_time(rtc, tm, 2, RTC_TC_SEC);
> +
> +	if (!result) {
> +		dev_info(rtc->rtc_dev->dev.parent, "check rtc set time\n");
> +#if IS_ENABLED(CONFIG_MTK_AEE_FEATURE)
> +		aee_kernel_warning("mt6685-rtc", "mt6685-rtc: set tick time failed\n");
> +#endif

NAK

> +	}
> +
> +exit:
> +	mutex_unlock(&rtc->lock);
> +	power_down_mclk(rtc);

I did not investigate locking but it feels like you lock everything
everywhere.

Considering how poor code is this, I suspect that locking is totally
bogus. Provide extensive description of locking in comment section in
the top.


> +	return ret;
> +}
> +
> +static int mtk_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
> +{
> +	struct rtc_time *tm = &alm->time;
> +	struct mt6685_rtc *rtc = dev_get_drvdata(dev);
> +	u32 irqen = 0, pdn2 = 0;
> +	int ret;
> +	u16 data[RTC_OFFSET_COUNT] = { 0 };
> +
> +	mutex_lock(&rtc->lock);
> +	ret = rtc_read(rtc, rtc->addr_base + RTC_IRQ_EN, &irqen);
> +	if (ret < 0)
> +		goto err_exit;
> +	ret = rtc_read(rtc, rtc->addr_base + RTC_PDN2, &pdn2);
> +	if (ret < 0)
> +		goto err_exit;
> +
> +	ret = rtc_bulk_read(rtc, rtc->addr_base + RTC_AL_SEC,
> +			    data, RTC_OFFSET_COUNT * 2);
> +	if (ret < 0)
> +		goto err_exit;
> +
> +	alm->enabled = !!(irqen & RTC_IRQ_EN_AL);
> +	alm->pending = !!(pdn2 & RTC_PDN2_PWRON_ALARM);
> +	mutex_unlock(&rtc->lock);
> +
> +	tm->tm_sec = data[RTC_OFFSET_SEC] & RTC_AL_SEC_MASK;
> +	tm->tm_min = data[RTC_OFFSET_MIN] & RTC_AL_MIN_MASK;
> +	tm->tm_hour = data[RTC_OFFSET_HOUR] & RTC_AL_HOU_MASK;
> +	tm->tm_mday = data[RTC_OFFSET_DOM] & RTC_AL_DOM_MASK;
> +	tm->tm_mon = data[RTC_OFFSET_MTH] & RTC_AL_MTH_MASK;
> +	tm->tm_year = data[RTC_OFFSET_YEAR] & RTC_AL_YEA_MASK;
> +
> +	tm->tm_year += RTC_MIN_YEAR_OFFSET;
> +	tm->tm_mon--;
> +
> +	dev_notice(rtc->rtc_dev->dev.parent,
> +		   "read al time = %04d/%02d/%02d %02d:%02d:%02d (%d)\n",
> +		   tm->tm_year + RTC_BASE_YEAR, tm->tm_mon + 1, tm->tm_mday,
> +		   tm->tm_hour, tm->tm_min, tm->tm_sec, alm->enabled);
> +
> +	return 0;
> +err_exit:
> +	mutex_unlock(&rtc->lock);
> +	return ret;
> +}
> +
> +static int mtk_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
> +{
> +	struct rtc_time *tm = &alm->time;
> +	struct mt6685_rtc *rtc = dev_get_drvdata(dev);
> +	int ret, result = 0;
> +	u16 data[RTC_OFFSET_COUNT];
> +	ktime_t target;
> +
> +	power_on_mclk(rtc);
> +
> +	if (alm->enabled == 1) {
> +		/* Add one more second to postpone wake time. */
> +		target = rtc_tm_to_ktime(*tm);
> +		target = ktime_add_ns(target, NSEC_PER_SEC);
> +		*tm = rtc_ktime_to_tm(target);
> +	}
> +
> +	tm->tm_year -= RTC_MIN_YEAR_OFFSET;
> +	tm->tm_mon++;
> +
> +	dev_notice(rtc->rtc_dev->dev.parent,
> +		   "set al time = %04d/%02d/%02d %02d:%02d:%02d (%d)\n",
> +		   tm->tm_year + RTC_MIN_YEAR, tm->tm_mon, tm->tm_mday,
> +		   tm->tm_hour, tm->tm_min, tm->tm_sec, alm->enabled);
> +
> +	mutex_lock(&rtc->lock);
> +
> +	switch (alm->enabled) {
> +	case 3:
> +		/* enable power-on alarm with logo */
> +		mtk_rtc_save_pwron_time(rtc, true, tm);
> +		break;
> +	case 4:
> +		/* disable power-on alarm */
> +		mtk_rtc_save_pwron_time(rtc, false, tm);
> +		break;
> +	default:
> +		break;
> +	}
> +
> +	ret = rtc_update_bits(rtc,
> +			      rtc->addr_base + RTC_PDN2,
> +			      RTC_PDN2_PWRON_ALARM, 0);
> +	if (ret < 0)
> +		goto exit;
> +	mtk_rtc_write_trigger(rtc);
> +
> +	ret = rtc_bulk_read(rtc, rtc->addr_base + RTC_AL_SEC,
> +			    data, RTC_OFFSET_COUNT * 2);
> +	if (ret < 0)
> +		goto exit;
> +
> +	data[RTC_OFFSET_SEC] = ((data[RTC_OFFSET_SEC] & ~(RTC_AL_SEC_MASK)) |
> +				(tm->tm_sec & RTC_AL_SEC_MASK));
> +	data[RTC_OFFSET_MIN] = ((data[RTC_OFFSET_MIN] & ~(RTC_AL_MIN_MASK)) |
> +				(tm->tm_min & RTC_AL_MIN_MASK));
> +	data[RTC_OFFSET_HOUR] = ((data[RTC_OFFSET_HOUR] & ~(RTC_AL_HOU_MASK)) |
> +				(tm->tm_hour & RTC_AL_HOU_MASK));
> +	data[RTC_OFFSET_DOM] = ((data[RTC_OFFSET_DOM] & ~(RTC_AL_DOM_MASK)) |
> +				(tm->tm_mday & RTC_AL_DOM_MASK));
> +	data[RTC_OFFSET_MTH] = ((data[RTC_OFFSET_MTH] & ~(RTC_AL_MTH_MASK)) |
> +				(tm->tm_mon & RTC_AL_MTH_MASK));
> +	data[RTC_OFFSET_YEAR] = ((data[RTC_OFFSET_YEAR] & ~(RTC_AL_YEA_MASK)) |
> +				(tm->tm_year & RTC_AL_YEA_MASK));
> +
> +	if (alm->enabled) {
> +		ret = rtc_bulk_write(rtc,
> +				     rtc->addr_base + RTC_AL_SEC,
> +				     data, RTC_OFFSET_COUNT * 2);
> +		if (ret < 0)
> +			goto exit;
> +		ret = rtc_write(rtc, rtc->addr_base + RTC_AL_MASK,
> +				RTC_AL_MASK_DOW);
> +		if (ret < 0)
> +			goto exit;
> +
> +		ret =  rtc_update_bits(rtc,
> +				       rtc->addr_base + RTC_IRQ_EN,
> +				       RTC_IRQ_EN_AL, RTC_IRQ_EN_AL);
> +		if (ret < 0)
> +			goto exit;
> +		} else {
> +			ret =  rtc_update_bits(rtc,
> +					       rtc->addr_base + RTC_IRQ_EN,
> +					       RTC_IRQ_EN_AL, 0);
> +			if (ret < 0)
> +				goto exit;
> +		}
> +
> +	/* All alarm time register write to hardware after calling
> +	 * mtk_rtc_write_trigger. This can avoid race condition if alarm
> +	 * occur happen during writing alarm time register.
> +	 */
> +	ret = mtk_rtc_write_trigger(rtc);
> +	if (ret < 0)
> +		goto exit;
> +
> +	result = mtk_rtc_check_set_time(rtc, tm, 2, RTC_AL_SEC);
> +
> +	if (!result) {
> +		dev_info(rtc->rtc_dev->dev.parent, "check rtc set alarm\n");
> +#if IS_ENABLED(CONFIG_MTK_AEE_FEATURE)
> +		aee_kernel_warning("mt6685-rtc", "mt6685-rtc: set alarm time failed\n");
> +#endif
> +	}
> +exit:
> +	mutex_unlock(&rtc->lock);
> +	power_down_mclk(rtc);
> +	return ret;
> +}
> +
> +static int rtc_alarm_set_power_on(struct device *dev, struct rtc_wkalrm *alm)
> +{
> +	int err = 0;
> +	struct rtc_time tm;
> +	time64_t now, scheduled;
> +
> +	err = rtc_valid_tm(&alm->time);
> +	if (err != 0)
> +		return err;
> +	scheduled = rtc_tm_to_time64(&alm->time);
> +
> +	err = mtk_rtc_read_time(dev, &tm);
> +	if (err != 0)
> +		return err;
> +	now = rtc_tm_to_time64(&tm);
> +
> +	if (scheduled <= now)
> +		alm->enabled = 4;
> +	else
> +		alm->enabled = 3;
> +
> +	mtk_rtc_set_alarm(dev, alm);
> +
> +	return err;
> +}
> +
> +static int mtk_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
> +{
> +	void __user *uarg = (void __user *)arg;
> +	int err = 0;
> +	struct rtc_wkalrm alm;
> +
> +	switch (cmd) {
> +	case RTC_POFF_ALM_SET:
> +		if (copy_from_user(&alm.time, uarg, sizeof(alm.time)))
> +			return -EFAULT;
> +		err = rtc_alarm_set_power_on(dev, &alm);
> +		break;
> +	default:
> +		err = -EINVAL;
> +		break;
> +	}
> +
> +	return err;
> +}
> +
> +static const struct rtc_class_ops mtk_rtc_ops = {
> +	.ioctl      = mtk_rtc_ioctl,
> +	.read_time  = mtk_rtc_read_time,
> +	.set_time   = mtk_rtc_set_time,
> +	.read_alarm = mtk_rtc_read_alarm,
> +	.set_alarm  = mtk_rtc_set_alarm,
> +};
> +
> +static int rtc_nvram_read(void *priv, unsigned int offset, void *val,
> +			  size_t bytes)
> +{
> +	struct mt6685_rtc *rtc = dev_get_drvdata(priv);
> +	unsigned int ival;
> +	int ret;
> +	u8 *buf = val;
> +
> +	mutex_lock(&rtc->lock);
> +
> +	for (; bytes; bytes--) {
> +		ret = rtc_field_read(rtc,
> +				     &rtc->data->spare_reg_fields[offset++],
> +				     &ival);
> +
> +		if (ret)
> +			goto out;
> +
> +		*buf++ = (u8)ival;
> +	}
> +
> +out:
> +	mutex_unlock(&rtc->lock);
> +	return ret;
> +}
> +
> +static int rtc_nvram_write(void *priv, unsigned int offset, void *val,
> +			   size_t bytes)
> +{
> +	struct mt6685_rtc *rtc = dev_get_drvdata(priv);
> +	unsigned int ival;
> +	int ret;
> +	u8 *buf = val;
> +
> +	power_on_mclk(rtc);
> +
> +	mutex_lock(&rtc->lock);
> +
> +	for (; bytes; bytes--) {
> +		ival = *buf++;
> +		ret = rtc_field_write(rtc,
> +				      &rtc->data->spare_reg_fields[offset++],
> +				      ival);
> +
> +		if (ret)
> +			goto out;
> +	}
> +
> +out:
> +	mutex_unlock(&rtc->lock);
> +	power_down_mclk(rtc);
> +	return ret;
> +}
> +
> +static int mtk_rtc_set_spare(struct device *dev)
> +{
> +	struct mt6685_rtc *rtc = dev_get_drvdata(dev);
> +	int ret;
> +	struct nvmem_config nvmem_cfg = {
> +		.name = "mtk_rtc_nvmem",
> +		.word_size = SPARE_REG_WIDTH,
> +		.stride = 1,
> +		.size = SPARE_RG_MAX * SPARE_REG_WIDTH,
> +		.reg_read = rtc_nvram_read,
> +		.reg_write = rtc_nvram_write,
> +		.priv = dev,
> +	};
> +
> +	ret = devm_rtc_nvmem_register(rtc->rtc_dev, &nvmem_cfg);
> +	if (ret)
> +		dev_err(rtc->rtc_dev->dev.parent, "nvmem register failed\n");
> +
> +	return ret;
> +}
> +
> +static int mtk_rtc_probe(struct platform_device *pdev)
> +{
> +	struct mt6685_rtc *rtc;
> +	struct device_node *np = pdev->dev.of_node;
> +	int ret;
> +#ifdef SUPPORT_PWR_OFF_ALARM
> +	struct device_node *of_chosen = NULL;
> +	struct tag_bootmode *tag = NULL;
> +#endif
> +	if (!of_device_is_available(np)) {
> +		dev_err(&pdev->dev, "rtc disabled\n");

NAK, this code is a disaster.

> +		return -1;
> +	}
> +
> +	rtc = devm_kzalloc(&pdev->dev, sizeof(struct mt6685_rtc), GFP_KERNEL);
> +	if (!rtc) {
> +		//dev_err(&pdev->dev, "devm_kzalloc failed\n");

NAK


> +		return -ENOMEM;
> +	}
> +
> +	rtc->data = of_device_get_match_data(&pdev->dev);
> +	if (!rtc->data) {
> +		dev_err(&pdev->dev, "of_device_get_match_data failed\n");

NAK

> +		return -ENODEV;
> +	}
> +
> +	if (of_property_read_u32(pdev->dev.of_node, "base", &rtc->addr_base))
> +		rtc->addr_base = RTC_DSN_ID;
> +
> +	pr_notice("%s: rtc->addr_base =0x%x\n", __func__, rtc->addr_base);

NAK

I finished here. The code is terrible and not suitable for mainline.
It's probably overcomplicated for something like RTC, but that's not yet
the main problem and I did not get there yet.

Drop all this code. Sorry, it's just not started correctly. Instead take
RECENT mainline driver and customize it using upstream, not downstream,
patterns and coding style.

Best regards,
Krzysztof
Krzysztof Kozlowski Oct. 31, 2024, 3:59 p.m. UTC | #2
On 31/10/2024 14:58, shunxi zhang wrote:
> From: Shunxi Zhang <ot_shunxi.zhang@mediatek.com>
> 
> Signed-off-by: Shunxi Zhang <ot_shunxi.zhang@mediatek.com>

...

> +
> +static const struct mtk_rtc_data mt6685_rtc_data = {
> +	.wrtgr = RTC_WRTGR,
> +	.hwid = HWID_MT6685,
> +	.chip_version = MT6685_SERIES,
> +	.spare_reg_fields = mt6685_spare_reg_fields,
> +	.cali_reg_fields = mt6685_cali_reg_fields,
> +	.single_read_write_is_supported = true,
> +};
> +
> +static const struct of_device_id mt6685_rtc_of_match[] = {
> +	{ .compatible = "mediatek,mt6685-rtc", .data = &mt6685_rtc_data },

Please run scripts/checkpatch.pl and fix reported warnings. Then please
run `scripts/checkpatch.pl --strict` and (probably) fix more warnings.
Some warnings can be ignored, especially from --strict run, but the code
here looks like it needs a fix. Feel free to get in touch if the warning
is not clear.

You did not even run basic tools... I doubt that this was ever built
with W=1 and static checkers.

But above warning about undocumented ABI is a NAK.

Please run standard kernel tools for static analysis, like coccinelle,
smatch and sparse, and fix reported warnings. Also please check for
warnings when building with W=1. Most of these commands (checks or W=1
build) can build specific targets, like some directory, to narrow the
scope to only your code. The code here looks like it needs a fix. Feel
free to get in touch if the warning is not clear.


Best regards,
Krzysztof
Krzysztof Kozlowski Oct. 31, 2024, 4:05 p.m. UTC | #3
On 31/10/2024 16:58, Krzysztof Kozlowski wrote:
>> +	regmap_write(rtc->regmap, RG_RTC_32K_CK_PDN_CLR, RG_RTC_32K_CK_PDN_MASK);
>> +	regmap_write(rtc->regmap, RG_RTC_MCLK_PDN_CLR, RG_RTC_MCLK_PDN_MASK);
>> +	counter++;
>> +	mdelay(1);
>> +	mutex_unlock(&rtc->clk_lock);
>> +}
>> +
>> +static void power_down_mclk(struct mt6685_rtc *rtc)
>> +{
>> +	mutex_lock(&rtc->clk_lock);
>> +	counter--;
>> +	if (counter < 0) {
>> +		//dump_stack();
>> +		pr_info("mclk_counter[%d]\n", counter);
> 
> Oh man... So many wrong things. This applies to entire code:
> 1. Drop dead code. All dead code.
> 
> 2. Do not use pr_xxx but dev_xxx
> 
> 3. Drop all such useless printks because your driver is supposed to be
> silent.
> 
> 4. Implement proper clock handling instead of reimplementing it yourself
> with some counters.

... clock handling or runtime PM, depending what this thing here really is.

Best regards,
Krzysztof
Alexandre Belloni Oct. 31, 2024, 5:24 p.m. UTC | #4
On 31/10/2024 21:58:02+0800, shunxi zhang wrote:
> +/* we map HW YEA 0 (2000) to 1968 not 1970 because 2000 is the leap year */
> +#define RTC_MIN_YEAR            1968
> +#define RTC_BASE_YEAR           1900
> +#define RTC_NUM_YEARS           128
> +#define RTC_MIN_YEAR_OFFSET     (RTC_MIN_YEAR - RTC_BASE_YEAR)

I will not take another driver with this. mt6397 needs to be fixed
first.
Markus Elfring Oct. 31, 2024, 7:50 p.m. UTC | #5
Please add a change description.
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/process/submitting-patches.rst?h=v6.12-rc5#n45


…
> +++ b/drivers/rtc/rtc-mt6685.c
> @@ -0,0 +1,1456 @@> +static void power_on_mclk(struct mt6685_rtc *rtc)
> +{
> +	mutex_lock(&rtc->clk_lock);> +	mdelay(1);
> +	mutex_unlock(&rtc->clk_lock);
> +}
…

Under which circumstances would you become interested to apply a statement
like “guard(mutex)(&rtc->clk_lock);”?
https://elixir.bootlin.com/linux/v6.12-rc5/source/include/linux/mutex.h#L201

Regards,
Markus
diff mbox series

Patch

diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 66eb1122248b..7af04dfac978 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -1898,6 +1898,16 @@  config RTC_DRV_MT6397
 
 	  If you want to use MediaTek(R) RTC interface, select Y or M here.
 
+config RTC_DRV_MT6685
+	tristate "Mediatek Real Time Clock driver"
+	depends on MFD_MT6685 || (COMPILE_TEST && IRQ_DOMAIN)
+	help
+	  This selects the Mediatek(R) RTC driver. RTC is part of Mediatek
+	  MT6685. You should enable MT6685 MFD before select
+	  Mediatek(R) RTC driver.
+
+	  If you want to use Mediatek(R) RTC interface, select Y or M here.
+
 config RTC_DRV_MT7622
 	tristate "MediaTek SoC based RTC"
 	depends on ARCH_MEDIATEK || COMPILE_TEST
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index f62340ecc534..ec982192526d 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -110,6 +110,7 @@  obj-$(CONFIG_RTC_DRV_SSD202D)	+= rtc-ssd202d.o
 obj-$(CONFIG_RTC_DRV_MSM6242)	+= rtc-msm6242.o
 obj-$(CONFIG_RTC_DRV_MT2712)	+= rtc-mt2712.o
 obj-$(CONFIG_RTC_DRV_MT6397)	+= rtc-mt6397.o
+obj-$(CONFIG_RTC_DRV_MT6685)	+= rtc-mt6685.o
 obj-$(CONFIG_RTC_DRV_MT7622)	+= rtc-mt7622.o
 obj-$(CONFIG_RTC_DRV_MV)	+= rtc-mv.o
 obj-$(CONFIG_RTC_DRV_MXC)	+= rtc-mxc.o
diff --git a/drivers/rtc/rtc-mt6685.c b/drivers/rtc/rtc-mt6685.c
new file mode 100644
index 000000000000..a3aa747a788a
--- /dev/null
+++ b/drivers/rtc/rtc-mt6685.c
@@ -0,0 +1,1456 @@ 
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2020 MediaTek Inc.
+ * Author: Amber Lin <Mw.lin@mediatek.com>
+ */
+
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/rtc.h>
+#include <linux/mfd/mt6685/rtc.h>
+#include <linux/mfd/mt6685/core.h>
+#include <linux/mfd/mt6685/registers.h>
+#include <linux/nvmem-provider.h>
+#include <linux/sched/clock.h>
+#include <linux/spmi.h>
+
+#if IS_ENABLED(CONFIG_MTK_AEE_FEATURE)
+#include <mt-plat/aee.h>
+#endif
+
+#ifdef SUPPORT_PWR_OFF_ALARM
+#include <linux/notifier.h>
+#include <linux/suspend.h>
+#include <linux/completion.h>
+#include <linux/workqueue.h>
+#include <linux/jiffies.h>
+#include <linux/cpumask.h>
+#include <linux/reboot.h>
+#endif
+
+/*debug information*/
+static int rtc_show_time;
+static int rtc_show_alarm;
+
+module_param(rtc_show_time, int, 0644);
+module_param(rtc_show_alarm, int, 0644);
+
+static int mtk_rtc_write_trigger(struct mt6685_rtc *rtc);
+
+static int counter;
+
+static void power_on_mclk(struct mt6685_rtc *rtc)
+{
+	mutex_lock(&rtc->clk_lock);
+	/*Power on RTC MCLK and 32k clk before write RTC register*/
+	regmap_write(rtc->regmap, RG_RTC_32K_CK_PDN_CLR, RG_RTC_32K_CK_PDN_MASK);
+	regmap_write(rtc->regmap, RG_RTC_MCLK_PDN_CLR, RG_RTC_MCLK_PDN_MASK);
+	counter++;
+	mdelay(1);
+	mutex_unlock(&rtc->clk_lock);
+}
+
+static void power_down_mclk(struct mt6685_rtc *rtc)
+{
+	mutex_lock(&rtc->clk_lock);
+	counter--;
+	if (counter < 0) {
+		//dump_stack();
+		pr_info("mclk_counter[%d]\n", counter);
+	}
+	if (counter == 0) {
+		/*Power down RTC MCLK and 32k clk after write RTC register*/
+		regmap_write(rtc->regmap, RG_RTC_32K_CK_PDN_SET, RG_RTC_32K_CK_PDN_MASK);
+		regmap_write(rtc->regmap, RG_RTC_MCLK_PDN_SET, RG_RTC_MCLK_PDN_MASK);
+		mdelay(1);
+	}
+	mutex_unlock(&rtc->clk_lock);
+}
+
+static int rtc_bulk_read(struct mt6685_rtc *rtc, unsigned int reg,
+			 void *val, size_t val_count)
+{
+	int ret;
+
+	if (rtc->data->single_read_write_is_supported) {
+		ret = regmap_bulk_read(rtc->regmap, reg, val, val_count);
+	} else {
+		int i;
+
+		for (i = 0; i < val_count; i += 2)
+			ret = regmap_bulk_read(rtc->regmap, reg + i, val + i, 2);
+	}
+
+	return ret;
+}
+
+static int rtc_read(struct mt6685_rtc *rtc, unsigned int reg,
+		    unsigned int *val)
+{
+	rtc_bulk_read(rtc, reg, val, 2);
+	return 0;
+}
+
+static int rtc_bulk_write(struct mt6685_rtc *rtc, unsigned int reg,
+			  const void *val, size_t val_count)
+{
+	int ret;
+
+	if (rtc->data->single_read_write_is_supported) {
+		ret = regmap_bulk_write(rtc->regmap, reg, val, val_count);
+	} else {
+		int i;
+
+		for (i = 0; i < val_count; i += 2)
+			ret = regmap_bulk_write(rtc->regmap, reg + i, val + i, 2);
+	}
+
+	return ret;
+}
+
+static int rtc_write(struct mt6685_rtc *rtc, unsigned int reg,
+		     unsigned int val)
+{
+	rtc_bulk_write(rtc, reg, &val, 2);
+	return 0;
+}
+
+static int rtc_update_bits(struct mt6685_rtc *rtc, unsigned int reg,
+			   unsigned int mask, unsigned int val)
+{
+	int ret;
+	unsigned int tmp, orig = 0;
+
+	ret = rtc_read(rtc, reg, &orig);
+	if (ret != 0)
+		return ret;
+	tmp = orig & ~mask;
+	tmp |= val & mask;
+	ret = rtc_write(rtc, reg, tmp);
+	return ret;
+}
+
+static const struct reg_field mt6685_spare_reg_fields[SPARE_RG_MAX] = {
+	[SPARE_FG2] = REG_FIELD(RTC_RG_FG2, 0, 7),
+	[SPARE_FG3] = REG_FIELD(RTC_RG_FG3, 0, 7),
+	[SPARE_SPAR0]  = REG_FIELD(RTC_SPAR0, 0, 7),
+#ifdef SUPPORT_PWR_OFF_ALARM
+	[SPARE_KPOC]   = REG_FIELD(RTC_PDN1_H, 6, 6),
+#endif
+};
+
+static int rtc_field_read(struct mt6685_rtc *rtc,
+			  const struct reg_field *field, unsigned int *val)
+{
+	int ret;
+	unsigned int orig, mask;
+
+	ret = rtc_read(rtc, rtc->addr_base + field->reg, &orig);
+	if (ret != 0)
+		return ret;
+
+	mask = GENMASK(field->msb, field->lsb);
+	orig &= mask;
+	orig >>= field->lsb;
+	*val = orig;
+
+	dev_notice(rtc->rtc_dev->dev.parent, "%s: rg:0x%x, val:0x%x\n",
+		   __func__, field->reg, *val);
+
+	return 0;
+}
+
+static int rtc_unlock_fg_rg(struct mt6685_rtc *rtc, const struct reg_field *field)
+{
+	int ret = 0;
+
+	if (field->reg == RTC_RG_FG2) {
+		ret = rtc_write(rtc, rtc->addr_base + RTC_RG_FG2, 0xaf);
+		ret |= rtc_write(rtc, rtc->addr_base + RTC_RG_FG2, 0xaf);
+		ret |= rtc_write(rtc, rtc->addr_base + RTC_RG_FG2, 0x5e);
+	} else if (field->reg == RTC_RG_FG3) {
+		ret = rtc_write(rtc, rtc->addr_base + RTC_RG_FG3, 0x66);
+		ret |= rtc_write(rtc, rtc->addr_base + RTC_RG_FG3, 0x66);
+		ret |= rtc_write(rtc, rtc->addr_base + RTC_RG_FG3, 0xf1);
+	}
+
+	if (ret != 0) {
+		dev_notice(rtc->rtc_dev->dev.parent, "%s failed\n", __func__);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int rtc_field_write(struct mt6685_rtc *rtc,
+			   const struct reg_field *field, unsigned int val)
+{
+	int ret;
+	unsigned int tmp, orig = 0, latest;
+	unsigned int mask;
+
+	ret = rtc_read(rtc, rtc->addr_base + field->reg, &orig);
+	if (ret != 0)
+		return ret;
+
+	if (rtc->data->chip_version == MT6685_SERIES) {
+		ret = rtc_unlock_fg_rg(rtc, field);
+		if (ret != 0)
+			return ret;
+	}
+
+	mask = GENMASK(field->msb, field->lsb);
+	tmp = orig & ~mask;
+	tmp |= (val << field->lsb) & mask;
+
+	ret = rtc_write(rtc, rtc->addr_base + field->reg, tmp);
+	if (ret != 0)
+		return ret;
+
+	mtk_rtc_write_trigger(rtc);
+
+	rtc_read(rtc, rtc->addr_base + field->reg, &latest);
+	latest &= mask;
+	latest >>= field->lsb;
+
+	if (latest != val)
+		pr_info("%s: reg:0x%x, val:0x%x, latest:0x%x",
+			__func__, field->reg, val, latest);
+
+	return 0;
+}
+
+static u16 rtc_pwron_reg[RTC_OFFSET_COUNT][3] = {
+	{RTC_PWRON_SEC, RTC_PWRON_SEC_MASK, RTC_PWRON_SEC_SHIFT},
+	{RTC_PWRON_MIN, RTC_PWRON_MIN_MASK, RTC_PWRON_MIN_SHIFT},
+	{RTC_PWRON_HOU, RTC_PWRON_HOU_MASK, RTC_PWRON_HOU_SHIFT},
+	{RTC_PWRON_DOM, RTC_PWRON_DOM_MASK, RTC_PWRON_DOM_SHIFT},
+	{0, 0, 0},
+	{RTC_PWRON_MTH, RTC_PWRON_MTH_MASK, RTC_PWRON_MTH_SHIFT},
+	{RTC_PWRON_YEA, RTC_PWRON_YEA_MASK, RTC_PWRON_YEA_SHIFT},
+};
+
+static const struct reg_field mt6685_cali_reg_fields[CALI_FILED_MAX] = {
+	[EOSC_CALI_TD]		= REG_FIELD(EOSC_CALI_TD_MT6685, 0, 2),
+};
+
+static int rtc_eosc_cali_td;
+module_param(rtc_eosc_cali_td, int, 0644);
+
+static void mtk_rtc_enable_k_eosc(struct device *dev)
+{
+	struct mt6685_rtc *rtc = dev_get_drvdata(dev);
+	u32 td;
+
+	power_on_mclk(rtc);
+
+	if (!rtc->cali_is_supported) {
+		power_down_mclk(rtc);
+		return;
+	}
+
+	if (rtc_eosc_cali_td) {
+		dev_notice(dev, "%s: rtc_eosc_cali_td = %d\n",
+			   __func__, rtc_eosc_cali_td);
+		switch (rtc_eosc_cali_td) {
+		case 1:
+			td = EOSC_CALI_TD_01_SEC;
+			break;
+		case 2:
+			td = EOSC_CALI_TD_02_SEC;
+			break;
+		case 4:
+			td = EOSC_CALI_TD_04_SEC;
+			break;
+		case 16:
+			td = EOSC_CALI_TD_16_SEC;
+			break;
+		default:
+			td = EOSC_CALI_TD_08_SEC;
+			break;
+		}
+
+		rtc_field_write(rtc, &rtc->data->cali_reg_fields[EOSC_CALI_TD], td);
+	}
+	power_down_mclk(rtc);
+}
+
+#ifdef SUPPORT_PWR_OFF_ALARM
+
+static u32 bootmode = NORMAL_BOOT;
+static struct wakeup_source *mt6685_rtc_suspend_lock;
+#if IS_ENABLED(CONFIG_PM)
+static bool rtc_pm_notifier_registered;
+static unsigned long rtc_pm_status;
+#endif
+static bool kpoc_alarm;
+
+#if IS_ENABLED(CONFIG_PM)
+
+#define PM_DUMMY 0xFFFF
+
+static int rtc_pm_event(struct notifier_block *notifier, unsigned long pm_event,
+			void *unused)
+{
+	struct mt6685_rtc *rtc = container_of(notifier,
+		struct mt6685_rtc, pm_nb);
+
+	switch (pm_event) {
+	case PM_SUSPEND_PREPARE:
+		rtc_pm_status = PM_SUSPEND_PREPARE;
+		return NOTIFY_DONE;
+	case PM_POST_SUSPEND:
+		rtc_pm_status = PM_POST_SUSPEND;
+		break;
+	default:
+		rtc_pm_status = PM_DUMMY;
+		break;
+	}
+
+	if (kpoc_alarm) {
+		dev_notice(rtc->rtc_dev->dev.parent,
+			   "%s trigger reboot\n", __func__);
+		complete(&rtc->comp);
+		kpoc_alarm = false;
+	}
+	return NOTIFY_DONE;
+}
+#endif /* CONFIG_PM */
+
+static void rtc_mark_kpoc(struct mt6685_rtc *rtc)
+{
+	power_on_mclk(rtc);
+	mutex_lock(&rtc->lock);
+	rtc_field_write(rtc, &rtc->data->spare_reg_fields[SPARE_KPOC], 1);
+	mutex_unlock(&rtc->lock);
+	power_down_mclk(rtc);
+}
+
+static void mtk_rtc_work_queue(struct work_struct *work)
+{
+	struct mt6685_rtc *rtc = container_of(work, struct mt6685_rtc, work);
+	unsigned long ret;
+	unsigned int msecs;
+
+	ret = wait_for_completion_timeout(&rtc->comp, msecs_to_jiffies(30000));
+	if (!ret) {
+		dev_notice(rtc->rtc_dev->dev.parent, "%s timeout\n", __func__);
+		WARN_ON(1);
+	} else {
+		msecs = jiffies_to_msecs(ret);
+		dev_notice(rtc->rtc_dev->dev.parent,
+			   "%s timeleft= %d\n", __func__, msecs);
+		rtc_mark_kpoc(rtc);
+		kernel_restart("kpoc");
+	}
+}
+
+static void mtk_rtc_reboot(struct mt6685_rtc *rtc)
+{
+	__pm_stay_awake(mt6685_rtc_suspend_lock);
+
+	init_completion(&rtc->comp);
+	schedule_work_on(cpumask_first(cpu_online_mask), &rtc->work);
+
+#if IS_ENABLED(CONFIG_PM)
+	if (!rtc_pm_notifier_registered)
+		goto reboot;
+
+	if (rtc_pm_status != PM_SUSPEND_PREPARE)
+		goto reboot;
+#endif
+
+	kpoc_alarm = true;
+
+	dev_notice(rtc->rtc_dev->dev.parent, "%s:wait\n", __func__);
+	return;
+
+#if IS_ENABLED(CONFIG_PM)
+reboot:
+	dev_notice(rtc->rtc_dev->dev.parent, "%s:trigger\n", __func__);
+	complete(&rtc->comp);
+#endif
+}
+
+static void mtk_rtc_update_pwron_alarm_flag(struct mt6685_rtc *rtc)
+{
+	int ret;
+
+	power_on_mclk(rtc);
+
+	ret = rtc_update_bits(rtc,
+			      rtc->addr_base + RTC_PDN1,
+			      RTC_PDN1_PWRON_TIME, 0);
+	if (ret < 0)
+		goto exit;
+
+	ret =  rtc_update_bits(rtc,
+			       rtc->addr_base + RTC_PDN2,
+			       RTC_PDN2_PWRON_ALARM, RTC_PDN2_PWRON_ALARM);
+	if (ret < 0)
+		goto exit;
+
+	mtk_rtc_write_trigger(rtc);
+	power_down_mclk(rtc);
+	dev_notice(rtc->rtc_dev->dev.parent, "%s info\n", __func__);
+	return;
+
+exit:
+	power_down_mclk(rtc);
+	dev_err(rtc->rtc_dev->dev.parent, "%s error\n", __func__);
+}
+
+static int mtk_rtc_restore_alarm(struct mt6685_rtc *rtc, struct rtc_time *tm)
+{
+	int ret;
+	u16 data[RTC_OFFSET_COUNT] = { 0 };
+
+	power_on_mclk(rtc);
+
+	ret = rtc_bulk_read(rtc, rtc->addr_base + RTC_AL_SEC,
+			    data, RTC_OFFSET_COUNT * 2);
+	if (ret < 0)
+		goto exit;
+
+	data[RTC_OFFSET_SEC] = ((data[RTC_OFFSET_SEC] & ~(RTC_AL_SEC_MASK)) |
+				(tm->tm_sec & RTC_AL_SEC_MASK));
+	data[RTC_OFFSET_MIN] = ((data[RTC_OFFSET_MIN] & ~(RTC_AL_MIN_MASK)) |
+				(tm->tm_min & RTC_AL_MIN_MASK));
+	data[RTC_OFFSET_HOUR] = ((data[RTC_OFFSET_HOUR] & ~(RTC_AL_HOU_MASK)) |
+				(tm->tm_hour & RTC_AL_HOU_MASK));
+	data[RTC_OFFSET_DOM] = ((data[RTC_OFFSET_DOM] & ~(RTC_AL_DOM_MASK)) |
+				(tm->tm_mday & RTC_AL_DOM_MASK));
+	data[RTC_OFFSET_MTH] = ((data[RTC_OFFSET_MTH] & ~(RTC_AL_MTH_MASK)) |
+				(tm->tm_mon & RTC_AL_MTH_MASK));
+	data[RTC_OFFSET_YEAR] = ((data[RTC_OFFSET_YEAR] & ~(RTC_AL_YEA_MASK)) |
+				(tm->tm_year & RTC_AL_YEA_MASK));
+
+	dev_notice(rtc->rtc_dev->dev.parent,
+		   "restore al time = %04d/%02d/%02d %02d:%02d:%02d\n",
+		   tm->tm_year + RTC_MIN_YEAR, tm->tm_mon, tm->tm_mday,
+		   tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+	ret = rtc_bulk_write(rtc, rtc->addr_base + RTC_AL_SEC,
+			     data, RTC_OFFSET_COUNT * 2);
+	if (ret < 0)
+		goto exit;
+
+	ret = rtc_write(rtc, rtc->addr_base + RTC_AL_MASK,
+			RTC_AL_MASK_DOW);
+	if (ret < 0)
+		goto exit;
+
+	ret =  rtc_update_bits(rtc,
+			       rtc->addr_base + RTC_IRQ_EN,
+			       RTC_IRQ_EN_AL, RTC_IRQ_EN_AL);
+	if (ret < 0)
+		goto exit;
+
+	mtk_rtc_write_trigger(rtc);
+	power_down_mclk(rtc);
+	return ret;
+
+exit:
+	power_down_mclk(rtc);
+	dev_err(rtc->rtc_dev->dev.parent, "%s error\n", __func__);
+	return ret;
+}
+
+static bool mtk_rtc_is_pwron_alarm(struct mt6685_rtc *rtc,
+				   struct rtc_time *nowtm, struct rtc_time *tm)
+{
+	u32 pdn1 = 0, spar1 = 0, pdn2 = 0, spar0 = 0;
+	int ret, sec = 0;
+	u16 data[RTC_OFFSET_COUNT] = { 0 };
+
+	ret = rtc_read(rtc, rtc->addr_base + RTC_PDN1, &pdn1);
+	if (ret < 0)
+		goto exit;
+
+	dev_notice(rtc->rtc_dev->dev.parent, "pdn1 = 0x%x\n", pdn1);
+
+	if (pdn1 & RTC_PDN1_PWRON_TIME) {/* power-on time is available */
+
+		/*get current rtc time*/
+		do {
+			ret = rtc_bulk_read(rtc,
+					    rtc->addr_base + RTC_TC_SEC,
+					    data, RTC_OFFSET_COUNT * 2);
+			if (ret < 0)
+				goto exit;
+			nowtm->tm_sec = data[RTC_OFFSET_SEC] & RTC_TC_SEC_MASK;
+			nowtm->tm_min = data[RTC_OFFSET_MIN] & RTC_TC_MIN_MASK;
+			nowtm->tm_hour = data[RTC_OFFSET_HOUR] & RTC_TC_HOU_MASK;
+			nowtm->tm_mday = data[RTC_OFFSET_DOM] & RTC_TC_DOM_MASK;
+			nowtm->tm_mon = data[RTC_OFFSET_MTH] & RTC_TC_MTH_MASK;
+			nowtm->tm_year = data[RTC_OFFSET_YEAR] & RTC_TC_YEA_MASK;
+
+			ret = rtc_read(rtc,
+				       rtc->addr_base + RTC_TC_SEC, &sec);
+			if (ret < 0)
+				goto exit;
+			sec &= RTC_TC_SEC_MASK;
+
+		} while (sec < nowtm->tm_sec);
+
+		dev_notice(rtc->rtc_dev->dev.parent,
+			   "get now time = %04d/%02d/%02d %02d:%02d:%02d\n",
+			   nowtm->tm_year + RTC_MIN_YEAR, nowtm->tm_mon,
+			   nowtm->tm_mday, nowtm->tm_hour,
+			   nowtm->tm_min, nowtm->tm_sec);
+
+		/*get power on time from SPARE */
+		ret = rtc_read(rtc,
+			       rtc->addr_base + RTC_SPAR0, &spar0);
+		if (ret < 0)
+			goto exit;
+
+		ret = rtc_read(rtc,
+			       rtc->addr_base + RTC_SPAR1, &spar1);
+		if (ret < 0)
+			goto exit;
+
+		ret = rtc_read(rtc,
+			       rtc->addr_base + RTC_PDN2, &pdn2);
+		if (ret < 0)
+			goto exit;
+		dev_notice(rtc->rtc_dev->dev.parent,
+			   "spar0=0x%x, spar1=0x%x, pdn2=0x%x\n",
+			   spar0, spar1, pdn2);
+
+		tm->tm_sec =
+			(spar0 & RTC_PWRON_SEC_MASK) >> RTC_PWRON_SEC_SHIFT;
+		tm->tm_min =
+			(spar1 & RTC_PWRON_MIN_MASK) >> RTC_PWRON_MIN_SHIFT;
+		tm->tm_hour =
+			(spar1 & RTC_PWRON_HOU_MASK) >> RTC_PWRON_HOU_SHIFT;
+		tm->tm_mday =
+			(spar1 & RTC_PWRON_DOM_MASK) >> RTC_PWRON_DOM_SHIFT;
+		tm->tm_mon =
+			(pdn2 & RTC_PWRON_MTH_MASK) >> RTC_PWRON_MTH_SHIFT;
+		tm->tm_year =
+			(pdn2 & RTC_PWRON_YEA_MASK) >> RTC_PWRON_YEA_SHIFT;
+
+		dev_notice(rtc->rtc_dev->dev.parent,
+			   "get pwron time = %04d/%02d/%02d %02d:%02d:%02d\n",
+			   tm->tm_year + RTC_MIN_YEAR, tm->tm_mon, tm->tm_mday,
+			   tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+		return true;
+	}
+	return false;
+exit:
+	dev_err(rtc->rtc_dev->dev.parent, "%s error\n", __func__);
+	return false;
+}
+#endif
+
+static int mtk_rtc_write_trigger(struct mt6685_rtc *rtc)
+{
+	unsigned long timeout = jiffies + HZ;
+	int ret;
+	u32 data = 0;
+
+	ret = rtc_write(rtc,
+			rtc->addr_base + rtc->data->wrtgr, 1);
+	if (ret < 0)
+		return ret;
+
+	while (1) {
+		ret = rtc_read(rtc, rtc->addr_base + RTC_BBPU,
+			       &data);
+		if (ret < 0)
+			break;
+		if (!(data & RTC_BBPU_CBUSY))
+			break;
+		if (time_after(jiffies, timeout)) {
+			ret = -ETIMEDOUT;
+			break;
+		}
+		cpu_relax();
+	}
+	return ret;
+}
+
+static void mtk_rtc_reset_bbpu_alarm_status(struct mt6685_rtc *rtc)
+{
+	u32 bbpu;
+	int ret;
+
+	power_on_mclk(rtc);
+
+	bbpu = RTC_BBPU_KEY | RTC_BBPU_PWREN | RTC_BBPU_RESET_AL;
+	ret = rtc_write(rtc, rtc->addr_base + RTC_BBPU, bbpu);
+	if (ret < 0)
+		goto exit;
+
+	mtk_rtc_write_trigger(rtc);
+	power_down_mclk(rtc);
+	return;
+exit:
+	power_down_mclk(rtc);
+	dev_err(rtc->rtc_dev->dev.parent, "%s error\n", __func__);
+}
+
+static int mtk_rtc_is_alarm_irq(struct mt6685_rtc *rtc)
+{
+	u32 irqsta = 0, bbpu = 0, sck = 0, sck_check = 0, irqsta_check = 0;
+	int ret;
+
+	power_on_mclk(rtc);
+
+	ret = rtc_read(rtc, rtc->addr_base + RTC_IRQ_STA, &irqsta);/* read clear */
+
+	/*clear SCK_TOP rtc interrupt*/
+	rtc_read(rtc, SCK_TOP_INT_STATUS0, &sck);
+	rtc_write(rtc, SCK_TOP_INT_STATUS0, sck);
+
+	rtc_read(rtc, SCK_TOP_INT_STATUS0, &sck_check);
+	if (sck_check) {
+		udelay(70);
+		rtc_write(rtc, SCK_TOP_INT_STATUS0, 1);
+
+		rtc_read(rtc, SCK_TOP_INT_STATUS0, &sck_check);
+		if (sck_check) {
+			dev_notice(rtc->rtc_dev->dev.parent,
+				   "%s: TOP INT STA 0x%x\n", __func__, sck_check);
+
+			rtc_read(rtc, rtc->addr_base + RTC_IRQ_STA, &irqsta_check);
+			dev_notice(rtc->rtc_dev->dev.parent,
+				   "%s: IRQ STA 0x%x\n", __func__, irqsta_check);
+		}
+	}
+
+	if (ret == 0 && (irqsta & RTC_IRQ_STA_AL)) {
+		bbpu = RTC_BBPU_KEY | RTC_BBPU_PWREN;
+		ret = rtc_write(rtc,
+				rtc->addr_base + RTC_BBPU, bbpu);
+		if (ret < 0)
+			dev_err(rtc->rtc_dev->dev.parent,
+				"%s: %d error\n", __func__, __LINE__);
+
+		ret =  rtc_update_bits(rtc,
+				       rtc->addr_base + RTC_IRQ_EN,
+				       RTC_IRQ_EN_AL, 0);
+		if (ret < 0)
+			dev_err(rtc->rtc_dev->dev.parent,
+				"%s: %d error\n", __func__, __LINE__);
+		mtk_rtc_write_trigger(rtc);
+		power_down_mclk(rtc);
+		return RTC_ALSTA;
+	}
+	power_down_mclk(rtc);
+	return RTC_NONE;
+}
+
+static irqreturn_t mtk_rtc_irq_handler_thread(int irq, void *data)
+{
+	struct mt6685_rtc *rtc = data;
+	bool pwron_alm = false;
+	int status = RTC_NONE;
+#ifdef SUPPORT_PWR_OFF_ALARM
+	bool pwron_alarm = false;
+	struct rtc_time nowtm, tm;
+#endif
+
+	mutex_lock(&rtc->lock);
+
+	status = mtk_rtc_is_alarm_irq(rtc);
+
+	if (!rtc->rtc_dev) {
+		mutex_unlock(&rtc->lock);
+		return IRQ_NONE;
+	}
+
+	dev_notice(rtc->rtc_dev->dev.parent, "%s:%d\n", __func__, status);
+
+	if (status == RTC_NONE) {
+		mutex_unlock(&rtc->lock);
+		return IRQ_NONE;
+	}
+
+	mtk_rtc_reset_bbpu_alarm_status(rtc);
+
+#ifdef SUPPORT_PWR_OFF_ALARM
+	pwron_alarm = mtk_rtc_is_pwron_alarm(rtc, &nowtm, &tm);
+	nowtm.tm_year += RTC_MIN_YEAR;
+	tm.tm_year += RTC_MIN_YEAR;
+	if (pwron_alarm) {
+		time64_t now_time, time;
+
+		now_time =
+		    mktime64(nowtm.tm_year, nowtm.tm_mon, nowtm.tm_mday,
+			     nowtm.tm_hour, nowtm.tm_min, nowtm.tm_sec);
+
+		if (now_time == -1) {
+			mutex_unlock(&rtc->lock);
+			goto out;
+		}
+
+		time =
+		    mktime64(tm.tm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour,
+			     tm.tm_min, tm.tm_sec);
+
+		if (time == -1) {
+			mutex_unlock(&rtc->lock);
+			goto out;
+		}
+
+		/* power on */
+		if (now_time >= time - 1 && now_time <= time + 4) {
+			if (bootmode == KERNEL_POWER_OFF_CHARGING_BOOT ||
+			    bootmode == LOW_POWER_OFF_CHARGING_BOOT) {
+				mtk_rtc_reboot(rtc);
+				mutex_unlock(&rtc->lock);
+				disable_irq_nosync(rtc->irq);
+				goto out;
+			} else {
+				mtk_rtc_update_pwron_alarm_flag(rtc);
+				pwron_alm = true;
+			}
+		} else if (now_time < time) {	/* set power-on alarm */
+			time -= 1;
+			rtc_time64_to_tm(time, &tm);
+			tm.tm_year -= RTC_MIN_YEAR_OFFSET;
+			tm.tm_mon += 1;
+			mtk_rtc_restore_alarm(rtc, &tm);
+		}
+	}
+#endif
+	mutex_unlock(&rtc->lock);
+
+out:
+	if (rtc->rtc_dev)
+		rtc_update_irq(rtc->rtc_dev, 1, RTC_IRQF | RTC_AF);
+
+	if (rtc_show_alarm)
+		dev_notice(rtc->rtc_dev->dev.parent, "%s time is up\n",
+			   pwron_alm ? "power-on" : "alarm");
+
+	return IRQ_HANDLED;
+}
+
+static int __mtk_rtc_read_time(struct mt6685_rtc *rtc,
+			       struct rtc_time *tm, int *sec)
+{
+	int ret;
+	unsigned int reload = 0;
+	u16 data[RTC_OFFSET_COUNT] = { 0 };
+
+	power_on_mclk(rtc);
+
+	rtc_read(rtc, rtc->addr_base + RTC_BBPU, &reload);
+	reload = reload | RTC_BBPU_KEY | RTC_BBPU_RELOAD;
+	rtc_write(rtc, rtc->addr_base + RTC_BBPU, reload);
+	mtk_rtc_write_trigger(rtc);
+	power_down_mclk(rtc);
+
+	mutex_lock(&rtc->lock);
+	ret = rtc_bulk_read(rtc, rtc->addr_base + RTC_TC_SEC,
+			    data, RTC_OFFSET_COUNT * 2);
+	if (ret < 0)
+		goto exit;
+
+	tm->tm_sec = data[RTC_OFFSET_SEC] & RTC_TC_SEC_MASK;
+	tm->tm_min = data[RTC_OFFSET_MIN] & RTC_TC_MIN_MASK;
+	tm->tm_hour = data[RTC_OFFSET_HOUR] & RTC_TC_HOU_MASK;
+	tm->tm_mday = data[RTC_OFFSET_DOM] & RTC_TC_DOM_MASK;
+	tm->tm_mon = data[RTC_OFFSET_MTH] & RTC_TC_MTH_MASK;
+	tm->tm_year = data[RTC_OFFSET_YEAR] & RTC_TC_YEA_MASK;
+
+	ret = rtc_read(rtc, rtc->addr_base + RTC_TC_SEC, sec);
+	*sec &= RTC_TC_SEC_MASK;
+exit:
+	mutex_unlock(&rtc->lock);
+	return ret;
+}
+
+static void mtk_rtc_set_pwron_time(struct mt6685_rtc *rtc, struct rtc_time *tm)
+{
+	u32 data[RTC_OFFSET_COUNT];
+	int ret, i;
+
+	data[RTC_OFFSET_SEC] =
+		((tm->tm_sec << RTC_PWRON_SEC_SHIFT) & RTC_PWRON_SEC_MASK);
+	data[RTC_OFFSET_MIN] =
+		((tm->tm_min << RTC_PWRON_MIN_SHIFT) & RTC_PWRON_MIN_MASK);
+	data[RTC_OFFSET_HOUR] =
+		((tm->tm_hour << RTC_PWRON_HOU_SHIFT) & RTC_PWRON_HOU_MASK);
+	data[RTC_OFFSET_DOM] =
+		((tm->tm_mday << RTC_PWRON_DOM_SHIFT) & RTC_PWRON_DOM_MASK);
+	data[RTC_OFFSET_MTH] =
+		((tm->tm_mon << RTC_PWRON_MTH_SHIFT) & RTC_PWRON_MTH_MASK);
+	data[RTC_OFFSET_YEAR] =
+		((tm->tm_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,
+				       rtc->addr_base + rtc_pwron_reg[i][RTC_REG],
+				       rtc_pwron_reg[i][RTC_MASK], data[i]);
+		if (ret < 0)
+			goto exit;
+		mtk_rtc_write_trigger(rtc);
+	}
+	return;
+exit:
+	dev_err(rtc->rtc_dev->dev.parent, "%s error\n", __func__);
+}
+
+static void mtk_rtc_save_pwron_time(struct mt6685_rtc *rtc,
+				    bool enable, struct rtc_time *tm)
+{
+	u32 pdn1 = 0;
+	int ret;
+
+	/* set power on time */
+	mtk_rtc_set_pwron_time(rtc, tm);
+
+	/* update power on alarm related flags */
+	if (enable)
+		pdn1 = RTC_PDN1_PWRON_TIME;
+	ret =  rtc_update_bits(rtc,
+			       rtc->addr_base + RTC_PDN1,
+			       RTC_PDN1_PWRON_TIME, pdn1);
+	if (ret < 0)
+		dev_err(rtc->rtc_dev->dev.parent, "%s error\n", __func__);
+
+	mtk_rtc_write_trigger(rtc);
+}
+
+static int mtk_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+	time64_t time;
+	struct mt6685_rtc *rtc = dev_get_drvdata(dev);
+	int days, sec, ret;
+	unsigned long long timeout = sched_clock() + 500000000;
+
+	do {
+		ret = __mtk_rtc_read_time(rtc, tm, &sec);
+		if (ret < 0)
+			goto exit;
+		if (sched_clock() > timeout) {
+			pr_notice("%s, time out\n", __func__);
+			break;
+		}
+	} while (sec < tm->tm_sec);
+
+	/* HW register use 7 bits to store year data, minus
+	 * RTC_MIN_YEAR_OFFSET before write year data to register, and plus
+	 * RTC_MIN_YEAR_OFFSET back after read year from register
+	 */
+	tm->tm_year += RTC_MIN_YEAR_OFFSET;//+110
+
+	/* HW register start mon from one, but tm_mon start from zero. */
+	tm->tm_mon--;
+	time = rtc_tm_to_time64(tm);
+
+	/* rtc_tm_to_time64 covert Gregorian date to seconds since
+	 * 01-01-1970 00:00:00, and this date is Thursday.
+	 */
+	days = div_s64(time, 86400);
+	tm->tm_wday = (days + 4) % 7;
+
+	if (rtc_show_time) {
+		dev_notice(rtc->rtc_dev->dev.parent,
+			   "read tc time = %04d/%02d/%02d (%d) %02d:%02d:%02d\n",
+			   tm->tm_year + RTC_BASE_YEAR, tm->tm_mon + 1,
+			   tm->tm_mday, tm->tm_wday, tm->tm_hour,
+			   tm->tm_min, tm->tm_sec);
+	}
+exit:
+	return ret;
+}
+
+static bool mtk_rtc_check_set_time(struct mt6685_rtc *rtc, struct rtc_time *tm,
+				   int retry_time, int rtc_time_reg)
+{
+	int ret, i, j, write_fail = 0, prot_key = 0xDEAD, hwid = 0, mclk = 0;
+	u16 data[RTC_OFFSET_COUNT], latest[RTC_OFFSET_COUNT];
+
+	data[RTC_OFFSET_SEC] = tm->tm_sec;
+	data[RTC_OFFSET_MIN] = tm->tm_min;
+	data[RTC_OFFSET_HOUR] = tm->tm_hour;
+	data[RTC_OFFSET_DOM] = tm->tm_mday;
+	data[RTC_OFFSET_MTH] = tm->tm_mon;
+	data[RTC_OFFSET_YEAR] = tm->tm_year;
+
+	for (j = 1; j <= retry_time; j++) {
+		write_fail = 0;
+
+		ret = rtc_bulk_read(rtc, rtc->addr_base + rtc_time_reg,
+				    latest, RTC_OFFSET_COUNT * 2);
+		if (ret < 0)
+			return ret;
+
+		for (i = 0; i < RTC_OFFSET_COUNT; i++) {
+			if (i == RTC_OFFSET_DOW)
+				continue;
+
+			latest[i] = latest[i] & rtc_time_mask[i];
+			if (latest[i] != data[i])
+				write_fail++;
+
+			if (j == retry_time) {
+				ret = rtc_read(rtc, rtc->data->hwid, &hwid);
+				if (ret < 0)
+					return ret;
+
+				ret = rtc_read(rtc, RG_RTC_MCLK_PDN, &mclk);
+				if (ret < 0)
+					return ret;
+				mclk = mclk >> RG_RTC_MCLK_PDN_STA_SHIFT & RG_RTC_MCLK_PDN_STA_MASK;
+
+				if (rtc->data->chip_version == MT6685_SERIES) {
+					ret = rtc_read(rtc,
+						       rtc->addr_base + RTC_SPAR_MACRO, &prot_key);
+
+					if (ret < 0)
+						return ret;
+
+					prot_key =
+						prot_key >> SPAR_PROT_STAT_SHIFT
+						& SPAR_PROT_STAT_MASK;
+				}
+
+				dev_info(rtc->rtc_dev->dev.parent,
+					 "[HWID 0x%x, MCLK 0x%x, prot key 0x%x] %s write %d, latest %d\n",
+					 hwid, mclk, prot_key, rtc_time_reg_name[i],
+					 data[i], latest[i]);
+			}
+		}
+
+		if (write_fail > 0)
+			mdelay(2);
+		else
+			break;
+	}
+
+	if (write_fail > 0)
+		return false;
+
+	return true;
+}
+
+static int mtk_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+	struct mt6685_rtc *rtc = dev_get_drvdata(dev);
+	int ret, result = 0;
+	u16 data[RTC_OFFSET_COUNT];
+
+	power_on_mclk(rtc);
+
+	dev_notice(rtc->rtc_dev->dev.parent,
+		   "set tc time = %04d/%02d/%02d %02d:%02d:%02d\n",
+		   tm->tm_year + RTC_BASE_YEAR, tm->tm_mon + 1, tm->tm_mday,
+		   tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+	tm->tm_year -= RTC_MIN_YEAR_OFFSET;
+	tm->tm_mon++;
+
+	data[RTC_OFFSET_SEC] = tm->tm_sec;
+	data[RTC_OFFSET_MIN] = tm->tm_min;
+	data[RTC_OFFSET_HOUR] = tm->tm_hour;
+	data[RTC_OFFSET_DOM] = tm->tm_mday;
+	data[RTC_OFFSET_MTH] = tm->tm_mon;
+	data[RTC_OFFSET_YEAR] = tm->tm_year;
+
+	mutex_lock(&rtc->lock);
+	ret = rtc_bulk_write(rtc, rtc->addr_base + RTC_TC_SEC,
+			     data, RTC_OFFSET_COUNT * 2);
+	if (ret < 0)
+		goto exit;
+
+	/* Time register write to hardware after call trigger function */
+	ret = mtk_rtc_write_trigger(rtc);
+	if (ret < 0)
+		goto exit;
+
+	result = mtk_rtc_check_set_time(rtc, tm, 2, RTC_TC_SEC);
+
+	if (!result) {
+		dev_info(rtc->rtc_dev->dev.parent, "check rtc set time\n");
+#if IS_ENABLED(CONFIG_MTK_AEE_FEATURE)
+		aee_kernel_warning("mt6685-rtc", "mt6685-rtc: set tick time failed\n");
+#endif
+	}
+
+exit:
+	mutex_unlock(&rtc->lock);
+	power_down_mclk(rtc);
+	return ret;
+}
+
+static int mtk_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
+{
+	struct rtc_time *tm = &alm->time;
+	struct mt6685_rtc *rtc = dev_get_drvdata(dev);
+	u32 irqen = 0, pdn2 = 0;
+	int ret;
+	u16 data[RTC_OFFSET_COUNT] = { 0 };
+
+	mutex_lock(&rtc->lock);
+	ret = rtc_read(rtc, rtc->addr_base + RTC_IRQ_EN, &irqen);
+	if (ret < 0)
+		goto err_exit;
+	ret = rtc_read(rtc, rtc->addr_base + RTC_PDN2, &pdn2);
+	if (ret < 0)
+		goto err_exit;
+
+	ret = rtc_bulk_read(rtc, rtc->addr_base + RTC_AL_SEC,
+			    data, RTC_OFFSET_COUNT * 2);
+	if (ret < 0)
+		goto err_exit;
+
+	alm->enabled = !!(irqen & RTC_IRQ_EN_AL);
+	alm->pending = !!(pdn2 & RTC_PDN2_PWRON_ALARM);
+	mutex_unlock(&rtc->lock);
+
+	tm->tm_sec = data[RTC_OFFSET_SEC] & RTC_AL_SEC_MASK;
+	tm->tm_min = data[RTC_OFFSET_MIN] & RTC_AL_MIN_MASK;
+	tm->tm_hour = data[RTC_OFFSET_HOUR] & RTC_AL_HOU_MASK;
+	tm->tm_mday = data[RTC_OFFSET_DOM] & RTC_AL_DOM_MASK;
+	tm->tm_mon = data[RTC_OFFSET_MTH] & RTC_AL_MTH_MASK;
+	tm->tm_year = data[RTC_OFFSET_YEAR] & RTC_AL_YEA_MASK;
+
+	tm->tm_year += RTC_MIN_YEAR_OFFSET;
+	tm->tm_mon--;
+
+	dev_notice(rtc->rtc_dev->dev.parent,
+		   "read al time = %04d/%02d/%02d %02d:%02d:%02d (%d)\n",
+		   tm->tm_year + RTC_BASE_YEAR, tm->tm_mon + 1, tm->tm_mday,
+		   tm->tm_hour, tm->tm_min, tm->tm_sec, alm->enabled);
+
+	return 0;
+err_exit:
+	mutex_unlock(&rtc->lock);
+	return ret;
+}
+
+static int mtk_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
+{
+	struct rtc_time *tm = &alm->time;
+	struct mt6685_rtc *rtc = dev_get_drvdata(dev);
+	int ret, result = 0;
+	u16 data[RTC_OFFSET_COUNT];
+	ktime_t target;
+
+	power_on_mclk(rtc);
+
+	if (alm->enabled == 1) {
+		/* Add one more second to postpone wake time. */
+		target = rtc_tm_to_ktime(*tm);
+		target = ktime_add_ns(target, NSEC_PER_SEC);
+		*tm = rtc_ktime_to_tm(target);
+	}
+
+	tm->tm_year -= RTC_MIN_YEAR_OFFSET;
+	tm->tm_mon++;
+
+	dev_notice(rtc->rtc_dev->dev.parent,
+		   "set al time = %04d/%02d/%02d %02d:%02d:%02d (%d)\n",
+		   tm->tm_year + RTC_MIN_YEAR, tm->tm_mon, tm->tm_mday,
+		   tm->tm_hour, tm->tm_min, tm->tm_sec, alm->enabled);
+
+	mutex_lock(&rtc->lock);
+
+	switch (alm->enabled) {
+	case 3:
+		/* enable power-on alarm with logo */
+		mtk_rtc_save_pwron_time(rtc, true, tm);
+		break;
+	case 4:
+		/* disable power-on alarm */
+		mtk_rtc_save_pwron_time(rtc, false, tm);
+		break;
+	default:
+		break;
+	}
+
+	ret = rtc_update_bits(rtc,
+			      rtc->addr_base + RTC_PDN2,
+			      RTC_PDN2_PWRON_ALARM, 0);
+	if (ret < 0)
+		goto exit;
+	mtk_rtc_write_trigger(rtc);
+
+	ret = rtc_bulk_read(rtc, rtc->addr_base + RTC_AL_SEC,
+			    data, RTC_OFFSET_COUNT * 2);
+	if (ret < 0)
+		goto exit;
+
+	data[RTC_OFFSET_SEC] = ((data[RTC_OFFSET_SEC] & ~(RTC_AL_SEC_MASK)) |
+				(tm->tm_sec & RTC_AL_SEC_MASK));
+	data[RTC_OFFSET_MIN] = ((data[RTC_OFFSET_MIN] & ~(RTC_AL_MIN_MASK)) |
+				(tm->tm_min & RTC_AL_MIN_MASK));
+	data[RTC_OFFSET_HOUR] = ((data[RTC_OFFSET_HOUR] & ~(RTC_AL_HOU_MASK)) |
+				(tm->tm_hour & RTC_AL_HOU_MASK));
+	data[RTC_OFFSET_DOM] = ((data[RTC_OFFSET_DOM] & ~(RTC_AL_DOM_MASK)) |
+				(tm->tm_mday & RTC_AL_DOM_MASK));
+	data[RTC_OFFSET_MTH] = ((data[RTC_OFFSET_MTH] & ~(RTC_AL_MTH_MASK)) |
+				(tm->tm_mon & RTC_AL_MTH_MASK));
+	data[RTC_OFFSET_YEAR] = ((data[RTC_OFFSET_YEAR] & ~(RTC_AL_YEA_MASK)) |
+				(tm->tm_year & RTC_AL_YEA_MASK));
+
+	if (alm->enabled) {
+		ret = rtc_bulk_write(rtc,
+				     rtc->addr_base + RTC_AL_SEC,
+				     data, RTC_OFFSET_COUNT * 2);
+		if (ret < 0)
+			goto exit;
+		ret = rtc_write(rtc, rtc->addr_base + RTC_AL_MASK,
+				RTC_AL_MASK_DOW);
+		if (ret < 0)
+			goto exit;
+
+		ret =  rtc_update_bits(rtc,
+				       rtc->addr_base + RTC_IRQ_EN,
+				       RTC_IRQ_EN_AL, RTC_IRQ_EN_AL);
+		if (ret < 0)
+			goto exit;
+		} else {
+			ret =  rtc_update_bits(rtc,
+					       rtc->addr_base + RTC_IRQ_EN,
+					       RTC_IRQ_EN_AL, 0);
+			if (ret < 0)
+				goto exit;
+		}
+
+	/* All alarm time register write to hardware after calling
+	 * mtk_rtc_write_trigger. This can avoid race condition if alarm
+	 * occur happen during writing alarm time register.
+	 */
+	ret = mtk_rtc_write_trigger(rtc);
+	if (ret < 0)
+		goto exit;
+
+	result = mtk_rtc_check_set_time(rtc, tm, 2, RTC_AL_SEC);
+
+	if (!result) {
+		dev_info(rtc->rtc_dev->dev.parent, "check rtc set alarm\n");
+#if IS_ENABLED(CONFIG_MTK_AEE_FEATURE)
+		aee_kernel_warning("mt6685-rtc", "mt6685-rtc: set alarm time failed\n");
+#endif
+	}
+exit:
+	mutex_unlock(&rtc->lock);
+	power_down_mclk(rtc);
+	return ret;
+}
+
+static int rtc_alarm_set_power_on(struct device *dev, struct rtc_wkalrm *alm)
+{
+	int err = 0;
+	struct rtc_time tm;
+	time64_t now, scheduled;
+
+	err = rtc_valid_tm(&alm->time);
+	if (err != 0)
+		return err;
+	scheduled = rtc_tm_to_time64(&alm->time);
+
+	err = mtk_rtc_read_time(dev, &tm);
+	if (err != 0)
+		return err;
+	now = rtc_tm_to_time64(&tm);
+
+	if (scheduled <= now)
+		alm->enabled = 4;
+	else
+		alm->enabled = 3;
+
+	mtk_rtc_set_alarm(dev, alm);
+
+	return err;
+}
+
+static int mtk_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
+{
+	void __user *uarg = (void __user *)arg;
+	int err = 0;
+	struct rtc_wkalrm alm;
+
+	switch (cmd) {
+	case RTC_POFF_ALM_SET:
+		if (copy_from_user(&alm.time, uarg, sizeof(alm.time)))
+			return -EFAULT;
+		err = rtc_alarm_set_power_on(dev, &alm);
+		break;
+	default:
+		err = -EINVAL;
+		break;
+	}
+
+	return err;
+}
+
+static const struct rtc_class_ops mtk_rtc_ops = {
+	.ioctl      = mtk_rtc_ioctl,
+	.read_time  = mtk_rtc_read_time,
+	.set_time   = mtk_rtc_set_time,
+	.read_alarm = mtk_rtc_read_alarm,
+	.set_alarm  = mtk_rtc_set_alarm,
+};
+
+static int rtc_nvram_read(void *priv, unsigned int offset, void *val,
+			  size_t bytes)
+{
+	struct mt6685_rtc *rtc = dev_get_drvdata(priv);
+	unsigned int ival;
+	int ret;
+	u8 *buf = val;
+
+	mutex_lock(&rtc->lock);
+
+	for (; bytes; bytes--) {
+		ret = rtc_field_read(rtc,
+				     &rtc->data->spare_reg_fields[offset++],
+				     &ival);
+
+		if (ret)
+			goto out;
+
+		*buf++ = (u8)ival;
+	}
+
+out:
+	mutex_unlock(&rtc->lock);
+	return ret;
+}
+
+static int rtc_nvram_write(void *priv, unsigned int offset, void *val,
+			   size_t bytes)
+{
+	struct mt6685_rtc *rtc = dev_get_drvdata(priv);
+	unsigned int ival;
+	int ret;
+	u8 *buf = val;
+
+	power_on_mclk(rtc);
+
+	mutex_lock(&rtc->lock);
+
+	for (; bytes; bytes--) {
+		ival = *buf++;
+		ret = rtc_field_write(rtc,
+				      &rtc->data->spare_reg_fields[offset++],
+				      ival);
+
+		if (ret)
+			goto out;
+	}
+
+out:
+	mutex_unlock(&rtc->lock);
+	power_down_mclk(rtc);
+	return ret;
+}
+
+static int mtk_rtc_set_spare(struct device *dev)
+{
+	struct mt6685_rtc *rtc = dev_get_drvdata(dev);
+	int ret;
+	struct nvmem_config nvmem_cfg = {
+		.name = "mtk_rtc_nvmem",
+		.word_size = SPARE_REG_WIDTH,
+		.stride = 1,
+		.size = SPARE_RG_MAX * SPARE_REG_WIDTH,
+		.reg_read = rtc_nvram_read,
+		.reg_write = rtc_nvram_write,
+		.priv = dev,
+	};
+
+	ret = devm_rtc_nvmem_register(rtc->rtc_dev, &nvmem_cfg);
+	if (ret)
+		dev_err(rtc->rtc_dev->dev.parent, "nvmem register failed\n");
+
+	return ret;
+}
+
+static int mtk_rtc_probe(struct platform_device *pdev)
+{
+	struct mt6685_rtc *rtc;
+	struct device_node *np = pdev->dev.of_node;
+	int ret;
+#ifdef SUPPORT_PWR_OFF_ALARM
+	struct device_node *of_chosen = NULL;
+	struct tag_bootmode *tag = NULL;
+#endif
+	if (!of_device_is_available(np)) {
+		dev_err(&pdev->dev, "rtc disabled\n");
+		return -1;
+	}
+
+	rtc = devm_kzalloc(&pdev->dev, sizeof(struct mt6685_rtc), GFP_KERNEL);
+	if (!rtc) {
+		//dev_err(&pdev->dev, "devm_kzalloc failed\n");
+		return -ENOMEM;
+	}
+
+	rtc->data = of_device_get_match_data(&pdev->dev);
+	if (!rtc->data) {
+		dev_err(&pdev->dev, "of_device_get_match_data failed\n");
+		return -ENODEV;
+	}
+
+	if (of_property_read_u32(pdev->dev.of_node, "base", &rtc->addr_base))
+		rtc->addr_base = RTC_DSN_ID;
+
+	pr_notice("%s: rtc->addr_base =0x%x\n", __func__, rtc->addr_base);
+
+	mutex_init(&rtc->lock);
+	mutex_init(&rtc->clk_lock);
+
+	platform_set_drvdata(pdev, rtc);
+
+	rtc->rtc_dev = devm_rtc_allocate_device(&pdev->dev);
+	if (IS_ERR(rtc->rtc_dev)) {
+		dev_err(&pdev->dev, "Failed devm_rtc_allocate_device: %p\n", rtc->rtc_dev);
+		return PTR_ERR(rtc->rtc_dev);
+	}
+
+	rtc->regmap = dev_get_regmap(pdev->dev.parent, NULL);
+	if (!rtc->regmap) {
+		pr_err("%s: get regmap failed\n", __func__);
+		return -ENODEV;
+	}
+
+#ifdef SUPPORT_PWR_OFF_ALARM
+	mt6685_rtc_suspend_lock =
+		wakeup_source_register(NULL, "mt6685-rtc suspend wakelock");
+
+	of_chosen = of_find_node_by_path("/chosen");
+	if (!of_chosen)
+		of_chosen = of_find_node_by_path("/chosen@0");
+
+	if (of_chosen) {
+		tag = (struct tag_bootmode *)of_get_property
+		       (of_chosen, "atag,boot", NULL);
+		if (!tag) {
+			dev_err(&pdev->dev,
+				"%s: failed to get atag,boot\n", __func__);
+		} else {
+			dev_notice(&pdev->dev,
+				   "%s, bootmode:%d\n", __func__, tag->bootmode);
+			bootmode = tag->bootmode;
+		}
+	} else {
+		dev_err(&pdev->dev,
+			"%s: failed to get /chosen and /chosen@0\n", __func__);
+	}
+
+#if IS_ENABLED(CONFIG_PM)
+	rtc->pm_nb.notifier_call = rtc_pm_event;
+	rtc->pm_nb.priority = 0;
+	if (register_pm_notifier(&rtc->pm_nb))
+		dev_err(&pdev->dev, "rtc pm faile\n");
+	else
+		rtc_pm_notifier_registered = true;
+#endif /* CONFIG_PM */
+
+	INIT_WORK(&rtc->work, mtk_rtc_work_queue);
+#endif
+
+	/* Obtain interrupt ID from DTS or MFD */
+	rtc->irq = platform_get_irq(pdev, 0);
+	if (rtc->irq < 0) {
+		dev_err(&pdev->dev, "Failed to get irq(%d)\n", rtc->irq);
+#if IS_ENABLED(CONFIG_PM)
+		rtc_pm_notifier_registered = false;
+		unregister_pm_notifier(&rtc->pm_nb);
+#endif
+		return rtc->irq;
+	}
+
+	ret = devm_request_threaded_irq(&pdev->dev, rtc->irq, NULL,
+					mtk_rtc_irq_handler_thread,
+					IRQF_ONESHOT | IRQF_TRIGGER_HIGH,
+					"mt6685-rtc", rtc);
+	if (ret) {
+		dev_err(&pdev->dev, "Failed to request alarm IRQ: %d: %d\n",
+			rtc->irq, ret);
+#if IS_ENABLED(CONFIG_PM)
+		rtc_pm_notifier_registered = false;
+		unregister_pm_notifier(&rtc->pm_nb);
+#endif
+		return ret;
+	}
+
+	/*Enable SCK_TOP rtc interrupt*/
+	rtc_update_bits(rtc, SCK_TOP_INT_CON0, EN_RTC_INTERRUPT, 1);
+
+	device_init_wakeup(&pdev->dev, 1);
+
+	rtc->rtc_dev->ops = &mtk_rtc_ops;
+
+	if (rtc->data->spare_reg_fields)
+		if (mtk_rtc_set_spare(&pdev->dev))
+			dev_info(&pdev->dev, "spare is not supported\n");
+
+	ret = devm_rtc_register_device(rtc->rtc_dev);
+	if (ret) {
+		dev_err(&pdev->dev, "register rtc device failed\n");
+	};
+
+	enable_irq_wake(rtc->irq);
+
+	if (rtc->data->cali_reg_fields)
+		rtc->cali_is_supported = true;
+
+	power_on_mclk(rtc);
+	power_down_mclk(rtc);
+	return 0;
+}
+
+static void mtk_rtc_shutdown(struct platform_device *pdev)
+{
+	int ret = 0;
+	struct mt6685_rtc *rtc = dev_get_drvdata(&pdev->dev);
+
+	if (rtc->data->chip_version == MT6685_SERIES) {
+		/*Normal sequence power off when PON falling*/
+		ret = rtc_update_bits(rtc, TOP2_ELR1, TOP2_ELR1_MASK, 1);
+		if (ret < 0)
+			dev_info(&pdev->dev, "check mt6685 TOP2_ELR1\n");
+	}
+
+	if (rtc->cali_is_supported)
+		mtk_rtc_enable_k_eosc(&pdev->dev);
+}
+
+static const struct mtk_rtc_data mt6685_rtc_data = {
+	.wrtgr = RTC_WRTGR,
+	.hwid = HWID_MT6685,
+	.chip_version = MT6685_SERIES,
+	.spare_reg_fields = mt6685_spare_reg_fields,
+	.cali_reg_fields = mt6685_cali_reg_fields,
+	.single_read_write_is_supported = true,
+};
+
+static const struct of_device_id mt6685_rtc_of_match[] = {
+	{ .compatible = "mediatek,mt6685-rtc", .data = &mt6685_rtc_data },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, mt6685_rtc_of_match);
+
+static struct platform_driver mtk_rtc_driver = {
+	.driver = {
+		.name = "mt6685-rtc",
+		.of_match_table = mt6685_rtc_of_match,
+	},
+	.probe	= mtk_rtc_probe,
+	.shutdown = mtk_rtc_shutdown,
+};
+
+module_platform_driver(mtk_rtc_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mw Lin <Mw.Lin@mediatek.com>");
+MODULE_DESCRIPTION("RTC Driver for MediaTek MT6685 Clock IC");
diff --git a/include/linux/mfd/mt6685-audclk.h b/include/linux/mfd/mt6685-audclk.h
new file mode 100644
index 000000000000..fd99effd0a6c
--- /dev/null
+++ b/include/linux/mfd/mt6685-audclk.h
@@ -0,0 +1,11 @@ 
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2021 MediaTek Inc.
+ */
+#ifndef _AUDIO_DCXO_H_
+#define _AUDIO_DCXO_H_
+
+/* just be called by audio module for dcxo */
+void mt6685_set_dcxo_mode(unsigned int mode);
+void mt6685_set_dcxo(bool enable);
+#endif
diff --git a/include/linux/mfd/mt6685/core.h b/include/linux/mfd/mt6685/core.h
new file mode 100644
index 000000000000..dcaf800e8212
--- /dev/null
+++ b/include/linux/mfd/mt6685/core.h
@@ -0,0 +1,22 @@ 
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2021 MediaTek Inc.
+ */
+
+#ifndef __MFD_MT6685_CORE_H__
+#define __MFD_MT6685_CORE_H__
+
+struct mt6685_chip {
+	struct device *dev;
+	struct regmap *regmap;
+	int irq;
+	struct irq_domain *irq_domain;
+	struct mutex irqlock; /* Mid-end lock for synchronous operation */
+	u16 wake_mask[2];
+	u16 irq_masks_cur[2];
+	u16 irq_masks_cache[2];
+	u16 int_con[2];
+	u16 int_status[2];
+};
+
+#endif /* __MFD_MT6685_CORE_H__ */
diff --git a/include/linux/mfd/mt6685/registers.h b/include/linux/mfd/mt6685/registers.h
new file mode 100644
index 000000000000..3072a59545b6
--- /dev/null
+++ b/include/linux/mfd/mt6685/registers.h
@@ -0,0 +1,921 @@ 
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2021 MediaTek Inc
+ */
+
+#ifndef _MT6685_HW_H_
+#define _MT6685_HW_H_
+
+#define MT6685_REG_BASE                  ((unsigned int)(0x0))
+#define MT6685_HWCID_L                   (MT6685_REG_BASE + 0x8)
+#define MT6685_TOP_CON                   (MT6685_REG_BASE + 0x18)
+#define MT6685_TOP_CKPDN_CON0            (MT6685_REG_BASE + 0x10b)
+#define MT6685_TOP_CKPDN_CON0_SET        (MT6685_REG_BASE + 0x10c)
+#define MT6685_TOP_CKPDN_CON0_CLR        (MT6685_REG_BASE + 0x10d)
+#define MT6685_TOP_CKSEL_CON0            (MT6685_REG_BASE + 0x111)
+#define MT6685_TOP_CKSEL_CON0_SET        (MT6685_REG_BASE + 0x112)
+#define MT6685_TOP_CKSEL_CON0_CLR        (MT6685_REG_BASE + 0x113)
+#define MT6685_TOP2_ELR1                 (MT6685_REG_BASE + 0x12f)
+#define MT6685_TOP_DIG_WPK               (MT6685_REG_BASE + 0x3a8)
+#define MT6685_TOP_DIG_WPK_H             (MT6685_REG_BASE + 0x3a9)
+#define MT6685_SCK_TOP_INT_STATUS0       (MT6685_REG_BASE + 0x534)
+#define MT6685_SCK_TOP_INT_RAW_STATUS0   (MT6685_REG_BASE + 0x536)
+#define MT6685_SCK_TOP_CON0_L            (MT6685_REG_BASE + 0x50c)
+#define MT6685_SCK_TOP_CON0_H            (MT6685_REG_BASE + 0x50d)
+#define MT6685_SCK_TOP_CKPDN_CON0_L      (MT6685_REG_BASE + 0x514)
+#define MT6685_SCK_TOP_CKPDN_CON0_L_SET  (MT6685_REG_BASE + 0x515)
+#define MT6685_SCK_TOP_CKPDN_CON0_L_CLR  (MT6685_REG_BASE + 0x516)
+#define MT6685_SCK_TOP_RST_CON0          (MT6685_REG_BASE + 0x522)
+#define MT6685_SCK_TOP_INT_CON0          (MT6685_REG_BASE + 0x528)
+#define MT6685_SCK_TOP_INT_CON0_SET      (MT6685_REG_BASE + 0x52a)
+#define MT6685_SCK_TOP_INT_CON0_CLR      (MT6685_REG_BASE + 0x52c)
+#define MT6685_FQMTR_CON0_L              (MT6685_REG_BASE + 0x546)
+#define MT6685_FQMTR_CON0_H              (MT6685_REG_BASE + 0x547)
+#define MT6685_FQMTR_CON1_L              (MT6685_REG_BASE + 0x548)
+#define MT6685_FQMTR_CON2_L              (MT6685_REG_BASE + 0x54a)
+#define MT6685_SCK_TOP_CKSEL_CON         (MT6685_REG_BASE + 0x568)
+#define MT6685_RTC_SPAR_RELOAD           (MT6685_REG_BASE + 0x56a)
+#define MT6685_RTC_ANA_ID                (MT6685_REG_BASE + 0x580)
+#define MT6685_RTC_DIG_ID                (MT6685_REG_BASE + 0x581)
+#define MT6685_RTC_ANA_REV               (MT6685_REG_BASE + 0x582)
+#define MT6685_RTC_DIG_REV               (MT6685_REG_BASE + 0x583)
+#define MT6685_RTC_DBI                   (MT6685_REG_BASE + 0x584)
+#define MT6685_RTC_ESP                   (MT6685_REG_BASE + 0x585)
+#define MT6685_RTC_FPI                   (MT6685_REG_BASE + 0x586)
+#define MT6685_RTC_DXI                   (MT6685_REG_BASE + 0x587)
+#define MT6685_RTC_BBPU_L                (MT6685_REG_BASE + 0x588)
+#define MT6685_RTC_BBPU_H                (MT6685_REG_BASE + 0x589)
+#define MT6685_RTC_IRQ_STA               (MT6685_REG_BASE + 0x58a)
+#define MT6685_RTC_IRQ_EN                (MT6685_REG_BASE + 0x58c)
+#define MT6685_RTC_CII_EN_L              (MT6685_REG_BASE + 0x58e)
+#define MT6685_RTC_CII_EN_H              (MT6685_REG_BASE + 0x58f)
+#define MT6685_RTC_AL_MASK               (MT6685_REG_BASE + 0x590)
+#define MT6685_RTC_TC_SEC                (MT6685_REG_BASE + 0x592)
+#define MT6685_RTC_TC_MIN                (MT6685_REG_BASE + 0x594)
+#define MT6685_RTC_TC_HOU                (MT6685_REG_BASE + 0x596)
+#define MT6685_RTC_TC_DOM                (MT6685_REG_BASE + 0x598)
+#define MT6685_RTC_TC_DOW                (MT6685_REG_BASE + 0x59a)
+#define MT6685_RTC_TC_MTH_L              (MT6685_REG_BASE + 0x59c)
+#define MT6685_RTC_TC_MTH_H              (MT6685_REG_BASE + 0x59d)
+#define MT6685_RTC_TC_YEA                (MT6685_REG_BASE + 0x59e)
+#define MT6685_RTC_AL_SEC_L              (MT6685_REG_BASE + 0x5a0)
+#define MT6685_RTC_AL_SEC_H              (MT6685_REG_BASE + 0x5a1)
+#define MT6685_RTC_AL_MIN                (MT6685_REG_BASE + 0x5a2)
+#define MT6685_RTC_AL_HOU_L              (MT6685_REG_BASE + 0x5a4)
+#define MT6685_RTC_AL_HOU_H              (MT6685_REG_BASE + 0x5a5)
+#define MT6685_RTC_AL_DOM_L              (MT6685_REG_BASE + 0x5a6)
+#define MT6685_RTC_AL_DOM_H              (MT6685_REG_BASE + 0x5a7)
+#define MT6685_RTC_AL_DOW_L              (MT6685_REG_BASE + 0x5a8)
+#define MT6685_RTC_AL_DOW_H              (MT6685_REG_BASE + 0x5a9)
+#define MT6685_RTC_AL_MTH_L              (MT6685_REG_BASE + 0x5aa)
+#define MT6685_RTC_AL_MTH_H              (MT6685_REG_BASE + 0x5ab)
+#define MT6685_RTC_AL_YEA_L              (MT6685_REG_BASE + 0x5ac)
+#define MT6685_RTC_AL_YEA_H              (MT6685_REG_BASE + 0x5ad)
+#define MT6685_RTC_OSC32CON_L            (MT6685_REG_BASE + 0x5ae)
+#define MT6685_RTC_OSC32CON_H            (MT6685_REG_BASE + 0x5af)
+#define MT6685_RTC_POWERKEY1_L           (MT6685_REG_BASE + 0x5b0)
+#define MT6685_RTC_POWERKEY1_H           (MT6685_REG_BASE + 0x5b1)
+#define MT6685_RTC_POWERKEY2_L           (MT6685_REG_BASE + 0x5b2)
+#define MT6685_RTC_POWERKEY2_H           (MT6685_REG_BASE + 0x5b3)
+#define MT6685_RTC_PDN1_L                (MT6685_REG_BASE + 0x5b4)
+#define MT6685_RTC_PDN1_H                (MT6685_REG_BASE + 0x5b5)
+#define MT6685_RTC_PDN2_L                (MT6685_REG_BASE + 0x5b6)
+#define MT6685_RTC_PDN2_H                (MT6685_REG_BASE + 0x5b7)
+#define MT6685_RTC_SPAR0_L               (MT6685_REG_BASE + 0x5b8)
+#define MT6685_RTC_SPAR0_H               (MT6685_REG_BASE + 0x5b9)
+#define MT6685_RTC_SPAR1_L               (MT6685_REG_BASE + 0x5ba)
+#define MT6685_RTC_SPAR1_H               (MT6685_REG_BASE + 0x5bb)
+#define MT6685_RTC_PROT_L                (MT6685_REG_BASE + 0x5bc)
+#define MT6685_RTC_PROT_H                (MT6685_REG_BASE + 0x5bd)
+#define MT6685_RTC_DIFF_L                (MT6685_REG_BASE + 0x5be)
+#define MT6685_RTC_DIFF_H                (MT6685_REG_BASE + 0x5bf)
+#define MT6685_RTC_CALI_L                (MT6685_REG_BASE + 0x5c0)
+#define MT6685_RTC_CALI_H                (MT6685_REG_BASE + 0x5c1)
+#define MT6685_RTC_WRTGR                 (MT6685_REG_BASE + 0x5c2)
+#define MT6685_RTC_CON_L                 (MT6685_REG_BASE + 0x5c4)
+#define MT6685_RTC_CON_H                 (MT6685_REG_BASE + 0x5c5)
+#define MT6685_RTC_SEC_CTRL              (MT6685_REG_BASE + 0x5c6)
+#define MT6685_RTC_INT_CNT_L             (MT6685_REG_BASE + 0x5c8)
+#define MT6685_RTC_INT_CNT_H             (MT6685_REG_BASE + 0x5c9)
+#define MT6685_RTC_SEC_DAT0_L            (MT6685_REG_BASE + 0x5ca)
+#define MT6685_RTC_SEC_DAT0_H            (MT6685_REG_BASE + 0x5cb)
+#define MT6685_RTC_SEC_DAT1_L            (MT6685_REG_BASE + 0x5cc)
+#define MT6685_RTC_SEC_DAT1_H            (MT6685_REG_BASE + 0x5cd)
+#define MT6685_RTC_SEC_DAT2_L            (MT6685_REG_BASE + 0x5ce)
+#define MT6685_RTC_SEC_DAT2_H            (MT6685_REG_BASE + 0x5cf)
+#define MT6685_RTC_RG_FG0                (MT6685_REG_BASE + 0x5d0)
+#define MT6685_RTC_RG_FG1                (MT6685_REG_BASE + 0x5d2)
+#define MT6685_RTC_RG_FG2                (MT6685_REG_BASE + 0x5d4)
+#define MT6685_RTC_RG_FG3                (MT6685_REG_BASE + 0x5d6)
+#define MT6685_RTC_SPAR_MACRO            (MT6685_REG_BASE + 0x5d8)
+#define MT6685_RTC_SPAR_CORE             (MT6685_REG_BASE + 0x5e0)
+#define MT6685_RTC_EOSC_CALI             (MT6685_REG_BASE + 0x5e2)
+#define MT6685_RTC_SEC_ANA_ID            (MT6685_REG_BASE + 0x600)
+#define MT6685_RTC_SEC_DIG_ID            (MT6685_REG_BASE + 0x601)
+#define MT6685_RTC_SEC_ANA_REV           (MT6685_REG_BASE + 0x602)
+#define MT6685_RTC_SEC_DIG_REV           (MT6685_REG_BASE + 0x603)
+#define MT6685_RTC_SEC_DBI               (MT6685_REG_BASE + 0x604)
+#define MT6685_RTC_SEC_ESP               (MT6685_REG_BASE + 0x605)
+#define MT6685_RTC_SEC_FPI               (MT6685_REG_BASE + 0x606)
+#define MT6685_RTC_SEC_DXI               (MT6685_REG_BASE + 0x607)
+#define MT6685_RTC_TC_SEC_SEC            (MT6685_REG_BASE + 0x608)
+#define MT6685_RTC_TC_MIN_SEC            (MT6685_REG_BASE + 0x60a)
+#define MT6685_RTC_TC_HOU_SEC            (MT6685_REG_BASE + 0x60c)
+#define MT6685_RTC_TC_DOM_SEC            (MT6685_REG_BASE + 0x60e)
+#define MT6685_RTC_TC_DOW_SEC            (MT6685_REG_BASE + 0x610)
+#define MT6685_RTC_TC_MTH_SEC            (MT6685_REG_BASE + 0x612)
+#define MT6685_RTC_TC_YEA_SEC            (MT6685_REG_BASE + 0x614)
+#define MT6685_RTC_SEC_CK_PDN            (MT6685_REG_BASE + 0x616)
+#define MT6685_RTC_SEC_WRTGR             (MT6685_REG_BASE + 0x618)
+#define MT6685_DCXO_DIG_MODE_CW0         (MT6685_REG_BASE + 0x789)
+/* mask is HEX;	shift is Integer */
+#define MT6685_RG_SRCLKEN_IN0_HW_MODE_ADDR                  \
+	MT6685_TOP_CON
+#define MT6685_RG_SRCLKEN_IN0_HW_MODE_MASK                  0x1
+#define MT6685_RG_SRCLKEN_IN0_HW_MODE_SHIFT                 1
+#define MT6685_RG_SRCLKEN_IN1_HW_MODE_ADDR                  \
+	MT6685_TOP_CON
+#define MT6685_RG_SRCLKEN_IN1_HW_MODE_MASK                  0x1
+#define MT6685_RG_FQMTR_32K_CK_PDN_ADDR                     \
+	MT6685_TOP_CKPDN_CON0
+#define MT6685_RG_FQMTR_32K_CK_PDN_MASK                     0x1
+#define MT6685_RG_FQMTR_32K_CK_PDN_SHIFT                    4
+	#define MT6685_RG_SRCLKEN_IN1_HW_MODE_SHIFT             2
+#define MT6685_RG_FQMTR_CK_PDN_ADDR                         \
+	MT6685_TOP_CKPDN_CON0
+#define MT6685_RG_FQMTR_CK_PDN_MASK                         0x1
+#define MT6685_RG_FQMTR_CK_PDN_SHIFT                        5
+#define MT6685_RG_INTRP_CK_PDN_ADDR                         \
+	MT6685_TOP_CKPDN_CON0
+#define MT6685_RG_INTRP_CK_PDN_MASK                         0x1
+#define MT6685_RG_INTRP_CK_PDN_SHIFT                        6
+#define MT6685_TOP_CKPDN_CON0_SET_ADDR                      \
+	MT6685_TOP_CKPDN_CON0_SET
+#define MT6685_TOP_CKPDN_CON0_SET_MASK                      0xFF
+#define MT6685_TOP_CKPDN_CON0_SET_SHIFT                     0
+#define MT6685_TOP_CKPDN_CON0_CLR_ADDR                      \
+	MT6685_TOP_CKPDN_CON0_CLR
+#define MT6685_TOP_CKPDN_CON0_CLR_MASK                      0xFF
+#define MT6685_TOP_CKPDN_CON0_CLR_SHIFT                     0
+#define MT6685_RG_FQMTR_CK_CKSEL_ADDR                       \
+	MT6685_TOP_CKSEL_CON0
+#define MT6685_RG_FQMTR_CK_CKSEL_MASK                       0x7
+#define MT6685_RG_FQMTR_CK_CKSEL_SHIFT                      0
+#define MT6685_RG_PMU32K_CK_CKSEL_ADDR                      \
+	MT6685_TOP_CKSEL_CON0
+#define MT6685_RG_PMU32K_CK_CKSEL_MASK                      0x1
+#define MT6685_RG_PMU32K_CK_CKSEL_SHIFT                     3
+#define MT6685_TOP_CKSEL_CON0_SET_ADDR                      \
+	MT6685_TOP_CKSEL_CON0_SET
+#define MT6685_TOP_CKSEL_CON0_SET_MASK                      0xFF
+#define MT6685_TOP_CKSEL_CON0_SET_SHIFT                     0
+#define MT6685_TOP_CKSEL_CON0_CLR_ADDR                      \
+	MT6685_TOP_CKSEL_CON0_CLR
+#define MT6685_TOP_CKSEL_CON0_CLR_MASK                      0xFF
+#define MT6685_TOP_CKSEL_CON0_CLR_SHIFT                     0
+#define MT6685_DIG_WPK_KEY_ADDR                             \
+	MT6685_TOP_DIG_WPK
+#define MT6685_DIG_WPK_KEY_MASK                             0xFF
+#define MT6685_DIG_WPK_KEY_SHIFT                            0
+#define MT6685_DIG_WPK_KEY_H_ADDR                           \
+	MT6685_TOP_DIG_WPK_H
+#define MT6685_DIG_WPK_KEY_H_MASK                           0xFF
+#define MT6685_DIG_WPK_KEY_H_SHIFT                          0
+#define MT6685_SCK_TOP_XTAL_SEL_ADDR                        \
+	MT6685_SCK_TOP_CON0_L
+#define MT6685_SCK_TOP_XTAL_SEL_MASK                        0x1
+#define MT6685_SCK_TOP_XTAL_SEL_SHIFT                       0
+#define MT6685_RG_RTC_SEC_MCLK_PDN_ADDR                     \
+	MT6685_SCK_TOP_CKPDN_CON0_L
+#define MT6685_RG_RTC_SEC_MCLK_PDN_MASK                     0x1
+#define MT6685_RG_RTC_SEC_MCLK_PDN_SHIFT                    0
+#define MT6685_RG_RTC_EOSC32_CK_PDN_ADDR                    \
+	MT6685_SCK_TOP_CKPDN_CON0_L
+#define MT6685_RG_RTC_EOSC32_CK_PDN_MASK                    0x1
+#define MT6685_RG_RTC_EOSC32_CK_PDN_SHIFT                   2
+#define MT6685_RG_RTC_SEC_32K_CK_PDN_ADDR                   \
+	MT6685_SCK_TOP_CKPDN_CON0_L
+#define MT6685_RG_RTC_SEC_32K_CK_PDN_MASK                   0x1
+#define MT6685_RG_RTC_SEC_32K_CK_PDN_SHIFT                  3
+#define MT6685_RG_RTC_MCLK_PDN_ADDR                         \
+	MT6685_SCK_TOP_CKPDN_CON0_L
+#define MT6685_RG_RTC_MCLK_PDN_MASK                         0x1
+#define MT6685_RG_RTC_MCLK_PDN_SHIFT                        4
+#define MT6685_RG_RTC_32K_CK_PDN_ADDR                       \
+	MT6685_SCK_TOP_CKPDN_CON0_L
+#define MT6685_RG_RTC_32K_CK_PDN_MASK                       0x1
+#define MT6685_RG_RTC_32K_CK_PDN_SHIFT                      5
+#define MT6685_SCK_TOP_CKPDN_CON0_L_SET_ADDR                \
+	MT6685_SCK_TOP_CKPDN_CON0_L_SET
+#define MT6685_SCK_TOP_CKPDN_CON0_L_SET_MASK                0xFF
+#define MT6685_SCK_TOP_CKPDN_CON0_L_SET_SHIFT               0
+#define MT6685_SCK_TOP_CKPDN_CON0_L_CLR_ADDR                \
+	MT6685_SCK_TOP_CKPDN_CON0_L_CLR
+#define MT6685_SCK_TOP_CKPDN_CON0_L_CLR_MASK                0xFF
+#define MT6685_SCK_TOP_CKPDN_CON0_L_CLR_SHIFT               0
+#define MT6685_RG_BANK_FQMTR_RST_ADDR                       \
+	MT6685_SCK_TOP_RST_CON0
+#define MT6685_RG_BANK_FQMTR_RST_MASK                       0x1
+#define MT6685_RG_BANK_FQMTR_RST_SHIFT                      6
+#define MT6685_RG_RTC_DIG_TEST_MODE_ADDR                    \
+	MT6685_RTC_DIG_CON0_H
+#define MT6685_RG_RTC_DIG_TEST_MODE_MASK                    0x1
+#define MT6685_RG_RTC_DIG_TEST_MODE_SHIFT                   7
+#define MT6685_FQMTR_TCKSEL_ADDR                            \
+	MT6685_FQMTR_CON0_L
+#define MT6685_FQMTR_TCKSEL_MASK                            0x7
+#define MT6685_FQMTR_TCKSEL_SHIFT                           0
+#define MT6685_FQMTR_BUSY_ADDR                              \
+	MT6685_FQMTR_CON0_L
+#define MT6685_FQMTR_BUSY_MASK                              0x1
+#define MT6685_FQMTR_BUSY_SHIFT                             3
+#define MT6685_FQMTR_DCXO26M_EN_ADDR                        \
+	MT6685_FQMTR_CON0_L
+#define MT6685_FQMTR_DCXO26M_EN_MASK                        0x1
+#define MT6685_FQMTR_DCXO26M_EN_SHIFT                       4
+#define MT6685_FQMTR_EN_ADDR                                \
+	MT6685_FQMTR_CON0_H
+#define MT6685_FQMTR_EN_MASK                                0x1
+#define MT6685_FQMTR_EN_SHIFT                               7
+#define MT6685_FQMTR_WINSET_L_ADDR                          \
+	MT6685_FQMTR_CON1_L
+#define MT6685_FQMTR_WINSET_L_MASK                          0xFF
+#define MT6685_FQMTR_WINSET_L_SHIFT                         0
+#define MT6685_FQMTR_WINSET_H_ADDR                          \
+	MT6685_FQMTR_CON1_H
+#define MT6685_FQMTR_WINSET_H_MASK                          0xFF
+#define MT6685_FQMTR_WINSET_H_SHIFT                         0
+#define MT6685_FQMTR_DATA_L_ADDR                            \
+	MT6685_FQMTR_CON2_L
+#define MT6685_FQMTR_DATA_L_MASK                            0xFF
+#define MT6685_FQMTR_DATA_L_SHIFT                           0
+#define MT6685_RG_RTC_32K1V8_0_SEL_ADDR                     \
+	MT6685_SCK_TOP_CKSEL_CON
+#define MT6685_RG_RTC_32K1V8_0_SEL_MASK                     0x3
+#define MT6685_RG_RTC_32K1V8_0_SEL_SHIFT                    0
+#define MT6685_SPAR_SW_RELOAD_ADDR                          \
+	MT6685_RTC_SPAR_RELOAD
+#define MT6685_SPAR_SW_RELOAD_MASK                          0x1
+#define MT6685_SPAR_SW_RELOAD_SHIFT                         0
+#define MT6685_RTC_ANA_ID_ADDR                              \
+	MT6685_RTC_ANA_ID
+#define MT6685_RTC_ANA_ID_MASK                              0xFF
+#define MT6685_RTC_ANA_ID_SHIFT                             0
+#define MT6685_RTC_DIG_ID_ADDR                              \
+	MT6685_RTC_DIG_ID
+#define MT6685_RTC_DIG_ID_MASK                              0xFF
+#define MT6685_RTC_DIG_ID_SHIFT                             0
+#define MT6685_RTC_ANA_MINOR_REV_ADDR                       \
+	MT6685_RTC_ANA_REV
+#define MT6685_RTC_ANA_MINOR_REV_MASK                       0xF
+#define MT6685_RTC_ANA_MINOR_REV_SHIFT                      0
+#define MT6685_RTC_ANA_MAJOR_REV_ADDR                       \
+	MT6685_RTC_ANA_REV
+#define MT6685_RTC_ANA_MAJOR_REV_MASK                       0xF
+#define MT6685_RTC_ANA_MAJOR_REV_SHIFT                      4
+#define MT6685_RTC_DIG_MINOR_REV_ADDR                       \
+	MT6685_RTC_DIG_REV
+#define MT6685_RTC_DIG_MINOR_REV_MASK                       0xF
+#define MT6685_RTC_DIG_MINOR_REV_SHIFT                      0
+#define MT6685_RTC_DIG_MAJOR_REV_ADDR                       \
+	MT6685_RTC_DIG_REV
+#define MT6685_RTC_DIG_MAJOR_REV_MASK                       0xF
+#define MT6685_RTC_DIG_MAJOR_REV_SHIFT                      4
+#define MT6685_RTC_CBS_ADDR                                 \
+	MT6685_RTC_DBI
+#define MT6685_RTC_CBS_MASK                                 0x3
+#define MT6685_RTC_CBS_SHIFT                                0
+#define MT6685_RTC_BIX_ADDR                                 \
+	MT6685_RTC_DBI
+#define MT6685_RTC_BIX_MASK                                 0x3
+#define MT6685_RTC_BIX_SHIFT                                2
+#define MT6685_RTC_ESP_ADDR                                 \
+	MT6685_RTC_ESP
+#define MT6685_RTC_ESP_MASK                                 0xFF
+#define MT6685_RTC_ESP_SHIFT                                0
+#define MT6685_RTC_FPI_ADDR                                 \
+	MT6685_RTC_FPI
+#define MT6685_RTC_FPI_MASK                                 0xFF
+#define MT6685_RTC_FPI_SHIFT                                0
+#define MT6685_RTC_DXI_ADDR                                 \
+	MT6685_RTC_DXI
+#define MT6685_RTC_DXI_MASK                                 0xFF
+#define MT6685_RTC_DXI_SHIFT                                0
+#define MT6685_BBPU_ADDR                                    \
+	MT6685_RTC_BBPU_L
+#define MT6685_BBPU_MASK                                    0xF
+#define MT6685_BBPU_SHIFT                                   0
+#define MT6685_CLRPKY_ADDR                                  \
+	MT6685_RTC_BBPU_L
+#define MT6685_CLRPKY_MASK                                  0x1
+#define MT6685_CLRPKY_SHIFT                                 4
+#define MT6685_RELOAD_ADDR                                  \
+	MT6685_RTC_BBPU_L
+#define MT6685_RELOAD_MASK                                  0x1
+#define MT6685_RELOAD_SHIFT                                 5
+#define MT6685_CBUSY_ADDR                                   \
+	MT6685_RTC_BBPU_L
+#define MT6685_CBUSY_MASK                                   0x1
+#define MT6685_CBUSY_SHIFT                                  6
+#define MT6685_ALARM_STATUS_ADDR                            \
+	MT6685_RTC_BBPU_L
+#define MT6685_ALARM_STATUS_MASK                            0x1
+#define MT6685_ALARM_STATUS_SHIFT                           7
+#define MT6685_KEY_BBPU_ADDR                                \
+	MT6685_RTC_BBPU_H
+#define MT6685_KEY_BBPU_MASK                                0xFF
+#define MT6685_KEY_BBPU_SHIFT                               0
+#define MT6685_ALSTA_ADDR                                   \
+	MT6685_RTC_IRQ_STA
+#define MT6685_ALSTA_MASK                                   0x1
+#define MT6685_ALSTA_SHIFT                                  0
+#define MT6685_TCSTA_ADDR                                   \
+	MT6685_RTC_IRQ_STA
+#define MT6685_TCSTA_MASK                                   0x1
+#define MT6685_TCSTA_SHIFT                                  1
+#define MT6685_LPSTA_ADDR                                   \
+	MT6685_RTC_IRQ_STA
+#define MT6685_LPSTA_MASK                                   0x1
+#define MT6685_LPSTA_SHIFT                                  3
+#define MT6685_AL_EN_ADDR                                   \
+	MT6685_RTC_IRQ_EN
+#define MT6685_AL_EN_MASK                                   0x1
+#define MT6685_AL_EN_SHIFT                                  0
+#define MT6685_TC_EN_ADDR                                   \
+	MT6685_RTC_IRQ_EN
+#define MT6685_TC_EN_MASK                                   0x1
+#define MT6685_TC_EN_SHIFT                                  1
+#define MT6685_ONESHOT_ADDR                                 \
+	MT6685_RTC_IRQ_EN
+#define MT6685_ONESHOT_MASK                                 0x1
+#define MT6685_ONESHOT_SHIFT                                2
+#define MT6685_LP_EN_ADDR                                   \
+	MT6685_RTC_IRQ_EN
+#define MT6685_LP_EN_MASK                                   0x1
+#define MT6685_LP_EN_SHIFT                                  3
+#define MT6685_SECCII_ADDR                                  \
+	MT6685_RTC_CII_EN_L
+#define MT6685_SECCII_MASK                                  0x1
+#define MT6685_SECCII_SHIFT                                 0
+#define MT6685_MINCII_ADDR                                  \
+	MT6685_RTC_CII_EN_L
+#define MT6685_MINCII_MASK                                  0x1
+#define MT6685_MINCII_SHIFT                                 1
+#define MT6685_HOUCII_ADDR                                  \
+	MT6685_RTC_CII_EN_L
+#define MT6685_HOUCII_MASK                                  0x1
+#define MT6685_HOUCII_SHIFT                                 2
+#define MT6685_DOMCII_ADDR                                  \
+	MT6685_RTC_CII_EN_L
+#define MT6685_DOMCII_MASK                                  0x1
+#define MT6685_DOMCII_SHIFT                                 3
+#define MT6685_DOWCII_ADDR                                  \
+	MT6685_RTC_CII_EN_L
+#define MT6685_DOWCII_MASK                                  0x1
+#define MT6685_DOWCII_SHIFT                                 4
+#define MT6685_MTHCII_ADDR                                  \
+	MT6685_RTC_CII_EN_L
+#define MT6685_MTHCII_MASK                                  0x1
+#define MT6685_MTHCII_SHIFT                                 5
+#define MT6685_YEACII_ADDR                                  \
+	MT6685_RTC_CII_EN_L
+#define MT6685_YEACII_MASK                                  0x1
+#define MT6685_YEACII_SHIFT                                 6
+#define MT6685_SECCII_1_2_ADDR                              \
+	MT6685_RTC_CII_EN_L
+#define MT6685_SECCII_1_2_MASK                              0x1
+#define MT6685_SECCII_1_2_SHIFT                             7
+#define MT6685_SECCII_1_4_ADDR                              \
+	MT6685_RTC_CII_EN_H
+#define MT6685_SECCII_1_4_MASK                              0x1
+#define MT6685_SECCII_1_4_SHIFT                             0
+#define MT6685_SECCII_1_8_ADDR                              \
+	MT6685_RTC_CII_EN_H
+#define MT6685_SECCII_1_8_MASK                              0x1
+#define MT6685_SECCII_1_8_SHIFT                             1
+#define MT6685_SEC_MSK_ADDR                                 \
+	MT6685_RTC_AL_MASK
+#define MT6685_SEC_MSK_MASK                                 0x1
+#define MT6685_SEC_MSK_SHIFT                                0
+#define MT6685_MIN_MSK_ADDR                                 \
+	MT6685_RTC_AL_MASK
+#define MT6685_MIN_MSK_MASK                                 0x1
+#define MT6685_MIN_MSK_SHIFT                                1
+#define MT6685_HOU_MSK_ADDR                                 \
+	MT6685_RTC_AL_MASK
+#define MT6685_HOU_MSK_MASK                                 0x1
+#define MT6685_HOU_MSK_SHIFT                                2
+#define MT6685_DOM_MSK_ADDR                                 \
+	MT6685_RTC_AL_MASK
+#define MT6685_DOM_MSK_MASK                                 0x1
+#define MT6685_DOM_MSK_SHIFT                                3
+#define MT6685_DOW_MSK_ADDR                                 \
+	MT6685_RTC_AL_MASK
+#define MT6685_DOW_MSK_MASK                                 0x1
+#define MT6685_DOW_MSK_SHIFT                                4
+#define MT6685_MTH_MSK_ADDR                                 \
+	MT6685_RTC_AL_MASK
+#define MT6685_MTH_MSK_MASK                                 0x1
+#define MT6685_MTH_MSK_SHIFT                                5
+#define MT6685_YEA_MSK_ADDR                                 \
+	MT6685_RTC_AL_MASK
+#define MT6685_YEA_MSK_MASK                                 0x1
+#define MT6685_YEA_MSK_SHIFT                                6
+#define MT6685_TC_SECOND_ADDR                               \
+	MT6685_RTC_TC_SEC
+#define MT6685_TC_SECOND_MASK                               0x3F
+#define MT6685_TC_SECOND_SHIFT                              0
+#define MT6685_TC_MINUTE_ADDR                               \
+	MT6685_RTC_TC_MIN
+#define MT6685_TC_MINUTE_MASK                               0x3F
+#define MT6685_TC_MINUTE_SHIFT                              0
+#define MT6685_TC_HOUR_ADDR                                 \
+	MT6685_RTC_TC_HOU
+#define MT6685_TC_HOUR_MASK                                 0x1F
+#define MT6685_TC_HOUR_SHIFT                                0
+#define MT6685_TC_DOM_ADDR                                  \
+	MT6685_RTC_TC_DOM
+#define MT6685_TC_DOM_MASK                                  0x1F
+#define MT6685_TC_DOM_SHIFT                                 0
+#define MT6685_TC_DOW_ADDR                                  \
+	MT6685_RTC_TC_DOW
+#define MT6685_TC_DOW_MASK                                  0x7
+#define MT6685_TC_DOW_SHIFT                                 0
+#define MT6685_TC_MONTH_ADDR                                \
+	MT6685_RTC_TC_MTH_L
+#define MT6685_TC_MONTH_MASK                                0xF
+#define MT6685_TC_MONTH_SHIFT                               0
+#define MT6685_RTC_MACRO_ID_L_ADDR                          \
+	MT6685_RTC_TC_MTH_L
+#define MT6685_RTC_MACRO_ID_L_MASK                          0xF
+#define MT6685_RTC_MACRO_ID_L_SHIFT                         4
+#define MT6685_RTC_MACRO_ID_H_ADDR                          \
+	MT6685_RTC_TC_MTH_H
+#define MT6685_RTC_MACRO_ID_H_MASK                          0xFF
+#define MT6685_RTC_MACRO_ID_H_SHIFT                         0
+#define MT6685_TC_YEAR_ADDR                                 \
+	MT6685_RTC_TC_YEA
+#define MT6685_TC_YEAR_MASK                                 0x7F
+#define MT6685_TC_YEAR_SHIFT                                0
+#define MT6685_AL_SECOND_ADDR                               \
+	MT6685_RTC_AL_SEC_L
+#define MT6685_AL_SECOND_MASK                               0x3F
+#define MT6685_AL_SECOND_SHIFT                              0
+#define MT6685_BBPU_AUTO_PDN_SEL_ADDR                       \
+	MT6685_RTC_AL_SEC_L
+#define MT6685_BBPU_AUTO_PDN_SEL_MASK                       0x1
+#define MT6685_BBPU_AUTO_PDN_SEL_SHIFT                      6
+#define MT6685_BBPU_2SEC_CK_SEL_ADDR                        \
+	MT6685_RTC_AL_SEC_L
+#define MT6685_BBPU_2SEC_CK_SEL_MASK                        0x1
+#define MT6685_BBPU_2SEC_CK_SEL_SHIFT                       7
+#define MT6685_BBPU_2SEC_EN_ADDR                            \
+	MT6685_RTC_AL_SEC_H
+#define MT6685_BBPU_2SEC_EN_MASK                            0x1
+#define MT6685_BBPU_2SEC_EN_SHIFT                           0
+#define MT6685_BBPU_2SEC_MODE_ADDR                          \
+	MT6685_RTC_AL_SEC_H
+#define MT6685_BBPU_2SEC_MODE_MASK                          0x3
+#define MT6685_BBPU_2SEC_MODE_SHIFT                         1
+#define MT6685_BBPU_2SEC_STAT_CLEAR_ADDR                    \
+	MT6685_RTC_AL_SEC_H
+#define MT6685_BBPU_2SEC_STAT_CLEAR_MASK                    0x1
+#define MT6685_BBPU_2SEC_STAT_CLEAR_SHIFT                   3
+#define MT6685_BBPU_2SEC_STAT_STA_ADDR                      \
+	MT6685_RTC_AL_SEC_H
+#define MT6685_BBPU_2SEC_STAT_STA_MASK                      0x1
+#define MT6685_BBPU_2SEC_STAT_STA_SHIFT                     4
+#define MT6685_RTC_LPD_OPT_ADDR                             \
+	MT6685_RTC_AL_SEC_H
+#define MT6685_RTC_LPD_OPT_MASK                             0x3
+#define MT6685_RTC_LPD_OPT_SHIFT                            5
+#define MT6685_K_EOSC32_VTCXO_ON_SEL_ADDR                   \
+	MT6685_RTC_AL_SEC_H
+#define MT6685_K_EOSC32_VTCXO_ON_SEL_MASK                   0x1
+#define MT6685_K_EOSC32_VTCXO_ON_SEL_SHIFT                  7
+#define MT6685_AL_MINUTE_ADDR                               \
+	MT6685_RTC_AL_MIN
+#define MT6685_AL_MINUTE_MASK                               0x3F
+#define MT6685_AL_MINUTE_SHIFT                              0
+#define MT6685_AL_HOUR_ADDR                                 \
+	MT6685_RTC_AL_HOU_L
+#define MT6685_AL_HOUR_MASK                                 0x1F
+#define MT6685_AL_HOUR_SHIFT                                0
+#define MT6685_NEW_SPARE0_ADDR                              \
+	MT6685_RTC_AL_HOU_H
+#define MT6685_NEW_SPARE0_MASK                              0xFF
+#define MT6685_NEW_SPARE0_SHIFT                             0
+#define MT6685_AL_DOM_ADDR                                  \
+	MT6685_RTC_AL_DOM_L
+#define MT6685_AL_DOM_MASK                                  0x1F
+#define MT6685_AL_DOM_SHIFT                                 0
+#define MT6685_NEW_SPARE1_ADDR                              \
+	MT6685_RTC_AL_DOM_H
+#define MT6685_NEW_SPARE1_MASK                              0xFF
+#define MT6685_NEW_SPARE1_SHIFT                             0
+#define MT6685_AL_DOW_ADDR                                  \
+	MT6685_RTC_AL_DOW_L
+#define MT6685_AL_DOW_MASK                                  0x7
+#define MT6685_AL_DOW_SHIFT                                 0
+#define MT6685_RG_EOSC_CALI_TD_ADDR                         \
+	MT6685_RTC_AL_DOW_L
+#define MT6685_RG_EOSC_CALI_TD_MASK                         0x7
+#define MT6685_RG_EOSC_CALI_TD_SHIFT                        5
+#define MT6685_NEW_SPARE2_ADDR                              \
+	MT6685_RTC_AL_DOW_H
+#define MT6685_NEW_SPARE2_MASK                              0xFF
+#define MT6685_NEW_SPARE2_SHIFT                             0
+#define MT6685_AL_MONTH_ADDR                                \
+	MT6685_RTC_AL_MTH_L
+#define MT6685_AL_MONTH_MASK                                0xF
+#define MT6685_AL_MONTH_SHIFT                               0
+#define MT6685_NEW_SPARE3_ADDR                              \
+	MT6685_RTC_AL_MTH_H
+#define MT6685_NEW_SPARE3_MASK                              0xFF
+#define MT6685_NEW_SPARE3_SHIFT                             0
+#define MT6685_AL_YEAR_ADDR                                 \
+	MT6685_RTC_AL_YEA_L
+#define MT6685_AL_YEAR_MASK                                 0x7F
+#define MT6685_AL_YEAR_SHIFT                                0
+#define MT6685_RTC_K_EOSC_RSV_ADDR                          \
+	MT6685_RTC_AL_YEA_H
+#define MT6685_RTC_K_EOSC_RSV_MASK                          0xFF
+#define MT6685_RTC_K_EOSC_RSV_SHIFT                         0
+#define MT6685_XOSCCALI_ADDR                                \
+	MT6685_RTC_OSC32CON_L
+#define MT6685_XOSCCALI_MASK                                0x1F
+#define MT6685_XOSCCALI_SHIFT                               0
+#define MT6685_RTC_XOSC32_ENB_ADDR                          \
+	MT6685_RTC_OSC32CON_L
+#define MT6685_RTC_XOSC32_ENB_MASK                          0x1
+#define MT6685_RTC_XOSC32_ENB_SHIFT                         5
+#define MT6685_RTC_EMBCK_SEL_MODE_ADDR                      \
+	MT6685_RTC_OSC32CON_L
+#define MT6685_RTC_EMBCK_SEL_MODE_MASK                      0x3
+#define MT6685_RTC_EMBCK_SEL_MODE_SHIFT                     6
+#define MT6685_RTC_EMBCK_SRC_SEL_ADDR                       \
+	MT6685_RTC_OSC32CON_H
+#define MT6685_RTC_EMBCK_SRC_SEL_MASK                       0x1
+#define MT6685_RTC_EMBCK_SRC_SEL_SHIFT                      0
+#define MT6685_RTC_EMBCK_SEL_OPTION_ADDR                    \
+	MT6685_RTC_OSC32CON_H
+#define MT6685_RTC_EMBCK_SEL_OPTION_MASK                    0x1
+#define MT6685_RTC_EMBCK_SEL_OPTION_SHIFT                   1
+#define MT6685_RTC_GPS_CKOUT_EN_ADDR                        \
+	MT6685_RTC_OSC32CON_H
+#define MT6685_RTC_GPS_CKOUT_EN_MASK                        0x1
+#define MT6685_RTC_GPS_CKOUT_EN_SHIFT                       2
+#define MT6685_RTC_EOSC32_VCT_EN_ADDR                       \
+	MT6685_RTC_OSC32CON_H
+#define MT6685_RTC_EOSC32_VCT_EN_MASK                       0x1
+#define MT6685_RTC_EOSC32_VCT_EN_SHIFT                      3
+#define MT6685_RTC_EOSC32_CHOP_EN_ADDR                      \
+	MT6685_RTC_OSC32CON_H
+#define MT6685_RTC_EOSC32_CHOP_EN_MASK                      0x1
+#define MT6685_RTC_EOSC32_CHOP_EN_SHIFT                     4
+#define MT6685_RTC_GP_OSC32_CON_ADDR                        \
+	MT6685_RTC_OSC32CON_H
+#define MT6685_RTC_GP_OSC32_CON_MASK                        0x3
+#define MT6685_RTC_GP_OSC32_CON_SHIFT                       5
+#define MT6685_RTC_REG_XOSC32_ENB_ADDR                      \
+	MT6685_RTC_OSC32CON_H
+#define MT6685_RTC_REG_XOSC32_ENB_MASK                      0x1
+#define MT6685_RTC_REG_XOSC32_ENB_SHIFT                     7
+#define MT6685_RTC_POWERKEY1_L_ADDR                         \
+	MT6685_RTC_POWERKEY1_L
+#define MT6685_RTC_POWERKEY1_L_MASK                         0xFF
+#define MT6685_RTC_POWERKEY1_L_SHIFT                        0
+#define MT6685_RTC_POWERKEY1_H_ADDR                         \
+	MT6685_RTC_POWERKEY1_H
+#define MT6685_RTC_POWERKEY1_H_MASK                         0xFF
+#define MT6685_RTC_POWERKEY1_H_SHIFT                        0
+#define MT6685_RTC_POWERKEY2_L_ADDR                         \
+	MT6685_RTC_POWERKEY2_L
+#define MT6685_RTC_POWERKEY2_L_MASK                         0xFF
+#define MT6685_RTC_POWERKEY2_L_SHIFT                        0
+#define MT6685_RTC_POWERKEY2_H_ADDR                         \
+	MT6685_RTC_POWERKEY2_H
+#define MT6685_RTC_POWERKEY2_H_MASK                         0xFF
+#define MT6685_RTC_POWERKEY2_H_SHIFT                        0
+#define MT6685_RTC_PDN1_L_ADDR                              \
+	MT6685_RTC_PDN1_L
+#define MT6685_RTC_PDN1_L_MASK                              0xFF
+#define MT6685_RTC_PDN1_L_SHIFT                             0
+#define MT6685_RTC_PDN1_H_ADDR                              \
+	MT6685_RTC_PDN1_H
+#define MT6685_RTC_PDN1_H_MASK                              0xFF
+#define MT6685_RTC_PDN1_H_SHIFT                             0
+#define MT6685_RTC_PDN2_L_ADDR                              \
+	MT6685_RTC_PDN2_L
+#define MT6685_RTC_PDN2_L_MASK                              0xFF
+#define MT6685_RTC_PDN2_L_SHIFT                             0
+#define MT6685_RTC_PDN2_H_ADDR                              \
+	MT6685_RTC_PDN2_H
+#define MT6685_RTC_PDN2_H_MASK                              0xFF
+#define MT6685_RTC_PDN2_H_SHIFT                             0
+#define MT6685_RTC_SPAR0_L_ADDR                             \
+	MT6685_RTC_SPAR0_L
+#define MT6685_RTC_SPAR0_L_MASK                             0xFF
+#define MT6685_RTC_SPAR0_L_SHIFT                            0
+#define MT6685_RTC_SPAR0_H_ADDR                             \
+	MT6685_RTC_SPAR0_H
+#define MT6685_RTC_SPAR0_H_MASK                             0xFF
+#define MT6685_RTC_SPAR0_H_SHIFT                            0
+#define MT6685_RTC_SPAR1_L_ADDR                             \
+	MT6685_RTC_SPAR1_L
+#define MT6685_RTC_SPAR1_L_MASK                             0xFF
+#define MT6685_RTC_SPAR1_L_SHIFT                            0
+#define MT6685_RTC_SPAR1_H_ADDR                             \
+	MT6685_RTC_SPAR1_H
+#define MT6685_RTC_SPAR1_H_MASK                             0xFF
+#define MT6685_RTC_SPAR1_H_SHIFT                            0
+#define MT6685_RTC_PROT_L_ADDR                              \
+	MT6685_RTC_PROT_L
+#define MT6685_RTC_PROT_L_MASK                              0xFF
+#define MT6685_RTC_PROT_L_SHIFT                             0
+#define MT6685_RTC_PROT_H_ADDR                              \
+	MT6685_RTC_PROT_H
+#define MT6685_RTC_PROT_H_MASK                              0xFF
+#define MT6685_RTC_PROT_H_SHIFT                             0
+#define MT6685_RTC_DIFF_L_ADDR                              \
+	MT6685_RTC_DIFF_L
+#define MT6685_RTC_DIFF_L_MASK                              0xFF
+#define MT6685_RTC_DIFF_L_SHIFT                             0
+#define MT6685_RTC_DIFF_H_ADDR                              \
+	MT6685_RTC_DIFF_H
+#define MT6685_RTC_DIFF_H_MASK                              0xF
+#define MT6685_RTC_DIFF_H_SHIFT                             0
+#define MT6685_POWER_DETECTED_ADDR                          \
+	MT6685_RTC_DIFF_H
+#define MT6685_POWER_DETECTED_MASK                          0x1
+#define MT6685_POWER_DETECTED_SHIFT                         4
+#define MT6685_K_EOSC32_RSV_ADDR                            \
+	MT6685_RTC_DIFF_H
+#define MT6685_K_EOSC32_RSV_MASK                            0x1
+#define MT6685_K_EOSC32_RSV_SHIFT                           6
+#define MT6685_CALI_RD_SEL_ADDR                             \
+	MT6685_RTC_DIFF_H
+#define MT6685_CALI_RD_SEL_MASK                             0x1
+#define MT6685_CALI_RD_SEL_SHIFT                            7
+#define MT6685_RTC_CALI_L_ADDR                              \
+	MT6685_RTC_CALI_L
+#define MT6685_RTC_CALI_L_MASK                              0xFF
+#define MT6685_RTC_CALI_L_SHIFT                             0
+#define MT6685_RTC_CALI_H_ADDR                              \
+	MT6685_RTC_CALI_H
+#define MT6685_RTC_CALI_H_MASK                              0x3F
+#define MT6685_RTC_CALI_H_SHIFT                             0
+#define MT6685_CALI_WR_SEL_ADDR                             \
+	MT6685_RTC_CALI_H
+#define MT6685_CALI_WR_SEL_MASK                             0x1
+#define MT6685_CALI_WR_SEL_SHIFT                            6
+#define MT6685_K_EOSC32_OVERFLOW_ADDR                       \
+	MT6685_RTC_CALI_H
+#define MT6685_K_EOSC32_OVERFLOW_MASK                       0x1
+#define MT6685_K_EOSC32_OVERFLOW_SHIFT                      7
+#define MT6685_WRTGR_ADDR                                   \
+	MT6685_RTC_WRTGR
+#define MT6685_WRTGR_MASK                                   0x1
+#define MT6685_WRTGR_SHIFT                                  0
+#define MT6685_VBAT_LPSTA_RAW_ADDR                          \
+	MT6685_RTC_CON_L
+#define MT6685_VBAT_LPSTA_RAW_MASK                          0x1
+#define MT6685_VBAT_LPSTA_RAW_SHIFT                         0
+#define MT6685_EOSC32_LPEN_ADDR                             \
+	MT6685_RTC_CON_L
+#define MT6685_EOSC32_LPEN_MASK                             0x1
+#define MT6685_EOSC32_LPEN_SHIFT                            1
+#define MT6685_XOSC32_LPEN_ADDR                             \
+	MT6685_RTC_CON_L
+#define MT6685_XOSC32_LPEN_MASK                             0x1
+#define MT6685_XOSC32_LPEN_SHIFT                            2
+#define MT6685_LPRST_ADDR                                   \
+	MT6685_RTC_CON_L
+#define MT6685_LPRST_MASK                                   0x1
+#define MT6685_LPRST_SHIFT                                  3
+#define MT6685_CDBO_ADDR                                    \
+	MT6685_RTC_CON_L
+#define MT6685_CDBO_MASK                                    0x1
+#define MT6685_CDBO_SHIFT                                   4
+#define MT6685_F32KOB_ADDR                                  \
+	MT6685_RTC_CON_L
+#define MT6685_F32KOB_MASK                                  0x1
+#define MT6685_F32KOB_SHIFT                                 5
+#define MT6685_GPO_ADDR                                     \
+	MT6685_RTC_CON_L
+#define MT6685_GPO_MASK                                     0x1
+#define MT6685_GPO_SHIFT                                    6
+#define MT6685_GOE_ADDR                                     \
+	MT6685_RTC_CON_L
+#define MT6685_GOE_MASK                                     0x1
+#define MT6685_GOE_SHIFT                                    7
+#define MT6685_GSR_ADDR                                     \
+	MT6685_RTC_CON_H
+#define MT6685_GSR_MASK                                     0x1
+#define MT6685_GSR_SHIFT                                    0
+#define MT6685_GSMT_ADDR                                    \
+	MT6685_RTC_CON_H
+#define MT6685_GSMT_MASK                                    0x1
+#define MT6685_GSMT_SHIFT                                   1
+#define MT6685_GPEN_ADDR                                    \
+	MT6685_RTC_CON_H
+#define MT6685_GPEN_MASK                                    0x1
+#define MT6685_GPEN_SHIFT                                   2
+#define MT6685_GPU_ADDR                                     \
+	MT6685_RTC_CON_H
+#define MT6685_GPU_MASK                                     0x1
+#define MT6685_GPU_SHIFT                                    3
+#define MT6685_GE4_ADDR                                     \
+	MT6685_RTC_CON_H
+#define MT6685_GE4_MASK                                     0x1
+#define MT6685_GE4_SHIFT                                    4
+#define MT6685_GE8_ADDR                                     \
+	MT6685_RTC_CON_H
+#define MT6685_GE8_MASK                                     0x1
+#define MT6685_GE8_SHIFT                                    5
+#define MT6685_GPI_ADDR                                     \
+	MT6685_RTC_CON_H
+#define MT6685_GPI_MASK                                     0x1
+#define MT6685_GPI_SHIFT                                    6
+#define MT6685_LPSTA_RAW_ADDR                               \
+	MT6685_RTC_CON_H
+#define MT6685_LPSTA_RAW_MASK                               0x1
+#define MT6685_LPSTA_RAW_SHIFT                              7
+#define MT6685_DAT0_LOCK_ADDR                               \
+	MT6685_RTC_SEC_CTRL
+#define MT6685_DAT0_LOCK_MASK                               0x1
+#define MT6685_DAT0_LOCK_SHIFT                              0
+#define MT6685_DAT1_LOCK_ADDR                               \
+	MT6685_RTC_SEC_CTRL
+#define MT6685_DAT1_LOCK_MASK                               0x1
+#define MT6685_DAT1_LOCK_SHIFT                              1
+#define MT6685_DAT2_LOCK_ADDR                               \
+	MT6685_RTC_SEC_CTRL
+#define MT6685_DAT2_LOCK_MASK                               0x1
+#define MT6685_DAT2_LOCK_SHIFT                              2
+#define MT6685_RTC_INT_CNT_L_ADDR                           \
+	MT6685_RTC_INT_CNT_L
+#define MT6685_RTC_INT_CNT_L_MASK                           0xFF
+#define MT6685_RTC_INT_CNT_L_SHIFT                          0
+#define MT6685_RTC_INT_CNT_H_ADDR                           \
+	MT6685_RTC_INT_CNT_H
+#define MT6685_RTC_INT_CNT_H_MASK                           0x7F
+#define MT6685_RTC_INT_CNT_H_SHIFT                          0
+#define MT6685_RTC_SEC_DAT0_L_ADDR                          \
+	MT6685_RTC_SEC_DAT0_L
+#define MT6685_RTC_SEC_DAT0_L_MASK                          0xFF
+#define MT6685_RTC_SEC_DAT0_L_SHIFT                         0
+#define MT6685_RTC_SEC_DAT0_H_ADDR                          \
+	MT6685_RTC_SEC_DAT0_H
+#define MT6685_RTC_SEC_DAT0_H_MASK                          0xFF
+#define MT6685_RTC_SEC_DAT0_H_SHIFT                         0
+#define MT6685_RTC_SEC_DAT1_L_ADDR                          \
+	MT6685_RTC_SEC_DAT1_L
+#define MT6685_RTC_SEC_DAT1_L_MASK                          0xFF
+#define MT6685_RTC_SEC_DAT1_L_SHIFT                         0
+#define MT6685_RTC_SEC_DAT1_H_ADDR                          \
+	MT6685_RTC_SEC_DAT1_H
+#define MT6685_RTC_SEC_DAT1_H_MASK                          0xFF
+#define MT6685_RTC_SEC_DAT1_H_SHIFT                         0
+#define MT6685_RTC_SEC_DAT2_L_ADDR                          \
+	MT6685_RTC_SEC_DAT2_L
+#define MT6685_RTC_SEC_DAT2_L_MASK                          0xFF
+#define MT6685_RTC_SEC_DAT2_L_SHIFT                         0
+#define MT6685_RTC_SEC_DAT2_H_ADDR                          \
+	MT6685_RTC_SEC_DAT2_H
+#define MT6685_RTC_SEC_DAT2_H_MASK                          0xFF
+#define MT6685_RTC_SEC_DAT2_H_SHIFT                         0
+#define MT6685_RTC_RG_FG0_ADDR                              \
+	MT6685_RTC_RG_FG0
+#define MT6685_RTC_RG_FG0_MASK                              0xFF
+#define MT6685_RTC_RG_FG0_SHIFT                             0
+#define MT6685_RTC_RG_FG1_ADDR                              \
+	MT6685_RTC_RG_FG1
+#define MT6685_RTC_RG_FG1_MASK                              0xFF
+#define MT6685_RTC_RG_FG1_SHIFT                             0
+#define MT6685_RTC_RG_FG2_ADDR                              \
+	MT6685_RTC_RG_FG2
+#define MT6685_RTC_RG_FG2_MASK                              0xFF
+#define MT6685_RTC_RG_FG2_SHIFT                             0
+#define MT6685_RTC_RG_FG3_ADDR                              \
+	MT6685_RTC_RG_FG3
+#define MT6685_RTC_RG_FG3_MASK                              0xFF
+#define MT6685_RTC_RG_FG3_SHIFT                             0
+#define MT6685_RTC_UVLO_WAIT_ADDR                           \
+	MT6685_RTC_SPAR_MACRO
+#define MT6685_RTC_UVLO_WAIT_MASK                           0x3
+#define MT6685_RTC_UVLO_WAIT_SHIFT                          0
+#define MT6685_RTC_SPAR_THRE_SEL_ADDR                       \
+	MT6685_RTC_SPAR_MACRO
+#define MT6685_RTC_SPAR_THRE_SEL_MASK                       0x1
+#define MT6685_RTC_SPAR_THRE_SEL_SHIFT                      2
+#define MT6685_RTC_SPAR_PWRKEY_MATCH_LPD_ADDR               \
+	MT6685_RTC_SPAR_MACRO
+#define MT6685_RTC_SPAR_PWRKEY_MATCH_LPD_MASK               0x1
+#define MT6685_RTC_SPAR_PWRKEY_MATCH_LPD_SHIFT              4
+#define MT6685_RTC_SPAR_PWRKEY_MATCH_ADDR                   \
+	MT6685_RTC_SPAR_MACRO
+#define MT6685_RTC_SPAR_PWRKEY_MATCH_MASK                   0x1
+#define MT6685_RTC_SPAR_PWRKEY_MATCH_SHIFT                  5
+#define MT6685_SPAR_PROT_STAT_ADDR                          \
+	MT6685_RTC_SPAR_MACRO
+#define MT6685_RTC_SPAR_PROT_STAT_MASK                      0x3
+#define MT6685_RTC_SPAR_PROT_STAT_SHIFT                     6
+#define MT6685_RTC_SPAR_CORE_ADDR                           \
+	MT6685_RTC_SPAR_CORE
+#define MT6685_RTC_SPAR_CORE_MASK                           0xFF
+#define MT6685_RTC_SPAR_CORE_SHIFT                          0
+#define MT6685_RTC_RG_EOSC_CALI_ADDR                        \
+	MT6685_RTC_EOSC_CALI
+#define MT6685_RTC_RG_EOSC_CALI_MASK                        0x1F
+#define MT6685_RTC_RG_EOSC_CALI_SHIFT                       0
+#define MT6685_RTC_SEC_ANA_ID_ADDR                          \
+	MT6685_RTC_SEC_ANA_ID
+#define MT6685_RTC_SEC_ANA_ID_MASK                          0xFF
+#define MT6685_RTC_SEC_ANA_ID_SHIFT                         0
+#define MT6685_RTC_SEC_DIG_ID_ADDR                          \
+	MT6685_RTC_SEC_DIG_ID
+#define MT6685_RTC_SEC_DIG_ID_MASK                          0xFF
+#define MT6685_RTC_SEC_DIG_ID_SHIFT                         0
+#define MT6685_RTC_SEC_ANA_MINOR_REV_ADDR                   \
+	MT6685_RTC_SEC_ANA_REV
+#define MT6685_RTC_SEC_ANA_MINOR_REV_MASK                   0xF
+#define MT6685_RTC_SEC_ANA_MINOR_REV_SHIFT                  0
+#define MT6685_RTC_SEC_ANA_MAJOR_REV_ADDR                   \
+	MT6685_RTC_SEC_ANA_REV
+#define MT6685_RTC_SEC_ANA_MAJOR_REV_MASK                   0xF
+#define MT6685_RTC_SEC_ANA_MAJOR_REV_SHIFT                  4
+#define MT6685_RTC_SEC_DIG_MINOR_REV_ADDR                   \
+	MT6685_RTC_SEC_DIG_REV
+#define MT6685_RTC_SEC_DIG_MINOR_REV_MASK                   0xF
+#define MT6685_RTC_SEC_DIG_MINOR_REV_SHIFT                  0
+#define MT6685_RTC_SEC_DIG_MAJOR_REV_ADDR                   \
+	MT6685_RTC_SEC_DIG_REV
+#define MT6685_RTC_SEC_DIG_MAJOR_REV_MASK                   0xF
+#define MT6685_RTC_SEC_DIG_MAJOR_REV_SHIFT                  4
+#define MT6685_RTC_SEC_CBS_ADDR                             \
+	MT6685_RTC_SEC_DBI
+#define MT6685_RTC_SEC_CBS_MASK                             0x3
+#define MT6685_RTC_SEC_CBS_SHIFT                            0
+#define MT6685_RTC_SEC_BIX_ADDR                             \
+	MT6685_RTC_SEC_DBI
+#define MT6685_RTC_SEC_BIX_MASK                             0x3
+#define MT6685_RTC_SEC_BIX_SHIFT                            2
+#define MT6685_RTC_SEC_ESP_ADDR                             \
+	MT6685_RTC_SEC_ESP
+#define MT6685_RTC_SEC_ESP_MASK                             0xFF
+#define MT6685_RTC_SEC_ESP_SHIFT                            0
+#define MT6685_RTC_SEC_FPI_ADDR                             \
+	MT6685_RTC_SEC_FPI
+#define MT6685_RTC_SEC_FPI_MASK                             0xFF
+#define MT6685_RTC_SEC_FPI_SHIFT                            0
+#define MT6685_RTC_SEC_DXI_ADDR                             \
+	MT6685_RTC_SEC_DXI
+#define MT6685_RTC_SEC_DXI_MASK                             0xFF
+#define MT6685_RTC_SEC_DXI_SHIFT                            0
+#define MT6685_TC_SECOND_SEC_ADDR                           \
+	MT6685_RTC_TC_SEC_SEC
+#define MT6685_TC_SECOND_SEC_MASK                           0x3F
+#define MT6685_TC_SECOND_SEC_SHIFT                          0
+#define MT6685_TC_MINUTE_SEC_ADDR                           \
+	MT6685_RTC_TC_MIN_SEC
+#define MT6685_TC_MINUTE_SEC_MASK                           0x3F
+#define MT6685_TC_MINUTE_SEC_SHIFT                          0
+#define MT6685_TC_HOUR_SEC_ADDR                             \
+	MT6685_RTC_TC_HOU_SEC
+#define MT6685_TC_HOUR_SEC_MASK                             0x1F
+#define MT6685_TC_HOUR_SEC_SHIFT                            0
+#define MT6685_TC_DOM_SEC_ADDR                              \
+	MT6685_RTC_TC_DOM_SEC
+#define MT6685_TC_DOM_SEC_MASK                              0x1F
+#define MT6685_TC_DOM_SEC_SHIFT                             0
+#define MT6685_TC_DOW_SEC_ADDR                              \
+	MT6685_RTC_TC_DOW_SEC
+#define MT6685_TC_DOW_SEC_MASK                              0x7
+#define MT6685_TC_DOW_SEC_SHIFT                             0
+#define MT6685_TC_MONTH_SEC_ADDR                            \
+	MT6685_RTC_TC_MTH_SEC
+#define MT6685_TC_MONTH_SEC_MASK                            0xF
+#define MT6685_TC_MONTH_SEC_SHIFT                           0
+#define MT6685_TC_YEAR_SEC_ADDR                             \
+	MT6685_RTC_TC_YEA_SEC
+#define MT6685_TC_YEAR_SEC_MASK                             0x7F
+#define MT6685_TC_YEAR_SEC_SHIFT                            0
+#define MT6685_RTC_SEC_CK_PDN_ADDR                          \
+	MT6685_RTC_SEC_CK_PDN
+#define MT6685_RTC_SEC_CK_PDN_MASK                          0x1
+#define MT6685_RTC_SEC_CK_PDN_SHIFT                         0
+#define MT6685_RTC_SEC_WRTGR_ADDR                           \
+	MT6685_RTC_SEC_WRTGR
+#define MT6685_RTC_SEC_WRTGR_MASK                           0x1
+#define MT6685_RTC_SEC_WRTGR_SHIFT                          0
+#define MT6685_XO_EN32K_MAN_ADDR                            \
+	MT6685_DCXO_DIG_MODE_CW0
+#define MT6685_XO_EN32K_MAN_MASK                            0x1
+#define MT6685_XO_EN32K_MAN_SHIFT                           1
+#define MT6685_RG_INT_EN_RTC_ADDR                           \
+	MT6685_SCK_TOP_INT_CON0
+#define MT6685_RG_INT_EN_RTC_MASK                           0x1
+#define MT6685_RG_INT_EN_RTC_SHIFT                          0
+
+#endif		/* _MT6685_HW_H_ */
diff --git a/include/linux/mfd/mt6685/rtc.h b/include/linux/mfd/mt6685/rtc.h
new file mode 100644
index 000000000000..cb5b62a717d5
--- /dev/null
+++ b/include/linux/mfd/mt6685/rtc.h
@@ -0,0 +1,318 @@ 
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2021 MediaTek Inc.
+ */
+
+#ifndef __MT6685_RTC_H__
+#define __MT6685_RTC_H__
+
+#include <linux/mfd/mt6685/registers.h>
+
+/*features*/
+#define SUPPORT_PWR_OFF_ALARM
+
+#define HWID                    MT6685_HWCID_L
+
+/* we map HW YEA 0 (2000) to 1968 not 1970 because 2000 is the leap year */
+#define RTC_MIN_YEAR            1968
+#define RTC_BASE_YEAR           1900
+#define RTC_NUM_YEARS           128
+#define RTC_MIN_YEAR_OFFSET     (RTC_MIN_YEAR - RTC_BASE_YEAR)
+
+#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
+/* 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 DCXO_ANA_ID                     0x200
+
+#define RTC_BBPU                        0x8
+#define RTC_WRTGR_MT6685                0x42
+#define RTC_IRQ_STA                     0xa
+#define RTC_IRQ_EN                      0xc
+#define RTC_AL_MASK                     0x10
+
+#define RTC_AL_SEC                      0x20
+#define RTC_AL_MIN                      0x22
+#define RTC_AL_HOU                      0x24
+#define RTC_AL_HOU_H                    0x25
+#define RTC_AL_DOM                      0x26
+#define RTC_AL_DOW                      0x28
+#define RTC_AL_DOW_H                    0x29
+#define RTC_AL_MTH                      0x2a
+#define RTC_AL_MTH_H                    0x2b
+#define RTC_AL_YEA                      0x2c
+#define RTC_AL_YEA_H                    0x2d
+#define RTC_OSC32CON                    0x2e
+#define RTC_POWERKEY1                   0x30
+#define RTC_POWERKEY2                   0x32
+#define RTC_PDN1                        0x34
+#define RTC_PDN1_H                      0x35
+#define RTC_PDN2                        0x36
+#define RTC_SPAR0                       0x38
+#define RTC_SPAR1                       0x3a
+#define RTC_PROT                        0x3c
+#define RTC_WRTGR                       0x42
+#define RTC_CON                         0x44
+#define RTC_INT_CNT_L                   0x48
+#define RTC_SPAR_MACRO                  0x58
+
+#define RTC_TC_SEC_MASK                 0x3f
+#define RTC_TC_MIN_MASK                 0x3f
+#define RTC_TC_HOU_MASK                 0x1f
+#define RTC_TC_DOM_MASK                 0x1f
+#define RTC_TC_DOW_MASK                 0x7
+#define RTC_TC_MTH_MASK                 0xf
+#define RTC_TC_YEA_MASK                 0x7f
+
+#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_YEA                   RTC_PDN2
+#define RTC_PWRON_MTH                   RTC_PDN2
+#define RTC_PWRON_SEC                   RTC_SPAR0
+#define RTC_PWRON_MIN                   RTC_SPAR1
+#define RTC_PWRON_HOU                   RTC_SPAR1
+#define RTC_PWRON_DOM                   RTC_SPAR1
+
+#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_PWRON_SEC_MASK              (RTC_AL_SEC_MASK << RTC_PWRON_SEC_SHIFT)
+#define RTC_PWRON_MIN_MASK              (RTC_AL_MIN_MASK << RTC_PWRON_MIN_SHIFT)
+#define RTC_PWRON_HOU_MASK              (RTC_AL_HOU_MASK << RTC_PWRON_HOU_SHIFT)
+#define RTC_PWRON_DOM_MASK              (RTC_AL_DOM_MASK << RTC_PWRON_DOM_SHIFT)
+#define RTC_PWRON_MTH_MASK              (RTC_AL_MTH_MASK << RTC_PWRON_MTH_SHIFT)
+#define RTC_PWRON_YEA_MASK              (RTC_AL_YEA_MASK << RTC_PWRON_YEA_SHIFT)
+
+#define RTC_BBPU_KEY                    0x4300
+#define RTC_BBPU_CBUSY                  BIT(6)
+#define RTC_BBPU_RELOAD                 BIT(5)
+#define RTC_BBPU_AUTO                   BIT(3)
+#define RTC_BBPU_CLR                    BIT(1)
+#define RTC_BBPU_PWREN                  BIT(0)
+#define RTC_BBPU_AL_STA                 BIT(7)
+#define RTC_BBPU_RESET_AL               BIT(3)
+#define RTC_BBPU_RESET_SPAR             BIT(2)
+
+#define RTC_AL_MASK_DOW                 BIT(4)
+
+#define RTC_IRQ_EN_LP                   BIT(3)
+#define RTC_IRQ_EN_ONESHOT              BIT(2)
+#define RTC_IRQ_EN_AL                   BIT(0)
+#define RTC_IRQ_EN_ONESHOT_AL           (RTC_IRQ_EN_ONESHOT | RTC_IRQ_EN_AL)
+
+#define RTC_IRQ_STA_LP                  BIT(3)
+#define RTC_IRQ_STA_AL                  BIT(0)
+
+#define RTC_PDN1_PWRON_TIME             BIT(7)
+#define RTC_PDN2_PWRON_LOGO             BIT(15)
+#define RTC_PDN2_PWRON_ALARM            BIT(4)
+
+#define RTC_RG_FG2                      0x54
+#define RTC_RG_FG3                      0x56
+
+#define EOSC_CALI_TD_MT6685				0x29
+#define EOSC_CALI_TD_MASK               0x3
+
+#define HWID_MT6685				        0x8
+
+#define TOP_RTC_EOSC32_CK_PDN           MT6685_SCK_TOP_CKPDN_CON0_L
+#define TOP_RTC_EOSC32_CK_PDN_MASK      (MT6685_RG_RTC_EOSC32_CK_PDN_MASK \
+						<< MT6685_RG_RTC_EOSC32_CK_PDN_SHIFT)
+
+#define TOP_DIG_WPK                     MT6685_TOP_DIG_WPK
+#define DIG_WPK_KEY_MASK        (MT6685_DIG_WPK_KEY_MASK << MT6685_DIG_WPK_KEY_SHIFT)
+
+#define TOP_DIG_WPK_H                   MT6685_TOP_DIG_WPK_H
+#define DIG_WPK_KEY_H_MASK      (MT6685_DIG_WPK_KEY_H_MASK << MT6685_DIG_WPK_KEY_H_SHIFT)
+
+#define RG_RTC_MCLK_PDN                 MT6685_SCK_TOP_CKPDN_CON0_L
+#define RG_RTC_MCLK_PDN_STA_MASK        MT6685_RG_RTC_MCLK_PDN_MASK
+#define RG_RTC_MCLK_PDN_STA_SHIFT       MT6685_RG_RTC_MCLK_PDN_SHIFT
+
+#define RG_RTC_MCLK_PDN_SET             MT6685_SCK_TOP_CKPDN_CON0_L_SET
+#define RG_RTC_MCLK_PDN_CLR             MT6685_SCK_TOP_CKPDN_CON0_L_CLR
+#define RG_RTC_MCLK_PDN_MASK    (MT6685_RG_RTC_MCLK_PDN_MASK << MT6685_RG_RTC_MCLK_PDN_SHIFT)
+
+#define RG_RTC_32K_CK_PDN_SET             MT6685_SCK_TOP_CKPDN_CON0_L_SET
+#define RG_RTC_32K_CK_PDN_CLR             MT6685_SCK_TOP_CKPDN_CON0_L_CLR
+#define RG_RTC_32K_CK_PDN_MASK   (MT6685_RG_RTC_32K_CK_PDN_MASK << MT6685_RG_RTC_32K_CK_PDN_SHIFT)
+
+#define SPAR_PROT_STAT_MASK             MT6685_RTC_SPAR_PROT_STAT_MASK
+#define SPAR_PROT_STAT_SHIFT            MT6685_RTC_SPAR_PROT_STAT_SHIFT
+
+/*SCK_TOP rtc interrupt*/
+#define SCK_TOP_INT_CON0                MT6685_SCK_TOP_INT_CON0
+#define EN_RTC_INTERRUPT                MT6685_RG_INT_EN_RTC_MASK
+#define SCK_TOP_INT_STATUS0             MT6685_SCK_TOP_INT_STATUS0
+
+#define TOP2_ELR1                       MT6685_TOP2_ELR1
+#define TOP2_ELR1_MASK                  BIT(0)
+
+#define MTK_RTC_POLL_DELAY_US            10
+#define MTK_RTC_POLL_TIMEOUT             (jiffies_to_usecs(HZ))
+
+#define RTC_POFF_ALM_SET                 _IOW('p', 0x15, struct rtc_time) /* Set alarm time  */
+
+#define SPARE_REG_WIDTH                  1
+
+enum mtk_rtc_spare_enum {
+	SPARE_FG2,
+	SPARE_FG3,
+	SPARE_SPAR0,
+#ifdef SUPPORT_PWR_OFF_ALARM
+	SPARE_KPOC,
+#endif
+	SPARE_RG_MAX,
+};
+
+enum rtc_irq_sta {
+	RTC_NONE,
+	RTC_ALSTA,
+	RTC_TCSTA,
+	RTC_LPSTA,
+};
+
+enum rtc_reg_set {
+	RTC_REG,
+	RTC_MASK,
+	RTC_SHIFT
+};
+
+enum chip_version {
+	NULL_SERIES,
+	MT6685_SERIES,
+};
+
+#define EOSC_SOL_1      0x5
+#define EOSC_SOL_2      0x7
+
+enum rtc_eosc_cali_td {
+	EOSC_CALI_TD_01_SEC = 0x3,
+	EOSC_CALI_TD_02_SEC,
+	EOSC_CALI_TD_04_SEC,
+	EOSC_CALI_TD_08_SEC,
+	EOSC_CALI_TD_16_SEC,
+};
+
+enum cali_field_enum {
+	EOSC_CALI_TD,
+	CALI_FILED_MAX,
+};
+
+#ifdef SUPPORT_PWR_OFF_ALARM
+struct tag_bootmode {
+	u32 size;
+	u32 tag;
+	u32 bootmode;
+	u32 boottype;
+};
+
+enum boot_mode_t {
+	NORMAL_BOOT = 0,
+	META_BOOT = 1,
+	RECOVERY_BOOT = 2,
+	SW_REBOOT = 3,
+	FACTORY_BOOT = 4,
+	ADVMETA_BOOT = 5,
+	ATE_FACTORY_BOOT = 6,
+	ALARM_BOOT = 7,
+	KERNEL_POWER_OFF_CHARGING_BOOT = 8,
+	LOW_POWER_OFF_CHARGING_BOOT = 9,
+	DONGLE_BOOT = 10,
+	UNKNOWN_BOOT
+};
+#endif
+
+struct mtk_rtc_data {
+	u32         wrtgr;
+	u32         hwid;
+	u32			chip_version;
+	bool        single_read_write_is_supported;
+	const struct reg_field *spare_reg_fields;
+	const struct reg_field *cali_reg_fields;
+};
+
+static const char *rtc_time_reg_name[RTC_OFFSET_COUNT] = {
+	[0] = "SEC",
+	[1] = "MIN",
+	[2] = "HOUR",
+	[3] = "DOM",
+	[4] = "DOW",
+	[5] = "MTH",
+	[6] = "YEAR",
+};
+
+enum rtc_time_mask {
+	SEC_MASK,
+	MIN_MASK,
+	HOU_MASK,
+	DOM_MASK,
+	DOW_MASK,
+	MTH_MASK,
+	YEA_MASK,
+	MASK_COUNT
+
+};
+
+static char rtc_time_mask[MASK_COUNT] = {
+	[SEC_MASK] = 0x3f,
+	[MIN_MASK] = 0x3f,
+	[HOU_MASK] = 0x1f,
+	[DOM_MASK] = 0x1f,
+	[DOW_MASK] = 0x7,
+	[MTH_MASK] = 0xf,
+	[YEA_MASK] = 0x7f
+};
+
+struct mt6685_rtc {
+	struct rtc_device       *rtc_dev;
+
+	/* Protect register access from multiple tasks */
+	struct mutex            lock;
+	/**
+	 * struct mutex - Mutex for controlling access to the clock
+	 *
+	 * This mutex is used to synchronize access to the clock in the RTC driver.
+	 */
+	struct mutex            clk_lock;
+	struct regmap           *regmap;
+	struct regmap           *regmap_spar;
+	int                     irq;
+	u32                     addr_base;
+	const struct mtk_rtc_data *data;
+	bool                    cali_is_supported;
+#ifdef SUPPORT_PWR_OFF_ALARM
+	struct work_struct work;
+	struct completion comp;
+#if IS_ENABLED(CONFIG_PM)
+struct notifier_block pm_nb;
+#endif
+#endif
+};
+
+#endif /* __MT6685_RTC_H__ */