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 */ | |
c2b0718f TI |
133 | err = snd_pcm_hw_constraint_integer(runtime, |
134 | SNDRV_PCM_HW_PARAM_PERIODS); | |
135 | if (err < 0) | |
1da177e4 LT |
136 | return err; |
137 | /* Avoid PAGE_SIZE boundary to fall inside of a period. */ | |
c2b0718f TI |
138 | err = snd_pcm_hw_constraint_pow2(runtime, 0, |
139 | SNDRV_PCM_HW_PARAM_PERIOD_BYTES); | |
140 | if (err < 0) | |
1da177e4 LT |
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 | 212 | |
1da177e4 | 213 | /* |
e7e69265 | 214 | pr_info( "Vortex: periods %d, period_bytes %d, channels = %d\n", params_periods(hw_params), |
1da177e4 LT |
215 | params_period_bytes(hw_params), params_channels(hw_params)); |
216 | */ | |
217 | spin_lock_irq(&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(chip, stream->dma, | |
224 | stream->nr_ch, stream->dir, | |
bb92b7c4 RY |
225 | stream->type, |
226 | substream->number); | |
1da177e4 LT |
227 | /* Alloc routes. */ |
228 | dma = | |
229 | vortex_adb_allocroute(chip, -1, | |
230 | params_channels(hw_params), | |
bb92b7c4 RY |
231 | substream->stream, type, |
232 | substream->number); | |
a278655f TI |
233 | if (dma < 0) { |
234 | spin_unlock_irq(&chip->lock); | |
1da177e4 | 235 | return dma; |
a278655f | 236 | } |
1da177e4 LT |
237 | stream = substream->runtime->private_data = &chip->dma_adb[dma]; |
238 | stream->substream = substream; | |
239 | /* Setup Buffers. */ | |
77a23f26 | 240 | vortex_adbdma_setbuffers(chip, dma, |
1da177e4 LT |
241 | params_period_bytes(hw_params), |
242 | params_periods(hw_params)); | |
bb92b7c4 RY |
243 | if (VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_ADB) { |
244 | chip->pcm_vol[substream->number].active = 1; | |
245 | vortex_notify_pcm_vol_change(chip->card, | |
246 | chip->pcm_vol[substream->number].kctl, 1); | |
247 | } | |
1da177e4 LT |
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; | |
77a23f26 | 259 | vortex_wtdma_setbuffers(chip, substream->number, |
1da177e4 LT |
260 | params_period_bytes(hw_params), |
261 | params_periods(hw_params)); | |
262 | } | |
263 | #endif | |
264 | spin_unlock_irq(&chip->lock); | |
265 | return 0; | |
266 | } | |
267 | ||
268 | /* hw_free callback */ | |
2fd16874 | 269 | static int snd_vortex_pcm_hw_free(struct snd_pcm_substream *substream) |
1da177e4 LT |
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(&chip->lock); | |
275 | // Delete audio routes. | |
276 | if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) { | |
bb92b7c4 RY |
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(chip->card, | |
281 | chip->pcm_vol[substream->number].kctl, | |
282 | 0); | |
283 | } | |
1da177e4 LT |
284 | vortex_adb_allocroute(chip, stream->dma, |
285 | stream->nr_ch, stream->dir, | |
bb92b7c4 RY |
286 | stream->type, |
287 | substream->number); | |
288 | } | |
1da177e4 LT |
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(&chip->lock); | |
298 | ||
8c847a42 | 299 | return 0; |
1da177e4 LT |
300 | } |
301 | ||
302 | /* prepare callback */ | |
2fd16874 | 303 | static int snd_vortex_pcm_prepare(struct snd_pcm_substream *substream) |
1da177e4 LT |
304 | { |
305 | vortex_t *chip = snd_pcm_substream_chip(substream); | |
2fd16874 | 306 | struct snd_pcm_runtime *runtime = substream->runtime; |
1da177e4 LT |
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; | |
6a40dc5a | 315 | fmt = vortex_alsafmt_aspfmt(runtime->format, chip); |
1da177e4 LT |
316 | spin_lock_irq(&chip->lock); |
317 | if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) { | |
3ae4e1f7 RY |
318 | vortex_adbdma_setmode(chip, dma, 1, dir, fmt, |
319 | runtime->channels == 1 ? 0 : 1, 0); | |
1da177e4 LT |
320 | vortex_adbdma_setstartbuffer(chip, dma, 0); |
321 | if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_SPDIF) | |
322 | vortex_adb_setsrc(chip, dma, 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(&chip->lock); | |
332 | return 0; | |
333 | } | |
334 | ||
335 | /* trigger callback */ | |
2fd16874 | 336 | static int snd_vortex_pcm_trigger(struct snd_pcm_substream *substream, int cmd) |
1da177e4 LT |
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(&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(chip, dma); | |
350 | vortex_adbdma_startfifo(chip, dma); | |
351 | } | |
352 | #ifndef CHIP_AU8810 | |
353 | else { | |
70c84418 | 354 | dev_info(chip->card->dev, "wt start %d\n", dma); |
1da177e4 LT |
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) | |
fb65c2df | 364 | vortex_adbdma_stopfifo(chip, dma); |
1da177e4 LT |
365 | #ifndef CHIP_AU8810 |
366 | else { | |
70c84418 | 367 | dev_info(chip->card->dev, "wt stop %d\n", dma); |
1da177e4 LT |
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(chip, 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(chip, dma); | |
385 | #ifndef CHIP_AU8810 | |
386 | else | |
387 | vortex_wtdma_resumefifo(chip, dma); | |
388 | #endif | |
389 | break; | |
390 | default: | |
391 | spin_unlock(&chip->lock); | |
392 | return -EINVAL; | |
393 | } | |
394 | spin_unlock(&chip->lock); | |
395 | return 0; | |
396 | } | |
397 | ||
398 | /* pointer callback */ | |
2fd16874 | 399 | static snd_pcm_uframes_t snd_vortex_pcm_pointer(struct snd_pcm_substream *substream) |
1da177e4 LT |
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(&chip->lock); | |
407 | if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) | |
408 | current_ptr = vortex_adbdma_getlinearpos(chip, 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(&chip->lock); | |
58a8738c TI |
415 | current_ptr = bytes_to_frames(substream->runtime, current_ptr); |
416 | if (current_ptr >= substream->runtime->buffer_size) | |
417 | current_ptr = 0; | |
418 | return current_ptr; | |
1da177e4 LT |
419 | } |
420 | ||
1da177e4 | 421 | /* operators */ |
0b5b2339 | 422 | static const struct snd_pcm_ops snd_vortex_playback_ops = { |
1da177e4 LT |
423 | .open = snd_vortex_pcm_open, |
424 | .close = snd_vortex_pcm_close, | |
1da177e4 LT |
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, | |
1da177e4 LT |
430 | }; |
431 | ||
432 | /* | |
433 | * definitions of capture are omitted here... | |
434 | */ | |
435 | ||
eafcdbdb | 436 | static const char * const vortex_pcm_prettyname[VORTEX_PCM_LAST] = { |
13eb4ab8 RY |
437 | CARD_NAME " ADB", |
438 | CARD_NAME " SPDIF", | |
439 | CARD_NAME " A3D", | |
440 | CARD_NAME " WT", | |
441 | CARD_NAME " I2S", | |
1da177e4 | 442 | }; |
eafcdbdb | 443 | static const char * const vortex_pcm_name[VORTEX_PCM_LAST] = { |
1da177e4 LT |
444 | "adb", |
445 | "spdif", | |
446 | "a3d", | |
447 | "wt", | |
448 | "i2s", | |
449 | }; | |
450 | ||
451 | /* SPDIF kcontrol */ | |
452 | ||
2fd16874 | 453 | static int snd_vortex_spdif_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) |
1da177e4 LT |
454 | { |
455 | uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; | |
456 | uinfo->count = 1; | |
457 | return 0; | |
458 | } | |
459 | ||
2fd16874 | 460 | static int snd_vortex_spdif_mask_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
1da177e4 LT |
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 | ||
2fd16874 | 469 | static int snd_vortex_spdif_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
1da177e4 LT |
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 | ||
2fd16874 | 483 | static int snd_vortex_spdif_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
1da177e4 LT |
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, vortex->spdif_sr, 1); | |
496 | return 1; | |
497 | } | |
498 | ||
499 | /* spdif controls */ | |
b4e5e707 | 500 | static const struct snd_kcontrol_new snd_vortex_mixer_spdif[] = { |
1da177e4 LT |
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 | ||
bb92b7c4 RY |
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; | |
395d9dd5 | 569 | } |
bb92b7c4 RY |
570 | vol = p->vol[i]; |
571 | vortex_mix_setinputvolumebyte(vortex, | |
572 | 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 | ||
f3b827e0 | 582 | static const struct snd_kcontrol_new snd_vortex_pcm_vol = { |
bb92b7c4 RY |
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 | ||
1da177e4 | 594 | /* create a pcm device */ |
e23e7a14 | 595 | static int snd_vortex_new_pcm(vortex_t *chip, int idx, int nr) |
1da177e4 | 596 | { |
2fd16874 TI |
597 | struct snd_pcm *pcm; |
598 | struct snd_kcontrol *kctl; | |
1da177e4 LT |
599 | int i; |
600 | int err, nr_capt; | |
601 | ||
3fa4a907 | 602 | if (!chip || idx < 0 || idx >= VORTEX_PCM_LAST) |
1da177e4 LT |
603 | return -ENODEV; |
604 | ||
605 | /* idx indicates which kind of PCM device. ADB, SPDIF, I2S and A3D share the | |
25985edc | 606 | * same dma engine. WT uses it own separate dma engine which can't capture. */ |
1da177e4 LT |
607 | if (idx == VORTEX_PCM_ADB) |
608 | nr_capt = nr; | |
609 | else | |
610 | nr_capt = 0; | |
3fa4a907 HH |
611 | err = snd_pcm_new(chip->card, vortex_pcm_prettyname[idx], idx, nr, |
612 | nr_capt, &pcm); | |
613 | if (err < 0) | |
1da177e4 | 614 | return err; |
13eb4ab8 RY |
615 | snprintf(pcm->name, sizeof(pcm->name), |
616 | "%s %s", CARD_NAME_SHORT, vortex_pcm_name[idx]); | |
1da177e4 LT |
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, SNDRV_PCM_STREAM_PLAYBACK, | |
623 | &snd_vortex_playback_ops); | |
624 | if (idx == VORTEX_PCM_ADB) | |
625 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, | |
626 | &snd_vortex_playback_ops); | |
627 | ||
628 | /* pre-allocation of Scatter-Gather buffers */ | |
629 | ||
8c847a42 TI |
630 | snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV_SG, |
631 | &chip->pci_dev->dev, 0x10000, 0x10000); | |
1da177e4 | 632 | |
f3c90242 RY |
633 | switch (VORTEX_PCM_TYPE(pcm)) { |
634 | case VORTEX_PCM_ADB: | |
635 | err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, | |
636 | snd_pcm_std_chmaps, | |
637 | VORTEX_IS_QUAD(chip) ? 4 : 2, | |
638 | 0, NULL); | |
639 | if (err < 0) | |
640 | return err; | |
641 | err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_CAPTURE, | |
642 | snd_pcm_std_chmaps, 2, 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 | |
1d198f26 | 654 | } |
f3c90242 | 655 | |
1da177e4 LT |
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(&snd_vortex_mixer_spdif[i], chip); | |
659 | if (!kctl) | |
660 | return -ENOMEM; | |
c2b0718f TI |
661 | err = snd_ctl_add(chip->card, kctl); |
662 | if (err < 0) | |
1da177e4 LT |
663 | return err; |
664 | } | |
665 | } | |
bb92b7c4 RY |
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(&snd_vortex_pcm_vol, 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(chip->card, kctl); | |
677 | if (err < 0) | |
678 | return err; | |
679 | } | |
680 | } | |
1da177e4 LT |
681 | return 0; |
682 | } |