#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)
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;
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)
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) |
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)
{
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);
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);
.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[] = {
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);