Skip to content

Add Support for a New Device

libretouch currently ships full support for one board, spotty_sm2 (SoundTouch 20 Series III), and work in progress on a second, lisa_scm. All other SoundTouch models use the same AM335x platform and one of two processor modules, so bringing up a new one is mostly a matter of describing its hardware, not of writing drivers.

Check the hardware overview first — a product without an entry of its own is not necessarily an unsupported board.

This guide covers basic support only: getting an unsupported board to boot a libretouch kernel and reach a shell on the serial console. Audio, display, keypad, IR and wireless come afterwards and are not covered here.

Basic support is reached when all of the following hold:

  • U-Boot loads and starts the kernel,
  • kernel messages appear on the serial console,
  • the reported memory size matches the board,
  • the NAND partitions appear in /proc/mtd with the expected sizes,
  • the micro-USB port comes up as a network link to the host,
  • the root filesystem mounts over NFS and a shell prompt appears.

Before you start

  • A serial console connection. Without it, a failed boot gives no information at all.
  • A Linux host set up for USB RNDIS network boot, and the ability to build an image. Bring-up runs over the micro-USB port, which every device has — see step 3 for why not a USB drive.
  • A device that still runs its original software, so its U-Boot environment is intact.

Warning: Nothing in this guide writes to NAND. Bring-up runs entirely over the micro-USB link and leaves the bootloader, its environment and the installed firmware untouched. Keep it that way until the board boots reliably — a damaged bootloader needs the unbrick procedure to recover.

Step 1: Identify the board

Interrupt U-Boot at the serial console and read the board's identity out of its environment:

printenv variant module_type

variant is the board codename (for example spotty); module_type is the processor module, either sm2 or scm. Together they form the name used throughout the project, such as spotty_sm2. The hardware overview lists the known boards and the products they are sold as.

Read the codename off the device rather than deriving it from the product name: the two do not always agree. The SoundTouch adapter reports lisa whichever of its seven product names it currently goes by — see One board, many product names. If your device reports a variant that already has support, you are done before you start.

One caveat on trusting variant: the bootloader normally works it out from the board on every boot, but a value stored in the environment overrides that and is reported instead. If the boot log says variant override - …, what you are reading came from the environment rather than from the hardware — see Why fw_setenv and not saveenv.

The module type matters more than the codename. The two module families route the same signals to different pins of the AM3356, so a device tree written for one is unusable on the other. Everything below has an SM2 and an SCM variant.

While at the U-Boot prompt, record the NAND layout as well:

printenv

The mlo_nand_address, uboot_nand_address, env_nand_address, kernel0_nand_address, kernel1_nand_address, ubi_fs0_nand_address, ubi_fs1_nand_address, fs_persistent_address, fs_swupdate_address and fs_manufacturing_address variables, with their matching *_size variables, give the board's real partition map. It has to agree with the partition map in the device tree, otherwise the kernel will address the wrong flash regions.

Step 2: Understand the device tree layering

Device trees are split into three levels so that a new board only has to describe what is genuinely its own:

File Contents
libretouch-common.dtsi AM335x SoC, DRAM, the NAND controller and its partition map, the USB host port, the UART3 console, and the pstore region used to recover crash logs
sm2-common.dtsi / scm-common.dtsi The pin muxing for those shared signals, plus the peripherals that belong to the processor module itself (codec bus, PMIC, and on SM2 the WiFi/BT radio)
the board .dts Everything specific to one product: keypad, LEDs, IR receiver, display, ethernet, audio routing

libretouch-common.dtsi is never used on its own: it references pin groups by name (uart3_pins, usb0_pins_default and so on) that only the module .dtsi defines. Exactly one of sm2-common.dtsi or scm-common.dtsi must be included alongside it.

The NAND pins are the one exception. They are wired straight to the SoC's dedicated GPMC balls on the mainboard instead of passing through the module connector, so they are identical on both families and live in libretouch-common.dtsi itself.

Watch the names: sm2-common.dtsi is the module fragment described above, while common-sm2.dts is a complete tree built from it — the boot-only tree of step 3. The complete tree is named the other way round on purpose, so that it reads as the common variant of the sm2 module: the bootloader loads <variant>_<module>.dtb, and common is the variant it uses when the board does not identify itself as a product it knows.

