1e91b94fdSAlexandre Belloni // SPDX-License-Identifier: GPL-2.0+
251aa905cSJoshua Henderson /*
351aa905cSJoshua Henderson * PIC32 RTC driver
451aa905cSJoshua Henderson *
551aa905cSJoshua Henderson * Joshua Henderson <joshua.henderson@microchip.com>
651aa905cSJoshua Henderson * Copyright (C) 2016 Microchip Technology Inc. All rights reserved.
751aa905cSJoshua Henderson *
851aa905cSJoshua Henderson */
951aa905cSJoshua Henderson #include <linux/init.h>
1051aa905cSJoshua Henderson #include <linux/module.h>
1151aa905cSJoshua Henderson #include <linux/of.h>
1251aa905cSJoshua Henderson #include <linux/platform_device.h>
1351aa905cSJoshua Henderson #include <linux/io.h>
1451aa905cSJoshua Henderson #include <linux/slab.h>
1551aa905cSJoshua Henderson #include <linux/clk.h>
1651aa905cSJoshua Henderson #include <linux/rtc.h>
1751aa905cSJoshua Henderson #include <linux/bcd.h>
1851aa905cSJoshua Henderson
1951aa905cSJoshua Henderson #include <asm/mach-pic32/pic32.h>
2051aa905cSJoshua Henderson
2151aa905cSJoshua Henderson #define PIC32_RTCCON 0x00
2251aa905cSJoshua Henderson #define PIC32_RTCCON_ON BIT(15)
2351aa905cSJoshua Henderson #define PIC32_RTCCON_SIDL BIT(13)
2451aa905cSJoshua Henderson #define PIC32_RTCCON_RTCCLKSEL (3 << 9)
2551aa905cSJoshua Henderson #define PIC32_RTCCON_RTCCLKON BIT(6)
2651aa905cSJoshua Henderson #define PIC32_RTCCON_RTCWREN BIT(3)
2751aa905cSJoshua Henderson #define PIC32_RTCCON_RTCSYNC BIT(2)
2851aa905cSJoshua Henderson #define PIC32_RTCCON_HALFSEC BIT(1)
2951aa905cSJoshua Henderson #define PIC32_RTCCON_RTCOE BIT(0)
3051aa905cSJoshua Henderson
3151aa905cSJoshua Henderson #define PIC32_RTCALRM 0x10
3251aa905cSJoshua Henderson #define PIC32_RTCALRM_ALRMEN BIT(15)
3351aa905cSJoshua Henderson #define PIC32_RTCALRM_CHIME BIT(14)
3451aa905cSJoshua Henderson #define PIC32_RTCALRM_PIV BIT(13)
3551aa905cSJoshua Henderson #define PIC32_RTCALRM_ALARMSYNC BIT(12)
3651aa905cSJoshua Henderson #define PIC32_RTCALRM_AMASK 0x0F00
3751aa905cSJoshua Henderson #define PIC32_RTCALRM_ARPT 0xFF
3851aa905cSJoshua Henderson
3951aa905cSJoshua Henderson #define PIC32_RTCHOUR 0x23
4051aa905cSJoshua Henderson #define PIC32_RTCMIN 0x22
4151aa905cSJoshua Henderson #define PIC32_RTCSEC 0x21
4251aa905cSJoshua Henderson #define PIC32_RTCYEAR 0x33
4351aa905cSJoshua Henderson #define PIC32_RTCMON 0x32
4451aa905cSJoshua Henderson #define PIC32_RTCDAY 0x31
4551aa905cSJoshua Henderson
4651aa905cSJoshua Henderson #define PIC32_ALRMTIME 0x40
4751aa905cSJoshua Henderson #define PIC32_ALRMDATE 0x50
4851aa905cSJoshua Henderson
4951aa905cSJoshua Henderson #define PIC32_ALRMHOUR 0x43
5051aa905cSJoshua Henderson #define PIC32_ALRMMIN 0x42
5151aa905cSJoshua Henderson #define PIC32_ALRMSEC 0x41
5251aa905cSJoshua Henderson #define PIC32_ALRMYEAR 0x53
5351aa905cSJoshua Henderson #define PIC32_ALRMMON 0x52
5451aa905cSJoshua Henderson #define PIC32_ALRMDAY 0x51
5551aa905cSJoshua Henderson
5651aa905cSJoshua Henderson struct pic32_rtc_dev {
5751aa905cSJoshua Henderson struct rtc_device *rtc;
5851aa905cSJoshua Henderson void __iomem *reg_base;
5951aa905cSJoshua Henderson struct clk *clk;
6051aa905cSJoshua Henderson spinlock_t alarm_lock;
6151aa905cSJoshua Henderson int alarm_irq;
6251aa905cSJoshua Henderson bool alarm_clk_enabled;
6351aa905cSJoshua Henderson };
6451aa905cSJoshua Henderson
pic32_rtc_alarm_clk_enable(struct pic32_rtc_dev * pdata,bool enable)6551aa905cSJoshua Henderson static void pic32_rtc_alarm_clk_enable(struct pic32_rtc_dev *pdata,
6651aa905cSJoshua Henderson bool enable)
6751aa905cSJoshua Henderson {
6851aa905cSJoshua Henderson unsigned long flags;
6951aa905cSJoshua Henderson
7051aa905cSJoshua Henderson spin_lock_irqsave(&pdata->alarm_lock, flags);
7151aa905cSJoshua Henderson if (enable) {
7251aa905cSJoshua Henderson if (!pdata->alarm_clk_enabled) {
7351aa905cSJoshua Henderson clk_enable(pdata->clk);
7451aa905cSJoshua Henderson pdata->alarm_clk_enabled = true;
7551aa905cSJoshua Henderson }
7651aa905cSJoshua Henderson } else {
7751aa905cSJoshua Henderson if (pdata->alarm_clk_enabled) {
7851aa905cSJoshua Henderson clk_disable(pdata->clk);
7951aa905cSJoshua Henderson pdata->alarm_clk_enabled = false;
8051aa905cSJoshua Henderson }
8151aa905cSJoshua Henderson }
8251aa905cSJoshua Henderson spin_unlock_irqrestore(&pdata->alarm_lock, flags);
8351aa905cSJoshua Henderson }
8451aa905cSJoshua Henderson
pic32_rtc_alarmirq(int irq,void * id)8551aa905cSJoshua Henderson static irqreturn_t pic32_rtc_alarmirq(int irq, void *id)
8651aa905cSJoshua Henderson {
8751aa905cSJoshua Henderson struct pic32_rtc_dev *pdata = (struct pic32_rtc_dev *)id;
8851aa905cSJoshua Henderson
8951aa905cSJoshua Henderson clk_enable(pdata->clk);
9051aa905cSJoshua Henderson rtc_update_irq(pdata->rtc, 1, RTC_AF | RTC_IRQF);
9151aa905cSJoshua Henderson clk_disable(pdata->clk);
9251aa905cSJoshua Henderson
9351aa905cSJoshua Henderson pic32_rtc_alarm_clk_enable(pdata, false);
9451aa905cSJoshua Henderson
9551aa905cSJoshua Henderson return IRQ_HANDLED;
9651aa905cSJoshua Henderson }
9751aa905cSJoshua Henderson
pic32_rtc_setaie(struct device * dev,unsigned int enabled)9851aa905cSJoshua Henderson static int pic32_rtc_setaie(struct device *dev, unsigned int enabled)
9951aa905cSJoshua Henderson {
10051aa905cSJoshua Henderson struct pic32_rtc_dev *pdata = dev_get_drvdata(dev);
10151aa905cSJoshua Henderson void __iomem *base = pdata->reg_base;
10251aa905cSJoshua Henderson
10351aa905cSJoshua Henderson clk_enable(pdata->clk);
10451aa905cSJoshua Henderson
10551aa905cSJoshua Henderson writel(PIC32_RTCALRM_ALRMEN,
10651aa905cSJoshua Henderson base + (enabled ? PIC32_SET(PIC32_RTCALRM) :
10751aa905cSJoshua Henderson PIC32_CLR(PIC32_RTCALRM)));
10851aa905cSJoshua Henderson
10951aa905cSJoshua Henderson clk_disable(pdata->clk);
11051aa905cSJoshua Henderson
11151aa905cSJoshua Henderson pic32_rtc_alarm_clk_enable(pdata, enabled);
11251aa905cSJoshua Henderson
11351aa905cSJoshua Henderson return 0;
11451aa905cSJoshua Henderson }
11551aa905cSJoshua Henderson
pic32_rtc_setfreq(struct device * dev,int freq)11651aa905cSJoshua Henderson static int pic32_rtc_setfreq(struct device *dev, int freq)
11751aa905cSJoshua Henderson {
11851aa905cSJoshua Henderson struct pic32_rtc_dev *pdata = dev_get_drvdata(dev);
11951aa905cSJoshua Henderson void __iomem *base = pdata->reg_base;
12051aa905cSJoshua Henderson
12151aa905cSJoshua Henderson clk_enable(pdata->clk);
12251aa905cSJoshua Henderson
12351aa905cSJoshua Henderson writel(PIC32_RTCALRM_AMASK, base + PIC32_CLR(PIC32_RTCALRM));
12451aa905cSJoshua Henderson writel(freq << 8, base + PIC32_SET(PIC32_RTCALRM));
12551aa905cSJoshua Henderson writel(PIC32_RTCALRM_CHIME, base + PIC32_SET(PIC32_RTCALRM));
12651aa905cSJoshua Henderson
12751aa905cSJoshua Henderson clk_disable(pdata->clk);
12851aa905cSJoshua Henderson
12951aa905cSJoshua Henderson return 0;
13051aa905cSJoshua Henderson }
13151aa905cSJoshua Henderson
pic32_rtc_gettime(struct device * dev,struct rtc_time * rtc_tm)13251aa905cSJoshua Henderson static int pic32_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm)
13351aa905cSJoshua Henderson {
13451aa905cSJoshua Henderson struct pic32_rtc_dev *pdata = dev_get_drvdata(dev);
13551aa905cSJoshua Henderson void __iomem *base = pdata->reg_base;
13651aa905cSJoshua Henderson unsigned int tries = 0;
13751aa905cSJoshua Henderson
13851aa905cSJoshua Henderson clk_enable(pdata->clk);
13951aa905cSJoshua Henderson
14051aa905cSJoshua Henderson do {
14151aa905cSJoshua Henderson rtc_tm->tm_hour = readb(base + PIC32_RTCHOUR);
14251aa905cSJoshua Henderson rtc_tm->tm_min = readb(base + PIC32_RTCMIN);
14351aa905cSJoshua Henderson rtc_tm->tm_mon = readb(base + PIC32_RTCMON);
14451aa905cSJoshua Henderson rtc_tm->tm_mday = readb(base + PIC32_RTCDAY);
14551aa905cSJoshua Henderson rtc_tm->tm_year = readb(base + PIC32_RTCYEAR);
14651aa905cSJoshua Henderson rtc_tm->tm_sec = readb(base + PIC32_RTCSEC);
14751aa905cSJoshua Henderson
14851aa905cSJoshua Henderson /*
14951aa905cSJoshua Henderson * The only way to work out whether the system was mid-update
15051aa905cSJoshua Henderson * when we read it is to check the second counter, and if it
15151aa905cSJoshua Henderson * is zero, then we re-try the entire read.
15251aa905cSJoshua Henderson */
15351aa905cSJoshua Henderson tries += 1;
15451aa905cSJoshua Henderson } while (rtc_tm->tm_sec == 0 && tries < 2);
15551aa905cSJoshua Henderson
15651aa905cSJoshua Henderson rtc_tm->tm_sec = bcd2bin(rtc_tm->tm_sec);
15751aa905cSJoshua Henderson rtc_tm->tm_min = bcd2bin(rtc_tm->tm_min);
15851aa905cSJoshua Henderson rtc_tm->tm_hour = bcd2bin(rtc_tm->tm_hour);
15951aa905cSJoshua Henderson rtc_tm->tm_mday = bcd2bin(rtc_tm->tm_mday);
16051aa905cSJoshua Henderson rtc_tm->tm_mon = bcd2bin(rtc_tm->tm_mon) - 1;
16151aa905cSJoshua Henderson rtc_tm->tm_year = bcd2bin(rtc_tm->tm_year);
16251aa905cSJoshua Henderson
16351aa905cSJoshua Henderson rtc_tm->tm_year += 100;
16451aa905cSJoshua Henderson
16593206f93SAndy Shevchenko dev_dbg(dev, "read time %ptR\n", rtc_tm);
16651aa905cSJoshua Henderson
16751aa905cSJoshua Henderson clk_disable(pdata->clk);
16822652ba7SAlexandre Belloni return 0;
16951aa905cSJoshua Henderson }
17051aa905cSJoshua Henderson
pic32_rtc_settime(struct device * dev,struct rtc_time * tm)17151aa905cSJoshua Henderson static int pic32_rtc_settime(struct device *dev, struct rtc_time *tm)
17251aa905cSJoshua Henderson {
17351aa905cSJoshua Henderson struct pic32_rtc_dev *pdata = dev_get_drvdata(dev);
17451aa905cSJoshua Henderson void __iomem *base = pdata->reg_base;
17551aa905cSJoshua Henderson
17693206f93SAndy Shevchenko dev_dbg(dev, "set time %ptR\n", tm);
17751aa905cSJoshua Henderson
17851aa905cSJoshua Henderson clk_enable(pdata->clk);
17951aa905cSJoshua Henderson writeb(bin2bcd(tm->tm_sec), base + PIC32_RTCSEC);
18051aa905cSJoshua Henderson writeb(bin2bcd(tm->tm_min), base + PIC32_RTCMIN);
18151aa905cSJoshua Henderson writeb(bin2bcd(tm->tm_hour), base + PIC32_RTCHOUR);
18251aa905cSJoshua Henderson writeb(bin2bcd(tm->tm_mday), base + PIC32_RTCDAY);
18351aa905cSJoshua Henderson writeb(bin2bcd(tm->tm_mon + 1), base + PIC32_RTCMON);
184c145e5f4SAlexandre Belloni writeb(bin2bcd(tm->tm_year - 100), base + PIC32_RTCYEAR);
18551aa905cSJoshua Henderson clk_disable(pdata->clk);
18651aa905cSJoshua Henderson
18751aa905cSJoshua Henderson return 0;
18851aa905cSJoshua Henderson }
18951aa905cSJoshua Henderson
pic32_rtc_getalarm(struct device * dev,struct rtc_wkalrm * alrm)19051aa905cSJoshua Henderson static int pic32_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm)
19151aa905cSJoshua Henderson {
19251aa905cSJoshua Henderson struct pic32_rtc_dev *pdata = dev_get_drvdata(dev);
19351aa905cSJoshua Henderson struct rtc_time *alm_tm = &alrm->time;
19451aa905cSJoshua Henderson void __iomem *base = pdata->reg_base;
19551aa905cSJoshua Henderson unsigned int alm_en;
19651aa905cSJoshua Henderson
19751aa905cSJoshua Henderson clk_enable(pdata->clk);
19851aa905cSJoshua Henderson alm_tm->tm_sec = readb(base + PIC32_ALRMSEC);
19951aa905cSJoshua Henderson alm_tm->tm_min = readb(base + PIC32_ALRMMIN);
20051aa905cSJoshua Henderson alm_tm->tm_hour = readb(base + PIC32_ALRMHOUR);
20151aa905cSJoshua Henderson alm_tm->tm_mon = readb(base + PIC32_ALRMMON);
20251aa905cSJoshua Henderson alm_tm->tm_mday = readb(base + PIC32_ALRMDAY);
20351aa905cSJoshua Henderson alm_tm->tm_year = readb(base + PIC32_ALRMYEAR);
20451aa905cSJoshua Henderson
20551aa905cSJoshua Henderson alm_en = readb(base + PIC32_RTCALRM);
20651aa905cSJoshua Henderson
20751aa905cSJoshua Henderson alrm->enabled = (alm_en & PIC32_RTCALRM_ALRMEN) ? 1 : 0;
20851aa905cSJoshua Henderson
20993206f93SAndy Shevchenko dev_dbg(dev, "getalarm: %d, %ptR\n", alm_en, alm_tm);
21051aa905cSJoshua Henderson
21151aa905cSJoshua Henderson alm_tm->tm_sec = bcd2bin(alm_tm->tm_sec);
21251aa905cSJoshua Henderson alm_tm->tm_min = bcd2bin(alm_tm->tm_min);
21351aa905cSJoshua Henderson alm_tm->tm_hour = bcd2bin(alm_tm->tm_hour);
21451aa905cSJoshua Henderson alm_tm->tm_mday = bcd2bin(alm_tm->tm_mday);
21551aa905cSJoshua Henderson alm_tm->tm_mon = bcd2bin(alm_tm->tm_mon) - 1;
21651aa905cSJoshua Henderson alm_tm->tm_year = bcd2bin(alm_tm->tm_year);
21751aa905cSJoshua Henderson
21851aa905cSJoshua Henderson clk_disable(pdata->clk);
21951aa905cSJoshua Henderson return 0;
22051aa905cSJoshua Henderson }
22151aa905cSJoshua Henderson
pic32_rtc_setalarm(struct device * dev,struct rtc_wkalrm * alrm)22251aa905cSJoshua Henderson static int pic32_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
22351aa905cSJoshua Henderson {
22451aa905cSJoshua Henderson struct pic32_rtc_dev *pdata = dev_get_drvdata(dev);
22551aa905cSJoshua Henderson struct rtc_time *tm = &alrm->time;
22651aa905cSJoshua Henderson void __iomem *base = pdata->reg_base;
22751aa905cSJoshua Henderson
22851aa905cSJoshua Henderson clk_enable(pdata->clk);
22993206f93SAndy Shevchenko dev_dbg(dev, "setalarm: %d, %ptR\n", alrm->enabled, tm);
23051aa905cSJoshua Henderson
23151aa905cSJoshua Henderson writel(0x00, base + PIC32_ALRMTIME);
23251aa905cSJoshua Henderson writel(0x00, base + PIC32_ALRMDATE);
23351aa905cSJoshua Henderson
23451aa905cSJoshua Henderson pic32_rtc_setaie(dev, alrm->enabled);
23551aa905cSJoshua Henderson
23651aa905cSJoshua Henderson clk_disable(pdata->clk);
23751aa905cSJoshua Henderson return 0;
23851aa905cSJoshua Henderson }
23951aa905cSJoshua Henderson
pic32_rtc_proc(struct device * dev,struct seq_file * seq)24051aa905cSJoshua Henderson static int pic32_rtc_proc(struct device *dev, struct seq_file *seq)
24151aa905cSJoshua Henderson {
24251aa905cSJoshua Henderson struct pic32_rtc_dev *pdata = dev_get_drvdata(dev);
24351aa905cSJoshua Henderson void __iomem *base = pdata->reg_base;
24451aa905cSJoshua Henderson unsigned int repeat;
24551aa905cSJoshua Henderson
24651aa905cSJoshua Henderson clk_enable(pdata->clk);
24751aa905cSJoshua Henderson
24851aa905cSJoshua Henderson repeat = readw(base + PIC32_RTCALRM);
24951aa905cSJoshua Henderson repeat &= PIC32_RTCALRM_ARPT;
25051aa905cSJoshua Henderson seq_printf(seq, "periodic_IRQ\t: %s\n", repeat ? "yes" : "no");
25151aa905cSJoshua Henderson
25251aa905cSJoshua Henderson clk_disable(pdata->clk);
25351aa905cSJoshua Henderson return 0;
25451aa905cSJoshua Henderson }
25551aa905cSJoshua Henderson
25651aa905cSJoshua Henderson static const struct rtc_class_ops pic32_rtcops = {
25751aa905cSJoshua Henderson .read_time = pic32_rtc_gettime,
25851aa905cSJoshua Henderson .set_time = pic32_rtc_settime,
25951aa905cSJoshua Henderson .read_alarm = pic32_rtc_getalarm,
26051aa905cSJoshua Henderson .set_alarm = pic32_rtc_setalarm,
26151aa905cSJoshua Henderson .proc = pic32_rtc_proc,
26251aa905cSJoshua Henderson .alarm_irq_enable = pic32_rtc_setaie,
26351aa905cSJoshua Henderson };
26451aa905cSJoshua Henderson
pic32_rtc_enable(struct pic32_rtc_dev * pdata,int en)26551aa905cSJoshua Henderson static void pic32_rtc_enable(struct pic32_rtc_dev *pdata, int en)
26651aa905cSJoshua Henderson {
26751aa905cSJoshua Henderson void __iomem *base = pdata->reg_base;
26851aa905cSJoshua Henderson
26951aa905cSJoshua Henderson if (!base)
27051aa905cSJoshua Henderson return;
27151aa905cSJoshua Henderson
27251aa905cSJoshua Henderson clk_enable(pdata->clk);
27351aa905cSJoshua Henderson if (!en) {
27451aa905cSJoshua Henderson writel(PIC32_RTCCON_ON, base + PIC32_CLR(PIC32_RTCCON));
27551aa905cSJoshua Henderson } else {
27651aa905cSJoshua Henderson pic32_syskey_unlock();
27751aa905cSJoshua Henderson
27851aa905cSJoshua Henderson writel(PIC32_RTCCON_RTCWREN, base + PIC32_SET(PIC32_RTCCON));
27951aa905cSJoshua Henderson writel(3 << 9, base + PIC32_CLR(PIC32_RTCCON));
28051aa905cSJoshua Henderson
28151aa905cSJoshua Henderson if (!(readl(base + PIC32_RTCCON) & PIC32_RTCCON_ON))
28251aa905cSJoshua Henderson writel(PIC32_RTCCON_ON, base + PIC32_SET(PIC32_RTCCON));
28351aa905cSJoshua Henderson }
28451aa905cSJoshua Henderson clk_disable(pdata->clk);
28551aa905cSJoshua Henderson }
28651aa905cSJoshua Henderson
pic32_rtc_remove(struct platform_device * pdev)287*c3d12a10SUwe Kleine-König static void pic32_rtc_remove(struct platform_device *pdev)
28851aa905cSJoshua Henderson {
28951aa905cSJoshua Henderson struct pic32_rtc_dev *pdata = platform_get_drvdata(pdev);
29051aa905cSJoshua Henderson
29151aa905cSJoshua Henderson pic32_rtc_setaie(&pdev->dev, 0);
29251aa905cSJoshua Henderson clk_unprepare(pdata->clk);
29351aa905cSJoshua Henderson pdata->clk = NULL;
29451aa905cSJoshua Henderson }
29551aa905cSJoshua Henderson
pic32_rtc_probe(struct platform_device * pdev)29651aa905cSJoshua Henderson static int pic32_rtc_probe(struct platform_device *pdev)
29751aa905cSJoshua Henderson {
29851aa905cSJoshua Henderson struct pic32_rtc_dev *pdata;
29951aa905cSJoshua Henderson int ret;
30051aa905cSJoshua Henderson
30151aa905cSJoshua Henderson pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
30251aa905cSJoshua Henderson if (!pdata)
30351aa905cSJoshua Henderson return -ENOMEM;
30451aa905cSJoshua Henderson
30551aa905cSJoshua Henderson platform_set_drvdata(pdev, pdata);
30651aa905cSJoshua Henderson
30751aa905cSJoshua Henderson pdata->alarm_irq = platform_get_irq(pdev, 0);
308faac9102SStephen Boyd if (pdata->alarm_irq < 0)
30951aa905cSJoshua Henderson return pdata->alarm_irq;
31051aa905cSJoshua Henderson
31109ef18bcSYueHaibing pdata->reg_base = devm_platform_ioremap_resource(pdev, 0);
31251aa905cSJoshua Henderson if (IS_ERR(pdata->reg_base))
31351aa905cSJoshua Henderson return PTR_ERR(pdata->reg_base);
31451aa905cSJoshua Henderson
31551aa905cSJoshua Henderson pdata->clk = devm_clk_get(&pdev->dev, NULL);
31651aa905cSJoshua Henderson if (IS_ERR(pdata->clk)) {
31751aa905cSJoshua Henderson dev_err(&pdev->dev, "failed to find rtc clock source\n");
31851aa905cSJoshua Henderson ret = PTR_ERR(pdata->clk);
31951aa905cSJoshua Henderson pdata->clk = NULL;
32051aa905cSJoshua Henderson return ret;
32151aa905cSJoshua Henderson }
32251aa905cSJoshua Henderson
32351aa905cSJoshua Henderson spin_lock_init(&pdata->alarm_lock);
32451aa905cSJoshua Henderson
32590cd5c88SGaosheng Cui pdata->rtc = devm_rtc_allocate_device(&pdev->dev);
32690cd5c88SGaosheng Cui if (IS_ERR(pdata->rtc))
32790cd5c88SGaosheng Cui return PTR_ERR(pdata->rtc);
32890cd5c88SGaosheng Cui
32951aa905cSJoshua Henderson clk_prepare_enable(pdata->clk);
33051aa905cSJoshua Henderson
33151aa905cSJoshua Henderson pic32_rtc_enable(pdata, 1);
33251aa905cSJoshua Henderson
33351aa905cSJoshua Henderson device_init_wakeup(&pdev->dev, 1);
33451aa905cSJoshua Henderson
3356515e23bSAlexandre Belloni pdata->rtc->ops = &pic32_rtcops;
336c145e5f4SAlexandre Belloni pdata->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
337c145e5f4SAlexandre Belloni pdata->rtc->range_max = RTC_TIMESTAMP_END_2099;
3386515e23bSAlexandre Belloni
339fdcfd854SBartosz Golaszewski ret = devm_rtc_register_device(pdata->rtc);
3406515e23bSAlexandre Belloni if (ret)
34151aa905cSJoshua Henderson goto err_nortc;
34251aa905cSJoshua Henderson
34351aa905cSJoshua Henderson pdata->rtc->max_user_freq = 128;
34451aa905cSJoshua Henderson
34551aa905cSJoshua Henderson pic32_rtc_setfreq(&pdev->dev, 1);
34651aa905cSJoshua Henderson ret = devm_request_irq(&pdev->dev, pdata->alarm_irq,
34751aa905cSJoshua Henderson pic32_rtc_alarmirq, 0,
34851aa905cSJoshua Henderson dev_name(&pdev->dev), pdata);
34951aa905cSJoshua Henderson if (ret) {
35051aa905cSJoshua Henderson dev_err(&pdev->dev,
35151aa905cSJoshua Henderson "IRQ %d error %d\n", pdata->alarm_irq, ret);
35251aa905cSJoshua Henderson goto err_nortc;
35351aa905cSJoshua Henderson }
35451aa905cSJoshua Henderson
35551aa905cSJoshua Henderson clk_disable(pdata->clk);
35651aa905cSJoshua Henderson
35751aa905cSJoshua Henderson return 0;
35851aa905cSJoshua Henderson
35951aa905cSJoshua Henderson err_nortc:
36051aa905cSJoshua Henderson pic32_rtc_enable(pdata, 0);
36151aa905cSJoshua Henderson clk_disable_unprepare(pdata->clk);
36251aa905cSJoshua Henderson
36351aa905cSJoshua Henderson return ret;
36451aa905cSJoshua Henderson }
36551aa905cSJoshua Henderson
36651aa905cSJoshua Henderson static const struct of_device_id pic32_rtc_dt_ids[] = {
36751aa905cSJoshua Henderson { .compatible = "microchip,pic32mzda-rtc" },
36851aa905cSJoshua Henderson { /* sentinel */ }
36951aa905cSJoshua Henderson };
37051aa905cSJoshua Henderson MODULE_DEVICE_TABLE(of, pic32_rtc_dt_ids);
37151aa905cSJoshua Henderson
37251aa905cSJoshua Henderson static struct platform_driver pic32_rtc_driver = {
37351aa905cSJoshua Henderson .probe = pic32_rtc_probe,
374*c3d12a10SUwe Kleine-König .remove_new = pic32_rtc_remove,
37551aa905cSJoshua Henderson .driver = {
37651aa905cSJoshua Henderson .name = "pic32-rtc",
37751aa905cSJoshua Henderson .of_match_table = of_match_ptr(pic32_rtc_dt_ids),
37851aa905cSJoshua Henderson },
37951aa905cSJoshua Henderson };
38051aa905cSJoshua Henderson module_platform_driver(pic32_rtc_driver);
38151aa905cSJoshua Henderson
38251aa905cSJoshua Henderson MODULE_DESCRIPTION("Microchip PIC32 RTC Driver");
38351aa905cSJoshua Henderson MODULE_AUTHOR("Joshua Henderson <joshua.henderson@microchip.com>");
38451aa905cSJoshua Henderson MODULE_LICENSE("GPL");
385