diff options
Diffstat (limited to 'sound/pci/ice1712')
-rw-r--r-- | sound/pci/ice1712/Makefile | 2 | ||||
-rw-r--r-- | sound/pci/ice1712/ice1712.h | 8 | ||||
-rw-r--r-- | sound/pci/ice1712/ice1724.c | 3 | ||||
-rw-r--r-- | sound/pci/ice1712/prodigy_hifi.c | 1195 |
4 files changed, 1206 insertions, 2 deletions
diff --git a/sound/pci/ice1712/Makefile b/sound/pci/ice1712/Makefile index ee86a1de72f8..f99fe089495d 100644 --- a/sound/pci/ice1712/Makefile +++ b/sound/pci/ice1712/Makefile | ||||
@@ -5,7 +5,7 @@ | ||||
5 | 5 | |||
6 | snd-ice17xx-ak4xxx-objs := ak4xxx.o | 6 | snd-ice17xx-ak4xxx-objs := ak4xxx.o | |
7 | snd-ice1712-objs := ice1712.o delta.o hoontech.o ews.o | 7 | snd-ice1712-objs := ice1712.o delta.o hoontech.o ews.o | |
8 | snd-ice1724-objs := ice1724.o amp.o revo.o aureon.o vt1720_mobo.o pontis.o prodigy192.o juli.o phase.o wtm.o se.o | 8 | snd-ice1724-objs := ice1724.o amp.o revo.o aureon.o vt1720_mobo.o pontis.o prodigy192.o prodigy_hifi.o juli.o phase.o wtm.o se.o | |
9 | 9 | |||
10 | # Toplevel Module Dependency | 10 | # Toplevel Module Dependency | |
11 | obj-$(CONFIG_SND_ICE1712) += snd-ice1712.o snd-ice17xx-ak4xxx.o | 11 | obj-$(CONFIG_SND_ICE1712) += snd-ice1712.o snd-ice17xx-ak4xxx.o | |
diff --git a/sound/pci/ice1712/ice1712.h b/sound/pci/ice1712/ice1712.h index 4dc576af506f..86e418e0b3ef 100644 --- a/sound/pci/ice1712/ice1712.h +++ b/sound/pci/ice1712/ice1712.h | ||||
@@ -407,7 +407,13 @@ struct snd_ice1712 { | ||||
407 | unsigned char ch1, ch2; | 407 | unsigned char ch1, ch2; | |
408 | } vol[8]; | 408 | } vol[8]; | |
409 | } se; | 409 | } se; | |
410 | 410 | struct prodigy_hifi_spec { | ||
411 | unsigned short master[2]; | |||
412 | unsigned short vol[8]; | |||
413 | } prodigy_hifi; | |||
414 | struct prodigy_hd2_spec { | |||
415 | unsigned short vol[2]; | |||
416 | } prodigy_hd2; | |||
411 | } spec; | 417 | } spec; | |
412 | 418 | |||
413 | }; | 419 | }; | |
diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c index 3147cbc9edb3..c89a4fe72a49 100644 --- a/sound/pci/ice1712/ice1724.c +++ b/sound/pci/ice1712/ice1724.c | ||||
@@ -47,6 +47,7 @@ | ||||
47 | #include "vt1720_mobo.h" | 47 | #include "vt1720_mobo.h" | |
48 | #include "pontis.h" | 48 | #include "pontis.h" | |
49 | #include "prodigy192.h" | 49 | #include "prodigy192.h" | |
50 | #include "prodigy_hifi.h" | |||
50 | #include "juli.h" | 51 | #include "juli.h" | |
51 | #include "phase.h" | 52 | #include "phase.h" | |
52 | #include "wtm.h" | 53 | #include "wtm.h" | |
@@ -62,6 +63,7 @@ MODULE_SUPPORTED_DEVICE("{" | ||||
62 | VT1720_MOBO_DEVICE_DESC | 63 | VT1720_MOBO_DEVICE_DESC | |
63 | PONTIS_DEVICE_DESC | 64 | PONTIS_DEVICE_DESC | |
64 | PRODIGY192_DEVICE_DESC | 65 | PRODIGY192_DEVICE_DESC | |
66 | PRODIGY_HIFI_DEVICE_DESC | |||
65 | JULI_DEVICE_DESC | 67 | JULI_DEVICE_DESC | |
66 | PHASE_DEVICE_DESC | 68 | PHASE_DEVICE_DESC | |
67 | WTM_DEVICE_DESC | 69 | WTM_DEVICE_DESC | |
@@ -1930,6 +1932,7 @@ static struct snd_ice1712_card_info *card_tables[] __devinitdata = { | ||||
1930 | snd_vt1724_aureon_cards, | 1932 | snd_vt1724_aureon_cards, | |
1931 | snd_vt1720_mobo_cards, | 1933 | snd_vt1720_mobo_cards, | |
1932 | snd_vt1720_pontis_cards, | 1934 | snd_vt1720_pontis_cards, | |
1935 | snd_vt1724_prodigy_hifi_cards, | |||
1933 | snd_vt1724_prodigy192_cards, | 1936 | snd_vt1724_prodigy192_cards, | |
1934 | snd_vt1724_juli_cards, | 1937 | snd_vt1724_juli_cards, | |
1935 | snd_vt1724_phase_cards, | 1938 | snd_vt1724_phase_cards, | |
diff --git a/sound/pci/ice1712/prodigy_hifi.c b/sound/pci/ice1712/prodigy_hifi.c new file mode 100644 index 000000000000..6ec1aa44c184 --- /dev/null +++ b/sound/pci/ice1712/prodigy_hifi.c | ||||
@@ -0,0 +1,1195 @@ | ||||
1 | /* | |||
2 | * ALSA driver for ICEnsemble VT1724 (Envy24HT) | |||
3 | * | |||
4 | * Lowlevel functions for Audiotrak Prodigy 7.1 Hifi | |||
5 | * based on pontis.c | |||
6 | * | |||
7 | * Copyright (c) 2007 Julian Scheel <julian@jusst.de> | |||
8 | * Copyright (c) 2007 allank | |||
9 | * Copyright (c) 2004 Takashi Iwai <tiwai@suse.de> | |||
10 | * | |||
11 | * This program is free software; you can redistribute it and/or modify | |||
12 | * it under the terms of the GNU General Public License as published by | |||
13 | * the Free Software Foundation; either version 2 of the License, or | |||
14 | * (at your option) any later version. | |||
15 | * | |||
16 | * This program is distributed in the hope that it will be useful, | |||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
19 | * GNU General Public License for more details. | |||
20 | * | |||
21 | * You should have received a copy of the GNU General Public License | |||
22 | * along with this program; if not, write to the Free Software | |||
23 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |||
24 | * | |||
25 | */ | |||
26 | ||||
27 | ||||
28 | #include <asm/io.h> | |||
29 | #include <linux/delay.h> | |||
30 | #include <linux/interrupt.h> | |||
31 | #include <linux/init.h> | |||
32 | #include <linux/slab.h> | |||
33 | #include <linux/mutex.h> | |||
34 | ||||
35 | #include <sound/core.h> | |||
36 | #include <sound/info.h> | |||
37 | #include <sound/tlv.h> | |||
38 | ||||
39 | #include "ice1712.h" | |||
40 | #include "envy24ht.h" | |||
41 | #include "prodigy_hifi.h" | |||
42 | ||||
43 | /* I2C addresses */ | |||
44 | #define WM_DEV 0x34 | |||
45 | ||||
46 | /* WM8776 registers */ | |||
47 | #define WM_HP_ATTEN_L 0x00 /* headphone left attenuation */ | |||
48 | #define WM_HP_ATTEN_R 0x01 /* headphone left attenuation */ | |||
49 | #define WM_HP_MASTER 0x02 /* headphone master (both channels), | |||
50 | override LLR */ | |||
51 | #define WM_DAC_ATTEN_L 0x03 /* digital left attenuation */ | |||
52 | #define WM_DAC_ATTEN_R 0x04 | |||
53 | #define WM_DAC_MASTER 0x05 | |||
54 | #define WM_PHASE_SWAP 0x06 /* DAC phase swap */ | |||
55 | #define WM_DAC_CTRL1 0x07 | |||
56 | #define WM_DAC_MUTE 0x08 | |||
57 | #define WM_DAC_CTRL2 0x09 | |||
58 | #define WM_DAC_INT 0x0a | |||
59 | #define WM_ADC_INT 0x0b | |||
60 | #define WM_MASTER_CTRL 0x0c | |||
61 | #define WM_POWERDOWN 0x0d | |||
62 | #define WM_ADC_ATTEN_L 0x0e | |||
63 | #define WM_ADC_ATTEN_R 0x0f | |||
64 | #define WM_ALC_CTRL1 0x10 | |||
65 | #define WM_ALC_CTRL2 0x11 | |||
66 | #define WM_ALC_CTRL3 0x12 | |||
67 | #define WM_NOISE_GATE 0x13 | |||
68 | #define WM_LIMITER 0x14 | |||
69 | #define WM_ADC_MUX 0x15 | |||
70 | #define WM_OUT_MUX 0x16 | |||
71 | #define WM_RESET 0x17 | |||
72 | ||||
73 | /* Analog Recording Source :- Mic, LineIn, CD/Video, */ | |||
74 | ||||
75 | /* implement capture source select control for WM8776 */ | |||
76 | ||||
77 | #define WM_AIN1 "AIN1" | |||
78 | #define WM_AIN2 "AIN2" | |||
79 | #define WM_AIN3 "AIN3" | |||
80 | #define WM_AIN4 "AIN4" | |||
81 | #define WM_AIN5 "AIN5" | |||
82 | ||||
83 | /* GPIO pins of envy24ht connected to wm8766 */ | |||
84 | #define WM8766_SPI_CLK (1<<17) /* CLK, Pin97 on ICE1724 */ | |||
85 | #define WM8766_SPI_MD (1<<16) /* DATA VT1724 -> WM8766, Pin96 */ | |||
86 | #define WM8766_SPI_ML (1<<18) /* Latch, Pin98 */ | |||
87 | ||||
88 | /* WM8766 registers */ | |||
89 | #define WM8766_DAC_CTRL 0x02 /* DAC Control */ | |||
90 | #define WM8766_INT_CTRL 0x03 /* Interface Control */ | |||
91 | #define WM8766_DAC_CTRL2 0x09 | |||
92 | #define WM8766_DAC_CTRL3 0x0a | |||
93 | #define WM8766_RESET 0x1f | |||
94 | #define WM8766_LDA1 0x00 | |||
95 | #define WM8766_LDA2 0x04 | |||
96 | #define WM8766_LDA3 0x06 | |||
97 | #define WM8766_RDA1 0x01 | |||
98 | #define WM8766_RDA2 0x05 | |||
99 | #define WM8766_RDA3 0x07 | |||
100 | #define WM8766_MUTE1 0x0C | |||
101 | #define WM8766_MUTE2 0x0F | |||
102 | ||||
103 | ||||
104 | /* | |||
105 | * Prodigy HD2 | |||
106 | */ | |||
107 | #define AK4396_ADDR 0x00 | |||
108 | #define AK4396_CSN (1 << 8) /* CSN->GPIO8, pin 75 */ | |||
109 | #define AK4396_CCLK (1 << 9) /* CCLK->GPIO9, pin 76 */ | |||
110 | #define AK4396_CDTI (1 << 10) /* CDTI->GPIO10, pin 77 */ | |||
111 | ||||
112 | /* ak4396 registers */ | |||
113 | #define AK4396_CTRL1 0x00 | |||
114 | #define AK4396_CTRL2 0x01 | |||
115 | #define AK4396_CTRL3 0x02 | |||
116 | #define AK4396_LCH_ATT 0x03 | |||
117 | #define AK4396_RCH_ATT 0x04 | |||
118 | ||||
119 | ||||
120 | /* | |||
121 | * get the current register value of WM codec | |||
122 | */ | |||
123 | static unsigned short wm_get(struct snd_ice1712 *ice, int reg) | |||
124 | { | |||
125 | reg <<= 1; | |||
126 | return ((unsigned short)ice->akm[0].images[reg] << 8) | | |||
127 | ice->akm[0].images[reg + 1]; | |||
128 | } | |||
129 | ||||
130 | /* | |||
131 | * set the register value of WM codec and remember it | |||
132 | */ | |||
133 | static void wm_put_nocache(struct snd_ice1712 *ice, int reg, unsigned short val) | |||
134 | { | |||
135 | unsigned short cval; | |||
136 | cval = (reg << 9) | val; | |||
137 | snd_vt1724_write_i2c(ice, WM_DEV, cval >> 8, cval & 0xff); | |||
138 | } | |||
139 | ||||
140 | static void wm_put(struct snd_ice1712 *ice, int reg, unsigned short val) | |||
141 | { | |||
142 | wm_put_nocache(ice, reg, val); | |||
143 | reg <<= 1; | |||
144 | ice->akm[0].images[reg] = val >> 8; | |||
145 | ice->akm[0].images[reg + 1] = val; | |||
146 | } | |||
147 | ||||
148 | /* | |||
149 | * write data in the SPI mode | |||
150 | */ | |||
151 | ||||
152 | static void set_gpio_bit(struct snd_ice1712 *ice, unsigned int bit, int val) | |||
153 | { | |||
154 | unsigned int tmp = snd_ice1712_gpio_read(ice); | |||
155 | if (val) | |||
156 | tmp |= bit; | |||
157 | else | |||
158 | tmp &= ~bit; | |||
159 | snd_ice1712_gpio_write(ice, tmp); | |||
160 | } | |||
161 | ||||
162 | /* | |||
163 | * SPI implementation for WM8766 codec - only writing supported, no readback | |||
164 | */ | |||
165 | ||||
166 | static void wm8766_spi_send_word(struct snd_ice1712 *ice, unsigned int data) | |||
167 | { | |||
168 | int i; | |||
169 | for (i = 0; i < 16; i++) { | |||
170 | set_gpio_bit(ice, WM8766_SPI_CLK, 0); | |||
171 | udelay(1); | |||
172 | set_gpio_bit(ice, WM8766_SPI_MD, data & 0x8000); | |||
173 | udelay(1); | |||
174 | set_gpio_bit(ice, WM8766_SPI_CLK, 1); | |||
175 | udelay(1); | |||
176 | data <<= 1; | |||
177 | } | |||
178 | } | |||
179 | ||||
180 | static void wm8766_spi_write(struct snd_ice1712 *ice, unsigned int reg, unsigned int data) | |||
181 | { | |||
182 | unsigned int block; | |||
183 | ||||
184 | snd_ice1712_gpio_set_dir(ice, WM8766_SPI_MD| | |||
185 | WM8766_SPI_CLK|WM8766_SPI_ML); | |||
186 | snd_ice1712_gpio_set_mask(ice, ~(WM8766_SPI_MD| | |||
187 | WM8766_SPI_CLK|WM8766_SPI_ML)); | |||
188 | /* latch must be low when writing */ | |||
189 | set_gpio_bit(ice, WM8766_SPI_ML, 0); | |||
190 | block = (reg << 9) | (data & 0x1ff); | |||
191 | wm8766_spi_send_word(ice, block); /* REGISTER ADDRESS */ | |||
192 | /* release latch */ | |||
193 | set_gpio_bit(ice, WM8766_SPI_ML, 1); | |||
194 | udelay(1); | |||
195 | /* restore */ | |||
196 | snd_ice1712_gpio_set_mask(ice, ice->gpio.write_mask); | |||
197 | snd_ice1712_gpio_set_dir(ice, ice->gpio.direction); | |||
198 | } | |||
199 | ||||
200 | ||||
201 | /* | |||
202 | * serial interface for ak4396 - only writing supported, no readback | |||
203 | */ | |||
204 | ||||
205 | static void ak4396_send_word(struct snd_ice1712 *ice, unsigned int data) | |||
206 | { | |||
207 | int i; | |||
208 | for (i = 0; i < 16; i++) { | |||
209 | set_gpio_bit(ice, AK4396_CCLK, 0); | |||
210 | udelay(1); | |||
211 | set_gpio_bit(ice, AK4396_CDTI, data & 0x8000); | |||
212 | udelay(1); | |||
213 | set_gpio_bit(ice, AK4396_CCLK, 1); | |||
214 | udelay(1); | |||
215 | data <<= 1; | |||
216 | } | |||
217 | } | |||
218 | ||||
219 | static void ak4396_write(struct snd_ice1712 *ice, unsigned int reg, unsigned int data) | |||
220 | { | |||
221 | unsigned int block; | |||
222 | ||||
223 | snd_ice1712_gpio_set_dir(ice, AK4396_CSN|AK4396_CCLK|AK4396_CDTI); | |||
224 | snd_ice1712_gpio_set_mask(ice, ~(AK4396_CSN|AK4396_CCLK|AK4396_CDTI)); | |||
225 | /* latch must be low when writing */ | |||
226 | set_gpio_bit(ice, AK4396_CSN, 0); | |||
227 | block = ((AK4396_ADDR & 0x03) << 14) | (1 << 13) | | |||
228 | ((reg & 0x1f) << 8) | (data & 0xff); | |||
229 | ak4396_send_word(ice, block); /* REGISTER ADDRESS */ | |||
230 | /* release latch */ | |||
231 | set_gpio_bit(ice, AK4396_CSN, 1); | |||
232 | udelay(1); | |||
233 | /* restore */ | |||
234 | snd_ice1712_gpio_set_mask(ice, ice->gpio.write_mask); | |||
235 | snd_ice1712_gpio_set_dir(ice, ice->gpio.direction); | |||
236 | } | |||
237 | ||||
238 | ||||
239 | /* | |||
240 | * ak4396 mixers | |||
241 | */ | |||
242 | ||||
243 | ||||
244 | ||||
245 | /* | |||
246 | * DAC volume attenuation mixer control (-64dB to 0dB) | |||
247 | */ | |||
248 | ||||
249 | static int ak4396_dac_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) | |||
250 | { | |||
251 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | |||
252 | uinfo->count = 2; | |||
253 | uinfo->value.integer.min = 0; /* mute */ | |||
254 | uinfo->value.integer.max = 0xFF; /* linear */ | |||
255 | return 0; | |||
256 | } | |||
257 | ||||
258 | static int ak4396_dac_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | |||
259 | { | |||
260 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | |||
261 | int i; | |||
262 | ||||
263 | for (i = 0; i < 2; i++) { | |||
264 | ucontrol->value.integer.value[i] =ice->spec.prodigy_hd2.vol[i]; | |||
265 | } | |||
266 | return 0; | |||
267 | } | |||
268 | ||||
269 | static int ak4396_dac_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | |||
270 | { | |||
271 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | |||
272 | int i; | |||
273 | int change = 0; | |||
274 | ||||
275 | mutex_lock(&ice->gpio_mutex); | |||
276 | for (i = 0; i < 2; i++) { | |||
277 | if (ucontrol->value.integer.value[i] != | |||
278 | ice->spec.prodigy_hd2.vol[i]) { | |||
279 | ice->spec.prodigy_hd2.vol[i] = | |||
280 | ucontrol->value.integer.value[i]; | |||
281 | ak4396_write(ice, AK4396_LCH_ATT+i, | |||
282 | (ice->spec.prodigy_hd2.vol[i] & 0xff)); | |||
283 | change = 1; | |||
284 | } | |||
285 | } | |||
286 | mutex_unlock(&ice->gpio_mutex); | |||
287 | return change; | |||
288 | } | |||
289 | ||||
290 | static const DECLARE_TLV_DB_SCALE(db_scale_wm_dac, -12700, 100, 1); | |||
291 | ||||
292 | static struct snd_kcontrol_new prodigy_hd2_controls[] __devinitdata = { | |||
293 | { | |||
294 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | |||
295 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | |||
296 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | |||
297 | .name = "Front Playback Volume", | |||
298 | .info = ak4396_dac_vol_info, | |||
299 | .get = ak4396_dac_vol_get, | |||
300 | .put = ak4396_dac_vol_put, | |||
301 | .tlv = { .p = db_scale_wm_dac }, | |||
302 | }, | |||
303 | }; | |||
304 | ||||
305 | ||||
306 | /* --------------- */ | |||
307 | ||||
308 | /* | |||
309 | * Logarithmic volume values for WM87*6 | |||
310 | * Computed as 20 * Log10(255 / x) | |||
311 | */ | |||
312 | static const unsigned char wm_vol[256] = { | |||
313 | 127, 48, 42, 39, 36, 34, 33, 31, 30, 29, 28, 27, 27, 26, 25, 25, 24, 24, 23, | |||
314 | 23, 22, 22, 21, 21, 21, 20, 20, 20, 19, 19, 19, 18, 18, 18, 18, 17, 17, 17, | |||
315 | 17, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 13, 13, 13, | |||
316 | 13, 13, 13, 13, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11, | |||
317 | 11, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 8, | |||
318 | 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, | |||
319 | 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, | |||
320 | 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, | |||
321 | 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, | |||
322 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | |||
323 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |||
324 | 0, 0 | |||
325 | }; | |||
326 | ||||
327 | #define WM_VOL_MAX (sizeof(wm_vol) - 1) | |||
328 | #define WM_VOL_MUTE 0x8000 | |||
329 | ||||
330 | ||||
331 | #define DAC_0dB 0xff | |||
332 | #define DAC_RES 128 | |||
333 | #define DAC_MIN (DAC_0dB - DAC_RES) | |||
334 | ||||
335 | ||||
336 | static void wm_set_vol(struct snd_ice1712 *ice, unsigned int index, unsigned short vol, unsigned short master) | |||
337 | { | |||
338 | unsigned char nvol; | |||
339 | ||||
340 | if ((master & WM_VOL_MUTE) || (vol & WM_VOL_MUTE)) | |||
341 | nvol = 0; | |||
342 | else { | |||
343 | nvol = (((vol & ~WM_VOL_MUTE) * (master & ~WM_VOL_MUTE)) / 128) | |||
344 | & WM_VOL_MAX; | |||
345 | nvol = (nvol ? (nvol + DAC_MIN) : 0) & 0xff; | |||
346 | } | |||
347 | ||||
348 | wm_put(ice, index, nvol); | |||
349 | wm_put_nocache(ice, index, 0x100 | nvol); | |||
350 | } | |||
351 | ||||
352 | static void wm8766_set_vol(struct snd_ice1712 *ice, unsigned int index, unsigned short vol, unsigned short master) | |||
353 | { | |||
354 | unsigned char nvol; | |||
355 | ||||
356 | if ((master & WM_VOL_MUTE) || (vol & WM_VOL_MUTE)) | |||
357 | nvol = 0; | |||
358 | else { | |||
359 | nvol = (((vol & ~WM_VOL_MUTE) * (master & ~WM_VOL_MUTE)) / 128) | |||
360 | & WM_VOL_MAX; | |||
361 | nvol = (nvol ? (nvol + DAC_MIN) : 0) & 0xff; | |||
362 | } | |||
363 | ||||
364 | ||||
365 | wm8766_spi_write(ice, index, (0x0100 | nvol)); | |||
366 | } | |||
367 | ||||
368 | ||||
369 | /* | |||
370 | * DAC volume attenuation mixer control (-64dB to 0dB) | |||
371 | */ | |||
372 | ||||
373 | static int wm_dac_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) | |||
374 | { | |||
375 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | |||
376 | uinfo->count = 2; | |||
377 | uinfo->value.integer.min = 0; /* mute */ | |||
378 | uinfo->value.integer.max = DAC_RES; /* 0dB, 0.5dB step */ | |||
379 | return 0; | |||
380 | } | |||
381 | ||||
382 | static int wm_dac_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | |||
383 | { | |||
384 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | |||
385 | int i; | |||
386 | ||||
387 | for (i = 0; i < 2; i++) { | |||
388 | ucontrol->value.integer.value[i] = | |||
389 | ice->spec.prodigy_hifi.vol[2+i] & ~WM_VOL_MUTE; | |||
390 | } | |||
391 | return 0; | |||
392 | } | |||
393 | ||||
394 | static int wm_dac_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | |||
395 | { | |||
396 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | |||
397 | int i, idx, change = 0; | |||
398 | ||||
399 | mutex_lock(&ice->gpio_mutex); | |||
400 | for (i = 0; i < 2; i++) { | |||
401 | if (ucontrol->value.integer.value[i] != | |||
402 | ice->spec.prodigy_hifi.vol[2+i]) { | |||
403 | idx = WM_DAC_ATTEN_L + i; | |||
404 | ice->spec.prodigy_hifi.vol[2+i] &= WM_VOL_MUTE; | |||
405 | ice->spec.prodigy_hifi.vol[2+i] |= | |||
406 | ucontrol->value.integer.value[i]; | |||
407 | wm_set_vol(ice, idx, ice->spec.prodigy_hifi.vol[2+i], | |||
408 | ice->spec.prodigy_hifi.master[i]); | |||
409 | change = 1; | |||
410 | } | |||
411 | } | |||
412 | mutex_unlock(&ice->gpio_mutex); | |||
413 | return change; | |||
414 | } | |||
415 | ||||
416 | ||||
417 | /* | |||
418 | * WM8766 DAC volume attenuation mixer control | |||
419 | */ | |||
420 | static int wm8766_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) | |||
421 | { | |||
422 | int voices = kcontrol->private_value >> 8; | |||
423 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | |||
424 | uinfo->count = voices; | |||
425 | uinfo->value.integer.min = 0; /* mute */ | |||
426 | uinfo->value.integer.max = DAC_RES; /* 0dB */ | |||
427 | return 0; | |||
428 | } | |||
429 | ||||
430 | static int wm8766_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | |||
431 | { | |||
432 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | |||
433 | int i, ofs, voices; | |||
434 | ||||
435 | voices = kcontrol->private_value >> 8; | |||
436 | ofs = kcontrol->private_value & 0xff; | |||
437 | for (i = 0; i < voices; i++) | |||
438 | ucontrol->value.integer.value[i] = | |||
439 | ice->spec.prodigy_hifi.vol[ofs+i]; | |||
440 | return 0; | |||
441 | } | |||
442 | ||||
443 | static int wm8766_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | |||
444 | { | |||
445 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | |||
446 | int i, idx, ofs, voices; | |||
447 | int change = 0; | |||
448 | ||||
449 | voices = kcontrol->private_value >> 8; | |||
450 | ofs = kcontrol->private_value & 0xff; | |||
451 | mutex_lock(&ice->gpio_mutex); | |||
452 | for (i = 0; i < voices; i++) { | |||
453 | if (ucontrol->value.integer.value[i] != | |||
454 | ice->spec.prodigy_hifi.vol[ofs+i]) { | |||
455 | idx = WM8766_LDA1 + ofs + i; | |||
456 | ice->spec.prodigy_hifi.vol[ofs+i] &= WM_VOL_MUTE; | |||
457 | ice->spec.prodigy_hifi.vol[ofs+i] |= | |||
458 | ucontrol->value.integer.value[i]; | |||
459 | wm8766_set_vol(ice, idx, | |||
460 | ice->spec.prodigy_hifi.vol[ofs+i], | |||
461 | ice->spec.prodigy_hifi.master[i]); | |||
462 | change = 1; | |||
463 | } | |||
464 | } | |||
465 | mutex_unlock(&ice->gpio_mutex); | |||
466 | return change; | |||
467 | } | |||
468 | ||||
469 | /* | |||
470 | * Master volume attenuation mixer control / applied to WM8776+WM8766 | |||
471 | */ | |||
472 | static int wm_master_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) | |||
473 | { | |||
474 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | |||
475 | uinfo->count = 2; | |||
476 | uinfo->value.integer.min = 0; | |||
477 | uinfo->value.integer.max = DAC_RES; | |||
478 | return 0; | |||
479 | } | |||
480 | ||||
481 | static int wm_master_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | |||
482 | { | |||
483 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | |||
484 | int i; | |||
485 | for (i=0; i<2; i++) | |||
486 | ucontrol->value.integer.value[i] = | |||
487 | ice->spec.prodigy_hifi.master[i]; | |||
488 | return 0; | |||
489 | } | |||
490 | ||||
491 | static int wm_master_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | |||
492 | { | |||
493 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | |||
494 | int ch, change = 0; | |||
495 | ||||
496 | mutex_lock(&ice->gpio_mutex); | |||
497 | for (ch = 0; ch < 2; ch++) { | |||
498 | if (ucontrol->value.integer.value[ch] != | |||
499 | ice->spec.prodigy_hifi.master[ch]) { | |||
500 | ice->spec.prodigy_hifi.master[ch] &= 0x00; | |||
501 | ice->spec.prodigy_hifi.master[ch] |= | |||
502 | ucontrol->value.integer.value[ch]; | |||
503 | ||||
504 | /* Apply to front DAC */ | |||
505 | wm_set_vol(ice, WM_DAC_ATTEN_L + ch, | |||
506 | ice->spec.prodigy_hifi.vol[2 + ch], | |||
507 | ice->spec.prodigy_hifi.master[ch]); | |||
508 | ||||
509 | wm8766_set_vol(ice, WM8766_LDA1 + ch, | |||
510 | ice->spec.prodigy_hifi.vol[0 + ch], | |||
511 | ice->spec.prodigy_hifi.master[ch]); | |||
512 | ||||
513 | wm8766_set_vol(ice, WM8766_LDA2 + ch, | |||
514 | ice->spec.prodigy_hifi.vol[4 + ch], | |||
515 | ice->spec.prodigy_hifi.master[ch]); | |||
516 | ||||
517 | wm8766_set_vol(ice, WM8766_LDA3 + ch, | |||
518 | ice->spec.prodigy_hifi.vol[6 + ch], | |||
519 | ice->spec.prodigy_hifi.master[ch]); | |||
520 | change = 1; | |||
521 | } | |||
522 | } | |||
523 | mutex_unlock(&ice->gpio_mutex); | |||
524 | return change; | |||
525 | } | |||
526 | ||||
527 | ||||
528 | ||||
529 | /* KONSTI */ | |||
530 | ||||
531 | static int wm_adc_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) | |||
532 | { | |||
533 | static char* texts[32] = {"NULL", WM_AIN1, WM_AIN2, WM_AIN1 "+" WM_AIN2, | |||
534 | WM_AIN3, WM_AIN1 "+" WM_AIN3, WM_AIN2 "+" WM_AIN3, | |||
535 | WM_AIN1 "+" WM_AIN2 "+" WM_AIN3, | |||
536 | WM_AIN4, WM_AIN1 "+" WM_AIN4, WM_AIN2 "+" WM_AIN4, | |||
537 | WM_AIN1 "+" WM_AIN2 "+" WM_AIN4, | |||
538 | WM_AIN3 "+" WM_AIN4, WM_AIN1 "+" WM_AIN3 "+" WM_AIN4, | |||
539 | WM_AIN2 "+" WM_AIN3 "+" WM_AIN4, | |||
540 | WM_AIN1 "+" WM_AIN2 "+" WM_AIN3 "+" WM_AIN4, | |||
541 | WM_AIN5, WM_AIN1 "+" WM_AIN5, WM_AIN2 "+" WM_AIN5, | |||
542 | WM_AIN1 "+" WM_AIN2 "+" WM_AIN5, | |||
543 | WM_AIN3 "+" WM_AIN5, WM_AIN1 "+" WM_AIN3 "+" WM_AIN5, | |||
544 | WM_AIN2 "+" WM_AIN3 "+" WM_AIN5, | |||
545 | WM_AIN1 "+" WM_AIN2 "+" WM_AIN3 "+" WM_AIN5, | |||
546 | WM_AIN4 "+" WM_AIN5, WM_AIN1 "+" WM_AIN4 "+" WM_AIN5, | |||
547 | WM_AIN2 "+" WM_AIN4 "+" WM_AIN5, | |||
548 | WM_AIN1 "+" WM_AIN2 "+" WM_AIN4 "+" WM_AIN5, | |||
549 | WM_AIN3 "+" WM_AIN4 "+" WM_AIN5, | |||
550 | WM_AIN1 "+" WM_AIN3 "+" WM_AIN4 "+" WM_AIN5, | |||
551 | WM_AIN2 "+" WM_AIN3 "+" WM_AIN4 "+" WM_AIN5, | |||
552 | WM_AIN1 "+" WM_AIN2 "+" WM_AIN3 "+" WM_AIN4 "+" WM_AIN5}; | |||
553 | ||||
554 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | |||
555 | uinfo->count = 1; | |||
556 | uinfo->value.enumerated.items = 32; | |||
557 | if (uinfo->value.enumerated.item > 31) | |||
558 | uinfo->value.enumerated.item = 31; | |||
559 | strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); | |||
560 | return 0; | |||
561 | } | |||
562 | ||||
563 | static int wm_adc_mux_enum_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | |||
564 | { | |||
565 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | |||
566 | ||||
567 | mutex_lock(&ice->gpio_mutex); | |||
568 | ucontrol->value.integer.value[0]=wm_get(ice, WM_ADC_MUX) & 0x1f; | |||
569 | mutex_unlock(&ice->gpio_mutex); | |||
570 | return 0; | |||
571 | } | |||
572 | ||||
573 | static int wm_adc_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | |||
574 | { | |||
575 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | |||
576 | unsigned short oval, nval; | |||
577 | ||||
578 | mutex_lock(&ice->gpio_mutex); | |||
579 | oval = wm_get(ice, WM_ADC_MUX); | |||
580 | nval = ( oval & 0xe0 ) | ucontrol->value.integer.value[0] ; | |||
581 | if ( nval != oval ) { | |||
582 | wm_put(ice, WM_ADC_MUX, nval); | |||
583 | } | |||
584 | mutex_unlock(&ice->gpio_mutex); | |||
585 | return 0; | |||
586 | } | |||
587 | ||||
588 | /* KONSTI */ | |||
589 | ||||
590 | /* | |||
591 | * ADC gain mixer control (-64dB to 0dB) | |||
592 | */ | |||
593 | ||||
594 | #define ADC_0dB 0xcf | |||
595 | #define ADC_RES 128 | |||
596 | #define ADC_MIN (ADC_0dB - ADC_RES) | |||
597 | ||||
598 | static int wm_adc_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) | |||
599 | { | |||
600 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | |||
601 | uinfo->count = 2; | |||
602 | uinfo->value.integer.min = 0; /* mute (-64dB) */ | |||
603 | uinfo->value.integer.max = ADC_RES; /* 0dB, 0.5dB step */ | |||
604 | return 0; | |||
605 | } | |||
606 | ||||
607 | static int wm_adc_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | |||
608 | { | |||
609 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | |||
610 | unsigned short val; | |||
611 | int i; | |||
612 | ||||
613 | mutex_lock(&ice->gpio_mutex); | |||
614 | for (i = 0; i < 2; i++) { | |||
615 | val = wm_get(ice, WM_ADC_ATTEN_L + i) & 0xff; | |||
616 | val = val > ADC_MIN ? (val - ADC_MIN) : 0; | |||
617 | ucontrol->value.integer.value[i] = val; | |||
618 | } | |||
619 | mutex_unlock(&ice->gpio_mutex); | |||
620 | return 0; | |||
621 | } | |||
622 | ||||
623 | static int wm_adc_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | |||
624 | { | |||
625 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | |||
626 | unsigned short ovol, nvol; | |||
627 | int i, idx, change = 0; | |||
628 | ||||
629 | mutex_lock(&ice->gpio_mutex); | |||
630 | for (i = 0; i < 2; i++) { | |||
631 | nvol = ucontrol->value.integer.value[i]; | |||
632 | nvol = nvol ? (nvol + ADC_MIN) : 0; | |||
633 | idx = WM_ADC_ATTEN_L + i; | |||
634 | ovol = wm_get(ice, idx) & 0xff; | |||
635 | if (ovol != nvol) { | |||
636 | wm_put(ice, idx, nvol); | |||
637 | change = 1; | |||
638 | } | |||
639 | } | |||
640 | mutex_unlock(&ice->gpio_mutex); | |||
641 | return change; | |||
642 | } | |||
643 | ||||
644 | /* | |||
645 | * ADC input mux mixer control | |||
646 | */ | |||
647 | static int wm_adc_mux_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) | |||
648 | { | |||
649 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | |||
650 | uinfo->count = 1; | |||
651 | uinfo->value.integer.min = 0; | |||
652 | uinfo->value.integer.max = 1; | |||
653 | return 0; | |||
654 | } | |||
655 | ||||
656 | static int wm_adc_mux_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | |||
657 | { | |||
658 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | |||
659 | int bit = kcontrol->private_value; | |||
660 | ||||
661 | mutex_lock(&ice->gpio_mutex); | |||
662 | ucontrol->value.integer.value[0] = (wm_get(ice, WM_ADC_MUX) & (1 << bit)) ? 1 : 0; | |||
663 | mutex_unlock(&ice->gpio_mutex); | |||
664 | return 0; | |||
665 | } | |||
666 | ||||
667 | static int wm_adc_mux_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | |||
668 | { | |||
669 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | |||
670 | int bit = kcontrol->private_value; | |||
671 | unsigned short oval, nval; | |||
672 | int change; | |||
673 | ||||
674 | mutex_lock(&ice->gpio_mutex); | |||
675 | nval = oval = wm_get(ice, WM_ADC_MUX); | |||
676 | if (ucontrol->value.integer.value[0]) | |||
677 | nval |= (1 << bit); | |||
678 | else | |||
679 | nval &= ~(1 << bit); | |||
680 | change = nval != oval; | |||
681 | if (change) { | |||
682 | wm_put(ice, WM_ADC_MUX, nval); | |||
683 | } | |||
684 | mutex_unlock(&ice->gpio_mutex); | |||
685 | return 0; | |||
686 | } | |||
687 | ||||
688 | /* | |||
689 | * Analog bypass (In -> Out) | |||
690 | */ | |||
691 | static int wm_bypass_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) | |||
692 | { | |||
693 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | |||
694 | uinfo->count = 1; | |||
695 | uinfo->value.integer.min = 0; | |||
696 | uinfo->value.integer.max = 1; | |||
697 | return 0; | |||
698 | } | |||
699 | ||||
700 | static int wm_bypass_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | |||
701 | { | |||
702 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | |||
703 | ||||
704 | mutex_lock(&ice->gpio_mutex); | |||
705 | ucontrol->value.integer.value[0] = (wm_get(ice, WM_OUT_MUX) & 0x04) ? 1 : 0; | |||
706 | mutex_unlock(&ice->gpio_mutex); | |||
707 | return 0; | |||
708 | } | |||
709 | ||||
710 | static int wm_bypass_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | |||
711 | { | |||
712 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | |||
713 | unsigned short val, oval; | |||
714 | int change = 0; | |||
715 | ||||
716 | mutex_lock(&ice->gpio_mutex); | |||
717 | val = oval = wm_get(ice, WM_OUT_MUX); | |||
718 | if (ucontrol->value.integer.value[0]) | |||
719 | val |= 0x04; | |||
720 | else | |||
721 | val &= ~0x04; | |||
722 | if (val != oval) { | |||
723 | wm_put(ice, WM_OUT_MUX, val); | |||
724 | change = 1; | |||
725 | } | |||
726 | mutex_unlock(&ice->gpio_mutex); | |||
727 | return change; | |||
728 | } | |||
729 | ||||
730 | /* | |||
731 | * Left/Right swap | |||
732 | */ | |||
733 | static int wm_chswap_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) | |||
734 | { | |||
735 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | |||
736 | uinfo->count = 1; | |||
737 | uinfo->value.integer.min = 0; | |||
738 | uinfo->value.integer.max = 1; | |||
739 | return 0; | |||
740 | } | |||
741 | ||||
742 | static int wm_chswap_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | |||
743 | { | |||
744 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | |||
745 | ||||
746 | mutex_lock(&ice->gpio_mutex); | |||
747 | ucontrol->value.integer.value[0] = | |||
748 | (wm_get(ice, WM_DAC_CTRL1) & 0xf0) != 0x90; | |||
749 | mutex_unlock(&ice->gpio_mutex); | |||
750 | return 0; | |||
751 | } | |||
752 | ||||
753 | static int wm_chswap_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | |||
754 | { | |||
755 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | |||
756 | unsigned short val, oval; | |||
757 | int change = 0; | |||
758 | ||||
759 | mutex_lock(&ice->gpio_mutex); | |||
760 | oval = wm_get(ice, WM_DAC_CTRL1); | |||
761 | val = oval & 0x0f; | |||
762 | if (ucontrol->value.integer.value[0]) | |||
763 | val |= 0x60; | |||
764 | else | |||
765 | val |= 0x90; | |||
766 | if (val != oval) { | |||
767 | wm_put(ice, WM_DAC_CTRL1, val); | |||
768 | wm_put_nocache(ice, WM_DAC_CTRL1, val); | |||
769 | change = 1; | |||
770 | } | |||
771 | mutex_unlock(&ice->gpio_mutex); | |||
772 | return change; | |||
773 | } | |||
774 | ||||
775 | ||||
776 | /* | |||
777 | * mixers | |||
778 | */ | |||
779 | ||||
780 | static struct snd_kcontrol_new prodigy_hifi_controls[] __devinitdata = { | |||
781 | { | |||
782 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | |||
783 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | |||
784 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | |||
785 | .name = "Master Playback Volume", | |||
786 | .info = wm_master_vol_info, | |||
787 | .get = wm_master_vol_get, | |||
788 | .put = wm_master_vol_put, | |||
789 | .tlv = { .p = db_scale_wm_dac } | |||
790 | }, | |||
791 | { | |||
792 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | |||
793 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | |||
794 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | |||
795 | .name = "Front Playback Volume", | |||
796 | .info = wm_dac_vol_info, | |||
797 | .get = wm_dac_vol_get, | |||
798 | .put = wm_dac_vol_put, | |||
799 | .tlv = { .p = db_scale_wm_dac }, | |||
800 | }, | |||
801 | { | |||
802 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | |||
803 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | |||
804 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | |||
805 | .name = "Rear Playback Volume", | |||
806 | .info = wm8766_vol_info, | |||
807 | .get = wm8766_vol_get, | |||
808 | .put = wm8766_vol_put, | |||
809 | .private_value = (2 << 8) | 0, | |||
810 | .tlv = { .p = db_scale_wm_dac }, | |||
811 | }, | |||
812 | { | |||
813 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | |||
814 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | |||
815 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | |||
816 | .name = "Center Playback Volume", | |||
817 | .info = wm8766_vol_info, | |||
818 | .get = wm8766_vol_get, | |||
819 | .put = wm8766_vol_put, | |||
820 | .private_value = (1 << 8) | 4, | |||
821 | .tlv = { .p = db_scale_wm_dac } | |||
822 | }, | |||
823 | { | |||
824 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | |||
825 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | |||
826 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | |||
827 | .name = "LFE Playback Volume", | |||
828 | .info = wm8766_vol_info, | |||
829 | .get = wm8766_vol_get, | |||
830 | .put = wm8766_vol_put, | |||
831 | .private_value = (1 << 8) | 5, | |||
832 | .tlv = { .p = db_scale_wm_dac } | |||
833 | }, | |||
834 | { | |||
835 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | |||
836 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | |||
837 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | |||
838 | .name = "Side Playback Volume", | |||
839 | .info = wm8766_vol_info, | |||
840 | .get = wm8766_vol_get, | |||
841 | .put = wm8766_vol_put, | |||
842 | .private_value = (2 << 8) | 6, | |||
843 | .tlv = { .p = db_scale_wm_dac }, | |||
844 | }, | |||
845 | { | |||
846 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | |||
847 | .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | | |||
848 | SNDRV_CTL_ELEM_ACCESS_TLV_READ), | |||
849 | .name = "Capture Volume", | |||
850 | .info = wm_adc_vol_info, | |||
851 | .get = wm_adc_vol_get, | |||
852 | .put = wm_adc_vol_put, | |||
853 | .tlv = { .p = db_scale_wm_dac }, | |||
854 | }, | |||
855 | { | |||
856 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | |||
857 | .name = "CD Capture Switch", | |||
858 | .info = wm_adc_mux_info, | |||
859 | .get = wm_adc_mux_get, | |||
860 | .put = wm_adc_mux_put, | |||
861 | .private_value = 0, | |||
862 | }, | |||
863 | { | |||
864 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | |||
865 | .name = "Line Capture Switch", | |||
866 | .info = wm_adc_mux_info, | |||
867 | .get = wm_adc_mux_get, | |||
868 | .put = wm_adc_mux_put, | |||
869 | .private_value = 1, | |||
870 | }, | |||
871 | { | |||
872 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | |||
873 | .name = "Analog Bypass Switch", | |||
874 | .info = wm_bypass_info, | |||
875 | .get = wm_bypass_get, | |||
876 | .put = wm_bypass_put, | |||
877 | }, | |||
878 | { | |||
879 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | |||
880 | .name = "Swap Output Channels", | |||
881 | .info = wm_chswap_info, | |||
882 | .get = wm_chswap_get, | |||
883 | .put = wm_chswap_put, | |||
884 | }, | |||
885 | { | |||
886 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | |||
887 | .name = "Analog Capture Source", | |||
888 | .info = wm_adc_mux_enum_info, | |||
889 | .get = wm_adc_mux_enum_get, | |||
890 | .put = wm_adc_mux_enum_put, | |||
891 | }, | |||
892 | }; | |||
893 | ||||
894 | /* | |||
895 | * WM codec registers | |||
896 | */ | |||
897 | static void wm_proc_regs_write(struct snd_info_entry *entry, struct snd_info_buffer *buffer) | |||
898 | { | |||
899 | struct snd_ice1712 *ice = (struct snd_ice1712 *)entry->private_data; | |||
900 | char line[64]; | |||
901 | unsigned int reg, val; | |||
902 | mutex_lock(&ice->gpio_mutex); | |||
903 | while (!snd_info_get_line(buffer, line, sizeof(line))) { | |||
904 | if (sscanf(line, "%x %x", ®, &val) != 2) | |||
905 | continue; | |||
906 | if (reg <= 0x17 && val <= 0xffff) | |||
907 | wm_put(ice, reg, val); | |||
908 | } | |||
909 | mutex_unlock(&ice->gpio_mutex); | |||
910 | } | |||
911 | ||||
912 | static void wm_proc_regs_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) | |||
913 | { | |||
914 | struct snd_ice1712 *ice = (struct snd_ice1712 *)entry->private_data; | |||
915 | int reg, val; | |||
916 | ||||
917 | mutex_lock(&ice->gpio_mutex); | |||
918 | for (reg = 0; reg <= 0x17; reg++) { | |||
919 | val = wm_get(ice, reg); | |||
920 | snd_iprintf(buffer, "%02x = %04x\n", reg, val); | |||
921 | } | |||
922 | mutex_unlock(&ice->gpio_mutex); | |||
923 | } | |||
924 | ||||
925 | static void wm_proc_init(struct snd_ice1712 *ice) | |||
926 | { | |||
927 | struct snd_info_entry *entry; | |||
928 | if (! snd_card_proc_new(ice->card, "wm_codec", &entry)) { | |||
929 | snd_info_set_text_ops(entry, ice, wm_proc_regs_read); | |||
930 | entry->mode |= S_IWUSR; | |||
931 | entry->c.text.write = wm_proc_regs_write; | |||
932 | } | |||
933 | } | |||
934 | ||||
935 | static int __devinit prodigy_hifi_add_controls(struct snd_ice1712 *ice) | |||
936 | { | |||
937 | unsigned int i; | |||
938 | int err; | |||
939 | ||||
940 | for (i = 0; i < ARRAY_SIZE(prodigy_hifi_controls); i++) { | |||
941 | err = snd_ctl_add(ice->card, snd_ctl_new1(&prodigy_hifi_controls[i], ice)); | |||
942 | if (err < 0) | |||
943 | return err; | |||
944 | } | |||
945 | ||||
946 | wm_proc_init(ice); | |||
947 | ||||
948 | return 0; | |||
949 | } | |||
950 | ||||
951 | static int __devinit prodigy_hd2_add_controls(struct snd_ice1712 *ice) | |||
952 | { | |||
953 | unsigned int i; | |||
954 | int err; | |||
955 | ||||
956 | for (i = 0; i < ARRAY_SIZE(prodigy_hd2_controls); i++) { | |||
957 | err = snd_ctl_add(ice->card, snd_ctl_new1(&prodigy_hd2_controls[i], ice)); | |||
958 | if (err < 0) | |||
959 | return err; | |||
960 | } | |||
961 | ||||
962 | wm_proc_init(ice); | |||
963 | ||||
964 | return 0; | |||
965 | } | |||
966 | ||||
967 | ||||
968 | /* | |||
969 | * initialize the chip | |||
970 | */ | |||
971 | static int __devinit prodigy_hifi_init(struct snd_ice1712 *ice) | |||
972 | { | |||
973 | static unsigned short wm_inits[] = { | |||
974 | /* These come first to reduce init pop noise */ | |||
975 | WM_ADC_MUX, 0x0003, /* ADC mute */ | |||
976 | /* 0x00c0 replaced by 0x0003 */ | |||
977 | ||||
978 | WM_DAC_MUTE, 0x0001, /* DAC softmute */ | |||
979 | WM_DAC_CTRL1, 0x0000, /* DAC mute */ | |||
980 | ||||
981 | WM_POWERDOWN, 0x0008, /* All power-up except HP */ | |||
982 | WM_RESET, 0x0000, /* reset */ | |||
983 | }; | |||
984 | static unsigned short wm_inits2[] = { | |||
985 | WM_MASTER_CTRL, 0x0022, /* 256fs, slave mode */ | |||
986 | WM_DAC_INT, 0x0022, /* I2S, normal polarity, 24bit */ | |||
987 | WM_ADC_INT, 0x0022, /* I2S, normal polarity, 24bit */ | |||
988 | WM_DAC_CTRL1, 0x0090, /* DAC L/R */ | |||
989 | WM_OUT_MUX, 0x0001, /* OUT DAC */ | |||
990 | WM_HP_ATTEN_L, 0x0179, /* HP 0dB */ | |||
991 | WM_HP_ATTEN_R, 0x0179, /* HP 0dB */ | |||
992 | WM_DAC_ATTEN_L, 0x0000, /* DAC 0dB */ | |||
993 | WM_DAC_ATTEN_L, 0x0100, /* DAC 0dB */ | |||
994 | WM_DAC_ATTEN_R, 0x0000, /* DAC 0dB */ | |||
995 | WM_DAC_ATTEN_R, 0x0100, /* DAC 0dB */ | |||
996 | WM_PHASE_SWAP, 0x0000, /* phase normal */ | |||
997 | #if 0 | |||
998 | WM_DAC_MASTER, 0x0100, /* DAC master muted */ | |||
999 | #endif | |||
1000 | WM_DAC_CTRL2, 0x0000, /* no deemphasis, no ZFLG */ | |||
1001 | WM_ADC_ATTEN_L, 0x0000, /* ADC muted */ | |||
1002 | WM_ADC_ATTEN_R, 0x0000, /* ADC muted */ | |||
1003 | #if 1 | |||
1004 | WM_ALC_CTRL1, 0x007b, /* */ | |||
1005 | WM_ALC_CTRL2, 0x0000, /* */ | |||
1006 | WM_ALC_CTRL3, 0x0000, /* */ | |||
1007 | WM_NOISE_GATE, 0x0000, /* */ | |||
1008 | #endif | |||
1009 | WM_DAC_MUTE, 0x0000, /* DAC unmute */ | |||
1010 | WM_ADC_MUX, 0x0003, /* ADC unmute, both CD/Line On */ | |||
1011 | }; | |||
1012 | static unsigned short wm8766_inits[] = { | |||
1013 | WM8766_RESET, 0x0000, | |||
1014 | WM8766_DAC_CTRL, 0x0120, | |||
1015 | WM8766_INT_CTRL, 0x0022, /* I2S Normal Mode, 24 bit */ | |||
1016 | WM8766_DAC_CTRL2, 0x0001, | |||
1017 | WM8766_DAC_CTRL3, 0x0080, | |||
1018 | WM8766_LDA1, 0x0100, | |||
1019 | WM8766_LDA2, 0x0100, | |||
1020 | WM8766_LDA3, 0x0100, | |||
1021 | WM8766_RDA1, 0x0100, | |||
1022 | WM8766_RDA2, 0x0100, | |||
1023 | WM8766_RDA3, 0x0100, | |||
1024 | WM8766_MUTE1, 0x0000, | |||
1025 | WM8766_MUTE2, 0x0000, | |||
1026 | }; | |||
1027 | ||||
1028 | ||||
1029 | unsigned int i; | |||
1030 | ||||
1031 | ice->vt1720 = 0; | |||
1032 | ice->vt1724 = 1; | |||
1033 | ||||
1034 | ice->num_total_dacs = 8; | |||
1035 | ice->num_total_adcs = 1; | |||
1036 | ice->akm_codecs = 2; | |||
1037 | ||||
1038 | /* HACK - use this as the SPDIF source. | |||
1039 | * don't call snd_ice1712_gpio_get/put(), otherwise it's overwritten | |||
1040 | */ | |||
1041 | ice->gpio.saved[0] = 0; | |||
1042 | /* to remeber the register values */ | |||
1043 | ||||
1044 | ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL); | |||
1045 | if (! ice->akm) | |||
1046 | return -ENOMEM; | |||
1047 | ice->akm_codecs = 1; | |||
1048 | ||||
1049 | /* initialize WM8776 codec */ | |||
1050 | for (i = 0; i < ARRAY_SIZE(wm_inits); i += 2) | |||
1051 | wm_put(ice, wm_inits[i], wm_inits[i+1]); | |||
1052 | schedule_timeout_uninterruptible(1); | |||
1053 | for (i = 0; i < ARRAY_SIZE(wm_inits2); i += 2) | |||
1054 | wm_put(ice, wm_inits2[i], wm_inits2[i+1]); | |||
1055 | ||||
1056 | /* initialize WM8766 codec */ | |||
1057 | ||||
1058 | for (i = 0; i < ARRAY_SIZE(wm8766_inits); i += 2) | |||
1059 | wm8766_spi_write(ice, wm8766_inits[i], wm8766_inits[i+1]); | |||
1060 | ||||
1061 | ||||
1062 | return 0; | |||
1063 | } | |||
1064 | ||||
1065 | ||||
1066 | /* | |||
1067 | * initialize the chip | |||
1068 | */ | |||
1069 | static int __devinit prodigy_hd2_init(struct snd_ice1712 *ice) | |||
1070 | { | |||
1071 | static unsigned short ak4396_inits[] = { | |||
1072 | AK4396_CTRL1, 0x87, /* I2S Normal Mode, 24 bit */ | |||
1073 | AK4396_CTRL2, 0x02, | |||
1074 | AK4396_CTRL3, 0x00, | |||
1075 | AK4396_LCH_ATT, 0x00, | |||
1076 | AK4396_RCH_ATT, 0x00, | |||
1077 | }; | |||
1078 | ||||
1079 | ||||
1080 | unsigned int i; | |||
1081 | ||||
1082 | ice->vt1720 = 0; | |||
1083 | ice->vt1724 = 1; | |||
1084 | ||||
1085 | ice->num_total_dacs = 1; | |||
1086 | ice->num_total_adcs = 1; | |||
1087 | ice->akm_codecs = 1; | |||
1088 | ||||
1089 | /* HACK - use this as the SPDIF source. | |||
1090 | * don't call snd_ice1712_gpio_get/put(), otherwise it's overwritten | |||
1091 | */ | |||
1092 | ice->gpio.saved[0] = 0; | |||
1093 | /* to remeber the register values */ | |||
1095 | ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL); | err = t3_seeprom_write(adapter, aligned_offset, *p); aligned_offset += 4; } if (!err) err = t3_seeprom_wp(adapter, 1); out: if (buf != data) kfree(buf); return err; } static void get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) { wol->supported = 0; wol->wolopts = 0; memset(&wol->sopass, 0, sizeof(wol->sopass)); } static int cxgb3_set_flags(struct net_device *dev, u32 data) { struct port_info *pi = netdev_priv(dev); int i; if (data & ETH_FLAG_LRO) { if (!(pi->rx_offload & T3_RX_CSUM)) return -EINVAL; pi->rx_offload |= T3_LRO; for (i = pi->first_qset; i < pi->first_qset + pi->nqsets; i++) set_qset_lro(dev, i, 1); } else { pi->rx_offload &= ~T3_LRO; for (i = pi->first_qset; i < pi->first_qset + pi->nqsets; i++) set_qset_lro(dev, i, 0); } return 0; } static const struct ethtool_ops cxgb_ethtool_ops = { .get_settings = get_settings, .set_settings = set_settings, .get_drvinfo = get_drvinfo, .get_msglevel = get_msglevel, .set_msglevel = set_msglevel, .get_ringparam = get_sge_param, .set_ringparam = set_sge_param, .get_coalesce = get_coalesce, .set_coalesce = set_coalesce, .get_eeprom_len = get_eeprom_len, .get_eeprom = get_eeprom, .set_eeprom = set_eeprom, .get_pauseparam = get_pauseparam, .set_pauseparam = set_pauseparam, .get_rx_csum = get_rx_csum, .set_rx_csum = set_rx_csum, .set_tx_csum = ethtool_op_set_tx_csum, .set_sg = ethtool_op_set_sg, .get_link = ethtool_op_get_link, .get_strings = get_strings, .phys_id = cxgb3_phys_id, .nway_reset = restart_autoneg, .get_sset_count = get_sset_count, .get_ethtool_stats = get_stats, .get_regs_len = get_regs_len, .get_regs = get_regs, .get_wol = get_wol, .set_tso = ethtool_op_set_tso, .get_flags = ethtool_op_get_flags, .set_flags = cxgb3_set_flags, }; static int in_range(int val, int lo, int hi) { return val < 0 || (val <= hi && val >= lo); } static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr) { struct port_info *pi = netdev_priv(dev); struct adapter *adapter = pi->adapter; u32 cmd; int ret; if (copy_from_user(&cmd, useraddr, sizeof(cmd))) return -EFAULT; switch (cmd) { case CHELSIO_SET_QSET_PARAMS:{ int i; struct qset_params *q; struct ch_qset_params t; int q1 = pi->first_qset; int nqsets = pi->nqsets; if (!capable(CAP_NET_ADMIN)) return -EPERM; if (copy_from_user(&t, useraddr, sizeof(t))) return -EFAULT; if (t.qset_idx >= SGE_QSETS) return -EINVAL;cgi/litmus-rt.git/tree/sound/pci/ice1712/prodigy_hifi.c?id=6b8d6e5518e2812b150c2d7c1e975a1bd33f0ccc#n1139'>11390x00, /* GPIO_MASK2 */ | ||
1140 | 0x00, /* GPIO_STATE */ | |||
1141 | 0x00, /* GPIO_STATE1 */ | |||
1142 | 0x00, /* GPIO_STATE2 */ | |||
1143 | }; | |||
1144 | ||||
1145 | static unsigned char fortissimo4_eeprom[] __devinitdata = { | |||
1146 | 0x43, /* SYSCONF: clock 512, ADC, 4DACs */ | |||
1147 | 0x80, /* ACLINK: I2S */ | |||
1148 | 0xfc, /* I2S: vol, 96k, 24bit, 192k */ | |||
1149 | 0xc1, /* SPDIF: out-en, out-int */ | |||
1150 | 0xff, /* GPIO_DIR */ | |||
1151 | 0xff, /* GPIO_DIR1 */ | |||
1152 | 0x5f, /* GPIO_DIR2 */ | |||
1153 | 0x00, /* GPIO_MASK */ | |||
1154 | 0x00, /* GPIO_MASK1 */ | |||
1155 | 0x00, /* GPIO_MASK2 */ | |||
1156 | 0x00, /* GPIO_STATE */ | |||
1157 | 0x00, /* GPIO_STATE1 */ | |||
1158 | 0x00, /* GPIO_STATE2 */ | |||
1159 | }; | |||
1160 | ||||
1161 | /* entry point */ | |||
1162 | struct snd_ice1712_card_info snd_vt1724_prodigy_hifi_cards[] __devinitdata = { | |||
1163 | { | |||
1164 | .subvendor = VT1724_SUBDEVICE_PRODIGY_HIFI, | |||
1165 | .name = "Audiotrak Prodigy 7.1 HiFi", | |||
1166 | .model = "prodigy71hifi", | |||
1167 | .chip_init = prodigy_hifi_init, | |||
1168 | .build_controls = prodigy_hifi_add_controls, | |||
1169 | .eeprom_size = sizeof(prodigy71hifi_eeprom), | |||
1170 | .eeprom_data = prodigy71hifi_eeprom, | |||
1171 | .driver = "Prodigy71HIFI", | |||
1172 | }, | |||
1173 | { | |||
1174 | .subvendor = VT1724_SUBDEVICE_PRODIGY_HD2, | |||
1175 | .name = "Audiotrak Prodigy HD2", | |||
1176 | .model = "prodigyhd2", | |||
1177 | .chip_init = prodigy_hd2_init, | |||
1178 | .build_controls = prodigy_hd2_add_controls, | |||
1179 | .eeprom_size = sizeof(prodigyhd2_eeprom), | |||
1180 | .eeprom_data = prodigyhd2_eeprom, | |||
1181 | .driver = "Prodigy71HD2", | |||
1182 | }, | |||
1183 | { | |||
1184 | .subvendor = VT1724_SUBDEVICE_FORTISSIMO4, | |||
1185 | .name = "Hercules Fortissimo IV", | |||
1186 | .model = "fortissimo4", | |||
1187 | .chip_init = prodigy_hifi_init, | |||
1188 | .build_controls = prodigy_hifi_add_controls, | |||
1189 | .eeprom_size = sizeof(fortissimo4_eeprom), | |||
1190 | .eeprom_data = fortissimo4_eeprom, | |||
1191 | .driver = "Fortissimo4", | |||
1192 | }, | |||
1193 | { } /* terminator */ | |||
1194 | }; | |||
1195 | ||||