[Feature] add poweralarm /wakup-alarm lib

Change-Id: Iff1697a5347d309e6d3ccbbcbf49f997abda76e4
diff --git a/meta/meta-mediatek-mt2735/recipes-lynq/libpoweralarm/libpoweralarm.bb b/meta/meta-mediatek-mt2735/recipes-lynq/libpoweralarm/libpoweralarm.bb
new file mode 100644
index 0000000..ef78913
--- /dev/null
+++ b/meta/meta-mediatek-mt2735/recipes-lynq/libpoweralarm/libpoweralarm.bb
@@ -0,0 +1,48 @@
+inherit externalsrc package
+
+DESCRIPTION = "libpoweralarm"
+LICENSE = "MediaTekProprietary"
+LIC_FILES_CHKSUM = "file://LICENSE;md5=e1696b147d49d491bcb4da1a57173fff"
+DEPENDS += "platform-libs  liblynq-log "
+inherit workonsrc
+WORKONSRC = "${TOPDIR}/../src/lynq/lib/libpoweralarm"
+
+TARGET_CC_ARCH += "${LDFLAGS}"
+BB_INCLUDE_ADD = "--sysroot=${STAGING_DIR_HOST}"
+BB_LDFLAGS_ADD = "--sysroot=${STAGING_DIR_HOST} -Wl,--hash-style=gnu"
+#Parameters passed to do_compile()
+EXTRA_OEMAKE = "'RAT_CONFIG_C2K_SUPPORT = ${RAT_CONFIG_C2K_SUPPORT}'\
+                'MTK_MULTI_SIM_SUPPORT = ${MTK_MULTI_SIM_SUPPORT}'\
+                'TARGET_PLATFORM = ${TARGET_PLATFORM}'"
+
+FILES_${PN} = "${base_libdir}/*.so \
+               ${base_bindir}\
+               ${base_sbindir} \
+               /etc/dbus-1/system.d/"
+FILES_${PN}-dev = "/test \
+                   ${includedir}"
+FILES_${PN}-doc = "/doc"
+FILES_${PN}-dbg ="${base_bindir}/.debug \
+                  ${base_libdir}/.debug \
+                  ${base_sbindir}/.debug"
+INSANE_SKIP_${PN} += "already-stripped"
+INSANE_SKIP_${PN} += "installed-vs-shipped"
+#INHIBIT_PACKAGE_STRIP = "1"
+do_compile () {
+	if [ "${PACKAGE_ARCH}" = "cortexa7hf-vfp-vfpv4-neon" ]; then
+		oe_runmake all ROOT=${STAGING_DIR_HOST} OFLAGS="--sysroot=${STAGING_DIR_HOST} -Os -mfpu=neon-vfpv4 -mhard-float -Wl,--hash-style=gnu -DTELEPHONYWARE"
+	elif [ "${PACKAGE_ARCH}" = "cortexa7hf-neon-vfpv4" ]; then
+		oe_runmake all ROOT=${STAGING_DIR_HOST} OFLAGS="--sysroot=${STAGING_DIR_HOST} -Os -mfpu=neon-vfpv4 -mhard-float -Wl,--hash-style=gnu -DTELEPHONYWARE"
+	elif [ "${PACKAGE_ARCH}" = "cortexa53hf-neon-fp-armv8" ]; then
+		oe_runmake all ROOT=${STAGING_DIR_HOST} OFLAGS="--sysroot=${STAGING_DIR_HOST} -Os -mfpu=neon-vfpv4 -mhard-float -Wl,--hash-style=gnu -DTELEPHONYWARE -mhard-float -mfpu=neon-fp-armv8 -mfloat-abi=hard -mcpu=cortex-a53 -mtune=cortex-a53"
+	else
+		oe_runmake all ROOT=${STAGING_DIR_HOST} OFLAGS="--sysroot=${STAGING_DIR_HOST} -Os -Wl,--hash-style=gnu -DTELEPHONYWARE"
+	fi
+}
+
+do_install() {
+    oe_runmake install ROOT=${D}
+    if [ -d "${WORKONSRC}" ] ; then
+        install -d ${D}${includedir}
+    fi
+}
diff --git a/meta/meta-mediatek-mt2735/recipes-lynq/packagegroups/packagegroup-lync-mt2735.bb b/meta/meta-mediatek-mt2735/recipes-lynq/packagegroups/packagegroup-lync-mt2735.bb
index 4e9671d..93cac26 100755
--- a/meta/meta-mediatek-mt2735/recipes-lynq/packagegroups/packagegroup-lync-mt2735.bb
+++ b/meta/meta-mediatek-mt2735/recipes-lynq/packagegroups/packagegroup-lync-mt2735.bb
@@ -5,6 +5,7 @@
 
 RDEPENDS_packagegroup-lync-mt2735 = "\
     libautosuspend \
+    libpoweralarm \
     lynq-autosuspend \
     lynq-system-service \
     liblynq-log \
diff --git a/src/bsp/lk/platform/mt2735/drivers/pmic/pmic.c b/src/bsp/lk/platform/mt2735/drivers/pmic/pmic.c
index 17280bd..c0e48de 100644
--- a/src/bsp/lk/platform/mt2735/drivers/pmic/pmic.c
+++ b/src/bsp/lk/platform/mt2735/drivers/pmic/pmic.c
@@ -412,7 +412,7 @@
 		pmic_read_interface(PMIC_PUP_PKEY_RELEASE_ADDR, &g_pwrkey_release,
 			PMIC_PUP_PKEY_RELEASE_MASK, PMIC_PUP_PKEY_RELEASE_SHIFT);
 	/*--UVLO off--*/