Step 3: Boot with a boot-only device tree

For a first boot, no new device tree is needed at all. Both module families already have a boot-only tree — libretouch-common.dtsi plus the module .dtsi, a model name and a command line, and nothing else:

Module Boot-only tree Deployed as
SM2 common-sm2.dts common_sm2.dtb
SCM common-scm.dts common_scm.dtb

Every board carrying that module boots with its family's tree, because a boot-only tree describes only what the module and the mainboard have in common. It is deliberately free of any board peripheral that could hang the boot, which is exactly what makes it the right first target for an unknown board.

Both trees are built and deployed by every machine, so nothing special has to be built to get one.

Use RNDIS, not a USB drive. Switching the shared USB controller to the USB-A socket is described only in a board's own device tree. A boot-only tree cannot do it, so a device booted with one never sees a USB drive — the kernel comes up and then waits forever at Waiting for root device /dev/sda2.... That is the whole point of this step, so bring-up runs over the micro-USB port instead. It is also the only option on the boards that have no USB-A socket at all; see USB ports.

Build the netboot machine and set the host up as described in USB RNDIS network boot:

MACHINE=libretouch-net bitbake libretouch-image

That page's TFTP directory already contains every device tree, the boot-only ones included, so the only change for bring-up is which one U-Boot asks for. An unknown board asks for the right file on its own: U-Boot puts common in ${variant} whenever the manufacturing data names no product it recognises, so ${variant}_${module_type}.dtb resolves to common_sm2.dtb or common_scm.dtb and the normal netboot command needs no editing.

If the board does identify itself as a known product — and you want the boot-only tree anyway, because the product tree is what you suspect of hanging the boot — force it at the U-Boot prompt before booting:

setenv variant common

That is a RAM-only change; do not saveenv it, or the board will keep claiming to be common long after bring-up is over (see Why fw_setenv and not saveenv).

Nothing in this step writes to the device.

Step 4: Verify the boot

On the shell that appears, check the four things the boot-only tree is responsible for:

cat /proc/device-tree/model
free -m
cat /proc/mtd
ip link

The model string confirms which tree was actually used, free reports the board's DRAM size, /proc/mtd must match the addresses collected in step 1, and ip link shows the RNDIS interface the root filesystem arrived over.

At this point the board has basic support.

Step 5: Add the board device tree

The board .dts starts as the boot-only tree with a proper identity, and grows one peripheral at a time:

/dts-v1/;

#include "libretouch-common.dtsi"
#include "sm2-common.dtsi"

/ {
    model = "Bose Soundtouch <product> (<codename>_<module_type>)";
    compatible = "libretouch,<module_type>", "libretouch,<codename>_<module_type>", "ti,am33xx";
};

Name the file <codename>-<module_type>.dts, following spotty-sm2.dts — step 6 derives everything else from the codename, so the name has to follow that pattern exactly.

Add peripherals in the order they can be tested: console and storage are already working, so ethernet or the keypad usually come next, and audio last. Boot after every addition — a wrong pin mux or a missing regulator typically shows up as a hang rather than an error message.

spotty-sm2.dts is the reference for what a complete board tree contains, and the driver guide describes the kernel interface and a test procedure for each function.

Getting the file into the build

libretouch does not carry a kernel tree of its own. All of its kernel changes are patches applied to the TI kernel, kept in

sources/meta-libretouch/recipes-kernel/linux/linux-ti-staging/

and listed in SRC_URI in sources/meta-libretouch/recipes-kernel/linux/linux-ti-staging_6.12.bbappend. To add a board device tree, put the new .dts under arch/arm/boot/dts/ti/omap/ and list its .dtb in that directory's Makefile — both as part of a patch file, added to that directory and to SRC_URI in the order it should apply.

The practical way to produce that patch is to let the build unpack and patch the kernel once, edit the result under build/tmp/work-shared/<machine>/kernel-source/ (or a private clone of the same kernel), and generate the patch with git format-patch. Rebuild with bitbake -c cleansstate virtual/kernel afterwards so the new patch is applied from a clean tree.

