Skip to content

Instantly share code, notes, and snippets.

@kellertk
Last active March 9, 2024 21:13
Show Gist options
  • Save kellertk/ceeda942f6470b8ba8211a80f024004d to your computer and use it in GitHub Desktop.
Save kellertk/ceeda942f6470b8ba8211a80f024004d to your computer and use it in GitHub Desktop.

The PiSugar2 is a battery board for the Raspberry Pi Zero. It has an integrated RTC chip available over I2C, but there are no drivers included in the kernel with the latest release of the pwnagotchi (or Kali in general). It's a ZXW Shenzhen SD3078; there is surprisingly little information out there about this chip. I suspect it's newish.

The PiSugar folks expect you to install Pisugar Power Manager, which is a web service to get battery status and set the RTC. I prefer to use the standard hwclock utility, because I don't need the extra function in the web interface. There is driver support for this chip in kernels 5.1 or newer, so we can grab that and compile it as an out of tree module. You may be able to adapt these instructions for your use.

Normally to do this you'd download the kernel headers, compile and install and be happy. I wasn't able to get the kernel headers for the kernel shipped with pwnagotchi working for me, so instead I did this against the full kernel source tree.

  1. Get the kernel source for whatever version that you're running.
pi@pwnagotchi:~ $ uname -r
4.19.93-Re4son+
pi@pwnagotchi:~ $ wget https://github.com/Re4son/re4son-raspberrypi-linux/archive/rpi-4.19.97-re4son.zip
...snip...
pi@pwnagotchi:~ $ unzip rpi-4.19.79-re4son.zip
  1. Install build dependencies.
pi@pwnagotchi:~ $ sudo apt install bison flex libssl-dev
  1. Prepare kernel for out-of-tree compilation.
pi@pwnagotchi:~ $ cd re4son-raspberrypi-linux-rpi-4.19.79-re4son/
pi@pwnagotchi:~/re4son-raspberrypi-linux-rpi-4.19.79-re4son $ make re4son_pi1_defconfig
...snip...
pi@pwnagotchi:~/re4son-raspberrypi-linux-rpi-4.19.79-re4son $ make modules_prepare
  1. Get the source.
pi@pwnagotchi:~/re4son-raspberrypi-linux-rpi-4.19.79-re4son $ cd ~
pi@pwnagotchi:~ $ mkdir rtc-sd3078
pi@pwnagotchi:~ $ cd rtc-sd3078/
pi@pwnagotchi:~/rtc-sd3078 $ wget https://raw.githubusercontent.com/torvalds/linux/master/drivers/rtc/rtc-sd3078.c
pi@pwnagotchi:~/rtc-sd3078 $ cat <<EOF > Makefile
obj-m+=rtc-sd3078.o

all:
	make -C /home/pi/re4son-raspberrypi-linux-rpi-4.19.97-re4son/ M=$(shell pwd) modules

clean:
	make -C /home/pi/re4son-raspberrypi-linux-rpi-4.19.97-re4son/ M=$(shell pwd) clean

modules_install: all
	$(MAKE) -C $(KERNEL_SRC) M=$(SRC) modules_install
	$(DEPMOD)
EOF
  1. Make the module.
pi@pwnagotchi:~/rtc-sd3078 $ make modules
  1. Smoke test! If you can see time, you're good. Otherwise, check dmesg or whatever. You can also set the RTC with hwclock -w.
pi@pwnagotchi:~/rtc-sd3078 $ sudo insmod rtc_sd3078.ko
pi@pwnagotchi:~/rtc-sd3078 $ sudo echo sd3078 0x32 > /sys/class/i2c-adapter/i2c-1/new_device
pi@pwnagotchi:~/rtc-sd3078 $ sudo hwclock -r
2020-07-01 13:00:44.834030-07:00
  1. Install the module
