18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Real Time Clock interface for StrongARM SA1x00 and XScale PXA2xx 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2000 Nils Faerber 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Based on rtc.c by Paul Gortmaker 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Original Driver by Nils Faerber <nils@kernelconcepts.de> 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * Modifications from: 128c2ecf20Sopenharmony_ci * CIH <cih@coventive.com> 138c2ecf20Sopenharmony_ci * Nicolas Pitre <nico@fluxnic.net> 148c2ecf20Sopenharmony_ci * Andrew Christian <andrew.christian@hp.com> 158c2ecf20Sopenharmony_ci * 168c2ecf20Sopenharmony_ci * Converted to the RTC subsystem and Driver Model 178c2ecf20Sopenharmony_ci * by Richard Purdie <rpurdie@rpsys.net> 188c2ecf20Sopenharmony_ci */ 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 218c2ecf20Sopenharmony_ci#include <linux/module.h> 228c2ecf20Sopenharmony_ci#include <linux/clk.h> 238c2ecf20Sopenharmony_ci#include <linux/rtc.h> 248c2ecf20Sopenharmony_ci#include <linux/init.h> 258c2ecf20Sopenharmony_ci#include <linux/fs.h> 268c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 278c2ecf20Sopenharmony_ci#include <linux/slab.h> 288c2ecf20Sopenharmony_ci#include <linux/string.h> 298c2ecf20Sopenharmony_ci#include <linux/of.h> 308c2ecf20Sopenharmony_ci#include <linux/pm.h> 318c2ecf20Sopenharmony_ci#include <linux/bitops.h> 328c2ecf20Sopenharmony_ci#include <linux/io.h> 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#define RTSR_HZE BIT(3) /* HZ interrupt enable */ 358c2ecf20Sopenharmony_ci#define RTSR_ALE BIT(2) /* RTC alarm interrupt enable */ 368c2ecf20Sopenharmony_ci#define RTSR_HZ BIT(1) /* HZ rising-edge detected */ 378c2ecf20Sopenharmony_ci#define RTSR_AL BIT(0) /* RTC alarm detected */ 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci#include "rtc-sa1100.h" 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci#define RTC_DEF_DIVIDER (32768 - 1) 428c2ecf20Sopenharmony_ci#define RTC_DEF_TRIM 0 438c2ecf20Sopenharmony_ci#define RTC_FREQ 1024 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_cistatic irqreturn_t sa1100_rtc_interrupt(int irq, void *dev_id) 478c2ecf20Sopenharmony_ci{ 488c2ecf20Sopenharmony_ci struct sa1100_rtc *info = dev_get_drvdata(dev_id); 498c2ecf20Sopenharmony_ci struct rtc_device *rtc = info->rtc; 508c2ecf20Sopenharmony_ci unsigned int rtsr; 518c2ecf20Sopenharmony_ci unsigned long events = 0; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci spin_lock(&info->lock); 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci rtsr = readl_relaxed(info->rtsr); 568c2ecf20Sopenharmony_ci /* clear interrupt sources */ 578c2ecf20Sopenharmony_ci writel_relaxed(0, info->rtsr); 588c2ecf20Sopenharmony_ci /* Fix for a nasty initialization problem the in SA11xx RTSR register. 598c2ecf20Sopenharmony_ci * See also the comments in sa1100_rtc_probe(). */ 608c2ecf20Sopenharmony_ci if (rtsr & (RTSR_ALE | RTSR_HZE)) { 618c2ecf20Sopenharmony_ci /* This is the original code, before there was the if test 628c2ecf20Sopenharmony_ci * above. This code does not clear interrupts that were not 638c2ecf20Sopenharmony_ci * enabled. */ 648c2ecf20Sopenharmony_ci writel_relaxed((RTSR_AL | RTSR_HZ) & (rtsr >> 2), info->rtsr); 658c2ecf20Sopenharmony_ci } else { 668c2ecf20Sopenharmony_ci /* For some reason, it is possible to enter this routine 678c2ecf20Sopenharmony_ci * without interruptions enabled, it has been tested with 688c2ecf20Sopenharmony_ci * several units (Bug in SA11xx chip?). 698c2ecf20Sopenharmony_ci * 708c2ecf20Sopenharmony_ci * This situation leads to an infinite "loop" of interrupt 718c2ecf20Sopenharmony_ci * routine calling and as a result the processor seems to 728c2ecf20Sopenharmony_ci * lock on its first call to open(). */ 738c2ecf20Sopenharmony_ci writel_relaxed(RTSR_AL | RTSR_HZ, info->rtsr); 748c2ecf20Sopenharmony_ci } 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci /* clear alarm interrupt if it has occurred */ 778c2ecf20Sopenharmony_ci if (rtsr & RTSR_AL) 788c2ecf20Sopenharmony_ci rtsr &= ~RTSR_ALE; 798c2ecf20Sopenharmony_ci writel_relaxed(rtsr & (RTSR_ALE | RTSR_HZE), info->rtsr); 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci /* update irq data & counter */ 828c2ecf20Sopenharmony_ci if (rtsr & RTSR_AL) 838c2ecf20Sopenharmony_ci events |= RTC_AF | RTC_IRQF; 848c2ecf20Sopenharmony_ci if (rtsr & RTSR_HZ) 858c2ecf20Sopenharmony_ci events |= RTC_UF | RTC_IRQF; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci rtc_update_irq(rtc, 1, events); 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci spin_unlock(&info->lock); 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci return IRQ_HANDLED; 928c2ecf20Sopenharmony_ci} 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_cistatic int sa1100_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) 958c2ecf20Sopenharmony_ci{ 968c2ecf20Sopenharmony_ci u32 rtsr; 978c2ecf20Sopenharmony_ci struct sa1100_rtc *info = dev_get_drvdata(dev); 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci spin_lock_irq(&info->lock); 1008c2ecf20Sopenharmony_ci rtsr = readl_relaxed(info->rtsr); 1018c2ecf20Sopenharmony_ci if (enabled) 1028c2ecf20Sopenharmony_ci rtsr |= RTSR_ALE; 1038c2ecf20Sopenharmony_ci else 1048c2ecf20Sopenharmony_ci rtsr &= ~RTSR_ALE; 1058c2ecf20Sopenharmony_ci writel_relaxed(rtsr, info->rtsr); 1068c2ecf20Sopenharmony_ci spin_unlock_irq(&info->lock); 1078c2ecf20Sopenharmony_ci return 0; 1088c2ecf20Sopenharmony_ci} 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_cistatic int sa1100_rtc_read_time(struct device *dev, struct rtc_time *tm) 1118c2ecf20Sopenharmony_ci{ 1128c2ecf20Sopenharmony_ci struct sa1100_rtc *info = dev_get_drvdata(dev); 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci rtc_time64_to_tm(readl_relaxed(info->rcnr), tm); 1158c2ecf20Sopenharmony_ci return 0; 1168c2ecf20Sopenharmony_ci} 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_cistatic int sa1100_rtc_set_time(struct device *dev, struct rtc_time *tm) 1198c2ecf20Sopenharmony_ci{ 1208c2ecf20Sopenharmony_ci struct sa1100_rtc *info = dev_get_drvdata(dev); 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci writel_relaxed(rtc_tm_to_time64(tm), info->rcnr); 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci return 0; 1258c2ecf20Sopenharmony_ci} 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_cistatic int sa1100_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) 1288c2ecf20Sopenharmony_ci{ 1298c2ecf20Sopenharmony_ci u32 rtsr; 1308c2ecf20Sopenharmony_ci struct sa1100_rtc *info = dev_get_drvdata(dev); 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci rtsr = readl_relaxed(info->rtsr); 1338c2ecf20Sopenharmony_ci alrm->enabled = (rtsr & RTSR_ALE) ? 1 : 0; 1348c2ecf20Sopenharmony_ci alrm->pending = (rtsr & RTSR_AL) ? 1 : 0; 1358c2ecf20Sopenharmony_ci return 0; 1368c2ecf20Sopenharmony_ci} 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_cistatic int sa1100_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) 1398c2ecf20Sopenharmony_ci{ 1408c2ecf20Sopenharmony_ci struct sa1100_rtc *info = dev_get_drvdata(dev); 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci spin_lock_irq(&info->lock); 1438c2ecf20Sopenharmony_ci writel_relaxed(readl_relaxed(info->rtsr) & 1448c2ecf20Sopenharmony_ci (RTSR_HZE | RTSR_ALE | RTSR_AL), info->rtsr); 1458c2ecf20Sopenharmony_ci writel_relaxed(rtc_tm_to_time64(&alrm->time), info->rtar); 1468c2ecf20Sopenharmony_ci if (alrm->enabled) 1478c2ecf20Sopenharmony_ci writel_relaxed(readl_relaxed(info->rtsr) | RTSR_ALE, info->rtsr); 1488c2ecf20Sopenharmony_ci else 1498c2ecf20Sopenharmony_ci writel_relaxed(readl_relaxed(info->rtsr) & ~RTSR_ALE, info->rtsr); 1508c2ecf20Sopenharmony_ci spin_unlock_irq(&info->lock); 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci return 0; 1538c2ecf20Sopenharmony_ci} 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_cistatic int sa1100_rtc_proc(struct device *dev, struct seq_file *seq) 1568c2ecf20Sopenharmony_ci{ 1578c2ecf20Sopenharmony_ci struct sa1100_rtc *info = dev_get_drvdata(dev); 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci seq_printf(seq, "trim/divider\t\t: 0x%08x\n", readl_relaxed(info->rttr)); 1608c2ecf20Sopenharmony_ci seq_printf(seq, "RTSR\t\t\t: 0x%08x\n", readl_relaxed(info->rtsr)); 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci return 0; 1638c2ecf20Sopenharmony_ci} 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_cistatic const struct rtc_class_ops sa1100_rtc_ops = { 1668c2ecf20Sopenharmony_ci .read_time = sa1100_rtc_read_time, 1678c2ecf20Sopenharmony_ci .set_time = sa1100_rtc_set_time, 1688c2ecf20Sopenharmony_ci .read_alarm = sa1100_rtc_read_alarm, 1698c2ecf20Sopenharmony_ci .set_alarm = sa1100_rtc_set_alarm, 1708c2ecf20Sopenharmony_ci .proc = sa1100_rtc_proc, 1718c2ecf20Sopenharmony_ci .alarm_irq_enable = sa1100_rtc_alarm_irq_enable, 1728c2ecf20Sopenharmony_ci}; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ciint sa1100_rtc_init(struct platform_device *pdev, struct sa1100_rtc *info) 1758c2ecf20Sopenharmony_ci{ 1768c2ecf20Sopenharmony_ci int ret; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci spin_lock_init(&info->lock); 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci info->clk = devm_clk_get(&pdev->dev, NULL); 1818c2ecf20Sopenharmony_ci if (IS_ERR(info->clk)) { 1828c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to find rtc clock source\n"); 1838c2ecf20Sopenharmony_ci return PTR_ERR(info->clk); 1848c2ecf20Sopenharmony_ci } 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci ret = clk_prepare_enable(info->clk); 1878c2ecf20Sopenharmony_ci if (ret) 1888c2ecf20Sopenharmony_ci return ret; 1898c2ecf20Sopenharmony_ci /* 1908c2ecf20Sopenharmony_ci * According to the manual we should be able to let RTTR be zero 1918c2ecf20Sopenharmony_ci * and then a default diviser for a 32.768KHz clock is used. 1928c2ecf20Sopenharmony_ci * Apparently this doesn't work, at least for my SA1110 rev 5. 1938c2ecf20Sopenharmony_ci * If the clock divider is uninitialized then reset it to the 1948c2ecf20Sopenharmony_ci * default value to get the 1Hz clock. 1958c2ecf20Sopenharmony_ci */ 1968c2ecf20Sopenharmony_ci if (readl_relaxed(info->rttr) == 0) { 1978c2ecf20Sopenharmony_ci writel_relaxed(RTC_DEF_DIVIDER + (RTC_DEF_TRIM << 16), info->rttr); 1988c2ecf20Sopenharmony_ci dev_warn(&pdev->dev, "warning: " 1998c2ecf20Sopenharmony_ci "initializing default clock divider/trim value\n"); 2008c2ecf20Sopenharmony_ci /* The current RTC value probably doesn't make sense either */ 2018c2ecf20Sopenharmony_ci writel_relaxed(0, info->rcnr); 2028c2ecf20Sopenharmony_ci } 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci info->rtc->ops = &sa1100_rtc_ops; 2058c2ecf20Sopenharmony_ci info->rtc->max_user_freq = RTC_FREQ; 2068c2ecf20Sopenharmony_ci info->rtc->range_max = U32_MAX; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci ret = rtc_register_device(info->rtc); 2098c2ecf20Sopenharmony_ci if (ret) { 2108c2ecf20Sopenharmony_ci clk_disable_unprepare(info->clk); 2118c2ecf20Sopenharmony_ci return ret; 2128c2ecf20Sopenharmony_ci } 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci /* Fix for a nasty initialization problem the in SA11xx RTSR register. 2158c2ecf20Sopenharmony_ci * See also the comments in sa1100_rtc_interrupt(). 2168c2ecf20Sopenharmony_ci * 2178c2ecf20Sopenharmony_ci * Sometimes bit 1 of the RTSR (RTSR_HZ) will wake up 1, which means an 2188c2ecf20Sopenharmony_ci * interrupt pending, even though interrupts were never enabled. 2198c2ecf20Sopenharmony_ci * In this case, this bit it must be reset before enabling 2208c2ecf20Sopenharmony_ci * interruptions to avoid a nonexistent interrupt to occur. 2218c2ecf20Sopenharmony_ci * 2228c2ecf20Sopenharmony_ci * In principle, the same problem would apply to bit 0, although it has 2238c2ecf20Sopenharmony_ci * never been observed to happen. 2248c2ecf20Sopenharmony_ci * 2258c2ecf20Sopenharmony_ci * This issue is addressed both here and in sa1100_rtc_interrupt(). 2268c2ecf20Sopenharmony_ci * If the issue is not addressed here, in the times when the processor 2278c2ecf20Sopenharmony_ci * wakes up with the bit set there will be one spurious interrupt. 2288c2ecf20Sopenharmony_ci * 2298c2ecf20Sopenharmony_ci * The issue is also dealt with in sa1100_rtc_interrupt() to be on the 2308c2ecf20Sopenharmony_ci * safe side, once the condition that lead to this strange 2318c2ecf20Sopenharmony_ci * initialization is unknown and could in principle happen during 2328c2ecf20Sopenharmony_ci * normal processing. 2338c2ecf20Sopenharmony_ci * 2348c2ecf20Sopenharmony_ci * Notice that clearing bit 1 and 0 is accomplished by writting ONES to 2358c2ecf20Sopenharmony_ci * the corresponding bits in RTSR. */ 2368c2ecf20Sopenharmony_ci writel_relaxed(RTSR_AL | RTSR_HZ, info->rtsr); 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci return 0; 2398c2ecf20Sopenharmony_ci} 2408c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(sa1100_rtc_init); 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_cistatic int sa1100_rtc_probe(struct platform_device *pdev) 2438c2ecf20Sopenharmony_ci{ 2448c2ecf20Sopenharmony_ci struct sa1100_rtc *info; 2458c2ecf20Sopenharmony_ci void __iomem *base; 2468c2ecf20Sopenharmony_ci int irq_1hz, irq_alarm; 2478c2ecf20Sopenharmony_ci int ret; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci irq_1hz = platform_get_irq_byname(pdev, "rtc 1Hz"); 2508c2ecf20Sopenharmony_ci irq_alarm = platform_get_irq_byname(pdev, "rtc alarm"); 2518c2ecf20Sopenharmony_ci if (irq_1hz < 0 || irq_alarm < 0) 2528c2ecf20Sopenharmony_ci return -ENODEV; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci info = devm_kzalloc(&pdev->dev, sizeof(struct sa1100_rtc), GFP_KERNEL); 2558c2ecf20Sopenharmony_ci if (!info) 2568c2ecf20Sopenharmony_ci return -ENOMEM; 2578c2ecf20Sopenharmony_ci info->irq_1hz = irq_1hz; 2588c2ecf20Sopenharmony_ci info->irq_alarm = irq_alarm; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci info->rtc = devm_rtc_allocate_device(&pdev->dev); 2618c2ecf20Sopenharmony_ci if (IS_ERR(info->rtc)) 2628c2ecf20Sopenharmony_ci return PTR_ERR(info->rtc); 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci ret = devm_request_irq(&pdev->dev, irq_1hz, sa1100_rtc_interrupt, 0, 2658c2ecf20Sopenharmony_ci "rtc 1Hz", &pdev->dev); 2668c2ecf20Sopenharmony_ci if (ret) { 2678c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "IRQ %d already in use.\n", irq_1hz); 2688c2ecf20Sopenharmony_ci return ret; 2698c2ecf20Sopenharmony_ci } 2708c2ecf20Sopenharmony_ci ret = devm_request_irq(&pdev->dev, irq_alarm, sa1100_rtc_interrupt, 0, 2718c2ecf20Sopenharmony_ci "rtc Alrm", &pdev->dev); 2728c2ecf20Sopenharmony_ci if (ret) { 2738c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "IRQ %d already in use.\n", irq_alarm); 2748c2ecf20Sopenharmony_ci return ret; 2758c2ecf20Sopenharmony_ci } 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci base = devm_platform_ioremap_resource(pdev, 0); 2788c2ecf20Sopenharmony_ci if (IS_ERR(base)) 2798c2ecf20Sopenharmony_ci return PTR_ERR(base); 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_ARCH_SA1100) || 2828c2ecf20Sopenharmony_ci of_device_is_compatible(pdev->dev.of_node, "mrvl,sa1100-rtc")) { 2838c2ecf20Sopenharmony_ci info->rcnr = base + 0x04; 2848c2ecf20Sopenharmony_ci info->rtsr = base + 0x10; 2858c2ecf20Sopenharmony_ci info->rtar = base + 0x00; 2868c2ecf20Sopenharmony_ci info->rttr = base + 0x08; 2878c2ecf20Sopenharmony_ci } else { 2888c2ecf20Sopenharmony_ci info->rcnr = base + 0x0; 2898c2ecf20Sopenharmony_ci info->rtsr = base + 0x8; 2908c2ecf20Sopenharmony_ci info->rtar = base + 0x4; 2918c2ecf20Sopenharmony_ci info->rttr = base + 0xc; 2928c2ecf20Sopenharmony_ci } 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, info); 2958c2ecf20Sopenharmony_ci device_init_wakeup(&pdev->dev, 1); 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci return sa1100_rtc_init(pdev, info); 2988c2ecf20Sopenharmony_ci} 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_cistatic int sa1100_rtc_remove(struct platform_device *pdev) 3018c2ecf20Sopenharmony_ci{ 3028c2ecf20Sopenharmony_ci struct sa1100_rtc *info = platform_get_drvdata(pdev); 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci if (info) { 3058c2ecf20Sopenharmony_ci spin_lock_irq(&info->lock); 3068c2ecf20Sopenharmony_ci writel_relaxed(0, info->rtsr); 3078c2ecf20Sopenharmony_ci spin_unlock_irq(&info->lock); 3088c2ecf20Sopenharmony_ci clk_disable_unprepare(info->clk); 3098c2ecf20Sopenharmony_ci } 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci return 0; 3128c2ecf20Sopenharmony_ci} 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 3158c2ecf20Sopenharmony_cistatic int sa1100_rtc_suspend(struct device *dev) 3168c2ecf20Sopenharmony_ci{ 3178c2ecf20Sopenharmony_ci struct sa1100_rtc *info = dev_get_drvdata(dev); 3188c2ecf20Sopenharmony_ci if (device_may_wakeup(dev)) 3198c2ecf20Sopenharmony_ci enable_irq_wake(info->irq_alarm); 3208c2ecf20Sopenharmony_ci return 0; 3218c2ecf20Sopenharmony_ci} 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_cistatic int sa1100_rtc_resume(struct device *dev) 3248c2ecf20Sopenharmony_ci{ 3258c2ecf20Sopenharmony_ci struct sa1100_rtc *info = dev_get_drvdata(dev); 3268c2ecf20Sopenharmony_ci if (device_may_wakeup(dev)) 3278c2ecf20Sopenharmony_ci disable_irq_wake(info->irq_alarm); 3288c2ecf20Sopenharmony_ci return 0; 3298c2ecf20Sopenharmony_ci} 3308c2ecf20Sopenharmony_ci#endif 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(sa1100_rtc_pm_ops, sa1100_rtc_suspend, 3338c2ecf20Sopenharmony_ci sa1100_rtc_resume); 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci#ifdef CONFIG_OF 3368c2ecf20Sopenharmony_cistatic const struct of_device_id sa1100_rtc_dt_ids[] = { 3378c2ecf20Sopenharmony_ci { .compatible = "mrvl,sa1100-rtc", }, 3388c2ecf20Sopenharmony_ci { .compatible = "mrvl,mmp-rtc", }, 3398c2ecf20Sopenharmony_ci {} 3408c2ecf20Sopenharmony_ci}; 3418c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, sa1100_rtc_dt_ids); 3428c2ecf20Sopenharmony_ci#endif 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_cistatic struct platform_driver sa1100_rtc_driver = { 3458c2ecf20Sopenharmony_ci .probe = sa1100_rtc_probe, 3468c2ecf20Sopenharmony_ci .remove = sa1100_rtc_remove, 3478c2ecf20Sopenharmony_ci .driver = { 3488c2ecf20Sopenharmony_ci .name = "sa1100-rtc", 3498c2ecf20Sopenharmony_ci .pm = &sa1100_rtc_pm_ops, 3508c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(sa1100_rtc_dt_ids), 3518c2ecf20Sopenharmony_ci }, 3528c2ecf20Sopenharmony_ci}; 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_cimodule_platform_driver(sa1100_rtc_driver); 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ciMODULE_AUTHOR("Richard Purdie <rpurdie@rpsys.net>"); 3578c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("SA11x0/PXA2xx Realtime Clock Driver (RTC)"); 3588c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 3598c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:sa1100-rtc"); 360