ASoC: Convert WM8900 to do more work at I2C probe time
[linux-2.6.git] / sound / soc / codecs / wm8900.c
index ebf58fb..6767de1 100644 (file)
 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;
 }