aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/rtc/rtc-spear.c
diff options
context:
space:
mode:
authorJonathan Herman <hermanjl@cs.unc.edu>2013-01-17 16:15:55 -0500
committerJonathan Herman <hermanjl@cs.unc.edu>2013-01-17 16:15:55 -0500
commit8dea78da5cee153b8af9c07a2745f6c55057fe12 (patch)
treea8f4d49d63b1ecc92f2fddceba0655b2472c5bd9 /drivers/rtc/rtc-spear.c
parent406089d01562f1e2bf9f089fd7637009ebaad589 (diff)
Patched in Tegra support.
Diffstat (limited to 'drivers/rtc/rtc-spear.c')
-rw-r--r--drivers/rtc/rtc-spear.c225
1 files changed, 121 insertions, 104 deletions
diff --git a/drivers/rtc/rtc-spear.c b/drivers/rtc/rtc-spear.c
index c2121b5a01f..893bac2bb21 100644
--- a/drivers/rtc/rtc-spear.c
+++ b/drivers/rtc/rtc-spear.c
@@ -16,7 +16,6 @@
16#include <linux/io.h> 16#include <linux/io.h>
17#include <linux/irq.h> 17#include <linux/irq.h>
18#include <linux/module.h> 18#include <linux/module.h>
19#include <linux/of.h>
20#include <linux/platform_device.h> 19#include <linux/platform_device.h>
21#include <linux/rtc.h> 20#include <linux/rtc.h>
22#include <linux/slab.h> 21#include <linux/slab.h>
@@ -78,11 +77,9 @@
78#define STATUS_FAIL (LOST_WR_TIME | LOST_WR_DATE) 77#define STATUS_FAIL (LOST_WR_TIME | LOST_WR_DATE)
79 78
80struct spear_rtc_config { 79struct spear_rtc_config {
81 struct rtc_device *rtc;
82 struct clk *clk; 80 struct clk *clk;
83 spinlock_t lock; 81 spinlock_t lock;
84 void __iomem *ioaddr; 82 void __iomem *ioaddr;
85 unsigned int irq_wake;
86}; 83};
87 84
88static inline void spear_rtc_clear_interrupt(struct spear_rtc_config *config) 85static inline void spear_rtc_clear_interrupt(struct spear_rtc_config *config)
@@ -152,7 +149,8 @@ static void rtc_wait_not_busy(struct spear_rtc_config *config)
152 149
153static irqreturn_t spear_rtc_irq(int irq, void *dev_id) 150static irqreturn_t spear_rtc_irq(int irq, void *dev_id)
154{ 151{
155 struct spear_rtc_config *config = dev_id; 152 struct rtc_device *rtc = (struct rtc_device *)dev_id;
153 struct spear_rtc_config *config = dev_get_drvdata(&rtc->dev);
156 unsigned long flags, events = 0; 154 unsigned long flags, events = 0;
157 unsigned int irq_data; 155 unsigned int irq_data;
158 156
@@ -163,7 +161,7 @@ static irqreturn_t spear_rtc_irq(int irq, void *dev_id)
163 if ((irq_data & RTC_INT_MASK)) { 161 if ((irq_data & RTC_INT_MASK)) {
164 spear_rtc_clear_interrupt(config); 162 spear_rtc_clear_interrupt(config);
165 events = RTC_IRQF | RTC_AF; 163 events = RTC_IRQF | RTC_AF;
166 rtc_update_irq(config->rtc, 1, events); 164 rtc_update_irq(rtc, 1, events);
167 return IRQ_HANDLED; 165 return IRQ_HANDLED;
168 } else 166 } else
169 return IRQ_NONE; 167 return IRQ_NONE;
@@ -205,7 +203,9 @@ static void bcd2tm(struct rtc_time *tm)
205 */ 203 */
206static int spear_rtc_read_time(struct device *dev, struct rtc_time *tm) 204static int spear_rtc_read_time(struct device *dev, struct rtc_time *tm)
207{ 205{
208 struct spear_rtc_config *config = dev_get_drvdata(dev); 206 struct platform_device *pdev = to_platform_device(dev);
207 struct rtc_device *rtc = platform_get_drvdata(pdev);
208 struct spear_rtc_config *config = dev_get_drvdata(&rtc->dev);
209 unsigned int time, date; 209 unsigned int time, date;
210 210
211 /* we don't report wday/yday/isdst ... */ 211 /* we don't report wday/yday/isdst ... */
@@ -234,8 +234,10 @@ static int spear_rtc_read_time(struct device *dev, struct rtc_time *tm)
234 */ 234 */
235static int spear_rtc_set_time(struct device *dev, struct rtc_time *tm) 235static int spear_rtc_set_time(struct device *dev, struct rtc_time *tm)
236{ 236{
237 struct spear_rtc_config *config = dev_get_drvdata(dev); 237 struct platform_device *pdev = to_platform_device(dev);
238 unsigned int time, date; 238 struct rtc_device *rtc = platform_get_drvdata(pdev);
239 struct spear_rtc_config *config = dev_get_drvdata(&rtc->dev);
240 unsigned int time, date, err = 0;
239 241
240 if (tm2bcd(tm) < 0) 242 if (tm2bcd(tm) < 0)
241 return -EINVAL; 243 return -EINVAL;
@@ -247,8 +249,11 @@ static int spear_rtc_set_time(struct device *dev, struct rtc_time *tm)
247 (tm->tm_year << YEAR_SHIFT); 249 (tm->tm_year << YEAR_SHIFT);
248 writel(time, config->ioaddr + TIME_REG); 250 writel(time, config->ioaddr + TIME_REG);
249 writel(date, config->ioaddr + DATE_REG); 251 writel(date, config->ioaddr + DATE_REG);
252 err = is_write_complete(config);
253 if (err < 0)
254 return err;
250 255
251 return is_write_complete(config); 256 return 0;
252} 257}
253 258
254/* 259/*
@@ -261,7 +266,9 @@ static int spear_rtc_set_time(struct device *dev, struct rtc_time *tm)
261 */ 266 */
262static int spear_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm) 267static int spear_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
263{ 268{
264 struct spear_rtc_config *config = dev_get_drvdata(dev); 269 struct platform_device *pdev = to_platform_device(dev);
270 struct rtc_device *rtc = platform_get_drvdata(pdev);
271 struct spear_rtc_config *config = dev_get_drvdata(&rtc->dev);
265 unsigned int time, date; 272 unsigned int time, date;
266 273
267 rtc_wait_not_busy(config); 274 rtc_wait_not_busy(config);
@@ -291,9 +298,10 @@ static int spear_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
291 */ 298 */
292static int spear_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) 299static int spear_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
293{ 300{
294 struct spear_rtc_config *config = dev_get_drvdata(dev); 301 struct platform_device *pdev = to_platform_device(dev);
295 unsigned int time, date; 302 struct rtc_device *rtc = platform_get_drvdata(pdev);
296 int err; 303 struct spear_rtc_config *config = dev_get_drvdata(&rtc->dev);
304 unsigned int time, date, err = 0;
297 305
298 if (tm2bcd(&alm->time) < 0) 306 if (tm2bcd(&alm->time) < 0)
299 return -EINVAL; 307 return -EINVAL;
@@ -318,44 +326,19 @@ static int spear_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
318 326
319 return 0; 327 return 0;
320} 328}
321
322static int spear_alarm_irq_enable(struct device *dev, unsigned int enabled)
323{
324 struct spear_rtc_config *config = dev_get_drvdata(dev);
325 int ret = 0;
326
327 spear_rtc_clear_interrupt(config);
328
329 switch (enabled) {
330 case 0:
331 /* alarm off */
332 spear_rtc_disable_interrupt(config);
333 break;
334 case 1:
335 /* alarm on */
336 spear_rtc_enable_interrupt(config);
337 break;
338 default:
339 ret = -EINVAL;
340 break;
341 }
342
343 return ret;
344}
345
346static struct rtc_class_ops spear_rtc_ops = { 329static struct rtc_class_ops spear_rtc_ops = {
347 .read_time = spear_rtc_read_time, 330 .read_time = spear_rtc_read_time,
348 .set_time = spear_rtc_set_time, 331 .set_time = spear_rtc_set_time,
349 .read_alarm = spear_rtc_read_alarm, 332 .read_alarm = spear_rtc_read_alarm,
350 .set_alarm = spear_rtc_set_alarm, 333 .set_alarm = spear_rtc_set_alarm,
351 .alarm_irq_enable = spear_alarm_irq_enable,
352}; 334};
353 335
354static int spear_rtc_probe(struct platform_device *pdev) 336static int __devinit spear_rtc_probe(struct platform_device *pdev)
355{ 337{
356 struct resource *res; 338 struct resource *res;
339 struct rtc_device *rtc;
357 struct spear_rtc_config *config; 340 struct spear_rtc_config *config;
358 int status = 0; 341 unsigned int status = 0;
359 int irq; 342 int irq;
360 343
361 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 344 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -363,76 +346,110 @@ static int spear_rtc_probe(struct platform_device *pdev)
363 dev_err(&pdev->dev, "no resource defined\n"); 346 dev_err(&pdev->dev, "no resource defined\n");
364 return -EBUSY; 347 return -EBUSY;
365 } 348 }
349 if (!request_mem_region(res->start, resource_size(res), pdev->name)) {
350 dev_err(&pdev->dev, "rtc region already claimed\n");
351 return -EBUSY;
352 }
366 353
367 config = devm_kzalloc(&pdev->dev, sizeof(*config), GFP_KERNEL); 354 config = kzalloc(sizeof(*config), GFP_KERNEL);
368 if (!config) { 355 if (!config) {
369 dev_err(&pdev->dev, "out of memory\n"); 356 dev_err(&pdev->dev, "out of memory\n");
370 return -ENOMEM; 357 status = -ENOMEM;
358 goto err_release_region;
371 } 359 }
372 360
373 /* alarm irqs */ 361 config->clk = clk_get(&pdev->dev, NULL);
374 irq = platform_get_irq(pdev, 0); 362 if (IS_ERR(config->clk)) {
375 if (irq < 0) { 363 status = PTR_ERR(config->clk);
376 dev_err(&pdev->dev, "no update irq?\n"); 364 goto err_kfree;
377 return irq;
378 } 365 }
379 366
380 status = devm_request_irq(&pdev->dev, irq, spear_rtc_irq, 0, pdev->name, 367 status = clk_enable(config->clk);
381 config); 368 if (status < 0)
382 if (status) { 369 goto err_clk_put;
383 dev_err(&pdev->dev, "Alarm interrupt IRQ%d already claimed\n",
384 irq);
385 return status;
386 }
387 370
388 config->ioaddr = devm_request_and_ioremap(&pdev->dev, res); 371 config->ioaddr = ioremap(res->start, resource_size(res));
389 if (!config->ioaddr) { 372 if (!config->ioaddr) {
390 dev_err(&pdev->dev, "request-ioremap fail\n"); 373 dev_err(&pdev->dev, "ioremap fail\n");
391 return -ENOMEM; 374 status = -ENOMEM;
375 goto err_disable_clock;
392 } 376 }
393 377
394 config->clk = devm_clk_get(&pdev->dev, NULL);
395 if (IS_ERR(config->clk))
396 return PTR_ERR(config->clk);
397
398 status = clk_prepare_enable(config->clk);
399 if (status < 0)
400 return status;
401
402 spin_lock_init(&config->lock); 378 spin_lock_init(&config->lock);
403 platform_set_drvdata(pdev, config);
404 379
405 config->rtc = rtc_device_register(pdev->name, &pdev->dev, 380 rtc = rtc_device_register(pdev->name, &pdev->dev, &spear_rtc_ops,
406 &spear_rtc_ops, THIS_MODULE); 381 THIS_MODULE);
407 if (IS_ERR(config->rtc)) { 382 if (IS_ERR(rtc)) {
408 dev_err(&pdev->dev, "can't register RTC device, err %ld\n", 383 dev_err(&pdev->dev, "can't register RTC device, err %ld\n",
409 PTR_ERR(config->rtc)); 384 PTR_ERR(rtc));
410 status = PTR_ERR(config->rtc); 385 status = PTR_ERR(rtc);
411 goto err_disable_clock; 386 goto err_iounmap;
412 } 387 }
413 388
414 config->rtc->uie_unsupported = 1; 389 platform_set_drvdata(pdev, rtc);
390 dev_set_drvdata(&rtc->dev, config);
391
392 /* alarm irqs */
393 irq = platform_get_irq(pdev, 0);
394 if (irq < 0) {
395 dev_err(&pdev->dev, "no update irq?\n");
396 status = irq;
397 goto err_clear_platdata;
398 }
399
400 status = request_irq(irq, spear_rtc_irq, 0, pdev->name, rtc);
401 if (status) {
402 dev_err(&pdev->dev, "Alarm interrupt IRQ%d already \
403 claimed\n", irq);
404 goto err_clear_platdata;
405 }
415 406
416 if (!device_can_wakeup(&pdev->dev)) 407 if (!device_can_wakeup(&pdev->dev))
417 device_init_wakeup(&pdev->dev, 1); 408 device_init_wakeup(&pdev->dev, 1);
418 409
419 return 0; 410 return 0;
420 411
421err_disable_clock: 412err_clear_platdata:
422 platform_set_drvdata(pdev, NULL); 413 platform_set_drvdata(pdev, NULL);
423 clk_disable_unprepare(config->clk); 414 dev_set_drvdata(&rtc->dev, NULL);
415 rtc_device_unregister(rtc);
416err_iounmap:
417 iounmap(config->ioaddr);
418err_disable_clock:
419 clk_disable(config->clk);
420err_clk_put:
421 clk_put(config->clk);
422err_kfree:
423 kfree(config);
424err_release_region:
425 release_mem_region(res->start, resource_size(res));
424 426
425 return status; 427 return status;
426} 428}
427 429
428static int spear_rtc_remove(struct platform_device *pdev) 430static int __devexit spear_rtc_remove(struct platform_device *pdev)
429{ 431{
430 struct spear_rtc_config *config = platform_get_drvdata(pdev); 432 struct rtc_device *rtc = platform_get_drvdata(pdev);
433 struct spear_rtc_config *config = dev_get_drvdata(&rtc->dev);
434 int irq;
435 struct resource *res;
431 436
432 rtc_device_unregister(config->rtc); 437 /* leave rtc running, but disable irqs */
433 spear_rtc_disable_interrupt(config); 438 spear_rtc_disable_interrupt(config);
434 clk_disable_unprepare(config->clk);
435 device_init_wakeup(&pdev->dev, 0); 439 device_init_wakeup(&pdev->dev, 0);
440 irq = platform_get_irq(pdev, 0);
441 if (irq)
442 free_irq(irq, pdev);
443 clk_disable(config->clk);
444 clk_put(config->clk);
445 iounmap(config->ioaddr);
446 kfree(config);
447 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
448 if (res)
449 release_mem_region(res->start, resource_size(res));
450 platform_set_drvdata(pdev, NULL);
451 dev_set_drvdata(&rtc->dev, NULL);
452 rtc_device_unregister(rtc);
436 453
437 return 0; 454 return 0;
438} 455}
@@ -441,14 +458,14 @@ static int spear_rtc_remove(struct platform_device *pdev)
441 458
442static int spear_rtc_suspend(struct platform_device *pdev, pm_message_t state) 459static int spear_rtc_suspend(struct platform_device *pdev, pm_message_t state)
443{ 460{
444 struct spear_rtc_config *config = platform_get_drvdata(pdev); 461 struct rtc_device *rtc = platform_get_drvdata(pdev);
462 struct spear_rtc_config *config = dev_get_drvdata(&rtc->dev);
445 int irq; 463 int irq;
446 464
447 irq = platform_get_irq(pdev, 0); 465 irq = platform_get_irq(pdev, 0);
448 if (device_may_wakeup(&pdev->dev)) { 466 if (device_may_wakeup(&pdev->dev))
449 if (!enable_irq_wake(irq)) 467 enable_irq_wake(irq);
450 config->irq_wake = 1; 468 else {
451 } else {
452 spear_rtc_disable_interrupt(config); 469 spear_rtc_disable_interrupt(config);
453 clk_disable(config->clk); 470 clk_disable(config->clk);
454 } 471 }
@@ -458,17 +475,15 @@ static int spear_rtc_suspend(struct platform_device *pdev, pm_message_t state)
458 475
459static int spear_rtc_resume(struct platform_device *pdev) 476static int spear_rtc_resume(struct platform_device *pdev)
460{ 477{
461 struct spear_rtc_config *config = platform_get_drvdata(pdev); 478 struct rtc_device *rtc = platform_get_drvdata(pdev);
479 struct spear_rtc_config *config = dev_get_drvdata(&rtc->dev);
462 int irq; 480 int irq;
463 481
464 irq = platform_get_irq(pdev, 0); 482 irq = platform_get_irq(pdev, 0);
465 483
466 if (device_may_wakeup(&pdev->dev)) { 484 if (device_may_wakeup(&pdev->dev))
467 if (config->irq_wake) { 485 disable_irq_wake(irq);
468 disable_irq_wake(irq); 486 else {
469 config->irq_wake = 0;
470 }
471 } else {
472 clk_enable(config->clk); 487 clk_enable(config->clk);
473 spear_rtc_enable_interrupt(config); 488 spear_rtc_enable_interrupt(config);
474 } 489 }
@@ -483,33 +498,35 @@ static int spear_rtc_resume(struct platform_device *pdev)
483 498
484static void spear_rtc_shutdown(struct platform_device *pdev) 499static void spear_rtc_shutdown(struct platform_device *pdev)
485{ 500{
486 struct spear_rtc_config *config = platform_get_drvdata(pdev); 501 struct rtc_device *rtc = platform_get_drvdata(pdev);
502 struct spear_rtc_config *config = dev_get_drvdata(&rtc->dev);
487 503
488 spear_rtc_disable_interrupt(config); 504 spear_rtc_disable_interrupt(config);
489 clk_disable(config->clk); 505 clk_disable(config->clk);
490} 506}
491 507
492#ifdef CONFIG_OF
493static const struct of_device_id spear_rtc_id_table[] = {
494 { .compatible = "st,spear600-rtc" },
495 {}
496};
497MODULE_DEVICE_TABLE(of, spear_rtc_id_table);
498#endif
499
500static struct platform_driver spear_rtc_driver = { 508static struct platform_driver spear_rtc_driver = {
501 .probe = spear_rtc_probe, 509 .probe = spear_rtc_probe,
502 .remove = spear_rtc_remove, 510 .remove = __devexit_p(spear_rtc_remove),
503 .suspend = spear_rtc_suspend, 511 .suspend = spear_rtc_suspend,
504 .resume = spear_rtc_resume, 512 .resume = spear_rtc_resume,
505 .shutdown = spear_rtc_shutdown, 513 .shutdown = spear_rtc_shutdown,
506 .driver = { 514 .driver = {
507 .name = "rtc-spear", 515 .name = "rtc-spear",
508 .of_match_table = of_match_ptr(spear_rtc_id_table),
509 }, 516 },
510}; 517};
511 518
512module_platform_driver(spear_rtc_driver); 519static int __init rtc_init(void)
520{
521 return platform_driver_register(&spear_rtc_driver);
522}
523module_init(rtc_init);
524
525static void __exit rtc_exit(void)
526{
527 platform_driver_unregister(&spear_rtc_driver);
528}
529module_exit(rtc_exit);
513 530
514MODULE_ALIAS("platform:rtc-spear"); 531MODULE_ALIAS("platform:rtc-spear");
515MODULE_AUTHOR("Rajeev Kumar <rajeev-dlh.kumar@st.com>"); 532MODULE_AUTHOR("Rajeev Kumar <rajeev-dlh.kumar@st.com>");