ASoC: multi-component - ASoC Multi-Component Support
[linux-flexiantxendom0-natty.git] / sound / soc / codecs / wm8776.c
index 4e212ed..51a2d26 100644 (file)
 
 #include "wm8776.h"
 
-static struct snd_soc_codec *wm8776_codec;
-struct snd_soc_codec_device soc_codec_dev_wm8776;
-
 /* codec private data */
 struct wm8776_priv {
-       struct snd_soc_codec codec;
+       enum snd_soc_control_type control_type;
+       void *control_data;
        u16 reg_cache[WM8776_CACHEREGNUM];
        int sysclk[2];
 };
 
-#ifdef CONFIG_SPI_MASTER
-static int wm8776_spi_write(struct spi_device *spi, const char *data, int len);
-#endif
-
 static const u16 wm8776_reg[WM8776_CACHEREGNUM] = {
        0x79, 0x79, 0x79, 0xff, 0xff,  /* 4 */
        0xff, 0x00, 0x90, 0x00, 0x00,  /* 9 */
@@ -144,7 +138,7 @@ static int wm8776_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
        struct snd_soc_codec *codec = dai->codec;
        int reg, iface, master;
 
-       switch (dai->id) {
+       switch (dai->driver->id) {
        case WM8776_DAI_DAC:
                reg = WM8776_DACIFCTRL;
                master = 0x80;
@@ -233,7 +227,7 @@ static int wm8776_hw_params(struct snd_pcm_substream *substream,
 
        iface = 0;
 
-       switch (dai->id) {
+       switch (dai->driver->id) {
        case WM8776_DAI_DAC:
                iface_reg = WM8776_DACIFCTRL;
                master = 0x80;
@@ -267,7 +261,7 @@ static int wm8776_hw_params(struct snd_pcm_substream *substream,
        /* Only need to set MCLK/LRCLK ratio if we're master */
        if (snd_soc_read(codec, WM8776_MSTRCTRL) & master) {
                for (i = 0; i < ARRAY_SIZE(mclk_ratios); i++) {
-                       if (wm8776->sysclk[dai->id] / params_rate(params)
+                       if (wm8776->sysclk[dai->driver->id] / params_rate(params)
                            == mclk_ratios[i])
                                break;
                }
@@ -275,7 +269,7 @@ static int wm8776_hw_params(struct snd_pcm_substream *substream,
                if (i == ARRAY_SIZE(mclk_ratios)) {
                        dev_err(codec->dev,
                                "Unable to configure MCLK ratio %d/%d\n",
-                               wm8776->sysclk[dai->id], params_rate(params));
+                               wm8776->sysclk[dai->driver->id], params_rate(params));
                        return -EINVAL;
                }
 
@@ -305,9 +299,9 @@ static int wm8776_set_sysclk(struct snd_soc_dai *dai,
        struct snd_soc_codec *codec = dai->codec;
        struct wm8776_priv *wm8776 = snd_soc_codec_get_drvdata(codec);
 
-       BUG_ON(dai->id >= ARRAY_SIZE(wm8776->sysclk));
+       BUG_ON(dai->driver->id >= ARRAY_SIZE(wm8776->sysclk));
 
-       wm8776->sysclk[dai->id] = freq;
+       wm8776->sysclk[dai->driver->id] = freq;
 
        return 0;
 }
@@ -357,10 +351,10 @@ static struct snd_soc_dai_ops wm8776_adc_ops = {
        .set_sysclk     = wm8776_set_sysclk,
 };
 
-struct snd_soc_dai wm8776_dai[] = {
+static struct snd_soc_dai_driver wm8776_dai[] = {
        {
-               .name = "WM8776 Playback",
-               .id = WM8776_DAI_DAC,
+               .name = "wm8776-hifi-playback",
+               .id     = WM8776_DAI_DAC,
                .playback = {
                        .stream_name = "Playback",
                        .channels_min = 2,
@@ -371,8 +365,8 @@ struct snd_soc_dai wm8776_dai[] = {
                .ops = &wm8776_dac_ops,
        },
        {
-               .name = "WM8776 Capture",
-               .id = WM8776_DAI_ADC,
+               .name = "wm8776-hifi-capture",
+               .id     = WM8776_DAI_ADC,
                .capture = {
                        .stream_name = "Capture",
                        .channels_min = 2,
@@ -383,23 +377,17 @@ struct snd_soc_dai wm8776_dai[] = {
                .ops = &wm8776_adc_ops,
        },
 };
-EXPORT_SYMBOL_GPL(wm8776_dai);
 
 #ifdef CONFIG_PM
-static int wm8776_suspend(struct platform_device *pdev, pm_message_t state)
+static int wm8776_suspend(struct snd_soc_codec *codec, pm_message_t state)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
-
        wm8776_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
        return 0;
 }
 
-static int wm8776_resume(struct platform_device *pdev)
+static int wm8776_resume(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec = socdev->card->codec;
        int i;
        u8 data[2];
        u16 *cache = codec->reg_cache;
@@ -422,27 +410,31 @@ static int wm8776_resume(struct platform_device *pdev)
 #define wm8776_resume NULL
 #endif
 
-static int wm8776_probe(struct platform_device *pdev)
+static int wm8776_probe(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-       struct snd_soc_codec *codec;
+       struct wm8776_priv *wm8776 = snd_soc_codec_get_drvdata(codec);
        int ret = 0;
 
-       if (wm8776_codec == NULL) {
-               dev_err(&pdev->dev, "Codec device not registered\n");
-               return -ENODEV;
+       codec->control_data = wm8776->control_data;
+       ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8776->control_type);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+               return ret;
        }
 
-       socdev->card->codec = wm8776_codec;
-       codec = wm8776_codec;
-
-       /* register pcms */
-       ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+       ret = wm8776_reset(codec);
        if (ret < 0) {
-               dev_err(codec->dev, "failed to create pcms: %d\n", ret);
-               goto pcm_err;
+               dev_err(codec->dev, "Failed to issue reset: %d\n", ret);
+               return ret;
        }
 
+       wm8776_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+       /* Latch the update bits; right channel only since we always
+        * update both. */
+       snd_soc_update_bits(codec, WM8776_HPRVOL, 0x100, 0x100);
+       snd_soc_update_bits(codec, WM8776_DACRVOL, 0x100, 0x100);
+
        snd_soc_add_controls(codec, wm8776_snd_controls,
                             ARRAY_SIZE(wm8776_snd_controls));
        snd_soc_dapm_new_controls(codec, wm8776_dapm_widgets,
@@ -450,168 +442,57 @@ static int wm8776_probe(struct platform_device *pdev)
        snd_soc_dapm_add_routes(codec, routes, ARRAY_SIZE(routes));
 
        return ret;
-
-pcm_err:
-       return ret;
 }
 
 /* power down chip */
-static int wm8776_remove(struct platform_device *pdev)
+static int wm8776_remove(struct snd_soc_codec *codec)
 {
-       struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
-       snd_soc_free_pcms(socdev);
-       snd_soc_dapm_free(socdev);
-
+       wm8776_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
 }
 
-struct snd_soc_codec_device soc_codec_dev_wm8776 = {
+static struct snd_soc_codec_driver soc_codec_dev_wm8776 = {
        .probe =        wm8776_probe,
        .remove =       wm8776_remove,
        .suspend =      wm8776_suspend,
        .resume =       wm8776_resume,
+       .set_bias_level = wm8776_set_bias_level,
+       .reg_cache_size = sizeof(wm8776_reg),
+       .reg_word_size = sizeof(u16),
+       .reg_cache_default = wm8776_reg,
 };
-EXPORT_SYMBOL_GPL(soc_codec_dev_wm8776);
-
-static int wm8776_register(struct wm8776_priv *wm8776,
-                          enum snd_soc_control_type control)
-{
-       int ret, i;
-       struct snd_soc_codec *codec = &wm8776->codec;
-
-       if (wm8776_codec) {
-               dev_err(codec->dev, "Another WM8776 is registered\n");
-               ret = -EINVAL;
-               goto err;
-       }
-
-       mutex_init(&codec->mutex);
-       INIT_LIST_HEAD(&codec->dapm_widgets);
-       INIT_LIST_HEAD(&codec->dapm_paths);
-
-       snd_soc_codec_set_drvdata(codec, wm8776);
-       codec->name = "WM8776";
-       codec->owner = THIS_MODULE;
-       codec->bias_level = SND_SOC_BIAS_OFF;
-       codec->set_bias_level = wm8776_set_bias_level;
-       codec->dai = wm8776_dai;
-       codec->num_dai = ARRAY_SIZE(wm8776_dai);
-       codec->reg_cache_size = WM8776_CACHEREGNUM;
-       codec->reg_cache = &wm8776->reg_cache;
-
-       memcpy(codec->reg_cache, wm8776_reg, sizeof(wm8776_reg));
-
-       ret = snd_soc_codec_set_cache_io(codec, 7, 9, control);
-       if (ret < 0) {
-               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
-               goto err;
-       }
-
-       for (i = 0; i < ARRAY_SIZE(wm8776_dai); i++)
-               wm8776_dai[i].dev = codec->dev;
-
-       ret = wm8776_reset(codec);
-       if (ret < 0) {
-               dev_err(codec->dev, "Failed to issue reset: %d\n", ret);
-               goto err;
-       }
-
-       wm8776_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
-       /* Latch the update bits; right channel only since we always
-        * update both. */
-       snd_soc_update_bits(codec, WM8776_HPRVOL, 0x100, 0x100);
-       snd_soc_update_bits(codec, WM8776_DACRVOL, 0x100, 0x100);
-
-       wm8776_codec = codec;
-
-       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(wm8776_dai, ARRAY_SIZE(wm8776_dai));
-       if (ret != 0) {
-               dev_err(codec->dev, "Failed to register DAIs: %d\n", ret);
-               goto err_codec;
-       }
-
-       return 0;
-
-err_codec:
-       snd_soc_unregister_codec(codec);
-err:
-       kfree(wm8776);
-       return ret;
-}
-
-static void wm8776_unregister(struct wm8776_priv *wm8776)
-{
-       wm8776_set_bias_level(&wm8776->codec, SND_SOC_BIAS_OFF);
-       snd_soc_unregister_dais(wm8776_dai, ARRAY_SIZE(wm8776_dai));
-       snd_soc_unregister_codec(&wm8776->codec);
-       kfree(wm8776);
-       wm8776_codec = NULL;
-}
 
 #if defined(CONFIG_SPI_MASTER)
-static int wm8776_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 wm8776_spi_probe(struct spi_device *spi)
 {
-       struct snd_soc_codec *codec;
        struct wm8776_priv *wm8776;
+       int ret;
 
        wm8776 = kzalloc(sizeof(struct wm8776_priv), GFP_KERNEL);
        if (wm8776 == NULL)
                return -ENOMEM;
 
-       codec = &wm8776->codec;
-       codec->control_data = spi;
-       codec->hw_write = (hw_write_t)wm8776_spi_write;
-       codec->dev = &spi->dev;
+       wm8776->control_data = spi;
+       wm8776->control_type = SND_SOC_SPI;
+       spi_set_drvdata(spi, wm8776);
 
-       dev_set_drvdata(&spi->dev, wm8776);
-
-       return wm8776_register(wm8776, SND_SOC_SPI);
+       ret = snd_soc_register_codec(&spi->dev,
+                       &soc_codec_dev_wm8776, wm8776_dai, ARRAY_SIZE(wm8776_dai));
+       if (ret < 0)
+               kfree(wm8776);
+       return ret;
 }
 
 static int __devexit wm8776_spi_remove(struct spi_device *spi)
 {
-       struct wm8776_priv *wm8776 = dev_get_drvdata(&spi->dev);
-
-       wm8776_unregister(wm8776);
-
+       snd_soc_unregister_codec(&spi->dev);
+       kfree(spi_get_drvdata(spi));
        return 0;
 }
 
 static struct spi_driver wm8776_spi_driver = {
        .driver = {
-               .name   = "wm8776",
+               .name   = "wm8776-codec",
                .bus    = &spi_bus_type,
                .owner  = THIS_MODULE,
        },
@@ -625,27 +506,27 @@ static __devinit int wm8776_i2c_probe(struct i2c_client *i2c,
                                      const struct i2c_device_id *id)
 {
        struct wm8776_priv *wm8776;
-       struct snd_soc_codec *codec;
+       int ret;
 
        wm8776 = kzalloc(sizeof(struct wm8776_priv), GFP_KERNEL);
        if (wm8776 == NULL)
                return -ENOMEM;
 
-       codec = &wm8776->codec;
-       codec->hw_write = (hw_write_t)i2c_master_send;
-
        i2c_set_clientdata(i2c, wm8776);
-       codec->control_data = i2c;
-
-       codec->dev = &i2c->dev;
+       wm8776->control_data = i2c;
+       wm8776->control_type = SND_SOC_I2C;
 
-       return wm8776_register(wm8776, SND_SOC_I2C);
+       ret =  snd_soc_register_codec(&i2c->dev,
+                       &soc_codec_dev_wm8776, wm8776_dai, ARRAY_SIZE(wm8776_dai));
+       if (ret < 0)
+               kfree(wm8776);
+       return ret;
 }
 
 static __devexit int wm8776_i2c_remove(struct i2c_client *client)
 {
-       struct wm8776_priv *wm8776 = i2c_get_clientdata(client);
-       wm8776_unregister(wm8776);
+       snd_soc_unregister_codec(&client->dev);
+       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
@@ -657,7 +538,7 @@ MODULE_DEVICE_TABLE(i2c, wm8776_i2c_id);
 
 static struct i2c_driver wm8776_i2c_driver = {
        .driver = {
-               .name = "wm8776",
+               .name = "wm8776-codec",
                .owner = THIS_MODULE,
        },
        .probe =    wm8776_i2c_probe,
@@ -668,22 +549,22 @@ static struct i2c_driver wm8776_i2c_driver = {
 
 static int __init wm8776_modinit(void)
 {
-       int ret;
+       int ret = 0;
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
        ret = i2c_add_driver(&wm8776_i2c_driver);
        if (ret != 0) {
-               printk(KERN_ERR "Failed to register WM8776 I2C driver: %d\n",
+               printk(KERN_ERR "Failed to register wm8776 I2C driver: %d\n",
                       ret);
        }
 #endif
 #if defined(CONFIG_SPI_MASTER)
        ret = spi_register_driver(&wm8776_spi_driver);
        if (ret != 0) {
-               printk(KERN_ERR "Failed to register WM8776 SPI driver: %d\n",
+               printk(KERN_ERR "Failed to register wm8776 SPI driver: %d\n",
                       ret);
        }
 #endif
-       return 0;
+       return ret;
 }
 module_init(wm8776_modinit);