aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHans-Christian Egtvedt <hans-christian.egtvedt@atmel.com>2009-02-05 07:10:59 -0500
committerTakashi Iwai <tiwai@suse.de>2009-02-05 09:08:48 -0500
commite4967d6016b7785edafdb871e6d3e4426cb4bd1f (patch)
tree28b805892ec72a1f4bec61cb1cf1698187e545d2
parent6bd0dd5f0ec67f654ebf95be8ef414afae1eecb7 (diff)
ALSA: Add ALSA driver for Atmel Audio Bitstream DAC
This patch adds ALSA support for the Audio Bistream DAC found on Atmel AVR32 devices. The ABDAC is an Atmel IP which might show up on AT91 devices in the future, hence making a generic driver which can be utilized by AT91 arch if needed. Datasheet describing the ABDAC peripheral is available in the AT32AP7000 datasheet, http://www.atmel.com/dyn/products/datasheets.asp?family_id=682 Tested on ATSTK1006 + ATSTK1000 with a class D amplifier stage. Signed-off-by: Hans-Christian Egtvedt <hans-christian.egtvedt@atmel.com> Signed-off-by: Takashi Iwai <tiwai@suse.de>
-rw-r--r--include/sound/atmel-abdac.h23
-rw-r--r--sound/atmel/Kconfig11
-rw-r--r--sound/atmel/Makefile3
-rw-r--r--sound/atmel/abdac.c602
4 files changed, 639 insertions, 0 deletions
diff --git a/include/sound/atmel-abdac.h b/include/sound/atmel-abdac.h
new file mode 100644
index 000000000000..edff6a8ba1b5
--- /dev/null
+++ b/include/sound/atmel-abdac.h
@@ -0,0 +1,23 @@
1/*
2 * Driver for the Atmel Audio Bitstream DAC (ABDAC)
3 *
4 * Copyright (C) 2009 Atmel Corporation
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 2 as published
8 * by the Free Software Foundation.
9 */
10#ifndef __INCLUDE_SOUND_ATMEL_ABDAC_H
11#define __INCLUDE_SOUND_ATMEL_ABDAC_H
12
13#include <linux/dw_dmac.h>
14
15/**
16 * struct atmel_abdac_pdata - board specific ABDAC configuration
17 * @dws: DMA slave interface to use for sound playback.
18 */
19struct atmel_abdac_pdata {
20 struct dw_dma_slave dws;
21};
22
23#endif /* __INCLUDE_SOUND_ATMEL_ABDAC_H */
diff --git a/sound/atmel/Kconfig b/sound/atmel/Kconfig
new file mode 100644
index 000000000000..715318e3670f
--- /dev/null
+++ b/sound/atmel/Kconfig
@@ -0,0 +1,11 @@
1menu "Atmel devices (AVR32 and AT91)"
2 depends on AVR32 || ARCH_AT91
3
4config SND_ATMEL_ABDAC
5 tristate "Atmel Audio Bitstream DAC (ABDAC) driver"
6 select SND_PCM
7 depends on DW_DMAC && AVR32
8 help
9 ALSA sound driver for the Atmel Audio Bitstream DAC (ABDAC).
10
11endmenu
diff --git a/sound/atmel/Makefile b/sound/atmel/Makefile
new file mode 100644
index 000000000000..c5a8213f9cb9
--- /dev/null
+++ b/sound/atmel/Makefile
@@ -0,0 +1,3 @@
1snd-atmel-abdac-objs := abdac.o
2
3obj-$(CONFIG_SND_ATMEL_ABDAC) += snd-atmel-abdac.o
diff --git a/sound/atmel/abdac.c b/sound/atmel/abdac.c
new file mode 100644
index 000000000000..28b3c7f7cfe6
--- /dev/null
+++ b/sound/atmel/abdac.c
@@ -0,0 +1,602 @@
1/*
2 * Driver for the Atmel on-chip Audio Bitstream DAC (ABDAC)
3 *
4 * Copyright (C) 2006-2009 Atmel Corporation
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 2 as published by
8 * the Free Software Foundation.
9 */
10#include <linux/clk.h>
11#include <linux/bitmap.h>
12#include <linux/dw_dmac.h>
13#include <linux/dmaengine.h>
14#include <linux/dma-mapping.h>
15#include <linux/init.h>
16#include <linux/interrupt.h>
17#include <linux/module.h>
18#include <linux/platform_device.h>
19#include <linux/io.h>
20
21#include <sound/core.h>
22#include <sound/initval.h>
23#include <sound/pcm.h>
24#include <sound/pcm_params.h>
25#include <sound/atmel-abdac.h>
26
27/* DAC register offsets */
28#define DAC_DATA 0x0000
29#define DAC_CTRL 0x0008
30#define DAC_INT_MASK 0x000c
31#define DAC_INT_EN 0x0010
32#define DAC_INT_DIS 0x0014
33#define DAC_INT_CLR 0x0018
34#define DAC_INT_STATUS 0x001c
35
36/* Bitfields in CTRL */
37#define DAC_SWAP_OFFSET 30
38#define DAC_SWAP_SIZE 1
39#define DAC_EN_OFFSET 31
40#define DAC_EN_SIZE 1
41
42/* Bitfields in INT_MASK/INT_EN/INT_DIS/INT_STATUS/INT_CLR */
43#define DAC_UNDERRUN_OFFSET 28
44#define DAC_UNDERRUN_SIZE 1
45#define DAC_TX_READY_OFFSET 29
46#define DAC_TX_READY_SIZE 1
47
48/* Bit manipulation macros */
49#define DAC_BIT(name) \
50 (1 << DAC_##name##_OFFSET)
51#define DAC_BF(name, value) \
52 (((value) & ((1 << DAC_##name##_SIZE) - 1)) \
53 << DAC_##name##_OFFSET)
54#define DAC_BFEXT(name, value) \
55 (((value) >> DAC_##name##_OFFSET) \
56 & ((1 << DAC_##name##_SIZE) - 1))
57#define DAC_BFINS(name, value, old) \
58 (((old) & ~(((1 << DAC_##name##_SIZE) - 1) \
59 << DAC_##name##_OFFSET)) \
60 | DAC_BF(name, value))
61
62/* Register access macros */
63#define dac_readl(port, reg) \
64 __raw_readl((port)->regs + DAC_##reg)
65#define dac_writel(port, reg, value) \
66 __raw_writel((value), (port)->regs + DAC_##reg)
67
68/*
69 * ABDAC supports a maximum of 6 different rates from a generic clock. The
70 * generic clock has a power of two divider, which gives 6 steps from 192 kHz
71 * to 5112 Hz.
72 */
73#define MAX_NUM_RATES 6
74/* ALSA seems to use rates between 192000 Hz and 5112 Hz. */
75#define RATE_MAX 192000
76#define RATE_MIN 5112
77
78enum {
79 DMA_READY = 0,
80};
81
82struct atmel_abdac_dma {
83 struct dma_chan *chan;
84 struct dw_cyclic_desc *cdesc;
85};
86
87struct atmel_abdac {
88 struct clk *pclk;
89 struct clk *sample_clk;
90 struct platform_device *pdev;
91 struct atmel_abdac_dma dma;
92
93 struct snd_pcm_hw_constraint_list constraints_rates;
94 struct snd_pcm_substream *substream;
95 struct snd_card *card;
96 struct snd_pcm *pcm;
97
98 void __iomem *regs;
99 unsigned long flags;
100 unsigned int rates[MAX_NUM_RATES];
101 unsigned int rates_num;
102 int irq;
103};
104
105#define get_dac(card) ((struct atmel_abdac *)(card)->private_data)
106
107/* This function is called by the DMA driver. */
108static void atmel_abdac_dma_period_done(void *arg)
109{
110 struct atmel_abdac *dac = arg;
111 snd_pcm_period_elapsed(dac->substream);
112}
113
114static int atmel_abdac_prepare_dma(struct atmel_abdac *dac,
115 struct snd_pcm_substream *substream,
116 enum dma_data_direction direction)
117{
118 struct dma_chan *chan = dac->dma.chan;
119 struct dw_cyclic_desc *cdesc;
120 struct snd_pcm_runtime *runtime = substream->runtime;
121 unsigned long buffer_len, period_len;
122
123 /*
124 * We don't do DMA on "complex" transfers, i.e. with
125 * non-halfword-aligned buffers or lengths.
126 */
127 if (runtime->dma_addr & 1 || runtime->buffer_size & 1) {
128 dev_dbg(&dac->pdev->dev, "too complex transfer\n");
129 return -EINVAL;
130 }
131
132 buffer_len = frames_to_bytes(runtime, runtime->buffer_size);
133 period_len = frames_to_bytes(runtime, runtime->period_size);
134
135 cdesc = dw_dma_cyclic_prep(chan, runtime->dma_addr, buffer_len,
136 period_len, DMA_TO_DEVICE);
137 if (IS_ERR(cdesc)) {
138 dev_dbg(&dac->pdev->dev, "could not prepare cyclic DMA\n");
139 return PTR_ERR(cdesc);
140 }
141
142 cdesc->period_callback = atmel_abdac_dma_period_done;
143 cdesc->period_callback_param = dac;
144
145 dac->dma.cdesc = cdesc;
146
147 set_bit(DMA_READY, &dac->flags);
148
149 return 0;
150}
151
152static struct snd_pcm_hardware atmel_abdac_hw = {
153 .info = (SNDRV_PCM_INFO_MMAP
154 | SNDRV_PCM_INFO_MMAP_VALID
155 | SNDRV_PCM_INFO_INTERLEAVED
156 | SNDRV_PCM_INFO_BLOCK_TRANSFER
157 | SNDRV_PCM_INFO_RESUME
158 | SNDRV_PCM_INFO_PAUSE),
159 .formats = (SNDRV_PCM_FMTBIT_S16_BE),
160 .rates = (SNDRV_PCM_RATE_KNOT),
161 .rate_min = RATE_MIN,
162 .rate_max = RATE_MAX,
163 .channels_min = 2,
164 .channels_max = 2,
165 .buffer_bytes_max = 64 * 4096,
166 .period_bytes_min = 4096,
167 .period_bytes_max = 4096,
168 .periods_min = 4,
169 .periods_max = 64,
170};
171
172static int atmel_abdac_open(struct snd_pcm_substream *substream)
173{
174 struct atmel_abdac *dac = snd_pcm_substream_chip(substream);
175
176 dac->substream = substream;
177 atmel_abdac_hw.rate_max = dac->rates[dac->rates_num - 1];
178 atmel_abdac_hw.rate_min = dac->rates[0];
179 substream->runtime->hw = atmel_abdac_hw;
180
181 return snd_pcm_hw_constraint_list(substream->runtime, 0,
182 SNDRV_PCM_HW_PARAM_RATE, &dac->constraints_rates);
183}
184
185static int atmel_abdac_close(struct snd_pcm_substream *substream)
186{
187 struct atmel_abdac *dac = snd_pcm_substream_chip(substream);
188 dac->substream = NULL;
189 return 0;
190}
191
192static int atmel_abdac_hw_params(struct snd_pcm_substream *substream,
193 struct snd_pcm_hw_params *hw_params)
194{
195 struct atmel_abdac *dac = snd_pcm_substream_chip(substream);
196 int retval;
197
198 retval = snd_pcm_lib_malloc_pages(substream,
199 params_buffer_bytes(hw_params));
200 if (retval < 0)
201 return retval;
202 /* snd_pcm_lib_malloc_pages returns 1 if buffer is changed. */
203 if (retval == 1)
204 if (test_and_clear_bit(DMA_READY, &dac->flags))
205 dw_dma_cyclic_free(dac->dma.chan);
206
207 return retval;
208}
209
210static int atmel_abdac_hw_free(struct snd_pcm_substream *substream)
211{
212 struct atmel_abdac *dac = snd_pcm_substream_chip(substream);
213 if (test_and_clear_bit(DMA_READY, &dac->flags))
214 dw_dma_cyclic_free(dac->dma.chan);
215 return snd_pcm_lib_free_pages(substream);
216}
217
218static int atmel_abdac_prepare(struct snd_pcm_substream *substream)
219{
220 struct atmel_abdac *dac = snd_pcm_substream_chip(substream);
221 int retval;
222
223 retval = clk_set_rate(dac->sample_clk, 256 * substream->runtime->rate);
224 if (retval)
225 return retval;
226
227 if (!test_bit(DMA_READY, &dac->flags))
228 retval = atmel_abdac_prepare_dma(dac, substream, DMA_TO_DEVICE);
229
230 return retval;
231}
232
233static int atmel_abdac_trigger(struct snd_pcm_substream *substream, int cmd)
234{
235 struct atmel_abdac *dac = snd_pcm_substream_chip(substream);
236 int retval = 0;
237
238 switch (cmd) {
239 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: /* fall through */
240 case SNDRV_PCM_TRIGGER_RESUME: /* fall through */
241 case SNDRV_PCM_TRIGGER_START:
242 clk_enable(dac->sample_clk);
243 retval = dw_dma_cyclic_start(dac->dma.chan);
244 if (retval)
245 goto out;
246 dac_writel(dac, CTRL, DAC_BIT(EN));
247 break;
248 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: /* fall through */
249 case SNDRV_PCM_TRIGGER_SUSPEND: /* fall through */
250 case SNDRV_PCM_TRIGGER_STOP:
251 dw_dma_cyclic_stop(dac->dma.chan);
252 dac_writel(dac, DATA, 0);
253 dac_writel(dac, CTRL, 0);
254 clk_disable(dac->sample_clk);
255 break;
256 default:
257 retval = -EINVAL;
258 break;
259 }
260out:
261 return retval;
262}
263
264static snd_pcm_uframes_t
265atmel_abdac_pointer(struct snd_pcm_substream *substream)
266{
267 struct atmel_abdac *dac = snd_pcm_substream_chip(substream);
268 struct snd_pcm_runtime *runtime = substream->runtime;
269 snd_pcm_uframes_t frames;
270 unsigned long bytes;
271
272 bytes = dw_dma_get_src_addr(dac->dma.chan);
273 bytes -= runtime->dma_addr;
274
275 frames = bytes_to_frames(runtime, bytes);
276 if (frames >= runtime->buffer_size)
277 frames -= runtime->buffer_size;
278
279 return frames;
280}
281
282static irqreturn_t abdac_interrupt(int irq, void *dev_id)
283{
284 struct atmel_abdac *dac = dev_id;
285 u32 status;
286
287 status = dac_readl(dac, INT_STATUS);
288 if (status & DAC_BIT(UNDERRUN)) {
289 dev_err(&dac->pdev->dev, "underrun detected\n");
290 dac_writel(dac, INT_CLR, DAC_BIT(UNDERRUN));
291 } else {
292 dev_err(&dac->pdev->dev, "spurious interrupt (status=0x%x)\n",
293 status);
294 dac_writel(dac, INT_CLR, status);
295 }
296
297 return IRQ_HANDLED;
298}
299
300static struct snd_pcm_ops atmel_abdac_ops = {
301 .open = atmel_abdac_open,
302 .close = atmel_abdac_close,
303 .ioctl = snd_pcm_lib_ioctl,
304 .hw_params = atmel_abdac_hw_params,
305 .hw_free = atmel_abdac_hw_free,
306 .prepare = atmel_abdac_prepare,
307 .trigger = atmel_abdac_trigger,
308 .pointer = atmel_abdac_pointer,
309};
310
311static int __devinit atmel_abdac_pcm_new(struct atmel_abdac *dac)
312{
313 struct snd_pcm_hardware hw = atmel_abdac_hw;
314 struct snd_pcm *pcm;
315 int retval;
316
317 retval = snd_pcm_new(dac->card, dac->card->shortname,
318 dac->pdev->id, 1, 0, &pcm);
319 if (retval)
320 return retval;
321
322 strcpy(pcm->name, dac->card->shortname);
323 pcm->private_data = dac;
324 pcm->info_flags = 0;
325 dac->pcm = pcm;
326
327 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &atmel_abdac_ops);
328
329 retval = snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
330 &dac->pdev->dev, hw.periods_min * hw.period_bytes_min,
331 hw.buffer_bytes_max);
332
333 return retval;
334}
335
336static bool filter(struct dma_chan *chan, void *slave)
337{
338 struct dw_dma_slave *dws = slave;
339
340 if (dws->dma_dev == chan->device->dev) {
341 chan->private = dws;
342 return true;
343 } else
344 return false;
345}
346
347static int set_sample_rates(struct atmel_abdac *dac)
348{
349 long new_rate = RATE_MAX;
350 int retval = -EINVAL;
351 int index = 0;
352
353 /* we start at 192 kHz and work our way down to 5112 Hz */
354 while (new_rate >= RATE_MIN && index < (MAX_NUM_RATES + 1)) {
355 new_rate = clk_round_rate(dac->sample_clk, 256 * new_rate);
356 if (new_rate < 0)
357 break;
358 /* make sure we are below the ABDAC clock */
359 if (new_rate <= clk_get_rate(dac->pclk)) {
360 dac->rates[index] = new_rate / 256;
361 index++;
362 }
363 /* divide by 256 and then by two to get next rate */
364 new_rate /= 256 * 2;
365 }
366
367 if (index) {
368 int i;
369
370 /* reverse array, smallest go first */
371 for (i = 0; i < (index / 2); i++) {
372 unsigned int tmp = dac->rates[index - 1 - i];
373 dac->rates[index - 1 - i] = dac->rates[i];
374 dac->rates[i] = tmp;
375 }
376
377 dac->constraints_rates.count = index;
378 dac->constraints_rates.list = dac->rates;
379 dac->constraints_rates.mask = 0;
380 dac->rates_num = index;
381
382 retval = 0;
383 }
384
385 return retval;
386}
387
388static int __devinit atmel_abdac_probe(struct platform_device *pdev)
389{
390 struct snd_card *card;
391 struct atmel_abdac *dac;
392 struct resource *regs;
393 struct atmel_abdac_pdata *pdata;
394 struct clk *pclk;
395 struct clk *sample_clk;
396 int retval;
397 int irq;
398
399 regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
400 if (!regs) {
401 dev_dbg(&pdev->dev, "no memory resource\n");
402 return -ENXIO;
403 }
404
405 irq = platform_get_irq(pdev, 0);
406 if (irq < 0) {
407 dev_dbg(&pdev->dev, "could not get IRQ number\n");
408 return irq;
409 }
410
411 pdata = pdev->dev.platform_data;
412 if (!pdata) {
413 dev_dbg(&pdev->dev, "no platform data\n");
414 return -ENXIO;
415 }
416
417 pclk = clk_get(&pdev->dev, "pclk");
418 if (IS_ERR(pclk)) {
419 dev_dbg(&pdev->dev, "no peripheral clock\n");
420 return PTR_ERR(pclk);
421 }
422 sample_clk = clk_get(&pdev->dev, "sample_clk");
423 if (IS_ERR(pclk)) {
424 dev_dbg(&pdev->dev, "no sample clock\n");
425 retval = PTR_ERR(pclk);
426 goto out_put_pclk;
427 }
428 clk_enable(pclk);
429
430 retval = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
431 THIS_MODULE, sizeof(struct atmel_abdac), &card);
432 if (retval) {
433 dev_dbg(&pdev->dev, "could not create sound card device\n");
434 goto out_put_sample_clk;
435 }
436
437 dac = get_dac(card);
438
439 dac->irq = irq;
440 dac->card = card;
441 dac->pclk = pclk;
442 dac->sample_clk = sample_clk;
443 dac->pdev = pdev;
444
445 retval = set_sample_rates(dac);
446 if (retval < 0) {
447 dev_dbg(&pdev->dev, "could not set supported rates\n");
448 goto out_free_card;
449 }
450
451 dac->regs = ioremap(regs->start, regs->end - regs->start + 1);
452 if (!dac->regs) {
453 dev_dbg(&pdev->dev, "could not remap register memory\n");
454 goto out_free_card;
455 }
456
457 /* make sure the DAC is silent and disabled */
458 dac_writel(dac, DATA, 0);
459 dac_writel(dac, CTRL, 0);
460
461 retval = request_irq(irq, abdac_interrupt, 0, "abdac", dac);
462 if (retval) {
463 dev_dbg(&pdev->dev, "could not request irq\n");
464 goto out_unmap_regs;
465 }
466
467 snd_card_set_dev(card, &pdev->dev);
468
469 if (pdata->dws.dma_dev) {
470 struct dw_dma_slave *dws = &pdata->dws;
471 dma_cap_mask_t mask;
472
473 dws->tx_reg = regs->start + DAC_DATA;
474
475 dma_cap_zero(mask);
476 dma_cap_set(DMA_SLAVE, mask);
477
478 dac->dma.chan = dma_request_channel(mask, filter, dws);
479 }
480 if (!pdata->dws.dma_dev || !dac->dma.chan) {
481 dev_dbg(&pdev->dev, "DMA not available\n");
482 retval = -ENODEV;
483 goto out_unset_card_dev;
484 }
485
486 strcpy(card->driver, "Atmel ABDAC");
487 strcpy(card->shortname, "Atmel ABDAC");
488 sprintf(card->longname, "Atmel Audio Bitstream DAC");
489
490 retval = atmel_abdac_pcm_new(dac);
491 if (retval) {
492 dev_dbg(&pdev->dev, "could not register ABDAC pcm device\n");
493 goto out_release_dma;
494 }
495
496 retval = snd_card_register(card);
497 if (retval) {
498 dev_dbg(&pdev->dev, "could not register sound card\n");
499 goto out_release_dma;
500 }
501
502 platform_set_drvdata(pdev, card);
503
504 dev_info(&pdev->dev, "Atmel ABDAC at 0x%p using %s\n",
505 dac->regs, dac->dma.chan->dev->device.bus_id);
506
507 return retval;
508
509out_release_dma:
510 dma_release_channel(dac->dma.chan);
511 dac->dma.chan = NULL;
512out_unset_card_dev:
513 snd_card_set_dev(card, NULL);
514 free_irq(irq, dac);
515out_unmap_regs:
516 iounmap(dac->regs);
517out_free_card:
518 snd_card_free(card);
519out_put_sample_clk:
520 clk_put(sample_clk);
521 clk_disable(pclk);
522out_put_pclk:
523 clk_put(pclk);
524 return retval;
525}
526
527#ifdef CONFIG_PM
528static int atmel_abdac_suspend(struct platform_device *pdev, pm_message_t msg)
529{
530 struct snd_card *card = platform_get_drvdata(pdev);
531 struct atmel_abdac *dac = card->private_data;
532
533 dw_dma_cyclic_stop(dac->dma.chan);
534 clk_disable(dac->sample_clk);
535 clk_disable(dac->pclk);
536
537 return 0;
538}
539
540static int atmel_abdac_resume(struct platform_device *pdev)
541{
542 struct snd_card *card = platform_get_drvdata(pdev);
543 struct atmel_abdac *dac = card->private_data;
544
545 clk_enable(dac->pclk);
546 clk_enable(dac->sample_clk);
547 if (test_bit(DMA_READY, &dac->flags))
548 dw_dma_cyclic_start(dac->dma.chan);
549
550 return 0;
551}
552#else
553#define atmel_abdac_suspend NULL
554#define atmel_abdac_resume NULL
555#endif
556
557static int __devexit atmel_abdac_remove(struct platform_device *pdev)
558{
559 struct snd_card *card = platform_get_drvdata(pdev);
560 struct atmel_abdac *dac = get_dac(card);
561
562 clk_put(dac->sample_clk);
563 clk_disable(dac->pclk);
564 clk_put(dac->pclk);
565
566 dma_release_channel(dac->dma.chan);
567 dac->dma.chan = NULL;
568 snd_card_set_dev(card, NULL);
569 iounmap(dac->regs);
570 free_irq(dac->irq, dac);
571 snd_card_free(card);
572
573 platform_set_drvdata(pdev, NULL);
574
575 return 0;
576}
577
578static struct platform_driver atmel_abdac_driver = {
579 .remove = __devexit_p(atmel_abdac_remove),
580 .driver = {
581 .name = "atmel_abdac",
582 },
583 .suspend = atmel_abdac_suspend,
584 .resume = atmel_abdac_resume,
585};
586
587static int __init atmel_abdac_init(void)
588{
589 return platform_driver_probe(&atmel_abdac_driver,
590 atmel_abdac_probe);
591}
592module_init(atmel_abdac_init);
593
594static void __exit atmel_abdac_exit(void)
595{
596 platform_driver_unregister(&atmel_abdac_driver);
597}
598module_exit(atmel_abdac_exit);
599
600MODULE_LICENSE("GPL");
601MODULE_DESCRIPTION("Driver for Atmel Audio Bitstream DAC (ABDAC)");
602MODULE_AUTHOR("Hans-Christian Egtvedt <hans-christian.egtvedt@atmel.com>");