[PATCH] RTC subsystem: class
authorAlessandro Zummo <a.zummo@towertech.it>
Mon, 27 Mar 2006 09:16:37 +0000 (01:16 -0800)
committerLinus Torvalds <torvalds@g5.osdl.org>
Mon, 27 Mar 2006 16:44:51 +0000 (08:44 -0800)
Add the basic RTC subsystem infrastructure to the kernel.

rtc/class.c - registration facilities for RTC drivers
rtc/interface.c - kernel/rtc interface functions
rtc/hctosys.c - snippet of code that copies hw clock to sw clock
at bootup, if configured to do so.

Signed-off-by: Alessandro Zummo <a.zummo@towertech.it>
Acked-by: Greg Kroah-Hartman <gregkh@suse.de>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
CREDITS
MAINTAINERS
drivers/rtc/Kconfig
drivers/rtc/Makefile
drivers/rtc/class.c [new file with mode: 0644]
drivers/rtc/hctosys.c [new file with mode: 0644]
drivers/rtc/interface.c [new file with mode: 0644]
include/linux/rtc.h

diff --git a/CREDITS b/CREDITS
index c6d69bf..35850d8 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -3741,10 +3741,11 @@ D: Mylex DAC960 PCI RAID driver
 D: Miscellaneous kernel fixes
 
 N: Alessandro Zummo
-E: azummo@ita.flashnet.it
-W: http://freepage.logicom.it/azummo/
+E: a.zummo@towertech.it
 D: CMI8330 support is sb_card.c
 D: ISAPnP fixes in sb_card.c
+D: ZyXEL omni.net lcd plus driver
+D: RTC subsystem
 S: Italy
 
 N: Marc Zyngier
index f278467..e5b051f 100644 (file)
@@ -2233,6 +2233,12 @@ M:       p_gortmaker@yahoo.com
 L:     linux-kernel@vger.kernel.org
 S:     Maintained
 
+REAL TIME CLOCK (RTC) SUBSYSTEM
+P:     Alessandro Zummo
+M:     a.zummo@towertech.it
+L:     linux-kernel@vger.kernel.org
+S:     Maintained
+
 REISERFS FILE SYSTEM
 P:     Hans Reiser
 M:     reiserfs-dev@namesys.com
index 15df7c1..a256f67 100644 (file)
@@ -1,6 +1,46 @@
-#
+\#
 # RTC class/drivers configuration
 #
 
+menu "Real Time Clock"
+
 config RTC_LIB
-       tristate
\ No newline at end of file
+       tristate
+
+config RTC_CLASS
+       tristate "RTC class"
+       depends on EXPERIMENTAL
+       default n
+       select RTC_LIB
+       help
+         Generic RTC class support. If you say yes here, you will
+         be allowed to plug one or more RTCs to your system. You will
+         probably want to enable one of more of the interfaces below.
+
+         This driver can also be built as a module. If so, the module
+         will be called rtc-class.
+
+config RTC_HCTOSYS
+       bool "Set system time from RTC on startup"
+       depends on RTC_CLASS = y
+       default y
+       help
+         If you say yes here, the system time will be set using
+         the value read from the specified RTC device. This is useful
+         in order to avoid unnecessary fschk runs.
+
+config RTC_HCTOSYS_DEVICE
+       string "The RTC to read the time from"
+       depends on RTC_HCTOSYS = y
+       default "rtc0"
+       help
+         The RTC device that will be used as the source for
+         the system time, usually rtc0.
+
+comment "RTC interfaces"
+       depends on RTC_CLASS
+
+comment "RTC drivers"
+       depends on RTC_CLASS
+
+endmenu
index eb9ad77..7b87f37 100644 (file)
@@ -2,4 +2,7 @@
 # Makefile for RTC class/drivers.
 #
 