If you have set up devtool modify for the kernel, edit the sources in the devtool workspace and commit there instead; the build takes the change from the workspace and the patches in the layer are then no longer the file being read. Do not edit both.

Step 6: Register the board

A new board does not get a machine of its own. Machines are named after the boot method — libretouch-nand, libretouch-usb, libretouch-net — and one image serves every board, whichever processor module it carries. The bootloader picks the right device tree at boot from the board's own manufacturing data, exactly as the original software does:

ubifsload ${loadaddr} /boot/${variant}_${module_type}.dtb    # NAND
fatload usb 0:1 ${loadaddr} ${variant}_${module_type}.dtb    # USB

So registering a board means adding one word to one list in conf/machine/include/libretouch-common.inc:

LIBRETOUCH_BOARDS ?= "spotty-sm2 lisa-scm <codename>-<module>"

That is the whole change. The codename must be exactly what printenv variant reported in step 1 and must contain no -, the module must be what printenv module_type reported, and the board's device tree must be <codename>-<module>.dts, because libretouch-common.inc derives the rest of it from those two words:

Derived Becomes
LIBRETOUCH_MODULES the processor modules the list mentions — each one contributes a boot-only tree
KERNEL_DEVICETREE ti/omap/<codename>-<module>.dtb per board, plus common-<module>.dtb per module — what gets built and deployed
LIBRETOUCH_BOOT_DTBS <codename>-<module>.dtb:<codename>_<module>.dtb per board — the built name mapped to the name the bootloader asks for
STU_BOARD_TAG <module>/<codename>+<codename>… per module, joined — the board tag in the .stu revision

Every boot path consumes LIBRETOUCH_BOOT_DTBS: the NAND image installs those files into /boot, and the USB image writes them to the FAT partition under the same names. Nothing has to be edited twice, and nothing can go stale.

The list always carries one more entry per module than there are products: common_<module>.dtb, the boot-only tree of step 3. It is what the bootloader asks for when the board's manufacturing data names no product it recognises, and what it retries with when the product's own tree is not on the medium — so a board still boots, on its module's tree, before step 6 has been done for it.

Existing devices keep booting from the same image, which is the point: one image that works on every product.

Step 7: Adjust the kernel configuration

All machines share one kernel configuration baseline, LIBRETOUCH_KERNEL_DEFCONFIG, with per-machine differences expressed as fragments appended to LIBRETOUCH_KERNEL_FRAGMENTS in the machine configuration. Fragments merge in order, so a later one overrides an earlier one.

Because one image serves every board, a board cannot have a kernel configuration of its own. Anything a new board needs goes into the shared defconfig, where it is available to all of them — which is usually right anyway, since they differ in peripherals rather than in drivers. Fragments stay reserved for boot-method differences, as the machine configurations use them.

Troubleshooting

Symptom Likely cause
No U-Boot output at all Serial wiring or adapter; check the console pinout
U-Boot output, but nothing after "Starting kernel" No device tree reached the kernel, or the console pin mux is wrong for this module type — confirm the common_${module_type}.dtb that was loaded matches the module_type from step 1
Kernel boots but reports the wrong memory size The memory node in libretouch-common.dtsi is set for 128 MB; a board with a different size needs an override
NAND errors, or /proc/mtd sizes that disagree with printenv The partition map in libretouch-common.dtsi does not match this board
"Waiting for root device" that never ends The kernel found no root filesystem. On the RNDIS path, check the host's NFS export and the nfsroot= argument; if the message names /dev/sda2 you are booting the USB-drive command by mistake, which a boot-only tree cannot satisfy
Root filesystem refuses to mount The stock environment demands ext3 on the second partition; an ext4-featured image is rejected
Kernel panics with no console output Read /sys/fs/pstore after the next boot; the crash log survives a warm reset

Beyond basic support

Once the board boots, extend it peripheral by peripheral using the driver guide, and update the device table in STATUS.md as functions start working.

From here the board is part of the ordinary images: MACHINE=libretouch-nand bitbake libretouch-image-nand builds the NAND update that boots it and every other product, and MACHINE=libretouch-usb bitbake libretouch-image the USB development image. See development setups for those boot paths.