pi@pwnagotchi:~/rtc-sd3078 $ sudo mkdir /lib/modules/$(uname -r)/extra
pi@pwnagotchi:~/rtc-sd3078 $ sudo cp rtc_sd3078.ko /lib/modules/$(uname -r)/extra/
pi@pwnagotchi:~/rtc-sd3078 $ sudo depmod -a
  1. Now that the module is installed, we have to create a device tree overlay so that the I2C device is enumerated on boot. I'm using the Raspberry PI's default I2C RTC overlay, but edited to include our new driver.
pi@pwnagotchi:~/rtc-sd3078 $ cat <<EOF > i2c-rtc-overlay.dts
// Definitions for several I2C based Real Time Clocks
/dts-v1/;
/plugin/;

/ {
        compatible = "brcm,bcm2835";

        fragment@0 {
                target = <&i2c_arm>;
                __dormant__ {
                        #address-cells = <1>;
                        #size-cells = <0>;
                        status = "okay";

                        abx80x: abx80x@69 {
                                compatible = "abracon,abx80x";
                                reg = <0x69>;
                                abracon,tc-diode = "standard";
                                abracon,tc-resistor = <0>;
                                status = "okay";
                        };
                };
        };

        fragment@1 {
                target = <&i2c_arm>;
                __dormant__ {
                        #address-cells = <1>;
                        #size-cells = <0>;
                        status = "okay";

                        ds1307: ds1307@68 {
                                compatible = "dallas,ds1307";
                                reg = <0x68>;
                                status = "okay";
                        };
                };
        };

        fragment@2 {
                target = <&i2c_arm>;
                __dormant__ {
                        #address-cells = <1>;
                        #size-cells = <0>;
                        status = "okay";

                        ds1339: ds1339@68 {
                                compatible = "dallas,ds1339";
                                trickle-resistor-ohms = <0>;
                                reg = <0x68>;
                                status = "okay";
                        };
                };
        };

        fragment@3 {
                target = <&i2c_arm>;
                __dormant__ {
                        #address-cells = <1>;
                        #size-cells = <0>;
                        status = "okay";

                        ds3231: ds3231@68 {
                                compatible = "maxim,ds3231";
                                reg = <0x68>;
                                status = "okay";
                        };
                };
        };

        fragment@4 {
                target = <&i2c_arm>;
                __dormant__ {
                        #address-cells = <1>;
                        #size-cells = <0>;
                        status = "okay";

                        mcp7940x: mcp7940x@6f {
                                compatible = "microchip,mcp7940x";
                                reg = <0x6f>;
                                status = "okay";
                        };
                };
        };

        fragment@5 {
                target = <&i2c_arm>;
                __dormant__ {
                        #address-cells = <1>;
                        #size-cells = <0>;
                        status = "okay";

                        mcp7941x: mcp7941x@6f {
                                compatible = "microchip,mcp7941x";
                                reg = <0x6f>;
                                status = "okay";
                        };
                };
        };

        fragment@6 {
                target = <&i2c_arm>;
                __dormant__ {
                        #address-cells = <1>;
                        #size-cells = <0>;
                        status = "okay";

                        pcf2127@51 {
                                compatible = "nxp,pcf2127";
                                reg = <0x51>;
                                status = "okay";
                        };
                };
        };

        fragment@7 {
                target = <&i2c_arm>;
                __dormant__ {
                        #address-cells = <1>;
                        #size-cells = <0>;
                        status = "okay";

                        pcf8523: pcf8523@68 {
                                compatible = "nxp,pcf8523";
                                reg = <0x68>;
                                status = "okay";
                        };
                };
        };

        fragment@8 {
                target = <&i2c_arm>;
                __dormant__ {
                        #address-cells = <1>;
                        #size-cells = <0>;
                        status = "okay";

                        pcf8563: pcf8563@51 {
                                compatible = "nxp,pcf8563";
                                reg = <0x51>;
                                status = "okay";
                        };
                };
        };

        fragment@9 {
                target = <&i2c_arm>;
                __dormant__ {
                        #address-cells = <1>;
                        #size-cells = <0>;
                        status = "okay";

                        m41t62: m41t62@68 {
                                compatible = "st,m41t62";
                                reg = <0x68>;
                                status = "okay";
                        };
                };
        };

        fragment@10 {
                target = <&i2c_arm>;
                __dormant__ {
                        #address-cells = <1>;
                        #size-cells = <0>;
                        status = "okay";

                        rv3028: rv3028@52 {
                                compatible = "microcrystal,rv3028";
                                reg = <0x52>;
                                status = "okay";
                        };
                };
        };

        fragment@11 {
                target = <&i2c_arm>;
                __dormant__ {
                        #address-cells = <1>;
                        #size-cells = <0>;
                        status = "okay";

                        pcf2129@51 {
                                compatible = "nxp,pcf2129";
                                reg = <0x51>;
                                status = "okay";
                        };
                };
        };

        fragment@12 {
                target = <&i2c_arm>;
                __dormant__ {
                        #address-cells = <1>;
                        #size-cells = <0>;
                        status = "okay";

                        pcf2129@51 {
                                compatible = "zxw,sd3078";
                                reg = <0x32>;
                                status = "okay";
                        };
                };
        };

        __overrides__ {
                abx80x = <0>,"+0";
                ds1307 = <0>,"+1";
                ds1339 = <0>,"+2";
                ds3231 = <0>,"+3";
                mcp7940x = <0>,"+4";
                mcp7941x = <0>,"+5";
                pcf2127 = <0>,"+6";
                pcf8523 = <0>,"+7";
                pcf8563 = <0>,"+8";
                m41t62 = <0>,"+9";
                rv3028 = <0>,"+10";
                pcf2129 = <0>,"+11";
                sd3078 = <0>,"+12";

                addr = <&abx80x>, "reg:0",
                       <&ds1307>, "reg:0",
                       <&ds1339>, "reg:0",
                       <&ds3231>, "reg:0",
                       <&mcp7940x>, "reg:0",
                       <&mcp7941x>, "reg:0",
                       <&pcf8523>, "reg:0",
                       <&pcf8563>, "reg:0",
                       <&m41t62>, "reg:0";
                trickle-diode-type = <&abx80x>,"abracon,tc-diode";
                trickle-resistor-ohms = <&ds1339>,"trickle-resistor-ohms:0",
                                        <&abx80x>,"abracon,tc-resistor",
                                        <&rv3028>,"trickle-resistor-ohms:0";
                backup-switchover-mode = <&rv3028>,"backup-switchover-mode:0";
                wakeup-source = <&ds1339>,"wakeup-source?",
                                <&ds3231>,"wakeup-source?",
                                <&mcp7940x>,"wakeup-source?",
                                <&mcp7941x>,"wakeup-source?",
                                <&m41t62>,"wakeup-source?";
        };
};
EOF
pi@pwnagotchi:~/rtc-sd3078 $ dtc -@ -I dts -O dtb -o i2c-rtc-modified.dtbo i2c-rtc-overlay.dts
pi@pwnagotchi:~/rtc-sd3078 $ sudo cp i2c-rtc-modfied.dtbo /boot/overlays
pi@pwnagotchi:~/rtc-sd3078 $ sudo echo "dtoverlay=i2c-rtc-modfied,sd3078" >> /boot/config.txt
pi@pwnagotchi:~/rtc-sd3078 $ sudo echo "rtc-sd3078" >> /etc/modules
  1. Reboot, and you should see that the /dev/rtc0 device exists at boot time. Now we need to tell systemd that we want to set the system clock to the time in the RTC early on in the boot process.
