[alsa-devel] ASoC updates for 2.6.30
The following changes since commit ce3bdaa8710c10eec5a6dae67aaf73088d0ced4f: Mark Brown (1): ASoC: Disable WM8731 line bypass by default
are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound-2.6.git for-2.6.30
Mark Brown (7): ASoC: Report I/O errors from WM8753 reset ASoC: Only unregister drivers we registered for WM8753 ASoC: Improve WM9713 voice DAC shutdown procedure ASoC: Fix Zylonite voice interface stereo configurations ASoC: Shuffle WM8753 device registration code ASoC: Convert WM8753 to register via normal device probe ASoC: Only write back non-default registers when resuming WM8753
sound/soc/codecs/wm8753.c | 421 +++++++++++++++++------------------- sound/soc/codecs/wm8753.h | 6 - sound/soc/codecs/wm9713.c | 7 +- sound/soc/pxa/zylonite.c | 5 +- sound/soc/s3c24xx/neo1973_wm8753.c | 6 - 5 files changed, 210 insertions(+), 235 deletions(-)
Signed-off-by: Mark Brown broonie@opensource.wolfsonmicro.com --- sound/soc/codecs/wm8753.c | 6 +++++- 1 files changed, 5 insertions(+), 1 deletions(-)
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c index 31ff337..180ec94 100644 --- a/sound/soc/codecs/wm8753.c +++ b/sound/soc/codecs/wm8753.c @@ -1561,7 +1561,11 @@ static int wm8753_init(struct snd_soc_device *socdev)
wm8753_set_dai_mode(codec, 0);
- wm8753_reset(codec); + ret = wm8753_reset(codec); + if (ret < 0) { + printk(KERN_ERR "wm8753: failed to reset device\n"); + return ret; + }
/* register pcms */ ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
Signed-off-by: Mark Brown broonie@opensource.wolfsonmicro.com --- sound/soc/codecs/wm8753.c | 10 +++++++--- 1 files changed, 7 insertions(+), 3 deletions(-)
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c index 180ec94..93c22c4 100644 --- a/sound/soc/codecs/wm8753.c +++ b/sound/soc/codecs/wm8753.c @@ -1845,6 +1845,7 @@ static int wm8753_remove(struct platform_device *pdev) { struct snd_soc_device *socdev = platform_get_drvdata(pdev); struct snd_soc_codec *codec = socdev->card->codec; + struct wm8753_setup_data *setup = socdev->codec_data;
if (codec->control_data) wm8753_set_bias_level(codec, SND_SOC_BIAS_OFF); @@ -1852,11 +1853,14 @@ static int wm8753_remove(struct platform_device *pdev) snd_soc_free_pcms(socdev); snd_soc_dapm_free(socdev); #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) - i2c_unregister_device(codec->control_data); - i2c_del_driver(&wm8753_i2c_driver); + if (setup->i2c_address) { + i2c_unregister_device(codec->control_data); + i2c_del_driver(&wm8753_i2c_driver); + } #endif #if defined(CONFIG_SPI_MASTER) - spi_unregister_driver(&wm8753_spi_driver); + if (setup->spi) + spi_unregister_driver(&wm8753_spi_driver); #endif kfree(codec->private_data); kfree(codec);
Signed-off-by: Mark Brown broonie@opensource.wolfsonmicro.com --- sound/soc/codecs/wm9713.c | 7 ++++--- 1 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index 54db9c5..a93aea5 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c @@ -940,13 +940,14 @@ static void wm9713_voiceshutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct snd_soc_codec *codec = dai->codec; - u16 status; + u16 status, rate;
/* Gracefully shut down the voice interface. */ status = ac97_read(codec, AC97_EXTENDED_STATUS) | 0x1000; - ac97_write(codec, AC97_HANDSET_RATE, 0x0280); + rate = ac97_read(codec, AC97_HANDSET_RATE) & 0xF0FF; + ac97_write(codec, AC97_HANDSET_RATE, rate | 0x0200); schedule_timeout_interruptible(msecs_to_jiffies(1)); - ac97_write(codec, AC97_HANDSET_RATE, 0x0F80); + ac97_write(codec, AC97_HANDSET_RATE, rate | 0x0F00); ac97_write(codec, AC97_EXTENDED_MID, status); }
We always run in the first timeslot of one.
Signed-off-by: Mark Brown broonie@opensource.wolfsonmicro.com --- sound/soc/pxa/zylonite.c | 5 ++--- 1 files changed, 2 insertions(+), 3 deletions(-)
diff --git a/sound/soc/pxa/zylonite.c b/sound/soc/pxa/zylonite.c index ec2fb76..0140a25 100644 --- a/sound/soc/pxa/zylonite.c +++ b/sound/soc/pxa/zylonite.c @@ -127,9 +127,8 @@ static int zylonite_voice_hw_params(struct snd_pcm_substream *substream, if (ret < 0) return ret;
- ret = snd_soc_dai_set_tdm_slot(cpu_dai, - params_channels(params), - params_channels(params)); + /* We're not really in network mode but the emulation wants this. */ + ret = snd_soc_dai_set_tdm_slot(cpu_dai, 1, 1); if (ret < 0) return ret;
On Wed, Feb 25, 2009 at 10:48:19AM +0000, Mark Brown wrote:
We always run in the first timeslot of one.
I'm currently fiddling around with these bits in order to find a suitable configuration where the codec is master, so this is interesting. As the whole frame in I2S is 64 bits long and one FIFO entry has 32 bits of audio data - how can you only deal with one timeslot and still playback stereo?
Signed-off-by: Mark Brown broonie@opensource.wolfsonmicro.com
sound/soc/pxa/zylonite.c | 5 ++--- 1 files changed, 2 insertions(+), 3 deletions(-)
diff --git a/sound/soc/pxa/zylonite.c b/sound/soc/pxa/zylonite.c index ec2fb76..0140a25 100644 --- a/sound/soc/pxa/zylonite.c +++ b/sound/soc/pxa/zylonite.c @@ -127,9 +127,8 @@ static int zylonite_voice_hw_params(struct snd_pcm_substream *substream, if (ret < 0) return ret;
- ret = snd_soc_dai_set_tdm_slot(cpu_dai,
params_channels(params),
params_channels(params));
- /* We're not really in network mode but the emulation wants this. */
- ret = snd_soc_dai_set_tdm_slot(cpu_dai, 1, 1);
As you set SND_SOC_DAIFMT_I2S, the MOD bit in SSCR0 is set which means you are actually running in network mode, right?
This register really appears mazy to me - sorry if these are obvious things I missed.
Daniel
On Wed, Feb 25, 2009 at 05:06:17PM +0100, Daniel Mack wrote:
On Wed, Feb 25, 2009 at 10:48:19AM +0000, Mark Brown wrote:
We always run in the first timeslot of one.
I'm currently fiddling around with these bits in order to find a suitable configuration where the codec is master, so this is
Several people have reported problems in slave mode, unfortunately I've no hardware which allows me to do tests in slave mode so I'm a bit stuck there.
interesting. As the whole frame in I2S is 64 bits long and one FIFO entry has 32 bits of audio data - how can you only deal with one timeslot and still playback stereo?
The I2S frame length depends on the number of bits per sample.
As you set SND_SOC_DAIFMT_I2S, the MOD bit in SSCR0 is set which means you are actually running in network mode, right?
This register really appears mazy to me - sorry if these are obvious things I missed.
We are running in network mode without an actual network.
On Wed, Feb 25, 2009 at 04:22:42PM +0000, Mark Brown wrote:
On Wed, Feb 25, 2009 at 05:06:17PM +0100, Daniel Mack wrote:
I'm currently fiddling around with these bits in order to find a suitable configuration where the codec is master, so this is
Several people have reported problems in slave mode, unfortunately I've no hardware which allows me to do tests in slave mode so I'm a bit stuck there.
Is there a thread you can point me to or where have people reported such things? Grep'ing the archives did unveil anything regarding this.
interesting. As the whole frame in I2S is 64 bits long and one FIFO entry has 32 bits of audio data - how can you only deal with one timeslot and still playback stereo?
The I2S frame length depends on the number of bits per sample.
Well, as far as I got it, these are different things in the register set. The I2S frame is 64 bits per definition (32 bits for each channel), and this is what the cs4270 requires to use.
The particular problem with the PXA SSP mode is that I've not yet seen a configuration (neighter in slave nor in master mode) where it sends out 16 bits of left channel information, followed by 16 bits of zeros, then 16 bits of right channel and finally another 16bits of zeros (which exactly what they talk about in the 'i2s via ssp' application note). Has anyone ever got that?
Thanks, Daniel
On Wed, Feb 25, 2009 at 05:41:13PM +0100, Daniel Mack wrote:
Is there a thread you can point me to or where have people reported such things? Grep'ing the archives did unveil anything regarding this.
Private e-mail only, sorry.
The I2S frame length depends on the number of bits per sample.
Well, as far as I got it, these are different things in the register set. The I2S frame is 64 bits per definition (32 bits for each channel), and this is what the cs4270 requires to use.
Ah, that's not true of I2S devices in general - most only require as many bit clocks as they have data. I've only ever tested with such devices.
The particular problem with the PXA SSP mode is that I've not yet seen a configuration (neighter in slave nor in master mode) where it sends out 16 bits of left channel information, followed by 16 bits of zeros, then 16 bits of right channel and finally another 16bits of zeros (which exactly what they talk about in the 'i2s via ssp' application note). Has anyone ever got that?
Not to my knowledge.
On Wed, Feb 25, 2009 at 5:54 PM, Mark Brown broonie@sirena.org.uk wrote:
On Wed, Feb 25, 2009 at 05:41:13PM +0100, Daniel Mack wrote:
Is there a thread you can point me to or where have people reported such things? Grep'ing the archives did unveil anything regarding this.
Private e-mail only, sorry.
Seconded.
I've got a Philips UDA1380 codec with its digital input pins connected to a PXA272's SSP1 port. From the diagrams in the codec's datasheet, I'd expect it to understand I2S formats with anything >= 8 bits per channel. But when driving it with the current pxa-ssp code, I only ever get one channel output to both left and right speakers. Whether this is the left or the right channel depends on the frame clock polarity setting (SSPSP[SFRMP]).
The I2S frame length depends on the number of bits per sample.
Well, as far as I got it, these are different things in the register set. The I2S frame is 64 bits per definition (32 bits for each channel), and this is what the cs4270 requires to use.
Ah, that's not true of I2S devices in general - most only require as many bit clocks as they have data. I've only ever tested with such devices.
The particular problem with the PXA SSP mode is that I've not yet seen a configuration (neighter in slave nor in master mode) where it sends out 16 bits of left channel information, followed by 16 bits of zeros, then 16 bits of right channel and finally another 16bits of zeros (which exactly what they talk about in the 'i2s via ssp' application note). Has anyone ever got that?
Not to my knowledge.
I think I've tried to do this by setting network mode with four slots à 16 bit data width, with a SFRMWDTH of 32 and only the first and third slot active (SSTSA[TTSA] = 0x5). During the inactive slots, SSPTXD should be forced low, as long as SSPSP[ETDS] is not set. It didn't work out, but I'm not sure whether I've set up everything correctly. My whole understanding of this SSP busineess is rather cloudy.
Is that 'i2s via ssp' application note downloadable somewhere?
regards Philipp
On Thu, Feb 26, 2009 at 10:59:16AM +0100, pHilipp Zabel wrote:
The particular problem with the PXA SSP mode is that I've not yet seen a configuration (neighter in slave nor in master mode) where it sends out 16 bits of left channel information, followed by 16 bits of zeros, then 16 bits of right channel and finally another 16bits of zeros (which exactly what they talk about in the 'i2s via ssp' application note). Has anyone ever got that?
Not to my knowledge.
I think I've tried to do this by setting network mode with four slots à 16 bit data width, with a SFRMWDTH of 32 and only the first and third slot active (SSTSA[TTSA] = 0x5). During the inactive slots, SSPTXD should be forced low, as long as SSPSP[ETDS] is not set. It didn't work out, but I'm not sure whether I've set up everything correctly.
This is exactly how I understand the docs as well, so thanks for sharing this :)
My whole understanding of this SSP busineess is rather cloudy.
To me too, especially because the documents are faulty.
Is that 'i2s via ssp' application note downloadable somewhere?
Only if you signed an NDA with Marvell :-/
Daniel
This patch should be pure code motion, separating that out from the functional changes to move to new style device registration.
Signed-off-by: Mark Brown broonie@opensource.wolfsonmicro.com --- sound/soc/codecs/wm8753.c | 209 +++++++++++++++++++++++---------------------- 1 files changed, 105 insertions(+), 104 deletions(-)
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c index 93c22c4..4b42688 100644 --- a/sound/soc/codecs/wm8753.c +++ b/sound/soc/codecs/wm8753.c @@ -51,6 +51,11 @@
#include "wm8753.h"
+#ifdef CONFIG_SPI_MASTER +static struct spi_driver wm8753_spi_driver; +static int wm8753_spi_write(struct spi_device *spi, const char *data, int len); +#endif + static int caps_charge = 2000; module_param(caps_charge, int, 0); MODULE_PARM_DESC(caps_charge, "WM8753 cap charge time (msecs)"); @@ -1626,53 +1631,7 @@ pcm_err: static struct snd_soc_device *wm8753_socdev;
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) - -/* - * WM8753 2 wire address is determined by GPIO5 - * state during powerup. - * low = 0x1a - * high = 0x1b - */ - -static int wm8753_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) -{ - struct snd_soc_device *socdev = wm8753_socdev; - struct snd_soc_codec *codec = socdev->card->codec; - int ret; - - i2c_set_clientdata(i2c, codec); - codec->control_data = i2c; - - ret = wm8753_init(socdev); - if (ret < 0) - pr_err("failed to initialise WM8753\n"); - - return ret; -} - -static int wm8753_i2c_remove(struct i2c_client *client) -{ - struct snd_soc_codec *codec = i2c_get_clientdata(client); - kfree(codec->reg_cache); - return 0; -} - -static const struct i2c_device_id wm8753_i2c_id[] = { - { "wm8753", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, wm8753_i2c_id); - -static struct i2c_driver wm8753_i2c_driver = { - .driver = { - .name = "WM8753 I2C Codec", - .owner = THIS_MODULE, - }, - .probe = wm8753_i2c_probe, - .remove = wm8753_i2c_remove, - .id_table = wm8753_i2c_id, -}; +static struct i2c_driver wm8753_i2c_driver;
static int wm8753_add_i2c_device(struct platform_device *pdev, const struct wm8753_setup_data *setup) @@ -1715,63 +1674,6 @@ err_driver: } #endif
-#if defined(CONFIG_SPI_MASTER) -static int __devinit wm8753_spi_probe(struct spi_device *spi) -{ - struct snd_soc_device *socdev = wm8753_socdev; - struct snd_soc_codec *codec = socdev->card->codec; - int ret; - - codec->control_data = spi; - - ret = wm8753_init(socdev); - if (ret < 0) - dev_err(&spi->dev, "failed to initialise WM8753\n"); - - return ret; -} - -static int __devexit wm8753_spi_remove(struct spi_device *spi) -{ - return 0; -} - -static struct spi_driver wm8753_spi_driver = { - .driver = { - .name = "wm8753", - .bus = &spi_bus_type, - .owner = THIS_MODULE, - }, - .probe = wm8753_spi_probe, - .remove = __devexit_p(wm8753_spi_remove), -}; - -static int wm8753_spi_write(struct spi_device *spi, const char *data, int len) -{ - struct spi_transfer t; - struct spi_message m; - u8 msg[2]; - - if (len <= 0) - return 0; - - msg[0] = data[0]; - msg[1] = data[1]; - - spi_message_init(&m); - memset(&t, 0, (sizeof t)); - - t.tx_buf = &msg[0]; - t.len = len; - - spi_message_add_tail(&t, &m); - spi_sync(spi, &m); - - return len; -} -#endif - - static int wm8753_probe(struct platform_device *pdev) { struct snd_soc_device *socdev = platform_get_drvdata(pdev); @@ -1876,6 +1778,105 @@ struct snd_soc_codec_device soc_codec_dev_wm8753 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_wm8753);
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) + +static int wm8753_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct snd_soc_device *socdev = wm8753_socdev; + struct snd_soc_codec *codec = socdev->card->codec; + int ret; + + i2c_set_clientdata(i2c, codec); + codec->control_data = i2c; + + ret = wm8753_init(socdev); + if (ret < 0) + pr_err("failed to initialise WM8753\n"); + + return ret; +} + +static int wm8753_i2c_remove(struct i2c_client *client) +{ + struct snd_soc_codec *codec = i2c_get_clientdata(client); + kfree(codec->reg_cache); + return 0; +} + +static const struct i2c_device_id wm8753_i2c_id[] = { + { "wm8753", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, wm8753_i2c_id); + +static struct i2c_driver wm8753_i2c_driver = { + .driver = { + .name = "WM8753 I2C Codec", + .owner = THIS_MODULE, + }, + .probe = wm8753_i2c_probe, + .remove = wm8753_i2c_remove, + .id_table = wm8753_i2c_id, +}; +#endif + +#if defined(CONFIG_SPI_MASTER) +static int wm8753_spi_write(struct spi_device *spi, const char *data, int len) +{ + struct spi_transfer t; + struct spi_message m; + u8 msg[2]; + + if (len <= 0) + return 0; + + msg[0] = data[0]; + msg[1] = data[1]; + + spi_message_init(&m); + memset(&t, 0, (sizeof t)); + + t.tx_buf = &msg[0]; + t.len = len; + + spi_message_add_tail(&t, &m); + spi_sync(spi, &m); + + return len; +} + +static int __devinit wm8753_spi_probe(struct spi_device *spi) +{ + struct snd_soc_device *socdev = wm8753_socdev; + struct snd_soc_codec *codec = socdev->card->codec; + int ret; + + codec->control_data = spi; + + ret = wm8753_init(socdev); + if (ret < 0) + dev_err(&spi->dev, "failed to initialise WM8753\n"); + + return ret; +} + +static int __devexit wm8753_spi_remove(struct spi_device *spi) +{ + return 0; +} + +static struct spi_driver wm8753_spi_driver = { + .driver = { + .name = "wm8753", + .bus = &spi_bus_type, + .owner = THIS_MODULE, + }, + .probe = wm8753_spi_probe, + .remove = __devexit_p(wm8753_spi_remove), +}; +#endif + static int __init wm8753_modinit(void) { return snd_soc_register_dais(wm8753_dai, ARRAY_SIZE(wm8753_dai));
The base support for the only in-tree user, the GTA01, is out of tree and will be updated separately.
Signed-off-by: Mark Brown broonie@opensource.wolfsonmicro.com --- sound/soc/codecs/wm8753.c | 369 +++++++++++++++++------------------- sound/soc/codecs/wm8753.h | 6 - sound/soc/s3c24xx/neo1973_wm8753.c | 6 - 3 files changed, 171 insertions(+), 210 deletions(-)
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c index 4b42688..bc29558 100644 --- a/sound/soc/codecs/wm8753.c +++ b/sound/soc/codecs/wm8753.c @@ -63,12 +63,6 @@ MODULE_PARM_DESC(caps_charge, "WM8753 cap charge time (msecs)"); static void wm8753_set_dai_mode(struct snd_soc_codec *codec, unsigned int mode);
-/* codec private data */ -struct wm8753_priv { - unsigned int sysclk; - unsigned int pcmclk; -}; - /* * wm8753 register cache * We can't read the WM8753 register space when we @@ -93,6 +87,14 @@ static const u16 wm8753_reg[] = { 0x0000, 0x0000 };
+/* codec private data */ +struct wm8753_priv { + unsigned int sysclk; + unsigned int pcmclk; + struct snd_soc_codec codec; + u16 reg_cache[ARRAY_SIZE(wm8753_reg)]; +}; + /* * read wm8753 register cache */ @@ -1542,36 +1544,24 @@ static int wm8753_resume(struct platform_device *pdev) return 0; }
-/* - * initialise the WM8753 driver - * register the mixer and dsp interfaces with the kernel - */ -static int wm8753_init(struct snd_soc_device *socdev) +static struct snd_soc_codec *wm8753_codec; + +static int wm8753_probe(struct platform_device *pdev) { - struct snd_soc_codec *codec = socdev->card->codec; - int reg, ret = 0; + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec; + int ret = 0;
- codec->name = "WM8753"; - codec->owner = THIS_MODULE; - codec->read = wm8753_read_reg_cache; - codec->write = wm8753_write; - codec->set_bias_level = wm8753_set_bias_level; - codec->dai = wm8753_dai; - codec->num_dai = 2; - codec->reg_cache_size = ARRAY_SIZE(wm8753_reg); - codec->reg_cache = kmemdup(wm8753_reg, sizeof(wm8753_reg), GFP_KERNEL); + if (!wm8753_codec) { + dev_err(&pdev->dev, "WM8753 codec not yet registered\n"); + return -EINVAL; + }
- if (codec->reg_cache == NULL) - return -ENOMEM; + socdev->card->codec = wm8753_codec; + codec = wm8753_codec;
wm8753_set_dai_mode(codec, 0);
- ret = wm8753_reset(codec); - if (ret < 0) { - printk(KERN_ERR "wm8753: failed to reset device\n"); - return ret; - } - /* register pcms */ ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); if (ret < 0) { @@ -1579,36 +1569,7 @@ static int wm8753_init(struct snd_soc_device *socdev) goto pcm_err; }
- /* charge output caps */ - wm8753_set_bias_level(codec, SND_SOC_BIAS_PREPARE); - codec->bias_level = SND_SOC_BIAS_STANDBY; - schedule_delayed_work(&codec->delayed_work, - msecs_to_jiffies(caps_charge)); - - /* set the update bits */ - reg = wm8753_read_reg_cache(codec, WM8753_LDAC); - wm8753_write(codec, WM8753_LDAC, reg | 0x0100); - reg = wm8753_read_reg_cache(codec, WM8753_RDAC); - wm8753_write(codec, WM8753_RDAC, reg | 0x0100); - reg = wm8753_read_reg_cache(codec, WM8753_LADC); - wm8753_write(codec, WM8753_LADC, reg | 0x0100); - reg = wm8753_read_reg_cache(codec, WM8753_RADC); - wm8753_write(codec, WM8753_RADC, reg | 0x0100); - reg = wm8753_read_reg_cache(codec, WM8753_LOUT1V); - wm8753_write(codec, WM8753_LOUT1V, reg | 0x0100); - reg = wm8753_read_reg_cache(codec, WM8753_ROUT1V); - wm8753_write(codec, WM8753_ROUT1V, reg | 0x0100); - reg = wm8753_read_reg_cache(codec, WM8753_LOUT2V); - wm8753_write(codec, WM8753_LOUT2V, reg | 0x0100); - reg = wm8753_read_reg_cache(codec, WM8753_ROUT2V); - wm8753_write(codec, WM8753_ROUT2V, reg | 0x0100); - reg = wm8753_read_reg_cache(codec, WM8753_LINVOL); - wm8753_write(codec, WM8753_LINVOL, reg | 0x0100); - reg = wm8753_read_reg_cache(codec, WM8753_RINVOL); - wm8753_write(codec, WM8753_RINVOL, reg | 0x0100); - - snd_soc_add_controls(codec, wm8753_snd_controls, - ARRAY_SIZE(wm8753_snd_controls)); + wm8753_add_controls(codec); wm8753_add_widgets(codec); ret = snd_soc_init_card(socdev); if (ret < 0) { @@ -1616,110 +1577,13 @@ static int wm8753_init(struct snd_soc_device *socdev) goto card_err; }
- return ret; + return 0;
card_err: snd_soc_free_pcms(socdev); snd_soc_dapm_free(socdev); -pcm_err: - kfree(codec->reg_cache); - return ret; -} - -/* If the i2c layer weren't so broken, we could pass this kind of data - around */ -static struct snd_soc_device *wm8753_socdev; - -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) -static struct i2c_driver wm8753_i2c_driver; - -static int wm8753_add_i2c_device(struct platform_device *pdev, - const struct wm8753_setup_data *setup) -{ - struct i2c_board_info info; - struct i2c_adapter *adapter; - struct i2c_client *client; - int ret; - - ret = i2c_add_driver(&wm8753_i2c_driver); - if (ret != 0) { - dev_err(&pdev->dev, "can't add i2c driver\n"); - return ret; - } - - memset(&info, 0, sizeof(struct i2c_board_info)); - info.addr = setup->i2c_address; - strlcpy(info.type, "wm8753", I2C_NAME_SIZE); - - adapter = i2c_get_adapter(setup->i2c_bus); - if (!adapter) { - dev_err(&pdev->dev, "can't get i2c adapter %d\n", - setup->i2c_bus); - goto err_driver; - } - - client = i2c_new_device(adapter, &info); - i2c_put_adapter(adapter); - if (!client) { - dev_err(&pdev->dev, "can't add i2c device at 0x%x\n", - (unsigned int)info.addr); - goto err_driver; - } - - return 0; - -err_driver: - i2c_del_driver(&wm8753_i2c_driver); - return -ENODEV; -} -#endif - -static int wm8753_probe(struct platform_device *pdev) -{ - struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct wm8753_setup_data *setup; - struct snd_soc_codec *codec; - struct wm8753_priv *wm8753; - int ret = 0; - - setup = socdev->codec_data; - codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); - if (codec == NULL) - return -ENOMEM; - - wm8753 = kzalloc(sizeof(struct wm8753_priv), GFP_KERNEL); - if (wm8753 == NULL) { - kfree(codec); - return -ENOMEM; - } - - codec->private_data = wm8753; - socdev->card->codec = codec; - mutex_init(&codec->mutex); - INIT_LIST_HEAD(&codec->dapm_widgets); - INIT_LIST_HEAD(&codec->dapm_paths); - wm8753_socdev = socdev; - INIT_DELAYED_WORK(&codec->delayed_work, wm8753_work); - -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) - if (setup->i2c_address) { - codec->hw_write = (hw_write_t)i2c_master_send; - ret = wm8753_add_i2c_device(pdev, setup); - } -#endif -#if defined(CONFIG_SPI_MASTER) - if (setup->spi) { - codec->hw_write = (hw_write_t)wm8753_spi_write; - ret = spi_register_driver(&wm8753_spi_driver); - if (ret != 0) - printk(KERN_ERR "can't add spi driver"); - } -#endif
- if (ret != 0) { - kfree(codec->private_data); - kfree(codec); - } +pcm_err: return ret; }
@@ -1746,26 +1610,9 @@ static int run_delayed_work(struct delayed_work *dwork) static int wm8753_remove(struct platform_device *pdev) { struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_codec *codec = socdev->card->codec; - struct wm8753_setup_data *setup = socdev->codec_data;
- if (codec->control_data) - wm8753_set_bias_level(codec, SND_SOC_BIAS_OFF); - run_delayed_work(&codec->delayed_work); snd_soc_free_pcms(socdev); snd_soc_dapm_free(socdev); -#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) - if (setup->i2c_address) { - i2c_unregister_device(codec->control_data); - i2c_del_driver(&wm8753_i2c_driver); - } -#endif -#if defined(CONFIG_SPI_MASTER) - if (setup->spi) - spi_unregister_driver(&wm8753_spi_driver); -#endif - kfree(codec->private_data); - kfree(codec);
return 0; } @@ -1778,30 +1625,134 @@ struct snd_soc_codec_device soc_codec_dev_wm8753 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_wm8753);
+static int wm8753_register(struct wm8753_priv *wm8753) +{ + int ret, i; + struct snd_soc_codec *codec = &wm8753->codec; + u16 reg; + + if (wm8753_codec) { + dev_err(codec->dev, "Multiple WM8753 devices not supported\n"); + ret = -EINVAL; + goto err; + } + + mutex_init(&codec->mutex); + INIT_LIST_HEAD(&codec->dapm_widgets); + INIT_LIST_HEAD(&codec->dapm_paths); + + codec->name = "WM8753"; + codec->owner = THIS_MODULE; + codec->read = wm8753_read_reg_cache; + codec->write = wm8753_write; + codec->bias_level = SND_SOC_BIAS_STANDBY; + codec->set_bias_level = wm8753_set_bias_level; + codec->dai = wm8753_dai; + codec->num_dai = 2; + codec->reg_cache_size = ARRAY_SIZE(wm8753->reg_cache); + codec->reg_cache = &wm8753->reg_cache; + codec->private_data = wm8753; + + memcpy(codec->reg_cache, wm8753_reg, sizeof(codec->reg_cache)); + INIT_DELAYED_WORK(&codec->delayed_work, wm8753_work); + + ret = wm8753_reset(codec); + if (ret < 0) { + dev_err(codec->dev, "Failed to issue reset\n"); + goto err; + } + + /* charge output caps */ + wm8753_set_bias_level(codec, SND_SOC_BIAS_PREPARE); + schedule_delayed_work(&codec->delayed_work, + msecs_to_jiffies(caps_charge)); + + /* set the update bits */ + reg = wm8753_read_reg_cache(codec, WM8753_LDAC); + wm8753_write(codec, WM8753_LDAC, reg | 0x0100); + reg = wm8753_read_reg_cache(codec, WM8753_RDAC); + wm8753_write(codec, WM8753_RDAC, reg | 0x0100); + reg = wm8753_read_reg_cache(codec, WM8753_LADC); + wm8753_write(codec, WM8753_LADC, reg | 0x0100); + reg = wm8753_read_reg_cache(codec, WM8753_RADC); + wm8753_write(codec, WM8753_RADC, reg | 0x0100); + reg = wm8753_read_reg_cache(codec, WM8753_LOUT1V); + wm8753_write(codec, WM8753_LOUT1V, reg | 0x0100); + reg = wm8753_read_reg_cache(codec, WM8753_ROUT1V); + wm8753_write(codec, WM8753_ROUT1V, reg | 0x0100); + reg = wm8753_read_reg_cache(codec, WM8753_LOUT2V); + wm8753_write(codec, WM8753_LOUT2V, reg | 0x0100); + reg = wm8753_read_reg_cache(codec, WM8753_ROUT2V); + wm8753_write(codec, WM8753_ROUT2V, reg | 0x0100); + reg = wm8753_read_reg_cache(codec, WM8753_LINVOL); + wm8753_write(codec, WM8753_LINVOL, reg | 0x0100); + reg = wm8753_read_reg_cache(codec, WM8753_RINVOL); + wm8753_write(codec, WM8753_RINVOL, reg | 0x0100); + + wm8753_codec = codec; + + for (i = 0; i < ARRAY_SIZE(wm8753_dai); i++) + wm8753_dai[i].dev = codec->dev; + + ret = snd_soc_register_codec(codec); + if (ret != 0) { + dev_err(codec->dev, "Failed to register codec: %d\n", ret); + goto err; + } + + ret = snd_soc_register_dais(&wm8753_dai[0], ARRAY_SIZE(wm8753_dai)); + if (ret != 0) { + dev_err(codec->dev, "Failed to register DAIs: %d\n", ret); + goto err_codec; + } + + return 0; + +err_codec: + run_delayed_work(&codec->delayed_work); + snd_soc_unregister_codec(codec); +err: + kfree(wm8753); + return ret; +} + +static void wm8753_unregister(struct wm8753_priv *wm8753) +{ + wm8753_set_bias_level(&wm8753->codec, SND_SOC_BIAS_OFF); + run_delayed_work(&wm8753->codec.delayed_work); + snd_soc_unregister_dais(&wm8753_dai[0], ARRAY_SIZE(wm8753_dai)); + snd_soc_unregister_codec(&wm8753->codec); + kfree(wm8753); + wm8753_codec = NULL; +} + #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
static int wm8753_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { - struct snd_soc_device *socdev = wm8753_socdev; - struct snd_soc_codec *codec = socdev->card->codec; - int ret; + struct snd_soc_codec *codec; + struct wm8753_priv *wm8753;
- i2c_set_clientdata(i2c, codec); - codec->control_data = i2c; + wm8753 = kzalloc(sizeof(struct wm8753_priv), GFP_KERNEL); + if (wm8753 == NULL) + return -ENOMEM;
- ret = wm8753_init(socdev); - if (ret < 0) - pr_err("failed to initialise WM8753\n"); + codec = &wm8753->codec; + codec->hw_write = (hw_write_t)i2c_master_send; + codec->control_data = i2c; + i2c_set_clientdata(i2c, wm8753);
- return ret; + codec->dev = &i2c->dev; + + return wm8753_register(wm8753); }
static int wm8753_i2c_remove(struct i2c_client *client) { - struct snd_soc_codec *codec = i2c_get_clientdata(client); - kfree(codec->reg_cache); - return 0; + struct wm8753_priv *wm8753 = i2c_get_clientdata(client); + wm8753_unregister(wm8753); + return 0; }
static const struct i2c_device_id wm8753_i2c_id[] = { @@ -1812,7 +1763,7 @@ MODULE_DEVICE_TABLE(i2c, wm8753_i2c_id);
static struct i2c_driver wm8753_i2c_driver = { .driver = { - .name = "WM8753 I2C Codec", + .name = "wm8753", .owner = THIS_MODULE, }, .probe = wm8753_i2c_probe, @@ -1848,21 +1799,27 @@ static int wm8753_spi_write(struct spi_device *spi, const char *data, int len)
static int __devinit wm8753_spi_probe(struct spi_device *spi) { - struct snd_soc_device *socdev = wm8753_socdev; - struct snd_soc_codec *codec = socdev->card->codec; - int ret; + struct snd_soc_codec *codec; + struct wm8753_priv *wm8753; + + wm8753 = kzalloc(sizeof(struct wm8753_priv), GFP_KERNEL); + if (wm8753 == NULL) + return -ENOMEM;
+ codec = &wm8753->codec; codec->control_data = spi; + codec->hw_write = (hw_write_t)wm8753_spi_write; + codec->dev = &spi->dev;
- ret = wm8753_init(socdev); - if (ret < 0) - dev_err(&spi->dev, "failed to initialise WM8753\n"); + spi->dev.driver_data = wm8753;
- return ret; + return wm8753_register(wm8753); }
static int __devexit wm8753_spi_remove(struct spi_device *spi) { + struct wm8753_priv *wm8753 = spi->dev.driver_data; + wm8753_unregister(wm8753); return 0; }
@@ -1879,13 +1836,29 @@ static struct spi_driver wm8753_spi_driver = {
static int __init wm8753_modinit(void) { - return snd_soc_register_dais(wm8753_dai, ARRAY_SIZE(wm8753_dai)); + int ret; +#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) + ret = i2c_add_driver(&wm8753_i2c_driver); + if (ret != 0) + pr_err("Failed to register WM8753 I2C driver: %d\n", ret); +#endif +#if defined(CONFIG_SPI_MASTER) + ret = spi_register_driver(&wm8753_spi_driver); + if (ret != 0) + pr_err("Failed to register WM8753 SPI driver: %d\n", ret); +#endif + return 0; } module_init(wm8753_modinit);
static void __exit wm8753_exit(void) { - snd_soc_unregister_dais(wm8753_dai, ARRAY_SIZE(wm8753_dai)); +#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) + i2c_del_driver(&wm8753_i2c_driver); +#endif +#if defined(CONFIG_SPI_MASTER) + spi_unregister_driver(&wm8753_spi_driver); +#endif } module_exit(wm8753_exit);
diff --git a/sound/soc/codecs/wm8753.h b/sound/soc/codecs/wm8753.h index f55704c..57b2ba2 100644 --- a/sound/soc/codecs/wm8753.h +++ b/sound/soc/codecs/wm8753.h @@ -77,12 +77,6 @@ #define WM8753_BIASCTL 0x3d #define WM8753_ADCTL2 0x3f
-struct wm8753_setup_data { - int spi; - int i2c_bus; - unsigned short i2c_address; -}; - #define WM8753_PLL1 0 #define WM8753_PLL2 1
diff --git a/sound/soc/s3c24xx/neo1973_wm8753.c b/sound/soc/s3c24xx/neo1973_wm8753.c index 45bb12e..286e11a 100644 --- a/sound/soc/s3c24xx/neo1973_wm8753.c +++ b/sound/soc/s3c24xx/neo1973_wm8753.c @@ -585,15 +585,9 @@ static struct snd_soc_card neo1973 = { .num_links = ARRAY_SIZE(neo1973_dai), };
-static struct wm8753_setup_data neo1973_wm8753_setup = { - .i2c_bus = 0, - .i2c_address = 0x1a, -}; - static struct snd_soc_device neo1973_snd_devdata = { .card = &neo1973, .codec_dev = &soc_codec_dev_wm8753, - .codec_data = &neo1973_wm8753_setup, };
static int lm4857_i2c_probe(struct i2c_client *client,
This will reduce the number of writes done on resume, allowing that to complete faster (especially on systems with very slow I2C like the current Samsung driver).
Signed-off-by: Mark Brown broonie@opensource.wolfsonmicro.com --- sound/soc/codecs/wm8753.c | 5 +++++ 1 files changed, 5 insertions(+), 0 deletions(-)
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c index bc29558..2241204 100644 --- a/sound/soc/codecs/wm8753.c +++ b/sound/soc/codecs/wm8753.c @@ -1526,6 +1526,11 @@ static int wm8753_resume(struct platform_device *pdev) for (i = 0; i < ARRAY_SIZE(wm8753_reg); i++) { if (i + 1 == WM8753_RESET) continue; + + /* No point in writing hardware default values back */ + if (cache[i] == wm8753_reg[i]) + continue; + data[0] = ((i + 1) << 1) | ((cache[i] >> 8) & 0x0001); data[1] = cache[i] & 0x00ff; codec->hw_write(codec->control_data, data, 2);
At Wed, 25 Feb 2009 10:47:02 +0000, Mark Brown wrote:
The following changes since commit ce3bdaa8710c10eec5a6dae67aaf73088d0ced4f: Mark Brown (1): ASoC: Disable WM8731 line bypass by default
are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound-2.6.git for-2.6.30
Pulled now. Thanks!
Takashi
Mark Brown (7): ASoC: Report I/O errors from WM8753 reset ASoC: Only unregister drivers we registered for WM8753 ASoC: Improve WM9713 voice DAC shutdown procedure ASoC: Fix Zylonite voice interface stereo configurations ASoC: Shuffle WM8753 device registration code ASoC: Convert WM8753 to register via normal device probe ASoC: Only write back non-default registers when resuming WM8753
sound/soc/codecs/wm8753.c | 421 +++++++++++++++++------------------- sound/soc/codecs/wm8753.h | 6 - sound/soc/codecs/wm9713.c | 7 +- sound/soc/pxa/zylonite.c | 5 +- sound/soc/s3c24xx/neo1973_wm8753.c | 6 - 5 files changed, 210 insertions(+), 235 deletions(-)
participants (5)
-
Daniel Mack
-
Mark Brown
-
Mark Brown
-
pHilipp Zabel
-
Takashi Iwai