aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/rtc/rtc-sysfs.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/rtc/rtc-sysfs.c')
-rw-r--r--drivers/rtc/rtc-sysfs.c129
1 files changed, 50 insertions, 79 deletions
diff --git a/drivers/rtc/rtc-sysfs.c b/drivers/rtc/rtc-sysfs.c
index 899ab8c514fa..69df94b44841 100644
--- a/drivers/rtc/rtc-sysfs.c
+++ b/drivers/rtc/rtc-sysfs.c
@@ -12,20 +12,26 @@
12#include <linux/module.h> 12#include <linux/module.h>
13#include <linux/rtc.h> 13#include <linux/rtc.h>
14 14
15#include "rtc-core.h"
16
17
15/* device attributes */ 18/* device attributes */
16 19
17static ssize_t rtc_sysfs_show_name(struct class_device *dev, char *buf) 20static ssize_t
21rtc_sysfs_show_name(struct device *dev, struct device_attribute *attr,
22 char *buf)
18{ 23{
19 return sprintf(buf, "%s\n", to_rtc_device(dev)->name); 24 return sprintf(buf, "%s\n", to_rtc_device(dev)->name);
20} 25}
21static CLASS_DEVICE_ATTR(name, S_IRUGO, rtc_sysfs_show_name, NULL);
22 26
23static ssize_t rtc_sysfs_show_date(struct class_device *dev, char *buf) 27static ssize_t
28rtc_sysfs_show_date(struct device *dev, struct device_attribute *attr,
29 char *buf)
24{ 30{
25 ssize_t retval; 31 ssize_t retval;
26 struct rtc_time tm; 32 struct rtc_time tm;
27 33
28 retval = rtc_read_time(dev, &tm); 34 retval = rtc_read_time(to_rtc_device(dev), &tm);
29 if (retval == 0) { 35 if (retval == 0) {
30 retval = sprintf(buf, "%04d-%02d-%02d\n", 36 retval = sprintf(buf, "%04d-%02d-%02d\n",
31 tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); 37 tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
@@ -33,14 +39,15 @@ static ssize_t rtc_sysfs_show_date(struct class_device *dev, char *buf)
33 39
34 return retval; 40 return retval;
35} 41}
36static CLASS_DEVICE_ATTR(date, S_IRUGO, rtc_sysfs_show_date, NULL);
37 42
38static ssize_t rtc_sysfs_show_time(struct class_device *dev, char *buf) 43static ssize_t
44rtc_sysfs_show_time(struct device *dev, struct device_attribute *attr,
45 char *buf)
39{ 46{
40 ssize_t retval; 47 ssize_t retval;
41 struct rtc_time tm; 48 struct rtc_time tm;
42 49
43 retval = rtc_read_time(dev, &tm); 50 retval = rtc_read_time(to_rtc_device(dev), &tm);
44 if (retval == 0) { 51 if (retval == 0) {
45 retval = sprintf(buf, "%02d:%02d:%02d\n", 52 retval = sprintf(buf, "%02d:%02d:%02d\n",
46 tm.tm_hour, tm.tm_min, tm.tm_sec); 53 tm.tm_hour, tm.tm_min, tm.tm_sec);
@@ -48,14 +55,15 @@ static ssize_t rtc_sysfs_show_time(struct class_device *dev, char *buf)
48 55
49 return retval; 56 return retval;
50} 57}
51static CLASS_DEVICE_ATTR(time, S_IRUGO, rtc_sysfs_show_time, NULL);
52 58
53static ssize_t rtc_sysfs_show_since_epoch(struct class_device *dev, char *buf) 59static ssize_t
60rtc_sysfs_show_since_epoch(struct device *dev, struct device_attribute *attr,
61 char *buf)
54{ 62{
55 ssize_t retval; 63 ssize_t retval;
56 struct rtc_time tm; 64 struct rtc_time tm;
57 65
58 retval = rtc_read_time(dev, &tm); 66 retval = rtc_read_time(to_rtc_device(dev), &tm);
59 if (retval == 0) { 67 if (retval == 0) {
60 unsigned long time; 68 unsigned long time;
61 rtc_tm_to_time(&tm, &time); 69 rtc_tm_to_time(&tm, &time);
@@ -64,23 +72,18 @@ static ssize_t rtc_sysfs_show_since_epoch(struct class_device *dev, char *buf)
64 72
65 return retval; 73 return retval;
66} 74}
67static CLASS_DEVICE_ATTR(since_epoch, S_IRUGO, rtc_sysfs_show_since_epoch, NULL);
68
69static struct attribute *rtc_attrs[] = {
70 &class_device_attr_name.attr,
71 &class_device_attr_date.attr,
72 &class_device_attr_time.attr,
73 &class_device_attr_since_epoch.attr,
74 NULL,
75};
76 75
77static struct attribute_group rtc_attr_group = { 76static struct device_attribute rtc_attrs[] = {
78 .attrs = rtc_attrs, 77 __ATTR(name, S_IRUGO, rtc_sysfs_show_name, NULL),
78 __ATTR(date, S_IRUGO, rtc_sysfs_show_date, NULL),
79 __ATTR(time, S_IRUGO, rtc_sysfs_show_time, NULL),
80 __ATTR(since_epoch, S_IRUGO, rtc_sysfs_show_since_epoch, NULL),
81 { },
79}; 82};
80 83
81
82static ssize_t 84static ssize_t
83rtc_sysfs_show_wakealarm(struct class_device *dev, char *buf) 85rtc_sysfs_show_wakealarm(struct device *dev, struct device_attribute *attr,
86 char *buf)
84{ 87{
85 ssize_t retval; 88 ssize_t retval;
86 unsigned long alarm; 89 unsigned long alarm;
@@ -94,7 +97,7 @@ rtc_sysfs_show_wakealarm(struct class_device *dev, char *buf)
94 * REVISIT maybe we should require RTC implementations to 97 * REVISIT maybe we should require RTC implementations to
95 * disable the RTC alarm after it triggers, for uniformity. 98 * disable the RTC alarm after it triggers, for uniformity.
96 */ 99 */
97 retval = rtc_read_alarm(dev, &alm); 100 retval = rtc_read_alarm(to_rtc_device(dev), &alm);
98 if (retval == 0 && alm.enabled) { 101 if (retval == 0 && alm.enabled) {
99 rtc_tm_to_time(&alm.time, &alarm); 102 rtc_tm_to_time(&alm.time, &alarm);
100 retval = sprintf(buf, "%lu\n", alarm); 103 retval = sprintf(buf, "%lu\n", alarm);
@@ -104,16 +107,18 @@ rtc_sysfs_show_wakealarm(struct class_device *dev, char *buf)
104} 107}
105 108
106static ssize_t 109static ssize_t
107rtc_sysfs_set_wakealarm(struct class_device *dev, const char *buf, size_t n) 110rtc_sysfs_set_wakealarm(struct device *dev, struct device_attribute *attr,
111 const char *buf, size_t n)
108{ 112{
109 ssize_t retval; 113 ssize_t retval;
110 unsigned long now, alarm; 114 unsigned long now, alarm;
111 struct rtc_wkalrm alm; 115 struct rtc_wkalrm alm;
116 struct rtc_device *rtc = to_rtc_device(dev);
112 117
113 /* Only request alarms that trigger in the future. Disable them 118 /* Only request alarms that trigger in the future. Disable them
114 * by writing another time, e.g. 0 meaning Jan 1 1970 UTC. 119 * by writing another time, e.g. 0 meaning Jan 1 1970 UTC.
115 */ 120 */
116 retval = rtc_read_time(dev, &alm.time); 121 retval = rtc_read_time(rtc, &alm.time);
117 if (retval < 0) 122 if (retval < 0)
118 return retval; 123 return retval;
119 rtc_tm_to_time(&alm.time, &now); 124 rtc_tm_to_time(&alm.time, &now);
@@ -124,7 +129,7 @@ rtc_sysfs_set_wakealarm(struct class_device *dev, const char *buf, size_t n)
124 * entirely prevent that here, without even the minimal 129 * entirely prevent that here, without even the minimal
125 * locking from the /dev/rtcN api. 130 * locking from the /dev/rtcN api.
126 */ 131 */
127 retval = rtc_read_alarm(dev, &alm); 132 retval = rtc_read_alarm(rtc, &alm);
128 if (retval < 0) 133 if (retval < 0)
129 return retval; 134 return retval;
130 if (alm.enabled) 135 if (alm.enabled)
@@ -141,10 +146,10 @@ rtc_sysfs_set_wakealarm(struct class_device *dev, const char *buf, size_t n)
141 } 146 }
142 rtc_time_to_tm(alarm, &alm.time); 147 rtc_time_to_tm(alarm, &alm.time);
143 148
144 retval = rtc_set_alarm(dev, &alm); 149 retval = rtc_set_alarm(rtc, &alm);
145 return (retval < 0) ? retval : n; 150 return (retval < 0) ? retval : n;
146} 151}
147static const CLASS_DEVICE_ATTR(wakealarm, S_IRUGO | S_IWUSR, 152static DEVICE_ATTR(wakealarm, S_IRUGO | S_IWUSR,
148 rtc_sysfs_show_wakealarm, rtc_sysfs_set_wakealarm); 153 rtc_sysfs_show_wakealarm, rtc_sysfs_set_wakealarm);
149 154
150 155
@@ -153,71 +158,37 @@ static const CLASS_DEVICE_ATTR(wakealarm, S_IRUGO | S_IWUSR,
153 * suspend-to-disk. So: no attribute unless that side effect is possible. 158 * suspend-to-disk. So: no attribute unless that side effect is possible.
154 * (Userspace may disable that mechanism later.) 159 * (Userspace may disable that mechanism later.)
155 */ 160 */
156static inline int rtc_does_wakealarm(struct class_device *class_dev) 161static inline int rtc_does_wakealarm(struct rtc_device *rtc)
157{ 162{
158 struct rtc_device *rtc; 163 if (!device_can_wakeup(rtc->dev.parent))
159
160 if (!device_can_wakeup(class_dev->dev))
161 return 0; 164 return 0;
162 rtc = to_rtc_device(class_dev);
163 return rtc->ops->set_alarm != NULL; 165 return rtc->ops->set_alarm != NULL;
164} 166}
165 167
166 168
167static int rtc_sysfs_add_device(struct class_device *class_dev, 169void rtc_sysfs_add_device(struct rtc_device *rtc)
168 struct class_interface *class_intf)
169{ 170{
170 int err; 171 int err;
171 172
172 dev_dbg(class_dev->dev, "rtc intf: sysfs\n"); 173 /* not all RTCs support both alarms and wakeup */
174 if (!rtc_does_wakealarm(rtc))
175 return;
173 176
174 err = sysfs_create_group(&class_dev->kobj, &rtc_attr_group); 177 err = device_create_file(&rtc->dev, &dev_attr_wakealarm);
175 if (err) 178 if (err)
176 dev_err(class_dev->dev, "failed to create %s\n", 179 dev_err(rtc->dev.parent, "failed to create "
177 "sysfs attributes"); 180 "alarm attribute, %d",
178 else if (rtc_does_wakealarm(class_dev)) { 181 err);
179 /* not all RTCs support both alarms and wakeup */
180 err = class_device_create_file(class_dev,
181 &class_device_attr_wakealarm);
182 if (err) {
183 dev_err(class_dev->dev, "failed to create %s\n",
184 "alarm attribute");
185 sysfs_remove_group(&class_dev->kobj, &rtc_attr_group);
186 }
187 }
188
189 return err;
190} 182}
191 183
192static void rtc_sysfs_remove_device(struct class_device *class_dev, 184void rtc_sysfs_del_device(struct rtc_device *rtc)
193 struct class_interface *class_intf)
194{ 185{
195 if (rtc_does_wakealarm(class_dev)) 186 /* REVISIT did we add it successfully? */
196 class_device_remove_file(class_dev, 187 if (rtc_does_wakealarm(rtc))
197 &class_device_attr_wakealarm); 188 device_remove_file(&rtc->dev, &dev_attr_wakealarm);
198 sysfs_remove_group(&class_dev->kobj, &rtc_attr_group);
199} 189}
200 190
201/* interface registration */ 191void __init rtc_sysfs_init(struct class *rtc_class)
202
203static struct class_interface rtc_sysfs_interface = {
204 .add = &rtc_sysfs_add_device,
205 .remove = &rtc_sysfs_remove_device,
206};
207
208static int __init rtc_sysfs_init(void)
209{ 192{
210 return rtc_interface_register(&rtc_sysfs_interface); 193 rtc_class->dev_attrs = rtc_attrs;
211} 194}
212
213static void __exit rtc_sysfs_exit(void)
214{
215 class_interface_unregister(&rtc_sysfs_interface);
216}
217
218subsys_initcall(rtc_sysfs_init);
219module_exit(rtc_sysfs_exit);
220
221MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
222MODULE_DESCRIPTION("RTC class sysfs interface");
223MODULE_LICENSE("GPL");