-		dprintf(INFO, "[PMIC]TOP_RST_STATUS[0x%x]=0x%x\n",
+		dprintf(ALWAYS, "[PMIC]TOP_RST_STATUS[0x%x]=0x%x\n",
 			MT6330_TOP_RST_STATUS, upmu_get_reg_value(MT6330_TOP_RST_STATUS));
 	/*special for RTC Alarm and SPAR*/
 		pon_sts = upmu_get_reg_value(MT6330_PONSTS);
diff --git a/src/bsp/lk/platform/mt2735/drivers/rtc/rtc.c b/src/bsp/lk/platform/mt2735/drivers/rtc/rtc.c
index 5e14d1a..df570c8 100644
--- a/src/bsp/lk/platform/mt2735/drivers/rtc/rtc.c
+++ b/src/bsp/lk/platform/mt2735/drivers/rtc/rtc.c
@@ -1033,6 +1033,7 @@
                         Write_trigger();
                     }
 #endif
+                RTC_LOG("Power on alarm\n");
                 return true;
             } else if (now_time < time) {   /* set power-on alarm */
                 RTC_Write(RTC_AL_YEA,  (RTC_Read(RTC_AL_YEA) & (~RTC_AL_YEA_MASK)) | ((yea - RTC_MIN_YEAR) & RTC_AL_YEA_MASK));
@@ -1046,6 +1047,7 @@
                 irqen = RTC_Read(RTC_IRQ_EN) | RTC_IRQ_EN_ONESHOT_AL;
                 RTC_Write(RTC_IRQ_EN, irqen);
                 Write_trigger();
+                RTC_LOG("Not power on alarm\n");
             } else {
                 pdn1 = (pdn1 & ~RTC_PDN1_PWRON_TIME);
 #if defined (MTK_KERNEL_POWER_OFF_CHARGING)
@@ -1056,7 +1058,9 @@
                 Write_trigger();
                 RTC_LOG("Expired alarm\n");
             }
