aboutsummaryrefslogtreecommitdiffstats
path: root/target
diff options
context:
space:
mode:
Diffstat (limited to 'target')
-rw-r--r--target/linux/generic/pending-5.4/190-rtc-rs5c372-support_alarms_up_to_1_week.patch96
-rw-r--r--target/linux/generic/pending-5.4/191-rtc-rs5c372-let_the_alarm_to_be_used_as_wakeup_source.patch72
2 files changed, 168 insertions, 0 deletions
diff --git a/target/linux/generic/pending-5.4/190-rtc-rs5c372-support_alarms_up_to_1_week.patch b/target/linux/generic/pending-5.4/190-rtc-rs5c372-support_alarms_up_to_1_week.patch
new file mode 100644
index 0000000000..83cab4e6d7
--- /dev/null
+++ b/target/linux/generic/pending-5.4/190-rtc-rs5c372-support_alarms_up_to_1_week.patch
@@ -0,0 +1,96 @@
+From: Daniel González Cabanelas <dgcbueu@gmail.com>
+Subject: [PATCH 1/2] rtc: rs5c372: support alarms up to 1 week
+
+The Ricoh R2221x, R2223x, RS5C372, RV5C387A chips can handle 1 week
+alarms.
+
+Read the "wday" alarm register and convert it to a date to support up 1
+week in our driver.
+
+Signed-off-by: Daniel González Cabanelas <dgcbueu@gmail.com>
+---
+ drivers/rtc/rtc-rs5c372.c | 48 ++++++++++++++++++++++++++++++++++-----
+ 1 file changed, 42 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/rtc/rtc-rs5c372.c b/drivers/rtc/rtc-rs5c372.c
+index 3bd6eaa0d..94b778c6e 100644
+--- a/drivers/rtc/rtc-rs5c372.c
++++ b/drivers/rtc/rtc-rs5c372.c
+@@ -393,7 +393,9 @@ static int rs5c_read_alarm(struct device *dev, struct rtc_wkalrm *t)
+ {
+ struct i2c_client *client = to_i2c_client(dev);
+ struct rs5c372 *rs5c = i2c_get_clientdata(client);
+- int status;
++ int status, wday_offs;
++ struct rtc_time rtc;
++ unsigned long alarm_secs;
+
+ status = rs5c_get_regs(rs5c);
+ if (status < 0)
+@@ -403,6 +405,30 @@ static int rs5c_read_alarm(struct device *dev, struct rtc_wkalrm *t)
+ t->time.tm_sec = 0;
+ t->time.tm_min = bcd2bin(rs5c->regs[RS5C_REG_ALARM_A_MIN] & 0x7f);
+ t->time.tm_hour = rs5c_reg2hr(rs5c, rs5c->regs[RS5C_REG_ALARM_A_HOURS]);
++ t->time.tm_wday = ffs(rs5c->regs[RS5C_REG_ALARM_A_WDAY] & 0x7f) - 1;
++
++ /* determine the day, month and year based on alarm wday, taking as a
++ * reference the current time from the rtc
++ */
++ status = rs5c372_rtc_read_time(dev, &rtc);
++ if (status < 0)
++ return status;
++
++ wday_offs = t->time.tm_wday - rtc.tm_wday;
++ alarm_secs = mktime64(rtc.tm_year + 1900,
++ rtc.tm_mon + 1,
++ rtc.tm_mday + wday_offs,
++ t->time.tm_hour,
++ t->time.tm_min,
++ t->time.tm_sec);
++
++ if (wday_offs < 0 || (wday_offs == 0 &&
++ (t->time.tm_hour < rtc.tm_hour ||
++ (t->time.tm_hour == rtc.tm_hour &&
++ t->time.tm_min <= rtc.tm_min))))
++ alarm_secs += 7 * 86400;
++
++ rtc_time64_to_tm(alarm_secs, &t->time);
+
+ /* ... and status */
+ t->enabled = !!(rs5c->regs[RS5C_REG_CTRL1] & RS5C_CTRL1_AALE);
+@@ -417,12 +443,20 @@ static int rs5c_set_alarm(struct device *dev, struct rtc_wkalrm *t)
+ struct rs5c372 *rs5c = i2c_get_clientdata(client);
+ int status, addr, i;
+ unsigned char buf[3];
++ struct rtc_time rtc_tm;
++ unsigned long rtc_secs, alarm_secs;
+
+- /* only handle up to 24 hours in the future, like RTC_ALM_SET */
+- if (t->time.tm_mday != -1
+- || t->time.tm_mon != -1
+- || t->time.tm_year != -1)
++ /* chip only can handle alarms up to one week in the future*/
++ status = rs5c372_rtc_read_time(dev, &rtc_tm);
++ if (status)
++ return status;
++ rtc_secs = rtc_tm_to_time64(&rtc_tm);
++ alarm_secs = rtc_tm_to_time64(&t->time);
++ if (alarm_secs >= rtc_secs + 7 * 86400) {
++ dev_err(dev, "%s: alarm maximum is one week in the future (%d)\n",
++ __func__, status);
+ return -EINVAL;
++ }
+
+ /* REVISIT: round up tm_sec */
+
+@@ -443,7 +477,9 @@ static int rs5c_set_alarm(struct device *dev, struct rtc_wkalrm *t)
+ /* set alarm */
+ buf[0] = bin2bcd(t->time.tm_min);
+ buf[1] = rs5c_hr2reg(rs5c, t->time.tm_hour);
+- buf[2] = 0x7f; /* any/all days */
++ /* each bit is the day of the week, 0x7f means all days */
++ buf[2] = (t->time.tm_wday >= 0 && t->time.tm_wday < 7) ?
++ BIT(t->time.tm_wday) : 0x7f;
+
+ for (i = 0; i < sizeof(buf); i++) {
+ addr = RS5C_ADDR(RS5C_REG_ALARM_A_MIN + i);
diff --git a/target/linux/generic/pending-5.4/191-rtc-rs5c372-let_the_alarm_to_be_used_as_wakeup_source.patch b/target/linux/generic/pending-5.4/191-rtc-rs5c372-let_the_alarm_to_be_used_as_wakeup_source.patch
new file mode 100644
index 0000000000..d5c8c23f65
--- /dev/null
+++ b/target/linux/generic/pending-5.4/191-rtc-rs5c372-let_the_alarm_to_be_used_as_wakeup_source.patch
@@ -0,0 +1,72 @@
+From: Daniel González Cabanelas <dgcbueu@gmail.com>
+Subject: [PATCH 2/2] rtc: rs5c372: let the alarm to be used as wakeup source
+
+Currently there is no use for the interrupts on the rs5c372 RTC and the
+wakealarm isn't enabled. There are some devices like NASes which use this
+RTC to wake up from the power off state when the INTR pin is activated by
+the alarm clock.
+
+Enable the alarm and let to be used as a wakeup source.
+
+Tested on a Buffalo LS421DE NAS.
+
+Signed-off-by: Daniel González Cabanelas <dgcbueu@gmail.com>
+---
+ drivers/rtc/rtc-rs5c372.c | 16 ++++++++++++++++
+ 1 file changed, 16 insertions(+)
+
+diff --git a/drivers/rtc/rtc-rs5c372.c b/drivers/rtc/rtc-rs5c372.c
+index 94b778c6e..76775d66e 100644
+--- a/drivers/rtc/rtc-rs5c372.c
++++ b/drivers/rtc/rtc-rs5c372.c
+@@ -654,6 +654,7 @@ static int rs5c372_probe(struct i2c_client *client,
+ int err = 0;
+ int smbus_mode = 0;
+ struct rs5c372 *rs5c372;
++ bool rs5c372_can_wakeup_device = false;
+
+ dev_dbg(&client->dev, "%s\n", __func__);
+
+@@ -689,6 +690,12 @@ static int rs5c372_probe(struct i2c_client *client,
+ else
+ rs5c372->type = id->driver_data;
+
++#ifdef CONFIG_OF
++ if(of_property_read_bool(client->dev.of_node,
++ "wakeup-source"))
++ rs5c372_can_wakeup_device = true;
++#endif
++
+ /* we read registers 0x0f then 0x00-0x0f; skip the first one */
+ rs5c372->regs = &rs5c372->buf[1];
+ rs5c372->smbus = smbus_mode;
+@@ -722,6 +729,8 @@ static int rs5c372_probe(struct i2c_client *client,
+ goto exit;
+ }
+
++ rs5c372->has_irq = 1;
++
+ /* if the oscillator lost power and no other software (like
+ * the bootloader) set it up, do it here.
+ *
+@@ -748,6 +757,10 @@ static int rs5c372_probe(struct i2c_client *client,
+ );
+
+ /* REVISIT use client->irq to register alarm irq ... */
++ if (rs5c372_can_wakeup_device) {
++ device_init_wakeup(&client->dev, true);
++ }
++
+ rs5c372->rtc = devm_rtc_device_register(&client->dev,
+ rs5c372_driver.driver.name,
+ &rs5c372_rtc_ops, THIS_MODULE);
+@@ -761,6 +774,9 @@ static int rs5c372_probe(struct i2c_client *client,
+ if (err)
+ goto exit;
+
++ /* the rs5c372 alarm only supports a minute accuracy */
++ rs5c372->rtc->uie_unsupported = 1;
++
+ return 0;
+
+ exit: