This commit is contained in:
Pat Nakajima 2026-05-13 20:23:09 +00:00
commit 9aa96cb51d
14 changed files with 476 additions and 0 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
cache/
build/
mnt/

60
audio/asound.conf Normal file
View File

@ -0,0 +1,60 @@
defaults.pcm.rate_converter "samplerate_best"
pcm.!default {
type plug
slave {
pcm "filtered"
rate 48000
}
}
pcm.filtered {
type ladspa
slave.pcm "out"
path "/usr/lib/ladspa"
plugins [
{
label highpass_iir
input {
controls [ 100 1 ]
}
}
{
label hardLimiter
input {
controls [ 0 1 0 ]
}
}
]
}
pcm.out {
type plug
slave {
pcm "hw:CARD=toesaudio,DEV=1"
format S16_LE
}
}
pcm.toes_playback {
type plug
slave {
pcm "out"
rate 48000
}
}
pcm.toes_capture {
type plug
slave {
pcm "hw:CARD=toesaudio,DEV=0"
format S32_LE
rate 48000
channels 2
}
}
ctl.!default {
type hw
card toesaudio
}

13
audio/build-audio.sh Executable file
View File

@ -0,0 +1,13 @@
#! /bin/bash
set -ex
# builds the audio overlay _inside_ the image.
modprobe i2c-dev || true
modprobe snd-soc-simple-card || true
modprobe snd-soc-tlv320aic31xx || true
modprobe snd-soc-ics43432 || true
dtc -@ -I dts -O dtb -o \
"/boot/firmware/overlays/toesaudio.dtbo" \
"/tmp/audio/toesaudio.dts"

83
audio/init-audio Normal file
View File

@ -0,0 +1,83 @@
#!/bin/bash
set -euo pipefail
CARD_ID="toesaudio"
CARD_NAME="toesaudio"
I2C_BUS="${I2C_BUS:-1}"
CODEC_ADDR="${CODEC_ADDR:-0x18}"
MIC_THSEL_LEVEL="${MIC_THSEL_LEVEL:-high}"
DAC=${1:-127}
DRIVER=${2:-0}
ANALOG=${3:-50}
find_card() {
awk -v id="$CARD_ID" -v name="$CARD_NAME" '
index($0, "[" id "]") || index($0, name) { print $1; exit }
' /proc/asound/cards
}
codec_ready() {
i2cget -y -f "$I2C_BUS" "$CODEC_ADDR" 0 >/dev/null 2>&1
}
set_mixer() {
amixer -q -c "$CARD" "$@" >/dev/null 2>&1 || true
}
set_mic_pins() {
if ! command -v pinctrl >/dev/null 2>&1; then
return 0
fi
case "$MIC_THSEL_LEVEL" in
low)
pinctrl set 8 op pn dl >/dev/null 2>&1 || true
;;
*)
pinctrl set 8 op pn dh >/dev/null 2>&1 || true
;;
esac
pinctrl set 13 ip pn >/dev/null 2>&1 || true
}
CARD=""
for _ in $(seq 1 20); do
CARD="$(find_card || true)"
if [ -n "$CARD" ]; then
break
fi
sleep 1
done
if [ -z "$CARD" ]; then
echo "toesaudio card not present; skipping restore."
exit 0
fi
for _ in $(seq 1 20); do
if codec_ready; then
break
fi
sleep 1
done
if ! codec_ready; then
echo "TLV320 codec not responding on i2c-${I2C_BUS} addr ${CODEC_ADDR}; skipping restore."
exit 0
fi
set_mic_pins
set_mixer sset 'DAC Left Input' 'Left Data'
set_mixer sset 'DAC Right Input' 'Right Data'
set_mixer sset 'Output Left From Left DAC' on
set_mixer sset 'Output Right From Right DAC' on
set_mixer sset 'Speaker' on
set_mixer sset 'Speaker Driver' "$DRIVER"
set_mixer sset 'Speaker Driver' on
set_mixer sset 'Speaker Analog' "$ANALOG"
set_mixer sset 'DAC' "${DAC},${DAC}"
set_mixer sset 'HP Left' off
set_mixer sset 'HP Right' off
set_mixer sset 'HP Driver' '0,0'
set_mixer sset 'HP Driver' off

11
audio/init-audio.service Normal file
View File

@ -0,0 +1,11 @@
[Unit]
Description=Restore barepi TLV320 speaker routing
After=sound.target
Wants=sound.target
[Service]
Type=oneshot
ExecStart=/usr/local/sbin/init-audio 127 0 50
[Install]
WantedBy=multi-user.target

137
audio/toesaudio.dts Normal file
View File

