1deeb4b53SMichel Pollet // SPDX-License-Identifier: GPL-2.0+
2deeb4b53SMichel Pollet /*
3deeb4b53SMichel Pollet * Renesas RZ/N1 Real Time Clock interface for Linux
4deeb4b53SMichel Pollet *
5deeb4b53SMichel Pollet * Copyright:
6deeb4b53SMichel Pollet * - 2014 Renesas Electronics Europe Limited
7deeb4b53SMichel Pollet * - 2022 Schneider Electric
8deeb4b53SMichel Pollet *
9deeb4b53SMichel Pollet * Authors:
10deeb4b53SMichel Pollet * - Michel Pollet <michel.pollet@bp.renesas.com>, <buserror@gmail.com>
11deeb4b53SMichel Pollet * - Miquel Raynal <miquel.raynal@bootlin.com>
12deeb4b53SMichel Pollet */
13deeb4b53SMichel Pollet
14deeb4b53SMichel Pollet #include <linux/bcd.h>
15deeb4b53SMichel Pollet #include <linux/init.h>
16deeb4b53SMichel Pollet #include <linux/iopoll.h>
17deeb4b53SMichel Pollet #include <linux/module.h>
1848144c28SRob Herring #include <linux/mod_devicetable.h>
19deeb4b53SMichel Pollet #include <linux/platform_device.h>
20deeb4b53SMichel Pollet #include <linux/pm_runtime.h>
21deeb4b53SMichel Pollet #include <linux/rtc.h>
22deeb4b53SMichel Pollet
23deeb4b53SMichel Pollet #define RZN1_RTC_CTL0 0x00
24deeb4b53SMichel Pollet #define RZN1_RTC_CTL0_SLSB_SUBU 0
25deeb4b53SMichel Pollet #define RZN1_RTC_CTL0_SLSB_SCMP BIT(4)
26deeb4b53SMichel Pollet #define RZN1_RTC_CTL0_AMPM BIT(5)
27deeb4b53SMichel Pollet #define RZN1_RTC_CTL0_CE BIT(7)
28deeb4b53SMichel Pollet
29deeb4b53SMichel Pollet #define RZN1_RTC_CTL1 0x04
30deeb4b53SMichel Pollet #define RZN1_RTC_CTL1_ALME BIT(4)
31deeb4b53SMichel Pollet
32deeb4b53SMichel Pollet #define RZN1_RTC_CTL2 0x08
33deeb4b53SMichel Pollet #define RZN1_RTC_CTL2_WAIT BIT(0)
34deeb4b53SMichel Pollet #define RZN1_RTC_CTL2_WST BIT(1)
35deeb4b53SMichel Pollet #define RZN1_RTC_CTL2_WUST BIT(5)
36deeb4b53SMichel Pollet #define RZN1_RTC_CTL2_STOPPED (RZN1_RTC_CTL2_WAIT | RZN1_RTC_CTL2_WST)
37deeb4b53SMichel Pollet
38deeb4b53SMichel Pollet #define RZN1_RTC_SEC 0x14
39deeb4b53SMichel Pollet #define RZN1_RTC_MIN 0x18
40deeb4b53SMichel Pollet #define RZN1_RTC_HOUR 0x1c
41deeb4b53SMichel Pollet #define RZN1_RTC_WEEK 0x20
42deeb4b53SMichel Pollet #define RZN1_RTC_DAY 0x24
43deeb4b53SMichel Pollet #define RZN1_RTC_MONTH 0x28
44deeb4b53SMichel Pollet #define RZN1_RTC_YEAR 0x2c
45deeb4b53SMichel Pollet
46deeb4b53SMichel Pollet #define RZN1_RTC_SUBU 0x38
47deeb4b53SMichel Pollet #define RZN1_RTC_SUBU_DEV BIT(7)
48deeb4b53SMichel Pollet #define RZN1_RTC_SUBU_DECR BIT(6)
49deeb4b53SMichel Pollet
50deeb4b53SMichel Pollet #define RZN1_RTC_ALM 0x40
51deeb4b53SMichel Pollet #define RZN1_RTC_ALH 0x44
52deeb4b53SMichel Pollet #define RZN1_RTC_ALW 0x48
53deeb4b53SMichel Pollet
54deeb4b53SMichel Pollet #define RZN1_RTC_SECC 0x4c
55deeb4b53SMichel Pollet #define RZN1_RTC_MINC 0x50
56deeb4b53SMichel Pollet #define RZN1_RTC_HOURC 0x54
57deeb4b53SMichel Pollet #define RZN1_RTC_WEEKC 0x58
58deeb4b53SMichel Pollet #define RZN1_RTC_DAYC 0x5c
59deeb4b53SMichel Pollet #define RZN1_RTC_MONTHC 0x60
60deeb4b53SMichel Pollet #define RZN1_RTC_YEARC 0x64
61deeb4b53SMichel Pollet
62deeb4b53SMichel Pollet struct rzn1_rtc {
63deeb4b53SMichel Pollet struct rtc_device *rtcdev;
64deeb4b53SMichel Pollet void __iomem *base;
65deeb4b53SMichel Pollet };
66deeb4b53SMichel Pollet
rzn1_rtc_get_time_snapshot(struct rzn1_rtc * rtc,struct rtc_time * tm)67deeb4b53SMichel Pollet static void rzn1_rtc_get_time_snapshot(struct rzn1_rtc *rtc, struct rtc_time *tm)
68deeb4b53SMichel Pollet {
69deeb4b53SMichel Pollet tm->tm_sec = readl(rtc->base + RZN1_RTC_SECC);
70deeb4b53SMichel Pollet tm->tm_min = readl(rtc->base + RZN1_RTC_MINC);
71deeb4b53SMichel Pollet tm->tm_hour = readl(rtc->base + RZN1_RTC_HOURC);
72deeb4b53SMichel Pollet tm->tm_wday = readl(rtc->base + RZN1_RTC_WEEKC);
73deeb4b53SMichel Pollet tm->tm_mday = readl(rtc->base + RZN1_RTC_DAYC);
74deeb4b53SMichel Pollet tm->tm_mon = readl(rtc->base + RZN1_RTC_MONTHC);
75deeb4b53SMichel Pollet tm->tm_year = readl(rtc->base + RZN1_RTC_YEARC);
76deeb4b53SMichel Pollet }
77deeb4b53SMichel Pollet
rzn1_rtc_tm_to_wday(struct rtc_time * tm)78deeb4b53SMichel Pollet static unsigned int rzn1_rtc_tm_to_wday(struct rtc_time *tm)
79deeb4b53SMichel Pollet {
80deeb4b53SMichel Pollet time64_t time;
81deeb4b53SMichel Pollet unsigned int days;
82deeb4b53SMichel Pollet u32 secs;
83deeb4b53SMichel Pollet
84deeb4b53SMichel Pollet time = rtc_tm_to_time64(tm);
85deeb4b53SMichel Pollet days = div_s64_rem(time, 86400, &secs);
86deeb4b53SMichel Pollet
87deeb4b53SMichel Pollet /* day of the week, 1970-01-01 was a Thursday */
88deeb4b53SMichel Pollet return (days + 4) % 7;
89deeb4b53SMichel Pollet }
90deeb4b53SMichel Pollet
rzn1_rtc_read_time(struct device * dev,struct rtc_time * tm)91deeb4b53SMichel Pollet static int rzn1_rtc_read_time(struct device *dev, struct rtc_time *tm)
92deeb4b53SMichel Pollet {
93deeb4b53SMichel Pollet struct rzn1_rtc *rtc = dev_get_drvdata(dev);
94deeb4b53SMichel Pollet u32 val, secs;
95deeb4b53SMichel Pollet
96deeb4b53SMichel Pollet /*
97deeb4b53SMichel Pollet * The RTC was not started or is stopped and thus does not carry the
98deeb4b53SMichel Pollet * proper time/date.
99deeb4b53SMichel Pollet */
100deeb4b53SMichel Pollet val = readl(rtc->base + RZN1_RTC_CTL2);
101deeb4b53SMichel Pollet if (val & RZN1_RTC_CTL2_STOPPED)
102deeb4b53SMichel Pollet return -EINVAL;
103deeb4b53SMichel Pollet
104deeb4b53SMichel Pollet rzn1_rtc_get_time_snapshot(rtc, tm);
105deeb4b53SMichel Pollet secs = readl(rtc->base + RZN1_RTC_SECC);
106deeb4b53SMichel Pollet if (tm->tm_sec != secs)
107deeb4b53SMichel Pollet rzn1_rtc_get_time_snapshot(rtc, tm);
108deeb4b53SMichel Pollet
109deeb4b53SMichel Pollet tm->tm_sec = bcd2bin(tm->tm_sec);
110deeb4b53SMichel Pollet tm->tm_min = bcd2bin(tm->tm_min);
111deeb4b53SMichel Pollet tm->tm_hour = bcd2bin(tm->tm_hour);
112deeb4b53SMichel Pollet tm->tm_wday = bcd2bin(tm->tm_wday);
113deeb4b53SMichel Pollet tm->tm_mday = bcd2bin(tm->tm_mday);
114*18db8ae7SWolfram Sang tm->tm_mon = bcd2bin(tm->tm_mon) - 1;
115*18db8ae7SWolfram Sang tm->tm_year = bcd2bin(tm->tm_year) + 100;
116deeb4b53SMichel Pollet
117deeb4b53SMichel Pollet return 0;
118deeb4b53SMichel Pollet }
119deeb4b53SMichel Pollet
rzn1_rtc_set_time(struct device * dev,struct rtc_time * tm)120deeb4b53SMichel Pollet static int rzn1_rtc_set_time(struct device *dev, struct rtc_time *tm)
121deeb4b53SMichel Pollet {
122deeb4b53SMichel Pollet struct rzn1_rtc *rtc = dev_get_drvdata(dev);
123deeb4b53SMichel Pollet u32 val;
124deeb4b53SMichel Pollet int ret;
125deeb4b53SMichel Pollet
126deeb4b53SMichel Pollet tm->tm_sec = bin2bcd(tm->tm_sec);
127deeb4b53SMichel Pollet tm->tm_min = bin2bcd(tm->tm_min);
128deeb4b53SMichel Pollet tm->tm_hour = bin2bcd(tm->tm_hour);
129deeb4b53SMichel Pollet tm->tm_wday = bin2bcd(rzn1_rtc_tm_to_wday(tm));
130deeb4b53SMichel Pollet tm->tm_mday = bin2bcd(tm->tm_mday);
131*18db8ae7SWolfram Sang tm->tm_mon = bin2bcd(tm->tm_mon + 1);
132*18db8ae7SWolfram Sang tm->tm_year = bin2bcd(tm->tm_year - 100);
133deeb4b53SMichel Pollet
134deeb4b53SMichel Pollet val = readl(rtc->base + RZN1_RTC_CTL2);
135deeb4b53SMichel Pollet if (!(val & RZN1_RTC_CTL2_STOPPED)) {
136deeb4b53SMichel Pollet /* Hold the counter if it was counting up */
137deeb4b53SMichel Pollet writel(RZN1_RTC_CTL2_WAIT, rtc->base + RZN1_RTC_CTL2);
138deeb4b53SMichel Pollet
139deeb4b53SMichel Pollet /* Wait for the counter to stop: two 32k clock cycles */
140deeb4b53SMichel Pollet usleep_range(61, 100);
141deeb4b53SMichel Pollet ret = readl_poll_timeout(rtc->base + RZN1_RTC_CTL2, val,
142deeb4b53SMichel Pollet val & RZN1_RTC_CTL2_WST, 0, 100);
143deeb4b53SMichel Pollet if (ret)
144deeb4b53SMichel Pollet return ret;
145deeb4b53SMichel Pollet }
146deeb4b53SMichel Pollet
147deeb4b53SMichel Pollet writel(tm->tm_sec, rtc->base + RZN1_RTC_SEC);
148deeb4b53SMichel Pollet writel(tm->tm_min, rtc->base + RZN1_RTC_MIN);
149deeb4b53SMichel Pollet writel(tm->tm_hour, rtc->base + RZN1_RTC_HOUR);
150deeb4b53SMichel Pollet writel(tm->tm_wday, rtc->base + RZN1_RTC_WEEK);
151deeb4b53SMichel Pollet writel(tm->tm_mday, rtc->base + RZN1_RTC_DAY);
152deeb4b53SMichel Pollet writel(tm->tm_mon, rtc->base + RZN1_RTC_MONTH);
153deeb4b53SMichel Pollet writel(tm->tm_year, rtc->base + RZN1_RTC_YEAR);
154deeb4b53SMichel Pollet writel(0, rtc->base + RZN1_RTC_CTL2);
155deeb4b53SMichel Pollet
156deeb4b53SMichel Pollet return 0;
157deeb4b53SMichel Pollet }
158deeb4b53SMichel Pollet
rzn1_rtc_alarm_irq(int irq,void * dev_id)159b5ad1bf0SMiquel Raynal static irqreturn_t rzn1_rtc_alarm_irq(int irq, void *dev_id)
160b5ad1bf0SMiquel Raynal {
161b5ad1bf0SMiquel Raynal struct rzn1_rtc *rtc = dev_id;
162b5ad1bf0SMiquel Raynal
163b5ad1bf0SMiquel Raynal rtc_update_irq(rtc->rtcdev, 1, RTC_AF | RTC_IRQF);
164b5ad1bf0SMiquel Raynal
165b5ad1bf0SMiquel Raynal return IRQ_HANDLED;
166b5ad1bf0SMiquel Raynal }
167b5ad1bf0SMiquel Raynal
rzn1_rtc_alarm_irq_enable(struct device * dev,unsigned int enable)168b5ad1bf0SMiquel Raynal static int rzn1_rtc_alarm_irq_enable(struct device *dev, unsigned int enable)
169b5ad1bf0SMiquel Raynal {
170b5ad1bf0SMiquel Raynal struct rzn1_rtc *rtc = dev_get_drvdata(dev);
171b5ad1bf0SMiquel Raynal u32 ctl1 = readl(rtc->base + RZN1_RTC_CTL1);
172b5ad1bf0SMiquel Raynal
173b5ad1bf0SMiquel Raynal if (enable)
174b5ad1bf0SMiquel Raynal ctl1 |= RZN1_RTC_CTL1_ALME;
175b5ad1bf0SMiquel Raynal else
176b5ad1bf0SMiquel Raynal ctl1 &= ~RZN1_RTC_CTL1_ALME;
177b5ad1bf0SMiquel Raynal
178b5ad1bf0SMiquel Raynal writel(ctl1, rtc->base + RZN1_RTC_CTL1);
179b5ad1bf0SMiquel Raynal
180b5ad1bf0SMiquel Raynal return 0;
181b5ad1bf0SMiquel Raynal }
182b5ad1bf0SMiquel Raynal
rzn1_rtc_read_alarm(struct device * dev,struct rtc_wkalrm * alrm)183b5ad1bf0SMiquel Raynal static int rzn1_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
184b5ad1bf0SMiquel Raynal {
185b5ad1bf0SMiquel Raynal struct rzn1_rtc *rtc = dev_get_drvdata(dev);
186b5ad1bf0SMiquel Raynal struct rtc_time *tm = &alrm->time;
187b5ad1bf0SMiquel Raynal unsigned int min, hour, wday, delta_days;
188b5ad1bf0SMiquel Raynal time64_t alarm;
189b5ad1bf0SMiquel Raynal u32 ctl1;
190b5ad1bf0SMiquel Raynal int ret;
191b5ad1bf0SMiquel Raynal
192b5ad1bf0SMiquel Raynal ret = rzn1_rtc_read_time(dev, tm);
193b5ad1bf0SMiquel Raynal if (ret)
194b5ad1bf0SMiquel Raynal return ret;
195b5ad1bf0SMiquel Raynal
196b5ad1bf0SMiquel Raynal min = readl(rtc->base + RZN1_RTC_ALM);
197b5ad1bf0SMiquel Raynal hour = readl(rtc->base + RZN1_RTC_ALH);
198b5ad1bf0SMiquel Raynal wday = readl(rtc->base + RZN1_RTC_ALW);
199b5ad1bf0SMiquel Raynal
200b5ad1bf0SMiquel Raynal tm->tm_sec = 0;
201b5ad1bf0SMiquel Raynal tm->tm_min = bcd2bin(min);
202b5ad1bf0SMiquel Raynal tm->tm_hour = bcd2bin(hour);
203b5ad1bf0SMiquel Raynal delta_days = ((fls(wday) - 1) - tm->tm_wday + 7) % 7;
204b5ad1bf0SMiquel Raynal tm->tm_wday = fls(wday) - 1;
205b5ad1bf0SMiquel Raynal
206b5ad1bf0SMiquel Raynal if (delta_days) {
207b5ad1bf0SMiquel Raynal alarm = rtc_tm_to_time64(tm) + (delta_days * 86400);
208b5ad1bf0SMiquel Raynal rtc_time64_to_tm(alarm, tm);
209b5ad1bf0SMiquel Raynal }
210b5ad1bf0SMiquel Raynal
211b5ad1bf0SMiquel Raynal ctl1 = readl(rtc->base + RZN1_RTC_CTL1);
212b5ad1bf0SMiquel Raynal alrm->enabled = !!(ctl1 & RZN1_RTC_CTL1_ALME);
213b5ad1bf0SMiquel Raynal
214b5ad1bf0SMiquel Raynal return 0;
215b5ad1bf0SMiquel Raynal }
216b5ad1bf0SMiquel Raynal
rzn1_rtc_set_alarm(struct device * dev,struct rtc_wkalrm * alrm)217b5ad1bf0SMiquel Raynal static int rzn1_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
218b5ad1bf0SMiquel Raynal {
219b5ad1bf0SMiquel Raynal struct rzn1_rtc *rtc = dev_get_drvdata(dev);
220b5ad1bf0SMiquel Raynal struct rtc_time *tm = &alrm->time, tm_now;
221b5ad1bf0SMiquel Raynal unsigned long alarm, farest;
222b5ad1bf0SMiquel Raynal unsigned int days_ahead, wday;
223b5ad1bf0SMiquel Raynal int ret;
224b5ad1bf0SMiquel Raynal
225b5ad1bf0SMiquel Raynal ret = rzn1_rtc_read_time(dev, &tm_now);
226b5ad1bf0SMiquel Raynal if (ret)
227b5ad1bf0SMiquel Raynal return ret;
228b5ad1bf0SMiquel Raynal
229b5ad1bf0SMiquel Raynal /* We cannot set alarms more than one week ahead */
2302b0386d5SGuenter Roeck farest = rtc_tm_to_time64(&tm_now) + rtc->rtcdev->alarm_offset_max;
231b5ad1bf0SMiquel Raynal alarm = rtc_tm_to_time64(tm);
232b5ad1bf0SMiquel Raynal if (time_after(alarm, farest))
233b5ad1bf0SMiquel Raynal return -ERANGE;
234b5ad1bf0SMiquel Raynal
235b5ad1bf0SMiquel Raynal /* Convert alarm day into week day */
236b5ad1bf0SMiquel Raynal days_ahead = tm->tm_mday - tm_now.tm_mday;
237b5ad1bf0SMiquel Raynal wday = (tm_now.tm_wday + days_ahead) % 7;
238b5ad1bf0SMiquel Raynal
239b5ad1bf0SMiquel Raynal writel(bin2bcd(tm->tm_min), rtc->base + RZN1_RTC_ALM);
240b5ad1bf0SMiquel Raynal writel(bin2bcd(tm->tm_hour), rtc->base + RZN1_RTC_ALH);
241b5ad1bf0SMiquel Raynal writel(BIT(wday), rtc->base + RZN1_RTC_ALW);
242b5ad1bf0SMiquel Raynal
243b5ad1bf0SMiquel Raynal rzn1_rtc_alarm_irq_enable(dev, alrm->enabled);
244b5ad1bf0SMiquel Raynal
245b5ad1bf0SMiquel Raynal return 0;
246b5ad1bf0SMiquel Raynal }
247b5ad1bf0SMiquel Raynal
rzn1_rtc_read_offset(struct device * dev,long * offset)248be4a11cfSMiquel Raynal static int rzn1_rtc_read_offset(struct device *dev, long *offset)
249be4a11cfSMiquel Raynal {
250be4a11cfSMiquel Raynal struct rzn1_rtc *rtc = dev_get_drvdata(dev);
251be4a11cfSMiquel Raynal unsigned int ppb_per_step;
252be4a11cfSMiquel Raynal bool subtract;
253be4a11cfSMiquel Raynal u32 val;
254be4a11cfSMiquel Raynal
255be4a11cfSMiquel Raynal val = readl(rtc->base + RZN1_RTC_SUBU);
256be4a11cfSMiquel Raynal ppb_per_step = val & RZN1_RTC_SUBU_DEV ? 1017 : 3051;
257be4a11cfSMiquel Raynal subtract = val & RZN1_RTC_SUBU_DECR;
258be4a11cfSMiquel Raynal val &= 0x3F;
259be4a11cfSMiquel Raynal
260be4a11cfSMiquel Raynal if (!val)
261be4a11cfSMiquel Raynal *offset = 0;
262be4a11cfSMiquel Raynal else if (subtract)
263be4a11cfSMiquel Raynal *offset = -(((~val) & 0x3F) + 1) * ppb_per_step;
264be4a11cfSMiquel Raynal else
265be4a11cfSMiquel Raynal *offset = (val - 1) * ppb_per_step;
266be4a11cfSMiquel Raynal
267be4a11cfSMiquel Raynal return 0;
268be4a11cfSMiquel Raynal }
269be4a11cfSMiquel Raynal
rzn1_rtc_set_offset(struct device * dev,long offset)270be4a11cfSMiquel Raynal static int rzn1_rtc_set_offset(struct device *dev, long offset)
271be4a11cfSMiquel Raynal {
272be4a11cfSMiquel Raynal struct rzn1_rtc *rtc = dev_get_drvdata(dev);
2733f348924SMiquel Raynal int stepsh, stepsl, steps;
27464d69b5dSMiquel Raynal u32 subu = 0, ctl2;
275be4a11cfSMiquel Raynal int ret;
276be4a11cfSMiquel Raynal
277be4a11cfSMiquel Raynal /*
278be4a11cfSMiquel Raynal * Check which resolution mode (every 20 or 60s) can be used.
279be4a11cfSMiquel Raynal * Between 2 and 124 clock pulses can be added or substracted.
280be4a11cfSMiquel Raynal *
281be4a11cfSMiquel Raynal * In 20s mode, the minimum resolution is 2 / (32768 * 20) which is
282be4a11cfSMiquel Raynal * close to 3051 ppb. In 60s mode, the resolution is closer to 1017.
283be4a11cfSMiquel Raynal */
284be4a11cfSMiquel Raynal stepsh = DIV_ROUND_CLOSEST(offset, 1017);
285be4a11cfSMiquel Raynal stepsl = DIV_ROUND_CLOSEST(offset, 3051);
286be4a11cfSMiquel Raynal
287be4a11cfSMiquel Raynal if (stepsh >= -0x3E && stepsh <= 0x3E) {
288be4a11cfSMiquel Raynal /* 1017 ppb per step */
289be4a11cfSMiquel Raynal steps = stepsh;
29064d69b5dSMiquel Raynal subu |= RZN1_RTC_SUBU_DEV;
291be4a11cfSMiquel Raynal } else if (stepsl >= -0x3E && stepsl <= 0x3E) {
292be4a11cfSMiquel Raynal /* 3051 ppb per step */
293be4a11cfSMiquel Raynal steps = stepsl;
294be4a11cfSMiquel Raynal } else {
295be4a11cfSMiquel Raynal return -ERANGE;
296be4a11cfSMiquel Raynal }
297be4a11cfSMiquel Raynal
298be4a11cfSMiquel Raynal if (!steps)
299be4a11cfSMiquel Raynal return 0;
300be4a11cfSMiquel Raynal
301be4a11cfSMiquel Raynal if (steps > 0) {
30264d69b5dSMiquel Raynal subu |= steps + 1;
303be4a11cfSMiquel Raynal } else {
30464d69b5dSMiquel Raynal subu |= RZN1_RTC_SUBU_DECR;
30564d69b5dSMiquel Raynal subu |= (~(-steps - 1)) & 0x3F;
306be4a11cfSMiquel Raynal }
307be4a11cfSMiquel Raynal
30864d69b5dSMiquel Raynal ret = readl_poll_timeout(rtc->base + RZN1_RTC_CTL2, ctl2,
30964d69b5dSMiquel Raynal !(ctl2 & RZN1_RTC_CTL2_WUST), 100, 2000000);
310be4a11cfSMiquel Raynal if (ret)
311be4a11cfSMiquel Raynal return ret;
312be4a11cfSMiquel Raynal
31364d69b5dSMiquel Raynal writel(subu, rtc->base + RZN1_RTC_SUBU);
314be4a11cfSMiquel Raynal
315be4a11cfSMiquel Raynal return 0;
316be4a11cfSMiquel Raynal }
317be4a11cfSMiquel Raynal
318deeb4b53SMichel Pollet static const struct rtc_class_ops rzn1_rtc_ops = {
319deeb4b53SMichel Pollet .read_time = rzn1_rtc_read_time,
320deeb4b53SMichel Pollet .set_time = rzn1_rtc_set_time,
321b5ad1bf0SMiquel Raynal .read_alarm = rzn1_rtc_read_alarm,
322b5ad1bf0SMiquel Raynal .set_alarm = rzn1_rtc_set_alarm,
323b5ad1bf0SMiquel Raynal .alarm_irq_enable = rzn1_rtc_alarm_irq_enable,
324be4a11cfSMiquel Raynal .read_offset = rzn1_rtc_read_offset,
325be4a11cfSMiquel Raynal .set_offset = rzn1_rtc_set_offset,
326deeb4b53SMichel Pollet };
327deeb4b53SMichel Pollet
rzn1_rtc_probe(struct platform_device * pdev)328deeb4b53SMichel Pollet static int rzn1_rtc_probe(struct platform_device *pdev)
329deeb4b53SMichel Pollet {
330deeb4b53SMichel Pollet struct rzn1_rtc *rtc;
331b5ad1bf0SMiquel Raynal int alarm_irq;
332deeb4b53SMichel Pollet int ret;
333deeb4b53SMichel Pollet
334deeb4b53SMichel Pollet rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
335deeb4b53SMichel Pollet if (!rtc)
336deeb4b53SMichel Pollet return -ENOMEM;
337deeb4b53SMichel Pollet
338deeb4b53SMichel Pollet platform_set_drvdata(pdev, rtc);
339deeb4b53SMichel Pollet
340deeb4b53SMichel Pollet rtc->base = devm_platform_ioremap_resource(pdev, 0);
341deeb4b53SMichel Pollet if (IS_ERR(rtc->base))
342deeb4b53SMichel Pollet return dev_err_probe(&pdev->dev, PTR_ERR(rtc->base), "Missing reg\n");
343deeb4b53SMichel Pollet
344b5ad1bf0SMiquel Raynal alarm_irq = platform_get_irq(pdev, 0);
345b5ad1bf0SMiquel Raynal if (alarm_irq < 0)
346b5ad1bf0SMiquel Raynal return alarm_irq;
347b5ad1bf0SMiquel Raynal
348deeb4b53SMichel Pollet rtc->rtcdev = devm_rtc_allocate_device(&pdev->dev);
349deeb4b53SMichel Pollet if (IS_ERR(rtc->rtcdev))
3500b6da785SDan Carpenter return PTR_ERR(rtc->rtcdev);
351deeb4b53SMichel Pollet
352deeb4b53SMichel Pollet rtc->rtcdev->range_min = RTC_TIMESTAMP_BEGIN_2000;
353deeb4b53SMichel Pollet rtc->rtcdev->range_max = RTC_TIMESTAMP_END_2099;
3542b0386d5SGuenter Roeck rtc->rtcdev->alarm_offset_max = 7 * 86400;
355deeb4b53SMichel Pollet rtc->rtcdev->ops = &rzn1_rtc_ops;
356b5ad1bf0SMiquel Raynal set_bit(RTC_FEATURE_ALARM_RES_MINUTE, rtc->rtcdev->features);
357deeb4b53SMichel Pollet clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, rtc->rtcdev->features);
358deeb4b53SMichel Pollet
3599800f24fSYushan Zhou ret = devm_pm_runtime_enable(&pdev->dev);
3609800f24fSYushan Zhou if (ret < 0)
3619800f24fSYushan Zhou return ret;
362deeb4b53SMichel Pollet ret = pm_runtime_resume_and_get(&pdev->dev);
363deeb4b53SMichel Pollet if (ret < 0)
364deeb4b53SMichel Pollet return ret;
365deeb4b53SMichel Pollet
366deeb4b53SMichel Pollet /*
367deeb4b53SMichel Pollet * Ensure the clock counter is enabled.
368deeb4b53SMichel Pollet * Set 24-hour mode and possible oscillator offset compensation in SUBU mode.
369deeb4b53SMichel Pollet */
370deeb4b53SMichel Pollet writel(RZN1_RTC_CTL0_CE | RZN1_RTC_CTL0_AMPM | RZN1_RTC_CTL0_SLSB_SUBU,
371deeb4b53SMichel Pollet rtc->base + RZN1_RTC_CTL0);
372deeb4b53SMichel Pollet
373deeb4b53SMichel Pollet /* Disable all interrupts */
374deeb4b53SMichel Pollet writel(0, rtc->base + RZN1_RTC_CTL1);
375deeb4b53SMichel Pollet
376b5ad1bf0SMiquel Raynal ret = devm_request_irq(&pdev->dev, alarm_irq, rzn1_rtc_alarm_irq, 0,
377b5ad1bf0SMiquel Raynal dev_name(&pdev->dev), rtc);
378b5ad1bf0SMiquel Raynal if (ret) {
379b5ad1bf0SMiquel Raynal dev_err(&pdev->dev, "RTC timer interrupt not available\n");
380b5ad1bf0SMiquel Raynal goto dis_runtime_pm;
381b5ad1bf0SMiquel Raynal }
382b5ad1bf0SMiquel Raynal
383deeb4b53SMichel Pollet ret = devm_rtc_register_device(rtc->rtcdev);
384deeb4b53SMichel Pollet if (ret)
385deeb4b53SMichel Pollet goto dis_runtime_pm;
386deeb4b53SMichel Pollet
387deeb4b53SMichel Pollet return 0;
388deeb4b53SMichel Pollet
389deeb4b53SMichel Pollet dis_runtime_pm:
390deeb4b53SMichel Pollet pm_runtime_put(&pdev->dev);
391deeb4b53SMichel Pollet
392deeb4b53SMichel Pollet return ret;
393deeb4b53SMichel Pollet }
394deeb4b53SMichel Pollet
rzn1_rtc_remove(struct platform_device * pdev)395e55fbc80SUwe Kleine-König static void rzn1_rtc_remove(struct platform_device *pdev)
396deeb4b53SMichel Pollet {
397deeb4b53SMichel Pollet pm_runtime_put(&pdev->dev);
398deeb4b53SMichel Pollet }
399deeb4b53SMichel Pollet
400deeb4b53SMichel Pollet static const struct of_device_id rzn1_rtc_of_match[] = {
401deeb4b53SMichel Pollet { .compatible = "renesas,rzn1-rtc" },
402deeb4b53SMichel Pollet {},
403deeb4b53SMichel Pollet };
404deeb4b53SMichel Pollet MODULE_DEVICE_TABLE(of, rzn1_rtc_of_match);
405deeb4b53SMichel Pollet
406deeb4b53SMichel Pollet static struct platform_driver rzn1_rtc_driver = {
407deeb4b53SMichel Pollet .probe = rzn1_rtc_probe,
408e55fbc80SUwe Kleine-König .remove_new = rzn1_rtc_remove,
409deeb4b53SMichel Pollet .driver = {
410deeb4b53SMichel Pollet .name = "rzn1-rtc",
411deeb4b53SMichel Pollet .of_match_table = rzn1_rtc_of_match,
412deeb4b53SMichel Pollet },
413deeb4b53SMichel Pollet };
414deeb4b53SMichel Pollet module_platform_driver(rzn1_rtc_driver);
415deeb4b53SMichel Pollet
416deeb4b53SMichel Pollet MODULE_AUTHOR("Michel Pollet <Michel.Pollet@bp.renesas.com");
417deeb4b53SMichel Pollet MODULE_AUTHOR("Miquel Raynal <miquel.raynal@bootlin.com");
418deeb4b53SMichel Pollet MODULE_DESCRIPTION("RZ/N1 RTC driver");
419deeb4b53SMichel Pollet MODULE_LICENSE("GPL");
420