[alsa-devel] [PATCH 0/8] ASoC updates
The following changes since commit f73f2a6a23e34de9cca9672f727694e5af00e6c7: Takashi Iwai (1): ALSA: ASoC - Fix symbol conflicts in omac-mcbsp.c
are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound-2.6.git for-tiwai
Mark Brown (5): ASoC: Work around warnings from some build environments ASoC: Add codec registration API ASoC: Convert WM8900 to do more work at I2C probe time ASoC: Convert WM8903 driver to register at I2C probe time ASoC: Stop WM8903 SYSCLK when suspending
Peter Ujfalusi (3): ASoC: TWL4030: Add missing Carkit output ASoC: TWL4030: Small cleanup ASoC: TWL4030: Change the name for the DACs
include/sound/soc.h | 5 + sound/soc/codecs/twl4030.c | 27 +++--- sound/soc/codecs/wm8900.c | 159 +++++++++++++++-------------- sound/soc/codecs/wm8900.h | 7 -- sound/soc/codecs/wm8903.c | 241 +++++++++++++++++++------------------------- sound/soc/codecs/wm8903.h | 5 - sound/soc/soc-core.c | 43 ++++++++ 7 files changed, 247 insertions(+), 240 deletions(-)
BUG() should be marked as not returning but for at least some configurations (including some widely deployed compilers) that's either not happening or being forgotten by the compiler. Add some extra return statements to the affected paths.
Signed-off-by: Mark Brown broonie@opensource.wolfsonmicro.com --- sound/soc/codecs/wm8903.c | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index 0b5bea3..b1f5cf7 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -392,6 +392,7 @@ static int wm8903_output_event(struct snd_soc_dapm_widget *w, break; default: BUG(); + return -EINVAL; /* Spurious warning from some compilers */ }
switch (w->shift) { @@ -403,6 +404,7 @@ static int wm8903_output_event(struct snd_soc_dapm_widget *w, break; default: BUG(); + return -EINVAL; /* Spurious warning from some compilers */ }
if (event & SND_SOC_DAPM_PRE_PMU) {
From: Peter Ujfalusi peter.ujfalusi@nokia.com
SND_SOC_DAPM_OUTPUT definition for carkitL/R was missing.
Signed-off-by: Peter Ujfalusi peter.ujfalusi@nokia.com Signed-off-by: Mark Brown broonie@opensource.wolfsonmicro.com --- sound/soc/codecs/twl4030.c | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 71ab534..13d5a12 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -761,6 +761,8 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { SND_SOC_DAPM_OUTPUT("PREDRIVER"), SND_SOC_DAPM_OUTPUT("HSOL"), SND_SOC_DAPM_OUTPUT("HSOR"), + SND_SOC_DAPM_OUTPUT("CARKITL"), + SND_SOC_DAPM_OUTPUT("CARKITR"), SND_SOC_DAPM_OUTPUT("HFL"), SND_SOC_DAPM_OUTPUT("HFR"),
From: Peter Ujfalusi peter.ujfalusi@nokia.com
The mux switch related texts fits to on line, no need to wrap them.
Signed-off-by: Peter Ujfalusi peter.ujfalusi@nokia.com Signed-off-by: Mark Brown broonie@opensource.wolfsonmicro.com --- sound/soc/codecs/twl4030.c | 9 +++------ 1 files changed, 3 insertions(+), 6 deletions(-)
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 13d5a12..b321928 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -192,8 +192,7 @@ static void twl4030_init_chip(struct snd_soc_codec *codec)
/* Earpiece */ static const char *twl4030_earpiece_texts[] = - {"Off", "DACL1", "DACL2", "Invalid", - "DACR1"}; + {"Off", "DACL1", "DACL2", "Invalid", "DACR1"};
static const struct soc_enum twl4030_earpiece_enum = SOC_ENUM_SINGLE(TWL4030_REG_EAR_CTL, 1, @@ -205,8 +204,7 @@ SOC_DAPM_ENUM("Route", twl4030_earpiece_enum);
/* PreDrive Left */ static const char *twl4030_predrivel_texts[] = - {"Off", "DACL1", "DACL2", "Invalid", - "DACR2"}; + {"Off", "DACL1", "DACL2", "Invalid", "DACR2"};
static const struct soc_enum twl4030_predrivel_enum = SOC_ENUM_SINGLE(TWL4030_REG_PREDL_CTL, 1, @@ -218,8 +216,7 @@ SOC_DAPM_ENUM("Route", twl4030_predrivel_enum);
/* PreDrive Right */ static const char *twl4030_predriver_texts[] = - {"Off", "DACR1", "DACR2", "Invalid", - "DACL2"}; + {"Off", "DACR1", "DACR2", "Invalid", "DACL2"};
static const struct soc_enum twl4030_predriver_enum = SOC_ENUM_SINGLE(TWL4030_REG_PREDR_CTL, 1,
From: Peter Ujfalusi peter.ujfalusi@nokia.com
To avoid confusion the names for the DACs changed: DACL1 -> DAC Left1 ...
Signed-off-by: Peter Ujfalusi peter.ujfalusi@nokia.com Signed-off-by: Mark Brown broonie@opensource.wolfsonmicro.com --- sound/soc/codecs/twl4030.c | 16 ++++++++-------- 1 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index b321928..1377302 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -764,13 +764,13 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { SND_SOC_DAPM_OUTPUT("HFR"),
/* DACs */ - SND_SOC_DAPM_DAC("DACR1", "Right Front Playback", + SND_SOC_DAPM_DAC("DAC Right1", "Right Front Playback", TWL4030_REG_AVDAC_CTL, 0, 0), - SND_SOC_DAPM_DAC("DACL1", "Left Front Playback", + SND_SOC_DAPM_DAC("DAC Left1", "Left Front Playback", TWL4030_REG_AVDAC_CTL, 1, 0), - SND_SOC_DAPM_DAC("DACR2", "Right Rear Playback", + SND_SOC_DAPM_DAC("DAC Right2", "Right Rear Playback", TWL4030_REG_AVDAC_CTL, 2, 0), - SND_SOC_DAPM_DAC("DACL2", "Left Rear Playback", + SND_SOC_DAPM_DAC("DAC Left2", "Left Rear Playback", TWL4030_REG_AVDAC_CTL, 3, 0),
/* Analog PGAs */ @@ -816,10 +816,10 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { };
static const struct snd_soc_dapm_route intercon[] = { - {"ARXL1_APGA", NULL, "DACL1"}, - {"ARXR1_APGA", NULL, "DACR1"}, - {"ARXL2_APGA", NULL, "DACL2"}, - {"ARXR2_APGA", NULL, "DACR2"}, + {"ARXL1_APGA", NULL, "DAC Left1"}, + {"ARXR1_APGA", NULL, "DAC Right1"}, + {"ARXL2_APGA", NULL, "DAC Left2"}, + {"ARXR2_APGA", NULL, "DAC Right2"},
/* Internal playback routings */ /* Earpiece */
Another part of the backporting of Liam's ASoC v2 work. Using this is more complicated than the other registration types since currently the codec is instantiated during the probe of the ASoC device so we can't currently readily wait for the codec to register.
Signed-off-by: Mark Brown broonie@opensource.wolfsonmicro.com --- include/sound/soc.h | 5 +++++ sound/soc/soc-core.c | 43 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 0 deletions(-)
diff --git a/include/sound/soc.h b/include/sound/soc.h index ce3661d..f86e455 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -161,6 +161,8 @@ extern struct snd_ac97_bus_ops soc_ac97_ops;
int snd_soc_register_platform(struct snd_soc_platform *platform); void snd_soc_unregister_platform(struct snd_soc_platform *platform); +int snd_soc_register_codec(struct snd_soc_codec *codec); +void snd_soc_unregister_codec(struct snd_soc_codec *codec);
/* pcm <-> DAI connect */ void snd_soc_free_pcms(struct snd_soc_device *socdev); @@ -247,6 +249,9 @@ struct snd_soc_codec { char *name; struct module *owner; struct mutex mutex; + struct device *dev; + + struct list_head list;
/* callbacks */ int (*set_bias_level)(struct snd_soc_codec *, diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 4d2db7c..b098c0b 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -47,6 +47,7 @@ static DEFINE_MUTEX(client_mutex); static LIST_HEAD(card_list); static LIST_HEAD(dai_list); static LIST_HEAD(platform_list); +static LIST_HEAD(codec_list);
static int snd_soc_register_card(struct snd_soc_card *card); static int snd_soc_unregister_card(struct snd_soc_card *card); @@ -2224,6 +2225,48 @@ void snd_soc_unregister_platform(struct snd_soc_platform *platform) } EXPORT_SYMBOL_GPL(snd_soc_unregister_platform);
+/** + * snd_soc_register_codec - Register a codec with the ASoC core + * + * @param codec codec to register + */ +int snd_soc_register_codec(struct snd_soc_codec *codec) +{ + if (!codec->name) + return -EINVAL; + + /* The device should become mandatory over time */ + if (!codec->dev) + printk(KERN_WARNING "No device for codec %s\n", codec->name); + + INIT_LIST_HEAD(&codec->list); + + mutex_lock(&client_mutex); + list_add(&codec->list, &codec_list); + snd_soc_instantiate_cards(); + mutex_unlock(&client_mutex); + + pr_debug("Registered codec '%s'\n", codec->name); + + return 0; +} +EXPORT_SYMBOL_GPL(snd_soc_register_codec); + +/** + * snd_soc_unregister_codec - Unregister a codec from the ASoC core + * + * @param codec codec to unregister + */ +void snd_soc_unregister_codec(struct snd_soc_codec *codec) +{ + mutex_lock(&client_mutex); + list_del(&codec->list); + mutex_unlock(&client_mutex); + + pr_debug("Unregistered codec '%s'\n", codec->name); +} +EXPORT_SYMBOL_GPL(snd_soc_unregister_codec); + static int __init snd_soc_init(void) { #ifdef CONFIG_DEBUG_FS
Redo the instantiation of the WM8900 to do most of the initialisation work when the I2C driver probes rather than when the ASoC device is instantiated, registering the codec with the ASoC core when done.
Also move all dynamic allocations into a single kmalloc() to simplify error handling and rename the I2C driver to make output more sensible.
Signed-off-by: Mark Brown broonie@opensource.wolfsonmicro.com --- sound/soc/codecs/wm8900.c | 159 +++++++++++++++++++++++---------------------- sound/soc/codecs/wm8900.h | 7 -- 2 files changed, 81 insertions(+), 85 deletions(-)
diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c index ebf58fb..6767de1 100644 --- a/sound/soc/codecs/wm8900.c +++ b/sound/soc/codecs/wm8900.c @@ -138,6 +138,10 @@ struct snd_soc_codec_device soc_codec_dev_wm8900;
struct wm8900_priv { + struct snd_soc_codec codec; + + u16 reg_cache[WM8900_MAXREG]; + u32 fll_in; /* FLL input frequency */ u32 fll_out; /* FLL output frequency */ }; @@ -1282,16 +1286,28 @@ static int wm8900_resume(struct platform_device *pdev) return 0; }
-/* - * initialise the WM8900 driver - * register the mixer and dsp interfaces with the kernel - */ -static int wm8900_init(struct snd_soc_device *socdev) +static struct snd_soc_codec *wm8900_codec; + +static int wm8900_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) { - struct snd_soc_codec *codec = socdev->codec; - int ret = 0; + struct wm8900_priv *wm8900; + struct snd_soc_codec *codec; unsigned int reg; - struct i2c_client *i2c_client = socdev->codec->control_data; + int ret; + + wm8900 = kzalloc(sizeof(struct wm8900_priv), GFP_KERNEL); + if (wm8900 == NULL) + return -ENOMEM; + + codec = &wm8900->codec; + codec->private_data = wm8900; + codec->reg_cache = &wm8900->reg_cache[0]; + codec->reg_cache_size = WM8900_MAXREG; + + mutex_init(&codec->mutex); + INIT_LIST_HEAD(&codec->dapm_widgets); + INIT_LIST_HEAD(&codec->dapm_paths);
codec->name = "WM8900"; codec->owner = THIS_MODULE; @@ -1299,33 +1315,28 @@ static int wm8900_init(struct snd_soc_device *socdev) codec->write = wm8900_write; codec->dai = &wm8900_dai; codec->num_dai = 1; - codec->reg_cache_size = WM8900_MAXREG; - codec->reg_cache = kmemdup(wm8900_reg_defaults, - sizeof(wm8900_reg_defaults), GFP_KERNEL); - - if (codec->reg_cache == NULL) - return -ENOMEM; + codec->hw_write = (hw_write_t)i2c_master_send; + codec->control_data = i2c; + codec->set_bias_level = wm8900_set_bias_level; + codec->dev = &i2c->dev;
reg = wm8900_read(codec, WM8900_REG_ID); if (reg != 0x8900) { - dev_err(&i2c_client->dev, "Device is not a WM8900 - ID %x\n", - reg); - return -ENODEV; - } - - codec->private_data = kzalloc(sizeof(struct wm8900_priv), GFP_KERNEL); - if (codec->private_data == NULL) { - ret = -ENOMEM; - goto priv_err; + dev_err(&i2c->dev, "Device is not a WM8900 - ID %x\n", reg); + ret = -ENODEV; + goto err; }
/* Read back from the chip */ reg = wm8900_chip_read(codec, WM8900_REG_POWER1); reg = (reg >> 12) & 0xf; - dev_info(&i2c_client->dev, "WM8900 revision %d\n", reg); + dev_info(&i2c->dev, "WM8900 revision %d\n", reg);
wm8900_reset(codec);
+ /* Turn the chip on */ + wm8900_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + /* Latch the volume update bits */ wm8900_write(codec, WM8900_REG_LINVOL, wm8900_read(codec, WM8900_REG_LINVOL) | 0x100); @@ -1351,52 +1362,43 @@ static int wm8900_init(struct snd_soc_device *socdev) /* Set the DAC and mixer output bias */ wm8900_write(codec, WM8900_REG_OUTBIASCTL, 0x81);
- /* Register pcms */ - ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); - if (ret < 0) { - dev_err(&i2c_client->dev, "Failed to register new PCMs\n"); - goto pcm_err; - } + wm8900_dai.dev = &i2c->dev;
- /* Turn the chip on */ - codec->bias_level = SND_SOC_BIAS_OFF; - wm8900_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + wm8900_codec = codec;
- wm8900_add_controls(codec); - wm8900_add_widgets(codec); + ret = snd_soc_register_codec(codec); + if (ret != 0) { + dev_err(&i2c->dev, "Failed to register codec: %d\n", ret); + goto err; + }
- ret = snd_soc_init_card(socdev); - if (ret < 0) { - dev_err(&i2c_client->dev, "Failed to register card\n"); - goto card_err; + ret = snd_soc_register_dai(&wm8900_dai); + if (ret != 0) { + dev_err(&i2c->dev, "Failed to register DAI: %d\n", ret); + goto err_codec; } - return ret;
-card_err: - snd_soc_free_pcms(socdev); - snd_soc_dapm_free(socdev); -pcm_err: - kfree(codec->reg_cache); -priv_err: - kfree(codec->private_data); return ret; -} - -static struct i2c_client *wm8900_client;
-static int wm8900_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) -{ - wm8900_client = i2c; - wm8900_dai.dev = &i2c->dev; - return snd_soc_register_dai(&wm8900_dai); +err_codec: + snd_soc_unregister_codec(codec); +err: + kfree(wm8900); + wm8900_codec = NULL; + return ret; }
static int wm8900_i2c_remove(struct i2c_client *client) { snd_soc_unregister_dai(&wm8900_dai); + snd_soc_unregister_codec(wm8900_codec); + + wm8900_set_bias_level(wm8900_codec, SND_SOC_BIAS_OFF); + wm8900_dai.dev = NULL; - wm8900_client = NULL; + kfree(wm8900_codec->private_data); + wm8900_codec = NULL; + return 0; }
@@ -1408,7 +1410,7 @@ MODULE_DEVICE_TABLE(i2c, wm8900_i2c_id);
static struct i2c_driver wm8900_i2c_driver = { .driver = { - .name = "WM8900 I2C codec", + .name = "WM8900", .owner = THIS_MODULE, }, .probe = wm8900_i2c_probe, @@ -1422,30 +1424,36 @@ static int wm8900_probe(struct platform_device *pdev) struct snd_soc_codec *codec; int ret = 0;
- if (!wm8900_client) { + if (!wm8900_codec) { dev_err(&pdev->dev, "I2C client not yet instantiated\n"); return -ENODEV; }
- codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); - if (codec == NULL) - return -ENOMEM; - - mutex_init(&codec->mutex); - INIT_LIST_HEAD(&codec->dapm_widgets); - INIT_LIST_HEAD(&codec->dapm_paths); - + codec = wm8900_codec; socdev->codec = codec;
- codec->set_bias_level = wm8900_set_bias_level; + /* Register pcms */ + ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to register new PCMs\n"); + goto pcm_err; + }
- codec->hw_write = (hw_write_t)i2c_master_send; - codec->control_data = wm8900_client; + wm8900_add_controls(codec); + wm8900_add_widgets(codec); + + ret = snd_soc_init_card(socdev); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to register card\n"); + goto card_err; + }
- ret = wm8900_init(socdev); - if (ret != 0) - kfree(codec); + return ret;
+card_err: + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); +pcm_err: return ret; }
@@ -1453,14 +1461,9 @@ static int wm8900_probe(struct platform_device *pdev) static int wm8900_remove(struct platform_device *pdev) { struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_codec *codec = socdev->codec; - - if (codec->control_data) - wm8900_set_bias_level(codec, SND_SOC_BIAS_OFF);
snd_soc_free_pcms(socdev); snd_soc_dapm_free(socdev); - kfree(codec);
return 0; } diff --git a/sound/soc/codecs/wm8900.h b/sound/soc/codecs/wm8900.h index 2249a44..fd15007 100644 --- a/sound/soc/codecs/wm8900.h +++ b/sound/soc/codecs/wm8900.h @@ -52,13 +52,6 @@ #define WM8900_DAC_CLKDIV_5_5 0x14 #define WM8900_DAC_CLKDIV_6 0x18
-#define WM8900_ - -struct wm8900_setup_data { - int i2c_bus; - unsigned short i2c_address; -}; - extern struct snd_soc_dai wm8900_dai; extern struct snd_soc_codec_device soc_codec_dev_wm8900;
The driver now registers the codec and DAI when probed as an I2C device. Also convert the driver to use a single dynamic allocation to simplify error handling.
Signed-off-by: Mark Brown broonie@opensource.wolfsonmicro.com --- sound/soc/codecs/wm8903.c | 230 +++++++++++++++++++-------------------------- sound/soc/codecs/wm8903.h | 5 - 2 files changed, 97 insertions(+), 138 deletions(-)
diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index b1f5cf7..c80968f 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -33,19 +33,6 @@
#include "wm8903.h"
-struct wm8903_priv { - int sysclk; - - /* Reference counts */ - int charge_pump_users; - int class_w_users; - int playback_active; - int capture_active; - - struct snd_pcm_substream *master_substream; - struct snd_pcm_substream *slave_substream; -}; - /* Register defaults at reset */ static u16 wm8903_reg_defaults[] = { 0x8903, /* R0 - SW Reset and ID */ @@ -223,6 +210,23 @@ static u16 wm8903_reg_defaults[] = { 0x0000, /* R172 - Analogue Output Bias 0 */ };
+struct wm8903_priv { + struct snd_soc_codec codec; + u16 reg_cache[ARRAY_SIZE(wm8903_reg_defaults)]; + + int sysclk; + + /* Reference counts */ + int charge_pump_users; + int class_w_users; + int playback_active; + int capture_active; + + struct snd_pcm_substream *master_substream; + struct snd_pcm_substream *slave_substream; +}; + + static unsigned int wm8903_read_reg_cache(struct snd_soc_codec *codec, unsigned int reg) { @@ -360,6 +364,8 @@ static void wm8903_sync_reg_cache(struct snd_soc_codec *codec, u16 *cache) static void wm8903_reset(struct snd_soc_codec *codec) { wm8903_write(codec, WM8903_SW_RESET_AND_ID, 0); + memcpy(codec->reg_cache, wm8903_reg_defaults, + sizeof(wm8903_reg_defaults)); }
#define WM8903_OUTPUT_SHORT 0x8 @@ -1563,39 +1569,48 @@ static int wm8903_resume(struct platform_device *pdev) return 0; }
-/* - * initialise the WM8903 driver - * register the mixer and dsp interfaces with the kernel - */ -static int wm8903_init(struct snd_soc_device *socdev) +static struct snd_soc_codec *wm8903_codec; + +static int wm8903_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) { - struct snd_soc_codec *codec = socdev->codec; - struct i2c_client *i2c = codec->control_data; - int ret = 0; + struct wm8903_priv *wm8903; + struct snd_soc_codec *codec; + int ret; u16 val;
- val = wm8903_hw_read(codec, WM8903_SW_RESET_AND_ID); - if (val != wm8903_reg_defaults[WM8903_SW_RESET_AND_ID]) { - dev_err(&i2c->dev, - "Device with ID register %x is not a WM8903\n", val); - return -ENODEV; - } + wm8903 = kzalloc(sizeof(struct wm8903_priv), GFP_KERNEL); + if (wm8903 == NULL) + return -ENOMEM;
+ codec = &wm8903->codec; + + mutex_init(&codec->mutex); + INIT_LIST_HEAD(&codec->dapm_widgets); + INIT_LIST_HEAD(&codec->dapm_paths); + + codec->dev = &i2c->dev; codec->name = "WM8903"; codec->owner = THIS_MODULE; codec->read = wm8903_read; codec->write = wm8903_write; + codec->hw_write = (hw_write_t)i2c_master_send; codec->bias_level = SND_SOC_BIAS_OFF; codec->set_bias_level = wm8903_set_bias_level; codec->dai = &wm8903_dai; codec->num_dai = 1; - codec->reg_cache_size = ARRAY_SIZE(wm8903_reg_defaults); - codec->reg_cache = kmemdup(wm8903_reg_defaults, - sizeof(wm8903_reg_defaults), - GFP_KERNEL); - if (codec->reg_cache == NULL) { - dev_err(&i2c->dev, "Failed to allocate register cache\n"); - return -ENOMEM; + codec->reg_cache_size = ARRAY_SIZE(wm8903->reg_cache); + codec->reg_cache = &wm8903->reg_cache[0]; + codec->private_data = wm8903; + + i2c_set_clientdata(i2c, codec); + codec->control_data = i2c; + + val = wm8903_hw_read(codec, WM8903_SW_RESET_AND_ID); + if (val != wm8903_reg_defaults[WM8903_SW_RESET_AND_ID]) { + dev_err(&i2c->dev, + "Device with ID register %x is not a WM8903\n", val); + return -ENODEV; }
val = wm8903_read(codec, WM8903_REVISION_NUMBER); @@ -1604,13 +1619,6 @@ static int wm8903_init(struct snd_soc_device *socdev)
wm8903_reset(codec);
- /* register pcms */ - ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); - if (ret < 0) { - dev_err(&i2c->dev, "failed to create pcms\n"); - goto pcm_err; - } - /* SYSCLK is required for pretty much anything */ wm8903_write(codec, WM8903_CLOCK_RATES_2, WM8903_CLK_SYS_ENA);
@@ -1648,47 +1656,45 @@ static int wm8903_init(struct snd_soc_device *socdev) val |= WM8903_DAC_MUTEMODE; wm8903_write(codec, WM8903_DAC_DIGITAL_1, val);
- wm8903_add_controls(codec); - wm8903_add_widgets(codec); - ret = snd_soc_init_card(socdev); - if (ret < 0) { - dev_err(&i2c->dev, "wm8903: failed to register card\n"); - goto card_err; + wm8903_dai.dev = &i2c->dev; + wm8903_codec = codec; + + ret = snd_soc_register_codec(codec); + if (ret != 0) { + dev_err(&i2c->dev, "Failed to register codec: %d\n", ret); + goto err; + } + + ret = snd_soc_register_dai(&wm8903_dai); + if (ret != 0) { + dev_err(&i2c->dev, "Failed to register DAI: %d\n", ret); + goto err_codec; }
return ret;
-card_err: - snd_soc_free_pcms(socdev); - snd_soc_dapm_free(socdev); -pcm_err: - kfree(codec->reg_cache); +err_codec: + snd_soc_unregister_codec(codec); +err: + wm8903_codec = NULL; + kfree(wm8903); return ret; }
-static struct snd_soc_device *wm8903_socdev; - -static int wm8903_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static int wm8903_i2c_remove(struct i2c_client *client) { - struct snd_soc_device *socdev = wm8903_socdev; - struct snd_soc_codec *codec = socdev->codec; - int ret; + struct snd_soc_codec *codec = i2c_get_clientdata(client);
- i2c_set_clientdata(i2c, codec); - codec->control_data = i2c; + snd_soc_unregister_dai(&wm8903_dai); + snd_soc_unregister_codec(codec);
- ret = wm8903_init(socdev); - if (ret < 0) - dev_err(&i2c->dev, "Device initialisation failed\n"); + wm8903_set_bias_level(codec, SND_SOC_BIAS_OFF);
- return ret; -} + kfree(codec->private_data); + + wm8903_codec = NULL; + wm8903_dai.dev = NULL;
-static int wm8903_i2c_remove(struct i2c_client *client) -{ - struct snd_soc_codec *codec = i2c_get_clientdata(client); - kfree(codec->reg_cache); return 0; }
@@ -1712,75 +1718,37 @@ static struct i2c_driver wm8903_i2c_driver = { 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; - struct i2c_client *i2c_client; int ret = 0;
- setup = socdev->codec_data; - - if (!setup->i2c_address) { - dev_err(&pdev->dev, "No codec address provided\n"); - return -ENODEV; + if (!wm8903_codec) { + dev_err(&pdev->dev, "I2C device not yet probed\n"); + goto err; }
- codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); - if (codec == NULL) - return -ENOMEM; + socdev->codec = wm8903_codec;
- wm8903 = kzalloc(sizeof(struct wm8903_priv), GFP_KERNEL); - if (wm8903 == NULL) { - ret = -ENOMEM; - goto err_codec; + /* register pcms */ + ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); + if (ret < 0) { + dev_err(&pdev->dev, "failed to create pcms\n"); + goto err; }
- codec->private_data = wm8903; - socdev->codec = codec; - mutex_init(&codec->mutex); - INIT_LIST_HEAD(&codec->dapm_widgets); - INIT_LIST_HEAD(&codec->dapm_paths); + wm8903_add_controls(socdev->codec); + wm8903_add_widgets(socdev->codec);
- 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\n"); - 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); - ret = -ENODEV; - goto err_adapter; - } - - i2c_client = i2c_new_device(adapter, &board_info); - i2c_put_adapter(adapter); - if (i2c_client == NULL) { - dev_err(&pdev->dev, - "I2C driver registration failed\n"); - ret = -ENODEV; - goto err_adapter; - } + ret = snd_soc_init_card(socdev); + if (ret < 0) { + dev_err(&pdev->dev, "wm8903: failed to register card\n"); + goto card_err; }
return ret;
-err_adapter: - i2c_del_driver(&wm8903_i2c_driver); -err_priv: - kfree(codec->private_data); -err_codec: - kfree(codec); +card_err: + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); +err: return ret; }
@@ -1795,10 +1763,6 @@ static int wm8903_remove(struct platform_device *pdev)
snd_soc_free_pcms(socdev); snd_soc_dapm_free(socdev); - i2c_unregister_device(socdev->codec->control_data); - i2c_del_driver(&wm8903_i2c_driver); - kfree(codec->private_data); - kfree(codec);
return 0; } @@ -1813,13 +1777,13 @@ EXPORT_SYMBOL_GPL(soc_codec_dev_wm8903);
static int __init wm8903_modinit(void) { - return snd_soc_register_dai(&wm8903_dai); + return i2c_add_driver(&wm8903_i2c_driver); } module_init(wm8903_modinit);
static void __exit wm8903_exit(void) { - snd_soc_unregister_dai(&wm8903_dai); + i2c_del_driver(&wm8903_i2c_driver); } module_exit(wm8903_exit);
diff --git a/sound/soc/codecs/wm8903.h b/sound/soc/codecs/wm8903.h index cec622f..0ea27e2 100644 --- a/sound/soc/codecs/wm8903.h +++ b/sound/soc/codecs/wm8903.h @@ -18,11 +18,6 @@ extern struct snd_soc_dai wm8903_dai; extern struct snd_soc_codec_device soc_codec_dev_wm8903;
-struct wm8903_setup_data { - int i2c_bus; - int i2c_address; -}; - #define WM8903_MCLK_DIV_2 1 #define WM8903_CLK_SYS 2 #define WM8903_BCLK 3
This will save some additional power.
Signed-off-by: Mark Brown broonie@opensource.wolfsonmicro.com --- sound/soc/codecs/wm8903.c | 9 ++++++--- 1 files changed, 6 insertions(+), 3 deletions(-)
diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index c80968f..bde7454 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -997,6 +997,9 @@ static int wm8903_set_bias_level(struct snd_soc_codec *codec,
case SND_SOC_BIAS_STANDBY: if (codec->bias_level == SND_SOC_BIAS_OFF) { + wm8903_write(codec, WM8903_CLOCK_RATES_2, + WM8903_CLK_SYS_ENA); + wm8903_run_sequence(codec, 0); wm8903_sync_reg_cache(codec, codec->reg_cache);
@@ -1027,6 +1030,9 @@ static int wm8903_set_bias_level(struct snd_soc_codec *codec,
case SND_SOC_BIAS_OFF: wm8903_run_sequence(codec, 32); + reg = wm8903_read(codec, WM8903_CLOCK_RATES_2); + reg &= ~WM8903_CLK_SYS_ENA; + wm8903_write(codec, WM8903_CLOCK_RATES_2, reg); break; }
@@ -1619,9 +1625,6 @@ static int wm8903_i2c_probe(struct i2c_client *i2c,
wm8903_reset(codec);
- /* SYSCLK is required for pretty much anything */ - wm8903_write(codec, WM8903_CLOCK_RATES_2, WM8903_CLK_SYS_ENA); - /* power on device */ wm8903_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
At Wed, 10 Dec 2008 19:58:59 +0000, Mark Brown wrote:
The following changes since commit f73f2a6a23e34de9cca9672f727694e5af00e6c7: Takashi Iwai (1): ALSA: ASoC - Fix symbol conflicts in omac-mcbsp.c
are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound-2.6.git for-tiwai
Pulled now. Thanks.
Takashi
Mark Brown (5): ASoC: Work around warnings from some build environments ASoC: Add codec registration API ASoC: Convert WM8900 to do more work at I2C probe time ASoC: Convert WM8903 driver to register at I2C probe time ASoC: Stop WM8903 SYSCLK when suspending
Peter Ujfalusi (3): ASoC: TWL4030: Add missing Carkit output ASoC: TWL4030: Small cleanup ASoC: TWL4030: Change the name for the DACs
include/sound/soc.h | 5 + sound/soc/codecs/twl4030.c | 27 +++--- sound/soc/codecs/wm8900.c | 159 +++++++++++++++-------------- sound/soc/codecs/wm8900.h | 7 -- sound/soc/codecs/wm8903.c | 241 +++++++++++++++++++------------------------- sound/soc/codecs/wm8903.h | 5 - sound/soc/soc-core.c | 43 ++++++++ 7 files changed, 247 insertions(+), 240 deletions(-)
participants (2)
-
Mark Brown
-
Takashi Iwai