aboutsummaryrefslogtreecommitdiffstats
path: root/sound/spi
diff options
context:
space:
mode:
authorHans-Christian Egtvedt <hcegtvedt@atmel.com>2007-07-23 10:01:38 -0400
committerJaroslav Kysela <perex@perex.cz>2007-10-16 09:57:50 -0400
commiteafe57084786d5711e434165297f13864697f9f9 (patch)
treea3b6a8cd16caf2396917cea765f1c35f478c99bb /sound/spi
parent3b0a899ca0fca7801127757cfaafb4d8671793f0 (diff)
[ALSA] ALSA sound driver for the AT73C213 DAC using Atmel SSC driver
This patch adds support for the AT73C213 DAC using the misc Atmel SSC driver in I2S mode. The driver also requires a SPI to setup the registers and control volume. It has been tested with an AT32AP7000 on the ATSTK1000 development board. The driver should also work with any Atmel device with an SSC module supported by the Atmel SSC driver (atmel-ssc). The atmel-ssc driver is just submitted to the Linux kernel. Please see mail thread http://lkml.org/lkml/2007/7/16/32 Signed-off-by: Hans-Christian Egtvedt <hcegtvedt@atmel.com> Signed-off-by: Takashi Iwai <tiwai@suse.de> Signed-off-by: Jaroslav Kysela <perex@suse.cz>
Diffstat (limited to 'sound/spi')
-rw-r--r--sound/spi/Kconfig25
-rw-r--r--sound/spi/Makefile3
-rw-r--r--sound/spi/at73c213.c1129
-rw-r--r--sound/spi/at73c213.h119
4 files changed, 1276 insertions, 0 deletions
diff --git a/sound/spi/Kconfig b/sound/spi/Kconfig
index 60fbb2ad87a7..0d08c29213c8 100644
--- a/sound/spi/Kconfig
+++ b/sound/spi/Kconfig
@@ -3,4 +3,29 @@
3menu "SPI devices" 3menu "SPI devices"
4 depends on SND != n 4 depends on SND != n
5 5
6config SND_AT73C213
7 tristate "Atmel AT73C213 DAC driver"
8 depends on ATMEL_SSC
9 select SND_PCM
10 help
11 Say Y here if you want to use the Atmel AT73C213 external DAC. This
12 DAC can be found on Atmel development boards.
13
14 This driver requires the Atmel SSC driver for sound sink, a
15 peripheral found on most AT91 and AVR32 microprocessors.
16
17 To compile this driver as a module, choose M here: the module will be
18 called snd-at73c213.
19
20config SND_AT73C213_TARGET_BITRATE
21 int "Target bitrate for AT73C213"
22 depends on SND_AT73C213
23 default "48000"
24 range 8000 50000
25 help
26 Sets the target bitrate for the bitrate calculator in the driver.
27 Limited by hardware to be between 8000 Hz and 50000 Hz.
28
29 Set to 48000 Hz by default.
30
6endmenu 31endmenu
diff --git a/sound/spi/Makefile b/sound/spi/Makefile
index 30d8ec97cfb6..026fb73f887f 100644
--- a/sound/spi/Makefile
+++ b/sound/spi/Makefile
@@ -1,2 +1,5 @@
1# Makefile for SPI drivers 1# Makefile for SPI drivers
2 2
3snd-at73c213-objs := at73c213.o
4
5obj-$(CONFIG_SND_AT73C213) += snd-at73c213.o
diff --git a/sound/spi/at73c213.c b/sound/spi/at73c213.c
new file mode 100644
index 000000000000..fee869bcc959
--- /dev/null
+++ b/sound/spi/at73c213.c
@@ -0,0 +1,1129 @@
1/*
2 * Driver for AT73C213 16-bit stereo DAC connected to Atmel SSC
3 *
4 * Copyright (C) 2006-2007 Atmel Norway
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
11/*#define DEBUG*/
12
13#include <linux/clk.h>
14#include <linux/err.h>
15#include <linux/delay.h>
16#include <linux/device.h>
17#include <linux/dma-mapping.h>
18#include <linux/init.h>
19#include <linux/interrupt.h>
20#include <linux/module.h>
21#include <linux/platform_device.h>
22#include <linux/io.h>
23
24#include <sound/driver.h>
25#include <sound/initval.h>
26#include <sound/control.h>
27#include <sound/core.h>
28#include <sound/pcm.h>
29
30#include <linux/atmel-ssc.h>
31
32#include <linux/spi/spi.h>
33#include <linux/spi/at73c213.h>
34
35#include "at73c213.h"
36
37#define BITRATE_MIN 8000 /* Hardware limit? */
38#define BITRATE_TARGET CONFIG_SND_AT73C213_TARGET_BITRATE
39#define BITRATE_MAX 50000 /* Hardware limit. */
40
41/* Initial (hardware reset) AT73C213 register values. */
42static u8 snd_at73c213_original_image[18] =
43{
44 0x00, /* 00 - CTRL */
45 0x05, /* 01 - LLIG */
46 0x05, /* 02 - RLIG */
47 0x08, /* 03 - LPMG */
48 0x08, /* 04 - RPMG */
49 0x00, /* 05 - LLOG */
50 0x00, /* 06 - RLOG */
51 0x22, /* 07 - OLC */
52 0x09, /* 08 - MC */
53 0x00, /* 09 - CSFC */
54 0x00, /* 0A - MISC */
55 0x00, /* 0B - */
56 0x00, /* 0C - PRECH */
57 0x05, /* 0D - AUXG */
58 0x00, /* 0E - */
59 0x00, /* 0F - */
60 0x00, /* 10 - RST */
61 0x00, /* 11 - PA_CTRL */
62};
63
64struct snd_at73c213 {
65 struct snd_card *card;
66 struct snd_pcm *pcm;
67 struct snd_pcm_substream *substream;
68 struct at73c213_board_info *board;
69 int irq;
70 int period;
71 unsigned long bitrate;
72 struct clk *bitclk;
73 struct ssc_device *ssc;
74 struct spi_device *spi;
75 u8 spi_wbuffer[2];
76 u8 spi_rbuffer[2];
77 /* Image of the SPI registers in AT73C213. */
78 u8 reg_image[18];
79 /* Protect registers against concurrent access. */
80 spinlock_t lock;
81};
82
83#define get_chip(card) ((struct snd_at73c213 *)card->private_data)
84
85static int
86snd_at73c213_write_reg(struct snd_at73c213 *chip, u8 reg, u8 val)
87{
88 struct spi_message msg;
89 struct spi_transfer msg_xfer = {
90 .len = 2,
91 .cs_change = 0,
92 };
93 int retval;
94
95 spi_message_init(&msg);
96
97 chip->spi_wbuffer[0] = reg;
98 chip->spi_wbuffer[1] = val;
99
100 msg_xfer.tx_buf = chip->spi_wbuffer;
101 msg_xfer.rx_buf = chip->spi_rbuffer;
102 spi_message_add_tail(&msg_xfer, &msg);
103
104 retval = spi_sync(chip->spi, &msg);
105
106 if (!retval)
107 chip->reg_image[reg] = val;
108
109 return retval;
110}
111
112static struct snd_pcm_hardware snd_at73c213_playback_hw = {
113 .info = SNDRV_PCM_INFO_INTERLEAVED |
114 SNDRV_PCM_INFO_BLOCK_TRANSFER,
115 .formats = SNDRV_PCM_FMTBIT_S16_BE,
116 .rates = SNDRV_PCM_RATE_CONTINUOUS,
117 .rate_min = 8000, /* Replaced by chip->bitrate later. */
118 .rate_max = 50000, /* Replaced by chip->bitrate later. */
119 .channels_min = 2,
120 .channels_max = 2,
121 .buffer_bytes_max = 64 * 1024 - 1,
122 .period_bytes_min = 512,
123 .period_bytes_max = 64 * 1024 - 1,
124 .periods_min = 4,
125 .periods_max = 1024,
126};
127
128/*
129 * Calculate and set bitrate and divisions.
130 */
131static int snd_at73c213_set_bitrate(struct snd_at73c213 *chip)
132{
133 unsigned long ssc_rate = clk_get_rate(chip->ssc->clk);
134 unsigned long dac_rate_new, ssc_div, status;
135 unsigned long ssc_div_max, ssc_div_min;
136 int max_tries;
137
138 /*
139 * We connect two clocks here, picking divisors so the I2S clocks
140 * out data at the same rate the DAC clocks it in ... and as close
141 * as practical to the desired target rate.
142 *
143 * The DAC master clock (MCLK) is programmable, and is either 256
144 * or (not here) 384 times the I2S output clock (BCLK).
145 */
146
147 /* SSC clock / (bitrate * stereo * 16-bit). */
148 ssc_div = ssc_rate / (BITRATE_TARGET * 2 * 16);
149 ssc_div_min = ssc_rate / (BITRATE_MAX * 2 * 16);
150 ssc_div_max = ssc_rate / (BITRATE_MIN * 2 * 16);
151 max_tries = (ssc_div_max - ssc_div_min) / 2;
152
153 if (max_tries < 1)
154 max_tries = 1;
155
156 /* ssc_div must be a power of 2. */
157 ssc_div = (ssc_div + 1) & ~1UL;
158
159 if ((ssc_rate / (ssc_div * 2 * 16)) < BITRATE_MIN) {
160 ssc_div -= 2;
161 if ((ssc_rate / (ssc_div * 2 * 16)) > BITRATE_MAX)
162 return -ENXIO;
163 }
164
165 /* Search for a possible bitrate. */
166 do {
167 /* SSC clock / (ssc divider * 16-bit * stereo). */
168 if ((ssc_rate / (ssc_div * 2 * 16)) < BITRATE_MIN)
169 return -ENXIO;
170
171 /* 256 / (2 * 16) = 8 */
172 dac_rate_new = 8 * (ssc_rate / ssc_div);
173
174 status = clk_round_rate(chip->board->dac_clk, dac_rate_new);
175 if (status < 0)
176 return status;
177
178 /* Ignore difference smaller than 256 Hz. */
179 if ((status/256) == (dac_rate_new/256))
180 goto set_rate;
181
182 ssc_div += 2;
183 } while (--max_tries);
184
185 /* Not able to find a valid bitrate. */
186 return -ENXIO;
187
188set_rate:
189 status = clk_set_rate(chip->board->dac_clk, status);
190 if (status < 0)
191 return status;
192
193 /* Set divider in SSC device. */
194 ssc_writel(chip->ssc->regs, CMR, ssc_div/2);
195
196 /* SSC clock / (ssc divider * 16-bit * stereo). */
197 chip->bitrate = ssc_rate / (ssc_div * 16 * 2);
198
199 dev_info(&chip->spi->dev,
200 "at73c213: supported bitrate is %lu (%lu divider)\n",
201 chip->bitrate, ssc_div);
202
203 return 0;
204}
205
206static int snd_at73c213_pcm_open(struct snd_pcm_substream *substream)
207{
208 struct snd_at73c213 *chip = snd_pcm_substream_chip(substream);
209 struct snd_pcm_runtime *runtime = substream->runtime;
210
211 snd_at73c213_playback_hw.rate_min = chip->bitrate;
212 snd_at73c213_playback_hw.rate_max = chip->bitrate;
213 runtime->hw = snd_at73c213_playback_hw;
214 chip->substream = substream;
215
216 return 0;
217}
218
219static int snd_at73c213_pcm_close(struct snd_pcm_substream *substream)
220{
221 struct snd_at73c213 *chip = snd_pcm_substream_chip(substream);
222 chip->substream = NULL;
223 return 0;
224}
225
226static int snd_at73c213_pcm_hw_params(struct snd_pcm_substream *substream,
227 struct snd_pcm_hw_params *hw_params)
228{
229 return snd_pcm_lib_malloc_pages(substream,
230 params_buffer_bytes(hw_params));
231}
232
233static int snd_at73c213_pcm_hw_free(struct snd_pcm_substream *substream)
234{
235 return snd_pcm_lib_free_pages(substream);
236}
237
238static int snd_at73c213_pcm_prepare(struct snd_pcm_substream *substream)
239{
240 struct snd_at73c213 *chip = snd_pcm_substream_chip(substream);
241 struct snd_pcm_runtime *runtime = substream->runtime;
242 int block_size;
243
244 block_size = frames_to_bytes(runtime, runtime->period_size);
245
246 chip->period = 0;
247
248 ssc_writel(chip->ssc->regs, PDC_TPR,
249 (long)runtime->dma_addr);
250 ssc_writel(chip->ssc->regs, PDC_TCR, runtime->period_size * 2);
251 ssc_writel(chip->ssc->regs, PDC_TNPR,
252 (long)runtime->dma_addr + block_size);
253 ssc_writel(chip->ssc->regs, PDC_TNCR, runtime->period_size * 2);
254
255 return 0;
256}
257
258static int snd_at73c213_pcm_trigger(struct snd_pcm_substream *substream,
259 int cmd)
260{
261 struct snd_at73c213 *chip = snd_pcm_substream_chip(substream);
262 int retval = 0;
263
264 spin_lock(&chip->lock);
265
266 switch (cmd) {
267 case SNDRV_PCM_TRIGGER_START:
268 ssc_writel(chip->ssc->regs, IER, SSC_BIT(IER_ENDTX));
269 ssc_writel(chip->ssc->regs, PDC_PTCR, SSC_BIT(PDC_PTCR_TXTEN));
270 break;
271 case SNDRV_PCM_TRIGGER_STOP:
272 ssc_writel(chip->ssc->regs, PDC_PTCR, SSC_BIT(PDC_PTCR_TXTDIS));
273 ssc_writel(chip->ssc->regs, IDR, SSC_BIT(IDR_ENDTX));
274 break;
275 default:
276 dev_dbg(&chip->spi->dev, "spurious command %x\n", cmd);
277 retval = -EINVAL;
278 break;
279 }
280
281 spin_unlock(&chip->lock);
282
283 return retval;
284}
285
286static snd_pcm_uframes_t
287snd_at73c213_pcm_pointer(struct snd_pcm_substream *substream)
288{
289 struct snd_at73c213 *chip = snd_pcm_substream_chip(substream);
290 struct snd_pcm_runtime *runtime = substream->runtime;
291 snd_pcm_uframes_t pos;
292 unsigned long bytes;
293
294 bytes = ssc_readl(chip->ssc->regs, PDC_TPR)
295 - (unsigned long)runtime->dma_addr;
296
297 pos = bytes_to_frames(runtime, bytes);
298 if (pos >= runtime->buffer_size)
299 pos -= runtime->buffer_size;
300
301 return pos;
302}
303
304static struct snd_pcm_ops at73c213_playback_ops = {
305 .open = snd_at73c213_pcm_open,
306 .close = snd_at73c213_pcm_close,
307 .ioctl = snd_pcm_lib_ioctl,
308 .hw_params = snd_at73c213_pcm_hw_params,
309 .hw_free = snd_at73c213_pcm_hw_free,
310 .prepare = snd_at73c213_pcm_prepare,
311 .trigger = snd_at73c213_pcm_trigger,
312 .pointer = snd_at73c213_pcm_pointer,
313};
314
315static void snd_at73c213_pcm_free(struct snd_pcm *pcm)
316{
317 struct snd_at73c213 *chip = snd_pcm_chip(pcm);
318 if (chip->pcm) {
319 snd_pcm_lib_preallocate_free_for_all(chip->pcm);
320 chip->pcm = NULL;
321 }
322}
323
324static int __devinit snd_at73c213_pcm_new(struct snd_at73c213 *chip, int device)
325{
326 struct snd_pcm *pcm;
327 int retval;
328
329 retval = snd_pcm_new(chip->card, chip->card->shortname,
330 device, 1, 0, &pcm);
331 if (retval < 0)
332 goto out;
333
334 pcm->private_data = chip;
335 pcm->private_free = snd_at73c213_pcm_free;
336 pcm->info_flags = SNDRV_PCM_INFO_BLOCK_TRANSFER;
337 strcpy(pcm->name, "at73c213");
338 chip->pcm = pcm;
339
340 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &at73c213_playback_ops);
341
342 retval = snd_pcm_lib_preallocate_pages_for_all(chip->pcm,
343 SNDRV_DMA_TYPE_DEV, &chip->ssc->pdev->dev,
344 64 * 1024, 64 * 1024);
345out:
346 return retval;
347}
348
349static irqreturn_t snd_at73c213_interrupt(int irq, void *dev_id)
350{
351 struct snd_at73c213 *chip = dev_id;
352 struct snd_pcm_runtime *runtime = chip->substream->runtime;
353 u32 status;
354 int offset;
355 int block_size;
356 int next_period;
357 int retval = IRQ_NONE;
358
359 spin_lock(&chip->lock);
360
361 block_size = frames_to_bytes(runtime, runtime->period_size);
362 status = ssc_readl(chip->ssc->regs, IMR);
363
364 if (status & SSC_BIT(IMR_ENDTX)) {
365 chip->period++;
366 if (chip->period == runtime->periods)
367 chip->period = 0;
368 next_period = chip->period + 1;
369 if (next_period == runtime->periods)
370 next_period = 0;
371
372 offset = block_size * next_period;
373
374 ssc_writel(chip->ssc->regs, PDC_TNPR,
375 (long)runtime->dma_addr + offset);
376 ssc_writel(chip->ssc->regs, PDC_TNCR, runtime->period_size * 2);
377 retval = IRQ_HANDLED;
378 }
379
380 ssc_readl(chip->ssc->regs, IMR);
381 spin_unlock(&chip->lock);
382
383 if (status & SSC_BIT(IMR_ENDTX))
384 snd_pcm_period_elapsed(chip->substream);
385
386 return retval;
387}
388
389/*
390 * Mixer functions.
391 */
392static int snd_at73c213_mono_get(struct snd_kcontrol *kcontrol,
393 struct snd_ctl_elem_value *ucontrol)
394{
395 struct snd_at73c213 *chip = snd_kcontrol_chip(kcontrol);
396 int reg = kcontrol->private_value & 0xff;
397 int shift = (kcontrol->private_value >> 8) & 0xff;
398 int mask = (kcontrol->private_value >> 16) & 0xff;
399 int invert = (kcontrol->private_value >> 24) & 0xff;
400
401 spin_lock_irq(&chip->lock);
402
403 ucontrol->value.integer.value[0] =
404 (chip->reg_image[reg] >> shift) & mask;
405
406 if (invert)
407 ucontrol->value.integer.value[0] =
408 mask - ucontrol->value.integer.value[0];
409
410 spin_unlock_irq(&chip->lock);
411
412 return 0;
413}
414
415static int snd_at73c213_mono_put(struct snd_kcontrol *kcontrol,
416 struct snd_ctl_elem_value *ucontrol)
417{
418 struct snd_at73c213 *chip = snd_kcontrol_chip(kcontrol);
419 int reg = kcontrol->private_value & 0xff;
420 int shift = (kcontrol->private_value >> 8) & 0xff;
421 int mask = (kcontrol->private_value >> 16) & 0xff;
422 int invert = (kcontrol->private_value >> 24) & 0xff;
423 int change, retval;
424 unsigned short val;
425
426 val = (ucontrol->value.integer.value[0] & mask);
427 if (invert)
428 val = mask - val;
429 val <<= shift;
430
431 spin_lock_irq(&chip->lock);
432
433 val = (chip->reg_image[reg] & ~(mask << shift)) | val;
434 change = val != chip->reg_image[reg];
435 retval = snd_at73c213_write_reg(chip, reg, val);
436
437 spin_unlock_irq(&chip->lock);
438
439 if (retval)
440 return retval;
441
442 return change;
443}
444
445static int snd_at73c213_stereo_info(struct snd_kcontrol *kcontrol,
446 struct snd_ctl_elem_info *uinfo)
447{
448 int mask = (kcontrol->private_value >> 24) & 0xff;
449
450 if (mask == 1)
451 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
452 else
453 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
454
455 uinfo->count = 2;
456 uinfo->value.integer.min = 0;
457 uinfo->value.integer.max = mask;
458
459 return 0;
460}
461
462static int snd_at73c213_stereo_get(struct snd_kcontrol *kcontrol,
463 struct snd_ctl_elem_value *ucontrol)
464{
465 struct snd_at73c213 *chip = snd_kcontrol_chip(kcontrol);
466 int left_reg = kcontrol->private_value & 0xff;
467 int right_reg = (kcontrol->private_value >> 8) & 0xff;
468 int shift_left = (kcontrol->private_value >> 16) & 0x07;
469 int shift_right = (kcontrol->private_value >> 19) & 0x07;
470 int mask = (kcontrol->private_value >> 24) & 0xff;
471 int invert = (kcontrol->private_value >> 22) & 1;
472
473 spin_lock_irq(&chip->lock);
474
475 ucontrol->value.integer.value[0] =
476 (chip->reg_image[left_reg] >> shift_left) & mask;
477 ucontrol->value.integer.value[1] =
478 (chip->reg_image[right_reg] >> shift_right) & mask;
479
480 if (invert) {
481 ucontrol->value.integer.value[0] =
482 mask - ucontrol->value.integer.value[0];
483 ucontrol->value.integer.value[1] =
484 mask - ucontrol->value.integer.value[1];
485 }
486
487 spin_unlock_irq(&chip->lock);
488
489 return 0;
490}
491
492static int snd_at73c213_stereo_put(struct snd_kcontrol *kcontrol,
493 struct snd_ctl_elem_value *ucontrol)
494{
495 struct snd_at73c213 *chip = snd_kcontrol_chip(kcontrol);
496 int left_reg = kcontrol->private_value & 0xff;
497 int right_reg = (kcontrol->private_value >> 8) & 0xff;
498 int shift_left = (kcontrol->private_value >> 16) & 0x07;
499 int shift_right = (kcontrol->private_value >> 19) & 0x07;
500 int mask = (kcontrol->private_value >> 24) & 0xff;
501 int invert = (kcontrol->private_value >> 22) & 1;
502 int change, retval;
503 unsigned short val1, val2;
504
505 val1 = ucontrol->value.integer.value[0] & mask;
506 val2 = ucontrol->value.integer.value[1] & mask;
507 if (invert) {
508 val1 = mask - val1;
509 val2 = mask - val2;
510 }
511 val1 <<= shift_left;
512 val2 <<= shift_right;
513
514 spin_lock_irq(&chip->lock);
515
516 val1 = (chip->reg_image[left_reg] & ~(mask << shift_left)) | val1;
517 val2 = (chip->reg_image[right_reg] & ~(mask << shift_right)) | val2;
518 change = val1 != chip->reg_image[left_reg]
519 || val2 != chip->reg_image[right_reg];
520 retval = snd_at73c213_write_reg(chip, left_reg, val1);
521 if (retval) {
522 spin_unlock_irq(&chip->lock);
523 goto out;
524 }
525 retval = snd_at73c213_write_reg(chip, right_reg, val2);
526 if (retval) {
527 spin_unlock_irq(&chip->lock);
528 goto out;
529 }
530
531 spin_unlock_irq(&chip->lock);
532
533 return change;
534
535out:
536 return retval;
537}
538
539static int snd_at73c213_mono_switch_info(struct snd_kcontrol *kcontrol,
540 struct snd_ctl_elem_info *uinfo)
541{
542 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
543 uinfo->count = 1;
544 uinfo->value.integer.min = 0;
545 uinfo->value.integer.max = 1;
546
547 return 0;
548}
549
550static int snd_at73c213_mono_switch_get(struct snd_kcontrol *kcontrol,
551 struct snd_ctl_elem_value *ucontrol)
552{
553 struct snd_at73c213 *chip = snd_kcontrol_chip(kcontrol);
554 int reg = kcontrol->private_value & 0xff;
555 int shift = (kcontrol->private_value >> 8) & 0xff;
556 int invert = (kcontrol->private_value >> 24) & 0xff;
557
558 spin_lock_irq(&chip->lock);
559
560 ucontrol->value.integer.value[0] =
561 (chip->reg_image[reg] >> shift) & 0x01;
562
563 if (invert)
564 ucontrol->value.integer.value[0] =
565 0x01 - ucontrol->value.integer.value[0];
566
567 spin_unlock_irq(&chip->lock);
568
569 return 0;
570}
571
572static int snd_at73c213_mono_switch_put(struct snd_kcontrol *kcontrol,
573 struct snd_ctl_elem_value *ucontrol)
574{
575 struct snd_at73c213 *chip = snd_kcontrol_chip(kcontrol);
576 int reg = kcontrol->private_value & 0xff;
577 int shift = (kcontrol->private_value >> 8) & 0xff;
578 int mask = (kcontrol->private_value >> 16) & 0xff;
579 int invert = (kcontrol->private_value >> 24) & 0xff;
580 int change, retval;
581 unsigned short val;
582
583 if (ucontrol->value.integer.value[0])
584 val = mask;
585 else
586 val = 0;
587
588 if (invert)
589 val = mask - val;
590 val <<= shift;
591
592 spin_lock_irq(&chip->lock);
593
594 val |= (chip->reg_image[reg] & ~(mask << shift));
595 change = val != chip->reg_image[reg];
596
597 retval = snd_at73c213_write_reg(chip, reg, val);
598
599 spin_unlock_irq(&chip->lock);
600
601 if (retval)
602 return retval;
603
604 return change;
605}
606
607static int snd_at73c213_pa_volume_info(struct snd_kcontrol *kcontrol,
608 struct snd_ctl_elem_info *uinfo)
609{
610 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
611 uinfo->count = 1;
612 uinfo->value.integer.min = 0;
613 uinfo->value.integer.max = ((kcontrol->private_value >> 16) & 0xff) - 1;
614
615 return 0;
616}
617
618static int snd_at73c213_line_capture_volume_info(
619 struct snd_kcontrol *kcontrol,
620 struct snd_ctl_elem_info *uinfo)
621{
622 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
623 uinfo->count = 2;
624 /* When inverted will give values 0x10001 => 0. */
625 uinfo->value.integer.min = 14;
626 uinfo->value.integer.max = 31;
627
628 return 0;
629}
630
631static int snd_at73c213_aux_capture_volume_info(
632 struct snd_kcontrol *kcontrol,
633 struct snd_ctl_elem_info *uinfo)
634{
635 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
636 uinfo->count = 1;
637 /* When inverted will give values 0x10001 => 0. */
638 uinfo->value.integer.min = 14;
639 uinfo->value.integer.max = 31;
640
641 return 0;
642}
643
644#define AT73C213_MONO_SWITCH(xname, xindex, reg, shift, mask, invert) \
645{ \
646 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
647 .name = xname, \
648 .index = xindex, \
649 .info = snd_at73c213_mono_switch_info, \
650 .get = snd_at73c213_mono_switch_get, \
651 .put = snd_at73c213_mono_switch_put, \
652 .private_value = (reg | (shift << 8) | (mask << 16) | (invert << 24)) \
653}
654
655#define AT73C213_STEREO(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert) \
656{ \
657 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
658 .name = xname, \
659 .index = xindex, \
660 .info = snd_at73c213_stereo_info, \
661 .get = snd_at73c213_stereo_get, \
662 .put = snd_at73c213_stereo_put, \
663 .private_value = (left_reg | (right_reg << 8) \
664 | (shift_left << 16) | (shift_right << 19) \
665 | (mask << 24) | (invert << 22)) \
666}
667
668static struct snd_kcontrol_new snd_at73c213_controls[] __devinitdata = {
669AT73C213_STEREO("Master Playback Volume", 0, DAC_LMPG, DAC_RMPG, 0, 0, 0x1f, 1),
670AT73C213_STEREO("Master Playback Switch", 0, DAC_LMPG, DAC_RMPG, 5, 5, 1, 1),
671AT73C213_STEREO("PCM Playback Volume", 0, DAC_LLOG, DAC_RLOG, 0, 0, 0x1f, 1),
672AT73C213_STEREO("PCM Playback Switch", 0, DAC_LLOG, DAC_RLOG, 5, 5, 1, 1),
673AT73C213_MONO_SWITCH("Mono PA Playback Switch", 0, DAC_CTRL, DAC_CTRL_ONPADRV,
674 0x01, 0),
675{
676 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
677 .name = "PA Playback Volume",
678 .index = 0,
679 .info = snd_at73c213_pa_volume_info,
680 .get = snd_at73c213_mono_get,
681 .put = snd_at73c213_mono_put,
682 .private_value = PA_CTRL | (PA_CTRL_APAGAIN << 8) | \
683 (0x0f << 16) | (1 << 24),
684},
685AT73C213_MONO_SWITCH("PA High Gain Playback Switch", 0, PA_CTRL, PA_CTRL_APALP,
686 0x01, 1),
687AT73C213_MONO_SWITCH("PA Playback Switch", 0, PA_CTRL, PA_CTRL_APAON, 0x01, 0),
688{
689 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
690 .name = "Aux Capture Volume",
691 .index = 0,
692 .info = snd_at73c213_aux_capture_volume_info,
693 .get = snd_at73c213_mono_get,
694 .put = snd_at73c213_mono_put,
695 .private_value = DAC_AUXG | (0 << 8) | (0x1f << 16) | (1 << 24),
696},
697AT73C213_MONO_SWITCH("Aux Capture Switch", 0, DAC_CTRL, DAC_CTRL_ONAUXIN,
698 0x01, 0),
699{
700 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
701 .name = "Line Capture Volume",
702 .index = 0,
703 .info = snd_at73c213_line_capture_volume_info,
704 .get = snd_at73c213_stereo_get,
705 .put = snd_at73c213_stereo_put,
706 .private_value = DAC_LLIG | (DAC_RLIG << 8) | (0 << 16) | (0 << 19)
707 | (0x1f << 24) | (1 << 22),
708},
709AT73C213_MONO_SWITCH("Line Capture Switch", 0, DAC_CTRL, 0, 0x03, 0),
710};
711
712static int __devinit snd_at73c213_mixer(struct snd_at73c213 *chip)
713{
714 struct snd_card *card;
715 int errval, idx;
716
717 if (chip == NULL || chip->pcm == NULL)
718 return -EINVAL;
719
720 card = chip->card;
721
722 strcpy(card->mixername, chip->pcm->name);
723
724 for (idx = 0; idx < ARRAY_SIZE(snd_at73c213_controls); idx++) {
725 errval = snd_ctl_add(card,
726 snd_ctl_new1(&snd_at73c213_controls[idx],
727 chip));
728 if (errval < 0)
729 goto cleanup;
730 }
731
732 return 0;
733
734cleanup:
735 for (idx = 1; idx < ARRAY_SIZE(snd_at73c213_controls) + 1; idx++) {
736 struct snd_kcontrol *kctl;
737 kctl = snd_ctl_find_numid(card, idx);
738 if (kctl)
739 snd_ctl_remove(card, kctl);
740 }
741 return errval;
742}
743
744/*
745 * Device functions
746 */
747static int snd_at73c213_ssc_init(struct snd_at73c213 *chip)
748{
749 /*
750 * Continuous clock output.
751 * Starts on falling TF.
752 * Delay 1 cycle (1 bit).
753 * Periode is 16 bit (16 - 1).
754 */
755 ssc_writel(chip->ssc->regs, TCMR,
756 SSC_BF(TCMR_CKO, 1)
757 | SSC_BF(TCMR_START, 4)
758 | SSC_BF(TCMR_STTDLY, 1)
759 | SSC_BF(TCMR_PERIOD, 16 - 1));
760 /*
761 * Data length is 16 bit (16 - 1).
762 * Transmit MSB first.
763 * Transmit 2 words each transfer.
764 * Frame sync length is 16 bit (16 - 1).
765 * Frame starts on negative pulse.
766 */
767 ssc_writel(chip->ssc->regs, TFMR,
768 SSC_BF(TFMR_DATLEN, 16 - 1)
769 | SSC_BIT(TFMR_MSBF)
770 | SSC_BF(TFMR_DATNB, 1)
771 | SSC_BF(TFMR_FSLEN, 16 - 1)
772 | SSC_BF(TFMR_FSOS, 1));
773
774 return 0;
775}
776
777static int snd_at73c213_chip_init(struct snd_at73c213 *chip)
778{
779 int retval;
780 unsigned char dac_ctrl = 0;
781
782 retval = snd_at73c213_set_bitrate(chip);
783 if (retval)
784 goto out;
785
786 /* Enable DAC master clock. */
787 clk_enable(chip->board->dac_clk);
788
789 /* Initialize at73c213 on SPI bus. */
790 retval = snd_at73c213_write_reg(chip, DAC_RST, 0x04);
791 if (retval)
792 goto out_clk;
793 msleep(1);
794 retval = snd_at73c213_write_reg(chip, DAC_RST, 0x03);
795 if (retval)
796 goto out_clk;
797
798 /* Precharge everything. */
799 retval = snd_at73c213_write_reg(chip, DAC_PRECH, 0xff);
800 if (retval)
801 goto out_clk;
802 retval = snd_at73c213_write_reg(chip, PA_CTRL, (1<<PA_CTRL_APAPRECH));
803 if (retval)
804 goto out_clk;
805 retval = snd_at73c213_write_reg(chip, DAC_CTRL,
806 (1<<DAC_CTRL_ONLNOL) | (1<<DAC_CTRL_ONLNOR));
807 if (retval)
808 goto out_clk;
809
810 msleep(50);
811
812 /* Stop precharging PA. */
813 retval = snd_at73c213_write_reg(chip, PA_CTRL,
814 (1<<PA_CTRL_APALP) | 0x0f);
815 if (retval)
816 goto out_clk;
817
818 msleep(450);
819
820 /* Stop precharging DAC, turn on master power. */
821 retval = snd_at73c213_write_reg(chip, DAC_PRECH, (1<<DAC_PRECH_ONMSTR));
822 if (retval)
823 goto out_clk;
824
825 msleep(1);
826
827 /* Turn on DAC. */
828 dac_ctrl = (1<<DAC_CTRL_ONDACL) | (1<<DAC_CTRL_ONDACR)
829 | (1<<DAC_CTRL_ONLNOL) | (1<<DAC_CTRL_ONLNOR);
830
831 retval = snd_at73c213_write_reg(chip, DAC_CTRL, dac_ctrl);
832 if (retval)
833 goto out_clk;
834
835 /* Mute sound. */
836 retval = snd_at73c213_write_reg(chip, DAC_LMPG, 0x3f);
837 if (retval)
838 goto out_clk;
839 retval = snd_at73c213_write_reg(chip, DAC_RMPG, 0x3f);
840 if (retval)
841 goto out_clk;
842 retval = snd_at73c213_write_reg(chip, DAC_LLOG, 0x3f);
843 if (retval)
844 goto out_clk;
845 retval = snd_at73c213_write_reg(chip, DAC_RLOG, 0x3f);
846 if (retval)
847 goto out_clk;
848 retval = snd_at73c213_write_reg(chip, DAC_LLIG, 0x11);
849 if (retval)
850 goto out_clk;
851 retval = snd_at73c213_write_reg(chip, DAC_RLIG, 0x11);
852 if (retval)
853 goto out_clk;
854 retval = snd_at73c213_write_reg(chip, DAC_AUXG, 0x11);
855 if (retval)
856 goto out_clk;
857
858 /* Enable I2S device, i.e. clock output. */
859 ssc_writel(chip->ssc->regs, CR, SSC_BIT(CR_TXEN));
860
861 goto out;
862
863out_clk:
864 clk_disable(chip->board->dac_clk);
865out:
866 return retval;
867}
868
869static int snd_at73c213_dev_free(struct snd_device *device)
870{
871 struct snd_at73c213 *chip = device->device_data;
872
873 ssc_writel(chip->ssc->regs, CR, SSC_BIT(CR_TXDIS));
874 if (chip->irq >= 0) {
875 free_irq(chip->irq, chip);
876 chip->irq = -1;
877 }
878
879 return 0;
880}
881
882static int __devinit snd_at73c213_dev_init(struct snd_card *card,
883 struct spi_device *spi)
884{
885 static struct snd_device_ops ops = {
886 .dev_free = snd_at73c213_dev_free,
887 };
888 struct snd_at73c213 *chip = get_chip(card);
889 int irq, retval;
890
891 irq = chip->ssc->irq;
892 if (irq < 0)
893 return irq;
894
895 spin_lock_init(&chip->lock);
896 chip->card = card;
897 chip->irq = -1;
898
899 retval = request_irq(irq, snd_at73c213_interrupt, 0, "at73c213", chip);
900 if (retval) {
901 dev_dbg(&chip->spi->dev, "unable to request irq %d\n", irq);
902 goto out;
903 }
904 chip->irq = irq;
905
906 memcpy(&chip->reg_image, &snd_at73c213_original_image,
907 sizeof(snd_at73c213_original_image));
908
909 retval = snd_at73c213_ssc_init(chip);
910 if (retval)
911 goto out_irq;
912
913 retval = snd_at73c213_chip_init(chip);
914 if (retval)
915 goto out_irq;
916
917 retval = snd_at73c213_pcm_new(chip, 0);
918 if (retval)
919 goto out_irq;
920
921 retval = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
922 if (retval)
923 goto out_irq;
924
925 retval = snd_at73c213_mixer(chip);
926 if (retval)
927 goto out_snd_dev;
928
929 snd_card_set_dev(card, &spi->dev);
930
931 goto out;
932
933out_snd_dev:
934 snd_device_free(card, chip);
935out_irq:
936 free_irq(chip->irq, chip);
937 chip->irq = -1;
938out:
939 return retval;
940}
941
942static int snd_at73c213_probe(struct spi_device *spi)
943{
944 struct snd_card *card;
945 struct snd_at73c213 *chip;
946 struct at73c213_board_info *board;
947 int retval;
948 char id[16];
949
950 board = spi->dev.platform_data;
951 if (!board) {
952 dev_dbg(&spi->dev, "no platform_data\n");
953 return -ENXIO;
954 }
955
956 if (!board->dac_clk) {
957 dev_dbg(&spi->dev, "no DAC clk\n");
958 return -ENXIO;
959 }
960
961 if (IS_ERR(board->dac_clk)) {
962 dev_dbg(&spi->dev, "no DAC clk\n");
963 return PTR_ERR(board->dac_clk);
964 }
965
966 retval = -ENOMEM;
967
968 /* Allocate "card" using some unused identifiers. */
969 snprintf(id, sizeof id, "at73c213_%d", board->ssc_id);
970 card = snd_card_new(-1, id, THIS_MODULE, sizeof(struct snd_at73c213));
971 if (!card)
972 goto out;
973
974 chip = card->private_data;
975 chip->spi = spi;
976 chip->board = board;
977
978 chip->ssc = ssc_request(board->ssc_id);
979 if (IS_ERR(chip->ssc)) {
980 dev_dbg(&spi->dev, "could not get ssc%d device\n",
981 board->ssc_id);
982 retval = PTR_ERR(chip->ssc);
983 goto out_card;
984 }
985
986 retval = snd_at73c213_dev_init(card, spi);
987 if (retval)
988 goto out_ssc;
989
990 strcpy(card->driver, "at73c213");
991 strcpy(card->shortname, board->shortname);
992 sprintf(card->longname, "%s on irq %d", card->shortname, chip->irq);
993
994 retval = snd_card_register(card);
995 if (retval)
996 goto out_ssc;
997
998 dev_set_drvdata(&spi->dev, card);
999
1000 goto out;
1001
1002out_ssc:
1003 ssc_free(chip->ssc);
1004out_card:
1005 snd_card_free(card);
1006out:
1007 return retval;
1008}
1009
1010static int __devexit snd_at73c213_remove(struct spi_device *spi)
1011{
1012 struct snd_card *card = dev_get_drvdata(&spi->dev);
1013 struct snd_at73c213 *chip = card->private_data;
1014 int retval;
1015
1016 /* Stop playback. */
1017 ssc_writel(chip->ssc->regs, CR, SSC_BIT(CR_TXDIS));
1018
1019 /* Mute sound. */
1020 retval = snd_at73c213_write_reg(chip, DAC_LMPG, 0x3f);
1021 if (retval)
1022 goto out;
1023 retval = snd_at73c213_write_reg(chip, DAC_RMPG, 0x3f);
1024 if (retval)
1025 goto out;
1026 retval = snd_at73c213_write_reg(chip, DAC_LLOG, 0x3f);
1027 if (retval)
1028 goto out;
1029 retval = snd_at73c213_write_reg(chip, DAC_RLOG, 0x3f);
1030 if (retval)
1031 goto out;
1032 retval = snd_at73c213_write_reg(chip, DAC_LLIG, 0x11);
1033 if (retval)
1034 goto out;
1035 retval = snd_at73c213_write_reg(chip, DAC_RLIG, 0x11);
1036 if (retval)
1037 goto out;
1038 retval = snd_at73c213_write_reg(chip, DAC_AUXG, 0x11);
1039 if (retval)
1040 goto out;
1041
1042 /* Turn off PA. */
1043 retval = snd_at73c213_write_reg(chip, PA_CTRL,
1044 chip->reg_image[PA_CTRL] | 0x0f);
1045 if (retval)
1046 goto out;
1047 msleep(10);
1048 retval = snd_at73c213_write_reg(chip, PA_CTRL,
1049 (1 << PA_CTRL_APALP) | 0x0f);
1050 if (retval)
1051 goto out;
1052
1053 /* Turn off external DAC. */
1054 retval = snd_at73c213_write_reg(chip, DAC_CTRL, 0x0c);
1055 if (retval)
1056 goto out;
1057 msleep(2);
1058 retval = snd_at73c213_write_reg(chip, DAC_CTRL, 0x00);
1059 if (retval)
1060 goto out;
1061
1062 /* Turn off master power. */
1063 retval = snd_at73c213_write_reg(chip, DAC_PRECH, 0x00);
1064 if (retval)
1065 goto out;
1066
1067out:
1068 /* Stop DAC master clock. */
1069 clk_disable(chip->board->dac_clk);
1070
1071 ssc_free(chip->ssc);
1072 snd_card_free(card);
1073 dev_set_drvdata(&spi->dev, NULL);
1074
1075 return 0;
1076}
1077
1078#ifdef CONFIG_PM
1079static int snd_at73c213_suspend(struct spi_device *spi, pm_message_t msg)
1080{
1081 struct snd_card *card = dev_get_drvdata(&spi->dev);
1082 struct snd_at73c213 *chip = card->private_data;
1083
1084 ssc_writel(chip->ssc->regs, CR, SSC_BIT(CR_TXDIS));
1085 clk_disable(chip->board->dac_clk);
1086
1087 return 0;
1088}
1089
1090static int snd_at73c213_resume(struct spi_device *spi)
1091{
1092 struct snd_card *card = dev_get_drvdata(&spi->dev);
1093 struct snd_at73c213 *chip = card->private_data;
1094
1095 clk_enable(chip->board->dac_clk);
1096 ssc_writel(chip->ssc->regs, CR, SSC_BIT(CR_TXEN));
1097
1098 return 0;
1099}
1100#else
1101#define snd_at73c213_suspend NULL
1102#define snd_at73c213_resume NULL
1103#endif
1104
1105static struct spi_driver at73c213_driver = {
1106 .driver = {
1107 .name = "at73c213",
1108 },
1109 .probe = snd_at73c213_probe,
1110 .suspend = snd_at73c213_suspend,
1111 .resume = snd_at73c213_resume,
1112 .remove = __devexit_p(snd_at73c213_remove),
1113};
1114
1115static int __init at73c213_init(void)
1116{
1117 return spi_register_driver(&at73c213_driver);
1118}
1119module_init(at73c213_init);
1120
1121static void __exit at73c213_exit(void)
1122{
1123 spi_unregister_driver(&at73c213_driver);
1124}
1125module_exit(at73c213_exit);
1126
1127MODULE_AUTHOR("Hans-Christian Egtvedt <hcegtvedt@atmel.com>");
1128MODULE_DESCRIPTION("Sound driver for AT73C213 with Atmel SSC");
1129MODULE_LICENSE("GPL");
diff --git a/sound/spi/at73c213.h b/sound/spi/at73c213.h
new file mode 100644
index 000000000000..fd8b372df5d1
--- /dev/null
+++ b/sound/spi/at73c213.h
@@ -0,0 +1,119 @@
1/*
2 * Driver for the AT73C213 16-bit stereo DAC on Atmel ATSTK1000
3 *
4 * Copyright (C) 2006 - 2007 Atmel Corporation
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 2 of the
9 * License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * 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
19 * 02111-1307, USA.
20 *
21 * The full GNU General Public License is included in this
22 * distribution in the file called COPYING.
23 */
24
25#ifndef _SND_AT73C213_H
26#define _SND_AT73C213_H
27
28/* DAC control register */
29#define DAC_CTRL 0x00
30#define DAC_CTRL_ONPADRV 7
31#define DAC_CTRL_ONAUXIN 6
32#define DAC_CTRL_ONDACR 5
33#define DAC_CTRL_ONDACL 4
34#define DAC_CTRL_ONLNOR 3
35#define DAC_CTRL_ONLNOL 2
36#define DAC_CTRL_ONLNIR 1
37#define DAC_CTRL_ONLNIL 0
38
39/* DAC left line in gain register */
40#define DAC_LLIG 0x01
41#define DAC_LLIG_LLIG 0
42
43/* DAC right line in gain register */
44#define DAC_RLIG 0x02
45#define DAC_RLIG_RLIG 0
46
47/* DAC Left Master Playback Gain Register */
48#define DAC_LMPG 0x03
49#define DAC_LMPG_LMPG 0
50
51/* DAC Right Master Playback Gain Register */
52#define DAC_RMPG 0x04
53#define DAC_RMPG_RMPG 0
54
55/* DAC Left Line Out Gain Register */
56#define DAC_LLOG 0x05
57#define DAC_LLOG_LLOG 0
58
59/* DAC Right Line Out Gain Register */
60#define DAC_RLOG 0x06
61#define DAC_RLOG_RLOG 0
62
63/* DAC Output Level Control Register */
64#define DAC_OLC 0x07
65#define DAC_OLC_RSHORT 7
66#define DAC_OLC_ROLC 4
67#define DAC_OLC_LSHORT 3
68#define DAC_OLC_LOLC 0
69
70/* DAC Mixer Control Register */
71#define DAC_MC 0x08
72#define DAC_MC_INVR 5
73#define DAC_MC_INVL 4
74#define DAC_MC_RMSMIN2 3
75#define DAC_MC_RMSMIN1 2
76#define DAC_MC_LMSMIN2 1
77#define DAC_MC_LMSMIN1 0
78
79/* DAC Clock and Sampling Frequency Control Register */
80#define DAC_CSFC 0x09
81#define DAC_CSFC_OVRSEL 4
82
83/* DAC Miscellaneous Register */
84#define DAC_MISC 0x0A
85#define DAC_MISC_VCMCAPSEL 7
86#define DAC_MISC_DINTSEL 4
87#define DAC_MISC_DITHEN 3
88#define DAC_MISC_DEEMPEN 2
89#define DAC_MISC_NBITS 0
90
91/* DAC Precharge Control Register */
92#define DAC_PRECH 0x0C
93#define DAC_PRECH_PRCHGPDRV 7
94#define DAC_PRECH_PRCHGAUX1 6
95#define DAC_PRECH_PRCHGLNOR 5
96#define DAC_PRECH_PRCHGLNOL 4
97#define DAC_PRECH_PRCHGLNIR 3
98#define DAC_PRECH_PRCHGLNIL 2
99#define DAC_PRECH_PRCHG 1
100#define DAC_PRECH_ONMSTR 0
101
102/* DAC Auxiliary Input Gain Control Register */
103#define DAC_AUXG 0x0D
104#define DAC_AUXG_AUXG 0
105
106/* DAC Reset Register */
107#define DAC_RST 0x10
108#define DAC_RST_RESMASK 2
109#define DAC_RST_RESFILZ 1
110#define DAC_RST_RSTZ 0
111
112/* Power Amplifier Control Register */
113#define PA_CTRL 0x11
114#define PA_CTRL_APAON 6
115#define PA_CTRL_APAPRECH 5
116#define PA_CTRL_APALP 4
117#define PA_CTRL_APAGAIN 0
118
119#endif /* _SND_AT73C213_H */