4 * Copyright (c) 2017 Andreas Färber
6 * SPDX-License-Identifier: GPL-2.0+
11 #include <linux/module.h>
13 #include <linux/of_address.h>
14 #include <linux/platform_device.h>
15 #include <linux/rtc.h>
16 #include <linux/spinlock.h>
18 #define RTD_RTCSEC 0x00
19 #define RTD_RTCMIN 0x04
20 #define RTD_RTCHR 0x08
21 #define RTD_RTCDATE1 0x0c
22 #define RTD_RTCDATE2 0x10
23 #define RTD_RTCACR 0x28
24 #define RTD_RTCEN 0x2c
25 #define RTD_RTCCR 0x30
27 #define RTD_RTCSEC_RTCSEC_MASK 0x7f
29 #define RTD_RTCMIN_RTCMIN_MASK 0x3f
31 #define RTD_RTCHR_RTCHR_MASK 0x1f
33 #define RTD_RTCDATE1_RTCDATE1_MASK 0xff
35 #define RTD_RTCDATE2_RTCDATE2_MASK 0x7f
37 #define RTD_RTCACR_RTCPWR BIT(7)
39 #define RTD_RTCEN_RTCEN_MASK 0xff
41 #define RTD_RTCCR_RTCRST BIT(6)
46 struct rtc_device
*rtcdev
;
47 unsigned int base_year
;
50 static inline int rtd119x_rtc_days_in_year(int year
)
52 return 365 + (is_leap_year(year
) ? 1 : 0);
55 static void rtd119x_rtc_reset(struct device
*dev
)
57 struct rtd119x_rtc
*data
= dev_get_drvdata(dev
);
60 val
= readl_relaxed(data
->base
+ RTD_RTCCR
);
61 val
|= RTD_RTCCR_RTCRST
;
62 writel_relaxed(val
, data
->base
+ RTD_RTCCR
);
64 val
&= ~RTD_RTCCR_RTCRST
;
65 writel(val
, data
->base
+ RTD_RTCCR
);
68 static void rtd119x_rtc_set_enabled(struct device
*dev
, bool enable
)
70 struct rtd119x_rtc
*data
= dev_get_drvdata(dev
);
73 val
= readl_relaxed(data
->base
+ RTD_RTCEN
);
75 if ((val
& RTD_RTCEN_RTCEN_MASK
) == 0x5a)
77 writel_relaxed(0x5a, data
->base
+ RTD_RTCEN
);
79 writel_relaxed(0, data
->base
+ RTD_RTCEN
);
83 static int rtd119x_rtc_read_time(struct device
*dev
, struct rtc_time
*tm
)
85 struct rtd119x_rtc
*data
= dev_get_drvdata(dev
);
92 tm
->tm_sec
= (readl_relaxed(data
->base
+ RTD_RTCSEC
) & RTD_RTCSEC_RTCSEC_MASK
) >> 1;
93 tm
->tm_min
= readl_relaxed(data
->base
+ RTD_RTCMIN
) & RTD_RTCMIN_RTCMIN_MASK
;
94 tm
->tm_hour
= readl_relaxed(data
->base
+ RTD_RTCHR
) & RTD_RTCHR_RTCHR_MASK
;
95 day
= readl_relaxed(data
->base
+ RTD_RTCDATE1
) & RTD_RTCDATE1_RTCDATE1_MASK
;
96 day
|= (readl_relaxed(data
->base
+ RTD_RTCDATE2
) & RTD_RTCDATE2_RTCDATE2_MASK
) << 8;
97 sec
= (readl_relaxed(data
->base
+ RTD_RTCSEC
) & RTD_RTCSEC_RTCSEC_MASK
) >> 1;
100 if (sec
== tm
->tm_sec
)
107 dev_dbg(dev
, "%s: needed %i tries\n", __func__
, tries
);
109 year
= data
->base_year
;
110 while (day
>= rtd119x_rtc_days_in_year(year
)) {
111 day
-= rtd119x_rtc_days_in_year(year
);
114 tm
->tm_year
= year
- 1900;
118 while (day
>= rtc_month_days(tm
->tm_mon
, year
)) {
119 day
-= rtc_month_days(tm
->tm_mon
, year
);
122 tm
->tm_mday
= day
+ 1;
127 static int rtd119x_rtc_set_time(struct device
*dev
, struct rtc_time
*tm
)
129 struct rtd119x_rtc
*data
= dev_get_drvdata(dev
);
133 if (1900 + tm
->tm_year
< data
->base_year
)
137 for (i
= data
->base_year
; i
< 1900 + tm
->tm_year
; i
++)
138 day
+= rtd119x_rtc_days_in_year(i
);
144 rtd119x_rtc_set_enabled(dev
, false);
146 writel_relaxed((tm
->tm_sec
<< 1) & RTD_RTCSEC_RTCSEC_MASK
, data
->base
+ RTD_RTCSEC
);
147 writel_relaxed(tm
->tm_min
& RTD_RTCMIN_RTCMIN_MASK
, data
->base
+ RTD_RTCMIN
);
148 writel_relaxed(tm
->tm_hour
& RTD_RTCHR_RTCHR_MASK
, data
->base
+ RTD_RTCHR
);
149 writel_relaxed(day
& RTD_RTCDATE1_RTCDATE1_MASK
, data
->base
+ RTD_RTCDATE1
);
150 writel_relaxed((day
>> 8) & RTD_RTCDATE2_RTCDATE2_MASK
, data
->base
+ RTD_RTCDATE2
);
152 rtd119x_rtc_set_enabled(dev
, true);
157 static const struct rtc_class_ops rtd119x_rtc_ops
= {
158 .read_time
= rtd119x_rtc_read_time
,
159 .set_time
= rtd119x_rtc_set_time
,
162 static const struct of_device_id rtd119x_rtc_dt_ids
[] = {
163 { .compatible
= "realtek,rtd1295-rtc" },
167 static int rtd119x_rtc_probe(struct platform_device
*pdev
)
169 struct rtd119x_rtc
*data
;
170 struct resource
*res
;
174 data
= devm_kzalloc(&pdev
->dev
, sizeof(*data
), GFP_KERNEL
);
178 platform_set_drvdata(pdev
, data
);
179 data
->base_year
= 2014;
181 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
182 data
->base
= devm_ioremap_resource(&pdev
->dev
, res
);
183 if (IS_ERR(data
->base
))
184 return PTR_ERR(data
->base
);
186 data
->clk
= of_clk_get(pdev
->dev
.of_node
, 0);
187 if (IS_ERR(data
->clk
))
188 return PTR_ERR(data
->clk
);
190 ret
= clk_prepare_enable(data
->clk
);
196 val
= readl_relaxed(data
->base
+ RTD_RTCACR
);
197 if (!(val
& RTD_RTCACR_RTCPWR
)) {
198 writel_relaxed(RTD_RTCACR_RTCPWR
, data
->base
+ RTD_RTCACR
);
200 rtd119x_rtc_reset(&pdev
->dev
);
202 writel_relaxed(0, data
->base
+ RTD_RTCMIN
);
203 writel_relaxed(0, data
->base
+ RTD_RTCHR
);
204 writel_relaxed(0, data
->base
+ RTD_RTCDATE1
);
205 writel_relaxed(0, data
->base
+ RTD_RTCDATE2
);
208 rtd119x_rtc_set_enabled(&pdev
->dev
, true);
210 data
->rtcdev
= devm_rtc_device_register(&pdev
->dev
, "rtc",
211 &rtd119x_rtc_ops
, THIS_MODULE
);
212 if (IS_ERR(data
->rtcdev
)) {
213 dev_err(&pdev
->dev
, "failed to register rtc device");
214 clk_disable_unprepare(data
->clk
);
216 return PTR_ERR(data
->rtcdev
);
222 static int rtd119x_rtc_remove(struct platform_device
*pdev
)
224 struct rtd119x_rtc
*data
= platform_get_drvdata(pdev
);
226 rtd119x_rtc_set_enabled(&pdev
->dev
, false);
228 clk_disable_unprepare(data
->clk
);
234 static struct platform_driver rtd119x_rtc_driver
= {
235 .probe
= rtd119x_rtc_probe
,
236 .remove
= rtd119x_rtc_remove
,
238 .name
= "rtd1295-rtc",
239 .of_match_table
= rtd119x_rtc_dt_ids
,
242 builtin_platform_driver(rtd119x_rtc_driver
);