Skip to content

Instantly share code, notes, and snippets.

@mkoterski
Forked from kellertk/pisugar2-rtc-pwnagotchi.md
Last active March 12, 2024 19:19
Show Gist options
  • Save mkoterski/26e0885363d77d3547b77fbead102d43 to your computer and use it in GitHub Desktop.
Save mkoterski/26e0885363d77d3547b77fbead102d43 to your computer and use it in GitHub Desktop.

Based on original work on https://gist.github.com/kellertk/ceeda942f6470b8ba8211a80f024004d (Thank you)

WORK IN PROGRESS!

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.118-Re4son+
pi@pwnagotchi:~ $ wget https://github.com/Re4son/re4son-raspberrypi-linux/archive/rpi-4.19.118-re4son.zip
...snip...
pi@pwnagotchi:~ $ unzip rpi-4.19.118-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.118-re4son/
pi@pwnagotchi:~/re4son-raspberrypi-linux-rpi-4.19.118-re4son $ sudo make re4son_pi1_defconfig

  HOSTCC  scripts/basic/fixdep
  HOSTCC  scripts/kconfig/conf.o
  YACC    scripts/kconfig/zconf.tab.c
  LEX     scripts/kconfig/zconf.lex.c
  HOSTCC  scripts/kconfig/zconf.tab.o
  HOSTLD  scripts/kconfig/conf
arch/arm/configs/re4son_pi1_defconfig:89:warning: override: reassigning to symbol CGROUP_BPF
arch/arm/configs/re4son_pi1_defconfig:94:warning: override: reassigning to symbol BPF_SYSCALL
arch/arm/configs/re4son_pi1_defconfig:745:warning: override: reassigning to symbol I2C_TINY_USB
#
# configuration written to .config
#

