summaryrefslogtreecommitdiffstats
path: root/sound/soc/codecs/wm8900.c
diff options
context:
space:
mode:
authorMark Brown <broonie@opensource.wolfsonmicro.com>2008-12-10 16:38:36 +0100
committerMark Brown <broonie@opensource.wolfsonmicro.com>2008-12-10 20:47:40 +0100
commit78e19a39d3985e2a06354493a70a200c0d432de5 (patch)
treef23c4a127696ccff5d378298790a53ccbb22ff61 /sound/soc/codecs/wm8900.c
parentASoC: Add codec registration API (diff)
downloadlinux-78e19a39d3985e2a06354493a70a200c0d432de5.tar.xz
linux-78e19a39d3985e2a06354493a70a200c0d432de5.zip
ASoC: Convert WM8900 to do more work at I2C probe time
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>
Diffstat (limited to 'sound/soc/codecs/wm8900.c')
-rw-r--r--sound/soc/codecs/wm8900.c159
1 files changed, 81 insertions, 78 deletions
diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c
index ebf58fba1beb..6767de10ded0 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;
}