Preface
Recently, I got myself a Sensirion SCD30 NDIR CO2 sensor, for which Raspberry Pi OS (Debian) does not build the driver. In order to avoid having to compile the entire kernel from source, I did the following:
Getting the kernel
The linux-source-6.18 package provides a tarball of the current kernel sources.
Alternatively, you can use apt source to fetch the kernel source.
Either way, you need to copy the driver’s source from the archive into a new directory,
with the tarball and for the SCD30 driver in particular, you may do this with:
tar xf /usr/src/linux-source-*.tar.xz --wildcards '*/drivers/iio/chemical/scd30*' --strip-components 4
Building the kernel Module out-of-tree
In /lib/modules/<kernelversion>/build, there’s a Makefile for this, to which you can just specify
the obj-m variable. To make this more convenient than a shell invocation, you may
place this additional Makefile in you driver directory.
obj-m += scd30_core.o scd30_i2c.o
KDIR ?= /lib/modules/$(shell uname -r)/build
all:
$(MAKE) -C $(KDIR) M=$(CURDIR) modules
install:
$(MAKE) -C $(KDIR) M=$(CURDIR) modules_install
clean:
$(MAKE) -C $(KDIR) M=$(CURDIR) clean
Then build and install with:
make
sudo make install
sudo depmod -a
make clean
Why not dkms?
It would introduce a dependency between the driver’s version and the source archive, and I wouldn’t want to fetch the entire source tree every kernel update. I am happy with only updating the driver once it either no longer compiles, or a bug I care about in it gets fixed.
SCD30 Device Tree
Now that the driver is installed, I want to automatically load it when the pi starts up. For this, a device-tree fragment is needed:
/dts-v1/;
/plugin/;
/ {
compatible = "brcm,bcm2835";
fragment@0 {
target = <&i2c1>;
__overlay__ {
status = "okay";
scd30: scd30@61 {
compatible = "sensirion,scd30";
reg = <0x61>;
};
};
};
};
It can be built and installed like this:
dtc -@ -I dts -O dtb -o scd30-i2c1.dtbo scd30-i2c1.dts
sudo cp scd30-i2c1.dtbo /boot/firmware/overlays/