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 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 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 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 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 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 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 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 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 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 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 28751aa905cSJoshua Henderson static int 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 return 0; 29651aa905cSJoshua Henderson } 29751aa905cSJoshua Henderson 29851aa905cSJoshua Henderson static int pic32_rtc_probe(struct platform_device *pdev) 29951aa905cSJoshua Henderson { 30051aa905cSJoshua Henderson struct pic32_rtc_dev *pdata; 30151aa905cSJoshua Henderson int ret; 30251aa905cSJoshua Henderson 30351aa905cSJoshua Henderson pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); 30451aa905cSJoshua Henderson if (!pdata) 30551aa905cSJoshua Henderson return -ENOMEM; 30651aa905cSJoshua Henderson 30751aa905cSJoshua Henderson platform_set_drvdata(pdev, pdata); 30851aa905cSJoshua Henderson 30951aa905cSJoshua Henderson pdata->alarm_irq = platform_get_irq(pdev, 0); 310faac9102SStephen Boyd if (pdata->alarm_irq < 0) 31151aa905cSJoshua Henderson return pdata->alarm_irq; 31251aa905cSJoshua Henderson 31309ef18bcSYueHaibing pdata->reg_base = devm_platform_ioremap_resource(pdev, 0); 31451aa905cSJoshua Henderson if (IS_ERR(pdata->reg_base)) 31551aa905cSJoshua Henderson return PTR_ERR(pdata->reg_base); 31651aa905cSJoshua Henderson 31751aa905cSJoshua Henderson pdata->clk = devm_clk_get(&pdev->dev, NULL); 31851aa905cSJoshua Henderson if (IS_ERR(pdata->clk)) { 31951aa905cSJoshua Henderson dev_err(&pdev->dev, "failed to find rtc clock source\n"); 32051aa905cSJoshua Henderson ret = PTR_ERR(pdata->clk); 32151aa905cSJoshua Henderson pdata->clk = NULL; 32251aa905cSJoshua Henderson return ret; 32351aa905cSJoshua Henderson } 32451aa905cSJoshua Henderson 32551aa905cSJoshua Henderson spin_lock_init(&pdata->alarm_lock); 32651aa905cSJoshua Henderson 32751aa905cSJoshua Henderson clk_prepare_enable(pdata->clk); 32851aa905cSJoshua Henderson 32951aa905cSJoshua Henderson pic32_rtc_enable(pdata, 1); 33051aa905cSJoshua Henderson 33151aa905cSJoshua Henderson device_init_wakeup(&pdev->dev, 1); 33251aa905cSJoshua Henderson 3336515e23bSAlexandre Belloni pdata->rtc = devm_rtc_allocate_device(&pdev->dev); 3346515e23bSAlexandre Belloni if (IS_ERR(pdata->rtc)) 3356515e23bSAlexandre Belloni return PTR_ERR(pdata->rtc); 3366515e23bSAlexandre Belloni 3376515e23bSAlexandre Belloni pdata->rtc->ops = &pic32_rtcops; 338c145e5f4SAlexandre Belloni pdata->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000; 339c145e5f4SAlexandre Belloni pdata->rtc->range_max = RTC_TIMESTAMP_END_2099; 3406515e23bSAlexandre Belloni 3416515e23bSAlexandre Belloni ret = rtc_register_device(pdata->rtc); 3426515e23bSAlexandre Belloni if (ret) 34351aa905cSJoshua Henderson goto err_nortc; 34451aa905cSJoshua Henderson 34551aa905cSJoshua Henderson pdata->rtc->max_user_freq = 128; 34651aa905cSJoshua Henderson 34751aa905cSJoshua Henderson pic32_rtc_setfreq(&pdev->dev, 1); 34851aa905cSJoshua Henderson ret = devm_request_irq(&pdev->dev, pdata->alarm_irq, 34951aa905cSJoshua Henderson pic32_rtc_alarmirq, 0, 35051aa905cSJoshua Henderson dev_name(&pdev->dev), pdata); 35151aa905cSJoshua Henderson if (ret) { 35251aa905cSJoshua Henderson dev_err(&pdev->dev, 35351aa905cSJoshua Henderson "IRQ %d error %d\n", pdata->alarm_irq, ret); 35451aa905cSJoshua Henderson goto err_nortc; 35551aa905cSJoshua Henderson } 35651aa905cSJoshua Henderson 35751aa905cSJoshua Henderson clk_disable(pdata->clk); 35851aa905cSJoshua Henderson 35951aa905cSJoshua Henderson return 0; 36051aa905cSJoshua Henderson 36151aa905cSJoshua Henderson err_nortc: 36251aa905cSJoshua Henderson pic32_rtc_enable(pdata, 0); 36351aa905cSJoshua Henderson clk_disable_unprepare(pdata->clk); 36451aa905cSJoshua Henderson 36551aa905cSJoshua Henderson return ret; 36651aa905cSJoshua Henderson } 36751aa905cSJoshua Henderson 36851aa905cSJoshua Henderson static const struct of_device_id pic32_rtc_dt_ids[] = { 36951aa905cSJoshua Henderson { .compatible = "microchip,pic32mzda-rtc" }, 37051aa905cSJoshua Henderson { /* sentinel */ } 37151aa905cSJoshua Henderson }; 37251aa905cSJoshua Henderson MODULE_DEVICE_TABLE(of, pic32_rtc_dt_ids); 37351aa905cSJoshua Henderson 37451aa905cSJoshua Henderson static struct platform_driver pic32_rtc_driver = { 37551aa905cSJoshua Henderson .probe = pic32_rtc_probe, 37651aa905cSJoshua Henderson .remove = pic32_rtc_remove, 37751aa905cSJoshua Henderson .driver = { 37851aa905cSJoshua Henderson .name = "pic32-rtc", 37951aa905cSJoshua Henderson .of_match_table = of_match_ptr(pic32_rtc_dt_ids), 38051aa905cSJoshua Henderson }, 38151aa905cSJoshua Henderson }; 38251aa905cSJoshua Henderson module_platform_driver(pic32_rtc_driver); 38351aa905cSJoshua Henderson 38451aa905cSJoshua Henderson MODULE_DESCRIPTION("Microchip PIC32 RTC Driver"); 38551aa905cSJoshua Henderson MODULE_AUTHOR("Joshua Henderson <joshua.henderson@microchip.com>"); 38651aa905cSJoshua Henderson MODULE_LICENSE("GPL"); 387