1 // SPDX-License-Identifier: GPL-2.0
3 * Driver for the RTC in Marvell SoCs.
6 #include <linux/init.h>
7 #include <linux/kernel.h>
10 #include <linux/bitops.h>
12 #include <linux/platform_device.h>
14 #include <linux/delay.h>
15 #include <linux/clk.h>
16 #include <linux/gfp.h>
17 #include <linux/module.h>
20 #define RTC_TIME_REG_OFFS 0
21 #define RTC_SECONDS_OFFS 0
22 #define RTC_MINUTES_OFFS 8
23 #define RTC_HOURS_OFFS 16
24 #define RTC_WDAY_OFFS 24
25 #define RTC_HOURS_12H_MODE BIT(22) /* 12 hour mode */
27 #define RTC_DATE_REG_OFFS 4
28 #define RTC_MDAY_OFFS 0
29 #define RTC_MONTH_OFFS 8
30 #define RTC_YEAR_OFFS 16
32 #define RTC_ALARM_TIME_REG_OFFS 8
33 #define RTC_ALARM_DATE_REG_OFFS 0xc
34 #define RTC_ALARM_VALID BIT(7)
36 #define RTC_ALARM_INTERRUPT_MASK_REG_OFFS 0x10
37 #define RTC_ALARM_INTERRUPT_CASUE_REG_OFFS 0x14
39 struct rtc_plat_data
{
40 struct rtc_device
*rtc
;
46 static int mv_rtc_set_time(struct device
*dev
, struct rtc_time
*tm
)
48 struct rtc_plat_data
*pdata
= dev_get_drvdata(dev
);
49 void __iomem
*ioaddr
= pdata
->ioaddr
;
52 rtc_reg
= (bin2bcd(tm
->tm_sec
) << RTC_SECONDS_OFFS
) |
53 (bin2bcd(tm
->tm_min
) << RTC_MINUTES_OFFS
) |
54 (bin2bcd(tm
->tm_hour
) << RTC_HOURS_OFFS
) |
55 (bin2bcd(tm
->tm_wday
) << RTC_WDAY_OFFS
);
56 writel(rtc_reg
, ioaddr
+ RTC_TIME_REG_OFFS
);
58 rtc_reg
= (bin2bcd(tm
->tm_mday
) << RTC_MDAY_OFFS
) |
59 (bin2bcd(tm
->tm_mon
+ 1) << RTC_MONTH_OFFS
) |
60 (bin2bcd(tm
->tm_year
- 100) << RTC_YEAR_OFFS
);
61 writel(rtc_reg
, ioaddr
+ RTC_DATE_REG_OFFS
);
66 static int mv_rtc_read_time(struct device
*dev
, struct rtc_time
*tm
)
68 struct rtc_plat_data
*pdata
= dev_get_drvdata(dev
);
69 void __iomem
*ioaddr
= pdata
->ioaddr
;
70 u32 rtc_time
, rtc_date
;
71 unsigned int year
, month
, day
, hour
, minute
, second
, wday
;
73 rtc_time
= readl(ioaddr
+ RTC_TIME_REG_OFFS
);
74 rtc_date
= readl(ioaddr
+ RTC_DATE_REG_OFFS
);
76 second
= rtc_time
& 0x7f;
77 minute
= (rtc_time
>> RTC_MINUTES_OFFS
) & 0x7f;
78 hour
= (rtc_time
>> RTC_HOURS_OFFS
) & 0x3f; /* assume 24 hour mode */
79 wday
= (rtc_time
>> RTC_WDAY_OFFS
) & 0x7;
81 day
= rtc_date
& 0x3f;
82 month
= (rtc_date
>> RTC_MONTH_OFFS
) & 0x3f;
83 year
= (rtc_date
>> RTC_YEAR_OFFS
) & 0xff;
85 tm
->tm_sec
= bcd2bin(second
);
86 tm
->tm_min
= bcd2bin(minute
);
87 tm
->tm_hour
= bcd2bin(hour
);
88 tm
->tm_mday
= bcd2bin(day
);
89 tm
->tm_wday
= bcd2bin(wday
);
90 tm
->tm_mon
= bcd2bin(month
) - 1;
91 /* hw counts from year 2000, but tm_year is relative to 1900 */
92 tm
->tm_year
= bcd2bin(year
) + 100;
97 static int mv_rtc_read_alarm(struct device
*dev
, struct rtc_wkalrm
*alm
)
99 struct rtc_plat_data
*pdata
= dev_get_drvdata(dev
);
100 void __iomem
*ioaddr
= pdata
->ioaddr
;
101 u32 rtc_time
, rtc_date
;
102 unsigned int year
, month
, day
, hour
, minute
, second
, wday
;
104 rtc_time
= readl(ioaddr
+ RTC_ALARM_TIME_REG_OFFS
);
105 rtc_date
= readl(ioaddr
+ RTC_ALARM_DATE_REG_OFFS
);
107 second
= rtc_time
& 0x7f;
108 minute
= (rtc_time
>> RTC_MINUTES_OFFS
) & 0x7f;
109 hour
= (rtc_time
>> RTC_HOURS_OFFS
) & 0x3f; /* assume 24 hour mode */
110 wday
= (rtc_time
>> RTC_WDAY_OFFS
) & 0x7;
112 day
= rtc_date
& 0x3f;
113 month
= (rtc_date
>> RTC_MONTH_OFFS
) & 0x3f;
114 year
= (rtc_date
>> RTC_YEAR_OFFS
) & 0xff;
116 alm
->time
.tm_sec
= bcd2bin(second
);
117 alm
->time
.tm_min
= bcd2bin(minute
);
118 alm
->time
.tm_hour
= bcd2bin(hour
);
119 alm
->time
.tm_mday
= bcd2bin(day
);
120 alm
->time
.tm_wday
= bcd2bin(wday
);
121 alm
->time
.tm_mon
= bcd2bin(month
) - 1;
122 /* hw counts from year 2000, but tm_year is relative to 1900 */
123 alm
->time
.tm_year
= bcd2bin(year
) + 100;
125 alm
->enabled
= !!readl(ioaddr
+ RTC_ALARM_INTERRUPT_MASK_REG_OFFS
);
127 return rtc_valid_tm(&alm
->time
);
130 static int mv_rtc_set_alarm(struct device
*dev
, struct rtc_wkalrm
*alm
)
132 struct rtc_plat_data
*pdata
= dev_get_drvdata(dev
);
133 void __iomem
*ioaddr
= pdata
->ioaddr
;
136 if (alm
->time
.tm_sec
>= 0)
137 rtc_reg
|= (RTC_ALARM_VALID
| bin2bcd(alm
->time
.tm_sec
))
139 if (alm
->time
.tm_min
>= 0)
140 rtc_reg
|= (RTC_ALARM_VALID
| bin2bcd(alm
->time
.tm_min
))
142 if (alm
->time
.tm_hour
>= 0)
143 rtc_reg
|= (RTC_ALARM_VALID
| bin2bcd(alm
->time
.tm_hour
))
146 writel(rtc_reg
, ioaddr
+ RTC_ALARM_TIME_REG_OFFS
);
148 if (alm
->time
.tm_mday
>= 0)
149 rtc_reg
= (RTC_ALARM_VALID
| bin2bcd(alm
->time
.tm_mday
))
154 if (alm
->time
.tm_mon
>= 0)
155 rtc_reg
|= (RTC_ALARM_VALID
| bin2bcd(alm
->time
.tm_mon
+ 1))
158 if (alm
->time
.tm_year
>= 0)
159 rtc_reg
|= (RTC_ALARM_VALID
| bin2bcd(alm
->time
.tm_year
- 100))
162 writel(rtc_reg
, ioaddr
+ RTC_ALARM_DATE_REG_OFFS
);
163 writel(0, ioaddr
+ RTC_ALARM_INTERRUPT_CASUE_REG_OFFS
);
164 writel(alm
->enabled
? 1 : 0,
165 ioaddr
+ RTC_ALARM_INTERRUPT_MASK_REG_OFFS
);
170 static int mv_rtc_alarm_irq_enable(struct device
*dev
, unsigned int enabled
)
172 struct rtc_plat_data
*pdata
= dev_get_drvdata(dev
);
173 void __iomem
*ioaddr
= pdata
->ioaddr
;
176 return -EINVAL
; /* fall back into rtc-dev's emulation */
179 writel(1, ioaddr
+ RTC_ALARM_INTERRUPT_MASK_REG_OFFS
);
181 writel(0, ioaddr
+ RTC_ALARM_INTERRUPT_MASK_REG_OFFS
);
185 static irqreturn_t
mv_rtc_interrupt(int irq
, void *data
)
187 struct rtc_plat_data
*pdata
= data
;
188 void __iomem
*ioaddr
= pdata
->ioaddr
;
191 if (!readl(ioaddr
+ RTC_ALARM_INTERRUPT_CASUE_REG_OFFS
))
194 /* clear interrupt */
195 writel(0, ioaddr
+ RTC_ALARM_INTERRUPT_CASUE_REG_OFFS
);
196 rtc_update_irq(pdata
->rtc
, 1, RTC_IRQF
| RTC_AF
);
200 static const struct rtc_class_ops mv_rtc_ops
= {
201 .read_time
= mv_rtc_read_time
,
202 .set_time
= mv_rtc_set_time
,
205 static const struct rtc_class_ops mv_rtc_alarm_ops
= {
206 .read_time
= mv_rtc_read_time
,
207 .set_time
= mv_rtc_set_time
,
208 .read_alarm
= mv_rtc_read_alarm
,
209 .set_alarm
= mv_rtc_set_alarm
,
210 .alarm_irq_enable
= mv_rtc_alarm_irq_enable
,
213 static int __init
mv_rtc_probe(struct platform_device
*pdev
)
215 struct rtc_plat_data
*pdata
;
219 pdata
= devm_kzalloc(&pdev
->dev
, sizeof(*pdata
), GFP_KERNEL
);
223 pdata
->ioaddr
= devm_platform_ioremap_resource(pdev
, 0);
224 if (IS_ERR(pdata
->ioaddr
))
225 return PTR_ERR(pdata
->ioaddr
);
227 pdata
->clk
= devm_clk_get(&pdev
->dev
, NULL
);
228 /* Not all SoCs require a clock.*/
229 if (!IS_ERR(pdata
->clk
))
230 clk_prepare_enable(pdata
->clk
);
232 /* make sure the 24 hour mode is enabled */
233 rtc_time
= readl(pdata
->ioaddr
+ RTC_TIME_REG_OFFS
);
234 if (rtc_time
& RTC_HOURS_12H_MODE
) {
235 dev_err(&pdev
->dev
, "12 Hour mode is enabled but not supported.\n");
240 /* make sure it is actually functional */
241 if (rtc_time
== 0x01000000) {
243 rtc_time
= readl(pdata
->ioaddr
+ RTC_TIME_REG_OFFS
);
244 if (rtc_time
== 0x01000000) {
245 dev_err(&pdev
->dev
, "internal RTC not ticking\n");
251 pdata
->irq
= platform_get_irq(pdev
, 0);
253 platform_set_drvdata(pdev
, pdata
);
255 pdata
->rtc
= devm_rtc_allocate_device(&pdev
->dev
);
256 if (IS_ERR(pdata
->rtc
)) {
257 ret
= PTR_ERR(pdata
->rtc
);
261 if (pdata
->irq
>= 0) {
262 writel(0, pdata
->ioaddr
+ RTC_ALARM_INTERRUPT_MASK_REG_OFFS
);
263 if (devm_request_irq(&pdev
->dev
, pdata
->irq
, mv_rtc_interrupt
,
265 pdev
->name
, pdata
) < 0) {
266 dev_warn(&pdev
->dev
, "interrupt not available.\n");
271 if (pdata
->irq
>= 0) {
272 device_init_wakeup(&pdev
->dev
, 1);
273 pdata
->rtc
->ops
= &mv_rtc_alarm_ops
;
275 pdata
->rtc
->ops
= &mv_rtc_ops
;
278 pdata
->rtc
->range_min
= RTC_TIMESTAMP_BEGIN_2000
;
279 pdata
->rtc
->range_max
= RTC_TIMESTAMP_END_2099
;
281 ret
= devm_rtc_register_device(pdata
->rtc
);
285 if (!IS_ERR(pdata
->clk
))
286 clk_disable_unprepare(pdata
->clk
);
291 static int __exit
mv_rtc_remove(struct platform_device
*pdev
)
293 struct rtc_plat_data
*pdata
= platform_get_drvdata(pdev
);
296 device_init_wakeup(&pdev
->dev
, 0);
298 if (!IS_ERR(pdata
->clk
))
299 clk_disable_unprepare(pdata
->clk
);
305 static const struct of_device_id rtc_mv_of_match_table
[] = {
306 { .compatible
= "marvell,orion-rtc", },
309 MODULE_DEVICE_TABLE(of
, rtc_mv_of_match_table
);
312 static struct platform_driver mv_rtc_driver
= {
313 .remove
= __exit_p(mv_rtc_remove
),
316 .of_match_table
= of_match_ptr(rtc_mv_of_match_table
),
320 module_platform_driver_probe(mv_rtc_driver
, mv_rtc_probe
);
322 MODULE_AUTHOR("Saeed Bishara <saeed@marvell.com>");
323 MODULE_DESCRIPTION("Marvell RTC driver");
324 MODULE_LICENSE("GPL");
325 MODULE_ALIAS("platform:rtc-mv");