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

📄 pontis.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *   ALSA driver for ICEnsemble VT1724 (Envy24HT) * *   Lowlevel functions for Pontis MS300 * *	Copyright (c) 2004 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 * */#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 <sound/info.h>#include "ice1712.h"#include "envy24ht.h"#include "pontis.h"/* I2C addresses */#define WM_DEV		0x34#define CS_DEV		0x20/* WM8776 registers */#define WM_HP_ATTEN_L		0x00	/* headphone left attenuation */#define WM_HP_ATTEN_R		0x01	/* headphone left attenuation */#define WM_HP_MASTER		0x02	/* headphone master (both channels), override LLR */#define WM_DAC_ATTEN_L		0x03	/* digital left attenuation */#define WM_DAC_ATTEN_R		0x04#define WM_DAC_MASTER		0x05#define WM_PHASE_SWAP		0x06	/* DAC phase swap */#define WM_DAC_CTRL1		0x07#define WM_DAC_MUTE		0x08#define WM_DAC_CTRL2		0x09#define WM_DAC_INT		0x0a#define WM_ADC_INT		0x0b#define WM_MASTER_CTRL		0x0c#define WM_POWERDOWN		0x0d#define WM_ADC_ATTEN_L		0x0e#define WM_ADC_ATTEN_R		0x0f#define WM_ALC_CTRL1		0x10#define WM_ALC_CTRL2		0x11#define WM_ALC_CTRL3		0x12#define WM_NOISE_GATE		0x13#define WM_LIMITER		0x14#define WM_ADC_MUX		0x15#define WM_OUT_MUX		0x16#define WM_RESET		0x17/* * GPIO */#define PONTIS_CS_CS		(1<<4)	/* CS */#define PONTIS_CS_CLK		(1<<5)	/* CLK */#define PONTIS_CS_RDATA		(1<<6)	/* CS8416 -> VT1720 */#define PONTIS_CS_WDATA		(1<<7)	/* VT1720 -> CS8416 *//* * 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_nocache(ice1712_t *ice, int reg, unsigned short val){	unsigned short cval;	cval = (reg << 9) | val;	snd_vt1724_write_i2c(ice, WM_DEV, cval >> 8, cval & 0xff);}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;}/* * DAC volume attenuation mixer control (-64dB to 0dB) */#define DAC_0dB	0xff#define DAC_RES	128#define DAC_MIN	(DAC_0dB - DAC_RES)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 = 2;	uinfo->value.integer.min = 0;	/* mute */	uinfo->value.integer.max = DAC_RES;	/* 0dB, 0.5dB step */	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);	unsigned short val;	int i;	down(&ice->gpio_mutex);	for (i = 0; i < 2; i++) {		val = wm_get(ice, WM_DAC_ATTEN_L + i) & 0xff;		val = val > DAC_MIN ? (val - DAC_MIN) : 0;		ucontrol->value.integer.value[i] = val;	}	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);	unsigned short oval, nval;	int i, idx, change = 0;	down(&ice->gpio_mutex);	for (i = 0; i < 2; i++) {		nval = ucontrol->value.integer.value[i];		nval = (nval ? (nval + DAC_MIN) : 0) & 0xff;		idx = WM_DAC_ATTEN_L + i;		oval = wm_get(ice, idx) & 0xff;		if (oval != nval) {			wm_put(ice, idx, nval);			wm_put_nocache(ice, idx, nval | 0x100);			change = 1;		}	}	up(&ice->gpio_mutex);	return change;}/* * ADC gain mixer control (-64dB to 0dB) */#define ADC_0dB	0xcf#define ADC_RES	128#define ADC_MIN	(ADC_0dB - ADC_RES)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 = 2;	uinfo->value.integer.min = 0;	/* mute (-64dB) */	uinfo->value.integer.max = ADC_RES;	/* 0dB, 0.5dB step */	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);	unsigned short val;	int i;	down(&ice->gpio_mutex);	for (i = 0; i < 2; i++) {		val = wm_get(ice, WM_ADC_ATTEN_L + i) & 0xff;		val = val > ADC_MIN ? (val - ADC_MIN) : 0;		ucontrol->value.integer.value[i] = val;	}	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);	unsigned short ovol, nvol;	int i, idx, change = 0;	down(&ice->gpio_mutex);	for (i = 0; i < 2; i++) {		nvol = ucontrol->value.integer.value[i];		nvol = nvol ? (nvol + ADC_MIN) : 0;		idx  = WM_ADC_ATTEN_L + i;		ovol = wm_get(ice, idx) & 0xff;		if (ovol != nvol) {			wm_put(ice, idx, nvol);			change = 1;		}	}	up(&ice->gpio_mutex);	return change;}/* * ADC input mux mixer control */static int wm_adc_mux_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_mux_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t *ucontrol){	ice1712_t *ice = snd_kcontrol_chip(kcontrol);	int bit = kcontrol->private_value;	down(&ice->gpio_mutex);	ucontrol->value.integer.value[0] = (wm_get(ice, WM_ADC_MUX) & (1 << bit)) ? 1 : 0;	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);	int bit = kcontrol->private_value;	unsigned short oval, nval;	int change;	down(&ice->gpio_mutex);	nval = oval = wm_get(ice, WM_ADC_MUX);	if (ucontrol->value.integer.value[0])		nval |= (1 << bit);	else		nval &= ~(1 << bit);	change = nval != oval;	if (change) {		wm_put(ice, WM_ADC_MUX, nval);	}	up(&ice->gpio_mutex);	return 0;}/* * Analog bypass (In -> Out) */static int wm_bypass_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_bypass_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_OUT_MUX) & 0x04) ? 1 : 0;	up(&ice->gpio_mutex);	return 0;}static int wm_bypass_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t *ucontrol){	ice1712_t *ice = snd_kcontrol_chip(kcontrol);	unsigned short val, oval;	int change = 0;	down(&ice->gpio_mutex);	val = oval = wm_get(ice, WM_OUT_MUX);	if (ucontrol->value.integer.value[0])		val |= 0x04;	else		val &= ~0x04;	if (val != oval) {		wm_put(ice, WM_OUT_MUX, val);		change = 1;	}	up(&ice->gpio_mutex);	return change;}/* * Left/Right swap */static int wm_chswap_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_chswap_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_DAC_CTRL1) & 0xf0) != 0x90;	up(&ice->gpio_mutex);	return 0;}static int wm_chswap_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t *ucontrol){	ice1712_t *ice = snd_kcontrol_chip(kcontrol);	unsigned short val, oval;	int change = 0;	down(&ice->gpio_mutex);	oval = wm_get(ice, WM_DAC_CTRL1);	val = oval & 0x0f;	if (ucontrol->value.integer.value[0])		val |= 0x60;	else		val |= 0x90;	if (val != oval) {		wm_put(ice, WM_DAC_CTRL1, val);		wm_put_nocache(ice, WM_DAC_CTRL1, val);		change = 1;	}	up(&ice->gpio_mutex);	return change;}/* * write data in the SPI mode */static void set_gpio_bit(ice1712_t *ice, unsigned int bit, int val){	unsigned int tmp = snd_ice1712_gpio_read(ice);	if (val)		tmp |= bit;	else		tmp &= ~bit;	snd_ice1712_gpio_write(ice, tmp);}static void spi_send_byte(ice1712_t *ice, unsigned char data){	int i;	for (i = 0; i < 8; i++) {		set_gpio_bit(ice, PONTIS_CS_CLK, 0);		udelay(1);		set_gpio_bit(ice, PONTIS_CS_WDATA, data & 0x80);		udelay(1);		set_gpio_bit(ice, PONTIS_CS_CLK, 1);		udelay(1);		data <<= 1;	}}static unsigned int spi_read_byte(ice1712_t *ice){	int i;	unsigned int val = 0;	for (i = 0; i < 8; i++) {		val <<= 1;		set_gpio_bit(ice, PONTIS_CS_CLK, 0);		udelay(1);		if (snd_ice1712_gpio_read(ice) & PONTIS_CS_RDATA)			val |= 1;		udelay(1);		set_gpio_bit(ice, PONTIS_CS_CLK, 1);		udelay(1);	}	return val;}static void spi_write(ice1712_t *ice, unsigned int dev, unsigned int reg, unsigned int data){	snd_ice1712_gpio_set_dir(ice, PONTIS_CS_CS|PONTIS_CS_WDATA|PONTIS_CS_CLK);	snd_ice1712_gpio_set_mask(ice, ~(PONTIS_CS_CS|PONTIS_CS_WDATA|PONTIS_CS_CLK));	set_gpio_bit(ice, PONTIS_CS_CS, 0);	spi_send_byte(ice, dev & ~1); /* WRITE */	spi_send_byte(ice, reg); /* MAP */	spi_send_byte(ice, data); /* DATA */	/* trigger */	set_gpio_bit(ice, PONTIS_CS_CS, 1);	udelay(1);	/* restore */	snd_ice1712_gpio_set_mask(ice, ice->gpio.write_mask);	snd_ice1712_gpio_set_dir(ice, ice->gpio.direction);}static unsigned int spi_read(ice1712_t *ice, unsigned int dev, unsigned int reg){	unsigned int val;	snd_ice1712_gpio_set_dir(ice, PONTIS_CS_CS|PONTIS_CS_WDATA|PONTIS_CS_CLK);	snd_ice1712_gpio_set_mask(ice, ~(PONTIS_CS_CS|PONTIS_CS_WDATA|PONTIS_CS_CLK));	set_gpio_bit(ice, PONTIS_CS_CS, 0);	spi_send_byte(ice, dev & ~1); /* WRITE */	spi_send_byte(ice, reg); /* MAP */	/* trigger */	set_gpio_bit(ice, PONTIS_CS_CS, 1);	udelay(1);	set_gpio_bit(ice, PONTIS_CS_CS, 0);	spi_send_byte(ice, dev | 1); /* READ */	val = spi_read_byte(ice);	/* trigger */	set_gpio_bit(ice, PONTIS_CS_CS, 1);	udelay(1);	/* restore */	snd_ice1712_gpio_set_mask(ice, ice->gpio.write_mask);	snd_ice1712_gpio_set_dir(ice, ice->gpio.direction);	return val;

⌨️ 快捷键说明

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