ASoC: Fix Zylonite voice interface stereo configurations
[safe/jmp/linux-2.6] / sound / soc / soc-core.c
index 4d2db7c..d4b90d8 100644 (file)
@@ -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);
@@ -233,7 +234,7 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
                cpu_dai->capture.active = codec_dai->capture.active = 1;
        cpu_dai->active = codec_dai->active = 1;
        cpu_dai->runtime = runtime;
-       socdev->codec->active++;
+       card->codec->active++;
        mutex_unlock(&pcm_mutex);
        return 0;
 
@@ -263,7 +264,7 @@ static void close_delayed_work(struct work_struct *work)
        struct snd_soc_card *card = container_of(work, struct snd_soc_card,
                                                 delayed_work.work);
        struct snd_soc_device *socdev = card->socdev;
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = card->codec;
        struct snd_soc_dai *codec_dai;
        int i;
 
@@ -318,7 +319,7 @@ static int soc_codec_close(struct snd_pcm_substream *substream)
        struct snd_soc_platform *platform = card->platform;
        struct snd_soc_dai *cpu_dai = machine->cpu_dai;
        struct snd_soc_dai *codec_dai = machine->codec_dai;
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = card->codec;
 
        mutex_lock(&pcm_mutex);
 
@@ -386,7 +387,7 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream)
        struct snd_soc_platform *platform = card->platform;
        struct snd_soc_dai *cpu_dai = machine->cpu_dai;
        struct snd_soc_dai *codec_dai = machine->codec_dai;
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = card->codec;
        int ret = 0;
 
        mutex_lock(&pcm_mutex);
@@ -552,7 +553,7 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
        struct snd_soc_platform *platform = card->platform;
        struct snd_soc_dai *cpu_dai = machine->cpu_dai;
        struct snd_soc_dai *codec_dai = machine->codec_dai;
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = card->codec;
 
        mutex_lock(&pcm_mutex);
 
