[ALSA] Enable capture from line-in and CD on Revolution 5.1
[pandora-kernel.git] / sound / i2c / other / ak4xxx-adda.c
index 5da49e2..fe61b92 100644 (file)
@@ -513,6 +513,66 @@ static int ak4xxx_switch_put(struct snd_kcontrol *kcontrol,
        return change;
 }
 
+#define AK5365_NUM_INPUTS 5
+
+static int ak4xxx_capture_source_info(struct snd_kcontrol *kcontrol,
+                                     struct snd_ctl_elem_info *uinfo)
+{
+       struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
+       int mixer_ch = AK_GET_SHIFT(kcontrol->private_value);
+       const char **input_names;
+       int  num_names, idx;
+
+       input_names = ak->adc_info[mixer_ch].input_names;
+
+       num_names = 0;
+       while (num_names < AK5365_NUM_INPUTS && input_names[num_names])
+               ++num_names;
+       
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       uinfo->count = 1;
+       uinfo->value.enumerated.items = num_names;
+       idx = uinfo->value.enumerated.item;
+       if (idx >= num_names)
+               return -EINVAL;
+       strncpy(uinfo->value.enumerated.name, input_names[idx],
+               sizeof(uinfo->value.enumerated.name));
+       return 0;
+}
+
+static int ak4xxx_capture_source_get(struct snd_kcontrol *kcontrol,
+                                    struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
+       int chip = AK_GET_CHIP(kcontrol->private_value);
+       int addr = AK_GET_ADDR(kcontrol->private_value);
+       int mask = AK_GET_MASK(kcontrol->private_value);
+       unsigned char val;
+
+       val = snd_akm4xxx_get(ak, chip, addr) & mask;
+       ucontrol->value.enumerated.item[0] = val;
+       return 0;
+}
+
+static int ak4xxx_capture_source_put(struct snd_kcontrol *kcontrol,
+                                    struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
+       int chip = AK_GET_CHIP(kcontrol->private_value);
+       int addr = AK_GET_ADDR(kcontrol->private_value);
+       int mask = AK_GET_MASK(kcontrol->private_value);
+       unsigned char oval, val;
+
+       oval = snd_akm4xxx_get(ak, chip, addr);
+       val = oval & ~mask;
+       val |= ucontrol->value.enumerated.item[0] & mask;
+       if (val != oval) {
+               snd_akm4xxx_write(ak, chip, addr, val);
+               return 1;
+       }
+       return 0;
+}
+
 /*
  * build AK4xxx controls
  */
@@ -647,9 +707,10 @@ static int build_adc_controls(struct snd_akm4xxx *ak)
 
                if (ak->type == SND_AK5365 && (idx % 2) == 0) {
                        if (! ak->adc_info || 
-                           ! ak->adc_info[mixer_ch].switch_name)
+                           ! ak->adc_info[mixer_ch].switch_name) {
                                knew.name = "Capture Switch";
-                       else
+                               knew.index = mixer_ch + ak->idx_offset * 2;
+                       } else
                                knew.name = ak->adc_info[mixer_ch].switch_name;
                        knew.info = ak4xxx_switch_info;
                        knew.get = ak4xxx_switch_get;
@@ -662,6 +723,26 @@ static int build_adc_controls(struct snd_akm4xxx *ak)
                        err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
                        if (err < 0)
                                return err;
+
+                       memset(&knew, 0, sizeof(knew));
+                       knew.name = ak->adc_info[mixer_ch].selector_name;
+                       if (!knew.name) {
+                               knew.name = "Capture Channel";
+                               knew.index = mixer_ch + ak->idx_offset * 2;
+                       }
+
+                       knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+                       knew.info = ak4xxx_capture_source_info;
+                       knew.get = ak4xxx_capture_source_get;
+                       knew.put = ak4xxx_capture_source_put;
+                       knew.access = 0;
+                       /* input selector control: reg. 1, bits 0-2.
+                        * mis-use 'shift' to pass mixer_ch */
+                       knew.private_value
+                               = AK_COMPOSE(idx/2, 1, mixer_ch, 0x07);
+                       err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
+                       if (err < 0)
+                               return err;
                }
 
                idx += num_stereo;