diff options
author | Pavel Hofman <pavel.hofman@ivitera.com> | 2009-09-16 16:25:41 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2009-09-21 09:49:04 -0400 |
commit | 6ef80706184be792499a4485a7957f2660b6a076 (patch) | |
tree | d99ce8553d1a3c854ef0995731560fa05bba3a76 /sound | |
parent | 1ff97cb9dd9f53b33ce6710a4f861f43e70e8ca4 (diff) |
ALSA: ice1724 - Infrasonic Quartet support
* three external clock types
* all controls supported
Signed-off-by: Pavel Hofman <pavel.hofman@ivitera.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound')
-rw-r--r-- | sound/pci/ice1712/Makefile | 2 | ||||
-rw-r--r-- | sound/pci/ice1712/ice1724.c | 3 | ||||
-rw-r--r-- | sound/pci/ice1712/quartet.c | 1130 | ||||
-rw-r--r-- | sound/pci/ice1712/quartet.h | 10 |
4 files changed, 1144 insertions, 1 deletions
diff --git a/sound/pci/ice1712/Makefile b/sound/pci/ice1712/Makefile index 536eae2ccf94..f7ce33f00ea5 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 prodigy_hifi.o juli.o phase.o wtm.o se.o maya44.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 maya44.o quartet.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/ice1724.c b/sound/pci/ice1712/ice1724.c index 3f11195b2631..3896fb931de1 100644 --- a/sound/pci/ice1712/ice1724.c +++ b/sound/pci/ice1712/ice1724.c | |||
@@ -53,6 +53,7 @@ | |||
53 | #include "phase.h" | 53 | #include "phase.h" |
54 | #include "wtm.h" | 54 | #include "wtm.h" |
55 | #include "se.h" | 55 | #include "se.h" |
56 | #include "quartet.h" | ||
56 | 57 | ||
57 | MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); | 58 | MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); |
58 | MODULE_DESCRIPTION("VIA ICEnsemble ICE1724/1720 (Envy24HT/PT)"); | 59 | MODULE_DESCRIPTION("VIA ICEnsemble ICE1724/1720 (Envy24HT/PT)"); |
@@ -70,6 +71,7 @@ MODULE_SUPPORTED_DEVICE("{" | |||
70 | PHASE_DEVICE_DESC | 71 | PHASE_DEVICE_DESC |
71 | WTM_DEVICE_DESC | 72 | WTM_DEVICE_DESC |
72 | SE_DEVICE_DESC | 73 | SE_DEVICE_DESC |
74 | QTET_DEVICE_DESC | ||
73 | "{VIA,VT1720}," | 75 | "{VIA,VT1720}," |
74 | "{VIA,VT1724}," | 76 | "{VIA,VT1724}," |
75 | "{ICEnsemble,Generic ICE1724}," | 77 | "{ICEnsemble,Generic ICE1724}," |
@@ -2184,6 +2186,7 @@ static struct snd_ice1712_card_info *card_tables[] __devinitdata = { | |||
2184 | snd_vt1724_phase_cards, | 2186 | snd_vt1724_phase_cards, |
2185 | snd_vt1724_wtm_cards, | 2187 | snd_vt1724_wtm_cards, |
2186 | snd_vt1724_se_cards, | 2188 | snd_vt1724_se_cards, |
2189 | snd_vt1724_qtet_cards, | ||
2187 | NULL, | 2190 | NULL, |
2188 | }; | 2191 | }; |
2189 | 2192 | ||
diff --git a/sound/pci/ice1712/quartet.c b/sound/pci/ice1712/quartet.c new file mode 100644 index 000000000000..1948632787e6 --- /dev/null +++ b/sound/pci/ice1712/quartet.c | |||
@@ -0,0 +1,1130 @@ | |||
1 | /* | ||
2 | * ALSA driver for ICEnsemble VT1724 (Envy24HT) | ||
3 | * | ||
4 | * Lowlevel functions for Infrasonic Quartet | ||
5 | * | ||
6 | * Copyright (c) 2009 Pavel Hofman <pavel.hofman@ivitera.com> | ||
7 | * | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
22 | * | ||
23 | */ | ||
24 | |||
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 | #include <sound/tlv.h> | ||
32 | #include <sound/info.h> | ||
33 | |||
34 | #include "ice1712.h" | ||
35 | #include "envy24ht.h" | ||
36 | #include <sound/ak4113.h> | ||
37 | #include "quartet.h" | ||
38 | |||
39 | struct qtet_spec { | ||
40 | struct ak4113 *ak4113; | ||
41 | unsigned int scr; /* system control register */ | ||
42 | unsigned int mcr; /* monitoring control register */ | ||
43 | unsigned int cpld; /* cpld register */ | ||
44 | }; | ||
45 | |||
46 | struct qtet_kcontrol_private { | ||
47 | unsigned int bit; | ||
48 | void (*set_register)(struct snd_ice1712 *ice, unsigned int val); | ||
49 | unsigned int (*get_register)(struct snd_ice1712 *ice); | ||
50 | unsigned char *texts[2]; | ||
51 | }; | ||
52 | |||
53 | enum { | ||
54 | IN12_SEL = 0, | ||
55 | IN34_SEL, | ||
56 | AIN34_SEL, | ||
57 | COAX_OUT, | ||
58 | IN12_MON12, | ||
59 | IN12_MON34, | ||
60 | IN34_MON12, | ||
61 | IN34_MON34, | ||
62 | OUT12_MON34, | ||
63 | OUT34_MON12, | ||
64 | }; | ||
65 | |||
66 | static char *ext_clock_names[3] = {"IEC958 In", "Word Clock 1xFS", | ||
67 | "Word Clock 256xFS"}; | ||
68 | |||
69 | /* chip address on I2C bus */ | ||
70 | #define AK4113_ADDR 0x26 /* S/PDIF receiver */ | ||
71 | |||
72 | /* chip address on SPI bus */ | ||
73 | #define AK4620_ADDR 0x02 /* ADC/DAC */ | ||
74 | |||
75 | |||
76 | /* | ||
77 | * GPIO pins | ||
78 | */ | ||
79 | |||
80 | /* GPIO0 - O - DATA0, def. 0 */ | ||
81 | #define GPIO_D0 (1<<0) | ||
82 | /* GPIO1 - I/O - DATA1, Jack Detect Input0 (0:present, 1:missing), def. 1 */ | ||
83 | #define GPIO_D1_JACKDTC0 (1<<1) | ||
84 | /* GPIO2 - I/O - DATA2, Jack Detect Input1 (0:present, 1:missing), def. 1 */ | ||
85 | #define GPIO_D2_JACKDTC1 (1<<2) | ||
86 | /* GPIO3 - I/O - DATA3, def. 1 */ | ||
87 | #define GPIO_D3 (1<<3) | ||
88 | /* GPIO4 - I/O - DATA4, SPI CDTO, def. 1 */ | ||
89 | #define GPIO_D4_SPI_CDTO (1<<4) | ||
90 | /* GPIO5 - I/O - DATA5, SPI CCLK, def. 1 */ | ||
91 | #define GPIO_D5_SPI_CCLK (1<<5) | ||
92 | /* GPIO6 - I/O - DATA6, Cable Detect Input (0:detected, 1:not detected */ | ||
93 | #define GPIO_D6_CD (1<<6) | ||
94 | /* GPIO7 - I/O - DATA7, Device Detect Input (0:detected, 1:not detected */ | ||
95 | #define GPIO_D7_DD (1<<7) | ||
96 | /* GPIO8 - O - CPLD Chip Select, def. 1 */ | ||
97 | #define GPIO_CPLD_CSN (1<<8) | ||
98 | /* GPIO9 - O - CPLD register read/write (0:write, 1:read), def. 0 */ | ||
99 | #define GPIO_CPLD_RW (1<<9) | ||
100 | /* GPIO10 - O - SPI Chip Select for CODEC#0, def. 1 */ | ||
101 | #define GPIO_SPI_CSN0 (1<<10) | ||
102 | /* GPIO11 - O - SPI Chip Select for CODEC#1, def. 1 */ | ||
103 | #define GPIO_SPI_CSN1 (1<<11) | ||
104 | /* GPIO12 - O - Ex. Register Output Enable (0:enable, 1:disable), def. 1, | ||
105 | * init 0 */ | ||
106 | #define GPIO_EX_GPIOE (1<<12) | ||
107 | /* GPIO13 - O - Ex. Register0 Chip Select for System Control Register, | ||
108 | * def. 1 */ | ||
109 | #define GPIO_SCR (1<<13) | ||
110 | /* GPIO14 - O - Ex. Register1 Chip Select for Monitor Control Register, | ||
111 | * def. 1 */ | ||
112 | #define GPIO_MCR (1<<14) | ||
113 | |||
114 | #define GPIO_SPI_ALL (GPIO_D4_SPI_CDTO | GPIO_D5_SPI_CCLK |\ | ||
115 | GPIO_SPI_CSN0 | GPIO_SPI_CSN1) | ||
116 | |||
117 | #define GPIO_DATA_MASK (GPIO_D0 | GPIO_D1_JACKDTC0 | \ | ||
118 | GPIO_D2_JACKDTC1 | GPIO_D3 | \ | ||
119 | GPIO_D4_SPI_CDTO | GPIO_D5_SPI_CCLK | \ | ||
120 | GPIO_D6_CD | GPIO_D7_DD) | ||
121 | |||
122 | /* System Control Register GPIO_SCR data bits */ | ||
123 | /* Mic/Line select relay (0:line, 1:mic) */ | ||
124 | #define SCR_RELAY GPIO_D0 | ||
125 | /* Phantom power drive control (0:5V, 1:48V) */ | ||
126 | #define SCR_PHP_V GPIO_D1_JACKDTC0 | ||
127 | /* H/W mute control (0:Normal, 1:Mute) */ | ||
128 | #define SCR_MUTE GPIO_D2_JACKDTC1 | ||
129 | /* Phantom power control (0:Phantom on, 1:off) */ | ||
130 | #define SCR_PHP GPIO_D3 | ||
131 | /* Analog input 1/2 Source Select */ | ||
132 | #define SCR_AIN12_SEL0 GPIO_D4_SPI_CDTO | ||
133 | #define SCR_AIN12_SEL1 GPIO_D5_SPI_CCLK | ||
134 | /* Analog input 3/4 Source Select (0:line, 1:hi-z) */ | ||
135 | #define SCR_AIN34_SEL GPIO_D6_CD | ||
136 | /* Codec Power Down (0:power down, 1:normal) */ | ||
137 | #define SCR_CODEC_PDN GPIO_D7_DD | ||
138 | |||
139 | #define SCR_AIN12_LINE (0) | ||
140 | #define SCR_AIN12_MIC (SCR_AIN12_SEL0) | ||
141 | #define SCR_AIN12_LOWCUT (SCR_AIN12_SEL1 | SCR_AIN12_SEL0) | ||
142 | |||
143 | /* Monitor Control Register GPIO_MCR data bits */ | ||
144 | /* Input 1/2 to Monitor 1/2 (0:off, 1:on) */ | ||
145 | #define MCR_IN12_MON12 GPIO_D0 | ||
146 | /* Input 1/2 to Monitor 3/4 (0:off, 1:on) */ | ||
147 | #define MCR_IN12_MON34 GPIO_D1_JACKDTC0 | ||
148 | /* Input 3/4 to Monitor 1/2 (0:off, 1:on) */ | ||
149 | #define MCR_IN34_MON12 GPIO_D2_JACKDTC1 | ||
150 | /* Input 3/4 to Monitor 3/4 (0:off, 1:on) */ | ||
151 | #define MCR_IN34_MON34 GPIO_D3 | ||
152 | /* Output to Monitor 1/2 (0:off, 1:on) */ | ||
153 | #define MCR_OUT34_MON12 GPIO_D4_SPI_CDTO | ||
154 | /* Output to Monitor 3/4 (0:off, 1:on) */ | ||
155 | #define MCR_OUT12_MON34 GPIO_D5_SPI_CCLK | ||
156 | |||
157 | /* CPLD Register DATA bits */ | ||
158 | /* Clock Rate Select */ | ||
159 | #define CPLD_CKS0 GPIO_D0 | ||
160 | #define CPLD_CKS1 GPIO_D1_JACKDTC0 | ||
161 | #define CPLD_CKS2 GPIO_D2_JACKDTC1 | ||
162 | /* Sync Source Select (0:Internal, 1:External) */ | ||
163 | #define CPLD_SYNC_SEL GPIO_D3 | ||
164 | /* Word Clock FS Select (0:FS, 1:256FS) */ | ||
165 | #define CPLD_WORD_SEL GPIO_D4_SPI_CDTO | ||
166 | /* Coaxial Output Source (IS-Link) (0:SPDIF, 1:I2S) */ | ||
167 | #define CPLD_COAX_OUT GPIO_D5_SPI_CCLK | ||
168 | /* Input 1/2 Source Select (0:Analog12, 1:An34) */ | ||
169 | #define CPLD_IN12_SEL GPIO_D6_CD | ||
170 | /* Input 3/4 Source Select (0:Analog34, 1:Digital In) */ | ||
171 | #define CPLD_IN34_SEL GPIO_D7_DD | ||
172 | |||
173 | /* internal clock (CPLD_SYNC_SEL = 0) options */ | ||
174 | #define CPLD_CKS_44100HZ (0) | ||
175 | #define CPLD_CKS_48000HZ (CPLD_CKS0) | ||
176 | #define CPLD_CKS_88200HZ (CPLD_CKS1) | ||
177 | #define CPLD_CKS_96000HZ (CPLD_CKS1 | CPLD_CKS0) | ||
178 | #define CPLD_CKS_176400HZ (CPLD_CKS2) | ||
179 | #define CPLD_CKS_192000HZ (CPLD_CKS2 | CPLD_CKS0) | ||
180 | |||
181 | #define CPLD_CKS_MASK (CPLD_CKS0 | CPLD_CKS1 | CPLD_CKS2) | ||
182 | |||
183 | /* external clock (CPLD_SYNC_SEL = 1) options */ | ||
184 | /* external clock - SPDIF */ | ||
185 | #define CPLD_EXT_SPDIF (0 | CPLD_SYNC_SEL) | ||
186 | /* external clock - WordClock 1xfs */ | ||
187 | #define CPLD_EXT_WORDCLOCK_1FS (CPLD_CKS1 | CPLD_SYNC_SEL) | ||
188 | /* external clock - WordClock 256xfs */ | ||
189 | #define CPLD_EXT_WORDCLOCK_256FS (CPLD_CKS1 | CPLD_WORD_SEL |\ | ||
190 | CPLD_SYNC_SEL) | ||
191 | |||
192 | #define EXT_SPDIF_TYPE 0 | ||
193 | #define EXT_WORDCLOCK_1FS_TYPE 1 | ||
194 | #define EXT_WORDCLOCK_256FS_TYPE 2 | ||
195 | |||
196 | #define AK4620_DFS0 (1<<0) | ||
197 | #define AK4620_DFS1 (1<<1) | ||
198 | #define AK4620_CKS0 (1<<2) | ||
199 | #define AK4620_CKS1 (1<<3) | ||
200 | /* Clock and Format Control register */ | ||
201 | #define AK4620_DFS_REG 0x02 | ||
202 | |||
203 | /* Deem and Volume Control register */ | ||
204 | #define AK4620_DEEMVOL_REG 0x03 | ||
205 | #define AK4620_SMUTE (1<<7) | ||
206 | |||
207 | /* | ||
208 | * Conversion from int value to its binary form. Used for debugging. | ||
209 | * The output buffer must be allocated prior to calling the function. | ||
210 | */ | ||
211 | static char *get_binary(char *buffer, int value) | ||
212 | { | ||
213 | int i, j, pos; | ||
214 | pos = 0; | ||
215 | for (i = 0; i < 4; ++i) { | ||
216 | for (j = 0; j < 8; ++j) { | ||
217 | if (value & (1 << (31-(i*8 + j)))) | ||
218 | buffer[pos] = '1'; | ||
219 | else | ||
220 | buffer[pos] = '0'; | ||
221 | pos++; | ||
222 | } | ||
223 | if (i < 3) { | ||
224 | buffer[pos] = ' '; | ||
225 | pos++; | ||
226 | } | ||
227 | } | ||
228 | buffer[pos] = '\0'; | ||
229 | return buffer; | ||
230 | } | ||
231 | |||
232 | /* | ||
233 | * Initial setup of the conversion array GPIO <-> rate | ||
234 | */ | ||
235 | static unsigned int qtet_rates[] = { | ||
236 | 44100, 48000, 88200, | ||
237 | 96000, 176400, 192000, | ||
238 | }; | ||
239 | |||
240 | static unsigned int cks_vals[] = { | ||
241 | CPLD_CKS_44100HZ, CPLD_CKS_48000HZ, CPLD_CKS_88200HZ, | ||
242 | CPLD_CKS_96000HZ, CPLD_CKS_176400HZ, CPLD_CKS_192000HZ, | ||
243 | }; | ||
244 | |||
245 | static struct snd_pcm_hw_constraint_list qtet_rates_info = { | ||
246 | .count = ARRAY_SIZE(qtet_rates), | ||
247 | .list = qtet_rates, | ||
248 | .mask = 0, | ||
249 | }; | ||
250 | |||
251 | static void qtet_ak4113_write(void *private_data, unsigned char reg, | ||
252 | unsigned char val) | ||
253 | { | ||
254 | snd_vt1724_write_i2c((struct snd_ice1712 *)private_data, AK4113_ADDR, | ||
255 | reg, val); | ||
256 | } | ||
257 | |||
258 | static unsigned char qtet_ak4113_read(void *private_data, unsigned char reg) | ||
259 | { | ||
260 | return snd_vt1724_read_i2c((struct snd_ice1712 *)private_data, | ||
261 | AK4113_ADDR, reg); | ||
262 | } | ||
263 | |||
264 | |||
265 | /* | ||
266 | * AK4620 section | ||
267 | */ | ||
268 | |||
269 | /* | ||
270 | * Write data to addr register of ak4620 | ||
271 | */ | ||
272 | static void qtet_akm_write(struct snd_akm4xxx *ak, int chip, | ||
273 | unsigned char addr, unsigned char data) | ||
274 | { | ||
275 | unsigned int tmp, orig_dir; | ||
276 | int idx; | ||
277 | unsigned int addrdata; | ||
278 | struct snd_ice1712 *ice = ak->private_data[0]; | ||
279 | |||
280 | if (snd_BUG_ON(chip < 0 || chip >= 4)) | ||
281 | return; | ||
282 | /*printk(KERN_DEBUG "Writing to AK4620: chip=%d, addr=0x%x, | ||
283 | data=0x%x\n", chip, addr, data);*/ | ||
284 | orig_dir = ice->gpio.get_dir(ice); | ||
285 | ice->gpio.set_dir(ice, orig_dir | GPIO_SPI_ALL); | ||
286 | /* set mask - only SPI bits */ | ||
287 | ice->gpio.set_mask(ice, ~GPIO_SPI_ALL); | ||
288 | |||
289 | tmp = ice->gpio.get_data(ice); | ||
290 | /* high all */ | ||
291 | tmp |= GPIO_SPI_ALL; | ||
292 | ice->gpio.set_data(ice, tmp); | ||
293 | udelay(100); | ||
294 | /* drop chip select */ | ||
295 | if (chip) | ||
296 | /* CODEC 1 */ | ||
297 | tmp &= ~GPIO_SPI_CSN1; | ||
298 | else | ||
299 | tmp &= ~GPIO_SPI_CSN0; | ||
300 | ice->gpio.set_data(ice, tmp); | ||
301 | udelay(100); | ||
302 | |||
303 | /* build I2C address + data byte */ | ||
304 | addrdata = (AK4620_ADDR << 6) | 0x20 | (addr & 0x1f); | ||
305 | addrdata = (addrdata << 8) | data; | ||
306 | for (idx = 15; idx >= 0; idx--) { | ||
307 | /* drop clock */ | ||
308 | tmp &= ~GPIO_D5_SPI_CCLK; | ||
309 | ice->gpio.set_data(ice, tmp); | ||
310 | udelay(100); | ||
311 | /* set data */ | ||
312 | if (addrdata & (1 << idx)) | ||
313 | tmp |= GPIO_D4_SPI_CDTO; | ||
314 | else | ||
315 | tmp &= ~GPIO_D4_SPI_CDTO; | ||
316 | ice->gpio.set_data(ice, tmp); | ||
317 | udelay(100); | ||
318 | /* raise clock */ | ||
319 | tmp |= GPIO_D5_SPI_CCLK; | ||
320 | ice->gpio.set_data(ice, tmp); | ||
321 | udelay(100); | ||
322 | } | ||
323 | /* all back to 1 */ | ||
324 | tmp |= GPIO_SPI_ALL; | ||
325 | ice->gpio.set_data(ice, tmp); | ||
326 | udelay(100); | ||
327 | |||
328 | /* return all gpios to non-writable */ | ||
329 | ice->gpio.set_mask(ice, 0xffffff); | ||
330 | /* restore GPIOs direction */ | ||
331 | ice->gpio.set_dir(ice, orig_dir); | ||
332 | } | ||
333 | |||
334 | static void qtet_akm_set_regs(struct snd_akm4xxx *ak, unsigned char addr, | ||
335 | unsigned char mask, unsigned char value) | ||
336 | { | ||
337 | unsigned char tmp; | ||
338 | int chip; | ||
339 | for (chip = 0; chip < ak->num_chips; chip++) { | ||
340 | tmp = snd_akm4xxx_get(ak, chip, addr); | ||
341 | /* clear the bits */ | ||
342 | tmp &= ~mask; | ||
343 | /* set the new bits */ | ||
344 | tmp |= value; | ||
345 | snd_akm4xxx_write(ak, chip, addr, tmp); | ||
346 | } | ||
347 | } | ||
348 | |||
349 | /* | ||
350 | * change the rate of AK4620 | ||
351 | */ | ||
352 | static void qtet_akm_set_rate_val(struct snd_akm4xxx *ak, unsigned int rate) | ||
353 | { | ||
354 | unsigned char ak4620_dfs; | ||
355 | |||
356 | if (rate == 0) /* no hint - S/PDIF input is master or the new spdif | ||
357 | input rate undetected, simply return */ | ||
358 | return; | ||
359 | |||
360 | /* adjust DFS on codecs - see datasheet */ | ||
361 | if (rate > 108000) | ||
362 | ak4620_dfs = AK4620_DFS1 | AK4620_CKS1; | ||
363 | else if (rate > 54000) | ||
364 | ak4620_dfs = AK4620_DFS0 | AK4620_CKS0; | ||
365 | else | ||
366 | ak4620_dfs = 0; | ||
367 | |||
368 | /* set new value */ | ||
369 | qtet_akm_set_regs(ak, AK4620_DFS_REG, AK4620_DFS0 | AK4620_DFS1 | | ||
370 | AK4620_CKS0 | AK4620_CKS1, ak4620_dfs); | ||
371 | } | ||
372 | |||
373 | #define AK_CONTROL(xname, xch) { .name = xname, .num_channels = xch } | ||
374 | |||
375 | #define PCM_12_PLAYBACK_VOLUME "PCM 1/2 Playback Volume" | ||
376 | #define PCM_34_PLAYBACK_VOLUME "PCM 3/4 Playback Volume" | ||
377 | #define PCM_12_CAPTURE_VOLUME "PCM 1/2 Capture Volume" | ||
378 | #define PCM_34_CAPTURE_VOLUME "PCM 3/4 Capture Volume" | ||
379 | |||
380 | static const struct snd_akm4xxx_dac_channel qtet_dac[] = { | ||
381 | AK_CONTROL(PCM_12_PLAYBACK_VOLUME, 2), | ||
382 | AK_CONTROL(PCM_34_PLAYBACK_VOLUME, 2), | ||
383 | }; | ||
384 | |||
385 | static const struct snd_akm4xxx_adc_channel qtet_adc[] = { | ||
386 | AK_CONTROL(PCM_12_CAPTURE_VOLUME, 2), | ||
387 | AK_CONTROL(PCM_34_CAPTURE_VOLUME, 2), | ||
388 | }; | ||
389 | |||
390 | static struct snd_akm4xxx akm_qtet_dac __devinitdata = { | ||
391 | .type = SND_AK4620, | ||
392 | .num_dacs = 4, /* DAC1 - Output 12 | ||
393 | */ | ||
394 | .num_adcs = 4, /* ADC1 - Input 12 | ||
395 | */ | ||
396 | .ops = { | ||
397 | .write = qtet_akm_write, | ||
398 | .set_rate_val = qtet_akm_set_rate_val, | ||
399 | }, | ||
400 | .dac_info = qtet_dac, | ||
401 | .adc_info = qtet_adc, | ||
402 | }; | ||
403 | |||
404 | /* Communication routines with the CPLD */ | ||
405 | |||
406 | |||
407 | /* Writes data to external register reg, both reg and data are | ||
408 | * GPIO representations */ | ||
409 | static void reg_write(struct snd_ice1712 *ice, unsigned int reg, | ||
410 | unsigned int data) | ||
411 | { | ||
412 | unsigned int tmp; | ||
413 | |||
414 | mutex_lock(&ice->gpio_mutex); | ||
415 | /* set direction of used GPIOs*/ | ||
416 | /* all outputs */ | ||
417 | tmp = 0x00ffff; | ||
418 | ice->gpio.set_dir(ice, tmp); | ||
419 | /* mask - writable bits */ | ||
420 | ice->gpio.set_mask(ice, ~(tmp)); | ||
421 | /* write the data */ | ||
422 | tmp = ice->gpio.get_data(ice); | ||
423 | tmp &= ~GPIO_DATA_MASK; | ||
424 | tmp |= data; | ||
425 | ice->gpio.set_data(ice, tmp); | ||
426 | udelay(100); | ||
427 | /* drop output enable */ | ||
428 | tmp &= ~GPIO_EX_GPIOE; | ||
429 | ice->gpio.set_data(ice, tmp); | ||
430 | udelay(100); | ||
431 | /* drop the register gpio */ | ||
432 | tmp &= ~reg; | ||
433 | ice->gpio.set_data(ice, tmp); | ||
434 | udelay(100); | ||
435 | /* raise the register GPIO */ | ||
436 | tmp |= reg; | ||
437 | ice->gpio.set_data(ice, tmp); | ||
438 | udelay(100); | ||
439 | |||
440 | /* raise all data gpios */ | ||
441 | tmp |= GPIO_DATA_MASK; | ||
442 | ice->gpio.set_data(ice, tmp); | ||
443 | /* mask - immutable bits */ | ||
444 | ice->gpio.set_mask(ice, 0xffffff); | ||
445 | /* outputs only 8-15 */ | ||
446 | ice->gpio.set_dir(ice, 0x00ff00); | ||
447 | mutex_unlock(&ice->gpio_mutex); | ||
448 | } | ||
449 | |||
450 | static unsigned int get_scr(struct snd_ice1712 *ice) | ||
451 | { | ||
452 | struct qtet_spec *spec = ice->spec; | ||
453 | return spec->scr; | ||
454 | } | ||
455 | |||
456 | static unsigned int get_mcr(struct snd_ice1712 *ice) | ||
457 | { | ||
458 | struct qtet_spec *spec = ice->spec; | ||
459 | return spec->mcr; | ||
460 | } | ||
461 | |||
462 | static unsigned int get_cpld(struct snd_ice1712 *ice) | ||
463 | { | ||
464 | struct qtet_spec *spec = ice->spec; | ||
465 | return spec->cpld; | ||
466 | } | ||
467 | |||
468 | static void set_scr(struct snd_ice1712 *ice, unsigned int val) | ||
469 | { | ||
470 | struct qtet_spec *spec = ice->spec; | ||
471 | reg_write(ice, GPIO_SCR, val); | ||
472 | spec->scr = val; | ||
473 | } | ||
474 | |||
475 | static void set_mcr(struct snd_ice1712 *ice, unsigned int val) | ||
476 | { | ||
477 | struct qtet_spec *spec = ice->spec; | ||
478 | reg_write(ice, GPIO_MCR, val); | ||
479 | spec->mcr = val; | ||
480 | } | ||
481 | |||
482 | static void set_cpld(struct snd_ice1712 *ice, unsigned int val) | ||
483 | { | ||
484 | struct qtet_spec *spec = ice->spec; | ||
485 | reg_write(ice, GPIO_CPLD_CSN, val); | ||
486 | spec->cpld = val; | ||
487 | } | ||
488 | #ifdef CONFIG_PROC_FS | ||
489 | static void proc_regs_read(struct snd_info_entry *entry, | ||
490 | struct snd_info_buffer *buffer) | ||
491 | { | ||
492 | struct snd_ice1712 *ice = entry->private_data; | ||
493 | char bin_buffer[36]; | ||
494 | |||
495 | snd_iprintf(buffer, "SCR: %s\n", get_binary(bin_buffer, | ||
496 | get_scr(ice))); | ||
497 | snd_iprintf(buffer, "MCR: %s\n", get_binary(bin_buffer, | ||
498 | get_mcr(ice))); | ||
499 | snd_iprintf(buffer, "CPLD: %s\n", get_binary(bin_buffer, | ||
500 | get_cpld(ice))); | ||
501 | } | ||
502 | |||
503 | static void proc_init(struct snd_ice1712 *ice) | ||
504 | { | ||
505 | struct snd_info_entry *entry; | ||
506 | if (!snd_card_proc_new(ice->card, "quartet", &entry)) | ||
507 | snd_info_set_text_ops(entry, ice, proc_regs_read); | ||
508 | } | ||
509 | #else /* !CONFIG_PROC_FS */ | ||
510 | static void proc_init(struct snd_ice1712 *ice) {} | ||
511 | #endif | ||
512 | |||
513 | static int qtet_mute_get(struct snd_kcontrol *kcontrol, | ||
514 | struct snd_ctl_elem_value *ucontrol) | ||
515 | { | ||
516 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | ||
517 | unsigned int val; | ||
518 | val = get_scr(ice) & SCR_MUTE; | ||
519 | ucontrol->value.integer.value[0] = (val) ? 0 : 1; | ||
520 | return 0; | ||
521 | } | ||
522 | |||
523 | static int qtet_mute_put(struct snd_kcontrol *kcontrol, | ||
524 | struct snd_ctl_elem_value *ucontrol) | ||
525 | { | ||
526 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | ||
527 | unsigned int old, new, smute; | ||
528 | old = get_scr(ice) & SCR_MUTE; | ||
529 | if (ucontrol->value.integer.value[0]) { | ||
530 | /* unmute */ | ||
531 | new = 0; | ||
532 | /* un-smuting DAC */ | ||
533 | smute = 0; | ||
534 | } else { | ||
535 | /* mute */ | ||
536 | new = SCR_MUTE; | ||
537 | /* smuting DAC */ | ||
538 | smute = AK4620_SMUTE; | ||
539 | } | ||
540 | if (old != new) { | ||
541 | struct snd_akm4xxx *ak = ice->akm; | ||
542 | set_scr(ice, (get_scr(ice) & ~SCR_MUTE) | new); | ||
543 | /* set smute */ | ||
544 | qtet_akm_set_regs(ak, AK4620_DEEMVOL_REG, AK4620_SMUTE, smute); | ||
545 | return 1; | ||
546 | } | ||
547 | /* no change */ | ||
548 | return 0; | ||
549 | } | ||
550 | |||
551 | static int qtet_ain12_enum_info(struct snd_kcontrol *kcontrol, | ||
552 | struct snd_ctl_elem_info *uinfo) | ||
553 | { | ||
554 | static char *texts[3] = {"Line In 1/2", "Mic", "Mic + Low-cut"}; | ||
555 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
556 | uinfo->count = 1; | ||
557 | uinfo->value.enumerated.items = ARRAY_SIZE(texts); | ||
558 | |||
559 | if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) | ||
560 | uinfo->value.enumerated.item = | ||
561 | uinfo->value.enumerated.items - 1; | ||
562 | strcpy(uinfo->value.enumerated.name, | ||
563 | texts[uinfo->value.enumerated.item]); | ||
564 | |||
565 | return 0; | ||
566 | } | ||
567 | |||
568 | static int qtet_ain12_sw_get(struct snd_kcontrol *kcontrol, | ||
569 | struct snd_ctl_elem_value *ucontrol) | ||
570 | { | ||
571 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | ||
572 | unsigned int val, result; | ||
573 | val = get_scr(ice) & (SCR_AIN12_SEL1 | SCR_AIN12_SEL0); | ||
574 | switch (val) { | ||
575 | case SCR_AIN12_LINE: | ||
576 | result = 0; | ||
577 | break; | ||
578 | case SCR_AIN12_MIC: | ||
579 | result = 1; | ||
580 | break; | ||
581 | case SCR_AIN12_LOWCUT: | ||
582 | result = 2; | ||
583 | break; | ||
584 | default: | ||
585 | /* BUG - no other combinations allowed */ | ||
586 | snd_BUG(); | ||
587 | result = 0; | ||
588 | } | ||
589 | ucontrol->value.integer.value[0] = result; | ||
590 | return 0; | ||
591 | } | ||
592 | |||
593 | static int qtet_ain12_sw_put(struct snd_kcontrol *kcontrol, | ||
594 | struct snd_ctl_elem_value *ucontrol) | ||
595 | { | ||
596 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | ||
597 | unsigned int old, new, tmp, masked_old; | ||
598 | old = new = get_scr(ice); | ||
599 | masked_old = old & (SCR_AIN12_SEL1 | SCR_AIN12_SEL0); | ||
600 | tmp = ucontrol->value.integer.value[0]; | ||
601 | if (tmp == 2) | ||
602 | tmp = 3; /* binary 10 is not supported */ | ||
603 | tmp <<= 4; /* shifting to SCR_AIN12_SEL0 */ | ||
604 | if (tmp != masked_old) { | ||
605 | /* change requested */ | ||
606 | switch (tmp) { | ||
607 | case SCR_AIN12_LINE: | ||
608 | new = old & ~(SCR_AIN12_SEL1 | SCR_AIN12_SEL0); | ||
609 | set_scr(ice, new); | ||
610 | /* turn off relay */ | ||
611 | new &= ~SCR_RELAY; | ||
612 | set_scr(ice, new); | ||
613 | break; | ||
614 | case SCR_AIN12_MIC: | ||
615 | /* turn on relay */ | ||
616 | new = old | SCR_RELAY; | ||
617 | set_scr(ice, new); | ||
618 | new = (new & ~SCR_AIN12_SEL1) | SCR_AIN12_SEL0; | ||
619 | set_scr(ice, new); | ||
620 | break; | ||
621 | case SCR_AIN12_LOWCUT: | ||
622 | /* turn on relay */ | ||
623 | new = old | SCR_RELAY; | ||
624 | set_scr(ice, new); | ||
625 | new |= SCR_AIN12_SEL1 | SCR_AIN12_SEL0; | ||
626 | set_scr(ice, new); | ||
627 | break; | ||
628 | default: | ||
629 | snd_BUG(); | ||
630 | } | ||
631 | return 1; | ||
632 | } | ||
633 | /* no change */ | ||
634 | return 0; | ||
635 | } | ||
636 | |||
637 | static int qtet_php_get(struct snd_kcontrol *kcontrol, | ||
638 | struct snd_ctl_elem_value *ucontrol) | ||
639 | { | ||
640 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | ||
641 | unsigned int val; | ||
642 | /* if phantom voltage =48V, phantom on */ | ||
643 | val = get_scr(ice) & SCR_PHP_V; | ||
644 | ucontrol->value.integer.value[0] = val ? 1 : 0; | ||
645 | return 0; | ||
646 | } | ||
647 | |||
648 | static int qtet_php_put(struct snd_kcontrol *kcontrol, | ||
649 | struct snd_ctl_elem_value *ucontrol) | ||
650 | { | ||
651 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | ||
652 | unsigned int old, new; | ||
653 | old = new = get_scr(ice); | ||
654 | if (ucontrol->value.integer.value[0] /* phantom on requested */ | ||
655 | && (~old & SCR_PHP_V)) /* 0 = voltage 5V */ { | ||
656 | /* is off, turn on */ | ||
657 | /* turn voltage on first, = 1 */ | ||
658 | new = old | SCR_PHP_V; | ||
659 | set_scr(ice, new); | ||
660 | /* turn phantom on, = 0 */ | ||
661 | new &= ~SCR_PHP; | ||
662 | set_scr(ice, new); | ||
663 | } else if (!ucontrol->value.integer.value[0] && (old & SCR_PHP_V)) { | ||
664 | /* phantom off requested and 1 = voltage 48V */ | ||
665 | /* is on, turn off */ | ||
666 | /* turn voltage off first, = 0 */ | ||
667 | new = old & ~SCR_PHP_V; | ||
668 | set_scr(ice, new); | ||
669 | /* turn phantom off, = 1 */ | ||
670 | new |= SCR_PHP; | ||
671 | set_scr(ice, new); | ||
672 | } | ||
673 | if (old != new) | ||
674 | return 1; | ||
675 | /* no change */ | ||
676 | return 0; | ||
677 | } | ||
678 | |||
679 | #define PRIV_SW(xid, xbit, xreg) [xid] = {.bit = xbit,\ | ||
680 | .set_register = set_##xreg,\ | ||
681 | .get_register = get_##xreg, } | ||
682 | |||
683 | |||
684 | #define PRIV_ENUM2(xid, xbit, xreg, xtext1, xtext2) [xid] = {.bit = xbit,\ | ||
685 | .set_register = set_##xreg,\ | ||
686 | .get_register = get_##xreg,\ | ||
687 | .texts = {xtext1, xtext2} } | ||
688 | |||
689 | static struct qtet_kcontrol_private qtet_privates[] = { | ||
690 | PRIV_ENUM2(IN12_SEL, CPLD_IN12_SEL, cpld, "An In 1/2", "An In 3/4"), | ||
691 | PRIV_ENUM2(IN34_SEL, CPLD_IN34_SEL, cpld, "An In 3/4", "IEC958 In"), | ||
692 | PRIV_ENUM2(AIN34_SEL, SCR_AIN34_SEL, scr, "Line In 3/4", "Hi-Z"), | ||
693 | PRIV_ENUM2(COAX_OUT, CPLD_COAX_OUT, cpld, "IEC958", "I2S"), | ||
694 | PRIV_SW(IN12_MON12, MCR_IN12_MON12, mcr), | ||
695 | PRIV_SW(IN12_MON34, MCR_IN12_MON34, mcr), | ||
696 | PRIV_SW(IN34_MON12, MCR_IN34_MON12, mcr), | ||
697 | PRIV_SW(IN34_MON34, MCR_IN34_MON34, mcr), | ||
698 | PRIV_SW(OUT12_MON34, MCR_OUT12_MON34, mcr), | ||
699 | PRIV_SW(OUT34_MON12, MCR_OUT34_MON12, mcr), | ||
700 | }; | ||
701 | |||
702 | static int qtet_enum_info(struct snd_kcontrol *kcontrol, | ||
703 | struct snd_ctl_elem_info *uinfo) | ||
704 | { | ||
705 | struct qtet_kcontrol_private private = | ||
706 | qtet_privates[kcontrol->private_value]; | ||
707 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
708 | uinfo->count = 1; | ||
709 | uinfo->value.enumerated.items = ARRAY_SIZE(private.texts); | ||
710 | |||
711 | if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) | ||
712 | uinfo->value.enumerated.item = | ||
713 | uinfo->value.enumerated.items - 1; | ||
714 | strcpy(uinfo->value.enumerated.name, | ||
715 | private.texts[uinfo->value.enumerated.item]); | ||
716 | |||
717 | return 0; | ||
718 | } | ||
719 | |||
720 | static int qtet_sw_get(struct snd_kcontrol *kcontrol, | ||
721 | struct snd_ctl_elem_value *ucontrol) | ||
722 | { | ||
723 | struct qtet_kcontrol_private private = | ||
724 | qtet_privates[kcontrol->private_value]; | ||
725 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | ||
726 | ucontrol->value.integer.value[0] = | ||
727 | (private.get_register(ice) & private.bit) ? 1 : 0; | ||
728 | return 0; | ||
729 | } | ||
730 | |||
731 | static int qtet_sw_put(struct snd_kcontrol *kcontrol, | ||
732 | struct snd_ctl_elem_value *ucontrol) | ||
733 | { | ||
734 | struct qtet_kcontrol_private private = | ||
735 | qtet_privates[kcontrol->private_value]; | ||
736 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | ||
737 | unsigned int old, new; | ||
738 | old = private.get_register(ice); | ||
739 | if (ucontrol->value.integer.value[0]) | ||
740 | new = old | private.bit; | ||
741 | else | ||
742 | new = old & ~private.bit; | ||
743 | if (old != new) { | ||
744 | private.set_register(ice, new); | ||
745 | return 1; | ||
746 | } | ||
747 | /* no change */ | ||
748 | return 0; | ||
749 | } | ||
750 | |||
751 | #define qtet_sw_info snd_ctl_boolean_mono_info | ||
752 | |||
753 | #define QTET_CONTROL(xname, xtype, xpriv) \ | ||
754 | {.iface = SNDRV_CTL_ELEM_IFACE_MIXER,\ | ||
755 | .name = xname,\ | ||
756 | .info = qtet_##xtype##_info,\ | ||
757 | .get = qtet_sw_get,\ | ||
758 | .put = qtet_sw_put,\ | ||
759 | .private_value = xpriv } | ||
760 | |||
761 | static struct snd_kcontrol_new qtet_controls[] __devinitdata = { | ||
762 | { | ||
763 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
764 | .name = "Master Playback Switch", | ||
765 | .info = qtet_sw_info, | ||
766 | .get = qtet_mute_get, | ||
767 | .put = qtet_mute_put, | ||
768 | .private_value = 0 | ||
769 | }, | ||
770 | { | ||
771 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
772 | .name = "Phantom Power", | ||
773 | .info = qtet_sw_info, | ||
774 | .get = qtet_php_get, | ||
775 | .put = qtet_php_put, | ||
776 | .private_value = 0 | ||
777 | }, | ||
778 | { | ||
779 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
780 | .name = "Analog In 1/2 Capture Switch", | ||
781 | .info = qtet_ain12_enum_info, | ||
782 | .get = qtet_ain12_sw_get, | ||
783 | .put = qtet_ain12_sw_put, | ||
784 | .private_value = 0 | ||
785 | }, | ||
786 | QTET_CONTROL("Analog In 3/4 Capture Switch", enum, AIN34_SEL), | ||
787 | QTET_CONTROL("PCM In 1/2 Capture Switch", enum, IN12_SEL), | ||
788 | QTET_CONTROL("PCM In 3/4 Capture Switch", enum, IN34_SEL), | ||
789 | QTET_CONTROL("Coax Output Source", enum, COAX_OUT), | ||
790 | QTET_CONTROL("Analog In 1/2 to Monitor 1/2", sw, IN12_MON12), | ||
791 | QTET_CONTROL("Analog In 1/2 to Monitor 3/4", sw, IN12_MON34), | ||
792 | QTET_CONTROL("Analog In 3/4 to Monitor 1/2", sw, IN34_MON12), | ||
793 | QTET_CONTROL("Analog In 3/4 to Monitor 3/4", sw, IN34_MON34), | ||
794 | QTET_CONTROL("Output 1/2 to Monitor 3/4", sw, OUT12_MON34), | ||
795 | QTET_CONTROL("Output 3/4 to Monitor 1/2", sw, OUT34_MON12), | ||
796 | }; | ||
797 | |||
798 | static char *slave_vols[] __devinitdata = { | ||
799 | PCM_12_PLAYBACK_VOLUME, | ||
800 | PCM_34_PLAYBACK_VOLUME, | ||
801 | NULL | ||
802 | }; | ||
803 | |||
804 | static __devinitdata | ||
805 | DECLARE_TLV_DB_SCALE(qtet_master_db_scale, -6350, 50, 1); | ||
806 | |||
807 | static struct snd_kcontrol __devinit *ctl_find(struct snd_card *card, | ||
808 | const char *name) | ||
809 | { | ||
810 | struct snd_ctl_elem_id sid; | ||
811 | memset(&sid, 0, sizeof(sid)); | ||
812 | /* FIXME: strcpy is bad. */ | ||
813 | strcpy(sid.name, name); | ||
814 | sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER; | ||
815 | return snd_ctl_find_id(card, &sid); | ||
816 | } | ||
817 | |||
818 | static void __devinit add_slaves(struct snd_card *card, | ||
819 | struct snd_kcontrol *master, char **list) | ||
820 | { | ||
821 | for (; *list; list++) { | ||
822 | struct snd_kcontrol *slave = ctl_find(card, *list); | ||
823 | if (slave) | ||
824 | snd_ctl_add_slave(master, slave); | ||
825 | } | ||
826 | } | ||
827 | |||
828 | static int __devinit qtet_add_controls(struct snd_ice1712 *ice) | ||
829 | { | ||
830 | struct qtet_spec *spec = ice->spec; | ||
831 | int err, i; | ||
832 | struct snd_kcontrol *vmaster; | ||
833 | err = snd_ice1712_akm4xxx_build_controls(ice); | ||
834 | if (err < 0) | ||
835 | return err; | ||
836 | for (i = 0; i < ARRAY_SIZE(qtet_controls); i++) { | ||
837 | err = snd_ctl_add(ice->card, | ||
838 | snd_ctl_new1(&qtet_controls[i], ice)); | ||
839 | if (err < 0) | ||
840 | return err; | ||
841 | } | ||
842 | |||
843 | /* Create virtual master control */ | ||
844 | vmaster = snd_ctl_make_virtual_master("Master Playback Volume", | ||
845 | qtet_master_db_scale); | ||
846 | if (!vmaster) | ||
847 | return -ENOMEM; | ||
848 | add_slaves(ice->card, vmaster, slave_vols); | ||
849 | err = snd_ctl_add(ice->card, vmaster); | ||
850 | if (err < 0) | ||
851 | return err; | ||
852 | /* only capture SPDIF over AK4113 */ | ||
853 | err = snd_ak4113_build(spec->ak4113, | ||
854 | ice->pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream); | ||
855 | if (err < 0) | ||
856 | return err; | ||
857 | return 0; | ||
858 | } | ||
859 | |||
860 | static inline int qtet_is_spdif_master(struct snd_ice1712 *ice) | ||
861 | { | ||
862 | /* CPLD_SYNC_SEL: 0 = internal, 1 = external (i.e. spdif master) */ | ||
863 | return (get_cpld(ice) & CPLD_SYNC_SEL) ? 1 : 0; | ||
864 | } | ||
865 | |||
866 | static unsigned int qtet_get_rate(struct snd_ice1712 *ice) | ||
867 | { | ||
868 | int i; | ||
869 | unsigned char result; | ||
870 | |||
871 | result = get_cpld(ice) & CPLD_CKS_MASK; | ||
872 | for (i = 0; i < ARRAY_SIZE(cks_vals); i++) | ||
873 | if (cks_vals[i] == result) | ||
874 | return qtet_rates[i]; | ||
875 | return 0; | ||
876 | } | ||
877 | |||
878 | static int get_cks_val(int rate) | ||
879 | { | ||
880 | int i; | ||
881 | for (i = 0; i < ARRAY_SIZE(qtet_rates); i++) | ||
882 | if (qtet_rates[i] == rate) | ||
883 | return cks_vals[i]; | ||
884 | return 0; | ||
885 | } | ||
886 | |||
887 | /* setting new rate */ | ||
888 | static void qtet_set_rate(struct snd_ice1712 *ice, unsigned int rate) | ||
889 | { | ||
890 | unsigned int new; | ||
891 | unsigned char val; | ||
892 | /* switching ice1724 to external clock - supplied by ext. circuits */ | ||
893 | val = inb(ICEMT1724(ice, RATE)); | ||
894 | outb(val | VT1724_SPDIF_MASTER, ICEMT1724(ice, RATE)); | ||
895 | |||
896 | new = (get_cpld(ice) & ~CPLD_CKS_MASK) | get_cks_val(rate); | ||
897 | /* switch to internal clock, drop CPLD_SYNC_SEL */ | ||
898 | new &= ~CPLD_SYNC_SEL; | ||
899 | /* printk(KERN_DEBUG "QT - set_rate: old %x, new %x\n", | ||
900 | get_cpld(ice), new); */ | ||
901 | set_cpld(ice, new); | ||
902 | } | ||
903 | |||
904 | static inline unsigned char qtet_set_mclk(struct snd_ice1712 *ice, | ||
905 | unsigned int rate) | ||
906 | { | ||
907 | /* no change in master clock */ | ||
908 | return 0; | ||
909 | } | ||
910 | |||
911 | /* setting clock to external - SPDIF */ | ||
912 | static int qtet_set_spdif_clock(struct snd_ice1712 *ice, int type) | ||
913 | { | ||
914 | unsigned int old, new; | ||
915 | |||
916 | old = new = get_cpld(ice); | ||
917 | new &= ~(CPLD_CKS_MASK | CPLD_WORD_SEL); | ||
918 | switch (type) { | ||
919 | case EXT_SPDIF_TYPE: | ||
920 | new |= CPLD_EXT_SPDIF; | ||
921 | break; | ||
922 | case EXT_WORDCLOCK_1FS_TYPE: | ||
923 | new |= CPLD_EXT_WORDCLOCK_1FS; | ||
924 | break; | ||
925 | case EXT_WORDCLOCK_256FS_TYPE: | ||
926 | new |= CPLD_EXT_WORDCLOCK_256FS; | ||
927 | break; | ||
928 | default: | ||
929 | snd_BUG(); | ||
930 | } | ||
931 | if (old != new) { | ||
932 | set_cpld(ice, new); | ||
933 | /* changed */ | ||
934 | return 1; | ||
935 | } | ||
936 | return 0; | ||
937 | } | ||
938 | |||
939 | static int qtet_get_spdif_master_type(struct snd_ice1712 *ice) | ||
940 | { | ||
941 | unsigned int val; | ||
942 | int result; | ||
943 | val = get_cpld(ice); | ||
944 | /* checking only rate/clock-related bits */ | ||
945 | val &= (CPLD_CKS_MASK | CPLD_WORD_SEL | CPLD_SYNC_SEL); | ||
946 | if (!(val & CPLD_SYNC_SEL)) { | ||
947 | /* switched to internal clock, is not any external type */ | ||
948 | result = -1; | ||
949 | } else { | ||
950 | switch (val) { | ||
951 | case (CPLD_EXT_SPDIF): | ||
952 | result = EXT_SPDIF_TYPE; | ||
953 | break; | ||
954 | case (CPLD_EXT_WORDCLOCK_1FS): | ||
955 | result = EXT_WORDCLOCK_1FS_TYPE; | ||
956 | break; | ||
957 | case (CPLD_EXT_WORDCLOCK_256FS): | ||
958 | result = EXT_WORDCLOCK_256FS_TYPE; | ||
959 | break; | ||
960 | default: | ||
961 | /* undefined combination of external clock setup */ | ||
962 | snd_BUG(); | ||
963 | result = 0; | ||
964 | } | ||
965 | } | ||
966 | return result; | ||
967 | } | ||
968 | |||
969 | /* Called when ak4113 detects change in the input SPDIF stream */ | ||
970 | static void qtet_ak4113_change(struct ak4113 *ak4113, unsigned char c0, | ||
971 | unsigned char c1) | ||
972 | { | ||
973 | struct snd_ice1712 *ice = ak4113->change_callback_private; | ||
974 | int rate; | ||
975 | if ((qtet_get_spdif_master_type(ice) == EXT_SPDIF_TYPE) && | ||
976 | c1) { | ||
977 | /* only for SPDIF master mode, rate was changed */ | ||
978 | rate = snd_ak4113_external_rate(ak4113); | ||
979 | /* printk(KERN_DEBUG "ak4113 - input rate changed to %d\n", | ||
980 | rate); */ | ||
981 | qtet_akm_set_rate_val(ice->akm, rate); | ||
982 | } | ||
983 | } | ||
984 | |||
985 | /* | ||
986 | * If clock slaved to SPDIF-IN, setting runtime rate | ||
987 | * to the detected external rate | ||
988 | */ | ||
989 | static void qtet_spdif_in_open(struct snd_ice1712 *ice, | ||
990 | struct snd_pcm_substream *substream) | ||
991 | { | ||
992 | struct qtet_spec *spec = ice->spec; | ||
993 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
994 | int rate; | ||
995 | |||
996 | if (qtet_get_spdif_master_type(ice) != EXT_SPDIF_TYPE) | ||
997 | /* not external SPDIF, no rate limitation */ | ||
998 | return; | ||
999 | /* only external SPDIF can detect incoming sample rate */ | ||
1000 | rate = snd_ak4113_external_rate(spec->ak4113); | ||
1001 | if (rate >= runtime->hw.rate_min && rate <= runtime->hw.rate_max) { | ||
1002 | runtime->hw.rate_min = rate; | ||
1003 | runtime->hw.rate_max = rate; | ||
1004 | } | ||
1005 | } | ||
1006 | |||
1007 | /* | ||
1008 | * initialize the chip | ||
1009 | */ | ||
1010 | static int __devinit qtet_init(struct snd_ice1712 *ice) | ||
1011 | { | ||
1012 | static const unsigned char ak4113_init_vals[] = { | ||
1013 | /* AK4113_REG_PWRDN */ AK4113_RST | AK4113_PWN | | ||
1014 | AK4113_OCKS0 | AK4113_OCKS1, | ||
1015 | /* AK4113_REQ_FORMAT */ AK4113_DIF_I24I2S | AK4113_VTX | | ||
1016 | AK4113_DEM_OFF | AK4113_DEAU, | ||
1017 | /* AK4113_REG_IO0 */ AK4113_OPS2 | AK4113_TXE | | ||
1018 | AK4113_XTL_24_576M, | ||
1019 | /* AK4113_REG_IO1 */ AK4113_EFH_1024LRCLK | AK4113_IPS(0), | ||
1020 | /* AK4113_REG_INT0_MASK */ 0, | ||
1021 | /* AK4113_REG_INT1_MASK */ 0, | ||
1022 | /* AK4113_REG_DATDTS */ 0, | ||
1023 | }; | ||
1024 | int err; | ||
1025 | struct qtet_spec *spec; | ||
1026 | struct snd_akm4xxx *ak; | ||
1027 | unsigned char val; | ||
1028 | |||
1029 | /* switching ice1724 to external clock - supplied by ext. circuits */ | ||
1030 | val = inb(ICEMT1724(ice, RATE)); | ||
1031 | outb(val | VT1724_SPDIF_MASTER, ICEMT1724(ice, RATE)); | ||
1032 | |||
1033 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | ||
1034 | if (!spec) | ||
1035 | return -ENOMEM; | ||
1036 | /* qtet is clocked by Xilinx array */ | ||
1037 | ice->hw_rates = &qtet_rates_info; | ||
1038 | ice->is_spdif_master = qtet_is_spdif_master; | ||
1039 | ice->get_rate = qtet_get_rate; | ||
1040 | ice->set_rate = qtet_set_rate; | ||
1041 | ice->set_mclk = qtet_set_mclk; | ||
1042 | ice->set_spdif_clock = qtet_set_spdif_clock; | ||
1043 | ice->get_spdif_master_type = qtet_get_spdif_master_type; | ||
1044 | ice->ext_clock_names = ext_clock_names; | ||
1045 | ice->ext_clock_count = ARRAY_SIZE(ext_clock_names); | ||
1046 | /* since Qtet can detect correct SPDIF-in rate, all streams can be | ||
1047 | * limited to this specific rate */ | ||
1048 | ice->spdif.ops.open = ice->pro_open = qtet_spdif_in_open; | ||
1049 | ice->spec = spec; | ||
1050 | |||
1051 | /* Mute Off */ | ||
1052 | /* SCR Initialize*/ | ||
1053 | /* keep codec power down first */ | ||
1054 | set_scr(ice, SCR_PHP); | ||
1055 | udelay(1); | ||
1056 | /* codec power up */ | ||
1057 | set_scr(ice, SCR_PHP | SCR_CODEC_PDN); | ||
1058 | |||
1059 | /* MCR Initialize */ | ||
1060 | set_mcr(ice, 0); | ||
1061 | |||
1062 | /* CPLD Initialize */ | ||
1063 | set_cpld(ice, 0); | ||
1064 | |||
1065 | |||
1066 | ice->num_total_dacs = 2; | ||
1067 | ice->num_total_adcs = 2; | ||
1068 | |||
1069 | ice->akm = kcalloc(2, sizeof(struct snd_akm4xxx), GFP_KERNEL); | ||
1070 | ak = ice->akm; | ||
1071 | if (!ak) | ||
1072 | return -ENOMEM; | ||
1073 | /* only one codec with two chips */ | ||
1074 | ice->akm_codecs = 1; | ||
1075 | err = snd_ice1712_akm4xxx_init(ak, &akm_qtet_dac, NULL, ice); | ||
1076 | if (err < 0) | ||
1077 | return err; | ||
1078 | err = snd_ak4113_create(ice->card, | ||
1079 | qtet_ak4113_read, | ||
1080 | qtet_ak4113_write, | ||
1081 | ak4113_init_vals, | ||
1082 | ice, &spec->ak4113); | ||
1083 | if (err < 0) | ||
1084 | return err; | ||
1085 | /* callback for codecs rate setting */ | ||
1086 | spec->ak4113->change_callback = qtet_ak4113_change; | ||
1087 | spec->ak4113->change_callback_private = ice; | ||
1088 | /* AK41143 in Quartet can detect external rate correctly | ||
1089 | * (i.e. check_flags = 0) */ | ||
1090 | spec->ak4113->check_flags = 0; | ||
1091 | |||
1092 | proc_init(ice); | ||
1093 | |||
1094 | qtet_set_rate(ice, 44100); | ||
1095 | return 0; | ||
1096 | } | ||
1097 | |||
1098 | static unsigned char qtet_eeprom[] __devinitdata = { | ||
1099 | [ICE_EEP2_SYSCONF] = 0x28, /* clock 256(24MHz), mpu401, 1xADC, | ||
1100 | 1xDACs, SPDIF in */ | ||
1101 | [ICE_EEP2_ACLINK] = 0x80, /* I2S */ | ||
1102 | [ICE_EEP2_I2S] = 0x78, /* 96k, 24bit, 192k */ | ||
1103 | [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, in, out-ext */ | ||
1104 | [ICE_EEP2_GPIO_DIR] = 0x00, /* 0-7 inputs, switched to output | ||
1105 | only during output operations */ | ||
1106 | [ICE_EEP2_GPIO_DIR1] = 0xff, /* 8-15 outputs */ | ||
1107 | [ICE_EEP2_GPIO_DIR2] = 0x00, | ||
1108 | [ICE_EEP2_GPIO_MASK] = 0xff, /* changed only for OUT operations */ | ||
1109 | [ICE_EEP2_GPIO_MASK1] = 0x00, | ||
1110 | [ICE_EEP2_GPIO_MASK2] = 0xff, | ||
1111 | |||
1112 | [ICE_EEP2_GPIO_STATE] = 0x00, /* inputs */ | ||
1113 | [ICE_EEP2_GPIO_STATE1] = 0x7d, /* all 1, but GPIO_CPLD_RW | ||
1114 | and GPIO15 always zero */ | ||
1115 | [ICE_EEP2_GPIO_STATE2] = 0x00, /* inputs */ | ||
1116 | }; | ||
1117 | |||
1118 | /* entry point */ | ||
1119 | struct snd_ice1712_card_info snd_vt1724_qtet_cards[] __devinitdata = { | ||
1120 | { | ||
1121 | .subvendor = VT1724_SUBDEVICE_QTET, | ||
1122 | .name = "Infrasonic Quartet", | ||
1123 | .model = "quartet", | ||
1124 | .chip_init = qtet_init, | ||
1125 | .build_controls = qtet_add_controls, | ||
1126 | .eeprom_size = sizeof(qtet_eeprom), | ||
1127 | .eeprom_data = qtet_eeprom, | ||
1128 | }, | ||
1129 | { } /* terminator */ | ||
1130 | }; | ||
diff --git a/sound/pci/ice1712/quartet.h b/sound/pci/ice1712/quartet.h new file mode 100644 index 000000000000..80809b72439a --- /dev/null +++ b/sound/pci/ice1712/quartet.h | |||
@@ -0,0 +1,10 @@ | |||
1 | #ifndef __SOUND_QTET_H | ||
2 | #define __SOUND_QTET_H | ||
3 | |||
4 | #define QTET_DEVICE_DESC "{Infrasonic,Quartet}," | ||
5 | |||
6 | #define VT1724_SUBDEVICE_QTET 0x30305349 /* Infrasonic Quartet */ | ||
7 | |||
8 | extern struct snd_ice1712_card_info snd_vt1724_qtet_cards[]; | ||
9 | |||
10 | #endif /* __SOUND_QTET_H */ | ||