xref: /openbmc/u-boot/drivers/rtc/mvrtc.c (revision 813d1fb5)
183d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
2b608b957SJason Cooper /*
3b608b957SJason Cooper  * Copyright (C) 2011
4b608b957SJason Cooper  * Jason Cooper <u-boot@lakedaemon.net>
5b608b957SJason Cooper  */
6b608b957SJason Cooper 
7b608b957SJason Cooper /*
8b608b957SJason Cooper  * Date & Time support for Marvell Integrated RTC
9b608b957SJason Cooper  */
10b608b957SJason Cooper 
11b608b957SJason Cooper #include <common.h>
12b608b957SJason Cooper #include <command.h>
13*d3671dfcSChris Packham #include <dm.h>
14b608b957SJason Cooper #include <rtc.h>
150ac16bf3SAnatolij Gustschin #include <asm/io.h>
16b608b957SJason Cooper #include "mvrtc.h"
17b608b957SJason Cooper 
18b608b957SJason Cooper /* This RTC does not support century, so we assume 20 */
19b608b957SJason Cooper #define CENTURY 20
20b608b957SJason Cooper 
__mv_rtc_get(struct mvrtc_registers * regs,struct rtc_time * t)21942bb6e2SChris Packham static int __mv_rtc_get(struct mvrtc_registers *regs, struct rtc_time *t)
22b608b957SJason Cooper {
23b608b957SJason Cooper 	u32 time;
24b608b957SJason Cooper 	u32 date;
25b608b957SJason Cooper 
26b608b957SJason Cooper 	/* read the time register */
27942bb6e2SChris Packham 	time = readl(&regs->time);
28b608b957SJason Cooper 
29b608b957SJason Cooper 	/* read the date register */
30942bb6e2SChris Packham 	date = readl(&regs->date);
31b608b957SJason Cooper 
32b608b957SJason Cooper 	/* test for 12 hour clock (can't tell if it's am/pm) */
33b608b957SJason Cooper 	if (time & MVRTC_HRFMT_MSK) {
34b608b957SJason Cooper 		printf("Error: RTC in 12 hour mode, can't determine AM/PM.\n");
35b608b957SJason Cooper 		return -1;
36b608b957SJason Cooper 	}
37b608b957SJason Cooper 
38b608b957SJason Cooper 	/* time */
39b608b957SJason Cooper 	t->tm_sec  = bcd2bin((time >> MVRTC_SEC_SFT)  & MVRTC_SEC_MSK);
40b608b957SJason Cooper 	t->tm_min  = bcd2bin((time >> MVRTC_MIN_SFT)  & MVRTC_MIN_MSK);
41b608b957SJason Cooper 	t->tm_hour = bcd2bin((time >> MVRTC_HOUR_SFT) & MVRTC_HOUR_MSK);
42b608b957SJason Cooper 	t->tm_wday = bcd2bin((time >> MVRTC_DAY_SFT)  & MVRTC_DAY_MSK);
43b608b957SJason Cooper 	t->tm_wday--;
44b608b957SJason Cooper 
45b608b957SJason Cooper 	/* date */
46b608b957SJason Cooper 	t->tm_mday = bcd2bin((date >> MVRTC_DATE_SFT) & MVRTC_DATE_MSK);
47b608b957SJason Cooper 	t->tm_mon  = bcd2bin((date >> MVRTC_MON_SFT)  & MVRTC_MON_MSK);
48b608b957SJason Cooper 	t->tm_year = bcd2bin((date >> MVRTC_YEAR_SFT) & MVRTC_YEAR_MSK);
49b608b957SJason Cooper 	t->tm_year += CENTURY * 100;
50b608b957SJason Cooper 
51b608b957SJason Cooper 	/* not supported in this RTC */
52b608b957SJason Cooper 	t->tm_yday  = 0;
53b608b957SJason Cooper 	t->tm_isdst = 0;
54b608b957SJason Cooper 
55b608b957SJason Cooper 	return 0;
56b608b957SJason Cooper }
57b608b957SJason Cooper 
58942bb6e2SChris Packham #ifndef CONFIG_DM_RTC
rtc_get(struct rtc_time * t)59942bb6e2SChris Packham int rtc_get(struct rtc_time *t)
60942bb6e2SChris Packham {
61942bb6e2SChris Packham 	struct mvrtc_registers *regs;
62942bb6e2SChris Packham 
63942bb6e2SChris Packham 	regs = (struct mvrtc_registers *)KW_RTC_BASE;
64942bb6e2SChris Packham 	return __mv_rtc_get(regs, t);
65942bb6e2SChris Packham }
66942bb6e2SChris Packham #endif /* !CONFIG_DM_RTC */
67942bb6e2SChris Packham 
__mv_rtc_set(struct mvrtc_registers * regs,const struct rtc_time * t)68942bb6e2SChris Packham static int __mv_rtc_set(struct mvrtc_registers *regs, const struct rtc_time *t)
69b608b957SJason Cooper {
70b608b957SJason Cooper 	u32 time = 0; /* sets hour format bit to zero, 24hr format. */
71b608b957SJason Cooper 	u32 date = 0;
72b608b957SJason Cooper 
73b608b957SJason Cooper 	/* check that this code isn't 80+ years old ;-) */
74b608b957SJason Cooper 	if ((t->tm_year / 100) != CENTURY)
75b608b957SJason Cooper 		printf("Warning: Only century %d supported.\n", CENTURY);
76b608b957SJason Cooper 
77b608b957SJason Cooper 	/* time */
78b608b957SJason Cooper 	time |= (bin2bcd(t->tm_sec)      & MVRTC_SEC_MSK)  << MVRTC_SEC_SFT;
79b608b957SJason Cooper 	time |= (bin2bcd(t->tm_min)      & MVRTC_MIN_MSK)  << MVRTC_MIN_SFT;
80b608b957SJason Cooper 	time |= (bin2bcd(t->tm_hour)     & MVRTC_HOUR_MSK) << MVRTC_HOUR_SFT;
81b608b957SJason Cooper 	time |= (bin2bcd(t->tm_wday + 1) & MVRTC_DAY_MSK)  << MVRTC_DAY_SFT;
82b608b957SJason Cooper 
83b608b957SJason Cooper 	/* date */
84b608b957SJason Cooper 	date |= (bin2bcd(t->tm_mday)       & MVRTC_DATE_MSK) << MVRTC_DATE_SFT;
85b608b957SJason Cooper 	date |= (bin2bcd(t->tm_mon)        & MVRTC_MON_MSK)  << MVRTC_MON_SFT;
86b608b957SJason Cooper 	date |= (bin2bcd(t->tm_year % 100) & MVRTC_YEAR_MSK) << MVRTC_YEAR_SFT;
87b608b957SJason Cooper 
88b608b957SJason Cooper 	/* write the time register */
89942bb6e2SChris Packham 	writel(time, &regs->time);
90b608b957SJason Cooper 
91b608b957SJason Cooper 	/* write the date register */
92942bb6e2SChris Packham 	writel(date, &regs->date);
93b608b957SJason Cooper 
94b608b957SJason Cooper 	return 0;
95b608b957SJason Cooper }
96b608b957SJason Cooper 
97942bb6e2SChris Packham #ifndef CONFIG_DM_RTC
rtc_set(struct rtc_time * t)98942bb6e2SChris Packham int rtc_set(struct rtc_time *t)
99942bb6e2SChris Packham {
100942bb6e2SChris Packham 	struct mvrtc_registers *regs;
101942bb6e2SChris Packham 
102942bb6e2SChris Packham 	regs = (struct mvrtc_registers *)KW_RTC_BASE;
103942bb6e2SChris Packham 	return __mv_rtc_set(regs, t);
104942bb6e2SChris Packham }
105942bb6e2SChris Packham #endif /* !CONFIG_DM_RTC */
106942bb6e2SChris Packham 
__mv_rtc_reset(struct mvrtc_registers * regs)107942bb6e2SChris Packham static void __mv_rtc_reset(struct mvrtc_registers *regs)
108b608b957SJason Cooper {
109b608b957SJason Cooper 	u32 time;
110b608b957SJason Cooper 	u32 sec;
111b608b957SJason Cooper 
112b608b957SJason Cooper 	/* no init routine for this RTC needed, just check that it's working */
113942bb6e2SChris Packham 	time = readl(&regs->time);
114b608b957SJason Cooper 	sec  = bcd2bin((time >> MVRTC_SEC_SFT) & MVRTC_SEC_MSK);
115b608b957SJason Cooper 	udelay(1000000);
116942bb6e2SChris Packham 	time = readl(&regs->time);
117b608b957SJason Cooper 
118b608b957SJason Cooper 	if (sec == bcd2bin((time >> MVRTC_SEC_SFT) & MVRTC_SEC_MSK))
119b608b957SJason Cooper 		printf("Error: RTC did not increment.\n");
120b608b957SJason Cooper }
121942bb6e2SChris Packham 
122942bb6e2SChris Packham #ifndef CONFIG_DM_RTC
rtc_reset(void)123942bb6e2SChris Packham void rtc_reset(void)
124942bb6e2SChris Packham {
125942bb6e2SChris Packham 	struct mvrtc_registers *regs;
126942bb6e2SChris Packham 
127942bb6e2SChris Packham 	regs = (struct mvrtc_registers *)KW_RTC_BASE;
128942bb6e2SChris Packham 	__mv_rtc_reset(regs);
129942bb6e2SChris Packham }
130942bb6e2SChris Packham #endif /* !CONFIG_DM_RTC */
131*d3671dfcSChris Packham 
132*d3671dfcSChris Packham #ifdef CONFIG_DM_RTC
mv_rtc_get(struct udevice * dev,struct rtc_time * tm)133*d3671dfcSChris Packham static int mv_rtc_get(struct udevice *dev, struct rtc_time *tm)
134*d3671dfcSChris Packham {
135*d3671dfcSChris Packham 	struct mvrtc_pdata *pdata = dev_get_platdata(dev);
136*d3671dfcSChris Packham 	struct mvrtc_registers *regs = (struct mvrtc_registers *)pdata->iobase;
137*d3671dfcSChris Packham 
138*d3671dfcSChris Packham 	return __mv_rtc_get(regs, tm);
139*d3671dfcSChris Packham }
140*d3671dfcSChris Packham 
mv_rtc_set(struct udevice * dev,const struct rtc_time * tm)141*d3671dfcSChris Packham static int mv_rtc_set(struct udevice *dev, const struct rtc_time *tm)
142*d3671dfcSChris Packham {
143*d3671dfcSChris Packham 	struct mvrtc_pdata *pdata = dev_get_platdata(dev);
144*d3671dfcSChris Packham 	struct mvrtc_registers *regs = (struct mvrtc_registers *)pdata->iobase;
145*d3671dfcSChris Packham 
146*d3671dfcSChris Packham 	return __mv_rtc_set(regs, tm);
147*d3671dfcSChris Packham }
148*d3671dfcSChris Packham 
mv_rtc_reset(struct udevice * dev)149*d3671dfcSChris Packham static int mv_rtc_reset(struct udevice *dev)
150*d3671dfcSChris Packham {
151*d3671dfcSChris Packham 	struct mvrtc_pdata *pdata = dev_get_platdata(dev);
152*d3671dfcSChris Packham 	struct mvrtc_registers *regs = (struct mvrtc_registers *)pdata->iobase;
153*d3671dfcSChris Packham 
154*d3671dfcSChris Packham 	__mv_rtc_reset(regs);
155*d3671dfcSChris Packham 	return 0;
156*d3671dfcSChris Packham }
157*d3671dfcSChris Packham 
158*d3671dfcSChris Packham static const struct rtc_ops mv_rtc_ops = {
159*d3671dfcSChris Packham 	.get = mv_rtc_get,
160*d3671dfcSChris Packham 	.set = mv_rtc_set,
161*d3671dfcSChris Packham 	.reset = mv_rtc_reset,
162*d3671dfcSChris Packham };
163*d3671dfcSChris Packham 
164*d3671dfcSChris Packham static const struct udevice_id mv_rtc_ids[] = {
165*d3671dfcSChris Packham 	{ .compatible = "marvell,kirkwood-rtc" },
166*d3671dfcSChris Packham 	{ .compatible = "marvell,orion-rtc" },
167*d3671dfcSChris Packham 	{ }
168*d3671dfcSChris Packham };
169*d3671dfcSChris Packham 
mv_rtc_ofdata_to_platdata(struct udevice * dev)170*d3671dfcSChris Packham static int mv_rtc_ofdata_to_platdata(struct udevice *dev)
171*d3671dfcSChris Packham {
172*d3671dfcSChris Packham 	struct mvrtc_pdata *pdata = dev_get_platdata(dev);
173*d3671dfcSChris Packham 
174*d3671dfcSChris Packham 	pdata->iobase = devfdt_get_addr(dev);
175*d3671dfcSChris Packham 	return 0;
176*d3671dfcSChris Packham }
177*d3671dfcSChris Packham 
178*d3671dfcSChris Packham U_BOOT_DRIVER(rtc_mv) = {
179*d3671dfcSChris Packham 	.name	= "rtc-mv",
180*d3671dfcSChris Packham 	.id	= UCLASS_RTC,
181*d3671dfcSChris Packham 	.ofdata_to_platdata = mv_rtc_ofdata_to_platdata,
182*d3671dfcSChris Packham 	.of_match = mv_rtc_ids,
183*d3671dfcSChris Packham 	.ops	= &mv_rtc_ops,
184*d3671dfcSChris Packham };
185*d3671dfcSChris Packham #endif /* CONFIG_DM_RTC */
186