⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 aureon.c

📁 优龙2410linux2.6.8内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *   ALSA driver for ICEnsemble VT1724 (Envy24HT) * *   Lowlevel functions for Terratec Aureon cards * *	Copyright (c) 2003 Takashi Iwai <tiwai@suse.de> * *   This program is free software; you can redistribute it and/or modify *   it under the terms of the GNU General Public License as published by *   the Free Software Foundation; either version 2 of the License, or *   (at your option) any later version. * *   This program is distributed in the hope that it will be useful, *   but WITHOUT ANY WARRANTY; without even the implied warranty of *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *   GNU General Public License for more details. * *   You should have received a copy of the GNU General Public License *   along with this program; if not, write to the Free Software *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA * * * NOTES: * * - we reuse the akm4xxx_t record for storing the wm8770 codec data. *   both wm and akm codecs are pretty similar, so we can integrate *   both controls in the future, once if wm codecs are reused in *   many boards. * * - writing over SPI is implemented but reading is not yet. *   the SPDIF-in channel status, etc. can be read from CS chip. * * - DAC digital volumes are not implemented in the mixer. *   if they show better response than DAC analog volumes, we can use them *   instead. * * - Aureon boards are equipped with AC97 codec, too.  it's used to do *   the analog mixing but not easily controllable (it's not connected *   directly from envy24ht chip).  so let's leave it as it is. * * *   Lowlevel functions for AudioTrak Prodigy 7.1 (and possibly 192) cards *      Copyright (c) 2003 Dimitromanolakis Apostolos <apostol@cs.utoronto.ca> * *   version 0.82: Stable / not all features work yet (no communication with AC97 secondary) *       added 64x/128x oversampling switch (should be 64x only for 96khz) *       fixed some recording labels (still need to check the rest) *       recording is working probably thanks to correct wm8770 initialization * *   version 0.5: Initial release: *           working: analog output, mixer, headphone amplifier switch *       not working: prety much everything else, at least i could verify that *                    we have no digital output, no capture, pretty bad clicks and poops *                    on mixer switch and other coll stuff. * * - Prodigy boards are equipped with AC97 STAC9744 chip , too.  it's used to do *   the analog mixing but not easily controllable (it's not connected *   directly from envy24ht chip).  so let's leave it as it is. * */      #include <sound/driver.h>#include <asm/io.h>#include <linux/delay.h>#include <linux/interrupt.h>#include <linux/init.h>#include <linux/slab.h>#include <sound/core.h>#include "ice1712.h"#include "envy24ht.h"#include "aureon.h"/* WM8770 registers */#define WM_DAC_ATTEN		0x00	/* DAC1-8 analog attenuation */#define WM_DAC_MASTER_ATTEN	0x08	/* DAC master analog attenuation */#define WM_DAC_DIG_ATTEN	0x09	/* DAC1-8 digital attenuation */#define WM_DAC_DIG_MATER_ATTEN	0x11	/* DAC master digital attenuation */#define WM_PHASE_SWAP		0x12	/* DAC phase */#define WM_DAC_CTRL1		0x13	/* DAC control bits */#define WM_MUTE			0x14	/* mute controls */#define WM_DAC_CTRL2		0x15	/* de-emphasis and zefo-flag */#define WM_INT_CTRL		0x16	/* interface control */#define WM_MASTER		0x17	/* master clock and mode */#define WM_POWERDOWN		0x18	/* power-down controls */#define WM_ADC_GAIN		0x19	/* ADC gain L(19)/R(1a) */#define WM_ADC_MUX		0x1b	/* input MUX */#define WM_OUT_MUX1		0x1c	/* output MUX */#define WM_OUT_MUX2		0x1e	/* output MUX */#define WM_RESET		0x1f	/* software reset *//* * write data in the SPI mode */static void aureon_spi_write(ice1712_t *ice, unsigned int cs, unsigned int data, int bits){	unsigned int tmp;	unsigned int cscs;	int i;	tmp = snd_ice1712_gpio_read(ice);	if (ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71)		cscs = PRODIGY_CS8415_CS;	else		cscs = AUREON_CS8415_CS;	snd_ice1712_gpio_set_mask(ice, ~(AUREON_WM_RW|AUREON_WM_DATA|AUREON_WM_CLK|					 AUREON_WM_CS|cscs));	tmp |= AUREON_WM_RW;	tmp &= ~cs;	snd_ice1712_gpio_write(ice, tmp);	udelay(1);	for (i = bits - 1; i >= 0; i--) {		tmp &= ~AUREON_WM_CLK;		snd_ice1712_gpio_write(ice, tmp);		udelay(1);		if (data & (1 << i))			tmp |= AUREON_WM_DATA;		else			tmp &= ~AUREON_WM_DATA;		snd_ice1712_gpio_write(ice, tmp);		udelay(1);		tmp |= AUREON_WM_CLK;		snd_ice1712_gpio_write(ice, tmp);		udelay(1);	}	tmp &= ~AUREON_WM_CLK;	tmp |= cs;	snd_ice1712_gpio_write(ice, tmp);	udelay(1);	tmp |= AUREON_WM_CLK;	snd_ice1712_gpio_write(ice, tmp);	udelay(1);}     /* * get the current register value of WM codec */static unsigned short wm_get(ice1712_t *ice, int reg){	reg <<= 1;	return ((unsigned short)ice->akm[0].images[reg] << 8) |		ice->akm[0].images[reg + 1];}/* * set the register value of WM codec and remember it */static void wm_put(ice1712_t *ice, int reg, unsigned short val){	aureon_spi_write(ice, AUREON_WM_CS, (reg << 9) | (val & 0x1ff), 16);	reg <<= 1;	ice->akm[0].images[reg] = val >> 8;	ice->akm[0].images[reg + 1] = val;}/* * DAC mute control */static int wm_dac_mute_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo){	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;	uinfo->count = 1;	uinfo->value.integer.min = 0;	uinfo->value.integer.max = 1;	return 0;}static int wm_dac_mute_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol){	ice1712_t *ice = snd_kcontrol_chip(kcontrol);	unsigned short val;	down(&ice->gpio_mutex);	val = wm_get(ice, snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)+WM_MUTE);	ucontrol->value.integer.value[0] = ~val>>4 & 0x1;	up(&ice->gpio_mutex);	return 0;}static int wm_dac_mute_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){	ice1712_t *ice = snd_kcontrol_chip(kcontrol);	unsigned short new, old;	int change;	snd_ice1712_save_gpio_status(ice);	old = wm_get(ice, snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)+WM_MUTE);	new = (~ucontrol->value.integer.value[0]<<4&0x10) | (old&~0x10);	change = (new != old);	if (change)		wm_put(ice, snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)+WM_MUTE, new);	snd_ice1712_restore_gpio_status(ice);	return change;}/* * DAC volume attenuation mixer control */static int wm_dac_vol_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo){	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;	uinfo->count = 1;	uinfo->value.integer.min = 0;		/* mute */	uinfo->value.integer.max = 101;		/* 0dB */	return 0;}static int wm_dac_vol_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol){	ice1712_t *ice = snd_kcontrol_chip(kcontrol);	int idx;	unsigned short vol;	down(&ice->gpio_mutex);	if (kcontrol->private_value)		idx = WM_DAC_MASTER_ATTEN;	else		idx  = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + WM_DAC_ATTEN;	vol = wm_get(ice, idx) & 0x7f;	if (vol <= 0x1a)		ucontrol->value.integer.value[0] = 0;	else		ucontrol->value.integer.value[0] = vol - 0x1a;	up(&ice->gpio_mutex);	return 0;}static int wm_dac_vol_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol){	ice1712_t *ice = snd_kcontrol_chip(kcontrol);	int idx;	unsigned short ovol, nvol;	int change;	snd_ice1712_save_gpio_status(ice);	if (kcontrol->private_value)		idx = WM_DAC_MASTER_ATTEN;	else		idx  = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + WM_DAC_ATTEN;	nvol = ucontrol->value.integer.value[0] + 0x1a;	ovol = wm_get(ice, idx) & 0x7f;	change = (ovol != nvol);	if (change) {		if (nvol <= 0x1a && ovol <= 0x1a)			change = 0;		else			wm_put(ice, idx, nvol | 0x180); /* update on zero detect */	}	snd_ice1712_restore_gpio_status(ice);	return change;}/* * ADC mute control */static int wm_adc_mute_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo){	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;	uinfo->count = 1;	uinfo->value.integer.min = 0;	uinfo->value.integer.max = 1;	return 0;}static int wm_adc_mute_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol){	ice1712_t *ice = snd_kcontrol_chip(kcontrol);	unsigned short val;	down(&ice->gpio_mutex);	val = wm_get(ice, snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)+WM_ADC_GAIN);	ucontrol->value.integer.value[0] = ~val>>5 & 0x1;	up(&ice->gpio_mutex);	return 0;}static int wm_adc_mute_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){	ice1712_t *ice = snd_kcontrol_chip(kcontrol);	unsigned short new, old;	int change;	snd_ice1712_save_gpio_status(ice);	old = wm_get(ice, snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)+WM_ADC_GAIN);	new = (~ucontrol->value.integer.value[0]<<5&0x20) | (old&~0x20);	change = (new != old);	if (change)		wm_put(ice, snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)+WM_ADC_GAIN, new);	snd_ice1712_restore_gpio_status(ice);	return change;}/* * ADC gain mixer control */static int wm_adc_vol_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo){	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;	uinfo->count = 1;	uinfo->value.integer.min = 0;		/* -12dB */	uinfo->value.integer.max = 0x1f;	/* 19dB */	return 0;}static int wm_adc_vol_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol){	ice1712_t *ice = snd_kcontrol_chip(kcontrol);	int idx;	unsigned short vol;	down(&ice->gpio_mutex);	idx  = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + WM_ADC_GAIN;	vol = wm_get(ice, idx) & 0x1f;	ucontrol->value.integer.value[0] = vol;	up(&ice->gpio_mutex);	return 0;}static int wm_adc_vol_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol){	ice1712_t *ice = snd_kcontrol_chip(kcontrol);	int idx;	unsigned short ovol, nvol;	int change;	snd_ice1712_save_gpio_status(ice);	idx  = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + WM_ADC_GAIN;	nvol = ucontrol->value.integer.value[0];	ovol = wm_get(ice, idx);	change = ((ovol & 0x1f)  != nvol);	if (change)		wm_put(ice, idx, nvol | (ovol & ~0x1f));	snd_ice1712_restore_gpio_status(ice);	return change;}/* * ADC input mux mixer control */static int wm_adc_mux_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo){	static char *texts[] = {		"CD",		//AIN1		"Aux",		//AIN2		"Line",		//AIN3		"Mic",		//AIN4		"AC97"		//AIN5	};	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;	uinfo->count = 1;	uinfo->value.enumerated.items = 5;	if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)		uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;	strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);	return 0;}static int wm_adc_mux_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t *ucontrol){	ice1712_t *ice = snd_kcontrol_chip(kcontrol);	unsigned short val;	down(&ice->gpio_mutex);	val = wm_get(ice, WM_ADC_MUX);	ucontrol->value.integer.value[0] = val & 7;	ucontrol->value.integer.value[1] = (val >> 4) & 7;	up(&ice->gpio_mutex);	return 0;}static int wm_adc_mux_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t *ucontrol){	ice1712_t *ice = snd_kcontrol_chip(kcontrol);	unsigned short oval, nval;	int change;	snd_ice1712_save_gpio_status(ice);	oval = wm_get(ice, WM_ADC_MUX);	nval = oval & ~0x77;	nval |= ucontrol->value.integer.value[0] & 7;	nval |= (ucontrol->value.integer.value[1] & 7) << 4;	change = (oval != nval);	if (change)		wm_put(ice, WM_ADC_MUX, nval);	snd_ice1712_restore_gpio_status(ice);	return 0;}/* * Headphone Amplifier */static int aureon_set_headphone_amp(ice1712_t *ice, int enable){	unsigned int tmp, tmp2;	tmp2 = tmp = snd_ice1712_gpio_read(ice);	if (enable)		tmp |= AUREON_HP_SEL;	else		tmp &= ~ AUREON_HP_SEL;	if (tmp != tmp2) {		snd_ice1712_gpio_write(ice, tmp);		return 1;	}	return 0;}static int aureon_get_headphone_amp(ice1712_t *ice){	unsigned int tmp = snd_ice1712_gpio_read(ice);	return ( tmp & AUREON_HP_SEL )!= 0;}static int aureon_bool_info(snd_kcontrol_t *k, snd_ctl_elem_info_t *uinfo){	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;	uinfo->count = 1;	uinfo->value.integer.min = 0;	uinfo->value.integer.max = 1;	return 0;}static int aureon_hpamp_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol){	ice1712_t *ice = snd_kcontrol_chip(kcontrol);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -