diff options
Diffstat (limited to 'sound/pci/ice1712/revo.c')
-rw-r--r-- | sound/pci/ice1712/revo.c | 205 |
1 files changed, 205 insertions, 0 deletions
diff --git a/sound/pci/ice1712/revo.c b/sound/pci/ice1712/revo.c new file mode 100644 index 000000000000..d48d42524ac5 --- /dev/null +++ b/sound/pci/ice1712/revo.c | |||
@@ -0,0 +1,205 @@ | |||
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 | }; | ||