brintos

brintos / linux-shallow public Read only

0
0
Text · 24.5 KiB · 1e47e46 Raw
951 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 *   ALSA driver for ICEnsemble ICE1724 (Envy24)4 *5 *   Lowlevel functions for Terratec PHASE 226 *7 *	Copyright (c) 2005 Misha Zhilin <misha@epiphan.com>8 */9 10/* PHASE 22 overview:11 *   Audio controller: VIA Envy24HT-S (slightly trimmed down Envy24HT, 4in/4out)12 *   Analog chip: AK4524 (partially via Philip's 74HCT125)13 *   Digital receiver: CS8414-CS (supported in this release)14 *		PHASE 22 revision 2.0 and Terrasoniq/Musonik TS22PCI have CS841615 *		(support status unknown, please test and report)16 *17 *   Envy connects to AK452418 *	- CS directly from GPIO 1019 *	- CCLK via 74HCT125's gate #4 from GPIO 420 *	- CDTI via 74HCT125's gate #2 from GPIO 521 *		CDTI may be completely blocked by 74HCT125's gate #122 *		controlled by GPIO 323 */24 25/* PHASE 28 overview:26 *   Audio controller: VIA Envy24HT (full untrimmed version, 4in/8out)27 *   Analog chip: WM8770 (8 channel 192k DAC, 2 channel 96k ADC)28 *   Digital receiver: CS8414-CS (supported in this release)29 */30 31#include <linux/delay.h>32#include <linux/interrupt.h>33#include <linux/init.h>34#include <linux/slab.h>35#include <linux/mutex.h>36 37#include <sound/core.h>38 39#include "ice1712.h"40#include "envy24ht.h"41#include "phase.h"42#include <sound/tlv.h>43 44/* AC97 register cache for Phase28 */45struct phase28_spec {46	unsigned short master[2];47	unsigned short vol[8];48};49 50/* WM8770 registers */51#define WM_DAC_ATTEN		0x00	/* DAC1-8 analog attenuation */52#define WM_DAC_MASTER_ATTEN	0x08	/* DAC master analog attenuation */53#define WM_DAC_DIG_ATTEN	0x09	/* DAC1-8 digital attenuation */54#define WM_DAC_DIG_MASTER_ATTEN	0x11	/* DAC master digital attenuation */55#define WM_PHASE_SWAP		0x12	/* DAC phase */56#define WM_DAC_CTRL1		0x13	/* DAC control bits */57#define WM_MUTE			0x14	/* mute controls */58#define WM_DAC_CTRL2		0x15	/* de-emphasis and zefo-flag */59#define WM_INT_CTRL		0x16	/* interface control */60#define WM_MASTER		0x17	/* master clock and mode */61#define WM_POWERDOWN		0x18	/* power-down controls */62#define WM_ADC_GAIN		0x19	/* ADC gain L(19)/R(1a) */63#define WM_ADC_MUX		0x1b	/* input MUX */64#define WM_OUT_MUX1		0x1c	/* output MUX */65#define WM_OUT_MUX2		0x1e	/* output MUX */66#define WM_RESET		0x1f	/* software reset */67 68 69/*70 * Logarithmic volume values for WM877071 * Computed as 20 * Log10(255 / x)72 */73static const unsigned char wm_vol[256] = {74	127, 48, 42, 39, 36, 34, 33, 31, 30, 29, 28, 27, 27, 26, 25, 25, 24,75	24, 23, 23, 22, 22, 21, 21, 21, 20, 20, 20, 19, 19, 19, 18, 18, 18, 18,76	17, 17, 17, 17, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14,77	14, 13, 13, 13, 13, 13, 13, 13, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11,78	11, 11, 11, 11, 11, 11, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9, 9,79	9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7,80	7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5,81	5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,82	4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,83	3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,84	2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,85	1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 086};87 88#define WM_VOL_MAX	(sizeof(wm_vol) - 1)89#define WM_VOL_MUTE	0x800090 91static const struct snd_akm4xxx akm_phase22 = {92	.type = SND_AK4524,93	.num_dacs = 2,94	.num_adcs = 2,95};96 97static const struct snd_ak4xxx_private akm_phase22_priv = {98	.caddr =	2,99	.cif =		1,100	.data_mask =	1 << 4,101	.clk_mask =	1 << 5,102	.cs_mask =	1 << 10,103	.cs_addr =	1 << 10,104	.cs_none =	0,105	.add_flags = 	1 << 3,106	.mask_flags =	0,107};108 109static int phase22_init(struct snd_ice1712 *ice)110{111	struct snd_akm4xxx *ak;112	int err;113 114	/* Configure DAC/ADC description for generic part of ice1724 */115	switch (ice->eeprom.subvendor) {116	case VT1724_SUBDEVICE_PHASE22:117	case VT1724_SUBDEVICE_TS22:118		ice->num_total_dacs = 2;119		ice->num_total_adcs = 2;120		ice->vt1720 = 1; /* Envy24HT-S have 16 bit wide GPIO */121		break;122	default:123		snd_BUG();124		return -EINVAL;125	}126 127	/* Initialize analog chips */128	ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL);129	ak = ice->akm;130	if (!ak)131		return -ENOMEM;132	ice->akm_codecs = 1;133	switch (ice->eeprom.subvendor) {134	case VT1724_SUBDEVICE_PHASE22:135	case VT1724_SUBDEVICE_TS22:136		err = snd_ice1712_akm4xxx_init(ak, &akm_phase22,137						&akm_phase22_priv, ice);138		if (err < 0)139			return err;140		break;141	}142 143	return 0;144}145 146static int phase22_add_controls(struct snd_ice1712 *ice)147{148	int err = 0;149 150	switch (ice->eeprom.subvendor) {151	case VT1724_SUBDEVICE_PHASE22:152	case VT1724_SUBDEVICE_TS22:153		err = snd_ice1712_akm4xxx_build_controls(ice);154		if (err < 0)155			return err;156	}157	return 0;158}159 160static const unsigned char phase22_eeprom[] = {161	[ICE_EEP2_SYSCONF]     = 0x28,  /* clock 512, mpu 401,162					spdif-in/1xADC, 1xDACs */163	[ICE_EEP2_ACLINK]      = 0x80,	/* I2S */164	[ICE_EEP2_I2S]         = 0xf0,	/* vol, 96k, 24bit */165	[ICE_EEP2_SPDIF]       = 0xc3,	/* out-en, out-int, spdif-in */166	[ICE_EEP2_GPIO_DIR]    = 0xff,167	[ICE_EEP2_GPIO_DIR1]   = 0xff,168	[ICE_EEP2_GPIO_DIR2]   = 0xff,169	[ICE_EEP2_GPIO_MASK]   = 0x00,170	[ICE_EEP2_GPIO_MASK1]  = 0x00,171	[ICE_EEP2_GPIO_MASK2]  = 0x00,172	[ICE_EEP2_GPIO_STATE]  = 0x00,173	[ICE_EEP2_GPIO_STATE1] = 0x00,174	[ICE_EEP2_GPIO_STATE2] = 0x00,175};176 177static const unsigned char phase28_eeprom[] = {178	[ICE_EEP2_SYSCONF]     = 0x2b,  /* clock 512, mpu401,179					spdif-in/1xADC, 4xDACs */180	[ICE_EEP2_ACLINK]      = 0x80,	/* I2S */181	[ICE_EEP2_I2S]         = 0xfc,	/* vol, 96k, 24bit, 192k */182	[ICE_EEP2_SPDIF]       = 0xc3,	/* out-en, out-int, spdif-in */183	[ICE_EEP2_GPIO_DIR]    = 0xff,184	[ICE_EEP2_GPIO_DIR1]   = 0xff,185	[ICE_EEP2_GPIO_DIR2]   = 0x5f,186	[ICE_EEP2_GPIO_MASK]   = 0x00,187	[ICE_EEP2_GPIO_MASK1]  = 0x00,188	[ICE_EEP2_GPIO_MASK2]  = 0x00,189	[ICE_EEP2_GPIO_STATE]  = 0x00,190	[ICE_EEP2_GPIO_STATE1] = 0x00,191	[ICE_EEP2_GPIO_STATE2] = 0x00,192};193 194/*195 * write data in the SPI mode196 */197static void phase28_spi_write(struct snd_ice1712 *ice, unsigned int cs,198				unsigned int data, int bits)199{200	unsigned int tmp;201	int i;202 203	tmp = snd_ice1712_gpio_read(ice);204 205	snd_ice1712_gpio_set_mask(ice, ~(PHASE28_WM_RW|PHASE28_SPI_MOSI|206					PHASE28_SPI_CLK|PHASE28_WM_CS));207	tmp |= PHASE28_WM_RW;208	tmp &= ~cs;209	snd_ice1712_gpio_write(ice, tmp);210	udelay(1);211 212	for (i = bits - 1; i >= 0; i--) {213		tmp &= ~PHASE28_SPI_CLK;214		snd_ice1712_gpio_write(ice, tmp);215		udelay(1);216		if (data & (1 << i))217			tmp |= PHASE28_SPI_MOSI;218		else219			tmp &= ~PHASE28_SPI_MOSI;220		snd_ice1712_gpio_write(ice, tmp);221		udelay(1);222		tmp |= PHASE28_SPI_CLK;223		snd_ice1712_gpio_write(ice, tmp);224		udelay(1);225	}226 227	tmp &= ~PHASE28_SPI_CLK;228	tmp |= cs;229	snd_ice1712_gpio_write(ice, tmp);230	udelay(1);231	tmp |= PHASE28_SPI_CLK;232	snd_ice1712_gpio_write(ice, tmp);233	udelay(1);234}235 236/*237 * get the current register value of WM codec238 */239static unsigned short wm_get(struct snd_ice1712 *ice, int reg)240{241	reg <<= 1;242	return ((unsigned short)ice->akm[0].images[reg] << 8) |243		ice->akm[0].images[reg + 1];244}245 246/*247 * set the register value of WM codec248 */249static void wm_put_nocache(struct snd_ice1712 *ice, int reg, unsigned short val)250{251	phase28_spi_write(ice, PHASE28_WM_CS, (reg << 9) | (val & 0x1ff), 16);252}253 254/*255 * set the register value of WM codec and remember it256 */257static void wm_put(struct snd_ice1712 *ice, int reg, unsigned short val)258{259	wm_put_nocache(ice, reg, val);260	reg <<= 1;261	ice->akm[0].images[reg] = val >> 8;262	ice->akm[0].images[reg + 1] = val;263}264 265static void wm_set_vol(struct snd_ice1712 *ice, unsigned int index,266			unsigned short vol, unsigned short master)267{268	unsigned char nvol;269 270	if ((master & WM_VOL_MUTE) || (vol & WM_VOL_MUTE))271		nvol = 0;272	else273		nvol = 127 - wm_vol[(((vol & ~WM_VOL_MUTE) *274			(master & ~WM_VOL_MUTE)) / 127) & WM_VOL_MAX];275 276	wm_put(ice, index, nvol);277	wm_put_nocache(ice, index, 0x180 | nvol);278}279 280/*281 * DAC mute control282 */283#define wm_pcm_mute_info	snd_ctl_boolean_mono_info284 285static int wm_pcm_mute_get(struct snd_kcontrol *kcontrol,286				struct snd_ctl_elem_value *ucontrol)287{288	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);289 290	mutex_lock(&ice->gpio_mutex);291	ucontrol->value.integer.value[0] = (wm_get(ice, WM_MUTE) & 0x10) ?292						0 : 1;293	mutex_unlock(&ice->gpio_mutex);294	return 0;295}296 297static int wm_pcm_mute_put(struct snd_kcontrol *kcontrol,298				struct snd_ctl_elem_value *ucontrol)299{300	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);301	unsigned short nval, oval;302	int change;303 304	snd_ice1712_save_gpio_status(ice);305	oval = wm_get(ice, WM_MUTE);306	nval = (oval & ~0x10) | (ucontrol->value.integer.value[0] ? 0 : 0x10);307	change = (nval != oval);308	if (change)309		wm_put(ice, WM_MUTE, nval);310	snd_ice1712_restore_gpio_status(ice);311 312	return change;313}314 315/*316 * Master volume attenuation mixer control317 */318static int wm_master_vol_info(struct snd_kcontrol *kcontrol,319				struct snd_ctl_elem_info *uinfo)320{321	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;322	uinfo->count = 2;323	uinfo->value.integer.min = 0;324	uinfo->value.integer.max = WM_VOL_MAX;325	return 0;326}327 328static int wm_master_vol_get(struct snd_kcontrol *kcontrol,329				struct snd_ctl_elem_value *ucontrol)330{331	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);332	struct phase28_spec *spec = ice->spec;333	int i;334	for (i = 0; i < 2; i++)335		ucontrol->value.integer.value[i] = spec->master[i] &336							~WM_VOL_MUTE;337	return 0;338}339 340static int wm_master_vol_put(struct snd_kcontrol *kcontrol,341				struct snd_ctl_elem_value *ucontrol)342{343	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);344	struct phase28_spec *spec = ice->spec;345	int ch, change = 0;346 347	snd_ice1712_save_gpio_status(ice);348	for (ch = 0; ch < 2; ch++) {349		unsigned int vol = ucontrol->value.integer.value[ch];350		if (vol > WM_VOL_MAX)351			continue;352		vol |= spec->master[ch] & WM_VOL_MUTE;353		if (vol != spec->master[ch]) {354			int dac;355			spec->master[ch] = vol;356			for (dac = 0; dac < ice->num_total_dacs; dac += 2)357				wm_set_vol(ice, WM_DAC_ATTEN + dac + ch,358					   spec->vol[dac + ch],359					   spec->master[ch]);360			change = 1;361		}362	}363	snd_ice1712_restore_gpio_status(ice);364	return change;365}366 367static int phase28_init(struct snd_ice1712 *ice)368{369	static const unsigned short wm_inits_phase28[] = {370		/* These come first to reduce init pop noise */371		0x1b, 0x044,	/* ADC Mux (AC'97 source) */372		0x1c, 0x00B,	/* Out Mux1 (VOUT1 = DAC+AUX, VOUT2 = DAC) */373		0x1d, 0x009,	/* Out Mux2 (VOUT2 = DAC, VOUT3 = DAC) */374 375		0x18, 0x000,	/* All power-up */376 377		0x16, 0x122,	/* I2S, normal polarity, 24bit */378		0x17, 0x022,	/* 256fs, slave mode */379		0x00, 0,	/* DAC1 analog mute */380		0x01, 0,	/* DAC2 analog mute */381		0x02, 0,	/* DAC3 analog mute */382		0x03, 0,	/* DAC4 analog mute */383		0x04, 0,	/* DAC5 analog mute */384		0x05, 0,	/* DAC6 analog mute */385		0x06, 0,	/* DAC7 analog mute */386		0x07, 0,	/* DAC8 analog mute */387		0x08, 0x100,	/* master analog mute */388		0x09, 0xff,	/* DAC1 digital full */389		0x0a, 0xff,	/* DAC2 digital full */390		0x0b, 0xff,	/* DAC3 digital full */391		0x0c, 0xff,	/* DAC4 digital full */392		0x0d, 0xff,	/* DAC5 digital full */393		0x0e, 0xff,	/* DAC6 digital full */394		0x0f, 0xff,	/* DAC7 digital full */395		0x10, 0xff,	/* DAC8 digital full */396		0x11, 0x1ff,	/* master digital full */397		0x12, 0x000,	/* phase normal */398		0x13, 0x090,	/* unmute DAC L/R */399		0x14, 0x000,	/* all unmute */400		0x15, 0x000,	/* no deemphasis, no ZFLG */401		0x19, 0x000,	/* -12dB ADC/L */402		0x1a, 0x000,	/* -12dB ADC/R */403		(unsigned short)-1404	};405 406	unsigned int tmp;407	struct snd_akm4xxx *ak;408	struct phase28_spec *spec;409	const unsigned short *p;410	int i;411 412	ice->num_total_dacs = 8;413	ice->num_total_adcs = 2;414 415	spec = kzalloc(sizeof(*spec), GFP_KERNEL);416	if (!spec)417		return -ENOMEM;418	ice->spec = spec;419 420	/* Initialize analog chips */421	ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL);422	ak = ice->akm;423	if (!ak)424		return -ENOMEM;425	ice->akm_codecs = 1;426 427	snd_ice1712_gpio_set_dir(ice, 0x5fffff); /* fix this for time being */428 429	/* reset the wm codec as the SPI mode */430	snd_ice1712_save_gpio_status(ice);431	snd_ice1712_gpio_set_mask(ice, ~(PHASE28_WM_RESET|PHASE28_WM_CS|432					PHASE28_HP_SEL));433 434	tmp = snd_ice1712_gpio_read(ice);435	tmp &= ~PHASE28_WM_RESET;436	snd_ice1712_gpio_write(ice, tmp);437	udelay(1);438	tmp |= PHASE28_WM_CS;439	snd_ice1712_gpio_write(ice, tmp);440	udelay(1);441	tmp |= PHASE28_WM_RESET;442	snd_ice1712_gpio_write(ice, tmp);443	udelay(1);444 445	p = wm_inits_phase28;446	for (; *p != (unsigned short)-1; p += 2)447		wm_put(ice, p[0], p[1]);448 449	snd_ice1712_restore_gpio_status(ice);450 451	spec->master[0] = WM_VOL_MUTE;452	spec->master[1] = WM_VOL_MUTE;453	for (i = 0; i < ice->num_total_dacs; i++) {454		spec->vol[i] = WM_VOL_MUTE;455		wm_set_vol(ice, i, spec->vol[i], spec->master[i % 2]);456	}457 458	return 0;459}460 461/*462 * DAC volume attenuation mixer control463 */464static int wm_vol_info(struct snd_kcontrol *kcontrol,465			struct snd_ctl_elem_info *uinfo)466{467	int voices = kcontrol->private_value >> 8;468	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;469	uinfo->count = voices;470	uinfo->value.integer.min = 0;		/* mute (-101dB) */471	uinfo->value.integer.max = 0x7F;	/* 0dB */472	return 0;473}474 475static int wm_vol_get(struct snd_kcontrol *kcontrol,476			struct snd_ctl_elem_value *ucontrol)477{478	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);479	struct phase28_spec *spec = ice->spec;480	int i, ofs, voices;481 482	voices = kcontrol->private_value >> 8;483	ofs = kcontrol->private_value & 0xff;484	for (i = 0; i < voices; i++)485		ucontrol->value.integer.value[i] =486			spec->vol[ofs+i] & ~WM_VOL_MUTE;487	return 0;488}489 490static int wm_vol_put(struct snd_kcontrol *kcontrol,491			struct snd_ctl_elem_value *ucontrol)492{493	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);494	struct phase28_spec *spec = ice->spec;495	int i, idx, ofs, voices;496	int change = 0;497 498	voices = kcontrol->private_value >> 8;499	ofs = kcontrol->private_value & 0xff;500	snd_ice1712_save_gpio_status(ice);501	for (i = 0; i < voices; i++) {502		unsigned int vol;503		vol = ucontrol->value.integer.value[i];504		if (vol > 0x7f)505			continue;506		vol |= spec->vol[ofs+i] & WM_VOL_MUTE;507		if (vol != spec->vol[ofs+i]) {508			spec->vol[ofs+i] = vol;509			idx  = WM_DAC_ATTEN + ofs + i;510			wm_set_vol(ice, idx, spec->vol[ofs+i],511				   spec->master[i]);512			change = 1;513		}514	}515	snd_ice1712_restore_gpio_status(ice);516	return change;517}518 519/*520 * WM8770 mute control521 */522static int wm_mute_info(struct snd_kcontrol *kcontrol,523			struct snd_ctl_elem_info *uinfo) {524	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;525	uinfo->count = kcontrol->private_value >> 8;526	uinfo->value.integer.min = 0;527	uinfo->value.integer.max = 1;528	return 0;529}530 531static int wm_mute_get(struct snd_kcontrol *kcontrol,532			struct snd_ctl_elem_value *ucontrol)533{534	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);535	struct phase28_spec *spec = ice->spec;536	int voices, ofs, i;537 538	voices = kcontrol->private_value >> 8;539	ofs = kcontrol->private_value & 0xFF;540 541	for (i = 0; i < voices; i++)542		ucontrol->value.integer.value[i] =543			(spec->vol[ofs+i] & WM_VOL_MUTE) ? 0 : 1;544	return 0;545}546 547static int wm_mute_put(struct snd_kcontrol *kcontrol,548			struct snd_ctl_elem_value *ucontrol)549{550	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);551	struct phase28_spec *spec = ice->spec;552	int change = 0, voices, ofs, i;553 554	voices = kcontrol->private_value >> 8;555	ofs = kcontrol->private_value & 0xFF;556 557	snd_ice1712_save_gpio_status(ice);558	for (i = 0; i < voices; i++) {559		int val = (spec->vol[ofs + i] & WM_VOL_MUTE) ? 0 : 1;560		if (ucontrol->value.integer.value[i] != val) {561			spec->vol[ofs + i] &= ~WM_VOL_MUTE;562			spec->vol[ofs + i] |=563				ucontrol->value.integer.value[i] ? 0 :564				WM_VOL_MUTE;565			wm_set_vol(ice, ofs + i, spec->vol[ofs + i],566					spec->master[i]);567			change = 1;568		}569	}570	snd_ice1712_restore_gpio_status(ice);571 572	return change;573}574 575/*576 * WM8770 master mute control577 */578#define wm_master_mute_info		snd_ctl_boolean_stereo_info579 580static int wm_master_mute_get(struct snd_kcontrol *kcontrol,581				struct snd_ctl_elem_value *ucontrol)582{583	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);584	struct phase28_spec *spec = ice->spec;585 586	ucontrol->value.integer.value[0] =587		(spec->master[0] & WM_VOL_MUTE) ? 0 : 1;588	ucontrol->value.integer.value[1] =589		(spec->master[1] & WM_VOL_MUTE) ? 0 : 1;590	return 0;591}592 593static int wm_master_mute_put(struct snd_kcontrol *kcontrol,594				struct snd_ctl_elem_value *ucontrol)595{596	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);597	struct phase28_spec *spec = ice->spec;598	int change = 0, i;599 600	snd_ice1712_save_gpio_status(ice);601	for (i = 0; i < 2; i++) {602		int val = (spec->master[i] & WM_VOL_MUTE) ? 0 : 1;603		if (ucontrol->value.integer.value[i] != val) {604			int dac;605			spec->master[i] &= ~WM_VOL_MUTE;606			spec->master[i] |=607				ucontrol->value.integer.value[i] ? 0 :608				WM_VOL_MUTE;609			for (dac = 0; dac < ice->num_total_dacs; dac += 2)610				wm_set_vol(ice, WM_DAC_ATTEN + dac + i,611						spec->vol[dac + i],612						spec->master[i]);613			change = 1;614		}615	}616	snd_ice1712_restore_gpio_status(ice);617 618	return change;619}620 621/* digital master volume */622#define PCM_0dB 0xff623#define PCM_RES 128	/* -64dB */624#define PCM_MIN (PCM_0dB - PCM_RES)625static int wm_pcm_vol_info(struct snd_kcontrol *kcontrol,626				struct snd_ctl_elem_info *uinfo)627{628	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;629	uinfo->count = 1;630	uinfo->value.integer.min = 0;		/* mute (-64dB) */631	uinfo->value.integer.max = PCM_RES;	/* 0dB */632	return 0;633}634 635static int wm_pcm_vol_get(struct snd_kcontrol *kcontrol,636				struct snd_ctl_elem_value *ucontrol)637{638	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);639	unsigned short val;640 641	mutex_lock(&ice->gpio_mutex);642	val = wm_get(ice, WM_DAC_DIG_MASTER_ATTEN) & 0xff;643	val = val > PCM_MIN ? (val - PCM_MIN) : 0;644	ucontrol->value.integer.value[0] = val;645	mutex_unlock(&ice->gpio_mutex);646	return 0;647}648 649static int wm_pcm_vol_put(struct snd_kcontrol *kcontrol,650				struct snd_ctl_elem_value *ucontrol)651{652	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);653	unsigned short ovol, nvol;654	int change = 0;655 656	nvol = ucontrol->value.integer.value[0];657	if (nvol > PCM_RES)658		return -EINVAL;659	snd_ice1712_save_gpio_status(ice);660	nvol = (nvol ? (nvol + PCM_MIN) : 0) & 0xff;661	ovol = wm_get(ice, WM_DAC_DIG_MASTER_ATTEN) & 0xff;662	if (ovol != nvol) {663		wm_put(ice, WM_DAC_DIG_MASTER_ATTEN, nvol); /* prelatch */664		/* update */665		wm_put_nocache(ice, WM_DAC_DIG_MASTER_ATTEN, nvol | 0x100);666		change = 1;667	}668	snd_ice1712_restore_gpio_status(ice);669	return change;670}671 672/*673 * Deemphasis674 */675#define phase28_deemp_info	snd_ctl_boolean_mono_info676 677static int phase28_deemp_get(struct snd_kcontrol *kcontrol,678				struct snd_ctl_elem_value *ucontrol)679{680	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);681	ucontrol->value.integer.value[0] = (wm_get(ice, WM_DAC_CTRL2) & 0xf) ==682						0xf;683	return 0;684}685 686static int phase28_deemp_put(struct snd_kcontrol *kcontrol,687				struct snd_ctl_elem_value *ucontrol)688{689	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);690	int temp, temp2;691	temp = wm_get(ice, WM_DAC_CTRL2);692	temp2 = temp;693	if (ucontrol->value.integer.value[0])694		temp |= 0xf;695	else696		temp &= ~0xf;697	if (temp != temp2) {698		wm_put(ice, WM_DAC_CTRL2, temp);699		return 1;700	}701	return 0;702}703 704/*705 * ADC Oversampling706 */707static int phase28_oversampling_info(struct snd_kcontrol *k,708					struct snd_ctl_elem_info *uinfo)709{710	static const char * const texts[2] = { "128x", "64x"	};711 712	return snd_ctl_enum_info(uinfo, 1, 2, texts);713}714 715static int phase28_oversampling_get(struct snd_kcontrol *kcontrol,716					struct snd_ctl_elem_value *ucontrol)717{718	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);719	ucontrol->value.enumerated.item[0] = (wm_get(ice, WM_MASTER) & 0x8) ==720						0x8;721	return 0;722}723 724static int phase28_oversampling_put(struct snd_kcontrol *kcontrol,725					struct snd_ctl_elem_value *ucontrol)726{727	int temp, temp2;728	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);729 730	temp = wm_get(ice, WM_MASTER);731	temp2 = temp;732 733	if (ucontrol->value.enumerated.item[0])734		temp |= 0x8;735	else736		temp &= ~0x8;737 738	if (temp != temp2) {739		wm_put(ice, WM_MASTER, temp);740		return 1;741	}742	return 0;743}744 745static const DECLARE_TLV_DB_SCALE(db_scale_wm_dac, -12700, 100, 1);746static const DECLARE_TLV_DB_SCALE(db_scale_wm_pcm, -6400, 50, 1);747 748static const struct snd_kcontrol_new phase28_dac_controls[] = {749	{750		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,751		.name = "Master Playback Switch",752		.info = wm_master_mute_info,753		.get = wm_master_mute_get,754		.put = wm_master_mute_put755	},756	{757		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,758		.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |759			   SNDRV_CTL_ELEM_ACCESS_TLV_READ),760		.name = "Master Playback Volume",761		.info = wm_master_vol_info,762		.get = wm_master_vol_get,763		.put = wm_master_vol_put,764		.tlv = { .p = db_scale_wm_dac }765	},766	{767		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,768		.name = "Front Playback Switch",769		.info = wm_mute_info,770		.get = wm_mute_get,771		.put = wm_mute_put,772		.private_value = (2 << 8) | 0773	},774	{775		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,776		.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |777			   SNDRV_CTL_ELEM_ACCESS_TLV_READ),778		.name = "Front Playback Volume",779		.info = wm_vol_info,780		.get = wm_vol_get,781		.put = wm_vol_put,782		.private_value = (2 << 8) | 0,783		.tlv = { .p = db_scale_wm_dac }784	},785	{786		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,787		.name = "Rear Playback Switch",788		.info = wm_mute_info,789		.get = wm_mute_get,790		.put = wm_mute_put,791		.private_value = (2 << 8) | 2792	},793	{794		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,795		.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |796			   SNDRV_CTL_ELEM_ACCESS_TLV_READ),797		.name = "Rear Playback Volume",798		.info = wm_vol_info,799		.get = wm_vol_get,800		.put = wm_vol_put,801		.private_value = (2 << 8) | 2,802		.tlv = { .p = db_scale_wm_dac }803	},804	{805		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,806		.name = "Center Playback Switch",807		.info = wm_mute_info,808		.get = wm_mute_get,809		.put = wm_mute_put,810		.private_value = (1 << 8) | 4811	},812	{813		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,814		.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |815			   SNDRV_CTL_ELEM_ACCESS_TLV_READ),816		.name = "Center Playback Volume",817		.info = wm_vol_info,818		.get = wm_vol_get,819		.put = wm_vol_put,820		.private_value = (1 << 8) | 4,821		.tlv = { .p = db_scale_wm_dac }822	},823	{824		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,825		.name = "LFE Playback Switch",826		.info = wm_mute_info,827		.get = wm_mute_get,828		.put = wm_mute_put,829		.private_value = (1 << 8) | 5830	},831	{832		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,833		.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |834			   SNDRV_CTL_ELEM_ACCESS_TLV_READ),835		.name = "LFE Playback Volume",836		.info = wm_vol_info,837		.get = wm_vol_get,838		.put = wm_vol_put,839		.private_value = (1 << 8) | 5,840		.tlv = { .p = db_scale_wm_dac }841	},842	{843		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,844		.name = "Side Playback Switch",845		.info = wm_mute_info,846		.get = wm_mute_get,847		.put = wm_mute_put,848		.private_value = (2 << 8) | 6849	},850	{851		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,852		.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |853			   SNDRV_CTL_ELEM_ACCESS_TLV_READ),854		.name = "Side Playback Volume",855		.info = wm_vol_info,856		.get = wm_vol_get,857		.put = wm_vol_put,858		.private_value = (2 << 8) | 6,859		.tlv = { .p = db_scale_wm_dac }860	}861};862 863static const struct snd_kcontrol_new wm_controls[] = {864	{865		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,866		.name = "PCM Playback Switch",867		.info = wm_pcm_mute_info,868		.get = wm_pcm_mute_get,869		.put = wm_pcm_mute_put870	},871	{872		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,873		.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |874			   SNDRV_CTL_ELEM_ACCESS_TLV_READ),875		.name = "PCM Playback Volume",876		.info = wm_pcm_vol_info,877		.get = wm_pcm_vol_get,878		.put = wm_pcm_vol_put,879		.tlv = { .p = db_scale_wm_pcm }880	},881	{882		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,883		.name = "DAC Deemphasis Switch",884		.info = phase28_deemp_info,885		.get = phase28_deemp_get,886		.put = phase28_deemp_put887	},888	{889		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,890		.name = "ADC Oversampling",891		.info = phase28_oversampling_info,892		.get = phase28_oversampling_get,893		.put = phase28_oversampling_put894	}895};896 897static int phase28_add_controls(struct snd_ice1712 *ice)898{899	unsigned int i, counts;900	int err;901 902	counts = ARRAY_SIZE(phase28_dac_controls);903	for (i = 0; i < counts; i++) {904		err = snd_ctl_add(ice->card,905					snd_ctl_new1(&phase28_dac_controls[i],906							ice));907		if (err < 0)908			return err;909	}910 911	for (i = 0; i < ARRAY_SIZE(wm_controls); i++) {912		err = snd_ctl_add(ice->card,913					snd_ctl_new1(&wm_controls[i], ice));914		if (err < 0)915			return err;916	}917 918	return 0;919}920 921struct snd_ice1712_card_info snd_vt1724_phase_cards[] = {922	{923		.subvendor = VT1724_SUBDEVICE_PHASE22,924		.name = "Terratec PHASE 22",925		.model = "phase22",926		.chip_init = phase22_init,927		.build_controls = phase22_add_controls,928		.eeprom_size = sizeof(phase22_eeprom),929		.eeprom_data = phase22_eeprom,930	},931	{932		.subvendor = VT1724_SUBDEVICE_PHASE28,933		.name = "Terratec PHASE 28",934		.model = "phase28",935		.chip_init = phase28_init,936		.build_controls = phase28_add_controls,937		.eeprom_size = sizeof(phase28_eeprom),938		.eeprom_data = phase28_eeprom,939	},940	{941		.subvendor = VT1724_SUBDEVICE_TS22,942		.name = "Terrasoniq TS22 PCI",943		.model = "TS22",944		.chip_init = phase22_init,945		.build_controls = phase22_add_controls,946		.eeprom_size = sizeof(phase22_eeprom),947		.eeprom_data = phase22_eeprom,948	},949	{ } /* terminator */950};951