kernel: bump 5.4 to 5.4.86
[openwrt/openwrt.git] / target / linux / generic / pending-5.4 / 190-rtc-rs5c372-support_alarms_up_to_1_week.patch
1 From: Daniel González Cabanelas <dgcbueu@gmail.com>
2 Subject: [PATCH 1/2] rtc: rs5c372: support alarms up to 1 week
3
4 The Ricoh R2221x, R2223x, RS5C372, RV5C387A chips can handle 1 week
5 alarms.
6
7 Read the "wday" alarm register and convert it to a date to support up 1
8 week in our driver.
9
10 Signed-off-by: Daniel González Cabanelas <dgcbueu@gmail.com>
11 ---
12 drivers/rtc/rtc-rs5c372.c | 48 ++++++++++++++++++++++++++++++++++-----
13 1 file changed, 42 insertions(+), 6 deletions(-)
14
15 --- a/drivers/rtc/rtc-rs5c372.c
16 +++ b/drivers/rtc/rtc-rs5c372.c
17 @@ -393,7 +393,9 @@ static int rs5c_read_alarm(struct device
18 {
19 struct i2c_client *client = to_i2c_client(dev);
20 struct rs5c372 *rs5c = i2c_get_clientdata(client);
21 - int status;
22 + int status, wday_offs;
23 + struct rtc_time rtc;
24 + unsigned long alarm_secs;
25
26 status = rs5c_get_regs(rs5c);
27 if (status < 0)
28 @@ -403,6 +405,30 @@ static int rs5c_read_alarm(struct device
29 t->time.tm_sec = 0;
30 t->time.tm_min = bcd2bin(rs5c->regs[RS5C_REG_ALARM_A_MIN] & 0x7f);
31 t->time.tm_hour = rs5c_reg2hr(rs5c, rs5c->regs[RS5C_REG_ALARM_A_HOURS]);
32 + t->time.tm_wday = ffs(rs5c->regs[RS5C_REG_ALARM_A_WDAY] & 0x7f) - 1;
33 +
34 + /* determine the day, month and year based on alarm wday, taking as a
35 + * reference the current time from the rtc
36 + */
37 + status = rs5c372_rtc_read_time(dev, &rtc);
38 + if (status < 0)
39 + return status;
40 +
41 + wday_offs = t->time.tm_wday - rtc.tm_wday;
42 + alarm_secs = mktime64(rtc.tm_year + 1900,
43 + rtc.tm_mon + 1,
44 + rtc.tm_mday + wday_offs,
45 + t->time.tm_hour,
46 + t->time.tm_min,
47 + t->time.tm_sec);
48 +
49 + if (wday_offs < 0 || (wday_offs == 0 &&
50 + (t->time.tm_hour < rtc.tm_hour ||
51 + (t->time.tm_hour == rtc.tm_hour &&
52 + t->time.tm_min <= rtc.tm_min))))
53 + alarm_secs += 7 * 86400;
54 +
55 + rtc_time64_to_tm(alarm_secs, &t->time);
56
57 /* ... and status */
58 t->enabled = !!(rs5c->regs[RS5C_REG_CTRL1] & RS5C_CTRL1_AALE);
59 @@ -417,12 +443,20 @@ static int rs5c_set_alarm(struct device
60 struct rs5c372 *rs5c = i2c_get_clientdata(client);
61 int status, addr, i;
62 unsigned char buf[3];
63 + struct rtc_time rtc_tm;
64 + unsigned long rtc_secs, alarm_secs;
65
66 - /* only handle up to 24 hours in the future, like RTC_ALM_SET */
67 - if (t->time.tm_mday != -1
68 - || t->time.tm_mon != -1
69 - || t->time.tm_year != -1)
70 + /* chip only can handle alarms up to one week in the future*/
71 + status = rs5c372_rtc_read_time(dev, &rtc_tm);
72 + if (status)
73 + return status;
74 + rtc_secs = rtc_tm_to_time64(&rtc_tm);
75 + alarm_secs = rtc_tm_to_time64(&t->time);
76 + if (alarm_secs >= rtc_secs + 7 * 86400) {
77 + dev_err(dev, "%s: alarm maximum is one week in the future (%d)\n",
78 + __func__, status);
79 return -EINVAL;
80 + }
81
82 /* REVISIT: round up tm_sec */
83
84 @@ -443,7 +477,9 @@ static int rs5c_set_alarm(struct device
85 /* set alarm */
86 buf[0] = bin2bcd(t->time.tm_min);
87 buf[1] = rs5c_hr2reg(rs5c, t->time.tm_hour);
88 - buf[2] = 0x7f; /* any/all days */
89 + /* each bit is the day of the week, 0x7f means all days */
90 + buf[2] = (t->time.tm_wday >= 0 && t->time.tm_wday < 7) ?
91 + BIT(t->time.tm_wday) : 0x7f;
92
93 for (i = 0; i < sizeof(buf); i++) {
94 addr = RS5C_ADDR(RS5C_REG_ALARM_A_MIN + i);