[alsa-devel] [PATCH] ASoC: Add WM8903 CODEC driver

Takashi Iwai tiwai at suse.de
Tue Aug 26 15:37:30 CEST 2008


At Tue, 26 Aug 2008 15:28:56 +0200,
Jean Delvare wrote:
> 
> Hi Mark,
> 
> On Tue, 26 Aug 2008 13:05:27 +0100, Mark Brown wrote:
> > The WM8903 is a high performance ultra-low power stereo CODEC optimised
> > for portable audio applications.  Features include:
> > 
> >     * 5mW power consumption for DAC to headphone playback
> >     * Stereo DAC SNR 96dB typical, THD -86dB typical
> >     * Stereo ADC SNR 93dB typical, THD -80dB typical
> >     * Up to 3 single ended inputs per stereo channel
> >     * Up to 2 pseudo differential inputs per stereo channel
> >     * Up to 1 fully differential mic input per stereo channel
> >     * Digital Dynamic Range Controller (compressor/limiter)
> >     * Digital sidetone mixing
> > 
> > Signed-off-by: Mark Brown <broonie at opensource.wolfsonmicro.com>
> > ---
> >  sound/soc/codecs/Kconfig  |    4 +
> >  sound/soc/codecs/Makefile |    2 +
> >  sound/soc/codecs/wm8903.c | 1813 +++++++++++++++++++++++++++++++++++++++++++++
> >  sound/soc/codecs/wm8903.h | 1463 ++++++++++++++++++++++++++++++++++++
> >  4 files changed, 3282 insertions(+), 0 deletions(-)
> >  create mode 100644 sound/soc/codecs/wm8903.c
> >  create mode 100644 sound/soc/codecs/wm8903.h
> 
> Here are minor issues I spotted in the i2c part of your driver:
> 
> > (...)
> > +static int wm8903_i2c_probe(struct i2c_client *i2c,
> > +			    const struct i2c_device_id *id)
> > +{
> > +	struct snd_soc_device *socdev = wm8903_socdev;
> > +	struct snd_soc_codec *codec = socdev->codec;
> > +	int ret;
> > +
> > +	i2c_set_clientdata(i2c, codec);
> > +	codec->control_data = i2c;
> > +
> > +	ret = wm8903_init(socdev);
> > +	if (ret < 0)
> > +		dev_err(&i2c->dev, "Device initialisation failed\n");
> > +
> > +	return ret;
> > +}
> > +
> > +static int wm8903_i2c_remove(struct i2c_client *client)
> > +{
> > +	struct snd_soc_codec *codec = i2c_get_clientdata(client);
> > +	kfree(codec->reg_cache);
> > +	return 0;
> > +}
> > +
> > +/* i2c codec control layer */
> > +static const struct i2c_device_id wm8903_i2c_id[] = {
> > +       { "wm8903", 0 },
> > +       { }
> > +};
> > +MODULE_DEVICE_TABLE(i2c, wm8903_i2c_id);
> > +
> > +static struct i2c_driver wm8903_i2c_driver = {
> > +	.driver = {
> > +		.name = "WM8903",
> > +		.owner = THIS_MODULE,
> > +	},
> > +	.probe    = wm8903_i2c_probe,
> > +	.remove   = wm8903_i2c_remove,
> > +	.id_table = wm8903_i2c_id,
> > +};
> > +
> > +static struct i2c_client *wm8903_i2c_device;
> 
> I know that I am the one who came up with this idea, but on second
> thought, wm8903_i2c_device will always be equal to
> wm8903_socdev->codec->control_data, so we can easily do without it.

Indeed.  It's a good cleanup.

> > +
> > +static int wm8903_probe(struct platform_device *pdev)
> > +{
> > +	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
> > +	struct wm8903_setup_data *setup;
> > +	struct snd_soc_codec *codec;
> > +	struct wm8903_priv *wm8903;
> > +	struct i2c_board_info board_info;
> > +	struct i2c_adapter *adapter;
> > +	int ret = 0;
> > +
> > +	setup = socdev->codec_data;
> > +
> > +	if (!setup->i2c_address) {
> > +		dev_err(&pdev->dev, "No codec address provided\n");
> > +		return -ENODEV;
> > +	}
> > +
> > +	codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
> > +	if (codec == NULL)
> > +		return -ENOMEM;
> > +
> > +	wm8903 = kzalloc(sizeof(struct wm8903_priv), GFP_KERNEL);
> > +	if (wm8903 == NULL) {
> > +		ret = -ENOMEM;
> > +		goto err_codec;
> > +	}
> > +
> > +	codec->private_data = wm8903;
> > +	socdev->codec = codec;
> > +	mutex_init(&codec->mutex);
> > +	INIT_LIST_HEAD(&codec->dapm_widgets);
> > +	INIT_LIST_HEAD(&codec->dapm_paths);
> > +
> > +	wm8903_socdev = socdev;
> > +
> > +	codec->hw_write = (hw_write_t)i2c_master_send;
> > +	ret = i2c_add_driver(&wm8903_i2c_driver);
> > +	if (ret != 0) {
> > +		dev_err(&pdev->dev, "can't add i2c driver");
> 
> Missing \n at end of string (looks like many other drivers have this
> problem - I found 11 other cases under sound/soc, I can send a patch
> fixing these if you want.)

It'd be appreciated.  If Mark didn't work on it yet, I'll merge them.

> > +		goto err_priv;
> > +	} else {
> > +		memset(&board_info, 0, sizeof(board_info));
> > +		strlcpy(board_info.type, "wm8903", I2C_NAME_SIZE);
> > +		board_info.addr = setup->i2c_address;
> > +
> > +		adapter = i2c_get_adapter(setup->i2c_bus);
> > +		if (!adapter) {
> > +			dev_err(&pdev->dev, "Can't get I2C bus %d\n",
> > +				setup->i2c_bus);
> > +			goto err_adapter;
> 
> You are jumping to the error path but ret has value 0. This means that
> the function returns success when you really mean failure, and trouble
> is likely to arise after that.

Good catch.

Mark, could you post a fix patch?  The original patch was already
merged, so I'd like to apply on it.


thanks,

Takashi


More information about the Alsa-devel mailing list