[alsa-devel] Proposed changes to soc core to allow multiple codecs bound together on a single bus
Hi all, I finally got my multi-codec board up and running, but by hacking the codec driver in a very nasty way. It would be much preferable to modify the soc core so that multiple codecs can be easily instantiated on a single bus.
Problem overview ----------------------------- The problem is this: a single CPU DAI is connected to multiple codecs. Each codec is assigned a different TDM slot on the TDM bus. All codecs are bound together and expected to start at the same time and have the same clocks, etc.
Either the CPU or one of the codecs can be the master, all other devices are slaves. Each codec, as it transmits, must tri-state its output when not transmitting valid data, so that the other codecs may transmit in their given time slot.
I think from user-space, these codecs should really be bound pretty tightly together, so they may be opened as a single 'sound card' with the sum of the channels available. My card is an 8 codec (2 channel/codec) card, so it should appear as a 16-channel sound card that opens/closes all in one go.
Currently, I don't see a way in the soc core to handle this kind of situation. It seems that when you add multiple codecs onto one host DAI, you may only open one codec at a time. The others are not available.
There are a few variations on this general theme: * 1 cpu DAI, many codecs, all sharing the same data in and data out pins (TDM/network mode) (like the McBSP) * 1 cpu DAI, many codecs, but the cpu dai may have more than 1 data pin (like the McASP on TI parts). Shared clocks. * multiple cpu DAIs bound together on the same clocks, multiple codecs.
What is the proper way to add this functionality to the SOC API?
Perhaps a specification like this: static char *my_codec_dais[] = { "tlv320aic3x-hifi.0", <---- in this case, the '.0' "tlv320aic3x-hifi.1", ---- means that it's slot 0 "tlv320aic3x-hifi.2", ---- on the TDM bus. "tlv320aic3x-hifi.3", }; static char *my_codec_names[] = { "tlv320aic3x-codec.2-0018", <--- codec on i2c bus 2, addr 0x18 "tlv320aic3x-codec.2-0019", <--- codec on i2c bus 2, addr 0x19 "tlv320aic3x-codec.2-001a", <--- codec on i2c bus 2, addr 0x1a "tlv320aic3x-codec.2-001b", <--- codec on i2c bus 2, addr 0x1b }; static struct snd_soc_dai_link my_dai[] = { .name = "my_dai_name", .stream_name = "my_stream_name", .cpu_dai_name = "omap-mcbsp-dai.2", .platform_name= "omap-pcm_audio", .codec_dai_name = my_codec_dais, .num_codec = ARRAY_SIZE(my_codec_dais), .codec_name = my_codec_names, .ops = &my_ops, };
The core will parse the dai name for the slot order, and pass it on to the codec during hw_params. Then the codec can properly set the TDM slot on the hardware interface.
It will also pass the cpu dai the number of slices that are configured, so it knows how many slots to be expecting.
This means that the snd_soc_pcm_runtime, and probably a bunch of other places, will need to keep track of multiple codecs, and multiple dai's, and functions like 'hw_params' will need to loop through multiple codec_dai's, so each codec and cpu dai can be configured correctly.
I suspect this would be a pretty major change to the SOC core, and non-trivial.
Any thoughts on this, or if I'm totally barking up the wrong tree here?
Thanks, -Caleb
On 04/06/11 01:04, Caleb Crome wrote:
Hi all, I finally got my multi-codec board up and running, but by hacking the codec driver in a very nasty way. It would be much preferable to modify the soc core so that multiple codecs can be easily instantiated on a single bus.
Problem overview
The problem is this: a single CPU DAI is connected to multiple codecs. Each codec is assigned a different TDM slot on the TDM bus. All codecs are bound together and expected to start at the same time and have the same clocks, etc.
Either the CPU or one of the codecs can be the master, all other devices are slaves. Each codec, as it transmits, must tri-state its output when not transmitting valid data, so that the other codecs may transmit in their given time slot.
I think from user-space, these codecs should really be bound pretty tightly together, so they may be opened as a single 'sound card' with the sum of the channels available. My card is an 8 codec (2 channel/codec) card, so it should appear as a 16-channel sound card that opens/closes all in one go.
Currently, I don't see a way in the soc core to handle this kind of situation. It seems that when you add multiple codecs onto one host DAI, you may only open one codec at a time. The others are not available.
There are a few variations on this general theme:
- 1 cpu DAI, many codecs, all sharing the same data in and data out pins
(TDM/network mode) (like the McBSP)
- 1 cpu DAI, many codecs, but the cpu dai may have more than 1 data pin
(like the McASP on TI parts). Shared clocks.
- multiple cpu DAIs bound together on the same clocks, multiple codecs.
What is the proper way to add this functionality to the SOC API?
Perhaps a specification like this: static char *my_codec_dais[] = { "tlv320aic3x-hifi.0", <---- in this case, the '.0' "tlv320aic3x-hifi.1", ---- means that it's slot 0 "tlv320aic3x-hifi.2", ---- on the TDM bus. "tlv320aic3x-hifi.3", }; static char *my_codec_names[] = { "tlv320aic3x-codec.2-0018", <--- codec on i2c bus 2, addr 0x18 "tlv320aic3x-codec.2-0019", <--- codec on i2c bus 2, addr 0x19 "tlv320aic3x-codec.2-001a", <--- codec on i2c bus 2, addr 0x1a "tlv320aic3x-codec.2-001b", <--- codec on i2c bus 2, addr 0x1b }; static struct snd_soc_dai_link my_dai[] = { .name = "my_dai_name", .stream_name = "my_stream_name", .cpu_dai_name = "omap-mcbsp-dai.2", .platform_name= "omap-pcm_audio", .codec_dai_name = my_codec_dais, .num_codec = ARRAY_SIZE(my_codec_dais), .codec_name = my_codec_names, .ops = &my_ops, };
The core will parse the dai name for the slot order, and pass it on to the codec during hw_params. Then the codec can properly set the TDM slot on the hardware interface.
It will also pass the cpu dai the number of slices that are configured, so it knows how many slots to be expecting.
This means that the snd_soc_pcm_runtime, and probably a bunch of other places, will need to keep track of multiple codecs, and multiple dai's, and functions like 'hw_params' will need to loop through multiple codec_dai's, so each codec and cpu dai can be configured correctly.
I suspect this would be a pretty major change to the SOC core, and non-trivial.
Any thoughts on this, or if I'm totally barking up the wrong tree here?
Thanks, -Caleb
The ASoC DSP support I'm working on atm does something similar here. We take 1 frontend (FE) alsa PCM and can map multiple backend (BE) DAIs to it. The PCM operations are all synchronised for each DAI, i.e. calls to hw_params(), trigger() etc are called on each BE at the same time as the FE.
This could be used to perform the multiple calls to configure each of your codecs, I dont think there would be many changes required to do this.
The stable code is on my dsp branches here
git.kernel.org/pub/scm/git/linux/kernel/lrg/asoc-2.6.git
The WIP branch for upstreaming atm is here (will be rebased frequently)
https://gitorious.org/omap-audio/linux-audio
Thanks
Liam
On Fri, Jun 03, 2011 at 05:04:12PM -0700, Caleb Crome wrote:
static char *my_codec_dais[] = { "tlv320aic3x-hifi.0", <---- in this case, the '.0' "tlv320aic3x-hifi.1", ---- means that it's slot 0 "tlv320aic3x-hifi.2", ---- on the TDM bus. "tlv320aic3x-hifi.3", }; static char *my_codec_names[] = { "tlv320aic3x-codec.2-0018", <--- codec on i2c bus 2, addr 0x18 "tlv320aic3x-codec.2-0019", <--- codec on i2c bus 2, addr 0x19 "tlv320aic3x-codec.2-001a", <--- codec on i2c bus 2, addr 0x1a "tlv320aic3x-codec.2-001b", <--- codec on i2c bus 2, addr 0x1b };
I don't like the need to line the two arrays up, and the DAI names really ought to be enough anyway (this applies in general, not just here).
The core will parse the dai name for the slot order, and pass it on to the codec during hw_params. Then the codec can properly set the TDM slot on the hardware interface.
No, the machine driver needs to own the TDM configuration. We need to have the flexibiltiy for the system to use arbatrary arrangements for things like buses with more than two devices on them and we need to be able to cope with random layouts of the channels (for example, all the left channels on one device, all the right channels on another device). We also need to be able to change this dynamically at runtime depending on the current needs of the system.
Thanks for the feedback Liam and Mark.
I'll take a look at the PCM changes, that would be great if it'll work for my situation, because something similar to what i was thinking would require major changes (at least as far as my feble brain is concerned).
I've checked out Liam's PCM code base, but haven't taken a look yet -- since my driver's now more-or-less working, I'm actually testing out my board...
Thanks, -Caleb
On Mon, Jun 6, 2011 at 3:51 AM, Mark Brown < broonie@opensource.wolfsonmicro.com> wrote:
On Fri, Jun 03, 2011 at 05:04:12PM -0700, Caleb Crome wrote:
static char *my_codec_dais[] = { "tlv320aic3x-hifi.0", <---- in this case, the '.0' "tlv320aic3x-hifi.1", ---- means that it's slot 0 "tlv320aic3x-hifi.2", ---- on the TDM bus. "tlv320aic3x-hifi.3", }; static char *my_codec_names[] = { "tlv320aic3x-codec.2-0018", <--- codec on i2c bus 2, addr 0x18 "tlv320aic3x-codec.2-0019", <--- codec on i2c bus 2, addr 0x19 "tlv320aic3x-codec.2-001a", <--- codec on i2c bus 2, addr 0x1a "tlv320aic3x-codec.2-001b", <--- codec on i2c bus 2, addr 0x1b };
I don't like the need to line the two arrays up, and the DAI names really ought to be enough anyway (this applies in general, not just here).
The core will parse the dai name for the slot order, and pass it on to
the
codec during hw_params. Then the codec can properly set the TDM slot on
the
hardware interface.
No, the machine driver needs to own the TDM configuration. We need to have the flexibiltiy for the system to use arbatrary arrangements for things like buses with more than two devices on them and we need to be able to cope with random layouts of the channels (for example, all the left channels on one device, all the right channels on another device). We also need to be able to change this dynamically at runtime depending on the current needs of the system.
participants (3)
-
Caleb Crome
-
Liam Girdwood
-
Mark Brown