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>
This commit is contained in:
Mark Brown 2008-12-10 15:38:36 +00:00
parent 0d0cf00a7f
commit 78e19a39d3
2 changed files with 87 additions and 91 deletions

View file

@ -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;
}
/* Turn the chip on */
codec->bias_level = SND_SOC_BIAS_OFF;
wm8900_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
wm8900_add_controls(codec);
wm8900_add_widgets(codec);
ret = snd_soc_init_card(socdev);
if (ret < 0) {
dev_err(&i2c_client->dev, "Failed to register card\n");
goto card_err;
}
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);
wm8900_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(&wm8900_dai);
if (ret != 0) {
dev_err(&i2c->dev, "Failed to register DAI: %d\n", ret);
goto err_codec;
}
return ret;
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,45 +1424,46 @@ 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 = wm8900_init(socdev);
if (ret != 0)
kfree(codec);
ret = snd_soc_init_card(socdev);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to register card\n");
goto card_err;
}
return ret;
card_err:
snd_soc_free_pcms(socdev);
snd_soc_dapm_free(socdev);
pcm_err:
return ret;
}
/* power down chip */
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;
}

View file

@ -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;