Merge branch 'fix/usb-audio' into for-linus
[safe/jmp/linux-2.6] / sound / soc / soc-core.c
index f73c134..ec3f8bb 100644 (file)
@@ -1385,7 +1385,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");
@@ -1585,6 +1588,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