]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - sound/pci/oxygen/oxygen_mixer.c
[ALSA] hda-intel - Add ratelimit to timeout messages
[linux-2.6-omap-h63xx.git] / sound / pci / oxygen / oxygen_mixer.c
index 6fd2a594e89e23a0e71d4951b47a2ebadc7821a1..6b7420fdd02683d48792285c63974068191a3d89 100644 (file)
@@ -23,6 +23,7 @@
 #include <sound/control.h>
 #include <sound/tlv.h>
 #include "oxygen.h"
+#include "cm9780.h"
 
 static int dac_volume_info(struct snd_kcontrol *ctl,
                           struct snd_ctl_elem_info *info)
@@ -120,10 +121,23 @@ static int upmix_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
 
 void oxygen_update_dac_routing(struct oxygen *chip)
 {
+       /* DAC 0: front, DAC 1: surround, DAC 2: center/LFE, DAC 3: back */
        static const unsigned int reg_values[3] = {
-               0xe400, /* front <- 0, surround <- 1, center <- 2, back <- 3 */
-               0xe000, /* front <- 0, surround <- 0, center <- 2, back <- 3 */
-               0x2000  /* front <- 0, surround <- 0, center <- 2, back <- 0 */
+               /* stereo -> front */
+               (0 << OXYGEN_PLAY_DAC0_SOURCE_SHIFT) |
+               (1 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) |
+               (2 << OXYGEN_PLAY_DAC2_SOURCE_SHIFT) |
+               (3 << OXYGEN_PLAY_DAC3_SOURCE_SHIFT),
+               /* stereo -> front+surround */
+               (0 << OXYGEN_PLAY_DAC0_SOURCE_SHIFT) |
+               (0 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) |
+               (2 << OXYGEN_PLAY_DAC2_SOURCE_SHIFT) |
+               (3 << OXYGEN_PLAY_DAC3_SOURCE_SHIFT),
+               /* stereo -> front+surround+back */
+               (0 << OXYGEN_PLAY_DAC0_SOURCE_SHIFT) |
+               (0 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) |
+               (2 << OXYGEN_PLAY_DAC2_SOURCE_SHIFT) |
+               (0 << OXYGEN_PLAY_DAC3_SOURCE_SHIFT),
        };
        u8 channels;
        unsigned int reg_value;
@@ -133,10 +147,21 @@ void oxygen_update_dac_routing(struct oxygen *chip)
        if (channels == OXYGEN_PLAY_CHANNELS_2)
                reg_value = reg_values[chip->dac_routing];
        else if (channels == OXYGEN_PLAY_CHANNELS_8)
-               reg_value = 0x6c00; /* surround <- 3, back <- 1 */
+               /* in 7.1 mode, "rear" channels go to the "back" jack */
+               reg_value = (0 << OXYGEN_PLAY_DAC0_SOURCE_SHIFT) |
+                           (3 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) |
+                           (2 << OXYGEN_PLAY_DAC2_SOURCE_SHIFT) |
+                           (1 << OXYGEN_PLAY_DAC3_SOURCE_SHIFT);
        else
-               reg_value = 0xe400;
-       oxygen_write16_masked(chip, OXYGEN_PLAY_ROUTING, reg_value, 0xff00);
+               reg_value = (0 << OXYGEN_PLAY_DAC0_SOURCE_SHIFT) |
+                           (1 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) |
+                           (2 << OXYGEN_PLAY_DAC2_SOURCE_SHIFT) |
+                           (3 << OXYGEN_PLAY_DAC3_SOURCE_SHIFT);
+       oxygen_write16_masked(chip, OXYGEN_PLAY_ROUTING, reg_value,
+                             OXYGEN_PLAY_DAC0_SOURCE_MASK |
+                             OXYGEN_PLAY_DAC1_SOURCE_MASK |
+                             OXYGEN_PLAY_DAC2_SOURCE_MASK |
+                             OXYGEN_PLAY_DAC3_SOURCE_MASK);
 }
 
 static int upmix_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
