parisc: set_time() catch errors
[linux-2.6.git] / drivers / rtc / rtc-parisc.c
1 /* rtc-parisc: RTC for HP PA-RISC firmware
2  *
3  * Copyright (C) 2008 Kyle McMartin <kyle@mcmartin.ca>
4  */
5
6 #include <linux/kernel.h>
7 #include <linux/module.h>
8 #include <linux/time.h>
9 #include <linux/platform_device.h>
10
11 #include <asm/rtc.h>
12
13 /* as simple as can be, and no simpler. */
14 struct parisc_rtc {
15         struct rtc_device *rtc;
16         spinlock_t lock;
17 };
18
19 static int parisc_get_time(struct device *dev, struct rtc_time *tm)
20 {
21         struct parisc_rtc *p = dev_get_drvdata(dev);
22         unsigned long flags, ret;
23
24         spin_lock_irqsave(&p->lock, flags);
25         ret = get_rtc_time(tm);
26         spin_unlock_irqrestore(&p->lock, flags);
27
28         if (ret & RTC_BATT_BAD)
29                 return -EOPNOTSUPP;
30
31         return 0;
32 }
33
34 static int parisc_set_time(struct device *dev, struct rtc_time *tm)
35 {
36         struct parisc_rtc *p = dev_get_drvdata(dev);
37         unsigned long flags;
38         int ret;
39
40         spin_lock_irqsave(&p->lock, flags);
41         ret = set_rtc_time(tm);
42         spin_unlock_irqrestore(&p->lock, flags);
43
44         if (ret < 0)
45                 return -EOPNOTSUPP;
46
47         return 0;
48 }
49
50 static const struct rtc_class_ops parisc_rtc_ops = {
51         .read_time = parisc_get_time,
52         .set_time = parisc_set_time,
53 };
54
55 static int __devinit parisc_rtc_probe(struct platform_device *dev)
56 {
57         struct parisc_rtc *p;
58
59         p = kzalloc(sizeof (*p), GFP_KERNEL);
60         if (!p)
61                 return -ENOMEM;
62
63         spin_lock_init(&p->lock);
64
65         p->rtc = rtc_device_register("rtc-parisc", &dev->dev, &parisc_rtc_ops,
66                                         THIS_MODULE);
67         if (IS_ERR(p->rtc)) {
68                 int err = PTR_ERR(p->rtc);
69                 kfree(p);
70                 return err;
71         }
72
73         platform_set_drvdata(dev, p);
74
75         return 0;
76 }
77
78 static int __devexit parisc_rtc_remove(struct platform_device *dev)
79 {
80         struct parisc_rtc *p = platform_get_drvdata(dev);
81
82         rtc_device_unregister(p->rtc);
83         kfree(p);
84
85         return 0;
86 }
87
88 static struct platform_driver parisc_rtc_driver = {
89         .driver = {
90                 .name = "rtc-parisc",
91                 .owner = THIS_MODULE,
92         },
93         .probe = parisc_rtc_probe,
94         .remove = __devexit_p(parisc_rtc_remove),
95 };
96
97 static int __init parisc_rtc_init(void)
98 {
99         return platform_driver_register(&parisc_rtc_driver);
100 }
101
102 static void __exit parisc_rtc_fini(void)
103 {
104         platform_driver_unregister(&parisc_rtc_driver);
105 }
106
107 module_init(parisc_rtc_init);
108 module_exit(parisc_rtc_fini);
109
110 MODULE_AUTHOR("Kyle McMartin <kyle@mcmartin.ca>");
111 MODULE_LICENSE("GPL");
112 MODULE_DESCRIPTION("HP PA-RISC RTC driver");