Driver integration in AAOS 14 on Raspberry PI

Volodymyr Kozhemiakin
Make Android
Published in
7 min readMar 29, 2024

In this guide, we’ll walk through integrating the TEA5767 FM tuner kernel driver to AOSP 14 on the Raspberry Pi 4. We start by adding the radio driver into the Linux kernel. Next, we’ll explore how to compile a new kernel that includes this driver and how to swap out AOSP’s original kernel with ours. Afterward, we proceed to rebuild AOSP, including our changes, and then prepare the Raspberry Pi for the firmware update. This step-by-step method ensures TEA5767 FM tuner integrates flawlessly, boosting our Raspberry Pi capabilities under AOSP 14. Through this integration, we gain direct access to the radio tuner via sysfs filesystem, unlocking additional functionalities for our device.

Photo by Marshall

Prerequisites

Before diving into integration, ensure we have:

Hardware:

  1. PC with working AOSP build environment
  2. Raspberry Pi 4 Model B
  3. TEA5767 FM tuner module
  4. Speaker with Mini-Jack 3.5 мм, cable USB-C, jumper wires.

Software:

  1. Android open source code (AOSP) 14
  2. Linux kernel driver source code
  3. Tuner Kernel driver

How to setup build environment, build firmware and flash Raspberry Pi 4— described in the previous story Android Automotive OS 14 on a Raspberry Pi 4 AOSP14

Linux kernel driver source code: As we know, the Linux kernel source code is built separately from the Android Open Source Project (AOSP). Separation between the kernel and AOSP enhances the flexibility, security, and hardware compatibility of Android devices, while also accommodating the diverse needs of device manufacturers and developers.

Download Raspberry vanilla Linux kernel driver source code using this instruction: https://github.com/raspberry-vanilla/android_kernel_manifest/tree/android-14.0

The TEA5767 is a compact, integrated stereo FM radio tuner module widely used in various electronic projects and consumer products. It operates in the FM band range from 87.5 to 108.0 MHz, making it suitable for receiving FM radio broadcasts. The module is designed to be easily interfaced with microcontrollers or processors through the I2C communication protocol.

Tuner Kernel driver tea5767_fm_tuner.c we can download from github https://github.com/mozcelikors/tea5767_kernel_driver

Speaker (earphone) with Mini-Jack 3.5 мм to connect to TEA5767 FM tuner module. Cable USB-C to connect Raspberry Pi 4 to PC to control the radio tuner via Android Debug Bridge (adb). Jumper wires for connecting Raspberry Pi 4 with TEA5767 FM tuner module.

Hardware setup

Connecting the TEA5767 FM module to a Raspberry Pi 4 involves interfacing the module via the I2C communication protocol. The TEA5767 module typically has four main pins that need to be connected: VCC, GND, SDA, and SCL.

  1. VCC: Connect the VCC pin of the TEA5767 module to a 3.3V pin on the Raspberry Pi (Pin 1 or Pin 17).
  2. GND: Connect the GND pin of the TEA5767 module to any GND pin on the Raspberry Pi (for example, Pin 6, 9, 14, 20, or 25).
  3. SDA: Connect the SDA pin of the TEA5767 module to the SDA pin of the Raspberry Pi (GPIO 2, Pin 3).
  4. SCL: Connect the SCL pin of the TEA5767 module to the SCL pin of the Raspberry Pi (GPIO 3, Pin 5).

Pinout of Raspberry Pi we can check here https://pinout.xyz/

Raspberry Pi hardware GPIO

Pinout of TEA5767 FM radio module we can see on back side.

TEA5767 hardware pinout

Finally, we got connection scheme TEA5767 FM radio module to Raspberry Pi 4 using jumper wires

Connection scheme TEA5767 FM radio module and Raspberry Pi 4

and the last, connect antenna and speaker (earphone) to TEA5767 module.

Software setup

The tea5767_fm_tuner.c kernel driver is responsible for communicating with the TEA5767 module over I2C, providing an interface to set the frequency, mute/unmute, print stationlist and set the station. We will add this driver to the device's kernel source and ensure it's loaded at boot time.

Adding the TEA5767 Driver to the Kernel:

1. Place the driver tea5767_fm_tuner.c file to kernel source tree common/drivers/media/tuners/ that we have downloaded.

2. Modify the Makefile in the same directory common/drivers/media/tuners/Makefile to include the TEA5767 driver in the kernel build.

# tea5767_fm_tuner.c
obj-$(CONFIG_RADIO_TEA5767) += tea5767_fm_tuner.o

3. Make sure that common/drivers/media/tuners/Kconfig and common/drivers/media/Kconfigfile contains the MEDIA_TUNER_TEA5767 config. It allows building the driver directly into the kernel or as a module, based on user choice.

config MEDIA_TUNER_TEA5767
tristate "TEA 5767 radio tuner"
depends on MEDIA_SUPPORT && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
Say Y here to include support for the Philips TEA5767 radio tuner.

4. Specify I2C pins, it requires device tree modification. Raspberry Pi 4 uses the BCM2711 SoC and its I2C buses are defined in the BCM2711 Device Tree Sources (DTS), so by looking at all .dts files we can identify the file bcm2711-rpi-4-b.dts

common/arch/arm64/boot/dts/broadcom/bcm2711-rpi-4-b.dts
common/arch/arm/boot/dts/bcm2711-rpi-4-b.dts

From Raspberry Pi pinout documentation we can see that GPIO2 and GPIO3 are I2C1 pins, so &i2c1 is the correct bus.

&i2c1 {
pinctrl-names = "default";
pinctrl-0 = <&i2c1_pins>;
clock-frequency = <100000>;
status = "okay";

tea5767@60 {
compatible = "mozcelikors,tea5767";
reg = <0x60>;
minstation = <88000>;
maxstation = <108000>;
};
};

