142986fb8SJan Kotas // SPDX-License-Identifier: GPL-2.0
242986fb8SJan Kotas
342986fb8SJan Kotas /*
442986fb8SJan Kotas * Copyright 2019 Cadence
542986fb8SJan Kotas *
642986fb8SJan Kotas * Authors:
742986fb8SJan Kotas * Jan Kotas <jank@cadence.com>
842986fb8SJan Kotas */
942986fb8SJan Kotas
1042986fb8SJan Kotas #include <linux/module.h>
1142986fb8SJan Kotas #include <linux/platform_device.h>
1242986fb8SJan Kotas #include <linux/of.h>
1342986fb8SJan Kotas #include <linux/io.h>
1442986fb8SJan Kotas #include <linux/rtc.h>
1542986fb8SJan Kotas #include <linux/clk.h>
1642986fb8SJan Kotas #include <linux/bcd.h>
1742986fb8SJan Kotas #include <linux/bitfield.h>
1842986fb8SJan Kotas #include <linux/interrupt.h>
1942986fb8SJan Kotas #include <linux/pm_wakeirq.h>
2042986fb8SJan Kotas
2142986fb8SJan Kotas /* Registers */
2242986fb8SJan Kotas #define CDNS_RTC_CTLR 0x00
2342986fb8SJan Kotas #define CDNS_RTC_HMR 0x04
2442986fb8SJan Kotas #define CDNS_RTC_TIMR 0x08
2542986fb8SJan Kotas #define CDNS_RTC_CALR 0x0C
2642986fb8SJan Kotas #define CDNS_RTC_TIMAR 0x10
2742986fb8SJan Kotas #define CDNS_RTC_CALAR 0x14
2842986fb8SJan Kotas #define CDNS_RTC_AENR 0x18
2942986fb8SJan Kotas #define CDNS_RTC_EFLR 0x1C
3042986fb8SJan Kotas #define CDNS_RTC_IENR 0x20
3142986fb8SJan Kotas #define CDNS_RTC_IDISR 0x24
3242986fb8SJan Kotas #define CDNS_RTC_IMSKR 0x28
3342986fb8SJan Kotas #define CDNS_RTC_STSR 0x2C
3442986fb8SJan Kotas #define CDNS_RTC_KRTCR 0x30
3542986fb8SJan Kotas
3642986fb8SJan Kotas /* Control */
3742986fb8SJan Kotas #define CDNS_RTC_CTLR_TIME BIT(0)
3842986fb8SJan Kotas #define CDNS_RTC_CTLR_CAL BIT(1)
3942986fb8SJan Kotas #define CDNS_RTC_CTLR_TIME_CAL (CDNS_RTC_CTLR_TIME | CDNS_RTC_CTLR_CAL)
4042986fb8SJan Kotas
4142986fb8SJan Kotas /* Status */
4242986fb8SJan Kotas #define CDNS_RTC_STSR_VT BIT(0)
4342986fb8SJan Kotas #define CDNS_RTC_STSR_VC BIT(1)
4442986fb8SJan Kotas #define CDNS_RTC_STSR_VTA BIT(2)
4542986fb8SJan Kotas #define CDNS_RTC_STSR_VCA BIT(3)
4642986fb8SJan Kotas #define CDNS_RTC_STSR_VT_VC (CDNS_RTC_STSR_VT | CDNS_RTC_STSR_VC)
4742986fb8SJan Kotas #define CDNS_RTC_STSR_VTA_VCA (CDNS_RTC_STSR_VTA | CDNS_RTC_STSR_VCA)
4842986fb8SJan Kotas
4942986fb8SJan Kotas /* Keep RTC */
5042986fb8SJan Kotas #define CDNS_RTC_KRTCR_KRTC BIT(0)
5142986fb8SJan Kotas
5242986fb8SJan Kotas /* Alarm, Event, Interrupt */
5342986fb8SJan Kotas #define CDNS_RTC_AEI_HOS BIT(0)
5442986fb8SJan Kotas #define CDNS_RTC_AEI_SEC BIT(1)
5542986fb8SJan Kotas #define CDNS_RTC_AEI_MIN BIT(2)
5642986fb8SJan Kotas #define CDNS_RTC_AEI_HOUR BIT(3)
5742986fb8SJan Kotas #define CDNS_RTC_AEI_DATE BIT(4)
5842986fb8SJan Kotas #define CDNS_RTC_AEI_MNTH BIT(5)
5942986fb8SJan Kotas #define CDNS_RTC_AEI_ALRM BIT(6)
6042986fb8SJan Kotas
6142986fb8SJan Kotas /* Time */
6242986fb8SJan Kotas #define CDNS_RTC_TIME_H GENMASK(7, 0)
6342986fb8SJan Kotas #define CDNS_RTC_TIME_S GENMASK(14, 8)
6442986fb8SJan Kotas #define CDNS_RTC_TIME_M GENMASK(22, 16)
6542986fb8SJan Kotas #define CDNS_RTC_TIME_HR GENMASK(29, 24)
6642986fb8SJan Kotas #define CDNS_RTC_TIME_PM BIT(30)
6742986fb8SJan Kotas #define CDNS_RTC_TIME_CH BIT(31)
6842986fb8SJan Kotas
6942986fb8SJan Kotas /* Calendar */
7042986fb8SJan Kotas #define CDNS_RTC_CAL_DAY GENMASK(2, 0)
7142986fb8SJan Kotas #define CDNS_RTC_CAL_M GENMASK(7, 3)
7242986fb8SJan Kotas #define CDNS_RTC_CAL_D GENMASK(13, 8)
7342986fb8SJan Kotas #define CDNS_RTC_CAL_Y GENMASK(23, 16)
7442986fb8SJan Kotas #define CDNS_RTC_CAL_C GENMASK(29, 24)
7542986fb8SJan Kotas #define CDNS_RTC_CAL_CH BIT(31)
7642986fb8SJan Kotas
7742986fb8SJan Kotas #define CDNS_RTC_MAX_REGS_TRIES 3
7842986fb8SJan Kotas
7942986fb8SJan Kotas struct cdns_rtc {
8042986fb8SJan Kotas struct rtc_device *rtc_dev;
8142986fb8SJan Kotas struct clk *pclk;
8242986fb8SJan Kotas struct clk *ref_clk;
8342986fb8SJan Kotas void __iomem *regs;
8442986fb8SJan Kotas int irq;
8542986fb8SJan Kotas };
8642986fb8SJan Kotas
cdns_rtc_set_enabled(struct cdns_rtc * crtc,bool enabled)8742986fb8SJan Kotas static void cdns_rtc_set_enabled(struct cdns_rtc *crtc, bool enabled)
8842986fb8SJan Kotas {
8942986fb8SJan Kotas u32 reg = enabled ? 0x0 : CDNS_RTC_CTLR_TIME_CAL;
9042986fb8SJan Kotas
9142986fb8SJan Kotas writel(reg, crtc->regs + CDNS_RTC_CTLR);
9242986fb8SJan Kotas }
9342986fb8SJan Kotas
cdns_rtc_get_enabled(struct cdns_rtc * crtc)9442986fb8SJan Kotas static bool cdns_rtc_get_enabled(struct cdns_rtc *crtc)
9542986fb8SJan Kotas {
9642986fb8SJan Kotas return !(readl(crtc->regs + CDNS_RTC_CTLR) & CDNS_RTC_CTLR_TIME_CAL);
9742986fb8SJan Kotas }
9842986fb8SJan Kotas
cdns_rtc_irq_handler(int irq,void * id)9942986fb8SJan Kotas static irqreturn_t cdns_rtc_irq_handler(int irq, void *id)
10042986fb8SJan Kotas {
10142986fb8SJan Kotas struct device *dev = id;
10242986fb8SJan Kotas struct cdns_rtc *crtc = dev_get_drvdata(dev);
10342986fb8SJan Kotas
10442986fb8SJan Kotas /* Reading the register clears it */
10542986fb8SJan Kotas if (!(readl(crtc->regs + CDNS_RTC_EFLR) & CDNS_RTC_AEI_ALRM))
10642986fb8SJan Kotas return IRQ_NONE;
10742986fb8SJan Kotas
10842986fb8SJan Kotas rtc_update_irq(crtc->rtc_dev, 1, RTC_IRQF | RTC_AF);
10942986fb8SJan Kotas return IRQ_HANDLED;
11042986fb8SJan Kotas }
11142986fb8SJan Kotas
cdns_rtc_time2reg(struct rtc_time * tm)11242986fb8SJan Kotas static u32 cdns_rtc_time2reg(struct rtc_time *tm)
11342986fb8SJan Kotas {
11442986fb8SJan Kotas return FIELD_PREP(CDNS_RTC_TIME_S, bin2bcd(tm->tm_sec))
11542986fb8SJan Kotas | FIELD_PREP(CDNS_RTC_TIME_M, bin2bcd(tm->tm_min))
11642986fb8SJan Kotas | FIELD_PREP(CDNS_RTC_TIME_HR, bin2bcd(tm->tm_hour));
11742986fb8SJan Kotas }
11842986fb8SJan Kotas
cdns_rtc_reg2time(u32 reg,struct rtc_time * tm)11942986fb8SJan Kotas static void cdns_rtc_reg2time(u32 reg, struct rtc_time *tm)
12042986fb8SJan Kotas {
12142986fb8SJan Kotas tm->tm_sec = bcd2bin(FIELD_GET(CDNS_RTC_TIME_S, reg));
12242986fb8SJan Kotas tm->tm_min = bcd2bin(FIELD_GET(CDNS_RTC_TIME_M, reg));
12342986fb8SJan Kotas tm->tm_hour = bcd2bin(FIELD_GET(CDNS_RTC_TIME_HR, reg));
12442986fb8SJan Kotas }
12542986fb8SJan Kotas
cdns_rtc_read_time(struct device * dev,struct rtc_time * tm)12642986fb8SJan Kotas static int cdns_rtc_read_time(struct device *dev, struct rtc_time *tm)
12742986fb8SJan Kotas {
12842986fb8SJan Kotas struct cdns_rtc *crtc = dev_get_drvdata(dev);
12942986fb8SJan Kotas u32 reg;
13042986fb8SJan Kotas
13142986fb8SJan Kotas /* If the RTC is disabled, assume the values are invalid */
13242986fb8SJan Kotas if (!cdns_rtc_get_enabled(crtc))
13342986fb8SJan Kotas return -EINVAL;
13442986fb8SJan Kotas
13542986fb8SJan Kotas cdns_rtc_set_enabled(crtc, false);
13642986fb8SJan Kotas
13742986fb8SJan Kotas reg = readl(crtc->regs + CDNS_RTC_TIMR);
13842986fb8SJan Kotas cdns_rtc_reg2time(reg, tm);
13942986fb8SJan Kotas
14042986fb8SJan Kotas reg = readl(crtc->regs + CDNS_RTC_CALR);
14142986fb8SJan Kotas tm->tm_mday = bcd2bin(FIELD_GET(CDNS_RTC_CAL_D, reg));
14242986fb8SJan Kotas tm->tm_mon = bcd2bin(FIELD_GET(CDNS_RTC_CAL_M, reg)) - 1;
14342986fb8SJan Kotas tm->tm_year = bcd2bin(FIELD_GET(CDNS_RTC_CAL_Y, reg))
14442986fb8SJan Kotas + bcd2bin(FIELD_GET(CDNS_RTC_CAL_C, reg)) * 100 - 1900;
14542986fb8SJan Kotas tm->tm_wday = bcd2bin(FIELD_GET(CDNS_RTC_CAL_DAY, reg)) - 1;
14642986fb8SJan Kotas
14742986fb8SJan Kotas cdns_rtc_set_enabled(crtc, true);
14842986fb8SJan Kotas return 0;
14942986fb8SJan Kotas }
15042986fb8SJan Kotas
cdns_rtc_set_time(struct device * dev,struct rtc_time * tm)15142986fb8SJan Kotas static int cdns_rtc_set_time(struct device *dev, struct rtc_time *tm)
15242986fb8SJan Kotas {
15342986fb8SJan Kotas struct cdns_rtc *crtc = dev_get_drvdata(dev);
15442986fb8SJan Kotas u32 timr, calr, stsr;
15542986fb8SJan Kotas int ret = -EIO;
15642986fb8SJan Kotas int year = tm->tm_year + 1900;
15742986fb8SJan Kotas int tries;
15842986fb8SJan Kotas
15942986fb8SJan Kotas cdns_rtc_set_enabled(crtc, false);
16042986fb8SJan Kotas
16142986fb8SJan Kotas timr = cdns_rtc_time2reg(tm);
16242986fb8SJan Kotas
16342986fb8SJan Kotas calr = FIELD_PREP(CDNS_RTC_CAL_D, bin2bcd(tm->tm_mday))
16442986fb8SJan Kotas | FIELD_PREP(CDNS_RTC_CAL_M, bin2bcd(tm->tm_mon + 1))
16542986fb8SJan Kotas | FIELD_PREP(CDNS_RTC_CAL_Y, bin2bcd(year % 100))
16642986fb8SJan Kotas | FIELD_PREP(CDNS_RTC_CAL_C, bin2bcd(year / 100))
16742986fb8SJan Kotas | FIELD_PREP(CDNS_RTC_CAL_DAY, tm->tm_wday + 1);
16842986fb8SJan Kotas
16942986fb8SJan Kotas /* Update registers, check valid flags */
17042986fb8SJan Kotas for (tries = 0; tries < CDNS_RTC_MAX_REGS_TRIES; tries++) {
17142986fb8SJan Kotas writel(timr, crtc->regs + CDNS_RTC_TIMR);
17242986fb8SJan Kotas writel(calr, crtc->regs + CDNS_RTC_CALR);
17342986fb8SJan Kotas stsr = readl(crtc->regs + CDNS_RTC_STSR);
17442986fb8SJan Kotas
17542986fb8SJan Kotas if ((stsr & CDNS_RTC_STSR_VT_VC) == CDNS_RTC_STSR_VT_VC) {
17642986fb8SJan Kotas ret = 0;
17742986fb8SJan Kotas break;
17842986fb8SJan Kotas }
17942986fb8SJan Kotas }
18042986fb8SJan Kotas
18142986fb8SJan Kotas cdns_rtc_set_enabled(crtc, true);
18242986fb8SJan Kotas return ret;
18342986fb8SJan Kotas }
18442986fb8SJan Kotas
cdns_rtc_alarm_irq_enable(struct device * dev,unsigned int enabled)18542986fb8SJan Kotas static int cdns_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
18642986fb8SJan Kotas {
18742986fb8SJan Kotas struct cdns_rtc *crtc = dev_get_drvdata(dev);
18842986fb8SJan Kotas
18942986fb8SJan Kotas if (enabled) {
19042986fb8SJan Kotas writel((CDNS_RTC_AEI_SEC | CDNS_RTC_AEI_MIN | CDNS_RTC_AEI_HOUR
19142986fb8SJan Kotas | CDNS_RTC_AEI_DATE | CDNS_RTC_AEI_MNTH),
19242986fb8SJan Kotas crtc->regs + CDNS_RTC_AENR);
19342986fb8SJan Kotas writel(CDNS_RTC_AEI_ALRM, crtc->regs + CDNS_RTC_IENR);
19442986fb8SJan Kotas } else {
19542986fb8SJan Kotas writel(0, crtc->regs + CDNS_RTC_AENR);
19642986fb8SJan Kotas writel(CDNS_RTC_AEI_ALRM, crtc->regs + CDNS_RTC_IDISR);
19742986fb8SJan Kotas }
19842986fb8SJan Kotas
19942986fb8SJan Kotas return 0;
20042986fb8SJan Kotas }
20142986fb8SJan Kotas
cdns_rtc_read_alarm(struct device * dev,struct rtc_wkalrm * alarm)20242986fb8SJan Kotas static int cdns_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
20342986fb8SJan Kotas {
20442986fb8SJan Kotas struct cdns_rtc *crtc = dev_get_drvdata(dev);
20542986fb8SJan Kotas u32 reg;
20642986fb8SJan Kotas
20742986fb8SJan Kotas reg = readl(crtc->regs + CDNS_RTC_TIMAR);
20842986fb8SJan Kotas cdns_rtc_reg2time(reg, &alarm->time);
20942986fb8SJan Kotas
21042986fb8SJan Kotas reg = readl(crtc->regs + CDNS_RTC_CALAR);
21142986fb8SJan Kotas alarm->time.tm_mday = bcd2bin(FIELD_GET(CDNS_RTC_CAL_D, reg));
21242986fb8SJan Kotas alarm->time.tm_mon = bcd2bin(FIELD_GET(CDNS_RTC_CAL_M, reg)) - 1;
21342986fb8SJan Kotas
21442986fb8SJan Kotas return 0;
21542986fb8SJan Kotas }
21642986fb8SJan Kotas
cdns_rtc_set_alarm(struct device * dev,struct rtc_wkalrm * alarm)21742986fb8SJan Kotas static int cdns_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
21842986fb8SJan Kotas {
21942986fb8SJan Kotas struct cdns_rtc *crtc = dev_get_drvdata(dev);
22042986fb8SJan Kotas int ret = -EIO;
22142986fb8SJan Kotas int tries;
22242986fb8SJan Kotas u32 timar, calar, stsr;
22342986fb8SJan Kotas
22442986fb8SJan Kotas cdns_rtc_alarm_irq_enable(dev, 0);
22542986fb8SJan Kotas
22642986fb8SJan Kotas timar = cdns_rtc_time2reg(&alarm->time);
22742986fb8SJan Kotas calar = FIELD_PREP(CDNS_RTC_CAL_D, bin2bcd(alarm->time.tm_mday))
22842986fb8SJan Kotas | FIELD_PREP(CDNS_RTC_CAL_M, bin2bcd(alarm->time.tm_mon + 1));
22942986fb8SJan Kotas
23042986fb8SJan Kotas /* Update registers, check valid alarm flags */
23142986fb8SJan Kotas for (tries = 0; tries < CDNS_RTC_MAX_REGS_TRIES; tries++) {
23242986fb8SJan Kotas writel(timar, crtc->regs + CDNS_RTC_TIMAR);
23342986fb8SJan Kotas writel(calar, crtc->regs + CDNS_RTC_CALAR);
23442986fb8SJan Kotas stsr = readl(crtc->regs + CDNS_RTC_STSR);
23542986fb8SJan Kotas
23642986fb8SJan Kotas if ((stsr & CDNS_RTC_STSR_VTA_VCA) == CDNS_RTC_STSR_VTA_VCA) {
23742986fb8SJan Kotas ret = 0;
23842986fb8SJan Kotas break;
23942986fb8SJan Kotas }
24042986fb8SJan Kotas }
24142986fb8SJan Kotas
24242986fb8SJan Kotas if (!ret)
24342986fb8SJan Kotas cdns_rtc_alarm_irq_enable(dev, alarm->enabled);
24442986fb8SJan Kotas return ret;
24542986fb8SJan Kotas }
24642986fb8SJan Kotas
24742986fb8SJan Kotas static const struct rtc_class_ops cdns_rtc_ops = {
24842986fb8SJan Kotas .read_time = cdns_rtc_read_time,
24942986fb8SJan Kotas .set_time = cdns_rtc_set_time,
25042986fb8SJan Kotas .read_alarm = cdns_rtc_read_alarm,
25142986fb8SJan Kotas .set_alarm = cdns_rtc_set_alarm,
25242986fb8SJan Kotas .alarm_irq_enable = cdns_rtc_alarm_irq_enable,
25342986fb8SJan Kotas };
25442986fb8SJan Kotas
cdns_rtc_probe(struct platform_device * pdev)25542986fb8SJan Kotas static int cdns_rtc_probe(struct platform_device *pdev)
25642986fb8SJan Kotas {
25742986fb8SJan Kotas struct cdns_rtc *crtc;
25842986fb8SJan Kotas int ret;
25942986fb8SJan Kotas unsigned long ref_clk_freq;
26042986fb8SJan Kotas
26142986fb8SJan Kotas crtc = devm_kzalloc(&pdev->dev, sizeof(*crtc), GFP_KERNEL);
26242986fb8SJan Kotas if (!crtc)
26342986fb8SJan Kotas return -ENOMEM;
26442986fb8SJan Kotas
26509ef18bcSYueHaibing crtc->regs = devm_platform_ioremap_resource(pdev, 0);
26642986fb8SJan Kotas if (IS_ERR(crtc->regs))
26742986fb8SJan Kotas return PTR_ERR(crtc->regs);
26842986fb8SJan Kotas
26942986fb8SJan Kotas crtc->irq = platform_get_irq(pdev, 0);
27042986fb8SJan Kotas if (crtc->irq < 0)
27142986fb8SJan Kotas return -EINVAL;
27242986fb8SJan Kotas
27342986fb8SJan Kotas crtc->pclk = devm_clk_get(&pdev->dev, "pclk");
27442986fb8SJan Kotas if (IS_ERR(crtc->pclk)) {
27542986fb8SJan Kotas ret = PTR_ERR(crtc->pclk);
27642986fb8SJan Kotas dev_err(&pdev->dev,
27742986fb8SJan Kotas "Failed to retrieve the peripheral clock, %d\n", ret);
27842986fb8SJan Kotas return ret;
27942986fb8SJan Kotas }
28042986fb8SJan Kotas
28142986fb8SJan Kotas crtc->ref_clk = devm_clk_get(&pdev->dev, "ref_clk");
28242986fb8SJan Kotas if (IS_ERR(crtc->ref_clk)) {
28342986fb8SJan Kotas ret = PTR_ERR(crtc->ref_clk);
28442986fb8SJan Kotas dev_err(&pdev->dev,
28542986fb8SJan Kotas "Failed to retrieve the reference clock, %d\n", ret);
28642986fb8SJan Kotas return ret;
28742986fb8SJan Kotas }
28842986fb8SJan Kotas
28942986fb8SJan Kotas crtc->rtc_dev = devm_rtc_allocate_device(&pdev->dev);
29044c638ceSAlexandre Belloni if (IS_ERR(crtc->rtc_dev))
29144c638ceSAlexandre Belloni return PTR_ERR(crtc->rtc_dev);
29242986fb8SJan Kotas
29342986fb8SJan Kotas platform_set_drvdata(pdev, crtc);
29442986fb8SJan Kotas
29542986fb8SJan Kotas ret = clk_prepare_enable(crtc->pclk);
29642986fb8SJan Kotas if (ret) {
29742986fb8SJan Kotas dev_err(&pdev->dev,
29842986fb8SJan Kotas "Failed to enable the peripheral clock, %d\n", ret);
29942986fb8SJan Kotas return ret;
30042986fb8SJan Kotas }
30142986fb8SJan Kotas
30242986fb8SJan Kotas ret = clk_prepare_enable(crtc->ref_clk);
30342986fb8SJan Kotas if (ret) {
30442986fb8SJan Kotas dev_err(&pdev->dev,
30542986fb8SJan Kotas "Failed to enable the reference clock, %d\n", ret);
30642986fb8SJan Kotas goto err_disable_pclk;
30742986fb8SJan Kotas }
30842986fb8SJan Kotas
30942986fb8SJan Kotas ref_clk_freq = clk_get_rate(crtc->ref_clk);
31042986fb8SJan Kotas if ((ref_clk_freq != 1) && (ref_clk_freq != 100)) {
31142986fb8SJan Kotas dev_err(&pdev->dev,
31242986fb8SJan Kotas "Invalid reference clock frequency %lu Hz.\n",
31342986fb8SJan Kotas ref_clk_freq);
31442986fb8SJan Kotas ret = -EINVAL;
31542986fb8SJan Kotas goto err_disable_ref_clk;
31642986fb8SJan Kotas }
31742986fb8SJan Kotas
31842986fb8SJan Kotas ret = devm_request_irq(&pdev->dev, crtc->irq,
31942986fb8SJan Kotas cdns_rtc_irq_handler, 0,
32042986fb8SJan Kotas dev_name(&pdev->dev), &pdev->dev);
32142986fb8SJan Kotas if (ret) {
32242986fb8SJan Kotas dev_err(&pdev->dev,
32342986fb8SJan Kotas "Failed to request interrupt for the device, %d\n",
32442986fb8SJan Kotas ret);
32542986fb8SJan Kotas goto err_disable_ref_clk;
32642986fb8SJan Kotas }
32742986fb8SJan Kotas
32842986fb8SJan Kotas /* The RTC supports 01.01.1900 - 31.12.2999 */
32942986fb8SJan Kotas crtc->rtc_dev->range_min = mktime64(1900, 1, 1, 0, 0, 0);
33042986fb8SJan Kotas crtc->rtc_dev->range_max = mktime64(2999, 12, 31, 23, 59, 59);
33142986fb8SJan Kotas
33242986fb8SJan Kotas crtc->rtc_dev->ops = &cdns_rtc_ops;
33342986fb8SJan Kotas device_init_wakeup(&pdev->dev, true);
33442986fb8SJan Kotas
33542986fb8SJan Kotas /* Always use 24-hour mode and keep the RTC values */
33642986fb8SJan Kotas writel(0, crtc->regs + CDNS_RTC_HMR);
33742986fb8SJan Kotas writel(CDNS_RTC_KRTCR_KRTC, crtc->regs + CDNS_RTC_KRTCR);
33842986fb8SJan Kotas
339fdcfd854SBartosz Golaszewski ret = devm_rtc_register_device(crtc->rtc_dev);
34044c638ceSAlexandre Belloni if (ret)
34142986fb8SJan Kotas goto err_disable_wakeup;
34242986fb8SJan Kotas
34342986fb8SJan Kotas return 0;
34442986fb8SJan Kotas
34542986fb8SJan Kotas err_disable_wakeup:
34642986fb8SJan Kotas device_init_wakeup(&pdev->dev, false);
34742986fb8SJan Kotas
34842986fb8SJan Kotas err_disable_ref_clk:
34942986fb8SJan Kotas clk_disable_unprepare(crtc->ref_clk);
35042986fb8SJan Kotas
35142986fb8SJan Kotas err_disable_pclk:
35242986fb8SJan Kotas clk_disable_unprepare(crtc->pclk);
35342986fb8SJan Kotas
35442986fb8SJan Kotas return ret;
35542986fb8SJan Kotas }
35642986fb8SJan Kotas
cdns_rtc_remove(struct platform_device * pdev)357*0b9efd82SUwe Kleine-König static void cdns_rtc_remove(struct platform_device *pdev)
35842986fb8SJan Kotas {
35942986fb8SJan Kotas struct cdns_rtc *crtc = platform_get_drvdata(pdev);
36042986fb8SJan Kotas
36142986fb8SJan Kotas cdns_rtc_alarm_irq_enable(&pdev->dev, 0);
36242986fb8SJan Kotas device_init_wakeup(&pdev->dev, 0);
36342986fb8SJan Kotas
36442986fb8SJan Kotas clk_disable_unprepare(crtc->pclk);
36542986fb8SJan Kotas clk_disable_unprepare(crtc->ref_clk);
36642986fb8SJan Kotas }
36742986fb8SJan Kotas
36842986fb8SJan Kotas #ifdef CONFIG_PM_SLEEP
cdns_rtc_suspend(struct device * dev)36942986fb8SJan Kotas static int cdns_rtc_suspend(struct device *dev)
37042986fb8SJan Kotas {
37142986fb8SJan Kotas struct cdns_rtc *crtc = dev_get_drvdata(dev);
37242986fb8SJan Kotas
37342986fb8SJan Kotas if (device_may_wakeup(dev))
37442986fb8SJan Kotas enable_irq_wake(crtc->irq);
37542986fb8SJan Kotas
37642986fb8SJan Kotas return 0;
37742986fb8SJan Kotas }
37842986fb8SJan Kotas
cdns_rtc_resume(struct device * dev)37942986fb8SJan Kotas static int cdns_rtc_resume(struct device *dev)
38042986fb8SJan Kotas {
38142986fb8SJan Kotas struct cdns_rtc *crtc = dev_get_drvdata(dev);
38242986fb8SJan Kotas
38342986fb8SJan Kotas if (device_may_wakeup(dev))
38442986fb8SJan Kotas disable_irq_wake(crtc->irq);
38542986fb8SJan Kotas
38642986fb8SJan Kotas return 0;
38742986fb8SJan Kotas }
38842986fb8SJan Kotas #endif
38942986fb8SJan Kotas
39042986fb8SJan Kotas static SIMPLE_DEV_PM_OPS(cdns_rtc_pm_ops, cdns_rtc_suspend, cdns_rtc_resume);
39142986fb8SJan Kotas
39242986fb8SJan Kotas static const struct of_device_id cdns_rtc_of_match[] = {
39342986fb8SJan Kotas { .compatible = "cdns,rtc-r109v3" },
39442986fb8SJan Kotas { },
39542986fb8SJan Kotas };
39642986fb8SJan Kotas MODULE_DEVICE_TABLE(of, cdns_rtc_of_match);
39742986fb8SJan Kotas
39842986fb8SJan Kotas static struct platform_driver cdns_rtc_driver = {
39942986fb8SJan Kotas .driver = {
40042986fb8SJan Kotas .name = "cdns-rtc",
40142986fb8SJan Kotas .of_match_table = cdns_rtc_of_match,
40242986fb8SJan Kotas .pm = &cdns_rtc_pm_ops,
40342986fb8SJan Kotas },
40442986fb8SJan Kotas .probe = cdns_rtc_probe,
405*0b9efd82SUwe Kleine-König .remove_new = cdns_rtc_remove,
40642986fb8SJan Kotas };
40742986fb8SJan Kotas module_platform_driver(cdns_rtc_driver);
40842986fb8SJan Kotas
40942986fb8SJan Kotas MODULE_AUTHOR("Jan Kotas <jank@cadence.com>");
41042986fb8SJan Kotas MODULE_DESCRIPTION("Cadence RTC driver");
41142986fb8SJan Kotas MODULE_LICENSE("GPL v2");
41242986fb8SJan Kotas MODULE_ALIAS("platform:cdns-rtc");
413