@@ -628,7 +629,7 @@ static int soc_suspend(struct platform_device *pdev, pm_message_t state)
        struct snd_soc_card *card = socdev->card;
        struct snd_soc_platform *platform = card->platform;
        struct snd_soc_codec_device *codec_dev = socdev->codec_dev;
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = card->codec;
        int i;
 
        /* Due to the resume being scheduled into a workqueue we could
@@ -704,7 +705,7 @@ static void soc_resume_deferred(struct work_struct *work)
        struct snd_soc_device *socdev = card->socdev;
        struct snd_soc_platform *platform = card->platform;
        struct snd_soc_codec_device *codec_dev = socdev->codec_dev;
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = card->codec;
        struct platform_device *pdev = to_platform_device(socdev->dev);
        int i;
 
@@ -981,8 +982,8 @@ static struct platform_driver soc_driver = {
 static int soc_new_pcm(struct snd_soc_device *socdev,
        struct snd_soc_dai_link *dai_link, int num)
 {
-       struct snd_soc_codec *codec = socdev->codec;
        struct snd_soc_card *card = socdev->card;
+       struct snd_soc_codec *codec = card->codec;
        struct snd_soc_platform *platform = card->platform;
        struct snd_soc_dai *codec_dai = dai_link->codec_dai;
        struct snd_soc_dai *cpu_dai = dai_link->cpu_dai;
@@ -997,7 +998,7 @@ static int soc_new_pcm(struct snd_soc_device *socdev,
 
        rtd->dai = dai_link;
        rtd->socdev = socdev;
-       codec_dai->codec = socdev->codec;
+       codec_dai->codec = card->codec;
 
        /* check client and interface hw capabilities */
        sprintf(new_name, "%s %s-%d", dai_link->stream_name, codec_dai->name,
@@ -1047,9 +1048,8 @@ static int soc_new_pcm(struct snd_soc_device *socdev,
 }
 
 /* codec register dump */
-static ssize_t soc_codec_reg_show(struct snd_soc_device *devdata, char *buf)
+static ssize_t soc_codec_reg_show(struct snd_soc_codec *codec, char *buf)
 {
-       struct snd_soc_codec *codec = devdata->codec;
        int i, step = 1, count = 0;
 
        if (!codec->reg_cache_size)
@@ -1089,7 +1089,7 @@ static ssize_t codec_reg_show(struct device *dev,
        struct device_attribute *attr, char *buf)
 {
        struct snd_soc_device *devdata = dev_get_drvdata(dev);
-       return soc_codec_reg_show(devdata, buf);
+       return soc_codec_reg_show(devdata->card->codec, buf);
 }
 
 static DEVICE_ATTR(codec_reg, 0444, codec_reg_show, NULL);
@@ -1106,12 +1106,10 @@ static ssize_t codec_reg_read_file(struct file *file, char __user *user_buf,
 {
        ssize_t ret;
        struct snd_soc_codec *codec = file->private_data;
-       struct device *card_dev = codec->card->dev;
-       struct snd_soc_device *devdata = card_dev->driver_data;
        char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
        if (!buf)
                return -ENOMEM;
-       ret = soc_codec_reg_show(devdata, buf);
+       ret = soc_codec_reg_show(codec, buf);
        if (ret >= 0)
                ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
        kfree(buf);
@@ -1299,6 +1297,8 @@ EXPORT_SYMBOL_GPL(snd_soc_test_bits);
 /**
  * snd_soc_new_pcms - create new sound card and pcms
  * @socdev: the SoC audio device
+ * @idx: ALSA card index
+ * @xid: card identification
  *
  * Create a new sound card based upon the codec and interface pcms.
  *
@@ -1306,19 +1306,19 @@ EXPORT_SYMBOL_GPL(snd_soc_test_bits);
  */
 int snd_soc_new_pcms(struct snd_soc_device *socdev, int idx, const char *xid)
 {
-       struct snd_soc_codec *codec = socdev->codec;
        struct snd_soc_card *card = socdev->card;
-       int ret = 0, i;
+       struct snd_soc_codec *codec = card->codec;
+       int ret, i;
 
        mutex_lock(&codec->mutex);
 
        /* register a sound card */
-       codec->card = snd_card_new(idx, xid, codec->owner, 0);
-       if (!codec->card) {
+       ret = snd_card_create(idx, xid, codec->owner, 0, &codec->card);
+       if (ret < 0) {
                printk(KERN_ERR "asoc: can't create sound card for codec %s\n",
                        codec->name);
                mutex_unlock(&codec->mutex);
-               return -ENODEV;
+               return ret;
        }
 
        codec->card->dev = socdev->dev;
@@ -1352,8 +1352,8 @@ EXPORT_SYMBOL_GPL(snd_soc_new_pcms);
  */
 int snd_soc_init_card(struct snd_soc_device *socdev)
 {
-       struct snd_soc_codec *codec = socdev->codec;
        struct snd_soc_card *card = socdev->card;
+       struct snd_soc_codec *codec = card->codec;
        int ret = 0, i, ac97 = 0, err = 0;
 
        for (i = 0; i < card->num_links; i++) {
@@ -1382,7 +1382,10 @@ int snd_soc_init_card(struct snd_soc_device *socdev)
 
        mutex_lock(&codec->mutex);
 #ifdef CONFIG_SND_SOC_AC97_BUS
-       if (ac97) {
+       /* Only instantiate AC97 if not already done by the adaptor
+        * for the generic AC97 subsystem.
+        */
+       if (ac97 && strcmp(codec->name, "AC97") != 0) {
                ret = soc_ac97_dev_register(codec);
                if (ret < 0) {
                        printk(KERN_ERR "asoc: AC97 device register failed\n");
@@ -1401,7 +1404,7 @@ int snd_soc_init_card(struct snd_soc_device *socdev)
        if (err < 0)
                printk(KERN_WARNING "asoc: failed to add codec sysfs files\n");
 
-       soc_init_codec_debugfs(socdev->codec);
+       soc_init_codec_debugfs(codec);
        mutex_unlock(&codec->mutex);
 
 out:
@@ -1418,14 +1421,14 @@ EXPORT_SYMBOL_GPL(snd_soc_init_card);
  */
 void snd_soc_free_pcms(struct snd_soc_device *socdev)
 {
-       struct snd_soc_codec *codec = socdev->codec;
+       struct snd_soc_codec *codec = socdev->card->codec;
 #ifdef CONFIG_SND_SOC_AC97_BUS
        struct snd_soc_dai *codec_dai;
        int i;
 #endif
 
        mutex_lock(&codec->mutex);
-       soc_cleanup_codec_debugfs(socdev->codec);
+       soc_cleanup_codec_debugfs(codec);
 #ifdef CONFIG_SND_SOC_AC97_BUS
        for (i = 0; i < codec->num_dai; i++) {
                codec_dai = &codec->dai[i];
@@ -1471,7 +1474,7 @@ EXPORT_SYMBOL_GPL(snd_soc_set_runtime_hwparams);
  * snd_soc_cnew - create new control
  * @_template: control template
  * @data: control private data
- * @lnng_name: control long name
+ * @long_name: control long name
  *
  * Create a new mixer control from a template control.
  *
@@ -1492,6 +1495,37 @@ struct snd_kcontrol *snd_soc_cnew(const struct snd_kcontrol_new *_template,
 EXPORT_SYMBOL_GPL(snd_soc_cnew);
 
 /**
+ * snd_soc_add_controls - add an array of controls to a codec.
+ * Convienience function to add a list of controls. Many codecs were
+ * duplicating this code.
+ *
+ * @codec: codec to add controls to
+ * @controls: array of controls to add
+ * @num_controls: number of elements in the array
+ *
+ * Return 0 for success, else error.
+ */
+int snd_soc_add_controls(struct snd_soc_codec *codec,
+       const struct snd_kcontrol_new *controls, int num_controls)
+{
+       struct snd_card *card = codec->card;
+       int err, i;
+
+       for (i = 0; i < num_controls; i++) {
+               const struct snd_kcontrol_new *control = &controls[i];
+               err = snd_ctl_add(card, snd_soc_cnew(control, codec, NULL));
+               if (err < 0) {
+                       dev_err(codec->dev, "%s: Failed to add %s\n",
+                               codec->name, control->name);
+                       return err;
+               }
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_add_controls);
+
+/**
  * snd_soc_info_enum_double - enumerated double mixer info callback
  * @kcontrol: mixer control
  * @uinfo: control element information
@@ -1521,7 +1555,7 @@ EXPORT_SYMBOL_GPL(snd_soc_info_enum_double);
 /**
  * snd_soc_get_enum_double - enumerated double mixer get callback
  * @kcontrol: mixer control
- * @uinfo: control element information
+ * @ucontrol: control element information
  *
  * Callback to get the value of a double enumerated mixer.
  *
@@ -1550,7 +1584,7 @@ EXPORT_SYMBOL_GPL(snd_soc_get_enum_double);
 /**
  * snd_soc_put_enum_double - enumerated double mixer put callback
  * @kcontrol: mixer control
- * @uinfo: control element information
+ * @ucontrol: control element information
  *
  * Callback to set the value of a double enumerated mixer.
  *
@@ -1582,6 +1616,80 @@ int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol,
 EXPORT_SYMBOL_GPL(snd_soc_put_enum_double);
 
 /**
+ * snd_soc_get_value_enum_double - semi enumerated double mixer get callback
+ * @kcontrol: mixer control
+ * @ucontrol: control element information
+ *
+ * Callback to get the value of a double semi enumerated mixer.
+ *
+ * Semi enumerated mixer: the enumerated items are referred as values. Can be
+ * used for handling bitfield coded enumeration for example.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_get_value_enum_double(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+       unsigned short reg_val, val, mux;
+
+       reg_val = snd_soc_read(codec, e->reg);
+       val = (reg_val >> e->shift_l) & e->mask;
+       for (mux = 0; mux < e->max; mux++) {
+               if (val == e->values[mux])
+                       break;
+       }
+       ucontrol->value.enumerated.item[0] = mux;
+       if (e->shift_l != e->shift_r) {
+               val = (reg_val >> e->shift_r) & e->mask;
+               for (mux = 0; mux < e->max; mux++) {
+                       if (val == e->values[mux])
+                               break;
+               }
+               ucontrol->value.enumerated.item[1] = mux;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_get_value_enum_double);
+
+/**
+ * snd_soc_put_value_enum_double - semi enumerated double mixer put callback
+ * @kcontrol: mixer control
+ * @ucontrol: control element information
+ *
+ * Callback to set the value of a double semi enumerated mixer.
+ *
+ * Semi enumerated mixer: the enumerated items are referred as values. Can be
+ * used for handling bitfield coded enumeration for example.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_put_value_enum_double(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+       unsigned short val;
+       unsigned short mask;
+
+       if (ucontrol->value.enumerated.item[0] > e->max - 1)
+               return -EINVAL;
+       val = e->values[ucontrol->value.enumerated.item[0]] << e->shift_l;
+       mask = e->mask << e->shift_l;
+       if (e->shift_l != e->shift_r) {
+               if (ucontrol->value.enumerated.item[1] > e->max - 1)
+                       return -EINVAL;
+               val |= e->values[ucontrol->value.enumerated.item[1]] << e->shift_r;
+               mask |= e->mask << e->shift_r;
+       }
+
+       return snd_soc_update_bits(codec, e->reg, mask, val);
+}
+EXPORT_SYMBOL_GPL(snd_soc_put_value_enum_double);
+
+/**
  * snd_soc_info_enum_ext - external enumerated single mixer info callback
  * @kcontrol: mixer control
  * @uinfo: control element information
@@ -1667,7 +1775,7 @@ EXPORT_SYMBOL_GPL(snd_soc_info_volsw);
 /**
  * snd_soc_get_volsw - single mixer get callback
  * @kcontrol: mixer control
- * @uinfo: control element information
+ * @ucontrol: control element information
  *
  * Callback to get the value of a single mixer control.
  *
@@ -1706,7 +1814,7 @@ EXPORT_SYMBOL_GPL(snd_soc_get_volsw);
 /**
  * snd_soc_put_volsw - single mixer put callback
  * @kcontrol: mixer control
- * @uinfo: control element information
+ * @ucontrol: control element information
  *
  * Callback to set the value of a single mixer control.
  *
@@ -1774,7 +1882,7 @@ EXPORT_SYMBOL_GPL(snd_soc_info_volsw_2r);
 /**
  * snd_soc_get_volsw_2r - double mixer get callback
  * @kcontrol: mixer control
- * @uinfo: control element information
+ * @ucontrol: control element information
  *
  * Callback to get the value of a double mixer control that spans 2 registers.
  *
@@ -1811,7 +1919,7 @@ EXPORT_SYMBOL_GPL(snd_soc_get_volsw_2r);
 /**
  * snd_soc_put_volsw_2r - double mixer set callback
  * @kcontrol: mixer control
- * @uinfo: control element information
+ * @ucontrol: control element information
  *
  * Callback to set the value of a double mixer control that spans 2 registers.
  *
@@ -1881,7 +1989,7 @@ EXPORT_SYMBOL_GPL(snd_soc_info_volsw_s8);
 /**
  * snd_soc_get_volsw_s8 - signed mixer get callback
  * @kcontrol: mixer control
- * @uinfo: control element information
+ * @ucontrol: control element information
  *
  * Callback to get the value of a signed mixer control.
  *
@@ -1908,7 +2016,7 @@ EXPORT_SYMBOL_GPL(snd_soc_get_volsw_s8);
 /**
  * snd_soc_put_volsw_sgn - signed mixer put callback
  * @kcontrol: mixer control
- * @uinfo: control element information
+ * @ucontrol: control element information
  *
  * Callback to set the value of a signed mixer control.
  *
@@ -1953,7 +2061,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_sysclk);
 /**
  * snd_soc_dai_set_clkdiv - configure DAI clock dividers.
  * @dai: DAI
- * @clk_id: DAI specific clock divider ID
+ * @div_id: DAI specific clock divider ID
  * @div: new clock divisor.
  *
  * Configures the clock dividers. This is used to derive the best DAI bit and
@@ -2059,7 +2167,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_digital_mute);
 /**
  * snd_soc_register_card - Register a card with the ASoC core
  *
- * @param card Card to register
+ * @card: Card to register
  *
  * Note that currently this is an internal only function: it will be
  * exposed to machine drivers after further backporting of ASoC v2
@@ -2086,7 +2194,7 @@ static int snd_soc_register_card(struct snd_soc_card *card)
 /**
  * snd_soc_unregister_card - Unregister a card with the ASoC core
  *
- * @param card Card to unregister
+ * @card: Card to unregister
  *
  * Note that currently this is an internal only function: it will be
  * exposed to machine drivers after further backporting of ASoC v2
@@ -2106,7 +2214,7 @@ static int snd_soc_unregister_card(struct snd_soc_card *card)
 /**
  * snd_soc_register_dai - Register a DAI with the ASoC core
  *
- * @param dai DAI to register
+ * @dai: DAI to register
  */
 int snd_soc_register_dai(struct snd_soc_dai *dai)
 {
@@ -2133,7 +2241,7 @@ EXPORT_SYMBOL_GPL(snd_soc_register_dai);
 /**
  * snd_soc_unregister_dai - Unregister a DAI from the ASoC core
  *
- * @param dai DAI to unregister
+ * @dai: DAI to unregister
  */
 void snd_soc_unregister_dai(struct snd_soc_dai *dai)
 {
@@ -2148,8 +2256,8 @@ EXPORT_SYMBOL_GPL(snd_soc_unregister_dai);
 /**
  * snd_soc_register_dais - Register multiple DAIs with the ASoC core
  *
- * @param dai Array of DAIs to register
- * @param count Number of DAIs
+ * @dai: Array of DAIs to register
+ * @count: Number of DAIs
  */
 int snd_soc_register_dais(struct snd_soc_dai *dai, size_t count)
 {
@@ -2174,8 +2282,8 @@ EXPORT_SYMBOL_GPL(snd_soc_register_dais);
 /**
  * snd_soc_unregister_dais - Unregister multiple DAIs from the ASoC core
  *
- * @param dai Array of DAIs to unregister
- * @param count Number of DAIs
+ * @dai: Array of DAIs to unregister
+ * @count: Number of DAIs
  */
 void snd_soc_unregister_dais(struct snd_soc_dai *dai, size_t count)
 {
@@ -2189,7 +2297,7 @@ EXPORT_SYMBOL_GPL(snd_soc_unregister_dais);
 /**
  * snd_soc_register_platform - Register a platform with the ASoC core
  *
- * @param platform platform to register
+ * @platform: platform to register
  */
 int snd_soc_register_platform(struct snd_soc_platform *platform)
 {
@@ -2212,7 +2320,7 @@ EXPORT_SYMBOL_GPL(snd_soc_register_platform);
 /**
  * snd_soc_unregister_platform - Unregister a platform from the ASoC core
  *
- * @param platform platform to unregister
+ * @platform: platform to unregister
  */
 void snd_soc_unregister_platform(struct snd_soc_platform *platform)
 {
@@ -2224,6 +2332,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
+ *
+ * @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
+ *
+ * @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