.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* drivers/rtc/rtc-s3c.c |
---|
2 | 3 | * |
---|
3 | 4 | * Copyright (c) 2010 Samsung Electronics Co., Ltd. |
---|
.. | .. |
---|
6 | 7 | * Copyright (c) 2004,2006 Simtec Electronics |
---|
7 | 8 | * Ben Dooks, <ben@simtec.co.uk> |
---|
8 | 9 | * http://armlinux.simtec.co.uk/ |
---|
9 | | - * |
---|
10 | | - * This program is free software; you can redistribute it and/or modify |
---|
11 | | - * it under the terms of the GNU General Public License version 2 as |
---|
12 | | - * published by the Free Software Foundation. |
---|
13 | 10 | * |
---|
14 | 11 | * S3C2410/S3C2440/S3C24XX Internal RTC Driver |
---|
15 | 12 | */ |
---|
.. | .. |
---|
26 | 23 | #include <linux/log2.h> |
---|
27 | 24 | #include <linux/slab.h> |
---|
28 | 25 | #include <linux/of.h> |
---|
| 26 | +#include <linux/of_device.h> |
---|
29 | 27 | #include <linux/uaccess.h> |
---|
30 | 28 | #include <linux/io.h> |
---|
31 | 29 | |
---|
.. | .. |
---|
39 | 37 | void __iomem *base; |
---|
40 | 38 | struct clk *rtc_clk; |
---|
41 | 39 | struct clk *rtc_src_clk; |
---|
42 | | - bool clk_disabled; |
---|
| 40 | + bool alarm_enabled; |
---|
43 | 41 | |
---|
44 | 42 | const struct s3c_rtc_data *data; |
---|
45 | 43 | |
---|
.. | .. |
---|
47 | 45 | int irq_tick; |
---|
48 | 46 | |
---|
49 | 47 | spinlock_t pie_lock; |
---|
50 | | - spinlock_t alarm_clk_lock; |
---|
| 48 | + spinlock_t alarm_lock; |
---|
51 | 49 | |
---|
52 | 50 | int ticnt_save; |
---|
53 | 51 | int ticnt_en_save; |
---|
.. | .. |
---|
70 | 68 | |
---|
71 | 69 | static int s3c_rtc_enable_clk(struct s3c_rtc *info) |
---|
72 | 70 | { |
---|
73 | | - unsigned long irq_flags; |
---|
74 | | - int ret = 0; |
---|
| 71 | + int ret; |
---|
75 | 72 | |
---|
76 | | - spin_lock_irqsave(&info->alarm_clk_lock, irq_flags); |
---|
| 73 | + ret = clk_enable(info->rtc_clk); |
---|
| 74 | + if (ret) |
---|
| 75 | + return ret; |
---|
77 | 76 | |
---|
78 | | - if (info->clk_disabled) { |
---|
79 | | - ret = clk_enable(info->rtc_clk); |
---|
80 | | - if (ret) |
---|
81 | | - goto out; |
---|
82 | | - |
---|
83 | | - if (info->data->needs_src_clk) { |
---|
84 | | - ret = clk_enable(info->rtc_src_clk); |
---|
85 | | - if (ret) { |
---|
86 | | - clk_disable(info->rtc_clk); |
---|
87 | | - goto out; |
---|
88 | | - } |
---|
| 77 | + if (info->data->needs_src_clk) { |
---|
| 78 | + ret = clk_enable(info->rtc_src_clk); |
---|
| 79 | + if (ret) { |
---|
| 80 | + clk_disable(info->rtc_clk); |
---|
| 81 | + return ret; |
---|
89 | 82 | } |
---|
90 | | - info->clk_disabled = false; |
---|
91 | 83 | } |
---|
92 | | - |
---|
93 | | -out: |
---|
94 | | - spin_unlock_irqrestore(&info->alarm_clk_lock, irq_flags); |
---|
95 | | - |
---|
96 | | - return ret; |
---|
| 84 | + return 0; |
---|
97 | 85 | } |
---|
98 | 86 | |
---|
99 | 87 | static void s3c_rtc_disable_clk(struct s3c_rtc *info) |
---|
100 | 88 | { |
---|
101 | | - unsigned long irq_flags; |
---|
102 | | - |
---|
103 | | - spin_lock_irqsave(&info->alarm_clk_lock, irq_flags); |
---|
104 | | - if (!info->clk_disabled) { |
---|
105 | | - if (info->data->needs_src_clk) |
---|
106 | | - clk_disable(info->rtc_src_clk); |
---|
107 | | - clk_disable(info->rtc_clk); |
---|
108 | | - info->clk_disabled = true; |
---|
109 | | - } |
---|
110 | | - spin_unlock_irqrestore(&info->alarm_clk_lock, irq_flags); |
---|
| 89 | + if (info->data->needs_src_clk) |
---|
| 90 | + clk_disable(info->rtc_src_clk); |
---|
| 91 | + clk_disable(info->rtc_clk); |
---|
111 | 92 | } |
---|
112 | 93 | |
---|
113 | 94 | /* IRQ Handlers */ |
---|
.. | .. |
---|
135 | 116 | static int s3c_rtc_setaie(struct device *dev, unsigned int enabled) |
---|
136 | 117 | { |
---|
137 | 118 | struct s3c_rtc *info = dev_get_drvdata(dev); |
---|
| 119 | + unsigned long flags; |
---|
138 | 120 | unsigned int tmp; |
---|
139 | 121 | int ret; |
---|
140 | 122 | |
---|
.. | .. |
---|
151 | 133 | |
---|
152 | 134 | writeb(tmp, info->base + S3C2410_RTCALM); |
---|
153 | 135 | |
---|
| 136 | + spin_lock_irqsave(&info->alarm_lock, flags); |
---|
| 137 | + |
---|
| 138 | + if (info->alarm_enabled && !enabled) |
---|
| 139 | + s3c_rtc_disable_clk(info); |
---|
| 140 | + else if (!info->alarm_enabled && enabled) |
---|
| 141 | + ret = s3c_rtc_enable_clk(info); |
---|
| 142 | + |
---|
| 143 | + info->alarm_enabled = enabled; |
---|
| 144 | + spin_unlock_irqrestore(&info->alarm_lock, flags); |
---|
| 145 | + |
---|
154 | 146 | s3c_rtc_disable_clk(info); |
---|
155 | 147 | |
---|
156 | | - if (enabled) { |
---|
157 | | - ret = s3c_rtc_enable_clk(info); |
---|
158 | | - if (ret) |
---|
159 | | - return ret; |
---|
160 | | - } else { |
---|
161 | | - s3c_rtc_disable_clk(info); |
---|
162 | | - } |
---|
163 | | - |
---|
164 | | - return 0; |
---|
| 148 | + return ret; |
---|
165 | 149 | } |
---|
166 | 150 | |
---|
167 | 151 | /* Set RTC frequency */ |
---|
.. | .. |
---|
225 | 209 | s3c_rtc_disable_clk(info); |
---|
226 | 210 | |
---|
227 | 211 | rtc_tm->tm_year += 100; |
---|
228 | | - |
---|
229 | | - dev_dbg(dev, "read time %04d.%02d.%02d %02d:%02d:%02d\n", |
---|
230 | | - 1900 + rtc_tm->tm_year, rtc_tm->tm_mon, rtc_tm->tm_mday, |
---|
231 | | - rtc_tm->tm_hour, rtc_tm->tm_min, rtc_tm->tm_sec); |
---|
232 | | - |
---|
233 | 212 | rtc_tm->tm_mon -= 1; |
---|
234 | 213 | |
---|
| 214 | + dev_dbg(dev, "read time %ptR\n", rtc_tm); |
---|
235 | 215 | return 0; |
---|
236 | 216 | } |
---|
237 | 217 | |
---|
.. | .. |
---|
241 | 221 | int year = tm->tm_year - 100; |
---|
242 | 222 | int ret; |
---|
243 | 223 | |
---|
244 | | - dev_dbg(dev, "set time %04d.%02d.%02d %02d:%02d:%02d\n", |
---|
245 | | - 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday, |
---|
246 | | - tm->tm_hour, tm->tm_min, tm->tm_sec); |
---|
| 224 | + dev_dbg(dev, "set time %ptR\n", tm); |
---|
247 | 225 | |
---|
248 | 226 | /* we get around y2k by simply not supporting it */ |
---|
249 | 227 | |
---|
.. | .. |
---|
292 | 270 | |
---|
293 | 271 | alrm->enabled = (alm_en & S3C2410_RTCALM_ALMEN) ? 1 : 0; |
---|
294 | 272 | |
---|
295 | | - dev_dbg(dev, "read alarm %d, %04d.%02d.%02d %02d:%02d:%02d\n", |
---|
296 | | - alm_en, |
---|
297 | | - 1900 + alm_tm->tm_year, alm_tm->tm_mon, alm_tm->tm_mday, |
---|
298 | | - alm_tm->tm_hour, alm_tm->tm_min, alm_tm->tm_sec); |
---|
| 273 | + dev_dbg(dev, "read alarm %d, %ptR\n", alm_en, alm_tm); |
---|
299 | 274 | |
---|
300 | 275 | /* decode the alarm enable field */ |
---|
301 | 276 | if (alm_en & S3C2410_RTCALM_SECEN) |
---|
.. | .. |
---|
328 | 303 | unsigned int alrm_en; |
---|
329 | 304 | int ret; |
---|
330 | 305 | |
---|
331 | | - dev_dbg(dev, "s3c_rtc_setalarm: %d, %04d.%02d.%02d %02d:%02d:%02d\n", |
---|
332 | | - alrm->enabled, |
---|
333 | | - 1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday, |
---|
334 | | - tm->tm_hour, tm->tm_min, tm->tm_sec); |
---|
| 306 | + dev_dbg(dev, "s3c_rtc_setalarm: %d, %ptR\n", alrm->enabled, tm); |
---|
335 | 307 | |
---|
336 | 308 | ret = s3c_rtc_enable_clk(info); |
---|
337 | 309 | if (ret) |
---|
.. | .. |
---|
369 | 341 | |
---|
370 | 342 | writeb(alrm_en, info->base + S3C2410_RTCALM); |
---|
371 | 343 | |
---|
372 | | - s3c_rtc_disable_clk(info); |
---|
373 | | - |
---|
374 | 344 | s3c_rtc_setaie(dev, alrm->enabled); |
---|
| 345 | + |
---|
| 346 | + s3c_rtc_disable_clk(info); |
---|
375 | 347 | |
---|
376 | 348 | return 0; |
---|
377 | 349 | } |
---|
.. | .. |
---|
468 | 440 | return 0; |
---|
469 | 441 | } |
---|
470 | 442 | |
---|
471 | | -static const struct of_device_id s3c_rtc_dt_match[]; |
---|
472 | | - |
---|
473 | | -static const struct s3c_rtc_data *s3c_rtc_get_data(struct platform_device *pdev) |
---|
474 | | -{ |
---|
475 | | - const struct of_device_id *match; |
---|
476 | | - |
---|
477 | | - match = of_match_node(s3c_rtc_dt_match, pdev->dev.of_node); |
---|
478 | | - return match->data; |
---|
479 | | -} |
---|
480 | | - |
---|
481 | 443 | static int s3c_rtc_probe(struct platform_device *pdev) |
---|
482 | 444 | { |
---|
483 | 445 | struct s3c_rtc *info = NULL; |
---|
484 | 446 | struct rtc_time rtc_tm; |
---|
485 | | - struct resource *res; |
---|
486 | 447 | int ret; |
---|
487 | 448 | |
---|
488 | 449 | info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); |
---|
.. | .. |
---|
491 | 452 | |
---|
492 | 453 | /* find the IRQs */ |
---|
493 | 454 | info->irq_tick = platform_get_irq(pdev, 1); |
---|
494 | | - if (info->irq_tick < 0) { |
---|
495 | | - dev_err(&pdev->dev, "no irq for rtc tick\n"); |
---|
| 455 | + if (info->irq_tick < 0) |
---|
496 | 456 | return info->irq_tick; |
---|
497 | | - } |
---|
498 | 457 | |
---|
499 | 458 | info->dev = &pdev->dev; |
---|
500 | | - info->data = s3c_rtc_get_data(pdev); |
---|
| 459 | + info->data = of_device_get_match_data(&pdev->dev); |
---|
501 | 460 | if (!info->data) { |
---|
502 | 461 | dev_err(&pdev->dev, "failed getting s3c_rtc_data\n"); |
---|
503 | 462 | return -EINVAL; |
---|
504 | 463 | } |
---|
505 | 464 | spin_lock_init(&info->pie_lock); |
---|
506 | | - spin_lock_init(&info->alarm_clk_lock); |
---|
| 465 | + spin_lock_init(&info->alarm_lock); |
---|
507 | 466 | |
---|
508 | 467 | platform_set_drvdata(pdev, info); |
---|
509 | 468 | |
---|
510 | 469 | info->irq_alarm = platform_get_irq(pdev, 0); |
---|
511 | | - if (info->irq_alarm < 0) { |
---|
512 | | - dev_err(&pdev->dev, "no irq for alarm\n"); |
---|
| 470 | + if (info->irq_alarm < 0) |
---|
513 | 471 | return info->irq_alarm; |
---|
514 | | - } |
---|
515 | 472 | |
---|
516 | 473 | dev_dbg(&pdev->dev, "s3c2410_rtc: tick irq %d, alarm irq %d\n", |
---|
517 | 474 | info->irq_tick, info->irq_alarm); |
---|
518 | 475 | |
---|
519 | 476 | /* get the memory region */ |
---|
520 | | - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
---|
521 | | - info->base = devm_ioremap_resource(&pdev->dev, res); |
---|
| 477 | + info->base = devm_platform_ioremap_resource(pdev, 0); |
---|
522 | 478 | if (IS_ERR(info->base)) |
---|
523 | 479 | return PTR_ERR(info->base); |
---|
524 | 480 | |
---|
.. | .. |
---|
538 | 494 | if (info->data->needs_src_clk) { |
---|
539 | 495 | info->rtc_src_clk = devm_clk_get(&pdev->dev, "rtc_src"); |
---|
540 | 496 | if (IS_ERR(info->rtc_src_clk)) { |
---|
541 | | - ret = PTR_ERR(info->rtc_src_clk); |
---|
542 | | - if (ret != -EPROBE_DEFER) |
---|
543 | | - dev_err(&pdev->dev, |
---|
544 | | - "failed to find rtc source clock\n"); |
---|
545 | | - else |
---|
546 | | - dev_dbg(&pdev->dev, |
---|
547 | | - "probe deferred due to missing rtc src clk\n"); |
---|
| 497 | + ret = dev_err_probe(&pdev->dev, PTR_ERR(info->rtc_src_clk), |
---|
| 498 | + "failed to find rtc source clock\n"); |
---|
548 | 499 | goto err_src_clk; |
---|
549 | 500 | } |
---|
550 | 501 | ret = clk_prepare_enable(info->rtc_src_clk); |
---|
.. | .. |
---|
603 | 554 | |
---|
604 | 555 | s3c_rtc_setfreq(info, 1); |
---|
605 | 556 | |
---|
| 557 | + s3c_rtc_disable_clk(info); |
---|
| 558 | + |
---|
606 | 559 | return 0; |
---|
607 | 560 | |
---|
608 | 561 | err_nortc: |
---|