18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * An RTC driver for the NVIDIA Tegra 200 series internal RTC. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2010-2019, NVIDIA Corporation. 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/clk.h> 98c2ecf20Sopenharmony_ci#include <linux/delay.h> 108c2ecf20Sopenharmony_ci#include <linux/init.h> 118c2ecf20Sopenharmony_ci#include <linux/io.h> 128c2ecf20Sopenharmony_ci#include <linux/irq.h> 138c2ecf20Sopenharmony_ci#include <linux/kernel.h> 148c2ecf20Sopenharmony_ci#include <linux/module.h> 158c2ecf20Sopenharmony_ci#include <linux/mod_devicetable.h> 168c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 178c2ecf20Sopenharmony_ci#include <linux/pm.h> 188c2ecf20Sopenharmony_ci#include <linux/rtc.h> 198c2ecf20Sopenharmony_ci#include <linux/slab.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci/* Set to 1 = busy every eight 32 kHz clocks during copy of sec+msec to AHB. */ 228c2ecf20Sopenharmony_ci#define TEGRA_RTC_REG_BUSY 0x004 238c2ecf20Sopenharmony_ci#define TEGRA_RTC_REG_SECONDS 0x008 248c2ecf20Sopenharmony_ci/* When msec is read, the seconds are buffered into shadow seconds. */ 258c2ecf20Sopenharmony_ci#define TEGRA_RTC_REG_SHADOW_SECONDS 0x00c 268c2ecf20Sopenharmony_ci#define TEGRA_RTC_REG_MILLI_SECONDS 0x010 278c2ecf20Sopenharmony_ci#define TEGRA_RTC_REG_SECONDS_ALARM0 0x014 288c2ecf20Sopenharmony_ci#define TEGRA_RTC_REG_SECONDS_ALARM1 0x018 298c2ecf20Sopenharmony_ci#define TEGRA_RTC_REG_MILLI_SECONDS_ALARM0 0x01c 308c2ecf20Sopenharmony_ci#define TEGRA_RTC_REG_INTR_MASK 0x028 318c2ecf20Sopenharmony_ci/* write 1 bits to clear status bits */ 328c2ecf20Sopenharmony_ci#define TEGRA_RTC_REG_INTR_STATUS 0x02c 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci/* bits in INTR_MASK */ 358c2ecf20Sopenharmony_ci#define TEGRA_RTC_INTR_MASK_MSEC_CDN_ALARM (1<<4) 368c2ecf20Sopenharmony_ci#define TEGRA_RTC_INTR_MASK_SEC_CDN_ALARM (1<<3) 378c2ecf20Sopenharmony_ci#define TEGRA_RTC_INTR_MASK_MSEC_ALARM (1<<2) 388c2ecf20Sopenharmony_ci#define TEGRA_RTC_INTR_MASK_SEC_ALARM1 (1<<1) 398c2ecf20Sopenharmony_ci#define TEGRA_RTC_INTR_MASK_SEC_ALARM0 (1<<0) 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci/* bits in INTR_STATUS */ 428c2ecf20Sopenharmony_ci#define TEGRA_RTC_INTR_STATUS_MSEC_CDN_ALARM (1<<4) 438c2ecf20Sopenharmony_ci#define TEGRA_RTC_INTR_STATUS_SEC_CDN_ALARM (1<<3) 448c2ecf20Sopenharmony_ci#define TEGRA_RTC_INTR_STATUS_MSEC_ALARM (1<<2) 458c2ecf20Sopenharmony_ci#define TEGRA_RTC_INTR_STATUS_SEC_ALARM1 (1<<1) 468c2ecf20Sopenharmony_ci#define TEGRA_RTC_INTR_STATUS_SEC_ALARM0 (1<<0) 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cistruct tegra_rtc_info { 498c2ecf20Sopenharmony_ci struct platform_device *pdev; 508c2ecf20Sopenharmony_ci struct rtc_device *rtc; 518c2ecf20Sopenharmony_ci void __iomem *base; /* NULL if not initialized */ 528c2ecf20Sopenharmony_ci struct clk *clk; 538c2ecf20Sopenharmony_ci int irq; /* alarm and periodic IRQ */ 548c2ecf20Sopenharmony_ci spinlock_t lock; 558c2ecf20Sopenharmony_ci}; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci/* 588c2ecf20Sopenharmony_ci * RTC hardware is busy when it is updating its values over AHB once every 598c2ecf20Sopenharmony_ci * eight 32 kHz clocks (~250 us). Outside of these updates the CPU is free to 608c2ecf20Sopenharmony_ci * write. CPU is always free to read. 618c2ecf20Sopenharmony_ci */ 628c2ecf20Sopenharmony_cistatic inline u32 tegra_rtc_check_busy(struct tegra_rtc_info *info) 638c2ecf20Sopenharmony_ci{ 648c2ecf20Sopenharmony_ci return readl(info->base + TEGRA_RTC_REG_BUSY) & 1; 658c2ecf20Sopenharmony_ci} 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci/* 688c2ecf20Sopenharmony_ci * Wait for hardware to be ready for writing. This function tries to maximize 698c2ecf20Sopenharmony_ci * the amount of time before the next update. It does this by waiting for the 708c2ecf20Sopenharmony_ci * RTC to become busy with its periodic update, then returning once the RTC 718c2ecf20Sopenharmony_ci * first becomes not busy. 728c2ecf20Sopenharmony_ci * 738c2ecf20Sopenharmony_ci * This periodic update (where the seconds and milliseconds are copied to the 748c2ecf20Sopenharmony_ci * AHB side) occurs every eight 32 kHz clocks (~250 us). The behavior of this 758c2ecf20Sopenharmony_ci * function allows us to make some assumptions without introducing a race, 768c2ecf20Sopenharmony_ci * because 250 us is plenty of time to read/write a value. 778c2ecf20Sopenharmony_ci */ 788c2ecf20Sopenharmony_cistatic int tegra_rtc_wait_while_busy(struct device *dev) 798c2ecf20Sopenharmony_ci{ 808c2ecf20Sopenharmony_ci struct tegra_rtc_info *info = dev_get_drvdata(dev); 818c2ecf20Sopenharmony_ci int retries = 500; /* ~490 us is the worst case, ~250 us is best */ 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci /* 848c2ecf20Sopenharmony_ci * First wait for the RTC to become busy. This is when it posts its 858c2ecf20Sopenharmony_ci * updated seconds+msec registers to AHB side. 868c2ecf20Sopenharmony_ci */ 878c2ecf20Sopenharmony_ci while (tegra_rtc_check_busy(info)) { 888c2ecf20Sopenharmony_ci if (!retries--) 898c2ecf20Sopenharmony_ci goto retry_failed; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci udelay(1); 928c2ecf20Sopenharmony_ci } 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci /* now we have about 250 us to manipulate registers */ 958c2ecf20Sopenharmony_ci return 0; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ciretry_failed: 988c2ecf20Sopenharmony_ci dev_err(dev, "write failed: retry count exceeded\n"); 998c2ecf20Sopenharmony_ci return -ETIMEDOUT; 1008c2ecf20Sopenharmony_ci} 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_cistatic int tegra_rtc_read_time(struct device *dev, struct rtc_time *tm) 1038c2ecf20Sopenharmony_ci{ 1048c2ecf20Sopenharmony_ci struct tegra_rtc_info *info = dev_get_drvdata(dev); 1058c2ecf20Sopenharmony_ci unsigned long flags; 1068c2ecf20Sopenharmony_ci u32 sec; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci /* 1098c2ecf20Sopenharmony_ci * RTC hardware copies seconds to shadow seconds when a read of 1108c2ecf20Sopenharmony_ci * milliseconds occurs. use a lock to keep other threads out. 1118c2ecf20Sopenharmony_ci */ 1128c2ecf20Sopenharmony_ci spin_lock_irqsave(&info->lock, flags); 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci readl(info->base + TEGRA_RTC_REG_MILLI_SECONDS); 1158c2ecf20Sopenharmony_ci sec = readl(info->base + TEGRA_RTC_REG_SHADOW_SECONDS); 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&info->lock, flags); 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci rtc_time64_to_tm(sec, tm); 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci dev_vdbg(dev, "time read as %u, %ptR\n", sec, tm); 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci return 0; 1248c2ecf20Sopenharmony_ci} 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_cistatic int tegra_rtc_set_time(struct device *dev, struct rtc_time *tm) 1278c2ecf20Sopenharmony_ci{ 1288c2ecf20Sopenharmony_ci struct tegra_rtc_info *info = dev_get_drvdata(dev); 1298c2ecf20Sopenharmony_ci u32 sec; 1308c2ecf20Sopenharmony_ci int ret; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci /* convert tm to seconds */ 1338c2ecf20Sopenharmony_ci sec = rtc_tm_to_time64(tm); 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci dev_vdbg(dev, "time set to %u, %ptR\n", sec, tm); 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci /* seconds only written if wait succeeded */ 1388c2ecf20Sopenharmony_ci ret = tegra_rtc_wait_while_busy(dev); 1398c2ecf20Sopenharmony_ci if (!ret) 1408c2ecf20Sopenharmony_ci writel(sec, info->base + TEGRA_RTC_REG_SECONDS); 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci dev_vdbg(dev, "time read back as %d\n", 1438c2ecf20Sopenharmony_ci readl(info->base + TEGRA_RTC_REG_SECONDS)); 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci return ret; 1468c2ecf20Sopenharmony_ci} 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_cistatic int tegra_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) 1498c2ecf20Sopenharmony_ci{ 1508c2ecf20Sopenharmony_ci struct tegra_rtc_info *info = dev_get_drvdata(dev); 1518c2ecf20Sopenharmony_ci u32 sec, value; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci sec = readl(info->base + TEGRA_RTC_REG_SECONDS_ALARM0); 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci if (sec == 0) { 1568c2ecf20Sopenharmony_ci /* alarm is disabled */ 1578c2ecf20Sopenharmony_ci alarm->enabled = 0; 1588c2ecf20Sopenharmony_ci } else { 1598c2ecf20Sopenharmony_ci /* alarm is enabled */ 1608c2ecf20Sopenharmony_ci alarm->enabled = 1; 1618c2ecf20Sopenharmony_ci rtc_time64_to_tm(sec, &alarm->time); 1628c2ecf20Sopenharmony_ci } 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci value = readl(info->base + TEGRA_RTC_REG_INTR_STATUS); 1658c2ecf20Sopenharmony_ci alarm->pending = (value & TEGRA_RTC_INTR_STATUS_SEC_ALARM0) != 0; 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci return 0; 1688c2ecf20Sopenharmony_ci} 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_cistatic int tegra_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) 1718c2ecf20Sopenharmony_ci{ 1728c2ecf20Sopenharmony_ci struct tegra_rtc_info *info = dev_get_drvdata(dev); 1738c2ecf20Sopenharmony_ci unsigned long flags; 1748c2ecf20Sopenharmony_ci u32 status; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci tegra_rtc_wait_while_busy(dev); 1778c2ecf20Sopenharmony_ci spin_lock_irqsave(&info->lock, flags); 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci /* read the original value, and OR in the flag */ 1808c2ecf20Sopenharmony_ci status = readl(info->base + TEGRA_RTC_REG_INTR_MASK); 1818c2ecf20Sopenharmony_ci if (enabled) 1828c2ecf20Sopenharmony_ci status |= TEGRA_RTC_INTR_MASK_SEC_ALARM0; /* set it */ 1838c2ecf20Sopenharmony_ci else 1848c2ecf20Sopenharmony_ci status &= ~TEGRA_RTC_INTR_MASK_SEC_ALARM0; /* clear it */ 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci writel(status, info->base + TEGRA_RTC_REG_INTR_MASK); 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&info->lock, flags); 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci return 0; 1918c2ecf20Sopenharmony_ci} 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_cistatic int tegra_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) 1948c2ecf20Sopenharmony_ci{ 1958c2ecf20Sopenharmony_ci struct tegra_rtc_info *info = dev_get_drvdata(dev); 1968c2ecf20Sopenharmony_ci u32 sec; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci if (alarm->enabled) 1998c2ecf20Sopenharmony_ci sec = rtc_tm_to_time64(&alarm->time); 2008c2ecf20Sopenharmony_ci else 2018c2ecf20Sopenharmony_ci sec = 0; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci tegra_rtc_wait_while_busy(dev); 2048c2ecf20Sopenharmony_ci writel(sec, info->base + TEGRA_RTC_REG_SECONDS_ALARM0); 2058c2ecf20Sopenharmony_ci dev_vdbg(dev, "alarm read back as %d\n", 2068c2ecf20Sopenharmony_ci readl(info->base + TEGRA_RTC_REG_SECONDS_ALARM0)); 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci /* if successfully written and alarm is enabled ... */ 2098c2ecf20Sopenharmony_ci if (sec) { 2108c2ecf20Sopenharmony_ci tegra_rtc_alarm_irq_enable(dev, 1); 2118c2ecf20Sopenharmony_ci dev_vdbg(dev, "alarm set as %u, %ptR\n", sec, &alarm->time); 2128c2ecf20Sopenharmony_ci } else { 2138c2ecf20Sopenharmony_ci /* disable alarm if 0 or write error */ 2148c2ecf20Sopenharmony_ci dev_vdbg(dev, "alarm disabled\n"); 2158c2ecf20Sopenharmony_ci tegra_rtc_alarm_irq_enable(dev, 0); 2168c2ecf20Sopenharmony_ci } 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci return 0; 2198c2ecf20Sopenharmony_ci} 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_cistatic int tegra_rtc_proc(struct device *dev, struct seq_file *seq) 2228c2ecf20Sopenharmony_ci{ 2238c2ecf20Sopenharmony_ci if (!dev || !dev->driver) 2248c2ecf20Sopenharmony_ci return 0; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci seq_printf(seq, "name\t\t: %s\n", dev_name(dev)); 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci return 0; 2298c2ecf20Sopenharmony_ci} 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_cistatic irqreturn_t tegra_rtc_irq_handler(int irq, void *data) 2328c2ecf20Sopenharmony_ci{ 2338c2ecf20Sopenharmony_ci struct device *dev = data; 2348c2ecf20Sopenharmony_ci struct tegra_rtc_info *info = dev_get_drvdata(dev); 2358c2ecf20Sopenharmony_ci unsigned long events = 0, flags; 2368c2ecf20Sopenharmony_ci u32 status; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci status = readl(info->base + TEGRA_RTC_REG_INTR_STATUS); 2398c2ecf20Sopenharmony_ci if (status) { 2408c2ecf20Sopenharmony_ci /* clear the interrupt masks and status on any IRQ */ 2418c2ecf20Sopenharmony_ci tegra_rtc_wait_while_busy(dev); 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci spin_lock_irqsave(&info->lock, flags); 2448c2ecf20Sopenharmony_ci writel(0, info->base + TEGRA_RTC_REG_INTR_MASK); 2458c2ecf20Sopenharmony_ci writel(status, info->base + TEGRA_RTC_REG_INTR_STATUS); 2468c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&info->lock, flags); 2478c2ecf20Sopenharmony_ci } 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci /* check if alarm */ 2508c2ecf20Sopenharmony_ci if (status & TEGRA_RTC_INTR_STATUS_SEC_ALARM0) 2518c2ecf20Sopenharmony_ci events |= RTC_IRQF | RTC_AF; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci /* check if periodic */ 2548c2ecf20Sopenharmony_ci if (status & TEGRA_RTC_INTR_STATUS_SEC_CDN_ALARM) 2558c2ecf20Sopenharmony_ci events |= RTC_IRQF | RTC_PF; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci rtc_update_irq(info->rtc, 1, events); 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci return IRQ_HANDLED; 2608c2ecf20Sopenharmony_ci} 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_cistatic const struct rtc_class_ops tegra_rtc_ops = { 2638c2ecf20Sopenharmony_ci .read_time = tegra_rtc_read_time, 2648c2ecf20Sopenharmony_ci .set_time = tegra_rtc_set_time, 2658c2ecf20Sopenharmony_ci .read_alarm = tegra_rtc_read_alarm, 2668c2ecf20Sopenharmony_ci .set_alarm = tegra_rtc_set_alarm, 2678c2ecf20Sopenharmony_ci .proc = tegra_rtc_proc, 2688c2ecf20Sopenharmony_ci .alarm_irq_enable = tegra_rtc_alarm_irq_enable, 2698c2ecf20Sopenharmony_ci}; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_cistatic const struct of_device_id tegra_rtc_dt_match[] = { 2728c2ecf20Sopenharmony_ci { .compatible = "nvidia,tegra20-rtc", }, 2738c2ecf20Sopenharmony_ci {} 2748c2ecf20Sopenharmony_ci}; 2758c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, tegra_rtc_dt_match); 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_cistatic int tegra_rtc_probe(struct platform_device *pdev) 2788c2ecf20Sopenharmony_ci{ 2798c2ecf20Sopenharmony_ci struct tegra_rtc_info *info; 2808c2ecf20Sopenharmony_ci int ret; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); 2838c2ecf20Sopenharmony_ci if (!info) 2848c2ecf20Sopenharmony_ci return -ENOMEM; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci info->base = devm_platform_ioremap_resource(pdev, 0); 2878c2ecf20Sopenharmony_ci if (IS_ERR(info->base)) 2888c2ecf20Sopenharmony_ci return PTR_ERR(info->base); 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci ret = platform_get_irq(pdev, 0); 2918c2ecf20Sopenharmony_ci if (ret <= 0) 2928c2ecf20Sopenharmony_ci return ret; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci info->irq = ret; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci info->rtc = devm_rtc_allocate_device(&pdev->dev); 2978c2ecf20Sopenharmony_ci if (IS_ERR(info->rtc)) 2988c2ecf20Sopenharmony_ci return PTR_ERR(info->rtc); 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci info->rtc->ops = &tegra_rtc_ops; 3018c2ecf20Sopenharmony_ci info->rtc->range_max = U32_MAX; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci info->clk = devm_clk_get(&pdev->dev, NULL); 3048c2ecf20Sopenharmony_ci if (IS_ERR(info->clk)) 3058c2ecf20Sopenharmony_ci return PTR_ERR(info->clk); 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci ret = clk_prepare_enable(info->clk); 3088c2ecf20Sopenharmony_ci if (ret < 0) 3098c2ecf20Sopenharmony_ci return ret; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci /* set context info */ 3128c2ecf20Sopenharmony_ci info->pdev = pdev; 3138c2ecf20Sopenharmony_ci spin_lock_init(&info->lock); 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, info); 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci /* clear out the hardware */ 3188c2ecf20Sopenharmony_ci writel(0, info->base + TEGRA_RTC_REG_SECONDS_ALARM0); 3198c2ecf20Sopenharmony_ci writel(0xffffffff, info->base + TEGRA_RTC_REG_INTR_STATUS); 3208c2ecf20Sopenharmony_ci writel(0, info->base + TEGRA_RTC_REG_INTR_MASK); 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci device_init_wakeup(&pdev->dev, 1); 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci ret = devm_request_irq(&pdev->dev, info->irq, tegra_rtc_irq_handler, 3258c2ecf20Sopenharmony_ci IRQF_TRIGGER_HIGH, dev_name(&pdev->dev), 3268c2ecf20Sopenharmony_ci &pdev->dev); 3278c2ecf20Sopenharmony_ci if (ret) { 3288c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to request interrupt: %d\n", ret); 3298c2ecf20Sopenharmony_ci goto disable_clk; 3308c2ecf20Sopenharmony_ci } 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci ret = rtc_register_device(info->rtc); 3338c2ecf20Sopenharmony_ci if (ret) 3348c2ecf20Sopenharmony_ci goto disable_clk; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci dev_notice(&pdev->dev, "Tegra internal Real Time Clock\n"); 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci return 0; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_cidisable_clk: 3418c2ecf20Sopenharmony_ci clk_disable_unprepare(info->clk); 3428c2ecf20Sopenharmony_ci return ret; 3438c2ecf20Sopenharmony_ci} 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_cistatic int tegra_rtc_remove(struct platform_device *pdev) 3468c2ecf20Sopenharmony_ci{ 3478c2ecf20Sopenharmony_ci struct tegra_rtc_info *info = platform_get_drvdata(pdev); 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci clk_disable_unprepare(info->clk); 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci return 0; 3528c2ecf20Sopenharmony_ci} 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 3558c2ecf20Sopenharmony_cistatic int tegra_rtc_suspend(struct device *dev) 3568c2ecf20Sopenharmony_ci{ 3578c2ecf20Sopenharmony_ci struct tegra_rtc_info *info = dev_get_drvdata(dev); 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci tegra_rtc_wait_while_busy(dev); 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci /* only use ALARM0 as a wake source */ 3628c2ecf20Sopenharmony_ci writel(0xffffffff, info->base + TEGRA_RTC_REG_INTR_STATUS); 3638c2ecf20Sopenharmony_ci writel(TEGRA_RTC_INTR_STATUS_SEC_ALARM0, 3648c2ecf20Sopenharmony_ci info->base + TEGRA_RTC_REG_INTR_MASK); 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci dev_vdbg(dev, "alarm sec = %d\n", 3678c2ecf20Sopenharmony_ci readl(info->base + TEGRA_RTC_REG_SECONDS_ALARM0)); 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci dev_vdbg(dev, "Suspend (device_may_wakeup=%d) IRQ:%d\n", 3708c2ecf20Sopenharmony_ci device_may_wakeup(dev), info->irq); 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci /* leave the alarms on as a wake source */ 3738c2ecf20Sopenharmony_ci if (device_may_wakeup(dev)) 3748c2ecf20Sopenharmony_ci enable_irq_wake(info->irq); 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci return 0; 3778c2ecf20Sopenharmony_ci} 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_cistatic int tegra_rtc_resume(struct device *dev) 3808c2ecf20Sopenharmony_ci{ 3818c2ecf20Sopenharmony_ci struct tegra_rtc_info *info = dev_get_drvdata(dev); 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci dev_vdbg(dev, "Resume (device_may_wakeup=%d)\n", 3848c2ecf20Sopenharmony_ci device_may_wakeup(dev)); 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci /* alarms were left on as a wake source, turn them off */ 3878c2ecf20Sopenharmony_ci if (device_may_wakeup(dev)) 3888c2ecf20Sopenharmony_ci disable_irq_wake(info->irq); 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci return 0; 3918c2ecf20Sopenharmony_ci} 3928c2ecf20Sopenharmony_ci#endif 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(tegra_rtc_pm_ops, tegra_rtc_suspend, tegra_rtc_resume); 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_cistatic void tegra_rtc_shutdown(struct platform_device *pdev) 3978c2ecf20Sopenharmony_ci{ 3988c2ecf20Sopenharmony_ci dev_vdbg(&pdev->dev, "disabling interrupts\n"); 3998c2ecf20Sopenharmony_ci tegra_rtc_alarm_irq_enable(&pdev->dev, 0); 4008c2ecf20Sopenharmony_ci} 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_cistatic struct platform_driver tegra_rtc_driver = { 4038c2ecf20Sopenharmony_ci .probe = tegra_rtc_probe, 4048c2ecf20Sopenharmony_ci .remove = tegra_rtc_remove, 4058c2ecf20Sopenharmony_ci .shutdown = tegra_rtc_shutdown, 4068c2ecf20Sopenharmony_ci .driver = { 4078c2ecf20Sopenharmony_ci .name = "tegra_rtc", 4088c2ecf20Sopenharmony_ci .of_match_table = tegra_rtc_dt_match, 4098c2ecf20Sopenharmony_ci .pm = &tegra_rtc_pm_ops, 4108c2ecf20Sopenharmony_ci }, 4118c2ecf20Sopenharmony_ci}; 4128c2ecf20Sopenharmony_cimodule_platform_driver(tegra_rtc_driver); 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ciMODULE_AUTHOR("Jon Mayo <jmayo@nvidia.com>"); 4158c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("driver for Tegra internal RTC"); 4168c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 417