xref: /openbmc/linux/drivers/rtc/rtc-stm32.c (revision 2cf2a1ac)
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>
995f7679cSValentin Caron #include <linux/errno.h>
104e64350fSAmelie Delaunay #include <linux/iopoll.h>
114e64350fSAmelie Delaunay #include <linux/ioport.h>
124e64350fSAmelie Delaunay #include <linux/mfd/syscon.h>
134e64350fSAmelie Delaunay #include <linux/module.h>
1448144c28SRob Herring #include <linux/of.h>
1548144c28SRob Herring #include <linux/platform_device.h>
16b72252b6SAmelie Delaunay #include <linux/pm_wakeirq.h>
174e64350fSAmelie Delaunay #include <linux/regmap.h>
184e64350fSAmelie Delaunay #include <linux/rtc.h>
194e64350fSAmelie Delaunay 
204e64350fSAmelie Delaunay #define DRIVER_NAME "stm32_rtc"
214e64350fSAmelie Delaunay 
224e64350fSAmelie Delaunay /* STM32_RTC_TR bit fields  */
234e64350fSAmelie Delaunay #define STM32_RTC_TR_SEC_SHIFT		0
244e64350fSAmelie Delaunay #define STM32_RTC_TR_SEC		GENMASK(6, 0)
254e64350fSAmelie Delaunay #define STM32_RTC_TR_MIN_SHIFT		8
264e64350fSAmelie Delaunay #define STM32_RTC_TR_MIN		GENMASK(14, 8)
274e64350fSAmelie Delaunay #define STM32_RTC_TR_HOUR_SHIFT		16
284e64350fSAmelie Delaunay #define STM32_RTC_TR_HOUR		GENMASK(21, 16)
294e64350fSAmelie Delaunay 
304e64350fSAmelie Delaunay /* STM32_RTC_DR bit fields */
314e64350fSAmelie Delaunay #define STM32_RTC_DR_DATE_SHIFT		0
324e64350fSAmelie Delaunay #define STM32_RTC_DR_DATE		GENMASK(5, 0)
334e64350fSAmelie Delaunay #define STM32_RTC_DR_MONTH_SHIFT	8
344e64350fSAmelie Delaunay #define STM32_RTC_DR_MONTH		GENMASK(12, 8)
354e64350fSAmelie Delaunay #define STM32_RTC_DR_WDAY_SHIFT		13
364e64350fSAmelie Delaunay #define STM32_RTC_DR_WDAY		GENMASK(15, 13)
374e64350fSAmelie Delaunay #define STM32_RTC_DR_YEAR_SHIFT		16
384e64350fSAmelie Delaunay #define STM32_RTC_DR_YEAR		GENMASK(23, 16)
394e64350fSAmelie Delaunay 
404e64350fSAmelie Delaunay /* STM32_RTC_CR bit fields */
414e64350fSAmelie Delaunay #define STM32_RTC_CR_FMT		BIT(6)
424e64350fSAmelie Delaunay #define STM32_RTC_CR_ALRAE		BIT(8)
434e64350fSAmelie Delaunay #define STM32_RTC_CR_ALRAIE		BIT(12)
444e64350fSAmelie Delaunay 
45b72252b6SAmelie Delaunay /* STM32_RTC_ISR/STM32_RTC_ICSR bit fields */
464e64350fSAmelie Delaunay #define STM32_RTC_ISR_ALRAWF		BIT(0)
474e64350fSAmelie Delaunay #define STM32_RTC_ISR_INITS		BIT(4)
484e64350fSAmelie Delaunay #define STM32_RTC_ISR_RSF		BIT(5)
494e64350fSAmelie Delaunay #define STM32_RTC_ISR_INITF		BIT(6)
504e64350fSAmelie Delaunay #define STM32_RTC_ISR_INIT		BIT(7)
514e64350fSAmelie Delaunay #define STM32_RTC_ISR_ALRAF		BIT(8)
524e64350fSAmelie Delaunay 
534e64350fSAmelie Delaunay /* STM32_RTC_PRER bit fields */
544e64350fSAmelie Delaunay #define STM32_RTC_PRER_PRED_S_SHIFT	0
554e64350fSAmelie Delaunay #define STM32_RTC_PRER_PRED_S		GENMASK(14, 0)
564e64350fSAmelie Delaunay #define STM32_RTC_PRER_PRED_A_SHIFT	16
574e64350fSAmelie Delaunay #define STM32_RTC_PRER_PRED_A		GENMASK(22, 16)
584e64350fSAmelie Delaunay 
594e64350fSAmelie Delaunay /* STM32_RTC_ALRMAR and STM32_RTC_ALRMBR bit fields */
604e64350fSAmelie Delaunay #define STM32_RTC_ALRMXR_SEC_SHIFT	0
614e64350fSAmelie Delaunay #define STM32_RTC_ALRMXR_SEC		GENMASK(6, 0)
624e64350fSAmelie Delaunay #define STM32_RTC_ALRMXR_SEC_MASK	BIT(7)
634e64350fSAmelie Delaunay #define STM32_RTC_ALRMXR_MIN_SHIFT	8
644e64350fSAmelie Delaunay #define STM32_RTC_ALRMXR_MIN		GENMASK(14, 8)
654e64350fSAmelie Delaunay #define STM32_RTC_ALRMXR_MIN_MASK	BIT(15)
664e64350fSAmelie Delaunay #define STM32_RTC_ALRMXR_HOUR_SHIFT	16
674e64350fSAmelie Delaunay #define STM32_RTC_ALRMXR_HOUR		GENMASK(21, 16)
684e64350fSAmelie Delaunay #define STM32_RTC_ALRMXR_PM		BIT(22)
694e64350fSAmelie Delaunay #define STM32_RTC_ALRMXR_HOUR_MASK	BIT(23)
704e64350fSAmelie Delaunay #define STM32_RTC_ALRMXR_DATE_SHIFT	24
714e64350fSAmelie Delaunay #define STM32_RTC_ALRMXR_DATE		GENMASK(29, 24)
724e64350fSAmelie Delaunay #define STM32_RTC_ALRMXR_WDSEL		BIT(30)
734e64350fSAmelie Delaunay #define STM32_RTC_ALRMXR_WDAY_SHIFT	24
744e64350fSAmelie Delaunay #define STM32_RTC_ALRMXR_WDAY		GENMASK(27, 24)
754e64350fSAmelie Delaunay #define STM32_RTC_ALRMXR_DATE_MASK	BIT(31)
764e64350fSAmelie Delaunay 
77b72252b6SAmelie Delaunay /* STM32_RTC_SR/_SCR bit fields */
78b72252b6SAmelie Delaunay #define STM32_RTC_SR_ALRA		BIT(0)
79b72252b6SAmelie Delaunay 
80b72252b6SAmelie Delaunay /* STM32_RTC_VERR bit fields */
81b72252b6SAmelie Delaunay #define STM32_RTC_VERR_MINREV_SHIFT	0
82b72252b6SAmelie Delaunay #define STM32_RTC_VERR_MINREV		GENMASK(3, 0)
83b72252b6SAmelie Delaunay #define STM32_RTC_VERR_MAJREV_SHIFT	4
84b72252b6SAmelie Delaunay #define STM32_RTC_VERR_MAJREV		GENMASK(7, 4)
85b72252b6SAmelie Delaunay 
864e64350fSAmelie Delaunay /* STM32_RTC_WPR key constants */
874e64350fSAmelie Delaunay #define RTC_WPR_1ST_KEY			0xCA
884e64350fSAmelie Delaunay #define RTC_WPR_2ND_KEY			0x53
894e64350fSAmelie Delaunay #define RTC_WPR_WRONG_KEY		0xFF
904e64350fSAmelie Delaunay 
91b72252b6SAmelie Delaunay /* Max STM32 RTC register offset is 0x3FC */
92b72252b6SAmelie Delaunay #define UNDEF_REG			0xFFFF
93b72252b6SAmelie Delaunay 
9446828a5fSValentin Caron /* STM32 RTC driver time helpers */
9546828a5fSValentin Caron #define SEC_PER_DAY		(24 * 60 * 60)
9646828a5fSValentin Caron 
9702b0cc34SAmelie Delaunay struct stm32_rtc;
9802b0cc34SAmelie Delaunay 
9902b0cc34SAmelie Delaunay struct stm32_rtc_registers {
100b72252b6SAmelie Delaunay 	u16 tr;
101b72252b6SAmelie Delaunay 	u16 dr;
102b72252b6SAmelie Delaunay 	u16 cr;
103b72252b6SAmelie Delaunay 	u16 isr;
104b72252b6SAmelie Delaunay 	u16 prer;
105b72252b6SAmelie Delaunay 	u16 alrmar;
106b72252b6SAmelie Delaunay 	u16 wpr;
107b72252b6SAmelie Delaunay 	u16 sr;
108b72252b6SAmelie Delaunay 	u16 scr;
109b72252b6SAmelie Delaunay 	u16 verr;
11002b0cc34SAmelie Delaunay };
11102b0cc34SAmelie Delaunay 
11202b0cc34SAmelie Delaunay struct stm32_rtc_events {
11302b0cc34SAmelie Delaunay 	u32 alra;
11402b0cc34SAmelie Delaunay };
11502b0cc34SAmelie Delaunay 
1169a6757eaSAmelie Delaunay struct stm32_rtc_data {
11702b0cc34SAmelie Delaunay 	const struct stm32_rtc_registers regs;
11802b0cc34SAmelie Delaunay 	const struct stm32_rtc_events events;
11902b0cc34SAmelie Delaunay 	void (*clear_events)(struct stm32_rtc *rtc, unsigned int flags);
1209a6757eaSAmelie Delaunay 	bool has_pclk;
12122cb47c1SAmelie Delaunay 	bool need_dbp;
12224879257SChristophe Guibout 	bool need_accuracy;
1239a6757eaSAmelie Delaunay };
1249a6757eaSAmelie Delaunay 
1254e64350fSAmelie Delaunay struct stm32_rtc {
1264e64350fSAmelie Delaunay 	struct rtc_device *rtc_dev;
1274e64350fSAmelie Delaunay 	void __iomem *base;
1284e64350fSAmelie Delaunay 	struct regmap *dbp;
12922cb47c1SAmelie Delaunay 	unsigned int dbp_reg;
13022cb47c1SAmelie Delaunay 	unsigned int dbp_mask;
1319a6757eaSAmelie Delaunay 	struct clk *pclk;
1329a6757eaSAmelie Delaunay 	struct clk *rtc_ck;
13302b0cc34SAmelie Delaunay 	const struct stm32_rtc_data *data;
1344e64350fSAmelie Delaunay 	int irq_alarm;
1354e64350fSAmelie Delaunay };
1364e64350fSAmelie Delaunay 
stm32_rtc_wpr_unlock(struct stm32_rtc * rtc)1374e64350fSAmelie Delaunay static void stm32_rtc_wpr_unlock(struct stm32_rtc *rtc)
1384e64350fSAmelie Delaunay {
13902b0cc34SAmelie Delaunay 	const struct stm32_rtc_registers *regs = &rtc->data->regs;
14002b0cc34SAmelie Delaunay 
14102b0cc34SAmelie Delaunay 	writel_relaxed(RTC_WPR_1ST_KEY, rtc->base + regs->wpr);
14202b0cc34SAmelie Delaunay 	writel_relaxed(RTC_WPR_2ND_KEY, rtc->base + regs->wpr);
1434e64350fSAmelie Delaunay }
1444e64350fSAmelie Delaunay 
stm32_rtc_wpr_lock(struct stm32_rtc * rtc)1454e64350fSAmelie Delaunay static void stm32_rtc_wpr_lock(struct stm32_rtc *rtc)
1464e64350fSAmelie Delaunay {
14702b0cc34SAmelie Delaunay 	const struct stm32_rtc_registers *regs = &rtc->data->regs;
14802b0cc34SAmelie Delaunay 
14902b0cc34SAmelie Delaunay 	writel_relaxed(RTC_WPR_WRONG_KEY, rtc->base + regs->wpr);
1504e64350fSAmelie Delaunay }
1514e64350fSAmelie Delaunay 
stm32_rtc_enter_init_mode(struct stm32_rtc * rtc)1524e64350fSAmelie Delaunay static int stm32_rtc_enter_init_mode(struct stm32_rtc *rtc)
1534e64350fSAmelie Delaunay {
15402b0cc34SAmelie Delaunay 	const struct stm32_rtc_registers *regs = &rtc->data->regs;
15502b0cc34SAmelie Delaunay 	unsigned int isr = readl_relaxed(rtc->base + regs->isr);
1564e64350fSAmelie Delaunay 
1574e64350fSAmelie Delaunay 	if (!(isr & STM32_RTC_ISR_INITF)) {
1584e64350fSAmelie Delaunay 		isr |= STM32_RTC_ISR_INIT;
15902b0cc34SAmelie Delaunay 		writel_relaxed(isr, rtc->base + regs->isr);
1604e64350fSAmelie Delaunay 
1614e64350fSAmelie Delaunay 		/*
1629a6757eaSAmelie Delaunay 		 * It takes around 2 rtc_ck clock cycles to enter in
1634e64350fSAmelie Delaunay 		 * initialization phase mode (and have INITF flag set). As
1649a6757eaSAmelie Delaunay 		 * slowest rtc_ck frequency may be 32kHz and highest should be
1654e64350fSAmelie Delaunay 		 * 1MHz, we poll every 10 us with a timeout of 100ms.
1664e64350fSAmelie Delaunay 		 */
167650915ecSValentin Caron 		return readl_relaxed_poll_timeout_atomic(rtc->base + regs->isr, isr,
168650915ecSValentin Caron 							 (isr & STM32_RTC_ISR_INITF),
1694e64350fSAmelie Delaunay 							 10, 100000);
1704e64350fSAmelie Delaunay 	}
1714e64350fSAmelie Delaunay 
1724e64350fSAmelie Delaunay 	return 0;
1734e64350fSAmelie Delaunay }
1744e64350fSAmelie Delaunay 
stm32_rtc_exit_init_mode(struct stm32_rtc * rtc)1754e64350fSAmelie Delaunay static void stm32_rtc_exit_init_mode(struct stm32_rtc *rtc)
1764e64350fSAmelie Delaunay {
17702b0cc34SAmelie Delaunay 	const struct stm32_rtc_registers *regs = &rtc->data->regs;
17802b0cc34SAmelie Delaunay 	unsigned int isr = readl_relaxed(rtc->base + regs->isr);
1794e64350fSAmelie Delaunay 
1804e64350fSAmelie Delaunay 	isr &= ~STM32_RTC_ISR_INIT;
18102b0cc34SAmelie Delaunay 	writel_relaxed(isr, rtc->base + regs->isr);
1824e64350fSAmelie Delaunay }
1834e64350fSAmelie Delaunay 
stm32_rtc_wait_sync(struct stm32_rtc * rtc)1844e64350fSAmelie Delaunay static int stm32_rtc_wait_sync(struct stm32_rtc *rtc)
1854e64350fSAmelie Delaunay {
18602b0cc34SAmelie Delaunay 	const struct stm32_rtc_registers *regs = &rtc->data->regs;
18702b0cc34SAmelie Delaunay 	unsigned int isr = readl_relaxed(rtc->base + regs->isr);
1884e64350fSAmelie Delaunay 
1894e64350fSAmelie Delaunay 	isr &= ~STM32_RTC_ISR_RSF;
19002b0cc34SAmelie Delaunay 	writel_relaxed(isr, rtc->base + regs->isr);
1914e64350fSAmelie Delaunay 
1924e64350fSAmelie Delaunay 	/*
1934e64350fSAmelie Delaunay 	 * Wait for RSF to be set to ensure the calendar registers are
1949a6757eaSAmelie Delaunay 	 * synchronised, it takes around 2 rtc_ck clock cycles
1954e64350fSAmelie Delaunay 	 */
19602b0cc34SAmelie Delaunay 	return readl_relaxed_poll_timeout_atomic(rtc->base + regs->isr,
1974e64350fSAmelie Delaunay 						 isr,
1984e64350fSAmelie Delaunay 						 (isr & STM32_RTC_ISR_RSF),
1994e64350fSAmelie Delaunay 						 10, 100000);
2004e64350fSAmelie Delaunay }
2014e64350fSAmelie Delaunay 
stm32_rtc_clear_event_flags(struct stm32_rtc * rtc,unsigned int flags)20202b0cc34SAmelie Delaunay static void stm32_rtc_clear_event_flags(struct stm32_rtc *rtc,
20302b0cc34SAmelie Delaunay 					unsigned int flags)
20402b0cc34SAmelie Delaunay {
20502b0cc34SAmelie Delaunay 	rtc->data->clear_events(rtc, flags);
20602b0cc34SAmelie Delaunay }
20702b0cc34SAmelie Delaunay 
stm32_rtc_alarm_irq(int irq,void * dev_id)2084e64350fSAmelie Delaunay static irqreturn_t stm32_rtc_alarm_irq(int irq, void *dev_id)
2094e64350fSAmelie Delaunay {
2104e64350fSAmelie Delaunay 	struct stm32_rtc *rtc = (struct stm32_rtc *)dev_id;
21102b0cc34SAmelie Delaunay 	const struct stm32_rtc_registers *regs = &rtc->data->regs;
21202b0cc34SAmelie Delaunay 	const struct stm32_rtc_events *evts = &rtc->data->events;
21302b0cc34SAmelie Delaunay 	unsigned int status, cr;
2144e64350fSAmelie Delaunay 
215f66e7f2dSAlexandre Belloni 	rtc_lock(rtc->rtc_dev);
2164e64350fSAmelie Delaunay 
217b72252b6SAmelie Delaunay 	status = readl_relaxed(rtc->base + regs->sr);
21802b0cc34SAmelie Delaunay 	cr = readl_relaxed(rtc->base + regs->cr);
2194e64350fSAmelie Delaunay 
22002b0cc34SAmelie Delaunay 	if ((status & evts->alra) &&
2214e64350fSAmelie Delaunay 	    (cr & STM32_RTC_CR_ALRAIE)) {
2224e64350fSAmelie Delaunay 		/* Alarm A flag - Alarm interrupt */
2234e64350fSAmelie Delaunay 		dev_dbg(&rtc->rtc_dev->dev, "Alarm occurred\n");
2244e64350fSAmelie Delaunay 
2254e64350fSAmelie Delaunay 		/* Pass event to the kernel */
2264e64350fSAmelie Delaunay 		rtc_update_irq(rtc->rtc_dev, 1, RTC_IRQF | RTC_AF);
2274e64350fSAmelie Delaunay 
22802b0cc34SAmelie Delaunay 		/* Clear event flags, otherwise new events won't be received */
22902b0cc34SAmelie Delaunay 		stm32_rtc_clear_event_flags(rtc, evts->alra);
2304e64350fSAmelie Delaunay 	}
2314e64350fSAmelie Delaunay 
232f66e7f2dSAlexandre Belloni 	rtc_unlock(rtc->rtc_dev);
2334e64350fSAmelie Delaunay 
2344e64350fSAmelie Delaunay 	return IRQ_HANDLED;
2354e64350fSAmelie Delaunay }
2364e64350fSAmelie Delaunay 
2374e64350fSAmelie Delaunay /* Convert rtc_time structure from bin to bcd format */
tm2bcd(struct rtc_time * tm)2384e64350fSAmelie Delaunay static void tm2bcd(struct rtc_time *tm)
2394e64350fSAmelie Delaunay {
2404e64350fSAmelie Delaunay 	tm->tm_sec = bin2bcd(tm->tm_sec);
2414e64350fSAmelie Delaunay 	tm->tm_min = bin2bcd(tm->tm_min);
2424e64350fSAmelie Delaunay 	tm->tm_hour = bin2bcd(tm->tm_hour);
2434e64350fSAmelie Delaunay 
2444e64350fSAmelie Delaunay 	tm->tm_mday = bin2bcd(tm->tm_mday);
2454e64350fSAmelie Delaunay 	tm->tm_mon = bin2bcd(tm->tm_mon + 1);
2464e64350fSAmelie Delaunay 	tm->tm_year = bin2bcd(tm->tm_year - 100);
2474e64350fSAmelie Delaunay 	/*
2484e64350fSAmelie Delaunay 	 * Number of days since Sunday
2494e64350fSAmelie Delaunay 	 * - on kernel side, 0=Sunday...6=Saturday
2504e64350fSAmelie Delaunay 	 * - on rtc side, 0=invalid,1=Monday...7=Sunday
2514e64350fSAmelie Delaunay 	 */
2524e64350fSAmelie Delaunay 	tm->tm_wday = (!tm->tm_wday) ? 7 : tm->tm_wday;
2534e64350fSAmelie Delaunay }
2544e64350fSAmelie Delaunay 
2554e64350fSAmelie Delaunay /* Convert rtc_time structure from bcd to bin format */
bcd2tm(struct rtc_time * tm)2564e64350fSAmelie Delaunay static void bcd2tm(struct rtc_time *tm)
2574e64350fSAmelie Delaunay {
2584e64350fSAmelie Delaunay 	tm->tm_sec = bcd2bin(tm->tm_sec);
2594e64350fSAmelie Delaunay 	tm->tm_min = bcd2bin(tm->tm_min);
2604e64350fSAmelie Delaunay 	tm->tm_hour = bcd2bin(tm->tm_hour);
2614e64350fSAmelie Delaunay 
2624e64350fSAmelie Delaunay 	tm->tm_mday = bcd2bin(tm->tm_mday);
2634e64350fSAmelie Delaunay 	tm->tm_mon = bcd2bin(tm->tm_mon) - 1;
2644e64350fSAmelie Delaunay 	tm->tm_year = bcd2bin(tm->tm_year) + 100;
2654e64350fSAmelie Delaunay 	/*
2664e64350fSAmelie Delaunay 	 * Number of days since Sunday
2674e64350fSAmelie Delaunay 	 * - on kernel side, 0=Sunday...6=Saturday
2684e64350fSAmelie Delaunay 	 * - on rtc side, 0=invalid,1=Monday...7=Sunday
2694e64350fSAmelie Delaunay 	 */
2704e64350fSAmelie Delaunay 	tm->tm_wday %= 7;
2714e64350fSAmelie Delaunay }
2724e64350fSAmelie Delaunay 
stm32_rtc_read_time(struct device * dev,struct rtc_time * tm)2734e64350fSAmelie Delaunay static int stm32_rtc_read_time(struct device *dev, struct rtc_time *tm)
2744e64350fSAmelie Delaunay {
2754e64350fSAmelie Delaunay 	struct stm32_rtc *rtc = dev_get_drvdata(dev);
27602b0cc34SAmelie Delaunay 	const struct stm32_rtc_registers *regs = &rtc->data->regs;
2774e64350fSAmelie Delaunay 	unsigned int tr, dr;
2784e64350fSAmelie Delaunay 
2794e64350fSAmelie Delaunay 	/* Time and Date in BCD format */
28002b0cc34SAmelie Delaunay 	tr = readl_relaxed(rtc->base + regs->tr);
28102b0cc34SAmelie Delaunay 	dr = readl_relaxed(rtc->base + regs->dr);
2824e64350fSAmelie Delaunay 
2834e64350fSAmelie Delaunay 	tm->tm_sec = (tr & STM32_RTC_TR_SEC) >> STM32_RTC_TR_SEC_SHIFT;
2844e64350fSAmelie Delaunay 	tm->tm_min = (tr & STM32_RTC_TR_MIN) >> STM32_RTC_TR_MIN_SHIFT;
2854e64350fSAmelie Delaunay 	tm->tm_hour = (tr & STM32_RTC_TR_HOUR) >> STM32_RTC_TR_HOUR_SHIFT;
2864e64350fSAmelie Delaunay 
2874e64350fSAmelie Delaunay 	tm->tm_mday = (dr & STM32_RTC_DR_DATE) >> STM32_RTC_DR_DATE_SHIFT;
2884e64350fSAmelie Delaunay 	tm->tm_mon = (dr & STM32_RTC_DR_MONTH) >> STM32_RTC_DR_MONTH_SHIFT;
2894e64350fSAmelie Delaunay 	tm->tm_year = (dr & STM32_RTC_DR_YEAR) >> STM32_RTC_DR_YEAR_SHIFT;
2904e64350fSAmelie Delaunay 	tm->tm_wday = (dr & STM32_RTC_DR_WDAY) >> STM32_RTC_DR_WDAY_SHIFT;
2914e64350fSAmelie Delaunay 
2924e64350fSAmelie Delaunay 	/* We don't report tm_yday and tm_isdst */
2934e64350fSAmelie Delaunay 
2944e64350fSAmelie Delaunay 	bcd2tm(tm);
2954e64350fSAmelie Delaunay 
2964e64350fSAmelie Delaunay 	return 0;
2974e64350fSAmelie Delaunay }
2984e64350fSAmelie Delaunay 
stm32_rtc_set_time(struct device * dev,struct rtc_time * tm)2994e64350fSAmelie Delaunay static int stm32_rtc_set_time(struct device *dev, struct rtc_time *tm)
3004e64350fSAmelie Delaunay {
3014e64350fSAmelie Delaunay 	struct stm32_rtc *rtc = dev_get_drvdata(dev);
30202b0cc34SAmelie Delaunay 	const struct stm32_rtc_registers *regs = &rtc->data->regs;
3034e64350fSAmelie Delaunay 	unsigned int tr, dr;
3044e64350fSAmelie Delaunay 	int ret = 0;
3054e64350fSAmelie Delaunay 
3064e64350fSAmelie Delaunay 	tm2bcd(tm);
3074e64350fSAmelie Delaunay 
3084e64350fSAmelie Delaunay 	/* Time in BCD format */
3094e64350fSAmelie Delaunay 	tr = ((tm->tm_sec << STM32_RTC_TR_SEC_SHIFT) & STM32_RTC_TR_SEC) |
3104e64350fSAmelie Delaunay 	     ((tm->tm_min << STM32_RTC_TR_MIN_SHIFT) & STM32_RTC_TR_MIN) |
3114e64350fSAmelie Delaunay 	     ((tm->tm_hour << STM32_RTC_TR_HOUR_SHIFT) & STM32_RTC_TR_HOUR);
3124e64350fSAmelie Delaunay 
3134e64350fSAmelie Delaunay 	/* Date in BCD format */
3144e64350fSAmelie Delaunay 	dr = ((tm->tm_mday << STM32_RTC_DR_DATE_SHIFT) & STM32_RTC_DR_DATE) |
3154e64350fSAmelie Delaunay 	     ((tm->tm_mon << STM32_RTC_DR_MONTH_SHIFT) & STM32_RTC_DR_MONTH) |
3164e64350fSAmelie Delaunay 	     ((tm->tm_year << STM32_RTC_DR_YEAR_SHIFT) & STM32_RTC_DR_YEAR) |
3174e64350fSAmelie Delaunay 	     ((tm->tm_wday << STM32_RTC_DR_WDAY_SHIFT) & STM32_RTC_DR_WDAY);
3184e64350fSAmelie Delaunay 
3194e64350fSAmelie Delaunay 	stm32_rtc_wpr_unlock(rtc);
3204e64350fSAmelie Delaunay 
3214e64350fSAmelie Delaunay 	ret = stm32_rtc_enter_init_mode(rtc);
3224e64350fSAmelie Delaunay 	if (ret) {
3234e64350fSAmelie Delaunay 		dev_err(dev, "Can't enter in init mode. Set time aborted.\n");
3244e64350fSAmelie Delaunay 		goto end;
3254e64350fSAmelie Delaunay 	}
3264e64350fSAmelie Delaunay 
32702b0cc34SAmelie Delaunay 	writel_relaxed(tr, rtc->base + regs->tr);
32802b0cc34SAmelie Delaunay 	writel_relaxed(dr, rtc->base + regs->dr);
3294e64350fSAmelie Delaunay 
3304e64350fSAmelie Delaunay 	stm32_rtc_exit_init_mode(rtc);
3314e64350fSAmelie Delaunay 
3324e64350fSAmelie Delaunay 	ret = stm32_rtc_wait_sync(rtc);
3334e64350fSAmelie Delaunay end:
3344e64350fSAmelie Delaunay 	stm32_rtc_wpr_lock(rtc);
3354e64350fSAmelie Delaunay 
3364e64350fSAmelie Delaunay 	return ret;
3374e64350fSAmelie Delaunay }
3384e64350fSAmelie Delaunay 
stm32_rtc_read_alarm(struct device * dev,struct rtc_wkalrm * alrm)3394e64350fSAmelie Delaunay static int stm32_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
3404e64350fSAmelie Delaunay {
3414e64350fSAmelie Delaunay 	struct stm32_rtc *rtc = dev_get_drvdata(dev);
34202b0cc34SAmelie Delaunay 	const struct stm32_rtc_registers *regs = &rtc->data->regs;
34302b0cc34SAmelie Delaunay 	const struct stm32_rtc_events *evts = &rtc->data->events;
3444e64350fSAmelie Delaunay 	struct rtc_time *tm = &alrm->time;
34502b0cc34SAmelie Delaunay 	unsigned int alrmar, cr, status;
3464e64350fSAmelie Delaunay 
34702b0cc34SAmelie Delaunay 	alrmar = readl_relaxed(rtc->base + regs->alrmar);
34802b0cc34SAmelie Delaunay 	cr = readl_relaxed(rtc->base + regs->cr);
349b72252b6SAmelie Delaunay 	status = readl_relaxed(rtc->base + regs->sr);
3504e64350fSAmelie Delaunay 
3514e64350fSAmelie Delaunay 	if (alrmar & STM32_RTC_ALRMXR_DATE_MASK) {
3524e64350fSAmelie Delaunay 		/*
3534e64350fSAmelie Delaunay 		 * Date/day doesn't matter in Alarm comparison so alarm
3544e64350fSAmelie Delaunay 		 * triggers every day
3554e64350fSAmelie Delaunay 		 */
3564e64350fSAmelie Delaunay 		tm->tm_mday = -1;
3574e64350fSAmelie Delaunay 		tm->tm_wday = -1;
3584e64350fSAmelie Delaunay 	} else {
3594e64350fSAmelie Delaunay 		if (alrmar & STM32_RTC_ALRMXR_WDSEL) {
3604e64350fSAmelie Delaunay 			/* Alarm is set to a day of week */
3614e64350fSAmelie Delaunay 			tm->tm_mday = -1;
3624e64350fSAmelie Delaunay 			tm->tm_wday = (alrmar & STM32_RTC_ALRMXR_WDAY) >>
3634e64350fSAmelie Delaunay 				      STM32_RTC_ALRMXR_WDAY_SHIFT;
3644e64350fSAmelie Delaunay 			tm->tm_wday %= 7;
3654e64350fSAmelie Delaunay 		} else {
3664e64350fSAmelie Delaunay 			/* Alarm is set to a day of month */
3674e64350fSAmelie Delaunay 			tm->tm_wday = -1;
3684e64350fSAmelie Delaunay 			tm->tm_mday = (alrmar & STM32_RTC_ALRMXR_DATE) >>
3694e64350fSAmelie Delaunay 				       STM32_RTC_ALRMXR_DATE_SHIFT;
3704e64350fSAmelie Delaunay 		}
3714e64350fSAmelie Delaunay 	}
3724e64350fSAmelie Delaunay 
3734e64350fSAmelie Delaunay 	if (alrmar & STM32_RTC_ALRMXR_HOUR_MASK) {
3744e64350fSAmelie Delaunay 		/* Hours don't matter in Alarm comparison */
3754e64350fSAmelie Delaunay 		tm->tm_hour = -1;
3764e64350fSAmelie Delaunay 	} else {
3774e64350fSAmelie Delaunay 		tm->tm_hour = (alrmar & STM32_RTC_ALRMXR_HOUR) >>
3784e64350fSAmelie Delaunay 			       STM32_RTC_ALRMXR_HOUR_SHIFT;
3794e64350fSAmelie Delaunay 		if (alrmar & STM32_RTC_ALRMXR_PM)
3804e64350fSAmelie Delaunay 			tm->tm_hour += 12;
3814e64350fSAmelie Delaunay 	}
3824e64350fSAmelie Delaunay 
3834e64350fSAmelie Delaunay 	if (alrmar & STM32_RTC_ALRMXR_MIN_MASK) {
3844e64350fSAmelie Delaunay 		/* Minutes don't matter in Alarm comparison */
3854e64350fSAmelie Delaunay 		tm->tm_min = -1;
3864e64350fSAmelie Delaunay 	} else {
3874e64350fSAmelie Delaunay 		tm->tm_min = (alrmar & STM32_RTC_ALRMXR_MIN) >>
3884e64350fSAmelie Delaunay 			      STM32_RTC_ALRMXR_MIN_SHIFT;
3894e64350fSAmelie Delaunay 	}
3904e64350fSAmelie Delaunay 
3914e64350fSAmelie Delaunay 	if (alrmar & STM32_RTC_ALRMXR_SEC_MASK) {
3924e64350fSAmelie Delaunay 		/* Seconds don't matter in Alarm comparison */
3934e64350fSAmelie Delaunay 		tm->tm_sec = -1;
3944e64350fSAmelie Delaunay 	} else {
3954e64350fSAmelie Delaunay 		tm->tm_sec = (alrmar & STM32_RTC_ALRMXR_SEC) >>
3964e64350fSAmelie Delaunay 			      STM32_RTC_ALRMXR_SEC_SHIFT;
3974e64350fSAmelie Delaunay 	}
3984e64350fSAmelie Delaunay 
3994e64350fSAmelie Delaunay 	bcd2tm(tm);
4004e64350fSAmelie Delaunay 
4014e64350fSAmelie Delaunay 	alrm->enabled = (cr & STM32_RTC_CR_ALRAE) ? 1 : 0;
40202b0cc34SAmelie Delaunay 	alrm->pending = (status & evts->alra) ? 1 : 0;
4034e64350fSAmelie Delaunay 
4044e64350fSAmelie Delaunay 	return 0;
4054e64350fSAmelie Delaunay }
4064e64350fSAmelie Delaunay 
stm32_rtc_alarm_irq_enable(struct device * dev,unsigned int enabled)4074e64350fSAmelie Delaunay static int stm32_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
4084e64350fSAmelie Delaunay {
4094e64350fSAmelie Delaunay 	struct stm32_rtc *rtc = dev_get_drvdata(dev);
41002b0cc34SAmelie Delaunay 	const struct stm32_rtc_registers *regs = &rtc->data->regs;
41102b0cc34SAmelie Delaunay 	const struct stm32_rtc_events *evts = &rtc->data->events;
41202b0cc34SAmelie Delaunay 	unsigned int cr;
4134e64350fSAmelie Delaunay 
41402b0cc34SAmelie Delaunay 	cr = readl_relaxed(rtc->base + regs->cr);
4154e64350fSAmelie Delaunay 
4164e64350fSAmelie Delaunay 	stm32_rtc_wpr_unlock(rtc);
4174e64350fSAmelie Delaunay 
4184e64350fSAmelie Delaunay 	/* We expose Alarm A to the kernel */
4194e64350fSAmelie Delaunay 	if (enabled)
4204e64350fSAmelie Delaunay 		cr |= (STM32_RTC_CR_ALRAIE | STM32_RTC_CR_ALRAE);
4214e64350fSAmelie Delaunay 	else
4224e64350fSAmelie Delaunay 		cr &= ~(STM32_RTC_CR_ALRAIE | STM32_RTC_CR_ALRAE);
42302b0cc34SAmelie Delaunay 	writel_relaxed(cr, rtc->base + regs->cr);
4244e64350fSAmelie Delaunay 
42502b0cc34SAmelie Delaunay 	/* Clear event flags, otherwise new events won't be received */
42602b0cc34SAmelie Delaunay 	stm32_rtc_clear_event_flags(rtc, evts->alra);
4274e64350fSAmelie Delaunay 
4284e64350fSAmelie Delaunay 	stm32_rtc_wpr_lock(rtc);
4294e64350fSAmelie Delaunay 
4304e64350fSAmelie Delaunay 	return 0;
4314e64350fSAmelie Delaunay }
4324e64350fSAmelie Delaunay 
stm32_rtc_valid_alrm(struct device * dev,struct rtc_time * tm)43346828a5fSValentin Caron static int stm32_rtc_valid_alrm(struct device *dev, struct rtc_time *tm)
4344e64350fSAmelie Delaunay {
43546828a5fSValentin Caron 	static struct rtc_time now;
43646828a5fSValentin Caron 	time64_t max_alarm_time64;
43746828a5fSValentin Caron 	int max_day_forward;
43846828a5fSValentin Caron 	int next_month;
43946828a5fSValentin Caron 	int next_year;
4404e64350fSAmelie Delaunay 
4414e64350fSAmelie Delaunay 	/*
4424e64350fSAmelie Delaunay 	 * Assuming current date is M-D-Y H:M:S.
4434e64350fSAmelie Delaunay 	 * RTC alarm can't be set on a specific month and year.
4444e64350fSAmelie Delaunay 	 * So the valid alarm range is:
4454e64350fSAmelie Delaunay 	 *	M-D-Y H:M:S < alarm <= (M+1)-D-Y H:M:S
4464e64350fSAmelie Delaunay 	 */
44746828a5fSValentin Caron 	stm32_rtc_read_time(dev, &now);
4484e64350fSAmelie Delaunay 
44946828a5fSValentin Caron 	/*
45046828a5fSValentin Caron 	 * Find the next month and the year of the next month.
45146828a5fSValentin Caron 	 * Note: tm_mon and next_month are from 0 to 11
45246828a5fSValentin Caron 	 */
45346828a5fSValentin Caron 	next_month = now.tm_mon + 1;
45446828a5fSValentin Caron 	if (next_month == 12) {
45546828a5fSValentin Caron 		next_month = 0;
45646828a5fSValentin Caron 		next_year = now.tm_year + 1;
45746828a5fSValentin Caron 	} else {
45846828a5fSValentin Caron 		next_year = now.tm_year;
45946828a5fSValentin Caron 	}
46046828a5fSValentin Caron 
46146828a5fSValentin Caron 	/* Find the maximum limit of alarm in days. */
46246828a5fSValentin Caron 	max_day_forward = rtc_month_days(now.tm_mon, now.tm_year)
46346828a5fSValentin Caron 			 - now.tm_mday
46446828a5fSValentin Caron 			 + min(rtc_month_days(next_month, next_year), now.tm_mday);
46546828a5fSValentin Caron 
46646828a5fSValentin Caron 	/* Convert to timestamp and compare the alarm time and its upper limit */
46746828a5fSValentin Caron 	max_alarm_time64 = rtc_tm_to_time64(&now) + max_day_forward * SEC_PER_DAY;
46846828a5fSValentin Caron 	return rtc_tm_to_time64(tm) <= max_alarm_time64 ? 0 : -EINVAL;
4694e64350fSAmelie Delaunay }
4704e64350fSAmelie Delaunay 
stm32_rtc_set_alarm(struct device * dev,struct rtc_wkalrm * alrm)4714e64350fSAmelie Delaunay static int stm32_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
4724e64350fSAmelie Delaunay {
4734e64350fSAmelie Delaunay 	struct stm32_rtc *rtc = dev_get_drvdata(dev);
47402b0cc34SAmelie Delaunay 	const struct stm32_rtc_registers *regs = &rtc->data->regs;
4754e64350fSAmelie Delaunay 	struct rtc_time *tm = &alrm->time;
4764e64350fSAmelie Delaunay 	unsigned int cr, isr, alrmar;
4774e64350fSAmelie Delaunay 	int ret = 0;
4784e64350fSAmelie Delaunay 
4794e64350fSAmelie Delaunay 	/*
4804e64350fSAmelie Delaunay 	 * RTC alarm can't be set on a specific date, unless this date is
4814e64350fSAmelie Delaunay 	 * up to the same day of month next month.
4824e64350fSAmelie Delaunay 	 */
48346828a5fSValentin Caron 	if (stm32_rtc_valid_alrm(dev, tm) < 0) {
4844e64350fSAmelie Delaunay 		dev_err(dev, "Alarm can be set only on upcoming month.\n");
4854e64350fSAmelie Delaunay 		return -EINVAL;
4864e64350fSAmelie Delaunay 	}
4874e64350fSAmelie Delaunay 
48846828a5fSValentin Caron 	tm2bcd(tm);
48946828a5fSValentin Caron 
4904e64350fSAmelie Delaunay 	alrmar = 0;
4914e64350fSAmelie Delaunay 	/* tm_year and tm_mon are not used because not supported by RTC */
4924e64350fSAmelie Delaunay 	alrmar |= (tm->tm_mday << STM32_RTC_ALRMXR_DATE_SHIFT) &
4934e64350fSAmelie Delaunay 		  STM32_RTC_ALRMXR_DATE;
4944e64350fSAmelie Delaunay 	/* 24-hour format */
4954e64350fSAmelie Delaunay 	alrmar &= ~STM32_RTC_ALRMXR_PM;
4964e64350fSAmelie Delaunay 	alrmar |= (tm->tm_hour << STM32_RTC_ALRMXR_HOUR_SHIFT) &
4974e64350fSAmelie Delaunay 		  STM32_RTC_ALRMXR_HOUR;
4984e64350fSAmelie Delaunay 	alrmar |= (tm->tm_min << STM32_RTC_ALRMXR_MIN_SHIFT) &
4994e64350fSAmelie Delaunay 		  STM32_RTC_ALRMXR_MIN;
5004e64350fSAmelie Delaunay 	alrmar |= (tm->tm_sec << STM32_RTC_ALRMXR_SEC_SHIFT) &
5014e64350fSAmelie Delaunay 		  STM32_RTC_ALRMXR_SEC;
5024e64350fSAmelie Delaunay 
5034e64350fSAmelie Delaunay 	stm32_rtc_wpr_unlock(rtc);
5044e64350fSAmelie Delaunay 
5054e64350fSAmelie Delaunay 	/* Disable Alarm */
50602b0cc34SAmelie Delaunay 	cr = readl_relaxed(rtc->base + regs->cr);
5074e64350fSAmelie Delaunay 	cr &= ~STM32_RTC_CR_ALRAE;
50802b0cc34SAmelie Delaunay 	writel_relaxed(cr, rtc->base + regs->cr);
5094e64350fSAmelie Delaunay 
5104e64350fSAmelie Delaunay 	/*
5114e64350fSAmelie Delaunay 	 * Poll Alarm write flag to be sure that Alarm update is allowed: it
5129a6757eaSAmelie Delaunay 	 * takes around 2 rtc_ck clock cycles
5134e64350fSAmelie Delaunay 	 */
51402b0cc34SAmelie Delaunay 	ret = readl_relaxed_poll_timeout_atomic(rtc->base + regs->isr,
5154e64350fSAmelie Delaunay 						isr,
5164e64350fSAmelie Delaunay 						(isr & STM32_RTC_ISR_ALRAWF),
5174e64350fSAmelie Delaunay 						10, 100000);
5184e64350fSAmelie Delaunay 
5194e64350fSAmelie Delaunay 	if (ret) {
5204e64350fSAmelie Delaunay 		dev_err(dev, "Alarm update not allowed\n");
5214e64350fSAmelie Delaunay 		goto end;
5224e64350fSAmelie Delaunay 	}
5234e64350fSAmelie Delaunay 
5244e64350fSAmelie Delaunay 	/* Write to Alarm register */
52502b0cc34SAmelie Delaunay 	writel_relaxed(alrmar, rtc->base + regs->alrmar);
5264e64350fSAmelie Delaunay 
527fe63604cSMarkus Elfring 	stm32_rtc_alarm_irq_enable(dev, alrm->enabled);
5284e64350fSAmelie Delaunay end:
5294e64350fSAmelie Delaunay 	stm32_rtc_wpr_lock(rtc);
5304e64350fSAmelie Delaunay 
5314e64350fSAmelie Delaunay 	return ret;
5324e64350fSAmelie Delaunay }
5334e64350fSAmelie Delaunay 
5344e64350fSAmelie Delaunay static const struct rtc_class_ops stm32_rtc_ops = {
5354e64350fSAmelie Delaunay 	.read_time	= stm32_rtc_read_time,
5364e64350fSAmelie Delaunay 	.set_time	= stm32_rtc_set_time,
5374e64350fSAmelie Delaunay 	.read_alarm	= stm32_rtc_read_alarm,
5384e64350fSAmelie Delaunay 	.set_alarm	= stm32_rtc_set_alarm,
5394e64350fSAmelie Delaunay 	.alarm_irq_enable = stm32_rtc_alarm_irq_enable,
5404e64350fSAmelie Delaunay };
5414e64350fSAmelie Delaunay 
stm32_rtc_clear_events(struct stm32_rtc * rtc,unsigned int flags)54202b0cc34SAmelie Delaunay static void stm32_rtc_clear_events(struct stm32_rtc *rtc,
54302b0cc34SAmelie Delaunay 				   unsigned int flags)
54402b0cc34SAmelie Delaunay {
54502b0cc34SAmelie Delaunay 	const struct stm32_rtc_registers *regs = &rtc->data->regs;
54602b0cc34SAmelie Delaunay 
54702b0cc34SAmelie Delaunay 	/* Flags are cleared by writing 0 in RTC_ISR */
54802b0cc34SAmelie Delaunay 	writel_relaxed(readl_relaxed(rtc->base + regs->isr) & ~flags,
54902b0cc34SAmelie Delaunay 		       rtc->base + regs->isr);
55002b0cc34SAmelie Delaunay }
55102b0cc34SAmelie Delaunay 
5529a6757eaSAmelie Delaunay static const struct stm32_rtc_data stm32_rtc_data = {
5539a6757eaSAmelie Delaunay 	.has_pclk = false,
55422cb47c1SAmelie Delaunay 	.need_dbp = true,
55524879257SChristophe Guibout 	.need_accuracy = false,
55602b0cc34SAmelie Delaunay 	.regs = {
55702b0cc34SAmelie Delaunay 		.tr = 0x00,
55802b0cc34SAmelie Delaunay 		.dr = 0x04,
55902b0cc34SAmelie Delaunay 		.cr = 0x08,
56002b0cc34SAmelie Delaunay 		.isr = 0x0C,
56102b0cc34SAmelie Delaunay 		.prer = 0x10,
56202b0cc34SAmelie Delaunay 		.alrmar = 0x1C,
56302b0cc34SAmelie Delaunay 		.wpr = 0x24,
564b72252b6SAmelie Delaunay 		.sr = 0x0C, /* set to ISR offset to ease alarm management */
565b72252b6SAmelie Delaunay 		.scr = UNDEF_REG,
566b72252b6SAmelie Delaunay 		.verr = UNDEF_REG,
56702b0cc34SAmelie Delaunay 	},
56802b0cc34SAmelie Delaunay 	.events = {
56902b0cc34SAmelie Delaunay 		.alra = STM32_RTC_ISR_ALRAF,
57002b0cc34SAmelie Delaunay 	},
57102b0cc34SAmelie Delaunay 	.clear_events = stm32_rtc_clear_events,
5729a6757eaSAmelie Delaunay };
5739a6757eaSAmelie Delaunay 
5749a6757eaSAmelie Delaunay static const struct stm32_rtc_data stm32h7_rtc_data = {
5759a6757eaSAmelie Delaunay 	.has_pclk = true,
57622cb47c1SAmelie Delaunay 	.need_dbp = true,
57724879257SChristophe Guibout 	.need_accuracy = false,
57802b0cc34SAmelie Delaunay 	.regs = {
57902b0cc34SAmelie Delaunay 		.tr = 0x00,
58002b0cc34SAmelie Delaunay 		.dr = 0x04,
58102b0cc34SAmelie Delaunay 		.cr = 0x08,
58202b0cc34SAmelie Delaunay 		.isr = 0x0C,
58302b0cc34SAmelie Delaunay 		.prer = 0x10,
58402b0cc34SAmelie Delaunay 		.alrmar = 0x1C,
58502b0cc34SAmelie Delaunay 		.wpr = 0x24,
586b72252b6SAmelie Delaunay 		.sr = 0x0C, /* set to ISR offset to ease alarm management */
587b72252b6SAmelie Delaunay 		.scr = UNDEF_REG,
588b72252b6SAmelie Delaunay 		.verr = UNDEF_REG,
58902b0cc34SAmelie Delaunay 	},
59002b0cc34SAmelie Delaunay 	.events = {
59102b0cc34SAmelie Delaunay 		.alra = STM32_RTC_ISR_ALRAF,
59202b0cc34SAmelie Delaunay 	},
59302b0cc34SAmelie Delaunay 	.clear_events = stm32_rtc_clear_events,
5949a6757eaSAmelie Delaunay };
5959a6757eaSAmelie Delaunay 
stm32mp1_rtc_clear_events(struct stm32_rtc * rtc,unsigned int flags)596b72252b6SAmelie Delaunay static void stm32mp1_rtc_clear_events(struct stm32_rtc *rtc,
597b72252b6SAmelie Delaunay 				      unsigned int flags)
598b72252b6SAmelie Delaunay {
599b72252b6SAmelie Delaunay 	struct stm32_rtc_registers regs = rtc->data->regs;
600b72252b6SAmelie Delaunay 
601b72252b6SAmelie Delaunay 	/* Flags are cleared by writing 1 in RTC_SCR */
602b72252b6SAmelie Delaunay 	writel_relaxed(flags, rtc->base + regs.scr);
603b72252b6SAmelie Delaunay }
604b72252b6SAmelie Delaunay 
605b72252b6SAmelie Delaunay static const struct stm32_rtc_data stm32mp1_data = {
606b72252b6SAmelie Delaunay 	.has_pclk = true,
607b72252b6SAmelie Delaunay 	.need_dbp = false,
60824879257SChristophe Guibout 	.need_accuracy = true,
609b72252b6SAmelie Delaunay 	.regs = {
610b72252b6SAmelie Delaunay 		.tr = 0x00,
611b72252b6SAmelie Delaunay 		.dr = 0x04,
612b72252b6SAmelie Delaunay 		.cr = 0x18,
613b72252b6SAmelie Delaunay 		.isr = 0x0C, /* named RTC_ICSR on stm32mp1 */
614b72252b6SAmelie Delaunay 		.prer = 0x10,
615b72252b6SAmelie Delaunay 		.alrmar = 0x40,
616b72252b6SAmelie Delaunay 		.wpr = 0x24,
617b72252b6SAmelie Delaunay 		.sr = 0x50,
618b72252b6SAmelie Delaunay 		.scr = 0x5C,
619b72252b6SAmelie Delaunay 		.verr = 0x3F4,
620b72252b6SAmelie Delaunay 	},
621b72252b6SAmelie Delaunay 	.events = {
622b72252b6SAmelie Delaunay 		.alra = STM32_RTC_SR_ALRA,
623b72252b6SAmelie Delaunay 	},
624b72252b6SAmelie Delaunay 	.clear_events = stm32mp1_rtc_clear_events,
625b72252b6SAmelie Delaunay };
626b72252b6SAmelie Delaunay 
6274e64350fSAmelie Delaunay static const struct of_device_id stm32_rtc_of_match[] = {
6289a6757eaSAmelie Delaunay 	{ .compatible = "st,stm32-rtc", .data = &stm32_rtc_data },
6299a6757eaSAmelie Delaunay 	{ .compatible = "st,stm32h7-rtc", .data = &stm32h7_rtc_data },
630b72252b6SAmelie Delaunay 	{ .compatible = "st,stm32mp1-rtc", .data = &stm32mp1_data },
6314e64350fSAmelie Delaunay 	{}
6324e64350fSAmelie Delaunay };
6334e64350fSAmelie Delaunay MODULE_DEVICE_TABLE(of, stm32_rtc_of_match);
6344e64350fSAmelie Delaunay 
stm32_rtc_init(struct platform_device * pdev,struct stm32_rtc * rtc)6354e64350fSAmelie Delaunay static int stm32_rtc_init(struct platform_device *pdev,
6364e64350fSAmelie Delaunay 			  struct stm32_rtc *rtc)
6374e64350fSAmelie Delaunay {
63802b0cc34SAmelie Delaunay 	const struct stm32_rtc_registers *regs = &rtc->data->regs;
6394e64350fSAmelie Delaunay 	unsigned int prer, pred_a, pred_s, pred_a_max, pred_s_max, cr;
6404e64350fSAmelie Delaunay 	unsigned int rate;
6411c18b8ecSAntonio Borneo 	int ret;
6424e64350fSAmelie Delaunay 
6439a6757eaSAmelie Delaunay 	rate = clk_get_rate(rtc->rtc_ck);
6444e64350fSAmelie Delaunay 
6454e64350fSAmelie Delaunay 	/* Find prediv_a and prediv_s to obtain the 1Hz calendar clock */
6464e64350fSAmelie Delaunay 	pred_a_max = STM32_RTC_PRER_PRED_A >> STM32_RTC_PRER_PRED_A_SHIFT;
6474e64350fSAmelie Delaunay 	pred_s_max = STM32_RTC_PRER_PRED_S >> STM32_RTC_PRER_PRED_S_SHIFT;
6484e64350fSAmelie Delaunay 
64924879257SChristophe Guibout 	if (rate > (pred_a_max + 1) * (pred_s_max + 1)) {
65024879257SChristophe Guibout 		dev_err(&pdev->dev, "rtc_ck rate is too high: %dHz\n", rate);
65124879257SChristophe Guibout 		return -EINVAL;
65224879257SChristophe Guibout 	}
65324879257SChristophe Guibout 
65424879257SChristophe Guibout 	if (rtc->data->need_accuracy) {
65524879257SChristophe Guibout 		for (pred_a = 0; pred_a <= pred_a_max; pred_a++) {
65624879257SChristophe Guibout 			pred_s = (rate / (pred_a + 1)) - 1;
65724879257SChristophe Guibout 
65824879257SChristophe Guibout 			if (pred_s <= pred_s_max && ((pred_s + 1) * (pred_a + 1)) == rate)
65924879257SChristophe Guibout 				break;
66024879257SChristophe Guibout 		}
66124879257SChristophe Guibout 	} else {
6621d70ba3bSAmelie Delaunay 		for (pred_a = pred_a_max; pred_a + 1 > 0; pred_a--) {
6634e64350fSAmelie Delaunay 			pred_s = (rate / (pred_a + 1)) - 1;
6644e64350fSAmelie Delaunay 
6654e64350fSAmelie Delaunay 			if (((pred_s + 1) * (pred_a + 1)) == rate)
6664e64350fSAmelie Delaunay 				break;
6674e64350fSAmelie Delaunay 		}
66824879257SChristophe Guibout 	}
6694e64350fSAmelie Delaunay 
6704e64350fSAmelie Delaunay 	/*
6714e64350fSAmelie Delaunay 	 * Can't find a 1Hz, so give priority to RTC power consumption
6724e64350fSAmelie Delaunay 	 * by choosing the higher possible value for prediv_a
6734e64350fSAmelie Delaunay 	 */
674650915ecSValentin Caron 	if (pred_s > pred_s_max || pred_a > pred_a_max) {
6754e64350fSAmelie Delaunay 		pred_a = pred_a_max;
6764e64350fSAmelie Delaunay 		pred_s = (rate / (pred_a + 1)) - 1;
6774e64350fSAmelie Delaunay 
6789a6757eaSAmelie Delaunay 		dev_warn(&pdev->dev, "rtc_ck is %s\n",
6791d70ba3bSAmelie Delaunay 			 (rate < ((pred_a + 1) * (pred_s + 1))) ?
6804e64350fSAmelie Delaunay 			 "fast" : "slow");
6814e64350fSAmelie Delaunay 	}
6824e64350fSAmelie Delaunay 
6831c18b8ecSAntonio Borneo 	cr = readl_relaxed(rtc->base + regs->cr);
6841c18b8ecSAntonio Borneo 
6851c18b8ecSAntonio Borneo 	prer = readl_relaxed(rtc->base + regs->prer);
6861c18b8ecSAntonio Borneo 	prer &= STM32_RTC_PRER_PRED_S | STM32_RTC_PRER_PRED_A;
6871c18b8ecSAntonio Borneo 
6881c18b8ecSAntonio Borneo 	pred_s = (pred_s << STM32_RTC_PRER_PRED_S_SHIFT) &
6891c18b8ecSAntonio Borneo 		 STM32_RTC_PRER_PRED_S;
6901c18b8ecSAntonio Borneo 	pred_a = (pred_a << STM32_RTC_PRER_PRED_A_SHIFT) &
6911c18b8ecSAntonio Borneo 		 STM32_RTC_PRER_PRED_A;
6921c18b8ecSAntonio Borneo 
6931c18b8ecSAntonio Borneo 	/* quit if there is nothing to initialize */
6941c18b8ecSAntonio Borneo 	if ((cr & STM32_RTC_CR_FMT) == 0 && prer == (pred_s | pred_a))
6951c18b8ecSAntonio Borneo 		return 0;
6961c18b8ecSAntonio Borneo 
6974e64350fSAmelie Delaunay 	stm32_rtc_wpr_unlock(rtc);
6984e64350fSAmelie Delaunay 
6994e64350fSAmelie Delaunay 	ret = stm32_rtc_enter_init_mode(rtc);
7004e64350fSAmelie Delaunay 	if (ret) {
7014e64350fSAmelie Delaunay 		dev_err(&pdev->dev,
7024e64350fSAmelie Delaunay 			"Can't enter in init mode. Prescaler config failed.\n");
7034e64350fSAmelie Delaunay 		goto end;
7044e64350fSAmelie Delaunay 	}
7054e64350fSAmelie Delaunay 
7061c18b8ecSAntonio Borneo 	writel_relaxed(pred_s, rtc->base + regs->prer);
7071c18b8ecSAntonio Borneo 	writel_relaxed(pred_a | pred_s, rtc->base + regs->prer);
7084e64350fSAmelie Delaunay 
7094e64350fSAmelie Delaunay 	/* Force 24h time format */
7104e64350fSAmelie Delaunay 	cr &= ~STM32_RTC_CR_FMT;
71102b0cc34SAmelie Delaunay 	writel_relaxed(cr, rtc->base + regs->cr);
7124e64350fSAmelie Delaunay 
7134e64350fSAmelie Delaunay 	stm32_rtc_exit_init_mode(rtc);
7144e64350fSAmelie Delaunay 
7154e64350fSAmelie Delaunay 	ret = stm32_rtc_wait_sync(rtc);
7164e64350fSAmelie Delaunay end:
7174e64350fSAmelie Delaunay 	stm32_rtc_wpr_lock(rtc);
7184e64350fSAmelie Delaunay 
7194e64350fSAmelie Delaunay 	return ret;
7204e64350fSAmelie Delaunay }
7214e64350fSAmelie Delaunay 
stm32_rtc_probe(struct platform_device * pdev)7224e64350fSAmelie Delaunay static int stm32_rtc_probe(struct platform_device *pdev)
7234e64350fSAmelie Delaunay {
7244e64350fSAmelie Delaunay 	struct stm32_rtc *rtc;
72502b0cc34SAmelie Delaunay 	const struct stm32_rtc_registers *regs;
7264e64350fSAmelie Delaunay 	int ret;
7274e64350fSAmelie Delaunay 
7284e64350fSAmelie Delaunay 	rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
7294e64350fSAmelie Delaunay 	if (!rtc)
7304e64350fSAmelie Delaunay 		return -ENOMEM;
7314e64350fSAmelie Delaunay 
73209ef18bcSYueHaibing 	rtc->base = devm_platform_ioremap_resource(pdev, 0);
7334e64350fSAmelie Delaunay 	if (IS_ERR(rtc->base))
7344e64350fSAmelie Delaunay 		return PTR_ERR(rtc->base);
7354e64350fSAmelie Delaunay 
73622cb47c1SAmelie Delaunay 	rtc->data = (struct stm32_rtc_data *)
73722cb47c1SAmelie Delaunay 		    of_device_get_match_data(&pdev->dev);
73802b0cc34SAmelie Delaunay 	regs = &rtc->data->regs;
73922cb47c1SAmelie Delaunay 
74022cb47c1SAmelie Delaunay 	if (rtc->data->need_dbp) {
7414e64350fSAmelie Delaunay 		rtc->dbp = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
7424e64350fSAmelie Delaunay 							   "st,syscfg");
7434e64350fSAmelie Delaunay 		if (IS_ERR(rtc->dbp)) {
7444e64350fSAmelie Delaunay 			dev_err(&pdev->dev, "no st,syscfg\n");
7454e64350fSAmelie Delaunay 			return PTR_ERR(rtc->dbp);
7464e64350fSAmelie Delaunay 		}
7474e64350fSAmelie Delaunay 
74822cb47c1SAmelie Delaunay 		ret = of_property_read_u32_index(pdev->dev.of_node, "st,syscfg",
74922cb47c1SAmelie Delaunay 						 1, &rtc->dbp_reg);
75022cb47c1SAmelie Delaunay 		if (ret) {
75122cb47c1SAmelie Delaunay 			dev_err(&pdev->dev, "can't read DBP register offset\n");
75222cb47c1SAmelie Delaunay 			return ret;
75322cb47c1SAmelie Delaunay 		}
75422cb47c1SAmelie Delaunay 
75522cb47c1SAmelie Delaunay 		ret = of_property_read_u32_index(pdev->dev.of_node, "st,syscfg",
75622cb47c1SAmelie Delaunay 						 2, &rtc->dbp_mask);
75722cb47c1SAmelie Delaunay 		if (ret) {
75822cb47c1SAmelie Delaunay 			dev_err(&pdev->dev, "can't read DBP register mask\n");
75922cb47c1SAmelie Delaunay 			return ret;
76022cb47c1SAmelie Delaunay 		}
76122cb47c1SAmelie Delaunay 	}
7629a6757eaSAmelie Delaunay 
7639a6757eaSAmelie Delaunay 	if (!rtc->data->has_pclk) {
7649a6757eaSAmelie Delaunay 		rtc->pclk = NULL;
7659a6757eaSAmelie Delaunay 		rtc->rtc_ck = devm_clk_get(&pdev->dev, NULL);
7669a6757eaSAmelie Delaunay 	} else {
7679a6757eaSAmelie Delaunay 		rtc->pclk = devm_clk_get(&pdev->dev, "pclk");
76895f7679cSValentin Caron 		if (IS_ERR(rtc->pclk))
76995f7679cSValentin Caron 			return dev_err_probe(&pdev->dev, PTR_ERR(rtc->pclk), "no pclk clock");
77095f7679cSValentin Caron 
7719a6757eaSAmelie Delaunay 		rtc->rtc_ck = devm_clk_get(&pdev->dev, "rtc_ck");
7729a6757eaSAmelie Delaunay 	}
77395f7679cSValentin Caron 	if (IS_ERR(rtc->rtc_ck))
77495f7679cSValentin Caron 		return dev_err_probe(&pdev->dev, PTR_ERR(rtc->rtc_ck), "no rtc_ck clock");
7754e64350fSAmelie Delaunay 
7769a6757eaSAmelie Delaunay 	if (rtc->data->has_pclk) {
7779a6757eaSAmelie Delaunay 		ret = clk_prepare_enable(rtc->pclk);
7784e64350fSAmelie Delaunay 		if (ret)
7794e64350fSAmelie Delaunay 			return ret;
7809a6757eaSAmelie Delaunay 	}
7819a6757eaSAmelie Delaunay 
7829a6757eaSAmelie Delaunay 	ret = clk_prepare_enable(rtc->rtc_ck);
7839a6757eaSAmelie Delaunay 	if (ret)
784950ac33dSMartin Fuzzey 		goto err_no_rtc_ck;
7854e64350fSAmelie Delaunay 
78622cb47c1SAmelie Delaunay 	if (rtc->data->need_dbp)
78722cb47c1SAmelie Delaunay 		regmap_update_bits(rtc->dbp, rtc->dbp_reg,
78822cb47c1SAmelie Delaunay 				   rtc->dbp_mask, rtc->dbp_mask);
7894e64350fSAmelie Delaunay 
7904e64350fSAmelie Delaunay 	/*
7914e64350fSAmelie Delaunay 	 * After a system reset, RTC_ISR.INITS flag can be read to check if
792819cbde5SAmelie Delaunay 	 * the calendar has been initialized or not. INITS flag is reset by a
7934e64350fSAmelie Delaunay 	 * power-on reset (no vbat, no power-supply). It is not reset if
7949a6757eaSAmelie Delaunay 	 * rtc_ck parent clock has changed (so RTC prescalers need to be
7954e64350fSAmelie Delaunay 	 * changed). That's why we cannot rely on this flag to know if RTC
7964e64350fSAmelie Delaunay 	 * init has to be done.
7974e64350fSAmelie Delaunay 	 */
7984e64350fSAmelie Delaunay 	ret = stm32_rtc_init(pdev, rtc);
7994e64350fSAmelie Delaunay 	if (ret)
8004e64350fSAmelie Delaunay 		goto err;
8014e64350fSAmelie Delaunay 
8024e64350fSAmelie Delaunay 	rtc->irq_alarm = platform_get_irq(pdev, 0);
8034e64350fSAmelie Delaunay 	if (rtc->irq_alarm <= 0) {
8044e64350fSAmelie Delaunay 		ret = rtc->irq_alarm;
8054e64350fSAmelie Delaunay 		goto err;
8064e64350fSAmelie Delaunay 	}
8074e64350fSAmelie Delaunay 
8084e64350fSAmelie Delaunay 	ret = device_init_wakeup(&pdev->dev, true);
8094e64350fSAmelie Delaunay 	if (ret)
81038e0689bSAlexandre Torgue 		goto err;
81138e0689bSAlexandre Torgue 
81238e0689bSAlexandre Torgue 	ret = dev_pm_set_wake_irq(&pdev->dev, rtc->irq_alarm);
81338e0689bSAlexandre Torgue 	if (ret)
81438e0689bSAlexandre Torgue 		goto err;
815b72252b6SAmelie Delaunay 
816b72252b6SAmelie Delaunay 	platform_set_drvdata(pdev, rtc);
8174e64350fSAmelie Delaunay 
8184e64350fSAmelie Delaunay 	rtc->rtc_dev = devm_rtc_device_register(&pdev->dev, pdev->name,
8194e64350fSAmelie Delaunay 						&stm32_rtc_ops, THIS_MODULE);
8204e64350fSAmelie Delaunay 	if (IS_ERR(rtc->rtc_dev)) {
8214e64350fSAmelie Delaunay 		ret = PTR_ERR(rtc->rtc_dev);
8224e64350fSAmelie Delaunay 		dev_err(&pdev->dev, "rtc device registration failed, err=%d\n",
8234e64350fSAmelie Delaunay 			ret);
8244e64350fSAmelie Delaunay 		goto err;
8254e64350fSAmelie Delaunay 	}
8264e64350fSAmelie Delaunay 
8274e64350fSAmelie Delaunay 	/* Handle RTC alarm interrupts */
8284e64350fSAmelie Delaunay 	ret = devm_request_threaded_irq(&pdev->dev, rtc->irq_alarm, NULL,
829d213217dSAmelie Delaunay 					stm32_rtc_alarm_irq, IRQF_ONESHOT,
8304e64350fSAmelie Delaunay 					pdev->name, rtc);
8314e64350fSAmelie Delaunay 	if (ret) {
8324e64350fSAmelie Delaunay 		dev_err(&pdev->dev, "IRQ%d (alarm interrupt) already claimed\n",
8334e64350fSAmelie Delaunay 			rtc->irq_alarm);
8344e64350fSAmelie Delaunay 		goto err;
8354e64350fSAmelie Delaunay 	}
8364e64350fSAmelie Delaunay 
8374e64350fSAmelie Delaunay 	/*
8384e64350fSAmelie Delaunay 	 * If INITS flag is reset (calendar year field set to 0x00), calendar
8394e64350fSAmelie Delaunay 	 * must be initialized
8404e64350fSAmelie Delaunay 	 */
84102b0cc34SAmelie Delaunay 	if (!(readl_relaxed(rtc->base + regs->isr) & STM32_RTC_ISR_INITS))
8424e64350fSAmelie Delaunay 		dev_warn(&pdev->dev, "Date/Time must be initialized\n");
8434e64350fSAmelie Delaunay 
844b72252b6SAmelie Delaunay 	if (regs->verr != UNDEF_REG) {
845b72252b6SAmelie Delaunay 		u32 ver = readl_relaxed(rtc->base + regs->verr);
846b72252b6SAmelie Delaunay 
847b72252b6SAmelie Delaunay 		dev_info(&pdev->dev, "registered rev:%d.%d\n",
848b72252b6SAmelie Delaunay 			 (ver >> STM32_RTC_VERR_MAJREV_SHIFT) & 0xF,
849b72252b6SAmelie Delaunay 			 (ver >> STM32_RTC_VERR_MINREV_SHIFT) & 0xF);
850b72252b6SAmelie Delaunay 	}
851b72252b6SAmelie Delaunay 
8524e64350fSAmelie Delaunay 	return 0;
853950ac33dSMartin Fuzzey 
8544e64350fSAmelie Delaunay err:
855950ac33dSMartin Fuzzey 	clk_disable_unprepare(rtc->rtc_ck);
856950ac33dSMartin Fuzzey err_no_rtc_ck:
8579a6757eaSAmelie Delaunay 	if (rtc->data->has_pclk)
8589a6757eaSAmelie Delaunay 		clk_disable_unprepare(rtc->pclk);
8594e64350fSAmelie Delaunay 
86022cb47c1SAmelie Delaunay 	if (rtc->data->need_dbp)
86122cb47c1SAmelie Delaunay 		regmap_update_bits(rtc->dbp, rtc->dbp_reg, rtc->dbp_mask, 0);
8624e64350fSAmelie Delaunay 
863b72252b6SAmelie Delaunay 	dev_pm_clear_wake_irq(&pdev->dev);
8644e64350fSAmelie Delaunay 	device_init_wakeup(&pdev->dev, false);
8654e64350fSAmelie Delaunay 
8664e64350fSAmelie Delaunay 	return ret;
8674e64350fSAmelie Delaunay }
8684e64350fSAmelie Delaunay 
stm32_rtc_remove(struct platform_device * pdev)86954c2cb27SUwe Kleine-König static void stm32_rtc_remove(struct platform_device *pdev)
8704e64350fSAmelie Delaunay {
8714e64350fSAmelie Delaunay 	struct stm32_rtc *rtc = platform_get_drvdata(pdev);
87202b0cc34SAmelie Delaunay 	const struct stm32_rtc_registers *regs = &rtc->data->regs;
8734e64350fSAmelie Delaunay 	unsigned int cr;
8744e64350fSAmelie Delaunay 
8754e64350fSAmelie Delaunay 	/* Disable interrupts */
8764e64350fSAmelie Delaunay 	stm32_rtc_wpr_unlock(rtc);
87702b0cc34SAmelie Delaunay 	cr = readl_relaxed(rtc->base + regs->cr);
8784e64350fSAmelie Delaunay 	cr &= ~STM32_RTC_CR_ALRAIE;
87902b0cc34SAmelie Delaunay 	writel_relaxed(cr, rtc->base + regs->cr);
8804e64350fSAmelie Delaunay 	stm32_rtc_wpr_lock(rtc);
8814e64350fSAmelie Delaunay 
8829a6757eaSAmelie Delaunay 	clk_disable_unprepare(rtc->rtc_ck);
8839a6757eaSAmelie Delaunay 	if (rtc->data->has_pclk)
8849a6757eaSAmelie Delaunay 		clk_disable_unprepare(rtc->pclk);
8854e64350fSAmelie Delaunay 
88622cb47c1SAmelie Delaunay 	/* Enable backup domain write protection if needed */
88722cb47c1SAmelie Delaunay 	if (rtc->data->need_dbp)
88822cb47c1SAmelie Delaunay 		regmap_update_bits(rtc->dbp, rtc->dbp_reg, rtc->dbp_mask, 0);
8894e64350fSAmelie Delaunay 
890b72252b6SAmelie Delaunay 	dev_pm_clear_wake_irq(&pdev->dev);
8914e64350fSAmelie Delaunay 	device_init_wakeup(&pdev->dev, false);
8924e64350fSAmelie Delaunay }
8934e64350fSAmelie Delaunay 
stm32_rtc_suspend(struct device * dev)8944e64350fSAmelie Delaunay static int stm32_rtc_suspend(struct device *dev)
8954e64350fSAmelie Delaunay {
8964e64350fSAmelie Delaunay 	struct stm32_rtc *rtc = dev_get_drvdata(dev);
8974e64350fSAmelie Delaunay 
8989a6757eaSAmelie Delaunay 	if (rtc->data->has_pclk)
8999a6757eaSAmelie Delaunay 		clk_disable_unprepare(rtc->pclk);
9009a6757eaSAmelie Delaunay 
9014e64350fSAmelie Delaunay 	return 0;
9024e64350fSAmelie Delaunay }
9034e64350fSAmelie Delaunay 
stm32_rtc_resume(struct device * dev)9044e64350fSAmelie Delaunay static int stm32_rtc_resume(struct device *dev)
9054e64350fSAmelie Delaunay {
9064e64350fSAmelie Delaunay 	struct stm32_rtc *rtc = dev_get_drvdata(dev);
9074e64350fSAmelie Delaunay 	int ret = 0;
9084e64350fSAmelie Delaunay 
9099a6757eaSAmelie Delaunay 	if (rtc->data->has_pclk) {
9109a6757eaSAmelie Delaunay 		ret = clk_prepare_enable(rtc->pclk);
9119a6757eaSAmelie Delaunay 		if (ret)
9129a6757eaSAmelie Delaunay 			return ret;
9139a6757eaSAmelie Delaunay 	}
9149a6757eaSAmelie Delaunay 
9154e64350fSAmelie Delaunay 	ret = stm32_rtc_wait_sync(rtc);
916cf33e911SChuhong Yuan 	if (ret < 0) {
917cf33e911SChuhong Yuan 		if (rtc->data->has_pclk)
918cf33e911SChuhong Yuan 			clk_disable_unprepare(rtc->pclk);
9194e64350fSAmelie Delaunay 		return ret;
920cf33e911SChuhong Yuan 	}
9214e64350fSAmelie Delaunay 
9224e64350fSAmelie Delaunay 	return ret;
9234e64350fSAmelie Delaunay }
9244e64350fSAmelie Delaunay 
925fb9a7e53SGabriel Fernandez static const struct dev_pm_ops stm32_rtc_pm_ops = {
926*2cf2a1acSNathan Chancellor 	NOIRQ_SYSTEM_SLEEP_PM_OPS(stm32_rtc_suspend, stm32_rtc_resume)
927fb9a7e53SGabriel Fernandez };
9284e64350fSAmelie Delaunay 
9294e64350fSAmelie Delaunay static struct platform_driver stm32_rtc_driver = {
9304e64350fSAmelie Delaunay 	.probe		= stm32_rtc_probe,
93154c2cb27SUwe Kleine-König 	.remove_new	= stm32_rtc_remove,
9324e64350fSAmelie Delaunay 	.driver		= {
9334e64350fSAmelie Delaunay 		.name	= DRIVER_NAME,
9344e64350fSAmelie Delaunay 		.pm	= &stm32_rtc_pm_ops,
9354e64350fSAmelie Delaunay 		.of_match_table = stm32_rtc_of_match,
9364e64350fSAmelie Delaunay 	},
9374e64350fSAmelie Delaunay };
9384e64350fSAmelie Delaunay 
9394e64350fSAmelie Delaunay module_platform_driver(stm32_rtc_driver);
9404e64350fSAmelie Delaunay 
9414e64350fSAmelie Delaunay MODULE_ALIAS("platform:" DRIVER_NAME);
9424e64350fSAmelie Delaunay MODULE_AUTHOR("Amelie Delaunay <amelie.delaunay@st.com>");
9434e64350fSAmelie Delaunay MODULE_DESCRIPTION("STMicroelectronics STM32 Real Time Clock driver");
9444e64350fSAmelie Delaunay MODULE_LICENSE("GPL v2");
945