All of lore.kernel.org
 help / color / mirror / Atom feed
From: Michael Langer <michael.brainbug.langer@googlemail.com>
To: Alessandro Zummo <a.zummo@towertech.it>
Cc: rtc-linux@googlegroups.com, linux-kernel@vger.kernel.org
Subject: [PATCH] rtc: add wakealarm support for rtc-s35390A rtc chip
Date: Sun, 23 Sep 2012 14:47:24 +0200	[thread overview]
Message-ID: <505F04DC.2020500@googlemail.com> (raw)

Hello,

this patch will add get/set alarm functionality to QNAP TS-219P+ NAS.
I have tested it against a debian wheezy kernel (3.2.23, armel) . After
that I applied the patch against HEAD of linus master branch and
compiled, not tested, successfully.

Regards
Michael

>From a01affe35c049f66fc83ee151d760f3c943aa327 Mon Sep 17 00:00:00 2001
From: Michael Langer <michael.brainbug.langer@googlemail.com>
Date: Sun, 23 Sep 2012 08:27:24 +0200
Subject: [PATCH] rtc: add wakealarm support for rtc-s35390A rtc chip

This adds basic get/set alarm support for the Seiko Instruments S-35390A.
The chip is used on the QNAP TS-219P+ NAS device.

Signed-off-by: Michael Langer <michael.brainbug.langer@googlemail.com>
---
 drivers/rtc/rtc-s35390a.c |  116
+++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 116 insertions(+)

diff --git a/drivers/rtc/rtc-s35390a.c b/drivers/rtc/rtc-s35390a.c
index c9562ce..ef41e7e 100644
--- a/drivers/rtc/rtc-s35390a.c
+++ b/drivers/rtc/rtc-s35390a.c
@@ -19,6 +19,8 @@
 #define S35390A_CMD_STATUS1    0
 #define S35390A_CMD_STATUS2    1
 #define S35390A_CMD_TIME1    2
+#define S35390A_CMD_TIME2    3
+#define S35390A_CMD_INT2_REG1    5
 
 #define S35390A_BYTE_YEAR    0
 #define S35390A_BYTE_MONTH    1
@@ -28,12 +30,23 @@
 #define S35390A_BYTE_MINS    5
 #define S35390A_BYTE_SECS    6
 
+#define S35390A_ALRM_BYTE_WDAY    0
+#define S35390A_ALRM_BYTE_HOURS    1
+#define S35390A_ALRM_BYTE_MINS    2
+
 #define S35390A_FLAG_POC    0x01
 #define S35390A_FLAG_BLD    0x02
 #define S35390A_FLAG_24H    0x40
 #define S35390A_FLAG_RESET    0x80
 #define S35390A_FLAG_TEST    0x01
 
+#define S35390A_INT2_MODE_MASK        0xF0
+
+#define S35390A_INT2_MODE_NOINTR    0x00
+#define S35390A_INT2_MODE_FREQ        0x10
+#define S35390A_INT2_MODE_ALARM        0x40
+#define S35390A_INT2_MODE_PMIN_EDG    0x20
+
 static const struct i2c_device_id s35390a_id[] = {
     { "s35390a", 0 },
     { }
@@ -184,6 +197,104 @@ static int s35390a_get_datetime(struct i2c_client
*client, struct rtc_time *tm)
     return rtc_valid_tm(tm);
 }
 
