[alsa-devel] ASoC - Support for multiple components

Liam Girdwood lrg at slimlogic.co.uk
Mon Apr 19 18:25:14 CEST 2010


Hi Grant,

On Mon, 2010-04-19 at 09:15 -0600, Grant Likely wrote:
> On Mon, Apr 19, 2010 at 8:09 AM, Liam Girdwood <lrg at slimlogic.co.uk> wrote:
> > Currently ASoC is designed around a single CODEC and a single platform
> > DMA engine in every sound card instance. This is fine for most embedded
> > devices but current smart phone and STB designs are starting to outgrow
> > this architecture.
> >
> > I'm currently working on adding ASoC support for multiple different
> > CODECs and Platforms (DMA, Audio Engines) into a single sound card
> > instance. This work will allow ASoC to support N CODECs and N platforms
> > per sound card instance and also allow better integration of audio
> > components from GSM MODEMs, BT, FM transceivers and PCM DSPs.
> >
> > I've now split each ASoC component (i.e. DMA, CODEC, DAI) into driver
> > and device structures. This now means each ASoC component is a regular
> > kernel device and can have private device data and platform_data. It
> > should also provide better support for open firmware and flattened
> > device tree.
> >
> > I've CC'ed folks on this mail who have either contributed or maintain
> > ASoC architecture code. Please have a look at your architecture and test
> > if you can. I only have access to OMAP and pxa3xx hardware and as such
> > have only tested the changes on these two architectures only. I'd
> > appreciated anyone else testing on the other architectures too.
> >
> > The changes are all purely mechanical to component registration and
> > component private data only. However, some architectures (txx9, imx,
> > s3c) required some extra effort to use the device model as they had (to
> > varying degrees) coupled their DMA and DAI code more tightly. The fsl
> > platform also required extra work around the open firmware interface.
> > Grant/Timur do we still need soc-of-simple now that all components are
> > regular devices ?
> >
> > The code is in my topic/multi-component branch here :-
> >
> > git://git.kernel.org/pub/scm/linux/kernel/git/lrg/asoc-2.6.git
> 
> Hi Liam,
> 
> This is definitely a step in the right direction.  All of the OF ASoC
> stuff is definitely a hack to work around the lack of separate devices
> & drivers in the ASoC subsystem.  I'll take a look through, but some
> more information would help a lot.  Can you write a description of the
> device model that you're using for the ASoC linkage?  Here are some of
> the questions I have:
> 
> - What bus type is used for codec and platform (dai) device
> registrations?  (okay, 'platform' is really confusing here because of
> the dual meaning with Linux driver core.  I'm going to use 'dai' in
> this email instead from now on.  It might not be the best term, but it
> at least it isn't ambiguous.)

The ASoC 'bus' type hasn't changed with this patch. The fabric/machine
driver still describes how the audio card is configured.

> - What does the device hierarchy look like (what is the parent device
> for each of the codec and devices)?
> - Related to that, how are things like i2c codecs handled?  By rights,
> there will be an i2c device registered under the i2c bus device for
> the control interface.  How will this relate to the ASoC model?

I2C/SPI codecs can now register with the driver core as I2C/SPI drivers.
e.g. the I2C/SPI device probe registers the ASoC device :-

struct snd_soc_codec_driver soc_codec_dev_wm8731 = {
	.name = "WM8731",
	.probe = 	wm8731_probe,
	.remove = 	wm8731_remove,
	.suspend = 	wm8731_suspend,
	.resume =	wm8731_resume,
	.owner = THIS_MODULE,
	.set_bias_level = wm8731_set_bias_level,
	.reg_cache_size = sizeof(wm8731_reg),
	.reg_cache_default = wm8731_reg,
};
EXPORT_SYMBOL_GPL(soc_codec_dev_wm8731);

#if defined(CONFIG_SPI_MASTER)
static int __devinit wm8731_spi_probe(struct spi_device *spi)
{
	struct wm8731_priv *wm8731;
	int ret;

	wm8731 = kzalloc(sizeof(struct wm8731_priv), GFP_KERNEL);
	if (wm8731 == NULL)
		return -ENOMEM;

	wm8731->control_data = spi;
	wm8731->control_type = SND_SOC_SPI;
	spi_set_drvdata(spi, wm8731);

	ret = snd_soc_register_codec(&spi->dev, spi->chip_select,
			&soc_codec_dev_wm8731, &wm8731_dai, 1);
	if (ret < 0)
		kfree(wm8731);
	return ret;
}

static int __devexit wm8731_spi_remove(struct spi_device *spi)
{
	snd_soc_unregister_codec(&spi->dev, spi->chip_select);
	kfree(spi_get_drvdata(spi));
	return 0;
}

static struct spi_driver wm8731_spi_driver = {
	.driver = {
		.name	= "wm8731",
		.bus	= &spi_bus_type,
		.owner	= THIS_MODULE,
	},
	.probe		= wm8731_spi_probe,
	.remove		= __devexit_p(wm8731_spi_remove),
};
#endif /* CONFIG_SPI_MASTER */

#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
static __devinit int wm8731_i2c_probe(struct i2c_client *i2c,
				      const struct i2c_device_id *id)
{
	struct wm8731_priv *wm8731;
	int ret;

	wm8731 = kzalloc(sizeof(struct wm8731_priv), GFP_KERNEL);
	if (wm8731 == NULL)
		return -ENOMEM;

	i2c_set_clientdata(i2c, wm8731);
	wm8731->control_data = i2c;
	wm8731->control_type = SND_SOC_I2C;

	ret =  snd_soc_register_codec(&i2c->dev, i2c->addr,
			&soc_codec_dev_wm8731, &wm8731_dai, 1);
	if (ret < 0)
		kfree(wm8731);
	return ret;
}

static __devexit int wm8731_i2c_remove(struct i2c_client *client)
{
	snd_soc_unregister_codec(&client->dev, client->addr);
	kfree(i2c_get_clientdata(client));
	return 0;
}

static const struct i2c_device_id wm8731_i2c_id[] = {
	{ "wm8731", 0 },
	{ }
};
MODULE_DEVICE_TABLE(i2c, wm8731_i2c_id);

static struct i2c_driver wm8731_i2c_driver = {
	.driver = {
		.name = "WM8731 I2C Codec",
		.owner = THIS_MODULE,
	},
	.probe =    wm8731_i2c_probe,
	.remove =   __devexit_p(wm8731_i2c_remove),
	.id_table = wm8731_i2c_id,
};
#endif

static int __init wm8731_modinit(void)
{
	int ret = 0;
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
	ret = i2c_add_driver(&wm8731_i2c_driver);
	if (ret != 0) {
		printk(KERN_ERR "Failed to register WM8731 I2C driver: %d\n",
		       ret);
	}
#endif
#if defined(CONFIG_SPI_MASTER)
	ret = spi_register_driver(&wm8731_spi_driver);
	if (ret != 0) {
		printk(KERN_ERR "Failed to register WM8731 SPI driver: %d\n",
		       ret);
	}
#endif
	return ret;
}
module_init(wm8731_modinit);

static void __exit wm8731_exit(void)
{
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
	i2c_del_driver(&wm8731_i2c_driver);
#endif
#if defined(CONFIG_SPI_MASTER)
	spi_unregister_driver(&wm8731_spi_driver);
#endif
}
module_exit(wm8731_exit);

So the arch/board driver would register an I2C/SPI device for the codec
(with any platform data) and initiate the I2C/SPI codec probe(). This in
turn registers the ASoC component device with the ASoC core so it can be
asoc_probed() when it's sibling component devices are registered (the
last part is pretty much the same as the current version). The only
difference now is that our component is a core device and passes in it's
device upon ASoC component registration.

> - None of the drivers appear to include struct device_driver; which
> tells me that they don't use the driver core binding model.  How do
> drivers get bound to devices?  Why does the ASoC code create an driver
> interface instead of using the core code (what does the core code not
> provide)?

ASoC doesn't fully use the driver model for components in this changeset
(or at all) due to the complex relationships between the individual
components for probing() and for control of PM operations (i.e. we cant
have pops and clicks at suspend). 

This is not to say ASoC wont use the full driver model for components in
the future. This work is an important step on the way to achieving this
aim. 

> - What code is responsible for performing the codec and dai driver
> registrations?

Please see above WM8713 codec driver code snippet for full use.

int snd_soc_register_codec(struct device *dev, int id,
		struct snd_soc_codec_driver *codec_drv,
		struct snd_soc_dai_driver *dai_drv, int num_dai);
void snd_soc_unregister_codec(struct device *dev, int id);

Registers and unregisters our codec and DAI devices. It also registers
the codec and DAI ASoC 'driver' too.

Liam

-- 
Freelance Developer, SlimLogic Ltd
ASoC and Voltage Regulator Maintainer.
http://www.slimlogic.co.uk



More information about the Alsa-devel mailing list