ALSA: oxygen: add S/PDIF source selection for Claro cards
authorClemens Ladisch <clemens@ladisch.de>
Tue, 11 Jan 2011 09:35:29 +0000 (10:35 +0100)
committerTakashi Iwai <tiwai@suse.de>
Tue, 11 Jan 2011 16:54:15 +0000 (17:54 +0100)
Add a mixer control to switch between the optical and coaxial S/PDIF
inputs on the HT-Omega Claro and Claro halo cards.

Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
Signed-off-by: Takashi Iwai <tiwai@suse.de>

sound/pci/oxygen/oxygen.c

index db39cfc..d7e8ddd 100644 (file)
@@ -34,6 +34,7 @@
  *   GPIO 6 -> enable on-board S/PDIF input
  *
  * Claro models:
+ *   GPIO 6 -> S/PDIF from optical (0) or coaxial (1) input
  *   GPIO 8 -> enable headphone amplifier
  *
  * CM9780:
@@ -137,6 +138,7 @@ MODULE_DEVICE_TABLE(pci, oxygen_ids);
 #define GPIO_MERIDIAN_DIG_EXT  0x0010
 #define GPIO_MERIDIAN_DIG_BOARD        0x0040
 
+#define GPIO_CLARO_DIG_COAX    0x0040
 #define GPIO_CLARO_HP          0x0100
 
 struct generic_data {
@@ -268,6 +270,8 @@ static void claro_enable_hp(struct oxygen *chip)
 
 static void claro_init(struct oxygen *chip)
 {
+       oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_CLARO_DIG_COAX);
+       oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_CLARO_DIG_COAX);
        ak4396_init(chip);
        wm8785_init(chip);
        claro_enable_hp(chip);
@@ -275,6 +279,8 @@ static void claro_init(struct oxygen *chip)
 
 static void claro_halo_init(struct oxygen *chip)
 {
+       oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_CLARO_DIG_COAX);
+       oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_CLARO_DIG_COAX);
        ak4396_init(chip);
        ak5385_init(chip);
        claro_enable_hp(chip);
@@ -523,14 +529,24 @@ static const struct snd_kcontrol_new hpf_control = {
        .put = hpf_put,
 };
 
-static int meridian_dig_source_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info)
+static int meridian_dig_source_info(struct snd_kcontrol *ctl,
+                                   struct snd_ctl_elem_info *info)
 {
        static const char *const names[2] = { "On-board", "Extension" };
 
        return snd_ctl_enum_info(info, 1, 2, names);
 }
 
-static int meridian_dig_source_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
+static int claro_dig_source_info(struct snd_kcontrol *ctl,
+                                struct snd_ctl_elem_info *info)
+{
+       static const char *const names[2] = { "Optical", "Coaxial" };
+
+       return snd_ctl_enum_info(info, 1, 2, names);
+}
+
+static int meridian_dig_source_get(struct snd_kcontrol *ctl,
+                                  struct snd_ctl_elem_value *value)
 {
        struct oxygen *chip = ctl->private_data;
 
@@ -540,7 +556,19 @@ static int meridian_dig_source_get(struct snd_kcontrol *ctl, struct snd_ctl_elem
        return 0;
 }
 
-static int meridian_dig_source_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
+static int claro_dig_source_get(struct snd_kcontrol *ctl,
+                               struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+
+       value->value.enumerated.item[0] =
+               !!(oxygen_read16(chip, OXYGEN_GPIO_DATA) &
+                  GPIO_CLARO_DIG_COAX);
+       return 0;
+}
+
+static int meridian_dig_source_put(struct snd_kcontrol *ctl,
+                                  struct snd_ctl_elem_value *value)
 {
        struct oxygen *chip = ctl->private_data;
        u16 old_reg, new_reg;
@@ -560,6 +588,25 @@ static int meridian_dig_source_put(struct snd_kcontrol *ctl, struct snd_ctl_elem
        return changed;
 }
 
+static int claro_dig_source_put(struct snd_kcontrol *ctl,
+                               struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+       u16 old_reg, new_reg;
+       int changed;
+
+       mutex_lock(&chip->mutex);
+       old_reg = oxygen_read16(chip, OXYGEN_GPIO_DATA);
+       new_reg = old_reg & ~GPIO_CLARO_DIG_COAX;
+       if (value->value.enumerated.item[0])
+               new_reg |= GPIO_CLARO_DIG_COAX;
+       changed = new_reg != old_reg;
+       if (changed)
+               oxygen_write16(chip, OXYGEN_GPIO_DATA, new_reg);
+       mutex_unlock(&chip->mutex);
+       return changed;
+}
+
 static const struct snd_kcontrol_new meridian_dig_source_control = {
        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
        .name = "IEC958 Source Capture Enum",
@@ -568,6 +615,14 @@ static const struct snd_kcontrol_new meridian_dig_source_control = {
        .put = meridian_dig_source_put,
 };
 
+static const struct snd_kcontrol_new claro_dig_source_control = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name = "IEC958 Source Capture Enum",
+       .info = claro_dig_source_info,
+       .get = claro_dig_source_get,
+       .put = claro_dig_source_put,
+};
+
 static int generic_mixer_init(struct oxygen *chip)
 {
        return snd_ctl_add(chip->card, snd_ctl_new1(&rolloff_control, chip));
@@ -600,6 +655,34 @@ static int meridian_mixer_init(struct oxygen *chip)
        return 0;
 }
 
+static int claro_mixer_init(struct oxygen *chip)
+{
+       int err;
+
+       err = generic_wm8785_mixer_init(chip);
+       if (err < 0)
+               return err;
+       err = snd_ctl_add(chip->card,
+                         snd_ctl_new1(&claro_dig_source_control, chip));
+       if (err < 0)
+               return err;
+       return 0;
+}
+
+static int claro_halo_mixer_init(struct oxygen *chip)
+{
+       int err;
+
+       err = generic_mixer_init(chip);
+       if (err < 0)
+               return err;
+       err = snd_ctl_add(chip->card,
+                         snd_ctl_new1(&claro_dig_source_control, chip));
+       if (err < 0)
+               return err;
+       return 0;
+}
+
 static void dump_ak4396_registers(struct oxygen *chip,
                                  struct snd_info_buffer *buffer)
 {
@@ -700,13 +783,14 @@ static int __devinit get_oxygen_model(struct oxygen *chip,
                break;
        case MODEL_CLARO:
                chip->model.init = claro_init;
+               chip->model.mixer_init = claro_mixer_init;
                chip->model.cleanup = claro_cleanup;
                chip->model.suspend = claro_suspend;
                chip->model.resume = claro_resume;
                break;
        case MODEL_CLARO_HALO:
                chip->model.init = claro_halo_init;
-               chip->model.mixer_init = generic_mixer_init;
+               chip->model.mixer_init = claro_halo_mixer_init;
                chip->model.cleanup = claro_cleanup;
                chip->model.suspend = claro_suspend;
                chip->model.resume = claro_resume;