From: "Lee, Chun-Yi" <joeyli.kernel@gmail.com>
To: "Rafael J. Wysocki" <rjw@rjwysocki.net>,
Alessandro Zummo <a.zummo@towertech.it>,
"H. Peter Anvin" <hpa@zytor.com>,
Matt Fleming <matt@console-pimps.org>,
Matthew Garrett <matthew.garrett@nebula.com>
Cc: Elliott@hp.com, samer.el-haj-mahmoud@hp.com,
Oliver Neukum <oneukum@suse.de>,
werner@suse.com, trenn@suse.de, JBeulich@suse.com,
linux-kernel@vger.kernel.org, rtc-linux@googlegroups.com,
x86@kernel.org,
"linux-efi@vger.kernel.org" <linux-efi@vger.kernel.org>,
linux-acpi@vger.kernel.org, "Lee, Chun-Yi" <jlee@suse.com>
Subject: [RFC PATCH 05/14] rtc: Add RTC driver of ACPI Time and Alarm Device
Date: Thu, 19 Dec 2013 15:51:46 +0800 [thread overview]
Message-ID: <1387439515-8926-6-git-send-email-jlee@suse.com> (raw)
In-Reply-To: <1387439515-8926-1-git-send-email-jlee@suse.com>
This patch add the RTC driver of ACPI TAD to provide userspace access
ACPI time through RTC interface.
Signed-off-by: Lee, Chun-Yi <jlee@suse.com>
---
drivers/rtc/Kconfig | 10 ++
drivers/rtc/Makefile | 1 +
drivers/rtc/rtc-acpitad.c | 294 +++++++++++++++++++++++++++++++++++++++++++++
drivers/rtc/rtc-dev.c | 4 +
drivers/rtc/rtc-sysfs.c | 8 ++
include/linux/rtc.h | 5 +
include/uapi/linux/rtc.h | 5 +
7 files changed, 327 insertions(+), 0 deletions(-)
create mode 100644 drivers/rtc/rtc-acpitad.c
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 0077302..349dbc4 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -878,6 +878,16 @@ config RTC_DRV_NUC900
If you say yes here you get support for the RTC subsystem of the
NUC910/NUC920 used in embedded systems.
+config RTC_ACPI_TAD
+ tristate "RTC ACPI Time and Alarm Device driver"
+ help
+ This driver exposes ACPI 5.0 Time and Alarm Device as RTC device.
+ Say Y (or M) if you have a computer with ACPI 5.0 firmware that
+ implemented Time and Alarm Device.
+
+ To compile this driver as a module, choose M here:
+ the module will be called rtc_acpitad.
+
comment "on-CPU RTC drivers"
config RTC_DRV_DAVINCI
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 27b4bd8..bca5ab3 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -20,6 +20,7 @@ obj-$(CONFIG_RTC_DRV_88PM860X) += rtc-88pm860x.o
obj-$(CONFIG_RTC_DRV_88PM80X) += rtc-88pm80x.o
obj-$(CONFIG_RTC_DRV_AB3100) += rtc-ab3100.o
obj-$(CONFIG_RTC_DRV_AB8500) += rtc-ab8500.o
+obj-$(CONFIG_RTC_ACPI_TAD) += rtc-acpitad.o
obj-$(CONFIG_RTC_DRV_AS3722) += rtc-as3722.o
obj-$(CONFIG_RTC_DRV_AT32AP700X)+= rtc-at32ap700x.o
obj-$(CONFIG_RTC_DRV_AT91RM9200)+= rtc-at91rm9200.o
diff --git a/drivers/rtc/rtc-acpitad.c b/drivers/rtc/rtc-acpitad.c
new file mode 100644
index 0000000..065a033
--- /dev/null
+++ b/drivers/rtc/rtc-acpitad.c
@@ -0,0 +1,294 @@
+/* A RTC driver for ACPI 5.0 Time and Alarm Device
+ *
+ * Copyright (C) 2013 SUSE Linux Products GmbH. All rights reserved.
+ * Written by Lee, Chun-Yi (jlee@suse.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/rtc.h>
+#include <linux/platform_device.h>
+#include <linux/acpi.h>
+
+/*
+ * returns day of the year [0-365]
+ */
+static inline int
+compute_yday(struct acpi_time *acpit)
+{
+ /* acpi_time.month is in the [1-12] so, we need -1 */
+ return rtc_year_days(acpit->day, acpit->month - 1, acpit->year);
+}
+
+/*
+ * returns day of the week [0-6] 0=Sunday
+ */
+static int
+compute_wday(struct acpi_time *acpit)
+{
+ int y;
+ int ndays = 0;
+
+ if (acpit->year < 1900) {
+ pr_err("ACPI year < 1900, invalid date\n");
+ return -1;
+ }
+
+ for (y = 1900; y < acpit->year; y++)
+ ndays += 365 + (is_leap_year(y) ? 1 : 0);
+
+ ndays += compute_yday(acpit);
+
+ /*
+ * 1=1/1/1900 was a Monday
+ */
+ return (ndays + 1) % 7;
+}
+
+static void
+convert_to_acpi_time(struct rtc_time *tm, struct acpi_time *acpit)
+{
+ acpit->year = tm->tm_year + 1900;
+ acpit->month = tm->tm_mon + 1;
+ acpit->day = tm->tm_mday;
+ acpit->hour = tm->tm_hour;
+ acpit->minute = tm->tm_min;
+ acpit->second = tm->tm_sec;
+ acpit->milliseconds = 0;
+ acpit->daylight = tm->tm_isdst ? ACPI_ISDST : 0;
+}
+
+static void
+convert_from_acpi_time(struct acpi_time *acpit, struct rtc_time *tm)
+{
+ memset(tm, 0, sizeof(*tm));
+ tm->tm_sec = acpit->second;
+ tm->tm_min = acpit->minute;
+ tm->tm_hour = acpit->hour;
+ tm->tm_mday = acpit->day;
+ tm->tm_mon = acpit->month - 1;
+ tm->tm_year = acpit->year - 1900;
+
+ /* day of the week [0-6], Sunday=0 */
+ tm->tm_wday = compute_wday(acpit);
+
+ /* day in the year [1-365]*/
+ tm->tm_yday = compute_yday(acpit);
+
+ switch (acpit->daylight & ACPI_ISDST) {
+ case ACPI_ISDST:
+ tm->tm_isdst = 1;
+ break;
+ case ACPI_TIME_AFFECTED_BY_DAYLIGHT:
+ tm->tm_isdst = 0;
+ break;
+ default:
+ tm->tm_isdst = -1;
+ }
+}
+
+static int acpitad_read_gmtoff(struct device *dev, long int *arg)
+{
+ struct acpi_time *acpit;
+ s16 timezone;
+ int ret;
+
+ acpit = kzalloc(sizeof(struct acpi_time), GFP_KERNEL);
+ if (!acpit)
+ return -ENOMEM;
+
+ ret = acpi_read_time(acpit);
+ if (ret)
+ goto error_read;
+
+ /* transfer minutes to seconds east of UTC for userspace */
+ timezone = (s16)le16_to_cpu(acpit->timezone);
+ *arg = ACPI_UNSPECIFIED_TIMEZONE * 60;
+ if (abs(timezone) != ACPI_UNSPECIFIED_TIMEZONE &&
+ abs(timezone) <= 1440)
+ *arg = timezone * 60 * -1;
+
+error_read:
+ kfree(acpit);
+
+ return ret;
+}
+
+
+static int acpitad_set_gmtoff(struct device *dev, long int arg)
+{
+ struct acpi_time *acpit;
+ s16 timezone;
+ int ret;
+
+ /* transfer seconds east of UTC to minutes for ACPI */
+ timezone = arg / 60 * -1;
+ if (abs(timezone) > 1440 &&
+ abs(timezone) != ACPI_UNSPECIFIED_TIMEZONE)
+ return -EINVAL;
+
+ /* can not use -2047 */
+ if (timezone == ACPI_UNSPECIFIED_TIMEZONE * -1)
+ timezone = ACPI_UNSPECIFIED_TIMEZONE;
+
+ acpit = kzalloc(sizeof(struct acpi_time), GFP_KERNEL);
+ if (!acpit)
+ return -ENOMEM;
+
+ ret = acpi_read_time(acpit);
+ if (ret)
+ goto error_read;
+
+ acpit->timezone = (s16)cpu_to_le16(timezone);
+ ret = acpi_set_time(acpit);
+
+error_read:
+ kfree(acpit);
+
+ return ret;
+}
+
+static int acpitad_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
+{
+ long int gmtoff;
+ int err;
+
+ switch (cmd) {
+ case RTC_RD_GMTOFF:
+ err = acpitad_read_gmtoff(dev, &gmtoff);
+ if (err)
+ return err;
+ return put_user(gmtoff, (unsigned long __user *)arg);
+ case RTC_SET_GMTOFF:
+ return acpitad_set_gmtoff(dev, arg);
+ default:
+ return -ENOIOCTLCMD;
+ }
+
+ return 0;
+}
+
+static int acpitad_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct acpi_time *acpit;
+ int ret;
+
+ acpit = kzalloc(sizeof(struct acpi_time), GFP_KERNEL);
+ if (!acpit)
+ return -ENOMEM;
+
+ ret = acpi_read_time(acpit);
+ if (ret)
+ return ret;
+
+ convert_from_acpi_time(acpit, tm);
+
+ return rtc_valid_tm(tm);
+}
+
+static int acpitad_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct acpi_time *acpit;
+ int ret;
+
+ acpit = kzalloc(sizeof(struct acpi_time), GFP_KERNEL);
+ if (!acpit)
+ return -ENOMEM;
+
+ /* read current timzone to avoid overwrite it by set time */
+ ret = acpi_read_time(acpit);
+ if (ret)
+ goto error_read;
+
+ convert_to_acpi_time(tm, acpit);
+
+ ret = acpi_set_time(acpit);
+
+error_read:
+ kfree(acpit);
+ return ret;
+}
+
+static struct rtc_class_ops acpi_rtc_ops = {
+ .ioctl = acpitad_rtc_ioctl,
+ .read_time = acpitad_read_time,
+ .set_time = acpitad_set_time,
+};
+
+static int acpitad_rtc_probe(struct platform_device *dev)
+{
+ unsigned long cap;
+ struct rtc_device *rtc;
+ int ret;
+
+ ret = acpi_tad_get_capability(&cap);
+ if (ret)
+ return ret;
+
+ if (!(cap & TAD_CAP_GETSETTIME)) {
+ acpi_rtc_ops.read_time = NULL;
+ acpi_rtc_ops.set_time = NULL;
+ pr_warn("No get/set time support\n");
+ }
+
+ /* ACPI Alarm at least need AC wake capability */
+ if (!(cap & TAD_CAP_ACWAKE)) {
+ acpi_rtc_ops.read_alarm = NULL;
+ acpi_rtc_ops.set_alarm = NULL;
+ pr_warn("No AC wake support\n");
+ }
+
+ /* register rtc device */
+ rtc = rtc_device_register("rtc-acpitad", &dev->dev, &acpi_rtc_ops,
+ THIS_MODULE);
+ if (IS_ERR(rtc))
+ return PTR_ERR(rtc);
+
+ rtc->uie_unsupported = 1;
+ rtc->caps = (RTC_TZ_CAP | RTC_DST_CAP);
+ platform_set_drvdata(dev, rtc);
+
+ return 0;
+}
+
+static int acpitad_rtc_remove(struct platform_device *dev)
+{
+ struct rtc_device *rtc = platform_get_drvdata(dev);
+
+ rtc_device_unregister(rtc);
+
+ return 0;
+}
+
+static struct platform_driver acpitad_rtc_driver = {
+ .driver = {
+ .name = "rtc-acpitad",
+ .owner = THIS_MODULE,
+ },
+ .probe = acpitad_rtc_probe,
+ .remove = acpitad_rtc_remove,
+};
+
+static int __init acpitad_rtc_init(void)
+{
+ return platform_driver_register(&acpitad_rtc_driver);
+}
+
+static void __exit acpitad_rtc_exit(void)
+{
+ platform_driver_unregister(&acpitad_rtc_driver);
+}
+
+module_init(acpitad_rtc_init);
+module_exit(acpitad_rtc_exit);
+
+MODULE_AUTHOR("Lee, Chun-Yi <jlee@suse.com>");
+MODULE_DESCRIPTION("RTC ACPI Time and Alarm Device driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:rtc-acpitad");
diff --git a/drivers/rtc/rtc-dev.c b/drivers/rtc/rtc-dev.c
index d049393..aab70e7 100644
--- a/drivers/rtc/rtc-dev.c
+++ b/drivers/rtc/rtc-dev.c
@@ -398,6 +398,10 @@ static long rtc_dev_ioctl(struct file *file,
err = -EFAULT;
return err;
+ case RTC_CAPS_READ:
+ err = put_user(rtc->caps, (unsigned int __user *)uarg);
+ break;
+
default:
/* Finally try the driver's ioctl interface */
if (ops->ioctl) {
diff --git a/drivers/rtc/rtc-sysfs.c b/drivers/rtc/rtc-sysfs.c
index babd43b..bdffb8f 100644
--- a/drivers/rtc/rtc-sysfs.c
+++ b/drivers/rtc/rtc-sysfs.c
@@ -122,6 +122,13 @@ hctosys_show(struct device *dev, struct device_attribute *attr, char *buf)
}
static DEVICE_ATTR_RO(hctosys);
+static ssize_t
+caps_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%d\n", to_rtc_device(dev)->caps);
+}
+static DEVICE_ATTR_RO(caps);
+
static struct attribute *rtc_attrs[] = {
&dev_attr_name.attr,
&dev_attr_date.attr,
@@ -129,6 +136,7 @@ static struct attribute *rtc_attrs[] = {
&dev_attr_since_epoch.attr,
&dev_attr_max_user_freq.attr,
&dev_attr_hctosys.attr,
+ &dev_attr_caps.attr,
NULL,
};
ATTRIBUTE_GROUPS(rtc);
diff --git a/include/linux/rtc.h b/include/linux/rtc.h
index c2c2897..e6380ec 100644
--- a/include/linux/rtc.h
+++ b/include/linux/rtc.h
@@ -116,6 +116,11 @@ struct rtc_device
/* Some hardware can't support UIE mode */
int uie_unsupported;
+ /* Time Zone and Daylight capabilities */
+#define RTC_TZ_CAP (1 << 0)
+#define RTC_DST_CAP (1 << 1)
+ int caps;
+
#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
struct work_struct uie_task;
struct timer_list uie_timer;
diff --git a/include/uapi/linux/rtc.h b/include/uapi/linux/rtc.h
index f8c82e6..5533914 100644
--- a/include/uapi/linux/rtc.h
+++ b/include/uapi/linux/rtc.h
@@ -94,6 +94,11 @@ struct rtc_pll_info {
#define RTC_VL_READ _IOR('p', 0x13, int) /* Voltage low detector */
#define RTC_VL_CLR _IO('p', 0x14) /* Clear voltage low information */
+#define RTC_RD_GMTOFF _IOR('p', 0x15, long int) /* Read time zone return seconds east of UTC */
+#define RTC_SET_GMTOFF _IOW('p', 0x16, long int) /* Set time zone input seconds east of UTC */
+
+#define RTC_CAPS_READ _IOR('p', 0x17, unsigned int) /* Get capabilities, e.g. TZ, DST */
+
/* interrupt flags */
#define RTC_IRQF 0x80 /* Any of the following is active */
#define RTC_PF 0x40 /* Periodic interrupt */
--
1.6.4.2
next prev parent reply other threads:[~2013-12-19 7:51 UTC|newest]
Thread overview: 44+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-12-19 7:51 [RFC PATCH 00/14] Support timezone of ACPI TAD and EFI TIME Lee, Chun-Yi
2013-12-19 7:51 ` [PATCH 01/14] rtc-efi: fix decrease day twice when computing year days Lee, Chun-Yi
[not found] ` <1387439515-8926-1-git-send-email-jlee-IBi9RG/b67k@public.gmane.org>
2013-12-19 7:51 ` [PATCH 03/14] rtc: block registration of rtc-cmos when CMOS RTC Not Present Lee, Chun-Yi
2013-12-19 7:51 ` [RFC PATCH 04/14] ACPI: Add ACPI 5.0 Time and Alarm Device driver Lee, Chun-Yi
[not found] ` <1387439515-8926-5-git-send-email-jlee-IBi9RG/b67k@public.gmane.org>
2013-12-19 15:22 ` H. Peter Anvin
[not found] ` <52B30F43.1060306-YMNOUZJC4hwAvxtiuMwx3w@public.gmane.org>
2013-12-20 5:41 ` joeyli
[not found] ` <1387518099.3539.4453.camel-ONCj+Eqt86TasUa73XJKwA@public.gmane.org>
2014-01-01 0:42 ` H. Peter Anvin
[not found] ` <52C3647B.7000708-YMNOUZJC4hwAvxtiuMwx3w@public.gmane.org>
2014-01-06 8:58 ` joeyli
2014-01-07 5:37 ` H. Peter Anvin
2014-01-07 10:40 ` joeyli
2014-01-07 16:35 ` H. Peter Anvin
2014-01-08 14:59 ` joeyli
[not found] ` <1389193142.3539.6123.camel-ONCj+Eqt86TasUa73XJKwA@public.gmane.org>
2014-01-08 17:56 ` H. Peter Anvin
[not found] ` <52CD9139.2070302-YMNOUZJC4hwAvxtiuMwx3w@public.gmane.org>
2014-01-09 3:47 ` joeyli
[not found] ` <1389239259.24105.2.camel-ONCj+Eqt86TasUa73XJKwA@public.gmane.org>
2014-01-09 4:00 ` H. Peter Anvin
2014-01-09 12:16 ` Rafael J. Wysocki
2014-01-02 8:09 ` Lan Tianyu
2014-01-06 9:20 ` joeyli
2013-12-19 7:51 ` Lee, Chun-Yi [this message]
2013-12-19 7:51 ` [RFC PATCH 06/14] rtc-efi: register rtc-efi device when EFI enabled Lee, Chun-Yi
2013-12-19 14:09 ` Matt Fleming
2013-12-20 4:24 ` joeyli
[not found] ` <1387513491.3539.4345.camel-ONCj+Eqt86TasUa73XJKwA@public.gmane.org>
2013-12-20 4:30 ` H. Peter Anvin
2013-12-20 10:37 ` Borislav Petkov
[not found] ` <20131220103755.GA14784-fF5Pk5pvG8Y@public.gmane.org>
2013-12-20 15:14 ` Matthew Garrett
2013-12-20 21:04 ` H. Peter Anvin
[not found] ` <52B4B0ED.7030600-YMNOUZJC4hwAvxtiuMwx3w@public.gmane.org>
2013-12-21 1:24 ` joeyli
2013-12-21 1:51 ` H. Peter Anvin
2013-12-21 15:34 ` joeyli
2013-12-20 16:48 ` H. Peter Anvin
2013-12-19 7:51 ` [RFC PATCH 07/14] rtc-efi: add GMTOFF support to rtc_efi Lee, Chun-Yi
[not found] ` <1387439515-8926-8-git-send-email-jlee-IBi9RG/b67k@public.gmane.org>
2013-12-20 15:11 ` Matthew Garrett
2013-12-21 3:56 ` joeyli
2013-12-19 7:51 ` [RFC PATCH 08/14] rtc-efi: set uie_unsupported for indicate rtc-efi doesn't support UIE mode Lee, Chun-Yi
2013-12-19 7:51 ` [RFC PATCH 09/14] efi: move functions of access efi time to header file for sharing Lee, Chun-Yi
2013-12-19 7:51 ` [RFC PATCH 10/14] rtc: improve and move week day computing function to rtc header Lee, Chun-Yi
2013-12-19 7:51 ` [RFC PATCH 11/14] rtc: switch to get/set rtc time to efi functions if CMOS RTC Not Present git set Lee, Chun-Yi
2013-12-19 7:51 ` [RFC PATCH 12/14] efi: adjust system time base on timezone from EFI time services Lee, Chun-Yi
2013-12-19 7:51 ` [RFC PATCH 13/14] Documentation/RTC: add document of ACPI TAD and EFI TIME driver Lee, Chun-Yi
2013-12-19 7:51 ` [TEST PATCH 14/14] acpi: add early parameter to set CMOS RTC Not Present bit for testing Lee, Chun-Yi
[not found] ` <1387448416-11672-1-git-send-email-jlee@suse.com>
[not found] ` <1387448416-11672-1-git-send-email-jlee-IBi9RG/b67k@public.gmane.org>
2013-12-19 10:49 ` [PATCH 02/14] x86-64/efi: Use EFI to deal with platform wall clock (again) Matt Fleming
[not found] ` <20131219104908.GE3145-HNK1S37rvNbeXh+fF434Mdi2O/JbrIOy@public.gmane.org>
2013-12-19 13:32 ` joeyli
[not found] ` <1387459939.3539.4092.camel-ONCj+Eqt86TasUa73XJKwA@public.gmane.org>
2013-12-20 11:29 ` One Thousand Gnomes
2013-12-23 23:25 ` H. Peter Anvin
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1387439515-8926-6-git-send-email-jlee@suse.com \
--to=joeyli.kernel@gmail.com \
--cc=Elliott@hp.com \
--cc=JBeulich@suse.com \
--cc=a.zummo@towertech.it \
--cc=hpa@zytor.com \
--cc=jlee@suse.com \
--cc=linux-acpi@vger.kernel.org \
--cc=linux-efi@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=matt@console-pimps.org \
--cc=matthew.garrett@nebula.com \
--cc=oneukum@suse.de \
--cc=rjw@rjwysocki.net \
--cc=rtc-linux@googlegroups.com \
--cc=samer.el-haj-mahmoud@hp.com \
--cc=trenn@suse.de \
--cc=werner@suse.com \
--cc=x86@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).