@@ -65,7 +65,7 @@ config CBUS_RETU_POWERBUTTON
If you want support for the Retu power button, you should say Y here.
config CBUS_RETU_RTC
- depends on CBUS_RETU && SYSFS
+ depends on CBUS_RETU && RTC_CLASS
tristate "Support for Retu pseudo-RTC"
---help---
Say Y here if you want support for the device that alleges to be an
@@ -40,6 +40,7 @@
#include <linux/completion.h>
#include <linux/platform_device.h>
#include <linux/mutex.h>
+#include <linux/rtc.h>
#include <linux/workqueue.h>
#include "cbus.h"
@@ -51,6 +52,7 @@ struct retu_rtc {
struct completion sync;
struct work_struct work;
struct device *dev;
+ struct rtc_device *rtc;
u16 alarm_expired;
u16 reset_occurred;
@@ -68,92 +70,6 @@ static void retu_rtc_barrier(struct retu_rtc *rtc)
retu_disable_irq(RETU_INT_RTCS);
}
-static ssize_t retu_rtc_time_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct retu_rtc *rtc = dev_get_drvdata(dev);
- u16 dsr, hmr, dsr2;
-
- mutex_lock(&rtc->mutex);
-
- do {
- u16 dummy;
-
- /*
- * Not being in_interrupt() for a retu rtc IRQ, we need to
- * read twice for consistency..
- */
- dummy = retu_read_reg(RETU_REG_RTCDSR);
- dsr = retu_read_reg(RETU_REG_RTCDSR);
-
- dummy = retu_read_reg(RETU_REG_RTCHMR);
- hmr = retu_read_reg(RETU_REG_RTCHMR);
-
- dummy = retu_read_reg(RETU_REG_RTCDSR);
- dsr2 = retu_read_reg(RETU_REG_RTCDSR);
- } while ((dsr != dsr2));
-
- mutex_unlock(&rtc->mutex);
-
- /*
- * Format a 32-bit date-string for userspace
- *
- * days | hours | minutes | seconds
- *
- * 8 bits for each.
- *
- * This mostly sucks because days and seconds are tracked in RTCDSR
- * while hours and minutes are tracked in RTCHMR. And yes, there
- * really are no words that can describe an 8 bit day register (or
- * rather, none that will be reprinted here).
- */
- return sprintf(buf, "0x%08x\n", (((dsr >> 8) & 0xff) << 24) |
- (((hmr >> 8) & 0x1f) << 16) |
- ((hmr & 0x3f) << 8) | (dsr & 0x3f));
-}
-
-static ssize_t retu_rtc_time_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- struct retu_rtc *rtc = dev_get_drvdata(dev);
-
- mutex_lock(&rtc->mutex);
- /*
- * Writing anything to the day counter forces it to 0
- * The seconds counter would be cleared by resetting the minutes
- * counter, however this won't happen, since we are using the
- * hh:mm counters as a set of free running counters and the
- * day counter as a multiple overflow holder.
- */
-
- /* Reset day counter, but keep Temperature Shutdown state */
- retu_write_reg(RETU_REG_RTCDSR,
- retu_read_reg(RETU_REG_RTCDSR) & (1 << 6));
-
- mutex_unlock(&rtc->mutex);
-
- return count;
-}
-static DEVICE_ATTR(time, S_IRUGO | S_IWUSR, retu_rtc_time_show,
- retu_rtc_time_store);
-
-static ssize_t retu_rtc_reset_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct retu_rtc *rtc = dev_get_drvdata(dev);
-
- /*
- * Returns the status of the rtc
- *
- * 0: no reset has occurred or the status has been cleared
- * 1: a reset has occurred
- *
- * RTC needs to be reset only when both main battery
- * _AND_ backup battery are discharged
- */
- return sprintf(buf, "%u\n", rtc->reset_occurred);
-}
-
static void retu_rtc_do_reset(struct retu_rtc *rtc)
{
u16 ccr1;
@@ -174,167 +90,6 @@ static void retu_rtc_do_reset(struct retu_rtc *rtc)
rtc->reset_occurred = 1;
}
-static ssize_t retu_rtc_reset_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- struct retu_rtc *rtc = dev_get_drvdata(dev);
- unsigned choice;
-
- if (sscanf(buf, "%u", &choice) != 1)
- return count;
- mutex_lock(&rtc->mutex);
- if (choice == 0)
- rtc->reset_occurred = 0;
- else if (choice == 1)
- retu_rtc_do_reset(rtc);
- mutex_unlock(&rtc->mutex);
- return count;
-}
-static DEVICE_ATTR(reset, S_IRUGO | S_IWUSR, retu_rtc_reset_show,
- retu_rtc_reset_store);
-
-static ssize_t retu_rtc_alarm_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct retu_rtc *rtc = dev_get_drvdata(dev);
- ssize_t retval;
- u16 chmar;
-
- mutex_lock(&rtc->mutex);
- /*
- * Format a 16-bit date-string for userspace
- *
- * hours | minutes
- * 8 bits for each.
- */
- chmar = retu_read_reg(RETU_REG_RTCHMAR);
- /* No shifting needed, only masking unrelated bits */
- retval = sprintf(buf, "0x%04x\n", chmar & 0x1f3f);
- mutex_unlock(&rtc->mutex);
-
- return retval;
-}
-
-static ssize_t retu_rtc_alarm_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- struct retu_rtc *rtc = dev_get_drvdata(dev);
-
- unsigned minutes;
- unsigned hours;
- unsigned alrm;
-
- u16 chmar;
-
- mutex_lock(&rtc->mutex);
-
- if (sscanf(buf, "%x", &alrm) != 1)
- return count;
- hours = (alrm >> 8) & 0x001f;
- minutes = (alrm >> 0) & 0x003f;
- if ((hours < 24 && minutes < 60) || (hours == 24 && minutes == 60)) {
- /*
- * OK, the time format for the alarm is valid (including the
- * disabling values)
- */
- /* Keeps the RTC watchdog status */
- chmar = retu_read_reg(RETU_REG_RTCHMAR) & 0x6000;
- chmar |= alrm & 0x1f3f; /* Stores the requested alarm */
- retu_rtc_barrier(rtc);
- retu_write_reg(RETU_REG_RTCHMAR, chmar);
- /* If the alarm is being disabled */
- if (hours == 24 && minutes == 60) {
- /* disable the interrupt */
- retu_disable_irq(RETU_INT_RTCA);
- rtc->alarm_expired = 0;
- } else
- /* enable the interrupt */
- retu_enable_irq(RETU_INT_RTCA);
- }
- mutex_unlock(&rtc->mutex);
-
- return count;
-}
-static DEVICE_ATTR(alarm, S_IRUGO | S_IWUSR, retu_rtc_alarm_show,
- retu_rtc_alarm_store);
-
-static ssize_t retu_rtc_alarm_expired_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct retu_rtc *rtc = dev_get_drvdata(dev);
- ssize_t retval;
-
- retval = sprintf(buf, "%u\n", rtc->alarm_expired);
-
- return retval;
-}
-
-static ssize_t retu_rtc_alarm_expired_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- struct retu_rtc *rtc = dev_get_drvdata(dev);
-
- rtc->alarm_expired = 0;
-
- return count;
-}
-static DEVICE_ATTR(alarm_expired, S_IRUGO | S_IWUSR,
- retu_rtc_alarm_expired_show, retu_rtc_alarm_expired_store);
-
-
-static ssize_t retu_rtc_cal_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct retu_rtc *rtc = dev_get_drvdata(dev);
- u16 rtccalr1;
-
- mutex_lock(&rtc->mutex);
- rtccalr1 = retu_read_reg(RETU_REG_RTCCALR);
- mutex_unlock(&rtc->mutex);
-
- /*
- * Shows the status of the Calibration Register.
- *
- * Default, after power loss: 0x0000
- * Default, for R&D: 0x00C0
- * Default, for factory: 0x00??
- *
- */
- return sprintf(buf, "0x%04x\n", rtccalr1 & 0x00ff);
-}
-
-static ssize_t retu_rtc_cal_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- struct retu_rtc *rtc = dev_get_drvdata(dev);
- unsigned calibration_value;
-
- if (sscanf(buf, "%x", &calibration_value) != 1)
- return count;
-
- mutex_lock(&rtc->mutex);
- retu_rtc_barrier(rtc);
- retu_write_reg(RETU_REG_RTCCALR, calibration_value & 0x00ff);
- mutex_unlock(&rtc->mutex);
-
- return count;
-}
-static DEVICE_ATTR(cal, S_IRUGO | S_IWUSR, retu_rtc_cal_show,
- retu_rtc_cal_store);
-
-static struct attribute *retu_rtc_attrs[] = {
- &dev_attr_cal.attr,
- &dev_attr_alarm_expired.attr,
- &dev_attr_alarm.attr,
- &dev_attr_reset.attr,
- &dev_attr_time.attr,
- NULL,
-};
-
-static const struct attribute_group retu_rtc_group = {
- .attrs = retu_rtc_attrs,
-};
-
static void retu_rtca_disable(struct retu_rtc *rtc)
{
retu_disable_irq(RETU_INT_RTCA);
@@ -348,8 +103,6 @@ static void retu_rtca_expired(struct work_struct *work)
struct retu_rtc *rtc = work_to_rtc(work);
retu_rtca_disable(rtc);
-
- sysfs_notify(&rtc->dev->kobj, NULL, "alarm_expired");
}
/*
@@ -397,6 +150,127 @@ static int retu_rtc_init_irq(struct retu_rtc *rtc)
return 0;
}
+static int retu_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
+{
+ struct retu_rtc *rtc = dev_get_drvdata(dev);
+ u16 chmar;
+
+ mutex_lock(&rtc->mutex);
+
+ chmar = ((alm->time.tm_hour & 0x1f) << 8) | (alm->time.tm_min & 0x3f);
+ retu_write_reg(RETU_REG_RTCHMAR, chmar);
+
+ mutex_unlock(&rtc->mutex);
+
+ return 0;
+}
+
+static int retu_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
+{
+ struct retu_rtc *rtc = dev_get_drvdata(dev);
+ u16 chmar;
+
+ mutex_lock(&rtc->mutex);
+
+ chmar = retu_read_reg(RETU_REG_RTCHMAR);
+
+ alm->time.tm_hour = (chmar >> 8) & 0x1f;
+ alm->time.tm_min = chmar & 0x3f;
+ alm->enabled = !!rtc->alarm_expired;
+
+ mutex_unlock(&rtc->mutex);
+
+ return 0;
+}
+
+static int retu_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct retu_rtc *rtc = dev_get_drvdata(dev);
+ u16 dsr;
+ u16 hmr;
+
+ dsr = ((tm->tm_mday & 0xff) << 8) | (tm->tm_hour & 0xff);
+ hmr = ((tm->tm_min & 0xff) << 8) | (tm->tm_sec & 0xff);
+
+ mutex_lock(&rtc->mutex);
+
+ retu_write_reg(RETU_REG_RTCDSR, dsr);
+ retu_write_reg(RETU_REG_RTCHMR, hmr);
+
+ mutex_unlock(&rtc->mutex);
+
+ return 0;
+}
+
+static int retu_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct retu_rtc *rtc = dev_get_drvdata(dev);
+ u16 dsr;
+ u16 hmr;
+
+ /*
+ * DSR holds days and hours
+ * HMR hols minutes and seconds
+ *
+ * both are 16 bit registers with 8-bit for each field.
+ */
+
+ mutex_lock(&rtc->mutex);
+
+ dsr = retu_read_reg(RETU_REG_RTCDSR);
+ hmr = retu_read_reg(RETU_REG_RTCHMR);
+
+ tm->tm_sec = hmr & 0xff;
+ tm->tm_min = hmr >> 8;
+ tm->tm_hour = dsr & 0xff;
+ tm->tm_mday = dsr >> 8;
+
+ mutex_unlock(&rtc->mutex);
+
+ return 0;
+}
+
+#ifdef CONFIG_RTC_INTF_DEV
+
+static int retu_rtc_ioctl(struct device *dev, unsigned int cmd,
+ unsigned long arg)
+{
+ struct retu_rtc *rtc = dev_get_drvdata(dev);
+
+ mutex_lock(&rtc->mutex);
+
+ switch (cmd) {
+ case RTC_AIE_OFF:
+ retu_disable_irq(RETU_INT_RTCA);
+ break;
+ case RTC_AIE_ON:
+ retu_enable_irq(RETU_INT_RTCA);
+ break;
+ case RTC_UIE_OFF:
+ retu_disable_irq(RETU_INT_RTCS);
+ break;
+ case RTC_UIE_ON:
+ retu_enable_irq(RETU_INT_RTCS);
+ break;
+ default:
+ return -ENOIOCTLCMD;
+ }
+
+ mutex_unlock(&rtc->mutex);
+
+ return 0;
+}
+#else
+#define retu_rtc_ioctl NULL
+#endif
+
+static struct rtc_class_ops retu_rtc_ops = {
+ .ioctl = retu_rtc_ioctl,
+ .read_time = retu_rtc_read_time,
+ .set_time = retu_rtc_set_time,
+ .read_alarm = retu_rtc_read_alarm,
+ .set_alarm = retu_rtc_set_alarm,
+};
static int __devinit retu_rtc_probe(struct platform_device *pdev)
{
@@ -437,9 +311,11 @@ static int __devinit retu_rtc_probe(struct platform_device *pdev)
else
retu_rtc_do_reset(rtc);
- r = sysfs_create_group(&pdev->dev.kobj, &retu_rtc_group);
- if (r) {
- dev_err(&pdev->dev, "couldn't create sysfs interface\n");
+
+ rtc->rtc = rtc_device_register(pdev->name, &pdev->dev, &
+ retu_rtc_ops, THIS_MODULE);
+ if (IS_ERR(rtc->rtc)) {
+ dev_err(&pdev->dev, "can't register RTC device\n");
goto err2;
}
@@ -466,7 +342,7 @@ static int __devexit retu_rtc_remove(struct platform_device *pdev)
retu_disable_irq(RETU_INT_RTCA);
retu_free_irq(RETU_INT_RTCS);
retu_free_irq(RETU_INT_RTCA);
- sysfs_remove_group(&pdev->dev.kobj, &retu_rtc_group);
+ rtc_device_unregister(rtc->rtc);
kfree(rtc);
return 0;