pi@pwnagotchi:~ $ sudo su
root@pwnagotchi:/home/pi# cat <<EOF > /etc/systemd/system/hwclock-start.service
[Unit]
Description=read rtc and write to system clock
Before=sysinit.target
After=local-fs.target
DefaultDependencies=no

[Service]
Type=oneshot
ExecStart=/sbin/hwclock --hctosys --utc

[Install]
WantedBy=basic.target
EOF
root@pwnagotchi:/home/pi# systemctl daemon-reload
root@pwnagotchi:/home/pi# systemctl enable hwclock-start
  1. Done! You should reboot, and carefully check that journalctl -b shows that the system clock was set early in the boot process. Example:
Feb 14 02:12:12 pwnagotchi systemd-fsck[171]: /dev/mmcblk0p1: 251 files, 134993/516191 clusters
Feb 14 02:12:12 pwnagotchi systemd[1]: Started File System Check on /dev/disk/by-partuuid/a07ef6e4-01.
Feb 14 02:12:12 pwnagotchi systemd[1]: Mounting /boot...
Feb 14 02:12:12 pwnagotchi systemd[1]: Mounted /boot.
Feb 14 02:12:12 pwnagotchi systemd[1]: Reached target Local File Systems.
Feb 14 02:12:12 pwnagotchi systemd[1]: Starting Set console font and keymap...
Feb 14 02:12:12 pwnagotchi systemd[1]: Starting read rtc and write to system clock...
Feb 14 02:12:12 pwnagotchi systemd[1]: Starting Raise network interfaces...
Feb 14 02:12:12 pwnagotchi systemd[1]: Condition check resulted in Commit a transient machine-id on disk being skipped.
Feb 14 02:12:12 pwnagotchi systemd[1]: Starting Create Volatile Files and Directories...
Feb 14 02:12:12 pwnagotchi systemd[1]: Started ifup for usb0.
Feb 14 02:12:12 pwnagotchi systemd[1]: Started Set console font and keymap.
Jul 01 09:47:37 pwnagotchi systemd[1]: hwclock-start.service: Succeeded.
Jul 01 09:47:37 pwnagotchi systemd[1]: Started read rtc and write to system clock.
Jul 01 09:47:37 pwnagotchi systemd[1]: Found device /dev/spidev0.0.
Jul 01 09:47:37 pwnagotchi systemd[1]: Started Load/Save RF Kill Switch Status.
@nachtschatt3n
Copy link

