1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * drivers/rtc/rtc-vt8500.c |
4 | * |
5 | * Copyright (C) 2010 Alexey Charkov <alchark@gmail.com> |
6 | * |
7 | * Based on rtc-pxa.c |
8 | */ |
9 | |
10 | #include <linux/module.h> |
11 | #include <linux/rtc.h> |
12 | #include <linux/init.h> |
13 | #include <linux/interrupt.h> |
14 | #include <linux/io.h> |
15 | #include <linux/bcd.h> |
16 | #include <linux/platform_device.h> |
17 | #include <linux/slab.h> |
18 | #include <linux/of.h> |
19 | |
20 | /* |
21 | * Register definitions |
22 | */ |
23 | #define VT8500_RTC_TS 0x00 /* Time set */ |
24 | #define VT8500_RTC_DS 0x04 /* Date set */ |
25 | #define VT8500_RTC_AS 0x08 /* Alarm set */ |
26 | #define VT8500_RTC_CR 0x0c /* Control */ |
27 | #define VT8500_RTC_TR 0x10 /* Time read */ |
28 | #define VT8500_RTC_DR 0x14 /* Date read */ |
29 | #define VT8500_RTC_WS 0x18 /* Write status */ |
30 | #define VT8500_RTC_CL 0x20 /* Calibration */ |
31 | #define VT8500_RTC_IS 0x24 /* Interrupt status */ |
32 | #define VT8500_RTC_ST 0x28 /* Status */ |
33 | |
34 | #define INVALID_TIME_BIT (1 << 31) |
35 | |
36 | #define DATE_CENTURY_S 19 |
37 | #define DATE_YEAR_S 11 |
38 | #define DATE_YEAR_MASK (0xff << DATE_YEAR_S) |
39 | #define DATE_MONTH_S 6 |
40 | #define DATE_MONTH_MASK (0x1f << DATE_MONTH_S) |
41 | #define DATE_DAY_MASK 0x3f |
42 | |
43 | #define TIME_DOW_S 20 |
44 | #define TIME_DOW_MASK (0x07 << TIME_DOW_S) |
45 | #define TIME_HOUR_S 14 |
46 | #define TIME_HOUR_MASK (0x3f << TIME_HOUR_S) |
47 | #define TIME_MIN_S 7 |
48 | #define TIME_MIN_MASK (0x7f << TIME_MIN_S) |
49 | #define TIME_SEC_MASK 0x7f |
50 | |
51 | #define ALARM_DAY_S 20 |
52 | #define ALARM_DAY_MASK (0x3f << ALARM_DAY_S) |
53 | |
54 | #define ALARM_DAY_BIT (1 << 29) |
55 | #define ALARM_HOUR_BIT (1 << 28) |
56 | #define ALARM_MIN_BIT (1 << 27) |
57 | #define ALARM_SEC_BIT (1 << 26) |
58 | |
59 | #define ALARM_ENABLE_MASK (ALARM_DAY_BIT \ |
60 | | ALARM_HOUR_BIT \ |
61 | | ALARM_MIN_BIT \ |
62 | | ALARM_SEC_BIT) |
63 | |
64 | #define VT8500_RTC_CR_ENABLE (1 << 0) /* Enable RTC */ |
65 | #define VT8500_RTC_CR_12H (1 << 1) /* 12h time format */ |
66 | #define VT8500_RTC_CR_SM_ENABLE (1 << 2) /* Enable periodic irqs */ |
67 | #define VT8500_RTC_CR_SM_SEC (1 << 3) /* 0: 1Hz/60, 1: 1Hz */ |
68 | #define VT8500_RTC_CR_CALIB (1 << 4) /* Enable calibration */ |
69 | |
70 | #define VT8500_RTC_IS_ALARM (1 << 0) /* Alarm interrupt status */ |
71 | |
72 | struct vt8500_rtc { |
73 | void __iomem *regbase; |
74 | int irq_alarm; |
75 | struct rtc_device *rtc; |
76 | spinlock_t lock; /* Protects this structure */ |
77 | }; |
78 | |
79 | static irqreturn_t vt8500_rtc_irq(int irq, void *dev_id) |
80 | { |
81 | struct vt8500_rtc *vt8500_rtc = dev_id; |
82 | u32 isr; |
83 | unsigned long events = 0; |
84 | |
85 | spin_lock(lock: &vt8500_rtc->lock); |
86 | |
87 | /* clear interrupt sources */ |
88 | isr = readl(addr: vt8500_rtc->regbase + VT8500_RTC_IS); |
89 | writel(val: isr, addr: vt8500_rtc->regbase + VT8500_RTC_IS); |
90 | |
91 | spin_unlock(lock: &vt8500_rtc->lock); |
92 | |
93 | if (isr & VT8500_RTC_IS_ALARM) |
94 | events |= RTC_AF | RTC_IRQF; |
95 | |
96 | rtc_update_irq(rtc: vt8500_rtc->rtc, num: 1, events); |
97 | |
98 | return IRQ_HANDLED; |
99 | } |
100 | |
101 | static int vt8500_rtc_read_time(struct device *dev, struct rtc_time *tm) |
102 | { |
103 | struct vt8500_rtc *vt8500_rtc = dev_get_drvdata(dev); |
104 | u32 date, time; |
105 | |
106 | date = readl(addr: vt8500_rtc->regbase + VT8500_RTC_DR); |
107 | time = readl(addr: vt8500_rtc->regbase + VT8500_RTC_TR); |
108 | |
109 | tm->tm_sec = bcd2bin(time & TIME_SEC_MASK); |
110 | tm->tm_min = bcd2bin((time & TIME_MIN_MASK) >> TIME_MIN_S); |
111 | tm->tm_hour = bcd2bin((time & TIME_HOUR_MASK) >> TIME_HOUR_S); |
112 | tm->tm_mday = bcd2bin(date & DATE_DAY_MASK); |
113 | tm->tm_mon = bcd2bin((date & DATE_MONTH_MASK) >> DATE_MONTH_S) - 1; |
114 | tm->tm_year = bcd2bin((date & DATE_YEAR_MASK) >> DATE_YEAR_S) |
115 | + ((date >> DATE_CENTURY_S) & 1 ? 200 : 100); |
116 | tm->tm_wday = (time & TIME_DOW_MASK) >> TIME_DOW_S; |
117 | |
118 | return 0; |
119 | } |
120 | |
121 | static int vt8500_rtc_set_time(struct device *dev, struct rtc_time *tm) |
122 | { |
123 | struct vt8500_rtc *vt8500_rtc = dev_get_drvdata(dev); |
124 | |
125 | writel(val: (bin2bcd(tm->tm_year % 100) << DATE_YEAR_S) |
126 | | (bin2bcd(tm->tm_mon + 1) << DATE_MONTH_S) |
127 | | (bin2bcd(tm->tm_mday)) |
128 | | ((tm->tm_year >= 200) << DATE_CENTURY_S), |
129 | addr: vt8500_rtc->regbase + VT8500_RTC_DS); |
130 | writel(val: (bin2bcd(tm->tm_wday) << TIME_DOW_S) |
131 | | (bin2bcd(tm->tm_hour) << TIME_HOUR_S) |
132 | | (bin2bcd(tm->tm_min) << TIME_MIN_S) |
133 | | (bin2bcd(tm->tm_sec)), |
134 | addr: vt8500_rtc->regbase + VT8500_RTC_TS); |
135 | |
136 | return 0; |
137 | } |
138 | |
139 | static int vt8500_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) |
140 | { |
141 | struct vt8500_rtc *vt8500_rtc = dev_get_drvdata(dev); |
142 | u32 isr, alarm; |
143 | |
144 | alarm = readl(addr: vt8500_rtc->regbase + VT8500_RTC_AS); |
145 | isr = readl(addr: vt8500_rtc->regbase + VT8500_RTC_IS); |
146 | |
147 | alrm->time.tm_mday = bcd2bin((alarm & ALARM_DAY_MASK) >> ALARM_DAY_S); |
148 | alrm->time.tm_hour = bcd2bin((alarm & TIME_HOUR_MASK) >> TIME_HOUR_S); |
149 | alrm->time.tm_min = bcd2bin((alarm & TIME_MIN_MASK) >> TIME_MIN_S); |
150 | alrm->time.tm_sec = bcd2bin((alarm & TIME_SEC_MASK)); |
151 | |
152 | alrm->enabled = (alarm & ALARM_ENABLE_MASK) ? 1 : 0; |
153 | alrm->pending = (isr & VT8500_RTC_IS_ALARM) ? 1 : 0; |
154 | |
155 | return rtc_valid_tm(tm: &alrm->time); |
156 | } |
157 | |
158 | static int vt8500_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) |
159 | { |
160 | struct vt8500_rtc *vt8500_rtc = dev_get_drvdata(dev); |
161 | |
162 | writel(val: (alrm->enabled ? ALARM_ENABLE_MASK : 0) |
163 | | (bin2bcd(alrm->time.tm_mday) << ALARM_DAY_S) |
164 | | (bin2bcd(alrm->time.tm_hour) << TIME_HOUR_S) |
165 | | (bin2bcd(alrm->time.tm_min) << TIME_MIN_S) |
166 | | (bin2bcd(alrm->time.tm_sec)), |
167 | addr: vt8500_rtc->regbase + VT8500_RTC_AS); |
168 | |
169 | return 0; |
170 | } |
171 | |
172 | static int vt8500_alarm_irq_enable(struct device *dev, unsigned int enabled) |
173 | { |
174 | struct vt8500_rtc *vt8500_rtc = dev_get_drvdata(dev); |
175 | unsigned long tmp = readl(addr: vt8500_rtc->regbase + VT8500_RTC_AS); |
176 | |
177 | if (enabled) |
178 | tmp |= ALARM_ENABLE_MASK; |
179 | else |
180 | tmp &= ~ALARM_ENABLE_MASK; |
181 | |
182 | writel(val: tmp, addr: vt8500_rtc->regbase + VT8500_RTC_AS); |
183 | return 0; |
184 | } |
185 | |
186 | static const struct rtc_class_ops vt8500_rtc_ops = { |
187 | .read_time = vt8500_rtc_read_time, |
188 | .set_time = vt8500_rtc_set_time, |
189 | .read_alarm = vt8500_rtc_read_alarm, |
190 | .set_alarm = vt8500_rtc_set_alarm, |
191 | .alarm_irq_enable = vt8500_alarm_irq_enable, |
192 | }; |
193 | |
194 | static int vt8500_rtc_probe(struct platform_device *pdev) |
195 | { |
196 | struct vt8500_rtc *vt8500_rtc; |
197 | int ret; |
198 | |
199 | vt8500_rtc = devm_kzalloc(dev: &pdev->dev, |
200 | size: sizeof(struct vt8500_rtc), GFP_KERNEL); |
201 | if (!vt8500_rtc) |
202 | return -ENOMEM; |
203 | |
204 | spin_lock_init(&vt8500_rtc->lock); |
205 | platform_set_drvdata(pdev, data: vt8500_rtc); |
206 | |
207 | vt8500_rtc->irq_alarm = platform_get_irq(pdev, 0); |
208 | if (vt8500_rtc->irq_alarm < 0) |
209 | return vt8500_rtc->irq_alarm; |
210 | |
211 | vt8500_rtc->regbase = devm_platform_ioremap_resource(pdev, index: 0); |
212 | if (IS_ERR(ptr: vt8500_rtc->regbase)) |
213 | return PTR_ERR(ptr: vt8500_rtc->regbase); |
214 | |
215 | /* Enable RTC and set it to 24-hour mode */ |
216 | writel(VT8500_RTC_CR_ENABLE, |
217 | addr: vt8500_rtc->regbase + VT8500_RTC_CR); |
218 | |
219 | vt8500_rtc->rtc = devm_rtc_allocate_device(dev: &pdev->dev); |
220 | if (IS_ERR(ptr: vt8500_rtc->rtc)) |
221 | return PTR_ERR(ptr: vt8500_rtc->rtc); |
222 | |
223 | vt8500_rtc->rtc->ops = &vt8500_rtc_ops; |
224 | vt8500_rtc->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000; |
225 | vt8500_rtc->rtc->range_max = RTC_TIMESTAMP_END_2199; |
226 | |
227 | ret = devm_request_irq(dev: &pdev->dev, irq: vt8500_rtc->irq_alarm, |
228 | handler: vt8500_rtc_irq, irqflags: 0, devname: "rtc alarm" , dev_id: vt8500_rtc); |
229 | if (ret < 0) { |
230 | dev_err(&pdev->dev, "can't get irq %i, err %d\n" , |
231 | vt8500_rtc->irq_alarm, ret); |
232 | return ret; |
233 | } |
234 | |
235 | return devm_rtc_register_device(vt8500_rtc->rtc); |
236 | } |
237 | |
238 | static void vt8500_rtc_remove(struct platform_device *pdev) |
239 | { |
240 | struct vt8500_rtc *vt8500_rtc = platform_get_drvdata(pdev); |
241 | |
242 | /* Disable alarm matching */ |
243 | writel(val: 0, addr: vt8500_rtc->regbase + VT8500_RTC_IS); |
244 | } |
245 | |
246 | static const struct of_device_id wmt_dt_ids[] = { |
247 | { .compatible = "via,vt8500-rtc" , }, |
248 | {} |
249 | }; |
250 | MODULE_DEVICE_TABLE(of, wmt_dt_ids); |
251 | |
252 | static struct platform_driver vt8500_rtc_driver = { |
253 | .probe = vt8500_rtc_probe, |
254 | .remove_new = vt8500_rtc_remove, |
255 | .driver = { |
256 | .name = "vt8500-rtc" , |
257 | .of_match_table = wmt_dt_ids, |
258 | }, |
259 | }; |
260 | |
261 | module_platform_driver(vt8500_rtc_driver); |
262 | |
263 | MODULE_AUTHOR("Alexey Charkov <alchark@gmail.com>" ); |
264 | MODULE_DESCRIPTION("VIA VT8500 SoC Realtime Clock Driver (RTC)" ); |
265 | MODULE_LICENSE("GPL v2" ); |
266 | MODULE_ALIAS("platform:vt8500-rtc" ); |
267 | |