162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * @File ctatc.c 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * @Brief 862306a36Sopenharmony_ci * This file contains the implementation of the device resource management 962306a36Sopenharmony_ci * object. 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * @Author Liu Chun 1262306a36Sopenharmony_ci * @Date Mar 28 2008 1362306a36Sopenharmony_ci */ 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include "ctatc.h" 1662306a36Sopenharmony_ci#include "ctpcm.h" 1762306a36Sopenharmony_ci#include "ctmixer.h" 1862306a36Sopenharmony_ci#include "ctsrc.h" 1962306a36Sopenharmony_ci#include "ctamixer.h" 2062306a36Sopenharmony_ci#include "ctdaio.h" 2162306a36Sopenharmony_ci#include "cttimer.h" 2262306a36Sopenharmony_ci#include <linux/delay.h> 2362306a36Sopenharmony_ci#include <linux/slab.h> 2462306a36Sopenharmony_ci#include <sound/pcm.h> 2562306a36Sopenharmony_ci#include <sound/control.h> 2662306a36Sopenharmony_ci#include <sound/asoundef.h> 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci#define MONO_SUM_SCALE 0x19a8 /* 2^(-0.5) in 14-bit floating format */ 2962306a36Sopenharmony_ci#define MAX_MULTI_CHN 8 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#define IEC958_DEFAULT_CON ((IEC958_AES0_NONAUDIO \ 3262306a36Sopenharmony_ci | IEC958_AES0_CON_NOT_COPYRIGHT) \ 3362306a36Sopenharmony_ci | ((IEC958_AES1_CON_MIXER \ 3462306a36Sopenharmony_ci | IEC958_AES1_CON_ORIGINAL) << 8) \ 3562306a36Sopenharmony_ci | (0x10 << 16) \ 3662306a36Sopenharmony_ci | ((IEC958_AES3_CON_FS_48000) << 24)) 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_cistatic const struct snd_pci_quirk subsys_20k1_list[] = { 3962306a36Sopenharmony_ci SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, 0x0021, "SB046x", CTSB046X), 4062306a36Sopenharmony_ci SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, 0x0022, "SB055x", CTSB055X), 4162306a36Sopenharmony_ci SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, 0x002f, "SB055x", CTSB055X), 4262306a36Sopenharmony_ci SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, 0x0029, "SB073x", CTSB073X), 4362306a36Sopenharmony_ci SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, 0x0031, "SB073x", CTSB073X), 4462306a36Sopenharmony_ci SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_CREATIVE, 0xf000, 0x6000, 4562306a36Sopenharmony_ci "UAA", CTUAA), 4662306a36Sopenharmony_ci { } /* terminator */ 4762306a36Sopenharmony_ci}; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_cistatic const struct snd_pci_quirk subsys_20k2_list[] = { 5062306a36Sopenharmony_ci SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB0760, 5162306a36Sopenharmony_ci "SB0760", CTSB0760), 5262306a36Sopenharmony_ci SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB1270, 5362306a36Sopenharmony_ci "SB1270", CTSB1270), 5462306a36Sopenharmony_ci SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB08801, 5562306a36Sopenharmony_ci "SB0880", CTSB0880), 5662306a36Sopenharmony_ci SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB08802, 5762306a36Sopenharmony_ci "SB0880", CTSB0880), 5862306a36Sopenharmony_ci SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB08803, 5962306a36Sopenharmony_ci "SB0880", CTSB0880), 6062306a36Sopenharmony_ci SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_CREATIVE, 0xf000, 6162306a36Sopenharmony_ci PCI_SUBDEVICE_ID_CREATIVE_HENDRIX, "HENDRIX", 6262306a36Sopenharmony_ci CTHENDRIX), 6362306a36Sopenharmony_ci { } /* terminator */ 6462306a36Sopenharmony_ci}; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_cistatic const char *ct_subsys_name[NUM_CTCARDS] = { 6762306a36Sopenharmony_ci /* 20k1 models */ 6862306a36Sopenharmony_ci [CTSB046X] = "SB046x", 6962306a36Sopenharmony_ci [CTSB055X] = "SB055x", 7062306a36Sopenharmony_ci [CTSB073X] = "SB073x", 7162306a36Sopenharmony_ci [CTUAA] = "UAA", 7262306a36Sopenharmony_ci [CT20K1_UNKNOWN] = "Unknown", 7362306a36Sopenharmony_ci /* 20k2 models */ 7462306a36Sopenharmony_ci [CTSB0760] = "SB076x", 7562306a36Sopenharmony_ci [CTHENDRIX] = "Hendrix", 7662306a36Sopenharmony_ci [CTSB0880] = "SB0880", 7762306a36Sopenharmony_ci [CTSB1270] = "SB1270", 7862306a36Sopenharmony_ci [CT20K2_UNKNOWN] = "Unknown", 7962306a36Sopenharmony_ci}; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_cistatic struct { 8262306a36Sopenharmony_ci int (*create)(struct ct_atc *atc, 8362306a36Sopenharmony_ci enum CTALSADEVS device, const char *device_name); 8462306a36Sopenharmony_ci int (*destroy)(void *alsa_dev); 8562306a36Sopenharmony_ci const char *public_name; 8662306a36Sopenharmony_ci} alsa_dev_funcs[NUM_CTALSADEVS] = { 8762306a36Sopenharmony_ci [FRONT] = { .create = ct_alsa_pcm_create, 8862306a36Sopenharmony_ci .destroy = NULL, 8962306a36Sopenharmony_ci .public_name = "Front/WaveIn"}, 9062306a36Sopenharmony_ci [SURROUND] = { .create = ct_alsa_pcm_create, 9162306a36Sopenharmony_ci .destroy = NULL, 9262306a36Sopenharmony_ci .public_name = "Surround"}, 9362306a36Sopenharmony_ci [CLFE] = { .create = ct_alsa_pcm_create, 9462306a36Sopenharmony_ci .destroy = NULL, 9562306a36Sopenharmony_ci .public_name = "Center/LFE"}, 9662306a36Sopenharmony_ci [SIDE] = { .create = ct_alsa_pcm_create, 9762306a36Sopenharmony_ci .destroy = NULL, 9862306a36Sopenharmony_ci .public_name = "Side"}, 9962306a36Sopenharmony_ci [IEC958] = { .create = ct_alsa_pcm_create, 10062306a36Sopenharmony_ci .destroy = NULL, 10162306a36Sopenharmony_ci .public_name = "IEC958 Non-audio"}, 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci [MIXER] = { .create = ct_alsa_mix_create, 10462306a36Sopenharmony_ci .destroy = NULL, 10562306a36Sopenharmony_ci .public_name = "Mixer"} 10662306a36Sopenharmony_ci}; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_citypedef int (*create_t)(struct hw *, void **); 10962306a36Sopenharmony_citypedef int (*destroy_t)(void *); 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_cistatic struct { 11262306a36Sopenharmony_ci int (*create)(struct hw *hw, void **rmgr); 11362306a36Sopenharmony_ci int (*destroy)(void *mgr); 11462306a36Sopenharmony_ci} rsc_mgr_funcs[NUM_RSCTYP] = { 11562306a36Sopenharmony_ci [SRC] = { .create = (create_t)src_mgr_create, 11662306a36Sopenharmony_ci .destroy = (destroy_t)src_mgr_destroy }, 11762306a36Sopenharmony_ci [SRCIMP] = { .create = (create_t)srcimp_mgr_create, 11862306a36Sopenharmony_ci .destroy = (destroy_t)srcimp_mgr_destroy }, 11962306a36Sopenharmony_ci [AMIXER] = { .create = (create_t)amixer_mgr_create, 12062306a36Sopenharmony_ci .destroy = (destroy_t)amixer_mgr_destroy }, 12162306a36Sopenharmony_ci [SUM] = { .create = (create_t)sum_mgr_create, 12262306a36Sopenharmony_ci .destroy = (destroy_t)sum_mgr_destroy }, 12362306a36Sopenharmony_ci [DAIO] = { .create = (create_t)daio_mgr_create, 12462306a36Sopenharmony_ci .destroy = (destroy_t)daio_mgr_destroy } 12562306a36Sopenharmony_ci}; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_cistatic int 12862306a36Sopenharmony_ciatc_pcm_release_resources(struct ct_atc *atc, struct ct_atc_pcm *apcm); 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci/* * 13162306a36Sopenharmony_ci * Only mono and interleaved modes are supported now. 13262306a36Sopenharmony_ci * Always allocates a contiguous channel block. 13362306a36Sopenharmony_ci * */ 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_cistatic int ct_map_audio_buffer(struct ct_atc *atc, struct ct_atc_pcm *apcm) 13662306a36Sopenharmony_ci{ 13762306a36Sopenharmony_ci struct snd_pcm_runtime *runtime; 13862306a36Sopenharmony_ci struct ct_vm *vm; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci if (!apcm->substream) 14162306a36Sopenharmony_ci return 0; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci runtime = apcm->substream->runtime; 14462306a36Sopenharmony_ci vm = atc->vm; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci apcm->vm_block = vm->map(vm, apcm->substream, runtime->dma_bytes); 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci if (!apcm->vm_block) 14962306a36Sopenharmony_ci return -ENOENT; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci return 0; 15262306a36Sopenharmony_ci} 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_cistatic void ct_unmap_audio_buffer(struct ct_atc *atc, struct ct_atc_pcm *apcm) 15562306a36Sopenharmony_ci{ 15662306a36Sopenharmony_ci struct ct_vm *vm; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci if (!apcm->vm_block) 15962306a36Sopenharmony_ci return; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci vm = atc->vm; 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci vm->unmap(vm, apcm->vm_block); 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci apcm->vm_block = NULL; 16662306a36Sopenharmony_ci} 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_cistatic unsigned long atc_get_ptp_phys(struct ct_atc *atc, int index) 16962306a36Sopenharmony_ci{ 17062306a36Sopenharmony_ci return atc->vm->get_ptp_phys(atc->vm, index); 17162306a36Sopenharmony_ci} 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_cistatic unsigned int convert_format(snd_pcm_format_t snd_format, 17462306a36Sopenharmony_ci struct snd_card *card) 17562306a36Sopenharmony_ci{ 17662306a36Sopenharmony_ci switch (snd_format) { 17762306a36Sopenharmony_ci case SNDRV_PCM_FORMAT_U8: 17862306a36Sopenharmony_ci return SRC_SF_U8; 17962306a36Sopenharmony_ci case SNDRV_PCM_FORMAT_S16_LE: 18062306a36Sopenharmony_ci return SRC_SF_S16; 18162306a36Sopenharmony_ci case SNDRV_PCM_FORMAT_S24_3LE: 18262306a36Sopenharmony_ci return SRC_SF_S24; 18362306a36Sopenharmony_ci case SNDRV_PCM_FORMAT_S32_LE: 18462306a36Sopenharmony_ci return SRC_SF_S32; 18562306a36Sopenharmony_ci case SNDRV_PCM_FORMAT_FLOAT_LE: 18662306a36Sopenharmony_ci return SRC_SF_F32; 18762306a36Sopenharmony_ci default: 18862306a36Sopenharmony_ci dev_err(card->dev, "not recognized snd format is %d\n", 18962306a36Sopenharmony_ci snd_format); 19062306a36Sopenharmony_ci return SRC_SF_S16; 19162306a36Sopenharmony_ci } 19262306a36Sopenharmony_ci} 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_cistatic unsigned int 19562306a36Sopenharmony_ciatc_get_pitch(unsigned int input_rate, unsigned int output_rate) 19662306a36Sopenharmony_ci{ 19762306a36Sopenharmony_ci unsigned int pitch; 19862306a36Sopenharmony_ci int b; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci /* get pitch and convert to fixed-point 8.24 format. */ 20162306a36Sopenharmony_ci pitch = (input_rate / output_rate) << 24; 20262306a36Sopenharmony_ci input_rate %= output_rate; 20362306a36Sopenharmony_ci input_rate /= 100; 20462306a36Sopenharmony_ci output_rate /= 100; 20562306a36Sopenharmony_ci for (b = 31; ((b >= 0) && !(input_rate >> b)); ) 20662306a36Sopenharmony_ci b--; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci if (b >= 0) { 20962306a36Sopenharmony_ci input_rate <<= (31 - b); 21062306a36Sopenharmony_ci input_rate /= output_rate; 21162306a36Sopenharmony_ci b = 24 - (31 - b); 21262306a36Sopenharmony_ci if (b >= 0) 21362306a36Sopenharmony_ci input_rate <<= b; 21462306a36Sopenharmony_ci else 21562306a36Sopenharmony_ci input_rate >>= -b; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci pitch |= input_rate; 21862306a36Sopenharmony_ci } 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci return pitch; 22162306a36Sopenharmony_ci} 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_cistatic int select_rom(unsigned int pitch) 22462306a36Sopenharmony_ci{ 22562306a36Sopenharmony_ci if (pitch > 0x00428f5c && pitch < 0x01b851ec) { 22662306a36Sopenharmony_ci /* 0.26 <= pitch <= 1.72 */ 22762306a36Sopenharmony_ci return 1; 22862306a36Sopenharmony_ci } else if (pitch == 0x01d66666 || pitch == 0x01d66667) { 22962306a36Sopenharmony_ci /* pitch == 1.8375 */ 23062306a36Sopenharmony_ci return 2; 23162306a36Sopenharmony_ci } else if (pitch == 0x02000000) { 23262306a36Sopenharmony_ci /* pitch == 2 */ 23362306a36Sopenharmony_ci return 3; 23462306a36Sopenharmony_ci } else if (pitch <= 0x08000000) { 23562306a36Sopenharmony_ci /* 0 <= pitch <= 8 */ 23662306a36Sopenharmony_ci return 0; 23762306a36Sopenharmony_ci } else { 23862306a36Sopenharmony_ci return -ENOENT; 23962306a36Sopenharmony_ci } 24062306a36Sopenharmony_ci} 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_cistatic int atc_pcm_playback_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm) 24362306a36Sopenharmony_ci{ 24462306a36Sopenharmony_ci struct src_mgr *src_mgr = atc->rsc_mgrs[SRC]; 24562306a36Sopenharmony_ci struct amixer_mgr *amixer_mgr = atc->rsc_mgrs[AMIXER]; 24662306a36Sopenharmony_ci struct src_desc desc = {0}; 24762306a36Sopenharmony_ci struct amixer_desc mix_dsc = {0}; 24862306a36Sopenharmony_ci struct src *src; 24962306a36Sopenharmony_ci struct amixer *amixer; 25062306a36Sopenharmony_ci int err; 25162306a36Sopenharmony_ci int n_amixer = apcm->substream->runtime->channels, i = 0; 25262306a36Sopenharmony_ci int device = apcm->substream->pcm->device; 25362306a36Sopenharmony_ci unsigned int pitch; 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci /* first release old resources */ 25662306a36Sopenharmony_ci atc_pcm_release_resources(atc, apcm); 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci /* Get SRC resource */ 25962306a36Sopenharmony_ci desc.multi = apcm->substream->runtime->channels; 26062306a36Sopenharmony_ci desc.msr = atc->msr; 26162306a36Sopenharmony_ci desc.mode = MEMRD; 26262306a36Sopenharmony_ci err = src_mgr->get_src(src_mgr, &desc, (struct src **)&apcm->src); 26362306a36Sopenharmony_ci if (err) 26462306a36Sopenharmony_ci goto error1; 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci pitch = atc_get_pitch(apcm->substream->runtime->rate, 26762306a36Sopenharmony_ci (atc->rsr * atc->msr)); 26862306a36Sopenharmony_ci src = apcm->src; 26962306a36Sopenharmony_ci src->ops->set_pitch(src, pitch); 27062306a36Sopenharmony_ci src->ops->set_rom(src, select_rom(pitch)); 27162306a36Sopenharmony_ci src->ops->set_sf(src, convert_format(apcm->substream->runtime->format, 27262306a36Sopenharmony_ci atc->card)); 27362306a36Sopenharmony_ci src->ops->set_pm(src, (src->ops->next_interleave(src) != NULL)); 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci /* Get AMIXER resource */ 27662306a36Sopenharmony_ci n_amixer = (n_amixer < 2) ? 2 : n_amixer; 27762306a36Sopenharmony_ci apcm->amixers = kcalloc(n_amixer, sizeof(void *), GFP_KERNEL); 27862306a36Sopenharmony_ci if (!apcm->amixers) { 27962306a36Sopenharmony_ci err = -ENOMEM; 28062306a36Sopenharmony_ci goto error1; 28162306a36Sopenharmony_ci } 28262306a36Sopenharmony_ci mix_dsc.msr = atc->msr; 28362306a36Sopenharmony_ci for (i = 0, apcm->n_amixer = 0; i < n_amixer; i++) { 28462306a36Sopenharmony_ci err = amixer_mgr->get_amixer(amixer_mgr, &mix_dsc, 28562306a36Sopenharmony_ci (struct amixer **)&apcm->amixers[i]); 28662306a36Sopenharmony_ci if (err) 28762306a36Sopenharmony_ci goto error1; 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci apcm->n_amixer++; 29062306a36Sopenharmony_ci } 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci /* Set up device virtual mem map */ 29362306a36Sopenharmony_ci err = ct_map_audio_buffer(atc, apcm); 29462306a36Sopenharmony_ci if (err < 0) 29562306a36Sopenharmony_ci goto error1; 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci /* Connect resources */ 29862306a36Sopenharmony_ci src = apcm->src; 29962306a36Sopenharmony_ci for (i = 0; i < n_amixer; i++) { 30062306a36Sopenharmony_ci amixer = apcm->amixers[i]; 30162306a36Sopenharmony_ci mutex_lock(&atc->atc_mutex); 30262306a36Sopenharmony_ci amixer->ops->setup(amixer, &src->rsc, 30362306a36Sopenharmony_ci INIT_VOL, atc->pcm[i+device*2]); 30462306a36Sopenharmony_ci mutex_unlock(&atc->atc_mutex); 30562306a36Sopenharmony_ci src = src->ops->next_interleave(src); 30662306a36Sopenharmony_ci if (!src) 30762306a36Sopenharmony_ci src = apcm->src; 30862306a36Sopenharmony_ci } 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci ct_timer_prepare(apcm->timer); 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci return 0; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_cierror1: 31562306a36Sopenharmony_ci atc_pcm_release_resources(atc, apcm); 31662306a36Sopenharmony_ci return err; 31762306a36Sopenharmony_ci} 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_cistatic int 32062306a36Sopenharmony_ciatc_pcm_release_resources(struct ct_atc *atc, struct ct_atc_pcm *apcm) 32162306a36Sopenharmony_ci{ 32262306a36Sopenharmony_ci struct src_mgr *src_mgr = atc->rsc_mgrs[SRC]; 32362306a36Sopenharmony_ci struct srcimp_mgr *srcimp_mgr = atc->rsc_mgrs[SRCIMP]; 32462306a36Sopenharmony_ci struct amixer_mgr *amixer_mgr = atc->rsc_mgrs[AMIXER]; 32562306a36Sopenharmony_ci struct sum_mgr *sum_mgr = atc->rsc_mgrs[SUM]; 32662306a36Sopenharmony_ci struct srcimp *srcimp; 32762306a36Sopenharmony_ci int i; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci if (apcm->srcimps) { 33062306a36Sopenharmony_ci for (i = 0; i < apcm->n_srcimp; i++) { 33162306a36Sopenharmony_ci srcimp = apcm->srcimps[i]; 33262306a36Sopenharmony_ci srcimp->ops->unmap(srcimp); 33362306a36Sopenharmony_ci srcimp_mgr->put_srcimp(srcimp_mgr, srcimp); 33462306a36Sopenharmony_ci apcm->srcimps[i] = NULL; 33562306a36Sopenharmony_ci } 33662306a36Sopenharmony_ci kfree(apcm->srcimps); 33762306a36Sopenharmony_ci apcm->srcimps = NULL; 33862306a36Sopenharmony_ci } 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci if (apcm->srccs) { 34162306a36Sopenharmony_ci for (i = 0; i < apcm->n_srcc; i++) { 34262306a36Sopenharmony_ci src_mgr->put_src(src_mgr, apcm->srccs[i]); 34362306a36Sopenharmony_ci apcm->srccs[i] = NULL; 34462306a36Sopenharmony_ci } 34562306a36Sopenharmony_ci kfree(apcm->srccs); 34662306a36Sopenharmony_ci apcm->srccs = NULL; 34762306a36Sopenharmony_ci } 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci if (apcm->amixers) { 35062306a36Sopenharmony_ci for (i = 0; i < apcm->n_amixer; i++) { 35162306a36Sopenharmony_ci amixer_mgr->put_amixer(amixer_mgr, apcm->amixers[i]); 35262306a36Sopenharmony_ci apcm->amixers[i] = NULL; 35362306a36Sopenharmony_ci } 35462306a36Sopenharmony_ci kfree(apcm->amixers); 35562306a36Sopenharmony_ci apcm->amixers = NULL; 35662306a36Sopenharmony_ci } 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci if (apcm->mono) { 35962306a36Sopenharmony_ci sum_mgr->put_sum(sum_mgr, apcm->mono); 36062306a36Sopenharmony_ci apcm->mono = NULL; 36162306a36Sopenharmony_ci } 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci if (apcm->src) { 36462306a36Sopenharmony_ci src_mgr->put_src(src_mgr, apcm->src); 36562306a36Sopenharmony_ci apcm->src = NULL; 36662306a36Sopenharmony_ci } 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci if (apcm->vm_block) { 36962306a36Sopenharmony_ci /* Undo device virtual mem map */ 37062306a36Sopenharmony_ci ct_unmap_audio_buffer(atc, apcm); 37162306a36Sopenharmony_ci apcm->vm_block = NULL; 37262306a36Sopenharmony_ci } 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci return 0; 37562306a36Sopenharmony_ci} 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_cistatic int atc_pcm_playback_start(struct ct_atc *atc, struct ct_atc_pcm *apcm) 37862306a36Sopenharmony_ci{ 37962306a36Sopenharmony_ci unsigned int max_cisz; 38062306a36Sopenharmony_ci struct src *src = apcm->src; 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci if (apcm->started) 38362306a36Sopenharmony_ci return 0; 38462306a36Sopenharmony_ci apcm->started = 1; 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci max_cisz = src->multi * src->rsc.msr; 38762306a36Sopenharmony_ci max_cisz = 0x80 * (max_cisz < 8 ? max_cisz : 8); 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci src->ops->set_sa(src, apcm->vm_block->addr); 39062306a36Sopenharmony_ci src->ops->set_la(src, apcm->vm_block->addr + apcm->vm_block->size); 39162306a36Sopenharmony_ci src->ops->set_ca(src, apcm->vm_block->addr + max_cisz); 39262306a36Sopenharmony_ci src->ops->set_cisz(src, max_cisz); 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci src->ops->set_bm(src, 1); 39562306a36Sopenharmony_ci src->ops->set_state(src, SRC_STATE_INIT); 39662306a36Sopenharmony_ci src->ops->commit_write(src); 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci ct_timer_start(apcm->timer); 39962306a36Sopenharmony_ci return 0; 40062306a36Sopenharmony_ci} 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_cistatic int atc_pcm_stop(struct ct_atc *atc, struct ct_atc_pcm *apcm) 40362306a36Sopenharmony_ci{ 40462306a36Sopenharmony_ci struct src *src; 40562306a36Sopenharmony_ci int i; 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci ct_timer_stop(apcm->timer); 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci src = apcm->src; 41062306a36Sopenharmony_ci src->ops->set_bm(src, 0); 41162306a36Sopenharmony_ci src->ops->set_state(src, SRC_STATE_OFF); 41262306a36Sopenharmony_ci src->ops->commit_write(src); 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci if (apcm->srccs) { 41562306a36Sopenharmony_ci for (i = 0; i < apcm->n_srcc; i++) { 41662306a36Sopenharmony_ci src = apcm->srccs[i]; 41762306a36Sopenharmony_ci src->ops->set_bm(src, 0); 41862306a36Sopenharmony_ci src->ops->set_state(src, SRC_STATE_OFF); 41962306a36Sopenharmony_ci src->ops->commit_write(src); 42062306a36Sopenharmony_ci } 42162306a36Sopenharmony_ci } 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci apcm->started = 0; 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci return 0; 42662306a36Sopenharmony_ci} 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_cistatic int 42962306a36Sopenharmony_ciatc_pcm_playback_position(struct ct_atc *atc, struct ct_atc_pcm *apcm) 43062306a36Sopenharmony_ci{ 43162306a36Sopenharmony_ci struct src *src = apcm->src; 43262306a36Sopenharmony_ci u32 size, max_cisz; 43362306a36Sopenharmony_ci int position; 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci if (!src) 43662306a36Sopenharmony_ci return 0; 43762306a36Sopenharmony_ci position = src->ops->get_ca(src); 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci if (position < apcm->vm_block->addr) { 44062306a36Sopenharmony_ci dev_dbg(atc->card->dev, 44162306a36Sopenharmony_ci "bad ca - ca=0x%08x, vba=0x%08x, vbs=0x%08x\n", 44262306a36Sopenharmony_ci position, apcm->vm_block->addr, apcm->vm_block->size); 44362306a36Sopenharmony_ci position = apcm->vm_block->addr; 44462306a36Sopenharmony_ci } 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci size = apcm->vm_block->size; 44762306a36Sopenharmony_ci max_cisz = src->multi * src->rsc.msr; 44862306a36Sopenharmony_ci max_cisz = 128 * (max_cisz < 8 ? max_cisz : 8); 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci return (position + size - max_cisz - apcm->vm_block->addr) % size; 45162306a36Sopenharmony_ci} 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_cistruct src_node_conf_t { 45462306a36Sopenharmony_ci unsigned int pitch; 45562306a36Sopenharmony_ci unsigned int msr:8; 45662306a36Sopenharmony_ci unsigned int mix_msr:8; 45762306a36Sopenharmony_ci unsigned int imp_msr:8; 45862306a36Sopenharmony_ci unsigned int vo:1; 45962306a36Sopenharmony_ci}; 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_cistatic void setup_src_node_conf(struct ct_atc *atc, struct ct_atc_pcm *apcm, 46262306a36Sopenharmony_ci struct src_node_conf_t *conf, int *n_srcc) 46362306a36Sopenharmony_ci{ 46462306a36Sopenharmony_ci unsigned int pitch; 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci /* get pitch and convert to fixed-point 8.24 format. */ 46762306a36Sopenharmony_ci pitch = atc_get_pitch((atc->rsr * atc->msr), 46862306a36Sopenharmony_ci apcm->substream->runtime->rate); 46962306a36Sopenharmony_ci *n_srcc = 0; 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci if (1 == atc->msr) { /* FIXME: do we really need SRC here if pitch==1 */ 47262306a36Sopenharmony_ci *n_srcc = apcm->substream->runtime->channels; 47362306a36Sopenharmony_ci conf[0].pitch = pitch; 47462306a36Sopenharmony_ci conf[0].mix_msr = conf[0].imp_msr = conf[0].msr = 1; 47562306a36Sopenharmony_ci conf[0].vo = 1; 47662306a36Sopenharmony_ci } else if (2 <= atc->msr) { 47762306a36Sopenharmony_ci if (0x8000000 < pitch) { 47862306a36Sopenharmony_ci /* Need two-stage SRCs, SRCIMPs and 47962306a36Sopenharmony_ci * AMIXERs for converting format */ 48062306a36Sopenharmony_ci conf[0].pitch = (atc->msr << 24); 48162306a36Sopenharmony_ci conf[0].msr = conf[0].mix_msr = 1; 48262306a36Sopenharmony_ci conf[0].imp_msr = atc->msr; 48362306a36Sopenharmony_ci conf[0].vo = 0; 48462306a36Sopenharmony_ci conf[1].pitch = atc_get_pitch(atc->rsr, 48562306a36Sopenharmony_ci apcm->substream->runtime->rate); 48662306a36Sopenharmony_ci conf[1].msr = conf[1].mix_msr = conf[1].imp_msr = 1; 48762306a36Sopenharmony_ci conf[1].vo = 1; 48862306a36Sopenharmony_ci *n_srcc = apcm->substream->runtime->channels * 2; 48962306a36Sopenharmony_ci } else if (0x1000000 < pitch) { 49062306a36Sopenharmony_ci /* Need one-stage SRCs, SRCIMPs and 49162306a36Sopenharmony_ci * AMIXERs for converting format */ 49262306a36Sopenharmony_ci conf[0].pitch = pitch; 49362306a36Sopenharmony_ci conf[0].msr = conf[0].mix_msr 49462306a36Sopenharmony_ci = conf[0].imp_msr = atc->msr; 49562306a36Sopenharmony_ci conf[0].vo = 1; 49662306a36Sopenharmony_ci *n_srcc = apcm->substream->runtime->channels; 49762306a36Sopenharmony_ci } 49862306a36Sopenharmony_ci } 49962306a36Sopenharmony_ci} 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_cistatic int 50262306a36Sopenharmony_ciatc_pcm_capture_get_resources(struct ct_atc *atc, struct ct_atc_pcm *apcm) 50362306a36Sopenharmony_ci{ 50462306a36Sopenharmony_ci struct src_mgr *src_mgr = atc->rsc_mgrs[SRC]; 50562306a36Sopenharmony_ci struct srcimp_mgr *srcimp_mgr = atc->rsc_mgrs[SRCIMP]; 50662306a36Sopenharmony_ci struct amixer_mgr *amixer_mgr = atc->rsc_mgrs[AMIXER]; 50762306a36Sopenharmony_ci struct sum_mgr *sum_mgr = atc->rsc_mgrs[SUM]; 50862306a36Sopenharmony_ci struct src_desc src_dsc = {0}; 50962306a36Sopenharmony_ci struct src *src; 51062306a36Sopenharmony_ci struct srcimp_desc srcimp_dsc = {0}; 51162306a36Sopenharmony_ci struct srcimp *srcimp; 51262306a36Sopenharmony_ci struct amixer_desc mix_dsc = {0}; 51362306a36Sopenharmony_ci struct sum_desc sum_dsc = {0}; 51462306a36Sopenharmony_ci unsigned int pitch; 51562306a36Sopenharmony_ci int multi, err, i; 51662306a36Sopenharmony_ci int n_srcimp, n_amixer, n_srcc, n_sum; 51762306a36Sopenharmony_ci struct src_node_conf_t src_node_conf[2] = {{0} }; 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci /* first release old resources */ 52062306a36Sopenharmony_ci atc_pcm_release_resources(atc, apcm); 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci /* The numbers of converting SRCs and SRCIMPs should be determined 52362306a36Sopenharmony_ci * by pitch value. */ 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci multi = apcm->substream->runtime->channels; 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci /* get pitch and convert to fixed-point 8.24 format. */ 52862306a36Sopenharmony_ci pitch = atc_get_pitch((atc->rsr * atc->msr), 52962306a36Sopenharmony_ci apcm->substream->runtime->rate); 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci setup_src_node_conf(atc, apcm, src_node_conf, &n_srcc); 53262306a36Sopenharmony_ci n_sum = (1 == multi) ? 1 : 0; 53362306a36Sopenharmony_ci n_amixer = n_sum * 2 + n_srcc; 53462306a36Sopenharmony_ci n_srcimp = n_srcc; 53562306a36Sopenharmony_ci if ((multi > 1) && (0x8000000 >= pitch)) { 53662306a36Sopenharmony_ci /* Need extra AMIXERs and SRCIMPs for special treatment 53762306a36Sopenharmony_ci * of interleaved recording of conjugate channels */ 53862306a36Sopenharmony_ci n_amixer += multi * atc->msr; 53962306a36Sopenharmony_ci n_srcimp += multi * atc->msr; 54062306a36Sopenharmony_ci } else { 54162306a36Sopenharmony_ci n_srcimp += multi; 54262306a36Sopenharmony_ci } 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci if (n_srcc) { 54562306a36Sopenharmony_ci apcm->srccs = kcalloc(n_srcc, sizeof(void *), GFP_KERNEL); 54662306a36Sopenharmony_ci if (!apcm->srccs) 54762306a36Sopenharmony_ci return -ENOMEM; 54862306a36Sopenharmony_ci } 54962306a36Sopenharmony_ci if (n_amixer) { 55062306a36Sopenharmony_ci apcm->amixers = kcalloc(n_amixer, sizeof(void *), GFP_KERNEL); 55162306a36Sopenharmony_ci if (!apcm->amixers) { 55262306a36Sopenharmony_ci err = -ENOMEM; 55362306a36Sopenharmony_ci goto error1; 55462306a36Sopenharmony_ci } 55562306a36Sopenharmony_ci } 55662306a36Sopenharmony_ci apcm->srcimps = kcalloc(n_srcimp, sizeof(void *), GFP_KERNEL); 55762306a36Sopenharmony_ci if (!apcm->srcimps) { 55862306a36Sopenharmony_ci err = -ENOMEM; 55962306a36Sopenharmony_ci goto error1; 56062306a36Sopenharmony_ci } 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci /* Allocate SRCs for sample rate conversion if needed */ 56362306a36Sopenharmony_ci src_dsc.multi = 1; 56462306a36Sopenharmony_ci src_dsc.mode = ARCRW; 56562306a36Sopenharmony_ci for (i = 0, apcm->n_srcc = 0; i < n_srcc; i++) { 56662306a36Sopenharmony_ci src_dsc.msr = src_node_conf[i/multi].msr; 56762306a36Sopenharmony_ci err = src_mgr->get_src(src_mgr, &src_dsc, 56862306a36Sopenharmony_ci (struct src **)&apcm->srccs[i]); 56962306a36Sopenharmony_ci if (err) 57062306a36Sopenharmony_ci goto error1; 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci src = apcm->srccs[i]; 57362306a36Sopenharmony_ci pitch = src_node_conf[i/multi].pitch; 57462306a36Sopenharmony_ci src->ops->set_pitch(src, pitch); 57562306a36Sopenharmony_ci src->ops->set_rom(src, select_rom(pitch)); 57662306a36Sopenharmony_ci src->ops->set_vo(src, src_node_conf[i/multi].vo); 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci apcm->n_srcc++; 57962306a36Sopenharmony_ci } 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci /* Allocate AMIXERs for routing SRCs of conversion if needed */ 58262306a36Sopenharmony_ci for (i = 0, apcm->n_amixer = 0; i < n_amixer; i++) { 58362306a36Sopenharmony_ci if (i < (n_sum*2)) 58462306a36Sopenharmony_ci mix_dsc.msr = atc->msr; 58562306a36Sopenharmony_ci else if (i < (n_sum*2+n_srcc)) 58662306a36Sopenharmony_ci mix_dsc.msr = src_node_conf[(i-n_sum*2)/multi].mix_msr; 58762306a36Sopenharmony_ci else 58862306a36Sopenharmony_ci mix_dsc.msr = 1; 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci err = amixer_mgr->get_amixer(amixer_mgr, &mix_dsc, 59162306a36Sopenharmony_ci (struct amixer **)&apcm->amixers[i]); 59262306a36Sopenharmony_ci if (err) 59362306a36Sopenharmony_ci goto error1; 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci apcm->n_amixer++; 59662306a36Sopenharmony_ci } 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci /* Allocate a SUM resource to mix all input channels together */ 59962306a36Sopenharmony_ci sum_dsc.msr = atc->msr; 60062306a36Sopenharmony_ci err = sum_mgr->get_sum(sum_mgr, &sum_dsc, (struct sum **)&apcm->mono); 60162306a36Sopenharmony_ci if (err) 60262306a36Sopenharmony_ci goto error1; 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci pitch = atc_get_pitch((atc->rsr * atc->msr), 60562306a36Sopenharmony_ci apcm->substream->runtime->rate); 60662306a36Sopenharmony_ci /* Allocate SRCIMP resources */ 60762306a36Sopenharmony_ci for (i = 0, apcm->n_srcimp = 0; i < n_srcimp; i++) { 60862306a36Sopenharmony_ci if (i < (n_srcc)) 60962306a36Sopenharmony_ci srcimp_dsc.msr = src_node_conf[i/multi].imp_msr; 61062306a36Sopenharmony_ci else if (1 == multi) 61162306a36Sopenharmony_ci srcimp_dsc.msr = (pitch <= 0x8000000) ? atc->msr : 1; 61262306a36Sopenharmony_ci else 61362306a36Sopenharmony_ci srcimp_dsc.msr = 1; 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci err = srcimp_mgr->get_srcimp(srcimp_mgr, &srcimp_dsc, &srcimp); 61662306a36Sopenharmony_ci if (err) 61762306a36Sopenharmony_ci goto error1; 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci apcm->srcimps[i] = srcimp; 62062306a36Sopenharmony_ci apcm->n_srcimp++; 62162306a36Sopenharmony_ci } 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci /* Allocate a SRC for writing data to host memory */ 62462306a36Sopenharmony_ci src_dsc.multi = apcm->substream->runtime->channels; 62562306a36Sopenharmony_ci src_dsc.msr = 1; 62662306a36Sopenharmony_ci src_dsc.mode = MEMWR; 62762306a36Sopenharmony_ci err = src_mgr->get_src(src_mgr, &src_dsc, (struct src **)&apcm->src); 62862306a36Sopenharmony_ci if (err) 62962306a36Sopenharmony_ci goto error1; 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci src = apcm->src; 63262306a36Sopenharmony_ci src->ops->set_pitch(src, pitch); 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci /* Set up device virtual mem map */ 63562306a36Sopenharmony_ci err = ct_map_audio_buffer(atc, apcm); 63662306a36Sopenharmony_ci if (err < 0) 63762306a36Sopenharmony_ci goto error1; 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci return 0; 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_cierror1: 64262306a36Sopenharmony_ci atc_pcm_release_resources(atc, apcm); 64362306a36Sopenharmony_ci return err; 64462306a36Sopenharmony_ci} 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_cistatic int atc_pcm_capture_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm) 64762306a36Sopenharmony_ci{ 64862306a36Sopenharmony_ci struct src *src; 64962306a36Sopenharmony_ci struct amixer *amixer; 65062306a36Sopenharmony_ci struct srcimp *srcimp; 65162306a36Sopenharmony_ci struct ct_mixer *mixer = atc->mixer; 65262306a36Sopenharmony_ci struct sum *mono; 65362306a36Sopenharmony_ci struct rsc *out_ports[8] = {NULL}; 65462306a36Sopenharmony_ci int err, i, j, n_sum, multi; 65562306a36Sopenharmony_ci unsigned int pitch; 65662306a36Sopenharmony_ci int mix_base = 0, imp_base = 0; 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci atc_pcm_release_resources(atc, apcm); 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci /* Get needed resources. */ 66162306a36Sopenharmony_ci err = atc_pcm_capture_get_resources(atc, apcm); 66262306a36Sopenharmony_ci if (err) 66362306a36Sopenharmony_ci return err; 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci /* Connect resources */ 66662306a36Sopenharmony_ci mixer->get_output_ports(mixer, MIX_PCMO_FRONT, 66762306a36Sopenharmony_ci &out_ports[0], &out_ports[1]); 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci multi = apcm->substream->runtime->channels; 67062306a36Sopenharmony_ci if (1 == multi) { 67162306a36Sopenharmony_ci mono = apcm->mono; 67262306a36Sopenharmony_ci for (i = 0; i < 2; i++) { 67362306a36Sopenharmony_ci amixer = apcm->amixers[i]; 67462306a36Sopenharmony_ci amixer->ops->setup(amixer, out_ports[i], 67562306a36Sopenharmony_ci MONO_SUM_SCALE, mono); 67662306a36Sopenharmony_ci } 67762306a36Sopenharmony_ci out_ports[0] = &mono->rsc; 67862306a36Sopenharmony_ci n_sum = 1; 67962306a36Sopenharmony_ci mix_base = n_sum * 2; 68062306a36Sopenharmony_ci } 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci for (i = 0; i < apcm->n_srcc; i++) { 68362306a36Sopenharmony_ci src = apcm->srccs[i]; 68462306a36Sopenharmony_ci srcimp = apcm->srcimps[imp_base+i]; 68562306a36Sopenharmony_ci amixer = apcm->amixers[mix_base+i]; 68662306a36Sopenharmony_ci srcimp->ops->map(srcimp, src, out_ports[i%multi]); 68762306a36Sopenharmony_ci amixer->ops->setup(amixer, &src->rsc, INIT_VOL, NULL); 68862306a36Sopenharmony_ci out_ports[i%multi] = &amixer->rsc; 68962306a36Sopenharmony_ci } 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci pitch = atc_get_pitch((atc->rsr * atc->msr), 69262306a36Sopenharmony_ci apcm->substream->runtime->rate); 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci if ((multi > 1) && (pitch <= 0x8000000)) { 69562306a36Sopenharmony_ci /* Special connection for interleaved 69662306a36Sopenharmony_ci * recording with conjugate channels */ 69762306a36Sopenharmony_ci for (i = 0; i < multi; i++) { 69862306a36Sopenharmony_ci out_ports[i]->ops->master(out_ports[i]); 69962306a36Sopenharmony_ci for (j = 0; j < atc->msr; j++) { 70062306a36Sopenharmony_ci amixer = apcm->amixers[apcm->n_srcc+j*multi+i]; 70162306a36Sopenharmony_ci amixer->ops->set_input(amixer, out_ports[i]); 70262306a36Sopenharmony_ci amixer->ops->set_scale(amixer, INIT_VOL); 70362306a36Sopenharmony_ci amixer->ops->set_sum(amixer, NULL); 70462306a36Sopenharmony_ci amixer->ops->commit_raw_write(amixer); 70562306a36Sopenharmony_ci out_ports[i]->ops->next_conj(out_ports[i]); 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci srcimp = apcm->srcimps[apcm->n_srcc+j*multi+i]; 70862306a36Sopenharmony_ci srcimp->ops->map(srcimp, apcm->src, 70962306a36Sopenharmony_ci &amixer->rsc); 71062306a36Sopenharmony_ci } 71162306a36Sopenharmony_ci } 71262306a36Sopenharmony_ci } else { 71362306a36Sopenharmony_ci for (i = 0; i < multi; i++) { 71462306a36Sopenharmony_ci srcimp = apcm->srcimps[apcm->n_srcc+i]; 71562306a36Sopenharmony_ci srcimp->ops->map(srcimp, apcm->src, out_ports[i]); 71662306a36Sopenharmony_ci } 71762306a36Sopenharmony_ci } 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci ct_timer_prepare(apcm->timer); 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci return 0; 72262306a36Sopenharmony_ci} 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_cistatic int atc_pcm_capture_start(struct ct_atc *atc, struct ct_atc_pcm *apcm) 72562306a36Sopenharmony_ci{ 72662306a36Sopenharmony_ci struct src *src; 72762306a36Sopenharmony_ci struct src_mgr *src_mgr = atc->rsc_mgrs[SRC]; 72862306a36Sopenharmony_ci int i, multi; 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci if (apcm->started) 73162306a36Sopenharmony_ci return 0; 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci apcm->started = 1; 73462306a36Sopenharmony_ci multi = apcm->substream->runtime->channels; 73562306a36Sopenharmony_ci /* Set up converting SRCs */ 73662306a36Sopenharmony_ci for (i = 0; i < apcm->n_srcc; i++) { 73762306a36Sopenharmony_ci src = apcm->srccs[i]; 73862306a36Sopenharmony_ci src->ops->set_pm(src, ((i%multi) != (multi-1))); 73962306a36Sopenharmony_ci src_mgr->src_disable(src_mgr, src); 74062306a36Sopenharmony_ci } 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci /* Set up recording SRC */ 74362306a36Sopenharmony_ci src = apcm->src; 74462306a36Sopenharmony_ci src->ops->set_sf(src, convert_format(apcm->substream->runtime->format, 74562306a36Sopenharmony_ci atc->card)); 74662306a36Sopenharmony_ci src->ops->set_sa(src, apcm->vm_block->addr); 74762306a36Sopenharmony_ci src->ops->set_la(src, apcm->vm_block->addr + apcm->vm_block->size); 74862306a36Sopenharmony_ci src->ops->set_ca(src, apcm->vm_block->addr); 74962306a36Sopenharmony_ci src_mgr->src_disable(src_mgr, src); 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci /* Disable relevant SRCs firstly */ 75262306a36Sopenharmony_ci src_mgr->commit_write(src_mgr); 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci /* Enable SRCs respectively */ 75562306a36Sopenharmony_ci for (i = 0; i < apcm->n_srcc; i++) { 75662306a36Sopenharmony_ci src = apcm->srccs[i]; 75762306a36Sopenharmony_ci src->ops->set_state(src, SRC_STATE_RUN); 75862306a36Sopenharmony_ci src->ops->commit_write(src); 75962306a36Sopenharmony_ci src_mgr->src_enable_s(src_mgr, src); 76062306a36Sopenharmony_ci } 76162306a36Sopenharmony_ci src = apcm->src; 76262306a36Sopenharmony_ci src->ops->set_bm(src, 1); 76362306a36Sopenharmony_ci src->ops->set_state(src, SRC_STATE_RUN); 76462306a36Sopenharmony_ci src->ops->commit_write(src); 76562306a36Sopenharmony_ci src_mgr->src_enable_s(src_mgr, src); 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci /* Enable relevant SRCs synchronously */ 76862306a36Sopenharmony_ci src_mgr->commit_write(src_mgr); 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci ct_timer_start(apcm->timer); 77162306a36Sopenharmony_ci return 0; 77262306a36Sopenharmony_ci} 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_cistatic int 77562306a36Sopenharmony_ciatc_pcm_capture_position(struct ct_atc *atc, struct ct_atc_pcm *apcm) 77662306a36Sopenharmony_ci{ 77762306a36Sopenharmony_ci struct src *src = apcm->src; 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci if (!src) 78062306a36Sopenharmony_ci return 0; 78162306a36Sopenharmony_ci return src->ops->get_ca(src) - apcm->vm_block->addr; 78262306a36Sopenharmony_ci} 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_cistatic int spdif_passthru_playback_get_resources(struct ct_atc *atc, 78562306a36Sopenharmony_ci struct ct_atc_pcm *apcm) 78662306a36Sopenharmony_ci{ 78762306a36Sopenharmony_ci struct src_mgr *src_mgr = atc->rsc_mgrs[SRC]; 78862306a36Sopenharmony_ci struct amixer_mgr *amixer_mgr = atc->rsc_mgrs[AMIXER]; 78962306a36Sopenharmony_ci struct src_desc desc = {0}; 79062306a36Sopenharmony_ci struct amixer_desc mix_dsc = {0}; 79162306a36Sopenharmony_ci struct src *src; 79262306a36Sopenharmony_ci int err; 79362306a36Sopenharmony_ci int n_amixer = apcm->substream->runtime->channels, i; 79462306a36Sopenharmony_ci unsigned int pitch, rsr = atc->pll_rate; 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci /* first release old resources */ 79762306a36Sopenharmony_ci atc_pcm_release_resources(atc, apcm); 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci /* Get SRC resource */ 80062306a36Sopenharmony_ci desc.multi = apcm->substream->runtime->channels; 80162306a36Sopenharmony_ci desc.msr = 1; 80262306a36Sopenharmony_ci while (apcm->substream->runtime->rate > (rsr * desc.msr)) 80362306a36Sopenharmony_ci desc.msr <<= 1; 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci desc.mode = MEMRD; 80662306a36Sopenharmony_ci err = src_mgr->get_src(src_mgr, &desc, (struct src **)&apcm->src); 80762306a36Sopenharmony_ci if (err) 80862306a36Sopenharmony_ci goto error1; 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ci pitch = atc_get_pitch(apcm->substream->runtime->rate, (rsr * desc.msr)); 81162306a36Sopenharmony_ci src = apcm->src; 81262306a36Sopenharmony_ci src->ops->set_pitch(src, pitch); 81362306a36Sopenharmony_ci src->ops->set_rom(src, select_rom(pitch)); 81462306a36Sopenharmony_ci src->ops->set_sf(src, convert_format(apcm->substream->runtime->format, 81562306a36Sopenharmony_ci atc->card)); 81662306a36Sopenharmony_ci src->ops->set_pm(src, (src->ops->next_interleave(src) != NULL)); 81762306a36Sopenharmony_ci src->ops->set_bp(src, 1); 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci /* Get AMIXER resource */ 82062306a36Sopenharmony_ci n_amixer = (n_amixer < 2) ? 2 : n_amixer; 82162306a36Sopenharmony_ci apcm->amixers = kcalloc(n_amixer, sizeof(void *), GFP_KERNEL); 82262306a36Sopenharmony_ci if (!apcm->amixers) { 82362306a36Sopenharmony_ci err = -ENOMEM; 82462306a36Sopenharmony_ci goto error1; 82562306a36Sopenharmony_ci } 82662306a36Sopenharmony_ci mix_dsc.msr = desc.msr; 82762306a36Sopenharmony_ci for (i = 0, apcm->n_amixer = 0; i < n_amixer; i++) { 82862306a36Sopenharmony_ci err = amixer_mgr->get_amixer(amixer_mgr, &mix_dsc, 82962306a36Sopenharmony_ci (struct amixer **)&apcm->amixers[i]); 83062306a36Sopenharmony_ci if (err) 83162306a36Sopenharmony_ci goto error1; 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_ci apcm->n_amixer++; 83462306a36Sopenharmony_ci } 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci /* Set up device virtual mem map */ 83762306a36Sopenharmony_ci err = ct_map_audio_buffer(atc, apcm); 83862306a36Sopenharmony_ci if (err < 0) 83962306a36Sopenharmony_ci goto error1; 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_ci return 0; 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_cierror1: 84462306a36Sopenharmony_ci atc_pcm_release_resources(atc, apcm); 84562306a36Sopenharmony_ci return err; 84662306a36Sopenharmony_ci} 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_cistatic int atc_pll_init(struct ct_atc *atc, int rate) 84962306a36Sopenharmony_ci{ 85062306a36Sopenharmony_ci struct hw *hw = atc->hw; 85162306a36Sopenharmony_ci int err; 85262306a36Sopenharmony_ci err = hw->pll_init(hw, rate); 85362306a36Sopenharmony_ci atc->pll_rate = err ? 0 : rate; 85462306a36Sopenharmony_ci return err; 85562306a36Sopenharmony_ci} 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_cistatic int 85862306a36Sopenharmony_cispdif_passthru_playback_setup(struct ct_atc *atc, struct ct_atc_pcm *apcm) 85962306a36Sopenharmony_ci{ 86062306a36Sopenharmony_ci struct dao *dao = container_of(atc->daios[SPDIFOO], struct dao, daio); 86162306a36Sopenharmony_ci unsigned int rate = apcm->substream->runtime->rate; 86262306a36Sopenharmony_ci unsigned int status; 86362306a36Sopenharmony_ci int err = 0; 86462306a36Sopenharmony_ci unsigned char iec958_con_fs; 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci switch (rate) { 86762306a36Sopenharmony_ci case 48000: 86862306a36Sopenharmony_ci iec958_con_fs = IEC958_AES3_CON_FS_48000; 86962306a36Sopenharmony_ci break; 87062306a36Sopenharmony_ci case 44100: 87162306a36Sopenharmony_ci iec958_con_fs = IEC958_AES3_CON_FS_44100; 87262306a36Sopenharmony_ci break; 87362306a36Sopenharmony_ci case 32000: 87462306a36Sopenharmony_ci iec958_con_fs = IEC958_AES3_CON_FS_32000; 87562306a36Sopenharmony_ci break; 87662306a36Sopenharmony_ci default: 87762306a36Sopenharmony_ci return -ENOENT; 87862306a36Sopenharmony_ci } 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_ci mutex_lock(&atc->atc_mutex); 88162306a36Sopenharmony_ci dao->ops->get_spos(dao, &status); 88262306a36Sopenharmony_ci if (((status >> 24) & IEC958_AES3_CON_FS) != iec958_con_fs) { 88362306a36Sopenharmony_ci status &= ~(IEC958_AES3_CON_FS << 24); 88462306a36Sopenharmony_ci status |= (iec958_con_fs << 24); 88562306a36Sopenharmony_ci dao->ops->set_spos(dao, status); 88662306a36Sopenharmony_ci dao->ops->commit_write(dao); 88762306a36Sopenharmony_ci } 88862306a36Sopenharmony_ci if ((rate != atc->pll_rate) && (32000 != rate)) 88962306a36Sopenharmony_ci err = atc_pll_init(atc, rate); 89062306a36Sopenharmony_ci mutex_unlock(&atc->atc_mutex); 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ci return err; 89362306a36Sopenharmony_ci} 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_cistatic int 89662306a36Sopenharmony_cispdif_passthru_playback_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm) 89762306a36Sopenharmony_ci{ 89862306a36Sopenharmony_ci struct src *src; 89962306a36Sopenharmony_ci struct amixer *amixer; 90062306a36Sopenharmony_ci struct dao *dao; 90162306a36Sopenharmony_ci int err; 90262306a36Sopenharmony_ci int i; 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci atc_pcm_release_resources(atc, apcm); 90562306a36Sopenharmony_ci 90662306a36Sopenharmony_ci /* Configure SPDIFOO and PLL to passthrough mode; 90762306a36Sopenharmony_ci * determine pll_rate. */ 90862306a36Sopenharmony_ci err = spdif_passthru_playback_setup(atc, apcm); 90962306a36Sopenharmony_ci if (err) 91062306a36Sopenharmony_ci return err; 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_ci /* Get needed resources. */ 91362306a36Sopenharmony_ci err = spdif_passthru_playback_get_resources(atc, apcm); 91462306a36Sopenharmony_ci if (err) 91562306a36Sopenharmony_ci return err; 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_ci /* Connect resources */ 91862306a36Sopenharmony_ci src = apcm->src; 91962306a36Sopenharmony_ci for (i = 0; i < apcm->n_amixer; i++) { 92062306a36Sopenharmony_ci amixer = apcm->amixers[i]; 92162306a36Sopenharmony_ci amixer->ops->setup(amixer, &src->rsc, INIT_VOL, NULL); 92262306a36Sopenharmony_ci src = src->ops->next_interleave(src); 92362306a36Sopenharmony_ci if (!src) 92462306a36Sopenharmony_ci src = apcm->src; 92562306a36Sopenharmony_ci } 92662306a36Sopenharmony_ci /* Connect to SPDIFOO */ 92762306a36Sopenharmony_ci mutex_lock(&atc->atc_mutex); 92862306a36Sopenharmony_ci dao = container_of(atc->daios[SPDIFOO], struct dao, daio); 92962306a36Sopenharmony_ci amixer = apcm->amixers[0]; 93062306a36Sopenharmony_ci dao->ops->set_left_input(dao, &amixer->rsc); 93162306a36Sopenharmony_ci amixer = apcm->amixers[1]; 93262306a36Sopenharmony_ci dao->ops->set_right_input(dao, &amixer->rsc); 93362306a36Sopenharmony_ci mutex_unlock(&atc->atc_mutex); 93462306a36Sopenharmony_ci 93562306a36Sopenharmony_ci ct_timer_prepare(apcm->timer); 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_ci return 0; 93862306a36Sopenharmony_ci} 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_cistatic int atc_select_line_in(struct ct_atc *atc) 94162306a36Sopenharmony_ci{ 94262306a36Sopenharmony_ci struct hw *hw = atc->hw; 94362306a36Sopenharmony_ci struct ct_mixer *mixer = atc->mixer; 94462306a36Sopenharmony_ci struct src *src; 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_ci if (hw->is_adc_source_selected(hw, ADC_LINEIN)) 94762306a36Sopenharmony_ci return 0; 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_ci mixer->set_input_left(mixer, MIX_MIC_IN, NULL); 95062306a36Sopenharmony_ci mixer->set_input_right(mixer, MIX_MIC_IN, NULL); 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_ci hw->select_adc_source(hw, ADC_LINEIN); 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_ci src = atc->srcs[2]; 95562306a36Sopenharmony_ci mixer->set_input_left(mixer, MIX_LINE_IN, &src->rsc); 95662306a36Sopenharmony_ci src = atc->srcs[3]; 95762306a36Sopenharmony_ci mixer->set_input_right(mixer, MIX_LINE_IN, &src->rsc); 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_ci return 0; 96062306a36Sopenharmony_ci} 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_cistatic int atc_select_mic_in(struct ct_atc *atc) 96362306a36Sopenharmony_ci{ 96462306a36Sopenharmony_ci struct hw *hw = atc->hw; 96562306a36Sopenharmony_ci struct ct_mixer *mixer = atc->mixer; 96662306a36Sopenharmony_ci struct src *src; 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ci if (hw->is_adc_source_selected(hw, ADC_MICIN)) 96962306a36Sopenharmony_ci return 0; 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_ci mixer->set_input_left(mixer, MIX_LINE_IN, NULL); 97262306a36Sopenharmony_ci mixer->set_input_right(mixer, MIX_LINE_IN, NULL); 97362306a36Sopenharmony_ci 97462306a36Sopenharmony_ci hw->select_adc_source(hw, ADC_MICIN); 97562306a36Sopenharmony_ci 97662306a36Sopenharmony_ci src = atc->srcs[2]; 97762306a36Sopenharmony_ci mixer->set_input_left(mixer, MIX_MIC_IN, &src->rsc); 97862306a36Sopenharmony_ci src = atc->srcs[3]; 97962306a36Sopenharmony_ci mixer->set_input_right(mixer, MIX_MIC_IN, &src->rsc); 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci return 0; 98262306a36Sopenharmony_ci} 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_cistatic struct capabilities atc_capabilities(struct ct_atc *atc) 98562306a36Sopenharmony_ci{ 98662306a36Sopenharmony_ci struct hw *hw = atc->hw; 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci return hw->capabilities(hw); 98962306a36Sopenharmony_ci} 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_cistatic int atc_output_switch_get(struct ct_atc *atc) 99262306a36Sopenharmony_ci{ 99362306a36Sopenharmony_ci struct hw *hw = atc->hw; 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_ci return hw->output_switch_get(hw); 99662306a36Sopenharmony_ci} 99762306a36Sopenharmony_ci 99862306a36Sopenharmony_cistatic int atc_output_switch_put(struct ct_atc *atc, int position) 99962306a36Sopenharmony_ci{ 100062306a36Sopenharmony_ci struct hw *hw = atc->hw; 100162306a36Sopenharmony_ci 100262306a36Sopenharmony_ci return hw->output_switch_put(hw, position); 100362306a36Sopenharmony_ci} 100462306a36Sopenharmony_ci 100562306a36Sopenharmony_cistatic int atc_mic_source_switch_get(struct ct_atc *atc) 100662306a36Sopenharmony_ci{ 100762306a36Sopenharmony_ci struct hw *hw = atc->hw; 100862306a36Sopenharmony_ci 100962306a36Sopenharmony_ci return hw->mic_source_switch_get(hw); 101062306a36Sopenharmony_ci} 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_cistatic int atc_mic_source_switch_put(struct ct_atc *atc, int position) 101362306a36Sopenharmony_ci{ 101462306a36Sopenharmony_ci struct hw *hw = atc->hw; 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_ci return hw->mic_source_switch_put(hw, position); 101762306a36Sopenharmony_ci} 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_cistatic int atc_select_digit_io(struct ct_atc *atc) 102062306a36Sopenharmony_ci{ 102162306a36Sopenharmony_ci struct hw *hw = atc->hw; 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ci if (hw->is_adc_source_selected(hw, ADC_NONE)) 102462306a36Sopenharmony_ci return 0; 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_ci hw->select_adc_source(hw, ADC_NONE); 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_ci return 0; 102962306a36Sopenharmony_ci} 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_cistatic int atc_daio_unmute(struct ct_atc *atc, unsigned char state, int type) 103262306a36Sopenharmony_ci{ 103362306a36Sopenharmony_ci struct daio_mgr *daio_mgr = atc->rsc_mgrs[DAIO]; 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_ci if (state) 103662306a36Sopenharmony_ci daio_mgr->daio_enable(daio_mgr, atc->daios[type]); 103762306a36Sopenharmony_ci else 103862306a36Sopenharmony_ci daio_mgr->daio_disable(daio_mgr, atc->daios[type]); 103962306a36Sopenharmony_ci 104062306a36Sopenharmony_ci daio_mgr->commit_write(daio_mgr); 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_ci return 0; 104362306a36Sopenharmony_ci} 104462306a36Sopenharmony_ci 104562306a36Sopenharmony_cistatic int 104662306a36Sopenharmony_ciatc_dao_get_status(struct ct_atc *atc, unsigned int *status, int type) 104762306a36Sopenharmony_ci{ 104862306a36Sopenharmony_ci struct dao *dao = container_of(atc->daios[type], struct dao, daio); 104962306a36Sopenharmony_ci return dao->ops->get_spos(dao, status); 105062306a36Sopenharmony_ci} 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_cistatic int 105362306a36Sopenharmony_ciatc_dao_set_status(struct ct_atc *atc, unsigned int status, int type) 105462306a36Sopenharmony_ci{ 105562306a36Sopenharmony_ci struct dao *dao = container_of(atc->daios[type], struct dao, daio); 105662306a36Sopenharmony_ci 105762306a36Sopenharmony_ci dao->ops->set_spos(dao, status); 105862306a36Sopenharmony_ci dao->ops->commit_write(dao); 105962306a36Sopenharmony_ci return 0; 106062306a36Sopenharmony_ci} 106162306a36Sopenharmony_ci 106262306a36Sopenharmony_cistatic int atc_line_front_unmute(struct ct_atc *atc, unsigned char state) 106362306a36Sopenharmony_ci{ 106462306a36Sopenharmony_ci return atc_daio_unmute(atc, state, LINEO1); 106562306a36Sopenharmony_ci} 106662306a36Sopenharmony_ci 106762306a36Sopenharmony_cistatic int atc_line_surround_unmute(struct ct_atc *atc, unsigned char state) 106862306a36Sopenharmony_ci{ 106962306a36Sopenharmony_ci return atc_daio_unmute(atc, state, LINEO2); 107062306a36Sopenharmony_ci} 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_cistatic int atc_line_clfe_unmute(struct ct_atc *atc, unsigned char state) 107362306a36Sopenharmony_ci{ 107462306a36Sopenharmony_ci return atc_daio_unmute(atc, state, LINEO3); 107562306a36Sopenharmony_ci} 107662306a36Sopenharmony_ci 107762306a36Sopenharmony_cistatic int atc_line_rear_unmute(struct ct_atc *atc, unsigned char state) 107862306a36Sopenharmony_ci{ 107962306a36Sopenharmony_ci return atc_daio_unmute(atc, state, LINEO4); 108062306a36Sopenharmony_ci} 108162306a36Sopenharmony_ci 108262306a36Sopenharmony_cistatic int atc_line_in_unmute(struct ct_atc *atc, unsigned char state) 108362306a36Sopenharmony_ci{ 108462306a36Sopenharmony_ci return atc_daio_unmute(atc, state, LINEIM); 108562306a36Sopenharmony_ci} 108662306a36Sopenharmony_ci 108762306a36Sopenharmony_cistatic int atc_mic_unmute(struct ct_atc *atc, unsigned char state) 108862306a36Sopenharmony_ci{ 108962306a36Sopenharmony_ci return atc_daio_unmute(atc, state, MIC); 109062306a36Sopenharmony_ci} 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_cistatic int atc_spdif_out_unmute(struct ct_atc *atc, unsigned char state) 109362306a36Sopenharmony_ci{ 109462306a36Sopenharmony_ci return atc_daio_unmute(atc, state, SPDIFOO); 109562306a36Sopenharmony_ci} 109662306a36Sopenharmony_ci 109762306a36Sopenharmony_cistatic int atc_spdif_in_unmute(struct ct_atc *atc, unsigned char state) 109862306a36Sopenharmony_ci{ 109962306a36Sopenharmony_ci return atc_daio_unmute(atc, state, SPDIFIO); 110062306a36Sopenharmony_ci} 110162306a36Sopenharmony_ci 110262306a36Sopenharmony_cistatic int atc_spdif_out_get_status(struct ct_atc *atc, unsigned int *status) 110362306a36Sopenharmony_ci{ 110462306a36Sopenharmony_ci return atc_dao_get_status(atc, status, SPDIFOO); 110562306a36Sopenharmony_ci} 110662306a36Sopenharmony_ci 110762306a36Sopenharmony_cistatic int atc_spdif_out_set_status(struct ct_atc *atc, unsigned int status) 110862306a36Sopenharmony_ci{ 110962306a36Sopenharmony_ci return atc_dao_set_status(atc, status, SPDIFOO); 111062306a36Sopenharmony_ci} 111162306a36Sopenharmony_ci 111262306a36Sopenharmony_cistatic int atc_spdif_out_passthru(struct ct_atc *atc, unsigned char state) 111362306a36Sopenharmony_ci{ 111462306a36Sopenharmony_ci struct dao_desc da_dsc = {0}; 111562306a36Sopenharmony_ci struct dao *dao; 111662306a36Sopenharmony_ci int err; 111762306a36Sopenharmony_ci struct ct_mixer *mixer = atc->mixer; 111862306a36Sopenharmony_ci struct rsc *rscs[2] = {NULL}; 111962306a36Sopenharmony_ci unsigned int spos = 0; 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_ci mutex_lock(&atc->atc_mutex); 112262306a36Sopenharmony_ci dao = container_of(atc->daios[SPDIFOO], struct dao, daio); 112362306a36Sopenharmony_ci da_dsc.msr = state ? 1 : atc->msr; 112462306a36Sopenharmony_ci da_dsc.passthru = state ? 1 : 0; 112562306a36Sopenharmony_ci err = dao->ops->reinit(dao, &da_dsc); 112662306a36Sopenharmony_ci if (state) { 112762306a36Sopenharmony_ci spos = IEC958_DEFAULT_CON; 112862306a36Sopenharmony_ci } else { 112962306a36Sopenharmony_ci mixer->get_output_ports(mixer, MIX_SPDIF_OUT, 113062306a36Sopenharmony_ci &rscs[0], &rscs[1]); 113162306a36Sopenharmony_ci dao->ops->set_left_input(dao, rscs[0]); 113262306a36Sopenharmony_ci dao->ops->set_right_input(dao, rscs[1]); 113362306a36Sopenharmony_ci /* Restore PLL to atc->rsr if needed. */ 113462306a36Sopenharmony_ci if (atc->pll_rate != atc->rsr) 113562306a36Sopenharmony_ci err = atc_pll_init(atc, atc->rsr); 113662306a36Sopenharmony_ci } 113762306a36Sopenharmony_ci dao->ops->set_spos(dao, spos); 113862306a36Sopenharmony_ci dao->ops->commit_write(dao); 113962306a36Sopenharmony_ci mutex_unlock(&atc->atc_mutex); 114062306a36Sopenharmony_ci 114162306a36Sopenharmony_ci return err; 114262306a36Sopenharmony_ci} 114362306a36Sopenharmony_ci 114462306a36Sopenharmony_cistatic int atc_release_resources(struct ct_atc *atc) 114562306a36Sopenharmony_ci{ 114662306a36Sopenharmony_ci int i; 114762306a36Sopenharmony_ci struct daio_mgr *daio_mgr = NULL; 114862306a36Sopenharmony_ci struct dao *dao = NULL; 114962306a36Sopenharmony_ci struct daio *daio = NULL; 115062306a36Sopenharmony_ci struct sum_mgr *sum_mgr = NULL; 115162306a36Sopenharmony_ci struct src_mgr *src_mgr = NULL; 115262306a36Sopenharmony_ci struct srcimp_mgr *srcimp_mgr = NULL; 115362306a36Sopenharmony_ci struct srcimp *srcimp = NULL; 115462306a36Sopenharmony_ci struct ct_mixer *mixer = NULL; 115562306a36Sopenharmony_ci 115662306a36Sopenharmony_ci /* disconnect internal mixer objects */ 115762306a36Sopenharmony_ci if (atc->mixer) { 115862306a36Sopenharmony_ci mixer = atc->mixer; 115962306a36Sopenharmony_ci mixer->set_input_left(mixer, MIX_LINE_IN, NULL); 116062306a36Sopenharmony_ci mixer->set_input_right(mixer, MIX_LINE_IN, NULL); 116162306a36Sopenharmony_ci mixer->set_input_left(mixer, MIX_MIC_IN, NULL); 116262306a36Sopenharmony_ci mixer->set_input_right(mixer, MIX_MIC_IN, NULL); 116362306a36Sopenharmony_ci mixer->set_input_left(mixer, MIX_SPDIF_IN, NULL); 116462306a36Sopenharmony_ci mixer->set_input_right(mixer, MIX_SPDIF_IN, NULL); 116562306a36Sopenharmony_ci } 116662306a36Sopenharmony_ci 116762306a36Sopenharmony_ci if (atc->daios) { 116862306a36Sopenharmony_ci daio_mgr = (struct daio_mgr *)atc->rsc_mgrs[DAIO]; 116962306a36Sopenharmony_ci for (i = 0; i < atc->n_daio; i++) { 117062306a36Sopenharmony_ci daio = atc->daios[i]; 117162306a36Sopenharmony_ci if (daio->type < LINEIM) { 117262306a36Sopenharmony_ci dao = container_of(daio, struct dao, daio); 117362306a36Sopenharmony_ci dao->ops->clear_left_input(dao); 117462306a36Sopenharmony_ci dao->ops->clear_right_input(dao); 117562306a36Sopenharmony_ci } 117662306a36Sopenharmony_ci daio_mgr->put_daio(daio_mgr, daio); 117762306a36Sopenharmony_ci } 117862306a36Sopenharmony_ci kfree(atc->daios); 117962306a36Sopenharmony_ci atc->daios = NULL; 118062306a36Sopenharmony_ci } 118162306a36Sopenharmony_ci 118262306a36Sopenharmony_ci if (atc->pcm) { 118362306a36Sopenharmony_ci sum_mgr = atc->rsc_mgrs[SUM]; 118462306a36Sopenharmony_ci for (i = 0; i < atc->n_pcm; i++) 118562306a36Sopenharmony_ci sum_mgr->put_sum(sum_mgr, atc->pcm[i]); 118662306a36Sopenharmony_ci 118762306a36Sopenharmony_ci kfree(atc->pcm); 118862306a36Sopenharmony_ci atc->pcm = NULL; 118962306a36Sopenharmony_ci } 119062306a36Sopenharmony_ci 119162306a36Sopenharmony_ci if (atc->srcs) { 119262306a36Sopenharmony_ci src_mgr = atc->rsc_mgrs[SRC]; 119362306a36Sopenharmony_ci for (i = 0; i < atc->n_src; i++) 119462306a36Sopenharmony_ci src_mgr->put_src(src_mgr, atc->srcs[i]); 119562306a36Sopenharmony_ci 119662306a36Sopenharmony_ci kfree(atc->srcs); 119762306a36Sopenharmony_ci atc->srcs = NULL; 119862306a36Sopenharmony_ci } 119962306a36Sopenharmony_ci 120062306a36Sopenharmony_ci if (atc->srcimps) { 120162306a36Sopenharmony_ci srcimp_mgr = atc->rsc_mgrs[SRCIMP]; 120262306a36Sopenharmony_ci for (i = 0; i < atc->n_srcimp; i++) { 120362306a36Sopenharmony_ci srcimp = atc->srcimps[i]; 120462306a36Sopenharmony_ci srcimp->ops->unmap(srcimp); 120562306a36Sopenharmony_ci srcimp_mgr->put_srcimp(srcimp_mgr, atc->srcimps[i]); 120662306a36Sopenharmony_ci } 120762306a36Sopenharmony_ci kfree(atc->srcimps); 120862306a36Sopenharmony_ci atc->srcimps = NULL; 120962306a36Sopenharmony_ci } 121062306a36Sopenharmony_ci 121162306a36Sopenharmony_ci return 0; 121262306a36Sopenharmony_ci} 121362306a36Sopenharmony_ci 121462306a36Sopenharmony_cistatic int ct_atc_destroy(struct ct_atc *atc) 121562306a36Sopenharmony_ci{ 121662306a36Sopenharmony_ci int i = 0; 121762306a36Sopenharmony_ci 121862306a36Sopenharmony_ci if (!atc) 121962306a36Sopenharmony_ci return 0; 122062306a36Sopenharmony_ci 122162306a36Sopenharmony_ci if (atc->timer) { 122262306a36Sopenharmony_ci ct_timer_free(atc->timer); 122362306a36Sopenharmony_ci atc->timer = NULL; 122462306a36Sopenharmony_ci } 122562306a36Sopenharmony_ci 122662306a36Sopenharmony_ci atc_release_resources(atc); 122762306a36Sopenharmony_ci 122862306a36Sopenharmony_ci /* Destroy internal mixer objects */ 122962306a36Sopenharmony_ci if (atc->mixer) 123062306a36Sopenharmony_ci ct_mixer_destroy(atc->mixer); 123162306a36Sopenharmony_ci 123262306a36Sopenharmony_ci for (i = 0; i < NUM_RSCTYP; i++) { 123362306a36Sopenharmony_ci if (rsc_mgr_funcs[i].destroy && atc->rsc_mgrs[i]) 123462306a36Sopenharmony_ci rsc_mgr_funcs[i].destroy(atc->rsc_mgrs[i]); 123562306a36Sopenharmony_ci 123662306a36Sopenharmony_ci } 123762306a36Sopenharmony_ci 123862306a36Sopenharmony_ci if (atc->hw) 123962306a36Sopenharmony_ci destroy_hw_obj(atc->hw); 124062306a36Sopenharmony_ci 124162306a36Sopenharmony_ci /* Destroy device virtual memory manager object */ 124262306a36Sopenharmony_ci if (atc->vm) { 124362306a36Sopenharmony_ci ct_vm_destroy(atc->vm); 124462306a36Sopenharmony_ci atc->vm = NULL; 124562306a36Sopenharmony_ci } 124662306a36Sopenharmony_ci 124762306a36Sopenharmony_ci kfree(atc); 124862306a36Sopenharmony_ci 124962306a36Sopenharmony_ci return 0; 125062306a36Sopenharmony_ci} 125162306a36Sopenharmony_ci 125262306a36Sopenharmony_cistatic int atc_dev_free(struct snd_device *dev) 125362306a36Sopenharmony_ci{ 125462306a36Sopenharmony_ci struct ct_atc *atc = dev->device_data; 125562306a36Sopenharmony_ci return ct_atc_destroy(atc); 125662306a36Sopenharmony_ci} 125762306a36Sopenharmony_ci 125862306a36Sopenharmony_cistatic int atc_identify_card(struct ct_atc *atc, unsigned int ssid) 125962306a36Sopenharmony_ci{ 126062306a36Sopenharmony_ci const struct snd_pci_quirk *p; 126162306a36Sopenharmony_ci const struct snd_pci_quirk *list; 126262306a36Sopenharmony_ci u16 vendor_id, device_id; 126362306a36Sopenharmony_ci 126462306a36Sopenharmony_ci switch (atc->chip_type) { 126562306a36Sopenharmony_ci case ATC20K1: 126662306a36Sopenharmony_ci atc->chip_name = "20K1"; 126762306a36Sopenharmony_ci list = subsys_20k1_list; 126862306a36Sopenharmony_ci break; 126962306a36Sopenharmony_ci case ATC20K2: 127062306a36Sopenharmony_ci atc->chip_name = "20K2"; 127162306a36Sopenharmony_ci list = subsys_20k2_list; 127262306a36Sopenharmony_ci break; 127362306a36Sopenharmony_ci default: 127462306a36Sopenharmony_ci return -ENOENT; 127562306a36Sopenharmony_ci } 127662306a36Sopenharmony_ci if (ssid) { 127762306a36Sopenharmony_ci vendor_id = ssid >> 16; 127862306a36Sopenharmony_ci device_id = ssid & 0xffff; 127962306a36Sopenharmony_ci } else { 128062306a36Sopenharmony_ci vendor_id = atc->pci->subsystem_vendor; 128162306a36Sopenharmony_ci device_id = atc->pci->subsystem_device; 128262306a36Sopenharmony_ci } 128362306a36Sopenharmony_ci p = snd_pci_quirk_lookup_id(vendor_id, device_id, list); 128462306a36Sopenharmony_ci if (p) { 128562306a36Sopenharmony_ci if (p->value < 0) { 128662306a36Sopenharmony_ci dev_err(atc->card->dev, 128762306a36Sopenharmony_ci "Device %04x:%04x is on the denylist\n", 128862306a36Sopenharmony_ci vendor_id, device_id); 128962306a36Sopenharmony_ci return -ENOENT; 129062306a36Sopenharmony_ci } 129162306a36Sopenharmony_ci atc->model = p->value; 129262306a36Sopenharmony_ci } else { 129362306a36Sopenharmony_ci if (atc->chip_type == ATC20K1) 129462306a36Sopenharmony_ci atc->model = CT20K1_UNKNOWN; 129562306a36Sopenharmony_ci else 129662306a36Sopenharmony_ci atc->model = CT20K2_UNKNOWN; 129762306a36Sopenharmony_ci } 129862306a36Sopenharmony_ci atc->model_name = ct_subsys_name[atc->model]; 129962306a36Sopenharmony_ci dev_info(atc->card->dev, "chip %s model %s (%04x:%04x) is found\n", 130062306a36Sopenharmony_ci atc->chip_name, atc->model_name, 130162306a36Sopenharmony_ci vendor_id, device_id); 130262306a36Sopenharmony_ci return 0; 130362306a36Sopenharmony_ci} 130462306a36Sopenharmony_ci 130562306a36Sopenharmony_ciint ct_atc_create_alsa_devs(struct ct_atc *atc) 130662306a36Sopenharmony_ci{ 130762306a36Sopenharmony_ci enum CTALSADEVS i; 130862306a36Sopenharmony_ci int err; 130962306a36Sopenharmony_ci 131062306a36Sopenharmony_ci alsa_dev_funcs[MIXER].public_name = atc->chip_name; 131162306a36Sopenharmony_ci 131262306a36Sopenharmony_ci for (i = 0; i < NUM_CTALSADEVS; i++) { 131362306a36Sopenharmony_ci if (!alsa_dev_funcs[i].create) 131462306a36Sopenharmony_ci continue; 131562306a36Sopenharmony_ci 131662306a36Sopenharmony_ci err = alsa_dev_funcs[i].create(atc, i, 131762306a36Sopenharmony_ci alsa_dev_funcs[i].public_name); 131862306a36Sopenharmony_ci if (err) { 131962306a36Sopenharmony_ci dev_err(atc->card->dev, 132062306a36Sopenharmony_ci "Creating alsa device %d failed!\n", i); 132162306a36Sopenharmony_ci return err; 132262306a36Sopenharmony_ci } 132362306a36Sopenharmony_ci } 132462306a36Sopenharmony_ci 132562306a36Sopenharmony_ci return 0; 132662306a36Sopenharmony_ci} 132762306a36Sopenharmony_ci 132862306a36Sopenharmony_cistatic int atc_create_hw_devs(struct ct_atc *atc) 132962306a36Sopenharmony_ci{ 133062306a36Sopenharmony_ci struct hw *hw; 133162306a36Sopenharmony_ci struct card_conf info = {0}; 133262306a36Sopenharmony_ci int i, err; 133362306a36Sopenharmony_ci 133462306a36Sopenharmony_ci err = create_hw_obj(atc->pci, atc->chip_type, atc->model, &hw); 133562306a36Sopenharmony_ci if (err) { 133662306a36Sopenharmony_ci dev_err(atc->card->dev, "Failed to create hw obj!!!\n"); 133762306a36Sopenharmony_ci return err; 133862306a36Sopenharmony_ci } 133962306a36Sopenharmony_ci hw->card = atc->card; 134062306a36Sopenharmony_ci atc->hw = hw; 134162306a36Sopenharmony_ci 134262306a36Sopenharmony_ci /* Initialize card hardware. */ 134362306a36Sopenharmony_ci info.rsr = atc->rsr; 134462306a36Sopenharmony_ci info.msr = atc->msr; 134562306a36Sopenharmony_ci info.vm_pgt_phys = atc_get_ptp_phys(atc, 0); 134662306a36Sopenharmony_ci err = hw->card_init(hw, &info); 134762306a36Sopenharmony_ci if (err < 0) 134862306a36Sopenharmony_ci return err; 134962306a36Sopenharmony_ci 135062306a36Sopenharmony_ci for (i = 0; i < NUM_RSCTYP; i++) { 135162306a36Sopenharmony_ci if (!rsc_mgr_funcs[i].create) 135262306a36Sopenharmony_ci continue; 135362306a36Sopenharmony_ci 135462306a36Sopenharmony_ci err = rsc_mgr_funcs[i].create(atc->hw, &atc->rsc_mgrs[i]); 135562306a36Sopenharmony_ci if (err) { 135662306a36Sopenharmony_ci dev_err(atc->card->dev, 135762306a36Sopenharmony_ci "Failed to create rsc_mgr %d!!!\n", i); 135862306a36Sopenharmony_ci return err; 135962306a36Sopenharmony_ci } 136062306a36Sopenharmony_ci } 136162306a36Sopenharmony_ci 136262306a36Sopenharmony_ci return 0; 136362306a36Sopenharmony_ci} 136462306a36Sopenharmony_ci 136562306a36Sopenharmony_cistatic int atc_get_resources(struct ct_atc *atc) 136662306a36Sopenharmony_ci{ 136762306a36Sopenharmony_ci struct daio_desc da_desc = {0}; 136862306a36Sopenharmony_ci struct daio_mgr *daio_mgr; 136962306a36Sopenharmony_ci struct src_desc src_dsc = {0}; 137062306a36Sopenharmony_ci struct src_mgr *src_mgr; 137162306a36Sopenharmony_ci struct srcimp_desc srcimp_dsc = {0}; 137262306a36Sopenharmony_ci struct srcimp_mgr *srcimp_mgr; 137362306a36Sopenharmony_ci struct sum_desc sum_dsc = {0}; 137462306a36Sopenharmony_ci struct sum_mgr *sum_mgr; 137562306a36Sopenharmony_ci int err, i, num_srcs, num_daios; 137662306a36Sopenharmony_ci 137762306a36Sopenharmony_ci num_daios = ((atc->model == CTSB1270) ? 8 : 7); 137862306a36Sopenharmony_ci num_srcs = ((atc->model == CTSB1270) ? 6 : 4); 137962306a36Sopenharmony_ci 138062306a36Sopenharmony_ci atc->daios = kcalloc(num_daios, sizeof(void *), GFP_KERNEL); 138162306a36Sopenharmony_ci if (!atc->daios) 138262306a36Sopenharmony_ci return -ENOMEM; 138362306a36Sopenharmony_ci 138462306a36Sopenharmony_ci atc->srcs = kcalloc(num_srcs, sizeof(void *), GFP_KERNEL); 138562306a36Sopenharmony_ci if (!atc->srcs) 138662306a36Sopenharmony_ci return -ENOMEM; 138762306a36Sopenharmony_ci 138862306a36Sopenharmony_ci atc->srcimps = kcalloc(num_srcs, sizeof(void *), GFP_KERNEL); 138962306a36Sopenharmony_ci if (!atc->srcimps) 139062306a36Sopenharmony_ci return -ENOMEM; 139162306a36Sopenharmony_ci 139262306a36Sopenharmony_ci atc->pcm = kcalloc(2 * 4, sizeof(void *), GFP_KERNEL); 139362306a36Sopenharmony_ci if (!atc->pcm) 139462306a36Sopenharmony_ci return -ENOMEM; 139562306a36Sopenharmony_ci 139662306a36Sopenharmony_ci daio_mgr = (struct daio_mgr *)atc->rsc_mgrs[DAIO]; 139762306a36Sopenharmony_ci da_desc.msr = atc->msr; 139862306a36Sopenharmony_ci for (i = 0, atc->n_daio = 0; i < num_daios; i++) { 139962306a36Sopenharmony_ci da_desc.type = (atc->model != CTSB073X) ? i : 140062306a36Sopenharmony_ci ((i == SPDIFIO) ? SPDIFI1 : i); 140162306a36Sopenharmony_ci err = daio_mgr->get_daio(daio_mgr, &da_desc, 140262306a36Sopenharmony_ci (struct daio **)&atc->daios[i]); 140362306a36Sopenharmony_ci if (err) { 140462306a36Sopenharmony_ci dev_err(atc->card->dev, 140562306a36Sopenharmony_ci "Failed to get DAIO resource %d!!!\n", 140662306a36Sopenharmony_ci i); 140762306a36Sopenharmony_ci return err; 140862306a36Sopenharmony_ci } 140962306a36Sopenharmony_ci atc->n_daio++; 141062306a36Sopenharmony_ci } 141162306a36Sopenharmony_ci 141262306a36Sopenharmony_ci src_mgr = atc->rsc_mgrs[SRC]; 141362306a36Sopenharmony_ci src_dsc.multi = 1; 141462306a36Sopenharmony_ci src_dsc.msr = atc->msr; 141562306a36Sopenharmony_ci src_dsc.mode = ARCRW; 141662306a36Sopenharmony_ci for (i = 0, atc->n_src = 0; i < num_srcs; i++) { 141762306a36Sopenharmony_ci err = src_mgr->get_src(src_mgr, &src_dsc, 141862306a36Sopenharmony_ci (struct src **)&atc->srcs[i]); 141962306a36Sopenharmony_ci if (err) 142062306a36Sopenharmony_ci return err; 142162306a36Sopenharmony_ci 142262306a36Sopenharmony_ci atc->n_src++; 142362306a36Sopenharmony_ci } 142462306a36Sopenharmony_ci 142562306a36Sopenharmony_ci srcimp_mgr = atc->rsc_mgrs[SRCIMP]; 142662306a36Sopenharmony_ci srcimp_dsc.msr = 8; 142762306a36Sopenharmony_ci for (i = 0, atc->n_srcimp = 0; i < num_srcs; i++) { 142862306a36Sopenharmony_ci err = srcimp_mgr->get_srcimp(srcimp_mgr, &srcimp_dsc, 142962306a36Sopenharmony_ci (struct srcimp **)&atc->srcimps[i]); 143062306a36Sopenharmony_ci if (err) 143162306a36Sopenharmony_ci return err; 143262306a36Sopenharmony_ci 143362306a36Sopenharmony_ci atc->n_srcimp++; 143462306a36Sopenharmony_ci } 143562306a36Sopenharmony_ci 143662306a36Sopenharmony_ci sum_mgr = atc->rsc_mgrs[SUM]; 143762306a36Sopenharmony_ci sum_dsc.msr = atc->msr; 143862306a36Sopenharmony_ci for (i = 0, atc->n_pcm = 0; i < (2*4); i++) { 143962306a36Sopenharmony_ci err = sum_mgr->get_sum(sum_mgr, &sum_dsc, 144062306a36Sopenharmony_ci (struct sum **)&atc->pcm[i]); 144162306a36Sopenharmony_ci if (err) 144262306a36Sopenharmony_ci return err; 144362306a36Sopenharmony_ci 144462306a36Sopenharmony_ci atc->n_pcm++; 144562306a36Sopenharmony_ci } 144662306a36Sopenharmony_ci 144762306a36Sopenharmony_ci return 0; 144862306a36Sopenharmony_ci} 144962306a36Sopenharmony_ci 145062306a36Sopenharmony_cistatic void 145162306a36Sopenharmony_ciatc_connect_dai(struct src_mgr *src_mgr, struct dai *dai, 145262306a36Sopenharmony_ci struct src **srcs, struct srcimp **srcimps) 145362306a36Sopenharmony_ci{ 145462306a36Sopenharmony_ci struct rsc *rscs[2] = {NULL}; 145562306a36Sopenharmony_ci struct src *src; 145662306a36Sopenharmony_ci struct srcimp *srcimp; 145762306a36Sopenharmony_ci int i = 0; 145862306a36Sopenharmony_ci 145962306a36Sopenharmony_ci rscs[0] = &dai->daio.rscl; 146062306a36Sopenharmony_ci rscs[1] = &dai->daio.rscr; 146162306a36Sopenharmony_ci for (i = 0; i < 2; i++) { 146262306a36Sopenharmony_ci src = srcs[i]; 146362306a36Sopenharmony_ci srcimp = srcimps[i]; 146462306a36Sopenharmony_ci srcimp->ops->map(srcimp, src, rscs[i]); 146562306a36Sopenharmony_ci src_mgr->src_disable(src_mgr, src); 146662306a36Sopenharmony_ci } 146762306a36Sopenharmony_ci 146862306a36Sopenharmony_ci src_mgr->commit_write(src_mgr); /* Actually disable SRCs */ 146962306a36Sopenharmony_ci 147062306a36Sopenharmony_ci src = srcs[0]; 147162306a36Sopenharmony_ci src->ops->set_pm(src, 1); 147262306a36Sopenharmony_ci for (i = 0; i < 2; i++) { 147362306a36Sopenharmony_ci src = srcs[i]; 147462306a36Sopenharmony_ci src->ops->set_state(src, SRC_STATE_RUN); 147562306a36Sopenharmony_ci src->ops->commit_write(src); 147662306a36Sopenharmony_ci src_mgr->src_enable_s(src_mgr, src); 147762306a36Sopenharmony_ci } 147862306a36Sopenharmony_ci 147962306a36Sopenharmony_ci dai->ops->set_srt_srcl(dai, &(srcs[0]->rsc)); 148062306a36Sopenharmony_ci dai->ops->set_srt_srcr(dai, &(srcs[1]->rsc)); 148162306a36Sopenharmony_ci 148262306a36Sopenharmony_ci dai->ops->set_enb_src(dai, 1); 148362306a36Sopenharmony_ci dai->ops->set_enb_srt(dai, 1); 148462306a36Sopenharmony_ci dai->ops->commit_write(dai); 148562306a36Sopenharmony_ci 148662306a36Sopenharmony_ci src_mgr->commit_write(src_mgr); /* Synchronously enable SRCs */ 148762306a36Sopenharmony_ci} 148862306a36Sopenharmony_ci 148962306a36Sopenharmony_cistatic void atc_connect_resources(struct ct_atc *atc) 149062306a36Sopenharmony_ci{ 149162306a36Sopenharmony_ci struct dai *dai; 149262306a36Sopenharmony_ci struct dao *dao; 149362306a36Sopenharmony_ci struct src *src; 149462306a36Sopenharmony_ci struct sum *sum; 149562306a36Sopenharmony_ci struct ct_mixer *mixer; 149662306a36Sopenharmony_ci struct rsc *rscs[2] = {NULL}; 149762306a36Sopenharmony_ci int i, j; 149862306a36Sopenharmony_ci 149962306a36Sopenharmony_ci mixer = atc->mixer; 150062306a36Sopenharmony_ci 150162306a36Sopenharmony_ci for (i = MIX_WAVE_FRONT, j = LINEO1; i <= MIX_SPDIF_OUT; i++, j++) { 150262306a36Sopenharmony_ci mixer->get_output_ports(mixer, i, &rscs[0], &rscs[1]); 150362306a36Sopenharmony_ci dao = container_of(atc->daios[j], struct dao, daio); 150462306a36Sopenharmony_ci dao->ops->set_left_input(dao, rscs[0]); 150562306a36Sopenharmony_ci dao->ops->set_right_input(dao, rscs[1]); 150662306a36Sopenharmony_ci } 150762306a36Sopenharmony_ci 150862306a36Sopenharmony_ci dai = container_of(atc->daios[LINEIM], struct dai, daio); 150962306a36Sopenharmony_ci atc_connect_dai(atc->rsc_mgrs[SRC], dai, 151062306a36Sopenharmony_ci (struct src **)&atc->srcs[2], 151162306a36Sopenharmony_ci (struct srcimp **)&atc->srcimps[2]); 151262306a36Sopenharmony_ci src = atc->srcs[2]; 151362306a36Sopenharmony_ci mixer->set_input_left(mixer, MIX_LINE_IN, &src->rsc); 151462306a36Sopenharmony_ci src = atc->srcs[3]; 151562306a36Sopenharmony_ci mixer->set_input_right(mixer, MIX_LINE_IN, &src->rsc); 151662306a36Sopenharmony_ci 151762306a36Sopenharmony_ci if (atc->model == CTSB1270) { 151862306a36Sopenharmony_ci /* Titanium HD has a dedicated ADC for the Mic. */ 151962306a36Sopenharmony_ci dai = container_of(atc->daios[MIC], struct dai, daio); 152062306a36Sopenharmony_ci atc_connect_dai(atc->rsc_mgrs[SRC], dai, 152162306a36Sopenharmony_ci (struct src **)&atc->srcs[4], 152262306a36Sopenharmony_ci (struct srcimp **)&atc->srcimps[4]); 152362306a36Sopenharmony_ci src = atc->srcs[4]; 152462306a36Sopenharmony_ci mixer->set_input_left(mixer, MIX_MIC_IN, &src->rsc); 152562306a36Sopenharmony_ci src = atc->srcs[5]; 152662306a36Sopenharmony_ci mixer->set_input_right(mixer, MIX_MIC_IN, &src->rsc); 152762306a36Sopenharmony_ci } 152862306a36Sopenharmony_ci 152962306a36Sopenharmony_ci dai = container_of(atc->daios[SPDIFIO], struct dai, daio); 153062306a36Sopenharmony_ci atc_connect_dai(atc->rsc_mgrs[SRC], dai, 153162306a36Sopenharmony_ci (struct src **)&atc->srcs[0], 153262306a36Sopenharmony_ci (struct srcimp **)&atc->srcimps[0]); 153362306a36Sopenharmony_ci 153462306a36Sopenharmony_ci src = atc->srcs[0]; 153562306a36Sopenharmony_ci mixer->set_input_left(mixer, MIX_SPDIF_IN, &src->rsc); 153662306a36Sopenharmony_ci src = atc->srcs[1]; 153762306a36Sopenharmony_ci mixer->set_input_right(mixer, MIX_SPDIF_IN, &src->rsc); 153862306a36Sopenharmony_ci 153962306a36Sopenharmony_ci for (i = MIX_PCMI_FRONT, j = 0; i <= MIX_PCMI_SURROUND; i++, j += 2) { 154062306a36Sopenharmony_ci sum = atc->pcm[j]; 154162306a36Sopenharmony_ci mixer->set_input_left(mixer, i, &sum->rsc); 154262306a36Sopenharmony_ci sum = atc->pcm[j+1]; 154362306a36Sopenharmony_ci mixer->set_input_right(mixer, i, &sum->rsc); 154462306a36Sopenharmony_ci } 154562306a36Sopenharmony_ci} 154662306a36Sopenharmony_ci 154762306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 154862306a36Sopenharmony_cistatic int atc_suspend(struct ct_atc *atc) 154962306a36Sopenharmony_ci{ 155062306a36Sopenharmony_ci struct hw *hw = atc->hw; 155162306a36Sopenharmony_ci 155262306a36Sopenharmony_ci snd_power_change_state(atc->card, SNDRV_CTL_POWER_D3hot); 155362306a36Sopenharmony_ci 155462306a36Sopenharmony_ci atc_release_resources(atc); 155562306a36Sopenharmony_ci 155662306a36Sopenharmony_ci hw->suspend(hw); 155762306a36Sopenharmony_ci 155862306a36Sopenharmony_ci return 0; 155962306a36Sopenharmony_ci} 156062306a36Sopenharmony_ci 156162306a36Sopenharmony_cistatic int atc_hw_resume(struct ct_atc *atc) 156262306a36Sopenharmony_ci{ 156362306a36Sopenharmony_ci struct hw *hw = atc->hw; 156462306a36Sopenharmony_ci struct card_conf info = {0}; 156562306a36Sopenharmony_ci 156662306a36Sopenharmony_ci /* Re-initialize card hardware. */ 156762306a36Sopenharmony_ci info.rsr = atc->rsr; 156862306a36Sopenharmony_ci info.msr = atc->msr; 156962306a36Sopenharmony_ci info.vm_pgt_phys = atc_get_ptp_phys(atc, 0); 157062306a36Sopenharmony_ci return hw->resume(hw, &info); 157162306a36Sopenharmony_ci} 157262306a36Sopenharmony_ci 157362306a36Sopenharmony_cistatic int atc_resources_resume(struct ct_atc *atc) 157462306a36Sopenharmony_ci{ 157562306a36Sopenharmony_ci struct ct_mixer *mixer; 157662306a36Sopenharmony_ci int err = 0; 157762306a36Sopenharmony_ci 157862306a36Sopenharmony_ci /* Get resources */ 157962306a36Sopenharmony_ci err = atc_get_resources(atc); 158062306a36Sopenharmony_ci if (err < 0) { 158162306a36Sopenharmony_ci atc_release_resources(atc); 158262306a36Sopenharmony_ci return err; 158362306a36Sopenharmony_ci } 158462306a36Sopenharmony_ci 158562306a36Sopenharmony_ci /* Build topology */ 158662306a36Sopenharmony_ci atc_connect_resources(atc); 158762306a36Sopenharmony_ci 158862306a36Sopenharmony_ci mixer = atc->mixer; 158962306a36Sopenharmony_ci mixer->resume(mixer); 159062306a36Sopenharmony_ci 159162306a36Sopenharmony_ci return 0; 159262306a36Sopenharmony_ci} 159362306a36Sopenharmony_ci 159462306a36Sopenharmony_cistatic int atc_resume(struct ct_atc *atc) 159562306a36Sopenharmony_ci{ 159662306a36Sopenharmony_ci int err = 0; 159762306a36Sopenharmony_ci 159862306a36Sopenharmony_ci /* Do hardware resume. */ 159962306a36Sopenharmony_ci err = atc_hw_resume(atc); 160062306a36Sopenharmony_ci if (err < 0) { 160162306a36Sopenharmony_ci dev_err(atc->card->dev, 160262306a36Sopenharmony_ci "pci_enable_device failed, disabling device\n"); 160362306a36Sopenharmony_ci snd_card_disconnect(atc->card); 160462306a36Sopenharmony_ci return err; 160562306a36Sopenharmony_ci } 160662306a36Sopenharmony_ci 160762306a36Sopenharmony_ci err = atc_resources_resume(atc); 160862306a36Sopenharmony_ci if (err < 0) 160962306a36Sopenharmony_ci return err; 161062306a36Sopenharmony_ci 161162306a36Sopenharmony_ci snd_power_change_state(atc->card, SNDRV_CTL_POWER_D0); 161262306a36Sopenharmony_ci 161362306a36Sopenharmony_ci return 0; 161462306a36Sopenharmony_ci} 161562306a36Sopenharmony_ci#endif 161662306a36Sopenharmony_ci 161762306a36Sopenharmony_cistatic const struct ct_atc atc_preset = { 161862306a36Sopenharmony_ci .map_audio_buffer = ct_map_audio_buffer, 161962306a36Sopenharmony_ci .unmap_audio_buffer = ct_unmap_audio_buffer, 162062306a36Sopenharmony_ci .pcm_playback_prepare = atc_pcm_playback_prepare, 162162306a36Sopenharmony_ci .pcm_release_resources = atc_pcm_release_resources, 162262306a36Sopenharmony_ci .pcm_playback_start = atc_pcm_playback_start, 162362306a36Sopenharmony_ci .pcm_playback_stop = atc_pcm_stop, 162462306a36Sopenharmony_ci .pcm_playback_position = atc_pcm_playback_position, 162562306a36Sopenharmony_ci .pcm_capture_prepare = atc_pcm_capture_prepare, 162662306a36Sopenharmony_ci .pcm_capture_start = atc_pcm_capture_start, 162762306a36Sopenharmony_ci .pcm_capture_stop = atc_pcm_stop, 162862306a36Sopenharmony_ci .pcm_capture_position = atc_pcm_capture_position, 162962306a36Sopenharmony_ci .spdif_passthru_playback_prepare = spdif_passthru_playback_prepare, 163062306a36Sopenharmony_ci .get_ptp_phys = atc_get_ptp_phys, 163162306a36Sopenharmony_ci .select_line_in = atc_select_line_in, 163262306a36Sopenharmony_ci .select_mic_in = atc_select_mic_in, 163362306a36Sopenharmony_ci .select_digit_io = atc_select_digit_io, 163462306a36Sopenharmony_ci .line_front_unmute = atc_line_front_unmute, 163562306a36Sopenharmony_ci .line_surround_unmute = atc_line_surround_unmute, 163662306a36Sopenharmony_ci .line_clfe_unmute = atc_line_clfe_unmute, 163762306a36Sopenharmony_ci .line_rear_unmute = atc_line_rear_unmute, 163862306a36Sopenharmony_ci .line_in_unmute = atc_line_in_unmute, 163962306a36Sopenharmony_ci .mic_unmute = atc_mic_unmute, 164062306a36Sopenharmony_ci .spdif_out_unmute = atc_spdif_out_unmute, 164162306a36Sopenharmony_ci .spdif_in_unmute = atc_spdif_in_unmute, 164262306a36Sopenharmony_ci .spdif_out_get_status = atc_spdif_out_get_status, 164362306a36Sopenharmony_ci .spdif_out_set_status = atc_spdif_out_set_status, 164462306a36Sopenharmony_ci .spdif_out_passthru = atc_spdif_out_passthru, 164562306a36Sopenharmony_ci .capabilities = atc_capabilities, 164662306a36Sopenharmony_ci .output_switch_get = atc_output_switch_get, 164762306a36Sopenharmony_ci .output_switch_put = atc_output_switch_put, 164862306a36Sopenharmony_ci .mic_source_switch_get = atc_mic_source_switch_get, 164962306a36Sopenharmony_ci .mic_source_switch_put = atc_mic_source_switch_put, 165062306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 165162306a36Sopenharmony_ci .suspend = atc_suspend, 165262306a36Sopenharmony_ci .resume = atc_resume, 165362306a36Sopenharmony_ci#endif 165462306a36Sopenharmony_ci}; 165562306a36Sopenharmony_ci 165662306a36Sopenharmony_ci/** 165762306a36Sopenharmony_ci * ct_atc_create - create and initialize a hardware manager 165862306a36Sopenharmony_ci * @card: corresponding alsa card object 165962306a36Sopenharmony_ci * @pci: corresponding kernel pci device object 166062306a36Sopenharmony_ci * @rsr: reference sampling rate 166162306a36Sopenharmony_ci * @msr: master sampling rate 166262306a36Sopenharmony_ci * @chip_type: CHIPTYP enum values 166362306a36Sopenharmony_ci * @ssid: vendor ID (upper 16 bits) and device ID (lower 16 bits) 166462306a36Sopenharmony_ci * @ratc: return created object address in it 166562306a36Sopenharmony_ci * 166662306a36Sopenharmony_ci * Creates and initializes a hardware manager. 166762306a36Sopenharmony_ci * 166862306a36Sopenharmony_ci * Creates kmallocated ct_atc structure. Initializes hardware. 166962306a36Sopenharmony_ci * Returns 0 if succeeds, or negative error code if fails. 167062306a36Sopenharmony_ci */ 167162306a36Sopenharmony_ci 167262306a36Sopenharmony_ciint ct_atc_create(struct snd_card *card, struct pci_dev *pci, 167362306a36Sopenharmony_ci unsigned int rsr, unsigned int msr, 167462306a36Sopenharmony_ci int chip_type, unsigned int ssid, 167562306a36Sopenharmony_ci struct ct_atc **ratc) 167662306a36Sopenharmony_ci{ 167762306a36Sopenharmony_ci struct ct_atc *atc; 167862306a36Sopenharmony_ci static const struct snd_device_ops ops = { 167962306a36Sopenharmony_ci .dev_free = atc_dev_free, 168062306a36Sopenharmony_ci }; 168162306a36Sopenharmony_ci int err; 168262306a36Sopenharmony_ci 168362306a36Sopenharmony_ci *ratc = NULL; 168462306a36Sopenharmony_ci 168562306a36Sopenharmony_ci atc = kzalloc(sizeof(*atc), GFP_KERNEL); 168662306a36Sopenharmony_ci if (!atc) 168762306a36Sopenharmony_ci return -ENOMEM; 168862306a36Sopenharmony_ci 168962306a36Sopenharmony_ci /* Set operations */ 169062306a36Sopenharmony_ci *atc = atc_preset; 169162306a36Sopenharmony_ci 169262306a36Sopenharmony_ci atc->card = card; 169362306a36Sopenharmony_ci atc->pci = pci; 169462306a36Sopenharmony_ci atc->rsr = rsr; 169562306a36Sopenharmony_ci atc->msr = msr; 169662306a36Sopenharmony_ci atc->chip_type = chip_type; 169762306a36Sopenharmony_ci 169862306a36Sopenharmony_ci mutex_init(&atc->atc_mutex); 169962306a36Sopenharmony_ci 170062306a36Sopenharmony_ci /* Find card model */ 170162306a36Sopenharmony_ci err = atc_identify_card(atc, ssid); 170262306a36Sopenharmony_ci if (err < 0) { 170362306a36Sopenharmony_ci dev_err(card->dev, "ctatc: Card not recognised\n"); 170462306a36Sopenharmony_ci goto error1; 170562306a36Sopenharmony_ci } 170662306a36Sopenharmony_ci 170762306a36Sopenharmony_ci /* Set up device virtual memory management object */ 170862306a36Sopenharmony_ci err = ct_vm_create(&atc->vm, pci); 170962306a36Sopenharmony_ci if (err < 0) 171062306a36Sopenharmony_ci goto error1; 171162306a36Sopenharmony_ci 171262306a36Sopenharmony_ci /* Create all atc hw devices */ 171362306a36Sopenharmony_ci err = atc_create_hw_devs(atc); 171462306a36Sopenharmony_ci if (err < 0) 171562306a36Sopenharmony_ci goto error1; 171662306a36Sopenharmony_ci 171762306a36Sopenharmony_ci err = ct_mixer_create(atc, (struct ct_mixer **)&atc->mixer); 171862306a36Sopenharmony_ci if (err) { 171962306a36Sopenharmony_ci dev_err(card->dev, "Failed to create mixer obj!!!\n"); 172062306a36Sopenharmony_ci goto error1; 172162306a36Sopenharmony_ci } 172262306a36Sopenharmony_ci 172362306a36Sopenharmony_ci /* Get resources */ 172462306a36Sopenharmony_ci err = atc_get_resources(atc); 172562306a36Sopenharmony_ci if (err < 0) 172662306a36Sopenharmony_ci goto error1; 172762306a36Sopenharmony_ci 172862306a36Sopenharmony_ci /* Build topology */ 172962306a36Sopenharmony_ci atc_connect_resources(atc); 173062306a36Sopenharmony_ci 173162306a36Sopenharmony_ci atc->timer = ct_timer_new(atc); 173262306a36Sopenharmony_ci if (!atc->timer) { 173362306a36Sopenharmony_ci err = -ENOMEM; 173462306a36Sopenharmony_ci goto error1; 173562306a36Sopenharmony_ci } 173662306a36Sopenharmony_ci 173762306a36Sopenharmony_ci err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, atc, &ops); 173862306a36Sopenharmony_ci if (err < 0) 173962306a36Sopenharmony_ci goto error1; 174062306a36Sopenharmony_ci 174162306a36Sopenharmony_ci *ratc = atc; 174262306a36Sopenharmony_ci return 0; 174362306a36Sopenharmony_ci 174462306a36Sopenharmony_cierror1: 174562306a36Sopenharmony_ci ct_atc_destroy(atc); 174662306a36Sopenharmony_ci dev_err(card->dev, "Something wrong!!!\n"); 174762306a36Sopenharmony_ci return err; 174862306a36Sopenharmony_ci} 1749