aboutsummaryrefslogtreecommitdiffstats
path: root/sound/mips
diff options
context:
space:
mode:
authorLars-Peter Clausen <lars@metafoo.de>2016-02-06 05:25:49 -0500
committerTakashi Iwai <tiwai@suse.de>2016-02-08 02:17:15 -0500
commitefd931d6c7fc49dc555150c600555df0fac7bf14 (patch)
treeb6eebe6c163903d87804954f7162a3090ffefbca /sound/mips
parentc9e9daccc7a6a670a6619723138ace6752f4773b (diff)
ALSA: Remove deprecated AU1X00 AC97 driver
The AU1X00 AC97 ALSA driver was deprecated in commit 7137c6bcb7ff ("ALSA: deprecate MIPS AU1X00 AC97 driver") in favor of the newer and better ASoC driver for the same hardware. This was almost 5 years ago and this driver has not been in use in the mainline kernel since, it should be safe to remove it at this point. Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/mips')
-rw-r--r--sound/mips/Kconfig12
-rw-r--r--sound/mips/Makefile2
-rw-r--r--sound/mips/au1x00.c734
3 files changed, 0 insertions, 748 deletions
diff --git a/sound/mips/Kconfig b/sound/mips/Kconfig
index 2153d31fb663..4a4705031cb9 100644
--- a/sound/mips/Kconfig
+++ b/sound/mips/Kconfig
@@ -23,17 +23,5 @@ config SND_SGI_HAL2
23 help 23 help
24 Sound support for the SGI Indy and Indigo2 Workstation. 24 Sound support for the SGI Indy and Indigo2 Workstation.
25 25
26
27config SND_AU1X00
28 tristate "Au1x00 AC97 Port Driver (DEPRECATED)"
29 depends on MIPS_ALCHEMY
30 select SND_PCM
31 select SND_AC97_CODEC
32 help
33 ALSA Sound driver for the Au1x00's AC97 port.
34
35 Newer drivers for ASoC are available, please do not use
36 this driver as it will be removed in the future.
37
38endif # SND_MIPS 26endif # SND_MIPS
39 27
diff --git a/sound/mips/Makefile b/sound/mips/Makefile
index 861ec0a574b4..b977c44330d6 100644
--- a/sound/mips/Makefile
+++ b/sound/mips/Makefile
@@ -2,11 +2,9 @@
2# Makefile for ALSA 2# Makefile for ALSA
3# 3#
4 4
5snd-au1x00-objs := au1x00.o
6snd-sgi-o2-objs := sgio2audio.o ad1843.o 5snd-sgi-o2-objs := sgio2audio.o ad1843.o
7snd-sgi-hal2-objs := hal2.o 6snd-sgi-hal2-objs := hal2.o
8 7
9# Toplevel Module Dependency 8# Toplevel Module Dependency
10obj-$(CONFIG_SND_AU1X00) += snd-au1x00.o
11obj-$(CONFIG_SND_SGI_O2) += snd-sgi-o2.o 9obj-$(CONFIG_SND_SGI_O2) += snd-sgi-o2.o
12obj-$(CONFIG_SND_SGI_HAL2) += snd-sgi-hal2.o 10obj-$(CONFIG_SND_SGI_HAL2) += snd-sgi-hal2.o
diff --git a/sound/mips/au1x00.c b/sound/mips/au1x00.c
deleted file mode 100644
index 1e30e8475431..000000000000
--- a/sound/mips/au1x00.c
+++ /dev/null
@@ -1,734 +0,0 @@
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/platform_device.h>
41#include <linux/slab.h>
42#include <linux/module.h>
43#include <sound/core.h>
44#include <sound/initval.h>
45#include <sound/pcm.h>
46#include <sound/pcm_params.h>
47#include <sound/ac97_codec.h>
48#include <asm/mach-au1x00/au1000.h>
49#include <asm/mach-au1x00/au1000_dma.h>
50
51MODULE_AUTHOR("Charles Eidsness <charles@cooper-street.com>");
52MODULE_DESCRIPTION("Au1000 AC'97 ALSA Driver");
53MODULE_LICENSE("GPL");
54MODULE_SUPPORTED_DEVICE("{{AMD,Au1000 AC'97}}");
55
56#define PLAYBACK 0
57#define CAPTURE 1
58#define AC97_SLOT_3 0x01
59#define AC97_SLOT_4 0x02
60#define AC97_SLOT_6 0x08
61#define AC97_CMD_IRQ 31
62#define READ 0
63#define WRITE 1
64#define READ_WAIT 2
65#define RW_DONE 3
66
67struct au1000_period
68{
69 u32 start;
70 u32 relative_end; /*realtive to start of buffer*/
71 struct au1000_period * next;
72};
73
74/*Au1000 AC97 Port Control Reisters*/
75struct au1000_ac97_reg {
76 u32 volatile config;
77 u32 volatile status;
78 u32 volatile data;
79 u32 volatile cmd;
80 u32 volatile cntrl;
81};
82
83struct audio_stream {
84 struct snd_pcm_substream *substream;
85 int dma;
86 spinlock_t dma_lock;
87 struct au1000_period * buffer;
88 unsigned int period_size;
89 unsigned int periods;
90};
91
92struct snd_au1000 {
93 struct snd_card *card;
94 struct au1000_ac97_reg volatile *ac97_ioport;
95
96 struct resource *ac97_res_port;
97 spinlock_t ac97_lock;
98 struct snd_ac97 *ac97;
99
100 struct snd_pcm *pcm;
101 struct audio_stream *stream[2]; /* playback & capture */
102 int dmaid[2]; /* tx(0)/rx(1) DMA ids */
103};
104
105/*--------------------------- Local Functions --------------------------------*/
106static void
107au1000_set_ac97_xmit_slots(struct snd_au1000 *au1000, long xmit_slots)
108{
109 u32 volatile ac97_config;
110
111 spin_lock(&au1000->ac97_lock);
112 ac97_config = au1000->ac97_ioport->config;
113 ac97_config = ac97_config & ~AC97C_XMIT_SLOTS_MASK;
114 ac97_config |= (xmit_slots << AC97C_XMIT_SLOTS_BIT);
115 au1000->ac97_ioport->config = ac97_config;
116 spin_unlock(&au1000->ac97_lock);
117}
118
119static void
120au1000_set_ac97_recv_slots(struct snd_au1000 *au1000, long recv_slots)
121{
122 u32 volatile ac97_config;
123
124 spin_lock(&au1000->ac97_lock);
125 ac97_config = au1000->ac97_ioport->config;
126 ac97_config = ac97_config & ~AC97C_RECV_SLOTS_MASK;
127 ac97_config |= (recv_slots << AC97C_RECV_SLOTS_BIT);
128 au1000->ac97_ioport->config = ac97_config;
129 spin_unlock(&au1000->ac97_lock);
130}
131
132
133static void
134au1000_release_dma_link(struct audio_stream *stream)
135{
136 struct au1000_period * pointer;
137 struct au1000_period * pointer_next;
138
139 stream->period_size = 0;
140 stream->periods = 0;
141 pointer = stream->buffer;
142 if (! pointer)
143 return;
144 do {
145 pointer_next = pointer->next;
146 kfree(pointer);
147 pointer = pointer_next;
148 } while (pointer != stream->buffer);
149 stream->buffer = NULL;
150}
151
152static int
153au1000_setup_dma_link(struct audio_stream *stream, unsigned int period_bytes,
154 unsigned int periods)
155{
156 struct snd_pcm_substream *substream = stream->substream;
157 struct snd_pcm_runtime *runtime = substream->runtime;
158 struct au1000_period *pointer;
159 unsigned long dma_start;
160 int i;
161
162 dma_start = virt_to_phys(runtime->dma_area);
163
164 if (stream->period_size == period_bytes &&
165 stream->periods == periods)
166 return 0; /* not changed */
167
168 au1000_release_dma_link(stream);
169
170 stream->period_size = period_bytes;
171 stream->periods = periods;
172
173 stream->buffer = kmalloc(sizeof(struct au1000_period), GFP_KERNEL);
174 if (! stream->buffer)
175 return -ENOMEM;
176 pointer = stream->buffer;
177 for (i = 0; i < periods; i++) {
178 pointer->start = (u32)(dma_start + (i * period_bytes));
179 pointer->relative_end = (u32) (((i+1) * period_bytes) - 0x1);
180 if (i < periods - 1) {
181 pointer->next = kmalloc(sizeof(struct au1000_period), GFP_KERNEL);
182 if (! pointer->next) {
183 au1000_release_dma_link(stream);
184 return -ENOMEM;
185 }
186 pointer = pointer->next;
187 }
188 }
189 pointer->next = stream->buffer;
190 return 0;
191}
192
193static void
194au1000_dma_stop(struct audio_stream *stream)
195{
196 if (snd_BUG_ON(!stream->buffer))
197 return;
198 disable_dma(stream->dma);
199}
200
201static void
202au1000_dma_start(struct audio_stream *stream)
203{
204 if (snd_BUG_ON(!stream->buffer))
205 return;
206
207 init_dma(stream->dma);
208 if (get_dma_active_buffer(stream->dma) == 0) {
209 clear_dma_done0(stream->dma);
210 set_dma_addr0(stream->dma, stream->buffer->start);
211 set_dma_count0(stream->dma, stream->period_size >> 1);
212 set_dma_addr1(stream->dma, stream->buffer->next->start);
213 set_dma_count1(stream->dma, stream->period_size >> 1);
214 } else {
215 clear_dma_done1(stream->dma);
216 set_dma_addr1(stream->dma, stream->buffer->start);
217 set_dma_count1(stream->dma, stream->period_size >> 1);
218 set_dma_addr0(stream->dma, stream->buffer->next->start);
219 set_dma_count0(stream->dma, stream->period_size >> 1);
220 }
221 enable_dma_buffers(stream->dma);
222 start_dma(stream->dma);
223}
224
225static irqreturn_t
226au1000_dma_interrupt(int irq, void *dev_id)
227{
228 struct audio_stream *stream = (struct audio_stream *) dev_id;
229 struct snd_pcm_substream *substream = stream->substream;
230
231 spin_lock(&stream->dma_lock);
232 switch (get_dma_buffer_done(stream->dma)) {
233 case DMA_D0:
234 stream->buffer = stream->buffer->next;
235 clear_dma_done0(stream->dma);
236 set_dma_addr0(stream->dma, stream->buffer->next->start);
237 set_dma_count0(stream->dma, stream->period_size >> 1);
238 enable_dma_buffer0(stream->dma);
239 break;
240 case DMA_D1:
241 stream->buffer = stream->buffer->next;
242 clear_dma_done1(stream->dma);
243 set_dma_addr1(stream->dma, stream->buffer->next->start);
244 set_dma_count1(stream->dma, stream->period_size >> 1);
245 enable_dma_buffer1(stream->dma);
246 break;
247 case (DMA_D0 | DMA_D1):
248 printk(KERN_ERR "DMA %d missed interrupt.\n",stream->dma);
249 au1000_dma_stop(stream);
250 au1000_dma_start(stream);
251 break;
252 case (~DMA_D0 & ~DMA_D1):
253 printk(KERN_ERR "DMA %d empty irq.\n",stream->dma);
254 }
255 spin_unlock(&stream->dma_lock);
256 snd_pcm_period_elapsed(substream);
257 return IRQ_HANDLED;
258}
259
260/*-------------------------- PCM Audio Streams -------------------------------*/
261
262static unsigned int rates[] = {8000, 11025, 16000, 22050};
263static struct snd_pcm_hw_constraint_list hw_constraints_rates = {
264 .count = ARRAY_SIZE(rates),
265 .list = rates,
266 .mask = 0,
267};
268
269static struct snd_pcm_hardware snd_au1000_hw =
270{
271 .info = (SNDRV_PCM_INFO_INTERLEAVED | \
272 SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),
273 .formats = SNDRV_PCM_FMTBIT_S16_LE,
274 .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |
275 SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050),
276 .rate_min = 8000,
277 .rate_max = 22050,
278 .channels_min = 1,
279 .channels_max = 2,
280 .buffer_bytes_max = 128*1024,
281 .period_bytes_min = 32,
282 .period_bytes_max = 16*1024,
283 .periods_min = 8,
284 .periods_max = 255,
285 .fifo_size = 16,
286};
287
288static int
289snd_au1000_playback_open(struct snd_pcm_substream *substream)
290{
291 struct snd_au1000 *au1000 = substream->pcm->private_data;
292
293 au1000->stream[PLAYBACK]->substream = substream;
294 au1000->stream[PLAYBACK]->buffer = NULL;
295 substream->private_data = au1000->stream[PLAYBACK];
296 substream->runtime->hw = snd_au1000_hw;
297 return (snd_pcm_hw_constraint_list(substream->runtime, 0,
298 SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates) < 0);
299}
300
301static int
302snd_au1000_capture_open(struct snd_pcm_substream *substream)
303{
304 struct snd_au1000 *au1000 = substream->pcm->private_data;
305
306 au1000->stream[CAPTURE]->substream = substream;
307 au1000->stream[CAPTURE]->buffer = NULL;
308 substream->private_data = au1000->stream[CAPTURE];
309 substream->runtime->hw = snd_au1000_hw;
310 return (snd_pcm_hw_constraint_list(substream->runtime, 0,
311 SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates) < 0);
312}
313
314static int
315snd_au1000_playback_close(struct snd_pcm_substream *substream)
316{
317 struct snd_au1000 *au1000 = substream->pcm->private_data;
318
319 au1000->stream[PLAYBACK]->substream = NULL;
320 return 0;
321}
322
323static int
324snd_au1000_capture_close(struct snd_pcm_substream *substream)
325{
326 struct snd_au1000 *au1000 = substream->pcm->private_data;
327
328 au1000->stream[CAPTURE]->substream = NULL;
329 return 0;
330}
331
332static int
333snd_au1000_hw_params(struct snd_pcm_substream *substream,
334 struct snd_pcm_hw_params *hw_params)
335{
336 struct audio_stream *stream = substream->private_data;
337 int err;
338
339 err = snd_pcm_lib_malloc_pages(substream,
340 params_buffer_bytes(hw_params));
341 if (err < 0)
342 return err;
343 return au1000_setup_dma_link(stream,
344 params_period_bytes(hw_params),
345 params_periods(hw_params));
346}
347
348static int
349snd_au1000_hw_free(struct snd_pcm_substream *substream)
350{
351 struct audio_stream *stream = substream->private_data;
352 au1000_release_dma_link(stream);
353 return snd_pcm_lib_free_pages(substream);
354}
355
356static int
357snd_au1000_playback_prepare(struct snd_pcm_substream *substream)
358{
359 struct snd_au1000 *au1000 = substream->pcm->private_data;
360 struct snd_pcm_runtime *runtime = substream->runtime;
361
362 if (runtime->channels == 1)
363 au1000_set_ac97_xmit_slots(au1000, AC97_SLOT_4);
364 else
365 au1000_set_ac97_xmit_slots(au1000, AC97_SLOT_3 | AC97_SLOT_4);
366 snd_ac97_set_rate(au1000->ac97, AC97_PCM_FRONT_DAC_RATE, runtime->rate);
367 return 0;
368}
369
370static int
371snd_au1000_capture_prepare(struct snd_pcm_substream *substream)
372{
373 struct snd_au1000 *au1000 = substream->pcm->private_data;
374 struct snd_pcm_runtime *runtime = substream->runtime;
375
376 if (runtime->channels == 1)
377 au1000_set_ac97_recv_slots(au1000, AC97_SLOT_4);
378 else
379 au1000_set_ac97_recv_slots(au1000, AC97_SLOT_3 | AC97_SLOT_4);
380 snd_ac97_set_rate(au1000->ac97, AC97_PCM_LR_ADC_RATE, runtime->rate);
381 return 0;
382}
383
384static int
385snd_au1000_trigger(struct snd_pcm_substream *substream, int cmd)
386{
387 struct audio_stream *stream = substream->private_data;
388 int err = 0;
389
390 spin_lock(&stream->dma_lock);
391 switch (cmd) {
392 case SNDRV_PCM_TRIGGER_START:
393 au1000_dma_start(stream);
394 break;
395 case SNDRV_PCM_TRIGGER_STOP:
396 au1000_dma_stop(stream);
397 break;
398 default:
399 err = -EINVAL;
400 break;
401 }
402 spin_unlock(&stream->dma_lock);
403 return err;
404}
405
406static snd_pcm_uframes_t
407snd_au1000_pointer(struct snd_pcm_substream *substream)
408{
409 struct audio_stream *stream = substream->private_data;
410 struct snd_pcm_runtime *runtime = substream->runtime;
411 long location;
412
413 spin_lock(&stream->dma_lock);
414 location = get_dma_residue(stream->dma);
415 spin_unlock(&stream->dma_lock);
416 location = stream->buffer->relative_end - location;
417 if (location == -1)
418 location = 0;
419 return bytes_to_frames(runtime,location);
420}
421
422static struct snd_pcm_ops snd_card_au1000_playback_ops = {
423 .open = snd_au1000_playback_open,
424 .close = snd_au1000_playback_close,
425 .ioctl = snd_pcm_lib_ioctl,
426 .hw_params = snd_au1000_hw_params,
427 .hw_free = snd_au1000_hw_free,
428 .prepare = snd_au1000_playback_prepare,
429 .trigger = snd_au1000_trigger,
430 .pointer = snd_au1000_pointer,
431};
432
433static struct snd_pcm_ops snd_card_au1000_capture_ops = {
434 .open = snd_au1000_capture_open,
435 .close = snd_au1000_capture_close,
436 .ioctl = snd_pcm_lib_ioctl,
437 .hw_params = snd_au1000_hw_params,
438 .hw_free = snd_au1000_hw_free,
439 .prepare = snd_au1000_capture_prepare,
440 .trigger = snd_au1000_trigger,
441 .pointer = snd_au1000_pointer,
442};
443
444static int
445snd_au1000_pcm_new(struct snd_au1000 *au1000)
446{
447 struct snd_pcm *pcm;
448 int err;
449 unsigned long flags;
450
451 if ((err = snd_pcm_new(au1000->card, "AU1000 AC97 PCM", 0, 1, 1, &pcm)) < 0)
452 return err;
453
454 snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
455 snd_dma_continuous_data(GFP_KERNEL), 128*1024, 128*1024);
456
457 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
458 &snd_card_au1000_playback_ops);
459 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
460 &snd_card_au1000_capture_ops);
461
462 pcm->private_data = au1000;
463 pcm->info_flags = 0;
464 strcpy(pcm->name, "Au1000 AC97 PCM");
465
466 spin_lock_init(&au1000->stream[PLAYBACK]->dma_lock);
467 spin_lock_init(&au1000->stream[CAPTURE]->dma_lock);
468
469 flags = claim_dma_lock();
470 au1000->stream[PLAYBACK]->dma = request_au1000_dma(au1000->dmaid[0],
471 "AC97 TX", au1000_dma_interrupt, 0,
472 au1000->stream[PLAYBACK]);
473 if (au1000->stream[PLAYBACK]->dma < 0) {
474 release_dma_lock(flags);
475 return -EBUSY;
476 }
477 au1000->stream[CAPTURE]->dma = request_au1000_dma(au1000->dmaid[1],
478 "AC97 RX", au1000_dma_interrupt, 0,
479 au1000->stream[CAPTURE]);
480 if (au1000->stream[CAPTURE]->dma < 0){
481 release_dma_lock(flags);
482 return -EBUSY;
483 }
484 /* enable DMA coherency in read/write DMA channels */
485 set_dma_mode(au1000->stream[PLAYBACK]->dma,
486 get_dma_mode(au1000->stream[PLAYBACK]->dma) & ~DMA_NC);
487 set_dma_mode(au1000->stream[CAPTURE]->dma,
488 get_dma_mode(au1000->stream[CAPTURE]->dma) & ~DMA_NC);
489 release_dma_lock(flags);
490 au1000->pcm = pcm;
491 return 0;
492}
493
494
495/*-------------------------- AC97 CODEC Control ------------------------------*/
496
497static unsigned short
498snd_au1000_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
499{
500 struct snd_au1000 *au1000 = ac97->private_data;
501 u32 volatile cmd;
502 u16 volatile data;
503 int i;
504
505 spin_lock(&au1000->ac97_lock);
506/* would rather use the interrupt than this polling but it works and I can't
507get the interrupt driven case to work efficiently */
508 for (i = 0; i < 0x5000; i++)
509 if (!(au1000->ac97_ioport->status & AC97C_CP))
510 break;
511 if (i == 0x5000)
512 printk(KERN_ERR "au1000 AC97: AC97 command read timeout\n");
513
514 cmd = (u32) reg & AC97C_INDEX_MASK;
515 cmd |= AC97C_READ;
516 au1000->ac97_ioport->cmd = cmd;
517
518 /* now wait for the data */
519 for (i = 0; i < 0x5000; i++)
520 if (!(au1000->ac97_ioport->status & AC97C_CP))
521 break;
522 if (i == 0x5000) {
523 printk(KERN_ERR "au1000 AC97: AC97 command read timeout\n");
524 spin_unlock(&au1000->ac97_lock);
525 return 0;
526 }
527
528 data = au1000->ac97_ioport->cmd & 0xffff;
529 spin_unlock(&au1000->ac97_lock);
530
531 return data;
532
533}
534
535
536static void
537snd_au1000_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short val)
538{
539 struct snd_au1000 *au1000 = ac97->private_data;
540 u32 cmd;
541 int i;
542
543 spin_lock(&au1000->ac97_lock);
544/* would rather use the interrupt than this polling but it works and I can't
545get the interrupt driven case to work efficiently */
546 for (i = 0; i < 0x5000; i++)
547 if (!(au1000->ac97_ioport->status & AC97C_CP))
548 break;
549 if (i == 0x5000)
550 printk(KERN_ERR "au1000 AC97: AC97 command write timeout\n");
551
552 cmd = (u32) reg & AC97C_INDEX_MASK;
553 cmd &= ~AC97C_READ;
554 cmd |= ((u32) val << AC97C_WD_BIT);
555 au1000->ac97_ioport->cmd = cmd;
556 spin_unlock(&au1000->ac97_lock);
557}
558
559/*------------------------------ Setup / Destroy ----------------------------*/
560
561static void snd_au1000_free(struct snd_card *card)
562{
563 struct snd_au1000 *au1000 = card->private_data;
564
565 if (au1000->stream[PLAYBACK]) {
566 if (au1000->stream[PLAYBACK]->dma >= 0)
567 free_au1000_dma(au1000->stream[PLAYBACK]->dma);
568 kfree(au1000->stream[PLAYBACK]);
569 }
570
571 if (au1000->stream[CAPTURE]) {
572 if (au1000->stream[CAPTURE]->dma >= 0)
573 free_au1000_dma(au1000->stream[CAPTURE]->dma);
574 kfree(au1000->stream[CAPTURE]);
575 }
576
577 if (au1000->ac97_res_port) {
578 /* put internal AC97 block into reset */
579 if (au1000->ac97_ioport) {
580 au1000->ac97_ioport->cntrl = AC97C_RS;
581 iounmap(au1000->ac97_ioport);
582 au1000->ac97_ioport = NULL;
583 }
584 release_and_free_resource(au1000->ac97_res_port);
585 au1000->ac97_res_port = NULL;
586 }
587}
588
589static struct snd_ac97_bus_ops ops = {
590 .write = snd_au1000_ac97_write,
591 .read = snd_au1000_ac97_read,
592};
593
594static int au1000_ac97_probe(struct platform_device *pdev)
595{
596 int err;
597 void __iomem *io;
598 struct resource *r;
599 struct snd_card *card;
600 struct snd_au1000 *au1000;
601 struct snd_ac97_bus *pbus;
602 struct snd_ac97_template ac97;
603
604 err = snd_card_new(&pdev->dev, -1, "AC97", THIS_MODULE,
605 sizeof(struct snd_au1000), &card);
606 if (err < 0)
607 return err;
608
609 au1000 = card->private_data;
610 au1000->card = card;
611 spin_lock_init(&au1000->ac97_lock);
612
613 /* from here on let ALSA call the special freeing function */
614 card->private_free = snd_au1000_free;
615
616 /* TX DMA ID */
617 r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
618 if (!r) {
619 err = -ENODEV;
620 snd_printk(KERN_INFO "no TX DMA platform resource!\n");
621 goto out;
622 }
623 au1000->dmaid[0] = r->start;
624
625 /* RX DMA ID */
626 r = platform_get_resource(pdev, IORESOURCE_DMA, 1);
627 if (!r) {
628 err = -ENODEV;
629 snd_printk(KERN_INFO "no RX DMA platform resource!\n");
630 goto out;
631 }
632 au1000->dmaid[1] = r->start;
633
634 au1000->stream[PLAYBACK] = kmalloc(sizeof(struct audio_stream),
635 GFP_KERNEL);
636 if (!au1000->stream[PLAYBACK]) {
637 err = -ENOMEM;
638 goto out;
639 }
640 au1000->stream[PLAYBACK]->dma = -1;
641
642 au1000->stream[CAPTURE] = kmalloc(sizeof(struct audio_stream),
643 GFP_KERNEL);
644 if (!au1000->stream[CAPTURE]) {
645 err = -ENOMEM;
646 goto out;
647 }
648 au1000->stream[CAPTURE]->dma = -1;
649
650 r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
651 if (!r) {
652 err = -ENODEV;
653 goto out;
654 }
655
656 err = -EBUSY;
657 au1000->ac97_res_port = request_mem_region(r->start, resource_size(r),
658 pdev->name);
659 if (!au1000->ac97_res_port) {
660 snd_printk(KERN_ERR "ALSA AC97: can't grab AC97 port\n");
661 goto out;
662 }
663
664 io = ioremap(r->start, resource_size(r));
665 if (!io)
666 goto out;
667
668 au1000->ac97_ioport = (struct au1000_ac97_reg *)io;
669
670 /* configure pins for AC'97
671 TODO: move to board_setup.c */
672 au_writel(au_readl(SYS_PINFUNC) & ~0x02, SYS_PINFUNC);
673
674 /* Initialise Au1000's AC'97 Control Block */
675 au1000->ac97_ioport->cntrl = AC97C_RS | AC97C_CE;
676 udelay(10);
677 au1000->ac97_ioport->cntrl = AC97C_CE;
678 udelay(10);
679
680 /* Initialise External CODEC -- cold reset */
681 au1000->ac97_ioport->config = AC97C_RESET;
682 udelay(10);
683 au1000->ac97_ioport->config = 0x0;
684 mdelay(5);
685
686 /* Initialise AC97 middle-layer */
687 err = snd_ac97_bus(au1000->card, 0, &ops, au1000, &pbus);
688 if (err < 0)
689 goto out;
690
691 memset(&ac97, 0, sizeof(ac97));
692 ac97.private_data = au1000;
693 err = snd_ac97_mixer(pbus, &ac97, &au1000->ac97);
694 if (err < 0)
695 goto out;
696
697 err = snd_au1000_pcm_new(au1000);
698 if (err < 0)
699 goto out;
700
701 strcpy(card->driver, "Au1000-AC97");
702 strcpy(card->shortname, "AMD Au1000-AC97");
703 sprintf(card->longname, "AMD Au1000--AC97 ALSA Driver");
704
705 err = snd_card_register(card);
706 if (err < 0)
707 goto out;
708
709 printk(KERN_INFO "ALSA AC97: Driver Initialized\n");
710
711 platform_set_drvdata(pdev, card);
712
713 return 0;
714
715 out:
716 snd_card_free(card);
717 return err;
718}
719
720static int au1000_ac97_remove(struct platform_device *pdev)
721{
722 return snd_card_free(platform_get_drvdata(pdev));
723}
724
725struct platform_driver au1000_ac97c_driver = {
726 .driver = {
727 .name = "au1000-ac97c",
728 .owner = THIS_MODULE,
729 },
730 .probe = au1000_ac97_probe,
731 .remove = au1000_ac97_remove,
732};
733
734module_platform_driver(au1000_ac97c_driver);