📄 delta.c
字号:
/* * ALSA driver for ICEnsemble ICE1712 (Envy24) * * Lowlevel functions for M-Audio Delta 1010, 44, 66, Dio2496, Audiophile * Digigram VX442 * * Copyright (c) 2000 Jaroslav Kysela <perex@suse.cz> * * 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 "delta.h"#define SND_CS8403#include <sound/cs8403.h>/* * CS8427 via SPI mode (for Audiophile), emulated I2C *//* send 8 bits */static void ap_cs8427_write_byte(ice1712_t *ice, unsigned char data, unsigned char tmp){ int idx; for (idx = 7; idx >= 0; idx--) { tmp &= ~(ICE1712_DELTA_AP_DOUT|ICE1712_DELTA_AP_CCLK); if (data & (1 << idx)) tmp |= ICE1712_DELTA_AP_DOUT; snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, tmp); udelay(5); tmp |= ICE1712_DELTA_AP_CCLK; snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, tmp); udelay(5); }}/* read 8 bits */static unsigned char ap_cs8427_read_byte(ice1712_t *ice, unsigned char tmp){ unsigned char data = 0; int idx; for (idx = 7; idx >= 0; idx--) { tmp &= ~ICE1712_DELTA_AP_CCLK; snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, tmp); udelay(5); if (snd_ice1712_read(ice, ICE1712_IREG_GPIO_DATA) & ICE1712_DELTA_AP_DIN) data |= 1 << idx; tmp |= ICE1712_DELTA_AP_CCLK; snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, tmp); udelay(5); } return data;}/* assert chip select */static unsigned char ap_cs8427_codec_select(ice1712_t *ice){ unsigned char tmp; tmp = snd_ice1712_read(ice, ICE1712_IREG_GPIO_DATA); switch (ice->eeprom.subvendor) { case ICE1712_SUBDEVICE_DELTA1010LT: tmp &= ~ICE1712_DELTA_1010LT_CS; tmp |= ICE1712_DELTA_1010LT_CCLK | ICE1712_DELTA_1010LT_CS_CS8427; break; case ICE1712_SUBDEVICE_AUDIOPHILE: case ICE1712_SUBDEVICE_DELTA410: tmp |= ICE1712_DELTA_AP_CCLK | ICE1712_DELTA_AP_CS_CODEC; tmp &= ~ICE1712_DELTA_AP_CS_DIGITAL; break; case ICE1712_SUBDEVICE_VX442: tmp |= ICE1712_VX442_CCLK | ICE1712_VX442_CODEC_CHIP_A | ICE1712_VX442_CODEC_CHIP_B; tmp &= ~ICE1712_VX442_CS_DIGITAL; break; } snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, tmp); udelay(5); return tmp;}/* deassert chip select */static void ap_cs8427_codec_deassert(ice1712_t *ice, unsigned char tmp){ switch (ice->eeprom.subvendor) { case ICE1712_SUBDEVICE_DELTA1010LT: tmp &= ~ICE1712_DELTA_1010LT_CS; tmp |= ICE1712_DELTA_1010LT_CS_NONE; break; case ICE1712_SUBDEVICE_AUDIOPHILE: case ICE1712_SUBDEVICE_DELTA410: tmp |= ICE1712_DELTA_AP_CS_DIGITAL; break; case ICE1712_SUBDEVICE_VX442: tmp |= ICE1712_VX442_CS_DIGITAL; break; } snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, tmp);}/* sequential write */static int ap_cs8427_sendbytes(snd_i2c_device_t *device, unsigned char *bytes, int count){ ice1712_t *ice = device->bus->private_data; int res = count; unsigned char tmp; down(&ice->gpio_mutex); tmp = ap_cs8427_codec_select(ice); ap_cs8427_write_byte(ice, (device->addr << 1) | 0, tmp); /* address + write mode */ while (count-- > 0) ap_cs8427_write_byte(ice, *bytes++, tmp); ap_cs8427_codec_deassert(ice, tmp); up(&ice->gpio_mutex); return res;}/* sequential read */static int ap_cs8427_readbytes(snd_i2c_device_t *device, unsigned char *bytes, int count){ ice1712_t *ice = device->bus->private_data; int res = count; unsigned char tmp; down(&ice->gpio_mutex); tmp = ap_cs8427_codec_select(ice); ap_cs8427_write_byte(ice, (device->addr << 1) | 1, tmp); /* address + read mode */ while (count-- > 0) *bytes++ = ap_cs8427_read_byte(ice, tmp); ap_cs8427_codec_deassert(ice, tmp); up(&ice->gpio_mutex); return res;}static int ap_cs8427_probeaddr(snd_i2c_bus_t *bus, unsigned short addr){ if (addr == 0x10) return 1; return -ENOENT;}static snd_i2c_ops_t ap_cs8427_i2c_ops = { .sendbytes = ap_cs8427_sendbytes, .readbytes = ap_cs8427_readbytes, .probeaddr = ap_cs8427_probeaddr,};/* */static void snd_ice1712_delta_cs8403_spdif_write(ice1712_t *ice, unsigned char bits){ unsigned char tmp, mask1, mask2; int idx; /* send byte to transmitter */ mask1 = ICE1712_DELTA_SPDIF_OUT_STAT_CLOCK; mask2 = ICE1712_DELTA_SPDIF_OUT_STAT_DATA; down(&ice->gpio_mutex); tmp = snd_ice1712_read(ice, ICE1712_IREG_GPIO_DATA); for (idx = 7; idx >= 0; idx--) { tmp &= ~(mask1 | mask2); if (bits & (1 << idx)) tmp |= mask2; snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, tmp); udelay(100); tmp |= mask1; snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, tmp); udelay(100); } tmp &= ~mask1; snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, tmp); up(&ice->gpio_mutex);}static void delta_spdif_default_get(ice1712_t *ice, snd_ctl_elem_value_t * ucontrol){ snd_cs8403_decode_spdif_bits(&ucontrol->value.iec958, ice->spdif.cs8403_bits);}static int delta_spdif_default_put(ice1712_t *ice, snd_ctl_elem_value_t * ucontrol){ unsigned int val; int change; val = snd_cs8403_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_delta_cs8403_spdif_write(ice, val); } else { spin_unlock_irq(&ice->reg_lock); } return change;}static void delta_spdif_stream_get(ice1712_t *ice, snd_ctl_elem_value_t * ucontrol){ snd_cs8403_decode_spdif_bits(&ucontrol->value.iec958, ice->spdif.cs8403_stream_bits);}static int delta_spdif_stream_put(ice1712_t *ice, snd_ctl_elem_value_t * ucontrol){ unsigned int val; int change; val = snd_cs8403_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_delta_cs8403_spdif_write(ice, val); } else { spin_unlock_irq(&ice->reg_lock); } return change;}/* * AK4524 on Delta 44 and 66 to choose the chip mask */static void delta_ak4524_lock(akm4xxx_t *ak, int chip){ struct snd_ak4xxx_private *priv = (void *)ak->private_value[0]; ice1712_t *ice = ak->private_data[0]; snd_ice1712_save_gpio_status(ice); priv->cs_mask = priv->cs_addr = chip == 0 ? ICE1712_DELTA_CODEC_CHIP_A : ICE1712_DELTA_CODEC_CHIP_B;}/* * AK4524 on Delta1010LT to choose the chip address */static void delta1010lt_ak4524_lock(akm4xxx_t *ak, int chip){ struct snd_ak4xxx_private *priv = (void *)ak->private_value[0]; ice1712_t *ice = ak->private_data[0]; snd_ice1712_save_gpio_status(ice); priv->cs_mask = ICE1712_DELTA_1010LT_CS; priv->cs_addr = chip << 4;}/* * AK4528 on VX442 to choose the chip mask */static void vx442_ak4524_lock(akm4xxx_t *ak, int chip){ struct snd_ak4xxx_private *priv = (void *)ak->private_value[0]; ice1712_t *ice = ak->private_data[0]; snd_ice1712_save_gpio_status(ice); priv->cs_mask = priv->cs_addr = chip == 0 ? ICE1712_VX442_CODEC_CHIP_A : ICE1712_VX442_CODEC_CHIP_B;}/* * change the DFS bit according rate for Delta1010 */static void delta_1010_set_rate_val(ice1712_t *ice, unsigned int rate){ unsigned char tmp, tmp2; if (rate == 0) /* no hint - S/PDIF input is master, simply return */ return; down(&ice->gpio_mutex); tmp = snd_ice1712_read(ice, ICE1712_IREG_GPIO_DATA); tmp2 = tmp & ~ICE1712_DELTA_DFS; if (rate > 48000) tmp2 |= ICE1712_DELTA_DFS; if (tmp != tmp2) snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, tmp2); up(&ice->gpio_mutex);}/* * change the rate of AK4524 on Delta 44/66, AP, 1010LT */static void delta_ak4524_set_rate_val(akm4xxx_t *ak, unsigned int rate){ unsigned char tmp, tmp2; ice1712_t *ice = ak->private_data[0]; if (rate == 0) /* no hint - S/PDIF input is master, simply return */ return; /* check before reset ak4524 to avoid unnecessary clicks */ down(&ice->gpio_mutex); tmp = snd_ice1712_read(ice, ICE1712_IREG_GPIO_DATA); up(&ice->gpio_mutex); tmp2 = tmp & ~ICE1712_DELTA_DFS; if (rate > 48000) tmp2 |= ICE1712_DELTA_DFS; if (tmp == tmp2) return; /* do it again */ snd_akm4xxx_reset(ak, 1); down(&ice->gpio_mutex); tmp = snd_ice1712_read(ice, ICE1712_IREG_GPIO_DATA) & ~ICE1712_DELTA_DFS; if (rate > 48000) tmp |= ICE1712_DELTA_DFS; snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, tmp); up(&ice->gpio_mutex); snd_akm4xxx_reset(ak, 0);}/* * change the rate of AK4524 on VX442 */static void vx442_ak4524_set_rate_val(akm4xxx_t *ak, unsigned int rate){ unsigned char val; val = (rate > 48000) ? 0x65 : 0x60; if (snd_akm4xxx_get(ak, 0, 0x02) != val || snd_akm4xxx_get(ak, 1, 0x02) != val) { snd_akm4xxx_reset(ak, 1); snd_akm4xxx_write(ak, 0, 0x02, val); snd_akm4xxx_write(ak, 1, 0x02, val); snd_akm4xxx_reset(ak, 0); }}/* * SPDIF ops for Delta 1010, Dio, 66 *//* open callback */static void delta_open_spdif(ice1712_t *ice, snd_pcm_substream_t * substream){ ice->spdif.cs8403_stream_bits = ice->spdif.cs8403_bits;}/* set up */static void delta_setup_spdif(ice1712_t *ice, int rate){ unsigned long flags; unsigned int tmp; int change; spin_lock_irqsave(&ice->reg_lock, flags); tmp = ice->spdif.cs8403_stream_bits; if (tmp & 0x01) /* consumer */ tmp &= (tmp & 0x01) ? ~0x06 : ~0x18; switch (rate) { case 32000: tmp |= (tmp & 0x01) ? 0x04 : 0x00; break; case 44100: tmp |= (tmp & 0x01) ? 0x00 : 0x10; break; case 48000: tmp |= (tmp & 0x01) ? 0x02 : 0x08; break; default: tmp |= (tmp & 0x01) ? 0x00 : 0x18; break; } change = ice->spdif.cs8403_stream_bits != tmp;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -