123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278 |
- /*
- * Copyright (C) 2018 MediaTek, Inc.
- * Copyright (C) 2021 XiaoMi, Inc.
- * Author: Wilma Wu <wilma.wu@mediatek.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
- #include <asm/div64.h>
- #include <linux/kernel.h>
- #include <linux/module.h>
- #include <linux/platform_device.h>
- #include <linux/pm.h>
- #include <linux/pm_wakeup.h>
- #include <linux/reboot.h>
- #include <linux/regmap.h>
- #include <linux/rtc.h>
- #include <linux/sched/clock.h>
- #include <linux/spinlock.h>
- #include <linux/types.h>
- #include <linux/bitops.h>
- #include <linux/mfd/mt6358/core.h>
- #include <linux/irqdomain.h>
- #include <linux/platform_device.h>
- #include <linux/of_address.h>
- #include <linux/of_irq.h>
- #include <linux/io.h>
- #include <asm/div64.h>
- /* For KPOC 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 "../misc/mediatek/include/mt-plat/mtk_boot_common.h"
- #include "../misc/mediatek/include/mt-plat/mtk_reboot.h"
- #include <linux/debugfs.h>
- #ifdef pr_fmt
- #undef pr_fmt
- #endif
- #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
- #define RTC_NAME "mt-rtc"
- #define IPIMB
- /* 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_MIN_YEAR_OFFSET (RTC_MIN_YEAR - RTC_BASE_YEAR)
- /* Min, Hour, Dom... register offset to RTC_TC_SEC */
- #define RTC_OFFSET_SEC 0
- #define RTC_OFFSET_MIN 1
- #define RTC_OFFSET_HOUR 2
- #define RTC_OFFSET_DOM 3
- #define RTC_OFFSET_DOW 4
- #define RTC_OFFSET_MTH 5
- #define RTC_OFFSET_YEAR 6
- #define RTC_OFFSET_COUNT 7
- #define RTC_DSN_ID 0x580
- #define RTC_BBPU 0x8
- #define RTC_IRQ_STA 0xa
- #define RTC_IRQ_EN 0xc
- #define RTC_AL_MASK 0x10
- #define RTC_TC_SEC 0x12
- #define RTC_AL_SEC 0x20
- #define RTC_AL_MIN 0x22
- #define RTC_AL_HOU 0x24
- #define RTC_AL_DOM 0x26
- #define RTC_AL_DOW 0x28
- #define RTC_AL_MTH 0x2a
- #define RTC_AL_YEA 0x2c
- #define RTC_OSC32CON 0x2e
- #define RTC_POWERKEY1 0x30
- #define RTC_POWERKEY2 0x32
- #define RTC_PDN1 0x34
- #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_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_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)
- static u16 rtc_alarm_reg[RTC_OFFSET_COUNT][3] = {
- {RTC_AL_SEC, RTC_AL_SEC_MASK, 0},
- {RTC_AL_MIN, RTC_AL_MIN_MASK, 0},
- {RTC_AL_HOU, RTC_AL_HOU_MASK, 0},
- {RTC_AL_DOM, RTC_AL_DOM_MASK, 0},
- {RTC_AL_DOW, RTC_AL_DOW_MASK, 0},
- {RTC_AL_MTH, RTC_AL_MTH_MASK, 0},
- {RTC_AL_YEA, RTC_AL_YEA_MASK, 0},
- };
- static u16 rtc_pwron_reg[RTC_OFFSET_COUNT][3] = {
- {RTC_SPAR0, RTC_PWRON_SEC_MASK, RTC_PWRON_SEC_SHIFT},
- {RTC_SPAR1, RTC_PWRON_MIN_MASK, RTC_PWRON_MIN_SHIFT},
- {RTC_SPAR1, RTC_PWRON_HOU_MASK, RTC_PWRON_HOU_SHIFT},
- {RTC_SPAR1, RTC_PWRON_DOM_MASK, RTC_PWRON_DOM_SHIFT},
- {0, 0, 0},
- {RTC_PDN2, RTC_PWRON_MTH_MASK, RTC_PWRON_MTH_SHIFT},
- {RTC_PDN2, RTC_PWRON_YEA_MASK, RTC_PWRON_YEA_SHIFT},
- };
- enum rtc_reg_set {
- RTC_REG,
- RTC_MASK,
- RTC_SHIFT
- };
- enum rtc_irq_sta {
- RTC_NONE,
- RTC_ALSTA,
- RTC_TCSTA,
- RTC_LPSTA,
- };
- struct mt6358_rtc {
- struct device *dev;
- struct rtc_device *rtc_dev;
- spinlock_t lock;
- struct regmap *regmap;
- int irq;
- u32 addr_base;
- struct work_struct work;
- struct completion comp;
- };
- static struct mt6358_rtc *mt_rtc;
- static struct wakeup_source *mt6358_rtc_suspend_lock;
- static int rtc_show_time;
- static int rtc_show_alarm = 1;
- static int apply_lpsd_solution;
- /*for KPOC alarm*/
- static bool rtc_pm_notifier_registered;
- static bool kpoc_alarm;
- static unsigned long rtc_pm_status;
- static int alarm1m15s;
- module_param(rtc_show_time, int, 0644);
- module_param(rtc_show_alarm, int, 0644);
- static int rtc_alarm_enabled = 1;
- static ssize_t mtk_rtc_debug_write(struct file *file,
- const char __user *buf, size_t size, loff_t *ppos)
- {
- char lbuf[128];
- char option[16];
- int setting;
- ssize_t res;
- if (*ppos != 0 || size >= sizeof(lbuf) || size == 0)
- return -EINVAL;
- res = simple_write_to_buffer(lbuf, sizeof(lbuf) - 1, ppos, buf, size);
- if (res <= 0)
- return -EFAULT;
- lbuf[size] = '\0';
- if (sscanf(lbuf, "%15s %d", option, &setting) != 2) {
- pr_notice("Invalid para %s\n", lbuf);
- return -EFAULT;
- }
- if (!strncmp(option, "alarm", strlen("alarm"))) {
- pr_notice("alarm = %d\n", setting);
- rtc_alarm_enabled = setting;
- if (rtc_alarm_enabled)
- enable_irq(mt_rtc->irq);
- else
- disable_irq_nosync(mt_rtc->irq);
- }
- return size;
- }
- static int mtk_rtc_debug_show(struct seq_file *s, void *unused)
- {
- seq_printf(s, "rtc alarm %s\n",
- rtc_alarm_enabled ? "enabled" : "disabled");
- return 0;
- }
- static int mtk_rtc_debug_open(struct inode *inode,
- struct file *file)
- {
- return single_open(file, mtk_rtc_debug_show, NULL);
- }
- static const struct file_operations mtk_rtc_debug_ops = {
- .open = mtk_rtc_debug_open,
- .read = seq_read,
- .write = mtk_rtc_debug_write,
- .llseek = seq_lseek,
- .release = single_release,
- };
- void __attribute__((weak)) arch_reset(char mode, const char *cmd)
- {
- pr_info("arch_reset is not ready\n");
- }
- static int rtc_read(unsigned int reg, unsigned int *val)
- {
- return regmap_read(mt_rtc->regmap, mt_rtc->addr_base + reg, val);
- }
- static int rtc_write(unsigned int reg, unsigned int val)
- {
- return regmap_write(mt_rtc->regmap, mt_rtc->addr_base + reg, val);
- }
- static int rtc_update_bits(unsigned int reg,
- unsigned int mask, unsigned int val)
- {
- return regmap_update_bits(mt_rtc->regmap,
- mt_rtc->addr_base + reg, mask, val);
- }
- static int rtc_field_read(unsigned int reg,
- unsigned int mask, unsigned int shift, unsigned int *val)
- {
- int ret;
- unsigned int reg_val = 0;
- ret = rtc_read(reg, ®_val);
- if (ret != 0)
- return ret;
- reg_val &= mask;
- reg_val >>= shift;
- *val = reg_val;
- return ret;
- }
- #define BULK_WRITE 0
- #define BULK_READ 1
- static int rtc_bulk_access(int mode, unsigned int reg, void *val,
- size_t val_count)
- {
- if (mode == BULK_WRITE) {
- return regmap_bulk_write(mt_rtc->regmap,
- mt_rtc->addr_base + reg, val, val_count);
- } else if (mode == BULK_READ) {
- return regmap_bulk_read(mt_rtc->regmap,
- mt_rtc->addr_base + reg, val, val_count);
- } else
- return -EPERM;
- }
- static int rtc_write_trigger(void)
- {
- int ret, bbpu = 0;
- unsigned long long timeout = sched_clock() + 500000000;
- u32 pwrkey1 = 0, pwrkey2 = 0, sec = 0;
- ret = rtc_write(RTC_WRTGR, 1);
- if (ret < 0)
- return ret;
- do {
- ret = rtc_read(RTC_BBPU, &bbpu);
- if (ret < 0)
- break;
- if ((bbpu & RTC_BBPU_CBUSY) == 0)
- break;
- else if (sched_clock() > timeout) {
- rtc_read(RTC_BBPU, &bbpu);
- rtc_read(RTC_POWERKEY1, &pwrkey1);
- rtc_read(RTC_POWERKEY2, &pwrkey2);
- rtc_read(RTC_TC_SEC, &sec);
- pr_err("%s, wait cbusy timeout, %x, %x, %x, %d\n",
- __func__, bbpu, pwrkey1, pwrkey2, sec);
- ret = -ETIMEDOUT;
- break;
- }
- } while (1);
- return ret;
- }
- static int mtk_rtc_read_time(struct rtc_time *tm)
- {
- u16 data[RTC_OFFSET_COUNT];
- int ret;
- u32 sec = 0;
- do {
- ret = rtc_bulk_access(BULK_READ, RTC_TC_SEC,
- data, RTC_OFFSET_COUNT);
- 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_TC_SEC, &sec);
- if (ret < 0)
- goto exit;
- } while (sec < tm->tm_sec);
- return ret;
- exit:
- pr_err("%s error\n", __func__);
- return ret;
- }
- static int mtk_rtc_set_alarm(struct rtc_time *tm)
- {
- int ret, i;
- u16 data[RTC_OFFSET_COUNT];
- data[RTC_OFFSET_SEC] = tm->tm_sec & RTC_AL_SEC_MASK;
- data[RTC_OFFSET_MIN] = tm->tm_min & RTC_AL_MIN_MASK;
- data[RTC_OFFSET_HOUR] = tm->tm_hour & RTC_AL_HOU_MASK;
- data[RTC_OFFSET_DOM] = tm->tm_mday & RTC_AL_DOM_MASK;
- data[RTC_OFFSET_MTH] = tm->tm_mon & RTC_AL_MTH_MASK;
- data[RTC_OFFSET_YEAR] = tm->tm_year & RTC_AL_YEA_MASK;
- for (i = RTC_OFFSET_SEC; i < RTC_OFFSET_COUNT; i++) {
- if (i == RTC_OFFSET_DOW)
- continue;
- ret = rtc_update_bits(rtc_alarm_reg[i][RTC_REG],
- rtc_alarm_reg[i][RTC_MASK], data[i]);
- if (ret < 0)
- goto exit;
- }
- ret = rtc_write(RTC_AL_MASK, RTC_AL_MASK_DOW); /* mask DOW */
- if (ret < 0)
- goto exit;
- ret = rtc_write_trigger();
- if (ret < 0)
- goto exit;
- ret = rtc_update_bits(RTC_IRQ_EN,
- RTC_IRQ_EN_ONESHOT_AL,
- RTC_IRQ_EN_ONESHOT_AL);
- if (ret < 0)
- goto exit;
- ret = rtc_write_trigger();
- if (ret < 0)
- goto exit;
- return ret;
- exit:
- pr_err("%s error\n", __func__);
- return ret;
- }
- bool mtk_rtc_is_pwron_alarm(struct rtc_time *nowtm, struct rtc_time *tm)
- {
- u32 pdn1 = 0;
- u32 data[RTC_OFFSET_COUNT] = {0};
- int ret, i;
- ret = rtc_read(RTC_PDN1, &pdn1);
- if (ret < 0)
- goto exit;
- pr_notice("pdn1 = 0x%4x\n", pdn1);
- if (pdn1 & RTC_PDN1_PWRON_TIME) { /* power-on time is available */
- ret = mtk_rtc_read_time(nowtm);
- if (ret < 0)
- goto exit;
- for (i = RTC_OFFSET_SEC; i < RTC_OFFSET_COUNT; i++) {
- if (i == RTC_OFFSET_DOW)
- continue;
- ret = rtc_field_read(rtc_pwron_reg[i][RTC_REG],
- rtc_pwron_reg[i][RTC_MASK],
- rtc_pwron_reg[i][RTC_SHIFT], &data[i]);
- if (ret < 0)
- goto exit;
- }
- tm->tm_sec = data[RTC_OFFSET_SEC];
- tm->tm_min = data[RTC_OFFSET_MIN];
- tm->tm_hour = data[RTC_OFFSET_HOUR];
- tm->tm_mday = data[RTC_OFFSET_DOM];
- tm->tm_mon = data[RTC_OFFSET_MTH];
- tm->tm_year = data[RTC_OFFSET_YEAR];
- return true;
- }
- return false;
- exit:
- pr_err("%s error\n", __func__);
- return false;
- }
- static int mtk_rtc_set_pwron_alarm_time(struct rtc_time *tm)
- {
- u16 data[RTC_OFFSET_COUNT];
- int ret, i;
- pr_err("%s\n", __func__);
- 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_pwron_reg[i][RTC_REG],
- rtc_pwron_reg[i][RTC_MASK], data[i]);
- if (ret < 0)
- goto exit;
- ret = rtc_write_trigger();
- if (ret < 0)
- goto exit;
- }
- return ret;
- exit:
- pr_err("%s error\n", __func__);
- return ret;
- }
- static int mtk_rtc_set_pwron_alarm(bool enable, struct rtc_time *tm, bool logo)
- {
- u16 pdn1 = 0, pdn2 = 0;
- int ret;
- ret = mtk_rtc_set_pwron_alarm_time(tm);
- if (ret < 0)
- goto exit;
- if (enable)
- pdn1 = RTC_PDN1_PWRON_TIME;
- ret = rtc_update_bits(RTC_PDN1, RTC_PDN1_PWRON_TIME, pdn1);
- if (ret < 0)
- goto exit;
- if (logo)
- pdn2 = RTC_PDN2_PWRON_LOGO;
- ret = rtc_update_bits(RTC_PDN2, RTC_PDN2_PWRON_LOGO, pdn2);
- if (ret < 0)
- goto exit;
- ret = rtc_write_trigger();
- if (ret < 0)
- goto exit;
- return ret;
- exit:
- pr_err("%s error\n", __func__);
- return ret;
- }
- void rtc_read_pwron_alarm(struct rtc_wkalrm *alm)
- {
- struct rtc_time *tm;
- u32 pdn1 = 0, pdn2 = 0;
- u16 data[RTC_OFFSET_COUNT];
- unsigned long flags;
- int ret;
- if (alm == NULL)
- return;
- tm = &alm->time;
- spin_lock_irqsave(&mt_rtc->lock, flags);
- ret = rtc_read(RTC_PDN1, &pdn1);
- if (ret < 0)
- goto exit;
- ret = rtc_read(RTC_PDN2, &pdn2);
- if (ret < 0)
- goto exit;
- alm->enabled = (pdn1 & RTC_PDN1_PWRON_TIME ?
- (pdn2 & RTC_PDN2_PWRON_LOGO ? 3 : 2) : 0);
- /* return Power-On Alarm bit */
- alm->pending = !!(pdn2 & RTC_PDN2_PWRON_ALARM);
- ret = rtc_bulk_access(BULK_READ, RTC_AL_SEC, data, RTC_OFFSET_COUNT);
- if (ret < 0)
- goto exit;
- 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;
- spin_unlock_irqrestore(&mt_rtc->lock, flags);
- tm->tm_year += RTC_MIN_YEAR_OFFSET;
- tm->tm_mon -= 1;
- if (rtc_show_alarm) {
- pr_notice("power-on = %04d/%02d/%02d %02d:%02d:%02d (%d)(%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, alm->pending);
- }
- return;
- exit:
- pr_err("%s error\n", __func__);
- }
- #ifdef CONFIG_PM
- #define PM_DUMMY 0xFFFF
- static int rtc_pm_event(struct notifier_block *notifier, unsigned long pm_event,
- void *unused)
- {
- pr_notice("%s = %lu\n", __func__, pm_event);
- 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) {
- pr_notice("%s trigger reboot\n", __func__);
- complete(&mt_rtc->comp);
- kpoc_alarm = false;
- }
- return NOTIFY_DONE;
- }
- static struct notifier_block rtc_pm_notifier_func = {
- .notifier_call = rtc_pm_event,
- .priority = 0,
- };
- #endif /* CONFIG_PM */
- static void mtk_rtc_work_queue(struct work_struct *work)
- {
- struct mt6358_rtc *rtc = container_of(work, struct mt6358_rtc, work);
- unsigned long ret;
- unsigned int msecs;
- ret = wait_for_completion_timeout(&rtc->comp, msecs_to_jiffies(30000));
- if (!ret) {
- pr_notice("%s timeout\n", __func__);
- BUG_ON(1);
- } else {
- msecs = jiffies_to_msecs(ret);
- pr_notice("%s timeleft= %d\n", __func__, msecs);
- kernel_restart("kpoc");
- }
- }
- static void mtk_rtc_reboot(void)
- {
- __pm_stay_awake(mt6358_rtc_suspend_lock);
- init_completion(&mt_rtc->comp);
- schedule_work_on(cpumask_first(cpu_online_mask), &mt_rtc->work);
- if (!rtc_pm_notifier_registered)
- goto reboot;
- if (rtc_pm_status != PM_SUSPEND_PREPARE)
- goto reboot;
- kpoc_alarm = true;
- pr_notice("%s:wait\n", __func__);
- return;
- reboot:
- pr_notice("%s:trigger\n", __func__);
- complete(&mt_rtc->comp);
- }
- #ifndef USER_BUILD_KERNEL
- void mtk_rtc_lp_exception(void)
- {
- u32 bbpu = 0, irqsta = 0, irqen = 0, osc32 = 0;
- u32 pwrkey1 = 0, pwrkey2 = 0, prot = 0, con = 0, sec1 = 0, sec2 = 0;
- rtc_read(RTC_BBPU, &bbpu);
- rtc_read(RTC_IRQ_STA, &irqsta);
- rtc_read(RTC_IRQ_EN, &irqen);
- rtc_read(RTC_OSC32CON, &osc32);
- rtc_read(RTC_POWERKEY1, &pwrkey1);
- rtc_read(RTC_POWERKEY2, &pwrkey2);
- rtc_read(RTC_PROT, &prot);
- rtc_read(RTC_CON, &con);
- rtc_read(RTC_TC_SEC, &sec1);
- mdelay(2000);
- rtc_read(RTC_TC_SEC, &sec2);
- pr_emerg("!!! 32K WAS STOPPED !!!\n"
- "RTC_BBPU = 0x%x\n"
- "RTC_IRQ_STA = 0x%x\n"
- "RTC_IRQ_EN = 0x%x\n"
- "RTC_OSC32CON = 0x%x\n"
- "RTC_POWERKEY1 = 0x%x\n"
- "RTC_POWERKEY2 = 0x%x\n"
- "RTC_PROT = 0x%x\n"
- "RTC_CON = 0x%x\n"
- "RTC_TC_SEC = %02d\n"
- "RTC_TC_SEC = %02d\n",
- bbpu, irqsta, irqen, osc32, pwrkey1, pwrkey2, prot, con, sec1,
- sec2);
- }
- #endif
- static int mtk_rtc_is_alarm_irq(void)
- {
- u32 irqsta = 0, bbpu;
- int ret, val;
- ret = rtc_read(RTC_IRQ_STA, &irqsta); /* read clear */
- if ((ret == 0) && (irqsta & RTC_IRQ_STA_AL)) {
- bbpu = RTC_BBPU_KEY | RTC_BBPU_PWREN;
- rtc_write(RTC_BBPU, bbpu);
- val = rtc_write_trigger();
- if (val < 0)
- pr_notice("%s error\n", __func__);
- return RTC_ALSTA;
- }
- #ifndef USER_BUILD_KERNEL
- if ((ret == 0) && (irqsta & RTC_IRQ_STA_LP)) {
- mtk_rtc_lp_exception();
- return RTC_LPSTA;
- }
- #endif
- return RTC_NONE;
- }
- static void mtk_rtc_update_pwron_alarm_flag(void)
- {
- int ret;
- ret = rtc_update_bits(RTC_PDN1, RTC_PDN1_PWRON_TIME, 0);
- if (ret < 0)
- goto exit;
- ret = rtc_update_bits(RTC_PDN2,
- RTC_PDN2_PWRON_ALARM,
- RTC_PDN2_PWRON_ALARM);
- if (ret < 0)
- goto exit;
- ret = rtc_write_trigger();
- if (ret < 0)
- goto exit;
- return;
- exit:
- pr_err("%s error\n", __func__);
- }
- static void mtk_rtc_reset_bbpu_alarm_status(void)
- {
- u32 bbpu;
- int ret;
- if (apply_lpsd_solution) {
- pr_notice("%s:lpsd\n", __func__);
- return;
- }
- bbpu = RTC_BBPU_KEY | RTC_BBPU_PWREN | RTC_BBPU_RESET_AL;
- rtc_write(RTC_BBPU, bbpu);
- ret = rtc_write_trigger();
- if (ret < 0)
- pr_err("%s error\n", __func__);
- return;
- }
- static irqreturn_t mtk_rtc_irq_handler(int irq, void *data)
- {
- bool pwron_alm = false, pwron_alarm = false;
- struct rtc_time nowtm, tm;
- int status = RTC_NONE;
- unsigned long flags;
- spin_lock_irqsave(&mt_rtc->lock, flags);
- status = mtk_rtc_is_alarm_irq();
- pr_notice("%s:%d\n", __func__, status);
- if (status == RTC_NONE) {
- spin_unlock_irqrestore(&mt_rtc->lock, flags);
- return IRQ_NONE;
- }
- if (status == RTC_LPSTA) {
- spin_unlock_irqrestore(&mt_rtc->lock, flags);
- return IRQ_HANDLED;
- }
- mtk_rtc_reset_bbpu_alarm_status();
- pwron_alarm = mtk_rtc_is_pwron_alarm(&nowtm, &tm);
- nowtm.tm_year += RTC_MIN_YEAR;
- tm.tm_year += RTC_MIN_YEAR;
- if (pwron_alarm) {
- time64_t now_time, time;
- now_time =
- mktime(nowtm.tm_year, nowtm.tm_mon, nowtm.tm_mday,
- nowtm.tm_hour, nowtm.tm_min, nowtm.tm_sec);
- if (now_time == -1) {
- spin_unlock_irqrestore(&mt_rtc->lock, flags);
- goto out;
- }
- time =
- mktime(tm.tm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour,
- tm.tm_min, tm.tm_sec);
- if (time == -1) {
- spin_unlock_irqrestore(&mt_rtc->lock, flags);
- goto out;
- }
- /* power on */
- if (now_time >= time - 1 && now_time <= time + 4) {
- if (get_boot_mode() == KERNEL_POWER_OFF_CHARGING_BOOT
- || get_boot_mode() == LOW_POWER_OFF_CHARGING_BOOT) {
- mtk_rtc_reboot();
- spin_unlock_irqrestore(&mt_rtc->lock, flags);
- disable_irq_nosync(mt_rtc->irq);
- goto out;
- } else {
- mtk_rtc_update_pwron_alarm_flag();
- 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_set_alarm(&tm);
- }
- }
- spin_unlock_irqrestore(&mt_rtc->lock, flags);
- out:
- if (mt_rtc->rtc_dev != NULL)
- rtc_update_irq(mt_rtc->rtc_dev, 1, RTC_IRQF | RTC_AF);
- if (rtc_show_alarm)
- pr_notice("%s time is up\n", pwron_alm ? "power-on" : "alarm");
- return IRQ_HANDLED;
- }
- static int rtc_ops_read_time(struct device *dev, struct rtc_time *tm)
- {
- unsigned long long time;
- unsigned long flags;
- struct mt6358_rtc *rtc = dev_get_drvdata(dev);
- int ret;
- spin_lock_irqsave(&rtc->lock, flags);
- ret = mtk_rtc_read_time(tm);
- if (ret < 0)
- goto exit;
- spin_unlock_irqrestore(&rtc->lock, flags);
- tm->tm_year += RTC_MIN_YEAR_OFFSET;
- tm->tm_mon--;
- time = rtc_tm_to_time64(tm);
- do_div(time, 86400);
- time += 4;
- tm->tm_wday = do_div(time, 7); /* 1970/01/01 is Thursday */
- if (rtc_show_time) {
- pr_notice("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);
- }
- return ret;
- exit:
- spin_unlock_irqrestore(&rtc->lock, flags);
- pr_err("%s error\n", __func__);
- return ret;
- }
- static int rtc_ops_set_time(struct device *dev, struct rtc_time *tm)
- {
- struct mt6358_rtc *rtc = dev_get_drvdata(dev);
- unsigned long flags;
- u16 data[RTC_OFFSET_COUNT];
- int ret;
- if (tm->tm_year > 195) {
- pr_err("%s: invalid year %04d > 2095\n",
- __func__, tm->tm_year + RTC_BASE_YEAR);
- return -EINVAL;
- }
- pr_notice("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;
- spin_lock_irqsave(&rtc->lock, flags);
- ret = rtc_bulk_access(BULK_WRITE, RTC_TC_SEC, data, RTC_OFFSET_COUNT);
- if (ret < 0)
- goto exit;
- ret = rtc_write_trigger();
- if (ret < 0)
- goto exit;
- spin_unlock_irqrestore(&rtc->lock, flags);
- return ret;
- exit:
- spin_unlock_irqrestore(&rtc->lock, flags);
- pr_err("%s error\n", __func__);
- return ret;
- }
- static int rtc_ops_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
- {
- unsigned long flags;
- struct rtc_time *tm = &alm->time;
- struct mt6358_rtc *rtc = dev_get_drvdata(dev);
- u32 irqen = 0, pdn2 = 0;
- u16 data[RTC_OFFSET_COUNT];
- int ret;
- spin_lock_irqsave(&rtc->lock, flags);
- ret = rtc_read(RTC_IRQ_EN, &irqen);
- if (ret < 0)
- goto exit;
- alm->enabled = !!(irqen & RTC_IRQ_EN_AL);
- /* return Power-On Alarm bit */
- ret = rtc_read(RTC_PDN2, &pdn2);
- if (ret < 0)
- goto exit;
- alm->pending = !!(pdn2 & RTC_PDN2_PWRON_ALARM);
- ret = rtc_bulk_access(BULK_READ, RTC_AL_SEC, data, RTC_OFFSET_COUNT);
- if (ret < 0)
- goto exit;
- 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;
- spin_unlock_irqrestore(&rtc->lock, flags);
- tm->tm_year += RTC_MIN_YEAR_OFFSET;
- tm->tm_mon--;
- pr_notice("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 ret;
- exit:
- spin_unlock_irqrestore(&rtc->lock, flags);
- pr_err("%s error\n", __func__);
- return ret;
- }
- static int rtc_ops_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
- {
- unsigned long flags;
- struct rtc_time tm = alm->time;
- ktime_t target;
- struct mt6358_rtc *rtc = dev_get_drvdata(dev);
- u32 irqsta;
- int ret = 0;
- if (tm.tm_year > 195) {
- pr_err("%s: invalid year %04d > 2095\n",
- __func__, tm.tm_year + RTC_BASE_YEAR);
- return -EINVAL;
- }
- 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);
- } else if (alm->enabled == 5) {
- /* Power on system 1 minute earlier */
- alarm1m15s = 1;
- }
- tm.tm_year -= RTC_MIN_YEAR_OFFSET;
- tm.tm_mon++;
- pr_notice("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);
- spin_lock_irqsave(&rtc->lock, flags);
- if (alm->enabled == 2) { /* enable power-on alarm */
- ret = mtk_rtc_set_pwron_alarm(true, &tm, false);
- } else if (alm->enabled == 3 || alm->enabled == 5) {
- /* enable power-on alarm with logo */
- ret = mtk_rtc_set_pwron_alarm(true, &tm, true);
- } else if (alm->enabled == 4) { /* disable power-on alarm */
- ret = mtk_rtc_set_pwron_alarm(false, &tm, false);
- alarm1m15s = 0;
- }
- if (ret < 0)
- goto exit;
- /* disable alarm and clear Power-On Alarm bit */
- ret = rtc_update_bits(RTC_IRQ_EN, RTC_IRQ_EN_AL, 0);
- if (ret < 0)
- goto exit;
- ret = rtc_update_bits(RTC_PDN2, RTC_PDN2_PWRON_ALARM, 0);
- if (ret < 0)
- goto exit;
- ret = rtc_write_trigger();
- if (ret < 0)
- goto exit;
- ret = rtc_read(RTC_IRQ_STA, &irqsta); /* read clear */
- if (ret < 0)
- goto exit;
- if (alm->enabled)
- ret = mtk_rtc_set_alarm(&tm);
- spin_unlock_irqrestore(&rtc->lock, flags);
- return ret;
- exit:
- spin_unlock_irqrestore(&rtc->lock, flags);
- pr_err("%s error\n", __func__);
- return ret;
- }
- static const struct rtc_class_ops rtc_ops = {
- .read_time = rtc_ops_read_time,
- .set_time = rtc_ops_set_time,
- .read_alarm = rtc_ops_read_alarm,
- .set_alarm = rtc_ops_set_alarm,
- };
- static void mtk_rtc_set_lp_irq(void)
- {
- unsigned int irqen = 0;
- int ret;
- #ifndef USER_BUILD_KERNEL
- irqen = RTC_IRQ_EN_LP;
- #endif
- ret = rtc_update_bits(RTC_IRQ_EN, RTC_IRQ_EN_LP, irqen);
- if (ret < 0)
- goto exit;
- ret = rtc_write_trigger();
- if (ret < 0)
- goto exit;
- return;
- exit:
- pr_err("%s error\n", __func__);
- }
- static int mtk_rtc_pdrv_probe(struct platform_device *pdev)
- {
- #ifndef IPIMB
- struct mt6358_chip *mt6358_chip = dev_get_drvdata(pdev->dev.parent);
- #endif
- struct mt6358_rtc *rtc;
- unsigned long flags;
- int ret;
- struct dentry *mtk_rtc_dir;
- struct dentry *mtk_rtc_file;
- rtc = devm_kzalloc(&pdev->dev, sizeof(struct mt6358_rtc), GFP_KERNEL);
- if (!rtc)
- return -ENOMEM;
- rtc->irq = platform_get_irq(pdev, 0);
- if (rtc->irq <= 0)
- return -EINVAL;
- pr_notice("%s: rtc->irq = %d(%d)\n", __func__, rtc->irq,
- platform_get_irq_byname(pdev, "rtc"));
- #ifndef IPIMB
- rtc->regmap = mt6358_chip->regmap;
- #else
- rtc->regmap = dev_get_regmap(pdev->dev.parent->parent, NULL);
- #endif
- if (!rtc->regmap) {
- pr_err("%s: get regmap failed\n", __func__);
- return -ENODEV;
- }
- rtc->dev = &pdev->dev;
- spin_lock_init(&rtc->lock);
- mt_rtc = rtc;
- platform_set_drvdata(pdev, rtc);
- 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);
- spin_lock_irqsave(&rtc->lock, flags);
- mtk_rtc_set_lp_irq();
- spin_unlock_irqrestore(&rtc->lock, flags);
- ret = request_threaded_irq(rtc->irq, NULL,
- mtk_rtc_irq_handler,
- IRQF_ONESHOT | IRQF_TRIGGER_HIGH,
- "mt6358-rtc", rtc);
- if (ret) {
- dev_dbg(&pdev->dev, "Failed to request alarm IRQ: %d: %d\n",
- rtc->irq, ret);
- goto out_dispose_irq;
- }
- device_init_wakeup(&pdev->dev, 1);
- mt6358_rtc_suspend_lock =
- wakeup_source_register(NULL, "mt6358-rtc suspend wakelock");
- /* register rtc device (/dev/rtc0) */
- rtc->rtc_dev = rtc_device_register(RTC_NAME,
- &pdev->dev, &rtc_ops, THIS_MODULE);
- if (IS_ERR(rtc->rtc_dev)) {
- dev_dbg(&pdev->dev, "register rtc device failed\n");
- ret = PTR_ERR(rtc->rtc_dev);
- goto out_free_irq;
- }
- if (of_property_read_bool(pdev->dev.of_node, "apply-lpsd-solution")) {
- apply_lpsd_solution = 1;
- pr_notice("%s: apply_lpsd_solution\n", __func__);
- }
- mtk_rtc_dir = debugfs_create_dir("mtk_rtc", NULL);
- if (!mtk_rtc_dir) {
- pr_err("create /sys/kernel/debug/mtk_rtc_dir failed\n");
- //return -ENOMEM;
- }
- mtk_rtc_file = debugfs_create_file("mtk_rtc", 0644,
- mtk_rtc_dir, NULL,
- &mtk_rtc_debug_ops);
- if (!mtk_rtc_file) {
- pr_err("create /sys/kernel/debug/mtk_rtc/mtk_rtc failed\n");
- //return -ENOMEM;
- }
- #ifdef CONFIG_PM
- if (register_pm_notifier(&rtc_pm_notifier_func))
- pr_notice("rtc pm failed\n");
- else
- rtc_pm_notifier_registered = true;
- #endif /* CONFIG_PM */
- INIT_WORK(&rtc->work, mtk_rtc_work_queue);
- return 0;
- out_free_irq:
- free_irq(rtc->irq, rtc->rtc_dev);
- out_dispose_irq:
- irq_dispose_mapping(rtc->irq);
- return ret;
- }
- static int mtk_rtc_pdrv_remove(struct platform_device *pdev)
- {
- struct mt6358_rtc *rtc = platform_get_drvdata(pdev);
- rtc_device_unregister(rtc->rtc_dev);
- return 0;
- }
- static void mtk_rtc_pdrv_shutdown(struct platform_device *pdev)
- {
- struct rtc_time rtc_time_now;
- struct rtc_time rtc_time_alarm;
- ktime_t ktime_now;
- ktime_t ktime_alarm;
- bool is_pwron_alarm;
- if (alarm1m15s == 1) {
- is_pwron_alarm = mtk_rtc_is_pwron_alarm(&rtc_time_now,
- &rtc_time_alarm);
- if (is_pwron_alarm) {
- rtc_time_now.tm_year += RTC_MIN_YEAR_OFFSET;
- rtc_time_now.tm_mon--;
- rtc_time_alarm.tm_year += RTC_MIN_YEAR_OFFSET;
- rtc_time_alarm.tm_mon--;
- pr_notice("now = %04d/%02d/%02d %02d:%02d:%02d\n",
- rtc_time_now.tm_year + 1900,
- rtc_time_now.tm_mon + 1,
- rtc_time_now.tm_mday,
- rtc_time_now.tm_hour,
- rtc_time_now.tm_min,
- rtc_time_now.tm_sec);
- pr_notice("alarm = %04d/%02d/%02d %02d:%02d:%02d\n",
- rtc_time_alarm.tm_year + 1900,
- rtc_time_alarm.tm_mon + 1,
- rtc_time_alarm.tm_mday,
- rtc_time_alarm.tm_hour,
- rtc_time_alarm.tm_min,
- rtc_time_alarm.tm_sec);
- ktime_now = rtc_tm_to_ktime(rtc_time_now);
- ktime_alarm = rtc_tm_to_ktime(rtc_time_alarm);
- if (ktime_after(ktime_alarm, ktime_now)) {
- /* alarm has not happened */
- ktime_alarm = ktime_sub_ms(ktime_alarm,
- MSEC_PER_SEC * 60);
- if (ktime_after(ktime_alarm, ktime_now))
- pr_notice("Alarm will happen after 1 minute\n");
- else {
- ktime_alarm = ktime_add_ms(ktime_now,
- MSEC_PER_SEC * 15);
- pr_notice("Alarm will happen in 15 seconds\n");
- }
- rtc_time_alarm = rtc_ktime_to_tm(ktime_alarm);
- pr_notice("new alarm = %04d/%02d/%02d %02d:%02d:%02d\n",
- rtc_time_alarm.tm_year + 1900,
- rtc_time_alarm.tm_mon + 1,
- rtc_time_alarm.tm_mday,
- rtc_time_alarm.tm_hour,
- rtc_time_alarm.tm_min,
- rtc_time_alarm.tm_sec);
- rtc_time_alarm.tm_year -= RTC_MIN_YEAR_OFFSET;
- rtc_time_alarm.tm_mon++;
- mtk_rtc_set_pwron_alarm_time(&rtc_time_alarm);
- mtk_rtc_set_alarm(&rtc_time_alarm);
- } else
- pr_notice("Alarm has happened before\n");
- } else
- pr_notice("No power-off alarm is set\n");
- }
- }
- static const struct of_device_id mt6358_rtc_of_match[] = {
- { .compatible = "mediatek,mt6357-rtc", },
- { .compatible = "mediatek,mt6358-rtc", },
- { .compatible = "mediatek,mt6359-rtc", },
- { }
- };
- MODULE_DEVICE_TABLE(of, mt6358_rtc_of_match);
- static struct platform_driver mtk_rtc_pdrv = {
- .probe = mtk_rtc_pdrv_probe,
- .remove = mtk_rtc_pdrv_remove,
- .shutdown = mtk_rtc_pdrv_shutdown,
- .driver = {
- .name = RTC_NAME,
- .owner = THIS_MODULE,
- .of_match_table = mt6358_rtc_of_match,
- },
- };
- module_platform_driver(mtk_rtc_pdrv);
- MODULE_LICENSE("GPL v2");
- MODULE_AUTHOR("Wilma Wu <wilma.wu@mediatek.com>");
- MODULE_DESCRIPTION("RTC Driver for MediaTek MT6358 PMIC");
|