xref: /openbmc/linux/sound/pci/oxygen/oxygen_mixer.c (revision 0d7b0c4a)
19c9cf6beSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2d0ce9946SClemens Ladisch /*
3d0ce9946SClemens Ladisch  * C-Media CMI8788 driver - mixer code
4d0ce9946SClemens Ladisch  *
5d0ce9946SClemens Ladisch  * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
6d0ce9946SClemens Ladisch  */
7d0ce9946SClemens Ladisch 
8d0ce9946SClemens Ladisch #include <linux/mutex.h>
9d0ce9946SClemens Ladisch #include <sound/ac97_codec.h>
10d0ce9946SClemens Ladisch #include <sound/asoundef.h>
11d0ce9946SClemens Ladisch #include <sound/control.h>
12d0ce9946SClemens Ladisch #include <sound/tlv.h>
13d0ce9946SClemens Ladisch #include "oxygen.h"
14878ac3eeSClemens Ladisch #include "cm9780.h"
15d0ce9946SClemens Ladisch 
dac_volume_info(struct snd_kcontrol * ctl,struct snd_ctl_elem_info * info)16d0ce9946SClemens Ladisch static int dac_volume_info(struct snd_kcontrol *ctl,
17d0ce9946SClemens Ladisch 			   struct snd_ctl_elem_info *info)
18d0ce9946SClemens Ladisch {
19976cd627SClemens Ladisch 	struct oxygen *chip = ctl->private_data;
20976cd627SClemens Ladisch 
21d0ce9946SClemens Ladisch 	info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
221f4d7be7SClemens Ladisch 	info->count = chip->model.dac_channels_mixer;
239bd6a73aSClemens Ladisch 	info->value.integer.min = chip->model.dac_volume_min;
249bd6a73aSClemens Ladisch 	info->value.integer.max = chip->model.dac_volume_max;
25d0ce9946SClemens Ladisch 	return 0;
26d0ce9946SClemens Ladisch }
27d0ce9946SClemens Ladisch 
dac_volume_get(struct snd_kcontrol * ctl,struct snd_ctl_elem_value * value)28d0ce9946SClemens Ladisch static int dac_volume_get(struct snd_kcontrol *ctl,
29d0ce9946SClemens Ladisch 			  struct snd_ctl_elem_value *value)
30d0ce9946SClemens Ladisch {
31d0ce9946SClemens Ladisch 	struct oxygen *chip = ctl->private_data;
32d0ce9946SClemens Ladisch 	unsigned int i;
33d0ce9946SClemens Ladisch 
34d0ce9946SClemens Ladisch 	mutex_lock(&chip->mutex);
351f4d7be7SClemens Ladisch 	for (i = 0; i < chip->model.dac_channels_mixer; ++i)
36d0ce9946SClemens Ladisch 		value->value.integer.value[i] = chip->dac_volume[i];
37d0ce9946SClemens Ladisch 	mutex_unlock(&chip->mutex);
38d0ce9946SClemens Ladisch 	return 0;
39d0ce9946SClemens Ladisch }
40d0ce9946SClemens Ladisch 
dac_volume_put(struct snd_kcontrol * ctl,struct snd_ctl_elem_value * value)41d0ce9946SClemens Ladisch static int dac_volume_put(struct snd_kcontrol *ctl,
42d0ce9946SClemens Ladisch 			  struct snd_ctl_elem_value *value)
43d0ce9946SClemens Ladisch {
44d0ce9946SClemens Ladisch 	struct oxygen *chip = ctl->private_data;
45d0ce9946SClemens Ladisch 	unsigned int i;
46d0ce9946SClemens Ladisch 	int changed;
47d0ce9946SClemens Ladisch 
48d0ce9946SClemens Ladisch 	changed = 0;
49d0ce9946SClemens Ladisch 	mutex_lock(&chip->mutex);
501f4d7be7SClemens Ladisch 	for (i = 0; i < chip->model.dac_channels_mixer; ++i)
51d0ce9946SClemens Ladisch 		if (value->value.integer.value[i] != chip->dac_volume[i]) {
52d0ce9946SClemens Ladisch 			chip->dac_volume[i] = value->value.integer.value[i];
53d0ce9946SClemens Ladisch 			changed = 1;
54d0ce9946SClemens Ladisch 		}
55d0ce9946SClemens Ladisch 	if (changed)
569bd6a73aSClemens Ladisch 		chip->model.update_dac_volume(chip);
57d0ce9946SClemens Ladisch 	mutex_unlock(&chip->mutex);
58d0ce9946SClemens Ladisch 	return changed;
59d0ce9946SClemens Ladisch }
60d0ce9946SClemens Ladisch 
dac_mute_get(struct snd_kcontrol * ctl,struct snd_ctl_elem_value * value)61d0ce9946SClemens Ladisch static int dac_mute_get(struct snd_kcontrol *ctl,
62d0ce9946SClemens Ladisch 			struct snd_ctl_elem_value *value)
63d0ce9946SClemens Ladisch {
64d0ce9946SClemens Ladisch 	struct oxygen *chip = ctl->private_data;
65d0ce9946SClemens Ladisch 
66d0ce9946SClemens Ladisch 	mutex_lock(&chip->mutex);
67d0ce9946SClemens Ladisch 	value->value.integer.value[0] = !chip->dac_mute;
68d0ce9946SClemens Ladisch 	mutex_unlock(&chip->mutex);
69d0ce9946SClemens Ladisch 	return 0;
70d0ce9946SClemens Ladisch }
71d0ce9946SClemens Ladisch 
dac_mute_put(struct snd_kcontrol * ctl,struct snd_ctl_elem_value * value)72d0ce9946SClemens Ladisch static int dac_mute_put(struct snd_kcontrol *ctl,
73d0ce9946SClemens Ladisch 			  struct snd_ctl_elem_value *value)
74d0ce9946SClemens Ladisch {
75d0ce9946SClemens Ladisch 	struct oxygen *chip = ctl->private_data;
76d0ce9946SClemens Ladisch 	int changed;
77d0ce9946SClemens Ladisch 
78d0ce9946SClemens Ladisch 	mutex_lock(&chip->mutex);
798ec7cfceSTomer Barletz 	changed = (!value->value.integer.value[0]) != chip->dac_mute;
80d0ce9946SClemens Ladisch 	if (changed) {
81d0ce9946SClemens Ladisch 		chip->dac_mute = !value->value.integer.value[0];
829bd6a73aSClemens Ladisch 		chip->model.update_dac_mute(chip);
83d0ce9946SClemens Ladisch 	}
84d0ce9946SClemens Ladisch 	mutex_unlock(&chip->mutex);
85d0ce9946SClemens Ladisch 	return changed;
86d0ce9946SClemens Ladisch }
87d0ce9946SClemens Ladisch 
upmix_item_count(struct oxygen * chip)8866410bfdSClemens Ladisch static unsigned int upmix_item_count(struct oxygen *chip)
8966410bfdSClemens Ladisch {
9066410bfdSClemens Ladisch 	if (chip->model.dac_channels_pcm < 8)
9166410bfdSClemens Ladisch 		return 2;
9266410bfdSClemens Ladisch 	else if (chip->model.update_center_lfe_mix)
9366410bfdSClemens Ladisch 		return 5;
9466410bfdSClemens Ladisch 	else
9566410bfdSClemens Ladisch 		return 3;
9666410bfdSClemens Ladisch }
9766410bfdSClemens Ladisch 
upmix_info(struct snd_kcontrol * ctl,struct snd_ctl_elem_info * info)98d0ce9946SClemens Ladisch static int upmix_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info)
99d0ce9946SClemens Ladisch {
1003d8bb454SClemens Ladisch 	static const char *const names[5] = {
1013d8bb454SClemens Ladisch 		"Front",
1023d8bb454SClemens Ladisch 		"Front+Surround",
1033d8bb454SClemens Ladisch 		"Front+Surround+Back",
1043d8bb454SClemens Ladisch 		"Front+Surround+Center/LFE",
1053d8bb454SClemens Ladisch 		"Front+Surround+Center/LFE+Back",
106d0ce9946SClemens Ladisch 	};
107976cd627SClemens Ladisch 	struct oxygen *chip = ctl->private_data;
10866410bfdSClemens Ladisch 	unsigned int count = upmix_item_count(chip);
109976cd627SClemens Ladisch 
1109600732bSClemens Ladisch 	return snd_ctl_enum_info(info, 1, count, names);
111d0ce9946SClemens Ladisch }
112d0ce9946SClemens Ladisch 
upmix_get(struct snd_kcontrol * ctl,struct snd_ctl_elem_value * value)113d0ce9946SClemens Ladisch static int upmix_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
114d0ce9946SClemens Ladisch {
115d0ce9946SClemens Ladisch 	struct oxygen *chip = ctl->private_data;
116d0ce9946SClemens Ladisch 
117d0ce9946SClemens Ladisch 	mutex_lock(&chip->mutex);
118d0ce9946SClemens Ladisch 	value->value.enumerated.item[0] = chip->dac_routing;
119d0ce9946SClemens Ladisch 	mutex_unlock(&chip->mutex);
120d0ce9946SClemens Ladisch 	return 0;
121d0ce9946SClemens Ladisch }
122d0ce9946SClemens Ladisch 
oxygen_update_dac_routing(struct oxygen * chip)123d0ce9946SClemens Ladisch void oxygen_update_dac_routing(struct oxygen *chip)
124d0ce9946SClemens Ladisch {
125c9946b2cSClemens Ladisch 	/* DAC 0: front, DAC 1: surround, DAC 2: center/LFE, DAC 3: back */
1263d8bb454SClemens Ladisch 	static const unsigned int reg_values[5] = {
127c9946b2cSClemens Ladisch 		/* stereo -> front */
128c9946b2cSClemens Ladisch 		(0 << OXYGEN_PLAY_DAC0_SOURCE_SHIFT) |
129c9946b2cSClemens Ladisch 		(1 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) |
130c9946b2cSClemens Ladisch 		(2 << OXYGEN_PLAY_DAC2_SOURCE_SHIFT) |
131c9946b2cSClemens Ladisch 		(3 << OXYGEN_PLAY_DAC3_SOURCE_SHIFT),
132c9946b2cSClemens Ladisch 		/* stereo -> front+surround */
133c9946b2cSClemens Ladisch 		(0 << OXYGEN_PLAY_DAC0_SOURCE_SHIFT) |
134c9946b2cSClemens Ladisch 		(0 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) |
135c9946b2cSClemens Ladisch 		(2 << OXYGEN_PLAY_DAC2_SOURCE_SHIFT) |
136c9946b2cSClemens Ladisch 		(3 << OXYGEN_PLAY_DAC3_SOURCE_SHIFT),
137c9946b2cSClemens Ladisch 		/* stereo -> front+surround+back */
138c9946b2cSClemens Ladisch 		(0 << OXYGEN_PLAY_DAC0_SOURCE_SHIFT) |
139c9946b2cSClemens Ladisch 		(0 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) |
140c9946b2cSClemens Ladisch 		(2 << OXYGEN_PLAY_DAC2_SOURCE_SHIFT) |
141c9946b2cSClemens Ladisch 		(0 << OXYGEN_PLAY_DAC3_SOURCE_SHIFT),
1423d8bb454SClemens Ladisch 		/* stereo -> front+surround+center/LFE */
1433d8bb454SClemens Ladisch 		(0 << OXYGEN_PLAY_DAC0_SOURCE_SHIFT) |
1443d8bb454SClemens Ladisch 		(0 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) |
1453d8bb454SClemens Ladisch 		(0 << OXYGEN_PLAY_DAC2_SOURCE_SHIFT) |
1463d8bb454SClemens Ladisch 		(3 << OXYGEN_PLAY_DAC3_SOURCE_SHIFT),
1473d8bb454SClemens Ladisch 		/* stereo -> front+surround+center/LFE+back */
1483d8bb454SClemens Ladisch 		(0 << OXYGEN_PLAY_DAC0_SOURCE_SHIFT) |
1493d8bb454SClemens Ladisch 		(0 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) |
1503d8bb454SClemens Ladisch 		(0 << OXYGEN_PLAY_DAC2_SOURCE_SHIFT) |
1513d8bb454SClemens Ladisch 		(0 << OXYGEN_PLAY_DAC3_SOURCE_SHIFT),
152d0ce9946SClemens Ladisch 	};
1537113e958SClemens Ladisch 	u8 channels;
154d0ce9946SClemens Ladisch 	unsigned int reg_value;
155d0ce9946SClemens Ladisch 
1567113e958SClemens Ladisch 	channels = oxygen_read8(chip, OXYGEN_PLAY_CHANNELS) &
1577113e958SClemens Ladisch 		OXYGEN_PLAY_CHANNELS_MASK;
1587113e958SClemens Ladisch 	if (channels == OXYGEN_PLAY_CHANNELS_2)
159d0ce9946SClemens Ladisch 		reg_value = reg_values[chip->dac_routing];
1607113e958SClemens Ladisch 	else if (channels == OXYGEN_PLAY_CHANNELS_8)
161c9946b2cSClemens Ladisch 		/* in 7.1 mode, "rear" channels go to the "back" jack */
162c9946b2cSClemens Ladisch 		reg_value = (0 << OXYGEN_PLAY_DAC0_SOURCE_SHIFT) |
163c9946b2cSClemens Ladisch 			    (3 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) |
164c9946b2cSClemens Ladisch 			    (2 << OXYGEN_PLAY_DAC2_SOURCE_SHIFT) |
165c9946b2cSClemens Ladisch 			    (1 << OXYGEN_PLAY_DAC3_SOURCE_SHIFT);
166d0ce9946SClemens Ladisch 	else
167c9946b2cSClemens Ladisch 		reg_value = (0 << OXYGEN_PLAY_DAC0_SOURCE_SHIFT) |
168c9946b2cSClemens Ladisch 			    (1 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) |
169c9946b2cSClemens Ladisch 			    (2 << OXYGEN_PLAY_DAC2_SOURCE_SHIFT) |
170c9946b2cSClemens Ladisch 			    (3 << OXYGEN_PLAY_DAC3_SOURCE_SHIFT);
171efbeb071SClemens Ladisch 	if (chip->model.adjust_dac_routing)
172efbeb071SClemens Ladisch 		reg_value = chip->model.adjust_dac_routing(chip, reg_value);
173c9946b2cSClemens Ladisch 	oxygen_write16_masked(chip, OXYGEN_PLAY_ROUTING, reg_value,
174c9946b2cSClemens Ladisch 			      OXYGEN_PLAY_DAC0_SOURCE_MASK |
175c9946b2cSClemens Ladisch 			      OXYGEN_PLAY_DAC1_SOURCE_MASK |
176c9946b2cSClemens Ladisch 			      OXYGEN_PLAY_DAC2_SOURCE_MASK |
177c9946b2cSClemens Ladisch 			      OXYGEN_PLAY_DAC3_SOURCE_MASK);
1783d8bb454SClemens Ladisch 	if (chip->model.update_center_lfe_mix)
1793d8bb454SClemens Ladisch 		chip->model.update_center_lfe_mix(chip, chip->dac_routing > 2);
180d0ce9946SClemens Ladisch }
181e9c2f10bSRoman Volkov EXPORT_SYMBOL(oxygen_update_dac_routing);
182d0ce9946SClemens Ladisch 
upmix_put(struct snd_kcontrol * ctl,struct snd_ctl_elem_value * value)183d0ce9946SClemens Ladisch static int upmix_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
184d0ce9946SClemens Ladisch {
185d0ce9946SClemens Ladisch 	struct oxygen *chip = ctl->private_data;
18666410bfdSClemens Ladisch 	unsigned int count = upmix_item_count(chip);
187d0ce9946SClemens Ladisch 	int changed;
188d0ce9946SClemens Ladisch 
1893d8bb454SClemens Ladisch 	if (value->value.enumerated.item[0] >= count)
1903d8bb454SClemens Ladisch 		return -EINVAL;
191d0ce9946SClemens Ladisch 	mutex_lock(&chip->mutex);
192d0ce9946SClemens Ladisch 	changed = value->value.enumerated.item[0] != chip->dac_routing;
193d0ce9946SClemens Ladisch 	if (changed) {
1943d8bb454SClemens Ladisch 		chip->dac_routing = value->value.enumerated.item[0];
195d0ce9946SClemens Ladisch 		oxygen_update_dac_routing(chip);
196d0ce9946SClemens Ladisch 	}
197d0ce9946SClemens Ladisch 	mutex_unlock(&chip->mutex);
198d0ce9946SClemens Ladisch 	return changed;
199d0ce9946SClemens Ladisch }
200d0ce9946SClemens Ladisch 
spdif_switch_get(struct snd_kcontrol * ctl,struct snd_ctl_elem_value * value)201d0ce9946SClemens Ladisch static int spdif_switch_get(struct snd_kcontrol *ctl,
202d0ce9946SClemens Ladisch 			    struct snd_ctl_elem_value *value)
203d0ce9946SClemens Ladisch {
204d0ce9946SClemens Ladisch 	struct oxygen *chip = ctl->private_data;
205d0ce9946SClemens Ladisch 
206d0ce9946SClemens Ladisch 	mutex_lock(&chip->mutex);
207d0ce9946SClemens Ladisch 	value->value.integer.value[0] = chip->spdif_playback_enable;
208d0ce9946SClemens Ladisch 	mutex_unlock(&chip->mutex);
209d0ce9946SClemens Ladisch 	return 0;
210d0ce9946SClemens Ladisch }
211d0ce9946SClemens Ladisch 
oxygen_spdif_rate(unsigned int oxygen_rate)212d0ce9946SClemens Ladisch static unsigned int oxygen_spdif_rate(unsigned int oxygen_rate)
213d0ce9946SClemens Ladisch {
214d0ce9946SClemens Ladisch 	switch (oxygen_rate) {
215d0ce9946SClemens Ladisch 	case OXYGEN_RATE_32000:
216d0ce9946SClemens Ladisch 		return IEC958_AES3_CON_FS_32000 << OXYGEN_SPDIF_CS_RATE_SHIFT;
217d0ce9946SClemens Ladisch 	case OXYGEN_RATE_44100:
218d0ce9946SClemens Ladisch 		return IEC958_AES3_CON_FS_44100 << OXYGEN_SPDIF_CS_RATE_SHIFT;
219d0ce9946SClemens Ladisch 	default: /* OXYGEN_RATE_48000 */
220d0ce9946SClemens Ladisch 		return IEC958_AES3_CON_FS_48000 << OXYGEN_SPDIF_CS_RATE_SHIFT;
221d0ce9946SClemens Ladisch 	case OXYGEN_RATE_64000:
222d0ce9946SClemens Ladisch 		return 0xb << OXYGEN_SPDIF_CS_RATE_SHIFT;
223d0ce9946SClemens Ladisch 	case OXYGEN_RATE_88200:
2246627bea1SClemens Ladisch 		return IEC958_AES3_CON_FS_88200 << OXYGEN_SPDIF_CS_RATE_SHIFT;
225d0ce9946SClemens Ladisch 	case OXYGEN_RATE_96000:
2266627bea1SClemens Ladisch 		return IEC958_AES3_CON_FS_96000 << OXYGEN_SPDIF_CS_RATE_SHIFT;
227d0ce9946SClemens Ladisch 	case OXYGEN_RATE_176400:
2286627bea1SClemens Ladisch 		return IEC958_AES3_CON_FS_176400 << OXYGEN_SPDIF_CS_RATE_SHIFT;
229d0ce9946SClemens Ladisch 	case OXYGEN_RATE_192000:
2306627bea1SClemens Ladisch 		return IEC958_AES3_CON_FS_192000 << OXYGEN_SPDIF_CS_RATE_SHIFT;
231d0ce9946SClemens Ladisch 	}
232d0ce9946SClemens Ladisch }
233d0ce9946SClemens Ladisch 
oxygen_update_spdif_source(struct oxygen * chip)234d0ce9946SClemens Ladisch void oxygen_update_spdif_source(struct oxygen *chip)
235d0ce9946SClemens Ladisch {
236d0ce9946SClemens Ladisch 	u32 old_control, new_control;
237d0ce9946SClemens Ladisch 	u16 old_routing, new_routing;
238d0ce9946SClemens Ladisch 	unsigned int oxygen_rate;
239d0ce9946SClemens Ladisch 
240d0ce9946SClemens Ladisch 	old_control = oxygen_read32(chip, OXYGEN_SPDIF_CONTROL);
241d0ce9946SClemens Ladisch 	old_routing = oxygen_read16(chip, OXYGEN_PLAY_ROUTING);
242d0ce9946SClemens Ladisch 	if (chip->pcm_active & (1 << PCM_SPDIF)) {
243d0ce9946SClemens Ladisch 		new_control = old_control | OXYGEN_SPDIF_OUT_ENABLE;
244c9946b2cSClemens Ladisch 		new_routing = (old_routing & ~OXYGEN_PLAY_SPDIF_MASK)
245c9946b2cSClemens Ladisch 			| OXYGEN_PLAY_SPDIF_SPDIF;
246d0ce9946SClemens Ladisch 		oxygen_rate = (old_control >> OXYGEN_SPDIF_OUT_RATE_SHIFT)
247d0ce9946SClemens Ladisch 			& OXYGEN_I2S_RATE_MASK;
248d0ce9946SClemens Ladisch 		/* S/PDIF rate was already set by the caller */
249d0ce9946SClemens Ladisch 	} else if ((chip->pcm_active & (1 << PCM_MULTICH)) &&
250d0ce9946SClemens Ladisch 		   chip->spdif_playback_enable) {
251c9946b2cSClemens Ladisch 		new_routing = (old_routing & ~OXYGEN_PLAY_SPDIF_MASK)
252c9946b2cSClemens Ladisch 			| OXYGEN_PLAY_SPDIF_MULTICH_01;
253d0ce9946SClemens Ladisch 		oxygen_rate = oxygen_read16(chip, OXYGEN_I2S_MULTICH_FORMAT)
254d0ce9946SClemens Ladisch 			& OXYGEN_I2S_RATE_MASK;
255d0ce9946SClemens Ladisch 		new_control = (old_control & ~OXYGEN_SPDIF_OUT_RATE_MASK) |
256d0ce9946SClemens Ladisch 			(oxygen_rate << OXYGEN_SPDIF_OUT_RATE_SHIFT) |
257d0ce9946SClemens Ladisch 			OXYGEN_SPDIF_OUT_ENABLE;
258d0ce9946SClemens Ladisch 	} else {
259d0ce9946SClemens Ladisch 		new_control = old_control & ~OXYGEN_SPDIF_OUT_ENABLE;
260d0ce9946SClemens Ladisch 		new_routing = old_routing;
261d0ce9946SClemens Ladisch 		oxygen_rate = OXYGEN_RATE_44100;
262d0ce9946SClemens Ladisch 	}
263d0ce9946SClemens Ladisch 	if (old_routing != new_routing) {
264d0ce9946SClemens Ladisch 		oxygen_write32(chip, OXYGEN_SPDIF_CONTROL,
265d0ce9946SClemens Ladisch 			       new_control & ~OXYGEN_SPDIF_OUT_ENABLE);
266d0ce9946SClemens Ladisch 		oxygen_write16(chip, OXYGEN_PLAY_ROUTING, new_routing);
267d0ce9946SClemens Ladisch 	}
268d0ce9946SClemens Ladisch 	if (new_control & OXYGEN_SPDIF_OUT_ENABLE)
269d0ce9946SClemens Ladisch 		oxygen_write32(chip, OXYGEN_SPDIF_OUTPUT_BITS,
270d0ce9946SClemens Ladisch 			       oxygen_spdif_rate(oxygen_rate) |
271d0ce9946SClemens Ladisch 			       ((chip->pcm_active & (1 << PCM_SPDIF)) ?
272d0ce9946SClemens Ladisch 				chip->spdif_pcm_bits : chip->spdif_bits));
273d0ce9946SClemens Ladisch 	oxygen_write32(chip, OXYGEN_SPDIF_CONTROL, new_control);
274d0ce9946SClemens Ladisch }
275d0ce9946SClemens Ladisch 
spdif_switch_put(struct snd_kcontrol * ctl,struct snd_ctl_elem_value * value)276d0ce9946SClemens Ladisch static int spdif_switch_put(struct snd_kcontrol *ctl,
277d0ce9946SClemens Ladisch 			    struct snd_ctl_elem_value *value)
278d0ce9946SClemens Ladisch {
279d0ce9946SClemens Ladisch 	struct oxygen *chip = ctl->private_data;
280d0ce9946SClemens Ladisch 	int changed;
281d0ce9946SClemens Ladisch 
282d0ce9946SClemens Ladisch 	mutex_lock(&chip->mutex);
283d0ce9946SClemens Ladisch 	changed = value->value.integer.value[0] != chip->spdif_playback_enable;
284d0ce9946SClemens Ladisch 	if (changed) {
285d0ce9946SClemens Ladisch 		chip->spdif_playback_enable = !!value->value.integer.value[0];
286d0ce9946SClemens Ladisch 		spin_lock_irq(&chip->reg_lock);
287d0ce9946SClemens Ladisch 		oxygen_update_spdif_source(chip);
288d0ce9946SClemens Ladisch 		spin_unlock_irq(&chip->reg_lock);
289d0ce9946SClemens Ladisch 	}
290d0ce9946SClemens Ladisch 	mutex_unlock(&chip->mutex);
291d0ce9946SClemens Ladisch 	return changed;
292d0ce9946SClemens Ladisch }
293d0ce9946SClemens Ladisch 
spdif_info(struct snd_kcontrol * ctl,struct snd_ctl_elem_info * info)294d0ce9946SClemens Ladisch static int spdif_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info)
295d0ce9946SClemens Ladisch {
296d0ce9946SClemens Ladisch 	info->type = SNDRV_CTL_ELEM_TYPE_IEC958;
297d0ce9946SClemens Ladisch 	info->count = 1;
298d0ce9946SClemens Ladisch 	return 0;
299d0ce9946SClemens Ladisch }
300d0ce9946SClemens Ladisch 
oxygen_to_iec958(u32 bits,struct snd_ctl_elem_value * value)301d0ce9946SClemens Ladisch static void oxygen_to_iec958(u32 bits, struct snd_ctl_elem_value *value)
302d0ce9946SClemens Ladisch {
303d0ce9946SClemens Ladisch 	value->value.iec958.status[0] =
304d0ce9946SClemens Ladisch 		bits & (OXYGEN_SPDIF_NONAUDIO | OXYGEN_SPDIF_C |
305d0ce9946SClemens Ladisch 			OXYGEN_SPDIF_PREEMPHASIS);
306d0ce9946SClemens Ladisch 	value->value.iec958.status[1] = /* category and original */
307d0ce9946SClemens Ladisch 		bits >> OXYGEN_SPDIF_CATEGORY_SHIFT;
308d0ce9946SClemens Ladisch }
309d0ce9946SClemens Ladisch 
iec958_to_oxygen(struct snd_ctl_elem_value * value)310d0ce9946SClemens Ladisch static u32 iec958_to_oxygen(struct snd_ctl_elem_value *value)
311d0ce9946SClemens Ladisch {
312d0ce9946SClemens Ladisch 	u32 bits;
313d0ce9946SClemens Ladisch 
314d0ce9946SClemens Ladisch 	bits = value->value.iec958.status[0] &
315d0ce9946SClemens Ladisch 		(OXYGEN_SPDIF_NONAUDIO | OXYGEN_SPDIF_C |
316d0ce9946SClemens Ladisch 		 OXYGEN_SPDIF_PREEMPHASIS);
317d0ce9946SClemens Ladisch 	bits |= value->value.iec958.status[1] << OXYGEN_SPDIF_CATEGORY_SHIFT;
318d0ce9946SClemens Ladisch 	if (bits & OXYGEN_SPDIF_NONAUDIO)
319d0ce9946SClemens Ladisch 		bits |= OXYGEN_SPDIF_V;
320d0ce9946SClemens Ladisch 	return bits;
321d0ce9946SClemens Ladisch }
322d0ce9946SClemens Ladisch 
write_spdif_bits(struct oxygen * chip,u32 bits)323d0ce9946SClemens Ladisch static inline void write_spdif_bits(struct oxygen *chip, u32 bits)
324d0ce9946SClemens Ladisch {
325d0ce9946SClemens Ladisch 	oxygen_write32_masked(chip, OXYGEN_SPDIF_OUTPUT_BITS, bits,
326d0ce9946SClemens Ladisch 			      OXYGEN_SPDIF_NONAUDIO |
327d0ce9946SClemens Ladisch 			      OXYGEN_SPDIF_C |
328d0ce9946SClemens Ladisch 			      OXYGEN_SPDIF_PREEMPHASIS |
329d0ce9946SClemens Ladisch 			      OXYGEN_SPDIF_CATEGORY_MASK |
330d0ce9946SClemens Ladisch 			      OXYGEN_SPDIF_ORIGINAL |
331d0ce9946SClemens Ladisch 			      OXYGEN_SPDIF_V);
332d0ce9946SClemens Ladisch }
333d0ce9946SClemens Ladisch 
spdif_default_get(struct snd_kcontrol * ctl,struct snd_ctl_elem_value * value)334d0ce9946SClemens Ladisch static int spdif_default_get(struct snd_kcontrol *ctl,
335d0ce9946SClemens Ladisch 			     struct snd_ctl_elem_value *value)
336d0ce9946SClemens Ladisch {
337d0ce9946SClemens Ladisch 	struct oxygen *chip = ctl->private_data;
338d0ce9946SClemens Ladisch 
339d0ce9946SClemens Ladisch 	mutex_lock(&chip->mutex);
340d0ce9946SClemens Ladisch 	oxygen_to_iec958(chip->spdif_bits, value);
341d0ce9946SClemens Ladisch 	mutex_unlock(&chip->mutex);
342d0ce9946SClemens Ladisch 	return 0;
343d0ce9946SClemens Ladisch }
344d0ce9946SClemens Ladisch 
spdif_default_put(struct snd_kcontrol * ctl,struct snd_ctl_elem_value * value)345d0ce9946SClemens Ladisch static int spdif_default_put(struct snd_kcontrol *ctl,
346d0ce9946SClemens Ladisch 			     struct snd_ctl_elem_value *value)
347d0ce9946SClemens Ladisch {
348d0ce9946SClemens Ladisch 	struct oxygen *chip = ctl->private_data;
349d0ce9946SClemens Ladisch 	u32 new_bits;
350d0ce9946SClemens Ladisch 	int changed;
351d0ce9946SClemens Ladisch 
352d0ce9946SClemens Ladisch 	new_bits = iec958_to_oxygen(value);
353d0ce9946SClemens Ladisch 	mutex_lock(&chip->mutex);
354d0ce9946SClemens Ladisch 	changed = new_bits != chip->spdif_bits;
355d0ce9946SClemens Ladisch 	if (changed) {
356d0ce9946SClemens Ladisch 		chip->spdif_bits = new_bits;
357d0ce9946SClemens Ladisch 		if (!(chip->pcm_active & (1 << PCM_SPDIF)))
358d0ce9946SClemens Ladisch 			write_spdif_bits(chip, new_bits);
359d0ce9946SClemens Ladisch 	}
360d0ce9946SClemens Ladisch 	mutex_unlock(&chip->mutex);
361d0ce9946SClemens Ladisch 	return changed;
362d0ce9946SClemens Ladisch }
363d0ce9946SClemens Ladisch 
spdif_mask_get(struct snd_kcontrol * ctl,struct snd_ctl_elem_value * value)364d0ce9946SClemens Ladisch static int spdif_mask_get(struct snd_kcontrol *ctl,
365d0ce9946SClemens Ladisch 			  struct snd_ctl_elem_value *value)
366d0ce9946SClemens Ladisch {
367d0ce9946SClemens Ladisch 	value->value.iec958.status[0] = IEC958_AES0_NONAUDIO |
368d0ce9946SClemens Ladisch 		IEC958_AES0_CON_NOT_COPYRIGHT | IEC958_AES0_CON_EMPHASIS;
369d0ce9946SClemens Ladisch 	value->value.iec958.status[1] =
370d0ce9946SClemens Ladisch 		IEC958_AES1_CON_CATEGORY | IEC958_AES1_CON_ORIGINAL;
371d0ce9946SClemens Ladisch 	return 0;
372d0ce9946SClemens Ladisch }
373d0ce9946SClemens Ladisch 
spdif_pcm_get(struct snd_kcontrol * ctl,struct snd_ctl_elem_value * value)374d0ce9946SClemens Ladisch static int spdif_pcm_get(struct snd_kcontrol *ctl,
375d0ce9946SClemens Ladisch 			 struct snd_ctl_elem_value *value)
376d0ce9946SClemens Ladisch {
377d0ce9946SClemens Ladisch 	struct oxygen *chip = ctl->private_data;
378d0ce9946SClemens Ladisch 
379d0ce9946SClemens Ladisch 	mutex_lock(&chip->mutex);
380d0ce9946SClemens Ladisch 	oxygen_to_iec958(chip->spdif_pcm_bits, value);
381d0ce9946SClemens Ladisch 	mutex_unlock(&chip->mutex);
382d0ce9946SClemens Ladisch 	return 0;
383d0ce9946SClemens Ladisch }
384d0ce9946SClemens Ladisch 
spdif_pcm_put(struct snd_kcontrol * ctl,struct snd_ctl_elem_value * value)385d0ce9946SClemens Ladisch static int spdif_pcm_put(struct snd_kcontrol *ctl,
386d0ce9946SClemens Ladisch 			 struct snd_ctl_elem_value *value)
387d0ce9946SClemens Ladisch {
388d0ce9946SClemens Ladisch 	struct oxygen *chip = ctl->private_data;
389d0ce9946SClemens Ladisch 	u32 new_bits;
390d0ce9946SClemens Ladisch 	int changed;
391d0ce9946SClemens Ladisch 
392d0ce9946SClemens Ladisch 	new_bits = iec958_to_oxygen(value);
393d0ce9946SClemens Ladisch 	mutex_lock(&chip->mutex);
394d0ce9946SClemens Ladisch 	changed = new_bits != chip->spdif_pcm_bits;
395d0ce9946SClemens Ladisch 	if (changed) {
396d0ce9946SClemens Ladisch 		chip->spdif_pcm_bits = new_bits;
397d0ce9946SClemens Ladisch 		if (chip->pcm_active & (1 << PCM_SPDIF))
398d0ce9946SClemens Ladisch 			write_spdif_bits(chip, new_bits);
399d0ce9946SClemens Ladisch 	}
400d0ce9946SClemens Ladisch 	mutex_unlock(&chip->mutex);
401d0ce9946SClemens Ladisch 	return changed;
402d0ce9946SClemens Ladisch }
403d0ce9946SClemens Ladisch 
spdif_input_mask_get(struct snd_kcontrol * ctl,struct snd_ctl_elem_value * value)404d0ce9946SClemens Ladisch static int spdif_input_mask_get(struct snd_kcontrol *ctl,
405d0ce9946SClemens Ladisch 				struct snd_ctl_elem_value *value)
406d0ce9946SClemens Ladisch {
407d0ce9946SClemens Ladisch 	value->value.iec958.status[0] = 0xff;
408d0ce9946SClemens Ladisch 	value->value.iec958.status[1] = 0xff;
409d0ce9946SClemens Ladisch 	value->value.iec958.status[2] = 0xff;
410d0ce9946SClemens Ladisch 	value->value.iec958.status[3] = 0xff;
411d0ce9946SClemens Ladisch 	return 0;
412d0ce9946SClemens Ladisch }
413d0ce9946SClemens Ladisch 
spdif_input_default_get(struct snd_kcontrol * ctl,struct snd_ctl_elem_value * value)414d0ce9946SClemens Ladisch static int spdif_input_default_get(struct snd_kcontrol *ctl,
415d0ce9946SClemens Ladisch 				   struct snd_ctl_elem_value *value)
416d0ce9946SClemens Ladisch {
417d0ce9946SClemens Ladisch 	struct oxygen *chip = ctl->private_data;
418d0ce9946SClemens Ladisch 	u32 bits;
419d0ce9946SClemens Ladisch 
420d0ce9946SClemens Ladisch 	bits = oxygen_read32(chip, OXYGEN_SPDIF_INPUT_BITS);
421d0ce9946SClemens Ladisch 	value->value.iec958.status[0] = bits;
422d0ce9946SClemens Ladisch 	value->value.iec958.status[1] = bits >> 8;
423d0ce9946SClemens Ladisch 	value->value.iec958.status[2] = bits >> 16;
424d0ce9946SClemens Ladisch 	value->value.iec958.status[3] = bits >> 24;
425d0ce9946SClemens Ladisch 	return 0;
426d0ce9946SClemens Ladisch }
427d0ce9946SClemens Ladisch 
spdif_bit_switch_get(struct snd_kcontrol * ctl,struct snd_ctl_elem_value * value)428860cffd5SClemens Ladisch static int spdif_bit_switch_get(struct snd_kcontrol *ctl,
42902f21c9dSClemens Ladisch 				struct snd_ctl_elem_value *value)
43002f21c9dSClemens Ladisch {
43102f21c9dSClemens Ladisch 	struct oxygen *chip = ctl->private_data;
432860cffd5SClemens Ladisch 	u32 bit = ctl->private_value;
43302f21c9dSClemens Ladisch 
43402f21c9dSClemens Ladisch 	value->value.integer.value[0] =
435860cffd5SClemens Ladisch 		!!(oxygen_read32(chip, OXYGEN_SPDIF_CONTROL) & bit);
43602f21c9dSClemens Ladisch 	return 0;
43702f21c9dSClemens Ladisch }
43802f21c9dSClemens Ladisch 
spdif_bit_switch_put(struct snd_kcontrol * ctl,struct snd_ctl_elem_value * value)439860cffd5SClemens Ladisch static int spdif_bit_switch_put(struct snd_kcontrol *ctl,
44002f21c9dSClemens Ladisch 				struct snd_ctl_elem_value *value)
44102f21c9dSClemens Ladisch {
44202f21c9dSClemens Ladisch 	struct oxygen *chip = ctl->private_data;
443860cffd5SClemens Ladisch 	u32 bit = ctl->private_value;
44402f21c9dSClemens Ladisch 	u32 oldreg, newreg;
44502f21c9dSClemens Ladisch 	int changed;
44602f21c9dSClemens Ladisch 
44702f21c9dSClemens Ladisch 	spin_lock_irq(&chip->reg_lock);
44802f21c9dSClemens Ladisch 	oldreg = oxygen_read32(chip, OXYGEN_SPDIF_CONTROL);
44902f21c9dSClemens Ladisch 	if (value->value.integer.value[0])
450860cffd5SClemens Ladisch 		newreg = oldreg | bit;
45102f21c9dSClemens Ladisch 	else
452860cffd5SClemens Ladisch 		newreg = oldreg & ~bit;
45302f21c9dSClemens Ladisch 	changed = newreg != oldreg;
45402f21c9dSClemens Ladisch 	if (changed)
45502f21c9dSClemens Ladisch 		oxygen_write32(chip, OXYGEN_SPDIF_CONTROL, newreg);
45602f21c9dSClemens Ladisch 	spin_unlock_irq(&chip->reg_lock);
45702f21c9dSClemens Ladisch 	return changed;
45802f21c9dSClemens Ladisch }
45902f21c9dSClemens Ladisch 
monitor_volume_info(struct snd_kcontrol * ctl,struct snd_ctl_elem_info * info)460fa5d8106SClemens Ladisch static int monitor_volume_info(struct snd_kcontrol *ctl,
461fa5d8106SClemens Ladisch 			       struct snd_ctl_elem_info *info)
462fa5d8106SClemens Ladisch {
463fa5d8106SClemens Ladisch 	info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
464fa5d8106SClemens Ladisch 	info->count = 1;
465fa5d8106SClemens Ladisch 	info->value.integer.min = 0;
466fa5d8106SClemens Ladisch 	info->value.integer.max = 1;
467fa5d8106SClemens Ladisch 	return 0;
468fa5d8106SClemens Ladisch }
469fa5d8106SClemens Ladisch 
monitor_get(struct snd_kcontrol * ctl,struct snd_ctl_elem_value * value)470fa5d8106SClemens Ladisch static int monitor_get(struct snd_kcontrol *ctl,
471fa5d8106SClemens Ladisch 		       struct snd_ctl_elem_value *value)
472fa5d8106SClemens Ladisch {
473fa5d8106SClemens Ladisch 	struct oxygen *chip = ctl->private_data;
474fa5d8106SClemens Ladisch 	u8 bit = ctl->private_value;
475fa5d8106SClemens Ladisch 	int invert = ctl->private_value & (1 << 8);
476fa5d8106SClemens Ladisch 
477fa5d8106SClemens Ladisch 	value->value.integer.value[0] =
478fa5d8106SClemens Ladisch 		!!invert ^ !!(oxygen_read8(chip, OXYGEN_ADC_MONITOR) & bit);
479fa5d8106SClemens Ladisch 	return 0;
480fa5d8106SClemens Ladisch }
481fa5d8106SClemens Ladisch 
monitor_put(struct snd_kcontrol * ctl,struct snd_ctl_elem_value * value)482fa5d8106SClemens Ladisch static int monitor_put(struct snd_kcontrol *ctl,
483fa5d8106SClemens Ladisch 		       struct snd_ctl_elem_value *value)
484fa5d8106SClemens Ladisch {
485fa5d8106SClemens Ladisch 	struct oxygen *chip = ctl->private_data;
486fa5d8106SClemens Ladisch 	u8 bit = ctl->private_value;
487fa5d8106SClemens Ladisch 	int invert = ctl->private_value & (1 << 8);
488fa5d8106SClemens Ladisch 	u8 oldreg, newreg;
489fa5d8106SClemens Ladisch 	int changed;
490fa5d8106SClemens Ladisch 
491fa5d8106SClemens Ladisch 	spin_lock_irq(&chip->reg_lock);
492fa5d8106SClemens Ladisch 	oldreg = oxygen_read8(chip, OXYGEN_ADC_MONITOR);
493fa5d8106SClemens Ladisch 	if ((!!value->value.integer.value[0] ^ !!invert) != 0)
494fa5d8106SClemens Ladisch 		newreg = oldreg | bit;
495fa5d8106SClemens Ladisch 	else
496fa5d8106SClemens Ladisch 		newreg = oldreg & ~bit;
497fa5d8106SClemens Ladisch 	changed = newreg != oldreg;
498fa5d8106SClemens Ladisch 	if (changed)
499fa5d8106SClemens Ladisch 		oxygen_write8(chip, OXYGEN_ADC_MONITOR, newreg);
500fa5d8106SClemens Ladisch 	spin_unlock_irq(&chip->reg_lock);
501fa5d8106SClemens Ladisch 	return changed;
502fa5d8106SClemens Ladisch }
503fa5d8106SClemens Ladisch 
ac97_switch_get(struct snd_kcontrol * ctl,struct snd_ctl_elem_value * value)504d0ce9946SClemens Ladisch static int ac97_switch_get(struct snd_kcontrol *ctl,
505d0ce9946SClemens Ladisch 			   struct snd_ctl_elem_value *value)
506d0ce9946SClemens Ladisch {
507d0ce9946SClemens Ladisch 	struct oxygen *chip = ctl->private_data;
508a3601560SClemens Ladisch 	unsigned int codec = (ctl->private_value >> 24) & 1;
509d0ce9946SClemens Ladisch 	unsigned int index = ctl->private_value & 0xff;
510d0ce9946SClemens Ladisch 	unsigned int bitnr = (ctl->private_value >> 8) & 0xff;
511d0ce9946SClemens Ladisch 	int invert = ctl->private_value & (1 << 16);
512d0ce9946SClemens Ladisch 	u16 reg;
513d0ce9946SClemens Ladisch 
514d0ce9946SClemens Ladisch 	mutex_lock(&chip->mutex);
515a3601560SClemens Ladisch 	reg = oxygen_read_ac97(chip, codec, index);
516d0ce9946SClemens Ladisch 	mutex_unlock(&chip->mutex);
517d0ce9946SClemens Ladisch 	if (!(reg & (1 << bitnr)) ^ !invert)
518d0ce9946SClemens Ladisch 		value->value.integer.value[0] = 1;
519d0ce9946SClemens Ladisch 	else
520d0ce9946SClemens Ladisch 		value->value.integer.value[0] = 0;
521d0ce9946SClemens Ladisch 	return 0;
522d0ce9946SClemens Ladisch }
523d0ce9946SClemens Ladisch 
mute_ac97_ctl(struct oxygen * chip,unsigned int control)524e97f7999SClemens Ladisch static void mute_ac97_ctl(struct oxygen *chip, unsigned int control)
525e97f7999SClemens Ladisch {
5263d839e5bSClemens Ladisch 	unsigned int priv_idx;
527e97f7999SClemens Ladisch 	u16 value;
528e97f7999SClemens Ladisch 
5293d839e5bSClemens Ladisch 	if (!chip->controls[control])
5303d839e5bSClemens Ladisch 		return;
5313d839e5bSClemens Ladisch 	priv_idx = chip->controls[control]->private_value & 0xff;
532e97f7999SClemens Ladisch 	value = oxygen_read_ac97(chip, 0, priv_idx);
533e97f7999SClemens Ladisch 	if (!(value & 0x8000)) {
534e97f7999SClemens Ladisch 		oxygen_write_ac97(chip, 0, priv_idx, value | 0x8000);
5359bd6a73aSClemens Ladisch 		if (chip->model.ac97_switch)
5369bd6a73aSClemens Ladisch 			chip->model.ac97_switch(chip, priv_idx, 0x8000);
537e97f7999SClemens Ladisch 		snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
538e97f7999SClemens Ladisch 			       &chip->controls[control]->id);
539e97f7999SClemens Ladisch 	}
540e97f7999SClemens Ladisch }
541e97f7999SClemens Ladisch 
ac97_switch_put(struct snd_kcontrol * ctl,struct snd_ctl_elem_value * value)542d0ce9946SClemens Ladisch static int ac97_switch_put(struct snd_kcontrol *ctl,
543d0ce9946SClemens Ladisch 			   struct snd_ctl_elem_value *value)
544d0ce9946SClemens Ladisch {
545d0ce9946SClemens Ladisch 	struct oxygen *chip = ctl->private_data;
546a3601560SClemens Ladisch 	unsigned int codec = (ctl->private_value >> 24) & 1;
547d0ce9946SClemens Ladisch 	unsigned int index = ctl->private_value & 0xff;
548d0ce9946SClemens Ladisch 	unsigned int bitnr = (ctl->private_value >> 8) & 0xff;
549d0ce9946SClemens Ladisch 	int invert = ctl->private_value & (1 << 16);
550d0ce9946SClemens Ladisch 	u16 oldreg, newreg;
551d0ce9946SClemens Ladisch 	int change;
552d0ce9946SClemens Ladisch 
553d0ce9946SClemens Ladisch 	mutex_lock(&chip->mutex);
554a3601560SClemens Ladisch 	oldreg = oxygen_read_ac97(chip, codec, index);
555d0ce9946SClemens Ladisch 	newreg = oldreg;
556d0ce9946SClemens Ladisch 	if (!value->value.integer.value[0] ^ !invert)
557d0ce9946SClemens Ladisch 		newreg |= 1 << bitnr;
558d0ce9946SClemens Ladisch 	else
559d0ce9946SClemens Ladisch 		newreg &= ~(1 << bitnr);
560d0ce9946SClemens Ladisch 	change = newreg != oldreg;
561d0ce9946SClemens Ladisch 	if (change) {
562a3601560SClemens Ladisch 		oxygen_write_ac97(chip, codec, index, newreg);
5639bd6a73aSClemens Ladisch 		if (codec == 0 && chip->model.ac97_switch)
5649bd6a73aSClemens Ladisch 			chip->model.ac97_switch(chip, index, newreg & 0x8000);
565e97f7999SClemens Ladisch 		if (index == AC97_LINE) {
566e97f7999SClemens Ladisch 			oxygen_write_ac97_masked(chip, 0, CM9780_GPIO_STATUS,
567e97f7999SClemens Ladisch 						 newreg & 0x8000 ?
568e97f7999SClemens Ladisch 						 CM9780_GPO0 : 0, CM9780_GPO0);
569e97f7999SClemens Ladisch 			if (!(newreg & 0x8000)) {
570e97f7999SClemens Ladisch 				mute_ac97_ctl(chip, CONTROL_MIC_CAPTURE_SWITCH);
571e97f7999SClemens Ladisch 				mute_ac97_ctl(chip, CONTROL_CD_CAPTURE_SWITCH);
572e97f7999SClemens Ladisch 				mute_ac97_ctl(chip, CONTROL_AUX_CAPTURE_SWITCH);
573e97f7999SClemens Ladisch 			}
574e97f7999SClemens Ladisch 		} else if ((index == AC97_MIC || index == AC97_CD ||
575e97f7999SClemens Ladisch 			    index == AC97_VIDEO || index == AC97_AUX) &&
576e97f7999SClemens Ladisch 			   bitnr == 15 && !(newreg & 0x8000)) {
577e97f7999SClemens Ladisch 			mute_ac97_ctl(chip, CONTROL_LINE_CAPTURE_SWITCH);
578e97f7999SClemens Ladisch 			oxygen_write_ac97_masked(chip, 0, CM9780_GPIO_STATUS,
579e97f7999SClemens Ladisch 						 CM9780_GPO0, CM9780_GPO0);
580e97f7999SClemens Ladisch 		}
581d0ce9946SClemens Ladisch 	}
582d0ce9946SClemens Ladisch 	mutex_unlock(&chip->mutex);
583d0ce9946SClemens Ladisch 	return change;
584d0ce9946SClemens Ladisch }
585d0ce9946SClemens Ladisch 
ac97_volume_info(struct snd_kcontrol * ctl,struct snd_ctl_elem_info * info)586d0ce9946SClemens Ladisch static int ac97_volume_info(struct snd_kcontrol *ctl,
587d0ce9946SClemens Ladisch 			    struct snd_ctl_elem_info *info)
588d0ce9946SClemens Ladisch {
58914744d7dSClemens Ladisch 	int stereo = (ctl->private_value >> 16) & 1;
59014744d7dSClemens Ladisch 
591d0ce9946SClemens Ladisch 	info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
59214744d7dSClemens Ladisch 	info->count = stereo ? 2 : 1;
593d0ce9946SClemens Ladisch 	info->value.integer.min = 0;
594d0ce9946SClemens Ladisch 	info->value.integer.max = 0x1f;
595d0ce9946SClemens Ladisch 	return 0;
596d0ce9946SClemens Ladisch }
597d0ce9946SClemens Ladisch 
ac97_volume_get(struct snd_kcontrol * ctl,struct snd_ctl_elem_value * value)598d0ce9946SClemens Ladisch static int ac97_volume_get(struct snd_kcontrol *ctl,
599d0ce9946SClemens Ladisch 			   struct snd_ctl_elem_value *value)
600d0ce9946SClemens Ladisch {
601d0ce9946SClemens Ladisch 	struct oxygen *chip = ctl->private_data;
602a3601560SClemens Ladisch 	unsigned int codec = (ctl->private_value >> 24) & 1;
60314744d7dSClemens Ladisch 	int stereo = (ctl->private_value >> 16) & 1;
604a3601560SClemens Ladisch 	unsigned int index = ctl->private_value & 0xff;
605d0ce9946SClemens Ladisch 	u16 reg;
606d0ce9946SClemens Ladisch 
607d0ce9946SClemens Ladisch 	mutex_lock(&chip->mutex);
608a3601560SClemens Ladisch 	reg = oxygen_read_ac97(chip, codec, index);
609d0ce9946SClemens Ladisch 	mutex_unlock(&chip->mutex);
6102492250eSClemens Ladisch 	if (!stereo) {
611d0ce9946SClemens Ladisch 		value->value.integer.value[0] = 31 - (reg & 0x1f);
6122492250eSClemens Ladisch 	} else {
6132492250eSClemens Ladisch 		value->value.integer.value[0] = 31 - ((reg >> 8) & 0x1f);
6142492250eSClemens Ladisch 		value->value.integer.value[1] = 31 - (reg & 0x1f);
6152492250eSClemens Ladisch 	}
616d0ce9946SClemens Ladisch 	return 0;
617d0ce9946SClemens Ladisch }
618d0ce9946SClemens Ladisch 
ac97_volume_put(struct snd_kcontrol * ctl,struct snd_ctl_elem_value * value)619d0ce9946SClemens Ladisch static int ac97_volume_put(struct snd_kcontrol *ctl,
620d0ce9946SClemens Ladisch 			   struct snd_ctl_elem_value *value)
621d0ce9946SClemens Ladisch {
622d0ce9946SClemens Ladisch 	struct oxygen *chip = ctl->private_data;
623a3601560SClemens Ladisch 	unsigned int codec = (ctl->private_value >> 24) & 1;
62414744d7dSClemens Ladisch 	int stereo = (ctl->private_value >> 16) & 1;
625a3601560SClemens Ladisch 	unsigned int index = ctl->private_value & 0xff;
626d0ce9946SClemens Ladisch 	u16 oldreg, newreg;
627d0ce9946SClemens Ladisch 	int change;
628d0ce9946SClemens Ladisch 
629d0ce9946SClemens Ladisch 	mutex_lock(&chip->mutex);
630a3601560SClemens Ladisch 	oldreg = oxygen_read_ac97(chip, codec, index);
6312492250eSClemens Ladisch 	if (!stereo) {
6322492250eSClemens Ladisch 		newreg = oldreg & ~0x1f;
6332492250eSClemens Ladisch 		newreg |= 31 - (value->value.integer.value[0] & 0x1f);
6342492250eSClemens Ladisch 	} else {
6352492250eSClemens Ladisch 		newreg = oldreg & ~0x1f1f;
6362492250eSClemens Ladisch 		newreg |= (31 - (value->value.integer.value[0] & 0x1f)) << 8;
6372492250eSClemens Ladisch 		newreg |= 31 - (value->value.integer.value[1] & 0x1f);
6382492250eSClemens Ladisch 	}
639d0ce9946SClemens Ladisch 	change = newreg != oldreg;
640d0ce9946SClemens Ladisch 	if (change)
641a3601560SClemens Ladisch 		oxygen_write_ac97(chip, codec, index, newreg);
642d0ce9946SClemens Ladisch 	mutex_unlock(&chip->mutex);
643d0ce9946SClemens Ladisch 	return change;
644d0ce9946SClemens Ladisch }
645d0ce9946SClemens Ladisch 
mic_fmic_source_info(struct snd_kcontrol * ctl,struct snd_ctl_elem_info * info)646e96f38f7SClemens Ladisch static int mic_fmic_source_info(struct snd_kcontrol *ctl,
647e96f38f7SClemens Ladisch 			   struct snd_ctl_elem_info *info)
648e96f38f7SClemens Ladisch {
649e96f38f7SClemens Ladisch 	static const char *const names[] = { "Mic Jack", "Front Panel" };
650e96f38f7SClemens Ladisch 
6519600732bSClemens Ladisch 	return snd_ctl_enum_info(info, 1, 2, names);
652e96f38f7SClemens Ladisch }
653e96f38f7SClemens Ladisch 
mic_fmic_source_get(struct snd_kcontrol * ctl,struct snd_ctl_elem_value * value)654e96f38f7SClemens Ladisch static int mic_fmic_source_get(struct snd_kcontrol *ctl,
655e96f38f7SClemens Ladisch 			       struct snd_ctl_elem_value *value)
656e96f38f7SClemens Ladisch {
657e96f38f7SClemens Ladisch 	struct oxygen *chip = ctl->private_data;
658e96f38f7SClemens Ladisch 
659e96f38f7SClemens Ladisch 	mutex_lock(&chip->mutex);
660e96f38f7SClemens Ladisch 	value->value.enumerated.item[0] =
661e96f38f7SClemens Ladisch 		!!(oxygen_read_ac97(chip, 0, CM9780_JACK) & CM9780_FMIC2MIC);
662e96f38f7SClemens Ladisch 	mutex_unlock(&chip->mutex);
663e96f38f7SClemens Ladisch 	return 0;
664e96f38f7SClemens Ladisch }
665e96f38f7SClemens Ladisch 
mic_fmic_source_put(struct snd_kcontrol * ctl,struct snd_ctl_elem_value * value)666e96f38f7SClemens Ladisch static int mic_fmic_source_put(struct snd_kcontrol *ctl,
667e96f38f7SClemens Ladisch 			       struct snd_ctl_elem_value *value)
668e96f38f7SClemens Ladisch {
669e96f38f7SClemens Ladisch 	struct oxygen *chip = ctl->private_data;
670e96f38f7SClemens Ladisch 	u16 oldreg, newreg;
671e96f38f7SClemens Ladisch 	int change;
672e96f38f7SClemens Ladisch 
673e96f38f7SClemens Ladisch 	mutex_lock(&chip->mutex);
674e96f38f7SClemens Ladisch 	oldreg = oxygen_read_ac97(chip, 0, CM9780_JACK);
675e96f38f7SClemens Ladisch 	if (value->value.enumerated.item[0])
676e96f38f7SClemens Ladisch 		newreg = oldreg | CM9780_FMIC2MIC;
677e96f38f7SClemens Ladisch 	else
678e96f38f7SClemens Ladisch 		newreg = oldreg & ~CM9780_FMIC2MIC;
679e96f38f7SClemens Ladisch 	change = newreg != oldreg;
680e96f38f7SClemens Ladisch 	if (change)
681e96f38f7SClemens Ladisch 		oxygen_write_ac97(chip, 0, CM9780_JACK, newreg);
682e96f38f7SClemens Ladisch 	mutex_unlock(&chip->mutex);
683e96f38f7SClemens Ladisch 	return change;
684e96f38f7SClemens Ladisch }
685e96f38f7SClemens Ladisch 
ac97_fp_rec_volume_info(struct snd_kcontrol * ctl,struct snd_ctl_elem_info * info)686a3601560SClemens Ladisch static int ac97_fp_rec_volume_info(struct snd_kcontrol *ctl,
687a3601560SClemens Ladisch 				   struct snd_ctl_elem_info *info)
688a3601560SClemens Ladisch {
689a3601560SClemens Ladisch 	info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
690a3601560SClemens Ladisch 	info->count = 2;
691a3601560SClemens Ladisch 	info->value.integer.min = 0;
692a3601560SClemens Ladisch 	info->value.integer.max = 7;
693a3601560SClemens Ladisch 	return 0;
694a3601560SClemens Ladisch }
695a3601560SClemens Ladisch 
ac97_fp_rec_volume_get(struct snd_kcontrol * ctl,struct snd_ctl_elem_value * value)696a3601560SClemens Ladisch static int ac97_fp_rec_volume_get(struct snd_kcontrol *ctl,
697a3601560SClemens Ladisch 				  struct snd_ctl_elem_value *value)
698a3601560SClemens Ladisch {
699a3601560SClemens Ladisch 	struct oxygen *chip = ctl->private_data;
700a3601560SClemens Ladisch 	u16 reg;
701a3601560SClemens Ladisch 
702a3601560SClemens Ladisch 	mutex_lock(&chip->mutex);
703a3601560SClemens Ladisch 	reg = oxygen_read_ac97(chip, 1, AC97_REC_GAIN);
704a3601560SClemens Ladisch 	mutex_unlock(&chip->mutex);
705a3601560SClemens Ladisch 	value->value.integer.value[0] = reg & 7;
706a3601560SClemens Ladisch 	value->value.integer.value[1] = (reg >> 8) & 7;
707a3601560SClemens Ladisch 	return 0;
708a3601560SClemens Ladisch }
709a3601560SClemens Ladisch 
ac97_fp_rec_volume_put(struct snd_kcontrol * ctl,struct snd_ctl_elem_value * value)710a3601560SClemens Ladisch static int ac97_fp_rec_volume_put(struct snd_kcontrol *ctl,
711a3601560SClemens Ladisch 				  struct snd_ctl_elem_value *value)
712a3601560SClemens Ladisch {
713a3601560SClemens Ladisch 	struct oxygen *chip = ctl->private_data;
714a3601560SClemens Ladisch 	u16 oldreg, newreg;
715a3601560SClemens Ladisch 	int change;
716a3601560SClemens Ladisch 
717a3601560SClemens Ladisch 	mutex_lock(&chip->mutex);
718a3601560SClemens Ladisch 	oldreg = oxygen_read_ac97(chip, 1, AC97_REC_GAIN);
719a3601560SClemens Ladisch 	newreg = oldreg & ~0x0707;
720a3601560SClemens Ladisch 	newreg = newreg | (value->value.integer.value[0] & 7);
721*0d7b0c4aSTakashi Iwai 	newreg = newreg | ((value->value.integer.value[1] & 7) << 8);
722a3601560SClemens Ladisch 	change = newreg != oldreg;
723a3601560SClemens Ladisch 	if (change)
724a3601560SClemens Ladisch 		oxygen_write_ac97(chip, 1, AC97_REC_GAIN, newreg);
725a3601560SClemens Ladisch 	mutex_unlock(&chip->mutex);
726a3601560SClemens Ladisch 	return change;
727a3601560SClemens Ladisch }
728a3601560SClemens Ladisch 
729a3601560SClemens Ladisch #define AC97_SWITCH(xname, codec, index, bitnr, invert) { \
730d0ce9946SClemens Ladisch 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
731d0ce9946SClemens Ladisch 		.name = xname, \
732d0ce9946SClemens Ladisch 		.info = snd_ctl_boolean_mono_info, \
733d0ce9946SClemens Ladisch 		.get = ac97_switch_get, \
734d0ce9946SClemens Ladisch 		.put = ac97_switch_put, \
735a3601560SClemens Ladisch 		.private_value = ((codec) << 24) | ((invert) << 16) | \
736a3601560SClemens Ladisch 				 ((bitnr) << 8) | (index), \
737d0ce9946SClemens Ladisch 	}
73814744d7dSClemens Ladisch #define AC97_VOLUME(xname, codec, index, stereo) { \
739d0ce9946SClemens Ladisch 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
740d0ce9946SClemens Ladisch 		.name = xname, \
741a3601560SClemens Ladisch 		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
742a3601560SClemens Ladisch 			  SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
743d0ce9946SClemens Ladisch 		.info = ac97_volume_info, \
744d0ce9946SClemens Ladisch 		.get = ac97_volume_get, \
745d0ce9946SClemens Ladisch 		.put = ac97_volume_put, \
746d0ce9946SClemens Ladisch 		.tlv = { .p = ac97_db_scale, }, \
74714744d7dSClemens Ladisch 		.private_value = ((codec) << 24) | ((stereo) << 16) | (index), \
748d0ce9946SClemens Ladisch 	}
749d0ce9946SClemens Ladisch 
7509a0b3792SClemens Ladisch static DECLARE_TLV_DB_SCALE(monitor_db_scale, -600, 600, 0);
751d0ce9946SClemens Ladisch static DECLARE_TLV_DB_SCALE(ac97_db_scale, -3450, 150, 0);
752a3601560SClemens Ladisch static DECLARE_TLV_DB_SCALE(ac97_rec_db_scale, 0, 150, 0);
753d0ce9946SClemens Ladisch 
754d0ce9946SClemens Ladisch static const struct snd_kcontrol_new controls[] = {
755d0ce9946SClemens Ladisch 	{
756d0ce9946SClemens Ladisch 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
757fb920b7dSClemens Ladisch 		.name = "Master Playback Volume",
758ccc80fb4SClemens Ladisch 		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
759d0ce9946SClemens Ladisch 		.info = dac_volume_info,
760d0ce9946SClemens Ladisch 		.get = dac_volume_get,
761d0ce9946SClemens Ladisch 		.put = dac_volume_put,
762d0ce9946SClemens Ladisch 	},
763d0ce9946SClemens Ladisch 	{
764d0ce9946SClemens Ladisch 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
765fb920b7dSClemens Ladisch 		.name = "Master Playback Switch",
766d0ce9946SClemens Ladisch 		.info = snd_ctl_boolean_mono_info,
767d0ce9946SClemens Ladisch 		.get = dac_mute_get,
768d0ce9946SClemens Ladisch 		.put = dac_mute_put,
769d0ce9946SClemens Ladisch 	},
770d0ce9946SClemens Ladisch 	{
771d0ce9946SClemens Ladisch 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
772d0ce9946SClemens Ladisch 		.name = "Stereo Upmixing",
773d0ce9946SClemens Ladisch 		.info = upmix_info,
774d0ce9946SClemens Ladisch 		.get = upmix_get,
775d0ce9946SClemens Ladisch 		.put = upmix_put,
776d0ce9946SClemens Ladisch 	},
77720eb26a2SClemens Ladisch };
77820eb26a2SClemens Ladisch 
77920eb26a2SClemens Ladisch static const struct snd_kcontrol_new spdif_output_controls[] = {
780d0ce9946SClemens Ladisch 	{
781d0ce9946SClemens Ladisch 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
782d0ce9946SClemens Ladisch 		.name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, SWITCH),
783d0ce9946SClemens Ladisch 		.info = snd_ctl_boolean_mono_info,
784d0ce9946SClemens Ladisch 		.get = spdif_switch_get,
785d0ce9946SClemens Ladisch 		.put = spdif_switch_put,
786d0ce9946SClemens Ladisch 	},
787d0ce9946SClemens Ladisch 	{
788d0ce9946SClemens Ladisch 		.iface = SNDRV_CTL_ELEM_IFACE_PCM,
789d0ce9946SClemens Ladisch 		.device = 1,
790d0ce9946SClemens Ladisch 		.name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
791d0ce9946SClemens Ladisch 		.info = spdif_info,
792d0ce9946SClemens Ladisch 		.get = spdif_default_get,
793d0ce9946SClemens Ladisch 		.put = spdif_default_put,
794d0ce9946SClemens Ladisch 	},
795d0ce9946SClemens Ladisch 	{
796d0ce9946SClemens Ladisch 		.iface = SNDRV_CTL_ELEM_IFACE_PCM,
797d0ce9946SClemens Ladisch 		.device = 1,
798d0ce9946SClemens Ladisch 		.name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, CON_MASK),
799d0ce9946SClemens Ladisch 		.access = SNDRV_CTL_ELEM_ACCESS_READ,
800d0ce9946SClemens Ladisch 		.info = spdif_info,
801d0ce9946SClemens Ladisch 		.get = spdif_mask_get,
802d0ce9946SClemens Ladisch 	},
803d0ce9946SClemens Ladisch 	{
804d0ce9946SClemens Ladisch 		.iface = SNDRV_CTL_ELEM_IFACE_PCM,
805d0ce9946SClemens Ladisch 		.device = 1,
806d0ce9946SClemens Ladisch 		.name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, PCM_STREAM),
807d0ce9946SClemens Ladisch 		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
808d0ce9946SClemens Ladisch 			  SNDRV_CTL_ELEM_ACCESS_INACTIVE,
809d0ce9946SClemens Ladisch 		.info = spdif_info,
810d0ce9946SClemens Ladisch 		.get = spdif_pcm_get,
811d0ce9946SClemens Ladisch 		.put = spdif_pcm_put,
812d0ce9946SClemens Ladisch 	},
8131d98c7d4SClemens Ladisch };
8141d98c7d4SClemens Ladisch 
8151d98c7d4SClemens Ladisch static const struct snd_kcontrol_new spdif_input_controls[] = {
816d0ce9946SClemens Ladisch 	{
817d0ce9946SClemens Ladisch 		.iface = SNDRV_CTL_ELEM_IFACE_PCM,
818d0ce9946SClemens Ladisch 		.device = 1,
819d0ce9946SClemens Ladisch 		.name = SNDRV_CTL_NAME_IEC958("", CAPTURE, MASK),
820d0ce9946SClemens Ladisch 		.access = SNDRV_CTL_ELEM_ACCESS_READ,
821d0ce9946SClemens Ladisch 		.info = spdif_info,
822d0ce9946SClemens Ladisch 		.get = spdif_input_mask_get,
823d0ce9946SClemens Ladisch 	},
824d0ce9946SClemens Ladisch 	{
825d0ce9946SClemens Ladisch 		.iface = SNDRV_CTL_ELEM_IFACE_PCM,
826d0ce9946SClemens Ladisch 		.device = 1,
827d0ce9946SClemens Ladisch 		.name = SNDRV_CTL_NAME_IEC958("", CAPTURE, DEFAULT),
828d0ce9946SClemens Ladisch 		.access = SNDRV_CTL_ELEM_ACCESS_READ,
829d0ce9946SClemens Ladisch 		.info = spdif_info,
830d0ce9946SClemens Ladisch 		.get = spdif_input_default_get,
831d0ce9946SClemens Ladisch 	},
83202f21c9dSClemens Ladisch 	{
83302f21c9dSClemens Ladisch 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
83402f21c9dSClemens Ladisch 		.name = SNDRV_CTL_NAME_IEC958("Loopback ", NONE, SWITCH),
83502f21c9dSClemens Ladisch 		.info = snd_ctl_boolean_mono_info,
836860cffd5SClemens Ladisch 		.get = spdif_bit_switch_get,
837860cffd5SClemens Ladisch 		.put = spdif_bit_switch_put,
838860cffd5SClemens Ladisch 		.private_value = OXYGEN_SPDIF_LOOPBACK,
839860cffd5SClemens Ladisch 	},
840860cffd5SClemens Ladisch 	{
841860cffd5SClemens Ladisch 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
842860cffd5SClemens Ladisch 		.name = SNDRV_CTL_NAME_IEC958("Validity Check ",CAPTURE,SWITCH),
843860cffd5SClemens Ladisch 		.info = snd_ctl_boolean_mono_info,
844860cffd5SClemens Ladisch 		.get = spdif_bit_switch_get,
845860cffd5SClemens Ladisch 		.put = spdif_bit_switch_put,
846860cffd5SClemens Ladisch 		.private_value = OXYGEN_SPDIF_SPDVALID,
84702f21c9dSClemens Ladisch 	},
84831c77643SClemens Ladisch };
84931c77643SClemens Ladisch 
850f009ad9bSClemens Ladisch static const struct {
851f009ad9bSClemens Ladisch 	unsigned int pcm_dev;
852f009ad9bSClemens Ladisch 	struct snd_kcontrol_new controls[2];
853f009ad9bSClemens Ladisch } monitor_controls[] = {
854f009ad9bSClemens Ladisch 	{
855f009ad9bSClemens Ladisch 		.pcm_dev = CAPTURE_0_FROM_I2S_1,
856f009ad9bSClemens Ladisch 		.controls = {
857fa5d8106SClemens Ladisch 			{
858fa5d8106SClemens Ladisch 				.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
85962428f7bSClemens Ladisch 				.name = "Analog Input Monitor Playback Switch",
860fa5d8106SClemens Ladisch 				.info = snd_ctl_boolean_mono_info,
861fa5d8106SClemens Ladisch 				.get = monitor_get,
862fa5d8106SClemens Ladisch 				.put = monitor_put,
863fa5d8106SClemens Ladisch 				.private_value = OXYGEN_ADC_MONITOR_A,
864fa5d8106SClemens Ladisch 			},
865fa5d8106SClemens Ladisch 			{
866fa5d8106SClemens Ladisch 				.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
86762428f7bSClemens Ladisch 				.name = "Analog Input Monitor Playback Volume",
868fa5d8106SClemens Ladisch 				.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
869fa5d8106SClemens Ladisch 					  SNDRV_CTL_ELEM_ACCESS_TLV_READ,
870fa5d8106SClemens Ladisch 				.info = monitor_volume_info,
871fa5d8106SClemens Ladisch 				.get = monitor_get,
872fa5d8106SClemens Ladisch 				.put = monitor_put,
873f009ad9bSClemens Ladisch 				.private_value = OXYGEN_ADC_MONITOR_A_HALF_VOL
874f009ad9bSClemens Ladisch 						| (1 << 8),
875fa5d8106SClemens Ladisch 				.tlv = { .p = monitor_db_scale, },
876fa5d8106SClemens Ladisch 			},
877f009ad9bSClemens Ladisch 		},
878f009ad9bSClemens Ladisch 	},
879f009ad9bSClemens Ladisch 	{
880f009ad9bSClemens Ladisch 		.pcm_dev = CAPTURE_0_FROM_I2S_2,
881f009ad9bSClemens Ladisch 		.controls = {
882fa5d8106SClemens Ladisch 			{
883fa5d8106SClemens Ladisch 				.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
88462428f7bSClemens Ladisch 				.name = "Analog Input Monitor Playback Switch",
885fa5d8106SClemens Ladisch 				.info = snd_ctl_boolean_mono_info,
886fa5d8106SClemens Ladisch 				.get = monitor_get,
887fa5d8106SClemens Ladisch 				.put = monitor_put,
888fa5d8106SClemens Ladisch 				.private_value = OXYGEN_ADC_MONITOR_B,
889fa5d8106SClemens Ladisch 			},
890fa5d8106SClemens Ladisch 			{
891fa5d8106SClemens Ladisch 				.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
89262428f7bSClemens Ladisch 				.name = "Analog Input Monitor Playback Volume",
893fa5d8106SClemens Ladisch 				.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
894fa5d8106SClemens Ladisch 					  SNDRV_CTL_ELEM_ACCESS_TLV_READ,
895fa5d8106SClemens Ladisch 				.info = monitor_volume_info,
896fa5d8106SClemens Ladisch 				.get = monitor_get,
897fa5d8106SClemens Ladisch 				.put = monitor_put,
898f009ad9bSClemens Ladisch 				.private_value = OXYGEN_ADC_MONITOR_B_HALF_VOL
899f009ad9bSClemens Ladisch 						| (1 << 8),
900fa5d8106SClemens Ladisch 				.tlv = { .p = monitor_db_scale, },
901fa5d8106SClemens Ladisch 			},
902f009ad9bSClemens Ladisch 		},
903f009ad9bSClemens Ladisch 	},
904f009ad9bSClemens Ladisch 	{
905f009ad9bSClemens Ladisch 		.pcm_dev = CAPTURE_2_FROM_I2S_2,
906f009ad9bSClemens Ladisch 		.controls = {
907fa5d8106SClemens Ladisch 			{
908fa5d8106SClemens Ladisch 				.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
90962428f7bSClemens Ladisch 				.name = "Analog Input Monitor Playback Switch",
910fa5d8106SClemens Ladisch 				.index = 1,
911fa5d8106SClemens Ladisch 				.info = snd_ctl_boolean_mono_info,
912fa5d8106SClemens Ladisch 				.get = monitor_get,
913fa5d8106SClemens Ladisch 				.put = monitor_put,
914fa5d8106SClemens Ladisch 				.private_value = OXYGEN_ADC_MONITOR_B,
915fa5d8106SClemens Ladisch 			},
916fa5d8106SClemens Ladisch 			{
917fa5d8106SClemens Ladisch 				.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
91862428f7bSClemens Ladisch 				.name = "Analog Input Monitor Playback Volume",
919fa5d8106SClemens Ladisch 				.index = 1,
920fa5d8106SClemens Ladisch 				.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
921fa5d8106SClemens Ladisch 					  SNDRV_CTL_ELEM_ACCESS_TLV_READ,
922fa5d8106SClemens Ladisch 				.info = monitor_volume_info,
923fa5d8106SClemens Ladisch 				.get = monitor_get,
924fa5d8106SClemens Ladisch 				.put = monitor_put,
925f009ad9bSClemens Ladisch 				.private_value = OXYGEN_ADC_MONITOR_B_HALF_VOL
926f009ad9bSClemens Ladisch 						| (1 << 8),
927fa5d8106SClemens Ladisch 				.tlv = { .p = monitor_db_scale, },
928fa5d8106SClemens Ladisch 			},
929f009ad9bSClemens Ladisch 		},
930f009ad9bSClemens Ladisch 	},
931f009ad9bSClemens Ladisch 	{
9320902fbb9SClemens Ladisch 		.pcm_dev = CAPTURE_3_FROM_I2S_3,
9330902fbb9SClemens Ladisch 		.controls = {
9340902fbb9SClemens Ladisch 			{
9350902fbb9SClemens Ladisch 				.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9360902fbb9SClemens Ladisch 				.name = "Analog Input Monitor Playback Switch",
9370902fbb9SClemens Ladisch 				.index = 2,
9380902fbb9SClemens Ladisch 				.info = snd_ctl_boolean_mono_info,
9390902fbb9SClemens Ladisch 				.get = monitor_get,
9400902fbb9SClemens Ladisch 				.put = monitor_put,
9410902fbb9SClemens Ladisch 				.private_value = OXYGEN_ADC_MONITOR_C,
9420902fbb9SClemens Ladisch 			},
9430902fbb9SClemens Ladisch 			{
9440902fbb9SClemens Ladisch 				.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9450902fbb9SClemens Ladisch 				.name = "Analog Input Monitor Playback Volume",
9460902fbb9SClemens Ladisch 				.index = 2,
9470902fbb9SClemens Ladisch 				.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
9480902fbb9SClemens Ladisch 					  SNDRV_CTL_ELEM_ACCESS_TLV_READ,
9490902fbb9SClemens Ladisch 				.info = monitor_volume_info,
9500902fbb9SClemens Ladisch 				.get = monitor_get,
9510902fbb9SClemens Ladisch 				.put = monitor_put,
9520902fbb9SClemens Ladisch 				.private_value = OXYGEN_ADC_MONITOR_C_HALF_VOL
9530902fbb9SClemens Ladisch 						| (1 << 8),
9540902fbb9SClemens Ladisch 				.tlv = { .p = monitor_db_scale, },
9550902fbb9SClemens Ladisch 			},
9560902fbb9SClemens Ladisch 		},
9570902fbb9SClemens Ladisch 	},
9580902fbb9SClemens Ladisch 	{
959f009ad9bSClemens Ladisch 		.pcm_dev = CAPTURE_1_FROM_SPDIF,
960f009ad9bSClemens Ladisch 		.controls = {
961fa5d8106SClemens Ladisch 			{
962fa5d8106SClemens Ladisch 				.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
96362428f7bSClemens Ladisch 				.name = "Digital Input Monitor Playback Switch",
964fa5d8106SClemens Ladisch 				.info = snd_ctl_boolean_mono_info,
965fa5d8106SClemens Ladisch 				.get = monitor_get,
966fa5d8106SClemens Ladisch 				.put = monitor_put,
967fa5d8106SClemens Ladisch 				.private_value = OXYGEN_ADC_MONITOR_C,
968fa5d8106SClemens Ladisch 			},
969fa5d8106SClemens Ladisch 			{
970fa5d8106SClemens Ladisch 				.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
97162428f7bSClemens Ladisch 				.name = "Digital Input Monitor Playback Volume",
972fa5d8106SClemens Ladisch 				.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
973fa5d8106SClemens Ladisch 					  SNDRV_CTL_ELEM_ACCESS_TLV_READ,
974fa5d8106SClemens Ladisch 				.info = monitor_volume_info,
975fa5d8106SClemens Ladisch 				.get = monitor_get,
976fa5d8106SClemens Ladisch 				.put = monitor_put,
977f009ad9bSClemens Ladisch 				.private_value = OXYGEN_ADC_MONITOR_C_HALF_VOL
978f009ad9bSClemens Ladisch 						| (1 << 8),
979fa5d8106SClemens Ladisch 				.tlv = { .p = monitor_db_scale, },
980fa5d8106SClemens Ladisch 			},
981f009ad9bSClemens Ladisch 		},
982f009ad9bSClemens Ladisch 	},
983fa5d8106SClemens Ladisch };
984fa5d8106SClemens Ladisch 
98531c77643SClemens Ladisch static const struct snd_kcontrol_new ac97_controls[] = {
98614744d7dSClemens Ladisch 	AC97_VOLUME("Mic Capture Volume", 0, AC97_MIC, 0),
987a3601560SClemens Ladisch 	AC97_SWITCH("Mic Capture Switch", 0, AC97_MIC, 15, 1),
988a3601560SClemens Ladisch 	AC97_SWITCH("Mic Boost (+20dB)", 0, AC97_MIC, 6, 0),
989e96f38f7SClemens Ladisch 	{
990e96f38f7SClemens Ladisch 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
991e96f38f7SClemens Ladisch 		.name = "Mic Source Capture Enum",
992e96f38f7SClemens Ladisch 		.info = mic_fmic_source_info,
993e96f38f7SClemens Ladisch 		.get = mic_fmic_source_get,
994e96f38f7SClemens Ladisch 		.put = mic_fmic_source_put,
995e96f38f7SClemens Ladisch 	},
996a3601560SClemens Ladisch 	AC97_SWITCH("Line Capture Switch", 0, AC97_LINE, 15, 1),
99714744d7dSClemens Ladisch 	AC97_VOLUME("CD Capture Volume", 0, AC97_CD, 1),
998a3601560SClemens Ladisch 	AC97_SWITCH("CD Capture Switch", 0, AC97_CD, 15, 1),
99914744d7dSClemens Ladisch 	AC97_VOLUME("Aux Capture Volume", 0, AC97_AUX, 1),
1000a3601560SClemens Ladisch 	AC97_SWITCH("Aux Capture Switch", 0, AC97_AUX, 15, 1),
1001a3601560SClemens Ladisch };
1002a3601560SClemens Ladisch 
1003a3601560SClemens Ladisch static const struct snd_kcontrol_new ac97_fp_controls[] = {
100414744d7dSClemens Ladisch 	AC97_VOLUME("Front Panel Playback Volume", 1, AC97_HEADPHONE, 1),
1005a3601560SClemens Ladisch 	AC97_SWITCH("Front Panel Playback Switch", 1, AC97_HEADPHONE, 15, 1),
1006a3601560SClemens Ladisch 	{
1007a3601560SClemens Ladisch 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1008a3601560SClemens Ladisch 		.name = "Front Panel Capture Volume",
1009a3601560SClemens Ladisch 		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
1010a3601560SClemens Ladisch 			  SNDRV_CTL_ELEM_ACCESS_TLV_READ,
1011a3601560SClemens Ladisch 		.info = ac97_fp_rec_volume_info,
1012a3601560SClemens Ladisch 		.get = ac97_fp_rec_volume_get,
1013a3601560SClemens Ladisch 		.put = ac97_fp_rec_volume_put,
1014a3601560SClemens Ladisch 		.tlv = { .p = ac97_rec_db_scale, },
1015a3601560SClemens Ladisch 	},
1016a3601560SClemens Ladisch 	AC97_SWITCH("Front Panel Capture Switch", 1, AC97_REC_GAIN, 15, 1),
1017d0ce9946SClemens Ladisch };
1018d0ce9946SClemens Ladisch 
oxygen_any_ctl_free(struct snd_kcontrol * ctl)1019d0ce9946SClemens Ladisch static void oxygen_any_ctl_free(struct snd_kcontrol *ctl)
1020d0ce9946SClemens Ladisch {
1021d0ce9946SClemens Ladisch 	struct oxygen *chip = ctl->private_data;
102201a3affbSClemens Ladisch 	unsigned int i;
1023d0ce9946SClemens Ladisch 
1024d0ce9946SClemens Ladisch 	/* I'm too lazy to write a function for each control :-) */
102501a3affbSClemens Ladisch 	for (i = 0; i < ARRAY_SIZE(chip->controls); ++i)
102601a3affbSClemens Ladisch 		chip->controls[i] = NULL;
1027d0ce9946SClemens Ladisch }
1028d0ce9946SClemens Ladisch 
add_controls(struct oxygen * chip,const struct snd_kcontrol_new controls[],unsigned int count)102931c77643SClemens Ladisch static int add_controls(struct oxygen *chip,
103031c77643SClemens Ladisch 			const struct snd_kcontrol_new controls[],
103131c77643SClemens Ladisch 			unsigned int count)
1032d0ce9946SClemens Ladisch {
103301a3affbSClemens Ladisch 	static const char *const known_ctl_names[CONTROL_COUNT] = {
103401a3affbSClemens Ladisch 		[CONTROL_SPDIF_PCM] =
103501a3affbSClemens Ladisch 			SNDRV_CTL_NAME_IEC958("", PLAYBACK, PCM_STREAM),
103601a3affbSClemens Ladisch 		[CONTROL_SPDIF_INPUT_BITS] =
103701a3affbSClemens Ladisch 			SNDRV_CTL_NAME_IEC958("", CAPTURE, DEFAULT),
1038893e44baSClemens Ladisch 		[CONTROL_MIC_CAPTURE_SWITCH] = "Mic Capture Switch",
1039893e44baSClemens Ladisch 		[CONTROL_LINE_CAPTURE_SWITCH] = "Line Capture Switch",
1040893e44baSClemens Ladisch 		[CONTROL_CD_CAPTURE_SWITCH] = "CD Capture Switch",
1041893e44baSClemens Ladisch 		[CONTROL_AUX_CAPTURE_SWITCH] = "Aux Capture Switch",
104201a3affbSClemens Ladisch 	};
10439ee92f53SYisheng Xie 	unsigned int i;
1044ccc80fb4SClemens Ladisch 	struct snd_kcontrol_new template;
1045d0ce9946SClemens Ladisch 	struct snd_kcontrol *ctl;
10469ee92f53SYisheng Xie 	int j, err;
1047d0ce9946SClemens Ladisch 
104831c77643SClemens Ladisch 	for (i = 0; i < count; ++i) {
1049ccc80fb4SClemens Ladisch 		template = controls[i];
10509bd6a73aSClemens Ladisch 		if (chip->model.control_filter) {
10519bd6a73aSClemens Ladisch 			err = chip->model.control_filter(&template);
1052ccc80fb4SClemens Ladisch 			if (err < 0)
1053ccc80fb4SClemens Ladisch 				return err;
1054c626026dSClemens Ladisch 			if (err == 1)
1055c626026dSClemens Ladisch 				continue;
10569f9115d8SClemens Ladisch 		}
105775919d7cSClemens Ladisch 		if (!strcmp(template.name, "Stereo Upmixing") &&
10581f4d7be7SClemens Ladisch 		    chip->model.dac_channels_pcm == 2)
105975919d7cSClemens Ladisch 			continue;
1060e96f38f7SClemens Ladisch 		if (!strcmp(template.name, "Mic Source Capture Enum") &&
1061e96f38f7SClemens Ladisch 		    !(chip->model.device_config & AC97_FMIC_SWITCH))
1062e96f38f7SClemens Ladisch 			continue;
1063b6ca8ab3SClemens Ladisch 		if (!strncmp(template.name, "CD Capture ", 11) &&
1064b6ca8ab3SClemens Ladisch 		    !(chip->model.device_config & AC97_CD_INPUT))
1065b6ca8ab3SClemens Ladisch 			continue;
10664972a177SClemens Ladisch 		if (!strcmp(template.name, "Master Playback Volume") &&
10679bd6a73aSClemens Ladisch 		    chip->model.dac_tlv) {
10689bd6a73aSClemens Ladisch 			template.tlv.p = chip->model.dac_tlv;
10694972a177SClemens Ladisch 			template.access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ;
10704972a177SClemens Ladisch 		}
1071e9d88a8bSClemens Ladisch 		ctl = snd_ctl_new1(&template, chip);
1072d0ce9946SClemens Ladisch 		if (!ctl)
1073d0ce9946SClemens Ladisch 			return -ENOMEM;
1074d0ce9946SClemens Ladisch 		err = snd_ctl_add(chip->card, ctl);
1075d0ce9946SClemens Ladisch 		if (err < 0)
1076d0ce9946SClemens Ladisch 			return err;
10779ee92f53SYisheng Xie 		j = match_string(known_ctl_names, CONTROL_COUNT, ctl->id.name);
10789ee92f53SYisheng Xie 		if (j >= 0) {
107901a3affbSClemens Ladisch 			chip->controls[j] = ctl;
1080d0ce9946SClemens Ladisch 			ctl->private_free = oxygen_any_ctl_free;
1081d0ce9946SClemens Ladisch 		}
1082d0ce9946SClemens Ladisch 	}
108331c77643SClemens Ladisch 	return 0;
108431c77643SClemens Ladisch }
108531c77643SClemens Ladisch 
oxygen_mixer_init(struct oxygen * chip)108631c77643SClemens Ladisch int oxygen_mixer_init(struct oxygen *chip)
108731c77643SClemens Ladisch {
1088f009ad9bSClemens Ladisch 	unsigned int i;
108931c77643SClemens Ladisch 	int err;
109031c77643SClemens Ladisch 
109131c77643SClemens Ladisch 	err = add_controls(chip, controls, ARRAY_SIZE(controls));
109231c77643SClemens Ladisch 	if (err < 0)
109331c77643SClemens Ladisch 		return err;
109420eb26a2SClemens Ladisch 	if (chip->model.device_config & PLAYBACK_1_TO_SPDIF) {
109520eb26a2SClemens Ladisch 		err = add_controls(chip, spdif_output_controls,
109620eb26a2SClemens Ladisch 				   ARRAY_SIZE(spdif_output_controls));
109720eb26a2SClemens Ladisch 		if (err < 0)
109820eb26a2SClemens Ladisch 			return err;
109920eb26a2SClemens Ladisch 	}
1100d76596b1SClemens Ladisch 	if (chip->model.device_config & CAPTURE_1_FROM_SPDIF) {
11011d98c7d4SClemens Ladisch 		err = add_controls(chip, spdif_input_controls,
11021d98c7d4SClemens Ladisch 				   ARRAY_SIZE(spdif_input_controls));
11031d98c7d4SClemens Ladisch 		if (err < 0)
11041d98c7d4SClemens Ladisch 			return err;
11051d98c7d4SClemens Ladisch 	}
1106f009ad9bSClemens Ladisch 	for (i = 0; i < ARRAY_SIZE(monitor_controls); ++i) {
1107d76596b1SClemens Ladisch 		if (!(chip->model.device_config & monitor_controls[i].pcm_dev))
1108f009ad9bSClemens Ladisch 			continue;
1109f009ad9bSClemens Ladisch 		err = add_controls(chip, monitor_controls[i].controls,
1110f009ad9bSClemens Ladisch 				   ARRAY_SIZE(monitor_controls[i].controls));
1111fa5d8106SClemens Ladisch 		if (err < 0)
1112fa5d8106SClemens Ladisch 			return err;
1113fa5d8106SClemens Ladisch 	}
111431c77643SClemens Ladisch 	if (chip->has_ac97_0) {
111531c77643SClemens Ladisch 		err = add_controls(chip, ac97_controls,
111631c77643SClemens Ladisch 				   ARRAY_SIZE(ac97_controls));
111731c77643SClemens Ladisch 		if (err < 0)
111831c77643SClemens Ladisch 			return err;
111931c77643SClemens Ladisch 	}
1120a3601560SClemens Ladisch 	if (chip->has_ac97_1) {
1121a3601560SClemens Ladisch 		err = add_controls(chip, ac97_fp_controls,
1122a3601560SClemens Ladisch 				   ARRAY_SIZE(ac97_fp_controls));
1123a3601560SClemens Ladisch 		if (err < 0)
1124a3601560SClemens Ladisch 			return err;
1125a3601560SClemens Ladisch 	}
11269bd6a73aSClemens Ladisch 	return chip->model.mixer_init ? chip->model.mixer_init(chip) : 0;
1127d0ce9946SClemens Ladisch }
1128