-obj-$(CONFIG_RTC_LIB)  += rtc-lib.o
+obj-$(CONFIG_RTC_LIB)          += rtc-lib.o
+obj-$(CONFIG_RTC_HCTOSYS)      += hctosys.o
+obj-$(CONFIG_RTC_CLASS)                += rtc-core.o
+rtc-core-y                     := class.o interface.o
diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c
new file mode 100644 (file)
index 0000000..8533936
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * RTC subsystem, base class
+ *
+ * Copyright (C) 2005 Tower Technologies
+ * Author: Alessandro Zummo <a.zummo@towertech.it>
+ *
+ * class skeleton from drivers/hwmon/hwmon.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/module.h>
+#include <linux/rtc.h>
+#include <linux/kdev_t.h>
+#include <linux/idr.h>
+
+static DEFINE_IDR(rtc_idr);
+static DEFINE_MUTEX(idr_lock);
+struct class *rtc_class;
+
+static void rtc_device_release(struct class_device *class_dev)
+{
+       struct rtc_device *rtc = to_rtc_device(class_dev);
+       mutex_lock(&idr_lock);
+       idr_remove(&rtc_idr, rtc->id);
+       mutex_unlock(&idr_lock);
+       kfree(rtc);
+}
+
+/**
+ * rtc_device_register - register w/ RTC class
+ * @dev: the device to register
+ *
+ * rtc_device_unregister() must be called when the class device is no
+ * longer needed.
+ *
+ * Returns the pointer to the new struct class device.
+ */
+struct rtc_device *rtc_device_register(const char *name, struct device *dev,
+                                       struct rtc_class_ops *ops,
+                                       struct module *owner)
+{
+       struct rtc_device *rtc;
+       int id, err;
+
+       if (idr_pre_get(&rtc_idr, GFP_KERNEL) == 0) {
+               err = -ENOMEM;
+               goto exit;
+       }
+
+
+       mutex_lock(&idr_lock);
+       err = idr_get_new(&rtc_idr, NULL, &id);
+       mutex_unlock(&idr_lock);
+
+       if (err < 0)
+               goto exit;
+
+       id = id & MAX_ID_MASK;
+
+       rtc = kzalloc(sizeof(struct rtc_device), GFP_KERNEL);
+       if (rtc == NULL) {
+               err = -ENOMEM;
+               goto exit_idr;
+       }
+
+       rtc->id = id;
+       rtc->ops = ops;
+       rtc->owner = owner;
+       rtc->class_dev.dev = dev;
+       rtc->class_dev.class = rtc_class;
+       rtc->class_dev.release = rtc_device_release;
+
+       mutex_init(&rtc->ops_lock);
+       spin_lock_init(&rtc->irq_lock);
+       spin_lock_init(&rtc->irq_task_lock);
+
+       strlcpy(rtc->name, name, RTC_DEVICE_NAME_SIZE);
+       snprintf(rtc->class_dev.class_id, BUS_ID_SIZE, "rtc%d", id);
+
+       err = class_device_register(&rtc->class_dev);
+       if (err)
+               goto exit_kfree;
+
+       dev_info(dev, "rtc core: registered %s as %s\n",
+                       rtc->name, rtc->class_dev.class_id);
+
+       return rtc;
+
+exit_kfree:
+       kfree(rtc);
+
+exit_idr:
+       idr_remove(&rtc_idr, id);
+
+exit:
+       return ERR_PTR(err);
+}
+EXPORT_SYMBOL_GPL(rtc_device_register);
+
+
+/**
+ * rtc_device_unregister - removes the previously registered RTC class device
+ *
+ * @rtc: the RTC class device to destroy
+ */
+void rtc_device_unregister(struct rtc_device *rtc)
+{
+       mutex_lock(&rtc->ops_lock);
+       rtc->ops = NULL;
+       mutex_unlock(&rtc->ops_lock);
+       class_device_unregister(&rtc->class_dev);
+}
+EXPORT_SYMBOL_GPL(rtc_device_unregister);
+
+int rtc_interface_register(struct class_interface *intf)
+{
+       intf->class = rtc_class;
+       return class_interface_register(intf);
+}
+EXPORT_SYMBOL_GPL(rtc_interface_register);
+
+static int __init rtc_init(void)
+{
+       rtc_class = class_create(THIS_MODULE, "rtc");
+       if (IS_ERR(rtc_class)) {
+               printk(KERN_ERR "%s: couldn't create class\n", __FILE__);
+               return PTR_ERR(rtc_class);
+       }
+       return 0;
+}
+
+static void __exit rtc_exit(void)
+{
+       class_destroy(rtc_class);
+}
+
+module_init(rtc_init);
+module_exit(rtc_exit);
+
+MODULE_AUTHOR("Alessandro Zummo <a.zummo@towerteh.it>");
+MODULE_DESCRIPTION("RTC class support");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/hctosys.c b/drivers/rtc/hctosys.c
new file mode 100644 (file)
index 0000000..d02fe9a
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * RTC subsystem, initialize system time on startup
+ *
+ * Copyright (C) 2005 Tower Technologies
+ * Author: Alessandro Zummo <a.zummo@towertech.it>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/rtc.h>
+
+/* IMPORTANT: the RTC only stores whole seconds. It is arbitrary
+ * whether it stores the most close value or the value with partial
+ * seconds truncated. However, it is important that we use it to store
+ * the truncated value. This is because otherwise it is necessary,
+ * in an rtc sync function, to read both xtime.tv_sec and
+ * xtime.tv_nsec. On some processors (i.e. ARM), an atomic read
+ * of >32bits is not possible. So storing the most close value would
+ * slow down the sync API. So here we have the truncated value and
+ * the best guess is to add 0.5s.
+ */
+
+static int __init rtc_hctosys(void)
+{
+       int err;
+       struct rtc_time tm;
+       struct class_device *class_dev = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE);
+
+       if (class_dev == NULL) {
+               printk("%s: unable to open rtc device (%s)\n",
+                       __FILE__, CONFIG_RTC_HCTOSYS_DEVICE);
+               return -ENODEV;
+       }
+
+       err = rtc_read_time(class_dev, &tm);
+       if (err == 0) {
+               err = rtc_valid_tm(&tm);
+               if (err == 0) {
+                       struct timespec tv;
+
+                       tv.tv_nsec = NSEC_PER_SEC >> 1;
+
+                       rtc_tm_to_time(&tm, &tv.tv_sec);
+
+                       do_settimeofday(&tv);
+
+                       dev_info(class_dev->dev,
+                               "setting the system clock to "
+                               "%d-%02d-%02d %02d:%02d:%02d (%u)\n",
+                               tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
+                               tm.tm_hour, tm.tm_min, tm.tm_sec,
+                               (unsigned int) tv.tv_sec);
+               }
+               else
+                       dev_err(class_dev->dev,
+                               "hctosys: invalid date/time\n");
+       }
+       else
+               dev_err(class_dev->dev,
+                       "hctosys: unable to read the hardware clock\n");
+
+       rtc_class_close(class_dev);
+
+       return 0;
+}
+
+late_initcall(rtc_hctosys);
diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c
new file mode 100644 (file)
index 0000000..56e4907
--- /dev/null
@@ -0,0 +1,277 @@
+/*
+ * RTC subsystem, interface functions
+ *
+ * Copyright (C) 2005 Tower Technologies
+ * Author: Alessandro Zummo <a.zummo@towertech.it>
+ *
+ * based on arch/arm/common/rtctime.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/rtc.h>
+
+int rtc_read_time(struct class_device *class_dev, struct rtc_time *tm)
+{
+       int err;
+       struct rtc_device *rtc = to_rtc_device(class_dev);
+
+       err = mutex_lock_interruptible(&rtc->ops_lock);
+       if (err)
+               return -EBUSY;
+
+       if (!rtc->ops)
+               err = -ENODEV;
+       else if (!rtc->ops->read_time)
+               err = -EINVAL;
+       else {
+               memset(tm, 0, sizeof(struct rtc_time));
+               err = rtc->ops->read_time(class_dev->dev, tm);
+       }
+
+       mutex_unlock(&rtc->ops_lock);
+       return err;
+}
+EXPORT_SYMBOL_GPL(rtc_read_time);
+
+int rtc_set_time(struct class_device *class_dev, struct rtc_time *tm)
+{
+       int err;
+       struct rtc_device *rtc = to_rtc_device(class_dev);
+
+       err = rtc_valid_tm(tm);
+       if (err != 0)
+               return err;
+
+       err = mutex_lock_interruptible(&rtc->ops_lock);
+       if (err)
+               return -EBUSY;
+
+       if (!rtc->ops)
+               err = -ENODEV;
+       else if (!rtc->ops->set_time)
+               err = -EINVAL;
+       else
+               err = rtc->ops->set_time(class_dev->dev, tm);
+
+       mutex_unlock(&rtc->ops_lock);
+       return err;
+}
+EXPORT_SYMBOL_GPL(rtc_set_time);
+
+int rtc_set_mmss(struct class_device *class_dev, unsigned long secs)
+{
+       int err;
+       struct rtc_device *rtc = to_rtc_device(class_dev);
+
+       err = mutex_lock_interruptible(&rtc->ops_lock);
+       if (err)
+               return -EBUSY;
+
+       if (!rtc->ops)
+               err = -ENODEV;
+       else if (rtc->ops->set_mmss)
+               err = rtc->ops->set_mmss(class_dev->dev, secs);
+       else if (rtc->ops->read_time && rtc->ops->set_time) {
+               struct rtc_time new, old;
+
+               err = rtc->ops->read_time(class_dev->dev, &old);
+               if (err == 0) {
+                       rtc_time_to_tm(secs, &new);
+
+                       /*
+                        * avoid writing when we're going to change the day of
+                        * the month. We will retry in the next minute. This
+                        * basically means that if the RTC must not drift
+                        * by more than 1 minute in 11 minutes.
+                        */
+                       if (!((old.tm_hour == 23 && old.tm_min == 59) ||
+                               (new.tm_hour == 23 && new.tm_min == 59)))
+                               err = rtc->ops->set_time(class_dev->dev, &new);
+               }
+       }
+       else
+               err = -EINVAL;
+
+       mutex_unlock(&rtc->ops_lock);
+
+       return err;
+}
+EXPORT_SYMBOL_GPL(rtc_set_mmss);
+
+int rtc_read_alarm(struct class_device *class_dev, struct rtc_wkalrm *alarm)
+{
+       int err;
+       struct rtc_device *rtc = to_rtc_device(class_dev);
+
+       err = mutex_lock_interruptible(&rtc->ops_lock);
+       if (err)
+               return -EBUSY;
+
+       if (rtc->ops == NULL)
+               err = -ENODEV;
+       else if (!rtc->ops->read_alarm)
+               err = -EINVAL;
+       else {
+               memset(alarm, 0, sizeof(struct rtc_wkalrm));
+               err = rtc->ops->read_alarm(class_dev->dev, alarm);
+       }
+
+       mutex_unlock(&rtc->ops_lock);
+       return err;
+}
+EXPORT_SYMBOL_GPL(rtc_read_alarm);
+
+int rtc_set_alarm(struct class_device *class_dev, struct rtc_wkalrm *alarm)
+{
+       int err;
+       struct rtc_device *rtc = to_rtc_device(class_dev);
+
+       err = mutex_lock_interruptible(&rtc->ops_lock);
+       if (err)
+               return -EBUSY;
+
+       if (!rtc->ops)
+               err = -ENODEV;
+       else if (!rtc->ops->set_alarm)
+               err = -EINVAL;
+       else
+               err = rtc->ops->set_alarm(class_dev->dev, alarm);
+
+       mutex_unlock(&rtc->ops_lock);
+       return err;
+}
+EXPORT_SYMBOL_GPL(rtc_set_alarm);
+
+void rtc_update_irq(struct class_device *class_dev,
+               unsigned long num, unsigned long events)
+{
+       struct rtc_device *rtc = to_rtc_device(class_dev);
+
+       spin_lock(&rtc->irq_lock);
+       rtc->irq_data = (rtc->irq_data + (num << 8)) | events;
+       spin_unlock(&rtc->irq_lock);
+
+       spin_lock(&rtc->irq_task_lock);
+       if (rtc->irq_task)
+               rtc->irq_task->func(rtc->irq_task->private_data);
+       spin_unlock(&rtc->irq_task_lock);
+
+       wake_up_interruptible(&rtc->irq_queue);
+       kill_fasync(&rtc->async_queue, SIGIO, POLL_IN);
+}
+EXPORT_SYMBOL_GPL(rtc_update_irq);
+
+struct class_device *rtc_class_open(char *name)
+{
+       struct class_device *class_dev = NULL,
+                               *class_dev_tmp;
+
+       down(&rtc_class->sem);
+       list_for_each_entry(class_dev_tmp, &rtc_class->children, node) {
+               if (strncmp(class_dev_tmp->class_id, name, BUS_ID_SIZE) == 0) {
+                       class_dev = class_dev_tmp;
+                       break;
+               }
+       }
+
+       if (class_dev) {
+               if (!try_module_get(to_rtc_device(class_dev)->owner))
+                       class_dev = NULL;
+       }
+       up(&rtc_class->sem);
+
+       return class_dev;
+}
+EXPORT_SYMBOL_GPL(rtc_class_open);
+
+void rtc_class_close(struct class_device *class_dev)
+{
+       module_put(to_rtc_device(class_dev)->owner);
+}
+EXPORT_SYMBOL_GPL(rtc_class_close);
+
+int rtc_irq_register(struct class_device *class_dev, struct rtc_task *task)
+{
+       int retval = -EBUSY;
+       struct rtc_device *rtc = to_rtc_device(class_dev);
+
+       if (task == NULL || task->func == NULL)
+               return -EINVAL;
+
+       spin_lock(&rtc->irq_task_lock);
+       if (rtc->irq_task == NULL) {
+               rtc->irq_task = task;
+               retval = 0;
+       }
+       spin_unlock(&rtc->irq_task_lock);
+
+       return retval;
+}
+EXPORT_SYMBOL_GPL(rtc_irq_register);
+
+void rtc_irq_unregister(struct class_device *class_dev, struct rtc_task *task)
+{
+       struct rtc_device *rtc = to_rtc_device(class_dev);
+
+       spin_lock(&rtc->irq_task_lock);
+       if (rtc->irq_task == task)
+               rtc->irq_task = NULL;
+       spin_unlock(&rtc->irq_task_lock);
+}
+EXPORT_SYMBOL_GPL(rtc_irq_unregister);
+
+int rtc_irq_set_state(struct class_device *class_dev, struct rtc_task *task, int enabled)
+{
+       int err = 0;
+       unsigned long flags;
+       struct rtc_device *rtc = to_rtc_device(class_dev);
+
+       spin_lock_irqsave(&rtc->irq_task_lock, flags);
+       if (rtc->irq_task != task)
+               err = -ENXIO;
+       spin_unlock_irqrestore(&rtc->irq_task_lock, flags);
+
+       if (err == 0)
+               err = rtc->ops->irq_set_state(class_dev->dev, enabled);
+
+       return err;
+}
+EXPORT_SYMBOL_GPL(rtc_irq_set_state);
+
+int rtc_irq_set_freq(struct class_device *class_dev, struct rtc_task *task, int freq)
+{
+       int err = 0, tmp = 0;
+       unsigned long flags;
+       struct rtc_device *rtc = to_rtc_device(class_dev);
+
+       /* allowed range is 2-8192 */
+       if (freq < 2 || freq > 8192)
+               return -EINVAL;
+/*
+       FIXME: this does not belong here, will move where appropriate
+       at a later stage. It cannot hurt right now, trust me :)
+       if ((freq > rtc_max_user_freq) && (!capable(CAP_SYS_RESOURCE)))
+               return -EACCES;
+*/
+       /* check if freq is a power of 2 */
+       while (freq > (1 << tmp))
+               tmp++;
+
+       if (freq != (1 << tmp))
+               return -EINVAL;
+
+       spin_lock_irqsave(&rtc->irq_task_lock, flags);
+       if (rtc->irq_task != task)
+               err = -ENXIO;
+       spin_unlock_irqrestore(&rtc->irq_task_lock, flags);
+
+       if (err == 0) {
+               err = rtc->ops->irq_set_freq(class_dev->dev, freq);
+               if (err == 0)
+                       rtc->irq_freq = freq;
+       }
+       return err;
+}
index 8454337..ab61cd1 100644 (file)
@@ -91,6 +91,12 @@ struct rtc_pll_info {
 #define RTC_PLL_GET    _IOR('p', 0x11, struct rtc_pll_info)  /* Get PLL correction */
 #define RTC_PLL_SET    _IOW('p', 0x12, struct rtc_pll_info)  /* Set PLL correction */
 
+/* interrupt flags */
+#define RTC_IRQF 0x80 /* any of the following is active */
+#define RTC_PF 0x40
+#define RTC_AF 0x20
+#define RTC_UF 0x10
+
 #ifdef __KERNEL__
 
 #include <linux/interrupt.h>
@@ -100,6 +106,87 @@ extern int rtc_valid_tm(struct rtc_time *tm);
 extern int rtc_tm_to_time(struct rtc_time *tm, unsigned long *time);
 extern void rtc_time_to_tm(unsigned long time, struct rtc_time *tm);
 
+#include <linux/device.h>
+#include <linux/seq_file.h>
+#include <linux/cdev.h>
+#include <linux/poll.h>
+#include <linux/mutex.h>
+
+extern struct class *rtc_class;
+
+struct rtc_class_ops {
+       int (*open)(struct device *);
+       void (*release)(struct device *);
+       int (*ioctl)(struct device *, unsigned int, unsigned long);
+       int (*read_time)(struct device *, struct rtc_time *);
+       int (*set_time)(struct device *, struct rtc_time *);
+       int (*read_alarm)(struct device *, struct rtc_wkalrm *);
+       int (*set_alarm)(struct device *, struct rtc_wkalrm *);
+       int (*proc)(struct device *, struct seq_file *);
+       int (*set_mmss)(struct device *, unsigned long secs);
+       int (*irq_set_state)(struct device *, int enabled);
+       int (*irq_set_freq)(struct device *, int freq);
+       int (*read_callback)(struct device *, int data);
+};
+
+#define RTC_DEVICE_NAME_SIZE 20
+struct rtc_task;
+
+struct rtc_device
+{
+       struct class_device class_dev;
+       struct module *owner;
+
+       int id;
+       char name[RTC_DEVICE_NAME_SIZE];
+
+       struct rtc_class_ops *ops;
+       struct mutex ops_lock;
+
+       struct class_device *rtc_dev;
+       struct cdev char_dev;
+       struct mutex char_lock;
+
+       unsigned long irq_data;
+       spinlock_t irq_lock;
+       wait_queue_head_t irq_queue;
+       struct fasync_struct *async_queue;
+
+       struct rtc_task *irq_task;
+       spinlock_t irq_task_lock;
+       int irq_freq;
+};
+#define to_rtc_device(d) container_of(d, struct rtc_device, class_dev)
+
+extern struct rtc_device *rtc_device_register(const char *name,
+                                       struct device *dev,
+                                       struct rtc_class_ops *ops,
+                                       struct module *owner);
+extern void rtc_device_unregister(struct rtc_device *rdev);
+extern int rtc_interface_register(struct class_interface *intf);
+
+extern int rtc_read_time(struct class_device *class_dev, struct rtc_time *tm);
+extern int rtc_set_time(struct class_device *class_dev, struct rtc_time *tm);
+extern int rtc_set_mmss(struct class_device *class_dev, unsigned long secs);
+extern int rtc_read_alarm(struct class_device *class_dev,
+                       struct rtc_wkalrm *alrm);
+extern int rtc_set_alarm(struct class_device *class_dev,
+                               struct rtc_wkalrm *alrm);
+extern void rtc_update_irq(struct class_device *class_dev,
+                       unsigned long num, unsigned long events);
+
+extern struct class_device *rtc_class_open(char *name);
+extern void rtc_class_close(struct class_device *class_dev);
+
+extern int rtc_irq_register(struct class_device *class_dev,
+                               struct rtc_task *task);
+extern void rtc_irq_unregister(struct class_device *class_dev,
+                               struct rtc_task *task);
+extern int rtc_irq_set_state(struct class_device *class_dev,
+                               struct rtc_task *task, int enabled);
+extern int rtc_irq_set_freq(struct class_device *class_dev,
+                               struct rtc_task *task, int freq);
+
 typedef struct rtc_task {
        void (*func)(void *private_data);
        void *private_data;