18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * SiRFSoC Real Time Clock interface for Linux 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2013 Cambridge Silicon Radio Limited, a CSR plc group company. 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/module.h> 98c2ecf20Sopenharmony_ci#include <linux/err.h> 108c2ecf20Sopenharmony_ci#include <linux/rtc.h> 118c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 128c2ecf20Sopenharmony_ci#include <linux/slab.h> 138c2ecf20Sopenharmony_ci#include <linux/io.h> 148c2ecf20Sopenharmony_ci#include <linux/of.h> 158c2ecf20Sopenharmony_ci#include <linux/regmap.h> 168c2ecf20Sopenharmony_ci#include <linux/rtc/sirfsoc_rtciobrg.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#define RTC_CN 0x00 208c2ecf20Sopenharmony_ci#define RTC_ALARM0 0x04 218c2ecf20Sopenharmony_ci#define RTC_ALARM1 0x18 228c2ecf20Sopenharmony_ci#define RTC_STATUS 0x08 238c2ecf20Sopenharmony_ci#define RTC_SW_VALUE 0x40 248c2ecf20Sopenharmony_ci#define SIRFSOC_RTC_AL1E (1<<6) 258c2ecf20Sopenharmony_ci#define SIRFSOC_RTC_AL1 (1<<4) 268c2ecf20Sopenharmony_ci#define SIRFSOC_RTC_HZE (1<<3) 278c2ecf20Sopenharmony_ci#define SIRFSOC_RTC_AL0E (1<<2) 288c2ecf20Sopenharmony_ci#define SIRFSOC_RTC_HZ (1<<1) 298c2ecf20Sopenharmony_ci#define SIRFSOC_RTC_AL0 (1<<0) 308c2ecf20Sopenharmony_ci#define RTC_DIV 0x0c 318c2ecf20Sopenharmony_ci#define RTC_DEEP_CTRL 0x14 328c2ecf20Sopenharmony_ci#define RTC_CLOCK_SWITCH 0x1c 338c2ecf20Sopenharmony_ci#define SIRFSOC_RTC_CLK 0x03 /* others are reserved */ 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci/* Refer to RTC DIV switch */ 368c2ecf20Sopenharmony_ci#define RTC_HZ 16 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci/* This macro is also defined in arch/arm/plat-sirfsoc/cpu.c */ 398c2ecf20Sopenharmony_ci#define RTC_SHIFT 4 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci#define INTR_SYSRTC_CN 0x48 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistruct sirfsoc_rtc_drv { 448c2ecf20Sopenharmony_ci struct rtc_device *rtc; 458c2ecf20Sopenharmony_ci u32 rtc_base; 468c2ecf20Sopenharmony_ci u32 irq; 478c2ecf20Sopenharmony_ci unsigned irq_wake; 488c2ecf20Sopenharmony_ci /* Overflow for every 8 years extra time */ 498c2ecf20Sopenharmony_ci u32 overflow_rtc; 508c2ecf20Sopenharmony_ci spinlock_t lock; 518c2ecf20Sopenharmony_ci struct regmap *regmap; 528c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 538c2ecf20Sopenharmony_ci u32 saved_counter; 548c2ecf20Sopenharmony_ci u32 saved_overflow_rtc; 558c2ecf20Sopenharmony_ci#endif 568c2ecf20Sopenharmony_ci}; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_cistatic u32 sirfsoc_rtc_readl(struct sirfsoc_rtc_drv *rtcdrv, u32 offset) 598c2ecf20Sopenharmony_ci{ 608c2ecf20Sopenharmony_ci u32 val; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci regmap_read(rtcdrv->regmap, rtcdrv->rtc_base + offset, &val); 638c2ecf20Sopenharmony_ci return val; 648c2ecf20Sopenharmony_ci} 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_cistatic void sirfsoc_rtc_writel(struct sirfsoc_rtc_drv *rtcdrv, 678c2ecf20Sopenharmony_ci u32 offset, u32 val) 688c2ecf20Sopenharmony_ci{ 698c2ecf20Sopenharmony_ci regmap_write(rtcdrv->regmap, rtcdrv->rtc_base + offset, val); 708c2ecf20Sopenharmony_ci} 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cistatic int sirfsoc_rtc_read_alarm(struct device *dev, 738c2ecf20Sopenharmony_ci struct rtc_wkalrm *alrm) 748c2ecf20Sopenharmony_ci{ 758c2ecf20Sopenharmony_ci unsigned long rtc_alarm, rtc_count; 768c2ecf20Sopenharmony_ci struct sirfsoc_rtc_drv *rtcdrv; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci rtcdrv = dev_get_drvdata(dev); 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci spin_lock_irq(&rtcdrv->lock); 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci rtc_count = sirfsoc_rtc_readl(rtcdrv, RTC_CN); 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci rtc_alarm = sirfsoc_rtc_readl(rtcdrv, RTC_ALARM0); 858c2ecf20Sopenharmony_ci memset(alrm, 0, sizeof(struct rtc_wkalrm)); 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci /* 888c2ecf20Sopenharmony_ci * assume alarm interval not beyond one round counter overflow_rtc: 898c2ecf20Sopenharmony_ci * 0->0xffffffff 908c2ecf20Sopenharmony_ci */ 918c2ecf20Sopenharmony_ci /* if alarm is in next overflow cycle */ 928c2ecf20Sopenharmony_ci if (rtc_count > rtc_alarm) 938c2ecf20Sopenharmony_ci rtc_time64_to_tm((rtcdrv->overflow_rtc + 1) 948c2ecf20Sopenharmony_ci << (BITS_PER_LONG - RTC_SHIFT) 958c2ecf20Sopenharmony_ci | rtc_alarm >> RTC_SHIFT, &alrm->time); 968c2ecf20Sopenharmony_ci else 978c2ecf20Sopenharmony_ci rtc_time64_to_tm(rtcdrv->overflow_rtc 988c2ecf20Sopenharmony_ci << (BITS_PER_LONG - RTC_SHIFT) 998c2ecf20Sopenharmony_ci | rtc_alarm >> RTC_SHIFT, &alrm->time); 1008c2ecf20Sopenharmony_ci if (sirfsoc_rtc_readl(rtcdrv, RTC_STATUS) & SIRFSOC_RTC_AL0E) 1018c2ecf20Sopenharmony_ci alrm->enabled = 1; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci spin_unlock_irq(&rtcdrv->lock); 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci return 0; 1068c2ecf20Sopenharmony_ci} 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_cistatic int sirfsoc_rtc_set_alarm(struct device *dev, 1098c2ecf20Sopenharmony_ci struct rtc_wkalrm *alrm) 1108c2ecf20Sopenharmony_ci{ 1118c2ecf20Sopenharmony_ci unsigned long rtc_status_reg, rtc_alarm; 1128c2ecf20Sopenharmony_ci struct sirfsoc_rtc_drv *rtcdrv; 1138c2ecf20Sopenharmony_ci rtcdrv = dev_get_drvdata(dev); 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci if (alrm->enabled) { 1168c2ecf20Sopenharmony_ci rtc_alarm = rtc_tm_to_time64(&alrm->time); 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci spin_lock_irq(&rtcdrv->lock); 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci rtc_status_reg = sirfsoc_rtc_readl(rtcdrv, RTC_STATUS); 1218c2ecf20Sopenharmony_ci if (rtc_status_reg & SIRFSOC_RTC_AL0E) { 1228c2ecf20Sopenharmony_ci /* 1238c2ecf20Sopenharmony_ci * An ongoing alarm in progress - ingore it and not 1248c2ecf20Sopenharmony_ci * to return EBUSY 1258c2ecf20Sopenharmony_ci */ 1268c2ecf20Sopenharmony_ci dev_info(dev, "An old alarm was set, will be replaced by a new one\n"); 1278c2ecf20Sopenharmony_ci } 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci sirfsoc_rtc_writel(rtcdrv, RTC_ALARM0, rtc_alarm << RTC_SHIFT); 1308c2ecf20Sopenharmony_ci rtc_status_reg &= ~0x07; /* mask out the lower status bits */ 1318c2ecf20Sopenharmony_ci /* 1328c2ecf20Sopenharmony_ci * This bit RTC_AL sets it as a wake-up source for Sleep Mode 1338c2ecf20Sopenharmony_ci * Writing 1 into this bit will clear it 1348c2ecf20Sopenharmony_ci */ 1358c2ecf20Sopenharmony_ci rtc_status_reg |= SIRFSOC_RTC_AL0; 1368c2ecf20Sopenharmony_ci /* enable the RTC alarm interrupt */ 1378c2ecf20Sopenharmony_ci rtc_status_reg |= SIRFSOC_RTC_AL0E; 1388c2ecf20Sopenharmony_ci sirfsoc_rtc_writel(rtcdrv, RTC_STATUS, rtc_status_reg); 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci spin_unlock_irq(&rtcdrv->lock); 1418c2ecf20Sopenharmony_ci } else { 1428c2ecf20Sopenharmony_ci /* 1438c2ecf20Sopenharmony_ci * if this function was called with enabled=0 1448c2ecf20Sopenharmony_ci * then it could mean that the application is 1458c2ecf20Sopenharmony_ci * trying to cancel an ongoing alarm 1468c2ecf20Sopenharmony_ci */ 1478c2ecf20Sopenharmony_ci spin_lock_irq(&rtcdrv->lock); 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci rtc_status_reg = sirfsoc_rtc_readl(rtcdrv, RTC_STATUS); 1508c2ecf20Sopenharmony_ci if (rtc_status_reg & SIRFSOC_RTC_AL0E) { 1518c2ecf20Sopenharmony_ci /* clear the RTC status register's alarm bit */ 1528c2ecf20Sopenharmony_ci rtc_status_reg &= ~0x07; 1538c2ecf20Sopenharmony_ci /* write 1 into SIRFSOC_RTC_AL0 to force a clear */ 1548c2ecf20Sopenharmony_ci rtc_status_reg |= (SIRFSOC_RTC_AL0); 1558c2ecf20Sopenharmony_ci /* Clear the Alarm enable bit */ 1568c2ecf20Sopenharmony_ci rtc_status_reg &= ~(SIRFSOC_RTC_AL0E); 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci sirfsoc_rtc_writel(rtcdrv, RTC_STATUS, 1598c2ecf20Sopenharmony_ci rtc_status_reg); 1608c2ecf20Sopenharmony_ci } 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci spin_unlock_irq(&rtcdrv->lock); 1638c2ecf20Sopenharmony_ci } 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci return 0; 1668c2ecf20Sopenharmony_ci} 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_cistatic int sirfsoc_rtc_read_time(struct device *dev, 1698c2ecf20Sopenharmony_ci struct rtc_time *tm) 1708c2ecf20Sopenharmony_ci{ 1718c2ecf20Sopenharmony_ci unsigned long tmp_rtc = 0; 1728c2ecf20Sopenharmony_ci struct sirfsoc_rtc_drv *rtcdrv; 1738c2ecf20Sopenharmony_ci rtcdrv = dev_get_drvdata(dev); 1748c2ecf20Sopenharmony_ci /* 1758c2ecf20Sopenharmony_ci * This patch is taken from WinCE - Need to validate this for 1768c2ecf20Sopenharmony_ci * correctness. To work around sirfsoc RTC counter double sync logic 1778c2ecf20Sopenharmony_ci * fail, read several times to make sure get stable value. 1788c2ecf20Sopenharmony_ci */ 1798c2ecf20Sopenharmony_ci do { 1808c2ecf20Sopenharmony_ci tmp_rtc = sirfsoc_rtc_readl(rtcdrv, RTC_CN); 1818c2ecf20Sopenharmony_ci cpu_relax(); 1828c2ecf20Sopenharmony_ci } while (tmp_rtc != sirfsoc_rtc_readl(rtcdrv, RTC_CN)); 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci rtc_time64_to_tm(rtcdrv->overflow_rtc << (BITS_PER_LONG - RTC_SHIFT) 1858c2ecf20Sopenharmony_ci | tmp_rtc >> RTC_SHIFT, tm); 1868c2ecf20Sopenharmony_ci return 0; 1878c2ecf20Sopenharmony_ci} 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_cistatic int sirfsoc_rtc_set_time(struct device *dev, 1908c2ecf20Sopenharmony_ci struct rtc_time *tm) 1918c2ecf20Sopenharmony_ci{ 1928c2ecf20Sopenharmony_ci unsigned long rtc_time; 1938c2ecf20Sopenharmony_ci struct sirfsoc_rtc_drv *rtcdrv; 1948c2ecf20Sopenharmony_ci rtcdrv = dev_get_drvdata(dev); 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci rtc_time = rtc_tm_to_time64(tm); 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci rtcdrv->overflow_rtc = rtc_time >> (BITS_PER_LONG - RTC_SHIFT); 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci sirfsoc_rtc_writel(rtcdrv, RTC_SW_VALUE, rtcdrv->overflow_rtc); 2018c2ecf20Sopenharmony_ci sirfsoc_rtc_writel(rtcdrv, RTC_CN, rtc_time << RTC_SHIFT); 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci return 0; 2048c2ecf20Sopenharmony_ci} 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_cistatic int sirfsoc_rtc_alarm_irq_enable(struct device *dev, 2078c2ecf20Sopenharmony_ci unsigned int enabled) 2088c2ecf20Sopenharmony_ci{ 2098c2ecf20Sopenharmony_ci unsigned long rtc_status_reg = 0x0; 2108c2ecf20Sopenharmony_ci struct sirfsoc_rtc_drv *rtcdrv; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci rtcdrv = dev_get_drvdata(dev); 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci spin_lock_irq(&rtcdrv->lock); 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci rtc_status_reg = sirfsoc_rtc_readl(rtcdrv, RTC_STATUS); 2178c2ecf20Sopenharmony_ci if (enabled) 2188c2ecf20Sopenharmony_ci rtc_status_reg |= SIRFSOC_RTC_AL0E; 2198c2ecf20Sopenharmony_ci else 2208c2ecf20Sopenharmony_ci rtc_status_reg &= ~SIRFSOC_RTC_AL0E; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci sirfsoc_rtc_writel(rtcdrv, RTC_STATUS, rtc_status_reg); 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci spin_unlock_irq(&rtcdrv->lock); 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci return 0; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci} 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_cistatic const struct rtc_class_ops sirfsoc_rtc_ops = { 2318c2ecf20Sopenharmony_ci .read_time = sirfsoc_rtc_read_time, 2328c2ecf20Sopenharmony_ci .set_time = sirfsoc_rtc_set_time, 2338c2ecf20Sopenharmony_ci .read_alarm = sirfsoc_rtc_read_alarm, 2348c2ecf20Sopenharmony_ci .set_alarm = sirfsoc_rtc_set_alarm, 2358c2ecf20Sopenharmony_ci .alarm_irq_enable = sirfsoc_rtc_alarm_irq_enable 2368c2ecf20Sopenharmony_ci}; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_cistatic irqreturn_t sirfsoc_rtc_irq_handler(int irq, void *pdata) 2398c2ecf20Sopenharmony_ci{ 2408c2ecf20Sopenharmony_ci struct sirfsoc_rtc_drv *rtcdrv = pdata; 2418c2ecf20Sopenharmony_ci unsigned long rtc_status_reg = 0x0; 2428c2ecf20Sopenharmony_ci unsigned long events = 0x0; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci spin_lock(&rtcdrv->lock); 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci rtc_status_reg = sirfsoc_rtc_readl(rtcdrv, RTC_STATUS); 2478c2ecf20Sopenharmony_ci /* this bit will be set ONLY if an alarm was active 2488c2ecf20Sopenharmony_ci * and it expired NOW 2498c2ecf20Sopenharmony_ci * So this is being used as an ASSERT 2508c2ecf20Sopenharmony_ci */ 2518c2ecf20Sopenharmony_ci if (rtc_status_reg & SIRFSOC_RTC_AL0) { 2528c2ecf20Sopenharmony_ci /* 2538c2ecf20Sopenharmony_ci * clear the RTC status register's alarm bit 2548c2ecf20Sopenharmony_ci * mask out the lower status bits 2558c2ecf20Sopenharmony_ci */ 2568c2ecf20Sopenharmony_ci rtc_status_reg &= ~0x07; 2578c2ecf20Sopenharmony_ci /* write 1 into SIRFSOC_RTC_AL0 to ACK the alarm interrupt */ 2588c2ecf20Sopenharmony_ci rtc_status_reg |= (SIRFSOC_RTC_AL0); 2598c2ecf20Sopenharmony_ci /* Clear the Alarm enable bit */ 2608c2ecf20Sopenharmony_ci rtc_status_reg &= ~(SIRFSOC_RTC_AL0E); 2618c2ecf20Sopenharmony_ci } 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci sirfsoc_rtc_writel(rtcdrv, RTC_STATUS, rtc_status_reg); 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci spin_unlock(&rtcdrv->lock); 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci /* this should wake up any apps polling/waiting on the read 2688c2ecf20Sopenharmony_ci * after setting the alarm 2698c2ecf20Sopenharmony_ci */ 2708c2ecf20Sopenharmony_ci events |= RTC_IRQF | RTC_AF; 2718c2ecf20Sopenharmony_ci rtc_update_irq(rtcdrv->rtc, 1, events); 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci return IRQ_HANDLED; 2748c2ecf20Sopenharmony_ci} 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_cistatic const struct of_device_id sirfsoc_rtc_of_match[] = { 2778c2ecf20Sopenharmony_ci { .compatible = "sirf,prima2-sysrtc"}, 2788c2ecf20Sopenharmony_ci {}, 2798c2ecf20Sopenharmony_ci}; 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_cistatic const struct regmap_config sysrtc_regmap_config = { 2828c2ecf20Sopenharmony_ci .reg_bits = 32, 2838c2ecf20Sopenharmony_ci .val_bits = 32, 2848c2ecf20Sopenharmony_ci .fast_io = true, 2858c2ecf20Sopenharmony_ci}; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, sirfsoc_rtc_of_match); 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_cistatic int sirfsoc_rtc_probe(struct platform_device *pdev) 2908c2ecf20Sopenharmony_ci{ 2918c2ecf20Sopenharmony_ci int err; 2928c2ecf20Sopenharmony_ci unsigned long rtc_div; 2938c2ecf20Sopenharmony_ci struct sirfsoc_rtc_drv *rtcdrv; 2948c2ecf20Sopenharmony_ci struct device_node *np = pdev->dev.of_node; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci rtcdrv = devm_kzalloc(&pdev->dev, 2978c2ecf20Sopenharmony_ci sizeof(struct sirfsoc_rtc_drv), GFP_KERNEL); 2988c2ecf20Sopenharmony_ci if (rtcdrv == NULL) 2998c2ecf20Sopenharmony_ci return -ENOMEM; 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci spin_lock_init(&rtcdrv->lock); 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci err = of_property_read_u32(np, "reg", &rtcdrv->rtc_base); 3048c2ecf20Sopenharmony_ci if (err) { 3058c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "unable to find base address of rtc node in dtb\n"); 3068c2ecf20Sopenharmony_ci return err; 3078c2ecf20Sopenharmony_ci } 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, rtcdrv); 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci /* Register rtc alarm as a wakeup source */ 3128c2ecf20Sopenharmony_ci device_init_wakeup(&pdev->dev, 1); 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci rtcdrv->regmap = devm_regmap_init_iobg(&pdev->dev, 3158c2ecf20Sopenharmony_ci &sysrtc_regmap_config); 3168c2ecf20Sopenharmony_ci if (IS_ERR(rtcdrv->regmap)) { 3178c2ecf20Sopenharmony_ci err = PTR_ERR(rtcdrv->regmap); 3188c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Failed to allocate register map: %d\n", 3198c2ecf20Sopenharmony_ci err); 3208c2ecf20Sopenharmony_ci return err; 3218c2ecf20Sopenharmony_ci } 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci /* 3248c2ecf20Sopenharmony_ci * Set SYS_RTC counter in RTC_HZ HZ Units 3258c2ecf20Sopenharmony_ci * We are using 32K RTC crystal (32768 / RTC_HZ / 2) -1 3268c2ecf20Sopenharmony_ci * If 16HZ, therefore RTC_DIV = 1023; 3278c2ecf20Sopenharmony_ci */ 3288c2ecf20Sopenharmony_ci rtc_div = ((32768 / RTC_HZ) / 2) - 1; 3298c2ecf20Sopenharmony_ci sirfsoc_rtc_writel(rtcdrv, RTC_DIV, rtc_div); 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci /* 0x3 -> RTC_CLK */ 3328c2ecf20Sopenharmony_ci sirfsoc_rtc_writel(rtcdrv, RTC_CLOCK_SWITCH, SIRFSOC_RTC_CLK); 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci /* reset SYS RTC ALARM0 */ 3358c2ecf20Sopenharmony_ci sirfsoc_rtc_writel(rtcdrv, RTC_ALARM0, 0x0); 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci /* reset SYS RTC ALARM1 */ 3388c2ecf20Sopenharmony_ci sirfsoc_rtc_writel(rtcdrv, RTC_ALARM1, 0x0); 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci /* Restore RTC Overflow From Register After Command Reboot */ 3418c2ecf20Sopenharmony_ci rtcdrv->overflow_rtc = 3428c2ecf20Sopenharmony_ci sirfsoc_rtc_readl(rtcdrv, RTC_SW_VALUE); 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci rtcdrv->rtc = devm_rtc_allocate_device(&pdev->dev); 3458c2ecf20Sopenharmony_ci if (IS_ERR(rtcdrv->rtc)) 3468c2ecf20Sopenharmony_ci return PTR_ERR(rtcdrv->rtc); 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci rtcdrv->rtc->ops = &sirfsoc_rtc_ops; 3498c2ecf20Sopenharmony_ci rtcdrv->rtc->range_max = (1ULL << 60) - 1; 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci rtcdrv->irq = platform_get_irq(pdev, 0); 3528c2ecf20Sopenharmony_ci err = devm_request_irq(&pdev->dev, rtcdrv->irq, sirfsoc_rtc_irq_handler, 3538c2ecf20Sopenharmony_ci IRQF_SHARED, pdev->name, rtcdrv); 3548c2ecf20Sopenharmony_ci if (err) { 3558c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Unable to register for the SiRF SOC RTC IRQ\n"); 3568c2ecf20Sopenharmony_ci return err; 3578c2ecf20Sopenharmony_ci } 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci return rtc_register_device(rtcdrv->rtc); 3608c2ecf20Sopenharmony_ci} 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 3638c2ecf20Sopenharmony_cistatic int sirfsoc_rtc_suspend(struct device *dev) 3648c2ecf20Sopenharmony_ci{ 3658c2ecf20Sopenharmony_ci struct sirfsoc_rtc_drv *rtcdrv = dev_get_drvdata(dev); 3668c2ecf20Sopenharmony_ci rtcdrv->overflow_rtc = 3678c2ecf20Sopenharmony_ci sirfsoc_rtc_readl(rtcdrv, RTC_SW_VALUE); 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci rtcdrv->saved_counter = 3708c2ecf20Sopenharmony_ci sirfsoc_rtc_readl(rtcdrv, RTC_CN); 3718c2ecf20Sopenharmony_ci rtcdrv->saved_overflow_rtc = rtcdrv->overflow_rtc; 3728c2ecf20Sopenharmony_ci if (device_may_wakeup(dev) && !enable_irq_wake(rtcdrv->irq)) 3738c2ecf20Sopenharmony_ci rtcdrv->irq_wake = 1; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci return 0; 3768c2ecf20Sopenharmony_ci} 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_cistatic int sirfsoc_rtc_resume(struct device *dev) 3798c2ecf20Sopenharmony_ci{ 3808c2ecf20Sopenharmony_ci u32 tmp; 3818c2ecf20Sopenharmony_ci struct sirfsoc_rtc_drv *rtcdrv = dev_get_drvdata(dev); 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci /* 3848c2ecf20Sopenharmony_ci * if resume from snapshot and the rtc power is lost, 3858c2ecf20Sopenharmony_ci * restroe the rtc settings 3868c2ecf20Sopenharmony_ci */ 3878c2ecf20Sopenharmony_ci if (SIRFSOC_RTC_CLK != sirfsoc_rtc_readl(rtcdrv, RTC_CLOCK_SWITCH)) { 3888c2ecf20Sopenharmony_ci u32 rtc_div; 3898c2ecf20Sopenharmony_ci /* 0x3 -> RTC_CLK */ 3908c2ecf20Sopenharmony_ci sirfsoc_rtc_writel(rtcdrv, RTC_CLOCK_SWITCH, SIRFSOC_RTC_CLK); 3918c2ecf20Sopenharmony_ci /* 3928c2ecf20Sopenharmony_ci * Set SYS_RTC counter in RTC_HZ HZ Units 3938c2ecf20Sopenharmony_ci * We are using 32K RTC crystal (32768 / RTC_HZ / 2) -1 3948c2ecf20Sopenharmony_ci * If 16HZ, therefore RTC_DIV = 1023; 3958c2ecf20Sopenharmony_ci */ 3968c2ecf20Sopenharmony_ci rtc_div = ((32768 / RTC_HZ) / 2) - 1; 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci sirfsoc_rtc_writel(rtcdrv, RTC_DIV, rtc_div); 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci /* reset SYS RTC ALARM0 */ 4018c2ecf20Sopenharmony_ci sirfsoc_rtc_writel(rtcdrv, RTC_ALARM0, 0x0); 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci /* reset SYS RTC ALARM1 */ 4048c2ecf20Sopenharmony_ci sirfsoc_rtc_writel(rtcdrv, RTC_ALARM1, 0x0); 4058c2ecf20Sopenharmony_ci } 4068c2ecf20Sopenharmony_ci rtcdrv->overflow_rtc = rtcdrv->saved_overflow_rtc; 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci /* 4098c2ecf20Sopenharmony_ci * if current counter is small than previous, 4108c2ecf20Sopenharmony_ci * it means overflow in sleep 4118c2ecf20Sopenharmony_ci */ 4128c2ecf20Sopenharmony_ci tmp = sirfsoc_rtc_readl(rtcdrv, RTC_CN); 4138c2ecf20Sopenharmony_ci if (tmp <= rtcdrv->saved_counter) 4148c2ecf20Sopenharmony_ci rtcdrv->overflow_rtc++; 4158c2ecf20Sopenharmony_ci /* 4168c2ecf20Sopenharmony_ci *PWRC Value Be Changed When Suspend, Restore Overflow 4178c2ecf20Sopenharmony_ci * In Memory To Register 4188c2ecf20Sopenharmony_ci */ 4198c2ecf20Sopenharmony_ci sirfsoc_rtc_writel(rtcdrv, RTC_SW_VALUE, rtcdrv->overflow_rtc); 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci if (device_may_wakeup(dev) && rtcdrv->irq_wake) { 4228c2ecf20Sopenharmony_ci disable_irq_wake(rtcdrv->irq); 4238c2ecf20Sopenharmony_ci rtcdrv->irq_wake = 0; 4248c2ecf20Sopenharmony_ci } 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci return 0; 4278c2ecf20Sopenharmony_ci} 4288c2ecf20Sopenharmony_ci#endif 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(sirfsoc_rtc_pm_ops, 4318c2ecf20Sopenharmony_ci sirfsoc_rtc_suspend, sirfsoc_rtc_resume); 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_cistatic struct platform_driver sirfsoc_rtc_driver = { 4348c2ecf20Sopenharmony_ci .driver = { 4358c2ecf20Sopenharmony_ci .name = "sirfsoc-rtc", 4368c2ecf20Sopenharmony_ci .pm = &sirfsoc_rtc_pm_ops, 4378c2ecf20Sopenharmony_ci .of_match_table = sirfsoc_rtc_of_match, 4388c2ecf20Sopenharmony_ci }, 4398c2ecf20Sopenharmony_ci .probe = sirfsoc_rtc_probe, 4408c2ecf20Sopenharmony_ci}; 4418c2ecf20Sopenharmony_cimodule_platform_driver(sirfsoc_rtc_driver); 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("SiRF SoC rtc driver"); 4448c2ecf20Sopenharmony_ciMODULE_AUTHOR("Xianglong Du <Xianglong.Du@csr.com>"); 4458c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 4468c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:sirfsoc-rtc"); 447