@ -0,0 +1,137 @@
/dts-v1/;
/plugin/;
/ {
compatible = "brcm,bcm2712";
fragment@0 {
target = <&i2s_clk_producer>;
__overlay__ {
status = "okay";
};
};
fragment@1 {
target-path = "/";
__overlay__ {
tlv320_dvdd: regulator-tlv320-dvdd {
compatible = "regulator-fixed";
regulator-name = "tlv320-dvdd-1v8";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
regulator-always-on;
};
tlv320_iovdd: regulator-tlv320-iovdd {
compatible = "regulator-fixed";
regulator-name = "tlv320-iovdd-3v3";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
regulator-always-on;
};
tlv320_avdd: regulator-tlv320-avdd {
compatible = "regulator-fixed";
regulator-name = "tlv320-avdd-3v3";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
regulator-always-on;
};
tlv320_hpvdd: regulator-tlv320-hpvdd {
compatible = "regulator-fixed";
regulator-name = "tlv320-hpvdd-3v3";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
regulator-always-on;
};
tlv320_spkvdd: regulator-tlv320-spkvdd {
compatible = "regulator-fixed";
regulator-name = "tlv320-spkvdd-5v0";
regulator-min-microvolt = <5000000>;
regulator-max-microvolt = <5000000>;
regulator-always-on;
};
/*
* The T5848 is a control-less I2S microphone from Linux's point
* of view, so use the generic ICS43432 codec DAI as a simple
* capture endpoint and keep the speaker path unchanged.
*/
mic_codec: t5848-codec {
compatible = "invensense,ics43432";
#sound-dai-cells = <0>;
};
};
};
fragment@2 {
target = <&i2c_arm>;
__overlay__ {
#address-cells = <1>;
#size-cells = <0>;
status = "okay";
dac_codec: tlv320dac3100@18 {
compatible = "ti,tlv320dac3100";
reg = <0x18>;
#sound-dai-cells = <0>;
AVDD-supply = <&tlv320_avdd>;
IOVDD-supply = <&tlv320_iovdd>;
DVDD-supply = <&tlv320_dvdd>;
HPVDD-supply = <&tlv320_hpvdd>;
SPLVDD-supply = <&tlv320_spkvdd>;
SPRVDD-supply = <&tlv320_spkvdd>;
reset-gpios = <&gpio 12 1>; /* GPIO_ACTIVE_LOW */
ti,pll-clkin-src = <1>;
status = "okay";
};
};
};
fragment@3 {
target-path = "/";
__overlay__ {
sound {
compatible = "simple-audio-card";
#address-cells = <1>;
#size-cells = <0>;
simple-audio-card,name = "toesaudio";
simple-audio-card,format = "i2s";
status = "okay";
simple-audio-card,dai-link@0 {
reg = <0>;
format = "i2s";
bitclock-master = <&cpu0>;
frame-master = <&cpu0>;
cpu0: cpu {
sound-dai = <&i2s_clk_producer>;
};
codec0: codec {
sound-dai = <&dac_codec>;
system-clock-frequency = <1536000>;
};
};
simple-audio-card,dai-link@1 {
reg = <1>;
format = "i2s";
bitclock-master = <&cpu1>;
frame-master = <&cpu1>;
cpu1: cpu {
sound-dai = <&i2s_clk_producer>;
};
codec1: codec {
sound-dai = <&mic_codec>;
};
};
};
};
};
};

10
build.sh Normal file
View File

@ -0,0 +1,10 @@
#! /bin/bash
set -ex
scripts/check-qemu.sh
scripts/download-base.sh
scripts/setup-mount.sh
scripts/copy-files.sh
scripts/update-configtxt.sh
scripts/build-in-chroot.sh

21
scripts/bootstrap-repo.sh Executable file
View File

@ -0,0 +1,21 @@
#! /bin/bash
set -ex
# bootstrap _this_ repo (toes-image-builder), not the image itself.
# should only have to do this once per host we run this on.
sudo apt-get update
sudo apt-get install -y \
qemu-user-static \
binfmt-support \
qemu-system-arm \
qemu-utils \
kpartx \
parted \
fdisk \
dosfstools \
e2fsprogs \
xz-utils \
rsync \
curl \
ca-certificates

49
scripts/build-in-chroot.sh Executable file
View File

