[Feature] add poweralarm /wakup-alarm lib

Change-Id: Iff1697a5347d309e6d3ccbbcbf49f997abda76e4
(cherry picked from commit fbb60882f87a08ee6b21eba6ff10ed1898e25d04)
diff --git a/src/kernel/linux/v4.19/drivers/rtc/rtc-mt6330.c b/src/kernel/linux/v4.19/drivers/rtc/rtc-mt6330.c
index 3dc075c..1b373a8 100644
--- a/src/kernel/linux/v4.19/drivers/rtc/rtc-mt6330.c
+++ b/src/kernel/linux/v4.19/drivers/rtc/rtc-mt6330.c
@@ -79,9 +79,16 @@
 #define RTC_AL_MTH_MASK		0x000f
 #define RTC_AL_YEA_MASK		0x007f
 
+#define RTC_PDN1               0x002c
+#define RTC_PDN1_PWRON_TIME    BIT(7)
+
 #define RTC_PDN2		0x002e
 #define RTC_PDN2_PWRON_ALARM	BIT(4)
 
+#define RTC_SPAR0              0x0030
+
+#define RTC_SPAR1              0x0032
+
 #define RTC_SPAR0_L			0x0030
 #define RTC_INT_CNT_L			0x0040
 
@@ -90,8 +97,34 @@
 #define RTC_NUM_YEARS		128
 #define RTC_MIN_YEAR_OFFSET	(RTC_MIN_YEAR - RTC_BASE_YEAR)
 
+#define RTC_PWRON_YEA          RTC_PDN2
+#define RTC_PWRON_YEA_MASK     0x7f00
+#define RTC_PWRON_YEA_SHIFT    8
+
+#define RTC_PWRON_MTH          RTC_PDN2
+#define RTC_PWRON_MTH_MASK     0x000f
+#define RTC_PWRON_MTH_SHIFT    0
+
+#define RTC_PWRON_SEC          RTC_SPAR0
+#define RTC_PWRON_SEC_MASK     0x003f
+#define RTC_PWRON_SEC_SHIFT    0
+
+#define RTC_PWRON_MIN          RTC_SPAR1
+#define RTC_PWRON_MIN_MASK     0x003f
+#define RTC_PWRON_MIN_SHIFT    0
+
+#define RTC_PWRON_HOU          RTC_SPAR1
+#define RTC_PWRON_HOU_MASK     0x07c0
+#define RTC_PWRON_HOU_SHIFT    6
+
+#define RTC_PWRON_DOM          RTC_SPAR1
+#define RTC_PWRON_DOM_MASK     0xf800
+#define RTC_PWRON_DOM_SHIFT    11
+
 #define SPARE_REG_WIDTH		1
 
+#define RTC_POFF_ALM_SET	_IOW('p', 0x15, struct rtc_time) /* Set alarm time  */
+
 enum mtk_rtc_spare_enum {
 	SPARE_AL_HOU,
 	SPARE_AL_MTH,
@@ -99,6 +132,12 @@
 	SPARE_RG_MAX,
 };
 
+enum rtc_reg_set {
+	RTC_REG,
+	RTC_MASK,
+	RTC_SHIFT
+};
+
 enum rtc_eosc_cali_td {
 	EOSC_CALI_TD_01_SEC = 0x3,
 	EOSC_CALI_TD_02_SEC,
@@ -141,6 +180,16 @@
 
 static int mtk_rtc_write_trigger(struct mt6330_rtc *rtc);
 
+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 mt6330_cali_reg_fields[CALI_FILED_MAX] = {
 	[RTC_EOSC32_CK_PDN]	= REG_FIELD(MT6330_SCK_TOP_CKPDN_CON0_L, 2, 2),
 	[EOSC_CALI_TD]		= REG_FIELD(MT6330_RTC_AL_DOW_L, 8, 10),
@@ -248,7 +297,7 @@
 	}
 	// else, not access RTC register
 
-	ret = regmap_bulk_write(rtc->regmap, reg, val, val_count);
+    ret = regmap_bulk_write(rtc->regmap, reg, val, val_count);
 
 	if (reg == rtc->addr_base + rtc->dev_comp->wrtgr_addr) {
 		// need 1 ms delay to make sure write completely
@@ -442,6 +491,81 @@
 	return ret;
 }
 
+static void mtk_rtc_set_pwron_time(struct mt6330_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);
+
+	printk_deferred(" %s set PWRON_SEC %x\n", __func__, data[RTC_OFFSET_SEC]);
+
+	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);
+	}
+
+	if (ret < 0)
+		goto exit;
+
+	return;
+
+exit:
+	dev_err(rtc->dev, "%s error\n", __func__);
+	printk_deferred("%s error\n", __func__);
+
+}
+
+void mtk_rtc_save_pwron_time(struct mt6330_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);
+
+	mtk_rtc_write_trigger(rtc);
+
+	if (ret < 0)
+		goto exit;
+
+//	mtk_rtc_write_trigger(rtc);
+
+	return;
+
+exit:
+	dev_err(rtc->dev, "%s error\n", __func__);
+}
+
 static int mtk_rtc_read_time(struct device *dev, struct rtc_time *tm)
 {
 	time64_t time;
@@ -557,6 +681,16 @@
 	struct mt6330_rtc *rtc = dev_get_drvdata(dev);
 	int ret;
 	u16 data[RTC_OFFSET_COUNT] = { 0 };
+	ktime_t target;
+
+	printk_deferred(" %s set %d\n", __func__, alm->enabled);
+
+	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);
+	}
 
 	if (tm->tm_year > 195) {
 		dev_err(rtc->dev, "%s: invalid year %04d > 2095\n",
@@ -568,6 +702,29 @@
 	tm->tm_mon++;
 
 	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)
@@ -586,6 +743,8 @@
 	data[RTC_OFFSET_YEAR] = ((data[RTC_OFFSET_YEAR] & ~(RTC_AL_YEA_MASK)) |
 				(tm->tm_year & RTC_AL_YEA_MASK));
 
+	printk_deferred(" %s set AL_SEC %x\n", __func__, data[RTC_OFFSET_SEC]);
+
 	if (alm->enabled) {
 		ret = rtc_bulk_read(rtc, rtc->addr_base + RTC_AL_SEC,
 			       data, RTC_OFFSET_COUNT * 2);
@@ -642,7 +801,54 @@
 	return ret;
 }
 
+int 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 = 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,