1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * RTC driver for Rockchip RK808 |
4 | * |
5 | * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd |
6 | * |
7 | * Author: Chris Zhong <zyw@rock-chips.com> |
8 | * Author: Zhang Qing <zhangqing@rock-chips.com> |
9 | */ |
10 | |
11 | #include <linux/module.h> |
12 | #include <linux/kernel.h> |
13 | #include <linux/rtc.h> |
14 | #include <linux/bcd.h> |
15 | #include <linux/mfd/rk808.h> |
16 | #include <linux/platform_device.h> |
17 | |
18 | /* RTC_CTRL_REG bitfields */ |
19 | #define BIT_RTC_CTRL_REG_STOP_RTC_M BIT(0) |
20 | |
21 | /* RK808 has a shadowed register for saving a "frozen" RTC time. |
22 | * When user setting "GET_TIME" to 1, the time will save in this shadowed |
23 | * register. If set "READSEL" to 1, user read rtc time register, actually |
24 | * get the time of that moment. If we need the real time, clr this bit. |
25 | */ |
26 | #define BIT_RTC_CTRL_REG_RTC_GET_TIME BIT(6) |
27 | #define BIT_RTC_CTRL_REG_RTC_READSEL_M BIT(7) |
28 | #define BIT_RTC_INTERRUPTS_REG_IT_ALARM_M BIT(3) |
29 | #define RTC_STATUS_MASK 0xFE |
30 | |
31 | #define SECONDS_REG_MSK 0x7F |
32 | #define MINUTES_REG_MAK 0x7F |
33 | #define HOURS_REG_MSK 0x3F |
34 | #define DAYS_REG_MSK 0x3F |
35 | #define MONTHS_REG_MSK 0x1F |
36 | #define YEARS_REG_MSK 0xFF |
37 | #define WEEKS_REG_MSK 0x7 |
38 | |
39 | /* REG_SECONDS_REG through REG_YEARS_REG is how many registers? */ |
40 | |
41 | #define NUM_TIME_REGS (RK808_WEEKS_REG - RK808_SECONDS_REG + 1) |
42 | #define NUM_ALARM_REGS (RK808_ALARM_YEARS_REG - RK808_ALARM_SECONDS_REG + 1) |
43 | |
44 | struct rk_rtc_compat_reg { |
45 | unsigned int ctrl_reg; |
46 | unsigned int status_reg; |
47 | unsigned int alarm_seconds_reg; |
48 | unsigned int int_reg; |
49 | unsigned int seconds_reg; |
50 | }; |
51 | |
52 | struct rk808_rtc { |
53 | struct regmap *regmap; |
54 | struct rtc_device *rtc; |
55 | struct rk_rtc_compat_reg *creg; |
56 | int irq; |
57 | }; |
58 | |
59 | /* |
60 | * The Rockchip calendar used by the RK808 counts November with 31 days. We use |
61 | * these translation functions to convert its dates to/from the Gregorian |
62 | * calendar used by the rest of the world. We arbitrarily define Jan 1st, 2016 |
63 | * as the day when both calendars were in sync, and treat all other dates |
64 | * relative to that. |
65 | * NOTE: Other system software (e.g. firmware) that reads the same hardware must |
66 | * implement this exact same conversion algorithm, with the same anchor date. |
67 | */ |
68 | static time64_t nov2dec_transitions(struct rtc_time *tm) |
69 | { |
70 | return (tm->tm_year + 1900) - 2016 + (tm->tm_mon + 1 > 11 ? 1 : 0); |
71 | } |
72 | |
73 | static void rockchip_to_gregorian(struct rtc_time *tm) |
74 | { |
75 | /* If it's Nov 31st, rtc_tm_to_time64() will count that like Dec 1st */ |
76 | time64_t time = rtc_tm_to_time64(tm); |
77 | rtc_time64_to_tm(time: time + nov2dec_transitions(tm) * 86400, tm); |
78 | } |
79 | |
80 | static void gregorian_to_rockchip(struct rtc_time *tm) |
81 | { |
82 | time64_t = nov2dec_transitions(tm); |
83 | time64_t time = rtc_tm_to_time64(tm); |
84 | rtc_time64_to_tm(time: time - extra_days * 86400, tm); |
85 | |
86 | /* Compensate if we went back over Nov 31st (will work up to 2381) */ |
87 | if (nov2dec_transitions(tm) < extra_days) { |
88 | if (tm->tm_mon + 1 == 11) |
89 | tm->tm_mday++; /* This may result in 31! */ |
90 | else |
91 | rtc_time64_to_tm(time: time - (extra_days - 1) * 86400, tm); |
92 | } |
93 | } |
94 | |
95 | /* Read current time and date in RTC */ |
96 | static int rk808_rtc_readtime(struct device *dev, struct rtc_time *tm) |
97 | { |
98 | struct rk808_rtc *rk808_rtc = dev_get_drvdata(dev); |
99 | u8 rtc_data[NUM_TIME_REGS]; |
100 | int ret; |
101 | |
102 | /* Force an update of the shadowed registers right now */ |
103 | ret = regmap_update_bits(map: rk808_rtc->regmap, reg: rk808_rtc->creg->ctrl_reg, |
104 | BIT_RTC_CTRL_REG_RTC_GET_TIME, |
105 | BIT_RTC_CTRL_REG_RTC_GET_TIME); |
106 | if (ret) { |
107 | dev_err(dev, "Failed to update bits rtc_ctrl: %d\n" , ret); |
108 | return ret; |
109 | } |
110 | |
111 | /* |
112 | * After we set the GET_TIME bit, the rtc time can't be read |
113 | * immediately. So we should wait up to 31.25 us, about one cycle of |
114 | * 32khz. If we clear the GET_TIME bit here, the time of i2c transfer |
115 | * certainly more than 31.25us: 16 * 2.5us at 400kHz bus frequency. |
116 | */ |
117 | ret = regmap_update_bits(map: rk808_rtc->regmap, reg: rk808_rtc->creg->ctrl_reg, |
118 | BIT_RTC_CTRL_REG_RTC_GET_TIME, |
119 | val: 0); |
120 | if (ret) { |
121 | dev_err(dev, "Failed to update bits rtc_ctrl: %d\n" , ret); |
122 | return ret; |
123 | } |
124 | |
125 | ret = regmap_bulk_read(map: rk808_rtc->regmap, reg: rk808_rtc->creg->seconds_reg, |
126 | val: rtc_data, NUM_TIME_REGS); |
127 | if (ret) { |
128 | dev_err(dev, "Failed to bulk read rtc_data: %d\n" , ret); |
129 | return ret; |
130 | } |
131 | |
132 | tm->tm_sec = bcd2bin(rtc_data[0] & SECONDS_REG_MSK); |
133 | tm->tm_min = bcd2bin(rtc_data[1] & MINUTES_REG_MAK); |
134 | tm->tm_hour = bcd2bin(rtc_data[2] & HOURS_REG_MSK); |
135 | tm->tm_mday = bcd2bin(rtc_data[3] & DAYS_REG_MSK); |
136 | tm->tm_mon = (bcd2bin(rtc_data[4] & MONTHS_REG_MSK)) - 1; |
137 | tm->tm_year = (bcd2bin(rtc_data[5] & YEARS_REG_MSK)) + 100; |
138 | tm->tm_wday = bcd2bin(rtc_data[6] & WEEKS_REG_MSK); |
139 | rockchip_to_gregorian(tm); |
140 | dev_dbg(dev, "RTC date/time %ptRd(%d) %ptRt\n" , tm, tm->tm_wday, tm); |
141 | |
142 | return ret; |
143 | } |
144 | |
145 | /* Set current time and date in RTC */ |
146 | static int rk808_rtc_set_time(struct device *dev, struct rtc_time *tm) |
147 | { |
148 | struct rk808_rtc *rk808_rtc = dev_get_drvdata(dev); |
149 | u8 rtc_data[NUM_TIME_REGS]; |
150 | int ret; |
151 | |
152 | dev_dbg(dev, "set RTC date/time %ptRd(%d) %ptRt\n" , tm, tm->tm_wday, tm); |
153 | gregorian_to_rockchip(tm); |
154 | rtc_data[0] = bin2bcd(tm->tm_sec); |
155 | rtc_data[1] = bin2bcd(tm->tm_min); |
156 | rtc_data[2] = bin2bcd(tm->tm_hour); |
157 | rtc_data[3] = bin2bcd(tm->tm_mday); |
158 | rtc_data[4] = bin2bcd(tm->tm_mon + 1); |
159 | rtc_data[5] = bin2bcd(tm->tm_year - 100); |
160 | rtc_data[6] = bin2bcd(tm->tm_wday); |
161 | |
162 | /* Stop RTC while updating the RTC registers */ |
163 | ret = regmap_update_bits(map: rk808_rtc->regmap, reg: rk808_rtc->creg->ctrl_reg, |
164 | BIT_RTC_CTRL_REG_STOP_RTC_M, |
165 | BIT_RTC_CTRL_REG_STOP_RTC_M); |
166 | if (ret) { |
167 | dev_err(dev, "Failed to update RTC control: %d\n" , ret); |
168 | return ret; |
169 | } |
170 | |
171 | ret = regmap_bulk_write(map: rk808_rtc->regmap, reg: rk808_rtc->creg->seconds_reg, |
172 | val: rtc_data, NUM_TIME_REGS); |
173 | if (ret) { |
174 | dev_err(dev, "Failed to bull write rtc_data: %d\n" , ret); |
175 | return ret; |
176 | } |
177 | /* Start RTC again */ |
178 | ret = regmap_update_bits(map: rk808_rtc->regmap, reg: rk808_rtc->creg->ctrl_reg, |
179 | BIT_RTC_CTRL_REG_STOP_RTC_M, val: 0); |
180 | if (ret) { |
181 | dev_err(dev, "Failed to update RTC control: %d\n" , ret); |
182 | return ret; |
183 | } |
184 | return 0; |
185 | } |
186 | |
187 | /* Read alarm time and date in RTC */ |
188 | static int rk808_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm) |
189 | { |
190 | struct rk808_rtc *rk808_rtc = dev_get_drvdata(dev); |
191 | u8 alrm_data[NUM_ALARM_REGS]; |
192 | uint32_t int_reg; |
193 | int ret; |
194 | |
195 | ret = regmap_bulk_read(map: rk808_rtc->regmap, |
196 | reg: rk808_rtc->creg->alarm_seconds_reg, |
197 | val: alrm_data, NUM_ALARM_REGS); |
198 | if (ret) { |
199 | dev_err(dev, "Failed to read RTC alarm date REG: %d\n" , ret); |
200 | return ret; |
201 | } |
202 | |
203 | alrm->time.tm_sec = bcd2bin(alrm_data[0] & SECONDS_REG_MSK); |
204 | alrm->time.tm_min = bcd2bin(alrm_data[1] & MINUTES_REG_MAK); |
205 | alrm->time.tm_hour = bcd2bin(alrm_data[2] & HOURS_REG_MSK); |
206 | alrm->time.tm_mday = bcd2bin(alrm_data[3] & DAYS_REG_MSK); |
207 | alrm->time.tm_mon = (bcd2bin(alrm_data[4] & MONTHS_REG_MSK)) - 1; |
208 | alrm->time.tm_year = (bcd2bin(alrm_data[5] & YEARS_REG_MSK)) + 100; |
209 | rockchip_to_gregorian(tm: &alrm->time); |
210 | |
211 | ret = regmap_read(map: rk808_rtc->regmap, reg: rk808_rtc->creg->int_reg, val: &int_reg); |
212 | if (ret) { |
213 | dev_err(dev, "Failed to read RTC INT REG: %d\n" , ret); |
214 | return ret; |
215 | } |
216 | |
217 | dev_dbg(dev, "alrm read RTC date/time %ptRd(%d) %ptRt\n" , |
218 | &alrm->time, alrm->time.tm_wday, &alrm->time); |
219 | |
220 | alrm->enabled = (int_reg & BIT_RTC_INTERRUPTS_REG_IT_ALARM_M) ? 1 : 0; |
221 | |
222 | return 0; |
223 | } |
224 | |
225 | static int rk808_rtc_stop_alarm(struct rk808_rtc *rk808_rtc) |
226 | { |
227 | int ret; |
228 | |
229 | ret = regmap_update_bits(map: rk808_rtc->regmap, reg: rk808_rtc->creg->int_reg, |
230 | BIT_RTC_INTERRUPTS_REG_IT_ALARM_M, val: 0); |
231 | |
232 | return ret; |
233 | } |
234 | |
235 | static int rk808_rtc_start_alarm(struct rk808_rtc *rk808_rtc) |
236 | { |
237 | int ret; |
238 | |
239 | ret = regmap_update_bits(map: rk808_rtc->regmap, reg: rk808_rtc->creg->int_reg, |
240 | BIT_RTC_INTERRUPTS_REG_IT_ALARM_M, |
241 | BIT_RTC_INTERRUPTS_REG_IT_ALARM_M); |
242 | |
243 | return ret; |
244 | } |
245 | |
246 | static int rk808_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) |
247 | { |
248 | struct rk808_rtc *rk808_rtc = dev_get_drvdata(dev); |
249 | u8 alrm_data[NUM_ALARM_REGS]; |
250 | int ret; |
251 | |
252 | ret = rk808_rtc_stop_alarm(rk808_rtc); |
253 | if (ret) { |
254 | dev_err(dev, "Failed to stop alarm: %d\n" , ret); |
255 | return ret; |
256 | } |
257 | dev_dbg(dev, "alrm set RTC date/time %ptRd(%d) %ptRt\n" , |
258 | &alrm->time, alrm->time.tm_wday, &alrm->time); |
259 | |
260 | gregorian_to_rockchip(tm: &alrm->time); |
261 | alrm_data[0] = bin2bcd(alrm->time.tm_sec); |
262 | alrm_data[1] = bin2bcd(alrm->time.tm_min); |
263 | alrm_data[2] = bin2bcd(alrm->time.tm_hour); |
264 | alrm_data[3] = bin2bcd(alrm->time.tm_mday); |
265 | alrm_data[4] = bin2bcd(alrm->time.tm_mon + 1); |
266 | alrm_data[5] = bin2bcd(alrm->time.tm_year - 100); |
267 | |
268 | ret = regmap_bulk_write(map: rk808_rtc->regmap, |
269 | reg: rk808_rtc->creg->alarm_seconds_reg, |
270 | val: alrm_data, NUM_ALARM_REGS); |
271 | if (ret) { |
272 | dev_err(dev, "Failed to bulk write: %d\n" , ret); |
273 | return ret; |
274 | } |
275 | if (alrm->enabled) { |
276 | ret = rk808_rtc_start_alarm(rk808_rtc); |
277 | if (ret) { |
278 | dev_err(dev, "Failed to start alarm: %d\n" , ret); |
279 | return ret; |
280 | } |
281 | } |
282 | return 0; |
283 | } |
284 | |
285 | static int rk808_rtc_alarm_irq_enable(struct device *dev, |
286 | unsigned int enabled) |
287 | { |
288 | struct rk808_rtc *rk808_rtc = dev_get_drvdata(dev); |
289 | |
290 | if (enabled) |
291 | return rk808_rtc_start_alarm(rk808_rtc); |
292 | |
293 | return rk808_rtc_stop_alarm(rk808_rtc); |
294 | } |
295 | |
296 | /* |
297 | * We will just handle setting the frequency and make use the framework for |
298 | * reading the periodic interupts. |
299 | * |
300 | * @freq: Current periodic IRQ freq: |
301 | * bit 0: every second |
302 | * bit 1: every minute |
303 | * bit 2: every hour |
304 | * bit 3: every day |
305 | */ |
306 | static irqreturn_t rk808_alarm_irq(int irq, void *data) |
307 | { |
308 | struct rk808_rtc *rk808_rtc = data; |
309 | int ret; |
310 | |
311 | ret = regmap_write(map: rk808_rtc->regmap, reg: rk808_rtc->creg->status_reg, |
312 | RTC_STATUS_MASK); |
313 | if (ret) { |
314 | dev_err(&rk808_rtc->rtc->dev, |
315 | "%s:Failed to update RTC status: %d\n" , __func__, ret); |
316 | return ret; |
317 | } |
318 | |
319 | rtc_update_irq(rtc: rk808_rtc->rtc, num: 1, RTC_IRQF | RTC_AF); |
320 | dev_dbg(&rk808_rtc->rtc->dev, |
321 | "%s:irq=%d\n" , __func__, irq); |
322 | return IRQ_HANDLED; |
323 | } |
324 | |
325 | static const struct rtc_class_ops rk808_rtc_ops = { |
326 | .read_time = rk808_rtc_readtime, |
327 | .set_time = rk808_rtc_set_time, |
328 | .read_alarm = rk808_rtc_readalarm, |
329 | .set_alarm = rk808_rtc_setalarm, |
330 | .alarm_irq_enable = rk808_rtc_alarm_irq_enable, |
331 | }; |
332 | |
333 | #ifdef CONFIG_PM_SLEEP |
334 | /* Turn off the alarm if it should not be a wake source. */ |
335 | static int rk808_rtc_suspend(struct device *dev) |
336 | { |
337 | struct rk808_rtc *rk808_rtc = dev_get_drvdata(dev); |
338 | |
339 | if (device_may_wakeup(dev)) |
340 | enable_irq_wake(irq: rk808_rtc->irq); |
341 | |
342 | return 0; |
343 | } |
344 | |
345 | /* Enable the alarm if it should be enabled (in case it was disabled to |
346 | * prevent use as a wake source). |
347 | */ |
348 | static int rk808_rtc_resume(struct device *dev) |
349 | { |
350 | struct rk808_rtc *rk808_rtc = dev_get_drvdata(dev); |
351 | |
352 | if (device_may_wakeup(dev)) |
353 | disable_irq_wake(irq: rk808_rtc->irq); |
354 | |
355 | return 0; |
356 | } |
357 | #endif |
358 | |
359 | static SIMPLE_DEV_PM_OPS(rk808_rtc_pm_ops, |
360 | rk808_rtc_suspend, rk808_rtc_resume); |
361 | |
362 | static struct rk_rtc_compat_reg rk808_creg = { |
363 | .ctrl_reg = RK808_RTC_CTRL_REG, |
364 | .status_reg = RK808_RTC_STATUS_REG, |
365 | .alarm_seconds_reg = RK808_ALARM_SECONDS_REG, |
366 | .int_reg = RK808_RTC_INT_REG, |
367 | .seconds_reg = RK808_SECONDS_REG, |
368 | }; |
369 | |
370 | static struct rk_rtc_compat_reg rk817_creg = { |
371 | .ctrl_reg = RK817_RTC_CTRL_REG, |
372 | .status_reg = RK817_RTC_STATUS_REG, |
373 | .alarm_seconds_reg = RK817_ALARM_SECONDS_REG, |
374 | .int_reg = RK817_RTC_INT_REG, |
375 | .seconds_reg = RK817_SECONDS_REG, |
376 | }; |
377 | |
378 | static int rk808_rtc_probe(struct platform_device *pdev) |
379 | { |
380 | struct rk808 *rk808 = dev_get_drvdata(dev: pdev->dev.parent); |
381 | struct rk808_rtc *rk808_rtc; |
382 | int ret; |
383 | |
384 | rk808_rtc = devm_kzalloc(dev: &pdev->dev, size: sizeof(*rk808_rtc), GFP_KERNEL); |
385 | if (rk808_rtc == NULL) |
386 | return -ENOMEM; |
387 | |
388 | switch (rk808->variant) { |
389 | case RK809_ID: |
390 | case RK817_ID: |
391 | rk808_rtc->creg = &rk817_creg; |
392 | break; |
393 | default: |
394 | rk808_rtc->creg = &rk808_creg; |
395 | break; |
396 | } |
397 | platform_set_drvdata(pdev, data: rk808_rtc); |
398 | rk808_rtc->regmap = dev_get_regmap(dev: pdev->dev.parent, NULL); |
399 | if (!rk808_rtc->regmap) |
400 | return -ENODEV; |
401 | |
402 | /* start rtc running by default, and use shadowed timer. */ |
403 | ret = regmap_update_bits(map: rk808_rtc->regmap, reg: rk808_rtc->creg->ctrl_reg, |
404 | BIT_RTC_CTRL_REG_STOP_RTC_M | |
405 | BIT_RTC_CTRL_REG_RTC_READSEL_M, |
406 | BIT_RTC_CTRL_REG_RTC_READSEL_M); |
407 | if (ret) { |
408 | dev_err(&pdev->dev, |
409 | "Failed to update RTC control: %d\n" , ret); |
410 | return ret; |
411 | } |
412 | |
413 | ret = regmap_write(map: rk808_rtc->regmap, reg: rk808_rtc->creg->status_reg, |
414 | RTC_STATUS_MASK); |
415 | if (ret) { |
416 | dev_err(&pdev->dev, |
417 | "Failed to write RTC status: %d\n" , ret); |
418 | return ret; |
419 | } |
420 | |
421 | device_init_wakeup(dev: &pdev->dev, enable: 1); |
422 | |
423 | rk808_rtc->rtc = devm_rtc_allocate_device(dev: &pdev->dev); |
424 | if (IS_ERR(ptr: rk808_rtc->rtc)) |
425 | return PTR_ERR(ptr: rk808_rtc->rtc); |
426 | |
427 | rk808_rtc->rtc->ops = &rk808_rtc_ops; |
428 | |
429 | rk808_rtc->irq = platform_get_irq(pdev, 0); |
430 | if (rk808_rtc->irq < 0) |
431 | return rk808_rtc->irq; |
432 | |
433 | /* request alarm irq of rk808 */ |
434 | ret = devm_request_threaded_irq(dev: &pdev->dev, irq: rk808_rtc->irq, NULL, |
435 | thread_fn: rk808_alarm_irq, irqflags: 0, |
436 | devname: "RTC alarm" , dev_id: rk808_rtc); |
437 | if (ret) { |
438 | dev_err(&pdev->dev, "Failed to request alarm IRQ %d: %d\n" , |
439 | rk808_rtc->irq, ret); |
440 | return ret; |
441 | } |
442 | |
443 | return devm_rtc_register_device(rk808_rtc->rtc); |
444 | } |
445 | |
446 | static struct platform_driver rk808_rtc_driver = { |
447 | .probe = rk808_rtc_probe, |
448 | .driver = { |
449 | .name = "rk808-rtc" , |
450 | .pm = &rk808_rtc_pm_ops, |
451 | }, |
452 | }; |
453 | |
454 | module_platform_driver(rk808_rtc_driver); |
455 | |
456 | MODULE_DESCRIPTION("RTC driver for the rk808 series PMICs" ); |
457 | MODULE_AUTHOR("Chris Zhong <zyw@rock-chips.com>" ); |
458 | MODULE_AUTHOR("Zhang Qing <zhangqing@rock-chips.com>" ); |
459 | MODULE_LICENSE("GPL" ); |
460 | MODULE_ALIAS("platform:rk808-rtc" ); |
461 | |