1 /* 2 * ALSA driver for ICEnsemble ICE1712 (Envy24) 3 * 4 * Lowlevel functions for M-Audio Revolution 7.1 5 * 6 * Copyright (c) 2003 Takashi Iwai <tiwai@suse.de> 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 21 * 22 */ 23 24 #include <sound/driver.h> 25 #include <asm/io.h> 26 #include <linux/delay.h> 27 #include <linux/interrupt.h> 28 #include <linux/init.h> 29 #include <linux/slab.h> 30 #include <sound/core.h> 31 32 #include "ice1712.h" 33 #include "envy24ht.h" 34 #include "revo.h" 35 36 static void revo_i2s_mclk_changed(ice1712_t *ice) 37 { 38 /* assert PRST# to converters; MT05 bit 7 */ 39 outb(inb(ICEMT1724(ice, AC97_CMD)) | 0x80, ICEMT1724(ice, AC97_CMD)); 40 mdelay(5); 41 /* deassert PRST# */ 42 outb(inb(ICEMT1724(ice, AC97_CMD)) & ~0x80, ICEMT1724(ice, AC97_CMD)); 43 } 44 45 /* 46 * change the rate of envy24HT, AK4355 and AK4381 47 */ 48 static void revo_set_rate_val(akm4xxx_t *ak, unsigned int rate) 49 { 50 unsigned char old, tmp, dfs; 51 int reg, shift; 52 53 if (rate == 0) /* no hint - S/PDIF input is master, simply return */ 54 return; 55 56 /* adjust DFS on codecs */ 57 if (rate > 96000) 58 dfs = 2; 59 else if (rate > 48000) 60 dfs = 1; 61 else 62 dfs = 0; 63 64 if (ak->type == SND_AK4355) { 65 reg = 2; 66 shift = 4; 67 } else { 68 reg = 1; 69 shift = 3; 70 } 71 tmp = snd_akm4xxx_get(ak, 0, reg); 72 old = (tmp >> shift) & 0x03; 73 if (old == dfs) 74 return; 75 76 /* reset DFS */ 77 snd_akm4xxx_reset(ak, 1); 78 tmp = snd_akm4xxx_get(ak, 0, reg); 79 tmp &= ~(0x03 << shift); 80 tmp |= dfs << shift; 81 // snd_akm4xxx_write(ak, 0, reg, tmp); 82 snd_akm4xxx_set(ak, 0, reg, tmp); /* the value is written in reset(0) */ 83 snd_akm4xxx_reset(ak, 0); 84 } 85 86 /* 87 * initialize the chips on M-Audio Revolution cards 88 */ 89 90 static akm4xxx_t akm_revo_front __devinitdata = { 91 .type = SND_AK4381, 92 .num_dacs = 2, 93 .ops = { 94 .set_rate_val = revo_set_rate_val 95 } 96 }; 97 98 static struct snd_ak4xxx_private akm_revo_front_priv __devinitdata = { 99 .caddr = 1, 100 .cif = 0, 101 .data_mask = VT1724_REVO_CDOUT, 102 .clk_mask = VT1724_REVO_CCLK, 103 .cs_mask = VT1724_REVO_CS0 | VT1724_REVO_CS1 | VT1724_REVO_CS2, 104 .cs_addr = VT1724_REVO_CS0 | VT1724_REVO_CS2, 105 .cs_none = VT1724_REVO_CS0 | VT1724_REVO_CS1 | VT1724_REVO_CS2, 106 .add_flags = VT1724_REVO_CCLK, /* high at init */ 107 .mask_flags = 0, 108 }; 109 110 static akm4xxx_t akm_revo_surround __devinitdata = { 111 .type = SND_AK4355, 112 .idx_offset = 1, 113 .num_dacs = 6, 114 .ops = { 115 .set_rate_val = revo_set_rate_val 116 } 117 }; 118 119 static struct snd_ak4xxx_private akm_revo_surround_priv __devinitdata = { 120 .caddr = 3, 121 .cif = 0, 122 .data_mask = VT1724_REVO_CDOUT, 123 .clk_mask = VT1724_REVO_CCLK, 124 .cs_mask = VT1724_REVO_CS0 | VT1724_REVO_CS1 | VT1724_REVO_CS2, 125 .cs_addr = VT1724_REVO_CS0 | VT1724_REVO_CS1, 126 .cs_none = VT1724_REVO_CS0 | VT1724_REVO_CS1 | VT1724_REVO_CS2, 127 .add_flags = VT1724_REVO_CCLK, /* high at init */ 128 .mask_flags = 0, 129 }; 130 131 static int __devinit revo_init(ice1712_t *ice) 132 { 133 akm4xxx_t *ak; 134 int err; 135 136 /* determine I2C, DACs and ADCs */ 137 switch (ice->eeprom.subvendor) { 138 case VT1724_SUBDEVICE_REVOLUTION71: 139 ice->num_total_dacs = 8; 140 ice->num_total_adcs = 2; 141 break; 142 default: 143 snd_BUG(); 144 return -EINVAL; 145 } 146 147 ice->gpio.i2s_mclk_changed = revo_i2s_mclk_changed; 148 149 /* second stage of initialization, analog parts and others */ 150 ak = ice->akm = kcalloc(2, sizeof(akm4xxx_t), GFP_KERNEL); 151 if (! ak) 152 return -ENOMEM; 153 ice->akm_codecs = 2; 154 switch (ice->eeprom.subvendor) { 155 case VT1724_SUBDEVICE_REVOLUTION71: 156 if ((err = snd_ice1712_akm4xxx_init(ak, &akm_revo_front, &akm_revo_front_priv, ice)) < 0) 157 return err; 158 if ((err = snd_ice1712_akm4xxx_init(ak + 1, &akm_revo_surround, &akm_revo_surround_priv, ice)) < 0) 159 return err; 160 /* unmute all codecs */ 161 snd_ice1712_gpio_write_bits(ice, VT1724_REVO_MUTE, VT1724_REVO_MUTE); 162 break; 163 } 164 165 return 0; 166 } 167 168 169 static int __devinit revo_add_controls(ice1712_t *ice) 170 { 171 int err; 172 173 switch (ice->eeprom.subvendor) { 174 case VT1724_SUBDEVICE_REVOLUTION71: 175 err = snd_ice1712_akm4xxx_build_controls(ice); 176 if (err < 0) 177 return err; 178 } 179 return 0; 180 } 181 182 /* entry point */ 183 struct snd_ice1712_card_info snd_vt1724_revo_cards[] __devinitdata = { 184 { 185 .subvendor = VT1724_SUBDEVICE_REVOLUTION71, 186 .name = "M Audio Revolution-7.1", 187 .model = "revo71", 188 .chip_init = revo_init, 189 .build_controls = revo_add_controls, 190 }, 191 { } /* terminator */ 192 }; 193