pi@pwnagotchi:~/re4son-raspberrypi-linux-rpi-4.19.118-re4son $ sudo make modules_prepare

  SYSHDR  arch/arm/include/generated/uapi/asm/unistd-common.h
  SYSHDR  arch/arm/include/generated/uapi/asm/unistd-oabi.h
  SYSHDR  arch/arm/include/generated/uapi/asm/unistd-eabi.h
  UPD     include/config/kernel.release
  WRAP    arch/arm/include/generated/uapi/asm/bitsperlong.h
  WRAP    arch/arm/include/generated/uapi/asm/bpf_perf_event.h
  WRAP    arch/arm/include/generated/uapi/asm/errno.h
  WRAP    arch/arm/include/generated/uapi/asm/ioctl.h
  WRAP    arch/arm/include/generated/uapi/asm/ipcbuf.h
  WRAP    arch/arm/include/generated/uapi/asm/msgbuf.h
  WRAP    arch/arm/include/generated/uapi/asm/param.h
  WRAP    arch/arm/include/generated/uapi/asm/poll.h
  WRAP    arch/arm/include/generated/uapi/asm/resource.h
  WRAP    arch/arm/include/generated/uapi/asm/sembuf.h
  WRAP    arch/arm/include/generated/uapi/asm/shmbuf.h
  WRAP    arch/arm/include/generated/uapi/asm/siginfo.h
  WRAP    arch/arm/include/generated/uapi/asm/socket.h
  WRAP    arch/arm/include/generated/uapi/asm/sockios.h
  WRAP    arch/arm/include/generated/uapi/asm/termbits.h
  WRAP    arch/arm/include/generated/uapi/asm/termios.h
  WRAP    arch/arm/include/generated/asm/compat.h
  WRAP    arch/arm/include/generated/asm/current.h
  WRAP    arch/arm/include/generated/asm/early_ioremap.h
  WRAP    arch/arm/include/generated/asm/emergency-restart.h
  WRAP    arch/arm/include/generated/asm/exec.h
  WRAP    arch/arm/include/generated/asm/extable.h
  WRAP    arch/arm/include/generated/asm/irq_regs.h
  WRAP    arch/arm/include/generated/asm/kdebug.h
  WRAP    arch/arm/include/generated/asm/local.h
  WRAP    arch/arm/include/generated/asm/local64.h
  WRAP    arch/arm/include/generated/asm/mm-arch-hooks.h
  WRAP    arch/arm/include/generated/asm/msi.h
  WRAP    arch/arm/include/generated/asm/parport.h
  WRAP    arch/arm/include/generated/asm/preempt.h
  WRAP    arch/arm/include/generated/asm/rwsem.h
  WRAP    arch/arm/include/generated/asm/seccomp.h
  WRAP    arch/arm/include/generated/asm/segment.h
  WRAP    arch/arm/include/generated/asm/serial.h
  WRAP    arch/arm/include/generated/asm/simd.h
  WRAP    arch/arm/include/generated/asm/sizes.h
  WRAP    arch/arm/include/generated/asm/timex.h
  WRAP    arch/arm/include/generated/asm/trace_clock.h
  UPD     include/generated/uapi/linux/version.h
  UPD     include/generated/utsrelease.h
  SYSNR   arch/arm/include/generated/asm/unistd-nr.h
  GEN     arch/arm/include/generated/asm/mach-types.h
  SYSTBL  arch/arm/include/generated/calls-oabi.S
  SYSTBL  arch/arm/include/generated/calls-eabi.S
  CC      kernel/bounds.s
  UPD     include/generated/bounds.h
  UPD     include/generated/timeconst.h
  CC      arch/arm/kernel/asm-offsets.s
  UPD     include/generated/asm-offsets.h
  CALL    scripts/checksyscalls.sh
  HOSTCC  scripts/dtc/dtc.o
  HOSTCC  scripts/dtc/flattree.o
  HOSTCC  scripts/dtc/fstree.o
  HOSTCC  scripts/dtc/data.o
  HOSTCC  scripts/dtc/livetree.o
  HOSTCC  scripts/dtc/treesource.o
  HOSTCC  scripts/dtc/srcpos.o
  HOSTCC  scripts/dtc/checks.o
  HOSTCC  scripts/dtc/util.o
  LEX     scripts/dtc/dtc-lexer.lex.c
  YACC    scripts/dtc/dtc-parser.tab.h
  HOSTCC  scripts/dtc/dtc-lexer.lex.o
  YACC    scripts/dtc/dtc-parser.tab.c
  HOSTCC  scripts/dtc/dtc-parser.tab.o
  HOSTLD  scripts/dtc/dtc
  HOSTCC  scripts/genksyms/genksyms.o
  YACC    scripts/genksyms/parse.tab.c
  HOSTCC  scripts/genksyms/parse.tab.o
  LEX     scripts/genksyms/lex.lex.c
  YACC    scripts/genksyms/parse.tab.h
  HOSTCC  scripts/genksyms/lex.lex.o
  HOSTLD  scripts/genksyms/genksyms
  CC      scripts/mod/empty.o
  HOSTCC  scripts/mod/mk_elfconfig
  MKELF   scripts/mod/elfconfig.h
  HOSTCC  scripts/mod/modpost.o
  CC      scripts/mod/devicetable-offsets.s
  UPD     scripts/mod/devicetable-offsets.h
  HOSTCC  scripts/mod/file2alias.o
  HOSTCC  scripts/mod/sumversion.o
  HOSTLD  scripts/mod/modpost
  HOSTCC  scripts/bin2c
  HOSTCC  scripts/kallsyms
  HOSTCC  scripts/pnmtologo
  HOSTCC  scripts/conmakehash
  HOSTCC  scripts/recordmcount
  HOSTCC  scripts/sortextable
  HOSTCC  scripts/asn1_compiler
  HOSTCC  scripts/extract-cert
  1. Get the source.
pi@pwnagotchi:~/re4son-raspberrypi-linux-rpi-4.19.118-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/pi2rtc/re4son-raspberrypi-linux-rpi-4.19.118-re4son/ M=$$(shell pwd) modules

clean:
make -C /home/pi/pi2rtc/re4son-raspberrypi-linux-rpi-4.19.118-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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment