162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci */
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci/*
662306a36Sopenharmony_ci * Vortex PCM ALSA driver.
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * Supports ADB and WT DMA. Unfortunately, WT channels do not run yet.
962306a36Sopenharmony_ci * It remains stuck,and DMA transfers do not happen.
1062306a36Sopenharmony_ci */
1162306a36Sopenharmony_ci#include <sound/asoundef.h>
1262306a36Sopenharmony_ci#include <linux/time.h>
1362306a36Sopenharmony_ci#include <sound/core.h>
1462306a36Sopenharmony_ci#include <sound/pcm.h>
1562306a36Sopenharmony_ci#include <sound/pcm_params.h>
1662306a36Sopenharmony_ci#include "au88x0.h"
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#define VORTEX_PCM_TYPE(x) (x->name[40])
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci/* hardware definition */
2162306a36Sopenharmony_cistatic const struct snd_pcm_hardware snd_vortex_playback_hw_adb = {
2262306a36Sopenharmony_ci	.info =
2362306a36Sopenharmony_ci	    (SNDRV_PCM_INFO_MMAP | /* SNDRV_PCM_INFO_RESUME | */
2462306a36Sopenharmony_ci	     SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_INTERLEAVED |
2562306a36Sopenharmony_ci	     SNDRV_PCM_INFO_MMAP_VALID),
2662306a36Sopenharmony_ci	.formats =
2762306a36Sopenharmony_ci	    SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U8 |
2862306a36Sopenharmony_ci	    SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW,
2962306a36Sopenharmony_ci	.rates = SNDRV_PCM_RATE_CONTINUOUS,
3062306a36Sopenharmony_ci	.rate_min = 5000,
3162306a36Sopenharmony_ci	.rate_max = 48000,
3262306a36Sopenharmony_ci	.channels_min = 1,
3362306a36Sopenharmony_ci	.channels_max = 2,
3462306a36Sopenharmony_ci	.buffer_bytes_max = 0x10000,
3562306a36Sopenharmony_ci	.period_bytes_min = 0x20,
3662306a36Sopenharmony_ci	.period_bytes_max = 0x1000,
3762306a36Sopenharmony_ci	.periods_min = 2,
3862306a36Sopenharmony_ci	.periods_max = 1024,
3962306a36Sopenharmony_ci};
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci#ifndef CHIP_AU8820
4262306a36Sopenharmony_cistatic const struct snd_pcm_hardware snd_vortex_playback_hw_a3d = {
4362306a36Sopenharmony_ci	.info =
4462306a36Sopenharmony_ci	    (SNDRV_PCM_INFO_MMAP | /* SNDRV_PCM_INFO_RESUME | */
4562306a36Sopenharmony_ci	     SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_INTERLEAVED |
4662306a36Sopenharmony_ci	     SNDRV_PCM_INFO_MMAP_VALID),
4762306a36Sopenharmony_ci	.formats =
4862306a36Sopenharmony_ci	    SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U8 |
4962306a36Sopenharmony_ci	    SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW,
5062306a36Sopenharmony_ci	.rates = SNDRV_PCM_RATE_CONTINUOUS,
5162306a36Sopenharmony_ci	.rate_min = 5000,
5262306a36Sopenharmony_ci	.rate_max = 48000,
5362306a36Sopenharmony_ci	.channels_min = 1,
5462306a36Sopenharmony_ci	.channels_max = 1,
5562306a36Sopenharmony_ci	.buffer_bytes_max = 0x10000,
5662306a36Sopenharmony_ci	.period_bytes_min = 0x100,
5762306a36Sopenharmony_ci	.period_bytes_max = 0x1000,
5862306a36Sopenharmony_ci	.periods_min = 2,
5962306a36Sopenharmony_ci	.periods_max = 64,
6062306a36Sopenharmony_ci};
6162306a36Sopenharmony_ci#endif
6262306a36Sopenharmony_cistatic const struct snd_pcm_hardware snd_vortex_playback_hw_spdif = {
6362306a36Sopenharmony_ci	.info =
6462306a36Sopenharmony_ci	    (SNDRV_PCM_INFO_MMAP | /* SNDRV_PCM_INFO_RESUME | */
6562306a36Sopenharmony_ci	     SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_INTERLEAVED |
6662306a36Sopenharmony_ci	     SNDRV_PCM_INFO_MMAP_VALID),
6762306a36Sopenharmony_ci	.formats =
6862306a36Sopenharmony_ci	    SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U8 |
6962306a36Sopenharmony_ci	    SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE | SNDRV_PCM_FMTBIT_MU_LAW |
7062306a36Sopenharmony_ci	    SNDRV_PCM_FMTBIT_A_LAW,
7162306a36Sopenharmony_ci	.rates =
7262306a36Sopenharmony_ci	    SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
7362306a36Sopenharmony_ci	.rate_min = 32000,
7462306a36Sopenharmony_ci	.rate_max = 48000,
7562306a36Sopenharmony_ci	.channels_min = 1,
7662306a36Sopenharmony_ci	.channels_max = 2,
7762306a36Sopenharmony_ci	.buffer_bytes_max = 0x10000,
7862306a36Sopenharmony_ci	.period_bytes_min = 0x100,
7962306a36Sopenharmony_ci	.period_bytes_max = 0x1000,
8062306a36Sopenharmony_ci	.periods_min = 2,
8162306a36Sopenharmony_ci	.periods_max = 64,
8262306a36Sopenharmony_ci};
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci#ifndef CHIP_AU8810
8562306a36Sopenharmony_cistatic const struct snd_pcm_hardware snd_vortex_playback_hw_wt = {
8662306a36Sopenharmony_ci	.info = (SNDRV_PCM_INFO_MMAP |
8762306a36Sopenharmony_ci		 SNDRV_PCM_INFO_INTERLEAVED |
8862306a36Sopenharmony_ci		 SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID),
8962306a36Sopenharmony_ci	.formats = SNDRV_PCM_FMTBIT_S16_LE,
9062306a36Sopenharmony_ci	.rates = SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_CONTINUOUS,	// SNDRV_PCM_RATE_48000,
9162306a36Sopenharmony_ci	.rate_min = 8000,
9262306a36Sopenharmony_ci	.rate_max = 48000,
9362306a36Sopenharmony_ci	.channels_min = 1,
9462306a36Sopenharmony_ci	.channels_max = 2,
9562306a36Sopenharmony_ci	.buffer_bytes_max = 0x10000,
9662306a36Sopenharmony_ci	.period_bytes_min = 0x0400,
9762306a36Sopenharmony_ci	.period_bytes_max = 0x1000,
9862306a36Sopenharmony_ci	.periods_min = 2,
9962306a36Sopenharmony_ci	.periods_max = 64,
10062306a36Sopenharmony_ci};
10162306a36Sopenharmony_ci#endif
10262306a36Sopenharmony_ci#ifdef CHIP_AU8830
10362306a36Sopenharmony_cistatic const unsigned int au8830_channels[3] = {
10462306a36Sopenharmony_ci	1, 2, 4,
10562306a36Sopenharmony_ci};
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_cistatic const struct snd_pcm_hw_constraint_list hw_constraints_au8830_channels = {
10862306a36Sopenharmony_ci	.count = ARRAY_SIZE(au8830_channels),
10962306a36Sopenharmony_ci	.list = au8830_channels,
11062306a36Sopenharmony_ci	.mask = 0,
11162306a36Sopenharmony_ci};
11262306a36Sopenharmony_ci#endif
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_cistatic void vortex_notify_pcm_vol_change(struct snd_card *card,
11562306a36Sopenharmony_ci			struct snd_kcontrol *kctl, int activate)
11662306a36Sopenharmony_ci{
11762306a36Sopenharmony_ci	if (activate)
11862306a36Sopenharmony_ci		kctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE;
11962306a36Sopenharmony_ci	else
12062306a36Sopenharmony_ci		kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE;
12162306a36Sopenharmony_ci	snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE |
12262306a36Sopenharmony_ci				SNDRV_CTL_EVENT_MASK_INFO, &(kctl->id));
12362306a36Sopenharmony_ci}
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci/* open callback */
12662306a36Sopenharmony_cistatic int snd_vortex_pcm_open(struct snd_pcm_substream *substream)
12762306a36Sopenharmony_ci{
12862306a36Sopenharmony_ci	vortex_t *vortex = snd_pcm_substream_chip(substream);
12962306a36Sopenharmony_ci	struct snd_pcm_runtime *runtime = substream->runtime;
13062306a36Sopenharmony_ci	int err;
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	/* Force equal size periods */
13362306a36Sopenharmony_ci	err = snd_pcm_hw_constraint_integer(runtime,
13462306a36Sopenharmony_ci					    SNDRV_PCM_HW_PARAM_PERIODS);
13562306a36Sopenharmony_ci	if (err < 0)
13662306a36Sopenharmony_ci		return err;
13762306a36Sopenharmony_ci	/* Avoid PAGE_SIZE boundary to fall inside of a period. */
13862306a36Sopenharmony_ci	err = snd_pcm_hw_constraint_pow2(runtime, 0,
13962306a36Sopenharmony_ci					 SNDRV_PCM_HW_PARAM_PERIOD_BYTES);
14062306a36Sopenharmony_ci	if (err < 0)
14162306a36Sopenharmony_ci		return err;
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	snd_pcm_hw_constraint_step(runtime, 0,
14462306a36Sopenharmony_ci					SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 64);
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) {
14762306a36Sopenharmony_ci#ifndef CHIP_AU8820
14862306a36Sopenharmony_ci		if (VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_A3D) {
14962306a36Sopenharmony_ci			runtime->hw = snd_vortex_playback_hw_a3d;
15062306a36Sopenharmony_ci		}
15162306a36Sopenharmony_ci#endif
15262306a36Sopenharmony_ci		if (VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_SPDIF) {
15362306a36Sopenharmony_ci			runtime->hw = snd_vortex_playback_hw_spdif;
15462306a36Sopenharmony_ci			switch (vortex->spdif_sr) {
15562306a36Sopenharmony_ci			case 32000:
15662306a36Sopenharmony_ci				runtime->hw.rates = SNDRV_PCM_RATE_32000;
15762306a36Sopenharmony_ci				break;
15862306a36Sopenharmony_ci			case 44100:
15962306a36Sopenharmony_ci				runtime->hw.rates = SNDRV_PCM_RATE_44100;
16062306a36Sopenharmony_ci				break;
16162306a36Sopenharmony_ci			case 48000:
16262306a36Sopenharmony_ci				runtime->hw.rates = SNDRV_PCM_RATE_48000;
16362306a36Sopenharmony_ci				break;
16462306a36Sopenharmony_ci			}
16562306a36Sopenharmony_ci		}
16662306a36Sopenharmony_ci		if (VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_ADB
16762306a36Sopenharmony_ci		    || VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_I2S)
16862306a36Sopenharmony_ci			runtime->hw = snd_vortex_playback_hw_adb;
16962306a36Sopenharmony_ci#ifdef CHIP_AU8830
17062306a36Sopenharmony_ci		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
17162306a36Sopenharmony_ci			VORTEX_IS_QUAD(vortex) &&
17262306a36Sopenharmony_ci			VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_ADB) {
17362306a36Sopenharmony_ci			runtime->hw.channels_max = 4;
17462306a36Sopenharmony_ci			snd_pcm_hw_constraint_list(runtime, 0,
17562306a36Sopenharmony_ci				SNDRV_PCM_HW_PARAM_CHANNELS,
17662306a36Sopenharmony_ci				&hw_constraints_au8830_channels);
17762306a36Sopenharmony_ci		}
17862306a36Sopenharmony_ci#endif
17962306a36Sopenharmony_ci		substream->runtime->private_data = NULL;
18062306a36Sopenharmony_ci	}
18162306a36Sopenharmony_ci#ifndef CHIP_AU8810
18262306a36Sopenharmony_ci	else {
18362306a36Sopenharmony_ci		runtime->hw = snd_vortex_playback_hw_wt;
18462306a36Sopenharmony_ci		substream->runtime->private_data = NULL;
18562306a36Sopenharmony_ci	}
18662306a36Sopenharmony_ci#endif
18762306a36Sopenharmony_ci	return 0;
18862306a36Sopenharmony_ci}
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci/* close callback */
19162306a36Sopenharmony_cistatic int snd_vortex_pcm_close(struct snd_pcm_substream *substream)
19262306a36Sopenharmony_ci{
19362306a36Sopenharmony_ci	//vortex_t *chip = snd_pcm_substream_chip(substream);
19462306a36Sopenharmony_ci	stream_t *stream = (stream_t *) substream->runtime->private_data;
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	// the hardware-specific codes will be here
19762306a36Sopenharmony_ci	if (stream != NULL) {
19862306a36Sopenharmony_ci		stream->substream = NULL;
19962306a36Sopenharmony_ci		stream->nr_ch = 0;
20062306a36Sopenharmony_ci	}
20162306a36Sopenharmony_ci	substream->runtime->private_data = NULL;
20262306a36Sopenharmony_ci	return 0;
20362306a36Sopenharmony_ci}
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci/* hw_params callback */
20662306a36Sopenharmony_cistatic int
20762306a36Sopenharmony_cisnd_vortex_pcm_hw_params(struct snd_pcm_substream *substream,
20862306a36Sopenharmony_ci			 struct snd_pcm_hw_params *hw_params)
20962306a36Sopenharmony_ci{
21062306a36Sopenharmony_ci	vortex_t *chip = snd_pcm_substream_chip(substream);
21162306a36Sopenharmony_ci	stream_t *stream = (stream_t *) (substream->runtime->private_data);
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	/*
21462306a36Sopenharmony_ci	   pr_info( "Vortex: periods %d, period_bytes %d, channels = %d\n", params_periods(hw_params),
21562306a36Sopenharmony_ci	   params_period_bytes(hw_params), params_channels(hw_params));
21662306a36Sopenharmony_ci	 */
21762306a36Sopenharmony_ci	spin_lock_irq(&chip->lock);
21862306a36Sopenharmony_ci	// Make audio routes and config buffer DMA.
21962306a36Sopenharmony_ci	if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) {
22062306a36Sopenharmony_ci		int dma, type = VORTEX_PCM_TYPE(substream->pcm);
22162306a36Sopenharmony_ci		/* Dealloc any routes. */
22262306a36Sopenharmony_ci		if (stream != NULL)
22362306a36Sopenharmony_ci			vortex_adb_allocroute(chip, stream->dma,
22462306a36Sopenharmony_ci					      stream->nr_ch, stream->dir,
22562306a36Sopenharmony_ci					      stream->type,
22662306a36Sopenharmony_ci					      substream->number);
22762306a36Sopenharmony_ci		/* Alloc routes. */
22862306a36Sopenharmony_ci		dma =
22962306a36Sopenharmony_ci		    vortex_adb_allocroute(chip, -1,
23062306a36Sopenharmony_ci					  params_channels(hw_params),
23162306a36Sopenharmony_ci					  substream->stream, type,
23262306a36Sopenharmony_ci					  substream->number);
23362306a36Sopenharmony_ci		if (dma < 0) {
23462306a36Sopenharmony_ci			spin_unlock_irq(&chip->lock);
23562306a36Sopenharmony_ci			return dma;
23662306a36Sopenharmony_ci		}
23762306a36Sopenharmony_ci		stream = substream->runtime->private_data = &chip->dma_adb[dma];
23862306a36Sopenharmony_ci		stream->substream = substream;
23962306a36Sopenharmony_ci		/* Setup Buffers. */
24062306a36Sopenharmony_ci		vortex_adbdma_setbuffers(chip, dma,
24162306a36Sopenharmony_ci					 params_period_bytes(hw_params),
24262306a36Sopenharmony_ci					 params_periods(hw_params));
24362306a36Sopenharmony_ci		if (VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_ADB) {
24462306a36Sopenharmony_ci			chip->pcm_vol[substream->number].active = 1;
24562306a36Sopenharmony_ci			vortex_notify_pcm_vol_change(chip->card,
24662306a36Sopenharmony_ci				chip->pcm_vol[substream->number].kctl, 1);
24762306a36Sopenharmony_ci		}
24862306a36Sopenharmony_ci	}
24962306a36Sopenharmony_ci#ifndef CHIP_AU8810
25062306a36Sopenharmony_ci	else {
25162306a36Sopenharmony_ci		/* if (stream != NULL)
25262306a36Sopenharmony_ci		   vortex_wt_allocroute(chip, substream->number, 0); */
25362306a36Sopenharmony_ci		vortex_wt_allocroute(chip, substream->number,
25462306a36Sopenharmony_ci				     params_channels(hw_params));
25562306a36Sopenharmony_ci		stream = substream->runtime->private_data =
25662306a36Sopenharmony_ci		    &chip->dma_wt[substream->number];
25762306a36Sopenharmony_ci		stream->dma = substream->number;
25862306a36Sopenharmony_ci		stream->substream = substream;
25962306a36Sopenharmony_ci		vortex_wtdma_setbuffers(chip, substream->number,
26062306a36Sopenharmony_ci					params_period_bytes(hw_params),
26162306a36Sopenharmony_ci					params_periods(hw_params));
26262306a36Sopenharmony_ci	}
26362306a36Sopenharmony_ci#endif
26462306a36Sopenharmony_ci	spin_unlock_irq(&chip->lock);
26562306a36Sopenharmony_ci	return 0;
26662306a36Sopenharmony_ci}
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci/* hw_free callback */
26962306a36Sopenharmony_cistatic int snd_vortex_pcm_hw_free(struct snd_pcm_substream *substream)
27062306a36Sopenharmony_ci{
27162306a36Sopenharmony_ci	vortex_t *chip = snd_pcm_substream_chip(substream);
27262306a36Sopenharmony_ci	stream_t *stream = (stream_t *) (substream->runtime->private_data);
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	spin_lock_irq(&chip->lock);
27562306a36Sopenharmony_ci	// Delete audio routes.
27662306a36Sopenharmony_ci	if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) {
27762306a36Sopenharmony_ci		if (stream != NULL) {
27862306a36Sopenharmony_ci			if (VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_ADB) {
27962306a36Sopenharmony_ci				chip->pcm_vol[substream->number].active = 0;
28062306a36Sopenharmony_ci				vortex_notify_pcm_vol_change(chip->card,
28162306a36Sopenharmony_ci					chip->pcm_vol[substream->number].kctl,
28262306a36Sopenharmony_ci					0);
28362306a36Sopenharmony_ci			}
28462306a36Sopenharmony_ci			vortex_adb_allocroute(chip, stream->dma,
28562306a36Sopenharmony_ci					      stream->nr_ch, stream->dir,
28662306a36Sopenharmony_ci					      stream->type,
28762306a36Sopenharmony_ci					      substream->number);
28862306a36Sopenharmony_ci		}
28962306a36Sopenharmony_ci	}
29062306a36Sopenharmony_ci#ifndef CHIP_AU8810
29162306a36Sopenharmony_ci	else {
29262306a36Sopenharmony_ci		if (stream != NULL)
29362306a36Sopenharmony_ci			vortex_wt_allocroute(chip, stream->dma, 0);
29462306a36Sopenharmony_ci	}
29562306a36Sopenharmony_ci#endif
29662306a36Sopenharmony_ci	substream->runtime->private_data = NULL;
29762306a36Sopenharmony_ci	spin_unlock_irq(&chip->lock);
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	return 0;
30062306a36Sopenharmony_ci}
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci/* prepare callback */
30362306a36Sopenharmony_cistatic int snd_vortex_pcm_prepare(struct snd_pcm_substream *substream)
30462306a36Sopenharmony_ci{
30562306a36Sopenharmony_ci	vortex_t *chip = snd_pcm_substream_chip(substream);
30662306a36Sopenharmony_ci	struct snd_pcm_runtime *runtime = substream->runtime;
30762306a36Sopenharmony_ci	stream_t *stream = (stream_t *) substream->runtime->private_data;
30862306a36Sopenharmony_ci	int dma = stream->dma, fmt, dir;
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	// set up the hardware with the current configuration.
31162306a36Sopenharmony_ci	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
31262306a36Sopenharmony_ci		dir = 1;
31362306a36Sopenharmony_ci	else
31462306a36Sopenharmony_ci		dir = 0;
31562306a36Sopenharmony_ci	fmt = vortex_alsafmt_aspfmt(runtime->format, chip);
31662306a36Sopenharmony_ci	spin_lock_irq(&chip->lock);
31762306a36Sopenharmony_ci	if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) {
31862306a36Sopenharmony_ci		vortex_adbdma_setmode(chip, dma, 1, dir, fmt,
31962306a36Sopenharmony_ci				runtime->channels == 1 ? 0 : 1, 0);
32062306a36Sopenharmony_ci		vortex_adbdma_setstartbuffer(chip, dma, 0);
32162306a36Sopenharmony_ci		if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_SPDIF)
32262306a36Sopenharmony_ci			vortex_adb_setsrc(chip, dma, runtime->rate, dir);
32362306a36Sopenharmony_ci	}
32462306a36Sopenharmony_ci#ifndef CHIP_AU8810
32562306a36Sopenharmony_ci	else {
32662306a36Sopenharmony_ci		vortex_wtdma_setmode(chip, dma, 1, fmt, 0, 0);
32762306a36Sopenharmony_ci		// FIXME: Set rate (i guess using vortex_wt_writereg() somehow).
32862306a36Sopenharmony_ci		vortex_wtdma_setstartbuffer(chip, dma, 0);
32962306a36Sopenharmony_ci	}
33062306a36Sopenharmony_ci#endif
33162306a36Sopenharmony_ci	spin_unlock_irq(&chip->lock);
33262306a36Sopenharmony_ci	return 0;
33362306a36Sopenharmony_ci}
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci/* trigger callback */
33662306a36Sopenharmony_cistatic int snd_vortex_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
33762306a36Sopenharmony_ci{
33862306a36Sopenharmony_ci	vortex_t *chip = snd_pcm_substream_chip(substream);
33962306a36Sopenharmony_ci	stream_t *stream = (stream_t *) substream->runtime->private_data;
34062306a36Sopenharmony_ci	int dma = stream->dma;
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci	spin_lock(&chip->lock);
34362306a36Sopenharmony_ci	switch (cmd) {
34462306a36Sopenharmony_ci	case SNDRV_PCM_TRIGGER_START:
34562306a36Sopenharmony_ci		// do something to start the PCM engine
34662306a36Sopenharmony_ci		//printk(KERN_INFO "vortex: start %d\n", dma);
34762306a36Sopenharmony_ci		stream->fifo_enabled = 1;
34862306a36Sopenharmony_ci		if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) {
34962306a36Sopenharmony_ci			vortex_adbdma_resetup(chip, dma);
35062306a36Sopenharmony_ci			vortex_adbdma_startfifo(chip, dma);
35162306a36Sopenharmony_ci		}
35262306a36Sopenharmony_ci#ifndef CHIP_AU8810
35362306a36Sopenharmony_ci		else {
35462306a36Sopenharmony_ci			dev_info(chip->card->dev, "wt start %d\n", dma);
35562306a36Sopenharmony_ci			vortex_wtdma_startfifo(chip, dma);
35662306a36Sopenharmony_ci		}
35762306a36Sopenharmony_ci#endif
35862306a36Sopenharmony_ci		break;
35962306a36Sopenharmony_ci	case SNDRV_PCM_TRIGGER_STOP:
36062306a36Sopenharmony_ci		// do something to stop the PCM engine
36162306a36Sopenharmony_ci		//printk(KERN_INFO "vortex: stop %d\n", dma);
36262306a36Sopenharmony_ci		stream->fifo_enabled = 0;
36362306a36Sopenharmony_ci		if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT)
36462306a36Sopenharmony_ci			vortex_adbdma_stopfifo(chip, dma);
36562306a36Sopenharmony_ci#ifndef CHIP_AU8810
36662306a36Sopenharmony_ci		else {
36762306a36Sopenharmony_ci			dev_info(chip->card->dev, "wt stop %d\n", dma);
36862306a36Sopenharmony_ci			vortex_wtdma_stopfifo(chip, dma);
36962306a36Sopenharmony_ci		}
37062306a36Sopenharmony_ci#endif
37162306a36Sopenharmony_ci		break;
37262306a36Sopenharmony_ci	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
37362306a36Sopenharmony_ci		//printk(KERN_INFO "vortex: pause %d\n", dma);
37462306a36Sopenharmony_ci		if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT)
37562306a36Sopenharmony_ci			vortex_adbdma_pausefifo(chip, dma);
37662306a36Sopenharmony_ci#ifndef CHIP_AU8810
37762306a36Sopenharmony_ci		else
37862306a36Sopenharmony_ci			vortex_wtdma_pausefifo(chip, dma);
37962306a36Sopenharmony_ci#endif
38062306a36Sopenharmony_ci		break;
38162306a36Sopenharmony_ci	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
38262306a36Sopenharmony_ci		//printk(KERN_INFO "vortex: resume %d\n", dma);
38362306a36Sopenharmony_ci		if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT)
38462306a36Sopenharmony_ci			vortex_adbdma_resumefifo(chip, dma);
38562306a36Sopenharmony_ci#ifndef CHIP_AU8810
38662306a36Sopenharmony_ci		else
38762306a36Sopenharmony_ci			vortex_wtdma_resumefifo(chip, dma);
38862306a36Sopenharmony_ci#endif
38962306a36Sopenharmony_ci		break;
39062306a36Sopenharmony_ci	default:
39162306a36Sopenharmony_ci		spin_unlock(&chip->lock);
39262306a36Sopenharmony_ci		return -EINVAL;
39362306a36Sopenharmony_ci	}
39462306a36Sopenharmony_ci	spin_unlock(&chip->lock);
39562306a36Sopenharmony_ci	return 0;
39662306a36Sopenharmony_ci}
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci/* pointer callback */
39962306a36Sopenharmony_cistatic snd_pcm_uframes_t snd_vortex_pcm_pointer(struct snd_pcm_substream *substream)
40062306a36Sopenharmony_ci{
40162306a36Sopenharmony_ci	vortex_t *chip = snd_pcm_substream_chip(substream);
40262306a36Sopenharmony_ci	stream_t *stream = (stream_t *) substream->runtime->private_data;
40362306a36Sopenharmony_ci	int dma = stream->dma;
40462306a36Sopenharmony_ci	snd_pcm_uframes_t current_ptr = 0;
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	spin_lock(&chip->lock);
40762306a36Sopenharmony_ci	if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT)
40862306a36Sopenharmony_ci		current_ptr = vortex_adbdma_getlinearpos(chip, dma);
40962306a36Sopenharmony_ci#ifndef CHIP_AU8810
41062306a36Sopenharmony_ci	else
41162306a36Sopenharmony_ci		current_ptr = vortex_wtdma_getlinearpos(chip, dma);
41262306a36Sopenharmony_ci#endif
41362306a36Sopenharmony_ci	//printk(KERN_INFO "vortex: pointer = 0x%x\n", current_ptr);
41462306a36Sopenharmony_ci	spin_unlock(&chip->lock);
41562306a36Sopenharmony_ci	current_ptr = bytes_to_frames(substream->runtime, current_ptr);
41662306a36Sopenharmony_ci	if (current_ptr >= substream->runtime->buffer_size)
41762306a36Sopenharmony_ci		current_ptr = 0;
41862306a36Sopenharmony_ci	return current_ptr;
41962306a36Sopenharmony_ci}
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci/* operators */
42262306a36Sopenharmony_cistatic const struct snd_pcm_ops snd_vortex_playback_ops = {
42362306a36Sopenharmony_ci	.open = snd_vortex_pcm_open,
42462306a36Sopenharmony_ci	.close = snd_vortex_pcm_close,
42562306a36Sopenharmony_ci	.hw_params = snd_vortex_pcm_hw_params,
42662306a36Sopenharmony_ci	.hw_free = snd_vortex_pcm_hw_free,
42762306a36Sopenharmony_ci	.prepare = snd_vortex_pcm_prepare,
42862306a36Sopenharmony_ci	.trigger = snd_vortex_pcm_trigger,
42962306a36Sopenharmony_ci	.pointer = snd_vortex_pcm_pointer,
43062306a36Sopenharmony_ci};
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci/*
43362306a36Sopenharmony_ci*  definitions of capture are omitted here...
43462306a36Sopenharmony_ci*/
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_cistatic const char * const vortex_pcm_prettyname[VORTEX_PCM_LAST] = {
43762306a36Sopenharmony_ci	CARD_NAME " ADB",
43862306a36Sopenharmony_ci	CARD_NAME " SPDIF",
43962306a36Sopenharmony_ci	CARD_NAME " A3D",
44062306a36Sopenharmony_ci	CARD_NAME " WT",
44162306a36Sopenharmony_ci	CARD_NAME " I2S",
44262306a36Sopenharmony_ci};
44362306a36Sopenharmony_cistatic const char * const vortex_pcm_name[VORTEX_PCM_LAST] = {
44462306a36Sopenharmony_ci	"adb",
44562306a36Sopenharmony_ci	"spdif",
44662306a36Sopenharmony_ci	"a3d",
44762306a36Sopenharmony_ci	"wt",
44862306a36Sopenharmony_ci	"i2s",
44962306a36Sopenharmony_ci};
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci/* SPDIF kcontrol */
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_cistatic int snd_vortex_spdif_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
45462306a36Sopenharmony_ci{
45562306a36Sopenharmony_ci	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
45662306a36Sopenharmony_ci	uinfo->count = 1;
45762306a36Sopenharmony_ci	return 0;
45862306a36Sopenharmony_ci}
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_cistatic int snd_vortex_spdif_mask_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
46162306a36Sopenharmony_ci{
46262306a36Sopenharmony_ci	ucontrol->value.iec958.status[0] = 0xff;
46362306a36Sopenharmony_ci	ucontrol->value.iec958.status[1] = 0xff;
46462306a36Sopenharmony_ci	ucontrol->value.iec958.status[2] = 0xff;
46562306a36Sopenharmony_ci	ucontrol->value.iec958.status[3] = IEC958_AES3_CON_FS;
46662306a36Sopenharmony_ci	return 0;
46762306a36Sopenharmony_ci}
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_cistatic int snd_vortex_spdif_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
47062306a36Sopenharmony_ci{
47162306a36Sopenharmony_ci	vortex_t *vortex = snd_kcontrol_chip(kcontrol);
47262306a36Sopenharmony_ci	ucontrol->value.iec958.status[0] = 0x00;
47362306a36Sopenharmony_ci	ucontrol->value.iec958.status[1] = IEC958_AES1_CON_ORIGINAL|IEC958_AES1_CON_DIGDIGCONV_ID;
47462306a36Sopenharmony_ci	ucontrol->value.iec958.status[2] = 0x00;
47562306a36Sopenharmony_ci	switch (vortex->spdif_sr) {
47662306a36Sopenharmony_ci	case 32000: ucontrol->value.iec958.status[3] = IEC958_AES3_CON_FS_32000; break;
47762306a36Sopenharmony_ci	case 44100: ucontrol->value.iec958.status[3] = IEC958_AES3_CON_FS_44100; break;
47862306a36Sopenharmony_ci	case 48000: ucontrol->value.iec958.status[3] = IEC958_AES3_CON_FS_48000; break;
47962306a36Sopenharmony_ci	}
48062306a36Sopenharmony_ci	return 0;
48162306a36Sopenharmony_ci}
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_cistatic int snd_vortex_spdif_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
48462306a36Sopenharmony_ci{
48562306a36Sopenharmony_ci	vortex_t *vortex = snd_kcontrol_chip(kcontrol);
48662306a36Sopenharmony_ci	int spdif_sr = 48000;
48762306a36Sopenharmony_ci	switch (ucontrol->value.iec958.status[3] & IEC958_AES3_CON_FS) {
48862306a36Sopenharmony_ci	case IEC958_AES3_CON_FS_32000: spdif_sr = 32000; break;
48962306a36Sopenharmony_ci	case IEC958_AES3_CON_FS_44100: spdif_sr = 44100; break;
49062306a36Sopenharmony_ci	case IEC958_AES3_CON_FS_48000: spdif_sr = 48000; break;
49162306a36Sopenharmony_ci	}
49262306a36Sopenharmony_ci	if (spdif_sr == vortex->spdif_sr)
49362306a36Sopenharmony_ci		return 0;
49462306a36Sopenharmony_ci	vortex->spdif_sr = spdif_sr;
49562306a36Sopenharmony_ci	vortex_spdif_init(vortex, vortex->spdif_sr, 1);
49662306a36Sopenharmony_ci	return 1;
49762306a36Sopenharmony_ci}
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci/* spdif controls */
50062306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_vortex_mixer_spdif[] = {
50162306a36Sopenharmony_ci	{
50262306a36Sopenharmony_ci		.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
50362306a36Sopenharmony_ci		.name =		SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
50462306a36Sopenharmony_ci		.info =		snd_vortex_spdif_info,
50562306a36Sopenharmony_ci		.get =		snd_vortex_spdif_get,
50662306a36Sopenharmony_ci		.put =		snd_vortex_spdif_put,
50762306a36Sopenharmony_ci	},
50862306a36Sopenharmony_ci	{
50962306a36Sopenharmony_ci		.access =	SNDRV_CTL_ELEM_ACCESS_READ,
51062306a36Sopenharmony_ci		.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
51162306a36Sopenharmony_ci		.name =		SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK),
51262306a36Sopenharmony_ci		.info =		snd_vortex_spdif_info,
51362306a36Sopenharmony_ci		.get =		snd_vortex_spdif_mask_get
51462306a36Sopenharmony_ci	},
51562306a36Sopenharmony_ci};
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci/* subdevice PCM Volume control */
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_cistatic int snd_vortex_pcm_vol_info(struct snd_kcontrol *kcontrol,
52062306a36Sopenharmony_ci				struct snd_ctl_elem_info *uinfo)
52162306a36Sopenharmony_ci{
52262306a36Sopenharmony_ci	vortex_t *vortex = snd_kcontrol_chip(kcontrol);
52362306a36Sopenharmony_ci	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
52462306a36Sopenharmony_ci	uinfo->count = (VORTEX_IS_QUAD(vortex) ? 4 : 2);
52562306a36Sopenharmony_ci	uinfo->value.integer.min = -128;
52662306a36Sopenharmony_ci	uinfo->value.integer.max = 32;
52762306a36Sopenharmony_ci	return 0;
52862306a36Sopenharmony_ci}
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_cistatic int snd_vortex_pcm_vol_get(struct snd_kcontrol *kcontrol,
53162306a36Sopenharmony_ci				struct snd_ctl_elem_value *ucontrol)
53262306a36Sopenharmony_ci{
53362306a36Sopenharmony_ci	int i;
53462306a36Sopenharmony_ci	vortex_t *vortex = snd_kcontrol_chip(kcontrol);
53562306a36Sopenharmony_ci	int subdev = kcontrol->id.subdevice;
53662306a36Sopenharmony_ci	struct pcm_vol *p = &vortex->pcm_vol[subdev];
53762306a36Sopenharmony_ci	int max_chn = (VORTEX_IS_QUAD(vortex) ? 4 : 2);
53862306a36Sopenharmony_ci	for (i = 0; i < max_chn; i++)
53962306a36Sopenharmony_ci		ucontrol->value.integer.value[i] = p->vol[i];
54062306a36Sopenharmony_ci	return 0;
54162306a36Sopenharmony_ci}
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_cistatic int snd_vortex_pcm_vol_put(struct snd_kcontrol *kcontrol,
54462306a36Sopenharmony_ci				struct snd_ctl_elem_value *ucontrol)
54562306a36Sopenharmony_ci{
54662306a36Sopenharmony_ci	int i;
54762306a36Sopenharmony_ci	int changed = 0;
54862306a36Sopenharmony_ci	int mixin;
54962306a36Sopenharmony_ci	unsigned char vol;
55062306a36Sopenharmony_ci	vortex_t *vortex = snd_kcontrol_chip(kcontrol);
55162306a36Sopenharmony_ci	int subdev = kcontrol->id.subdevice;
55262306a36Sopenharmony_ci	struct pcm_vol *p = &vortex->pcm_vol[subdev];
55362306a36Sopenharmony_ci	int max_chn = (VORTEX_IS_QUAD(vortex) ? 4 : 2);
55462306a36Sopenharmony_ci	for (i = 0; i < max_chn; i++) {
55562306a36Sopenharmony_ci		if (p->vol[i] != ucontrol->value.integer.value[i]) {
55662306a36Sopenharmony_ci			p->vol[i] = ucontrol->value.integer.value[i];
55762306a36Sopenharmony_ci			if (p->active) {
55862306a36Sopenharmony_ci				switch (vortex->dma_adb[p->dma].nr_ch) {
55962306a36Sopenharmony_ci				case 1:
56062306a36Sopenharmony_ci					mixin = p->mixin[0];
56162306a36Sopenharmony_ci					break;
56262306a36Sopenharmony_ci				case 2:
56362306a36Sopenharmony_ci				default:
56462306a36Sopenharmony_ci					mixin = p->mixin[(i < 2) ? i : (i - 2)];
56562306a36Sopenharmony_ci					break;
56662306a36Sopenharmony_ci				case 4:
56762306a36Sopenharmony_ci					mixin = p->mixin[i];
56862306a36Sopenharmony_ci					break;
56962306a36Sopenharmony_ci				}
57062306a36Sopenharmony_ci				vol = p->vol[i];
57162306a36Sopenharmony_ci				vortex_mix_setinputvolumebyte(vortex,
57262306a36Sopenharmony_ci					vortex->mixplayb[i], mixin, vol);
57362306a36Sopenharmony_ci			}
57462306a36Sopenharmony_ci			changed = 1;
57562306a36Sopenharmony_ci		}
57662306a36Sopenharmony_ci	}
57762306a36Sopenharmony_ci	return changed;
57862306a36Sopenharmony_ci}
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_cistatic const DECLARE_TLV_DB_MINMAX(vortex_pcm_vol_db_scale, -9600, 2400);
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_vortex_pcm_vol = {
58362306a36Sopenharmony_ci	.iface = SNDRV_CTL_ELEM_IFACE_PCM,
58462306a36Sopenharmony_ci	.name = "PCM Playback Volume",
58562306a36Sopenharmony_ci	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
58662306a36Sopenharmony_ci		SNDRV_CTL_ELEM_ACCESS_TLV_READ |
58762306a36Sopenharmony_ci		SNDRV_CTL_ELEM_ACCESS_INACTIVE,
58862306a36Sopenharmony_ci	.info = snd_vortex_pcm_vol_info,
58962306a36Sopenharmony_ci	.get = snd_vortex_pcm_vol_get,
59062306a36Sopenharmony_ci	.put = snd_vortex_pcm_vol_put,
59162306a36Sopenharmony_ci	.tlv = { .p = vortex_pcm_vol_db_scale },
59262306a36Sopenharmony_ci};
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci/* create a pcm device */
59562306a36Sopenharmony_cistatic int snd_vortex_new_pcm(vortex_t *chip, int idx, int nr)
59662306a36Sopenharmony_ci{
59762306a36Sopenharmony_ci	struct snd_pcm *pcm;
59862306a36Sopenharmony_ci	struct snd_kcontrol *kctl;
59962306a36Sopenharmony_ci	int i;
60062306a36Sopenharmony_ci	int err, nr_capt;
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci	if (!chip || idx < 0 || idx >= VORTEX_PCM_LAST)
60362306a36Sopenharmony_ci		return -ENODEV;
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci	/* idx indicates which kind of PCM device. ADB, SPDIF, I2S and A3D share the
60662306a36Sopenharmony_ci	 * same dma engine. WT uses it own separate dma engine which can't capture. */
60762306a36Sopenharmony_ci	if (idx == VORTEX_PCM_ADB)
60862306a36Sopenharmony_ci		nr_capt = nr;
60962306a36Sopenharmony_ci	else
61062306a36Sopenharmony_ci		nr_capt = 0;
61162306a36Sopenharmony_ci	err = snd_pcm_new(chip->card, vortex_pcm_prettyname[idx], idx, nr,
61262306a36Sopenharmony_ci			  nr_capt, &pcm);
61362306a36Sopenharmony_ci	if (err < 0)
61462306a36Sopenharmony_ci		return err;
61562306a36Sopenharmony_ci	snprintf(pcm->name, sizeof(pcm->name),
61662306a36Sopenharmony_ci		"%s %s", CARD_NAME_SHORT, vortex_pcm_name[idx]);
61762306a36Sopenharmony_ci	chip->pcm[idx] = pcm;
61862306a36Sopenharmony_ci	// This is an evil hack, but it saves a lot of duplicated code.
61962306a36Sopenharmony_ci	VORTEX_PCM_TYPE(pcm) = idx;
62062306a36Sopenharmony_ci	pcm->private_data = chip;
62162306a36Sopenharmony_ci	/* set operators */
62262306a36Sopenharmony_ci	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
62362306a36Sopenharmony_ci			&snd_vortex_playback_ops);
62462306a36Sopenharmony_ci	if (idx == VORTEX_PCM_ADB)
62562306a36Sopenharmony_ci		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
62662306a36Sopenharmony_ci				&snd_vortex_playback_ops);
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci	/* pre-allocation of Scatter-Gather buffers */
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci	snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
63162306a36Sopenharmony_ci				       &chip->pci_dev->dev, 0x10000, 0x10000);
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_ci	switch (VORTEX_PCM_TYPE(pcm)) {
63462306a36Sopenharmony_ci	case VORTEX_PCM_ADB:
63562306a36Sopenharmony_ci		err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
63662306a36Sopenharmony_ci					     snd_pcm_std_chmaps,
63762306a36Sopenharmony_ci					     VORTEX_IS_QUAD(chip) ? 4 : 2,
63862306a36Sopenharmony_ci					     0, NULL);
63962306a36Sopenharmony_ci		if (err < 0)
64062306a36Sopenharmony_ci			return err;
64162306a36Sopenharmony_ci		err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_CAPTURE,
64262306a36Sopenharmony_ci					     snd_pcm_std_chmaps, 2, 0, NULL);
64362306a36Sopenharmony_ci		if (err < 0)
64462306a36Sopenharmony_ci			return err;
64562306a36Sopenharmony_ci		break;
64662306a36Sopenharmony_ci#ifdef CHIP_AU8830
64762306a36Sopenharmony_ci	case VORTEX_PCM_A3D:
64862306a36Sopenharmony_ci		err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
64962306a36Sopenharmony_ci					     snd_pcm_std_chmaps, 1, 0, NULL);
65062306a36Sopenharmony_ci		if (err < 0)
65162306a36Sopenharmony_ci			return err;
65262306a36Sopenharmony_ci		break;
65362306a36Sopenharmony_ci#endif
65462306a36Sopenharmony_ci	}
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_ci	if (VORTEX_PCM_TYPE(pcm) == VORTEX_PCM_SPDIF) {
65762306a36Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(snd_vortex_mixer_spdif); i++) {
65862306a36Sopenharmony_ci			kctl = snd_ctl_new1(&snd_vortex_mixer_spdif[i], chip);
65962306a36Sopenharmony_ci			if (!kctl)
66062306a36Sopenharmony_ci				return -ENOMEM;
66162306a36Sopenharmony_ci			err = snd_ctl_add(chip->card, kctl);
66262306a36Sopenharmony_ci			if (err < 0)
66362306a36Sopenharmony_ci				return err;
66462306a36Sopenharmony_ci		}
66562306a36Sopenharmony_ci	}
66662306a36Sopenharmony_ci	if (VORTEX_PCM_TYPE(pcm) == VORTEX_PCM_ADB) {
66762306a36Sopenharmony_ci		for (i = 0; i < NR_PCM; i++) {
66862306a36Sopenharmony_ci			chip->pcm_vol[i].active = 0;
66962306a36Sopenharmony_ci			chip->pcm_vol[i].dma = -1;
67062306a36Sopenharmony_ci			kctl = snd_ctl_new1(&snd_vortex_pcm_vol, chip);
67162306a36Sopenharmony_ci			if (!kctl)
67262306a36Sopenharmony_ci				return -ENOMEM;
67362306a36Sopenharmony_ci			chip->pcm_vol[i].kctl = kctl;
67462306a36Sopenharmony_ci			kctl->id.device = 0;
67562306a36Sopenharmony_ci			kctl->id.subdevice = i;
67662306a36Sopenharmony_ci			err = snd_ctl_add(chip->card, kctl);
67762306a36Sopenharmony_ci			if (err < 0)
67862306a36Sopenharmony_ci				return err;
67962306a36Sopenharmony_ci		}
68062306a36Sopenharmony_ci	}
68162306a36Sopenharmony_ci	return 0;
68262306a36Sopenharmony_ci}
683