diff options
Diffstat (limited to 'sound/isa/ad1848/ad1848_lib.c')
-rw-r--r-- | sound/isa/ad1848/ad1848_lib.c | 1267 |
1 files changed, 0 insertions, 1267 deletions
diff --git a/sound/isa/ad1848/ad1848_lib.c b/sound/isa/ad1848/ad1848_lib.c deleted file mode 100644 index 630c90f9ee50..000000000000 --- a/sound/isa/ad1848/ad1848_lib.c +++ /dev/null | |||
@@ -1,1267 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (c) by Jaroslav Kysela <perex@perex.cz> | ||
3 | * Routines for control of AD1848/AD1847/CS4248 | ||
4 | * | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #define SNDRV_MAIN_OBJECT_FILE | ||
23 | #include <linux/delay.h> | ||
24 | #include <linux/init.h> | ||
25 | #include <linux/interrupt.h> | ||
26 | #include <linux/slab.h> | ||
27 | #include <linux/ioport.h> | ||
28 | #include <sound/core.h> | ||
29 | #include <sound/ad1848.h> | ||
30 | #include <sound/control.h> | ||
31 | #include <sound/tlv.h> | ||
32 | #include <sound/pcm_params.h> | ||
33 | |||
34 | #include <asm/io.h> | ||
35 | #include <asm/dma.h> | ||
36 | |||
37 | MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); | ||
38 | MODULE_DESCRIPTION("Routines for control of AD1848/AD1847/CS4248"); | ||
39 | MODULE_LICENSE("GPL"); | ||
40 | |||
41 | #if 0 | ||
42 | #define SNDRV_DEBUG_MCE | ||
43 | #endif | ||
44 | |||
45 | /* | ||
46 | * Some variables | ||
47 | */ | ||
48 | |||
49 | static unsigned char freq_bits[14] = { | ||
50 | /* 5510 */ 0x00 | AD1848_XTAL2, | ||
51 | /* 6620 */ 0x0E | AD1848_XTAL2, | ||
52 | /* 8000 */ 0x00 | AD1848_XTAL1, | ||
53 | /* 9600 */ 0x0E | AD1848_XTAL1, | ||
54 | /* 11025 */ 0x02 | AD1848_XTAL2, | ||
55 | /* 16000 */ 0x02 | AD1848_XTAL1, | ||
56 | /* 18900 */ 0x04 | AD1848_XTAL2, | ||
57 | /* 22050 */ 0x06 | AD1848_XTAL2, | ||
58 | /* 27042 */ 0x04 | AD1848_XTAL1, | ||
59 | /* 32000 */ 0x06 | AD1848_XTAL1, | ||
60 | /* 33075 */ 0x0C | AD1848_XTAL2, | ||
61 | /* 37800 */ 0x08 | AD1848_XTAL2, | ||
62 | /* 44100 */ 0x0A | AD1848_XTAL2, | ||
63 | /* 48000 */ 0x0C | AD1848_XTAL1 | ||
64 | }; | ||
65 | |||
66 | static unsigned int rates[14] = { | ||
67 | 5510, 6620, 8000, 9600, 11025, 16000, 18900, 22050, | ||
68 | 27042, 32000, 33075, 37800, 44100, 48000 | ||
69 | }; | ||
70 | |||
71 | static struct snd_pcm_hw_constraint_list hw_constraints_rates = { | ||
72 | .count = ARRAY_SIZE(rates), | ||
73 | .list = rates, | ||
74 | .mask = 0, | ||
75 | }; | ||
76 | |||
77 | static unsigned char snd_ad1848_original_image[16] = | ||
78 | { | ||
79 | 0x00, /* 00 - lic */ | ||
80 | 0x00, /* 01 - ric */ | ||
81 | 0x9f, /* 02 - la1ic */ | ||
82 | 0x9f, /* 03 - ra1ic */ | ||
83 | 0x9f, /* 04 - la2ic */ | ||
84 | 0x9f, /* 05 - ra2ic */ | ||
85 | 0xbf, /* 06 - loc */ | ||
86 | 0xbf, /* 07 - roc */ | ||
87 | 0x20, /* 08 - dfr */ | ||
88 | AD1848_AUTOCALIB, /* 09 - ic */ | ||
89 | 0x00, /* 0a - pc */ | ||
90 | 0x00, /* 0b - ti */ | ||
91 | 0x00, /* 0c - mi */ | ||
92 | 0x00, /* 0d - lbc */ | ||
93 | 0x00, /* 0e - dru */ | ||
94 | 0x00, /* 0f - drl */ | ||
95 | }; | ||
96 | |||
97 | /* | ||
98 | * Basic I/O functions | ||
99 | */ | ||
100 | |||
101 | static void snd_ad1848_wait(struct snd_ad1848 *chip) | ||
102 | { | ||
103 | int timeout; | ||
104 | |||
105 | for (timeout = 250; timeout > 0; timeout--) { | ||
106 | if ((inb(AD1848P(chip, REGSEL)) & AD1848_INIT) == 0) | ||
107 | break; | ||
108 | udelay(100); | ||
109 | } | ||
110 | } | ||
111 | |||
112 | void snd_ad1848_out(struct snd_ad1848 *chip, | ||
113 | unsigned char reg, | ||
114 | unsigned char value) | ||
115 | { | ||
116 | snd_ad1848_wait(chip); | ||
117 | #ifdef CONFIG_SND_DEBUG | ||
118 | if (inb(AD1848P(chip, REGSEL)) & AD1848_INIT) | ||
119 | snd_printk(KERN_WARNING "auto calibration time out - " | ||
120 | "reg = 0x%x, value = 0x%x\n", reg, value); | ||
121 | #endif | ||
122 | outb(chip->mce_bit | reg, AD1848P(chip, REGSEL)); | ||
123 | outb(chip->image[reg] = value, AD1848P(chip, REG)); | ||
124 | mb(); | ||
125 | snd_printdd("codec out - reg 0x%x = 0x%x\n", | ||
126 | chip->mce_bit | reg, value); | ||
127 | } | ||
128 | |||
129 | EXPORT_SYMBOL(snd_ad1848_out); | ||
130 | |||
131 | static void snd_ad1848_dout(struct snd_ad1848 *chip, | ||
132 | unsigned char reg, unsigned char value) | ||
133 | { | ||
134 | snd_ad1848_wait(chip); | ||
135 | outb(chip->mce_bit | reg, AD1848P(chip, REGSEL)); | ||
136 | outb(value, AD1848P(chip, REG)); | ||
137 | mb(); | ||
138 | } | ||
139 | |||
140 | static unsigned char snd_ad1848_in(struct snd_ad1848 *chip, unsigned char reg) | ||
141 | { | ||
142 | snd_ad1848_wait(chip); | ||
143 | #ifdef CONFIG_SND_DEBUG | ||
144 | if (inb(AD1848P(chip, REGSEL)) & AD1848_INIT) | ||
145 | snd_printk(KERN_WARNING "auto calibration time out - " | ||
146 | "reg = 0x%x\n", reg); | ||
147 | #endif | ||
148 | outb(chip->mce_bit | reg, AD1848P(chip, REGSEL)); | ||
149 | mb(); | ||
150 | return inb(AD1848P(chip, REG)); | ||
151 | } | ||
152 | |||
153 | #if 0 | ||
154 | |||
155 | static void snd_ad1848_debug(struct snd_ad1848 *chip) | ||
156 | { | ||
157 | printk("AD1848 REGS: INDEX = 0x%02x ", inb(AD1848P(chip, REGSEL))); | ||
158 | printk(" STATUS = 0x%02x\n", inb(AD1848P(chip, STATUS))); | ||
159 | printk(" 0x00: left input = 0x%02x ", snd_ad1848_in(chip, 0x00)); | ||
160 | printk(" 0x08: playback format = 0x%02x\n", snd_ad1848_in(chip, 0x08)); | ||
161 | printk(" 0x01: right input = 0x%02x ", snd_ad1848_in(chip, 0x01)); | ||
162 | printk(" 0x09: iface (CFIG 1) = 0x%02x\n", snd_ad1848_in(chip, 0x09)); | ||
163 | printk(" 0x02: AUXA left = 0x%02x ", snd_ad1848_in(chip, 0x02)); | ||
164 | printk(" 0x0a: pin control = 0x%02x\n", snd_ad1848_in(chip, 0x0a)); | ||
165 | printk(" 0x03: AUXA right = 0x%02x ", snd_ad1848_in(chip, 0x03)); | ||
166 | printk(" 0x0b: init & status = 0x%02x\n", snd_ad1848_in(chip, 0x0b)); | ||
167 | printk(" 0x04: AUXB left = 0x%02x ", snd_ad1848_in(chip, 0x04)); | ||
168 | printk(" 0x0c: revision & mode = 0x%02x\n", snd_ad1848_in(chip, 0x0c)); | ||
169 | printk(" 0x05: AUXB right = 0x%02x ", snd_ad1848_in(chip, 0x05)); | ||
170 | printk(" 0x0d: loopback = 0x%02x\n", snd_ad1848_in(chip, 0x0d)); | ||
171 | printk(" 0x06: left output = 0x%02x ", snd_ad1848_in(chip, 0x06)); | ||
172 | printk(" 0x0e: data upr count = 0x%02x\n", snd_ad1848_in(chip, 0x0e)); | ||
173 | printk(" 0x07: right output = 0x%02x ", snd_ad1848_in(chip, 0x07)); | ||
174 | printk(" 0x0f: data lwr count = 0x%02x\n", snd_ad1848_in(chip, 0x0f)); | ||
175 | } | ||
176 | |||
177 | #endif | ||
178 | |||
179 | /* | ||
180 | * AD1848 detection / MCE routines | ||
181 | */ | ||
182 | |||
183 | static void snd_ad1848_mce_up(struct snd_ad1848 *chip) | ||
184 | { | ||
185 | unsigned long flags; | ||
186 | int timeout; | ||
187 | |||
188 | snd_ad1848_wait(chip); | ||
189 | #ifdef CONFIG_SND_DEBUG | ||
190 | if (inb(AD1848P(chip, REGSEL)) & AD1848_INIT) | ||
191 | snd_printk(KERN_WARNING "mce_up - auto calibration time out (0)\n"); | ||
192 | #endif | ||
193 | spin_lock_irqsave(&chip->reg_lock, flags); | ||
194 | chip->mce_bit |= AD1848_MCE; | ||
195 | timeout = inb(AD1848P(chip, REGSEL)); | ||
196 | if (timeout == 0x80) | ||
197 | snd_printk(KERN_WARNING "mce_up [0x%lx]: serious init problem - codec still busy\n", chip->port); | ||
198 | if (!(timeout & AD1848_MCE)) | ||
199 | outb(chip->mce_bit | (timeout & 0x1f), AD1848P(chip, REGSEL)); | ||
200 | spin_unlock_irqrestore(&chip->reg_lock, flags); | ||
201 | } | ||
202 | |||
203 | static void snd_ad1848_mce_down(struct snd_ad1848 *chip) | ||
204 | { | ||
205 | unsigned long flags, timeout; | ||
206 | int reg; | ||
207 | |||
208 | spin_lock_irqsave(&chip->reg_lock, flags); | ||
209 | for (timeout = 5; timeout > 0; timeout--) | ||
210 | inb(AD1848P(chip, REGSEL)); | ||
211 | /* end of cleanup sequence */ | ||
212 | for (timeout = 12000; timeout > 0 && (inb(AD1848P(chip, REGSEL)) & AD1848_INIT); timeout--) | ||
213 | udelay(100); | ||
214 | |||
215 | snd_printdd("(1) timeout = %ld\n", timeout); | ||
216 | |||
217 | #ifdef CONFIG_SND_DEBUG | ||
218 | if (inb(AD1848P(chip, REGSEL)) & AD1848_INIT) | ||
219 | snd_printk(KERN_WARNING "mce_down [0x%lx] - auto calibration time out (0)\n", AD1848P(chip, REGSEL)); | ||
220 | #endif | ||
221 | |||
222 | chip->mce_bit &= ~AD1848_MCE; | ||
223 | reg = inb(AD1848P(chip, REGSEL)); | ||
224 | outb(chip->mce_bit | (reg & 0x1f), AD1848P(chip, REGSEL)); | ||
225 | if (reg == 0x80) | ||
226 | snd_printk(KERN_WARNING "mce_down [0x%lx]: serious init problem - codec still busy\n", chip->port); | ||
227 | if ((reg & AD1848_MCE) == 0) { | ||
228 | spin_unlock_irqrestore(&chip->reg_lock, flags); | ||
229 | return; | ||
230 | } | ||
231 | |||
232 | /* | ||
233 | * Wait for auto-calibration (AC) process to finish, i.e. ACI to go low. | ||
234 | * It may take up to 5 sample periods (at most 907 us @ 5.5125 kHz) for | ||
235 | * the process to _start_, so it is important to wait at least that long | ||
236 | * before checking. Otherwise we might think AC has finished when it | ||
237 | * has in fact not begun. It could take 128 (no AC) or 384 (AC) cycles | ||
238 | * for ACI to drop. This gives a wait of at most 70 ms with a more | ||
239 | * typical value of 3-9 ms. | ||
240 | */ | ||
241 | timeout = jiffies + msecs_to_jiffies(250); | ||
242 | do { | ||
243 | spin_unlock_irqrestore(&chip->reg_lock, flags); | ||
244 | msleep(1); | ||
245 | spin_lock_irqsave(&chip->reg_lock, flags); | ||
246 | reg = snd_ad1848_in(chip, AD1848_TEST_INIT) & | ||
247 | AD1848_CALIB_IN_PROGRESS; | ||
248 | } while (reg && time_before(jiffies, timeout)); | ||
249 | spin_unlock_irqrestore(&chip->reg_lock, flags); | ||
250 | if (reg) | ||
251 | snd_printk(KERN_ERR | ||
252 | "mce_down - auto calibration time out (2)\n"); | ||
253 | |||
254 | snd_printdd("(4) jiffies = %lu\n", jiffies); | ||
255 | snd_printd("mce_down - exit = 0x%x\n", inb(AD1848P(chip, REGSEL))); | ||
256 | } | ||
257 | |||
258 | static unsigned int snd_ad1848_get_count(unsigned char format, | ||
259 | unsigned int size) | ||
260 | { | ||
261 | switch (format & 0xe0) { | ||
262 | case AD1848_LINEAR_16: | ||
263 | size >>= 1; | ||
264 | break; | ||
265 | } | ||
266 | if (format & AD1848_STEREO) | ||
267 | size >>= 1; | ||
268 | return size; | ||
269 | } | ||
270 | |||
271 | static int snd_ad1848_trigger(struct snd_ad1848 *chip, unsigned char what, | ||
272 | int channel, int cmd) | ||
273 | { | ||
274 | int result = 0; | ||
275 | |||
276 | #if 0 | ||
277 | printk("codec trigger!!! - what = %i, enable = %i, status = 0x%x\n", what, enable, inb(AD1848P(card, STATUS))); | ||
278 | #endif | ||
279 | spin_lock(&chip->reg_lock); | ||
280 | if (cmd == SNDRV_PCM_TRIGGER_START) { | ||
281 | if (chip->image[AD1848_IFACE_CTRL] & what) { | ||
282 | spin_unlock(&chip->reg_lock); | ||
283 | return 0; | ||
284 | } | ||
285 | snd_ad1848_out(chip, AD1848_IFACE_CTRL, chip->image[AD1848_IFACE_CTRL] |= what); | ||
286 | chip->mode |= AD1848_MODE_RUNNING; | ||
287 | } else if (cmd == SNDRV_PCM_TRIGGER_STOP) { | ||
288 | if (!(chip->image[AD1848_IFACE_CTRL] & what)) { | ||
289 | spin_unlock(&chip->reg_lock); | ||
290 | return 0; | ||
291 | } | ||
292 | snd_ad1848_out(chip, AD1848_IFACE_CTRL, chip->image[AD1848_IFACE_CTRL] &= ~what); | ||
293 | chip->mode &= ~AD1848_MODE_RUNNING; | ||
294 | } else { | ||
295 | result = -EINVAL; | ||
296 | } | ||
297 | spin_unlock(&chip->reg_lock); | ||
298 | return result; | ||
299 | } | ||
300 | |||
301 | /* | ||
302 | * CODEC I/O | ||
303 | */ | ||
304 | |||
305 | static unsigned char snd_ad1848_get_rate(unsigned int rate) | ||
306 | { | ||
307 | int i; | ||
308 | |||
309 | for (i = 0; i < ARRAY_SIZE(rates); i++) | ||
310 | if (rate == rates[i]) | ||
311 | return freq_bits[i]; | ||
312 | snd_BUG(); | ||
313 | return freq_bits[ARRAY_SIZE(rates) - 1]; | ||
314 | } | ||
315 | |||
316 | static int snd_ad1848_ioctl(struct snd_pcm_substream *substream, | ||
317 | unsigned int cmd, void *arg) | ||
318 | { | ||
319 | return snd_pcm_lib_ioctl(substream, cmd, arg); | ||
320 | } | ||
321 | |||
322 | static unsigned char snd_ad1848_get_format(int format, int channels) | ||
323 | { | ||
324 | unsigned char rformat; | ||
325 | |||
326 | rformat = AD1848_LINEAR_8; | ||
327 | switch (format) { | ||
328 | case SNDRV_PCM_FORMAT_A_LAW: rformat = AD1848_ALAW_8; break; | ||
329 | case SNDRV_PCM_FORMAT_MU_LAW: rformat = AD1848_ULAW_8; break; | ||
330 | case SNDRV_PCM_FORMAT_S16_LE: rformat = AD1848_LINEAR_16; break; | ||
331 | } | ||
332 | if (channels > 1) | ||
333 | rformat |= AD1848_STEREO; | ||
334 | #if 0 | ||
335 | snd_printk("get_format: 0x%x (mode=0x%x)\n", format, mode); | ||
336 | #endif | ||
337 | return rformat; | ||
338 | } | ||
339 | |||
340 | static void snd_ad1848_calibrate_mute(struct snd_ad1848 *chip, int mute) | ||
341 | { | ||
342 | unsigned long flags; | ||
343 | |||
344 | mute = mute ? 1 : 0; | ||
345 | spin_lock_irqsave(&chip->reg_lock, flags); | ||
346 | if (chip->calibrate_mute == mute) { | ||
347 | spin_unlock_irqrestore(&chip->reg_lock, flags); | ||
348 | return; | ||
349 | } | ||
350 | if (!mute) { | ||
351 | snd_ad1848_dout(chip, AD1848_LEFT_INPUT, chip->image[AD1848_LEFT_INPUT]); | ||
352 | snd_ad1848_dout(chip, AD1848_RIGHT_INPUT, chip->image[AD1848_RIGHT_INPUT]); | ||
353 | } | ||
354 | snd_ad1848_dout(chip, AD1848_AUX1_LEFT_INPUT, mute ? 0x80 : chip->image[AD1848_AUX1_LEFT_INPUT]); | ||
355 | snd_ad1848_dout(chip, AD1848_AUX1_RIGHT_INPUT, mute ? 0x80 : chip->image[AD1848_AUX1_RIGHT_INPUT]); | ||
356 | snd_ad1848_dout(chip, AD1848_AUX2_LEFT_INPUT, mute ? 0x80 : chip->image[AD1848_AUX2_LEFT_INPUT]); | ||
357 | snd_ad1848_dout(chip, AD1848_AUX2_RIGHT_INPUT, mute ? 0x80 : chip->image[AD1848_AUX2_RIGHT_INPUT]); | ||
358 | snd_ad1848_dout(chip, AD1848_LEFT_OUTPUT, mute ? 0x80 : chip->image[AD1848_LEFT_OUTPUT]); | ||
359 | snd_ad1848_dout(chip, AD1848_RIGHT_OUTPUT, mute ? 0x80 : chip->image[AD1848_RIGHT_OUTPUT]); | ||
360 | chip->calibrate_mute = mute; | ||
361 | spin_unlock_irqrestore(&chip->reg_lock, flags); | ||
362 | } | ||
363 | |||
364 | static void snd_ad1848_set_data_format(struct snd_ad1848 *chip, struct snd_pcm_hw_params *hw_params) | ||
365 | { | ||
366 | if (hw_params == NULL) { | ||
367 | chip->image[AD1848_DATA_FORMAT] = 0x20; | ||
368 | } else { | ||
369 | chip->image[AD1848_DATA_FORMAT] = | ||
370 | snd_ad1848_get_format(params_format(hw_params), params_channels(hw_params)) | | ||
371 | snd_ad1848_get_rate(params_rate(hw_params)); | ||
372 | } | ||
373 | // snd_printk(">>> pmode = 0x%x, dfr = 0x%x\n", pstr->mode, chip->image[AD1848_DATA_FORMAT]); | ||
374 | } | ||
375 | |||
376 | static int snd_ad1848_open(struct snd_ad1848 *chip, unsigned int mode) | ||
377 | { | ||
378 | unsigned long flags; | ||
379 | |||
380 | if (chip->mode & AD1848_MODE_OPEN) | ||
381 | return -EAGAIN; | ||
382 | |||
383 | snd_ad1848_mce_down(chip); | ||
384 | |||
385 | #ifdef SNDRV_DEBUG_MCE | ||
386 | snd_printk("open: (1)\n"); | ||
387 | #endif | ||
388 | snd_ad1848_mce_up(chip); | ||
389 | spin_lock_irqsave(&chip->reg_lock, flags); | ||
390 | chip->image[AD1848_IFACE_CTRL] &= ~(AD1848_PLAYBACK_ENABLE | AD1848_PLAYBACK_PIO | | ||
391 | AD1848_CAPTURE_ENABLE | AD1848_CAPTURE_PIO | | ||
392 | AD1848_CALIB_MODE); | ||
393 | chip->image[AD1848_IFACE_CTRL] |= AD1848_AUTOCALIB; | ||
394 | snd_ad1848_out(chip, AD1848_IFACE_CTRL, chip->image[AD1848_IFACE_CTRL]); | ||
395 | spin_unlock_irqrestore(&chip->reg_lock, flags); | ||
396 | snd_ad1848_mce_down(chip); | ||
397 | |||
398 | #ifdef SNDRV_DEBUG_MCE | ||
399 | snd_printk("open: (2)\n"); | ||
400 | #endif | ||
401 | |||
402 | snd_ad1848_set_data_format(chip, NULL); | ||
403 | |||
404 | snd_ad1848_mce_up(chip); | ||
405 | spin_lock_irqsave(&chip->reg_lock, flags); | ||
406 | snd_ad1848_out(chip, AD1848_DATA_FORMAT, chip->image[AD1848_DATA_FORMAT]); | ||
407 | spin_unlock_irqrestore(&chip->reg_lock, flags); | ||
408 | snd_ad1848_mce_down(chip); | ||
409 | |||
410 | #ifdef SNDRV_DEBUG_MCE | ||
411 | snd_printk("open: (3)\n"); | ||
412 | #endif | ||
413 | |||
414 | /* ok. now enable and ack CODEC IRQ */ | ||
415 | spin_lock_irqsave(&chip->reg_lock, flags); | ||
416 | outb(0, AD1848P(chip, STATUS)); /* clear IRQ */ | ||
417 | outb(0, AD1848P(chip, STATUS)); /* clear IRQ */ | ||
418 | chip->image[AD1848_PIN_CTRL] |= AD1848_IRQ_ENABLE; | ||
419 | snd_ad1848_out(chip, AD1848_PIN_CTRL, chip->image[AD1848_PIN_CTRL]); | ||
420 | spin_unlock_irqrestore(&chip->reg_lock, flags); | ||
421 | |||
422 | chip->mode = mode; | ||
423 | |||
424 | return 0; | ||
425 | } | ||
426 | |||
427 | static void snd_ad1848_close(struct snd_ad1848 *chip) | ||
428 | { | ||
429 | unsigned long flags; | ||
430 | |||
431 | if (!chip->mode) | ||
432 | return; | ||
433 | /* disable IRQ */ | ||
434 | spin_lock_irqsave(&chip->reg_lock, flags); | ||
435 | outb(0, AD1848P(chip, STATUS)); /* clear IRQ */ | ||
436 | outb(0, AD1848P(chip, STATUS)); /* clear IRQ */ | ||
437 | chip->image[AD1848_PIN_CTRL] &= ~AD1848_IRQ_ENABLE; | ||
438 | snd_ad1848_out(chip, AD1848_PIN_CTRL, chip->image[AD1848_PIN_CTRL]); | ||
439 | spin_unlock_irqrestore(&chip->reg_lock, flags); | ||
440 | |||
441 | /* now disable capture & playback */ | ||
442 | |||
443 | snd_ad1848_mce_up(chip); | ||
444 | spin_lock_irqsave(&chip->reg_lock, flags); | ||
445 | chip->image[AD1848_IFACE_CTRL] &= ~(AD1848_PLAYBACK_ENABLE | AD1848_PLAYBACK_PIO | | ||
446 | AD1848_CAPTURE_ENABLE | AD1848_CAPTURE_PIO); | ||
447 | snd_ad1848_out(chip, AD1848_IFACE_CTRL, chip->image[AD1848_IFACE_CTRL]); | ||
448 | spin_unlock_irqrestore(&chip->reg_lock, flags); | ||
449 | snd_ad1848_mce_down(chip); | ||
450 | |||
451 | /* clear IRQ again */ | ||
452 | spin_lock_irqsave(&chip->reg_lock, flags); | ||
453 | outb(0, AD1848P(chip, STATUS)); /* clear IRQ */ | ||
454 | outb(0, AD1848P(chip, STATUS)); /* clear IRQ */ | ||
455 | spin_unlock_irqrestore(&chip->reg_lock, flags); | ||
456 | |||
457 | chip->mode = 0; | ||
458 | } | ||
459 | |||
460 | /* | ||
461 | * ok.. exported functions.. | ||
462 | */ | ||
463 | |||
464 | static int snd_ad1848_playback_trigger(struct snd_pcm_substream *substream, | ||
465 | int cmd) | ||
466 | { | ||
467 | struct snd_ad1848 *chip = snd_pcm_substream_chip(substream); | ||
468 | return snd_ad1848_trigger(chip, AD1848_PLAYBACK_ENABLE, SNDRV_PCM_STREAM_PLAYBACK, cmd); | ||
469 | } | ||
470 | |||
471 | static int snd_ad1848_capture_trigger(struct snd_pcm_substream *substream, | ||
472 | int cmd) | ||
473 | { | ||
474 | struct snd_ad1848 *chip = snd_pcm_substream_chip(substream); | ||
475 | return snd_ad1848_trigger(chip, AD1848_CAPTURE_ENABLE, SNDRV_PCM_STREAM_CAPTURE, cmd); | ||
476 | } | ||
477 | |||
478 | static int snd_ad1848_playback_hw_params(struct snd_pcm_substream *substream, | ||
479 | struct snd_pcm_hw_params *hw_params) | ||
480 | { | ||
481 | struct snd_ad1848 *chip = snd_pcm_substream_chip(substream); | ||
482 | unsigned long flags; | ||
483 | int err; | ||
484 | |||
485 | if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0) | ||
486 | return err; | ||
487 | snd_ad1848_calibrate_mute(chip, 1); | ||
488 | snd_ad1848_set_data_format(chip, hw_params); | ||
489 | snd_ad1848_mce_up(chip); | ||
490 | spin_lock_irqsave(&chip->reg_lock, flags); | ||
491 | snd_ad1848_out(chip, AD1848_DATA_FORMAT, chip->image[AD1848_DATA_FORMAT]); | ||
492 | spin_unlock_irqrestore(&chip->reg_lock, flags); | ||
493 | snd_ad1848_mce_down(chip); | ||
494 | snd_ad1848_calibrate_mute(chip, 0); | ||
495 | return 0; | ||
496 | } | ||
497 | |||
498 | static int snd_ad1848_playback_hw_free(struct snd_pcm_substream *substream) | ||
499 | { | ||
500 | return snd_pcm_lib_free_pages(substream); | ||
501 | } | ||
502 | |||
503 | static int snd_ad1848_playback_prepare(struct snd_pcm_substream *substream) | ||
504 | { | ||
505 | struct snd_ad1848 *chip = snd_pcm_substream_chip(substream); | ||
506 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
507 | unsigned long flags; | ||
508 | unsigned int size = snd_pcm_lib_buffer_bytes(substream); | ||
509 | unsigned int count = snd_pcm_lib_period_bytes(substream); | ||
510 | |||
511 | chip->dma_size = size; | ||
512 | chip->image[AD1848_IFACE_CTRL] &= ~(AD1848_PLAYBACK_ENABLE | AD1848_PLAYBACK_PIO); | ||
513 | snd_dma_program(chip->dma, runtime->dma_addr, size, DMA_MODE_WRITE | DMA_AUTOINIT); | ||
514 | count = snd_ad1848_get_count(chip->image[AD1848_DATA_FORMAT], count) - 1; | ||
515 | spin_lock_irqsave(&chip->reg_lock, flags); | ||
516 | snd_ad1848_out(chip, AD1848_DATA_LWR_CNT, (unsigned char) count); | ||
517 | snd_ad1848_out(chip, AD1848_DATA_UPR_CNT, (unsigned char) (count >> 8)); | ||
518 | spin_unlock_irqrestore(&chip->reg_lock, flags); | ||
519 | return 0; | ||
520 | } | ||
521 | |||
522 | static int snd_ad1848_capture_hw_params(struct snd_pcm_substream *substream, | ||
523 | struct snd_pcm_hw_params *hw_params) | ||
524 | { | ||
525 | struct snd_ad1848 *chip = snd_pcm_substream_chip(substream); | ||
526 | unsigned long flags; | ||
527 | int err; | ||
528 | |||
529 | if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0) | ||
530 | return err; | ||
531 | snd_ad1848_calibrate_mute(chip, 1); | ||
532 | snd_ad1848_set_data_format(chip, hw_params); | ||
533 | snd_ad1848_mce_up(chip); | ||
534 | spin_lock_irqsave(&chip->reg_lock, flags); | ||
535 | snd_ad1848_out(chip, AD1848_DATA_FORMAT, chip->image[AD1848_DATA_FORMAT]); | ||
536 | spin_unlock_irqrestore(&chip->reg_lock, flags); | ||
537 | snd_ad1848_mce_down(chip); | ||
538 | snd_ad1848_calibrate_mute(chip, 0); | ||
539 | return 0; | ||
540 | } | ||
541 | |||
542 | static int snd_ad1848_capture_hw_free(struct snd_pcm_substream *substream) | ||
543 | { | ||
544 | return snd_pcm_lib_free_pages(substream); | ||
545 | } | ||
546 | |||
547 | static int snd_ad1848_capture_prepare(struct snd_pcm_substream *substream) | ||
548 | { | ||
549 | struct snd_ad1848 *chip = snd_pcm_substream_chip(substream); | ||
550 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
551 | unsigned long flags; | ||
552 | unsigned int size = snd_pcm_lib_buffer_bytes(substream); | ||
553 | unsigned int count = snd_pcm_lib_period_bytes(substream); | ||
554 | |||
555 | chip->dma_size = size; | ||
556 | chip->image[AD1848_IFACE_CTRL] &= ~(AD1848_CAPTURE_ENABLE | AD1848_CAPTURE_PIO); | ||
557 | snd_dma_program(chip->dma, runtime->dma_addr, size, DMA_MODE_READ | DMA_AUTOINIT); | ||
558 | count = snd_ad1848_get_count(chip->image[AD1848_DATA_FORMAT], count) - 1; | ||
559 | spin_lock_irqsave(&chip->reg_lock, flags); | ||
560 | snd_ad1848_out(chip, AD1848_DATA_LWR_CNT, (unsigned char) count); | ||
561 | snd_ad1848_out(chip, AD1848_DATA_UPR_CNT, (unsigned char) (count >> 8)); | ||
562 | spin_unlock_irqrestore(&chip->reg_lock, flags); | ||
563 | return 0; | ||
564 | } | ||
565 | |||
566 | static irqreturn_t snd_ad1848_interrupt(int irq, void *dev_id) | ||
567 | { | ||
568 | struct snd_ad1848 *chip = dev_id; | ||
569 | |||
570 | if ((chip->mode & AD1848_MODE_PLAY) && chip->playback_substream && | ||
571 | (chip->mode & AD1848_MODE_RUNNING)) | ||
572 | snd_pcm_period_elapsed(chip->playback_substream); | ||
573 | if ((chip->mode & AD1848_MODE_CAPTURE) && chip->capture_substream && | ||
574 | (chip->mode & AD1848_MODE_RUNNING)) | ||
575 | snd_pcm_period_elapsed(chip->capture_substream); | ||
576 | outb(0, AD1848P(chip, STATUS)); /* clear global interrupt bit */ | ||
577 | return IRQ_HANDLED; | ||
578 | } | ||
579 | |||
580 | static snd_pcm_uframes_t snd_ad1848_playback_pointer(struct snd_pcm_substream *substream) | ||
581 | { | ||
582 | struct snd_ad1848 *chip = snd_pcm_substream_chip(substream); | ||
583 | size_t ptr; | ||
584 | |||
585 | if (!(chip->image[AD1848_IFACE_CTRL] & AD1848_PLAYBACK_ENABLE)) | ||
586 | return 0; | ||
587 | ptr = snd_dma_pointer(chip->dma, chip->dma_size); | ||
588 | return bytes_to_frames(substream->runtime, ptr); | ||
589 | } | ||
590 | |||
591 | static snd_pcm_uframes_t snd_ad1848_capture_pointer(struct snd_pcm_substream *substream) | ||
592 | { | ||
593 | struct snd_ad1848 *chip = snd_pcm_substream_chip(substream); | ||
594 | size_t ptr; | ||
595 | |||
596 | if (!(chip->image[AD1848_IFACE_CTRL] & AD1848_CAPTURE_ENABLE)) | ||
597 | return 0; | ||
598 | ptr = snd_dma_pointer(chip->dma, chip->dma_size); | ||
599 | return bytes_to_frames(substream->runtime, ptr); | ||
600 | } | ||
601 | |||
602 | /* | ||
603 | |||
604 | */ | ||
605 | |||
606 | static void snd_ad1848_thinkpad_twiddle(struct snd_ad1848 *chip, int on) { | ||
607 | |||
608 | int tmp; | ||
609 | |||
610 | if (!chip->thinkpad_flag) return; | ||
611 | |||
612 | outb(0x1c, AD1848_THINKPAD_CTL_PORT1); | ||
613 | tmp = inb(AD1848_THINKPAD_CTL_PORT2); | ||
614 | |||
615 | if (on) | ||
616 | /* turn it on */ | ||
617 | tmp |= AD1848_THINKPAD_CS4248_ENABLE_BIT; | ||
618 | else | ||
619 | /* turn it off */ | ||
620 | tmp &= ~AD1848_THINKPAD_CS4248_ENABLE_BIT; | ||
621 | |||
622 | outb(tmp, AD1848_THINKPAD_CTL_PORT2); | ||
623 | |||
624 | } | ||
625 | |||
626 | #ifdef CONFIG_PM | ||
627 | static void snd_ad1848_suspend(struct snd_ad1848 *chip) | ||
628 | { | ||
629 | snd_pcm_suspend_all(chip->pcm); | ||
630 | if (chip->thinkpad_flag) | ||
631 | snd_ad1848_thinkpad_twiddle(chip, 0); | ||
632 | } | ||
633 | |||
634 | static void snd_ad1848_resume(struct snd_ad1848 *chip) | ||
635 | { | ||
636 | int i; | ||
637 | |||
638 | if (chip->thinkpad_flag) | ||
639 | snd_ad1848_thinkpad_twiddle(chip, 1); | ||
640 | |||
641 | /* clear any pendings IRQ */ | ||
642 | inb(AD1848P(chip, STATUS)); | ||
643 | outb(0, AD1848P(chip, STATUS)); | ||
644 | mb(); | ||
645 | |||
646 | snd_ad1848_mce_down(chip); | ||
647 | for (i = 0; i < 16; i++) | ||
648 | snd_ad1848_out(chip, i, chip->image[i]); | ||
649 | snd_ad1848_mce_up(chip); | ||
650 | snd_ad1848_mce_down(chip); | ||
651 | } | ||
652 | #endif /* CONFIG_PM */ | ||
653 | |||
654 | static int snd_ad1848_probe(struct snd_ad1848 * chip) | ||
655 | { | ||
656 | unsigned long flags; | ||
657 | int i, id, rev, ad1847; | ||
658 | unsigned char *ptr; | ||
659 | |||
660 | #if 0 | ||
661 | snd_ad1848_debug(chip); | ||
662 | #endif | ||
663 | id = ad1847 = 0; | ||
664 | for (i = 0; i < 1000; i++) { | ||
665 | mb(); | ||
666 | if (inb(AD1848P(chip, REGSEL)) & AD1848_INIT) | ||
667 | udelay(500); | ||
668 | else { | ||
669 | spin_lock_irqsave(&chip->reg_lock, flags); | ||
670 | snd_ad1848_out(chip, AD1848_MISC_INFO, 0x00); | ||
671 | snd_ad1848_out(chip, AD1848_LEFT_INPUT, 0xaa); | ||
672 | snd_ad1848_out(chip, AD1848_RIGHT_INPUT, 0x45); | ||
673 | rev = snd_ad1848_in(chip, AD1848_RIGHT_INPUT); | ||
674 | if (rev == 0x65) { | ||
675 | spin_unlock_irqrestore(&chip->reg_lock, flags); | ||
676 | id = 1; | ||
677 | ad1847 = 1; | ||
678 | break; | ||
679 | } | ||
680 | if (snd_ad1848_in(chip, AD1848_LEFT_INPUT) == 0xaa && rev == 0x45) { | ||
681 | spin_unlock_irqrestore(&chip->reg_lock, flags); | ||
682 | id = 1; | ||
683 | break; | ||
684 | } | ||
685 | spin_unlock_irqrestore(&chip->reg_lock, flags); | ||
686 | } | ||
687 | } | ||
688 | if (id != 1) | ||
689 | return -ENODEV; /* no valid device found */ | ||
690 | if (chip->hardware == AD1848_HW_DETECT) { | ||
691 | if (ad1847) { | ||
692 | chip->hardware = AD1848_HW_AD1847; | ||
693 | } else { | ||
694 | chip->hardware = AD1848_HW_AD1848; | ||
695 | rev = snd_ad1848_in(chip, AD1848_MISC_INFO); | ||
696 | if (rev & 0x80) { | ||
697 | chip->hardware = AD1848_HW_CS4248; | ||
698 | } else if ((rev & 0x0f) == 0x0a) { | ||
699 | snd_ad1848_out(chip, AD1848_MISC_INFO, 0x40); | ||
700 | for (i = 0; i < 16; ++i) { | ||
701 | if (snd_ad1848_in(chip, i) != snd_ad1848_in(chip, i + 16)) { | ||
702 | chip->hardware = AD1848_HW_CMI8330; | ||
703 | break; | ||
704 | } | ||
705 | } | ||
706 | snd_ad1848_out(chip, AD1848_MISC_INFO, 0x00); | ||
707 | } | ||
708 | } | ||
709 | } | ||
710 | spin_lock_irqsave(&chip->reg_lock, flags); | ||
711 | inb(AD1848P(chip, STATUS)); /* clear any pendings IRQ */ | ||
712 | outb(0, AD1848P(chip, STATUS)); | ||
713 | mb(); | ||
714 | spin_unlock_irqrestore(&chip->reg_lock, flags); | ||
715 | |||
716 | chip->image[AD1848_MISC_INFO] = 0x00; | ||
717 | chip->image[AD1848_IFACE_CTRL] = | ||
718 | (chip->image[AD1848_IFACE_CTRL] & ~AD1848_SINGLE_DMA) | AD1848_SINGLE_DMA; | ||
719 | ptr = (unsigned char *) &chip->image; | ||
720 | snd_ad1848_mce_down(chip); | ||
721 | spin_lock_irqsave(&chip->reg_lock, flags); | ||
722 | for (i = 0; i < 16; i++) /* ok.. fill all AD1848 registers */ | ||
723 | snd_ad1848_out(chip, i, *ptr++); | ||
724 | spin_unlock_irqrestore(&chip->reg_lock, flags); | ||
725 | snd_ad1848_mce_up(chip); | ||
726 | snd_ad1848_mce_down(chip); | ||
727 | return 0; /* all things are ok.. */ | ||
728 | } | ||
729 | |||
730 | /* | ||
731 | |||
732 | */ | ||
733 | |||
734 | static struct snd_pcm_hardware snd_ad1848_playback = | ||
735 | { | ||
736 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | | ||
737 | SNDRV_PCM_INFO_MMAP_VALID), | ||
738 | .formats = (SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW | | ||
739 | SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE), | ||
740 | .rates = SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_48000, | ||
741 | .rate_min = 5510, | ||
742 | .rate_max = 48000, | ||
743 | .channels_min = 1, | ||
744 | .channels_max = 2, | ||
745 | .buffer_bytes_max = (128*1024), | ||
746 | .period_bytes_min = 64, | ||
747 | .period_bytes_max = (128*1024), | ||
748 | .periods_min = 1, | ||
749 | .periods_max = 1024, | ||
750 | .fifo_size = 0, | ||
751 | }; | ||
752 | |||
753 | static struct snd_pcm_hardware snd_ad1848_capture = | ||
754 | { | ||
755 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | | ||
756 | SNDRV_PCM_INFO_MMAP_VALID), | ||
757 | .formats = (SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW | | ||
758 | SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE), | ||
759 | .rates = SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_48000, | ||
760 | .rate_min = 5510, | ||
761 | .rate_max = 48000, | ||
762 | .channels_min = 1, | ||
763 | .channels_max = 2, | ||
764 | .buffer_bytes_max = (128*1024), | ||
765 | .period_bytes_min = 64, | ||
766 | .period_bytes_max = (128*1024), | ||
767 | .periods_min = 1, | ||
768 | .periods_max = 1024, | ||
769 | .fifo_size = 0, | ||
770 | }; | ||
771 | |||
772 | /* | ||
773 | |||
774 | */ | ||
775 | |||
776 | static int snd_ad1848_playback_open(struct snd_pcm_substream *substream) | ||
777 | { | ||
778 | struct snd_ad1848 *chip = snd_pcm_substream_chip(substream); | ||
779 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
780 | int err; | ||
781 | |||
782 | if ((err = snd_ad1848_open(chip, AD1848_MODE_PLAY)) < 0) | ||
783 | return err; | ||
784 | chip->playback_substream = substream; | ||
785 | runtime->hw = snd_ad1848_playback; | ||
786 | snd_pcm_limit_isa_dma_size(chip->dma, &runtime->hw.buffer_bytes_max); | ||
787 | snd_pcm_limit_isa_dma_size(chip->dma, &runtime->hw.period_bytes_max); | ||
788 | snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates); | ||
789 | return 0; | ||
790 | } | ||
791 | |||
792 | static int snd_ad1848_capture_open(struct snd_pcm_substream *substream) | ||
793 | { | ||
794 | struct snd_ad1848 *chip = snd_pcm_substream_chip(substream); | ||
795 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
796 | int err; | ||
797 | |||
798 | if ((err = snd_ad1848_open(chip, AD1848_MODE_CAPTURE)) < 0) | ||
799 | return err; | ||
800 | chip->capture_substream = substream; | ||
801 | runtime->hw = snd_ad1848_capture; | ||
802 | snd_pcm_limit_isa_dma_size(chip->dma, &runtime->hw.buffer_bytes_max); | ||
803 | snd_pcm_limit_isa_dma_size(chip->dma, &runtime->hw.period_bytes_max); | ||
804 | snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates); | ||
805 | return 0; | ||
806 | } | ||
807 | |||
808 | static int snd_ad1848_playback_close(struct snd_pcm_substream *substream) | ||
809 | { | ||
810 | struct snd_ad1848 *chip = snd_pcm_substream_chip(substream); | ||
811 | |||
812 | chip->mode &= ~AD1848_MODE_PLAY; | ||
813 | chip->playback_substream = NULL; | ||
814 | snd_ad1848_close(chip); | ||
815 | return 0; | ||
816 | } | ||
817 | |||
818 | static int snd_ad1848_capture_close(struct snd_pcm_substream *substream) | ||
819 | { | ||
820 | struct snd_ad1848 *chip = snd_pcm_substream_chip(substream); | ||
821 | |||
822 | chip->mode &= ~AD1848_MODE_CAPTURE; | ||
823 | chip->capture_substream = NULL; | ||
824 | snd_ad1848_close(chip); | ||
825 | return 0; | ||
826 | } | ||
827 | |||
828 | static int snd_ad1848_free(struct snd_ad1848 *chip) | ||
829 | { | ||
830 | release_and_free_resource(chip->res_port); | ||
831 | if (chip->irq >= 0) | ||
832 | free_irq(chip->irq, (void *) chip); | ||
833 | if (chip->dma >= 0) { | ||
834 | snd_dma_disable(chip->dma); | ||
835 | free_dma(chip->dma); | ||
836 | } | ||
837 | kfree(chip); | ||
838 | return 0; | ||
839 | } | ||
840 | |||
841 | static int snd_ad1848_dev_free(struct snd_device *device) | ||
842 | { | ||
843 | struct snd_ad1848 *chip = device->device_data; | ||
844 | return snd_ad1848_free(chip); | ||
845 | } | ||
846 | |||
847 | static const char *snd_ad1848_chip_id(struct snd_ad1848 *chip) | ||
848 | { | ||
849 | switch (chip->hardware) { | ||
850 | case AD1848_HW_AD1847: return "AD1847"; | ||
851 | case AD1848_HW_AD1848: return "AD1848"; | ||
852 | case AD1848_HW_CS4248: return "CS4248"; | ||
853 | case AD1848_HW_CMI8330: return "CMI8330/C3D"; | ||
854 | default: return "???"; | ||
855 | } | ||
856 | } | ||
857 | |||
858 | int snd_ad1848_create(struct snd_card *card, | ||
859 | unsigned long port, | ||
860 | int irq, int dma, | ||
861 | unsigned short hardware, | ||
862 | struct snd_ad1848 ** rchip) | ||
863 | { | ||
864 | static struct snd_device_ops ops = { | ||
865 | .dev_free = snd_ad1848_dev_free, | ||
866 | }; | ||
867 | struct snd_ad1848 *chip; | ||
868 | int err; | ||
869 | |||
870 | *rchip = NULL; | ||
871 | chip = kzalloc(sizeof(*chip), GFP_KERNEL); | ||
872 | if (chip == NULL) | ||
873 | return -ENOMEM; | ||
874 | spin_lock_init(&chip->reg_lock); | ||
875 | chip->card = card; | ||
876 | chip->port = port; | ||
877 | chip->irq = -1; | ||
878 | chip->dma = -1; | ||
879 | chip->hardware = hardware; | ||
880 | memcpy(&chip->image, &snd_ad1848_original_image, sizeof(snd_ad1848_original_image)); | ||
881 | |||
882 | if ((chip->res_port = request_region(port, 4, "AD1848")) == NULL) { | ||
883 | snd_printk(KERN_ERR "ad1848: can't grab port 0x%lx\n", port); | ||
884 | snd_ad1848_free(chip); | ||
885 | return -EBUSY; | ||
886 | } | ||
887 | if (request_irq(irq, snd_ad1848_interrupt, IRQF_DISABLED, "AD1848", (void *) chip)) { | ||
888 | snd_printk(KERN_ERR "ad1848: can't grab IRQ %d\n", irq); | ||
889 | snd_ad1848_free(chip); | ||
890 | return -EBUSY; | ||
891 | } | ||
892 | chip->irq = irq; | ||
893 | if (request_dma(dma, "AD1848")) { | ||
894 | snd_printk(KERN_ERR "ad1848: can't grab DMA %d\n", dma); | ||
895 | snd_ad1848_free(chip); | ||
896 | return -EBUSY; | ||
897 | } | ||
898 | chip->dma = dma; | ||
899 | |||
900 | if (hardware == AD1848_HW_THINKPAD) { | ||
901 | chip->thinkpad_flag = 1; | ||
902 | chip->hardware = AD1848_HW_DETECT; /* reset */ | ||
903 | snd_ad1848_thinkpad_twiddle(chip, 1); | ||
904 | } | ||
905 | |||
906 | if (snd_ad1848_probe(chip) < 0) { | ||
907 | snd_ad1848_free(chip); | ||
908 | return -ENODEV; | ||
909 | } | ||
910 | |||
911 | /* Register device */ | ||
912 | if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { | ||
913 | snd_ad1848_free(chip); | ||
914 | return err; | ||
915 | } | ||
916 | |||
917 | #ifdef CONFIG_PM | ||
918 | chip->suspend = snd_ad1848_suspend; | ||
919 | chip->resume = snd_ad1848_resume; | ||
920 | #endif | ||
921 | |||
922 | *rchip = chip; | ||
923 | return 0; | ||
924 | } | ||
925 | |||
926 | EXPORT_SYMBOL(snd_ad1848_create); | ||
927 | |||
928 | static struct snd_pcm_ops snd_ad1848_playback_ops = { | ||
929 | .open = snd_ad1848_playback_open, | ||
930 | .close = snd_ad1848_playback_close, | ||
931 | .ioctl = snd_ad1848_ioctl, | ||
932 | .hw_params = snd_ad1848_playback_hw_params, | ||
933 | .hw_free = snd_ad1848_playback_hw_free, | ||
934 | .prepare = snd_ad1848_playback_prepare, | ||
935 | .trigger = snd_ad1848_playback_trigger, | ||
936 | .pointer = snd_ad1848_playback_pointer, | ||
937 | }; | ||
938 | |||
939 | static struct snd_pcm_ops snd_ad1848_capture_ops = { | ||
940 | .open = snd_ad1848_capture_open, | ||
941 | .close = snd_ad1848_capture_close, | ||
942 | .ioctl = snd_ad1848_ioctl, | ||
943 | .hw_params = snd_ad1848_capture_hw_params, | ||
944 | .hw_free = snd_ad1848_capture_hw_free, | ||
945 | .prepare = snd_ad1848_capture_prepare, | ||
946 | .trigger = snd_ad1848_capture_trigger, | ||
947 | .pointer = snd_ad1848_capture_pointer, | ||
948 | }; | ||
949 | |||
950 | int snd_ad1848_pcm(struct snd_ad1848 *chip, int device, struct snd_pcm **rpcm) | ||
951 | { | ||
952 | struct snd_pcm *pcm; | ||
953 | int err; | ||
954 | |||
955 | if ((err = snd_pcm_new(chip->card, "AD1848", device, 1, 1, &pcm)) < 0) | ||
956 | return err; | ||
957 | |||
958 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_ad1848_playback_ops); | ||
959 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_ad1848_capture_ops); | ||
960 | |||
961 | pcm->private_data = chip; | ||
962 | pcm->info_flags = SNDRV_PCM_INFO_HALF_DUPLEX; | ||
963 | strcpy(pcm->name, snd_ad1848_chip_id(chip)); | ||
964 | |||
965 | snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, | ||
966 | snd_dma_isa_data(), | ||
967 | 64*1024, chip->dma > 3 ? 128*1024 : 64*1024); | ||
968 | |||
969 | chip->pcm = pcm; | ||
970 | if (rpcm) | ||
971 | *rpcm = pcm; | ||
972 | return 0; | ||
973 | } | ||
974 | |||
975 | EXPORT_SYMBOL(snd_ad1848_pcm); | ||
976 | |||
977 | const struct snd_pcm_ops *snd_ad1848_get_pcm_ops(int direction) | ||
978 | { | ||
979 | return direction == SNDRV_PCM_STREAM_PLAYBACK ? | ||
980 | &snd_ad1848_playback_ops : &snd_ad1848_capture_ops; | ||
981 | } | ||
982 | |||
983 | EXPORT_SYMBOL(snd_ad1848_get_pcm_ops); | ||
984 | |||
985 | /* | ||
986 | * MIXER part | ||
987 | */ | ||
988 | |||
989 | static int snd_ad1848_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) | ||
990 | { | ||
991 | static char *texts[4] = { | ||
992 | "Line", "Aux", "Mic", "Mix" | ||
993 | }; | ||
994 | |||
995 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
996 | uinfo->count = 2; | ||
997 | uinfo->value.enumerated.items = 4; | ||
998 | if (uinfo->value.enumerated.item > 3) | ||
999 | uinfo->value.enumerated.item = 3; | ||
1000 | strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); | ||
1001 | return 0; | ||
1002 | } | ||
1003 | |||
1004 | static int snd_ad1848_get_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | ||
1005 | { | ||
1006 | struct snd_ad1848 *chip = snd_kcontrol_chip(kcontrol); | ||
1007 | unsigned long flags; | ||
1008 | |||
1009 | spin_lock_irqsave(&chip->reg_lock, flags); | ||
1010 | ucontrol->value.enumerated.item[0] = (chip->image[AD1848_LEFT_INPUT] & AD1848_MIXS_ALL) >> 6; | ||
1011 | ucontrol->value.enumerated.item[1] = (chip->image[AD1848_RIGHT_INPUT] & AD1848_MIXS_ALL) >> 6; | ||
1012 | spin_unlock_irqrestore(&chip->reg_lock, flags); | ||
1013 | return 0; | ||
1014 | } | ||
1015 | |||
1016 | static int snd_ad1848_put_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | ||
1017 | { | ||
1018 | struct snd_ad1848 *chip = snd_kcontrol_chip(kcontrol); | ||
1019 | unsigned long flags; | ||
1020 | unsigned short left, right; | ||
1021 | int change; | ||
1022 | |||
1023 | if (ucontrol->value.enumerated.item[0] > 3 || | ||
1024 | ucontrol->value.enumerated.item[1] > 3) | ||
1025 | return -EINVAL; | ||
1026 | left = ucontrol->value.enumerated.item[0] << 6; | ||
1027 | right = ucontrol->value.enumerated.item[1] << 6; | ||
1028 | spin_lock_irqsave(&chip->reg_lock, flags); | ||
1029 | left = (chip->image[AD1848_LEFT_INPUT] & ~AD1848_MIXS_ALL) | left; | ||
1030 | right = (chip->image[AD1848_RIGHT_INPUT] & ~AD1848_MIXS_ALL) | right; | ||
1031 | change = left != chip->image[AD1848_LEFT_INPUT] || | ||
1032 | right != chip->image[AD1848_RIGHT_INPUT]; | ||
1033 | snd_ad1848_out(chip, AD1848_LEFT_INPUT, left); | ||
1034 | snd_ad1848_out(chip, AD1848_RIGHT_INPUT, right); | ||
1035 | spin_unlock_irqrestore(&chip->reg_lock, flags); | ||
1036 | return change; | ||
1037 | } | ||
1038 | |||
1039 | static int snd_ad1848_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) | ||
1040 | { | ||
1041 | int mask = (kcontrol->private_value >> 16) & 0xff; | ||
1042 | |||
1043 | uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
1044 | uinfo->count = 1; | ||
1045 | uinfo->value.integer.min = 0; | ||
1046 | uinfo->value.integer.max = mask; | ||
1047 | return 0; | ||
1048 | } | ||
1049 | |||
1050 | static int snd_ad1848_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | ||
1051 | { | ||
1052 | struct snd_ad1848 *chip = snd_kcontrol_chip(kcontrol); | ||
1053 | unsigned long flags; | ||
1054 | int reg = kcontrol->private_value & 0xff; | ||
1055 | int shift = (kcontrol->private_value >> 8) & 0xff; | ||
1056 | int mask = (kcontrol->private_value >> 16) & 0xff; | ||
1057 | int invert = (kcontrol->private_value >> 24) & 0xff; | ||
1058 | |||
1059 | spin_lock_irqsave(&chip->reg_lock, flags); | ||
1060 | ucontrol->value.integer.value[0] = (chip->image[reg] >> shift) & mask; | ||
1061 | spin_unlock_irqrestore(&chip->reg_lock, flags); | ||
1062 | if (invert) | ||
1063 | ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0]; | ||
1064 | return 0; | ||
1065 | } | ||
1066 | |||
1067 | static int snd_ad1848_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | ||
1068 | { | ||
1069 | struct snd_ad1848 *chip = snd_kcontrol_chip(kcontrol); | ||
1070 | unsigned long flags; | ||
1071 | int reg = kcontrol->private_value & 0xff; | ||
1072 | int shift = (kcontrol->private_value >> 8) & 0xff; | ||
1073 | int mask = (kcontrol->private_value >> 16) & 0xff; | ||
1074 | int invert = (kcontrol->private_value >> 24) & 0xff; | ||
1075 | int change; | ||
1076 | unsigned short val; | ||
1077 | |||
1078 | val = (ucontrol->value.integer.value[0] & mask); | ||
1079 | if (invert) | ||
1080 | val = mask - val; | ||
1081 | val <<= shift; | ||
1082 | spin_lock_irqsave(&chip->reg_lock, flags); | ||
1083 | val = (chip->image[reg] & ~(mask << shift)) | val; | ||
1084 | change = val != chip->image[reg]; | ||
1085 | snd_ad1848_out(chip, reg, val); | ||
1086 | spin_unlock_irqrestore(&chip->reg_lock, flags); | ||
1087 | return change; | ||
1088 | } | ||
1089 | |||
1090 | static int snd_ad1848_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) | ||
1091 | { | ||
1092 | int mask = (kcontrol->private_value >> 24) & 0xff; | ||
1093 | |||
1094 | uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
1095 | uinfo->count = 2; | ||
1096 | uinfo->value.integer.min = 0; | ||
1097 | uinfo->value.integer.max = mask; | ||
1098 | return 0; | ||
1099 | } | ||
1100 | |||
1101 | static int snd_ad1848_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | ||
1102 | { | ||
1103 | struct snd_ad1848 *chip = snd_kcontrol_chip(kcontrol); | ||
1104 | unsigned long flags; | ||
1105 | int left_reg = kcontrol->private_value & 0xff; | ||
1106 | int right_reg = (kcontrol->private_value >> 8) & 0xff; | ||
1107 | int shift_left = (kcontrol->private_value >> 16) & 0x07; | ||
1108 | int shift_right = (kcontrol->private_value >> 19) & 0x07; | ||
1109 | int mask = (kcontrol->private_value >> 24) & 0xff; | ||
1110 | int invert = (kcontrol->private_value >> 22) & 1; | ||
1111 | |||
1112 | spin_lock_irqsave(&chip->reg_lock, flags); | ||
1113 | ucontrol->value.integer.value[0] = (chip->image[left_reg] >> shift_left) & mask; | ||
1114 | ucontrol->value.integer.value[1] = (chip->image[right_reg] >> shift_right) & mask; | ||
1115 | spin_unlock_irqrestore(&chip->reg_lock, flags); | ||
1116 | if (invert) { | ||
1117 | ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0]; | ||
1118 | ucontrol->value.integer.value[1] = mask - ucontrol->value.integer.value[1]; | ||
1119 | } | ||
1120 | return 0; | ||
1121 | } | ||
1122 | |||
1123 | static int snd_ad1848_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | ||
1124 | { | ||
1125 | struct snd_ad1848 *chip = snd_kcontrol_chip(kcontrol); | ||
1126 | unsigned long flags; | ||
1127 | int left_reg = kcontrol->private_value & 0xff; | ||
1128 | int right_reg = (kcontrol->private_value >> 8) & 0xff; | ||
1129 | int shift_left = (kcontrol->private_value >> 16) & 0x07; | ||
1130 | int shift_right = (kcontrol->private_value >> 19) & 0x07; | ||
1131 | int mask = (kcontrol->private_value >> 24) & 0xff; | ||
1132 | int invert = (kcontrol->private_value >> 22) & 1; | ||
1133 | int change; | ||
1134 | unsigned short val1, val2; | ||
1135 | |||
1136 | val1 = ucontrol->value.integer.value[0] & mask; | ||
1137 | val2 = ucontrol->value.integer.value[1] & mask; | ||
1138 | if (invert) { | ||
1139 | val1 = mask - val1; | ||
1140 | val2 = mask - val2; | ||
1141 | } | ||
1142 | val1 <<= shift_left; | ||
1143 | val2 <<= shift_right; | ||
1144 | spin_lock_irqsave(&chip->reg_lock, flags); | ||
1145 | if (left_reg != right_reg) { | ||
1146 | val1 = (chip->image[left_reg] & ~(mask << shift_left)) | val1; | ||
1147 | val2 = (chip->image[right_reg] & ~(mask << shift_right)) | val2; | ||
1148 | change = val1 != chip->image[left_reg] || val2 != chip->image[right_reg]; | ||
1149 | snd_ad1848_out(chip, left_reg, val1); | ||
1150 | snd_ad1848_out(chip, right_reg, val2); | ||
1151 | } else { | ||
1152 | val1 = (chip->image[left_reg] & ~((mask << shift_left) | (mask << shift_right))) | val1 | val2; | ||
1153 | change = val1 != chip->image[left_reg]; | ||
1154 | snd_ad1848_out(chip, left_reg, val1); | ||
1155 | } | ||
1156 | spin_unlock_irqrestore(&chip->reg_lock, flags); | ||
1157 | return change; | ||
1158 | } | ||
1159 | |||
1160 | /* | ||
1161 | */ | ||
1162 | int snd_ad1848_add_ctl_elem(struct snd_ad1848 *chip, | ||
1163 | const struct ad1848_mix_elem *c) | ||
1164 | { | ||
1165 | static struct snd_kcontrol_new newctls[] = { | ||
1166 | [AD1848_MIX_SINGLE] = { | ||
1167 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1168 | .info = snd_ad1848_info_single, | ||
1169 | .get = snd_ad1848_get_single, | ||
1170 | .put = snd_ad1848_put_single, | ||
1171 | }, | ||
1172 | [AD1848_MIX_DOUBLE] = { | ||
1173 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1174 | .info = snd_ad1848_info_double, | ||
1175 | .get = snd_ad1848_get_double, | ||
1176 | .put = snd_ad1848_put_double, | ||
1177 | }, | ||
1178 | [AD1848_MIX_CAPTURE] = { | ||
1179 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1180 | .info = snd_ad1848_info_mux, | ||
1181 | .get = snd_ad1848_get_mux, | ||
1182 | .put = snd_ad1848_put_mux, | ||
1183 | }, | ||
1184 | }; | ||
1185 | struct snd_kcontrol *ctl; | ||
1186 | int err; | ||
1187 | |||
1188 | ctl = snd_ctl_new1(&newctls[c->type], chip); | ||
1189 | if (! ctl) | ||
1190 | return -ENOMEM; | ||
1191 | strlcpy(ctl->id.name, c->name, sizeof(ctl->id.name)); | ||
1192 | ctl->id.index = c->index; | ||
1193 | ctl->private_value = c->private_value; | ||
1194 | if (c->tlv) { | ||
1195 | ctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ; | ||
1196 | ctl->tlv.p = c->tlv; | ||
1197 | } | ||
1198 | if ((err = snd_ctl_add(chip->card, ctl)) < 0) | ||
1199 | return err; | ||
1200 | return 0; | ||
1201 | } | ||
1202 | |||
1203 | EXPORT_SYMBOL(snd_ad1848_add_ctl_elem); | ||
1204 | |||
1205 | static const DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0); | ||
1206 | static const DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0); | ||
1207 | static const DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0); | ||
1208 | |||
1209 | static struct ad1848_mix_elem snd_ad1848_controls[] = { | ||
1210 | AD1848_DOUBLE("PCM Playback Switch", 0, AD1848_LEFT_OUTPUT, AD1848_RIGHT_OUTPUT, 7, 7, 1, 1), | ||
1211 | AD1848_DOUBLE_TLV("PCM Playback Volume", 0, AD1848_LEFT_OUTPUT, AD1848_RIGHT_OUTPUT, 0, 0, 63, 1, | ||
1212 | db_scale_6bit), | ||
1213 | AD1848_DOUBLE("Aux Playback Switch", 0, AD1848_AUX1_LEFT_INPUT, AD1848_AUX1_RIGHT_INPUT, 7, 7, 1, 1), | ||
1214 | AD1848_DOUBLE_TLV("Aux Playback Volume", 0, AD1848_AUX1_LEFT_INPUT, AD1848_AUX1_RIGHT_INPUT, 0, 0, 31, 1, | ||
1215 | db_scale_5bit_12db_max), | ||
1216 | AD1848_DOUBLE("Aux Playback Switch", 1, AD1848_AUX2_LEFT_INPUT, AD1848_AUX2_RIGHT_INPUT, 7, 7, 1, 1), | ||
1217 | AD1848_DOUBLE_TLV("Aux Playback Volume", 1, AD1848_AUX2_LEFT_INPUT, AD1848_AUX2_RIGHT_INPUT, 0, 0, 31, 1, | ||
1218 | db_scale_5bit_12db_max), | ||
1219 | AD1848_DOUBLE_TLV("Capture Volume", 0, AD1848_LEFT_INPUT, AD1848_RIGHT_INPUT, 0, 0, 15, 0, | ||
1220 | db_scale_rec_gain), | ||
1221 | { | ||
1222 | .name = "Capture Source", | ||
1223 | .type = AD1848_MIX_CAPTURE, | ||
1224 | }, | ||
1225 | AD1848_SINGLE("Loopback Capture Switch", 0, AD1848_LOOPBACK, 0, 1, 0), | ||
1226 | AD1848_SINGLE_TLV("Loopback Capture Volume", 0, AD1848_LOOPBACK, 1, 63, 0, | ||
1227 | db_scale_6bit), | ||
1228 | }; | ||
1229 | |||
1230 | int snd_ad1848_mixer(struct snd_ad1848 *chip) | ||
1231 | { | ||
1232 | struct snd_card *card; | ||
1233 | struct snd_pcm *pcm; | ||
1234 | unsigned int idx; | ||
1235 | int err; | ||
1236 | |||
1237 | snd_assert(chip != NULL && chip->pcm != NULL, return -EINVAL); | ||
1238 | |||
1239 | pcm = chip->pcm; | ||
1240 | card = chip->card; | ||
1241 | |||
1242 | strcpy(card->mixername, pcm->name); | ||
1243 | |||
1244 | for (idx = 0; idx < ARRAY_SIZE(snd_ad1848_controls); idx++) | ||
1245 | if ((err = snd_ad1848_add_ctl_elem(chip, &snd_ad1848_controls[idx])) < 0) | ||
1246 | return err; | ||
1247 | |||
1248 | return 0; | ||
1249 | } | ||
1250 | |||
1251 | EXPORT_SYMBOL(snd_ad1848_mixer); | ||
1252 | |||
1253 | /* | ||
1254 | * INIT part | ||
1255 | */ | ||
1256 | |||
1257 | static int __init alsa_ad1848_init(void) | ||
1258 | { | ||
1259 | return 0; | ||
1260 | } | ||
1261 | |||
1262 | static void __exit alsa_ad1848_exit(void) | ||
1263 | { | ||
1264 | } | ||
1265 | |||
1266 | module_init(alsa_ad1848_init) | ||
1267 | module_exit(alsa_ad1848_exit) | ||