-        }
+        } else {
+		RTC_LOG("Not power on alarm\n");
+	}
     }
 
     if ((pdn1 & RTC_PDN1_RECOVERY_MASK) == RTC_PDN1_FAC_RESET) {    /* factory data reset */
diff --git a/src/bsp/lk/platform/mt2735/drivers/wdt/mtk_wdt.c b/src/bsp/lk/platform/mt2735/drivers/wdt/mtk_wdt.c
index a2477ef..86e9d19 100644
--- a/src/bsp/lk/platform/mt2735/drivers/wdt/mtk_wdt.c
+++ b/src/bsp/lk/platform/mt2735/drivers/wdt/mtk_wdt.c
@@ -72,7 +72,50 @@
 
 static uint32_t wdt_reset_status;
 static uint8_t wdt_inited = 0U;
+static unsigned int rgu_mode;
 
+enum {
+	MTK_WDT_NONRST2_BOOT_MASK       = 0xF,
+	MTK_WDT_NONRST2_BOOT_CHARGER    = 1,
+	MTK_WDT_NONRST2_BOOT_RECOVERY   = 2,
+	MTK_WDT_NONRST2_BOOT_BOOTLOADER = 3,
+	MTK_WDT_NONRST2_BOOT_DM_VERITY  = 4,
+	MTK_WDT_NONRST2_BOOT_KPOC       = 5,
+	MTK_WDT_NONRST2_BOOT_DDR_RSVD   = 6,
+	MTK_WDT_NONRST2_BOOT_META       = 7,
+	MTK_WDT_NONRST2_BOOT_RPMBPK     = 8,
+	MTK_WDT_NONRST2_BYPASS_PWR_KEY  = 1 << 13,
+	MTK_WDT_NONRST2_STAGE_OFS       = 29,
+	MTK_WDT_NONRST2_LAST_STAGE_OFS  = 26
+};
+
+static unsigned int mtk_wdt_get_status(void)
+{
+	static unsigned int wdt_sta = 0;
+	static unsigned int wdt_sta_handled = 0;
+	unsigned int reg;
+
+	/*
+	 * Note:
+	 * Because WDT_STA register will be cleared after writing WDT_MODE,
+	 * we use a static variable to keep orinigal WDT_STA.
+	 *
+	 * After reset, static varialbe will always be clear to 0,
+	 * so only read WDT_STA when static variable is 0 is OK
+	 *
+	 * Use "wdt_sta_handled" to indicate if WDT_STATUS is preserved.
+	 * Do not use "wdt_sta" as indication because dummy handling will be
+	 * executed in case WDT_STATUS is 0 originally.
+	 */
+	if (wdt_sta_handled == 0) {
+
+		wdt_sta = wdt_readl(WDT_STA);
+
+		wdt_sta_handled = 1;
+	}
+
+	return wdt_sta;
+}
 
 static inline void mtk_wdt_clear_all_status(void)
 {
@@ -146,6 +189,21 @@
 void mtk_wdt_init(void)
 {
 	unsigned int wdt_ctrl;
+
+	rgu_mode = wdt_readl(WDT_MODE);
+
+	dprintf(ALWAYS, "MODE:               0x%x\n", wdt_readl(WDT_MODE));
+	dprintf(ALWAYS, "STA:                0x%x\n", mtk_wdt_get_status());
+	dprintf(ALWAYS, "LENGTH:             0x%x\n", wdt_readl(WDT_LENGTH));
+	dprintf(ALWAYS, "INTERVAL:           0x%x\n", wdt_readl(WDT_INTERNAL));
+	dprintf(ALWAYS, "SWSYSRST:           0x%x\n", wdt_readl(WDT_SWSYSRST));
+	dprintf(ALWAYS, "LATCH_CTL:          0x%x\n", wdt_readl(WDT_LATCH_CTL));
+	dprintf(ALWAYS, "NONRST_REG:         0x%x\n", wdt_readl(WDT_NONRST_REG));
+	dprintf(ALWAYS, "NONRST_REG2:        0x%x\n", wdt_readl(WDT_NONRST_REG2));
+
+	if (wdt_readl(WDT_NONRST_REG2) & MTK_WDT_NONRST2_BYPASS_PWR_KEY)
+		rgu_mode |= MTK_WDT_NONRST2_BYPASS_PWR_KEY;
+
 	mtk_wdt_set_default_mode(WDT_DISABLE, WDT_TIMEOUT_LK_SEC);
 
 	if (wdt_inited == 0U) {
@@ -317,6 +375,44 @@
 	}
 	return WDT_NOT_WDT_REBOOT;
 }
+#else
+int mtk_wdt_boot_check(void)
+{
+	unsigned int wdt_sta = wdt_reset_status;
+	int ret = WDT_NOT_WDT_REBOOT;
+
+	/*
+	 * For DA download hope to timeout reboot, and boot to u-boot/kernel configurable reason,
+	 * we set both timeout reboot and software reboot can check whether bypass power key.
+	 */
+	if (wdt_sta & (MTK_WDT_STATUS_HWWDT_RST | MTK_WDT_STATUS_SWWDT_RST |
+		MTK_WDT_STATUS_MD_THERMAL_RST | MTK_WDT_STATUS_SPMWDT_RST |
+		MTK_WDT_STATUS_THERMAL_DIRECT_RST | MTK_WDT_STATUS_SECURITY_RST |
+		MTK_WDT_STATUS_DEBUGWDT_RST | MTK_WDT_STATUS_EINT_RST |
+		MTK_WDT_STATUS_SYSRST_RST | MTK_WDT_STATUS_DVFSP_RST | MTK_WDT_STATUS_MCUPM_RST |
+		MTK_WDT_STATUS_SSPM_RST)) {
+		if (rgu_mode & MTK_WDT_NONRST2_BYPASS_PWR_KEY) {
+			/* HW or SW reboot, and auto restart is set, means bypass power key */
+			ret = WDT_BY_PASS_PWK_REBOOT;
+
+		} else {
+
+			/* HW or SW reboot, but auto restart is not set, means NOT bypass power key */
+			ret = WDT_NORMAL_REBOOT;
+		}
+	} else {
+		/*
+		 * For PMIC full reset, return "bypass pwr key reboot" to help AEE works.
+		 * I.e., Prevent entering charger mode.
+		 */
+		if (mtk_wdt_is_pmic_full_reset()) {
+			dprintf(INFO, "PMIC full rst: true\n");
+			ret = WDT_BY_PASS_PWK_REBOOT;
+		}
+	}
+
+	return ret;
+}
 #endif
 
 #else	/* !ENABLE_WDT_MODULE */
diff --git a/src/bsp/lk/platform/mt2735/include/platform/mtk_wdt.h b/src/bsp/lk/platform/mt2735/include/platform/mtk_wdt.h
index f4b91b8..8d8a589 100644
--- a/src/bsp/lk/platform/mt2735/include/platform/mtk_wdt.h
+++ b/src/bsp/lk/platform/mt2735/include/platform/mtk_wdt.h
@@ -60,21 +60,28 @@
  */
 void mtk_arch_reset(char bypass_pwrkey);
 
-#if LK_AS_BL33
-
 #define WDT_NORMAL_REBOOT               (0x100)
 #define WDT_BY_PASS_PWK_REBOOT          (0x200)
 #define WDT_NOT_WDT_REBOOT              (0x400)
 
 /*WDT_STATUS*/
 #define MTK_WDT_STATUS_HWWDT_RST_WITH_IRQ    (0xA0000000)
-#define MTK_WDT_STATUS_HWWDT_RST    (0x80000000)
-#define MTK_WDT_STATUS_SWWDT_RST    (0x40000000)
-#define MTK_WDT_STATUS_IRQWDT_RST   (0x20000000)
-#define MTK_WDT_STATUS_SECURITY_RST (1<<28)
-#define MTK_WDT_STATUS_DEBUGWDT_RST (0x00080000)
-#define MTK_WDT_STATUS_SPMWDT_RST   (0x0001)
 #define MTK_WDT_STATUS_THERMAL_CTL_RST   (1<<18)
+#define MTK_WDT_STATUS_MD_THERMAL_RST       (1)
+#define MTK_WDT_STATUS_SPMWDT_RST           (1<<1)
+#define MTK_WDT_STATUS_EINT_RST             (1<<2)
+#define MTK_WDT_STATUS_SYSRST_RST           (1<<3)
+#define MTK_WDT_STATUS_DVFSP_RST            (1<<4)
+#define MTK_WDT_STATUS_MCUPM_RST            (1<<5)
+#define MTK_WDT_STATUS_PCIE_PERST_RST       (1<<7)
+#define MTK_WDT_STATUS_SSPM_RST             (1<<16)
+#define MTK_WDT_STATUS_MDDBG_RST            (1<<17)
+#define MTK_WDT_STATUS_THERMAL_DIRECT_RST   (1<<18)
+#define MTK_WDT_STATUS_DEBUGWDT_RST         (1<<19)
+#define MTK_WDT_STATUS_SECURITY_RST         (1<<28)
+#define MTK_WDT_STATUS_IRQWDT_RST           (1<<29)
+#define MTK_WDT_STATUS_SWWDT_RST            (1<<30)
+#define MTK_WDT_STATUS_HWWDT_RST            (1<<31)
 
 /* Reboot reason */
 #define RE_BOOT_REASON_UNKNOW           (0x00)
@@ -93,7 +100,4 @@
 #define WDT_BY_PASS_PWK_REBOOT          (0x200)
 #define WDT_NOT_WDT_REBOOT              (0x400)
 
-
 int mtk_wdt_boot_check(void);
-
-#endif
diff --git a/src/bsp/lk/platform/mt2735/include/platform/platform_blx.h b/src/bsp/lk/platform/mt2735/include/platform/platform_blx.h
index ab0818d..929526f 100644
--- a/src/bsp/lk/platform/mt2735/include/platform/platform_blx.h
+++ b/src/bsp/lk/platform/mt2735/include/platform/platform_blx.h
@@ -36,6 +36,9 @@
     BR_KERNEL_PANIC,
     BR_WDT_SW,
     BR_WST_HW,
+    BR_POWER_EXC = 30,
+    BR_LONG_POWKEY,
+    BR_POWER_LOSS
 } boot_reason_t;
 
 void platform_memory_init(void);
diff --git a/src/bsp/lk/platform/mt2735/platform_bl2.c b/src/bsp/lk/platform/mt2735/platform_bl2.c
index c18da3f..630a31d 100644
--- a/src/bsp/lk/platform/mt2735/platform_bl2.c
+++ b/src/bsp/lk/platform/mt2735/platform_bl2.c
@@ -50,6 +50,7 @@
 #include <platform/rtc.h>
 #include <boot_args.h>
 #include <string.h>
+#include <platform/platform_blx.h>
 
 static uint32_t g_boot_reason = 0;
 static uint32_t g_rgu_mode = 0;
@@ -118,6 +119,22 @@
 };
 #endif /* WITH_KERNEL_VM */
 
