1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
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> |
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 */ |
21 | static const struct snd_pcm_hardware snd_vortex_playback_hw_adb = { |
22 | .info = |
23 | (SNDRV_PCM_INFO_MMAP | /* SNDRV_PCM_INFO_RESUME | */ |
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, |
33 | .channels_max = 2, |
34 | .buffer_bytes_max = 0x10000, |
35 | .period_bytes_min = 0x20, |
36 | .period_bytes_max = 0x1000, |
37 | .periods_min = 2, |
38 | .periods_max = 1024, |
39 | }; |
40 | |
41 | #ifndef CHIP_AU8820 |
42 | static const struct snd_pcm_hardware snd_vortex_playback_hw_a3d = { |
43 | .info = |
44 | (SNDRV_PCM_INFO_MMAP | /* SNDRV_PCM_INFO_RESUME | */ |
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 |
62 | static const struct snd_pcm_hardware snd_vortex_playback_hw_spdif = { |
63 | .info = |
64 | (SNDRV_PCM_INFO_MMAP | /* SNDRV_PCM_INFO_RESUME | */ |
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 |
85 | static const struct snd_pcm_hardware snd_vortex_playback_hw_wt = { |
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 |
102 | #ifdef CHIP_AU8830 |
103 | static const unsigned int au8830_channels[3] = { |
104 | 1, 2, 4, |
105 | }; |
106 | |
107 | static const struct snd_pcm_hw_constraint_list hw_constraints_au8830_channels = { |
108 | .count = ARRAY_SIZE(au8830_channels), |
109 | .list = au8830_channels, |
110 | .mask = 0, |
111 | }; |
112 | #endif |
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, id: &(kctl->id)); |
123 | } |
124 | |
125 | /* open callback */ |
126 | static int snd_vortex_pcm_open(struct snd_pcm_substream *substream) |
127 | { |
128 | vortex_t *vortex = snd_pcm_substream_chip(substream); |
129 | struct snd_pcm_runtime *runtime = substream->runtime; |
130 | int err; |
131 | |
132 | /* Force equal size periods */ |
133 | err = snd_pcm_hw_constraint_integer(runtime, |
134 | SNDRV_PCM_HW_PARAM_PERIODS); |
135 | if (err < 0) |
136 | return err; |
137 | /* Avoid PAGE_SIZE boundary to fall inside of a period. */ |
138 | err = snd_pcm_hw_constraint_pow2(runtime, cond: 0, |
139 | SNDRV_PCM_HW_PARAM_PERIOD_BYTES); |
140 | if (err < 0) |
141 | return err; |
142 | |
143 | snd_pcm_hw_constraint_step(runtime, cond: 0, |
144 | SNDRV_PCM_HW_PARAM_BUFFER_BYTES, step: 64); |
145 | |
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; |
169 | #ifdef CHIP_AU8830 |
170 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && |
171 | VORTEX_IS_QUAD(vortex) && |
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 |
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 */ |
191 | static int snd_vortex_pcm_close(struct snd_pcm_substream *substream) |
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 |
207 | snd_vortex_pcm_hw_params(struct snd_pcm_substream *substream, |
208 | struct snd_pcm_hw_params *hw_params) |
209 | { |
210 | vortex_t *chip = snd_pcm_substream_chip(substream); |
211 | stream_t *stream = (stream_t *) (substream->runtime->private_data); |
212 | |
213 | /* |
214 | pr_info( "Vortex: periods %d, period_bytes %d, channels = %d\n", params_periods(hw_params), |
215 | params_period_bytes(hw_params), params_channels(hw_params)); |
216 | */ |
217 | spin_lock_irq(lock: &chip->lock); |
218 | // Make audio routes and config buffer DMA. |
219 | if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) { |
220 | int dma, type = VORTEX_PCM_TYPE(substream->pcm); |
221 | /* Dealloc any routes. */ |
222 | if (stream != NULL) |
223 | vortex_adb_allocroute(vortex: chip, dma: stream->dma, |
224 | nr_ch: stream->nr_ch, dir: stream->dir, |
225 | type: stream->type, |
226 | subdev: substream->number); |
227 | /* Alloc routes. */ |
228 | dma = |
229 | vortex_adb_allocroute(vortex: chip, dma: -1, |
230 | nr_ch: params_channels(p: hw_params), |
231 | dir: substream->stream, type, |
232 | subdev: substream->number); |
233 | if (dma < 0) { |
234 | spin_unlock_irq(lock: &chip->lock); |
235 | return dma; |
236 | } |
237 | stream = substream->runtime->private_data = &chip->dma_adb[dma]; |
238 | stream->substream = substream; |
239 | /* Setup Buffers. */ |
240 | vortex_adbdma_setbuffers(vortex: chip, adbdma: dma, |
241 | psize: params_period_bytes(p: hw_params), |
242 | count: params_periods(p: hw_params)); |
243 | if (VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_ADB) { |
244 | chip->pcm_vol[substream->number].active = 1; |
245 | vortex_notify_pcm_vol_change(card: chip->card, |
246 | kctl: chip->pcm_vol[substream->number].kctl, activate: 1); |
247 | } |
248 | } |
249 | #ifndef CHIP_AU8810 |
250 | else { |
251 | /* if (stream != NULL) |
252 | vortex_wt_allocroute(chip, substream->number, 0); */ |
253 | vortex_wt_allocroute(chip, substream->number, |
254 | params_channels(hw_params)); |
255 | stream = substream->runtime->private_data = |
256 | &chip->dma_wt[substream->number]; |
257 | stream->dma = substream->number; |
258 | stream->substream = substream; |
259 | vortex_wtdma_setbuffers(chip, substream->number, |
260 | params_period_bytes(hw_params), |
261 | params_periods(hw_params)); |
262 | } |
263 | #endif |
264 | spin_unlock_irq(lock: &chip->lock); |
265 | return 0; |
266 | } |
267 | |
268 | /* hw_free callback */ |
269 | static int snd_vortex_pcm_hw_free(struct snd_pcm_substream *substream) |
270 | { |
271 | vortex_t *chip = snd_pcm_substream_chip(substream); |
272 | stream_t *stream = (stream_t *) (substream->runtime->private_data); |
273 | |
274 | spin_lock_irq(lock: &chip->lock); |
275 | // Delete audio routes. |
276 | if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) { |
277 | if (stream != NULL) { |
278 | if (VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_ADB) { |
279 | chip->pcm_vol[substream->number].active = 0; |
280 | vortex_notify_pcm_vol_change(card: chip->card, |
281 | kctl: chip->pcm_vol[substream->number].kctl, |
282 | activate: 0); |
283 | } |
284 | vortex_adb_allocroute(vortex: chip, dma: stream->dma, |
285 | nr_ch: stream->nr_ch, dir: stream->dir, |
286 | type: stream->type, |
287 | subdev: substream->number); |
288 | } |
289 | } |
290 | #ifndef CHIP_AU8810 |
291 | else { |
292 | if (stream != NULL) |
293 | vortex_wt_allocroute(chip, stream->dma, 0); |
294 | } |
295 | #endif |
296 | substream->runtime->private_data = NULL; |
297 | spin_unlock_irq(lock: &chip->lock); |
298 | |
299 | return 0; |
300 | } |
301 | |
302 | /* prepare callback */ |
303 | static int snd_vortex_pcm_prepare(struct snd_pcm_substream *substream) |
304 | { |
305 | vortex_t *chip = snd_pcm_substream_chip(substream); |
306 | struct snd_pcm_runtime *runtime = substream->runtime; |
307 | stream_t *stream = (stream_t *) substream->runtime->private_data; |
308 | int dma = stream->dma, fmt, dir; |
309 | |
310 | // set up the hardware with the current configuration. |
311 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
312 | dir = 1; |
313 | else |
314 | dir = 0; |
315 | fmt = vortex_alsafmt_aspfmt(alsafmt: runtime->format, v: chip); |
316 | spin_lock_irq(lock: &chip->lock); |
317 | if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) { |
318 | vortex_adbdma_setmode(vortex: chip, adbdma: dma, ie: 1, dir, fmt, |
319 | stereo: runtime->channels == 1 ? 0 : 1, offset: 0); |
320 | vortex_adbdma_setstartbuffer(vortex: chip, adbdma: dma, sb: 0); |
321 | if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_SPDIF) |
322 | vortex_adb_setsrc(vortex: chip, adbdma: dma, rate: runtime->rate, dir); |
323 | } |
324 | #ifndef CHIP_AU8810 |
325 | else { |
326 | vortex_wtdma_setmode(chip, dma, 1, fmt, 0, 0); |
327 | // FIXME: Set rate (i guess using vortex_wt_writereg() somehow). |
328 | vortex_wtdma_setstartbuffer(chip, dma, 0); |
329 | } |
330 | #endif |
331 | spin_unlock_irq(lock: &chip->lock); |
332 | return 0; |
333 | } |
334 | |
335 | /* trigger callback */ |
336 | static int snd_vortex_pcm_trigger(struct snd_pcm_substream *substream, int cmd) |
337 | { |
338 | vortex_t *chip = snd_pcm_substream_chip(substream); |
339 | stream_t *stream = (stream_t *) substream->runtime->private_data; |
340 | int dma = stream->dma; |
341 | |
342 | spin_lock(lock: &chip->lock); |
343 | switch (cmd) { |
344 | case SNDRV_PCM_TRIGGER_START: |
345 | // do something to start the PCM engine |
346 | //printk(KERN_INFO "vortex: start %d\n", dma); |
347 | stream->fifo_enabled = 1; |
348 | if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) { |
349 | vortex_adbdma_resetup(vortex: chip, adbdma: dma); |
350 | vortex_adbdma_startfifo(vortex: chip, adbdma: dma); |
351 | } |
352 | #ifndef CHIP_AU8810 |
353 | else { |
354 | dev_info(chip->card->dev, "wt start %d\n" , dma); |
355 | vortex_wtdma_startfifo(chip, dma); |
356 | } |
357 | #endif |
358 | break; |
359 | case SNDRV_PCM_TRIGGER_STOP: |
360 | // do something to stop the PCM engine |
361 | //printk(KERN_INFO "vortex: stop %d\n", dma); |
362 | stream->fifo_enabled = 0; |
363 | if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) |
364 | vortex_adbdma_stopfifo(vortex: chip, adbdma: dma); |
365 | #ifndef CHIP_AU8810 |
366 | else { |
367 | dev_info(chip->card->dev, "wt stop %d\n" , dma); |
368 | vortex_wtdma_stopfifo(chip, dma); |
369 | } |
370 | #endif |
371 | break; |
372 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: |
373 | //printk(KERN_INFO "vortex: pause %d\n", dma); |
374 | if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) |
375 | vortex_adbdma_pausefifo(vortex: chip, adbdma: dma); |
376 | #ifndef CHIP_AU8810 |
377 | else |
378 | vortex_wtdma_pausefifo(chip, dma); |
379 | #endif |
380 | break; |
381 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: |
382 | //printk(KERN_INFO "vortex: resume %d\n", dma); |
383 | if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) |
384 | vortex_adbdma_resumefifo(vortex: chip, adbdma: dma); |
385 | #ifndef CHIP_AU8810 |
386 | else |
387 | vortex_wtdma_resumefifo(chip, dma); |
388 | #endif |
389 | break; |
390 | default: |
391 | spin_unlock(lock: &chip->lock); |
392 | return -EINVAL; |
393 | } |
394 | spin_unlock(lock: &chip->lock); |
395 | return 0; |
396 | } |
397 | |
398 | /* pointer callback */ |
399 | static snd_pcm_uframes_t snd_vortex_pcm_pointer(struct snd_pcm_substream *substream) |
400 | { |
401 | vortex_t *chip = snd_pcm_substream_chip(substream); |
402 | stream_t *stream = (stream_t *) substream->runtime->private_data; |
403 | int dma = stream->dma; |
404 | snd_pcm_uframes_t current_ptr = 0; |
405 | |
406 | spin_lock(lock: &chip->lock); |
407 | if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) |
408 | current_ptr = vortex_adbdma_getlinearpos(vortex: chip, adbdma: dma); |
409 | #ifndef CHIP_AU8810 |
410 | else |
411 | current_ptr = vortex_wtdma_getlinearpos(chip, dma); |
412 | #endif |
413 | //printk(KERN_INFO "vortex: pointer = 0x%x\n", current_ptr); |
414 | spin_unlock(lock: &chip->lock); |
415 | current_ptr = bytes_to_frames(runtime: substream->runtime, size: current_ptr); |
416 | if (current_ptr >= substream->runtime->buffer_size) |
417 | current_ptr = 0; |
418 | return current_ptr; |
419 | } |
420 | |
421 | /* operators */ |
422 | static const struct snd_pcm_ops snd_vortex_playback_ops = { |
423 | .open = snd_vortex_pcm_open, |
424 | .close = snd_vortex_pcm_close, |
425 | .hw_params = snd_vortex_pcm_hw_params, |
426 | .hw_free = snd_vortex_pcm_hw_free, |
427 | .prepare = snd_vortex_pcm_prepare, |
428 | .trigger = snd_vortex_pcm_trigger, |
429 | .pointer = snd_vortex_pcm_pointer, |
430 | }; |
431 | |
432 | /* |
433 | * definitions of capture are omitted here... |
434 | */ |
435 | |
436 | static const char * const vortex_pcm_prettyname[VORTEX_PCM_LAST] = { |
437 | CARD_NAME " ADB" , |
438 | CARD_NAME " SPDIF" , |
439 | CARD_NAME " A3D" , |
440 | CARD_NAME " WT" , |
441 | CARD_NAME " I2S" , |
442 | }; |
443 | static const char * const vortex_pcm_name[VORTEX_PCM_LAST] = { |
444 | "adb" , |
445 | "spdif" , |
446 | "a3d" , |
447 | "wt" , |
448 | "i2s" , |
449 | }; |
450 | |
451 | /* SPDIF kcontrol */ |
452 | |
453 | static int snd_vortex_spdif_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) |
454 | { |
455 | uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; |
456 | uinfo->count = 1; |
457 | return 0; |
458 | } |
459 | |
460 | static int snd_vortex_spdif_mask_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
461 | { |
462 | ucontrol->value.iec958.status[0] = 0xff; |
463 | ucontrol->value.iec958.status[1] = 0xff; |
464 | ucontrol->value.iec958.status[2] = 0xff; |
465 | ucontrol->value.iec958.status[3] = IEC958_AES3_CON_FS; |
466 | return 0; |
467 | } |
468 | |
469 | static int snd_vortex_spdif_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
470 | { |
471 | vortex_t *vortex = snd_kcontrol_chip(kcontrol); |
472 | ucontrol->value.iec958.status[0] = 0x00; |
473 | ucontrol->value.iec958.status[1] = IEC958_AES1_CON_ORIGINAL|IEC958_AES1_CON_DIGDIGCONV_ID; |
474 | ucontrol->value.iec958.status[2] = 0x00; |
475 | switch (vortex->spdif_sr) { |
476 | case 32000: ucontrol->value.iec958.status[3] = IEC958_AES3_CON_FS_32000; break; |
477 | case 44100: ucontrol->value.iec958.status[3] = IEC958_AES3_CON_FS_44100; break; |
478 | case 48000: ucontrol->value.iec958.status[3] = IEC958_AES3_CON_FS_48000; break; |
479 | } |
480 | return 0; |
481 | } |
482 | |
483 | static int snd_vortex_spdif_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
484 | { |
485 | vortex_t *vortex = snd_kcontrol_chip(kcontrol); |
486 | int spdif_sr = 48000; |
487 | switch (ucontrol->value.iec958.status[3] & IEC958_AES3_CON_FS) { |
488 | case IEC958_AES3_CON_FS_32000: spdif_sr = 32000; break; |
489 | case IEC958_AES3_CON_FS_44100: spdif_sr = 44100; break; |
490 | case IEC958_AES3_CON_FS_48000: spdif_sr = 48000; break; |
491 | } |
492 | if (spdif_sr == vortex->spdif_sr) |
493 | return 0; |
494 | vortex->spdif_sr = spdif_sr; |
495 | vortex_spdif_init(vortex, spdif_sr: vortex->spdif_sr, spdif_mode: 1); |
496 | return 1; |
497 | } |
498 | |
499 | /* spdif controls */ |
500 | static const struct snd_kcontrol_new snd_vortex_mixer_spdif[] = { |
501 | { |
502 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, |
503 | .name = SNDRV_CTL_NAME_IEC958("" ,PLAYBACK,DEFAULT), |
504 | .info = snd_vortex_spdif_info, |
505 | .get = snd_vortex_spdif_get, |
506 | .put = snd_vortex_spdif_put, |
507 | }, |
508 | { |
509 | .access = SNDRV_CTL_ELEM_ACCESS_READ, |
510 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, |
511 | .name = SNDRV_CTL_NAME_IEC958("" ,PLAYBACK,CON_MASK), |
512 | .info = snd_vortex_spdif_info, |
513 | .get = snd_vortex_spdif_mask_get |
514 | }, |
515 | }; |
516 | |
517 | /* subdevice PCM Volume control */ |
518 | |
519 | static int snd_vortex_pcm_vol_info(struct snd_kcontrol *kcontrol, |
520 | struct snd_ctl_elem_info *uinfo) |
521 | { |
522 | vortex_t *vortex = snd_kcontrol_chip(kcontrol); |
523 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; |
524 | uinfo->count = (VORTEX_IS_QUAD(vortex) ? 4 : 2); |
525 | uinfo->value.integer.min = -128; |
526 | uinfo->value.integer.max = 32; |
527 | return 0; |
528 | } |
529 | |
530 | static int snd_vortex_pcm_vol_get(struct snd_kcontrol *kcontrol, |
531 | struct snd_ctl_elem_value *ucontrol) |
532 | { |
533 | int i; |
534 | vortex_t *vortex = snd_kcontrol_chip(kcontrol); |
535 | int subdev = kcontrol->id.subdevice; |
536 | struct pcm_vol *p = &vortex->pcm_vol[subdev]; |
537 | int max_chn = (VORTEX_IS_QUAD(vortex) ? 4 : 2); |
538 | for (i = 0; i < max_chn; i++) |
539 | ucontrol->value.integer.value[i] = p->vol[i]; |
540 | return 0; |
541 | } |
542 | |
543 | static int snd_vortex_pcm_vol_put(struct snd_kcontrol *kcontrol, |
544 | struct snd_ctl_elem_value *ucontrol) |
545 | { |
546 | int i; |
547 | int changed = 0; |
548 | int mixin; |
549 | unsigned char vol; |
550 | vortex_t *vortex = snd_kcontrol_chip(kcontrol); |
551 | int subdev = kcontrol->id.subdevice; |
552 | struct pcm_vol *p = &vortex->pcm_vol[subdev]; |
553 | int max_chn = (VORTEX_IS_QUAD(vortex) ? 4 : 2); |
554 | for (i = 0; i < max_chn; i++) { |
555 | if (p->vol[i] != ucontrol->value.integer.value[i]) { |
556 | p->vol[i] = ucontrol->value.integer.value[i]; |
557 | if (p->active) { |
558 | switch (vortex->dma_adb[p->dma].nr_ch) { |
559 | case 1: |
560 | mixin = p->mixin[0]; |
561 | break; |
562 | case 2: |
563 | default: |
564 | mixin = p->mixin[(i < 2) ? i : (i - 2)]; |
565 | break; |
566 | case 4: |
567 | mixin = p->mixin[i]; |
568 | break; |
569 | } |
570 | vol = p->vol[i]; |
571 | vortex_mix_setinputvolumebyte(vortex, |
572 | mix: vortex->mixplayb[i], mixin, vol); |
573 | } |
574 | changed = 1; |
575 | } |
576 | } |
577 | return changed; |
578 | } |
579 | |
580 | static const DECLARE_TLV_DB_MINMAX(vortex_pcm_vol_db_scale, -9600, 2400); |
581 | |
582 | static const struct snd_kcontrol_new snd_vortex_pcm_vol = { |
583 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, |
584 | .name = "PCM Playback Volume" , |
585 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | |
586 | SNDRV_CTL_ELEM_ACCESS_TLV_READ | |
587 | SNDRV_CTL_ELEM_ACCESS_INACTIVE, |
588 | .info = snd_vortex_pcm_vol_info, |
589 | .get = snd_vortex_pcm_vol_get, |
590 | .put = snd_vortex_pcm_vol_put, |
591 | .tlv = { .p = vortex_pcm_vol_db_scale }, |
592 | }; |
593 | |
594 | /* create a pcm device */ |
595 | static int snd_vortex_new_pcm(vortex_t *chip, int idx, int nr) |
596 | { |
597 | struct snd_pcm *pcm; |
598 | struct snd_kcontrol *kctl; |
599 | int i; |
600 | int err, nr_capt; |
601 | |
602 | if (!chip || idx < 0 || idx >= VORTEX_PCM_LAST) |
603 | return -ENODEV; |
604 | |
605 | /* idx indicates which kind of PCM device. ADB, SPDIF, I2S and A3D share the |
606 | * same dma engine. WT uses it own separate dma engine which can't capture. */ |
607 | if (idx == VORTEX_PCM_ADB) |
608 | nr_capt = nr; |
609 | else |
610 | nr_capt = 0; |
611 | err = snd_pcm_new(card: chip->card, id: vortex_pcm_prettyname[idx], device: idx, playback_count: nr, |
612 | capture_count: nr_capt, rpcm: &pcm); |
613 | if (err < 0) |
614 | return err; |
615 | snprintf(buf: pcm->name, size: sizeof(pcm->name), |
616 | fmt: "%s %s" , CARD_NAME_SHORT, vortex_pcm_name[idx]); |
617 | chip->pcm[idx] = pcm; |
618 | // This is an evil hack, but it saves a lot of duplicated code. |
619 | VORTEX_PCM_TYPE(pcm) = idx; |
620 | pcm->private_data = chip; |
621 | /* set operators */ |
622 | snd_pcm_set_ops(pcm, direction: SNDRV_PCM_STREAM_PLAYBACK, |
623 | ops: &snd_vortex_playback_ops); |
624 | if (idx == VORTEX_PCM_ADB) |
625 | snd_pcm_set_ops(pcm, direction: SNDRV_PCM_STREAM_CAPTURE, |
626 | ops: &snd_vortex_playback_ops); |
627 | |
628 | /* pre-allocation of Scatter-Gather buffers */ |
629 | |
630 | snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV_SG, |
631 | data: &chip->pci_dev->dev, size: 0x10000, max: 0x10000); |
632 | |
633 | switch (VORTEX_PCM_TYPE(pcm)) { |
634 | case VORTEX_PCM_ADB: |
635 | err = snd_pcm_add_chmap_ctls(pcm, stream: SNDRV_PCM_STREAM_PLAYBACK, |
636 | chmap: snd_pcm_std_chmaps, |
637 | VORTEX_IS_QUAD(chip) ? 4 : 2, |
638 | private_value: 0, NULL); |
639 | if (err < 0) |
640 | return err; |
641 | err = snd_pcm_add_chmap_ctls(pcm, stream: SNDRV_PCM_STREAM_CAPTURE, |
642 | chmap: snd_pcm_std_chmaps, max_channels: 2, private_value: 0, NULL); |
643 | if (err < 0) |
644 | return err; |
645 | break; |
646 | #ifdef CHIP_AU8830 |
647 | case VORTEX_PCM_A3D: |
648 | err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, |
649 | snd_pcm_std_chmaps, 1, 0, NULL); |
650 | if (err < 0) |
651 | return err; |
652 | break; |
653 | #endif |
654 | } |
655 | |
656 | if (VORTEX_PCM_TYPE(pcm) == VORTEX_PCM_SPDIF) { |
657 | for (i = 0; i < ARRAY_SIZE(snd_vortex_mixer_spdif); i++) { |
658 | kctl = snd_ctl_new1(kcontrolnew: &snd_vortex_mixer_spdif[i], private_data: chip); |
659 | if (!kctl) |
660 | return -ENOMEM; |
661 | err = snd_ctl_add(card: chip->card, kcontrol: kctl); |
662 | if (err < 0) |
663 | return err; |
664 | } |
665 | } |
666 | if (VORTEX_PCM_TYPE(pcm) == VORTEX_PCM_ADB) { |
667 | for (i = 0; i < NR_PCM; i++) { |
668 | chip->pcm_vol[i].active = 0; |
669 | chip->pcm_vol[i].dma = -1; |
670 | kctl = snd_ctl_new1(kcontrolnew: &snd_vortex_pcm_vol, private_data: chip); |
671 | if (!kctl) |
672 | return -ENOMEM; |
673 | chip->pcm_vol[i].kctl = kctl; |
674 | kctl->id.device = 0; |
675 | kctl->id.subdevice = i; |
676 | err = snd_ctl_add(card: chip->card, kcontrol: kctl); |
677 | if (err < 0) |
678 | return err; |
679 | } |
680 | } |
681 | return 0; |
682 | } |
683 | |