nachtschatt3n commented Aug 29, 2020

Thanks for the great work! Just some little typos :

  • its not "insmod rtc_sd3078.ko" it is "insmod rtc-sd3078.ko"
  • the rtc-sd3078 Makefile has the kernel folders they need to be adjusted
  • it's not make modules .. its make all & make modules_install
  • echo "dtoverlay=i2c-rtc-modfied,sd3078" >> /boot/config.txt -> its i2c-rtc-modified

@mkoterski
Copy link

Did you get it working in the end nachschatt3n? I am working on an updated guide and would love to have it documented.

@joel-gfdez
Copy link

Great, I got it working. Thank you very much! I also had to apply the modifications stated by @nachtschatt3n

@nachtschatt3n
Copy link

@mkoterski yes it worked, but now after 2 months, the PiSugar2 bord died ...

@xevilstar
Copy link

I'd like to know if there are any differences if I was to apply this procedure on a raspberrypi 4 with a arm64 linux raspberrypi os on

@xlla
Copy link

xlla commented Sep 29, 2022

I can't compile it for kernel 4.19.118+

  CC [M]  /home/pi/git/rtc-sd3078/rtc-sd3078.o
/home/pi/git/rtc-sd3078/rtc-sd3078.c: In function ‘sd3078_probe’:
/home/pi/git/rtc-sd3078/rtc-sd3078.c:194:8: error: implicit declaration of function ‘devm_rtc_register_device’; did you mean ‘rtc_register_device’? [-Werror=implicit-function-declaration]
  ret = devm_rtc_register_device(sd3078->rtc);
        ^~~~~~~~~~~~~~~~~~~~~~~~
        rtc_register_device
cc1: some warnings being treated as errors
make[2]: *** [scripts/Makefile.build:310: /home/pi/git/rtc-sd3078/rtc-sd3078.o] Error 1
make[1]: *** [Makefile:1522: _module_/home/pi/git/rtc-sd3078] Error 2

@thegogglesdonothing
Copy link

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment