Cherry pick patches for rtc-s35390a from next
This fixes shutting down some QNAP NAS devices after being waked up by the rtc.
This commit is contained in:
parent
2064fe3730
commit
0818af71cc
|
@ -1,3 +1,9 @@
|
|||
linux (4.6.3-2) UNRELEASED; urgency=medium
|
||||
|
||||
* Cherry pick patches for rtc-s35390a from next. (Closes: #794266)
|
||||
|
||||
-- Uwe Kleine-König <ukleinek@debian.org> Sun, 10 Jul 2016 15:25:48 +0200
|
||||
|
||||
linux (4.6.3-1) unstable; urgency=medium
|
||||
|
||||
[ Ben Hutchings ]
|
||||
|
|
42
debian/patches/bugfix/all/rtc-initialize-output-parameter-for-read-alarm-to-un.patch
vendored
Normal file
42
debian/patches/bugfix/all/rtc-initialize-output-parameter-for-read-alarm-to-un.patch
vendored
Normal file
|
@ -0,0 +1,42 @@
|
|||
From: Uwe Kleine-König <uwe@kleine-koenig.org>
|
||||
Date: Wed, 11 May 2016 09:11:23 +0200
|
||||
Subject: [PATCH] rtc: initialize output parameter for read alarm to
|
||||
"uninitialized"
|
||||
Origin: https://git.kernel.org/cgit/linux/kernel/git/next/linux-next.git/commit/?id=d68778b80dd78ad6ed998397af182163d0ef16b0
|
||||
|
||||
rtc drivers are supposed to set values they don't support to -1. To
|
||||
simplify this for drivers and also make it harder for them to get it
|
||||
wrong initialize the values to -1.
|
||||
|
||||
Signed-off-by: Uwe Kleine-König <uwe@kleine-koenig.org>
|
||||
Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
|
||||
---
|
||||
drivers/rtc/interface.c | 12 +++++++++++-
|
||||
1 file changed, 11 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c
|
||||
index 9ef5f6f89f98..99475908e556 100644
|
||||
--- a/drivers/rtc/interface.c
|
||||
+++ b/drivers/rtc/interface.c
|
||||
@@ -104,7 +104,17 @@ static int rtc_read_alarm_internal(struct rtc_device *rtc, struct rtc_wkalrm *al
|
||||
else if (!rtc->ops->read_alarm)
|
||||
err = -EINVAL;
|
||||
else {
|
||||
- memset(alarm, 0, sizeof(struct rtc_wkalrm));
|
||||
+ alarm->enabled = 0;
|
||||
+ alarm->pending = 0;
|
||||
+ alarm->time.tm_sec = -1;
|
||||
+ alarm->time.tm_min = -1;
|
||||
+ alarm->time.tm_hour = -1;
|
||||
+ alarm->time.tm_mday = -1;
|
||||
+ alarm->time.tm_mon = -1;
|
||||
+ alarm->time.tm_year = -1;
|
||||
+ alarm->time.tm_wday = -1;
|
||||
+ alarm->time.tm_yday = -1;
|
||||
+ alarm->time.tm_isdst = -1;
|
||||
err = rtc->ops->read_alarm(rtc->dev.parent, alarm);
|
||||
}
|
||||
|
||||
--
|
||||
2.8.1
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
From: Uwe Kleine-König <uwe@kleine-koenig.org>
|
||||
Date: Sat, 2 Jul 2016 17:28:08 +0200
|
||||
Subject: [PATCH] rtc: s35390a: fix reading out alarm
|
||||
Origin: https://git.kernel.org/cgit/linux/kernel/git/next/linux-next.git/commit/?id=ee82c046c1031af95e8c24dda072e04c565d4247
|
||||
|
||||
There are several issues fixed in this patch:
|
||||
|
||||
- When alarm isn't enabled, set .enabled to zero instead of returning
|
||||
-EINVAL.
|
||||
- Ignore how IRQ1 is configured when determining if IRQ2 is on.
|
||||
- The three alarm registers have an enable flag which must be
|
||||
evaluated.
|
||||
- The chip always triggers when the seconds register gets 0.
|
||||
|
||||
Note that the rtc framework however doesn't handle the result correctly
|
||||
because it doesn't check wday being initialized and so interprets an
|
||||
alarm being set for 10:00 AM in three days as 10:00 AM tomorrow (or
|
||||
today if that's not over yet).
|
||||
|
||||
Signed-off-by: Uwe Kleine-König <uwe@kleine-koenig.org>
|
||||
Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
|
||||
---
|
||||
drivers/rtc/rtc-s35390a.c | 40 +++++++++++++++++++++++++++++++---------
|
||||
1 file changed, 31 insertions(+), 9 deletions(-)
|
||||
|
||||
diff --git a/drivers/rtc/rtc-s35390a.c b/drivers/rtc/rtc-s35390a.c
|
||||
index f40afdd0e5f5..6507a01cf9ad 100644
|
||||
--- a/drivers/rtc/rtc-s35390a.c
|
||||
+++ b/drivers/rtc/rtc-s35390a.c
|
||||
@@ -242,6 +242,8 @@ static int s35390a_set_alarm(struct i2c_client *client, struct rtc_wkalrm *alm)
|
||||
|
||||
if (alm->time.tm_wday != -1)
|
||||
buf[S35390A_ALRM_BYTE_WDAY] = bin2bcd(alm->time.tm_wday) | 0x80;
|
||||
+ else
|
||||
+ buf[S35390A_ALRM_BYTE_WDAY] = 0;
|
||||
|
||||
buf[S35390A_ALRM_BYTE_HOURS] = s35390a_hr2reg(s35390a,
|
||||
alm->time.tm_hour) | 0x80;
|
||||
@@ -269,23 +271,43 @@ static int s35390a_read_alarm(struct i2c_client *client, struct rtc_wkalrm *alm)
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
- if (bitrev8(sts) != S35390A_INT2_MODE_ALARM)
|
||||
- return -EINVAL;
|
||||
+ if ((bitrev8(sts) & S35390A_INT2_MODE_MASK) != S35390A_INT2_MODE_ALARM) {
|
||||
+ /*
|
||||
+ * When the alarm isn't enabled, the register to configure
|
||||
+ * the alarm time isn't accessible.
|
||||
+ */
|
||||
+ alm->enabled = 0;
|
||||
+ return 0;
|
||||
+ } else {
|
||||
+ alm->enabled = 1;
|
||||
+ }
|
||||
|
||||
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) {
|
||||
+ 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]);
|
||||
+ /*
|
||||
+ * B0 of the three matching registers is an enable flag. Iff it is set
|
||||
+ * the configured value is used for matching.
|
||||
+ */
|
||||
+ if (buf[S35390A_ALRM_BYTE_WDAY] & 0x80)
|
||||
+ alm->time.tm_wday =
|
||||
+ bcd2bin(buf[S35390A_ALRM_BYTE_WDAY] & ~0x80);
|
||||
+
|
||||
+ if (buf[S35390A_ALRM_BYTE_HOURS] & 0x80)
|
||||
+ alm->time.tm_hour =
|
||||
+ s35390a_reg2hr(s35390a,
|
||||
+ buf[S35390A_ALRM_BYTE_HOURS] & ~0x80);
|
||||
+
|
||||
+ if (buf[S35390A_ALRM_BYTE_MINS] & 0x80)
|
||||
+ alm->time.tm_min = bcd2bin(buf[S35390A_ALRM_BYTE_MINS] & ~0x80);
|
||||
+
|
||||
+ /* alarm triggers always at s=0 */
|
||||
+ alm->time.tm_sec = 0;
|
||||
|
||||
dev_dbg(&client->dev, "%s: alm is mins=%d, hours=%d, wday=%d\n",
|
||||
__func__, alm->time.tm_min, alm->time.tm_hour,
|
||||
--
|
||||
2.8.1
|
||||
|
128
debian/patches/bugfix/all/rtc-s35390a-implement-reset-routine-as-suggested-by-.patch
vendored
Normal file
128
debian/patches/bugfix/all/rtc-s35390a-implement-reset-routine-as-suggested-by-.patch
vendored
Normal file
|
@ -0,0 +1,128 @@
|
|||
From: Uwe Kleine-König <uwe@kleine-koenig.org>
|
||||
Date: Sat, 2 Jul 2016 17:28:09 +0200
|
||||
Subject: [PATCH] rtc: s35390a: implement reset routine as suggested by the
|
||||
reference
|
||||
Origin: https://git.kernel.org/cgit/linux/kernel/git/next/linux-next.git/commit/?id=0af8a35b6ab4ba000d8f18748bb621c8ed5e7827
|
||||
|
||||
There were two deviations from the reference manual: you have to wait
|
||||
half a second when POC is active and you might have to repeat
|
||||
initialization when POC or BLD are still set after the sequence.
|
||||
|
||||
Note however that as POC and BLD are cleared by read the driver might
|
||||
not be able to detect that a reset is necessary. I don't have a good
|
||||
idea how to fix this.
|
||||
|
||||
Additionally report the value read from STATUS1 to the caller. This
|
||||
prepares the next patch.
|
||||
|
||||
Signed-off-by: Uwe Kleine-König <uwe@kleine-koenig.org>
|
||||
Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
|
||||
---
|
||||
drivers/rtc/rtc-s35390a.c | 65 +++++++++++++++++++++++++++++++++++++++--------
|
||||
1 file changed, 55 insertions(+), 10 deletions(-)
|
||||
|
||||
diff --git a/drivers/rtc/rtc-s35390a.c b/drivers/rtc/rtc-s35390a.c
|
||||
index 6507a01cf9ad..6c90c9f48cab 100644
|
||||
--- a/drivers/rtc/rtc-s35390a.c
|
||||
+++ b/drivers/rtc/rtc-s35390a.c
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <linux/bitrev.h>
|
||||
#include <linux/bcd.h>
|
||||
#include <linux/slab.h>
|
||||
+#include <linux/delay.h>
|
||||
|
||||
#define S35390A_CMD_STATUS1 0
|
||||
#define S35390A_CMD_STATUS2 1
|
||||
@@ -94,19 +95,63 @@ static int s35390a_get_reg(struct s35390a *s35390a, int reg, char *buf, int len)
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static int s35390a_reset(struct s35390a *s35390a)
|
||||
+/*
|
||||
+ * Returns <0 on error, 0 if rtc is setup fine and 1 if the chip was reset.
|
||||
+ * To keep the information if an irq is pending, pass the value read from
|
||||
+ * STATUS1 to the caller.
|
||||
+ */
|
||||
+static int s35390a_reset(struct s35390a *s35390a, char *status1)
|
||||
{
|
||||
- char buf[1];
|
||||
+ char buf;
|
||||
+ int ret;
|
||||
+ unsigned initcount = 0;
|
||||
|
||||
- if (s35390a_get_reg(s35390a, S35390A_CMD_STATUS1, buf, sizeof(buf)) < 0)
|
||||
- return -EIO;
|
||||
+ ret = s35390a_get_reg(s35390a, S35390A_CMD_STATUS1, status1, 1);
|
||||
+ if (ret < 0)
|
||||
+ return ret;
|
||||
|
||||
- if (!(buf[0] & (S35390A_FLAG_POC | S35390A_FLAG_BLD)))
|
||||
+ if (*status1 & S35390A_FLAG_POC)
|
||||
+ /*
|
||||
+ * Do not communicate for 0.5 seconds since the power-on
|
||||
+ * detection circuit is in operation.
|
||||
+ */
|
||||
+ msleep(500);
|
||||
+ else if (!(*status1 & S35390A_FLAG_BLD))
|
||||
+ /*
|
||||
+ * If both POC and BLD are unset everything is fine.
|
||||
+ */
|
||||
return 0;
|
||||
|
||||
- buf[0] |= (S35390A_FLAG_RESET | S35390A_FLAG_24H);
|
||||
- buf[0] &= 0xf0;
|
||||
- return s35390a_set_reg(s35390a, S35390A_CMD_STATUS1, buf, sizeof(buf));
|
||||
+ /*
|
||||
+ * At least one of POC and BLD are set, so reinitialise chip. Keeping
|
||||
+ * this information in the hardware to know later that the time isn't
|
||||
+ * valid is unfortunately not possible because POC and BLD are cleared
|
||||
+ * on read. So the reset is best done now.
|
||||
+ *
|
||||
+ * The 24H bit is kept over reset, so set it already here.
|
||||
+ */
|
||||
+initialize:
|
||||
+ *status1 = S35390A_FLAG_24H;
|
||||
+ buf = S35390A_FLAG_RESET | S35390A_FLAG_24H;
|
||||
+ ret = s35390a_set_reg(s35390a, S35390A_CMD_STATUS1, &buf, 1);
|
||||
+
|
||||
+ if (ret < 0)
|
||||
+ return ret;
|
||||
+
|
||||
+ ret = s35390a_get_reg(s35390a, S35390A_CMD_STATUS1, &buf, 1);
|
||||
+ if (ret < 0)
|
||||
+ return ret;
|
||||
+
|
||||
+ if (buf & (S35390A_FLAG_POC | S35390A_FLAG_BLD)) {
|
||||
+ /* Try up to five times to reset the chip */
|
||||
+ if (initcount < 5) {
|
||||
+ ++initcount;
|
||||
+ goto initialize;
|
||||
+ } else
|
||||
+ return -EIO;
|
||||
+ }
|
||||
+
|
||||
+ return 1;
|
||||
}
|
||||
|
||||
static int s35390a_disable_test_mode(struct s35390a *s35390a)
|
||||
@@ -353,7 +398,7 @@ static int s35390a_probe(struct i2c_client *client,
|
||||
unsigned int i;
|
||||
struct s35390a *s35390a;
|
||||
struct rtc_time tm;
|
||||
- char buf[1];
|
||||
+ char buf[1], status1;
|
||||
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
|
||||
err = -ENODEV;
|
||||
@@ -382,7 +427,7 @@ static int s35390a_probe(struct i2c_client *client,
|
||||
}
|
||||
}
|
||||
|
||||
- err = s35390a_reset(s35390a);
|
||||
+ err = s35390a_reset(s35390a, &status1);
|
||||
if (err < 0) {
|
||||
dev_err(&client->dev, "error resetting chip\n");
|
||||
goto exit_dummy;
|
||||
--
|
||||
2.8.1
|
||||
|
|
@ -0,0 +1,123 @@
|
|||
From: Uwe Kleine-König <uwe@kleine-koenig.org>
|
||||
Date: Sat, 2 Jul 2016 17:28:10 +0200
|
||||
Subject: [PATCH] rtc: s35390a: improve irq handling
|
||||
Origin: https://git.kernel.org/cgit/linux/kernel/git/next/linux-next.git/commit/?id=998dd84e542720cf02cbe9ea002de3850df32996
|
||||
|
||||
On some QNAP NAS devices the rtc can wake the machine. Several people
|
||||
noticed that once the machine was woken this way it fails to shut down.
|
||||
That's because the driver fails to acknowledge the interrupt and so it
|
||||
keeps active and restarts the machine immediatly after shutdown. See
|
||||
https://bugs.debian.org/794266 for a bug report.
|
||||
|
||||
Doing this correctly requires to interpret the INT2 flag of the first read
|
||||
of the STATUS1 register because this bit is cleared by read.
|
||||
|
||||
Note this is not maximally robust though because a pending irq isn't
|
||||
detected when the STATUS1 register was already read (and so INT2 is not
|
||||
set) but the irq was not disabled. But that is a hardware imposed problem
|
||||
that cannot easily be fixed by software.
|
||||
|
||||
Signed-off-by: Uwe Kleine-König <uwe@kleine-koenig.org>
|
||||
Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
|
||||
---
|
||||
drivers/rtc/rtc-s35390a.c | 48 ++++++++++++++++++++++++++++++-----------------
|
||||
1 file changed, 31 insertions(+), 17 deletions(-)
|
||||
|
||||
diff --git a/drivers/rtc/rtc-s35390a.c b/drivers/rtc/rtc-s35390a.c
|
||||
index 6c90c9f48cab..d5b572266a72 100644
|
||||
--- a/drivers/rtc/rtc-s35390a.c
|
||||
+++ b/drivers/rtc/rtc-s35390a.c
|
||||
@@ -35,10 +35,14 @@
|
||||
#define S35390A_ALRM_BYTE_HOURS 1
|
||||
#define S35390A_ALRM_BYTE_MINS 2
|
||||
|
||||
+/* flags for STATUS1 */
|
||||
#define S35390A_FLAG_POC 0x01
|
||||
#define S35390A_FLAG_BLD 0x02
|
||||
+#define S35390A_FLAG_INT2 0x04
|
||||
#define S35390A_FLAG_24H 0x40
|
||||
#define S35390A_FLAG_RESET 0x80
|
||||
+
|
||||
+/* flag for STATUS2 */
|
||||
#define S35390A_FLAG_TEST 0x01
|
||||
|
||||
#define S35390A_INT2_MODE_MASK 0xF0
|
||||
@@ -394,11 +398,11 @@ static struct i2c_driver s35390a_driver;
|
||||
static int s35390a_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
- int err;
|
||||
+ int err, err_reset;
|
||||
unsigned int i;
|
||||
struct s35390a *s35390a;
|
||||
struct rtc_time tm;
|
||||
- char buf[1], status1;
|
||||
+ char buf, status1;
|
||||
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
|
||||
err = -ENODEV;
|
||||
@@ -427,29 +431,35 @@ static int s35390a_probe(struct i2c_client *client,
|
||||
}
|
||||
}
|
||||
|
||||
- err = s35390a_reset(s35390a, &status1);
|
||||
- if (err < 0) {
|
||||
+ err_reset = s35390a_reset(s35390a, &status1);
|
||||
+ if (err_reset < 0) {
|
||||
+ err = err_reset;
|
||||
dev_err(&client->dev, "error resetting chip\n");
|
||||
goto exit_dummy;
|
||||
}
|
||||
|
||||
- err = s35390a_disable_test_mode(s35390a);
|
||||
- if (err < 0) {
|
||||
- dev_err(&client->dev, "error disabling test mode\n");
|
||||
- goto exit_dummy;
|
||||
- }
|
||||
-
|
||||
- err = s35390a_get_reg(s35390a, S35390A_CMD_STATUS1, buf, sizeof(buf));
|
||||
- if (err < 0) {
|
||||
- dev_err(&client->dev, "error checking 12/24 hour mode\n");
|
||||
- goto exit_dummy;
|
||||
- }
|
||||
- if (buf[0] & S35390A_FLAG_24H)
|
||||
+ if (status1 & S35390A_FLAG_24H)
|
||||
s35390a->twentyfourhour = 1;
|
||||
else
|
||||
s35390a->twentyfourhour = 0;
|
||||
|
||||
- if (s35390a_get_datetime(client, &tm) < 0)
|
||||
+ if (status1 & S35390A_FLAG_INT2) {
|
||||
+ /* disable alarm (and maybe test mode) */
|
||||
+ buf = 0;
|
||||
+ err = s35390a_set_reg(s35390a, S35390A_CMD_STATUS2, &buf, 1);
|
||||
+ if (err < 0) {
|
||||
+ dev_err(&client->dev, "error disabling alarm");
|
||||
+ goto exit_dummy;
|
||||
+ }
|
||||
+ } else {
|
||||
+ err = s35390a_disable_test_mode(s35390a);
|
||||
+ if (err < 0) {
|
||||
+ dev_err(&client->dev, "error disabling test mode\n");
|
||||
+ goto exit_dummy;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (err_reset > 0 || s35390a_get_datetime(client, &tm) < 0)
|
||||
dev_warn(&client->dev, "clock needs to be set\n");
|
||||
|
||||
device_set_wakeup_capable(&client->dev, 1);
|
||||
@@ -462,6 +472,10 @@ static int s35390a_probe(struct i2c_client *client,
|
||||
err = PTR_ERR(s35390a->rtc);
|
||||
goto exit_dummy;
|
||||
}
|
||||
+
|
||||
+ if (status1 & S35390A_FLAG_INT2)
|
||||
+ rtc_update_irq(s35390a->rtc, 1, RTC_AF);
|
||||
+
|
||||
return 0;
|
||||
|
||||
exit_dummy:
|
||||
--
|
||||
2.8.1
|
||||
|
|
@ -145,3 +145,9 @@ bugfix/all/liblockdep-enable-wall-by-default.patch
|
|||
bugfix/all/liblockdep-fix-unused-value-warnings.patch
|
||||
bugfix/all/liblockdep-fix-set-but-not-used-warnings.patch
|
||||
bugfix/all/liblockdep-fix-defined-but-not-used-warning-for-init.patch
|
||||
|
||||
# Debian bug #794266
|
||||
bugfix/all/rtc-initialize-output-parameter-for-read-alarm-to-un.patch
|
||||
bugfix/all/rtc-s35390a-fix-reading-out-alarm.patch
|
||||
bugfix/all/rtc-s35390a-implement-reset-routine-as-suggested-by-.patch
|
||||
bugfix/all/rtc-s35390a-improve-irq-handling.patch
|
||||
|
|
Loading…
Reference in New Issue