Skip to content

Commit aeb81bc

Browse files
board/opentrons/ot2: Work around RV-3028 problems via artificial delay
1 parent 43d8ac9 commit aeb81bc

File tree

1 file changed

+65
-0
lines changed

1 file changed

+65
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
From 16292687fd316543bba3d0d0179c2439a85acb6a Mon Sep 17 00:00:00 2001
2+
From: Max Marrone <[email protected]>
3+
Date: Mon, 8 Aug 2022 15:34:12 -0400
4+
Subject: [PATCH] Work around RV-3028 problems via artificial delay
5+
6+
This is an Opentrons workaround for what we suspect is an undocumented
7+
silicon erratum in the RV-3028 RTC. It adds an artificial sleep whenever
8+
something reads the current time from the RTC's registers.
9+
10+
Whenever there is an open I2C transaction, the RV-3028 will hold its
11+
time registers steady, in order to avoid a torn read/write hazard.
12+
If the time registers would have ticked to a new value during that
13+
transaction, the RV-3028 is supposed to postpone that update and
14+
apply it as soon as the transaction ends.
15+
16+
But on some boards, we're seeing the time registers never update at
17+
all whenever they're under rapid polling. `hwclock` does rapid
18+
polling under normal usage, so this causes it to error with
19+
"Timed out waiting for time change".
20+
21+
We theorize that problematic RV-3028 chips need a big block of idle
22+
bus time in order to apply postponed time updates.
23+
24+
See Opentrons Jira RSS-9 for investigation details.
25+
26+
We sleep for 2-4 milliseconds. Shorter sleeps might also work;
27+
we just haven't tested with them.
28+
---
29+
drivers/rtc/rtc-rv3028.c | 6 ++++++
30+
1 file changed, 6 insertions(+)
31+
32+
diff --git a/drivers/rtc/rtc-rv3028.c b/drivers/rtc/rtc-rv3028.c
33+
index a714e5aeefb8..d499a2e5d956 100644
34+
--- a/drivers/rtc/rtc-rv3028.c
35+
+++ b/drivers/rtc/rtc-rv3028.c
36+
@@ -10,6 +10,7 @@
37+
38+
#include <linux/bcd.h>
39+
#include <linux/bitops.h>
40+
+#include <linux/delay.h>
41+
#include <linux/i2c.h>
42+
#include <linux/interrupt.h>
43+
#include <linux/kernel.h>
44+
@@ -79,6 +80,9 @@
45+
46+
#define OFFSET_STEP_PPT 953674
47+
48+
+#define WORKAROUND_SLEEP_MIN_US 2000
49+
+#define WORKAROUND_SLEEP_MAX_US 4000
50+
+
51+
enum rv3028_type {
52+
rv_3028,
53+
};
54+
@@ -227,6 +231,8 @@ static int rv3028_get_time(struct device *dev, struct rtc_time *tm)
55+
return -EINVAL;
56+
}
57+
58+
+ usleep_range(WORKAROUND_SLEEP_MIN_US, WORKAROUND_SLEEP_MAX_US);
59+
+
60+
ret = regmap_bulk_read(rv3028->regmap, RV3028_SEC, date, sizeof(date));
61+
if (ret)
62+
return ret;
63+
--
64+
2.37.1
65+

0 commit comments

Comments
 (0)