14e64350fSAmelie Delaunay /* 24e64350fSAmelie Delaunay * Copyright (C) Amelie Delaunay 2016 34e64350fSAmelie Delaunay * Author: Amelie Delaunay <amelie.delaunay@st.com> 44e64350fSAmelie Delaunay * License terms: GNU General Public License (GPL), version 2 54e64350fSAmelie Delaunay */ 64e64350fSAmelie Delaunay 74e64350fSAmelie Delaunay #include <linux/bcd.h> 84e64350fSAmelie Delaunay #include <linux/clk.h> 94e64350fSAmelie Delaunay #include <linux/iopoll.h> 104e64350fSAmelie Delaunay #include <linux/ioport.h> 114e64350fSAmelie Delaunay #include <linux/mfd/syscon.h> 124e64350fSAmelie Delaunay #include <linux/module.h> 134e64350fSAmelie Delaunay #include <linux/of_device.h> 144e64350fSAmelie Delaunay #include <linux/regmap.h> 154e64350fSAmelie Delaunay #include <linux/rtc.h> 164e64350fSAmelie Delaunay 174e64350fSAmelie Delaunay #define DRIVER_NAME "stm32_rtc" 184e64350fSAmelie Delaunay 194e64350fSAmelie Delaunay /* STM32 RTC registers */ 204e64350fSAmelie Delaunay #define STM32_RTC_TR 0x00 214e64350fSAmelie Delaunay #define STM32_RTC_DR 0x04 224e64350fSAmelie Delaunay #define STM32_RTC_CR 0x08 234e64350fSAmelie Delaunay #define STM32_RTC_ISR 0x0C 244e64350fSAmelie Delaunay #define STM32_RTC_PRER 0x10 254e64350fSAmelie Delaunay #define STM32_RTC_ALRMAR 0x1C 264e64350fSAmelie Delaunay #define STM32_RTC_WPR 0x24 274e64350fSAmelie Delaunay 284e64350fSAmelie Delaunay /* STM32_RTC_TR bit fields */ 294e64350fSAmelie Delaunay #define STM32_RTC_TR_SEC_SHIFT 0 304e64350fSAmelie Delaunay #define STM32_RTC_TR_SEC GENMASK(6, 0) 314e64350fSAmelie Delaunay #define STM32_RTC_TR_MIN_SHIFT 8 324e64350fSAmelie Delaunay #define STM32_RTC_TR_MIN GENMASK(14, 8) 334e64350fSAmelie Delaunay #define STM32_RTC_TR_HOUR_SHIFT 16 344e64350fSAmelie Delaunay #define STM32_RTC_TR_HOUR GENMASK(21, 16) 354e64350fSAmelie Delaunay 364e64350fSAmelie Delaunay /* STM32_RTC_DR bit fields */ 374e64350fSAmelie Delaunay #define STM32_RTC_DR_DATE_SHIFT 0 384e64350fSAmelie Delaunay #define STM32_RTC_DR_DATE GENMASK(5, 0) 394e64350fSAmelie Delaunay #define STM32_RTC_DR_MONTH_SHIFT 8 404e64350fSAmelie Delaunay #define STM32_RTC_DR_MONTH GENMASK(12, 8) 414e64350fSAmelie Delaunay #define STM32_RTC_DR_WDAY_SHIFT 13 424e64350fSAmelie Delaunay #define STM32_RTC_DR_WDAY GENMASK(15, 13) 434e64350fSAmelie Delaunay #define STM32_RTC_DR_YEAR_SHIFT 16 444e64350fSAmelie Delaunay #define STM32_RTC_DR_YEAR GENMASK(23, 16) 454e64350fSAmelie Delaunay 464e64350fSAmelie Delaunay /* STM32_RTC_CR bit fields */ 474e64350fSAmelie Delaunay #define STM32_RTC_CR_FMT BIT(6) 484e64350fSAmelie Delaunay #define STM32_RTC_CR_ALRAE BIT(8) 494e64350fSAmelie Delaunay #define STM32_RTC_CR_ALRAIE BIT(12) 504e64350fSAmelie Delaunay 514e64350fSAmelie Delaunay /* STM32_RTC_ISR bit fields */ 524e64350fSAmelie Delaunay #define STM32_RTC_ISR_ALRAWF BIT(0) 534e64350fSAmelie Delaunay #define STM32_RTC_ISR_INITS BIT(4) 544e64350fSAmelie Delaunay #define STM32_RTC_ISR_RSF BIT(5) 554e64350fSAmelie Delaunay #define STM32_RTC_ISR_INITF BIT(6) 564e64350fSAmelie Delaunay #define STM32_RTC_ISR_INIT BIT(7) 574e64350fSAmelie Delaunay #define STM32_RTC_ISR_ALRAF BIT(8) 584e64350fSAmelie Delaunay 594e64350fSAmelie Delaunay /* STM32_RTC_PRER bit fields */ 604e64350fSAmelie Delaunay #define STM32_RTC_PRER_PRED_S_SHIFT 0 614e64350fSAmelie Delaunay #define STM32_RTC_PRER_PRED_S GENMASK(14, 0) 624e64350fSAmelie Delaunay #define STM32_RTC_PRER_PRED_A_SHIFT 16 634e64350fSAmelie Delaunay #define STM32_RTC_PRER_PRED_A GENMASK(22, 16) 644e64350fSAmelie Delaunay 654e64350fSAmelie Delaunay /* STM32_RTC_ALRMAR and STM32_RTC_ALRMBR bit fields */ 664e64350fSAmelie Delaunay #define STM32_RTC_ALRMXR_SEC_SHIFT 0 674e64350fSAmelie Delaunay #define STM32_RTC_ALRMXR_SEC GENMASK(6, 0) 684e64350fSAmelie Delaunay #define STM32_RTC_ALRMXR_SEC_MASK BIT(7) 694e64350fSAmelie Delaunay #define STM32_RTC_ALRMXR_MIN_SHIFT 8 704e64350fSAmelie Delaunay #define STM32_RTC_ALRMXR_MIN GENMASK(14, 8) 714e64350fSAmelie Delaunay #define STM32_RTC_ALRMXR_MIN_MASK BIT(15) 724e64350fSAmelie Delaunay #define STM32_RTC_ALRMXR_HOUR_SHIFT 16 734e64350fSAmelie Delaunay #define STM32_RTC_ALRMXR_HOUR GENMASK(21, 16) 744e64350fSAmelie Delaunay #define STM32_RTC_ALRMXR_PM BIT(22) 754e64350fSAmelie Delaunay #define STM32_RTC_ALRMXR_HOUR_MASK BIT(23) 764e64350fSAmelie Delaunay #define STM32_RTC_ALRMXR_DATE_SHIFT 24 774e64350fSAmelie Delaunay #define STM32_RTC_ALRMXR_DATE GENMASK(29, 24) 784e64350fSAmelie Delaunay #define STM32_RTC_ALRMXR_WDSEL BIT(30) 794e64350fSAmelie Delaunay #define STM32_RTC_ALRMXR_WDAY_SHIFT 24 804e64350fSAmelie Delaunay #define STM32_RTC_ALRMXR_WDAY GENMASK(27, 24) 814e64350fSAmelie Delaunay #define STM32_RTC_ALRMXR_DATE_MASK BIT(31) 824e64350fSAmelie Delaunay 834e64350fSAmelie Delaunay /* STM32_RTC_WPR key constants */ 844e64350fSAmelie Delaunay #define RTC_WPR_1ST_KEY 0xCA 854e64350fSAmelie Delaunay #define RTC_WPR_2ND_KEY 0x53 864e64350fSAmelie Delaunay #define RTC_WPR_WRONG_KEY 0xFF 874e64350fSAmelie Delaunay 884e64350fSAmelie Delaunay /* 894e64350fSAmelie Delaunay * RTC registers are protected against parasitic write access. 904e64350fSAmelie Delaunay * PWR_CR_DBP bit must be set to enable write access to RTC registers. 914e64350fSAmelie Delaunay */ 924e64350fSAmelie Delaunay /* STM32_PWR_CR */ 934e64350fSAmelie Delaunay #define PWR_CR 0x00 944e64350fSAmelie Delaunay /* STM32_PWR_CR bit field */ 954e64350fSAmelie Delaunay #define PWR_CR_DBP BIT(8) 964e64350fSAmelie Delaunay 974e64350fSAmelie Delaunay struct stm32_rtc { 984e64350fSAmelie Delaunay struct rtc_device *rtc_dev; 994e64350fSAmelie Delaunay void __iomem *base; 1004e64350fSAmelie Delaunay struct regmap *dbp; 1014e64350fSAmelie Delaunay struct clk *ck_rtc; 1024e64350fSAmelie Delaunay int irq_alarm; 1034e64350fSAmelie Delaunay }; 1044e64350fSAmelie Delaunay 1054e64350fSAmelie Delaunay static void stm32_rtc_wpr_unlock(struct stm32_rtc *rtc) 1064e64350fSAmelie Delaunay { 1074e64350fSAmelie Delaunay writel_relaxed(RTC_WPR_1ST_KEY, rtc->base + STM32_RTC_WPR); 1084e64350fSAmelie Delaunay writel_relaxed(RTC_WPR_2ND_KEY, rtc->base + STM32_RTC_WPR); 1094e64350fSAmelie Delaunay } 1104e64350fSAmelie Delaunay 1114e64350fSAmelie Delaunay static void stm32_rtc_wpr_lock(struct stm32_rtc *rtc) 1124e64350fSAmelie Delaunay { 1134e64350fSAmelie Delaunay writel_relaxed(RTC_WPR_WRONG_KEY, rtc->base + STM32_RTC_WPR); 1144e64350fSAmelie Delaunay } 1154e64350fSAmelie Delaunay 1164e64350fSAmelie Delaunay static int stm32_rtc_enter_init_mode(struct stm32_rtc *rtc) 1174e64350fSAmelie Delaunay { 1184e64350fSAmelie Delaunay unsigned int isr = readl_relaxed(rtc->base + STM32_RTC_ISR); 1194e64350fSAmelie Delaunay 1204e64350fSAmelie Delaunay if (!(isr & STM32_RTC_ISR_INITF)) { 1214e64350fSAmelie Delaunay isr |= STM32_RTC_ISR_INIT; 1224e64350fSAmelie Delaunay writel_relaxed(isr, rtc->base + STM32_RTC_ISR); 1234e64350fSAmelie Delaunay 1244e64350fSAmelie Delaunay /* 1254e64350fSAmelie Delaunay * It takes around 2 ck_rtc clock cycles to enter in 1264e64350fSAmelie Delaunay * initialization phase mode (and have INITF flag set). As 1274e64350fSAmelie Delaunay * slowest ck_rtc frequency may be 32kHz and highest should be 1284e64350fSAmelie Delaunay * 1MHz, we poll every 10 us with a timeout of 100ms. 1294e64350fSAmelie Delaunay */ 1304e64350fSAmelie Delaunay return readl_relaxed_poll_timeout_atomic( 1314e64350fSAmelie Delaunay rtc->base + STM32_RTC_ISR, 1324e64350fSAmelie Delaunay isr, (isr & STM32_RTC_ISR_INITF), 1334e64350fSAmelie Delaunay 10, 100000); 1344e64350fSAmelie Delaunay } 1354e64350fSAmelie Delaunay 1364e64350fSAmelie Delaunay return 0; 1374e64350fSAmelie Delaunay } 1384e64350fSAmelie Delaunay 1394e64350fSAmelie Delaunay static void stm32_rtc_exit_init_mode(struct stm32_rtc *rtc) 1404e64350fSAmelie Delaunay { 1414e64350fSAmelie Delaunay unsigned int isr = readl_relaxed(rtc->base + STM32_RTC_ISR); 1424e64350fSAmelie Delaunay 1434e64350fSAmelie Delaunay isr &= ~STM32_RTC_ISR_INIT; 1444e64350fSAmelie Delaunay writel_relaxed(isr, rtc->base + STM32_RTC_ISR); 1454e64350fSAmelie Delaunay } 1464e64350fSAmelie Delaunay 1474e64350fSAmelie Delaunay static int stm32_rtc_wait_sync(struct stm32_rtc *rtc) 1484e64350fSAmelie Delaunay { 1494e64350fSAmelie Delaunay unsigned int isr = readl_relaxed(rtc->base + STM32_RTC_ISR); 1504e64350fSAmelie Delaunay 1514e64350fSAmelie Delaunay isr &= ~STM32_RTC_ISR_RSF; 1524e64350fSAmelie Delaunay writel_relaxed(isr, rtc->base + STM32_RTC_ISR); 1534e64350fSAmelie Delaunay 1544e64350fSAmelie Delaunay /* 1554e64350fSAmelie Delaunay * Wait for RSF to be set to ensure the calendar registers are 1564e64350fSAmelie Delaunay * synchronised, it takes around 2 ck_rtc clock cycles 1574e64350fSAmelie Delaunay */ 1584e64350fSAmelie Delaunay return readl_relaxed_poll_timeout_atomic(rtc->base + STM32_RTC_ISR, 1594e64350fSAmelie Delaunay isr, 1604e64350fSAmelie Delaunay (isr & STM32_RTC_ISR_RSF), 1614e64350fSAmelie Delaunay 10, 100000); 1624e64350fSAmelie Delaunay } 1634e64350fSAmelie Delaunay 1644e64350fSAmelie Delaunay static irqreturn_t stm32_rtc_alarm_irq(int irq, void *dev_id) 1654e64350fSAmelie Delaunay { 1664e64350fSAmelie Delaunay struct stm32_rtc *rtc = (struct stm32_rtc *)dev_id; 1674e64350fSAmelie Delaunay unsigned int isr, cr; 1684e64350fSAmelie Delaunay 1694e64350fSAmelie Delaunay mutex_lock(&rtc->rtc_dev->ops_lock); 1704e64350fSAmelie Delaunay 1714e64350fSAmelie Delaunay isr = readl_relaxed(rtc->base + STM32_RTC_ISR); 1724e64350fSAmelie Delaunay cr = readl_relaxed(rtc->base + STM32_RTC_CR); 1734e64350fSAmelie Delaunay 1744e64350fSAmelie Delaunay if ((isr & STM32_RTC_ISR_ALRAF) && 1754e64350fSAmelie Delaunay (cr & STM32_RTC_CR_ALRAIE)) { 1764e64350fSAmelie Delaunay /* Alarm A flag - Alarm interrupt */ 1774e64350fSAmelie Delaunay dev_dbg(&rtc->rtc_dev->dev, "Alarm occurred\n"); 1784e64350fSAmelie Delaunay 1794e64350fSAmelie Delaunay /* Pass event to the kernel */ 1804e64350fSAmelie Delaunay rtc_update_irq(rtc->rtc_dev, 1, RTC_IRQF | RTC_AF); 1814e64350fSAmelie Delaunay 1824e64350fSAmelie Delaunay /* Clear event flag, otherwise new events won't be received */ 1834e64350fSAmelie Delaunay writel_relaxed(isr & ~STM32_RTC_ISR_ALRAF, 1844e64350fSAmelie Delaunay rtc->base + STM32_RTC_ISR); 1854e64350fSAmelie Delaunay } 1864e64350fSAmelie Delaunay 1874e64350fSAmelie Delaunay mutex_unlock(&rtc->rtc_dev->ops_lock); 1884e64350fSAmelie Delaunay 1894e64350fSAmelie Delaunay return IRQ_HANDLED; 1904e64350fSAmelie Delaunay } 1914e64350fSAmelie Delaunay 1924e64350fSAmelie Delaunay /* Convert rtc_time structure from bin to bcd format */ 1934e64350fSAmelie Delaunay static void tm2bcd(struct rtc_time *tm) 1944e64350fSAmelie Delaunay { 1954e64350fSAmelie Delaunay tm->tm_sec = bin2bcd(tm->tm_sec); 1964e64350fSAmelie Delaunay tm->tm_min = bin2bcd(tm->tm_min); 1974e64350fSAmelie Delaunay tm->tm_hour = bin2bcd(tm->tm_hour); 1984e64350fSAmelie Delaunay 1994e64350fSAmelie Delaunay tm->tm_mday = bin2bcd(tm->tm_mday); 2004e64350fSAmelie Delaunay tm->tm_mon = bin2bcd(tm->tm_mon + 1); 2014e64350fSAmelie Delaunay tm->tm_year = bin2bcd(tm->tm_year - 100); 2024e64350fSAmelie Delaunay /* 2034e64350fSAmelie Delaunay * Number of days since Sunday 2044e64350fSAmelie Delaunay * - on kernel side, 0=Sunday...6=Saturday 2054e64350fSAmelie Delaunay * - on rtc side, 0=invalid,1=Monday...7=Sunday 2064e64350fSAmelie Delaunay */ 2074e64350fSAmelie Delaunay tm->tm_wday = (!tm->tm_wday) ? 7 : tm->tm_wday; 2084e64350fSAmelie Delaunay } 2094e64350fSAmelie Delaunay 2104e64350fSAmelie Delaunay /* Convert rtc_time structure from bcd to bin format */ 2114e64350fSAmelie Delaunay static void bcd2tm(struct rtc_time *tm) 2124e64350fSAmelie Delaunay { 2134e64350fSAmelie Delaunay tm->tm_sec = bcd2bin(tm->tm_sec); 2144e64350fSAmelie Delaunay tm->tm_min = bcd2bin(tm->tm_min); 2154e64350fSAmelie Delaunay tm->tm_hour = bcd2bin(tm->tm_hour); 2164e64350fSAmelie Delaunay 2174e64350fSAmelie Delaunay tm->tm_mday = bcd2bin(tm->tm_mday); 2184e64350fSAmelie Delaunay tm->tm_mon = bcd2bin(tm->tm_mon) - 1; 2194e64350fSAmelie Delaunay tm->tm_year = bcd2bin(tm->tm_year) + 100; 2204e64350fSAmelie Delaunay /* 2214e64350fSAmelie Delaunay * Number of days since Sunday 2224e64350fSAmelie Delaunay * - on kernel side, 0=Sunday...6=Saturday 2234e64350fSAmelie Delaunay * - on rtc side, 0=invalid,1=Monday...7=Sunday 2244e64350fSAmelie Delaunay */ 2254e64350fSAmelie Delaunay tm->tm_wday %= 7; 2264e64350fSAmelie Delaunay } 2274e64350fSAmelie Delaunay 2284e64350fSAmelie Delaunay static int stm32_rtc_read_time(struct device *dev, struct rtc_time *tm) 2294e64350fSAmelie Delaunay { 2304e64350fSAmelie Delaunay struct stm32_rtc *rtc = dev_get_drvdata(dev); 2314e64350fSAmelie Delaunay unsigned int tr, dr; 2324e64350fSAmelie Delaunay 2334e64350fSAmelie Delaunay /* Time and Date in BCD format */ 2344e64350fSAmelie Delaunay tr = readl_relaxed(rtc->base + STM32_RTC_TR); 2354e64350fSAmelie Delaunay dr = readl_relaxed(rtc->base + STM32_RTC_DR); 2364e64350fSAmelie Delaunay 2374e64350fSAmelie Delaunay tm->tm_sec = (tr & STM32_RTC_TR_SEC) >> STM32_RTC_TR_SEC_SHIFT; 2384e64350fSAmelie Delaunay tm->tm_min = (tr & STM32_RTC_TR_MIN) >> STM32_RTC_TR_MIN_SHIFT; 2394e64350fSAmelie Delaunay tm->tm_hour = (tr & STM32_RTC_TR_HOUR) >> STM32_RTC_TR_HOUR_SHIFT; 2404e64350fSAmelie Delaunay 2414e64350fSAmelie Delaunay tm->tm_mday = (dr & STM32_RTC_DR_DATE) >> STM32_RTC_DR_DATE_SHIFT; 2424e64350fSAmelie Delaunay tm->tm_mon = (dr & STM32_RTC_DR_MONTH) >> STM32_RTC_DR_MONTH_SHIFT; 2434e64350fSAmelie Delaunay tm->tm_year = (dr & STM32_RTC_DR_YEAR) >> STM32_RTC_DR_YEAR_SHIFT; 2444e64350fSAmelie Delaunay tm->tm_wday = (dr & STM32_RTC_DR_WDAY) >> STM32_RTC_DR_WDAY_SHIFT; 2454e64350fSAmelie Delaunay 2464e64350fSAmelie Delaunay /* We don't report tm_yday and tm_isdst */ 2474e64350fSAmelie Delaunay 2484e64350fSAmelie Delaunay bcd2tm(tm); 2494e64350fSAmelie Delaunay 2504e64350fSAmelie Delaunay return 0; 2514e64350fSAmelie Delaunay } 2524e64350fSAmelie Delaunay 2534e64350fSAmelie Delaunay static int stm32_rtc_set_time(struct device *dev, struct rtc_time *tm) 2544e64350fSAmelie Delaunay { 2554e64350fSAmelie Delaunay struct stm32_rtc *rtc = dev_get_drvdata(dev); 2564e64350fSAmelie Delaunay unsigned int tr, dr; 2574e64350fSAmelie Delaunay int ret = 0; 2584e64350fSAmelie Delaunay 2594e64350fSAmelie Delaunay tm2bcd(tm); 2604e64350fSAmelie Delaunay 2614e64350fSAmelie Delaunay /* Time in BCD format */ 2624e64350fSAmelie Delaunay tr = ((tm->tm_sec << STM32_RTC_TR_SEC_SHIFT) & STM32_RTC_TR_SEC) | 2634e64350fSAmelie Delaunay ((tm->tm_min << STM32_RTC_TR_MIN_SHIFT) & STM32_RTC_TR_MIN) | 2644e64350fSAmelie Delaunay ((tm->tm_hour << STM32_RTC_TR_HOUR_SHIFT) & STM32_RTC_TR_HOUR); 2654e64350fSAmelie Delaunay 2664e64350fSAmelie Delaunay /* Date in BCD format */ 2674e64350fSAmelie Delaunay dr = ((tm->tm_mday << STM32_RTC_DR_DATE_SHIFT) & STM32_RTC_DR_DATE) | 2684e64350fSAmelie Delaunay ((tm->tm_mon << STM32_RTC_DR_MONTH_SHIFT) & STM32_RTC_DR_MONTH) | 2694e64350fSAmelie Delaunay ((tm->tm_year << STM32_RTC_DR_YEAR_SHIFT) & STM32_RTC_DR_YEAR) | 2704e64350fSAmelie Delaunay ((tm->tm_wday << STM32_RTC_DR_WDAY_SHIFT) & STM32_RTC_DR_WDAY); 2714e64350fSAmelie Delaunay 2724e64350fSAmelie Delaunay stm32_rtc_wpr_unlock(rtc); 2734e64350fSAmelie Delaunay 2744e64350fSAmelie Delaunay ret = stm32_rtc_enter_init_mode(rtc); 2754e64350fSAmelie Delaunay if (ret) { 2764e64350fSAmelie Delaunay dev_err(dev, "Can't enter in init mode. Set time aborted.\n"); 2774e64350fSAmelie Delaunay goto end; 2784e64350fSAmelie Delaunay } 2794e64350fSAmelie Delaunay 2804e64350fSAmelie Delaunay writel_relaxed(tr, rtc->base + STM32_RTC_TR); 2814e64350fSAmelie Delaunay writel_relaxed(dr, rtc->base + STM32_RTC_DR); 2824e64350fSAmelie Delaunay 2834e64350fSAmelie Delaunay stm32_rtc_exit_init_mode(rtc); 2844e64350fSAmelie Delaunay 2854e64350fSAmelie Delaunay ret = stm32_rtc_wait_sync(rtc); 2864e64350fSAmelie Delaunay end: 2874e64350fSAmelie Delaunay stm32_rtc_wpr_lock(rtc); 2884e64350fSAmelie Delaunay 2894e64350fSAmelie Delaunay return ret; 2904e64350fSAmelie Delaunay } 2914e64350fSAmelie Delaunay 2924e64350fSAmelie Delaunay static int stm32_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) 2934e64350fSAmelie Delaunay { 2944e64350fSAmelie Delaunay struct stm32_rtc *rtc = dev_get_drvdata(dev); 2954e64350fSAmelie Delaunay struct rtc_time *tm = &alrm->time; 2964e64350fSAmelie Delaunay unsigned int alrmar, cr, isr; 2974e64350fSAmelie Delaunay 2984e64350fSAmelie Delaunay alrmar = readl_relaxed(rtc->base + STM32_RTC_ALRMAR); 2994e64350fSAmelie Delaunay cr = readl_relaxed(rtc->base + STM32_RTC_CR); 3004e64350fSAmelie Delaunay isr = readl_relaxed(rtc->base + STM32_RTC_ISR); 3014e64350fSAmelie Delaunay 3024e64350fSAmelie Delaunay if (alrmar & STM32_RTC_ALRMXR_DATE_MASK) { 3034e64350fSAmelie Delaunay /* 3044e64350fSAmelie Delaunay * Date/day doesn't matter in Alarm comparison so alarm 3054e64350fSAmelie Delaunay * triggers every day 3064e64350fSAmelie Delaunay */ 3074e64350fSAmelie Delaunay tm->tm_mday = -1; 3084e64350fSAmelie Delaunay tm->tm_wday = -1; 3094e64350fSAmelie Delaunay } else { 3104e64350fSAmelie Delaunay if (alrmar & STM32_RTC_ALRMXR_WDSEL) { 3114e64350fSAmelie Delaunay /* Alarm is set to a day of week */ 3124e64350fSAmelie Delaunay tm->tm_mday = -1; 3134e64350fSAmelie Delaunay tm->tm_wday = (alrmar & STM32_RTC_ALRMXR_WDAY) >> 3144e64350fSAmelie Delaunay STM32_RTC_ALRMXR_WDAY_SHIFT; 3154e64350fSAmelie Delaunay tm->tm_wday %= 7; 3164e64350fSAmelie Delaunay } else { 3174e64350fSAmelie Delaunay /* Alarm is set to a day of month */ 3184e64350fSAmelie Delaunay tm->tm_wday = -1; 3194e64350fSAmelie Delaunay tm->tm_mday = (alrmar & STM32_RTC_ALRMXR_DATE) >> 3204e64350fSAmelie Delaunay STM32_RTC_ALRMXR_DATE_SHIFT; 3214e64350fSAmelie Delaunay } 3224e64350fSAmelie Delaunay } 3234e64350fSAmelie Delaunay 3244e64350fSAmelie Delaunay if (alrmar & STM32_RTC_ALRMXR_HOUR_MASK) { 3254e64350fSAmelie Delaunay /* Hours don't matter in Alarm comparison */ 3264e64350fSAmelie Delaunay tm->tm_hour = -1; 3274e64350fSAmelie Delaunay } else { 3284e64350fSAmelie Delaunay tm->tm_hour = (alrmar & STM32_RTC_ALRMXR_HOUR) >> 3294e64350fSAmelie Delaunay STM32_RTC_ALRMXR_HOUR_SHIFT; 3304e64350fSAmelie Delaunay if (alrmar & STM32_RTC_ALRMXR_PM) 3314e64350fSAmelie Delaunay tm->tm_hour += 12; 3324e64350fSAmelie Delaunay } 3334e64350fSAmelie Delaunay 3344e64350fSAmelie Delaunay if (alrmar & STM32_RTC_ALRMXR_MIN_MASK) { 3354e64350fSAmelie Delaunay /* Minutes don't matter in Alarm comparison */ 3364e64350fSAmelie Delaunay tm->tm_min = -1; 3374e64350fSAmelie Delaunay } else { 3384e64350fSAmelie Delaunay tm->tm_min = (alrmar & STM32_RTC_ALRMXR_MIN) >> 3394e64350fSAmelie Delaunay STM32_RTC_ALRMXR_MIN_SHIFT; 3404e64350fSAmelie Delaunay } 3414e64350fSAmelie Delaunay 3424e64350fSAmelie Delaunay if (alrmar & STM32_RTC_ALRMXR_SEC_MASK) { 3434e64350fSAmelie Delaunay /* Seconds don't matter in Alarm comparison */ 3444e64350fSAmelie Delaunay tm->tm_sec = -1; 3454e64350fSAmelie Delaunay } else { 3464e64350fSAmelie Delaunay tm->tm_sec = (alrmar & STM32_RTC_ALRMXR_SEC) >> 3474e64350fSAmelie Delaunay STM32_RTC_ALRMXR_SEC_SHIFT; 3484e64350fSAmelie Delaunay } 3494e64350fSAmelie Delaunay 3504e64350fSAmelie Delaunay bcd2tm(tm); 3514e64350fSAmelie Delaunay 3524e64350fSAmelie Delaunay alrm->enabled = (cr & STM32_RTC_CR_ALRAE) ? 1 : 0; 3534e64350fSAmelie Delaunay alrm->pending = (isr & STM32_RTC_ISR_ALRAF) ? 1 : 0; 3544e64350fSAmelie Delaunay 3554e64350fSAmelie Delaunay return 0; 3564e64350fSAmelie Delaunay } 3574e64350fSAmelie Delaunay 3584e64350fSAmelie Delaunay static int stm32_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) 3594e64350fSAmelie Delaunay { 3604e64350fSAmelie Delaunay struct stm32_rtc *rtc = dev_get_drvdata(dev); 3614e64350fSAmelie Delaunay unsigned int isr, cr; 3624e64350fSAmelie Delaunay 3634e64350fSAmelie Delaunay cr = readl_relaxed(rtc->base + STM32_RTC_CR); 3644e64350fSAmelie Delaunay 3654e64350fSAmelie Delaunay stm32_rtc_wpr_unlock(rtc); 3664e64350fSAmelie Delaunay 3674e64350fSAmelie Delaunay /* We expose Alarm A to the kernel */ 3684e64350fSAmelie Delaunay if (enabled) 3694e64350fSAmelie Delaunay cr |= (STM32_RTC_CR_ALRAIE | STM32_RTC_CR_ALRAE); 3704e64350fSAmelie Delaunay else 3714e64350fSAmelie Delaunay cr &= ~(STM32_RTC_CR_ALRAIE | STM32_RTC_CR_ALRAE); 3724e64350fSAmelie Delaunay writel_relaxed(cr, rtc->base + STM32_RTC_CR); 3734e64350fSAmelie Delaunay 3744e64350fSAmelie Delaunay /* Clear event flag, otherwise new events won't be received */ 3754e64350fSAmelie Delaunay isr = readl_relaxed(rtc->base + STM32_RTC_ISR); 3764e64350fSAmelie Delaunay isr &= ~STM32_RTC_ISR_ALRAF; 3774e64350fSAmelie Delaunay writel_relaxed(isr, rtc->base + STM32_RTC_ISR); 3784e64350fSAmelie Delaunay 3794e64350fSAmelie Delaunay stm32_rtc_wpr_lock(rtc); 3804e64350fSAmelie Delaunay 3814e64350fSAmelie Delaunay return 0; 3824e64350fSAmelie Delaunay } 3834e64350fSAmelie Delaunay 3844e64350fSAmelie Delaunay static int stm32_rtc_valid_alrm(struct stm32_rtc *rtc, struct rtc_time *tm) 3854e64350fSAmelie Delaunay { 3864e64350fSAmelie Delaunay unsigned int cur_day, cur_mon, cur_year, cur_hour, cur_min, cur_sec; 3874e64350fSAmelie Delaunay unsigned int dr = readl_relaxed(rtc->base + STM32_RTC_DR); 3884e64350fSAmelie Delaunay unsigned int tr = readl_relaxed(rtc->base + STM32_RTC_TR); 3894e64350fSAmelie Delaunay 3904e64350fSAmelie Delaunay cur_day = (dr & STM32_RTC_DR_DATE) >> STM32_RTC_DR_DATE_SHIFT; 3914e64350fSAmelie Delaunay cur_mon = (dr & STM32_RTC_DR_MONTH) >> STM32_RTC_DR_MONTH_SHIFT; 3924e64350fSAmelie Delaunay cur_year = (dr & STM32_RTC_DR_YEAR) >> STM32_RTC_DR_YEAR_SHIFT; 3934e64350fSAmelie Delaunay cur_sec = (tr & STM32_RTC_TR_SEC) >> STM32_RTC_TR_SEC_SHIFT; 3944e64350fSAmelie Delaunay cur_min = (tr & STM32_RTC_TR_MIN) >> STM32_RTC_TR_MIN_SHIFT; 3954e64350fSAmelie Delaunay cur_hour = (tr & STM32_RTC_TR_HOUR) >> STM32_RTC_TR_HOUR_SHIFT; 3964e64350fSAmelie Delaunay 3974e64350fSAmelie Delaunay /* 3984e64350fSAmelie Delaunay * Assuming current date is M-D-Y H:M:S. 3994e64350fSAmelie Delaunay * RTC alarm can't be set on a specific month and year. 4004e64350fSAmelie Delaunay * So the valid alarm range is: 4014e64350fSAmelie Delaunay * M-D-Y H:M:S < alarm <= (M+1)-D-Y H:M:S 4024e64350fSAmelie Delaunay * with a specific case for December... 4034e64350fSAmelie Delaunay */ 4044e64350fSAmelie Delaunay if ((((tm->tm_year > cur_year) && 4054e64350fSAmelie Delaunay (tm->tm_mon == 0x1) && (cur_mon == 0x12)) || 4064e64350fSAmelie Delaunay ((tm->tm_year == cur_year) && 4074e64350fSAmelie Delaunay (tm->tm_mon <= cur_mon + 1))) && 4084e64350fSAmelie Delaunay ((tm->tm_mday > cur_day) || 4094e64350fSAmelie Delaunay ((tm->tm_mday == cur_day) && 4104e64350fSAmelie Delaunay ((tm->tm_hour > cur_hour) || 4114e64350fSAmelie Delaunay ((tm->tm_hour == cur_hour) && (tm->tm_min > cur_min)) || 4124e64350fSAmelie Delaunay ((tm->tm_hour == cur_hour) && (tm->tm_min == cur_min) && 4134e64350fSAmelie Delaunay (tm->tm_sec >= cur_sec)))))) 4144e64350fSAmelie Delaunay return 0; 4154e64350fSAmelie Delaunay 4164e64350fSAmelie Delaunay return -EINVAL; 4174e64350fSAmelie Delaunay } 4184e64350fSAmelie Delaunay 4194e64350fSAmelie Delaunay static int stm32_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) 4204e64350fSAmelie Delaunay { 4214e64350fSAmelie Delaunay struct stm32_rtc *rtc = dev_get_drvdata(dev); 4224e64350fSAmelie Delaunay struct rtc_time *tm = &alrm->time; 4234e64350fSAmelie Delaunay unsigned int cr, isr, alrmar; 4244e64350fSAmelie Delaunay int ret = 0; 4254e64350fSAmelie Delaunay 4264e64350fSAmelie Delaunay tm2bcd(tm); 4274e64350fSAmelie Delaunay 4284e64350fSAmelie Delaunay /* 4294e64350fSAmelie Delaunay * RTC alarm can't be set on a specific date, unless this date is 4304e64350fSAmelie Delaunay * up to the same day of month next month. 4314e64350fSAmelie Delaunay */ 4324e64350fSAmelie Delaunay if (stm32_rtc_valid_alrm(rtc, tm) < 0) { 4334e64350fSAmelie Delaunay dev_err(dev, "Alarm can be set only on upcoming month.\n"); 4344e64350fSAmelie Delaunay return -EINVAL; 4354e64350fSAmelie Delaunay } 4364e64350fSAmelie Delaunay 4374e64350fSAmelie Delaunay alrmar = 0; 4384e64350fSAmelie Delaunay /* tm_year and tm_mon are not used because not supported by RTC */ 4394e64350fSAmelie Delaunay alrmar |= (tm->tm_mday << STM32_RTC_ALRMXR_DATE_SHIFT) & 4404e64350fSAmelie Delaunay STM32_RTC_ALRMXR_DATE; 4414e64350fSAmelie Delaunay /* 24-hour format */ 4424e64350fSAmelie Delaunay alrmar &= ~STM32_RTC_ALRMXR_PM; 4434e64350fSAmelie Delaunay alrmar |= (tm->tm_hour << STM32_RTC_ALRMXR_HOUR_SHIFT) & 4444e64350fSAmelie Delaunay STM32_RTC_ALRMXR_HOUR; 4454e64350fSAmelie Delaunay alrmar |= (tm->tm_min << STM32_RTC_ALRMXR_MIN_SHIFT) & 4464e64350fSAmelie Delaunay STM32_RTC_ALRMXR_MIN; 4474e64350fSAmelie Delaunay alrmar |= (tm->tm_sec << STM32_RTC_ALRMXR_SEC_SHIFT) & 4484e64350fSAmelie Delaunay STM32_RTC_ALRMXR_SEC; 4494e64350fSAmelie Delaunay 4504e64350fSAmelie Delaunay stm32_rtc_wpr_unlock(rtc); 4514e64350fSAmelie Delaunay 4524e64350fSAmelie Delaunay /* Disable Alarm */ 4534e64350fSAmelie Delaunay cr = readl_relaxed(rtc->base + STM32_RTC_CR); 4544e64350fSAmelie Delaunay cr &= ~STM32_RTC_CR_ALRAE; 4554e64350fSAmelie Delaunay writel_relaxed(cr, rtc->base + STM32_RTC_CR); 4564e64350fSAmelie Delaunay 4574e64350fSAmelie Delaunay /* 4584e64350fSAmelie Delaunay * Poll Alarm write flag to be sure that Alarm update is allowed: it 4594e64350fSAmelie Delaunay * takes around 2 ck_rtc clock cycles 4604e64350fSAmelie Delaunay */ 4614e64350fSAmelie Delaunay ret = readl_relaxed_poll_timeout_atomic(rtc->base + STM32_RTC_ISR, 4624e64350fSAmelie Delaunay isr, 4634e64350fSAmelie Delaunay (isr & STM32_RTC_ISR_ALRAWF), 4644e64350fSAmelie Delaunay 10, 100000); 4654e64350fSAmelie Delaunay 4664e64350fSAmelie Delaunay if (ret) { 4674e64350fSAmelie Delaunay dev_err(dev, "Alarm update not allowed\n"); 4684e64350fSAmelie Delaunay goto end; 4694e64350fSAmelie Delaunay } 4704e64350fSAmelie Delaunay 4714e64350fSAmelie Delaunay /* Write to Alarm register */ 4724e64350fSAmelie Delaunay writel_relaxed(alrmar, rtc->base + STM32_RTC_ALRMAR); 4734e64350fSAmelie Delaunay 4744e64350fSAmelie Delaunay if (alrm->enabled) 4754e64350fSAmelie Delaunay stm32_rtc_alarm_irq_enable(dev, 1); 4764e64350fSAmelie Delaunay else 4774e64350fSAmelie Delaunay stm32_rtc_alarm_irq_enable(dev, 0); 4784e64350fSAmelie Delaunay 4794e64350fSAmelie Delaunay end: 4804e64350fSAmelie Delaunay stm32_rtc_wpr_lock(rtc); 4814e64350fSAmelie Delaunay 4824e64350fSAmelie Delaunay return ret; 4834e64350fSAmelie Delaunay } 4844e64350fSAmelie Delaunay 4854e64350fSAmelie Delaunay static const struct rtc_class_ops stm32_rtc_ops = { 4864e64350fSAmelie Delaunay .read_time = stm32_rtc_read_time, 4874e64350fSAmelie Delaunay .set_time = stm32_rtc_set_time, 4884e64350fSAmelie Delaunay .read_alarm = stm32_rtc_read_alarm, 4894e64350fSAmelie Delaunay .set_alarm = stm32_rtc_set_alarm, 4904e64350fSAmelie Delaunay .alarm_irq_enable = stm32_rtc_alarm_irq_enable, 4914e64350fSAmelie Delaunay }; 4924e64350fSAmelie Delaunay 4934e64350fSAmelie Delaunay static const struct of_device_id stm32_rtc_of_match[] = { 4944e64350fSAmelie Delaunay { .compatible = "st,stm32-rtc" }, 4954e64350fSAmelie Delaunay {} 4964e64350fSAmelie Delaunay }; 4974e64350fSAmelie Delaunay MODULE_DEVICE_TABLE(of, stm32_rtc_of_match); 4984e64350fSAmelie Delaunay 4994e64350fSAmelie Delaunay static int stm32_rtc_init(struct platform_device *pdev, 5004e64350fSAmelie Delaunay struct stm32_rtc *rtc) 5014e64350fSAmelie Delaunay { 5024e64350fSAmelie Delaunay unsigned int prer, pred_a, pred_s, pred_a_max, pred_s_max, cr; 5034e64350fSAmelie Delaunay unsigned int rate; 5044e64350fSAmelie Delaunay int ret = 0; 5054e64350fSAmelie Delaunay 5064e64350fSAmelie Delaunay rate = clk_get_rate(rtc->ck_rtc); 5074e64350fSAmelie Delaunay 5084e64350fSAmelie Delaunay /* Find prediv_a and prediv_s to obtain the 1Hz calendar clock */ 5094e64350fSAmelie Delaunay pred_a_max = STM32_RTC_PRER_PRED_A >> STM32_RTC_PRER_PRED_A_SHIFT; 5104e64350fSAmelie Delaunay pred_s_max = STM32_RTC_PRER_PRED_S >> STM32_RTC_PRER_PRED_S_SHIFT; 5114e64350fSAmelie Delaunay 5124e64350fSAmelie Delaunay for (pred_a = pred_a_max; pred_a >= 0; pred_a--) { 5134e64350fSAmelie Delaunay pred_s = (rate / (pred_a + 1)) - 1; 5144e64350fSAmelie Delaunay 5154e64350fSAmelie Delaunay if (((pred_s + 1) * (pred_a + 1)) == rate) 5164e64350fSAmelie Delaunay break; 5174e64350fSAmelie Delaunay } 5184e64350fSAmelie Delaunay 5194e64350fSAmelie Delaunay /* 5204e64350fSAmelie Delaunay * Can't find a 1Hz, so give priority to RTC power consumption 5214e64350fSAmelie Delaunay * by choosing the higher possible value for prediv_a 5224e64350fSAmelie Delaunay */ 5234e64350fSAmelie Delaunay if ((pred_s > pred_s_max) || (pred_a > pred_a_max)) { 5244e64350fSAmelie Delaunay pred_a = pred_a_max; 5254e64350fSAmelie Delaunay pred_s = (rate / (pred_a + 1)) - 1; 5264e64350fSAmelie Delaunay 5274e64350fSAmelie Delaunay dev_warn(&pdev->dev, "ck_rtc is %s\n", 5284e64350fSAmelie Delaunay (rate - ((pred_a + 1) * (pred_s + 1)) < 0) ? 5294e64350fSAmelie Delaunay "fast" : "slow"); 5304e64350fSAmelie Delaunay } 5314e64350fSAmelie Delaunay 5324e64350fSAmelie Delaunay stm32_rtc_wpr_unlock(rtc); 5334e64350fSAmelie Delaunay 5344e64350fSAmelie Delaunay ret = stm32_rtc_enter_init_mode(rtc); 5354e64350fSAmelie Delaunay if (ret) { 5364e64350fSAmelie Delaunay dev_err(&pdev->dev, 5374e64350fSAmelie Delaunay "Can't enter in init mode. Prescaler config failed.\n"); 5384e64350fSAmelie Delaunay goto end; 5394e64350fSAmelie Delaunay } 5404e64350fSAmelie Delaunay 5414e64350fSAmelie Delaunay prer = (pred_s << STM32_RTC_PRER_PRED_S_SHIFT) & STM32_RTC_PRER_PRED_S; 5424e64350fSAmelie Delaunay writel_relaxed(prer, rtc->base + STM32_RTC_PRER); 5434e64350fSAmelie Delaunay prer |= (pred_a << STM32_RTC_PRER_PRED_A_SHIFT) & STM32_RTC_PRER_PRED_A; 5444e64350fSAmelie Delaunay writel_relaxed(prer, rtc->base + STM32_RTC_PRER); 5454e64350fSAmelie Delaunay 5464e64350fSAmelie Delaunay /* Force 24h time format */ 5474e64350fSAmelie Delaunay cr = readl_relaxed(rtc->base + STM32_RTC_CR); 5484e64350fSAmelie Delaunay cr &= ~STM32_RTC_CR_FMT; 5494e64350fSAmelie Delaunay writel_relaxed(cr, rtc->base + STM32_RTC_CR); 5504e64350fSAmelie Delaunay 5514e64350fSAmelie Delaunay stm32_rtc_exit_init_mode(rtc); 5524e64350fSAmelie Delaunay 5534e64350fSAmelie Delaunay ret = stm32_rtc_wait_sync(rtc); 5544e64350fSAmelie Delaunay end: 5554e64350fSAmelie Delaunay stm32_rtc_wpr_lock(rtc); 5564e64350fSAmelie Delaunay 5574e64350fSAmelie Delaunay return ret; 5584e64350fSAmelie Delaunay } 5594e64350fSAmelie Delaunay 5604e64350fSAmelie Delaunay static int stm32_rtc_probe(struct platform_device *pdev) 5614e64350fSAmelie Delaunay { 5624e64350fSAmelie Delaunay struct stm32_rtc *rtc; 5634e64350fSAmelie Delaunay struct resource *res; 5644e64350fSAmelie Delaunay int ret; 5654e64350fSAmelie Delaunay 5664e64350fSAmelie Delaunay rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL); 5674e64350fSAmelie Delaunay if (!rtc) 5684e64350fSAmelie Delaunay return -ENOMEM; 5694e64350fSAmelie Delaunay 5704e64350fSAmelie Delaunay res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 5714e64350fSAmelie Delaunay rtc->base = devm_ioremap_resource(&pdev->dev, res); 5724e64350fSAmelie Delaunay if (IS_ERR(rtc->base)) 5734e64350fSAmelie Delaunay return PTR_ERR(rtc->base); 5744e64350fSAmelie Delaunay 5754e64350fSAmelie Delaunay rtc->dbp = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, 5764e64350fSAmelie Delaunay "st,syscfg"); 5774e64350fSAmelie Delaunay if (IS_ERR(rtc->dbp)) { 5784e64350fSAmelie Delaunay dev_err(&pdev->dev, "no st,syscfg\n"); 5794e64350fSAmelie Delaunay return PTR_ERR(rtc->dbp); 5804e64350fSAmelie Delaunay } 5814e64350fSAmelie Delaunay 5824e64350fSAmelie Delaunay rtc->ck_rtc = devm_clk_get(&pdev->dev, NULL); 5834e64350fSAmelie Delaunay if (IS_ERR(rtc->ck_rtc)) { 5844e64350fSAmelie Delaunay dev_err(&pdev->dev, "no ck_rtc clock"); 5854e64350fSAmelie Delaunay return PTR_ERR(rtc->ck_rtc); 5864e64350fSAmelie Delaunay } 5874e64350fSAmelie Delaunay 5884e64350fSAmelie Delaunay ret = clk_prepare_enable(rtc->ck_rtc); 5894e64350fSAmelie Delaunay if (ret) 5904e64350fSAmelie Delaunay return ret; 5914e64350fSAmelie Delaunay 5924e64350fSAmelie Delaunay regmap_update_bits(rtc->dbp, PWR_CR, PWR_CR_DBP, PWR_CR_DBP); 5934e64350fSAmelie Delaunay 5944e64350fSAmelie Delaunay /* 5954e64350fSAmelie Delaunay * After a system reset, RTC_ISR.INITS flag can be read to check if 5964e64350fSAmelie Delaunay * the calendar has been initalized or not. INITS flag is reset by a 5974e64350fSAmelie Delaunay * power-on reset (no vbat, no power-supply). It is not reset if 5984e64350fSAmelie Delaunay * ck_rtc parent clock has changed (so RTC prescalers need to be 5994e64350fSAmelie Delaunay * changed). That's why we cannot rely on this flag to know if RTC 6004e64350fSAmelie Delaunay * init has to be done. 6014e64350fSAmelie Delaunay */ 6024e64350fSAmelie Delaunay ret = stm32_rtc_init(pdev, rtc); 6034e64350fSAmelie Delaunay if (ret) 6044e64350fSAmelie Delaunay goto err; 6054e64350fSAmelie Delaunay 6064e64350fSAmelie Delaunay rtc->irq_alarm = platform_get_irq(pdev, 0); 6074e64350fSAmelie Delaunay if (rtc->irq_alarm <= 0) { 6084e64350fSAmelie Delaunay dev_err(&pdev->dev, "no alarm irq\n"); 6094e64350fSAmelie Delaunay ret = rtc->irq_alarm; 6104e64350fSAmelie Delaunay goto err; 6114e64350fSAmelie Delaunay } 6124e64350fSAmelie Delaunay 6134e64350fSAmelie Delaunay platform_set_drvdata(pdev, rtc); 6144e64350fSAmelie Delaunay 6154e64350fSAmelie Delaunay ret = device_init_wakeup(&pdev->dev, true); 6164e64350fSAmelie Delaunay if (ret) 6174e64350fSAmelie Delaunay dev_warn(&pdev->dev, 6184e64350fSAmelie Delaunay "alarm won't be able to wake up the system"); 6194e64350fSAmelie Delaunay 6204e64350fSAmelie Delaunay rtc->rtc_dev = devm_rtc_device_register(&pdev->dev, pdev->name, 6214e64350fSAmelie Delaunay &stm32_rtc_ops, THIS_MODULE); 6224e64350fSAmelie Delaunay if (IS_ERR(rtc->rtc_dev)) { 6234e64350fSAmelie Delaunay ret = PTR_ERR(rtc->rtc_dev); 6244e64350fSAmelie Delaunay dev_err(&pdev->dev, "rtc device registration failed, err=%d\n", 6254e64350fSAmelie Delaunay ret); 6264e64350fSAmelie Delaunay goto err; 6274e64350fSAmelie Delaunay } 6284e64350fSAmelie Delaunay 6294e64350fSAmelie Delaunay /* Handle RTC alarm interrupts */ 6304e64350fSAmelie Delaunay ret = devm_request_threaded_irq(&pdev->dev, rtc->irq_alarm, NULL, 6314e64350fSAmelie Delaunay stm32_rtc_alarm_irq, 6324e64350fSAmelie Delaunay IRQF_TRIGGER_RISING | IRQF_ONESHOT, 6334e64350fSAmelie Delaunay pdev->name, rtc); 6344e64350fSAmelie Delaunay if (ret) { 6354e64350fSAmelie Delaunay dev_err(&pdev->dev, "IRQ%d (alarm interrupt) already claimed\n", 6364e64350fSAmelie Delaunay rtc->irq_alarm); 6374e64350fSAmelie Delaunay goto err; 6384e64350fSAmelie Delaunay } 6394e64350fSAmelie Delaunay 6404e64350fSAmelie Delaunay /* 6414e64350fSAmelie Delaunay * If INITS flag is reset (calendar year field set to 0x00), calendar 6424e64350fSAmelie Delaunay * must be initialized 6434e64350fSAmelie Delaunay */ 6444e64350fSAmelie Delaunay if (!(readl_relaxed(rtc->base + STM32_RTC_ISR) & STM32_RTC_ISR_INITS)) 6454e64350fSAmelie Delaunay dev_warn(&pdev->dev, "Date/Time must be initialized\n"); 6464e64350fSAmelie Delaunay 6474e64350fSAmelie Delaunay return 0; 6484e64350fSAmelie Delaunay err: 6494e64350fSAmelie Delaunay clk_disable_unprepare(rtc->ck_rtc); 6504e64350fSAmelie Delaunay 651a560c527SAmelie Delaunay regmap_update_bits(rtc->dbp, PWR_CR, PWR_CR_DBP, 0); 6524e64350fSAmelie Delaunay 6534e64350fSAmelie Delaunay device_init_wakeup(&pdev->dev, false); 6544e64350fSAmelie Delaunay 6554e64350fSAmelie Delaunay return ret; 6564e64350fSAmelie Delaunay } 6574e64350fSAmelie Delaunay 6580404abb2SArnd Bergmann static int stm32_rtc_remove(struct platform_device *pdev) 6594e64350fSAmelie Delaunay { 6604e64350fSAmelie Delaunay struct stm32_rtc *rtc = platform_get_drvdata(pdev); 6614e64350fSAmelie Delaunay unsigned int cr; 6624e64350fSAmelie Delaunay 6634e64350fSAmelie Delaunay /* Disable interrupts */ 6644e64350fSAmelie Delaunay stm32_rtc_wpr_unlock(rtc); 6654e64350fSAmelie Delaunay cr = readl_relaxed(rtc->base + STM32_RTC_CR); 6664e64350fSAmelie Delaunay cr &= ~STM32_RTC_CR_ALRAIE; 6674e64350fSAmelie Delaunay writel_relaxed(cr, rtc->base + STM32_RTC_CR); 6684e64350fSAmelie Delaunay stm32_rtc_wpr_lock(rtc); 6694e64350fSAmelie Delaunay 6704e64350fSAmelie Delaunay clk_disable_unprepare(rtc->ck_rtc); 6714e64350fSAmelie Delaunay 6724e64350fSAmelie Delaunay /* Enable backup domain write protection */ 673a560c527SAmelie Delaunay regmap_update_bits(rtc->dbp, PWR_CR, PWR_CR_DBP, 0); 6744e64350fSAmelie Delaunay 6754e64350fSAmelie Delaunay device_init_wakeup(&pdev->dev, false); 6764e64350fSAmelie Delaunay 6774e64350fSAmelie Delaunay return 0; 6784e64350fSAmelie Delaunay } 6794e64350fSAmelie Delaunay 6804e64350fSAmelie Delaunay #ifdef CONFIG_PM_SLEEP 6814e64350fSAmelie Delaunay static int stm32_rtc_suspend(struct device *dev) 6824e64350fSAmelie Delaunay { 6834e64350fSAmelie Delaunay struct stm32_rtc *rtc = dev_get_drvdata(dev); 6844e64350fSAmelie Delaunay 6854e64350fSAmelie Delaunay if (device_may_wakeup(dev)) 6864e64350fSAmelie Delaunay return enable_irq_wake(rtc->irq_alarm); 6874e64350fSAmelie Delaunay 6884e64350fSAmelie Delaunay return 0; 6894e64350fSAmelie Delaunay } 6904e64350fSAmelie Delaunay 6914e64350fSAmelie Delaunay static int stm32_rtc_resume(struct device *dev) 6924e64350fSAmelie Delaunay { 6934e64350fSAmelie Delaunay struct stm32_rtc *rtc = dev_get_drvdata(dev); 6944e64350fSAmelie Delaunay int ret = 0; 6954e64350fSAmelie Delaunay 6964e64350fSAmelie Delaunay ret = stm32_rtc_wait_sync(rtc); 6974e64350fSAmelie Delaunay if (ret < 0) 6984e64350fSAmelie Delaunay return ret; 6994e64350fSAmelie Delaunay 7004e64350fSAmelie Delaunay if (device_may_wakeup(dev)) 7014e64350fSAmelie Delaunay return disable_irq_wake(rtc->irq_alarm); 7024e64350fSAmelie Delaunay 7034e64350fSAmelie Delaunay return ret; 7044e64350fSAmelie Delaunay } 7054e64350fSAmelie Delaunay #endif 7064e64350fSAmelie Delaunay 7074e64350fSAmelie Delaunay static SIMPLE_DEV_PM_OPS(stm32_rtc_pm_ops, 7084e64350fSAmelie Delaunay stm32_rtc_suspend, stm32_rtc_resume); 7094e64350fSAmelie Delaunay 7104e64350fSAmelie Delaunay static struct platform_driver stm32_rtc_driver = { 7114e64350fSAmelie Delaunay .probe = stm32_rtc_probe, 7124e64350fSAmelie Delaunay .remove = stm32_rtc_remove, 7134e64350fSAmelie Delaunay .driver = { 7144e64350fSAmelie Delaunay .name = DRIVER_NAME, 7154e64350fSAmelie Delaunay .pm = &stm32_rtc_pm_ops, 7164e64350fSAmelie Delaunay .of_match_table = stm32_rtc_of_match, 7174e64350fSAmelie Delaunay }, 7184e64350fSAmelie Delaunay }; 7194e64350fSAmelie Delaunay 7204e64350fSAmelie Delaunay module_platform_driver(stm32_rtc_driver); 7214e64350fSAmelie Delaunay 7224e64350fSAmelie Delaunay MODULE_ALIAS("platform:" DRIVER_NAME); 7234e64350fSAmelie Delaunay MODULE_AUTHOR("Amelie Delaunay <amelie.delaunay@st.com>"); 7244e64350fSAmelie Delaunay MODULE_DESCRIPTION("STMicroelectronics STM32 Real Time Clock driver"); 7254e64350fSAmelie Delaunay MODULE_LICENSE("GPL v2"); 726