@ -0,0 +1,49 @@
#! /bin/bash
set -ex
# runs _inside_ the image, under qemu arm64.
echo "====> mounting"
sudo chroot mnt/root /bin/bash
echo "====> updating apt"
apt-get update
echo "====> installing apt packages"
apt-get install -y \
ca-certificates \
curl \
jq \
git \
locales \
network-manager \
pkg-config \
libdbus-1-dev \
avahi-daemon \
avahi-utils \
libavahi-client-dev \
bluez \
build-essential \
python3-dev \
python3-pip \
sox \
alsa-utils \
libasound2-plugins \
swh-plugins \
i2c-tools \
device-tree-compiler \
unzip \
"linux-modules-$(uname -r)"
# setup locale
locale-gen en_US.UTF-8
update-locale LANG=en_US.UTF-8 LC_ALL=en_US.UTF-8
echo "====> installing rgbled"
curl -fsSL https://git.nose.space/nakajima/rgbled/releases/download/v0.1.1/install.sh | bash
echo "====> installing bun"
curl -fsSL https://bun.com/install | bash
echo "====> installing baudy"
cd /tmp
git clone https://git.nose.space/nakajima/baudy

21
scripts/check-qemu.sh Executable file
View File

@ -0,0 +1,21 @@
#! /bin/bash
set -ex
# make sure the repo is properly setup by bootstrap-repo.sh
required_binfmt="/proc/sys/fs/binfmt_misc/qemu-aarch64"
if [ ! -e "$required_binfmt" ]; then
echo "missing qemu-aarch64 binfmt registration" >&2
exit 1
fi
if ! grep -q '^enabled$' "$required_binfmt"; then
echo "qemu-aarch64 binfmt is not enabled" >&2
exit 1
fi
if ! grep -q 'flags:.*F' "$required_binfmt"; then
echo "qemu-aarch64 binfmt lacks F flag; this builder expects systemd-binfmt with fixed interpreter" >&2
exit 1
fi

13
scripts/copy-files.sh Executable file
View File

@ -0,0 +1,13 @@
#! /bin/bash
set -ex
# copy files from this repo to _inside_ the image
cp audio/toesaudio.dts mnt/root/tmp/toesaudio.dts
cp audio/asound.conf mnt/root/etc/asound.conf
cp audio/init-audio mnt/root/usr/local/sbin/init-audio
cp audio/init-audio.service mnt/root/etc/systemd/system/init-audio.service
cp audio/build-audio.sh mnt/root/tmp/build-audio.sh
# make sure these are executable
chmod +x mnt/root/usr/local/sbin/init-audio
chmod +x mnt/root/tmp/build-audio.sh

15
scripts/download-base.sh Executable file
View File

@ -0,0 +1,15 @@
#! /bin/bash
set -ex
# downloads the ubuntu base image
if [ -f "cache/ubuntu-24.04.4-preinstalled-server-arm64+raspi.img.xz" ]; then
exit 0
fi
mkdir -p cache
cd cache
curl -LO https://cdimage.ubuntu.com/releases/noble/release/ubuntu-24.04.4-preinstalled-server-arm64+raspi.img.xz
curl -LO https://cdimage.ubuntu.com/releases/noble/release/SHA256SUMS
curl -LO https://cdimage.ubuntu.com/releases/noble/release/SHA256SUMS.gpg
sha256sum -c SHA256SUMS --ignore-missing

18
scripts/setup-mount.sh Executable file
View File

@ -0,0 +1,18 @@
#! /bin/bash
set -ex
# unpacks the base image so we can do our stuff to it
mkdir -p build
xz -dkc cache/ubuntu-24.04.4-preinstalled-server-arm64+raspi.img.xz >build/toes-ubuntu-base.img
loop_device="$(sudo losetup --find --show --partscan build/toes-ubuntu-base.img)"
echo "$loop_device"
lsblk "$loop_device"
mkdir -p mnt/root mnt/boot
sudo mount "${loop_device}p2" mnt/root
sudo mount "${loop_device}p1" mnt/boot

View File

@ -0,0 +1,22 @@
#! /bin/bash
set -ex
# add stuff we want to config.txt
add = <<-END
dtparam=spi=on
# we can adjust these values as needed
dtparam=cooling_fan=on,fan_temp0=62000,fan_temp0_hyst=8000,fan_temp0_speed=80,fan_temp1=70000,fan_temp1_hyst=5000,fan_temp1_speed=100,fan_temp2=76000,fan_temp2_hyst=4000,fan_temp2_speed=170,fan_temp3=80000,fan_temp3_hyst=3000,fan_temp3_speed=250
# enable i2s for audio
dtparam=i2s=on
# use an external antenna instead of the pcb antenna on the CM
dtparam=ant2
# load our audio driver
dtoverlay=toesaudio
# enable gpio12 which we use to reset the audio codec
gpio=12=op,dh
END
sed -i "s/dtparam=spi=on/$add" mnt/boot/config.txt
# we don't need fancy graphics. we don't have a screen.
echo "\ngpu_mem=16" >>mnt/boot/config.txt