+static int s35390a_set_alarm(struct i2c_client *client, struct
rtc_wkalrm *alm)
+{
+    struct s35390a *s35390a = i2c_get_clientdata(client);
+    char buf[3], sts = 0;
+    int err, i;
+
+    dev_dbg(&client->dev, "%s: alm is secs=%d, mins=%d, hours=%d
mday=%d, "\
+        "mon=%d, year=%d, wday=%d\n", __func__, alm->time.tm_sec,
+        alm->time.tm_min, alm->time.tm_hour, alm->time.tm_mday,
+        alm->time.tm_mon, alm->time.tm_year, alm->time.tm_wday);
+
+    /* disable interrupt */
+    err = s35390a_set_reg(s35390a, S35390A_CMD_STATUS2, &sts, sizeof(sts));
+    if (err < 0)
+        return err;
+
+    /* clear pending interrupt, if any */
+    err = s35390a_get_reg(s35390a, S35390A_CMD_STATUS1, &sts, sizeof(sts));
+    if (err < 0)
+        return err;
+
+    if (alm->enabled)
+        sts = S35390A_INT2_MODE_ALARM;
+    else
+        sts = S35390A_INT2_MODE_NOINTR;
+
+    /* This chip expects the bits of each byte to be in reverse order */
+    sts = bitrev8(sts);
+
+    /* set interupt mode*/
+    err = s35390a_set_reg(s35390a, S35390A_CMD_STATUS2, &sts, sizeof(sts));
+    if (err < 0)
+        return err;
+
+    if (alm->time.tm_wday != -1)
+        buf[S35390A_ALRM_BYTE_WDAY] = bin2bcd(alm->time.tm_wday) | 0x80;
+
+    buf[S35390A_ALRM_BYTE_HOURS] = s35390a_hr2reg(s35390a,
+            alm->time.tm_hour) | 0x80;
+    buf[S35390A_ALRM_BYTE_MINS] = bin2bcd(alm->time.tm_min) | 0x80;
+
+    if (alm->time.tm_hour >= 12)
+        buf[S35390A_ALRM_BYTE_HOURS] |= 0x40;
+
+    for (i = 0; i < 3; ++i)
+        buf[i] = bitrev8(buf[i]);
+
+    err = s35390a_set_reg(s35390a, S35390A_CMD_INT2_REG1, buf,
+                                sizeof(buf));
+
+    return err;
+}
+
+static int s35390a_read_alarm(struct i2c_client *client, struct
rtc_wkalrm *alm)
+{
+    struct s35390a *s35390a = i2c_get_clientdata(client);
+    char buf[3], sts;
+    int i, err;
+
+    err = s35390a_get_reg(s35390a, S35390A_CMD_STATUS2, &sts, sizeof(sts));
+    if (err < 0)
+        return err;
+
+    if (bitrev8(sts) != S35390A_INT2_MODE_ALARM)
+        return -EINVAL;
+
+    err = s35390a_get_reg(s35390a, S35390A_CMD_INT2_REG1, buf,
sizeof(buf));
+    if (err < 0)
+        return err;
+
+    /* This chip returns the bits of each byte in reverse order */
+    for (i = 0; i < 3; ++i) {
+        buf[i] = bitrev8(buf[i]);
+        buf[i] &= ~0x80;
+    }
+
+    alm->time.tm_wday = bcd2bin(buf[S35390A_ALRM_BYTE_WDAY]);
+    alm->time.tm_hour = s35390a_reg2hr(s35390a,
+                        buf[S35390A_ALRM_BYTE_HOURS]);
+    alm->time.tm_min = bcd2bin(buf[S35390A_ALRM_BYTE_MINS]);
+
+    dev_dbg(&client->dev, "%s: alm is mins=%d, hours=%d, wday=%d\n",
+            __func__, alm->time.tm_min, alm->time.tm_hour,
+            alm->time.tm_wday);
+
+    return 0;
+}
+
+static int s35390a_rtc_read_alarm(struct device *dev, struct rtc_wkalrm
*alm)
+{
+    return s35390a_read_alarm(to_i2c_client(dev), alm);
+}
+
+static int s35390a_rtc_set_alarm(struct device *dev, struct rtc_wkalrm
*alm)
+{
+    return s35390a_set_alarm(to_i2c_client(dev), alm);
+}
+
 static int s35390a_rtc_read_time(struct device *dev, struct rtc_time *tm)
 {
     return s35390a_get_datetime(to_i2c_client(dev), tm);
@@ -197,6 +308,9 @@ static int s35390a_rtc_set_time(struct device *dev,
struct rtc_time *tm)
 static const struct rtc_class_ops s35390a_rtc_ops = {
     .read_time    = s35390a_rtc_read_time,
     .set_time    = s35390a_rtc_set_time,
+    .set_alarm    = s35390a_rtc_set_alarm,
+    .read_alarm    = s35390a_rtc_read_alarm,
+
 };
 
 static struct i2c_driver s35390a_driver;
@@ -261,6 +375,8 @@ static int s35390a_probe(struct i2c_client *client,
     if (s35390a_get_datetime(client, &tm) < 0)
         dev_warn(&client->dev, "clock needs to be set\n");
 
+    device_set_wakeup_capable(&client->dev, 1);
+
     s35390a->rtc = rtc_device_register(s35390a_driver.driver.name,
                 &client->dev, &s35390a_rtc_ops, THIS_MODULE);
 
-- 
1.7.10.4


             reply	other threads:[~2012-09-23 12:47 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-09-23 12:47 Michael Langer [this message]
  -- strict thread matches above, loose matches on Subject: below --
2012-09-26 18:42 [PATCH] rtc: add wakealarm support for rtc-s35390A rtc chip Michael Langer

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=505F04DC.2020500@googlemail.com \
    --to=michael.brainbug.langer@googlemail.com \
    --cc=a.zummo@towertech.it \
    --cc=linux-kernel@vger.kernel.org \
    --cc=rtc-linux@googlegroups.com \
    /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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.