1c5c3e19225217536d90515c494e55e642a21e4faAlessandro Zummo/*
2c5c3e19225217536d90515c494e55e642a21e4faAlessandro Zummo * RTC subsystem, sysfs interface
3c5c3e19225217536d90515c494e55e642a21e4faAlessandro Zummo *
4c5c3e19225217536d90515c494e55e642a21e4faAlessandro Zummo * Copyright (C) 2005 Tower Technologies
5c5c3e19225217536d90515c494e55e642a21e4faAlessandro Zummo * Author: Alessandro Zummo <a.zummo@towertech.it>
6c5c3e19225217536d90515c494e55e642a21e4faAlessandro Zummo *
7c5c3e19225217536d90515c494e55e642a21e4faAlessandro Zummo * This program is free software; you can redistribute it and/or modify
8c5c3e19225217536d90515c494e55e642a21e4faAlessandro Zummo * it under the terms of the GNU General Public License version 2 as
9c5c3e19225217536d90515c494e55e642a21e4faAlessandro Zummo * published by the Free Software Foundation.
10c5c3e19225217536d90515c494e55e642a21e4faAlessandro Zummo*/
11c5c3e19225217536d90515c494e55e642a21e4faAlessandro Zummo
12c5c3e19225217536d90515c494e55e642a21e4faAlessandro Zummo#include <linux/module.h>
13c5c3e19225217536d90515c494e55e642a21e4faAlessandro Zummo#include <linux/rtc.h>
14c5c3e19225217536d90515c494e55e642a21e4faAlessandro Zummo
15ab6a2d70d18edc7a716ef3127b9e13382faec98cDavid Brownell#include "rtc-core.h"
16ab6a2d70d18edc7a716ef3127b9e13382faec98cDavid Brownell
17ab6a2d70d18edc7a716ef3127b9e13382faec98cDavid Brownell
18c5c3e19225217536d90515c494e55e642a21e4faAlessandro Zummo/* device attributes */
19c5c3e19225217536d90515c494e55e642a21e4faAlessandro Zummo
208a0bdfd7a05f5bb0486fbe7146a2cf775957e95eDavid Brownell/*
218a0bdfd7a05f5bb0486fbe7146a2cf775957e95eDavid Brownell * NOTE:  RTC times displayed in sysfs use the RTC's timezone.  That's
228a0bdfd7a05f5bb0486fbe7146a2cf775957e95eDavid Brownell * ideally UTC.  However, PCs that also boot to MS-Windows normally use
238a0bdfd7a05f5bb0486fbe7146a2cf775957e95eDavid Brownell * the local time and change to match daylight savings time.  That affects
248a0bdfd7a05f5bb0486fbe7146a2cf775957e95eDavid Brownell * attributes including date, time, since_epoch, and wakealarm.
258a0bdfd7a05f5bb0486fbe7146a2cf775957e95eDavid Brownell */
268a0bdfd7a05f5bb0486fbe7146a2cf775957e95eDavid Brownell
27cd9662094edf4173e87f0452e57e4eacc228f8ffDavid Brownellstatic ssize_t
28cd9662094edf4173e87f0452e57e4eacc228f8ffDavid Brownellrtc_sysfs_show_name(struct device *dev, struct device_attribute *attr,
29cd9662094edf4173e87f0452e57e4eacc228f8ffDavid Brownell		char *buf)
30c5c3e19225217536d90515c494e55e642a21e4faAlessandro Zummo{
31c5c3e19225217536d90515c494e55e642a21e4faAlessandro Zummo	return sprintf(buf, "%s\n", to_rtc_device(dev)->name);
32c5c3e19225217536d90515c494e55e642a21e4faAlessandro Zummo}
33c5c3e19225217536d90515c494e55e642a21e4faAlessandro Zummo
34cd9662094edf4173e87f0452e57e4eacc228f8ffDavid Brownellstatic ssize_t
35cd9662094edf4173e87f0452e57e4eacc228f8ffDavid Brownellrtc_sysfs_show_date(struct device *dev, struct device_attribute *attr,
36cd9662094edf4173e87f0452e57e4eacc228f8ffDavid Brownell		char *buf)
37c5c3e19225217536d90515c494e55e642a21e4faAlessandro Zummo{
38c5c3e19225217536d90515c494e55e642a21e4faAlessandro Zummo	ssize_t retval;
39c5c3e19225217536d90515c494e55e642a21e4faAlessandro Zummo	struct rtc_time tm;
40c5c3e19225217536d90515c494e55e642a21e4faAlessandro Zummo
41ab6a2d70d18edc7a716ef3127b9e13382faec98cDavid Brownell	retval = rtc_read_time(to_rtc_device(dev), &tm);
42c5c3e19225217536d90515c494e55e642a21e4faAlessandro Zummo	if (retval == 0) {
43c5c3e19225217536d90515c494e55e642a21e4faAlessandro Zummo		retval = sprintf(buf, "%04d-%02d-%02d\n",
44c5c3e19225217536d90515c494e55e642a21e4faAlessandro Zummo			tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
45c5c3e19225217536d90515c494e55e642a21e4faAlessandro Zummo	}
46c5c3e19225217536d90515c494e55e642a21e4faAlessandro Zummo
47c5c3e19225217536d90515c494e55e642a21e4faAlessandro Zummo	return retval;
48c5c3e19225217536d90515c494e55e642a21e4faAlessandro Zummo}
49c5c3e19225217536d90515c494e55e642a21e4faAlessandro Zummo
50cd9662094edf4173e87f0452e57e4eacc228f8ffDavid Brownellstatic ssize_t
51cd9662094edf4173e87f0452e57e4eacc228f8ffDavid Brownellrtc_sysfs_show_time(struct device *dev, struct device_attribute *attr,
52cd9662094edf4173e87f0452e57e4eacc228f8ffDavid Brownell		char *buf)
53c5c3e19225217536d90515c494e55e642a21e4faAlessandro Zummo{
54c5c3e19225217536d90515c494e55e642a21e4faAlessandro Zummo	ssize_t retval;
55c5c3e19225217536d90515c494e55e642a21e4faAlessandro Zummo	struct rtc_time tm;
56c5c3e19225217536d90515c494e55e642a21e4faAlessandro Zummo
57ab6a2d70d18edc7a716ef3127b9e13382faec98cDavid Brownell	retval = rtc_read_time(to_rtc_device(dev), &tm);
58c5c3e19225217536d90515c494e55e642a21e4faAlessandro Zummo	if (retval == 0) {
59c5c3e19225217536d90515c494e55e642a21e4faAlessandro Zummo		retval = sprintf(buf, "%02d:%02d:%02d\n",
60c5c3e19225217536d90515c494e55e642a21e4faAlessandro Zummo			tm.tm_hour, tm.tm_min, tm.tm_sec);
61c5c3e19225217536d90515c494e55e642a21e4faAlessandro Zummo	}
62c5c3e19225217536d90515c494e55e642a21e4faAlessandro Zummo
63c5c3e19225217536d90515c494e55e642a21e4faAlessandro Zummo	return retval;
64c5c3e19225217536d90515c494e55e642a21e4faAlessandro Zummo}
65c5c3e19225217536d90515c494e55e642a21e4faAlessandro Zummo
66cd9662094edf4173e87f0452e57e4eacc228f8ffDavid Brownellstatic ssize_t
67cd9662094edf4173e87f0452e57e4eacc228f8ffDavid Brownellrtc_sysfs_show_since_epoch(struct device *dev, struct device_attribute *attr,
68cd9662094edf4173e87f0452e57e4eacc228f8ffDavid Brownell		char *buf)
69c5c3e19225217536d90515c494e55e642a21e4faAlessandro Zummo{
70c5c3e19225217536d90515c494e55e642a21e4faAlessandro Zummo	ssize_t retval;
71c5c3e19225217536d90515c494e55e642a21e4faAlessandro Zummo	struct rtc_time tm;
72c5c3e19225217536d90515c494e55e642a21e4faAlessandro Zummo
73ab6a2d70d18edc7a716ef3127b9e13382faec98cDavid Brownell	retval = rtc_read_time(to_rtc_device(dev), &tm);
74c5c3e19225217536d90515c494e55e642a21e4faAlessandro Zummo	if (retval == 0) {
75c5c3e19225217536d90515c494e55e642a21e4faAlessandro Zummo		unsigned long time;
76c5c3e19225217536d90515c494e55e642a21e4faAlessandro Zummo		rtc_tm_to_time(&tm, &time);
77c5c3e19225217536d90515c494e55e642a21e4faAlessandro Zummo		retval = sprintf(buf, "%lu\n", time);
78c5c3e19225217536d90515c494e55e642a21e4faAlessandro Zummo	}
79c5c3e19225217536d90515c494e55e642a21e4faAlessandro Zummo
80c5c3e19225217536d90515c494e55e642a21e4faAlessandro Zummo	return retval;
81c5c3e19225217536d90515c494e55e642a21e4faAlessandro Zummo}
82c5c3e19225217536d90515c494e55e642a21e4faAlessandro Zummo
8306c65eb45578c52d1bc69d044239646d4c90e7eaBryan Kadzbanstatic ssize_t
8406c65eb45578c52d1bc69d044239646d4c90e7eaBryan Kadzbanrtc_sysfs_show_max_user_freq(struct device *dev, struct device_attribute *attr,
8506c65eb45578c52d1bc69d044239646d4c90e7eaBryan Kadzban		char *buf)
8606c65eb45578c52d1bc69d044239646d4c90e7eaBryan Kadzban{
8706c65eb45578c52d1bc69d044239646d4c90e7eaBryan Kadzban	return sprintf(buf, "%d\n", to_rtc_device(dev)->max_user_freq);
8806c65eb45578c52d1bc69d044239646d4c90e7eaBryan Kadzban}
8906c65eb45578c52d1bc69d044239646d4c90e7eaBryan Kadzban
9006c65eb45578c52d1bc69d044239646d4c90e7eaBryan Kadzbanstatic ssize_t
9106c65eb45578c52d1bc69d044239646d4c90e7eaBryan Kadzbanrtc_sysfs_set_max_user_freq(struct device *dev, struct device_attribute *attr,
9206c65eb45578c52d1bc69d044239646d4c90e7eaBryan Kadzban		const char *buf, size_t n)
9306c65eb45578c52d1bc69d044239646d4c90e7eaBryan Kadzban{
9406c65eb45578c52d1bc69d044239646d4c90e7eaBryan Kadzban	struct rtc_device *rtc = to_rtc_device(dev);
9506c65eb45578c52d1bc69d044239646d4c90e7eaBryan Kadzban	unsigned long val = simple_strtoul(buf, NULL, 0);
9606c65eb45578c52d1bc69d044239646d4c90e7eaBryan Kadzban
9706c65eb45578c52d1bc69d044239646d4c90e7eaBryan Kadzban	if (val >= 4096 || val == 0)
9806c65eb45578c52d1bc69d044239646d4c90e7eaBryan Kadzban		return -EINVAL;
9906c65eb45578c52d1bc69d044239646d4c90e7eaBryan Kadzban
10006c65eb45578c52d1bc69d044239646d4c90e7eaBryan Kadzban	rtc->max_user_freq = (int)val;
10106c65eb45578c52d1bc69d044239646d4c90e7eaBryan Kadzban
10206c65eb45578c52d1bc69d044239646d4c90e7eaBryan Kadzban	return n;
10306c65eb45578c52d1bc69d044239646d4c90e7eaBryan Kadzban}
10406c65eb45578c52d1bc69d044239646d4c90e7eaBryan Kadzban
105d8c1acb1664d17dd995e34507533321e986d9215Matthew Garrettstatic ssize_t
106d8c1acb1664d17dd995e34507533321e986d9215Matthew Garrettrtc_sysfs_show_hctosys(struct device *dev, struct device_attribute *attr,
107d8c1acb1664d17dd995e34507533321e986d9215Matthew Garrett		char *buf)
108d8c1acb1664d17dd995e34507533321e986d9215Matthew Garrett{
109d8c1acb1664d17dd995e34507533321e986d9215Matthew Garrett#ifdef CONFIG_RTC_HCTOSYS_DEVICE
110d0ab4a4d5094e5d17b103dc5073529a04f00a469Uwe Kleine-König	if (rtc_hctosys_ret == 0 &&
111d0ab4a4d5094e5d17b103dc5073529a04f00a469Uwe Kleine-König			strcmp(dev_name(&to_rtc_device(dev)->dev),
112d0ab4a4d5094e5d17b103dc5073529a04f00a469Uwe Kleine-König				CONFIG_RTC_HCTOSYS_DEVICE) == 0)
113d8c1acb1664d17dd995e34507533321e986d9215Matthew Garrett		return sprintf(buf, "1\n");
114d8c1acb1664d17dd995e34507533321e986d9215Matthew Garrett	else
115d8c1acb1664d17dd995e34507533321e986d9215Matthew Garrett#endif
116d8c1acb1664d17dd995e34507533321e986d9215Matthew Garrett		return sprintf(buf, "0\n");
117d8c1acb1664d17dd995e34507533321e986d9215Matthew Garrett}
118d8c1acb1664d17dd995e34507533321e986d9215Matthew Garrett
119cd9662094edf4173e87f0452e57e4eacc228f8ffDavid Brownellstatic struct device_attribute rtc_attrs[] = {
120446ecbd925dc580c9972049c926c17aa8d967fe4David Brownell	__ATTR(name, S_IRUGO, rtc_sysfs_show_name, NULL),
121446ecbd925dc580c9972049c926c17aa8d967fe4David Brownell	__ATTR(date, S_IRUGO, rtc_sysfs_show_date, NULL),
122446ecbd925dc580c9972049c926c17aa8d967fe4David Brownell	__ATTR(time, S_IRUGO, rtc_sysfs_show_time, NULL),
123446ecbd925dc580c9972049c926c17aa8d967fe4David Brownell	__ATTR(since_epoch, S_IRUGO, rtc_sysfs_show_since_epoch, NULL),
12406c65eb45578c52d1bc69d044239646d4c90e7eaBryan Kadzban	__ATTR(max_user_freq, S_IRUGO | S_IWUSR, rtc_sysfs_show_max_user_freq,
12506c65eb45578c52d1bc69d044239646d4c90e7eaBryan Kadzban			rtc_sysfs_set_max_user_freq),
126d8c1acb1664d17dd995e34507533321e986d9215Matthew Garrett	__ATTR(hctosys, S_IRUGO, rtc_sysfs_show_hctosys, NULL),
127446ecbd925dc580c9972049c926c17aa8d967fe4David Brownell	{ },
128c5c3e19225217536d90515c494e55e642a21e4faAlessandro Zummo};
129c5c3e19225217536d90515c494e55e642a21e4faAlessandro Zummo
1303925a5ce44330767f7f0de5c58c6a797009f0f75David Brownellstatic ssize_t
131cd9662094edf4173e87f0452e57e4eacc228f8ffDavid Brownellrtc_sysfs_show_wakealarm(struct device *dev, struct device_attribute *attr,
132cd9662094edf4173e87f0452e57e4eacc228f8ffDavid Brownell		char *buf)
1333925a5ce44330767f7f0de5c58c6a797009f0f75David Brownell{
1343925a5ce44330767f7f0de5c58c6a797009f0f75David Brownell	ssize_t retval;
1353925a5ce44330767f7f0de5c58c6a797009f0f75David Brownell	unsigned long alarm;
1363925a5ce44330767f7f0de5c58c6a797009f0f75David Brownell	struct rtc_wkalrm alm;
1373925a5ce44330767f7f0de5c58c6a797009f0f75David Brownell
1388a0bdfd7a05f5bb0486fbe7146a2cf775957e95eDavid Brownell	/* Don't show disabled alarms.  For uniformity, RTC alarms are
1398a0bdfd7a05f5bb0486fbe7146a2cf775957e95eDavid Brownell	 * conceptually one-shot, even though some common RTCs (on PCs)
1408a0bdfd7a05f5bb0486fbe7146a2cf775957e95eDavid Brownell	 * don't actually work that way.
1413925a5ce44330767f7f0de5c58c6a797009f0f75David Brownell	 *
1428a0bdfd7a05f5bb0486fbe7146a2cf775957e95eDavid Brownell	 * NOTE: RTC implementations where the alarm doesn't match an
1438a0bdfd7a05f5bb0486fbe7146a2cf775957e95eDavid Brownell	 * exact YYYY-MM-DD HH:MM[:SS] date *must* disable their RTC
1448a0bdfd7a05f5bb0486fbe7146a2cf775957e95eDavid Brownell	 * alarms after they trigger, to ensure one-shot semantics.
1453925a5ce44330767f7f0de5c58c6a797009f0f75David Brownell	 */
146ab6a2d70d18edc7a716ef3127b9e13382faec98cDavid Brownell	retval = rtc_read_alarm(to_rtc_device(dev), &alm);
1473925a5ce44330767f7f0de5c58c6a797009f0f75David Brownell	if (retval == 0 && alm.enabled) {
1483925a5ce44330767f7f0de5c58c6a797009f0f75David Brownell		rtc_tm_to_time(&alm.time, &alarm);
1493925a5ce44330767f7f0de5c58c6a797009f0f75David Brownell		retval = sprintf(buf, "%lu\n", alarm);
1503925a5ce44330767f7f0de5c58c6a797009f0f75David Brownell	}
1513925a5ce44330767f7f0de5c58c6a797009f0f75David Brownell
1523925a5ce44330767f7f0de5c58c6a797009f0f75David Brownell	return retval;
1533925a5ce44330767f7f0de5c58c6a797009f0f75David Brownell}
1543925a5ce44330767f7f0de5c58c6a797009f0f75David Brownell
1553925a5ce44330767f7f0de5c58c6a797009f0f75David Brownellstatic ssize_t
156cd9662094edf4173e87f0452e57e4eacc228f8ffDavid Brownellrtc_sysfs_set_wakealarm(struct device *dev, struct device_attribute *attr,
157cd9662094edf4173e87f0452e57e4eacc228f8ffDavid Brownell		const char *buf, size_t n)
1583925a5ce44330767f7f0de5c58c6a797009f0f75David Brownell{
1593925a5ce44330767f7f0de5c58c6a797009f0f75David Brownell	ssize_t retval;
1603925a5ce44330767f7f0de5c58c6a797009f0f75David Brownell	unsigned long now, alarm;
1613925a5ce44330767f7f0de5c58c6a797009f0f75David Brownell	struct rtc_wkalrm alm;
162ab6a2d70d18edc7a716ef3127b9e13382faec98cDavid Brownell	struct rtc_device *rtc = to_rtc_device(dev);
163c116bc2ae516e9949d645bc75b1ee294ff15db23Zhao Yakui	char *buf_ptr;
164c116bc2ae516e9949d645bc75b1ee294ff15db23Zhao Yakui	int adjust = 0;
1653925a5ce44330767f7f0de5c58c6a797009f0f75David Brownell
1663925a5ce44330767f7f0de5c58c6a797009f0f75David Brownell	/* Only request alarms that trigger in the future.  Disable them
1673925a5ce44330767f7f0de5c58c6a797009f0f75David Brownell	 * by writing another time, e.g. 0 meaning Jan 1 1970 UTC.
1683925a5ce44330767f7f0de5c58c6a797009f0f75David Brownell	 */
169ab6a2d70d18edc7a716ef3127b9e13382faec98cDavid Brownell	retval = rtc_read_time(rtc, &alm.time);
1703925a5ce44330767f7f0de5c58c6a797009f0f75David Brownell	if (retval < 0)
1713925a5ce44330767f7f0de5c58c6a797009f0f75David Brownell		return retval;
1723925a5ce44330767f7f0de5c58c6a797009f0f75David Brownell	rtc_tm_to_time(&alm.time, &now);
1733925a5ce44330767f7f0de5c58c6a797009f0f75David Brownell
174c116bc2ae516e9949d645bc75b1ee294ff15db23Zhao Yakui	buf_ptr = (char *)buf;
175c116bc2ae516e9949d645bc75b1ee294ff15db23Zhao Yakui	if (*buf_ptr == '+') {
176c116bc2ae516e9949d645bc75b1ee294ff15db23Zhao Yakui		buf_ptr++;
177c116bc2ae516e9949d645bc75b1ee294ff15db23Zhao Yakui		adjust = 1;
178c116bc2ae516e9949d645bc75b1ee294ff15db23Zhao Yakui	}
179c116bc2ae516e9949d645bc75b1ee294ff15db23Zhao Yakui	alarm = simple_strtoul(buf_ptr, NULL, 0);
180c116bc2ae516e9949d645bc75b1ee294ff15db23Zhao Yakui	if (adjust) {
181c116bc2ae516e9949d645bc75b1ee294ff15db23Zhao Yakui		alarm += now;
182c116bc2ae516e9949d645bc75b1ee294ff15db23Zhao Yakui	}
1833925a5ce44330767f7f0de5c58c6a797009f0f75David Brownell	if (alarm > now) {
1843925a5ce44330767f7f0de5c58c6a797009f0f75David Brownell		/* Avoid accidentally clobbering active alarms; we can't
1853925a5ce44330767f7f0de5c58c6a797009f0f75David Brownell		 * entirely prevent that here, without even the minimal
1863925a5ce44330767f7f0de5c58c6a797009f0f75David Brownell		 * locking from the /dev/rtcN api.
1873925a5ce44330767f7f0de5c58c6a797009f0f75David Brownell		 */
188ab6a2d70d18edc7a716ef3127b9e13382faec98cDavid Brownell		retval = rtc_read_alarm(rtc, &alm);
1893925a5ce44330767f7f0de5c58c6a797009f0f75David Brownell		if (retval < 0)
1903925a5ce44330767f7f0de5c58c6a797009f0f75David Brownell			return retval;
1913925a5ce44330767f7f0de5c58c6a797009f0f75David Brownell		if (alm.enabled)
1923925a5ce44330767f7f0de5c58c6a797009f0f75David Brownell			return -EBUSY;
1933925a5ce44330767f7f0de5c58c6a797009f0f75David Brownell
1943925a5ce44330767f7f0de5c58c6a797009f0f75David Brownell		alm.enabled = 1;
1953925a5ce44330767f7f0de5c58c6a797009f0f75David Brownell	} else {
1963925a5ce44330767f7f0de5c58c6a797009f0f75David Brownell		alm.enabled = 0;
1973925a5ce44330767f7f0de5c58c6a797009f0f75David Brownell
1983925a5ce44330767f7f0de5c58c6a797009f0f75David Brownell		/* Provide a valid future alarm time.  Linux isn't EFI,
1993925a5ce44330767f7f0de5c58c6a797009f0f75David Brownell		 * this time won't be ignored when disabling the alarm.
2003925a5ce44330767f7f0de5c58c6a797009f0f75David Brownell		 */
2013925a5ce44330767f7f0de5c58c6a797009f0f75David Brownell		alarm = now + 300;
2023925a5ce44330767f7f0de5c58c6a797009f0f75David Brownell	}
2033925a5ce44330767f7f0de5c58c6a797009f0f75David Brownell	rtc_time_to_tm(alarm, &alm.time);
2043925a5ce44330767f7f0de5c58c6a797009f0f75David Brownell
205ab6a2d70d18edc7a716ef3127b9e13382faec98cDavid Brownell	retval = rtc_set_alarm(rtc, &alm);
2063925a5ce44330767f7f0de5c58c6a797009f0f75David Brownell	return (retval < 0) ? retval : n;
2073925a5ce44330767f7f0de5c58c6a797009f0f75David Brownell}
208cd9662094edf4173e87f0452e57e4eacc228f8ffDavid Brownellstatic DEVICE_ATTR(wakealarm, S_IRUGO | S_IWUSR,
2093925a5ce44330767f7f0de5c58c6a797009f0f75David Brownell		rtc_sysfs_show_wakealarm, rtc_sysfs_set_wakealarm);
2103925a5ce44330767f7f0de5c58c6a797009f0f75David Brownell
2113925a5ce44330767f7f0de5c58c6a797009f0f75David Brownell
2123925a5ce44330767f7f0de5c58c6a797009f0f75David Brownell/* The reason to trigger an alarm with no process watching it (via sysfs)
2133925a5ce44330767f7f0de5c58c6a797009f0f75David Brownell * is its side effect:  waking from a system state like suspend-to-RAM or
2143925a5ce44330767f7f0de5c58c6a797009f0f75David Brownell * suspend-to-disk.  So: no attribute unless that side effect is possible.
2153925a5ce44330767f7f0de5c58c6a797009f0f75David Brownell * (Userspace may disable that mechanism later.)
2163925a5ce44330767f7f0de5c58c6a797009f0f75David Brownell */
217446ecbd925dc580c9972049c926c17aa8d967fe4David Brownellstatic inline int rtc_does_wakealarm(struct rtc_device *rtc)
2183925a5ce44330767f7f0de5c58c6a797009f0f75David Brownell{
219cd9662094edf4173e87f0452e57e4eacc228f8ffDavid Brownell	if (!device_can_wakeup(rtc->dev.parent))
2203925a5ce44330767f7f0de5c58c6a797009f0f75David Brownell		return 0;
2213925a5ce44330767f7f0de5c58c6a797009f0f75David Brownell	return rtc->ops->set_alarm != NULL;
2223925a5ce44330767f7f0de5c58c6a797009f0f75David Brownell}
2233925a5ce44330767f7f0de5c58c6a797009f0f75David Brownell
2243925a5ce44330767f7f0de5c58c6a797009f0f75David Brownell
225446ecbd925dc580c9972049c926c17aa8d967fe4David Brownellvoid rtc_sysfs_add_device(struct rtc_device *rtc)
226c5c3e19225217536d90515c494e55e642a21e4faAlessandro Zummo{
227c5c3e19225217536d90515c494e55e642a21e4faAlessandro Zummo	int err;
228c5c3e19225217536d90515c494e55e642a21e4faAlessandro Zummo
229446ecbd925dc580c9972049c926c17aa8d967fe4David Brownell	/* not all RTCs support both alarms and wakeup */
230446ecbd925dc580c9972049c926c17aa8d967fe4David Brownell	if (!rtc_does_wakealarm(rtc))
231446ecbd925dc580c9972049c926c17aa8d967fe4David Brownell		return;
232c5c3e19225217536d90515c494e55e642a21e4faAlessandro Zummo
233cd9662094edf4173e87f0452e57e4eacc228f8ffDavid Brownell	err = device_create_file(&rtc->dev, &dev_attr_wakealarm);
234c5c3e19225217536d90515c494e55e642a21e4faAlessandro Zummo	if (err)
235898eb71cb17644964c5895fb190e79e3d0c49679Joe Perches		dev_err(rtc->dev.parent,
236898eb71cb17644964c5895fb190e79e3d0c49679Joe Perches			"failed to create alarm attribute, %d\n", err);
237c5c3e19225217536d90515c494e55e642a21e4faAlessandro Zummo}
238c5c3e19225217536d90515c494e55e642a21e4faAlessandro Zummo
239446ecbd925dc580c9972049c926c17aa8d967fe4David Brownellvoid rtc_sysfs_del_device(struct rtc_device *rtc)
240c5c3e19225217536d90515c494e55e642a21e4faAlessandro Zummo{
241446ecbd925dc580c9972049c926c17aa8d967fe4David Brownell	/* REVISIT did we add it successfully? */
242446ecbd925dc580c9972049c926c17aa8d967fe4David Brownell	if (rtc_does_wakealarm(rtc))
243cd9662094edf4173e87f0452e57e4eacc228f8ffDavid Brownell		device_remove_file(&rtc->dev, &dev_attr_wakealarm);
244c5c3e19225217536d90515c494e55e642a21e4faAlessandro Zummo}
245c5c3e19225217536d90515c494e55e642a21e4faAlessandro Zummo
246446ecbd925dc580c9972049c926c17aa8d967fe4David Brownellvoid __init rtc_sysfs_init(struct class *rtc_class)
247c5c3e19225217536d90515c494e55e642a21e4faAlessandro Zummo{
248cd9662094edf4173e87f0452e57e4eacc228f8ffDavid Brownell	rtc_class->dev_attrs = rtc_attrs;
249c5c3e19225217536d90515c494e55e642a21e4faAlessandro Zummo}
250