xref: /openbmc/linux/drivers/rtc/rtc-stm32.c (revision 1d70ba3b)
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 {
3861d70ba3bSAmelie Delaunay 	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 
5121d70ba3bSAmelie Delaunay 	for (pred_a = pred_a_max; pred_a + 1 > 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",
5281d70ba3bSAmelie Delaunay 			 (rate < ((pred_a + 1) * (pred_s + 1))) ?
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