@@ -199,13 +224,15 @@ void oxygen_update_spdif_source(struct oxygen *chip)
        old_routing = oxygen_read16(chip, OXYGEN_PLAY_ROUTING);
        if (chip->pcm_active & (1 << PCM_SPDIF)) {
                new_control = old_control | OXYGEN_SPDIF_OUT_ENABLE;
-               new_routing = (old_routing & ~0x00e0) | 0x0000;
+               new_routing = (old_routing & ~OXYGEN_PLAY_SPDIF_MASK)
+                       | OXYGEN_PLAY_SPDIF_SPDIF;
                oxygen_rate = (old_control >> OXYGEN_SPDIF_OUT_RATE_SHIFT)
                        & OXYGEN_I2S_RATE_MASK;
                /* S/PDIF rate was already set by the caller */
        } else if ((chip->pcm_active & (1 << PCM_MULTICH)) &&
                   chip->spdif_playback_enable) {
-               new_routing = (old_routing & ~0x00e0) | 0x0020;
+               new_routing = (old_routing & ~OXYGEN_PLAY_SPDIF_MASK)
+                       | OXYGEN_PLAY_SPDIF_MULTICH_01;
                oxygen_rate = oxygen_read16(chip, OXYGEN_I2S_MULTICH_FORMAT)
                        & OXYGEN_I2S_RATE_MASK;
                new_control = (old_control & ~OXYGEN_SPDIF_OUT_RATE_MASK) |
@@ -381,6 +408,37 @@ static int spdif_input_default_get(struct snd_kcontrol *ctl,
        return 0;
 }
 
+static int spdif_loopback_get(struct snd_kcontrol *ctl,
+                             struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+
+       value->value.integer.value[0] =
+               !!(oxygen_read32(chip, OXYGEN_SPDIF_CONTROL)
+                  & OXYGEN_SPDIF_LOOPBACK);
+       return 0;
+}
+
+static int spdif_loopback_put(struct snd_kcontrol *ctl,
+                             struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+       u32 oldreg, newreg;
+       int changed;
+
+       spin_lock_irq(&chip->reg_lock);
+       oldreg = oxygen_read32(chip, OXYGEN_SPDIF_CONTROL);
+       if (value->value.integer.value[0])
+               newreg = oldreg | OXYGEN_SPDIF_LOOPBACK;
+       else
+               newreg = oldreg & ~OXYGEN_SPDIF_LOOPBACK;
+       changed = newreg != oldreg;
+       if (changed)
+               oxygen_write32(chip, OXYGEN_SPDIF_CONTROL, newreg);
+       spin_unlock_irq(&chip->reg_lock);
+       return changed;
+}
+
 static int ac97_switch_get(struct snd_kcontrol *ctl,
                           struct snd_ctl_elem_value *value)
 {
@@ -434,8 +492,9 @@ static int ac97_switch_put(struct snd_kcontrol *ctl,
        if (change) {
                oxygen_write_ac97(chip, 0, index, newreg);
                if (index == AC97_LINE) {
-                       oxygen_write_ac97_masked(chip, 0, 0x72,
-                                                !!(newreg & 0x8000), 0x0001);
+                       oxygen_write_ac97_masked(chip, 0, CM9780_GPIO_STATUS,
+                                                newreg & 0x8000 ?
+                                                CM9780_GPO0 : 0, CM9780_GPO0);
                        if (!(newreg & 0x8000)) {
                                ac97_mute_ctl(chip, CONTROL_MIC_CAPTURE_SWITCH);
                                ac97_mute_ctl(chip, CONTROL_CD_CAPTURE_SWITCH);
@@ -445,7 +504,8 @@ static int ac97_switch_put(struct snd_kcontrol *ctl,
                            index == AC97_VIDEO || index == AC97_AUX) &&
                           bitnr == 15 && !(newreg & 0x8000)) {
                        ac97_mute_ctl(chip, CONTROL_LINE_CAPTURE_SWITCH);
-                       oxygen_write_ac97_masked(chip, 0, 0x72, 0x0001, 0x0001);
+                       oxygen_write_ac97_masked(chip, 0, CM9780_GPIO_STATUS,
+                                                CM9780_GPO0, CM9780_GPO0);
                }
        }
        mutex_unlock(&chip->mutex);
@@ -591,6 +651,13 @@ static const struct snd_kcontrol_new controls[] = {
                .info = spdif_info,
                .get = spdif_input_default_get,
        },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = SNDRV_CTL_NAME_IEC958("Loopback ", NONE, SWITCH),
+               .info = snd_ctl_boolean_mono_info,
+               .get = spdif_loopback_get,
+               .put = spdif_loopback_put,
+       },
 };
 
 static const struct snd_kcontrol_new ac97_controls[] = {
@@ -638,7 +705,7 @@ static int add_controls(struct oxygen *chip,
                err = chip->model->control_filter(&template);
                if (err < 0)
                        return err;
-               ctl = snd_ctl_new1(&controls[i], chip);
+               ctl = snd_ctl_new1(&template, chip);
                if (!ctl)
                        return -ENOMEM;
                err = snd_ctl_add(chip->card, ctl);