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

📄 phase.c

📁 底层驱动开发
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *   ALSA driver for ICEnsemble ICE1724 (Envy24) * *   Lowlevel functions for Terratec PHASE 22 * *	Copyright (c) 2005 Misha Zhilin <misha@epiphan.com> * *   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 * *//* PHASE 22 overview: *   Audio controller: VIA Envy24HT-S (slightly trimmed down version of Envy24HT) *   Analog chip: AK4524 (partially via Philip's 74HCT125) *   Digital receiver: CS8414-CS (not supported in this release) * *   Envy connects to AK4524 *	- CS directly from GPIO 10 *	- CCLK via 74HCT125's gate #4 from GPIO 4 *	- CDTI via 74HCT125's gate #2 from GPIO 5 *		CDTI may be completely blocked by 74HCT125's gate #1 controlled by GPIO 3 */#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 "phase.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_MASTER_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 *//* * Logarithmic volume values for WM8770 * Computed as 20 * Log10(255 / x) */static unsigned char wm_vol[256] = {	127, 48, 42, 39, 36, 34, 33, 31, 30, 29, 28, 27, 27, 26, 25, 25, 24, 24, 23,	23, 22, 22, 21, 21, 21, 20, 20, 20, 19, 19, 19, 18, 18, 18, 18, 17, 17, 17,	17, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 13, 13, 13,	13, 13, 13, 13, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11,	11, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 8,	8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6,	6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,	5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3,	3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,	2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	0, 0};#define WM_VOL_MAX	(sizeof(wm_vol) - 1)#define WM_VOL_MUTE	0x8000static akm4xxx_t akm_phase22 __devinitdata = {	.type = SND_AK4524,	.num_dacs = 2,	.num_adcs = 2,};static struct snd_ak4xxx_private akm_phase22_priv __devinitdata = {	.caddr =	2,	.cif =		1,	.data_mask =	1 << 4,	.clk_mask =	1 << 5,	.cs_mask =	1 << 10,	.cs_addr =	1 << 10,	.cs_none =	0,	.add_flags = 	1 << 3,	.mask_flags =	0,};static int __devinit phase22_init(ice1712_t *ice){	akm4xxx_t *ak;	int err;	// Configure DAC/ADC description for generic part of ice1724	switch (ice->eeprom.subvendor) {	case VT1724_SUBDEVICE_PHASE22:		ice->num_total_dacs = 2;		ice->num_total_adcs = 2;		ice->vt1720 = 1; // Envy24HT-S have 16 bit wide GPIO		break;	default:		snd_BUG();		return -EINVAL;	}	// Initialize analog chips	ak = ice->akm = kzalloc(sizeof(akm4xxx_t), GFP_KERNEL);	if (! ak)		return -ENOMEM;	ice->akm_codecs = 1;	switch (ice->eeprom.subvendor) {	case VT1724_SUBDEVICE_PHASE22:		if ((err = snd_ice1712_akm4xxx_init(ak, &akm_phase22, &akm_phase22_priv, ice)) < 0)			return err;		break;	}	return 0;}static int __devinit phase22_add_controls(ice1712_t *ice){	int err = 0;	switch (ice->eeprom.subvendor) {	case VT1724_SUBDEVICE_PHASE22:		err = snd_ice1712_akm4xxx_build_controls(ice);		if (err < 0)			return err;	}	return 0;}static unsigned char phase22_eeprom[] __devinitdata = {	0x00,	/* SYSCONF: 1xADC, 1xDACs */	0x80,	/* ACLINK: I2S */	0xf8,	/* I2S: vol, 96k, 24bit*/	0xc3,	/* SPDIF: out-en, out-int, spdif-in */	0xFF,	/* GPIO_DIR */	0xFF,	/* GPIO_DIR1 */	0xFF,	/* GPIO_DIR2 */	0x00,	/* GPIO_MASK */	0x00,	/* GPIO_MASK1 */	0x00,	/* GPIO_MASK2 */	0x00,	/* GPIO_STATE: */	0x00,	/* GPIO_STATE1: */	0x00,	/* GPIO_STATE2 */};static unsigned char phase28_eeprom[] __devinitdata = {	0x0b,	/* SYSCONF: clock 512, spdif-in/ADC, 4DACs */	0x80,	/* ACLINK: I2S */	0xfc,	/* I2S: vol, 96k, 24bit, 192k */	0xc3,	/* SPDIF: out-en, out-int, spdif-in */	0xff,	/* GPIO_DIR */	0xff,	/* GPIO_DIR1 */	0x5f,	/* GPIO_DIR2 */	0x00,	/* GPIO_MASK */	0x00,	/* GPIO_MASK1 */	0x00,	/* GPIO_MASK2 */	0x00,	/* GPIO_STATE */	0x00,	/* GPIO_STATE1 */	0x00,	/* GPIO_STATE2 */};/* * write data in the SPI mode */static void phase28_spi_write(ice1712_t *ice, unsigned int cs, unsigned int data, int bits){	unsigned int tmp;	int i;	tmp = snd_ice1712_gpio_read(ice);	snd_ice1712_gpio_set_mask(ice, ~(PHASE28_WM_RW|PHASE28_SPI_MOSI|PHASE28_SPI_CLK|					 PHASE28_WM_CS));	tmp |= PHASE28_WM_RW;	tmp &= ~cs;	snd_ice1712_gpio_write(ice, tmp);	udelay(1);	for (i = bits - 1; i >= 0; i--) {		tmp &= ~PHASE28_SPI_CLK;		snd_ice1712_gpio_write(ice, tmp);		udelay(1);		if (data & (1 << i))			tmp |= PHASE28_SPI_MOSI;		else			tmp &= ~PHASE28_SPI_MOSI;		snd_ice1712_gpio_write(ice, tmp);		udelay(1);		tmp |= PHASE28_SPI_CLK;		snd_ice1712_gpio_write(ice, tmp);		udelay(1);	}	tmp &= ~PHASE28_SPI_CLK;	tmp |= cs;	snd_ice1712_gpio_write(ice, tmp);	udelay(1);	tmp |= PHASE28_SPI_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 */static void wm_put_nocache(ice1712_t *ice, int reg, unsigned short val){	phase28_spi_write(ice, PHASE28_WM_CS, (reg << 9) | (val & 0x1ff), 16);}/* * set the register value of WM codec and remember it */static void wm_put(ice1712_t *ice, int reg, unsigned short val){	wm_put_nocache(ice, reg, val);	reg <<= 1;	ice->akm[0].images[reg] = val >> 8;	ice->akm[0].images[reg + 1] = val;}static void wm_set_vol(ice1712_t *ice, unsigned int index, unsigned short vol, unsigned short master){	unsigned char nvol;	if ((master & WM_VOL_MUTE) || (vol & WM_VOL_MUTE))		nvol = 0;	else		nvol = 127 - wm_vol[(((vol & ~WM_VOL_MUTE) * (master & ~WM_VOL_MUTE)) / 127) & WM_VOL_MAX];	wm_put(ice, index, nvol);	wm_put_nocache(ice, index, 0x180 | nvol);}/* * DAC mute control */#define wm_pcm_mute_info	phase28_mono_bool_infostatic int wm_pcm_mute_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol){	ice1712_t *ice = snd_kcontrol_chip(kcontrol);	down(&ice->gpio_mutex);	ucontrol->value.integer.value[0] = (wm_get(ice, WM_MUTE) & 0x10) ? 0 : 1;	up(&ice->gpio_mutex);	return 0;}static int wm_pcm_mute_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){	ice1712_t *ice = snd_kcontrol_chip(kcontrol);	unsigned short nval, oval;	int change;	snd_ice1712_save_gpio_status(ice);	oval = wm_get(ice, WM_MUTE);	nval = (oval & ~0x10) | (ucontrol->value.integer.value[0] ? 0 : 0x10);	if ((change = (nval != oval)))		wm_put(ice, WM_MUTE, nval);	snd_ice1712_restore_gpio_status(ice);	return change;}/* * Master volume attenuation mixer control */static int wm_master_vol_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo){	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;	uinfo->count = 2;	uinfo->value.integer.min = 0;	uinfo->value.integer.max = WM_VOL_MAX;	return 0;}static int wm_master_vol_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol){	ice1712_t *ice = snd_kcontrol_chip(kcontrol);	int i;	for (i=0; i<2; i++)		ucontrol->value.integer.value[i] = ice->spec.phase28.master[i] & ~WM_VOL_MUTE;	return 0;}static int wm_master_vol_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol){	ice1712_t *ice = snd_kcontrol_chip(kcontrol);	int ch, change = 0;	snd_ice1712_save_gpio_status(ice);	for (ch = 0; ch < 2; ch++) {		if (ucontrol->value.integer.value[ch] != ice->spec.phase28.master[ch]) {			int dac;			ice->spec.phase28.master[ch] &= WM_VOL_MUTE;			ice->spec.phase28.master[ch] |= ucontrol->value.integer.value[ch];			for (dac = 0; dac < ice->num_total_dacs; dac += 2)				wm_set_vol(ice, WM_DAC_ATTEN + dac + ch,					   ice->spec.phase28.vol[dac + ch],					   ice->spec.phase28.master[ch]);			change = 1;		}	}	snd_ice1712_restore_gpio_status(ice);	return change;}static int __devinit phase28_init(ice1712_t *ice){	static unsigned short wm_inits_phase28[] = {		/* These come first to reduce init pop noise */		0x1b, 0x044,		/* ADC Mux (AC'97 source) */		0x1c, 0x00B,		/* Out Mux1 (VOUT1 = DAC+AUX, VOUT2 = DAC) */		0x1d, 0x009,		/* Out Mux2 (VOUT2 = DAC, VOUT3 = DAC) */		0x18, 0x000,		/* All power-up */		0x16, 0x122,		/* I2S, normal polarity, 24bit */		0x17, 0x022,		/* 256fs, slave mode */		0x00, 0,		/* DAC1 analog mute */		0x01, 0,		/* DAC2 analog mute */		0x02, 0,		/* DAC3 analog mute */		0x03, 0,		/* DAC4 analog mute */		0x04, 0,		/* DAC5 analog mute */		0x05, 0,		/* DAC6 analog mute */		0x06, 0,		/* DAC7 analog mute */		0x07, 0,		/* DAC8 analog mute */		0x08, 0x100,		/* master analog mute */		0x09, 0xff,		/* DAC1 digital full */		0x0a, 0xff,		/* DAC2 digital full */		0x0b, 0xff,		/* DAC3 digital full */		0x0c, 0xff,		/* DAC4 digital full */		0x0d, 0xff,		/* DAC5 digital full */		0x0e, 0xff,		/* DAC6 digital full */		0x0f, 0xff,		/* DAC7 digital full */		0x10, 0xff,		/* DAC8 digital full */		0x11, 0x1ff,		/* master digital full */		0x12, 0x000,		/* phase normal */		0x13, 0x090,		/* unmute DAC L/R */		0x14, 0x000,		/* all unmute */		0x15, 0x000,		/* no deemphasis, no ZFLG */		0x19, 0x000,		/* -12dB ADC/L */		0x1a, 0x000,		/* -12dB ADC/R */		(unsigned short)-1	};	unsigned int tmp;	akm4xxx_t *ak;	unsigned short *p;	int i;	ice->num_total_dacs = 8;	ice->num_total_adcs = 2;	// Initialize analog chips	ak = ice->akm = kzalloc(sizeof(akm4xxx_t), GFP_KERNEL);	if (!ak)		return -ENOMEM;	ice->akm_codecs = 1;	snd_ice1712_gpio_set_dir(ice, 0x5fffff); /* fix this for the time being */	/* reset the wm codec as the SPI mode */	snd_ice1712_save_gpio_status(ice);	snd_ice1712_gpio_set_mask(ice, ~(PHASE28_WM_RESET|PHASE28_WM_CS|PHASE28_HP_SEL));	tmp = snd_ice1712_gpio_read(ice);	tmp &= ~PHASE28_WM_RESET;	snd_ice1712_gpio_write(ice, tmp);	udelay(1);	tmp |= PHASE28_WM_CS;	snd_ice1712_gpio_write(ice, tmp);	udelay(1);	tmp |= PHASE28_WM_RESET;	snd_ice1712_gpio_write(ice, tmp);	udelay(1);	p = wm_inits_phase28;	for (; *p != (unsigned short)-1; p += 2)		wm_put(ice, p[0], p[1]);	snd_ice1712_restore_gpio_status(ice);	ice->spec.phase28.master[0] = WM_VOL_MUTE;	ice->spec.phase28.master[1] = WM_VOL_MUTE;	for (i = 0; i < ice->num_total_dacs; i++) {		ice->spec.phase28.vol[i] = WM_VOL_MUTE;		wm_set_vol(ice, i, ice->spec.phase28.vol[i], ice->spec.phase28.master[i % 2]);	}	return 0;}/* * DAC volume attenuation mixer control */static int wm_vol_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo){	int voices = kcontrol->private_value >> 8;	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;	uinfo->count = voices;

⌨️ 快捷键说明

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