Root/
1 | /* |
2 | * BRIEF MODULE DESCRIPTION |
3 | * Driver for AMD Au1000 MIPS Processor, AC'97 Sound Port |
4 | * |
5 | * Copyright 2004 Cooper Street Innovations Inc. |
6 | * Author: Charles Eidsness <charles@cooper-street.com> |
7 | * |
8 | * This program is free software; you can redistribute it and/or modify it |
9 | * under the terms of the GNU General Public License as published by the |
10 | * Free Software Foundation; either version 2 of the License, or (at your |
11 | * option) any later version. |
12 | * |
13 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED |
14 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
15 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN |
16 | * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
17 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
18 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF |
19 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON |
20 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
21 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
22 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
23 | * |
24 | * You should have received a copy of the GNU General Public License along |
25 | * with this program; if not, write to the Free Software Foundation, Inc., |
26 | * 675 Mass Ave, Cambridge, MA 02139, USA. |
27 | * |
28 | * History: |
29 | * |
30 | * 2004-09-09 Charles Eidsness -- Original verion -- based on |
31 | * sa11xx-uda1341.c ALSA driver and the |
32 | * au1000.c OSS driver. |
33 | * 2004-09-09 Matt Porter -- Added support for ALSA 1.0.6 |
34 | * |
35 | */ |
36 | |
37 | #include <linux/ioport.h> |
38 | #include <linux/interrupt.h> |
39 | #include <linux/init.h> |
40 | #include <linux/slab.h> |
41 | #include <sound/core.h> |
42 | #include <sound/initval.h> |
43 | #include <sound/pcm.h> |
44 | #include <sound/pcm_params.h> |
45 | #include <sound/ac97_codec.h> |
46 | #include <asm/mach-au1x00/au1000.h> |
47 | #include <asm/mach-au1x00/au1000_dma.h> |
48 | |
49 | MODULE_AUTHOR("Charles Eidsness <charles@cooper-street.com>"); |
50 | MODULE_DESCRIPTION("Au1000 AC'97 ALSA Driver"); |
51 | MODULE_LICENSE("GPL"); |
52 | MODULE_SUPPORTED_DEVICE("{{AMD,Au1000 AC'97}}"); |
53 | |
54 | #define PLAYBACK 0 |
55 | #define CAPTURE 1 |
56 | #define AC97_SLOT_3 0x01 |
57 | #define AC97_SLOT_4 0x02 |
58 | #define AC97_SLOT_6 0x08 |
59 | #define AC97_CMD_IRQ 31 |
60 | #define READ 0 |
61 | #define WRITE 1 |
62 | #define READ_WAIT 2 |
63 | #define RW_DONE 3 |
64 | |
65 | struct au1000_period |
66 | { |
67 | u32 start; |
68 | u32 relative_end; /*realtive to start of buffer*/ |
69 | struct au1000_period * next; |
70 | }; |
71 | |
72 | /*Au1000 AC97 Port Control Reisters*/ |
73 | struct au1000_ac97_reg { |
74 | u32 volatile config; |
75 | u32 volatile status; |
76 | u32 volatile data; |
77 | u32 volatile cmd; |
78 | u32 volatile cntrl; |
79 | }; |
80 | |
81 | struct audio_stream { |
82 | struct snd_pcm_substream *substream; |
83 | int dma; |
84 | spinlock_t dma_lock; |
85 | struct au1000_period * buffer; |
86 | unsigned int period_size; |
87 | unsigned int periods; |
88 | }; |
89 | |
90 | struct snd_au1000 { |
91 | struct snd_card *card; |
92 | struct au1000_ac97_reg volatile *ac97_ioport; |
93 | |
94 | struct resource *ac97_res_port; |
95 | spinlock_t ac97_lock; |
96 | struct snd_ac97 *ac97; |
97 | |
98 | struct snd_pcm *pcm; |
99 | struct audio_stream *stream[2]; /* playback & capture */ |
100 | }; |
101 | |
102 | /*--------------------------- Local Functions --------------------------------*/ |
103 | static void |
104 | au1000_set_ac97_xmit_slots(struct snd_au1000 *au1000, long xmit_slots) |
105 | { |
106 | u32 volatile ac97_config; |
107 | |
108 | spin_lock(&au1000->ac97_lock); |
109 | ac97_config = au1000->ac97_ioport->config; |
110 | ac97_config = ac97_config & ~AC97C_XMIT_SLOTS_MASK; |
111 | ac97_config |= (xmit_slots << AC97C_XMIT_SLOTS_BIT); |
112 | au1000->ac97_ioport->config = ac97_config; |
113 | spin_unlock(&au1000->ac97_lock); |
114 | } |
115 | |
116 | static void |
117 | au1000_set_ac97_recv_slots(struct snd_au1000 *au1000, long recv_slots) |
118 | { |
119 | u32 volatile ac97_config; |
120 | |
121 | spin_lock(&au1000->ac97_lock); |
122 | ac97_config = au1000->ac97_ioport->config; |
123 | ac97_config = ac97_config & ~AC97C_RECV_SLOTS_MASK; |
124 | ac97_config |= (recv_slots << AC97C_RECV_SLOTS_BIT); |
125 | au1000->ac97_ioport->config = ac97_config; |
126 | spin_unlock(&au1000->ac97_lock); |
127 | } |
128 | |
129 | |
130 | static void |
131 | au1000_release_dma_link(struct audio_stream *stream) |
132 | { |
133 | struct au1000_period * pointer; |
134 | struct au1000_period * pointer_next; |
135 | |
136 | stream->period_size = 0; |
137 | stream->periods = 0; |
138 | pointer = stream->buffer; |
139 | if (! pointer) |
140 | return; |
141 | do { |
142 | pointer_next = pointer->next; |
143 | kfree(pointer); |
144 | pointer = pointer_next; |
145 | } while (pointer != stream->buffer); |
146 | stream->buffer = NULL; |
147 | } |
148 | |
149 | static int |
150 | au1000_setup_dma_link(struct audio_stream *stream, unsigned int period_bytes, |
151 | unsigned int periods) |
152 | { |
153 | struct snd_pcm_substream *substream = stream->substream; |
154 | struct snd_pcm_runtime *runtime = substream->runtime; |
155 | struct au1000_period *pointer; |
156 | unsigned long dma_start; |
157 | int i; |
158 | |
159 | dma_start = virt_to_phys(runtime->dma_area); |
160 | |
161 | if (stream->period_size == period_bytes && |
162 | stream->periods == periods) |
163 | return 0; /* not changed */ |
164 | |
165 | au1000_release_dma_link(stream); |
166 | |
167 | stream->period_size = period_bytes; |
168 | stream->periods = periods; |
169 | |
170 | stream->buffer = kmalloc(sizeof(struct au1000_period), GFP_KERNEL); |
171 | if (! stream->buffer) |
172 | return -ENOMEM; |
173 | pointer = stream->buffer; |
174 | for (i = 0; i < periods; i++) { |
175 | pointer->start = (u32)(dma_start + (i * period_bytes)); |
176 | pointer->relative_end = (u32) (((i+1) * period_bytes) - 0x1); |
177 | if (i < periods - 1) { |
178 | pointer->next = kmalloc(sizeof(struct au1000_period), GFP_KERNEL); |
179 | if (! pointer->next) { |
180 | au1000_release_dma_link(stream); |
181 | return -ENOMEM; |
182 | } |
183 | pointer = pointer->next; |
184 | } |
185 | } |
186 | pointer->next = stream->buffer; |
187 | return 0; |
188 | } |
189 | |
190 | static void |
191 | au1000_dma_stop(struct audio_stream *stream) |
192 | { |
193 | if (snd_BUG_ON(!stream->buffer)) |
194 | return; |
195 | disable_dma(stream->dma); |
196 | } |
197 | |
198 | static void |
199 | au1000_dma_start(struct audio_stream *stream) |
200 | { |
201 | if (snd_BUG_ON(!stream->buffer)) |
202 | return; |
203 | |
204 | init_dma(stream->dma); |
205 | if (get_dma_active_buffer(stream->dma) == 0) { |
206 | clear_dma_done0(stream->dma); |
207 | set_dma_addr0(stream->dma, stream->buffer->start); |
208 | set_dma_count0(stream->dma, stream->period_size >> 1); |
209 | set_dma_addr1(stream->dma, stream->buffer->next->start); |
210 | set_dma_count1(stream->dma, stream->period_size >> 1); |
211 | } else { |
212 | clear_dma_done1(stream->dma); |
213 | set_dma_addr1(stream->dma, stream->buffer->start); |
214 | set_dma_count1(stream->dma, stream->period_size >> 1); |
215 | set_dma_addr0(stream->dma, stream->buffer->next->start); |
216 | set_dma_count0(stream->dma, stream->period_size >> 1); |
217 | } |
218 | enable_dma_buffers(stream->dma); |
219 | start_dma(stream->dma); |
220 | } |
221 | |
222 | static irqreturn_t |
223 | au1000_dma_interrupt(int irq, void *dev_id) |
224 | { |
225 | struct audio_stream *stream = (struct audio_stream *) dev_id; |
226 | struct snd_pcm_substream *substream = stream->substream; |
227 | |
228 | spin_lock(&stream->dma_lock); |
229 | switch (get_dma_buffer_done(stream->dma)) { |
230 | case DMA_D0: |
231 | stream->buffer = stream->buffer->next; |
232 | clear_dma_done0(stream->dma); |
233 | set_dma_addr0(stream->dma, stream->buffer->next->start); |
234 | set_dma_count0(stream->dma, stream->period_size >> 1); |
235 | enable_dma_buffer0(stream->dma); |
236 | break; |
237 | case DMA_D1: |
238 | stream->buffer = stream->buffer->next; |
239 | clear_dma_done1(stream->dma); |
240 | set_dma_addr1(stream->dma, stream->buffer->next->start); |
241 | set_dma_count1(stream->dma, stream->period_size >> 1); |
242 | enable_dma_buffer1(stream->dma); |
243 | break; |
244 | case (DMA_D0 | DMA_D1): |
245 | printk(KERN_ERR "DMA %d missed interrupt.\n",stream->dma); |
246 | au1000_dma_stop(stream); |
247 | au1000_dma_start(stream); |
248 | break; |
249 | case (~DMA_D0 & ~DMA_D1): |
250 | printk(KERN_ERR "DMA %d empty irq.\n",stream->dma); |
251 | } |
252 | spin_unlock(&stream->dma_lock); |
253 | snd_pcm_period_elapsed(substream); |
254 | return IRQ_HANDLED; |
255 | } |
256 | |
257 | /*-------------------------- PCM Audio Streams -------------------------------*/ |
258 | |
259 | static unsigned int rates[] = {8000, 11025, 16000, 22050}; |
260 | static struct snd_pcm_hw_constraint_list hw_constraints_rates = { |
261 | .count = ARRAY_SIZE(rates), |
262 | .list = rates, |
263 | .mask = 0, |
264 | }; |
265 | |
266 | static struct snd_pcm_hardware snd_au1000_hw = |
267 | { |
268 | .info = (SNDRV_PCM_INFO_INTERLEAVED | \ |
269 | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID), |
270 | .formats = SNDRV_PCM_FMTBIT_S16_LE, |
271 | .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | |
272 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050), |
273 | .rate_min = 8000, |
274 | .rate_max = 22050, |
275 | .channels_min = 1, |
276 | .channels_max = 2, |
277 | .buffer_bytes_max = 128*1024, |
278 | .period_bytes_min = 32, |
279 | .period_bytes_max = 16*1024, |
280 | .periods_min = 8, |
281 | .periods_max = 255, |
282 | .fifo_size = 16, |
283 | }; |
284 | |
285 | static int |
286 | snd_au1000_playback_open(struct snd_pcm_substream *substream) |
287 | { |
288 | struct snd_au1000 *au1000 = substream->pcm->private_data; |
289 | |
290 | au1000->stream[PLAYBACK]->substream = substream; |
291 | au1000->stream[PLAYBACK]->buffer = NULL; |
292 | substream->private_data = au1000->stream[PLAYBACK]; |
293 | substream->runtime->hw = snd_au1000_hw; |
294 | return (snd_pcm_hw_constraint_list(substream->runtime, 0, |
295 | SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates) < 0); |
296 | } |
297 | |
298 | static int |
299 | snd_au1000_capture_open(struct snd_pcm_substream *substream) |
300 | { |
301 | struct snd_au1000 *au1000 = substream->pcm->private_data; |
302 | |
303 | au1000->stream[CAPTURE]->substream = substream; |
304 | au1000->stream[CAPTURE]->buffer = NULL; |
305 | substream->private_data = au1000->stream[CAPTURE]; |
306 | substream->runtime->hw = snd_au1000_hw; |
307 | return (snd_pcm_hw_constraint_list(substream->runtime, 0, |
308 | SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates) < 0); |
309 | } |
310 | |
311 | static int |
312 | snd_au1000_playback_close(struct snd_pcm_substream *substream) |
313 | { |
314 | struct snd_au1000 *au1000 = substream->pcm->private_data; |
315 | |
316 | au1000->stream[PLAYBACK]->substream = NULL; |
317 | return 0; |
318 | } |
319 | |
320 | static int |
321 | snd_au1000_capture_close(struct snd_pcm_substream *substream) |
322 | { |
323 | struct snd_au1000 *au1000 = substream->pcm->private_data; |
324 | |
325 | au1000->stream[CAPTURE]->substream = NULL; |
326 | return 0; |
327 | } |
328 | |
329 | static int |
330 | snd_au1000_hw_params(struct snd_pcm_substream *substream, |
331 | struct snd_pcm_hw_params *hw_params) |
332 | { |
333 | struct audio_stream *stream = substream->private_data; |
334 | int err; |
335 | |
336 | err = snd_pcm_lib_malloc_pages(substream, |
337 | params_buffer_bytes(hw_params)); |
338 | if (err < 0) |
339 | return err; |
340 | return au1000_setup_dma_link(stream, |
341 | params_period_bytes(hw_params), |
342 | params_periods(hw_params)); |
343 | } |
344 | |
345 | static int |
346 | snd_au1000_hw_free(struct snd_pcm_substream *substream) |
347 | { |
348 | struct audio_stream *stream = substream->private_data; |
349 | au1000_release_dma_link(stream); |
350 | return snd_pcm_lib_free_pages(substream); |
351 | } |
352 | |
353 | static int |
354 | snd_au1000_playback_prepare(struct snd_pcm_substream *substream) |
355 | { |
356 | struct snd_au1000 *au1000 = substream->pcm->private_data; |
357 | struct snd_pcm_runtime *runtime = substream->runtime; |
358 | |
359 | if (runtime->channels == 1) |
360 | au1000_set_ac97_xmit_slots(au1000, AC97_SLOT_4); |
361 | else |
362 | au1000_set_ac97_xmit_slots(au1000, AC97_SLOT_3 | AC97_SLOT_4); |
363 | snd_ac97_set_rate(au1000->ac97, AC97_PCM_FRONT_DAC_RATE, runtime->rate); |
364 | return 0; |
365 | } |
366 | |
367 | static int |
368 | snd_au1000_capture_prepare(struct snd_pcm_substream *substream) |
369 | { |
370 | struct snd_au1000 *au1000 = substream->pcm->private_data; |
371 | struct snd_pcm_runtime *runtime = substream->runtime; |
372 | |
373 | if (runtime->channels == 1) |
374 | au1000_set_ac97_recv_slots(au1000, AC97_SLOT_4); |
375 | else |
376 | au1000_set_ac97_recv_slots(au1000, AC97_SLOT_3 | AC97_SLOT_4); |
377 | snd_ac97_set_rate(au1000->ac97, AC97_PCM_LR_ADC_RATE, runtime->rate); |
378 | return 0; |
379 | } |
380 | |
381 | static int |
382 | snd_au1000_trigger(struct snd_pcm_substream *substream, int cmd) |
383 | { |
384 | struct audio_stream *stream = substream->private_data; |
385 | int err = 0; |
386 | |
387 | spin_lock(&stream->dma_lock); |
388 | switch (cmd) { |
389 | case SNDRV_PCM_TRIGGER_START: |
390 | au1000_dma_start(stream); |
391 | break; |
392 | case SNDRV_PCM_TRIGGER_STOP: |
393 | au1000_dma_stop(stream); |
394 | break; |
395 | default: |
396 | err = -EINVAL; |
397 | break; |
398 | } |
399 | spin_unlock(&stream->dma_lock); |
400 | return err; |
401 | } |
402 | |
403 | static snd_pcm_uframes_t |
404 | snd_au1000_pointer(struct snd_pcm_substream *substream) |
405 | { |
406 | struct audio_stream *stream = substream->private_data; |
407 | struct snd_pcm_runtime *runtime = substream->runtime; |
408 | long location; |
409 | |
410 | spin_lock(&stream->dma_lock); |
411 | location = get_dma_residue(stream->dma); |
412 | spin_unlock(&stream->dma_lock); |
413 | location = stream->buffer->relative_end - location; |
414 | if (location == -1) |
415 | location = 0; |
416 | return bytes_to_frames(runtime,location); |
417 | } |
418 | |
419 | static struct snd_pcm_ops snd_card_au1000_playback_ops = { |
420 | .open = snd_au1000_playback_open, |
421 | .close = snd_au1000_playback_close, |
422 | .ioctl = snd_pcm_lib_ioctl, |
423 | .hw_params = snd_au1000_hw_params, |
424 | .hw_free = snd_au1000_hw_free, |
425 | .prepare = snd_au1000_playback_prepare, |
426 | .trigger = snd_au1000_trigger, |
427 | .pointer = snd_au1000_pointer, |
428 | }; |
429 | |
430 | static struct snd_pcm_ops snd_card_au1000_capture_ops = { |
431 | .open = snd_au1000_capture_open, |
432 | .close = snd_au1000_capture_close, |
433 | .ioctl = snd_pcm_lib_ioctl, |
434 | .hw_params = snd_au1000_hw_params, |
435 | .hw_free = snd_au1000_hw_free, |
436 | .prepare = snd_au1000_capture_prepare, |
437 | .trigger = snd_au1000_trigger, |
438 | .pointer = snd_au1000_pointer, |
439 | }; |
440 | |
441 | static int __devinit |
442 | snd_au1000_pcm_new(struct snd_au1000 *au1000) |
443 | { |
444 | struct snd_pcm *pcm; |
445 | int err; |
446 | unsigned long flags; |
447 | |
448 | if ((err = snd_pcm_new(au1000->card, "AU1000 AC97 PCM", 0, 1, 1, &pcm)) < 0) |
449 | return err; |
450 | |
451 | snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, |
452 | snd_dma_continuous_data(GFP_KERNEL), 128*1024, 128*1024); |
453 | |
454 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, |
455 | &snd_card_au1000_playback_ops); |
456 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, |
457 | &snd_card_au1000_capture_ops); |
458 | |
459 | pcm->private_data = au1000; |
460 | pcm->info_flags = 0; |
461 | strcpy(pcm->name, "Au1000 AC97 PCM"); |
462 | |
463 | spin_lock_init(&au1000->stream[PLAYBACK]->dma_lock); |
464 | spin_lock_init(&au1000->stream[CAPTURE]->dma_lock); |
465 | |
466 | flags = claim_dma_lock(); |
467 | if ((au1000->stream[PLAYBACK]->dma = request_au1000_dma(DMA_ID_AC97C_TX, |
468 | "AC97 TX", au1000_dma_interrupt, IRQF_DISABLED, |
469 | au1000->stream[PLAYBACK])) < 0) { |
470 | release_dma_lock(flags); |
471 | return -EBUSY; |
472 | } |
473 | if ((au1000->stream[CAPTURE]->dma = request_au1000_dma(DMA_ID_AC97C_RX, |
474 | "AC97 RX", au1000_dma_interrupt, IRQF_DISABLED, |
475 | au1000->stream[CAPTURE])) < 0){ |
476 | release_dma_lock(flags); |
477 | return -EBUSY; |
478 | } |
479 | /* enable DMA coherency in read/write DMA channels */ |
480 | set_dma_mode(au1000->stream[PLAYBACK]->dma, |
481 | get_dma_mode(au1000->stream[PLAYBACK]->dma) & ~DMA_NC); |
482 | set_dma_mode(au1000->stream[CAPTURE]->dma, |
483 | get_dma_mode(au1000->stream[CAPTURE]->dma) & ~DMA_NC); |
484 | release_dma_lock(flags); |
485 | au1000->pcm = pcm; |
486 | return 0; |
487 | } |
488 | |
489 | |
490 | /*-------------------------- AC97 CODEC Control ------------------------------*/ |
491 | |
492 | static unsigned short |
493 | snd_au1000_ac97_read(struct snd_ac97 *ac97, unsigned short reg) |
494 | { |
495 | struct snd_au1000 *au1000 = ac97->private_data; |
496 | u32 volatile cmd; |
497 | u16 volatile data; |
498 | int i; |
499 | |
500 | spin_lock(&au1000->ac97_lock); |
501 | /* would rather use the interrupt than this polling but it works and I can't |
502 | get the interrupt driven case to work efficiently */ |
503 | for (i = 0; i < 0x5000; i++) |
504 | if (!(au1000->ac97_ioport->status & AC97C_CP)) |
505 | break; |
506 | if (i == 0x5000) |
507 | printk(KERN_ERR "au1000 AC97: AC97 command read timeout\n"); |
508 | |
509 | cmd = (u32) reg & AC97C_INDEX_MASK; |
510 | cmd |= AC97C_READ; |
511 | au1000->ac97_ioport->cmd = cmd; |
512 | |
513 | /* now wait for the data */ |
514 | for (i = 0; i < 0x5000; i++) |
515 | if (!(au1000->ac97_ioport->status & AC97C_CP)) |
516 | break; |
517 | if (i == 0x5000) { |
518 | printk(KERN_ERR "au1000 AC97: AC97 command read timeout\n"); |
519 | return 0; |
520 | } |
521 | |
522 | data = au1000->ac97_ioport->cmd & 0xffff; |
523 | spin_unlock(&au1000->ac97_lock); |
524 | |
525 | return data; |
526 | |
527 | } |
528 | |
529 | |
530 | static void |
531 | snd_au1000_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short val) |
532 | { |
533 | struct snd_au1000 *au1000 = ac97->private_data; |
534 | u32 cmd; |
535 | int i; |
536 | |
537 | spin_lock(&au1000->ac97_lock); |
538 | /* would rather use the interrupt than this polling but it works and I can't |
539 | get the interrupt driven case to work efficiently */ |
540 | for (i = 0; i < 0x5000; i++) |
541 | if (!(au1000->ac97_ioport->status & AC97C_CP)) |
542 | break; |
543 | if (i == 0x5000) |
544 | printk(KERN_ERR "au1000 AC97: AC97 command write timeout\n"); |
545 | |
546 | cmd = (u32) reg & AC97C_INDEX_MASK; |
547 | cmd &= ~AC97C_READ; |
548 | cmd |= ((u32) val << AC97C_WD_BIT); |
549 | au1000->ac97_ioport->cmd = cmd; |
550 | spin_unlock(&au1000->ac97_lock); |
551 | } |
552 | |
553 | static int __devinit |
554 | snd_au1000_ac97_new(struct snd_au1000 *au1000) |
555 | { |
556 | int err; |
557 | struct snd_ac97_bus *pbus; |
558 | struct snd_ac97_template ac97; |
559 | static struct snd_ac97_bus_ops ops = { |
560 | .write = snd_au1000_ac97_write, |
561 | .read = snd_au1000_ac97_read, |
562 | }; |
563 | |
564 | if ((au1000->ac97_res_port = request_mem_region(CPHYSADDR(AC97C_CONFIG), |
565 | 0x100000, "Au1x00 AC97")) == NULL) { |
566 | snd_printk(KERN_ERR "ALSA AC97: can't grap AC97 port\n"); |
567 | return -EBUSY; |
568 | } |
569 | au1000->ac97_ioport = (struct au1000_ac97_reg *) |
570 | KSEG1ADDR(au1000->ac97_res_port->start); |
571 | |
572 | spin_lock_init(&au1000->ac97_lock); |
573 | |
574 | /* configure pins for AC'97 |
575 | TODO: move to board_setup.c */ |
576 | au_writel(au_readl(SYS_PINFUNC) & ~0x02, SYS_PINFUNC); |
577 | |
578 | /* Initialise Au1000's AC'97 Control Block */ |
579 | au1000->ac97_ioport->cntrl = AC97C_RS | AC97C_CE; |
580 | udelay(10); |
581 | au1000->ac97_ioport->cntrl = AC97C_CE; |
582 | udelay(10); |
583 | |
584 | /* Initialise External CODEC -- cold reset */ |
585 | au1000->ac97_ioport->config = AC97C_RESET; |
586 | udelay(10); |
587 | au1000->ac97_ioport->config = 0x0; |
588 | mdelay(5); |
589 | |
590 | /* Initialise AC97 middle-layer */ |
591 | if ((err = snd_ac97_bus(au1000->card, 0, &ops, au1000, &pbus)) < 0) |
592 | return err; |
593 | |
594 | memset(&ac97, 0, sizeof(ac97)); |
595 | ac97.private_data = au1000; |
596 | if ((err = snd_ac97_mixer(pbus, &ac97, &au1000->ac97)) < 0) |
597 | return err; |
598 | |
599 | return 0; |
600 | } |
601 | |
602 | /*------------------------------ Setup / Destroy ----------------------------*/ |
603 | |
604 | void |
605 | snd_au1000_free(struct snd_card *card) |
606 | { |
607 | struct snd_au1000 *au1000 = card->private_data; |
608 | |
609 | if (au1000->ac97_res_port) { |
610 | /* put internal AC97 block into reset */ |
611 | au1000->ac97_ioport->cntrl = AC97C_RS; |
612 | au1000->ac97_ioport = NULL; |
613 | release_and_free_resource(au1000->ac97_res_port); |
614 | } |
615 | |
616 | if (au1000->stream[PLAYBACK]) { |
617 | if (au1000->stream[PLAYBACK]->dma >= 0) |
618 | free_au1000_dma(au1000->stream[PLAYBACK]->dma); |
619 | kfree(au1000->stream[PLAYBACK]); |
620 | } |
621 | |
622 | if (au1000->stream[CAPTURE]) { |
623 | if (au1000->stream[CAPTURE]->dma >= 0) |
624 | free_au1000_dma(au1000->stream[CAPTURE]->dma); |
625 | kfree(au1000->stream[CAPTURE]); |
626 | } |
627 | } |
628 | |
629 | |
630 | static struct snd_card *au1000_card; |
631 | |
632 | static int __init |
633 | au1000_init(void) |
634 | { |
635 | int err; |
636 | struct snd_card *card; |
637 | struct snd_au1000 *au1000; |
638 | |
639 | err = snd_card_create(-1, "AC97", THIS_MODULE, |
640 | sizeof(struct snd_au1000), &card); |
641 | if (err < 0) |
642 | return err; |
643 | |
644 | card->private_free = snd_au1000_free; |
645 | au1000 = card->private_data; |
646 | au1000->card = card; |
647 | |
648 | au1000->stream[PLAYBACK] = kmalloc(sizeof(struct audio_stream), GFP_KERNEL); |
649 | au1000->stream[CAPTURE ] = kmalloc(sizeof(struct audio_stream), GFP_KERNEL); |
650 | /* so that snd_au1000_free will work as intended */ |
651 | au1000->ac97_res_port = NULL; |
652 | if (au1000->stream[PLAYBACK]) |
653 | au1000->stream[PLAYBACK]->dma = -1; |
654 | if (au1000->stream[CAPTURE ]) |
655 | au1000->stream[CAPTURE ]->dma = -1; |
656 | |
657 | if (au1000->stream[PLAYBACK] == NULL || |
658 | au1000->stream[CAPTURE ] == NULL) { |
659 | snd_card_free(card); |
660 | return -ENOMEM; |
661 | } |
662 | |
663 | if ((err = snd_au1000_ac97_new(au1000)) < 0 ) { |
664 | snd_card_free(card); |
665 | return err; |
666 | } |
667 | |
668 | if ((err = snd_au1000_pcm_new(au1000)) < 0) { |
669 | snd_card_free(card); |
670 | return err; |
671 | } |
672 | |
673 | strcpy(card->driver, "Au1000-AC97"); |
674 | strcpy(card->shortname, "AMD Au1000-AC97"); |
675 | sprintf(card->longname, "AMD Au1000--AC97 ALSA Driver"); |
676 | |
677 | if ((err = snd_card_register(card)) < 0) { |
678 | snd_card_free(card); |
679 | return err; |
680 | } |
681 | |
682 | printk(KERN_INFO "ALSA AC97: Driver Initialized\n"); |
683 | au1000_card = card; |
684 | return 0; |
685 | } |
686 | |
687 | static void __exit au1000_exit(void) |
688 | { |
689 | snd_card_free(au1000_card); |
690 | } |
691 | |
692 | module_init(au1000_init); |
693 | module_exit(au1000_exit); |
694 | |
695 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9