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(struct snd_ice1712 *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(struct snd_akm4xxx *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 || ak->type == SND_AK4358) { 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 struct snd_akm4xxx 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 struct snd_akm4xxx 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 struct snd_akm4xxx akm_revo51 __devinitdata = { 132 .type = SND_AK4358, 133 .num_dacs = 6, 134 .ops = { 135 .set_rate_val = revo_set_rate_val 136 } 137 }; 138 139 static struct snd_ak4xxx_private akm_revo51_priv __devinitdata = { 140 .caddr = 2, 141 .cif = 0, 142 .data_mask = VT1724_REVO_CDOUT, 143 .clk_mask = VT1724_REVO_CCLK, 144 .cs_mask = VT1724_REVO_CS0 | VT1724_REVO_CS1 | VT1724_REVO_CS2, 145 .cs_addr = 0, 146 .cs_none = VT1724_REVO_CS0 | VT1724_REVO_CS1 | VT1724_REVO_CS2, 147 .add_flags = VT1724_REVO_CCLK, /* high at init */ 148 .mask_flags = 0, 149 }; 150 151 static int __devinit revo_init(struct snd_ice1712 *ice) 152 { 153 struct snd_akm4xxx *ak; 154 int err; 155 156 /* determine I2C, DACs and ADCs */ 157 switch (ice->eeprom.subvendor) { 158 case VT1724_SUBDEVICE_REVOLUTION71: 159 ice->num_total_dacs = 8; 160 ice->num_total_adcs = 2; 161 ice->gpio.i2s_mclk_changed = revo_i2s_mclk_changed; 162 break; 163 case VT1724_SUBDEVICE_REVOLUTION51: 164 ice->num_total_dacs = 6; 165 ice->num_total_adcs = 2; 166 break; 167 default: 168 snd_BUG(); 169 return -EINVAL; 170 } 171 172 /* second stage of initialization, analog parts and others */ 173 ak = ice->akm = kcalloc(2, sizeof(struct snd_akm4xxx), GFP_KERNEL); 174 if (! ak) 175 return -ENOMEM; 176 ice->akm_codecs = 2; 177 switch (ice->eeprom.subvendor) { 178 case VT1724_SUBDEVICE_REVOLUTION71: 179 ice->akm_codecs = 2; 180 if ((err = snd_ice1712_akm4xxx_init(ak, &akm_revo_front, &akm_revo_front_priv, ice)) < 0) 181 return err; 182 if ((err = snd_ice1712_akm4xxx_init(ak + 1, &akm_revo_surround, &akm_revo_surround_priv, ice)) < 0) 183 return err; 184 /* unmute all codecs */ 185 snd_ice1712_gpio_write_bits(ice, VT1724_REVO_MUTE, VT1724_REVO_MUTE); 186 break; 187 case VT1724_SUBDEVICE_REVOLUTION51: 188 ice->akm_codecs = 1; 189 if ((err = snd_ice1712_akm4xxx_init(ak, &akm_revo51, &akm_revo51_priv, ice)) < 0) 190 return err; 191 /* unmute all codecs - needed! */ 192 snd_ice1712_gpio_write_bits(ice, VT1724_REVO_MUTE, VT1724_REVO_MUTE); 193 break; 194 } 195 196 return 0; 197 } 198 199 200 static int __devinit revo_add_controls(struct snd_ice1712 *ice) 201 { 202 int err; 203 204 switch (ice->eeprom.subvendor) { 205 case VT1724_SUBDEVICE_REVOLUTION71: 206 case VT1724_SUBDEVICE_REVOLUTION51: 207 err = snd_ice1712_akm4xxx_build_controls(ice); 208 if (err < 0) 209 return err; 210 } 211 return 0; 212 } 213 214 /* entry point */ 215 struct snd_ice1712_card_info snd_vt1724_revo_cards[] __devinitdata = { 216 { 217 .subvendor = VT1724_SUBDEVICE_REVOLUTION71, 218 .name = "M Audio Revolution-7.1", 219 .model = "revo71", 220 .chip_init = revo_init, 221 .build_controls = revo_add_controls, 222 }, 223 { 224 .subvendor = VT1724_SUBDEVICE_REVOLUTION51, 225 .name = "M Audio Revolution-5.1", 226 .model = "revo51", 227 .chip_init = revo_init, 228 .build_controls = revo_add_controls, 229 }, 230 { } /* terminator */ 231 }; 232