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