+extern U32 upmu_is_chr_det(void);
+
+int usb_accessory_in(void)
+{
+#if !CFG_FPGA_PLATFORM
+    int exist = 0;
+
+    if (upmu_is_chr_det() == KAL_TRUE) {
+        exist = 1;
+    }
+    return exist;
+#else
+    return 1;
+#endif
+}
+
 static inline size_t query_plat_dram_sz(void)
 {
     return mt_mem_size();
@@ -237,6 +254,8 @@
 
 void platform_early_init_blx(void)
 {
+    boot_reason_t reason;
+
     mtk_timer_init();
 
 #if !CFG_FPGA_PLATFORM
@@ -274,6 +293,12 @@
     clk_buf_init();
 
     mt_dcm_init();
+
+
+	reason = platform_boot_status();
+	if (reason == BR_RTC || reason == BR_POWER_KEY || reason == BR_USB || reason == BR_WDT || reason == BR_WDT_BY_PASS_PWK || reason == BR_2SEC_REBOOT)
+		rtc_bbpu_power_on();
+
 #endif
 
     bgr_init();
@@ -281,6 +306,65 @@
     dprintf(CRITICAL, "BL2 Build Time: %s %s\n", __DATE__, __TIME__);
 }
 
+int platform_wdt_boot_check(void)
+{
+    return mtk_wdt_boot_check();
+}
+
+boot_reason_t platform_boot_status(void)
+{
+	u32 pmic_reboot = get_pmic_boot_status();
+
+	if (rtc_boot_check()) {
+		dprintf(CRITICAL, "%s RTC boot!\n");
+		return BR_RTC;
+	}
+
+	if (pmic_reboot == 1) {
+		dprintf(CRITICAL, "pmic: power exception(OC/PG)!\n");
+		return BR_POWER_EXC;
+	} else if (pmic_reboot == 2) {
+		dprintf(CRITICAL, "pmic: long power key press reboot!\n");
+		return BR_LONG_POWKEY;
+	} else if (pmic_reboot == 3) {
+		if(rtc_2sec_reboot_check()) {
+			dprintf(CRITICAL, "pmic: 2sec reboot!\n");
+			return BR_2SEC_REBOOT;
+		} else {
+			dprintf(CRITICAL, "pmic: power miss!\n");
+			return BR_POWER_LOSS;
+		}
+	}
+
+    if (platform_wdt_boot_check() == WDT_NORMAL_REBOOT) {
+        dprintf(CRITICAL, "SW reset without bypass power key flag\n");
+        dprintf(CRITICAL, "WDT normal boot!\n");
+        return BR_WDT;
+    } else if(platform_wdt_boot_check() == WDT_BY_PASS_PWK_REBOOT) {
+        dprintf(CRITICAL, "SW reset with bypass power key flag\n");
+        dprintf(CRITICAL, "WDT reboot bypass power key!\n");
+        return BR_WDT_BY_PASS_PWK;
+    }
+
+    if (usb_accessory_in()) {
+        dprintf(CRITICAL, "%s USB/charger boot!\n");
+        return BR_USB;
+    }
+
+#if !CFG_FPGA_PLATFORM
+	/* check power key */
+	if ((pmic_detect_powerkey() && !is_pwrkey_short_press())
+		|| is_pmic_long_press_reset()) {
+		dprintf(CRITICAL, "%s Power key boot!\n");
+		return BR_POWER_KEY;
+	}
+#endif
+
+    pl_power_off();
+
+    return BR_UNKNOWN;
+}
+
 void platform_init_blx()
 {
 }
diff --git a/src/kernel/linux/v4.19/drivers/rtc/interface.c b/src/kernel/linux/v4.19/drivers/rtc/interface.c
index ce051f9..089ff8c 100644
--- a/src/kernel/linux/v4.19/drivers/rtc/interface.c
+++ b/src/kernel/linux/v4.19/drivers/rtc/interface.c
@@ -482,6 +482,7 @@
 
 	rtc->aie_timer.node.expires = rtc_tm_to_ktime(alarm->time);
 	rtc->aie_timer.period = 0;
+	rtc->aie_timer.enabled = alarm->enabled;
 	if (alarm->enabled)
 		err = rtc_timer_enqueue(rtc, &rtc->aie_timer);
 
@@ -821,7 +822,8 @@
 	struct rtc_time tm;
 	ktime_t now;
 
-	timer->enabled = 1;
+	if(timer->enabled == 0)
+		timer->enabled = 1;
 	__rtc_read_time(rtc, &tm);
 	now = rtc_tm_to_ktime(tm);
 
@@ -838,7 +840,7 @@
 		struct rtc_wkalrm alarm;
 		int err;
 		alarm.time = rtc_ktime_to_tm(timer->node.expires);
-		alarm.enabled = 1;
+		alarm.enabled = timer->enabled;
 		err = __rtc_set_alarm(rtc, &alarm);
 		if (err == -ETIME) {
 			pm_stay_awake(rtc->dev.parent);
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,
diff --git a/src/kernel/linux/v4.19/drivers/rtc/rtc-sysfs.c b/src/kernel/linux/v4.19/drivers/rtc/rtc-sysfs.c
index 9746c32..a1dc393 100644
--- a/src/kernel/linux/v4.19/drivers/rtc/rtc-sysfs.c
+++ b/src/kernel/linux/v4.19/drivers/rtc/rtc-sysfs.c
@@ -165,6 +165,7 @@
 	const char *buf_ptr;
 	int adjust = 0;
 
+	printk_deferred("%s \n", __func__);
 	/* Only request alarms that trigger in the future.  Disable them
 	 * by writing another time, e.g. 0 meaning Jan 1 1970 UTC.
 	 */
@@ -221,6 +222,101 @@
 static DEVICE_ATTR_RW(wakealarm);
 
 static ssize_t
+poweralarm_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	ssize_t retval;
+	time64_t alarm;
+	struct rtc_wkalrm alm;
+
+	/* Don't show disabled alarms.  For uniformity, RTC alarms are
+	 * conceptually one-shot, even though some common RTCs (on PCs)
+	 * don't actually work that way.
+	 *
+	 * NOTE: RTC implementations where the alarm doesn't match an
+	 * exact YYYY-MM-DD HH:MM[:SS] date *must* disable their RTC
+	 * alarms after they trigger, to ensure one-shot semantics.
+	 */
+	retval = rtc_read_alarm(to_rtc_device(dev), &alm);
+	if (retval == 0 && alm.enabled) {
+		alarm = rtc_tm_to_time64(&alm.time);
+		retval = sprintf(buf, "%lld\n", alarm);
+	}
+
+	return retval;
+}
+
+
+static ssize_t
+poweralarm_store(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t n)
+{
+	ssize_t retval;
+	time64_t now, alarm;
+	time64_t push = 0;
+	struct rtc_wkalrm alm;
+	struct rtc_device *rtc = to_rtc_device(dev);
+	const char *buf_ptr;
+	int adjust = 0;
+
+	printk_deferred("%s \n", __func__);
+
+	/* Only request alarms that trigger in the future.  Disable them
+	 * by writing another time, e.g. 0 meaning Jan 1 1970 UTC.
+	 */
+	retval = rtc_read_time(rtc, &alm.time);
+	if (retval < 0)
+		return retval;
+	now = rtc_tm_to_time64(&alm.time);
+
+	buf_ptr = buf;
+	if (*buf_ptr == '+') {
+		buf_ptr++;
+		if (*buf_ptr == '=') {
+			buf_ptr++;
+			push = 1;
+		} else
+			adjust = 1;
+	}
+	retval = kstrtos64(buf_ptr, 0, &alarm);
+	if (retval)
+		return retval;
+	if (adjust) {
+		alarm += now;
+	}
+	if (alarm > now || push) {
+		/* Avoid accidentally clobbering active alarms; we can't
+		 * entirely prevent that here, without even the minimal
+		 * locking from the /dev/rtcN api.
+		 */
+		retval = rtc_read_alarm(rtc, &alm);
+		if (retval < 0)
+			return retval;
+		if (alm.enabled) {
+			
+			if (push) {
+				push = rtc_tm_to_time64(&alm.time);
+				alarm += push;
+			} else
+				return -EBUSY;
+		} else if (push)
+			return -EINVAL;
+		alm.enabled = 3;
+	} else {
+		alm.enabled = 4;
+
+		/* Provide a valid future alarm time.  Linux isn't EFI,
+		 * this time won't be ignored when disabling the alarm.
+		 */
+		alarm = now + 300;
+	}
+	rtc_time64_to_tm(alarm, &alm.time);
+
+	retval = rtc_set_alarm(rtc, &alm);
+	return (retval < 0) ? retval : n;
+}
+static DEVICE_ATTR_RW(poweralarm);
+
+static ssize_t
 offset_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
 	ssize_t retval;
@@ -264,6 +360,7 @@
 	&dev_attr_max_user_freq.attr,
 	&dev_attr_hctosys.attr,
 	&dev_attr_wakealarm.attr,
+	&dev_attr_poweralarm.attr,
 	&dev_attr_offset.attr,
 	&dev_attr_range.attr,
 	NULL,
diff --git a/src/lynq/lib/libpoweralarm/LICENSE b/src/lynq/lib/libpoweralarm/LICENSE
new file mode 100644
index 0000000..77f59ed
--- /dev/null
+++ b/src/lynq/lib/libpoweralarm/LICENSE
@@ -0,0 +1,31 @@
+Copyright Statement:
+
+This software/firmware and related documentation ("MediaTek Software") are
+protected under relevant copyright laws. The information contained herein is
+confidential and proprietary to MediaTek Inc. and/or its licensors. Without
+the prior written permission of MediaTek inc. and/or its licensors, any
+reproduction, modification, use or disclosure of MediaTek Software, and
+information contained herein, in whole or in part, shall be strictly
+prohibited.
+
+MediaTek Inc. (C) 2015. All rights reserved.
+
+BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
+ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL
+WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
+WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
+NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH
+RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
+INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES
+TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
+RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
+OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK
+SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE
+RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S
+ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE
+RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE
+MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
+CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
diff --git a/src/lynq/lib/libpoweralarm/format_change.c b/src/lynq/lib/libpoweralarm/format_change.c
new file mode 100644
index 0000000..d9cac51
--- /dev/null
+++ b/src/lynq/lib/libpoweralarm/format_change.c
@@ -0,0 +1,133 @@
+#include"./include/format_change.h"
+#include<log/log.h>
+
+
+/*****************************************************************************
+*   Prototype    : format_change
+*   Description  : convert the incoming fixed format string into the corresponding alarm seconds
+*   Input        : char *buffer ;  input format : 2022-04-23-15-30-00 ( Mon-Day-Hour-Min-Sec ) Or  1200 ( seconds )              
+*   Output       : None
+*   Return Value : -1: match error ; >0: set to wake up the devices after seconds
+*
+*****************************************************************************/
+ssize_t format_change(char *buffer)
+{
+    time_t rawtime;
+    time_t alarm_tamp;
+    struct tm *info = NULL;
+    struct tm *set_alarm = NULL;
+    char *time_buff = NULL;
+
+    char ebuff[256];
+    regex_t reg_alm,reg_sec;
+    char *pattern_setalm = "^20[0-9][0-9]-[01]?[1-9]-[0-3]?[0-9]-[0-2]?[0-9]-[0-5]?[0-9]-[0-5]?[0-9]$";//regular expression 1 ,  in order that match alarm time string eg:Mon-Day-Hour-Min-Sec 
+    char *pattern_setsec = "^[1-9][0-9]*$";//regular expression 2 ,  in order that match seconds 
+    int cflags = REG_EXTENDED | REG_ICASE | REG_NOSUB;//POSIX extend,not care up and low letters,not store result
+
+    int ret;
+    ssize_t sec;
+
+    ret = regcomp(&reg_alm,pattern_setalm,cflags);  //匹配规则1:\d\d\d\d\d-\d\d-\d\d-\d\d-\d\d-\d\d
+    if(ret) // judge error code : 0 symbolize success ; other value symbolizes fail 
+    {
+        regerror(ret,&reg_alm,ebuff,256);
+        ALOGI(ebuff);
+        regfree(&reg_alm);  //free mattch pattern
+        regfree(&reg_sec);
+        return -1;
+    }
+
+    ret = regcomp(&reg_sec,pattern_setsec,cflags); //匹配规则2:^\d\d*$
+    if(ret)// judge error code : 0 symbolize success ; other value symbolizes fail 
+    {
+        regerror(ret,&reg_sec,ebuff,256);
+        ALOGI(ebuff);
+        regfree(&reg_alm);  //free mattch pattern
+        regfree(&reg_sec);
+        return -1;
+    }
+
+    time(&rawtime);  //获取自1970年到现在一共过去了几秒,赋值给rawtime
+
+    info =localtime(&rawtime); //转换为UTC时间
+
+    bool leap_flag = (bool)(((info->tm_year%4==0)&&(info->tm_year%100!=0)) || (info->tm_year%400 == 0));  //判断当前是否为闰年
+    int day_array[13] = {0,31, leap_flag?29:28,31,30,31,30,31,31,30,31,30,31};   //设置每个月的天数
+
+    if((ret = regexec(&reg_alm,buffer,0,NULL,0)) == 0)   //Retrieve the incoming buffer string according to matching rule 1
+    {
+        set_alarm = (struct tm *)malloc(sizeof(struct tm));
+        memset(set_alarm,0,sizeof(struct tm));
+        memcpy(set_alarm,info,sizeof(struct tm));  //拷贝当前时间信息
+
+        ret = sscanf(buffer,"%d-%d-%d-%d-%d-%d",&(set_alarm->tm_year),&(set_alarm->tm_mon),&(set_alarm->tm_mday),&(set_alarm->tm_hour),&(set_alarm->tm_min),&(set_alarm->tm_sec));//read data form formatted string
+        
+        if(ret == -1)  //sscanf no mattch
+        {
+            ALOGI("sscanf error code -1\n");
+            free(set_alarm);
+            return -1;
+        }
+        else if(ret == 6) //Success mattch 
+        {
+            if((set_alarm->tm_hour > 23) || (set_alarm->tm_hour < 0)) //judge hour 
+            {
+                ALOGI("hour error\n");
+                ret = -1;
+            }
+            if((set_alarm->tm_mon > 12) || (set_alarm->tm_mon < 1))  //judge month
+            {
+                ALOGI("mon error\n");
+                ret = -1;
+            }
+            if((set_alarm->tm_mday > day_array[set_alarm->tm_mon]) || (set_alarm->tm_mday < 1)) //judge day
+            {
+                ALOGI("day error\n");
+                ret = -1;
+            }
+            if(ret == -1) //Error setting alarm time
+            {
+                free(set_alarm);
+                return -1;
+            }
+
+            set_alarm->tm_mon -= 1; 
+            sprintf(ebuff,"set alarm is %s\n",asctime(set_alarm)); //print log
+            ALOGI(ebuff);
+            alarm_tamp = mktime(set_alarm); //struct tm transform struct time_t
+            time(&rawtime); 
+            //printf("tamp: %ld\n",alarm_tamp);
+            sec = alarm_tamp - rawtime; //set second
+            free(set_alarm);
+
+            if(sec <= 0) //the current alarm time is less than the current system time
+            { 
+                ALOGI("sec <= 0 setalarm error\n");
+                return -1;
+            }
+        }
+        else //sscanf mattch fail
+        {
+            ALOGI("sscanf error other\n");
+            free(set_alarm);
+            return -1;
+        }
+    }
+    else if ((ret = regexec(&reg_sec,buffer,0,NULL,0)) == 0) //Retrieve the incoming buffer string according to matching rule 2
+    {
+        sec = (ssize_t)atoi(buffer); //string convert ssize_t
+    }
+    else //matching rule 1 and 2 all fail
+    {
+        regerror(ret,&reg_sec,ebuff,256); //free memony
+        ALOGI(ebuff);
+        regfree(&reg_alm); 
+        regfree(&reg_sec);
+        return -1;
+    }
+
+    regfree(&reg_alm);
+    regfree(&reg_sec);
+    
+    return sec;
+}
\ No newline at end of file
diff --git a/src/lynq/lib/libpoweralarm/include/format_change.h b/src/lynq/lib/libpoweralarm/include/format_change.h
new file mode 100644
index 0000000..0656c9f
--- /dev/null
+++ b/src/lynq/lib/libpoweralarm/include/format_change.h
@@ -0,0 +1,15 @@
+#ifndef _FORMAT_CHANGE_H_
+#define _FORMAT_CHANGE_H_
+
+#include<stdio.h>
+#include<stdlib.h>
+#include<regex.h>
+#include<stdbool.h>
+#include<time.h>
+#include<string.h>
+
+
+ssize_t format_change(char *buffer);
+
+
+#endif
\ No newline at end of file
diff --git a/src/lynq/lib/libpoweralarm/libpoweralarm.c b/src/lynq/lib/libpoweralarm/libpoweralarm.c
new file mode 100644
index 0000000..ac3203c
--- /dev/null
+++ b/src/lynq/lib/libpoweralarm/libpoweralarm.c
@@ -0,0 +1,86 @@
+#include<stdio.h>
+#include<stdlib.h>
+#include<unistd.h>
+#include<stdbool.h>
+#include<log/log.h>
+#include"./include/format_change.h"
+
+
+#define LOG_TAG "libpoweralarm" 
+#define RTCFILE_POWERALARM "/sys/class/rtc/rtc0/poweralarm"
+
+#define RTCFILE_WAKEALARM "/sys/class/rtc/rtc0/wakealarm"
+
+extern "C" ssize_t wakealarm(char *buffer);
+
+
+extern "C" ssize_t poweralarm(char *buffer);
+
+ssize_t poweralarm(char *buffer);
+
+ssize_t wakealarm(char *buffer);
+/*****************************************************************************
+* 
+*   Prototype    : poweralarm
+*   Description  : set shutdown wake-up alarm clock 
+*   Input        : char *buffer ;  input format : 04-23-15-30-00 ( Mon-Day-Hour-Min-Sec ) Or  1200 ( seconds )              
+*   Output       : None
+*   Return Value : -1: error ; >0: set to wake up the devices after seconds
+*
+*****************************************************************************/
+ssize_t poweralarm(char *buffer)
+{
+    ssize_t sec;
+    char *time_buff = NULL;
+
+    sec = format_change(buffer); //computing seconds for shutdown alarm
+    if(sec < 0)
+    {
+        ALOGI("No Mattch\n");
+        return -1;
+    }
+    
+    time_buff = (char*)malloc(100);
+    bzero(time_buff,100);
+
+    sprintf(time_buff,"echo +%ld > %s",sec,RTCFILE_POWERALARM); //write formatted data into time_buff
+    system(time_buff);
+    ALOGI(time_buff);
+
+    free(time_buff);
+
+    return sec; // wake-up devices after sec seconds
+}
+
+
+/*****************************************************************************
+*   Prototype    : wakealarm
+*   Description  : set the wake-up alarm clock in low power mode
+*   Input        : char *buffer ;  input format : 04-23-15-30-00 ( Mon-Day-Hour-Min-Sec ) Or  1200 ( seconds )              
+*   Output       : None
+*   Return Value : -1: error ; >0: set to wake up the devices after seconds
+*
+*****************************************************************************/
+ssize_t wakealarm(char *buffer)
+{
+    ssize_t sec;
+    char *time_buff = NULL;
+
+    sec = format_change(buffer); //computing seconds for lowpower alarm
+    if(sec < 0)
+    {
+        ALOGI("No Mattch\n");
+        return -1;
+    }
+    
+    time_buff = (char*)malloc(100);
+    bzero(time_buff,100);
+
+    sprintf(time_buff,"echo +%ld > %s",sec,RTCFILE_WAKEALARM); //write formatted data into time_buff
+    system(time_buff);
+    ALOGI(time_buff);
+
+    free(time_buff);
+
+    return sec; // wake-up devices after sec seconds
+}
diff --git a/src/lynq/lib/libpoweralarm/makefile b/src/lynq/lib/libpoweralarm/makefile
new file mode 100644
index 0000000..3cdf04f
--- /dev/null
+++ b/src/lynq/lib/libpoweralarm/makefile
@@ -0,0 +1,69 @@
+SHELL = /bin/sh
+RM = rm -f
+
+LOCAL_CFLAGS := -Wall \
+                -std=gnu++14 \
+                -g -Os \
+                -flto \
+                -DRIL_SHLIB \
+                -DATCI_PARSE \
+                -fPIC \
+                -DKEEP_ALIVE \
+                -DECALL_SUPPORT \
+               
+
+
+
+$(warning ################# libautosuspend ROOT: $(ROOT),includedir:$(includedir))
+LOCAL_PATH   = .
+
+LOCAL_C_INCLUDES = \
+  -I. \
+  -I$(ROOT)$(includedir)/logger \
+  -I$(ROOT)$(includedir)/liblog \
+
+
+LOCAL_LIBS := \
+    -L. \
+    -ldl \
+    -lstdc++ \
+    -llog \
+    -lcutils \
+    -lutils \
+    -lbinder \
+    -lpthread \
+    -llynq-log \
+
+
+SOURCES = $(wildcard *.c)
+
+EXECUTABLE = libpoweralarm.so
+
+OBJECTS=$(SOURCES:.c=.o)
+
+
+.PHONY: build clean install pack_rootfs 
+all: build
+$(EXECUTABLE): $(OBJECTS)
+	$(CXX) -shared -Wl,--no-undefined $(OBJECTS) $(LOCAL_LIBS) $(LOCAL_CFLAGS) $(LOCAL_C_INCLUDES) -o $@
+
+%.o : %.c
+	$(CXX) $(LOCAL_C_INCLUDES) $(LOCAL_CFLAGS) $(LOCAL_LIBS) -o $@ -c $<
+
+build:  $(EXECUTABLE)
+	$(warning ########## build $(EXECUTABLE)  ##########)
+install:
+	mkdir -p $(ROOT)$(base_libdir)/
+	install $(EXECUTABLE) $(ROOT)$(base_libdir)/
+	mkdir -p $(ROOT)$(includedir)/$(NAME)/sdk
+pack_rootfs:
+	mkdir -p $(PACK_INITRAMFS_TO)$(base_libdir)/
+	cp -af $(EXECUTABLE) $(PACK_INITRAMFS_TO)$(base_libdir)/
+	$(CROSS)strip $(PACK_INITRAMFS_TO)$(base_libdir)/$(EXECUTABLE)
+	mkdir -p $(PACK_TO)$(base_libdir)/
+	cp -af $(EXECUTABLE) $(PACK_TO)$(base_libdir)/
+	$(CROSS)strip $(PACK_TO)$(base_libdir)/$(EXECUTABLE)
+.PHONY: clean
+clean:
+	$(RM) $(OBJECTS) $(EXECUTABLE)
+	-find . -name "*.o" -delete