[alsa-devel] Thoughts on ASOC v2 driver architecture

Jon Smirl jonsmirl at gmail.com
Mon Jun 16 15:26:31 CEST 2008

On 6/16/08, Liam Girdwood <lg at opensource.wolfsonmicro.com> wrote:
> On Sun, 2008-06-15 at 14:10 -0400, Jon Smirl wrote:
>  > I'm trying to sort out an architecture that will let all of the code
>  > used in my ASOC drivers to be automatically loaded by the kernel.  So
>  > if I'm confused and have some of this wrong please explain where I've
>  > gone astray.
>  >
>  > First, what are the physical hardware devices present? From the device
>  > tree it says I have two i2s controllers each with an i2c controlled
>  > codec. It also says I have a system wide DMA controller. And finally
>  > there is the "fabric" which represent the specific pcb (populated
>  > jacks, etc) used by the system (the root of the device tree).
>  >
>  > Upon booting the kernel it will find the five open firmware devices
>  > (two i2s, two codecs, one DMA) and load the appropriate of drivers for
>  > them. Note that this is the system wide DMA driver, not the ASOC one.
>  > Three drivers will be loaded and five devices will be created.
>  >
> I assume your system is PPC.

Yes, similar patterns to this happen on the other platforms. They use
code in the arch directories to load their drivers instead of a device

>  > The codec devices will each register one codec and multiple codec
>  > DAIs. Each i2c channel will register a platform_dai.
>  >
> I also assume you mean I2S instead of I2C here ;)


>  A codec will only register a DAI (Digital Audio Interface - I2S, PCM,
>  AC97) for each physical or logical DAI it has. i.e. the WM8750 on the
>  Sharp Tosa only has 1 physical DAI and registers only 1 DAI with the
>  core. However, the WM8753 used on the OpenMoko Neo1973 has 2 physical
>  DAIs and can also reconfigure them at runtime and hence registers 4 DAIs
>  with the core.

yes, the ones I am writing have done this

>  A platform (i.e. SoC CPU platform) will register a DAI for every DAI
>  present at DAI module load time. i.e. on pxa2xx we can register a DAI
>  for AC97, I2S and PCM (SSP).

i agree

>  > The next part, the platform device,  is where I'm having trouble. Why
>  > is the DMA subsystem in it's own ASOC device? I already have a
>  > separate system wide device for my DMA hardware.  Looking at the
>  > implementations of a couple of the ASOC DMA drivers, there is nothing
>  > global about the driver, everything is done with per channel
>  > instances.
>  >
>  > Should the DMA code instead simply be a library that is linked to by
>  > the i2s drivers? And then move the entry points registered by the DMA
>  > driver up into the platform_dai? It seems to me like implementation of
>  > the DMA code should be a private matter for the platform_dai/i2s
>  > driver. Note that I'm not saying that there shouldn't be modularized
>  > ASOC DMA code, instead, why should ASOC be aware of this shared code?
>  > To see if this model would work I tried to visualize a system where
>  > one i2s controller is using DMA and the second is doing programmed IO.
>  >
>  > So if the DMA API is pushed into the platform_dai that would free up
>  > the platform device. It could then be used to support the fabric code
>  > (fabric is the motherboard specific bits of code). It should probably
>  > be renamed to the machine device instead of platform device. To handle
>  > the case of HDA not needing a fabric driver,  ASOC would have a
>  > default internal machine driver that a fabric driver could override.
>  > This also implies that the fabric driver can't be the last driver
>  > registered with ASOC.
> HDA has it's own controller and codec spec and hence won't require ASoC.
>  ASoC is only for codecs and CPUs with simple DAIs i.e. I2S, PCM and
>  AC97.

I haven't worked with HDA, only i2s and ac97. So far none of the SOC
CPUs have HDA.

>  > There would be one global fabric driver, but it would get called on a
>  > per instance basis. You could implement (made up scenarios)  two amps
>  > on the motherboard and only enough power to turn one of them on. Or
>  > maybe a front panel switch that switches which channel the front panel
>  > controls act on.
>  >
>  > I'd end up with this object model
>  >
>  > generic machine (optional machine specific fabric override)
>  >     platform i2s (platform_dai, soc_snd_card)
>  >         generic codec (choice of codec dai)
>  >     platform i2s (platform_dai, soc_snd_card)
>  >         generic codec (choice of codec dai)
>  >
>  > The platform specific i2s drivers are linked to a shared library of
>  > platform DMA code.
>  >
> Ok, I think I have a good idea of what you are proposing here.
>  The ASoC DMA is currently very much like a library in that it exports
>  it's ALSA PCM functions to the core (by registering itself) and whilst
>  the DMA functions are not directly called by client CPU DAI drivers they
>  are indirectly called on the client DAIs behalf by the ASoC core (in
>  response to ALSA core). This means we don't have to burden our DAI
>  drivers with CPU DMA specific calls.

You're missing the part I'm have trouble with. My company has four
board models that all use the same PCB but are populated differently .
The device tree for each different population model has a different
name so the kernel can tell exactly which hardware it is running on.

I'd like to have these drivers:
codec - generic driver for my codec chip
platform_dai - in my case an i2s driver, links to a private DMA
library, this code is generic to my SOC CPU
machine(fabric) - a driver that specifically handle this board's configuration.

I'd like for the fabric driver to be dynamically loaded by the device tree.

Given the way I'm looking at the problem, the current design is
inverted. With current code the machine driver is loaded, it then in
turn registers the cpu_dai and codec. This causes all of the common
registration code to end up in the machine driver. These drivers then
get copy/pasted for all of the different machine variants.

The root of my problem is that I want to handle my four board variants
with a single kernel. So when the kernel loads, I need to figure out
which board specific code to load. In the current ASOC design it is
assumed that this code is permanently linked in as a platform driver.

I need a slightly different boot sequence.

kernel boots
of_platform drivers load - this loads the i2s driver and the codec driver
in i2s probe it looks at the device tree and loads the right
machine(fabric) driver.
asoc_register hooks everything up

The current model works like this:
kernel boots
linked in platform drivers initialize - machine(fabric) driver
of_platform drivers load - this loads the i2s driver and the codec driver
i2s probe occurs
asoc_register hooks everything up
--- the machine(fabric) driver was determined at kernel compile time.

I can't make the machine(fabric) driver in to an of_platform driver
because there is no real hardware behind it. In older threads we
discussed creating a virtual OF device for it but
nobody liked the idea.

If I keep thinking about this sooner or later I'll come up with a boot
sequence that works.

>  Fwiw, I do think platform driver could really be better named to be more
>  function specific e.g. dma driver. I'm also considering a rename of
>  machine to fabric.
>  We also have CPU DAIs that are shared between different CPU
>  architectures (with different DMA). e.g. i.MX31 and FSL PPC share the
>  same SSI architecture - breaking the tightly coupled library model.

Nothing I propose stops this, there just isn't any requirement that
ASOC be aware that it is happing. struct snd_pcm_ops could hang off
from the cpu_dai.

Jon Smirl
jonsmirl at gmail.com

More information about the Alsa-devel mailing list