I would very much appreciate inclusion of the rv3028 RTC driver module if possible.
The PR that brought it into upstream is here: https://github.com/torvalds/linux/commit/e6e7376cfd7b3f9b63de3a22792f64d9bfb2ab53
It looks like it requires (or requires updates to) 'rtc_add_group' and rtc_nvram_register
along with some constants not defined in rtc.h
for 4.14.y so I'm not sure how straight forward this is?
Thank you.
Is 4.14 a requirement for you? 4.19 is our current master branch.
Not at all! In my case it happened to be the kernel available via apt and I was attempting to build the module out-of-tree for testing.
Can you build and test https://github.com/raspberrypi/linux/pull/2913?
Thank you- on it.
Built and testing against 4.19.30
using (as root):
modprobe rtc-rv3028
echo rv3028 0x52 > /sys/class/i2c-adapter/i2c-1/new_device
hwclock --systohc
hwclock --show
I believe the following dtoverlay is required for battery backup functionality to be enabled:
/dts-v1/;
/plugin/;
/ {
compatible = "brcm,bcm2708";
fragment@0 {
target = <&i2c_arm>;
__overlay__ {
#address-cells = <1>;
#size-cells = <0>;
status = "okay";
rv3028@52 {
compatible = "microcrystal,rv3028";
reg = <0x52>;
trickle-resistor-ohms = <11000>;
status = "okay";
};
};
};
};
Could this please be merged into https://github.com/raspberrypi/linux/blob/e2d2941326922b63d722ebc46520c3a2287b675f/arch/arm/boot/dts/overlays/i2c-rtc-overlay.dts ?
I believe the existing address, and trickle-resistor-ohms parameters would apply.
Thank you for cranking this out so quickly, much appreciated!
Could this please be merged into https://github.com/raspberrypi/linux/blob/e2d2941326922b63d722ebc46520c3a2287b675f/arch/arm/boot/dts/overlays/i2c-rtc-overlay.dts ?
Already done. 8-)
I believe the existing address, and trickle-resistor-ohms parameters would apply.
Not the address - that's fixed - but I could add the trickle-resistor.
Now updated with trickle-resistor support - use the trickle-resistor-ohms
parameter.
Actually I'm wrong regarding backup battery functionality. Looking at the datasheet for details on register 0x37
suggests it requires BSM
(Backup Switchover Mode) to be changed, but this driver currently does not support that at all. I'll have to add a backup-switchover-mode
property to make this settable.
Brilliant! Thank you.
This patch adds suggested functionality for backup-switchover-mode
.
Without this parameter supplied, the RTC is never told to use its backup battery and thus loses the time on power off.
Possible options are:
I'll also ping it over to the module author:
diff --git a/drivers/rtc/rtc-rv3028.c b/drivers/rtc/rtc-rv3028.c
index d04c2d481..d674a8257 100644
--- a/drivers/rtc/rtc-rv3028.c
+++ b/drivers/rtc/rtc-rv3028.c
@@ -74,6 +74,7 @@
#define RV3028_BACKUP_TCE BIT(5)
#define RV3028_BACKUP_TCR_MASK GENMASK(1,0)
+#define RV3028_BACKUP_BSM_MASK 0b00001100
#define OFFSET_STEP_PPT 953674
@@ -601,6 +602,7 @@ static int rv3028_probe(struct i2c_client *client)
struct rv3028_data *rv3028;
int ret, status;
u32 ohms;
+ u8 bsm;
struct nvmem_config nvmem_cfg = {
.name = "rv3028_nvram",
.word_size = 1,
@@ -671,6 +673,17 @@ static int rv3028_probe(struct i2c_client *client)
if (ret)
return ret;
+ /* setup backup switchover mode */
+ if (!device_property_read_u8(&client->dev, "backup-switchover-mode",
+ &bsm)) {
+ ret = regmap_update_bits(rv3028->regmap, RV3028_BACKUP,
+ RV3028_BACKUP_BSM_MASK,
+ (bsm & 0b11) << 2);
+
+ if (ret)
+ return ret;
+ }
+
/* setup trickle charger */
if (!device_property_read_u32(&client->dev, "trickle-resistor-ohms",
&ohms)) {
Can you submit this as a PR, ideally with the required overlay parameter?
If you're happy with the rest of the functionality I'll merge it now.
No problem, will get a PR under way once it's merged.
And, yes, everything else seems to work as expected.
Thanks again!
Have at it!
@Gadgetoid This appears to have been fixed - can the issue be closed?
I'm think I'm having trouble with the backup-switchover-mode
parameter.
On my RPi4, I've set in my /boot/config.txt
dtoverlay=i2c-rtc,rv3028,backup-switchover-mode=1
I can successfully hwclock -w
and then hwclock -r
, but on reboot (with battery backup) I always get
pi@raspberrypi:~ $ dmesg | grep rv3028
[ 22.951325] rtc-rv3028 1-0052: Voltage low, data loss detected.
[ 22.974359] rtc-rv3028 1-0052: Voltage low, data is invalid.
[ 22.975039] rtc-rv3028 1-0052: registered as rtc0
with no data retained. I've also tried setting the parameter to other values with no luck. Also tried invalid value (4) but don't see a "invalid backup switchover mode value" in my dmesg. Am I using the overlay wrong? Any tip appreciated!
Have you run hwclock --systohc
? My understanding is that this is needed to reset the internal state.
Thanks @pelwell , in the hwclock man page -w
is equivalent to -systohc
so I think I've covered it
Here's a more detailed dump:
pi@raspberrypi:~ $ uname -a
Linux raspberrypi 4.19.58-v7l+ #1245 SMP Fri Jul 12 17:31:45 BST 2019 armv7l GNU/Linux
pi@raspberrypi:~ $ tail -n 1 /boot/config.txt
dtoverlay=i2c-rtc,rv3028,backup-switchover-mode=1
pi@raspberrypi:~ $ sudo hwclock -r
hwclock: ioctl(RTC_RD_TIME) to /dev/rtc0 to read the time failed: Invalid argument
pi@raspberrypi:~ $ dmesg | grep rtc
[ 5.490099] rtc-rv3028 1-0052: Voltage low, data loss detected.
[ 5.499733] rtc-rv3028 1-0052: Voltage low, data is invalid.
[ 5.500603] rtc-rv3028 1-0052: registered as rtc0
[ 5.682168] rtc-rv3028 1-0052: Voltage low, data is invalid.
[ 5.683034] rtc-rv3028 1-0052: Voltage low, data is invalid.
[ 5.683915] rtc-rv3028 1-0052: Voltage low, data is invalid.
[ 27.867501] rtc-rv3028 1-0052: Voltage low, data is invalid.
[ 27.868361] rtc-rv3028 1-0052: Voltage low, data is invalid.
[ 27.869222] rtc-rv3028 1-0052: Voltage low, data is invalid.
pi@raspberrypi:~ $ sudo hwclock -w
pi@raspberrypi:~ $ sudo hwclock -r
2020-01-02 16:50:06.026608-08:00
pi@raspberrypi:~ $ sudo i2cdetect -y 1
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- UU -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
pi@raspberrypi:~ $ sudo rmmod rtc_rv3028
pi@raspberrypi:~ $ sudo i2cdump -y 1 0x52
No size specified (using byte-data access)
0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
00: 26 51 00 00 03 01 20 80 80 80 00 00 00 00 10 20 &Q..?? ???....?
10: 84 00 00 00 00 00 00 00 00 00 00 9c 00 00 00 00 ?..........?....
20: 00 00 00 00 00 00 4f 00 33 00 00 24 62 0c 13 15 ......O.3..$b???
30: 00 00 00 00 00 c0 ff 90 99 19 00 00 00 00 00 00 .....?.???......
40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Am communicating with a rep from microcrystal and they pointed out from this register dump that neither the time setting or the switchover config is reflected here
Address 0x37 = 0x90 => switchover is not configured Address 0x02 = 0x00 => RTC hour is not equal to 16 (time set 2020-01-02 16:50:06) Address 0x04 = 0x03 => RTC day is not equal to 02(time set 2020-01-02 16:50:06)
If I were you I'd try the --systohc
variant anyway, But I think you're on the right lines in looking for a failure to write the data.
See no difference with the --systohc
variant.
I was able to unload the driver, set the switchover register with i2cset -y 1 0x52 0x37 1
, and see it reflected in the register dump. But moot point since is seems like the time itself isn't being written and reflected in the register dump
this is all with an RV-3028-C7 eval board
so the correct setting was actually ic2set -y 1 0x52 0x37 0x06
, and doing that the battery switchover works. Can use i2cset as workaround. Not sure what part of backup-switchover-mode is not working
This is what I get for my working RV3028, setup with dtoverlay=i2c-rtc,rv3028. It was sitting unpowered for a couple of days. I can't say that i know what it means, but I'll post it anyway.
pi@raspberrypi:~ $ sudo rmmod rtc_rv3028
pi@raspberrypi:~ $ sudo i2cdump -y 1 0x52
No size specified (using byte-data access)
…….0...1....2...3....4....5....6....7....8....9...a....b....c...d....e...f 0123456789abcdef
00: 03 30 13 04 04 02 20 80 80 80 00 00 00 00 30 20 ?0???? ???....0
10: 84 00 00 00 00 00 00 00 00 00 00 31 2a 09 00 00 ?..........1*?..
20: 00 00 00 00 00 00 73 00 33 00 00 14 62 0e 16 17 ......s.3..?b???
30: 00 00 00 00 00 c0 ff 9c a9 19 00 00 00 00 00 00 .....?.???......
40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
pi@raspberrypi:~ $
I struck out trying to get a battery for my other board. All I could find were packs of 10 or more, no singles. I have another RV3028 on its way here and may just wait till it shows up. Then try its battery in my dud breakout. I don't really want to mess with taking the battery out of my one working setup.
Is there a solution for this problem yet? I have the same issue.
I did the following and have mine working.
I installed the pimoroni software and ran the set-time.py file. This sets the battery backup as on.
I then enabled i2c via raspberry Pi Configuration
Then opened a terminal window and ran
sudo i2cdetect -y 1
The RV3028 shows up as 52
I then edited the config.txt
sudo nano /boot/config.txt
and added
dtoverlay=i2c-rtc,rv3028
ctrl x, y, enter
sudo reboot
Then open the terminal window and ran
sudo i2cdetect -y 1
The 52 is now UU which means its under system control
Next I disable the “fake hwclock” which interferes with the ‘real’ hwclock
sudo apt-get -y remove fake-hwclock
sudo update-rc.d -f fake-hwclock remove
sudo systemctl disable fake-hwclock
Now with the fake-hw clock off, you can start the original ‘hardware clock’ script.
sudo nano /lib/udev/hwclock-set
and comment out these lines:
/sbin/hwclock --rtc=$dev --systz --badyear
/sbin/hwclock --rtc=$dev --systz
ctrl x, y, enter
Sync time from Pi to RTC
sudo hwclock -w
sudo hwclock -r
sudo reboot
A side effect of doing all this is now set-time.py and get-time.py no longer work, they error out.
If you remark out the dtoverlay=i2c-rtc,rv3028 entry in config.txt and reboot, they will then work though.
A workaround is to set the backup switchover register (see application manual) to desired value manually
e.g. ic2set -f -y 1 0x52 0x37 0x04
However, with dtoverlay=i2c-rtc,rv3028
I kept checking with i2cdump periodically (on a raspberry pi doing nothing) and found eventually (e.g. 12h) the register resets to disable switchover mode. So you would need to keep doing ic2set periodically.
I also tried with dtoverlay=i2c-rtc,rv3028,backup-switchover-mode=1
, but I found at sometimes on reboot the register value was not persisting, so would have to be re-set with ic2set.
I may either
a) not use any dtoverlay
, and likely just interact with the RTC via https://github.com/pimoroni/rv3028-python
b) use dtoverlay=i2c-rtc,rv3028
, but surround any interaction with the hwclock with modprobe/rmmod/i2cset to ensure the driver is only active when I want it to be, and make sure the switchover mode is set correctly when I'm done
So far with the driver unloaded the backup switchover register persists consistently
@Gadgetoid You have some experience with this device and the driver - do you understand why the switchover mode is being disabled?
in this other thread (https://github.com/pimoroni/rv3028-python/issues/9) I suggest it could be related to eeprom writing
I wonder if it's the driver, or a nuance of the RTC. p.39 of the application manual (3.15.6 EEPROM BACKUP REGISTER), Symbol BSM states "To read/write from/to the EEPROM, the user has to disable the Backup Switchover function by setting the BSM field to 00 or 10 (see routine in EEPROM READ/WRITE CONDITIONS)". So I wonder if the driver does some EEPROM write which ends up resetting BSM to off.
response from @Gadgetoid
So I wonder if the driver does some EEPROM write which ends up resetting BSM to off.
I can't see any evidence of this happening in the rv3028 driver, but it does include functions for reading/writing the EEPROM.
Interestingly this would suggest a bug in
rv3028_eeprom_write
since it does not appear to reset backup-switchover-mode.Backup Switchover Mode is enabled - depending on the config property - here:
Reading the driver, the BSM bits appear to be handled correctly - the register that contains them (RV3028_BACKUP) is only written using regmap_update_bits with suitable masks, so the BSM state appears not to be accidentally dropped. If there is a bug in the driver, it's not obvious.
Thanks for all the replies. I am seeing the same with i2cdump that the switchover mode is occasionally being reset to 10. I'll look through the driver.
You might be able to use the kernel's trace mechanism to monitor the I2C traffic. There's a brief example here: https://riptutorial.com/linux-kernel/example/11983/tracing-i2c-events
cool, I've enabled tracing and will report back any findings :)
Woohoo, I managed to catch it in action with trace. Here's the trace output between my i2cdump calls where it showed the register change. According to the i2cdumps, the register 0x37 changed from 0x04 to 0x90.
This is suspiciously around when the clock goes from 23rd to 00th hour.
kworker/0:2-6579 [000] .... 18117.852162: i2c_write: i2c-1 #0 a=052 f=0000 l=8 [00-54-58-23-02-10-02-20]
kworker/0:2-6579 [000] .... 18117.853874: i2c_result: i2c-1 n=1 ret=1
kworker/0:2-6579 [000] .... 18117.853882: i2c_write: i2c-1 #0 a=052 f=0000 l=1 [0e]
kworker/0:2-6579 [000] .... 18117.853885: i2c_read: i2c-1 #1 a=052 f=0001 l=1
kworker/0:2-6579 [000] .... 18117.854727: i2c_reply: i2c-1 #1 a=052 f=0001 l=1 [10]
kworker/0:2-6579 [000] .... 18117.854728: i2c_result: i2c-1 n=2 ret=2
kworker/0:2-6579 [000] .... 18117.854742: i2c_write: i2c-1 #0 a=052 f=0000 l=1 [0e]
kworker/0:2-6579 [000] .... 18117.854743: i2c_read: i2c-1 #1 a=052 f=0001 l=1
kworker/0:2-6579 [000] .... 18117.855584: i2c_reply: i2c-1 #1 a=052 f=0001 l=1 [10]
kworker/0:2-6579 [000] .... 18117.855586: i2c_result: i2c-1 n=2 ret=2
kworker/0:2-6579 [000] .... 18117.855592: i2c_write: i2c-1 #0 a=052 f=0000 l=1 [00]
kworker/0:2-6579 [000] .... 18117.855593: i2c_read: i2c-1 #1 a=052 f=0001 l=7
kworker/0:2-6579 [000] .... 18117.857516: i2c_reply: i2c-1 #1 a=052 f=0001 l=7 [54-58-23-02-10-02-20]
kworker/0:2-6579 [000] .... 18117.857518: i2c_result: i2c-1 n=2 ret=2
kworker/0:1-6717 [000] .... 18814.908913: i2c_write: i2c-1 #0 a=052 f=0000 l=8 [00-31-10-00-04-11-02-20]
kworker/0:1-6717 [000] .... 18814.910620: i2c_result: i2c-1 n=1 ret=1
kworker/0:1-6717 [000] .... 18814.910631: i2c_write: i2c-1 #0 a=052 f=0000 l=1 [0e]
kworker/0:1-6717 [000] .... 18814.910634: i2c_read: i2c-1 #1 a=052 f=0001 l=1
kworker/0:1-6717 [000] .... 18814.911477: i2c_reply: i2c-1 #1 a=052 f=0001 l=1 [10]
kworker/0:1-6717 [000] .... 18814.911479: i2c_result: i2c-1 n=2 ret=2
kworker/0:1-6717 [000] .... 18814.911492: i2c_write: i2c-1 #0 a=052 f=0000 l=1 [0e]
kworker/0:1-6717 [000] .... 18814.911493: i2c_read: i2c-1 #1 a=052 f=0001 l=1
kworker/0:1-6717 [000] .... 18814.912334: i2c_reply: i2c-1 #1 a=052 f=0001 l=1 [10]
kworker/0:1-6717 [000] .... 18814.912336: i2c_result: i2c-1 n=2 ret=2
kworker/0:1-6717 [000] .... 18814.912342: i2c_write: i2c-1 #0 a=052 f=0000 l=1 [00]
kworker/0:1-6717 [000] .... 18814.912343: i2c_read: i2c-1 #1 a=052 f=0001 l=7
kworker/0:1-6717 [000] .... 18814.914271: i2c_reply: i2c-1 #1 a=052 f=0001 l=7 [31-10-00-04-11-02-20]
kworker/0:1-6717 [000] .... 18814.914273: i2c_result: i2c-1 n=2 ret=2
kworker/0:0-6748 [000] .... 19510.893096: i2c_write: i2c-1 #0 a=052 f=0000 l=8 [00-07-22-00-04-11-02-20]
kworker/0:0-6748 [000] .... 19510.894802: i2c_result: i2c-1 n=1 ret=1
kworker/0:0-6748 [000] .... 19510.894813: i2c_write: i2c-1 #0 a=052 f=0000 l=1 [0e]
kworker/0:0-6748 [000] .... 19510.894815: i2c_read: i2c-1 #1 a=052 f=0001 l=1
kworker/0:0-6748 [000] .... 19510.895657: i2c_reply: i2c-1 #1 a=052 f=0001 l=1 [10]
kworker/0:0-6748 [000] .... 19510.895659: i2c_result: i2c-1 n=2 ret=2
kworker/0:0-6748 [000] .... 19510.895672: i2c_write: i2c-1 #0 a=052 f=0000 l=1 [0e]
kworker/0:0-6748 [000] .... 19510.895673: i2c_read: i2c-1 #1 a=052 f=0001 l=1
kworker/0:0-6748 [000] .... 19510.896513: i2c_reply: i2c-1 #1 a=052 f=0001 l=1 [10]
kworker/0:0-6748 [000] .... 19510.896515: i2c_result: i2c-1 n=2 ret=2
kworker/0:0-6748 [000] .... 19510.896520: i2c_write: i2c-1 #0 a=052 f=0000 l=1 [00]
kworker/0:0-6748 [000] .... 19510.896521: i2c_read: i2c-1 #1 a=052 f=0001 l=7
kworker/0:0-6748 [000] .... 19510.898445: i2c_reply: i2c-1 #1 a=052 f=0001 l=7 [07-22-00-04-11-02-20]
kworker/0:0-6748 [000] .... 19510.898446: i2c_result: i2c-1 n=2 ret=2
kworker/0:0-6748 [000] .... 20206.856625: i2c_write: i2c-1 #0 a=052 f=0000 l=8 [00-43-33-00-04-11-02-20]
kworker/0:0-6748 [000] .... 20206.858334: i2c_result: i2c-1 n=1 ret=1
kworker/0:0-6748 [000] .... 20206.858341: i2c_write: i2c-1 #0 a=052 f=0000 l=1 [0e]
kworker/0:0-6748 [000] .... 20206.858343: i2c_read: i2c-1 #1 a=052 f=0001 l=1
kworker/0:0-6748 [000] .... 20206.859185: i2c_reply: i2c-1 #1 a=052 f=0001 l=1 [10]
kworker/0:0-6748 [000] .... 20206.859187: i2c_result: i2c-1 n=2 ret=2
kworker/0:0-6748 [000] .... 20206.859200: i2c_write: i2c-1 #0 a=052 f=0000 l=1 [0e]
kworker/0:0-6748 [000] .... 20206.859202: i2c_read: i2c-1 #1 a=052 f=0001 l=1
kworker/0:0-6748 [000] .... 20206.860043: i2c_reply: i2c-1 #1 a=052 f=0001 l=1 [10]
kworker/0:0-6748 [000] .... 20206.860045: i2c_result: i2c-1 n=2 ret=2
kworker/0:0-6748 [000] .... 20206.860051: i2c_write: i2c-1 #0 a=052 f=0000 l=1 [00]
kworker/0:0-6748 [000] .... 20206.860052: i2c_read: i2c-1 #1 a=052 f=0001 l=7
kworker/0:0-6748 [000] .... 20206.861975: i2c_reply: i2c-1 #1 a=052 f=0001 l=7 [43-33-00-04-11-02-20]
kworker/0:0-6748 [000] .... 20206.861977: i2c_result: i2c-1 n=2 ret=2
kworker/0:0-6748 [000] .... 20904.950027: i2c_write: i2c-1 #0 a=052 f=0000 l=8 [00-21-45-00-04-11-02-20]
kworker/0:0-6748 [000] .... 20904.951734: i2c_result: i2c-1 n=1 ret=1
kworker/0:0-6748 [000] .... 20904.951742: i2c_write: i2c-1 #0 a=052 f=0000 l=1 [0e]
kworker/0:0-6748 [000] .... 20904.951744: i2c_read: i2c-1 #1 a=052 f=0001 l=1
kworker/0:0-6748 [000] .... 20904.952587: i2c_reply: i2c-1 #1 a=052 f=0001 l=1 [10]
kworker/0:0-6748 [000] .... 20904.952589: i2c_result: i2c-1 n=2 ret=2
kworker/0:0-6748 [000] .... 20904.952601: i2c_write: i2c-1 #0 a=052 f=0000 l=1 [0e]
kworker/0:0-6748 [000] .... 20904.952602: i2c_read: i2c-1 #1 a=052 f=0001 l=1
kworker/0:0-6748 [000] .... 20904.953443: i2c_reply: i2c-1 #1 a=052 f=0001 l=1 [10]
kworker/0:0-6748 [000] .... 20904.953445: i2c_result: i2c-1 n=2 ret=2
kworker/0:0-6748 [000] .... 20904.953451: i2c_write: i2c-1 #0 a=052 f=0000 l=1 [00]
kworker/0:0-6748 [000] .... 20904.953453: i2c_read: i2c-1 #1 a=052 f=0001 l=7
kworker/0:0-6748 [000] .... 20904.955383: i2c_reply: i2c-1 #1 a=052 f=0001 l=7 [21-45-00-04-11-02-20]
kworker/0:0-6748 [000] .... 20904.955385: i2c_result: i2c-1 n=2 ret=2
kworker/0:1-6971 [000] .... 21599.933329: i2c_write: i2c-1 #0 a=052 f=0000 l=8 [00-56-56-00-04-11-02-20]
kworker/0:1-6971 [000] .... 21599.935041: i2c_result: i2c-1 n=1 ret=1
kworker/0:1-6971 [000] .... 21599.935049: i2c_write: i2c-1 #0 a=052 f=0000 l=1 [0e]
kworker/0:1-6971 [000] .... 21599.935051: i2c_read: i2c-1 #1 a=052 f=0001 l=1
kworker/0:1-6971 [000] .... 21599.935896: i2c_reply: i2c-1 #1 a=052 f=0001 l=1 [10]
kworker/0:1-6971 [000] .... 21599.935898: i2c_result: i2c-1 n=2 ret=2
kworker/0:1-6971 [000] .... 21599.935913: i2c_write: i2c-1 #0 a=052 f=0000 l=1 [0e]
kworker/0:1-6971 [000] .... 21599.935914: i2c_read: i2c-1 #1 a=052 f=0001 l=1
kworker/0:1-6971 [000] .... 21599.936754: i2c_reply: i2c-1 #1 a=052 f=0001 l=1 [10]
kworker/0:1-6971 [000] .... 21599.936756: i2c_result: i2c-1 n=2 ret=2
kworker/0:1-6971 [000] .... 21599.936762: i2c_write: i2c-1 #0 a=052 f=0000 l=1 [00]
kworker/0:1-6971 [000] .... 21599.936763: i2c_read: i2c-1 #1 a=052 f=0001 l=7
kworker/0:1-6971 [000] .... 21599.938686: i2c_reply: i2c-1 #1 a=052 f=0001 l=7 [56-56-00-04-11-02-20]
kworker/0:1-6971 [000] .... 21599.938688: i2c_result: i2c-1 n=2 ret=2
That's an interesting tracing for two reasons:
Just got this back from MicroCrystal. Haven't had a chance to look into it yet, but might expalin what is being seen near midnight:
Anyway, the “automatic backup switchover” is disabled by default and must be set in the “Configuration EEPROM” (address 0x37), not only in the “RAM mirror”!
Indeed, the switchover function uses the RAM Mirror settings which are updated by the EEPROM once a day at around midnight or after a power fail.
Please have a look at the attached application manual chapter 4.2 for Backup Switchover function and chapter 4.6 for EEPROM read/write.
Please note that the Linux (kernel) driver developed by Micro Crystal does not implement the switchover control.
You must unload the rtc_rv-3028 module ($ sudo rmmod rtc_rv3028) and set the field BSM = 01 or 11 “manually” with the i2C get/set (Linux I2c-tools) commands
If you come up with a patch then I'd be happy to host it here for testing until it is upstreamed.
- It doesn't show access to any other registers, so i2cdump appears to be bypassing the tracing (unless the period covered by the trace didn't cover a time when i2cdump was used).
Note: I only pasted the trace output between the i2cdump calls where I saw the change (not including the trace output from i2cdump)
App Manual interesting bits:
All Configuration EEPROM at addresses 2Bh and 30h to 37h are memorized in the EEPROM and mirrored in the RAM. Functions become active as soon as the RAM mirror bytes are written.
Configuration EEPROM registers or to read or write from/to a single EEPROM Memory byte.
Before using this commands, the automatic refresh function has to be disabled (EERD = 1) and the busy status bit EEbusy has to indicate, that the last transfer has been finished (EEbusy = 0). Before entering the command 11h, 12h, 21h or 22h, EECMD has to be written with 00h
includes commands for UPDATE (all ram -> eeprom), REFRESH (all eeprom -> ram), as well as individual bytes
4.6.2 Automatic refresh (all eeprom -> ram)
To keep the integrity of the configuration data, all data of the Configuration RAM are refreshed by the data in the Configuration EEPROM each 24 hours, at date increment (at the beginning of the last second before midnight).
4.6.3 Update (all ram -> eeprom)
Before starting to change the configuration stored in the EEPROM, the auto refresh of the registers from the EEPROM has to be disabled by writing 1 into the EERD control bit.
Backup Switchover Mode
To read/write from/to the EEPROM, the user has to disable the Backup Switchover function by setting the BSM field to 00 or 10 (see routine in EEPROM READ/WRITE CONDITIONS)
If I interpret this correct, by design, to write to the EEPROM you must disable backup switchover. The BSM value in EEPROM can only be "off". Any refresh of eeprom -> ram will effectively turn off BSM overwriting whatever the setting is to "off". Currently (default?) automatic refresh is enabled, so once a day at midnight, the BSM value stored in in the ram mirror is reset to "off".
Sounds like auto refresh needs disabled, since this is counterintuitive (if you want BSM enabled, you don't want it to reset once a day).
So still with dtoverlay=i2c-rtc,rv3028
without the backup-switchover-mode
parameter, I am reproducing the loss of BSM:
# enable BSM
sudo i2cset -f -y 1 0x52 0x37 0x04
# confirm register 0x37 is set correctly
sudo i2cdump -f -y 1 0x52
# change date to 1 second before midnight (according to the RTC - this is offset from my local timezone)
sudo date -s "2020-02-11 15:59"
sudo hwclock -w
# confirm register 0x37 is set correctly
sudo i2cdump -f -y 1 0x52
# wait for 00:00
sudo hwclock -r
# now see register 0x37 is no longer set correctly
sudo i2cdump -f -y 1 0x52
Now I can fix this by disabling EERD (0Fh Control 1 register) by writing 1 to bit 3 with sudo i2cset -f -y 0x52 0x0f 0x08
and seeing the value in register 0x37 persist across 23:59 to 00:00
I can confirm this works.
So that is one issue. The other seems to be that the backup-switchover-mode
parameter does not actually seem to work (does not set the register 0x37). In fact I could not get the warning on this line to show up even using invalid values https://github.com/raspberrypi/linux/blob/ab8652c03fa081b27de7e28a74c2536cb2aa3e5b/drivers/rtc/rtc-rv3028.c#L687
Any thoughts?
It's because the overlay treats backup-switchover-mode as a u32, which is sensible, but the driver reads it as a u8. This wouldn't be a problem if device tree stored values in little-endian, but in big endian it ends up reading one of the leading zeroes.
Sorry for the radio silence here, I've been juggling other things- looks like I'd probably broken my own testing efforts by mixing experiments with Python and kernel drivers.
I last touched this stuff a good year or so ago, so it'll take me a while to get up to speed but I think - with the very useful information supplied above (thank you) - I should be able to fix these bugs.
Edit: This patch should- I think- fix the issue ( as elucidated by pelwell) with reading backup-switchover-mode from the config:
diff --git a/drivers/rtc/rtc-rv3028.c b/drivers/rtc/rtc-rv3028.c
index b69d8e6408aa..48b5d1332a7a 100644
--- a/drivers/rtc/rtc-rv3028.c
+++ b/drivers/rtc/rtc-rv3028.c
@@ -602,7 +602,7 @@ static int rv3028_probe(struct i2c_client *client)
struct rv3028_data *rv3028;
int ret, status;
u32 ohms;
- u8 bsm;
+ u32 bsm;
struct nvmem_config nvmem_cfg = {
.name = "rv3028_nvram",
.word_size = 1,
@@ -674,7 +674,7 @@ static int rv3028_probe(struct i2c_client *client)
return ret;
/* setup backup switchover mode */
- if (!device_property_read_u8(&client->dev, "backup-switchover-mode",
+ if (!device_property_read_u32(&client->dev, "backup-switchover-mode",
&bsm)) {
if (bsm <= 3) {
ret = regmap_update_bits(rv3028->regmap, RV3028_BACKUP,
Now from what I can tell regarding EEPROM <-> RAM, there's no hard requirement to completely disable backup-switchover mode in order to write EEPROM values. The EEPROM READ/WRITE CONDITIONS (section 4.6.8) seem to (albeit with all the clarity of a bucket of mud) stipulate that the device doesn't enter VBAT mode during an EEPROM write, and should be powered by Vdd >= 1.5v.
Or- rather - it seems that Vdd can drop below the threshold required to stably write the EEPROM (1.5v), while still operating normally until it completes a switch to VBAT mode. This is noteworthy since the minimum VBACKUP voltage is 1.1v which is lower than this threshold- so a condition could occur where a drop on Vdd is sufficient to cause an unstable EEPROM write, but not sufficient enough to kick in VBAT mode.
I'm not entirely sure why you'd ever want a periodic refresh from EEPROM -> RAM, but then I'm not sure it's entirely safe to disable. That said it would appear to be much simpler (given the idiosyncracies of this kernel driver code) to disable EEPROM -> RAM auto-refresh than issue the sequence of commands and waits required to save the BSM bits into backup EEPROM.
I guess we have two easy choices:
disable-eeprom-ram-refresh
) that explicitly disables this feature and require itAnd one... difficult one:
Choice 3 requires a sequence similar to that detailed in (MIT licensed) code here: https://lang-ship.com/reference/Arduino/libraries/RTC_RV-3028-C7_Arduino_Library/class_r_v3028.html#a9cbc9a009d4e5dbfeb29e366140be42b
All of these options have drawbacks.
disable-eeprom-ram-refresh
is there for, and makes the BSM mode setting weirdly interdependent upon itAnyway, I don't want to work in a vacuum here, I'm extremely new to kernel module development, so I patiently await your feedback! Thanks all.
I'd imagine if anyone is using the EEPROM or features other than basic timekeeping they are writing their own custom code to talk over i2c and set various registers.
I'd vote for # 1 and include a note in the overlay doc that autorefresh is implicitly disabled
If it helps anyone, my hwclock-start.service currently calls this script on every boot:
#!/bin/bash
# disable auto refresh
i2cset -f -y 1 0x52 0x0F 0x08
# enable BSM
i2cset -f -y 1 0x52 0x37 0x04
# sync time (fails on first install until hwclock -w)
# if this fails, set date to 2000
/sbin/hwclock --hctosys --utc || { date -s "2000-01-01 00:00"; hwclock -w; }
I asked Micro Crystal about the backup, and their application engineer said that the EEPROM->RAM refresh allows automatic self-recovery of configurations in the event of total power loss, since a refresh occurs at power-on. The datasheet also says the automatic refresh is "to keep the integrity of the configuration data", which makes sense since capacitor-based RAM slowly leaks charge and needs to be occasionally rewritten to keep its data.
So the RAM->EEPROM update shouldn't actually be needed, as long as the Pi writes the configuration RAM at the appropriate times (on power on and once every 24 hours.)
As for the options you mentioned:
enable-eeprom-ram-refresh
or two different values for backup-switchover-mode
? As long as the kernel driver is refreshing the RAM itself, the EEPROM->RAM refresh would be an "advanced feature" only needed by users who are directly setting their own configurations.@amahoneyLIT: As a newbie to writing such custom code, is it safe to use i2cset -f
like that without disabling the driver first? I'm currently using it to set the alarm on the RV3028, and if I could do that without rmmod and modprobe that would be preferable.
@TrevorMuraro I was doing the rmmod/modprobe dance before, but haven't had any trouble using "-f" yet. Maybe I'll add it back to my script; I was also tired of typing those commands. Probably safer to use rmmod/modprobe though, especially if you don't have to type it out.
Because I'm feeling completionistic, I wrote a script that sets the BSM in EEPROM too:
#!/bin/bash
# Thanks to https://lang-ship.com/reference/Arduino/libraries/RTC_RV-3028-C7_Arduino_Library/class_r_v3028.html#a9cbc9a009d4e5dbfeb29e366140be42b
# And the folks at https://github.com/raspberrypi/linux/issues/2912
function wait_for_EEBusy_done {
busy=$((0x80))
while (( busy == 0x80 ))
do
status=$( i2cget -y 1 0x52 0x0E )
busy=$((status & 0x80))
done
}
rmmod rtc_rv3028
wait_for_EEBusy_done
# disable auto refresh
register=$( i2cget -y 1 0x52 0x0F )
writeback=$((register | 0x08))
i2cset -y 1 0x52 0x0F $writeback
# enable BSM in level switching mode
register=$( i2cget -y 1 0x52 0x37 )
writeback=$((register | 0x0C))
i2cset -y 1 0x52 0x37 $writeback
# update EEPROM
i2cset -y 1 0x52 0x27 0x00
i2cset -y 1 0x52 0x27 0x11
wait_for_EEBusy_done
# reenable auto refresh
register=$( i2cget -y 1 0x52 0x0F )
writeback=$((register & ~0x08))
i2cset -y 1 0x52 0x0F $writeback
wait_for_EEBusy_done
modprobe rtc_rv3028
Cut power (with no backup) and plugged it back in, register 0x37 was still set.
Best part? You only need to run it once and it's set forever.
Sorry @Gadgetoid, I didn't see your edit with the patch, because GitHub.
I prefer option 1. Automatically writing the EEPROM sounds dangerous, and I think that anyone using the BSM option is probably clued up enough to be able to find this thread should anything go wrong (which I doubt).
Option 3:
Setting the backup switchover mode (bsm) in RAM is a bit weak, without also disabling the
EEPROM->RAM mirror function. The mirror function is there for a reason, so maybe not the best idea to disable it. A better way to do it is to read the EEPROM bsm, and if it's not set, then set it. For reference, this is an implementation of option 3 mentioned above. Writing eeprom on every boot-up would be a risk of wearing out flash and higher risk of memory-write during power-down. If you just set bsm once when the device tree value changes, that's not too bad.
The code attached below reads the device tree parameter: backup-switchover-mode = <3>; If it doesn't match the eeprom value, we do the eeprom write. The low voltage flag must also be cleared, by writing to the seconds register by setting date/time, and then "hwclock -w".
Perhaps someone can take a look at the attached patch and clean it up for proper submission. I've tested it, and it seems to work as intended. This is a co-authored work between myself and working partner. We don't have the time to clean it up, or figure out formatting the code for a proper release, so please bear with me. I've also realized the documentation should have been updated in the patch to be formally correct.
I notice that your patch duplicates and extends @Gadgetoid's patch, but excludes updating the BACKUP register. Is this intentional?
And do you (or anyone reading) think the TCE and TCR values should also be written to the EEPROM? If so, the EEPROM update for both/either could be moved and made to service both needs.
@pelwell All I did was change @Gadgetoid 's patch to read/write the EEPROM value instead of the RAM value for BSM. The calls to rv3028_eeprom_write and rv3028_eeprom_read appear to take care of the refresh and flags, and since the routines are already there, I figured might as well use them. We don't need to write the RAM BACKUP value anymore. It's taken care of in the rv3028_eeprom_write when the RAM refresh is turned back on. With that in mind, I guess any previously set RAM values would be overwritten in that register. It's fine for now since the trickle charge is setup after the BSM setup.
I suppose this could be extended to support the TCR and TCE in EEPROM, great idea. I'm not using those functions at all, as I'm using external charger.
OK - I'll update my work-in-progress and turn it into a Pull Request for testing.
@pelwell This might need a bit more thinking to get it right for "all" the use cases. It doesn't make sense to extend to TCR and TCE in separate EEPROM writes. The EEPROM backup register should probably only be written once and only if one of the individual values doesn't match.
Maybe a better approach is just a single device-tree value for BACKUP of 0x00 to 0xFF representing the entire register? Trying to keep things simple, but functional for different use cases. Other ideas welcome of course.
I've tried to be a bit smarter than that: https://github.com/raspberrypi/linux/pull/3616
So do we really need to write to eeprom and use auto-refresh?
Per @TrevorMuraro 's response:
I asked Micro Crystal about the backup, and their application engineer said that the EEPROM->RAM refresh allows automatic self-recovery of configurations in the event of total power loss, since a refresh occurs at power-on. The datasheet also says the automatic refresh is "to keep the integrity of the configuration data", which makes sense since capacitor-based RAM slowly leaks charge and needs to be occasionally rewritten to keep its data.
So is the risk that the RTC registers in RAM degrade after some unknown period much greater than 24h if we don't auto-refresh?
backup-switchover-mode parameter does not actually seem to work (does not set the register 0x37). In fact I could not get the warning on this line to show up even using invalid values
dev_warn(&client->dev, "invalid backup switchover mode valuen");
@pelwell is this still an issue?
It's because the overlay treats backup-switchover-mode as a u32, which is sensible, but the driver reads it as a u8. This wouldn't be a problem if device tree stored values in little-endian, but in big endian it ends up reading one of the leading zeroes.
Yes, it is still an issue - I've updated the PR accordingly.
Has anyone managed to try the patch in PR #3616?
Anyone? I'd like to merge the patch in #3616, but not without some confirmation.
Anyone? I'd like to merge the patch in #3616, but not without some confirmation.
I just tried it with the 4.19.93, but modified the patch a tiny bit to still include rtc-core.h. I am using it with dtoverlay=i2c-rtc,rv3028,backup-switchover-mode=1
but I always get the "Voltage low, data loss detected." error on startup. With that said, my custom hardware is not really verified at this point so it could be a HW issue.
Let me know if there is something you'd like me to try out.
I'm limited on time but may be able to test it, depending on how complicated it is to build (which I also don't know how to do). Is there a guide someone can point me to?
Building kernel info:
https://www.raspberrypi.org/documentation/linux/kernel/building.md
assuming that works you can apply the suggested patch with:
curl -L https://github.com/raspberrypi/linux/pull/3616/commits/78c4fadc9398ead67ccf302db555df6d55914dac.patch | git am -3
I got it to work for me now. All I did was add a ram_refresh
function that I called after the eeprom write that you did in #3616. Since the setting has to be in RAM to be active, to my understanding, that step is necessary if you don't want to wait until the next automatic refresh for it to take effect. @pelwell I can create a PR if you want me to.
Yes, a single PR with #3616 and your own patch would be great.
Most helpful comment
Because I'm feeling completionistic, I wrote a script that sets the BSM in EEPROM too:
Cut power (with no backup) and plugged it back in, register 0x37 was still set.
Best part? You only need to run it once and it's set forever.