• CTAG-ALSA
  • CTAG face support in Linux 5.x kernel

I started from the bb Buster image you linked elsewhere, but any modern image should work the same.

You'll need this in /opt/source/dtb-5.10-ti https://github.com/BelaPlatform/BeagleBoard-DeviceTrees/tree/v5.10.x-ti . make && make install

This uEnv https://gist.github.com/giuliomoro/29885ee2321164e2fc9ba30ed43522a6

I used this kernel source https://github.com/giuliomoro/linux/tree/5.10
following the instructions to build it that are split across several files here https://github.com/anbraten/beagle-bone-builder/tree/master/scripts , where I used a user_config.sh as follows (only the first one is really relevant as I didn't manage to finish building the image. There is no docs as to what these values are supposed to be):

KERNEL_BRANCH=5.10
ROOTFS_NAME=debian-10.13-minimal-armhf-2022-10-06
UBOOT_VERSION=v2019.04

For relatively quick iteration - after a full build and install - I build with
(after sourcing scripts/config.sh) :

make ARCH=arm CROSS_COMPILE="${CACHED_CC}"  modules && \
sudo make ARCH=arm CROSS_COMPILE="${CACHED_CC}" modules_install INSTALL_MOD_PATH=/lfs/tmp/fs/rootfs`

and then scp the relevant files /lfs/tmp/fs/rootfs/lib/modules/5.10.145+/kernel/sound/soc/ctag/snd-soc-davinci-ctag-face-2-4.ko.xz and /lfs/tmp/fs/rootfs/lib/modules/5.10.145+/kernel/sound/soc/codecs/snd-soc-ad193x.ko.xz to the board and reboot. I have to reboot because modprobe -r doesn't want to remove the modules for me. If you have suggestions on how to iterate more quickly (I think I could manually zip the two relevant modules instead of relying on modules_install to do it for me), I am all ears.

The latest commit on the kernel repo includes some debugging printks (and also changing the data format). I print the registers of the codec and they can be compared against the ones used when running CTAG with Bela:

0 156
1 8
2 64
3 12
4 24
5 0
6 0
7 0
8 0
9 0
10 0
11 0
12 0
13 0
14 0
15 35
16 108

(note that they don't necessarily have to match because the McASP config could also be different).

Anyhow, that's what I have so far. @siraaris if you want to keep digging, check for consistency in the dai format as seen from the codec and from the mcasp.

further thought: as it seems that the format for the codec is hardcoded in AUDIOCARD_AD193X_DAIFMT , there may be two ways out: one is editing the driver until it works, the other is fixing it from the device tree overlay.

I've compiled up a kernel with above instructions and confirm that the driver loads:

[   24.785735] snd_davinci_audiocard_probe
[   24.785981] snd_ctag_face_2_4 sound: snd_soc_register_card failed (-517)
[   25.792533] ad193x_probe
[   25.792681] has_adc
[   26.005560] snd_davinci_audiocard_probe
[   26.006447] ad193x_component_probe
[   26.006461] ad193x_reset
[   26.008468] ad193x_reg_default_init
[   26.011822] 0 0x00
[   26.011838] 1 0x00
[   26.011845] 2 0x00
[   26.011851] 3 0x00
[   26.011858] 4 0x00
[   26.011864] 5 0x00
[   26.011870] 6 0x00
[   26.011876] 7 0x00
[   26.011883] 8 0x00
[   26.011889] 9 0x00
[   26.011895] 10 0x00
[   26.011902] 11 0x00
[   26.011908] 12 0x00
[   26.011914] 13 0x00
[   26.011920] 14 0x00
[   26.011927] 15 0x00
[   26.011933] 16 0x00
[   26.022437] has_adc
[   26.027926] has_adc
[   26.028170] snd_davinci_audiocard_init
[   26.028225] SET_TDM_SLOT for both to ff ff 8 32
[   26.028236] ad193x_set_tdm_slot ff ff 8 32
[   26.033355] has_adc
[   26.034470] ad193x_set_dai_fmt
[   26.034483] ad1938 DSP
[   26.034490] has_adc

I can remove modules:

rmmod snd_soc_davinci_ctag_face_2_4 snd_soc_ad193x_spi snd_soc_ad193x

and re-insert:

modprobe snd-soc-ad193x snd-soc-ad193x-spi snd-soc-davinci-ctag-face-2-4

When I enable debugging, here's the dmesg:

mclk not found may be of interest.

[ 3404.436826] snd_davinci_audiocard_remove
[ 3408.609296] ad193x_probe
[ 3408.611999] has_adc
[ 3442.848434] ad193x_probe
[ 3442.851404] has_adc
[ 3443.896054] snd_davinci_audiocard_probe
[ 3443.900744] ad193x_component_probe
[ 3443.906847] ad193x_reset
[ 3443.912941] ad193x_reg_default_init
[ 3443.918309] 0 0x00
[ 3443.920343] 1 0x08
[ 3443.924266] 2 0x00
[ 3443.927683] 3 0x00
[ 3443.931054] 4 0x00
[ 3443.934339] 5 0x00
[ 3443.936372] 6 0x00
[ 3443.940308] 7 0x00
[ 3443.943720] 8 0x00
[ 3443.947160] 9 0x00
[ 3443.950500] 10 0x00
[ 3443.952619] 11 0x00
[ 3443.956377] 12 0x00
[ 3443.959821] 13 0x00
[ 3443.963270] 14 0x00
[ 3443.966905] 15 0x00
[ 3443.970321] 16 0x00
[ 3443.975176] has_adc
[ 3443.977738] has_adc
[ 3443.980099] snd_davinci_audiocard_init
[ 3443.986467] SET_TDM_SLOT for both to ff ff 8 32
[ 3443.992464] ad193x_set_tdm_slot ff ff 8 32
[ 3443.998260] has_adc
[ 3444.000550] ad193x_set_dai_fmt
[ 3444.005590] ad1938 DSP
[ 3444.007975] has_adc
[ 3598.828548] snd_davinci_audiocard_remove
[ 3603.000851] ad193x_probe
[ 3603.003822] has_adc
[ 3604.050799] snd_davinci_audiocard_probe
[ 3604.055085] snd_ctag_face_2_4 sound: mclk not found.
[ 3604.065521] ad193x_component_probe
[ 3604.068960] ad193x_reset
[ 3604.075884] ad193x_reg_default_init
[ 3604.081360] 0 0x00
[ 3604.083394] 1 0x08
[ 3604.087203] 2 0x00
[ 3604.090549] 3 0x00
[ 3604.092581] 4 0x00
[ 3604.096393] 5 0x00
[ 3604.099816] 6 0x00
[ 3604.103174] 7 0x00
[ 3604.106510] 8 0x00
[ 3604.108543] 9 0x00
[ 3604.112390] 10 0x00
[ 3604.115763] 11 0x00
[ 3604.119186] 12 0x00
[ 3604.122606] 13 0x00
[ 3604.124724] 14 0x00
[ 3604.128588] 15 0x00
[ 3604.132094] 16 0x00
[ 3604.136604] has_adc
[ 3604.140253] has_adc
[ 3604.143987] snd_davinci_audiocard_init
[ 3604.149230] snd_ctag_face_2_4 sound: Using configuration from dt overlay.
[ 3604.159443] SET_TDM_SLOT for both to ff ff 8 32
[ 3604.165662] ad193x_set_tdm_slot ff ff 8 32
[ 3604.171533] has_adc
[ 3604.175225] ad193x_set_dai_fmt
[ 3604.179545] ad1938 DSP
[ 3604.183257] has_adc
5 days later

An update: it works-hacked. https://github.com/giuliomoro/linux/tree/5.10-ctag-hacks

Notes first:

Workflow

Quick reload of modules: you need to unload and reload them in this order:

sudo modprobe -r snd_soc_davinci_ctag_face_2_4
sudo modprobe -r snd_soc_ad193x_spi
sudo modprobe -r snd_soc_ad193x
sudo modprobe -r snd_soc_davinci_mcasp
sudo modprobe snd_soc_davinci_mcasp
sudo modprobe snd_soc_ad193x
sudo modprobe snd_soc_ad193x_spi
sudo modprobe snd_soc_davinci_ctag_face_2_4

My current fast iteration script is as follows:

on the build machine quick-build.sh in kernel/ is:

#!/bin/bash
. ../../scripts/config.sh && make ARCH=arm -j$(nproc) CROSS_COMPILE="${CACHED_CC}"  modules
set -x
rm -rf  sound/soc/{ctag,codecs,ti}/snd-*.xz
xz -k sound/soc/ti/snd-soc-davinci-mcasp.ko
xz -k sound/soc/ctag/snd-soc-davinci-ctag-face-2-4.ko
xz -k sound/soc/codecs/snd-soc-ad193x.ko

on the target I have

#!/bin/bash
set -ex
REMOTE=bui
REMOTE_PREFIX=/lfs/tmp/kernel/sound/soc/
LOCAL_PREFIX=/lib/modules/5.10.145+/kernel/sound/soc/
MOD_EXT=.ko.xz
MODULES_PATHS="ti/snd-soc-davinci-mcasp codecs/snd-soc-ad193x ctag/snd-soc-davinci-ctag-face-2-4"
#MODULES_PATHS="codecs/snd-soc-ad193x ctag/snd-soc-davinci-ctag-face-2-4"
MODULES=
for a in $MODULES_PATHS; do
	MODULES="$MODULES $(basename $a)"
done
MODULES="$MODULES snd_soc_ad193x_spi"
RSYNC_LIST=
for a in $MODULES_PATHS; do
	RSYNC_LIST="$RSYNC_LIST $REMOTE:$REMOTE_PREFIX/$a$MOD_EXT"
done

rsync -av $RSYNC_LIST ./
sudo modprobe -r snd_soc_davinci_ctag_face_2_4
sudo modprobe -r snd_soc_ad193x_spi
sudo modprobe -r snd_soc_ad193x
sudo modprobe -r snd_soc_davinci_mcasp

for a in $MODULES_PATHS; do
	sudo cp $(basename $a)$MOD_EXT $LOCAL_PREFIX/$a$MOD_EXT
done
for a in $MODULES; do
	sudo modprobe $a
done

Then from the target I can run:

ssh bui "cd /lfs/tmp/kernel/ && ./quick-build.sh" && ./deploy.sh  && sleep 0.5 && aplay -D plughw:CARD=C8CH,DEV=0 ~/out.wav

(the above is mostly for my future self).

Driver and codec issues

Most of the entries in the dtb are ignored. As far as I can tell from grep ing through sound/, mcasp-controller-bit-delay-tx and mcasp-controller-bit-delay-rx from the device tree are not handled anywhere.

The AD1938 seems to mostly ignore the values in SDATA delay (DAC Control Register0 bits 5:3, AD193X_DAC_CTRL0) when in TDM mode. I don't see this explicitly stated in the datasheet anywhere. However it seems to be affected - at least to a certain extent - by SDATA delay (ADC Control Register 1 bits 4:2, AD193X_ADC_CTRL1), which makes little sense to me.

I found out experimentally that, when the DAC is set to TDM mode (and it ignores the DAC SDATA delay in AD193X_DAC_CTRL0 and with the ADC SDATA delay in AD193X_ADC_CTRL1 set to the default value of 1), it expects a data format that corresponds to what the McASP would call "data_delay = 2" ( i.e.: the word starts not at the same time as the frame clock ("data_delay = 0"), not on the first bitclock after the frame clock ("data_delay = 1"), but on the second bitclock after the frame clock ("data_delay = 2"). The data_delay property in the McASP's XFMT register (DAVINCI_MCASP_TXFMT_REG), however, can only be set to 0 or 1 in davinci_mcasp_set_dai_fmt(), and it currently can only be set to 2 via a hack, or perhaps calling mcasp_set_bits() from the driver after davinci_mcasp_set_dai_fmt() has been called. I didn't investigate that part.
https://github.com/giuliomoro/linux/commit/dc06cf9e383d265ebb3c055ddd2ac87a8fe7e60f shows this solution (via hack), which would also break any other driver using McASP.

An alternative, which leverages the fact that somehow the DAC format is affected by the ADC format register is in https://github.com/giuliomoro/linux/commit/0bf82f6cf053d8d6bfa600e04f60d12db17dc92e. This doesn't break any core mcasp stuff, but it leverages a poorly understood undefined or undocumented behaviour. Good enough for a PoC.

Known issues

Probably a better approach is needed, but this codec behaves so weirdly that I am not sure it's worth the pain.

I noticed that with either version of the driver above, if you stop/restart the aplay enough times, you may get that the output's amplitude becomes smaller, almost half, as if it was shifted by one bit to the right, but I don't see any bit shifting on the McASP side. If you unload and reload the snd_soc_davinci_ctag_face_2_4 module at that point, the amplitude increases slightly. If you also unload and reload (in order) snd_soc_ad193x_spi, then it goes back to normal. It may well be some issue with how the codec is handled there .. for instance: is it being reset appropriately? I didn't look at it.

You can easily reproduce the issue letting this running:

while sleep 0.1; do aplay -D plughw:CARD=C8CH,DEV=0 ~/out.wav & sleep 0.5; killall -2 aplay; done

A workaround is to always run

sudo modprobe -r snd_soc_davinci_ctag_face_2_4
sudo modprobe -r snd_soc_ad193x_spi
sudo modprobe snd_soc_ad193x_spi
sudo modprobe snd_soc_davinci_ctag_face_2_4

after opening/closing the soundcard (via aplay or otherwise).

    giuliomoro looking at your overlay, is there a delay of 1 for the McASP controller and another 1 for the interface (making a total delay of 2?). It does seem that the overlay would be the way to make this work. Reviewing the driver kernel code in the BB and TI kernels there’s not much difference (I notice the _priv struct is slightly different).

    My approach is based (following in parallel what you’ve been doing) on using buildroot to create a very small firmware for my project, removing all the unessary items/modules etc as I only need Ethernet and CTAG and GSTreamer plus ALSA.

    Ideally I’d have the CTAG driver compiled in not as a module.

      siraaris ooking at your overlay, is there a delay of 1 for the McASP controller and another 1 for the interface (making a total delay of 2?).

      As mentioned, I think many of the entries in the dtb are ignored. I could not manage to generate any difference on the McASP side (i.e.: observable changes in the delay between frame clock and data) or on the codec side (i.e.: observable changes in the registers set by the driver (as printed or changes in the analog signal generated by the DAC) when changing any of ti,audio-codec-bit-delay-dac or ti,audio-codec-bit-delay-dac = <1>. Inspecting the driver's source I don't see where those would be read anyhow and - interestingly - inspecting the commit log (-p) of the relevant files doesn't show me these have ever been used anywhere (as far as I can tell).

      siraaris Ideally I’d have the CTAG driver compiled in not as a module.

      Even when it is, you should still be able to bind/unbind it if needed, i.e.::

      echo  "ocp:bone_sound" | sudo tee /sys/bus/platform/drivers/snd_ctag_face_2_4/unbind
      echo  "ocp:bone_sound" | sudo tee /sys/bus/platform/drivers/snd_ctag_face_2_4/bind

      (I think). But sure it would be best to just fix the driver so it doesn't require this step.

      17 days later

      Just a quick note, I spent some time getting a Yocto setup working with 5.10-ctag-hacks. Had to combine the CTAG overlay into the device tree am335x-boneblack.dts as I couldn't get loading of DTBO's working.

      Did a very quick test, and confirm driver loading, and aplay/arecord seem to behave as expected on initial inspection.

      I think that I'll be able to progress with the POC and get a better sense and actual listening of the project during the end of year break - thank you.

        siraaris I couldn't get loading of DTBO's working.

        That's normally done in uboot.

        a year later

        I've been trying to follow along. I've compiled new kernel modules for the BBB bullseye release 11.7 with the 5.10-ctag-hacks and the API changes.
        If I don't include the DTBO overlay in the eEnv.txt then the sound card shows up in ALSA but its not really working.
        If I actively enable the DTBO overlay the in uEnv.txt the sound card doesn't show up at all in ALSA.

        @siraaris It seems you got things working. I understand you integrated the CTAG overlay into the device tree am335x-boneblack.dts, correct? Is there any way you could share you merged device tree file?
        Did you have to make further changes to the driver/codes as proposed by giuliomoro ?

          amessner If I don't include the DTBO overlay in the eEnv.txt then the sound card shows up in ALSA but its not really working.
          If I actively enable the DTBO overlay the in uEnv.txt the sound card doesn't show up at all in ALSA.

          can you show the content of uEnv.txt in either cases?

            giuliomoro
            I've attached the uEnv.txt where I see a sound card in ALSA but it doesn't actually use the device tree overlay for the CTAG face -> uEnv_original.txt
            I can run "speaker-test -D hw:0 -c 2 -r 48000 -t sine -f 1000" (please note channel count 2). If I try any higher channel count it doesn't work. And even with 2 channels I don't hear anything on any of the CTAG outputs.

            I've tried multiple configurations, the last one I tried is actually taken from one of your earlier posts. With this uEnv.txt I don't see a sound card in ALSA at all -> uEnv.txt.

            I found that adding the device tree overlay for CTAG to the uEnv.txt OR disabling any of the overlays for video, audio, etc will cause the sound card to disappear

            uenv.txt
            2kB
            uenv-original.txt
            2kB

            .

            OK I managed to have a look at this. You need this branch in /opt/sources/dtb-5.10-ti and then do make && sudo make install to put the update base device tree and overlay in place. At that point those will be loaded OK, but no soundcard will appear because the driver is not there and so you need to build and install the driver, as you can tell because modprobe snd-soc-ad193x snd-soc-ad193x-spi snd-soc-davinci-ctag-face-2-4 fails. I have not repeated the build and install procedure because it should be the same as previously and also I don't have machine to build it on with me right now, but hopefully you can.

            Thank you @giuliomoro.

            @amessner based on the above activity I dug out my BBB/CTAG and am going to attempt to rekindle where I got to previously - might be a week or so.

            Ok I made some progress.

            I used the latest Bullseye Image for the BBB (kernel 5.10.168-ti-r72) as a base.
            Then patched (https://github.com/anbraten/beagle-bone-builder/tree/master/resources/ctag-2.4) and compiled the drivers for snd-soc-ad193x, snd-soc-ad193x-spi and snd-soc-davinci-ctag-face-2-4, copied them over and confirmed that they load.

            Then I updated the uEnv.txt (see uEnv.txt of my last post)

            Now I can play sounds on 2 channels, but not on the other 6.
            If I try recording something it also doesn't "really" work. Sometimes I get a very noisy file, sometimes nothing.

            Did anyone get as far as to record something successfully? Or did you just test by playing back a test wav file?

            @giuliomoro if I try to use your device tree branch then the image won't even boot anymore.

              I won't be able to have another look until some point next week.

              amessner if I try to use your device tree branch then the image won't even boot anymore

              to troubleshoot that you'd need to get a serial log from the UART0 port on the BBB.