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 unsigned int rates[] = { 132 32000, 44100, 48000, 64000, 88200, 96000, 133 176400, 192000, 134 }; 135 136 static snd_pcm_hw_constraint_list_t revo_rates = { 137 .count = ARRAY_SIZE(rates), 138 .list = rates, 139 .mask = 0, 140 }; 141 142 static int __devinit revo_init(ice1712_t *ice) 143 { 144 akm4xxx_t *ak; 145 int err; 146 147 /* determine I2C, DACs and ADCs */ 148 switch (ice->eeprom.subvendor) { 149 case VT1724_SUBDEVICE_REVOLUTION71: 150 ice->num_total_dacs = 8; 151 ice->num_total_adcs = 2; 152 break; 153 default: 154 snd_BUG(); 155 return -EINVAL; 156 } 157 158 ice->gpio.i2s_mclk_changed = revo_i2s_mclk_changed; 159 160 /* second stage of initialization, analog parts and others */ 161 ak = ice->akm = kcalloc(2, sizeof(akm4xxx_t), GFP_KERNEL); 162 if (! ak) 163 return -ENOMEM; 164 ice->akm_codecs = 2; 165 switch (ice->eeprom.subvendor) { 166 case VT1724_SUBDEVICE_REVOLUTION71: 167 if ((err = snd_ice1712_akm4xxx_init(ak, &akm_revo_front, &akm_revo_front_priv, ice)) < 0) 168 return err; 169 if ((err = snd_ice1712_akm4xxx_init(ak + 1, &akm_revo_surround, &akm_revo_surround_priv, ice)) < 0) 170 return err; 171 /* unmute all codecs */ 172 snd_ice1712_gpio_write_bits(ice, VT1724_REVO_MUTE, VT1724_REVO_MUTE); 173 break; 174 } 175 176 ice->hw_rates = &revo_rates; /* AK codecs don't support lower than 32k */ 177 178 return 0; 179 } 180 181 182 static int __devinit revo_add_controls(ice1712_t *ice) 183 { 184 int err; 185 186 switch (ice->eeprom.subvendor) { 187 case VT1724_SUBDEVICE_REVOLUTION71: 188 err = snd_ice1712_akm4xxx_build_controls(ice); 189 if (err < 0) 190 return err; 191 } 192 return 0; 193 } 194 195 /* entry point */ 196 struct snd_ice1712_card_info snd_vt1724_revo_cards[] __devinitdata = { 197 { 198 .subvendor = VT1724_SUBDEVICE_REVOLUTION71, 199 .name = "M Audio Revolution-7.1", 200 .model = "revo71", 201 .chip_init = revo_init, 202 .build_controls = revo_add_controls, 203 }, 204 { } /* terminator */ 205 }; 206