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

📄 ews.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *   ALSA driver for ICEnsemble ICE1712 (Envy24) * *   Lowlevel functions for Terratec EWS88MT/D, EWX24/96, DMX 6Fire * *	Copyright (c) 2000 Jaroslav Kysela <perex@suse.cz> *                    2002 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/cs8427.h>#include <sound/asoundef.h>#include "ice1712.h"#include "ews.h"#define SND_CS8404#include <sound/cs8403.h>enum {	EWS_I2C_CS8404 = 0, EWS_I2C_PCF1, EWS_I2C_PCF2,	EWS_I2C_88D = 0,	EWS_I2C_6FIRE = 0};	/* * access via i2c mode (for EWX 24/96, EWS 88MT&D) *//* send SDA and SCL */static void ewx_i2c_setlines(snd_i2c_bus_t *bus, int clk, int data){	ice1712_t *ice = bus->private_data;	unsigned char tmp = 0;	if (clk)		tmp |= ICE1712_EWX2496_SERIAL_CLOCK;	if (data)		tmp |= ICE1712_EWX2496_SERIAL_DATA;	snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, tmp);	udelay(5);}static int ewx_i2c_getclock(snd_i2c_bus_t *bus){	ice1712_t *ice = bus->private_data;	return snd_ice1712_read(ice, ICE1712_IREG_GPIO_DATA) & ICE1712_EWX2496_SERIAL_CLOCK ? 1 : 0;}static int ewx_i2c_getdata(snd_i2c_bus_t *bus, int ack){	ice1712_t *ice = bus->private_data;	int bit;	/* set RW pin to low */	snd_ice1712_write(ice, ICE1712_IREG_GPIO_WRITE_MASK, ~ICE1712_EWX2496_RW);	snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, 0);	if (ack)		udelay(5);	bit = snd_ice1712_read(ice, ICE1712_IREG_GPIO_DATA) & ICE1712_EWX2496_SERIAL_DATA ? 1 : 0;	/* set RW pin to high */	snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, ICE1712_EWX2496_RW);	/* reset write mask */	snd_ice1712_write(ice, ICE1712_IREG_GPIO_WRITE_MASK, ~ICE1712_EWX2496_SERIAL_CLOCK);	return bit;}static void ewx_i2c_start(snd_i2c_bus_t *bus){	ice1712_t *ice = bus->private_data;	unsigned char mask;	snd_ice1712_save_gpio_status(ice);	/* set RW high */	mask = ICE1712_EWX2496_RW;	switch (ice->eeprom.subvendor) {	case ICE1712_SUBDEVICE_EWX2496:		mask |= ICE1712_EWX2496_AK4524_CS; /* CS high also */		break;	case ICE1712_SUBDEVICE_DMX6FIRE:		mask |= ICE1712_6FIRE_AK4524_CS_MASK; /* CS high also */		break;	}	snd_ice1712_gpio_write_bits(ice, mask, mask);}static void ewx_i2c_stop(snd_i2c_bus_t *bus){	ice1712_t *ice = bus->private_data;	snd_ice1712_restore_gpio_status(ice);}static void ewx_i2c_direction(snd_i2c_bus_t *bus, int clock, int data){	ice1712_t *ice = bus->private_data;	unsigned char mask = 0;	if (clock)		mask |= ICE1712_EWX2496_SERIAL_CLOCK; /* write SCL */	if (data)		mask |= ICE1712_EWX2496_SERIAL_DATA; /* write SDA */	ice->gpio.direction &= ~(ICE1712_EWX2496_SERIAL_CLOCK|ICE1712_EWX2496_SERIAL_DATA);	ice->gpio.direction |= mask;	snd_ice1712_write(ice, ICE1712_IREG_GPIO_DIRECTION, ice->gpio.direction);	snd_ice1712_write(ice, ICE1712_IREG_GPIO_WRITE_MASK, ~mask);}static snd_i2c_bit_ops_t snd_ice1712_ewx_cs8427_bit_ops = {	.start = ewx_i2c_start,	.stop = ewx_i2c_stop,	.direction = ewx_i2c_direction,	.setlines = ewx_i2c_setlines,	.getclock = ewx_i2c_getclock,	.getdata = ewx_i2c_getdata,};/* * AK4524 access *//* AK4524 chip select; address 0x48 bit 0-3 */static int snd_ice1712_ews88mt_chip_select(ice1712_t *ice, int chip_mask){	unsigned char data, ndata;	snd_assert(chip_mask >= 0 && chip_mask <= 0x0f, return -EINVAL);	snd_i2c_lock(ice->i2c);	if (snd_i2c_readbytes(ice->spec.i2cdevs[EWS_I2C_PCF2], &data, 1) != 1)		goto __error;	ndata = (data & 0xf0) | chip_mask;	if (ndata != data)		if (snd_i2c_sendbytes(ice->spec.i2cdevs[EWS_I2C_PCF2], &ndata, 1) != 1)			goto __error;	snd_i2c_unlock(ice->i2c);	return 0;     __error:	snd_i2c_unlock(ice->i2c);	snd_printk(KERN_ERR "AK4524 chip select failed, check cable to the front module\n");	return -EIO;}/* start callback for EWS88MT, needs to select a certain chip mask */static void ews88mt_ak4524_lock(akm4xxx_t *ak, int chip){	ice1712_t *ice = ak->private_data[0];	unsigned char tmp;	/* assert AK4524 CS */	if (snd_ice1712_ews88mt_chip_select(ice, ~(1 << chip) & 0x0f) < 0)		snd_printk(KERN_ERR "fatal error (ews88mt chip select)\n");	snd_ice1712_save_gpio_status(ice);	tmp = ICE1712_EWS88_SERIAL_DATA |		ICE1712_EWS88_SERIAL_CLOCK |		ICE1712_EWS88_RW;	snd_ice1712_write(ice, ICE1712_IREG_GPIO_DIRECTION,			  ice->gpio.direction | tmp);	snd_ice1712_write(ice, ICE1712_IREG_GPIO_WRITE_MASK, ~tmp);}/* stop callback for EWS88MT, needs to deselect chip mask */static void ews88mt_ak4524_unlock(akm4xxx_t *ak, int chip){	ice1712_t *ice = ak->private_data[0];	snd_ice1712_restore_gpio_status(ice);	udelay(1);	snd_ice1712_ews88mt_chip_select(ice, 0x0f);}/* start callback for EWX24/96 */static void ewx2496_ak4524_lock(akm4xxx_t *ak, int chip){	ice1712_t *ice = ak->private_data[0];	unsigned char tmp;	snd_ice1712_save_gpio_status(ice);	tmp =  ICE1712_EWX2496_SERIAL_DATA |		ICE1712_EWX2496_SERIAL_CLOCK |		ICE1712_EWX2496_AK4524_CS |		ICE1712_EWX2496_RW;	snd_ice1712_write(ice, ICE1712_IREG_GPIO_DIRECTION,			  ice->gpio.direction | tmp);	snd_ice1712_write(ice, ICE1712_IREG_GPIO_WRITE_MASK, ~tmp);}/* start callback for DMX 6fire */static void dmx6fire_ak4524_lock(akm4xxx_t *ak, int chip){	struct snd_ak4xxx_private *priv = (void *)ak->private_value[0];	ice1712_t *ice = ak->private_data[0];	unsigned char tmp;	snd_ice1712_save_gpio_status(ice);	tmp = priv->cs_mask = priv->cs_addr = (1 << chip) & ICE1712_6FIRE_AK4524_CS_MASK;	tmp |= ICE1712_6FIRE_SERIAL_DATA |		ICE1712_6FIRE_SERIAL_CLOCK |		ICE1712_6FIRE_RW;	snd_ice1712_write(ice, ICE1712_IREG_GPIO_DIRECTION,			  ice->gpio.direction | tmp);	snd_ice1712_write(ice, ICE1712_IREG_GPIO_WRITE_MASK, ~tmp);}/* * CS8404 interface on EWS88MT/D */static void snd_ice1712_ews_cs8404_spdif_write(ice1712_t *ice, unsigned char bits){	unsigned char bytes[2];	snd_i2c_lock(ice->i2c);	switch (ice->eeprom.subvendor) {	case ICE1712_SUBDEVICE_EWS88MT:	case ICE1712_SUBDEVICE_EWS88MT_NEW:	case ICE1712_SUBDEVICE_PHASE88:		if (snd_i2c_sendbytes(ice->spec.i2cdevs[EWS_I2C_CS8404], &bits, 1) != 1)			goto _error;		break;	case ICE1712_SUBDEVICE_EWS88D:		if (snd_i2c_readbytes(ice->spec.i2cdevs[EWS_I2C_88D], bytes, 2) != 2)			goto _error;		if (bits != bytes[1]) {			bytes[1] = bits;			if (snd_i2c_sendbytes(ice->spec.i2cdevs[EWS_I2C_88D], bytes, 2) != 2)				goto _error;		}		break;	} _error:	snd_i2c_unlock(ice->i2c);}/* */static void ews88_spdif_default_get(ice1712_t *ice, snd_ctl_elem_value_t * ucontrol){	snd_cs8404_decode_spdif_bits(&ucontrol->value.iec958, ice->spdif.cs8403_bits);}static int ews88_spdif_default_put(ice1712_t *ice, snd_ctl_elem_value_t * ucontrol){	unsigned int val;	int change;	val = snd_cs8404_encode_spdif_bits(&ucontrol->value.iec958);	spin_lock_irq(&ice->reg_lock);	change = ice->spdif.cs8403_bits != val;	ice->spdif.cs8403_bits = val;	if (change && ice->playback_pro_substream == NULL) {		spin_unlock_irq(&ice->reg_lock);		snd_ice1712_ews_cs8404_spdif_write(ice, val);	} else {		spin_unlock_irq(&ice->reg_lock);	}	return change;}static void ews88_spdif_stream_get(ice1712_t *ice, snd_ctl_elem_value_t * ucontrol){	snd_cs8404_decode_spdif_bits(&ucontrol->value.iec958, ice->spdif.cs8403_stream_bits);}static int ews88_spdif_stream_put(ice1712_t *ice, snd_ctl_elem_value_t * ucontrol){	unsigned int val;	int change;	val = snd_cs8404_encode_spdif_bits(&ucontrol->value.iec958);	spin_lock_irq(&ice->reg_lock);	change = ice->spdif.cs8403_stream_bits != val;	ice->spdif.cs8403_stream_bits = val;	if (change && ice->playback_pro_substream != NULL) {		spin_unlock_irq(&ice->reg_lock);		snd_ice1712_ews_cs8404_spdif_write(ice, val);	} else {		spin_unlock_irq(&ice->reg_lock);	}	return change;}/* open callback */static void ews88_open_spdif(ice1712_t *ice, snd_pcm_substream_t * substream){	ice->spdif.cs8403_stream_bits = ice->spdif.cs8403_bits;}/* set up SPDIF for EWS88MT / EWS88D */static void ews88_setup_spdif(ice1712_t *ice, int rate){	unsigned long flags;	unsigned char tmp;	int change;	spin_lock_irqsave(&ice->reg_lock, flags);	tmp = ice->spdif.cs8403_stream_bits;	if (tmp & 0x10)		/* consumer */		tmp &= (tmp & 0x01) ? ~0x06 : ~0x60;	switch (rate) {	case 32000: tmp |= (tmp & 0x01) ? 0x02 : 0x00; break;	case 44100: tmp |= (tmp & 0x01) ? 0x06 : 0x40; break;	case 48000: tmp |= (tmp & 0x01) ? 0x04 : 0x20; break;	default: tmp |= (tmp & 0x01) ? 0x06 : 0x40; break;	}	change = ice->spdif.cs8403_stream_bits != tmp;	ice->spdif.cs8403_stream_bits = tmp;	spin_unlock_irqrestore(&ice->reg_lock, flags);	if (change)		snd_ctl_notify(ice->card, SNDRV_CTL_EVENT_MASK_VALUE, &ice->spdif.stream_ctl->id);	snd_ice1712_ews_cs8404_spdif_write(ice, tmp);}/* */static akm4xxx_t akm_ews88mt __devinitdata = {	.num_adcs = 8,	.num_dacs = 8,	.type = SND_AK4524,	.ops = {		.lock = ews88mt_ak4524_lock,		.unlock = ews88mt_ak4524_unlock	}};static struct snd_ak4xxx_private akm_ews88mt_priv __devinitdata = {	.caddr = 2,	.cif = 1, /* CIF high */	.data_mask = ICE1712_EWS88_SERIAL_DATA,	.clk_mask = ICE1712_EWS88_SERIAL_CLOCK,	.cs_mask = 0,	.cs_addr = 0,	.cs_none = 0, /* no chip select on gpio */	.add_flags = ICE1712_EWS88_RW, /* set rw bit high */	.mask_flags = 0,};static akm4xxx_t akm_ewx2496 __devinitdata = {	.num_adcs = 2,	.num_dacs = 2,	.type = SND_AK4524,	.ops = {		.lock = ewx2496_ak4524_lock	}};static struct snd_ak4xxx_private akm_ewx2496_priv __devinitdata = {	.caddr = 2,	.cif = 1, /* CIF high */	.data_mask = ICE1712_EWS88_SERIAL_DATA,	.clk_mask = ICE1712_EWS88_SERIAL_CLOCK,	.cs_mask = ICE1712_EWX2496_AK4524_CS,	.cs_addr = ICE1712_EWX2496_AK4524_CS,	.cs_none = 0,	.add_flags = ICE1712_EWS88_RW, /* set rw bit high */	.mask_flags = 0,};static akm4xxx_t akm_6fire __devinitdata = {	.num_adcs = 6,	.num_dacs = 6,	.type = SND_AK4524,	.ops = {		.lock = dmx6fire_ak4524_lock	}};static struct snd_ak4xxx_private akm_6fire_priv __devinitdata = {	.caddr = 2,	.cif = 1, /* CIF high */	.data_mask = ICE1712_6FIRE_SERIAL_DATA,	.clk_mask = ICE1712_6FIRE_SERIAL_CLOCK,	.cs_mask = 0,	.cs_addr = 0, /* set later */	.cs_none = 0,	.add_flags = ICE1712_6FIRE_RW, /* set rw bit high */	.mask_flags = 0,};/* * initialize the chip *//* 6fire specific */#define PCF9554_REG_INPUT      0#define PCF9554_REG_OUTPUT     1#define PCF9554_REG_POLARITY   2#define PCF9554_REG_CONFIG     3static int snd_ice1712_6fire_write_pca(ice1712_t *ice, unsigned char reg, unsigned char data);static int __devinit snd_ice1712_ews_init(ice1712_t *ice){	int err;	akm4xxx_t *ak;	/* set the analog DACs */	switch (ice->eeprom.subvendor) {	case ICE1712_SUBDEVICE_EWX2496:		ice->num_total_dacs = 2;		ice->num_total_adcs = 2;		break;		case ICE1712_SUBDEVICE_EWS88MT:	case ICE1712_SUBDEVICE_EWS88MT_NEW:	case ICE1712_SUBDEVICE_PHASE88:		ice->num_total_dacs = 8;		ice->num_total_adcs = 8;		break;	case ICE1712_SUBDEVICE_EWS88D:		/* Note: not analog but ADAT I/O */		ice->num_total_dacs = 8;		ice->num_total_adcs = 8;		break;	case ICE1712_SUBDEVICE_DMX6FIRE:		ice->num_total_dacs = 6;		ice->num_total_adcs = 6;		break;	}	/* create i2c */	if ((err = snd_i2c_bus_create(ice->card, "ICE1712 GPIO 1", NULL, &ice->i2c)) < 0) {		snd_printk(KERN_ERR "unable to create I2C bus\n");		return err;	}	ice->i2c->private_data = ice;	ice->i2c->hw_ops.bit = &snd_ice1712_ewx_cs8427_bit_ops;	/* create i2c devices */	switch (ice->eeprom.subvendor) {	case ICE1712_SUBDEVICE_DMX6FIRE:		if ((err = snd_i2c_device_create(ice->i2c, "PCF9554", ICE1712_6FIRE_PCF9554_ADDR, &ice->spec.i2cdevs[EWS_I2C_6FIRE])) < 0) {			snd_printk(KERN_ERR "PCF9554 initialization failed\n");			return err;		}		snd_ice1712_6fire_write_pca(ice, PCF9554_REG_CONFIG, 0x80);		break;	case ICE1712_SUBDEVICE_EWS88MT:	case ICE1712_SUBDEVICE_EWS88MT_NEW:	case ICE1712_SUBDEVICE_PHASE88:		if ((err = snd_i2c_device_create(ice->i2c, "CS8404", ICE1712_EWS88MT_CS8404_ADDR, &ice->spec.i2cdevs[EWS_I2C_CS8404])) < 0)			return err;		if ((err = snd_i2c_device_create(ice->i2c, "PCF8574 (1st)", ICE1712_EWS88MT_INPUT_ADDR, &ice->spec.i2cdevs[EWS_I2C_PCF1])) < 0)			return err;		if ((err = snd_i2c_device_create(ice->i2c, "PCF8574 (2nd)", ICE1712_EWS88MT_OUTPUT_ADDR, &ice->spec.i2cdevs[EWS_I2C_PCF2])) < 0)			return err;		/* Check if the front module is connected */		if ((err = snd_ice1712_ews88mt_chip_select(ice, 0x0f)) < 0)			return err;		break;	case ICE1712_SUBDEVICE_EWS88D:		if ((err = snd_i2c_device_create(ice->i2c, "PCF8575", ICE1712_EWS88D_PCF_ADDR, &ice->spec.i2cdevs[EWS_I2C_88D])) < 0)			return err;		break;	}	/* set up SPDIF interface */	switch (ice->eeprom.subvendor) {	case ICE1712_SUBDEVICE_EWX2496:		if ((err = snd_ice1712_init_cs8427(ice, CS8427_BASE_ADDR)) < 0)			return err;		snd_cs8427_reg_write(ice->cs8427, CS8427_REG_RECVERRMASK, CS8427_UNLOCK | CS8427_CONF | CS8427_BIP | CS8427_PAR);		break;	case ICE1712_SUBDEVICE_DMX6FIRE:		if ((err = snd_ice1712_init_cs8427(ice, ICE1712_6FIRE_CS8427_ADDR)) < 0)			return err;		snd_cs8427_reg_write(ice->cs8427, CS8427_REG_RECVERRMASK, CS8427_UNLOCK | CS8427_CONF | CS8427_BIP | CS8427_PAR);		break;	case ICE1712_SUBDEVICE_EWS88MT:	case ICE1712_SUBDEVICE_EWS88MT_NEW:	case ICE1712_SUBDEVICE_PHASE88:	case ICE1712_SUBDEVICE_EWS88D:		/* set up CS8404 */		ice->spdif.ops.open = ews88_open_spdif;		ice->spdif.ops.setup_rate = ews88_setup_spdif;		ice->spdif.ops.default_get = ews88_spdif_default_get;		ice->spdif.ops.default_put = ews88_spdif_default_put;		ice->spdif.ops.stream_get = ews88_spdif_stream_get;		ice->spdif.ops.stream_put = ews88_spdif_stream_put;		/* Set spdif defaults */		snd_ice1712_ews_cs8404_spdif_write(ice, ice->spdif.cs8403_bits);		break;	}	/* no analog? */	switch (ice->eeprom.subvendor) {	case ICE1712_SUBDEVICE_EWS88D:		return 0;	}	/* analog section */	ak = ice->akm = kmalloc(sizeof(akm4xxx_t), GFP_KERNEL);	if (! ak)		return -ENOMEM;	ice->akm_codecs = 1;	switch (ice->eeprom.subvendor) {	case ICE1712_SUBDEVICE_EWS88MT:	case ICE1712_SUBDEVICE_EWS88MT_NEW:	case ICE1712_SUBDEVICE_PHASE88:		err = snd_ice1712_akm4xxx_init(ak, &akm_ews88mt, &akm_ews88mt_priv, ice);

⌨️ 快捷键说明

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