124805645SAmelie Delaunay // SPDX-License-Identifier: GPL-2.0 24e64350fSAmelie Delaunay /* 324805645SAmelie Delaunay * Copyright (C) STMicroelectronics 2017 424805645SAmelie Delaunay * Author: Amelie Delaunay <amelie.delaunay@st.com> 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> 14b72252b6SAmelie Delaunay #include <linux/pm_wakeirq.h> 154e64350fSAmelie Delaunay #include <linux/regmap.h> 164e64350fSAmelie Delaunay #include <linux/rtc.h> 174e64350fSAmelie Delaunay 184e64350fSAmelie Delaunay #define DRIVER_NAME "stm32_rtc" 194e64350fSAmelie Delaunay 204e64350fSAmelie Delaunay /* STM32_RTC_TR bit fields */ 214e64350fSAmelie Delaunay #define STM32_RTC_TR_SEC_SHIFT 0 224e64350fSAmelie Delaunay #define STM32_RTC_TR_SEC GENMASK(6, 0) 234e64350fSAmelie Delaunay #define STM32_RTC_TR_MIN_SHIFT 8 244e64350fSAmelie Delaunay #define STM32_RTC_TR_MIN GENMASK(14, 8) 254e64350fSAmelie Delaunay #define STM32_RTC_TR_HOUR_SHIFT 16 264e64350fSAmelie Delaunay #define STM32_RTC_TR_HOUR GENMASK(21, 16) 274e64350fSAmelie Delaunay 284e64350fSAmelie Delaunay /* STM32_RTC_DR bit fields */ 294e64350fSAmelie Delaunay #define STM32_RTC_DR_DATE_SHIFT 0 304e64350fSAmelie Delaunay #define STM32_RTC_DR_DATE GENMASK(5, 0) 314e64350fSAmelie Delaunay #define STM32_RTC_DR_MONTH_SHIFT 8 324e64350fSAmelie Delaunay #define STM32_RTC_DR_MONTH GENMASK(12, 8) 334e64350fSAmelie Delaunay #define STM32_RTC_DR_WDAY_SHIFT 13 344e64350fSAmelie Delaunay #define STM32_RTC_DR_WDAY GENMASK(15, 13) 354e64350fSAmelie Delaunay #define STM32_RTC_DR_YEAR_SHIFT 16 364e64350fSAmelie Delaunay #define STM32_RTC_DR_YEAR GENMASK(23, 16) 374e64350fSAmelie Delaunay 384e64350fSAmelie Delaunay /* STM32_RTC_CR bit fields */ 394e64350fSAmelie Delaunay #define STM32_RTC_CR_FMT BIT(6) 404e64350fSAmelie Delaunay #define STM32_RTC_CR_ALRAE BIT(8) 414e64350fSAmelie Delaunay #define STM32_RTC_CR_ALRAIE BIT(12) 424e64350fSAmelie Delaunay 43b72252b6SAmelie Delaunay /* STM32_RTC_ISR/STM32_RTC_ICSR bit fields */ 444e64350fSAmelie Delaunay #define STM32_RTC_ISR_ALRAWF BIT(0) 454e64350fSAmelie Delaunay #define STM32_RTC_ISR_INITS BIT(4) 464e64350fSAmelie Delaunay #define STM32_RTC_ISR_RSF BIT(5) 474e64350fSAmelie Delaunay #define STM32_RTC_ISR_INITF BIT(6) 484e64350fSAmelie Delaunay #define STM32_RTC_ISR_INIT BIT(7) 494e64350fSAmelie Delaunay #define STM32_RTC_ISR_ALRAF BIT(8) 504e64350fSAmelie Delaunay 514e64350fSAmelie Delaunay /* STM32_RTC_PRER bit fields */ 524e64350fSAmelie Delaunay #define STM32_RTC_PRER_PRED_S_SHIFT 0 534e64350fSAmelie Delaunay #define STM32_RTC_PRER_PRED_S GENMASK(14, 0) 544e64350fSAmelie Delaunay #define STM32_RTC_PRER_PRED_A_SHIFT 16 554e64350fSAmelie Delaunay #define STM32_RTC_PRER_PRED_A GENMASK(22, 16) 564e64350fSAmelie Delaunay 574e64350fSAmelie Delaunay /* STM32_RTC_ALRMAR and STM32_RTC_ALRMBR bit fields */ 584e64350fSAmelie Delaunay #define STM32_RTC_ALRMXR_SEC_SHIFT 0 594e64350fSAmelie Delaunay #define STM32_RTC_ALRMXR_SEC GENMASK(6, 0) 604e64350fSAmelie Delaunay #define STM32_RTC_ALRMXR_SEC_MASK BIT(7) 614e64350fSAmelie Delaunay #define STM32_RTC_ALRMXR_MIN_SHIFT 8 624e64350fSAmelie Delaunay #define STM32_RTC_ALRMXR_MIN GENMASK(14, 8) 634e64350fSAmelie Delaunay #define STM32_RTC_ALRMXR_MIN_MASK BIT(15) 644e64350fSAmelie Delaunay #define STM32_RTC_ALRMXR_HOUR_SHIFT 16 654e64350fSAmelie Delaunay #define STM32_RTC_ALRMXR_HOUR GENMASK(21, 16) 664e64350fSAmelie Delaunay #define STM32_RTC_ALRMXR_PM BIT(22) 674e64350fSAmelie Delaunay #define STM32_RTC_ALRMXR_HOUR_MASK BIT(23) 684e64350fSAmelie Delaunay #define STM32_RTC_ALRMXR_DATE_SHIFT 24 694e64350fSAmelie Delaunay #define STM32_RTC_ALRMXR_DATE GENMASK(29, 24) 704e64350fSAmelie Delaunay #define STM32_RTC_ALRMXR_WDSEL BIT(30) 714e64350fSAmelie Delaunay #define STM32_RTC_ALRMXR_WDAY_SHIFT 24 724e64350fSAmelie Delaunay #define STM32_RTC_ALRMXR_WDAY GENMASK(27, 24) 734e64350fSAmelie Delaunay #define STM32_RTC_ALRMXR_DATE_MASK BIT(31) 744e64350fSAmelie Delaunay 75b72252b6SAmelie Delaunay /* STM32_RTC_SR/_SCR bit fields */ 76b72252b6SAmelie Delaunay #define STM32_RTC_SR_ALRA BIT(0) 77b72252b6SAmelie Delaunay 78b72252b6SAmelie Delaunay /* STM32_RTC_VERR bit fields */ 79b72252b6SAmelie Delaunay #define STM32_RTC_VERR_MINREV_SHIFT 0 80b72252b6SAmelie Delaunay #define STM32_RTC_VERR_MINREV GENMASK(3, 0) 81b72252b6SAmelie Delaunay #define STM32_RTC_VERR_MAJREV_SHIFT 4 82b72252b6SAmelie Delaunay #define STM32_RTC_VERR_MAJREV GENMASK(7, 4) 83b72252b6SAmelie Delaunay 844e64350fSAmelie Delaunay /* STM32_RTC_WPR key constants */ 854e64350fSAmelie Delaunay #define RTC_WPR_1ST_KEY 0xCA 864e64350fSAmelie Delaunay #define RTC_WPR_2ND_KEY 0x53 874e64350fSAmelie Delaunay #define RTC_WPR_WRONG_KEY 0xFF 884e64350fSAmelie Delaunay 89b72252b6SAmelie Delaunay /* Max STM32 RTC register offset is 0x3FC */ 90b72252b6SAmelie Delaunay #define UNDEF_REG 0xFFFF 91b72252b6SAmelie Delaunay 9202b0cc34SAmelie Delaunay struct stm32_rtc; 9302b0cc34SAmelie Delaunay 9402b0cc34SAmelie Delaunay struct stm32_rtc_registers { 95b72252b6SAmelie Delaunay u16 tr; 96b72252b6SAmelie Delaunay u16 dr; 97b72252b6SAmelie Delaunay u16 cr; 98b72252b6SAmelie Delaunay u16 isr; 99b72252b6SAmelie Delaunay u16 prer; 100b72252b6SAmelie Delaunay u16 alrmar; 101b72252b6SAmelie Delaunay u16 wpr; 102b72252b6SAmelie Delaunay u16 sr; 103b72252b6SAmelie Delaunay u16 scr; 104b72252b6SAmelie Delaunay u16 verr; 10502b0cc34SAmelie Delaunay }; 10602b0cc34SAmelie Delaunay 10702b0cc34SAmelie Delaunay struct stm32_rtc_events { 10802b0cc34SAmelie Delaunay u32 alra; 10902b0cc34SAmelie Delaunay }; 11002b0cc34SAmelie Delaunay 1119a6757eaSAmelie Delaunay struct stm32_rtc_data { 11202b0cc34SAmelie Delaunay const struct stm32_rtc_registers regs; 11302b0cc34SAmelie Delaunay const struct stm32_rtc_events events; 11402b0cc34SAmelie Delaunay void (*clear_events)(struct stm32_rtc *rtc, unsigned int flags); 1159a6757eaSAmelie Delaunay bool has_pclk; 11622cb47c1SAmelie Delaunay bool need_dbp; 117b72252b6SAmelie Delaunay bool has_wakeirq; 1189a6757eaSAmelie Delaunay }; 1199a6757eaSAmelie Delaunay 1204e64350fSAmelie Delaunay struct stm32_rtc { 1214e64350fSAmelie Delaunay struct rtc_device *rtc_dev; 1224e64350fSAmelie Delaunay void __iomem *base; 1234e64350fSAmelie Delaunay struct regmap *dbp; 12422cb47c1SAmelie Delaunay unsigned int dbp_reg; 12522cb47c1SAmelie Delaunay unsigned int dbp_mask; 1269a6757eaSAmelie Delaunay struct clk *pclk; 1279a6757eaSAmelie Delaunay struct clk *rtc_ck; 12802b0cc34SAmelie Delaunay const struct stm32_rtc_data *data; 1294e64350fSAmelie Delaunay int irq_alarm; 130b72252b6SAmelie Delaunay int wakeirq_alarm; 1314e64350fSAmelie Delaunay }; 1324e64350fSAmelie Delaunay 1334e64350fSAmelie Delaunay static void stm32_rtc_wpr_unlock(struct stm32_rtc *rtc) 1344e64350fSAmelie Delaunay { 13502b0cc34SAmelie Delaunay const struct stm32_rtc_registers *regs = &rtc->data->regs; 13602b0cc34SAmelie Delaunay 13702b0cc34SAmelie Delaunay writel_relaxed(RTC_WPR_1ST_KEY, rtc->base + regs->wpr); 13802b0cc34SAmelie Delaunay writel_relaxed(RTC_WPR_2ND_KEY, rtc->base + regs->wpr); 1394e64350fSAmelie Delaunay } 1404e64350fSAmelie Delaunay 1414e64350fSAmelie Delaunay static void stm32_rtc_wpr_lock(struct stm32_rtc *rtc) 1424e64350fSAmelie Delaunay { 14302b0cc34SAmelie Delaunay const struct stm32_rtc_registers *regs = &rtc->data->regs; 14402b0cc34SAmelie Delaunay 14502b0cc34SAmelie Delaunay writel_relaxed(RTC_WPR_WRONG_KEY, rtc->base + regs->wpr); 1464e64350fSAmelie Delaunay } 1474e64350fSAmelie Delaunay 1484e64350fSAmelie Delaunay static int stm32_rtc_enter_init_mode(struct stm32_rtc *rtc) 1494e64350fSAmelie Delaunay { 15002b0cc34SAmelie Delaunay const struct stm32_rtc_registers *regs = &rtc->data->regs; 15102b0cc34SAmelie Delaunay unsigned int isr = readl_relaxed(rtc->base + regs->isr); 1524e64350fSAmelie Delaunay 1534e64350fSAmelie Delaunay if (!(isr & STM32_RTC_ISR_INITF)) { 1544e64350fSAmelie Delaunay isr |= STM32_RTC_ISR_INIT; 15502b0cc34SAmelie Delaunay writel_relaxed(isr, rtc->base + regs->isr); 1564e64350fSAmelie Delaunay 1574e64350fSAmelie Delaunay /* 1589a6757eaSAmelie Delaunay * It takes around 2 rtc_ck clock cycles to enter in 1594e64350fSAmelie Delaunay * initialization phase mode (and have INITF flag set). As 1609a6757eaSAmelie Delaunay * slowest rtc_ck frequency may be 32kHz and highest should be 1614e64350fSAmelie Delaunay * 1MHz, we poll every 10 us with a timeout of 100ms. 1624e64350fSAmelie Delaunay */ 1634e64350fSAmelie Delaunay return readl_relaxed_poll_timeout_atomic( 16402b0cc34SAmelie Delaunay rtc->base + regs->isr, 1654e64350fSAmelie Delaunay isr, (isr & STM32_RTC_ISR_INITF), 1664e64350fSAmelie Delaunay 10, 100000); 1674e64350fSAmelie Delaunay } 1684e64350fSAmelie Delaunay 1694e64350fSAmelie Delaunay return 0; 1704e64350fSAmelie Delaunay } 1714e64350fSAmelie Delaunay 1724e64350fSAmelie Delaunay static void stm32_rtc_exit_init_mode(struct stm32_rtc *rtc) 1734e64350fSAmelie Delaunay { 17402b0cc34SAmelie Delaunay const struct stm32_rtc_registers *regs = &rtc->data->regs; 17502b0cc34SAmelie Delaunay unsigned int isr = readl_relaxed(rtc->base + regs->isr); 1764e64350fSAmelie Delaunay 1774e64350fSAmelie Delaunay isr &= ~STM32_RTC_ISR_INIT; 17802b0cc34SAmelie Delaunay writel_relaxed(isr, rtc->base + regs->isr); 1794e64350fSAmelie Delaunay } 1804e64350fSAmelie Delaunay 1814e64350fSAmelie Delaunay static int stm32_rtc_wait_sync(struct stm32_rtc *rtc) 1824e64350fSAmelie Delaunay { 18302b0cc34SAmelie Delaunay const struct stm32_rtc_registers *regs = &rtc->data->regs; 18402b0cc34SAmelie Delaunay unsigned int isr = readl_relaxed(rtc->base + regs->isr); 1854e64350fSAmelie Delaunay 1864e64350fSAmelie Delaunay isr &= ~STM32_RTC_ISR_RSF; 18702b0cc34SAmelie Delaunay writel_relaxed(isr, rtc->base + regs->isr); 1884e64350fSAmelie Delaunay 1894e64350fSAmelie Delaunay /* 1904e64350fSAmelie Delaunay * Wait for RSF to be set to ensure the calendar registers are 1919a6757eaSAmelie Delaunay * synchronised, it takes around 2 rtc_ck clock cycles 1924e64350fSAmelie Delaunay */ 19302b0cc34SAmelie Delaunay return readl_relaxed_poll_timeout_atomic(rtc->base + regs->isr, 1944e64350fSAmelie Delaunay isr, 1954e64350fSAmelie Delaunay (isr & STM32_RTC_ISR_RSF), 1964e64350fSAmelie Delaunay 10, 100000); 1974e64350fSAmelie Delaunay } 1984e64350fSAmelie Delaunay 19902b0cc34SAmelie Delaunay static void stm32_rtc_clear_event_flags(struct stm32_rtc *rtc, 20002b0cc34SAmelie Delaunay unsigned int flags) 20102b0cc34SAmelie Delaunay { 20202b0cc34SAmelie Delaunay rtc->data->clear_events(rtc, flags); 20302b0cc34SAmelie Delaunay } 20402b0cc34SAmelie Delaunay 2054e64350fSAmelie Delaunay static irqreturn_t stm32_rtc_alarm_irq(int irq, void *dev_id) 2064e64350fSAmelie Delaunay { 2074e64350fSAmelie Delaunay struct stm32_rtc *rtc = (struct stm32_rtc *)dev_id; 20802b0cc34SAmelie Delaunay const struct stm32_rtc_registers *regs = &rtc->data->regs; 20902b0cc34SAmelie Delaunay const struct stm32_rtc_events *evts = &rtc->data->events; 21002b0cc34SAmelie Delaunay unsigned int status, cr; 2114e64350fSAmelie Delaunay 2124e64350fSAmelie Delaunay mutex_lock(&rtc->rtc_dev->ops_lock); 2134e64350fSAmelie Delaunay 214b72252b6SAmelie Delaunay status = readl_relaxed(rtc->base + regs->sr); 21502b0cc34SAmelie Delaunay cr = readl_relaxed(rtc->base + regs->cr); 2164e64350fSAmelie Delaunay 21702b0cc34SAmelie Delaunay if ((status & evts->alra) && 2184e64350fSAmelie Delaunay (cr & STM32_RTC_CR_ALRAIE)) { 2194e64350fSAmelie Delaunay /* Alarm A flag - Alarm interrupt */ 2204e64350fSAmelie Delaunay dev_dbg(&rtc->rtc_dev->dev, "Alarm occurred\n"); 2214e64350fSAmelie Delaunay 2224e64350fSAmelie Delaunay /* Pass event to the kernel */ 2234e64350fSAmelie Delaunay rtc_update_irq(rtc->rtc_dev, 1, RTC_IRQF | RTC_AF); 2244e64350fSAmelie Delaunay 22502b0cc34SAmelie Delaunay /* Clear event flags, otherwise new events won't be received */ 22602b0cc34SAmelie Delaunay stm32_rtc_clear_event_flags(rtc, evts->alra); 2274e64350fSAmelie Delaunay } 2284e64350fSAmelie Delaunay 2294e64350fSAmelie Delaunay mutex_unlock(&rtc->rtc_dev->ops_lock); 2304e64350fSAmelie Delaunay 2314e64350fSAmelie Delaunay return IRQ_HANDLED; 2324e64350fSAmelie Delaunay } 2334e64350fSAmelie Delaunay 2344e64350fSAmelie Delaunay /* Convert rtc_time structure from bin to bcd format */ 2354e64350fSAmelie Delaunay static void tm2bcd(struct rtc_time *tm) 2364e64350fSAmelie Delaunay { 2374e64350fSAmelie Delaunay tm->tm_sec = bin2bcd(tm->tm_sec); 2384e64350fSAmelie Delaunay tm->tm_min = bin2bcd(tm->tm_min); 2394e64350fSAmelie Delaunay tm->tm_hour = bin2bcd(tm->tm_hour); 2404e64350fSAmelie Delaunay 2414e64350fSAmelie Delaunay tm->tm_mday = bin2bcd(tm->tm_mday); 2424e64350fSAmelie Delaunay tm->tm_mon = bin2bcd(tm->tm_mon + 1); 2434e64350fSAmelie Delaunay tm->tm_year = bin2bcd(tm->tm_year - 100); 2444e64350fSAmelie Delaunay /* 2454e64350fSAmelie Delaunay * Number of days since Sunday 2464e64350fSAmelie Delaunay * - on kernel side, 0=Sunday...6=Saturday 2474e64350fSAmelie Delaunay * - on rtc side, 0=invalid,1=Monday...7=Sunday 2484e64350fSAmelie Delaunay */ 2494e64350fSAmelie Delaunay tm->tm_wday = (!tm->tm_wday) ? 7 : tm->tm_wday; 2504e64350fSAmelie Delaunay } 2514e64350fSAmelie Delaunay 2524e64350fSAmelie Delaunay /* Convert rtc_time structure from bcd to bin format */ 2534e64350fSAmelie Delaunay static void bcd2tm(struct rtc_time *tm) 2544e64350fSAmelie Delaunay { 2554e64350fSAmelie Delaunay tm->tm_sec = bcd2bin(tm->tm_sec); 2564e64350fSAmelie Delaunay tm->tm_min = bcd2bin(tm->tm_min); 2574e64350fSAmelie Delaunay tm->tm_hour = bcd2bin(tm->tm_hour); 2584e64350fSAmelie Delaunay 2594e64350fSAmelie Delaunay tm->tm_mday = bcd2bin(tm->tm_mday); 2604e64350fSAmelie Delaunay tm->tm_mon = bcd2bin(tm->tm_mon) - 1; 2614e64350fSAmelie Delaunay tm->tm_year = bcd2bin(tm->tm_year) + 100; 2624e64350fSAmelie Delaunay /* 2634e64350fSAmelie Delaunay * Number of days since Sunday 2644e64350fSAmelie Delaunay * - on kernel side, 0=Sunday...6=Saturday 2654e64350fSAmelie Delaunay * - on rtc side, 0=invalid,1=Monday...7=Sunday 2664e64350fSAmelie Delaunay */ 2674e64350fSAmelie Delaunay tm->tm_wday %= 7; 2684e64350fSAmelie Delaunay } 2694e64350fSAmelie Delaunay 2704e64350fSAmelie Delaunay static int stm32_rtc_read_time(struct device *dev, struct rtc_time *tm) 2714e64350fSAmelie Delaunay { 2724e64350fSAmelie Delaunay struct stm32_rtc *rtc = dev_get_drvdata(dev); 27302b0cc34SAmelie Delaunay const struct stm32_rtc_registers *regs = &rtc->data->regs; 2744e64350fSAmelie Delaunay unsigned int tr, dr; 2754e64350fSAmelie Delaunay 2764e64350fSAmelie Delaunay /* Time and Date in BCD format */ 27702b0cc34SAmelie Delaunay tr = readl_relaxed(rtc->base + regs->tr); 27802b0cc34SAmelie Delaunay dr = readl_relaxed(rtc->base + regs->dr); 2794e64350fSAmelie Delaunay 2804e64350fSAmelie Delaunay tm->tm_sec = (tr & STM32_RTC_TR_SEC) >> STM32_RTC_TR_SEC_SHIFT; 2814e64350fSAmelie Delaunay tm->tm_min = (tr & STM32_RTC_TR_MIN) >> STM32_RTC_TR_MIN_SHIFT; 2824e64350fSAmelie Delaunay tm->tm_hour = (tr & STM32_RTC_TR_HOUR) >> STM32_RTC_TR_HOUR_SHIFT; 2834e64350fSAmelie Delaunay 2844e64350fSAmelie Delaunay tm->tm_mday = (dr & STM32_RTC_DR_DATE) >> STM32_RTC_DR_DATE_SHIFT; 2854e64350fSAmelie Delaunay tm->tm_mon = (dr & STM32_RTC_DR_MONTH) >> STM32_RTC_DR_MONTH_SHIFT; 2864e64350fSAmelie Delaunay tm->tm_year = (dr & STM32_RTC_DR_YEAR) >> STM32_RTC_DR_YEAR_SHIFT; 2874e64350fSAmelie Delaunay tm->tm_wday = (dr & STM32_RTC_DR_WDAY) >> STM32_RTC_DR_WDAY_SHIFT; 2884e64350fSAmelie Delaunay 2894e64350fSAmelie Delaunay /* We don't report tm_yday and tm_isdst */ 2904e64350fSAmelie Delaunay 2914e64350fSAmelie Delaunay bcd2tm(tm); 2924e64350fSAmelie Delaunay 2934e64350fSAmelie Delaunay return 0; 2944e64350fSAmelie Delaunay } 2954e64350fSAmelie Delaunay 2964e64350fSAmelie Delaunay static int stm32_rtc_set_time(struct device *dev, struct rtc_time *tm) 2974e64350fSAmelie Delaunay { 2984e64350fSAmelie Delaunay struct stm32_rtc *rtc = dev_get_drvdata(dev); 29902b0cc34SAmelie Delaunay const struct stm32_rtc_registers *regs = &rtc->data->regs; 3004e64350fSAmelie Delaunay unsigned int tr, dr; 3014e64350fSAmelie Delaunay int ret = 0; 3024e64350fSAmelie Delaunay 3034e64350fSAmelie Delaunay tm2bcd(tm); 3044e64350fSAmelie Delaunay 3054e64350fSAmelie Delaunay /* Time in BCD format */ 3064e64350fSAmelie Delaunay tr = ((tm->tm_sec << STM32_RTC_TR_SEC_SHIFT) & STM32_RTC_TR_SEC) | 3074e64350fSAmelie Delaunay ((tm->tm_min << STM32_RTC_TR_MIN_SHIFT) & STM32_RTC_TR_MIN) | 3084e64350fSAmelie Delaunay ((tm->tm_hour << STM32_RTC_TR_HOUR_SHIFT) & STM32_RTC_TR_HOUR); 3094e64350fSAmelie Delaunay 3104e64350fSAmelie Delaunay /* Date in BCD format */ 3114e64350fSAmelie Delaunay dr = ((tm->tm_mday << STM32_RTC_DR_DATE_SHIFT) & STM32_RTC_DR_DATE) | 3124e64350fSAmelie Delaunay ((tm->tm_mon << STM32_RTC_DR_MONTH_SHIFT) & STM32_RTC_DR_MONTH) | 3134e64350fSAmelie Delaunay ((tm->tm_year << STM32_RTC_DR_YEAR_SHIFT) & STM32_RTC_DR_YEAR) | 3144e64350fSAmelie Delaunay ((tm->tm_wday << STM32_RTC_DR_WDAY_SHIFT) & STM32_RTC_DR_WDAY); 3154e64350fSAmelie Delaunay 3164e64350fSAmelie Delaunay stm32_rtc_wpr_unlock(rtc); 3174e64350fSAmelie Delaunay 3184e64350fSAmelie Delaunay ret = stm32_rtc_enter_init_mode(rtc); 3194e64350fSAmelie Delaunay if (ret) { 3204e64350fSAmelie Delaunay dev_err(dev, "Can't enter in init mode. Set time aborted.\n"); 3214e64350fSAmelie Delaunay goto end; 3224e64350fSAmelie Delaunay } 3234e64350fSAmelie Delaunay 32402b0cc34SAmelie Delaunay writel_relaxed(tr, rtc->base + regs->tr); 32502b0cc34SAmelie Delaunay writel_relaxed(dr, rtc->base + regs->dr); 3264e64350fSAmelie Delaunay 3274e64350fSAmelie Delaunay stm32_rtc_exit_init_mode(rtc); 3284e64350fSAmelie Delaunay 3294e64350fSAmelie Delaunay ret = stm32_rtc_wait_sync(rtc); 3304e64350fSAmelie Delaunay end: 3314e64350fSAmelie Delaunay stm32_rtc_wpr_lock(rtc); 3324e64350fSAmelie Delaunay 3334e64350fSAmelie Delaunay return ret; 3344e64350fSAmelie Delaunay } 3354e64350fSAmelie Delaunay 3364e64350fSAmelie Delaunay static int stm32_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) 3374e64350fSAmelie Delaunay { 3384e64350fSAmelie Delaunay struct stm32_rtc *rtc = dev_get_drvdata(dev); 33902b0cc34SAmelie Delaunay const struct stm32_rtc_registers *regs = &rtc->data->regs; 34002b0cc34SAmelie Delaunay const struct stm32_rtc_events *evts = &rtc->data->events; 3414e64350fSAmelie Delaunay struct rtc_time *tm = &alrm->time; 34202b0cc34SAmelie Delaunay unsigned int alrmar, cr, status; 3434e64350fSAmelie Delaunay 34402b0cc34SAmelie Delaunay alrmar = readl_relaxed(rtc->base + regs->alrmar); 34502b0cc34SAmelie Delaunay cr = readl_relaxed(rtc->base + regs->cr); 346b72252b6SAmelie Delaunay status = readl_relaxed(rtc->base + regs->sr); 3474e64350fSAmelie Delaunay 3484e64350fSAmelie Delaunay if (alrmar & STM32_RTC_ALRMXR_DATE_MASK) { 3494e64350fSAmelie Delaunay /* 3504e64350fSAmelie Delaunay * Date/day doesn't matter in Alarm comparison so alarm 3514e64350fSAmelie Delaunay * triggers every day 3524e64350fSAmelie Delaunay */ 3534e64350fSAmelie Delaunay tm->tm_mday = -1; 3544e64350fSAmelie Delaunay tm->tm_wday = -1; 3554e64350fSAmelie Delaunay } else { 3564e64350fSAmelie Delaunay if (alrmar & STM32_RTC_ALRMXR_WDSEL) { 3574e64350fSAmelie Delaunay /* Alarm is set to a day of week */ 3584e64350fSAmelie Delaunay tm->tm_mday = -1; 3594e64350fSAmelie Delaunay tm->tm_wday = (alrmar & STM32_RTC_ALRMXR_WDAY) >> 3604e64350fSAmelie Delaunay STM32_RTC_ALRMXR_WDAY_SHIFT; 3614e64350fSAmelie Delaunay tm->tm_wday %= 7; 3624e64350fSAmelie Delaunay } else { 3634e64350fSAmelie Delaunay /* Alarm is set to a day of month */ 3644e64350fSAmelie Delaunay tm->tm_wday = -1; 3654e64350fSAmelie Delaunay tm->tm_mday = (alrmar & STM32_RTC_ALRMXR_DATE) >> 3664e64350fSAmelie Delaunay STM32_RTC_ALRMXR_DATE_SHIFT; 3674e64350fSAmelie Delaunay } 3684e64350fSAmelie Delaunay } 3694e64350fSAmelie Delaunay 3704e64350fSAmelie Delaunay if (alrmar & STM32_RTC_ALRMXR_HOUR_MASK) { 3714e64350fSAmelie Delaunay /* Hours don't matter in Alarm comparison */ 3724e64350fSAmelie Delaunay tm->tm_hour = -1; 3734e64350fSAmelie Delaunay } else { 3744e64350fSAmelie Delaunay tm->tm_hour = (alrmar & STM32_RTC_ALRMXR_HOUR) >> 3754e64350fSAmelie Delaunay STM32_RTC_ALRMXR_HOUR_SHIFT; 3764e64350fSAmelie Delaunay if (alrmar & STM32_RTC_ALRMXR_PM) 3774e64350fSAmelie Delaunay tm->tm_hour += 12; 3784e64350fSAmelie Delaunay } 3794e64350fSAmelie Delaunay 3804e64350fSAmelie Delaunay if (alrmar & STM32_RTC_ALRMXR_MIN_MASK) { 3814e64350fSAmelie Delaunay /* Minutes don't matter in Alarm comparison */ 3824e64350fSAmelie Delaunay tm->tm_min = -1; 3834e64350fSAmelie Delaunay } else { 3844e64350fSAmelie Delaunay tm->tm_min = (alrmar & STM32_RTC_ALRMXR_MIN) >> 3854e64350fSAmelie Delaunay STM32_RTC_ALRMXR_MIN_SHIFT; 3864e64350fSAmelie Delaunay } 3874e64350fSAmelie Delaunay 3884e64350fSAmelie Delaunay if (alrmar & STM32_RTC_ALRMXR_SEC_MASK) { 3894e64350fSAmelie Delaunay /* Seconds don't matter in Alarm comparison */ 3904e64350fSAmelie Delaunay tm->tm_sec = -1; 3914e64350fSAmelie Delaunay } else { 3924e64350fSAmelie Delaunay tm->tm_sec = (alrmar & STM32_RTC_ALRMXR_SEC) >> 3934e64350fSAmelie Delaunay STM32_RTC_ALRMXR_SEC_SHIFT; 3944e64350fSAmelie Delaunay } 3954e64350fSAmelie Delaunay 3964e64350fSAmelie Delaunay bcd2tm(tm); 3974e64350fSAmelie Delaunay 3984e64350fSAmelie Delaunay alrm->enabled = (cr & STM32_RTC_CR_ALRAE) ? 1 : 0; 39902b0cc34SAmelie Delaunay alrm->pending = (status & evts->alra) ? 1 : 0; 4004e64350fSAmelie Delaunay 4014e64350fSAmelie Delaunay return 0; 4024e64350fSAmelie Delaunay } 4034e64350fSAmelie Delaunay 4044e64350fSAmelie Delaunay static int stm32_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) 4054e64350fSAmelie Delaunay { 4064e64350fSAmelie Delaunay struct stm32_rtc *rtc = dev_get_drvdata(dev); 40702b0cc34SAmelie Delaunay const struct stm32_rtc_registers *regs = &rtc->data->regs; 40802b0cc34SAmelie Delaunay const struct stm32_rtc_events *evts = &rtc->data->events; 40902b0cc34SAmelie Delaunay unsigned int cr; 4104e64350fSAmelie Delaunay 41102b0cc34SAmelie Delaunay cr = readl_relaxed(rtc->base + regs->cr); 4124e64350fSAmelie Delaunay 4134e64350fSAmelie Delaunay stm32_rtc_wpr_unlock(rtc); 4144e64350fSAmelie Delaunay 4154e64350fSAmelie Delaunay /* We expose Alarm A to the kernel */ 4164e64350fSAmelie Delaunay if (enabled) 4174e64350fSAmelie Delaunay cr |= (STM32_RTC_CR_ALRAIE | STM32_RTC_CR_ALRAE); 4184e64350fSAmelie Delaunay else 4194e64350fSAmelie Delaunay cr &= ~(STM32_RTC_CR_ALRAIE | STM32_RTC_CR_ALRAE); 42002b0cc34SAmelie Delaunay writel_relaxed(cr, rtc->base + regs->cr); 4214e64350fSAmelie Delaunay 42202b0cc34SAmelie Delaunay /* Clear event flags, otherwise new events won't be received */ 42302b0cc34SAmelie Delaunay stm32_rtc_clear_event_flags(rtc, evts->alra); 4244e64350fSAmelie Delaunay 4254e64350fSAmelie Delaunay stm32_rtc_wpr_lock(rtc); 4264e64350fSAmelie Delaunay 4274e64350fSAmelie Delaunay return 0; 4284e64350fSAmelie Delaunay } 4294e64350fSAmelie Delaunay 4304e64350fSAmelie Delaunay static int stm32_rtc_valid_alrm(struct stm32_rtc *rtc, struct rtc_time *tm) 4314e64350fSAmelie Delaunay { 43202b0cc34SAmelie Delaunay const struct stm32_rtc_registers *regs = &rtc->data->regs; 4331d70ba3bSAmelie Delaunay int cur_day, cur_mon, cur_year, cur_hour, cur_min, cur_sec; 43402b0cc34SAmelie Delaunay unsigned int dr = readl_relaxed(rtc->base + regs->dr); 43502b0cc34SAmelie Delaunay unsigned int tr = readl_relaxed(rtc->base + regs->tr); 4364e64350fSAmelie Delaunay 4374e64350fSAmelie Delaunay cur_day = (dr & STM32_RTC_DR_DATE) >> STM32_RTC_DR_DATE_SHIFT; 4384e64350fSAmelie Delaunay cur_mon = (dr & STM32_RTC_DR_MONTH) >> STM32_RTC_DR_MONTH_SHIFT; 4394e64350fSAmelie Delaunay cur_year = (dr & STM32_RTC_DR_YEAR) >> STM32_RTC_DR_YEAR_SHIFT; 4404e64350fSAmelie Delaunay cur_sec = (tr & STM32_RTC_TR_SEC) >> STM32_RTC_TR_SEC_SHIFT; 4414e64350fSAmelie Delaunay cur_min = (tr & STM32_RTC_TR_MIN) >> STM32_RTC_TR_MIN_SHIFT; 4424e64350fSAmelie Delaunay cur_hour = (tr & STM32_RTC_TR_HOUR) >> STM32_RTC_TR_HOUR_SHIFT; 4434e64350fSAmelie Delaunay 4444e64350fSAmelie Delaunay /* 4454e64350fSAmelie Delaunay * Assuming current date is M-D-Y H:M:S. 4464e64350fSAmelie Delaunay * RTC alarm can't be set on a specific month and year. 4474e64350fSAmelie Delaunay * So the valid alarm range is: 4484e64350fSAmelie Delaunay * M-D-Y H:M:S < alarm <= (M+1)-D-Y H:M:S 4494e64350fSAmelie Delaunay * with a specific case for December... 4504e64350fSAmelie Delaunay */ 4514e64350fSAmelie Delaunay if ((((tm->tm_year > cur_year) && 4524e64350fSAmelie Delaunay (tm->tm_mon == 0x1) && (cur_mon == 0x12)) || 4534e64350fSAmelie Delaunay ((tm->tm_year == cur_year) && 4544e64350fSAmelie Delaunay (tm->tm_mon <= cur_mon + 1))) && 4554e64350fSAmelie Delaunay ((tm->tm_mday > cur_day) || 4564e64350fSAmelie Delaunay ((tm->tm_mday == cur_day) && 4574e64350fSAmelie Delaunay ((tm->tm_hour > cur_hour) || 4584e64350fSAmelie Delaunay ((tm->tm_hour == cur_hour) && (tm->tm_min > cur_min)) || 4594e64350fSAmelie Delaunay ((tm->tm_hour == cur_hour) && (tm->tm_min == cur_min) && 4604e64350fSAmelie Delaunay (tm->tm_sec >= cur_sec)))))) 4614e64350fSAmelie Delaunay return 0; 4624e64350fSAmelie Delaunay 4634e64350fSAmelie Delaunay return -EINVAL; 4644e64350fSAmelie Delaunay } 4654e64350fSAmelie Delaunay 4664e64350fSAmelie Delaunay static int stm32_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) 4674e64350fSAmelie Delaunay { 4684e64350fSAmelie Delaunay struct stm32_rtc *rtc = dev_get_drvdata(dev); 46902b0cc34SAmelie Delaunay const struct stm32_rtc_registers *regs = &rtc->data->regs; 4704e64350fSAmelie Delaunay struct rtc_time *tm = &alrm->time; 4714e64350fSAmelie Delaunay unsigned int cr, isr, alrmar; 4724e64350fSAmelie Delaunay int ret = 0; 4734e64350fSAmelie Delaunay 4744e64350fSAmelie Delaunay tm2bcd(tm); 4754e64350fSAmelie Delaunay 4764e64350fSAmelie Delaunay /* 4774e64350fSAmelie Delaunay * RTC alarm can't be set on a specific date, unless this date is 4784e64350fSAmelie Delaunay * up to the same day of month next month. 4794e64350fSAmelie Delaunay */ 4804e64350fSAmelie Delaunay if (stm32_rtc_valid_alrm(rtc, tm) < 0) { 4814e64350fSAmelie Delaunay dev_err(dev, "Alarm can be set only on upcoming month.\n"); 4824e64350fSAmelie Delaunay return -EINVAL; 4834e64350fSAmelie Delaunay } 4844e64350fSAmelie Delaunay 4854e64350fSAmelie Delaunay alrmar = 0; 4864e64350fSAmelie Delaunay /* tm_year and tm_mon are not used because not supported by RTC */ 4874e64350fSAmelie Delaunay alrmar |= (tm->tm_mday << STM32_RTC_ALRMXR_DATE_SHIFT) & 4884e64350fSAmelie Delaunay STM32_RTC_ALRMXR_DATE; 4894e64350fSAmelie Delaunay /* 24-hour format */ 4904e64350fSAmelie Delaunay alrmar &= ~STM32_RTC_ALRMXR_PM; 4914e64350fSAmelie Delaunay alrmar |= (tm->tm_hour << STM32_RTC_ALRMXR_HOUR_SHIFT) & 4924e64350fSAmelie Delaunay STM32_RTC_ALRMXR_HOUR; 4934e64350fSAmelie Delaunay alrmar |= (tm->tm_min << STM32_RTC_ALRMXR_MIN_SHIFT) & 4944e64350fSAmelie Delaunay STM32_RTC_ALRMXR_MIN; 4954e64350fSAmelie Delaunay alrmar |= (tm->tm_sec << STM32_RTC_ALRMXR_SEC_SHIFT) & 4964e64350fSAmelie Delaunay STM32_RTC_ALRMXR_SEC; 4974e64350fSAmelie Delaunay 4984e64350fSAmelie Delaunay stm32_rtc_wpr_unlock(rtc); 4994e64350fSAmelie Delaunay 5004e64350fSAmelie Delaunay /* Disable Alarm */ 50102b0cc34SAmelie Delaunay cr = readl_relaxed(rtc->base + regs->cr); 5024e64350fSAmelie Delaunay cr &= ~STM32_RTC_CR_ALRAE; 50302b0cc34SAmelie Delaunay writel_relaxed(cr, rtc->base + regs->cr); 5044e64350fSAmelie Delaunay 5054e64350fSAmelie Delaunay /* 5064e64350fSAmelie Delaunay * Poll Alarm write flag to be sure that Alarm update is allowed: it 5079a6757eaSAmelie Delaunay * takes around 2 rtc_ck clock cycles 5084e64350fSAmelie Delaunay */ 50902b0cc34SAmelie Delaunay ret = readl_relaxed_poll_timeout_atomic(rtc->base + regs->isr, 5104e64350fSAmelie Delaunay isr, 5114e64350fSAmelie Delaunay (isr & STM32_RTC_ISR_ALRAWF), 5124e64350fSAmelie Delaunay 10, 100000); 5134e64350fSAmelie Delaunay 5144e64350fSAmelie Delaunay if (ret) { 5154e64350fSAmelie Delaunay dev_err(dev, "Alarm update not allowed\n"); 5164e64350fSAmelie Delaunay goto end; 5174e64350fSAmelie Delaunay } 5184e64350fSAmelie Delaunay 5194e64350fSAmelie Delaunay /* Write to Alarm register */ 52002b0cc34SAmelie Delaunay writel_relaxed(alrmar, rtc->base + regs->alrmar); 5214e64350fSAmelie Delaunay 522fe63604cSMarkus Elfring stm32_rtc_alarm_irq_enable(dev, alrm->enabled); 5234e64350fSAmelie Delaunay end: 5244e64350fSAmelie Delaunay stm32_rtc_wpr_lock(rtc); 5254e64350fSAmelie Delaunay 5264e64350fSAmelie Delaunay return ret; 5274e64350fSAmelie Delaunay } 5284e64350fSAmelie Delaunay 5294e64350fSAmelie Delaunay static const struct rtc_class_ops stm32_rtc_ops = { 5304e64350fSAmelie Delaunay .read_time = stm32_rtc_read_time, 5314e64350fSAmelie Delaunay .set_time = stm32_rtc_set_time, 5324e64350fSAmelie Delaunay .read_alarm = stm32_rtc_read_alarm, 5334e64350fSAmelie Delaunay .set_alarm = stm32_rtc_set_alarm, 5344e64350fSAmelie Delaunay .alarm_irq_enable = stm32_rtc_alarm_irq_enable, 5354e64350fSAmelie Delaunay }; 5364e64350fSAmelie Delaunay 53702b0cc34SAmelie Delaunay static void stm32_rtc_clear_events(struct stm32_rtc *rtc, 53802b0cc34SAmelie Delaunay unsigned int flags) 53902b0cc34SAmelie Delaunay { 54002b0cc34SAmelie Delaunay const struct stm32_rtc_registers *regs = &rtc->data->regs; 54102b0cc34SAmelie Delaunay 54202b0cc34SAmelie Delaunay /* Flags are cleared by writing 0 in RTC_ISR */ 54302b0cc34SAmelie Delaunay writel_relaxed(readl_relaxed(rtc->base + regs->isr) & ~flags, 54402b0cc34SAmelie Delaunay rtc->base + regs->isr); 54502b0cc34SAmelie Delaunay } 54602b0cc34SAmelie Delaunay 5479a6757eaSAmelie Delaunay static const struct stm32_rtc_data stm32_rtc_data = { 5489a6757eaSAmelie Delaunay .has_pclk = false, 54922cb47c1SAmelie Delaunay .need_dbp = true, 550b72252b6SAmelie Delaunay .has_wakeirq = false, 55102b0cc34SAmelie Delaunay .regs = { 55202b0cc34SAmelie Delaunay .tr = 0x00, 55302b0cc34SAmelie Delaunay .dr = 0x04, 55402b0cc34SAmelie Delaunay .cr = 0x08, 55502b0cc34SAmelie Delaunay .isr = 0x0C, 55602b0cc34SAmelie Delaunay .prer = 0x10, 55702b0cc34SAmelie Delaunay .alrmar = 0x1C, 55802b0cc34SAmelie Delaunay .wpr = 0x24, 559b72252b6SAmelie Delaunay .sr = 0x0C, /* set to ISR offset to ease alarm management */ 560b72252b6SAmelie Delaunay .scr = UNDEF_REG, 561b72252b6SAmelie Delaunay .verr = UNDEF_REG, 56202b0cc34SAmelie Delaunay }, 56302b0cc34SAmelie Delaunay .events = { 56402b0cc34SAmelie Delaunay .alra = STM32_RTC_ISR_ALRAF, 56502b0cc34SAmelie Delaunay }, 56602b0cc34SAmelie Delaunay .clear_events = stm32_rtc_clear_events, 5679a6757eaSAmelie Delaunay }; 5689a6757eaSAmelie Delaunay 5699a6757eaSAmelie Delaunay static const struct stm32_rtc_data stm32h7_rtc_data = { 5709a6757eaSAmelie Delaunay .has_pclk = true, 57122cb47c1SAmelie Delaunay .need_dbp = true, 572b72252b6SAmelie Delaunay .has_wakeirq = false, 57302b0cc34SAmelie Delaunay .regs = { 57402b0cc34SAmelie Delaunay .tr = 0x00, 57502b0cc34SAmelie Delaunay .dr = 0x04, 57602b0cc34SAmelie Delaunay .cr = 0x08, 57702b0cc34SAmelie Delaunay .isr = 0x0C, 57802b0cc34SAmelie Delaunay .prer = 0x10, 57902b0cc34SAmelie Delaunay .alrmar = 0x1C, 58002b0cc34SAmelie Delaunay .wpr = 0x24, 581b72252b6SAmelie Delaunay .sr = 0x0C, /* set to ISR offset to ease alarm management */ 582b72252b6SAmelie Delaunay .scr = UNDEF_REG, 583b72252b6SAmelie Delaunay .verr = UNDEF_REG, 58402b0cc34SAmelie Delaunay }, 58502b0cc34SAmelie Delaunay .events = { 58602b0cc34SAmelie Delaunay .alra = STM32_RTC_ISR_ALRAF, 58702b0cc34SAmelie Delaunay }, 58802b0cc34SAmelie Delaunay .clear_events = stm32_rtc_clear_events, 5899a6757eaSAmelie Delaunay }; 5909a6757eaSAmelie Delaunay 591b72252b6SAmelie Delaunay static void stm32mp1_rtc_clear_events(struct stm32_rtc *rtc, 592b72252b6SAmelie Delaunay unsigned int flags) 593b72252b6SAmelie Delaunay { 594b72252b6SAmelie Delaunay struct stm32_rtc_registers regs = rtc->data->regs; 595b72252b6SAmelie Delaunay 596b72252b6SAmelie Delaunay /* Flags are cleared by writing 1 in RTC_SCR */ 597b72252b6SAmelie Delaunay writel_relaxed(flags, rtc->base + regs.scr); 598b72252b6SAmelie Delaunay } 599b72252b6SAmelie Delaunay 600b72252b6SAmelie Delaunay static const struct stm32_rtc_data stm32mp1_data = { 601b72252b6SAmelie Delaunay .has_pclk = true, 602b72252b6SAmelie Delaunay .need_dbp = false, 603b72252b6SAmelie Delaunay .has_wakeirq = true, 604b72252b6SAmelie Delaunay .regs = { 605b72252b6SAmelie Delaunay .tr = 0x00, 606b72252b6SAmelie Delaunay .dr = 0x04, 607b72252b6SAmelie Delaunay .cr = 0x18, 608b72252b6SAmelie Delaunay .isr = 0x0C, /* named RTC_ICSR on stm32mp1 */ 609b72252b6SAmelie Delaunay .prer = 0x10, 610b72252b6SAmelie Delaunay .alrmar = 0x40, 611b72252b6SAmelie Delaunay .wpr = 0x24, 612b72252b6SAmelie Delaunay .sr = 0x50, 613b72252b6SAmelie Delaunay .scr = 0x5C, 614b72252b6SAmelie Delaunay .verr = 0x3F4, 615b72252b6SAmelie Delaunay }, 616b72252b6SAmelie Delaunay .events = { 617b72252b6SAmelie Delaunay .alra = STM32_RTC_SR_ALRA, 618b72252b6SAmelie Delaunay }, 619b72252b6SAmelie Delaunay .clear_events = stm32mp1_rtc_clear_events, 620b72252b6SAmelie Delaunay }; 621b72252b6SAmelie Delaunay 6224e64350fSAmelie Delaunay static const struct of_device_id stm32_rtc_of_match[] = { 6239a6757eaSAmelie Delaunay { .compatible = "st,stm32-rtc", .data = &stm32_rtc_data }, 6249a6757eaSAmelie Delaunay { .compatible = "st,stm32h7-rtc", .data = &stm32h7_rtc_data }, 625b72252b6SAmelie Delaunay { .compatible = "st,stm32mp1-rtc", .data = &stm32mp1_data }, 6264e64350fSAmelie Delaunay {} 6274e64350fSAmelie Delaunay }; 6284e64350fSAmelie Delaunay MODULE_DEVICE_TABLE(of, stm32_rtc_of_match); 6294e64350fSAmelie Delaunay 6304e64350fSAmelie Delaunay static int stm32_rtc_init(struct platform_device *pdev, 6314e64350fSAmelie Delaunay struct stm32_rtc *rtc) 6324e64350fSAmelie Delaunay { 63302b0cc34SAmelie Delaunay const struct stm32_rtc_registers *regs = &rtc->data->regs; 6344e64350fSAmelie Delaunay unsigned int prer, pred_a, pred_s, pred_a_max, pred_s_max, cr; 6354e64350fSAmelie Delaunay unsigned int rate; 6364e64350fSAmelie Delaunay int ret = 0; 6374e64350fSAmelie Delaunay 6389a6757eaSAmelie Delaunay rate = clk_get_rate(rtc->rtc_ck); 6394e64350fSAmelie Delaunay 6404e64350fSAmelie Delaunay /* Find prediv_a and prediv_s to obtain the 1Hz calendar clock */ 6414e64350fSAmelie Delaunay pred_a_max = STM32_RTC_PRER_PRED_A >> STM32_RTC_PRER_PRED_A_SHIFT; 6424e64350fSAmelie Delaunay pred_s_max = STM32_RTC_PRER_PRED_S >> STM32_RTC_PRER_PRED_S_SHIFT; 6434e64350fSAmelie Delaunay 6441d70ba3bSAmelie Delaunay for (pred_a = pred_a_max; pred_a + 1 > 0; pred_a--) { 6454e64350fSAmelie Delaunay pred_s = (rate / (pred_a + 1)) - 1; 6464e64350fSAmelie Delaunay 6474e64350fSAmelie Delaunay if (((pred_s + 1) * (pred_a + 1)) == rate) 6484e64350fSAmelie Delaunay break; 6494e64350fSAmelie Delaunay } 6504e64350fSAmelie Delaunay 6514e64350fSAmelie Delaunay /* 6524e64350fSAmelie Delaunay * Can't find a 1Hz, so give priority to RTC power consumption 6534e64350fSAmelie Delaunay * by choosing the higher possible value for prediv_a 6544e64350fSAmelie Delaunay */ 6554e64350fSAmelie Delaunay if ((pred_s > pred_s_max) || (pred_a > pred_a_max)) { 6564e64350fSAmelie Delaunay pred_a = pred_a_max; 6574e64350fSAmelie Delaunay pred_s = (rate / (pred_a + 1)) - 1; 6584e64350fSAmelie Delaunay 6599a6757eaSAmelie Delaunay dev_warn(&pdev->dev, "rtc_ck is %s\n", 6601d70ba3bSAmelie Delaunay (rate < ((pred_a + 1) * (pred_s + 1))) ? 6614e64350fSAmelie Delaunay "fast" : "slow"); 6624e64350fSAmelie Delaunay } 6634e64350fSAmelie Delaunay 6644e64350fSAmelie Delaunay stm32_rtc_wpr_unlock(rtc); 6654e64350fSAmelie Delaunay 6664e64350fSAmelie Delaunay ret = stm32_rtc_enter_init_mode(rtc); 6674e64350fSAmelie Delaunay if (ret) { 6684e64350fSAmelie Delaunay dev_err(&pdev->dev, 6694e64350fSAmelie Delaunay "Can't enter in init mode. Prescaler config failed.\n"); 6704e64350fSAmelie Delaunay goto end; 6714e64350fSAmelie Delaunay } 6724e64350fSAmelie Delaunay 6734e64350fSAmelie Delaunay prer = (pred_s << STM32_RTC_PRER_PRED_S_SHIFT) & STM32_RTC_PRER_PRED_S; 67402b0cc34SAmelie Delaunay writel_relaxed(prer, rtc->base + regs->prer); 6754e64350fSAmelie Delaunay prer |= (pred_a << STM32_RTC_PRER_PRED_A_SHIFT) & STM32_RTC_PRER_PRED_A; 67602b0cc34SAmelie Delaunay writel_relaxed(prer, rtc->base + regs->prer); 6774e64350fSAmelie Delaunay 6784e64350fSAmelie Delaunay /* Force 24h time format */ 67902b0cc34SAmelie Delaunay cr = readl_relaxed(rtc->base + regs->cr); 6804e64350fSAmelie Delaunay cr &= ~STM32_RTC_CR_FMT; 68102b0cc34SAmelie Delaunay writel_relaxed(cr, rtc->base + regs->cr); 6824e64350fSAmelie Delaunay 6834e64350fSAmelie Delaunay stm32_rtc_exit_init_mode(rtc); 6844e64350fSAmelie Delaunay 6854e64350fSAmelie Delaunay ret = stm32_rtc_wait_sync(rtc); 6864e64350fSAmelie Delaunay end: 6874e64350fSAmelie Delaunay stm32_rtc_wpr_lock(rtc); 6884e64350fSAmelie Delaunay 6894e64350fSAmelie Delaunay return ret; 6904e64350fSAmelie Delaunay } 6914e64350fSAmelie Delaunay 6924e64350fSAmelie Delaunay static int stm32_rtc_probe(struct platform_device *pdev) 6934e64350fSAmelie Delaunay { 6944e64350fSAmelie Delaunay struct stm32_rtc *rtc; 69502b0cc34SAmelie Delaunay const struct stm32_rtc_registers *regs; 6964e64350fSAmelie Delaunay struct resource *res; 6974e64350fSAmelie Delaunay int ret; 6984e64350fSAmelie Delaunay 6994e64350fSAmelie Delaunay rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL); 7004e64350fSAmelie Delaunay if (!rtc) 7014e64350fSAmelie Delaunay return -ENOMEM; 7024e64350fSAmelie Delaunay 7034e64350fSAmelie Delaunay res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 7044e64350fSAmelie Delaunay rtc->base = devm_ioremap_resource(&pdev->dev, res); 7054e64350fSAmelie Delaunay if (IS_ERR(rtc->base)) 7064e64350fSAmelie Delaunay return PTR_ERR(rtc->base); 7074e64350fSAmelie Delaunay 70822cb47c1SAmelie Delaunay rtc->data = (struct stm32_rtc_data *) 70922cb47c1SAmelie Delaunay of_device_get_match_data(&pdev->dev); 71002b0cc34SAmelie Delaunay regs = &rtc->data->regs; 71122cb47c1SAmelie Delaunay 71222cb47c1SAmelie Delaunay if (rtc->data->need_dbp) { 7134e64350fSAmelie Delaunay rtc->dbp = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, 7144e64350fSAmelie Delaunay "st,syscfg"); 7154e64350fSAmelie Delaunay if (IS_ERR(rtc->dbp)) { 7164e64350fSAmelie Delaunay dev_err(&pdev->dev, "no st,syscfg\n"); 7174e64350fSAmelie Delaunay return PTR_ERR(rtc->dbp); 7184e64350fSAmelie Delaunay } 7194e64350fSAmelie Delaunay 72022cb47c1SAmelie Delaunay ret = of_property_read_u32_index(pdev->dev.of_node, "st,syscfg", 72122cb47c1SAmelie Delaunay 1, &rtc->dbp_reg); 72222cb47c1SAmelie Delaunay if (ret) { 72322cb47c1SAmelie Delaunay dev_err(&pdev->dev, "can't read DBP register offset\n"); 72422cb47c1SAmelie Delaunay return ret; 72522cb47c1SAmelie Delaunay } 72622cb47c1SAmelie Delaunay 72722cb47c1SAmelie Delaunay ret = of_property_read_u32_index(pdev->dev.of_node, "st,syscfg", 72822cb47c1SAmelie Delaunay 2, &rtc->dbp_mask); 72922cb47c1SAmelie Delaunay if (ret) { 73022cb47c1SAmelie Delaunay dev_err(&pdev->dev, "can't read DBP register mask\n"); 73122cb47c1SAmelie Delaunay return ret; 73222cb47c1SAmelie Delaunay } 73322cb47c1SAmelie Delaunay } 7349a6757eaSAmelie Delaunay 7359a6757eaSAmelie Delaunay if (!rtc->data->has_pclk) { 7369a6757eaSAmelie Delaunay rtc->pclk = NULL; 7379a6757eaSAmelie Delaunay rtc->rtc_ck = devm_clk_get(&pdev->dev, NULL); 7389a6757eaSAmelie Delaunay } else { 7399a6757eaSAmelie Delaunay rtc->pclk = devm_clk_get(&pdev->dev, "pclk"); 7409a6757eaSAmelie Delaunay if (IS_ERR(rtc->pclk)) { 7419a6757eaSAmelie Delaunay dev_err(&pdev->dev, "no pclk clock"); 7429a6757eaSAmelie Delaunay return PTR_ERR(rtc->pclk); 7439a6757eaSAmelie Delaunay } 7449a6757eaSAmelie Delaunay rtc->rtc_ck = devm_clk_get(&pdev->dev, "rtc_ck"); 7459a6757eaSAmelie Delaunay } 7469a6757eaSAmelie Delaunay if (IS_ERR(rtc->rtc_ck)) { 7479a6757eaSAmelie Delaunay dev_err(&pdev->dev, "no rtc_ck clock"); 7489a6757eaSAmelie Delaunay return PTR_ERR(rtc->rtc_ck); 7494e64350fSAmelie Delaunay } 7504e64350fSAmelie Delaunay 7519a6757eaSAmelie Delaunay if (rtc->data->has_pclk) { 7529a6757eaSAmelie Delaunay ret = clk_prepare_enable(rtc->pclk); 7534e64350fSAmelie Delaunay if (ret) 7544e64350fSAmelie Delaunay return ret; 7559a6757eaSAmelie Delaunay } 7569a6757eaSAmelie Delaunay 7579a6757eaSAmelie Delaunay ret = clk_prepare_enable(rtc->rtc_ck); 7589a6757eaSAmelie Delaunay if (ret) 7599a6757eaSAmelie Delaunay goto err; 7604e64350fSAmelie Delaunay 76122cb47c1SAmelie Delaunay if (rtc->data->need_dbp) 76222cb47c1SAmelie Delaunay regmap_update_bits(rtc->dbp, rtc->dbp_reg, 76322cb47c1SAmelie Delaunay rtc->dbp_mask, rtc->dbp_mask); 7644e64350fSAmelie Delaunay 7654e64350fSAmelie Delaunay /* 7664e64350fSAmelie Delaunay * After a system reset, RTC_ISR.INITS flag can be read to check if 767819cbde5SAmelie Delaunay * the calendar has been initialized or not. INITS flag is reset by a 7684e64350fSAmelie Delaunay * power-on reset (no vbat, no power-supply). It is not reset if 7699a6757eaSAmelie Delaunay * rtc_ck parent clock has changed (so RTC prescalers need to be 7704e64350fSAmelie Delaunay * changed). That's why we cannot rely on this flag to know if RTC 7714e64350fSAmelie Delaunay * init has to be done. 7724e64350fSAmelie Delaunay */ 7734e64350fSAmelie Delaunay ret = stm32_rtc_init(pdev, rtc); 7744e64350fSAmelie Delaunay if (ret) 7754e64350fSAmelie Delaunay goto err; 7764e64350fSAmelie Delaunay 7774e64350fSAmelie Delaunay rtc->irq_alarm = platform_get_irq(pdev, 0); 7784e64350fSAmelie Delaunay if (rtc->irq_alarm <= 0) { 7794e64350fSAmelie Delaunay dev_err(&pdev->dev, "no alarm irq\n"); 7804e64350fSAmelie Delaunay ret = rtc->irq_alarm; 7814e64350fSAmelie Delaunay goto err; 7824e64350fSAmelie Delaunay } 7834e64350fSAmelie Delaunay 7844e64350fSAmelie Delaunay ret = device_init_wakeup(&pdev->dev, true); 785b72252b6SAmelie Delaunay if (rtc->data->has_wakeirq) { 786b72252b6SAmelie Delaunay rtc->wakeirq_alarm = platform_get_irq(pdev, 1); 787cf612c59SFabien Dessenne if (rtc->wakeirq_alarm > 0) { 788b72252b6SAmelie Delaunay ret = dev_pm_set_dedicated_wake_irq(&pdev->dev, 789b72252b6SAmelie Delaunay rtc->wakeirq_alarm); 790cf612c59SFabien Dessenne } else { 791cf612c59SFabien Dessenne ret = rtc->wakeirq_alarm; 792cf612c59SFabien Dessenne if (rtc->wakeirq_alarm == -EPROBE_DEFER) 793cf612c59SFabien Dessenne goto err; 794cf612c59SFabien Dessenne } 795b72252b6SAmelie Delaunay } 7964e64350fSAmelie Delaunay if (ret) 797b72252b6SAmelie Delaunay dev_warn(&pdev->dev, "alarm can't wake up the system: %d", ret); 798b72252b6SAmelie Delaunay 799b72252b6SAmelie Delaunay platform_set_drvdata(pdev, rtc); 8004e64350fSAmelie Delaunay 8014e64350fSAmelie Delaunay rtc->rtc_dev = devm_rtc_device_register(&pdev->dev, pdev->name, 8024e64350fSAmelie Delaunay &stm32_rtc_ops, THIS_MODULE); 8034e64350fSAmelie Delaunay if (IS_ERR(rtc->rtc_dev)) { 8044e64350fSAmelie Delaunay ret = PTR_ERR(rtc->rtc_dev); 8054e64350fSAmelie Delaunay dev_err(&pdev->dev, "rtc device registration failed, err=%d\n", 8064e64350fSAmelie Delaunay ret); 8074e64350fSAmelie Delaunay goto err; 8084e64350fSAmelie Delaunay } 8094e64350fSAmelie Delaunay 8104e64350fSAmelie Delaunay /* Handle RTC alarm interrupts */ 8114e64350fSAmelie Delaunay ret = devm_request_threaded_irq(&pdev->dev, rtc->irq_alarm, NULL, 812d213217dSAmelie Delaunay stm32_rtc_alarm_irq, IRQF_ONESHOT, 8134e64350fSAmelie Delaunay pdev->name, rtc); 8144e64350fSAmelie Delaunay if (ret) { 8154e64350fSAmelie Delaunay dev_err(&pdev->dev, "IRQ%d (alarm interrupt) already claimed\n", 8164e64350fSAmelie Delaunay rtc->irq_alarm); 8174e64350fSAmelie Delaunay goto err; 8184e64350fSAmelie Delaunay } 8194e64350fSAmelie Delaunay 8204e64350fSAmelie Delaunay /* 8214e64350fSAmelie Delaunay * If INITS flag is reset (calendar year field set to 0x00), calendar 8224e64350fSAmelie Delaunay * must be initialized 8234e64350fSAmelie Delaunay */ 82402b0cc34SAmelie Delaunay if (!(readl_relaxed(rtc->base + regs->isr) & STM32_RTC_ISR_INITS)) 8254e64350fSAmelie Delaunay dev_warn(&pdev->dev, "Date/Time must be initialized\n"); 8264e64350fSAmelie Delaunay 827b72252b6SAmelie Delaunay if (regs->verr != UNDEF_REG) { 828b72252b6SAmelie Delaunay u32 ver = readl_relaxed(rtc->base + regs->verr); 829b72252b6SAmelie Delaunay 830b72252b6SAmelie Delaunay dev_info(&pdev->dev, "registered rev:%d.%d\n", 831b72252b6SAmelie Delaunay (ver >> STM32_RTC_VERR_MAJREV_SHIFT) & 0xF, 832b72252b6SAmelie Delaunay (ver >> STM32_RTC_VERR_MINREV_SHIFT) & 0xF); 833b72252b6SAmelie Delaunay } 834b72252b6SAmelie Delaunay 8354e64350fSAmelie Delaunay return 0; 8364e64350fSAmelie Delaunay err: 8379a6757eaSAmelie Delaunay if (rtc->data->has_pclk) 8389a6757eaSAmelie Delaunay clk_disable_unprepare(rtc->pclk); 8399a6757eaSAmelie Delaunay clk_disable_unprepare(rtc->rtc_ck); 8404e64350fSAmelie Delaunay 84122cb47c1SAmelie Delaunay if (rtc->data->need_dbp) 84222cb47c1SAmelie Delaunay regmap_update_bits(rtc->dbp, rtc->dbp_reg, rtc->dbp_mask, 0); 8434e64350fSAmelie Delaunay 844b72252b6SAmelie Delaunay dev_pm_clear_wake_irq(&pdev->dev); 8454e64350fSAmelie Delaunay device_init_wakeup(&pdev->dev, false); 8464e64350fSAmelie Delaunay 8474e64350fSAmelie Delaunay return ret; 8484e64350fSAmelie Delaunay } 8494e64350fSAmelie Delaunay 8500404abb2SArnd Bergmann static int stm32_rtc_remove(struct platform_device *pdev) 8514e64350fSAmelie Delaunay { 8524e64350fSAmelie Delaunay struct stm32_rtc *rtc = platform_get_drvdata(pdev); 85302b0cc34SAmelie Delaunay const struct stm32_rtc_registers *regs = &rtc->data->regs; 8544e64350fSAmelie Delaunay unsigned int cr; 8554e64350fSAmelie Delaunay 8564e64350fSAmelie Delaunay /* Disable interrupts */ 8574e64350fSAmelie Delaunay stm32_rtc_wpr_unlock(rtc); 85802b0cc34SAmelie Delaunay cr = readl_relaxed(rtc->base + regs->cr); 8594e64350fSAmelie Delaunay cr &= ~STM32_RTC_CR_ALRAIE; 86002b0cc34SAmelie Delaunay writel_relaxed(cr, rtc->base + regs->cr); 8614e64350fSAmelie Delaunay stm32_rtc_wpr_lock(rtc); 8624e64350fSAmelie Delaunay 8639a6757eaSAmelie Delaunay clk_disable_unprepare(rtc->rtc_ck); 8649a6757eaSAmelie Delaunay if (rtc->data->has_pclk) 8659a6757eaSAmelie Delaunay clk_disable_unprepare(rtc->pclk); 8664e64350fSAmelie Delaunay 86722cb47c1SAmelie Delaunay /* Enable backup domain write protection if needed */ 86822cb47c1SAmelie Delaunay if (rtc->data->need_dbp) 86922cb47c1SAmelie Delaunay regmap_update_bits(rtc->dbp, rtc->dbp_reg, rtc->dbp_mask, 0); 8704e64350fSAmelie Delaunay 871b72252b6SAmelie Delaunay dev_pm_clear_wake_irq(&pdev->dev); 8724e64350fSAmelie Delaunay device_init_wakeup(&pdev->dev, false); 8734e64350fSAmelie Delaunay 8744e64350fSAmelie Delaunay return 0; 8754e64350fSAmelie Delaunay } 8764e64350fSAmelie Delaunay 8774e64350fSAmelie Delaunay #ifdef CONFIG_PM_SLEEP 8784e64350fSAmelie Delaunay static int stm32_rtc_suspend(struct device *dev) 8794e64350fSAmelie Delaunay { 8804e64350fSAmelie Delaunay struct stm32_rtc *rtc = dev_get_drvdata(dev); 8814e64350fSAmelie Delaunay 8829a6757eaSAmelie Delaunay if (rtc->data->has_pclk) 8839a6757eaSAmelie Delaunay clk_disable_unprepare(rtc->pclk); 8849a6757eaSAmelie Delaunay 8854e64350fSAmelie Delaunay if (device_may_wakeup(dev)) 8864e64350fSAmelie Delaunay return enable_irq_wake(rtc->irq_alarm); 8874e64350fSAmelie Delaunay 8884e64350fSAmelie Delaunay return 0; 8894e64350fSAmelie Delaunay } 8904e64350fSAmelie Delaunay 8914e64350fSAmelie Delaunay static int stm32_rtc_resume(struct device *dev) 8924e64350fSAmelie Delaunay { 8934e64350fSAmelie Delaunay struct stm32_rtc *rtc = dev_get_drvdata(dev); 8944e64350fSAmelie Delaunay int ret = 0; 8954e64350fSAmelie Delaunay 8969a6757eaSAmelie Delaunay if (rtc->data->has_pclk) { 8979a6757eaSAmelie Delaunay ret = clk_prepare_enable(rtc->pclk); 8989a6757eaSAmelie Delaunay if (ret) 8999a6757eaSAmelie Delaunay return ret; 9009a6757eaSAmelie Delaunay } 9019a6757eaSAmelie Delaunay 9024e64350fSAmelie Delaunay ret = stm32_rtc_wait_sync(rtc); 9034e64350fSAmelie Delaunay if (ret < 0) 9044e64350fSAmelie Delaunay return ret; 9054e64350fSAmelie Delaunay 9064e64350fSAmelie Delaunay if (device_may_wakeup(dev)) 9074e64350fSAmelie Delaunay return disable_irq_wake(rtc->irq_alarm); 9084e64350fSAmelie Delaunay 9094e64350fSAmelie Delaunay return ret; 9104e64350fSAmelie Delaunay } 9114e64350fSAmelie Delaunay #endif 9124e64350fSAmelie Delaunay 9134e64350fSAmelie Delaunay static SIMPLE_DEV_PM_OPS(stm32_rtc_pm_ops, 9144e64350fSAmelie Delaunay stm32_rtc_suspend, stm32_rtc_resume); 9154e64350fSAmelie Delaunay 9164e64350fSAmelie Delaunay static struct platform_driver stm32_rtc_driver = { 9174e64350fSAmelie Delaunay .probe = stm32_rtc_probe, 9184e64350fSAmelie Delaunay .remove = stm32_rtc_remove, 9194e64350fSAmelie Delaunay .driver = { 9204e64350fSAmelie Delaunay .name = DRIVER_NAME, 9214e64350fSAmelie Delaunay .pm = &stm32_rtc_pm_ops, 9224e64350fSAmelie Delaunay .of_match_table = stm32_rtc_of_match, 9234e64350fSAmelie Delaunay }, 9244e64350fSAmelie Delaunay }; 9254e64350fSAmelie Delaunay 9264e64350fSAmelie Delaunay module_platform_driver(stm32_rtc_driver); 9274e64350fSAmelie Delaunay 9284e64350fSAmelie Delaunay MODULE_ALIAS("platform:" DRIVER_NAME); 9294e64350fSAmelie Delaunay MODULE_AUTHOR("Amelie Delaunay <amelie.delaunay@st.com>"); 9304e64350fSAmelie Delaunay MODULE_DESCRIPTION("STMicroelectronics STM32 Real Time Clock driver"); 9314e64350fSAmelie Delaunay MODULE_LICENSE("GPL v2"); 932