Commit | Line | Data |
---|---|---|
005fdd53 | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
1da177e4 | 2 | /* |
1da177e4 LT |
3 | */ |
4 | ||
5 | /* | |
6 | * Vortex PCM ALSA driver. | |
7 | * | |
8 | * Supports ADB and WT DMA. Unfortunately, WT channels do not run yet. | |
9 | * It remains stuck,and DMA transfers do not happen. | |
10 | */ | |
11 | #include <sound/asoundef.h> | |
1da177e4 LT |
12 | #include <linux/time.h> |
13 | #include <sound/core.h> | |
14 | #include <sound/pcm.h> | |
15 | #include <sound/pcm_params.h> | |
16 | #include "au88x0.h" | |
17 | ||
18 | #define VORTEX_PCM_TYPE(x) (x->name[40]) | |
19 | ||
20 | /* hardware definition */ | |
aa38e71d | 21 | static const struct snd_pcm_hardware snd_vortex_playback_hw_adb = { |
1da177e4 | 22 | .info = |
41e4845c | 23 | (SNDRV_PCM_INFO_MMAP | /* SNDRV_PCM_INFO_RESUME | */ |
1da177e4 LT |
24 | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_INTERLEAVED | |
25 | SNDRV_PCM_INFO_MMAP_VALID), | |
26 | .formats = | |
27 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U8 | | |
28 | SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW, | |
29 | .rates = SNDRV_PCM_RATE_CONTINUOUS, | |
30 | .rate_min = 5000, | |
31 | .rate_max = 48000, | |
32 | .channels_min = 1, | |
1da177e4 | 33 | .channels_max = 2, |
1da177e4 | 34 | .buffer_bytes_max = 0x10000, |
54a96dad | 35 | .period_bytes_min = 0x20, |
1da177e4 LT |
36 | .period_bytes_max = 0x1000, |
37 | .periods_min = 2, | |
54a96dad | 38 | .periods_max = 1024, |
1da177e4 LT |
39 | }; |
40 | ||
41 | #ifndef CHIP_AU8820 | |
aa38e71d | 42 | static const struct snd_pcm_hardware snd_vortex_playback_hw_a3d = { |
1da177e4 | 43 | .info = |
41e4845c | 44 | (SNDRV_PCM_INFO_MMAP | /* SNDRV_PCM_INFO_RESUME | */ |
1da177e4 LT |
45 | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_INTERLEAVED | |
46 | SNDRV_PCM_INFO_MMAP_VALID), | |
47 | .formats = | |
48 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U8 | | |
49 | SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW, | |
50 | .rates = SNDRV_PCM_RATE_CONTINUOUS, | |
51 | .rate_min = 5000, | |
52 | .rate_max = 48000, | |
53 | .channels_min = 1, | |
54 | .channels_max = 1, | |
55 | .buffer_bytes_max = 0x10000, | |
56 | .period_bytes_min = 0x100, | |
57 | .period_bytes_max = 0x1000, | |
58 | .periods_min = 2, | |
59 | .periods_max = 64, | |
60 | }; | |
61 | #endif | |
aa38e71d | 62 | static const struct snd_pcm_hardware snd_vortex_playback_hw_spdif = { |
1da177e4 | 63 | .info = |
41e4845c | 64 | (SNDRV_PCM_INFO_MMAP | /* SNDRV_PCM_INFO_RESUME | */ |
1da177e4 LT |
65 | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_INTERLEAVED | |
66 | SNDRV_PCM_INFO_MMAP_VALID), | |
67 | .formats = | |
68 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U8 | | |
69 | SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE | SNDRV_PCM_FMTBIT_MU_LAW | | |
70 | SNDRV_PCM_FMTBIT_A_LAW, | |
71 | .rates = | |
72 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000, | |
73 | .rate_min = 32000, | |
74 | .rate_max = 48000, | |
75 | .channels_min = 1, | |
76 | .channels_max = 2, | |
77 | .buffer_bytes_max = 0x10000, | |
78 | .period_bytes_min = 0x100, | |
79 | .period_bytes_max = 0x1000, | |
80 | .periods_min = 2, | |
81 | .periods_max = 64, | |
82 | }; | |
83 | ||
84 | #ifndef CHIP_AU8810 | |
aa38e71d | 85 | static const struct snd_pcm_hardware snd_vortex_playback_hw_wt = { |
1da177e4 LT |
86 | .info = (SNDRV_PCM_INFO_MMAP | |
87 | SNDRV_PCM_INFO_INTERLEAVED | | |
88 | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID), | |
89 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | |
90 | .rates = SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_CONTINUOUS, // SNDRV_PCM_RATE_48000, | |
91 | .rate_min = 8000, | |
92 | .rate_max = 48000, | |
93 | .channels_min = 1, | |
94 | .channels_max = 2, | |
95 | .buffer_bytes_max = 0x10000, | |
96 | .period_bytes_min = 0x0400, | |
97 | .period_bytes_max = 0x1000, | |
98 | .periods_min = 2, | |
99 | .periods_max = 64, | |
100 | }; | |
101 | #endif | |
d9ab3443 | 102 | #ifdef CHIP_AU8830 |
2e5eb6b7 | 103 | static const unsigned int au8830_channels[3] = { |
d9ab3443 RY |
104 | 1, 2, 4, |
105 | }; | |
106 | ||
2e5eb6b7 | 107 | static const struct snd_pcm_hw_constraint_list hw_constraints_au8830_channels = { |
d9ab3443 RY |
108 | .count = ARRAY_SIZE(au8830_channels), |
109 | .list = au8830_channels, | |
110 | .mask = 0, | |
111 | }; | |
112 | #endif | |
bb92b7c4 RY |
113 | |
114 | static void vortex_notify_pcm_vol_change(struct snd_card *card, | |
115 | struct snd_kcontrol *kctl, int activate) | |
116 | { | |
117 | if (activate) | |
118 | kctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE; | |
119 | else | |
120 | kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE; | |
121 | snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE | | |
122 | SNDRV_CTL_EVENT_MASK_INFO, &(kctl->id)); | |
123 | } | |
124 | ||
1da177e4 | 125 | /* open callback */ |
2fd16874 | 126 | static int snd_vortex_pcm_open(struct snd_pcm_substream *substream) |
1da177e4 LT |
127 | { |
128 | vortex_t *vortex = snd_pcm_substream_chip(substream); | |
2fd16874 | 129 | struct snd_pcm_runtime *runtime = substream->runtime; |
1da177e4 LT |
130 | int err; |
131 | ||
132 | /* Force equal size periods */ | |
133 | if ((err = | |
134 | snd_pcm_hw_constraint_integer(runtime, | |
135 | SNDRV_PCM_HW_PARAM_PERIODS)) < 0) | |
136 | return err; | |
137 | /* Avoid PAGE_SIZE boundary to fall inside of a period. */ | |
138 | if ((err = | |
139 | snd_pcm_hw_constraint_pow2(runtime, 0, | |
140 | SNDRV_PCM_HW_PARAM_PERIOD_BYTES)) < 0) | |
141 | return err; | |
142 | ||
54a96dad RY |
143 | snd_pcm_hw_constraint_step(runtime, 0, |
144 | SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 64); | |
145 | ||
1da177e4 LT |
146 | if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) { |
147 | #ifndef CHIP_AU8820 | |
148 | if (VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_A3D) { | |
149 | runtime->hw = snd_vortex_playback_hw_a3d; | |
150 | } | |
151 | #endif | |
152 | if (VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_SPDIF) { | |
153 | runtime->hw = snd_vortex_playback_hw_spdif; | |
154 | switch (vortex->spdif_sr) { | |
155 | case 32000: | |
156 | runtime->hw.rates = SNDRV_PCM_RATE_32000; | |
157 | break; | |
158 | case 44100: | |
159 | runtime->hw.rates = SNDRV_PCM_RATE_44100; | |
160 | break; | |
161 | case 48000: | |
162 | runtime->hw.rates = SNDRV_PCM_RATE_48000; | |
163 | break; | |
164 | } | |
165 | } | |
166 | if (VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_ADB | |
167 | || VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_I2S) | |
168 | runtime->hw = snd_vortex_playback_hw_adb; | |
d9ab3443 RY |
169 | #ifdef CHIP_AU8830 |
170 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && | |
7b32486c | 171 | VORTEX_IS_QUAD(vortex) && |
d9ab3443 RY |
172 | VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_ADB) { |
173 | runtime->hw.channels_max = 4; | |
174 | snd_pcm_hw_constraint_list(runtime, 0, | |
175 | SNDRV_PCM_HW_PARAM_CHANNELS, | |
176 | &hw_constraints_au8830_channels); | |
177 | } | |
178 | #endif | |
1da177e4 LT |
179 | substream->runtime->private_data = NULL; |
180 | } | |
181 | #ifndef CHIP_AU8810 | |
182 | else { | |
183 | runtime->hw = snd_vortex_playback_hw_wt; | |
184 | substream->runtime->private_data = NULL; | |
185 | } | |
186 | #endif | |
187 | return 0; | |
188 | } | |
189 | ||
190 | /* close callback */ | |
2fd16874 | 191 | static int snd_vortex_pcm_close(struct snd_pcm_substream *substream) |
1da177e4 LT |
192 | { |
193 | //vortex_t *chip = snd_pcm_substream_chip(substream); | |
194 | stream_t *stream = (stream_t *) substream->runtime->private_data; | |
195 | ||
196 | // the hardware-specific codes will be here | |
197 | if (stream != NULL) { | |
198 | stream->substream = NULL; | |
199 | stream->nr_ch = 0; | |
200 | } | |
201 | substream->runtime->private_data = NULL; | |
202 | return 0; | |
203 | } | |
204 | ||
205 | /* hw_params callback */ | |
206 | static int | |
2fd16874 TI |
207 | snd_vortex_pcm_hw_params(struct snd_pcm_substream *substream, |
208 | struct snd_pcm_hw_params *hw_params) | |
1da177e4 LT |
209 | { |
210 | vortex_t *chip = snd_pcm_substream_chip(substream); | |
211 | stream_t *stream = (stream_t *) (substream->runtime->private_data); | |
1da177e4 LT |
212 | int err; |
213 | ||
214 | // Alloc buffer memory. | |
215 | err = | |
216 | snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); | |
217 | if (err < 0) { | |
70c84418 | 218 | dev_err(chip->card->dev, "Vortex: pcm page alloc failed!\n"); |
1da177e4 LT |
219 | return err; |
220 | } | |
1da177e4 | 221 | /* |
e7e69265 | 222 | pr_info( "Vortex: periods %d, period_bytes %d, channels = %d\n", params_periods(hw_params), |
1da177e4 LT |
223 | params_period_bytes(hw_params), params_channels(hw_params)); |
224 | */ | |
225 | spin_lock_irq(&chip->lock); | |
226 | // Make audio routes and config buffer DMA. | |
227 | if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) { | |
228 | int dma, type = VORTEX_PCM_TYPE(substream->pcm); | |
229 | /* Dealloc any routes. */ | |
230 | if (stream != NULL) | |
231 | vortex_adb_allocroute(chip, stream->dma, | |
232 | stream->nr_ch, stream->dir, | |
bb92b7c4 RY |
233 | stream->type, |
234 | substream->number); | |
1da177e4 LT |
235 | /* Alloc routes. */ |
236 | dma = | |
237 | vortex_adb_allocroute(chip, -1, | |
238 | params_channels(hw_params), | |
bb92b7c4 RY |
239 | substream->stream, type, |
240 | substream->number); | |
a278655f TI |
241 | if (dma < 0) { |
242 | spin_unlock_irq(&chip->lock); | |
1da177e4 | 243 | return dma; |
a278655f | 244 | } |
1da177e4 LT |
245 | stream = substream->runtime->private_data = &chip->dma_adb[dma]; |
246 | stream->substream = substream; | |
247 | /* Setup Buffers. */ | |
77a23f26 | 248 | vortex_adbdma_setbuffers(chip, dma, |
1da177e4 LT |
249 | params_period_bytes(hw_params), |
250 | params_periods(hw_params)); | |
bb92b7c4 RY |
251 | if (VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_ADB) { |
252 | chip->pcm_vol[substream->number].active = 1; | |
253 | vortex_notify_pcm_vol_change(chip->card, | |
254 | chip->pcm_vol[substream->number].kctl, 1); | |
255 | } | |
1da177e4 LT |
256 | } |
257 | #ifndef CHIP_AU8810 | |
258 | else { | |
259 | /* if (stream != NULL) | |
260 | vortex_wt_allocroute(chip, substream->number, 0); */ | |
261 | vortex_wt_allocroute(chip, substream->number, | |
262 | params_channels(hw_params)); | |
263 | stream = substream->runtime->private_data = | |
264 | &chip->dma_wt[substream->number]; | |
265 | stream->dma = substream->number; | |
266 | stream->substream = substream; | |
77a23f26 | 267 | vortex_wtdma_setbuffers(chip, substream->number, |
1da177e4 LT |
268 | params_period_bytes(hw_params), |
269 | params_periods(hw_params)); | |
270 | } | |
271 | #endif | |
272 | spin_unlock_irq(&chip->lock); | |
273 | return 0; | |
274 | } | |
275 | ||
276 | /* hw_free callback */ | |
2fd16874 | 277 | static int snd_vortex_pcm_hw_free(struct snd_pcm_substream *substream) |
1da177e4 LT |
278 | { |
279 | vortex_t *chip = snd_pcm_substream_chip(substream); | |
280 | stream_t *stream = (stream_t *) (substream->runtime->private_data); | |
281 | ||
282 | spin_lock_irq(&chip->lock); | |
283 | // Delete audio routes. | |
284 | if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) { | |
bb92b7c4 RY |
285 | if (stream != NULL) { |
286 | if (VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_ADB) { | |
287 | chip->pcm_vol[substream->number].active = 0; | |
288 | vortex_notify_pcm_vol_change(chip->card, | |
289 | chip->pcm_vol[substream->number].kctl, | |
290 | 0); | |
291 | } | |
1da177e4 LT |
292 | vortex_adb_allocroute(chip, stream->dma, |
293 | stream->nr_ch, stream->dir, | |
bb92b7c4 RY |
294 | stream->type, |
295 | substream->number); | |
296 | } | |
1da177e4 LT |
297 | } |
298 | #ifndef CHIP_AU8810 | |
299 | else { | |
300 | if (stream != NULL) | |
301 | vortex_wt_allocroute(chip, stream->dma, 0); | |
302 | } | |
303 | #endif | |
304 | substream->runtime->private_data = NULL; | |
305 | spin_unlock_irq(&chip->lock); | |
306 | ||
307 | return snd_pcm_lib_free_pages(substream); | |
308 | } | |
309 | ||
310 | /* prepare callback */ | |
2fd16874 | 311 | static int snd_vortex_pcm_prepare(struct snd_pcm_substream *substream) |
1da177e4 LT |
312 | { |
313 | vortex_t *chip = snd_pcm_substream_chip(substream); | |
2fd16874 | 314 | struct snd_pcm_runtime *runtime = substream->runtime; |
1da177e4 LT |
315 | stream_t *stream = (stream_t *) substream->runtime->private_data; |
316 | int dma = stream->dma, fmt, dir; | |
317 | ||
318 | // set up the hardware with the current configuration. | |
319 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | |
320 | dir = 1; | |
321 | else | |
322 | dir = 0; | |
6a40dc5a | 323 | fmt = vortex_alsafmt_aspfmt(runtime->format, chip); |
1da177e4 LT |
324 | spin_lock_irq(&chip->lock); |
325 | if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) { | |
3ae4e1f7 RY |
326 | vortex_adbdma_setmode(chip, dma, 1, dir, fmt, |
327 | runtime->channels == 1 ? 0 : 1, 0); | |
1da177e4 LT |
328 | vortex_adbdma_setstartbuffer(chip, dma, 0); |
329 | if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_SPDIF) | |
330 | vortex_adb_setsrc(chip, dma, runtime->rate, dir); | |
331 | } | |
332 | #ifndef CHIP_AU8810 | |
333 | else { | |
334 | vortex_wtdma_setmode(chip, dma, 1, fmt, 0, 0); | |
335 | // FIXME: Set rate (i guess using vortex_wt_writereg() somehow). | |
336 | vortex_wtdma_setstartbuffer(chip, dma, 0); | |
337 | } | |
338 | #endif | |
339 | spin_unlock_irq(&chip->lock); | |
340 | return 0; | |
341 | } | |
342 | ||
343 | /* trigger callback */ | |
2fd16874 | 344 | static int snd_vortex_pcm_trigger(struct snd_pcm_substream *substream, int cmd) |
1da177e4 LT |
345 | { |
346 | vortex_t *chip = snd_pcm_substream_chip(substream); | |
347 | stream_t *stream = (stream_t *) substream->runtime->private_data; | |
348 | int dma = stream->dma; | |
349 | ||
350 | spin_lock(&chip->lock); | |
351 | switch (cmd) { | |
352 | case SNDRV_PCM_TRIGGER_START: | |
353 | // do something to start the PCM engine | |
354 | //printk(KERN_INFO "vortex: start %d\n", dma); | |
355 | stream->fifo_enabled = 1; | |
356 | if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) { | |
357 | vortex_adbdma_resetup(chip, dma); | |
358 | vortex_adbdma_startfifo(chip, dma); | |
359 | } | |
360 | #ifndef CHIP_AU8810 | |
361 | else { | |
70c84418 | 362 | dev_info(chip->card->dev, "wt start %d\n", dma); |
1da177e4 LT |
363 | vortex_wtdma_startfifo(chip, dma); |
364 | } | |
365 | #endif | |
366 | break; | |
367 | case SNDRV_PCM_TRIGGER_STOP: | |
368 | // do something to stop the PCM engine | |
369 | //printk(KERN_INFO "vortex: stop %d\n", dma); | |
370 | stream->fifo_enabled = 0; | |
371 | if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) | |
fb65c2df | 372 | vortex_adbdma_stopfifo(chip, dma); |
1da177e4 LT |
373 | #ifndef CHIP_AU8810 |
374 | else { | |
70c84418 | 375 | dev_info(chip->card->dev, "wt stop %d\n", dma); |
1da177e4 LT |
376 | vortex_wtdma_stopfifo(chip, dma); |
377 | } | |
378 | #endif | |
379 | break; | |
380 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | |
381 | //printk(KERN_INFO "vortex: pause %d\n", dma); | |
382 | if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) | |
383 | vortex_adbdma_pausefifo(chip, dma); | |
384 | #ifndef CHIP_AU8810 | |
385 | else | |
386 | vortex_wtdma_pausefifo(chip, dma); | |
387 | #endif | |
388 | break; | |
389 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | |
390 | //printk(KERN_INFO "vortex: resume %d\n", dma); | |
391 | if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) | |
392 | vortex_adbdma_resumefifo(chip, dma); | |
393 | #ifndef CHIP_AU8810 | |
394 | else | |
395 | vortex_wtdma_resumefifo(chip, dma); | |
396 | #endif | |
397 | break; | |
398 | default: | |
399 | spin_unlock(&chip->lock); | |
400 | return -EINVAL; | |
401 | } | |
402 | spin_unlock(&chip->lock); | |
403 | return 0; | |
404 | } | |
405 | ||
406 | /* pointer callback */ | |
2fd16874 | 407 | static snd_pcm_uframes_t snd_vortex_pcm_pointer(struct snd_pcm_substream *substream) |
1da177e4 LT |
408 | { |
409 | vortex_t *chip = snd_pcm_substream_chip(substream); | |
410 | stream_t *stream = (stream_t *) substream->runtime->private_data; | |
411 | int dma = stream->dma; | |
412 | snd_pcm_uframes_t current_ptr = 0; | |
413 | ||
414 | spin_lock(&chip->lock); | |
415 | if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) | |
416 | current_ptr = vortex_adbdma_getlinearpos(chip, dma); | |
417 | #ifndef CHIP_AU8810 | |
418 | else | |
419 | current_ptr = vortex_wtdma_getlinearpos(chip, dma); | |
420 | #endif | |
421 | //printk(KERN_INFO "vortex: pointer = 0x%x\n", current_ptr); | |
422 | spin_unlock(&chip->lock); | |
58a8738c TI |
423 | current_ptr = bytes_to_frames(substream->runtime, current_ptr); |
424 | if (current_ptr >= substream->runtime->buffer_size) | |
425 | current_ptr = 0; | |
426 | return current_ptr; | |
1da177e4 LT |
427 | } |
428 | ||
1da177e4 | 429 | /* operators */ |
0b5b2339 | 430 | static const struct snd_pcm_ops snd_vortex_playback_ops = { |
1da177e4 LT |
431 | .open = snd_vortex_pcm_open, |
432 | .close = snd_vortex_pcm_close, | |
433 | .ioctl = snd_pcm_lib_ioctl, | |
434 | .hw_params = snd_vortex_pcm_hw_params, | |
435 | .hw_free = snd_vortex_pcm_hw_free, | |
436 | .prepare = snd_vortex_pcm_prepare, | |
437 | .trigger = snd_vortex_pcm_trigger, | |
438 | .pointer = snd_vortex_pcm_pointer, | |
1da177e4 LT |
439 | }; |
440 | ||
441 | /* | |
442 | * definitions of capture are omitted here... | |
443 | */ | |
444 | ||
445 | static char *vortex_pcm_prettyname[VORTEX_PCM_LAST] = { | |
13eb4ab8 RY |
446 | CARD_NAME " ADB", |
447 | CARD_NAME " SPDIF", | |
448 | CARD_NAME " A3D", | |
449 | CARD_NAME " WT", | |
450 | CARD_NAME " I2S", | |
1da177e4 LT |
451 | }; |
452 | static char *vortex_pcm_name[VORTEX_PCM_LAST] = { | |
453 | "adb", | |
454 | "spdif", | |
455 | "a3d", | |
456 | "wt", | |
457 | "i2s", | |
458 | }; | |
459 | ||
460 | /* SPDIF kcontrol */ | |
461 | ||
2fd16874 | 462 | static int snd_vortex_spdif_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) |
1da177e4 LT |
463 | { |
464 | uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; | |
465 | uinfo->count = 1; | |
466 | return 0; | |
467 | } | |
468 | ||
2fd16874 | 469 | static int snd_vortex_spdif_mask_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
1da177e4 LT |
470 | { |
471 | ucontrol->value.iec958.status[0] = 0xff; | |
472 | ucontrol->value.iec958.status[1] = 0xff; | |
473 | ucontrol->value.iec958.status[2] = 0xff; | |
474 | ucontrol->value.iec958.status[3] = IEC958_AES3_CON_FS; | |
475 | return 0; | |
476 | } | |
477 | ||
2fd16874 | 478 | static int snd_vortex_spdif_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
1da177e4 LT |
479 | { |
480 | vortex_t *vortex = snd_kcontrol_chip(kcontrol); | |
481 | ucontrol->value.iec958.status[0] = 0x00; | |
482 | ucontrol->value.iec958.status[1] = IEC958_AES1_CON_ORIGINAL|IEC958_AES1_CON_DIGDIGCONV_ID; | |
483 | ucontrol->value.iec958.status[2] = 0x00; | |
484 | switch (vortex->spdif_sr) { | |
485 | case 32000: ucontrol->value.iec958.status[3] = IEC958_AES3_CON_FS_32000; break; | |
486 | case 44100: ucontrol->value.iec958.status[3] = IEC958_AES3_CON_FS_44100; break; | |
487 | case 48000: ucontrol->value.iec958.status[3] = IEC958_AES3_CON_FS_48000; break; | |
488 | } | |
489 | return 0; | |
490 | } | |
491 | ||
2fd16874 | 492 | static int snd_vortex_spdif_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
1da177e4 LT |
493 | { |
494 | vortex_t *vortex = snd_kcontrol_chip(kcontrol); | |
495 | int spdif_sr = 48000; | |
496 | switch (ucontrol->value.iec958.status[3] & IEC958_AES3_CON_FS) { | |
497 | case IEC958_AES3_CON_FS_32000: spdif_sr = 32000; break; | |
498 | case IEC958_AES3_CON_FS_44100: spdif_sr = 44100; break; | |
499 | case IEC958_AES3_CON_FS_48000: spdif_sr = 48000; break; | |
500 | } | |
501 | if (spdif_sr == vortex->spdif_sr) | |
502 | return 0; | |
503 | vortex->spdif_sr = spdif_sr; | |
504 | vortex_spdif_init(vortex, vortex->spdif_sr, 1); | |
505 | return 1; | |
506 | } | |
507 | ||
508 | /* spdif controls */ | |
e23e7a14 | 509 | static struct snd_kcontrol_new snd_vortex_mixer_spdif[] = { |
1da177e4 LT |
510 | { |
511 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | |
512 | .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), | |
513 | .info = snd_vortex_spdif_info, | |
514 | .get = snd_vortex_spdif_get, | |
515 | .put = snd_vortex_spdif_put, | |
516 | }, | |
517 | { | |
518 | .access = SNDRV_CTL_ELEM_ACCESS_READ, | |
519 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | |
520 | .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK), | |
521 | .info = snd_vortex_spdif_info, | |
522 | .get = snd_vortex_spdif_mask_get | |
523 | }, | |
524 | }; | |
525 | ||
bb92b7c4 RY |
526 | /* subdevice PCM Volume control */ |
527 | ||
528 | static int snd_vortex_pcm_vol_info(struct snd_kcontrol *kcontrol, | |
529 | struct snd_ctl_elem_info *uinfo) | |
530 | { | |
531 | vortex_t *vortex = snd_kcontrol_chip(kcontrol); | |
532 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | |
533 | uinfo->count = (VORTEX_IS_QUAD(vortex) ? 4 : 2); | |
534 | uinfo->value.integer.min = -128; | |
535 | uinfo->value.integer.max = 32; | |
536 | return 0; | |
537 | } | |
538 | ||
539 | static int snd_vortex_pcm_vol_get(struct snd_kcontrol *kcontrol, | |
540 | struct snd_ctl_elem_value *ucontrol) | |
541 | { | |
542 | int i; | |
543 | vortex_t *vortex = snd_kcontrol_chip(kcontrol); | |
544 | int subdev = kcontrol->id.subdevice; | |
545 | struct pcm_vol *p = &vortex->pcm_vol[subdev]; | |
546 | int max_chn = (VORTEX_IS_QUAD(vortex) ? 4 : 2); | |
547 | for (i = 0; i < max_chn; i++) | |
548 | ucontrol->value.integer.value[i] = p->vol[i]; | |
549 | return 0; | |
550 | } | |
551 | ||
552 | static int snd_vortex_pcm_vol_put(struct snd_kcontrol *kcontrol, | |
553 | struct snd_ctl_elem_value *ucontrol) | |
554 | { | |
555 | int i; | |
556 | int changed = 0; | |
557 | int mixin; | |
558 | unsigned char vol; | |
559 | vortex_t *vortex = snd_kcontrol_chip(kcontrol); | |
560 | int subdev = kcontrol->id.subdevice; | |
561 | struct pcm_vol *p = &vortex->pcm_vol[subdev]; | |
562 | int max_chn = (VORTEX_IS_QUAD(vortex) ? 4 : 2); | |
563 | for (i = 0; i < max_chn; i++) { | |
564 | if (p->vol[i] != ucontrol->value.integer.value[i]) { | |
565 | p->vol[i] = ucontrol->value.integer.value[i]; | |
566 | if (p->active) { | |
567 | switch (vortex->dma_adb[p->dma].nr_ch) { | |
568 | case 1: | |
569 | mixin = p->mixin[0]; | |
570 | break; | |
571 | case 2: | |
572 | default: | |
573 | mixin = p->mixin[(i < 2) ? i : (i - 2)]; | |
574 | break; | |
575 | case 4: | |
576 | mixin = p->mixin[i]; | |
577 | break; | |
395d9dd5 | 578 | } |
bb92b7c4 RY |
579 | vol = p->vol[i]; |
580 | vortex_mix_setinputvolumebyte(vortex, | |
581 | vortex->mixplayb[i], mixin, vol); | |
582 | } | |
583 | changed = 1; | |
584 | } | |
585 | } | |
586 | return changed; | |
587 | } | |
588 | ||
589 | static const DECLARE_TLV_DB_MINMAX(vortex_pcm_vol_db_scale, -9600, 2400); | |
590 | ||
f3b827e0 | 591 | static const struct snd_kcontrol_new snd_vortex_pcm_vol = { |
bb92b7c4 RY |
592 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, |
593 | .name = "PCM Playback Volume", | |
594 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | | |
595 | SNDRV_CTL_ELEM_ACCESS_TLV_READ | | |
596 | SNDRV_CTL_ELEM_ACCESS_INACTIVE, | |
597 | .info = snd_vortex_pcm_vol_info, | |
598 | .get = snd_vortex_pcm_vol_get, | |
599 | .put = snd_vortex_pcm_vol_put, | |
600 | .tlv = { .p = vortex_pcm_vol_db_scale }, | |
601 | }; | |
602 | ||
1da177e4 | 603 | /* create a pcm device */ |
e23e7a14 | 604 | static int snd_vortex_new_pcm(vortex_t *chip, int idx, int nr) |
1da177e4 | 605 | { |
2fd16874 TI |
606 | struct snd_pcm *pcm; |
607 | struct snd_kcontrol *kctl; | |
1da177e4 LT |
608 | int i; |
609 | int err, nr_capt; | |
610 | ||
3fa4a907 | 611 | if (!chip || idx < 0 || idx >= VORTEX_PCM_LAST) |
1da177e4 LT |
612 | return -ENODEV; |
613 | ||
614 | /* idx indicates which kind of PCM device. ADB, SPDIF, I2S and A3D share the | |
25985edc | 615 | * same dma engine. WT uses it own separate dma engine which can't capture. */ |
1da177e4 LT |
616 | if (idx == VORTEX_PCM_ADB) |
617 | nr_capt = nr; | |
618 | else | |
619 | nr_capt = 0; | |
3fa4a907 HH |
620 | err = snd_pcm_new(chip->card, vortex_pcm_prettyname[idx], idx, nr, |
621 | nr_capt, &pcm); | |
622 | if (err < 0) | |
1da177e4 | 623 | return err; |
13eb4ab8 RY |
624 | snprintf(pcm->name, sizeof(pcm->name), |
625 | "%s %s", CARD_NAME_SHORT, vortex_pcm_name[idx]); | |
1da177e4 LT |
626 | chip->pcm[idx] = pcm; |
627 | // This is an evil hack, but it saves a lot of duplicated code. | |
628 | VORTEX_PCM_TYPE(pcm) = idx; | |
629 | pcm->private_data = chip; | |
630 | /* set operators */ | |
631 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, | |
632 | &snd_vortex_playback_ops); | |
633 | if (idx == VORTEX_PCM_ADB) | |
634 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, | |
635 | &snd_vortex_playback_ops); | |
636 | ||
637 | /* pre-allocation of Scatter-Gather buffers */ | |
638 | ||
639 | snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG, | |
640 | snd_dma_pci_data(chip->pci_dev), | |
641 | 0x10000, 0x10000); | |
642 | ||
f3c90242 RY |
643 | switch (VORTEX_PCM_TYPE(pcm)) { |
644 | case VORTEX_PCM_ADB: | |
645 | err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, | |
646 | snd_pcm_std_chmaps, | |
647 | VORTEX_IS_QUAD(chip) ? 4 : 2, | |
648 | 0, NULL); | |
649 | if (err < 0) | |
650 | return err; | |
651 | err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_CAPTURE, | |
652 | snd_pcm_std_chmaps, 2, 0, NULL); | |
653 | if (err < 0) | |
654 | return err; | |
655 | break; | |
656 | #ifdef CHIP_AU8830 | |
657 | case VORTEX_PCM_A3D: | |
658 | err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, | |
659 | snd_pcm_std_chmaps, 1, 0, NULL); | |
660 | if (err < 0) | |
661 | return err; | |
662 | break; | |
663 | #endif | |
1d198f26 | 664 | } |
f3c90242 | 665 | |
1da177e4 LT |
666 | if (VORTEX_PCM_TYPE(pcm) == VORTEX_PCM_SPDIF) { |
667 | for (i = 0; i < ARRAY_SIZE(snd_vortex_mixer_spdif); i++) { | |
668 | kctl = snd_ctl_new1(&snd_vortex_mixer_spdif[i], chip); | |
669 | if (!kctl) | |
670 | return -ENOMEM; | |
671 | if ((err = snd_ctl_add(chip->card, kctl)) < 0) | |
672 | return err; | |
673 | } | |
674 | } | |
bb92b7c4 RY |
675 | if (VORTEX_PCM_TYPE(pcm) == VORTEX_PCM_ADB) { |
676 | for (i = 0; i < NR_PCM; i++) { | |
677 | chip->pcm_vol[i].active = 0; | |
678 | chip->pcm_vol[i].dma = -1; | |
679 | kctl = snd_ctl_new1(&snd_vortex_pcm_vol, chip); | |
680 | if (!kctl) | |
681 | return -ENOMEM; | |
682 | chip->pcm_vol[i].kctl = kctl; | |
683 | kctl->id.device = 0; | |
684 | kctl->id.subdevice = i; | |
685 | err = snd_ctl_add(chip->card, kctl); | |
686 | if (err < 0) | |
687 | return err; | |
688 | } | |
689 | } | |
1da177e4 LT |
690 | return 0; |
691 | } |