5. Enable kernel config

CONFIG_MEDIA_TUNER_TEA5767=y: This option compiles the TEA5767 tuner driver directly into the kernel binary. It means the driver is part of the kernel image and is loaded automatically on boot.

CONFIG_MEDIA_TUNER_TEA5767=m: This option compiles the TEA5767 tuner driver as a loadable kernel module (LKM). The module .ko file is separate from the main kernel binary. It allows the system administrator or automated scripts to load and unload the driver dynamically, depending on whether the device is needed or not.

common/arch/arm/configs/ezx_defconfig
# CONFIG_MEDIA_TUNER_TEA5767 is not set
CONFIG_MEDIA_TUNER_TEA5767=y

6. Add flags to Makefile in the same folder common/drivers/media/tuners/Makefile to exclude some rules during compiling tea5767_fm_tuner.c kernel driver or fix source code.

MAKEFLAGS += -Wno-unused-function -Wno-unused-variable

When all configs were done we can build, run command on the root dir of Kernel source tree.

BUILD_CONFIG=common/build.config.rpi4 build/build.sh

After successful build we can see that files have been copied to out/dist/

  ...
HDRINST usr/include/asm/sockios.h
INSTALL /media/vkozhemi/dd7/kernel_AOSP_rasp/out/kernel_uapi_headers/usr/include
make: Leaving directory '/media/vkozhemi/dd7/kernel_AOSP_rasp/out/common'
Copying kernel UAPI headers to /media/vkozhemi/dd7/kernel_AOSP_rasp/out/dist/kernel-uapi-headers.tar.gz
========================================================
Copying kernel headers to /media/vkozhemi/dd7/kernel_AOSP_rasp/out/dist/kernel-headers.tar.gz
/media/vkozhemi/dd7/kernel_AOSP_rasp/common /media/vkozhemi/dd7/kernel_AOSP_rasp
/media/vkozhemi/dd7/kernel_AOSP_rasp
========================================================
Files copied to /media/vkozhemi/dd7/kernel_AOSP_rasp/out/dist

Compiled kernel Image, dtbs, and overlays can be found in out/common/arch/arm64/boot directory.

Before copying built kernel files to Android source tree, we need to download AOSP14. I used this instruction https://github.com/raspberry-vanilla/android_local_manifest or Android Automotive OS 14 on a Raspberry Pi 4 AOSP14.

Once we download AOSP14, replace existing files in device/brcm/rpi4-kernel directory of the Android source tree to include them in Android 14 build. We can also replace existing files in the boot partition out/target/product/rpi4/rpibootof Raspberry Pi 4 Android 14 image.

When all files have been replaced we can build AOSP and flash Raspberry Pi 4 with SD Card.

Control tuner via sysfs

Connect Raspberry Pi 4 to PC using USB-C cable. If TEA5767 device has been successfully recognized by the system through the Device Tree configuration we can find directory path

adb shell
cd /sys/devices/platform/soc/fe804000.i2c/i2c-1/1-0060/tea5767

The corresponding driver for the TEA5767 has been loaded and initialized correctly. The directory path shows the device’s hierarchy in the system, indicating it’s connected via the I2C bus with the address 0x60.

Here we can find sysfs interface

Sysfs Interface

The presence of files (mute, station, stationlist) in the sysfs directory for the device indicates that the driver exposes certain controls. This is a standard method in Linux for user space programs to interact with kernel drivers.

To control TEA5767 FM tuner we can use commands in dir

/sys/class/i2c-dev/i2c-1/device/1-0060/tea5767:

  • Mute: echo “1” > mute
  • Unmute: echo “0” > mute
  • Check Mute Status: cat mute
  • Get Current Station Frequency: cat station
  • Get Available Stations: cat stationlist
  • Tune into a Station (Frequency in kHZ): echo 105500 > station

Modifying files within the /sys directory requires superuser (root) privileges because these files interface directly with kernel space, affecting hardware behavior. To set files (mute, station, stationlist) it requires to get root adb root or su first.

Get mute, station, stationlist and set station

Finally it works!

Recommendations about Device Tree Overlays

Device Tree Overlays: Instead of modifying the base DTS file directly, consider using device tree overlay. Overlays are more flexible and modular way to modify the device tree without altering base DTS files. We create separate .dts file for our overlay and compile it into a .dtbo file, then configure our system to load this overlay at boot time. This approach is particularly useful for adding custom hardware configurations without touching the core device tree files, making our changes easier to manage and preserve across kernel updates.

To use an overlay, we would create a file (e.g., tea5767-overlay.dts) with content similar to the modified block above, then compile and enable it following Raspberry Pi's overlay loading mechanism (typically via /boot/config.txt).

Conclusions:

In this story, we learned how to add a radio tuner to Android system on Raspberry Pi. We discovered how to update the Android kernel, make changes to device tree, and use sysfs to directly control the tuner. This experience showed us how flexible Android is and how we can add new features to it.

This project was interesting way for me to learn about the deep connection between hardware and software in Android low level. We also saw how sharing our work and learning from others makes the whole Android community better.

Links that was helpful:

  1. https://github.com/raspberry-vanilla/android_local_manifest/tree/android-14.0
  2. https://github.com/raspberry-vanilla/android_kernel_manifest/tree/android-14.0
  3. https://github.com/mozcelikors/tea5767_kernel_driver

--

--

Volodymyr Kozhemiakin
Make Android

Android Engineer | Mobile | Automotive | Enterprise | AOSP | Applications, Android Framework, System Services, HAL, Kernel | C/C++ | Java | Kotlin