18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/** 38c2ecf20Sopenharmony_ci * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * @File ctatc.c 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * @Brief 88c2ecf20Sopenharmony_ci * This file contains the implementation of the device resource management 98c2ecf20Sopenharmony_ci * object. 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * @Author Liu Chun 128c2ecf20Sopenharmony_ci * @Date Mar 28 2008 138c2ecf20Sopenharmony_ci */ 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include "ctatc.h" 168c2ecf20Sopenharmony_ci#include "ctpcm.h" 178c2ecf20Sopenharmony_ci#include "ctmixer.h" 188c2ecf20Sopenharmony_ci#include "ctsrc.h" 198c2ecf20Sopenharmony_ci#include "ctamixer.h" 208c2ecf20Sopenharmony_ci#include "ctdaio.h" 218c2ecf20Sopenharmony_ci#include "cttimer.h" 228c2ecf20Sopenharmony_ci#include <linux/delay.h> 238c2ecf20Sopenharmony_ci#include <linux/slab.h> 248c2ecf20Sopenharmony_ci#include <sound/pcm.h> 258c2ecf20Sopenharmony_ci#include <sound/control.h> 268c2ecf20Sopenharmony_ci#include <sound/asoundef.h> 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#define MONO_SUM_SCALE 0x19a8 /* 2^(-0.5) in 14-bit floating format */ 298c2ecf20Sopenharmony_ci#define MAX_MULTI_CHN 8 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#define IEC958_DEFAULT_CON ((IEC958_AES0_NONAUDIO \ 328c2ecf20Sopenharmony_ci | IEC958_AES0_CON_NOT_COPYRIGHT) \ 338c2ecf20Sopenharmony_ci | ((IEC958_AES1_CON_MIXER \ 348c2ecf20Sopenharmony_ci | IEC958_AES1_CON_ORIGINAL) << 8) \ 358c2ecf20Sopenharmony_ci | (0x10 << 16) \ 368c2ecf20Sopenharmony_ci | ((IEC958_AES3_CON_FS_48000) << 24)) 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_cistatic const struct snd_pci_quirk subsys_20k1_list[] = { 398c2ecf20Sopenharmony_ci SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, 0x0021, "SB046x", CTSB046X), 408c2ecf20Sopenharmony_ci SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, 0x0022, "SB055x", CTSB055X), 418c2ecf20Sopenharmony_ci SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, 0x002f, "SB055x", CTSB055X), 428c2ecf20Sopenharmony_ci SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, 0x0029, "SB073x", CTSB073X), 438c2ecf20Sopenharmony_ci SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, 0x0031, "SB073x", CTSB073X), 448c2ecf20Sopenharmony_ci SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_CREATIVE, 0xf000, 0x6000, 458c2ecf20Sopenharmony_ci "UAA", CTUAA), 468c2ecf20Sopenharmony_ci { } /* terminator */ 478c2ecf20Sopenharmony_ci}; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_cistatic const struct snd_pci_quirk subsys_20k2_list[] = { 508c2ecf20Sopenharmony_ci SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB0760, 518c2ecf20Sopenharmony_ci "SB0760", CTSB0760), 528c2ecf20Sopenharmony_ci SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB1270, 538c2ecf20Sopenharmony_ci "SB1270", CTSB1270), 548c2ecf20Sopenharmony_ci SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB08801, 558c2ecf20Sopenharmony_ci "SB0880", CTSB0880), 568c2ecf20Sopenharmony_ci SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB08802, 578c2ecf20Sopenharmony_ci "SB0880", CTSB0880), 588c2ecf20Sopenharmony_ci SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB08803, 598c2ecf20Sopenharmony_ci "SB0880", CTSB0880), 608c2ecf20Sopenharmony_ci SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_CREATIVE, 0xf000, 618c2ecf20Sopenharmony_ci PCI_SUBDEVICE_ID_CREATIVE_HENDRIX, "HENDRIX", 628c2ecf20Sopenharmony_ci CTHENDRIX), 638c2ecf20Sopenharmony_ci { } /* terminator */ 648c2ecf20Sopenharmony_ci}; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_cistatic const char *ct_subsys_name[NUM_CTCARDS] = { 678c2ecf20Sopenharmony_ci /* 20k1 models */ 688c2ecf20Sopenharmony_ci [CTSB046X] = "SB046x", 698c2ecf20Sopenharmony_ci [CTSB055X] = "SB055x", 708c2ecf20Sopenharmony_ci [CTSB073X] = "SB073x", 718c2ecf20Sopenharmony_ci [CTUAA] = "UAA", 728c2ecf20Sopenharmony_ci [CT20K1_UNKNOWN] = "Unknown", 738c2ecf20Sopenharmony_ci /* 20k2 models */ 748c2ecf20Sopenharmony_ci [CTSB0760] = "SB076x", 758c2ecf20Sopenharmony_ci [CTHENDRIX] = "Hendrix", 768c2ecf20Sopenharmony_ci [CTSB0880] = "SB0880", 778c2ecf20Sopenharmony_ci [CTSB1270] = "SB1270", 788c2ecf20Sopenharmony_ci [CT20K2_UNKNOWN] = "Unknown", 798c2ecf20Sopenharmony_ci}; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_cistatic struct { 828c2ecf20Sopenharmony_ci int (*create)(struct ct_atc *atc, 838c2ecf20Sopenharmony_ci enum CTALSADEVS device, const char *device_name); 848c2ecf20Sopenharmony_ci int (*destroy)(void *alsa_dev); 858c2ecf20Sopenharmony_ci const char *public_name; 868c2ecf20Sopenharmony_ci} alsa_dev_funcs[NUM_CTALSADEVS] = { 878c2ecf20Sopenharmony_ci [FRONT] = { .create = ct_alsa_pcm_create, 888c2ecf20Sopenharmony_ci .destroy = NULL, 898c2ecf20Sopenharmony_ci .public_name = "Front/WaveIn"}, 908c2ecf20Sopenharmony_ci [SURROUND] = { .create = ct_alsa_pcm_create, 918c2ecf20Sopenharmony_ci .destroy = NULL, 928c2ecf20Sopenharmony_ci .public_name = "Surround"}, 938c2ecf20Sopenharmony_ci [CLFE] = { .create = ct_alsa_pcm_create, 948c2ecf20Sopenharmony_ci .destroy = NULL, 958c2ecf20Sopenharmony_ci .public_name = "Center/LFE"}, 968c2ecf20Sopenharmony_ci [SIDE] = { .create = ct_alsa_pcm_create, 978c2ecf20Sopenharmony_ci .destroy = NULL, 988c2ecf20Sopenharmony_ci .public_name = "Side"}, 998c2ecf20Sopenharmony_ci [IEC958] = { .create = ct_alsa_pcm_create, 1008c2ecf20Sopenharmony_ci .destroy = NULL, 1018c2ecf20Sopenharmony_ci .public_name = "IEC958 Non-audio"}, 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci [MIXER] = { .create = ct_alsa_mix_create, 1048c2ecf20Sopenharmony_ci .destroy = NULL, 1058c2ecf20Sopenharmony_ci .public_name = "Mixer"} 1068c2ecf20Sopenharmony_ci}; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_citypedef int (*create_t)(struct hw *, void **); 1098c2ecf20Sopenharmony_citypedef int (*destroy_t)(void *); 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_cistatic struct { 1128c2ecf20Sopenharmony_ci int (*create)(struct hw *hw, void **rmgr); 1138c2ecf20Sopenharmony_ci int (*destroy)(void *mgr); 1148c2ecf20Sopenharmony_ci} rsc_mgr_funcs[NUM_RSCTYP] = { 1158c2ecf20Sopenharmony_ci [SRC] = { .create = (create_t)src_mgr_create, 1168c2ecf20Sopenharmony_ci .destroy = (destroy_t)src_mgr_destroy }, 1178c2ecf20Sopenharmony_ci [SRCIMP] = { .create = (create_t)srcimp_mgr_create, 1188c2ecf20Sopenharmony_ci .destroy = (destroy_t)srcimp_mgr_destroy }, 1198c2ecf20Sopenharmony_ci [AMIXER] = { .create = (create_t)amixer_mgr_create, 1208c2ecf20Sopenharmony_ci .destroy = (destroy_t)amixer_mgr_destroy }, 1218c2ecf20Sopenharmony_ci [SUM] = { .create = (create_t)sum_mgr_create, 1228c2ecf20Sopenharmony_ci .destroy = (destroy_t)sum_mgr_destroy }, 1238c2ecf20Sopenharmony_ci [DAIO] = { .create = (create_t)daio_mgr_create, 1248c2ecf20Sopenharmony_ci .destroy = (destroy_t)daio_mgr_destroy } 1258c2ecf20Sopenharmony_ci}; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_cistatic int 1288c2ecf20Sopenharmony_ciatc_pcm_release_resources(struct ct_atc *atc, struct ct_atc_pcm *apcm); 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci/* * 1318c2ecf20Sopenharmony_ci * Only mono and interleaved modes are supported now. 1328c2ecf20Sopenharmony_ci * Always allocates a contiguous channel block. 1338c2ecf20Sopenharmony_ci * */ 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_cistatic int ct_map_audio_buffer(struct ct_atc *atc, struct ct_atc_pcm *apcm) 1368c2ecf20Sopenharmony_ci{ 1378c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime; 1388c2ecf20Sopenharmony_ci struct ct_vm *vm; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci if (!apcm->substream) 1418c2ecf20Sopenharmony_ci return 0; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci runtime = apcm->substream->runtime; 1448c2ecf20Sopenharmony_ci vm = atc->vm; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci apcm->vm_block = vm->map(vm, apcm->substream, runtime->dma_bytes); 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci if (!apcm->vm_block) 1498c2ecf20Sopenharmony_ci return -ENOENT; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci return 0; 1528c2ecf20Sopenharmony_ci} 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_cistatic void ct_unmap_audio_buffer(struct ct_atc *atc, struct ct_atc_pcm *apcm) 1558c2ecf20Sopenharmony_ci{ 1568c2ecf20Sopenharmony_ci struct ct_vm *vm; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci if (!apcm->vm_block) 1598c2ecf20Sopenharmony_ci return; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci vm = atc->vm; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci vm->unmap(vm, apcm->vm_block); 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci apcm->vm_block = NULL; 1668c2ecf20Sopenharmony_ci} 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_cistatic unsigned long atc_get_ptp_phys(struct ct_atc *atc, int index) 1698c2ecf20Sopenharmony_ci{ 1708c2ecf20Sopenharmony_ci return atc->vm->get_ptp_phys(atc->vm, index); 1718c2ecf20Sopenharmony_ci} 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_cistatic unsigned int convert_format(snd_pcm_format_t snd_format, 1748c2ecf20Sopenharmony_ci struct snd_card *card) 1758c2ecf20Sopenharmony_ci{ 1768c2ecf20Sopenharmony_ci switch (snd_format) { 1778c2ecf20Sopenharmony_ci case SNDRV_PCM_FORMAT_U8: 1788c2ecf20Sopenharmony_ci return SRC_SF_U8; 1798c2ecf20Sopenharmony_ci case SNDRV_PCM_FORMAT_S16_LE: 1808c2ecf20Sopenharmony_ci return SRC_SF_S16; 1818c2ecf20Sopenharmony_ci case SNDRV_PCM_FORMAT_S24_3LE: 1828c2ecf20Sopenharmony_ci return SRC_SF_S24; 1838c2ecf20Sopenharmony_ci case SNDRV_PCM_FORMAT_S32_LE: 1848c2ecf20Sopenharmony_ci return SRC_SF_S32; 1858c2ecf20Sopenharmony_ci case SNDRV_PCM_FORMAT_FLOAT_LE: 1868c2ecf20Sopenharmony_ci return SRC_SF_F32; 1878c2ecf20Sopenharmony_ci default: 1888c2ecf20Sopenharmony_ci dev_err(card->dev, "not recognized snd format is %d\n", 1898c2ecf20Sopenharmony_ci snd_format); 1908c2ecf20Sopenharmony_ci return SRC_SF_S16; 1918c2ecf20Sopenharmony_ci } 1928c2ecf20Sopenharmony_ci} 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_cistatic unsigned int 1958c2ecf20Sopenharmony_ciatc_get_pitch(unsigned int input_rate, unsigned int output_rate) 1968c2ecf20Sopenharmony_ci{ 1978c2ecf20Sopenharmony_ci unsigned int pitch; 1988c2ecf20Sopenharmony_ci int b; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci /* get pitch and convert to fixed-point 8.24 format. */ 2018c2ecf20Sopenharmony_ci pitch = (input_rate / output_rate) << 24; 2028c2ecf20Sopenharmony_ci input_rate %= output_rate; 2038c2ecf20Sopenharmony_ci input_rate /= 100; 2048c2ecf20Sopenharmony_ci output_rate /= 100; 2058c2ecf20Sopenharmony_ci for (b = 31; ((b >= 0) && !(input_rate >> b)); ) 2068c2ecf20Sopenharmony_ci b--; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci if (b >= 0) { 2098c2ecf20Sopenharmony_ci input_rate <<= (31 - b); 2108c2ecf20Sopenharmony_ci input_rate /= output_rate; 2118c2ecf20Sopenharmony_ci b = 24 - (31 - b); 2128c2ecf20Sopenharmony_ci if (b >= 0) 2138c2ecf20Sopenharmony_ci input_rate <<= b; 2148c2ecf20Sopenharmony_ci else 2158c2ecf20Sopenharmony_ci input_rate >>= -b; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci pitch |= input_rate; 2188c2ecf20Sopenharmony_ci } 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci return pitch; 2218c2ecf20Sopenharmony_ci} 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_cistatic int select_rom(unsigned int pitch) 2248c2ecf20Sopenharmony_ci{ 2258c2ecf20Sopenharmony_ci if (pitch > 0x00428f5c && pitch < 0x01b851ec) { 2268c2ecf20Sopenharmony_ci /* 0.26 <= pitch <= 1.72 */ 2278c2ecf20Sopenharmony_ci return 1; 2288c2ecf20Sopenharmony_ci } else if (pitch == 0x01d66666 || pitch == 0x01d66667) { 2298c2ecf20Sopenharmony_ci /* pitch == 1.8375 */ 2308c2ecf20Sopenharmony_ci return 2; 2318c2ecf20Sopenharmony_ci } else if (pitch == 0x02000000) { 2328c2ecf20Sopenharmony_ci /* pitch == 2 */ 2338c2ecf20Sopenharmony_ci return 3; 2348c2ecf20Sopenharmony_ci } else if (pitch <= 0x08000000) { 2358c2ecf20Sopenharmony_ci /* 0 <= pitch <= 8 */ 2368c2ecf20Sopenharmony_ci return 0; 2378c2ecf20Sopenharmony_ci } else { 2388c2ecf20Sopenharmony_ci return -ENOENT; 2398c2ecf20Sopenharmony_ci } 2408c2ecf20Sopenharmony_ci} 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_cistatic int atc_pcm_playback_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm) 2438c2ecf20Sopenharmony_ci{ 2448c2ecf20Sopenharmony_ci struct src_mgr *src_mgr = atc->rsc_mgrs[SRC]; 2458c2ecf20Sopenharmony_ci struct amixer_mgr *amixer_mgr = atc->rsc_mgrs[AMIXER]; 2468c2ecf20Sopenharmony_ci struct src_desc desc = {0}; 2478c2ecf20Sopenharmony_ci struct amixer_desc mix_dsc = {0}; 2488c2ecf20Sopenharmony_ci struct src *src; 2498c2ecf20Sopenharmony_ci struct amixer *amixer; 2508c2ecf20Sopenharmony_ci int err; 2518c2ecf20Sopenharmony_ci int n_amixer = apcm->substream->runtime->channels, i = 0; 2528c2ecf20Sopenharmony_ci int device = apcm->substream->pcm->device; 2538c2ecf20Sopenharmony_ci unsigned int pitch; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci /* first release old resources */ 2568c2ecf20Sopenharmony_ci atc_pcm_release_resources(atc, apcm); 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci /* Get SRC resource */ 2598c2ecf20Sopenharmony_ci desc.multi = apcm->substream->runtime->channels; 2608c2ecf20Sopenharmony_ci desc.msr = atc->msr; 2618c2ecf20Sopenharmony_ci desc.mode = MEMRD; 2628c2ecf20Sopenharmony_ci err = src_mgr->get_src(src_mgr, &desc, (struct src **)&apcm->src); 2638c2ecf20Sopenharmony_ci if (err) 2648c2ecf20Sopenharmony_ci goto error1; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci pitch = atc_get_pitch(apcm->substream->runtime->rate, 2678c2ecf20Sopenharmony_ci (atc->rsr * atc->msr)); 2688c2ecf20Sopenharmony_ci src = apcm->src; 2698c2ecf20Sopenharmony_ci src->ops->set_pitch(src, pitch); 2708c2ecf20Sopenharmony_ci src->ops->set_rom(src, select_rom(pitch)); 2718c2ecf20Sopenharmony_ci src->ops->set_sf(src, convert_format(apcm->substream->runtime->format, 2728c2ecf20Sopenharmony_ci atc->card)); 2738c2ecf20Sopenharmony_ci src->ops->set_pm(src, (src->ops->next_interleave(src) != NULL)); 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci /* Get AMIXER resource */ 2768c2ecf20Sopenharmony_ci n_amixer = (n_amixer < 2) ? 2 : n_amixer; 2778c2ecf20Sopenharmony_ci apcm->amixers = kcalloc(n_amixer, sizeof(void *), GFP_KERNEL); 2788c2ecf20Sopenharmony_ci if (!apcm->amixers) { 2798c2ecf20Sopenharmony_ci err = -ENOMEM; 2808c2ecf20Sopenharmony_ci goto error1; 2818c2ecf20Sopenharmony_ci } 2828c2ecf20Sopenharmony_ci mix_dsc.msr = atc->msr; 2838c2ecf20Sopenharmony_ci for (i = 0, apcm->n_amixer = 0; i < n_amixer; i++) { 2848c2ecf20Sopenharmony_ci err = amixer_mgr->get_amixer(amixer_mgr, &mix_dsc, 2858c2ecf20Sopenharmony_ci (struct amixer **)&apcm->amixers[i]); 2868c2ecf20Sopenharmony_ci if (err) 2878c2ecf20Sopenharmony_ci goto error1; 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci apcm->n_amixer++; 2908c2ecf20Sopenharmony_ci } 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci /* Set up device virtual mem map */ 2938c2ecf20Sopenharmony_ci err = ct_map_audio_buffer(atc, apcm); 2948c2ecf20Sopenharmony_ci if (err < 0) 2958c2ecf20Sopenharmony_ci goto error1; 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci /* Connect resources */ 2988c2ecf20Sopenharmony_ci src = apcm->src; 2998c2ecf20Sopenharmony_ci for (i = 0; i < n_amixer; i++) { 3008c2ecf20Sopenharmony_ci amixer = apcm->amixers[i]; 3018c2ecf20Sopenharmony_ci mutex_lock(&atc->atc_mutex); 3028c2ecf20Sopenharmony_ci amixer->ops->setup(amixer, &src->rsc, 3038c2ecf20Sopenharmony_ci INIT_VOL, atc->pcm[i+device*2]); 3048c2ecf20Sopenharmony_ci mutex_unlock(&atc->atc_mutex); 3058c2ecf20Sopenharmony_ci src = src->ops->next_interleave(src); 3068c2ecf20Sopenharmony_ci if (!src) 3078c2ecf20Sopenharmony_ci src = apcm->src; 3088c2ecf20Sopenharmony_ci } 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci ct_timer_prepare(apcm->timer); 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci return 0; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_cierror1: 3158c2ecf20Sopenharmony_ci atc_pcm_release_resources(atc, apcm); 3168c2ecf20Sopenharmony_ci return err; 3178c2ecf20Sopenharmony_ci} 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_cistatic int 3208c2ecf20Sopenharmony_ciatc_pcm_release_resources(struct ct_atc *atc, struct ct_atc_pcm *apcm) 3218c2ecf20Sopenharmony_ci{ 3228c2ecf20Sopenharmony_ci struct src_mgr *src_mgr = atc->rsc_mgrs[SRC]; 3238c2ecf20Sopenharmony_ci struct srcimp_mgr *srcimp_mgr = atc->rsc_mgrs[SRCIMP]; 3248c2ecf20Sopenharmony_ci struct amixer_mgr *amixer_mgr = atc->rsc_mgrs[AMIXER]; 3258c2ecf20Sopenharmony_ci struct sum_mgr *sum_mgr = atc->rsc_mgrs[SUM]; 3268c2ecf20Sopenharmony_ci struct srcimp *srcimp; 3278c2ecf20Sopenharmony_ci int i; 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci if (apcm->srcimps) { 3308c2ecf20Sopenharmony_ci for (i = 0; i < apcm->n_srcimp; i++) { 3318c2ecf20Sopenharmony_ci srcimp = apcm->srcimps[i]; 3328c2ecf20Sopenharmony_ci srcimp->ops->unmap(srcimp); 3338c2ecf20Sopenharmony_ci srcimp_mgr->put_srcimp(srcimp_mgr, srcimp); 3348c2ecf20Sopenharmony_ci apcm->srcimps[i] = NULL; 3358c2ecf20Sopenharmony_ci } 3368c2ecf20Sopenharmony_ci kfree(apcm->srcimps); 3378c2ecf20Sopenharmony_ci apcm->srcimps = NULL; 3388c2ecf20Sopenharmony_ci } 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci if (apcm->srccs) { 3418c2ecf20Sopenharmony_ci for (i = 0; i < apcm->n_srcc; i++) { 3428c2ecf20Sopenharmony_ci src_mgr->put_src(src_mgr, apcm->srccs[i]); 3438c2ecf20Sopenharmony_ci apcm->srccs[i] = NULL; 3448c2ecf20Sopenharmony_ci } 3458c2ecf20Sopenharmony_ci kfree(apcm->srccs); 3468c2ecf20Sopenharmony_ci apcm->srccs = NULL; 3478c2ecf20Sopenharmony_ci } 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci if (apcm->amixers) { 3508c2ecf20Sopenharmony_ci for (i = 0; i < apcm->n_amixer; i++) { 3518c2ecf20Sopenharmony_ci amixer_mgr->put_amixer(amixer_mgr, apcm->amixers[i]); 3528c2ecf20Sopenharmony_ci apcm->amixers[i] = NULL; 3538c2ecf20Sopenharmony_ci } 3548c2ecf20Sopenharmony_ci kfree(apcm->amixers); 3558c2ecf20Sopenharmony_ci apcm->amixers = NULL; 3568c2ecf20Sopenharmony_ci } 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci if (apcm->mono) { 3598c2ecf20Sopenharmony_ci sum_mgr->put_sum(sum_mgr, apcm->mono); 3608c2ecf20Sopenharmony_ci apcm->mono = NULL; 3618c2ecf20Sopenharmony_ci } 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci if (apcm->src) { 3648c2ecf20Sopenharmony_ci src_mgr->put_src(src_mgr, apcm->src); 3658c2ecf20Sopenharmony_ci apcm->src = NULL; 3668c2ecf20Sopenharmony_ci } 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci if (apcm->vm_block) { 3698c2ecf20Sopenharmony_ci /* Undo device virtual mem map */ 3708c2ecf20Sopenharmony_ci ct_unmap_audio_buffer(atc, apcm); 3718c2ecf20Sopenharmony_ci apcm->vm_block = NULL; 3728c2ecf20Sopenharmony_ci } 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci return 0; 3758c2ecf20Sopenharmony_ci} 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_cistatic int atc_pcm_playback_start(struct ct_atc *atc, struct ct_atc_pcm *apcm) 3788c2ecf20Sopenharmony_ci{ 3798c2ecf20Sopenharmony_ci unsigned int max_cisz; 3808c2ecf20Sopenharmony_ci struct src *src = apcm->src; 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci if (apcm->started) 3838c2ecf20Sopenharmony_ci return 0; 3848c2ecf20Sopenharmony_ci apcm->started = 1; 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci max_cisz = src->multi * src->rsc.msr; 3878c2ecf20Sopenharmony_ci max_cisz = 0x80 * (max_cisz < 8 ? max_cisz : 8); 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci src->ops->set_sa(src, apcm->vm_block->addr); 3908c2ecf20Sopenharmony_ci src->ops->set_la(src, apcm->vm_block->addr + apcm->vm_block->size); 3918c2ecf20Sopenharmony_ci src->ops->set_ca(src, apcm->vm_block->addr + max_cisz); 3928c2ecf20Sopenharmony_ci src->ops->set_cisz(src, max_cisz); 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci src->ops->set_bm(src, 1); 3958c2ecf20Sopenharmony_ci src->ops->set_state(src, SRC_STATE_INIT); 3968c2ecf20Sopenharmony_ci src->ops->commit_write(src); 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci ct_timer_start(apcm->timer); 3998c2ecf20Sopenharmony_ci return 0; 4008c2ecf20Sopenharmony_ci} 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_cistatic int atc_pcm_stop(struct ct_atc *atc, struct ct_atc_pcm *apcm) 4038c2ecf20Sopenharmony_ci{ 4048c2ecf20Sopenharmony_ci struct src *src; 4058c2ecf20Sopenharmony_ci int i; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci ct_timer_stop(apcm->timer); 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci src = apcm->src; 4108c2ecf20Sopenharmony_ci src->ops->set_bm(src, 0); 4118c2ecf20Sopenharmony_ci src->ops->set_state(src, SRC_STATE_OFF); 4128c2ecf20Sopenharmony_ci src->ops->commit_write(src); 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci if (apcm->srccs) { 4158c2ecf20Sopenharmony_ci for (i = 0; i < apcm->n_srcc; i++) { 4168c2ecf20Sopenharmony_ci src = apcm->srccs[i]; 4178c2ecf20Sopenharmony_ci src->ops->set_bm(src, 0); 4188c2ecf20Sopenharmony_ci src->ops->set_state(src, SRC_STATE_OFF); 4198c2ecf20Sopenharmony_ci src->ops->commit_write(src); 4208c2ecf20Sopenharmony_ci } 4218c2ecf20Sopenharmony_ci } 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci apcm->started = 0; 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci return 0; 4268c2ecf20Sopenharmony_ci} 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_cistatic int 4298c2ecf20Sopenharmony_ciatc_pcm_playback_position(struct ct_atc *atc, struct ct_atc_pcm *apcm) 4308c2ecf20Sopenharmony_ci{ 4318c2ecf20Sopenharmony_ci struct src *src = apcm->src; 4328c2ecf20Sopenharmony_ci u32 size, max_cisz; 4338c2ecf20Sopenharmony_ci int position; 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci if (!src) 4368c2ecf20Sopenharmony_ci return 0; 4378c2ecf20Sopenharmony_ci position = src->ops->get_ca(src); 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci if (position < apcm->vm_block->addr) { 4408c2ecf20Sopenharmony_ci dev_dbg(atc->card->dev, 4418c2ecf20Sopenharmony_ci "bad ca - ca=0x%08x, vba=0x%08x, vbs=0x%08x\n", 4428c2ecf20Sopenharmony_ci position, apcm->vm_block->addr, apcm->vm_block->size); 4438c2ecf20Sopenharmony_ci position = apcm->vm_block->addr; 4448c2ecf20Sopenharmony_ci } 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci size = apcm->vm_block->size; 4478c2ecf20Sopenharmony_ci max_cisz = src->multi * src->rsc.msr; 4488c2ecf20Sopenharmony_ci max_cisz = 128 * (max_cisz < 8 ? max_cisz : 8); 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci return (position + size - max_cisz - apcm->vm_block->addr) % size; 4518c2ecf20Sopenharmony_ci} 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_cistruct src_node_conf_t { 4548c2ecf20Sopenharmony_ci unsigned int pitch; 4558c2ecf20Sopenharmony_ci unsigned int msr:8; 4568c2ecf20Sopenharmony_ci unsigned int mix_msr:8; 4578c2ecf20Sopenharmony_ci unsigned int imp_msr:8; 4588c2ecf20Sopenharmony_ci unsigned int vo:1; 4598c2ecf20Sopenharmony_ci}; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_cistatic void setup_src_node_conf(struct ct_atc *atc, struct ct_atc_pcm *apcm, 4628c2ecf20Sopenharmony_ci struct src_node_conf_t *conf, int *n_srcc) 4638c2ecf20Sopenharmony_ci{ 4648c2ecf20Sopenharmony_ci unsigned int pitch; 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci /* get pitch and convert to fixed-point 8.24 format. */ 4678c2ecf20Sopenharmony_ci pitch = atc_get_pitch((atc->rsr * atc->msr), 4688c2ecf20Sopenharmony_ci apcm->substream->runtime->rate); 4698c2ecf20Sopenharmony_ci *n_srcc = 0; 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci if (1 == atc->msr) { /* FIXME: do we really need SRC here if pitch==1 */ 4728c2ecf20Sopenharmony_ci *n_srcc = apcm->substream->runtime->channels; 4738c2ecf20Sopenharmony_ci conf[0].pitch = pitch; 4748c2ecf20Sopenharmony_ci conf[0].mix_msr = conf[0].imp_msr = conf[0].msr = 1; 4758c2ecf20Sopenharmony_ci conf[0].vo = 1; 4768c2ecf20Sopenharmony_ci } else if (2 <= atc->msr) { 4778c2ecf20Sopenharmony_ci if (0x8000000 < pitch) { 4788c2ecf20Sopenharmony_ci /* Need two-stage SRCs, SRCIMPs and 4798c2ecf20Sopenharmony_ci * AMIXERs for converting format */ 4808c2ecf20Sopenharmony_ci conf[0].pitch = (atc->msr << 24); 4818c2ecf20Sopenharmony_ci conf[0].msr = conf[0].mix_msr = 1; 4828c2ecf20Sopenharmony_ci conf[0].imp_msr = atc->msr; 4838c2ecf20Sopenharmony_ci conf[0].vo = 0; 4848c2ecf20Sopenharmony_ci conf[1].pitch = atc_get_pitch(atc->rsr, 4858c2ecf20Sopenharmony_ci apcm->substream->runtime->rate); 4868c2ecf20Sopenharmony_ci conf[1].msr = conf[1].mix_msr = conf[1].imp_msr = 1; 4878c2ecf20Sopenharmony_ci conf[1].vo = 1; 4888c2ecf20Sopenharmony_ci *n_srcc = apcm->substream->runtime->channels * 2; 4898c2ecf20Sopenharmony_ci } else if (0x1000000 < pitch) { 4908c2ecf20Sopenharmony_ci /* Need one-stage SRCs, SRCIMPs and 4918c2ecf20Sopenharmony_ci * AMIXERs for converting format */ 4928c2ecf20Sopenharmony_ci conf[0].pitch = pitch; 4938c2ecf20Sopenharmony_ci conf[0].msr = conf[0].mix_msr 4948c2ecf20Sopenharmony_ci = conf[0].imp_msr = atc->msr; 4958c2ecf20Sopenharmony_ci conf[0].vo = 1; 4968c2ecf20Sopenharmony_ci *n_srcc = apcm->substream->runtime->channels; 4978c2ecf20Sopenharmony_ci } 4988c2ecf20Sopenharmony_ci } 4998c2ecf20Sopenharmony_ci} 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_cistatic int 5028c2ecf20Sopenharmony_ciatc_pcm_capture_get_resources(struct ct_atc *atc, struct ct_atc_pcm *apcm) 5038c2ecf20Sopenharmony_ci{ 5048c2ecf20Sopenharmony_ci struct src_mgr *src_mgr = atc->rsc_mgrs[SRC]; 5058c2ecf20Sopenharmony_ci struct srcimp_mgr *srcimp_mgr = atc->rsc_mgrs[SRCIMP]; 5068c2ecf20Sopenharmony_ci struct amixer_mgr *amixer_mgr = atc->rsc_mgrs[AMIXER]; 5078c2ecf20Sopenharmony_ci struct sum_mgr *sum_mgr = atc->rsc_mgrs[SUM]; 5088c2ecf20Sopenharmony_ci struct src_desc src_dsc = {0}; 5098c2ecf20Sopenharmony_ci struct src *src; 5108c2ecf20Sopenharmony_ci struct srcimp_desc srcimp_dsc = {0}; 5118c2ecf20Sopenharmony_ci struct srcimp *srcimp; 5128c2ecf20Sopenharmony_ci struct amixer_desc mix_dsc = {0}; 5138c2ecf20Sopenharmony_ci struct sum_desc sum_dsc = {0}; 5148c2ecf20Sopenharmony_ci unsigned int pitch; 5158c2ecf20Sopenharmony_ci int multi, err, i; 5168c2ecf20Sopenharmony_ci int n_srcimp, n_amixer, n_srcc, n_sum; 5178c2ecf20Sopenharmony_ci struct src_node_conf_t src_node_conf[2] = {{0} }; 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci /* first release old resources */ 5208c2ecf20Sopenharmony_ci atc_pcm_release_resources(atc, apcm); 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci /* The numbers of converting SRCs and SRCIMPs should be determined 5238c2ecf20Sopenharmony_ci * by pitch value. */ 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci multi = apcm->substream->runtime->channels; 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci /* get pitch and convert to fixed-point 8.24 format. */ 5288c2ecf20Sopenharmony_ci pitch = atc_get_pitch((atc->rsr * atc->msr), 5298c2ecf20Sopenharmony_ci apcm->substream->runtime->rate); 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci setup_src_node_conf(atc, apcm, src_node_conf, &n_srcc); 5328c2ecf20Sopenharmony_ci n_sum = (1 == multi) ? 1 : 0; 5338c2ecf20Sopenharmony_ci n_amixer = n_sum * 2 + n_srcc; 5348c2ecf20Sopenharmony_ci n_srcimp = n_srcc; 5358c2ecf20Sopenharmony_ci if ((multi > 1) && (0x8000000 >= pitch)) { 5368c2ecf20Sopenharmony_ci /* Need extra AMIXERs and SRCIMPs for special treatment 5378c2ecf20Sopenharmony_ci * of interleaved recording of conjugate channels */ 5388c2ecf20Sopenharmony_ci n_amixer += multi * atc->msr; 5398c2ecf20Sopenharmony_ci n_srcimp += multi * atc->msr; 5408c2ecf20Sopenharmony_ci } else { 5418c2ecf20Sopenharmony_ci n_srcimp += multi; 5428c2ecf20Sopenharmony_ci } 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci if (n_srcc) { 5458c2ecf20Sopenharmony_ci apcm->srccs = kcalloc(n_srcc, sizeof(void *), GFP_KERNEL); 5468c2ecf20Sopenharmony_ci if (!apcm->srccs) 5478c2ecf20Sopenharmony_ci return -ENOMEM; 5488c2ecf20Sopenharmony_ci } 5498c2ecf20Sopenharmony_ci if (n_amixer) { 5508c2ecf20Sopenharmony_ci apcm->amixers = kcalloc(n_amixer, sizeof(void *), GFP_KERNEL); 5518c2ecf20Sopenharmony_ci if (!apcm->amixers) { 5528c2ecf20Sopenharmony_ci err = -ENOMEM; 5538c2ecf20Sopenharmony_ci goto error1; 5548c2ecf20Sopenharmony_ci } 5558c2ecf20Sopenharmony_ci } 5568c2ecf20Sopenharmony_ci apcm->srcimps = kcalloc(n_srcimp, sizeof(void *), GFP_KERNEL); 5578c2ecf20Sopenharmony_ci if (!apcm->srcimps) { 5588c2ecf20Sopenharmony_ci err = -ENOMEM; 5598c2ecf20Sopenharmony_ci goto error1; 5608c2ecf20Sopenharmony_ci } 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci /* Allocate SRCs for sample rate conversion if needed */ 5638c2ecf20Sopenharmony_ci src_dsc.multi = 1; 5648c2ecf20Sopenharmony_ci src_dsc.mode = ARCRW; 5658c2ecf20Sopenharmony_ci for (i = 0, apcm->n_srcc = 0; i < n_srcc; i++) { 5668c2ecf20Sopenharmony_ci src_dsc.msr = src_node_conf[i/multi].msr; 5678c2ecf20Sopenharmony_ci err = src_mgr->get_src(src_mgr, &src_dsc, 5688c2ecf20Sopenharmony_ci (struct src **)&apcm->srccs[i]); 5698c2ecf20Sopenharmony_ci if (err) 5708c2ecf20Sopenharmony_ci goto error1; 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci src = apcm->srccs[i]; 5738c2ecf20Sopenharmony_ci pitch = src_node_conf[i/multi].pitch; 5748c2ecf20Sopenharmony_ci src->ops->set_pitch(src, pitch); 5758c2ecf20Sopenharmony_ci src->ops->set_rom(src, select_rom(pitch)); 5768c2ecf20Sopenharmony_ci src->ops->set_vo(src, src_node_conf[i/multi].vo); 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci apcm->n_srcc++; 5798c2ecf20Sopenharmony_ci } 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci /* Allocate AMIXERs for routing SRCs of conversion if needed */ 5828c2ecf20Sopenharmony_ci for (i = 0, apcm->n_amixer = 0; i < n_amixer; i++) { 5838c2ecf20Sopenharmony_ci if (i < (n_sum*2)) 5848c2ecf20Sopenharmony_ci mix_dsc.msr = atc->msr; 5858c2ecf20Sopenharmony_ci else if (i < (n_sum*2+n_srcc)) 5868c2ecf20Sopenharmony_ci mix_dsc.msr = src_node_conf[(i-n_sum*2)/multi].mix_msr; 5878c2ecf20Sopenharmony_ci else 5888c2ecf20Sopenharmony_ci mix_dsc.msr = 1; 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci err = amixer_mgr->get_amixer(amixer_mgr, &mix_dsc, 5918c2ecf20Sopenharmony_ci (struct amixer **)&apcm->amixers[i]); 5928c2ecf20Sopenharmony_ci if (err) 5938c2ecf20Sopenharmony_ci goto error1; 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci apcm->n_amixer++; 5968c2ecf20Sopenharmony_ci } 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci /* Allocate a SUM resource to mix all input channels together */ 5998c2ecf20Sopenharmony_ci sum_dsc.msr = atc->msr; 6008c2ecf20Sopenharmony_ci err = sum_mgr->get_sum(sum_mgr, &sum_dsc, (struct sum **)&apcm->mono); 6018c2ecf20Sopenharmony_ci if (err) 6028c2ecf20Sopenharmony_ci goto error1; 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci pitch = atc_get_pitch((atc->rsr * atc->msr), 6058c2ecf20Sopenharmony_ci apcm->substream->runtime->rate); 6068c2ecf20Sopenharmony_ci /* Allocate SRCIMP resources */ 6078c2ecf20Sopenharmony_ci for (i = 0, apcm->n_srcimp = 0; i < n_srcimp; i++) { 6088c2ecf20Sopenharmony_ci if (i < (n_srcc)) 6098c2ecf20Sopenharmony_ci srcimp_dsc.msr = src_node_conf[i/multi].imp_msr; 6108c2ecf20Sopenharmony_ci else if (1 == multi) 6118c2ecf20Sopenharmony_ci srcimp_dsc.msr = (pitch <= 0x8000000) ? atc->msr : 1; 6128c2ecf20Sopenharmony_ci else 6138c2ecf20Sopenharmony_ci srcimp_dsc.msr = 1; 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci err = srcimp_mgr->get_srcimp(srcimp_mgr, &srcimp_dsc, &srcimp); 6168c2ecf20Sopenharmony_ci if (err) 6178c2ecf20Sopenharmony_ci goto error1; 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci apcm->srcimps[i] = srcimp; 6208c2ecf20Sopenharmony_ci apcm->n_srcimp++; 6218c2ecf20Sopenharmony_ci } 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci /* Allocate a SRC for writing data to host memory */ 6248c2ecf20Sopenharmony_ci src_dsc.multi = apcm->substream->runtime->channels; 6258c2ecf20Sopenharmony_ci src_dsc.msr = 1; 6268c2ecf20Sopenharmony_ci src_dsc.mode = MEMWR; 6278c2ecf20Sopenharmony_ci err = src_mgr->get_src(src_mgr, &src_dsc, (struct src **)&apcm->src); 6288c2ecf20Sopenharmony_ci if (err) 6298c2ecf20Sopenharmony_ci goto error1; 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci src = apcm->src; 6328c2ecf20Sopenharmony_ci src->ops->set_pitch(src, pitch); 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci /* Set up device virtual mem map */ 6358c2ecf20Sopenharmony_ci err = ct_map_audio_buffer(atc, apcm); 6368c2ecf20Sopenharmony_ci if (err < 0) 6378c2ecf20Sopenharmony_ci goto error1; 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci return 0; 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_cierror1: 6428c2ecf20Sopenharmony_ci atc_pcm_release_resources(atc, apcm); 6438c2ecf20Sopenharmony_ci return err; 6448c2ecf20Sopenharmony_ci} 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_cistatic int atc_pcm_capture_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm) 6478c2ecf20Sopenharmony_ci{ 6488c2ecf20Sopenharmony_ci struct src *src; 6498c2ecf20Sopenharmony_ci struct amixer *amixer; 6508c2ecf20Sopenharmony_ci struct srcimp *srcimp; 6518c2ecf20Sopenharmony_ci struct ct_mixer *mixer = atc->mixer; 6528c2ecf20Sopenharmony_ci struct sum *mono; 6538c2ecf20Sopenharmony_ci struct rsc *out_ports[8] = {NULL}; 6548c2ecf20Sopenharmony_ci int err, i, j, n_sum, multi; 6558c2ecf20Sopenharmony_ci unsigned int pitch; 6568c2ecf20Sopenharmony_ci int mix_base = 0, imp_base = 0; 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci atc_pcm_release_resources(atc, apcm); 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci /* Get needed resources. */ 6618c2ecf20Sopenharmony_ci err = atc_pcm_capture_get_resources(atc, apcm); 6628c2ecf20Sopenharmony_ci if (err) 6638c2ecf20Sopenharmony_ci return err; 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci /* Connect resources */ 6668c2ecf20Sopenharmony_ci mixer->get_output_ports(mixer, MIX_PCMO_FRONT, 6678c2ecf20Sopenharmony_ci &out_ports[0], &out_ports[1]); 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci multi = apcm->substream->runtime->channels; 6708c2ecf20Sopenharmony_ci if (1 == multi) { 6718c2ecf20Sopenharmony_ci mono = apcm->mono; 6728c2ecf20Sopenharmony_ci for (i = 0; i < 2; i++) { 6738c2ecf20Sopenharmony_ci amixer = apcm->amixers[i]; 6748c2ecf20Sopenharmony_ci amixer->ops->setup(amixer, out_ports[i], 6758c2ecf20Sopenharmony_ci MONO_SUM_SCALE, mono); 6768c2ecf20Sopenharmony_ci } 6778c2ecf20Sopenharmony_ci out_ports[0] = &mono->rsc; 6788c2ecf20Sopenharmony_ci n_sum = 1; 6798c2ecf20Sopenharmony_ci mix_base = n_sum * 2; 6808c2ecf20Sopenharmony_ci } 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci for (i = 0; i < apcm->n_srcc; i++) { 6838c2ecf20Sopenharmony_ci src = apcm->srccs[i]; 6848c2ecf20Sopenharmony_ci srcimp = apcm->srcimps[imp_base+i]; 6858c2ecf20Sopenharmony_ci amixer = apcm->amixers[mix_base+i]; 6868c2ecf20Sopenharmony_ci srcimp->ops->map(srcimp, src, out_ports[i%multi]); 6878c2ecf20Sopenharmony_ci amixer->ops->setup(amixer, &src->rsc, INIT_VOL, NULL); 6888c2ecf20Sopenharmony_ci out_ports[i%multi] = &amixer->rsc; 6898c2ecf20Sopenharmony_ci } 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci pitch = atc_get_pitch((atc->rsr * atc->msr), 6928c2ecf20Sopenharmony_ci apcm->substream->runtime->rate); 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ci if ((multi > 1) && (pitch <= 0x8000000)) { 6958c2ecf20Sopenharmony_ci /* Special connection for interleaved 6968c2ecf20Sopenharmony_ci * recording with conjugate channels */ 6978c2ecf20Sopenharmony_ci for (i = 0; i < multi; i++) { 6988c2ecf20Sopenharmony_ci out_ports[i]->ops->master(out_ports[i]); 6998c2ecf20Sopenharmony_ci for (j = 0; j < atc->msr; j++) { 7008c2ecf20Sopenharmony_ci amixer = apcm->amixers[apcm->n_srcc+j*multi+i]; 7018c2ecf20Sopenharmony_ci amixer->ops->set_input(amixer, out_ports[i]); 7028c2ecf20Sopenharmony_ci amixer->ops->set_scale(amixer, INIT_VOL); 7038c2ecf20Sopenharmony_ci amixer->ops->set_sum(amixer, NULL); 7048c2ecf20Sopenharmony_ci amixer->ops->commit_raw_write(amixer); 7058c2ecf20Sopenharmony_ci out_ports[i]->ops->next_conj(out_ports[i]); 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci srcimp = apcm->srcimps[apcm->n_srcc+j*multi+i]; 7088c2ecf20Sopenharmony_ci srcimp->ops->map(srcimp, apcm->src, 7098c2ecf20Sopenharmony_ci &amixer->rsc); 7108c2ecf20Sopenharmony_ci } 7118c2ecf20Sopenharmony_ci } 7128c2ecf20Sopenharmony_ci } else { 7138c2ecf20Sopenharmony_ci for (i = 0; i < multi; i++) { 7148c2ecf20Sopenharmony_ci srcimp = apcm->srcimps[apcm->n_srcc+i]; 7158c2ecf20Sopenharmony_ci srcimp->ops->map(srcimp, apcm->src, out_ports[i]); 7168c2ecf20Sopenharmony_ci } 7178c2ecf20Sopenharmony_ci } 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci ct_timer_prepare(apcm->timer); 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci return 0; 7228c2ecf20Sopenharmony_ci} 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_cistatic int atc_pcm_capture_start(struct ct_atc *atc, struct ct_atc_pcm *apcm) 7258c2ecf20Sopenharmony_ci{ 7268c2ecf20Sopenharmony_ci struct src *src; 7278c2ecf20Sopenharmony_ci struct src_mgr *src_mgr = atc->rsc_mgrs[SRC]; 7288c2ecf20Sopenharmony_ci int i, multi; 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci if (apcm->started) 7318c2ecf20Sopenharmony_ci return 0; 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci apcm->started = 1; 7348c2ecf20Sopenharmony_ci multi = apcm->substream->runtime->channels; 7358c2ecf20Sopenharmony_ci /* Set up converting SRCs */ 7368c2ecf20Sopenharmony_ci for (i = 0; i < apcm->n_srcc; i++) { 7378c2ecf20Sopenharmony_ci src = apcm->srccs[i]; 7388c2ecf20Sopenharmony_ci src->ops->set_pm(src, ((i%multi) != (multi-1))); 7398c2ecf20Sopenharmony_ci src_mgr->src_disable(src_mgr, src); 7408c2ecf20Sopenharmony_ci } 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci /* Set up recording SRC */ 7438c2ecf20Sopenharmony_ci src = apcm->src; 7448c2ecf20Sopenharmony_ci src->ops->set_sf(src, convert_format(apcm->substream->runtime->format, 7458c2ecf20Sopenharmony_ci atc->card)); 7468c2ecf20Sopenharmony_ci src->ops->set_sa(src, apcm->vm_block->addr); 7478c2ecf20Sopenharmony_ci src->ops->set_la(src, apcm->vm_block->addr + apcm->vm_block->size); 7488c2ecf20Sopenharmony_ci src->ops->set_ca(src, apcm->vm_block->addr); 7498c2ecf20Sopenharmony_ci src_mgr->src_disable(src_mgr, src); 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci /* Disable relevant SRCs firstly */ 7528c2ecf20Sopenharmony_ci src_mgr->commit_write(src_mgr); 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci /* Enable SRCs respectively */ 7558c2ecf20Sopenharmony_ci for (i = 0; i < apcm->n_srcc; i++) { 7568c2ecf20Sopenharmony_ci src = apcm->srccs[i]; 7578c2ecf20Sopenharmony_ci src->ops->set_state(src, SRC_STATE_RUN); 7588c2ecf20Sopenharmony_ci src->ops->commit_write(src); 7598c2ecf20Sopenharmony_ci src_mgr->src_enable_s(src_mgr, src); 7608c2ecf20Sopenharmony_ci } 7618c2ecf20Sopenharmony_ci src = apcm->src; 7628c2ecf20Sopenharmony_ci src->ops->set_bm(src, 1); 7638c2ecf20Sopenharmony_ci src->ops->set_state(src, SRC_STATE_RUN); 7648c2ecf20Sopenharmony_ci src->ops->commit_write(src); 7658c2ecf20Sopenharmony_ci src_mgr->src_enable_s(src_mgr, src); 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci /* Enable relevant SRCs synchronously */ 7688c2ecf20Sopenharmony_ci src_mgr->commit_write(src_mgr); 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci ct_timer_start(apcm->timer); 7718c2ecf20Sopenharmony_ci return 0; 7728c2ecf20Sopenharmony_ci} 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_cistatic int 7758c2ecf20Sopenharmony_ciatc_pcm_capture_position(struct ct_atc *atc, struct ct_atc_pcm *apcm) 7768c2ecf20Sopenharmony_ci{ 7778c2ecf20Sopenharmony_ci struct src *src = apcm->src; 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci if (!src) 7808c2ecf20Sopenharmony_ci return 0; 7818c2ecf20Sopenharmony_ci return src->ops->get_ca(src) - apcm->vm_block->addr; 7828c2ecf20Sopenharmony_ci} 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_cistatic int spdif_passthru_playback_get_resources(struct ct_atc *atc, 7858c2ecf20Sopenharmony_ci struct ct_atc_pcm *apcm) 7868c2ecf20Sopenharmony_ci{ 7878c2ecf20Sopenharmony_ci struct src_mgr *src_mgr = atc->rsc_mgrs[SRC]; 7888c2ecf20Sopenharmony_ci struct amixer_mgr *amixer_mgr = atc->rsc_mgrs[AMIXER]; 7898c2ecf20Sopenharmony_ci struct src_desc desc = {0}; 7908c2ecf20Sopenharmony_ci struct amixer_desc mix_dsc = {0}; 7918c2ecf20Sopenharmony_ci struct src *src; 7928c2ecf20Sopenharmony_ci int err; 7938c2ecf20Sopenharmony_ci int n_amixer = apcm->substream->runtime->channels, i; 7948c2ecf20Sopenharmony_ci unsigned int pitch, rsr = atc->pll_rate; 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci /* first release old resources */ 7978c2ecf20Sopenharmony_ci atc_pcm_release_resources(atc, apcm); 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci /* Get SRC resource */ 8008c2ecf20Sopenharmony_ci desc.multi = apcm->substream->runtime->channels; 8018c2ecf20Sopenharmony_ci desc.msr = 1; 8028c2ecf20Sopenharmony_ci while (apcm->substream->runtime->rate > (rsr * desc.msr)) 8038c2ecf20Sopenharmony_ci desc.msr <<= 1; 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci desc.mode = MEMRD; 8068c2ecf20Sopenharmony_ci err = src_mgr->get_src(src_mgr, &desc, (struct src **)&apcm->src); 8078c2ecf20Sopenharmony_ci if (err) 8088c2ecf20Sopenharmony_ci goto error1; 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_ci pitch = atc_get_pitch(apcm->substream->runtime->rate, (rsr * desc.msr)); 8118c2ecf20Sopenharmony_ci src = apcm->src; 8128c2ecf20Sopenharmony_ci src->ops->set_pitch(src, pitch); 8138c2ecf20Sopenharmony_ci src->ops->set_rom(src, select_rom(pitch)); 8148c2ecf20Sopenharmony_ci src->ops->set_sf(src, convert_format(apcm->substream->runtime->format, 8158c2ecf20Sopenharmony_ci atc->card)); 8168c2ecf20Sopenharmony_ci src->ops->set_pm(src, (src->ops->next_interleave(src) != NULL)); 8178c2ecf20Sopenharmony_ci src->ops->set_bp(src, 1); 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci /* Get AMIXER resource */ 8208c2ecf20Sopenharmony_ci n_amixer = (n_amixer < 2) ? 2 : n_amixer; 8218c2ecf20Sopenharmony_ci apcm->amixers = kcalloc(n_amixer, sizeof(void *), GFP_KERNEL); 8228c2ecf20Sopenharmony_ci if (!apcm->amixers) { 8238c2ecf20Sopenharmony_ci err = -ENOMEM; 8248c2ecf20Sopenharmony_ci goto error1; 8258c2ecf20Sopenharmony_ci } 8268c2ecf20Sopenharmony_ci mix_dsc.msr = desc.msr; 8278c2ecf20Sopenharmony_ci for (i = 0, apcm->n_amixer = 0; i < n_amixer; i++) { 8288c2ecf20Sopenharmony_ci err = amixer_mgr->get_amixer(amixer_mgr, &mix_dsc, 8298c2ecf20Sopenharmony_ci (struct amixer **)&apcm->amixers[i]); 8308c2ecf20Sopenharmony_ci if (err) 8318c2ecf20Sopenharmony_ci goto error1; 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci apcm->n_amixer++; 8348c2ecf20Sopenharmony_ci } 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci /* Set up device virtual mem map */ 8378c2ecf20Sopenharmony_ci err = ct_map_audio_buffer(atc, apcm); 8388c2ecf20Sopenharmony_ci if (err < 0) 8398c2ecf20Sopenharmony_ci goto error1; 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci return 0; 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_cierror1: 8448c2ecf20Sopenharmony_ci atc_pcm_release_resources(atc, apcm); 8458c2ecf20Sopenharmony_ci return err; 8468c2ecf20Sopenharmony_ci} 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_cistatic int atc_pll_init(struct ct_atc *atc, int rate) 8498c2ecf20Sopenharmony_ci{ 8508c2ecf20Sopenharmony_ci struct hw *hw = atc->hw; 8518c2ecf20Sopenharmony_ci int err; 8528c2ecf20Sopenharmony_ci err = hw->pll_init(hw, rate); 8538c2ecf20Sopenharmony_ci atc->pll_rate = err ? 0 : rate; 8548c2ecf20Sopenharmony_ci return err; 8558c2ecf20Sopenharmony_ci} 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_cistatic int 8588c2ecf20Sopenharmony_cispdif_passthru_playback_setup(struct ct_atc *atc, struct ct_atc_pcm *apcm) 8598c2ecf20Sopenharmony_ci{ 8608c2ecf20Sopenharmony_ci struct dao *dao = container_of(atc->daios[SPDIFOO], struct dao, daio); 8618c2ecf20Sopenharmony_ci unsigned int rate = apcm->substream->runtime->rate; 8628c2ecf20Sopenharmony_ci unsigned int status; 8638c2ecf20Sopenharmony_ci int err = 0; 8648c2ecf20Sopenharmony_ci unsigned char iec958_con_fs; 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci switch (rate) { 8678c2ecf20Sopenharmony_ci case 48000: 8688c2ecf20Sopenharmony_ci iec958_con_fs = IEC958_AES3_CON_FS_48000; 8698c2ecf20Sopenharmony_ci break; 8708c2ecf20Sopenharmony_ci case 44100: 8718c2ecf20Sopenharmony_ci iec958_con_fs = IEC958_AES3_CON_FS_44100; 8728c2ecf20Sopenharmony_ci break; 8738c2ecf20Sopenharmony_ci case 32000: 8748c2ecf20Sopenharmony_ci iec958_con_fs = IEC958_AES3_CON_FS_32000; 8758c2ecf20Sopenharmony_ci break; 8768c2ecf20Sopenharmony_ci default: 8778c2ecf20Sopenharmony_ci return -ENOENT; 8788c2ecf20Sopenharmony_ci } 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_ci mutex_lock(&atc->atc_mutex); 8818c2ecf20Sopenharmony_ci dao->ops->get_spos(dao, &status); 8828c2ecf20Sopenharmony_ci if (((status >> 24) & IEC958_AES3_CON_FS) != iec958_con_fs) { 8838c2ecf20Sopenharmony_ci status &= ~(IEC958_AES3_CON_FS << 24); 8848c2ecf20Sopenharmony_ci status |= (iec958_con_fs << 24); 8858c2ecf20Sopenharmony_ci dao->ops->set_spos(dao, status); 8868c2ecf20Sopenharmony_ci dao->ops->commit_write(dao); 8878c2ecf20Sopenharmony_ci } 8888c2ecf20Sopenharmony_ci if ((rate != atc->pll_rate) && (32000 != rate)) 8898c2ecf20Sopenharmony_ci err = atc_pll_init(atc, rate); 8908c2ecf20Sopenharmony_ci mutex_unlock(&atc->atc_mutex); 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci return err; 8938c2ecf20Sopenharmony_ci} 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_cistatic int 8968c2ecf20Sopenharmony_cispdif_passthru_playback_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm) 8978c2ecf20Sopenharmony_ci{ 8988c2ecf20Sopenharmony_ci struct src *src; 8998c2ecf20Sopenharmony_ci struct amixer *amixer; 9008c2ecf20Sopenharmony_ci struct dao *dao; 9018c2ecf20Sopenharmony_ci int err; 9028c2ecf20Sopenharmony_ci int i; 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_ci atc_pcm_release_resources(atc, apcm); 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_ci /* Configure SPDIFOO and PLL to passthrough mode; 9078c2ecf20Sopenharmony_ci * determine pll_rate. */ 9088c2ecf20Sopenharmony_ci err = spdif_passthru_playback_setup(atc, apcm); 9098c2ecf20Sopenharmony_ci if (err) 9108c2ecf20Sopenharmony_ci return err; 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_ci /* Get needed resources. */ 9138c2ecf20Sopenharmony_ci err = spdif_passthru_playback_get_resources(atc, apcm); 9148c2ecf20Sopenharmony_ci if (err) 9158c2ecf20Sopenharmony_ci return err; 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_ci /* Connect resources */ 9188c2ecf20Sopenharmony_ci src = apcm->src; 9198c2ecf20Sopenharmony_ci for (i = 0; i < apcm->n_amixer; i++) { 9208c2ecf20Sopenharmony_ci amixer = apcm->amixers[i]; 9218c2ecf20Sopenharmony_ci amixer->ops->setup(amixer, &src->rsc, INIT_VOL, NULL); 9228c2ecf20Sopenharmony_ci src = src->ops->next_interleave(src); 9238c2ecf20Sopenharmony_ci if (!src) 9248c2ecf20Sopenharmony_ci src = apcm->src; 9258c2ecf20Sopenharmony_ci } 9268c2ecf20Sopenharmony_ci /* Connect to SPDIFOO */ 9278c2ecf20Sopenharmony_ci mutex_lock(&atc->atc_mutex); 9288c2ecf20Sopenharmony_ci dao = container_of(atc->daios[SPDIFOO], struct dao, daio); 9298c2ecf20Sopenharmony_ci amixer = apcm->amixers[0]; 9308c2ecf20Sopenharmony_ci dao->ops->set_left_input(dao, &amixer->rsc); 9318c2ecf20Sopenharmony_ci amixer = apcm->amixers[1]; 9328c2ecf20Sopenharmony_ci dao->ops->set_right_input(dao, &amixer->rsc); 9338c2ecf20Sopenharmony_ci mutex_unlock(&atc->atc_mutex); 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci ct_timer_prepare(apcm->timer); 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_ci return 0; 9388c2ecf20Sopenharmony_ci} 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_cistatic int atc_select_line_in(struct ct_atc *atc) 9418c2ecf20Sopenharmony_ci{ 9428c2ecf20Sopenharmony_ci struct hw *hw = atc->hw; 9438c2ecf20Sopenharmony_ci struct ct_mixer *mixer = atc->mixer; 9448c2ecf20Sopenharmony_ci struct src *src; 9458c2ecf20Sopenharmony_ci 9468c2ecf20Sopenharmony_ci if (hw->is_adc_source_selected(hw, ADC_LINEIN)) 9478c2ecf20Sopenharmony_ci return 0; 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_ci mixer->set_input_left(mixer, MIX_MIC_IN, NULL); 9508c2ecf20Sopenharmony_ci mixer->set_input_right(mixer, MIX_MIC_IN, NULL); 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ci hw->select_adc_source(hw, ADC_LINEIN); 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_ci src = atc->srcs[2]; 9558c2ecf20Sopenharmony_ci mixer->set_input_left(mixer, MIX_LINE_IN, &src->rsc); 9568c2ecf20Sopenharmony_ci src = atc->srcs[3]; 9578c2ecf20Sopenharmony_ci mixer->set_input_right(mixer, MIX_LINE_IN, &src->rsc); 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_ci return 0; 9608c2ecf20Sopenharmony_ci} 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_cistatic int atc_select_mic_in(struct ct_atc *atc) 9638c2ecf20Sopenharmony_ci{ 9648c2ecf20Sopenharmony_ci struct hw *hw = atc->hw; 9658c2ecf20Sopenharmony_ci struct ct_mixer *mixer = atc->mixer; 9668c2ecf20Sopenharmony_ci struct src *src; 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci if (hw->is_adc_source_selected(hw, ADC_MICIN)) 9698c2ecf20Sopenharmony_ci return 0; 9708c2ecf20Sopenharmony_ci 9718c2ecf20Sopenharmony_ci mixer->set_input_left(mixer, MIX_LINE_IN, NULL); 9728c2ecf20Sopenharmony_ci mixer->set_input_right(mixer, MIX_LINE_IN, NULL); 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_ci hw->select_adc_source(hw, ADC_MICIN); 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_ci src = atc->srcs[2]; 9778c2ecf20Sopenharmony_ci mixer->set_input_left(mixer, MIX_MIC_IN, &src->rsc); 9788c2ecf20Sopenharmony_ci src = atc->srcs[3]; 9798c2ecf20Sopenharmony_ci mixer->set_input_right(mixer, MIX_MIC_IN, &src->rsc); 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_ci return 0; 9828c2ecf20Sopenharmony_ci} 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_cistatic struct capabilities atc_capabilities(struct ct_atc *atc) 9858c2ecf20Sopenharmony_ci{ 9868c2ecf20Sopenharmony_ci struct hw *hw = atc->hw; 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_ci return hw->capabilities(hw); 9898c2ecf20Sopenharmony_ci} 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_cistatic int atc_output_switch_get(struct ct_atc *atc) 9928c2ecf20Sopenharmony_ci{ 9938c2ecf20Sopenharmony_ci struct hw *hw = atc->hw; 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_ci return hw->output_switch_get(hw); 9968c2ecf20Sopenharmony_ci} 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_cistatic int atc_output_switch_put(struct ct_atc *atc, int position) 9998c2ecf20Sopenharmony_ci{ 10008c2ecf20Sopenharmony_ci struct hw *hw = atc->hw; 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_ci return hw->output_switch_put(hw, position); 10038c2ecf20Sopenharmony_ci} 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_cistatic int atc_mic_source_switch_get(struct ct_atc *atc) 10068c2ecf20Sopenharmony_ci{ 10078c2ecf20Sopenharmony_ci struct hw *hw = atc->hw; 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_ci return hw->mic_source_switch_get(hw); 10108c2ecf20Sopenharmony_ci} 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_cistatic int atc_mic_source_switch_put(struct ct_atc *atc, int position) 10138c2ecf20Sopenharmony_ci{ 10148c2ecf20Sopenharmony_ci struct hw *hw = atc->hw; 10158c2ecf20Sopenharmony_ci 10168c2ecf20Sopenharmony_ci return hw->mic_source_switch_put(hw, position); 10178c2ecf20Sopenharmony_ci} 10188c2ecf20Sopenharmony_ci 10198c2ecf20Sopenharmony_cistatic int atc_select_digit_io(struct ct_atc *atc) 10208c2ecf20Sopenharmony_ci{ 10218c2ecf20Sopenharmony_ci struct hw *hw = atc->hw; 10228c2ecf20Sopenharmony_ci 10238c2ecf20Sopenharmony_ci if (hw->is_adc_source_selected(hw, ADC_NONE)) 10248c2ecf20Sopenharmony_ci return 0; 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_ci hw->select_adc_source(hw, ADC_NONE); 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_ci return 0; 10298c2ecf20Sopenharmony_ci} 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_cistatic int atc_daio_unmute(struct ct_atc *atc, unsigned char state, int type) 10328c2ecf20Sopenharmony_ci{ 10338c2ecf20Sopenharmony_ci struct daio_mgr *daio_mgr = atc->rsc_mgrs[DAIO]; 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci if (state) 10368c2ecf20Sopenharmony_ci daio_mgr->daio_enable(daio_mgr, atc->daios[type]); 10378c2ecf20Sopenharmony_ci else 10388c2ecf20Sopenharmony_ci daio_mgr->daio_disable(daio_mgr, atc->daios[type]); 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_ci daio_mgr->commit_write(daio_mgr); 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_ci return 0; 10438c2ecf20Sopenharmony_ci} 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_cistatic int 10468c2ecf20Sopenharmony_ciatc_dao_get_status(struct ct_atc *atc, unsigned int *status, int type) 10478c2ecf20Sopenharmony_ci{ 10488c2ecf20Sopenharmony_ci struct dao *dao = container_of(atc->daios[type], struct dao, daio); 10498c2ecf20Sopenharmony_ci return dao->ops->get_spos(dao, status); 10508c2ecf20Sopenharmony_ci} 10518c2ecf20Sopenharmony_ci 10528c2ecf20Sopenharmony_cistatic int 10538c2ecf20Sopenharmony_ciatc_dao_set_status(struct ct_atc *atc, unsigned int status, int type) 10548c2ecf20Sopenharmony_ci{ 10558c2ecf20Sopenharmony_ci struct dao *dao = container_of(atc->daios[type], struct dao, daio); 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_ci dao->ops->set_spos(dao, status); 10588c2ecf20Sopenharmony_ci dao->ops->commit_write(dao); 10598c2ecf20Sopenharmony_ci return 0; 10608c2ecf20Sopenharmony_ci} 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_cistatic int atc_line_front_unmute(struct ct_atc *atc, unsigned char state) 10638c2ecf20Sopenharmony_ci{ 10648c2ecf20Sopenharmony_ci return atc_daio_unmute(atc, state, LINEO1); 10658c2ecf20Sopenharmony_ci} 10668c2ecf20Sopenharmony_ci 10678c2ecf20Sopenharmony_cistatic int atc_line_surround_unmute(struct ct_atc *atc, unsigned char state) 10688c2ecf20Sopenharmony_ci{ 10698c2ecf20Sopenharmony_ci return atc_daio_unmute(atc, state, LINEO2); 10708c2ecf20Sopenharmony_ci} 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_cistatic int atc_line_clfe_unmute(struct ct_atc *atc, unsigned char state) 10738c2ecf20Sopenharmony_ci{ 10748c2ecf20Sopenharmony_ci return atc_daio_unmute(atc, state, LINEO3); 10758c2ecf20Sopenharmony_ci} 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_cistatic int atc_line_rear_unmute(struct ct_atc *atc, unsigned char state) 10788c2ecf20Sopenharmony_ci{ 10798c2ecf20Sopenharmony_ci return atc_daio_unmute(atc, state, LINEO4); 10808c2ecf20Sopenharmony_ci} 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_cistatic int atc_line_in_unmute(struct ct_atc *atc, unsigned char state) 10838c2ecf20Sopenharmony_ci{ 10848c2ecf20Sopenharmony_ci return atc_daio_unmute(atc, state, LINEIM); 10858c2ecf20Sopenharmony_ci} 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_cistatic int atc_mic_unmute(struct ct_atc *atc, unsigned char state) 10888c2ecf20Sopenharmony_ci{ 10898c2ecf20Sopenharmony_ci return atc_daio_unmute(atc, state, MIC); 10908c2ecf20Sopenharmony_ci} 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_cistatic int atc_spdif_out_unmute(struct ct_atc *atc, unsigned char state) 10938c2ecf20Sopenharmony_ci{ 10948c2ecf20Sopenharmony_ci return atc_daio_unmute(atc, state, SPDIFOO); 10958c2ecf20Sopenharmony_ci} 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_cistatic int atc_spdif_in_unmute(struct ct_atc *atc, unsigned char state) 10988c2ecf20Sopenharmony_ci{ 10998c2ecf20Sopenharmony_ci return atc_daio_unmute(atc, state, SPDIFIO); 11008c2ecf20Sopenharmony_ci} 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_cistatic int atc_spdif_out_get_status(struct ct_atc *atc, unsigned int *status) 11038c2ecf20Sopenharmony_ci{ 11048c2ecf20Sopenharmony_ci return atc_dao_get_status(atc, status, SPDIFOO); 11058c2ecf20Sopenharmony_ci} 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_cistatic int atc_spdif_out_set_status(struct ct_atc *atc, unsigned int status) 11088c2ecf20Sopenharmony_ci{ 11098c2ecf20Sopenharmony_ci return atc_dao_set_status(atc, status, SPDIFOO); 11108c2ecf20Sopenharmony_ci} 11118c2ecf20Sopenharmony_ci 11128c2ecf20Sopenharmony_cistatic int atc_spdif_out_passthru(struct ct_atc *atc, unsigned char state) 11138c2ecf20Sopenharmony_ci{ 11148c2ecf20Sopenharmony_ci struct dao_desc da_dsc = {0}; 11158c2ecf20Sopenharmony_ci struct dao *dao; 11168c2ecf20Sopenharmony_ci int err; 11178c2ecf20Sopenharmony_ci struct ct_mixer *mixer = atc->mixer; 11188c2ecf20Sopenharmony_ci struct rsc *rscs[2] = {NULL}; 11198c2ecf20Sopenharmony_ci unsigned int spos = 0; 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_ci mutex_lock(&atc->atc_mutex); 11228c2ecf20Sopenharmony_ci dao = container_of(atc->daios[SPDIFOO], struct dao, daio); 11238c2ecf20Sopenharmony_ci da_dsc.msr = state ? 1 : atc->msr; 11248c2ecf20Sopenharmony_ci da_dsc.passthru = state ? 1 : 0; 11258c2ecf20Sopenharmony_ci err = dao->ops->reinit(dao, &da_dsc); 11268c2ecf20Sopenharmony_ci if (state) { 11278c2ecf20Sopenharmony_ci spos = IEC958_DEFAULT_CON; 11288c2ecf20Sopenharmony_ci } else { 11298c2ecf20Sopenharmony_ci mixer->get_output_ports(mixer, MIX_SPDIF_OUT, 11308c2ecf20Sopenharmony_ci &rscs[0], &rscs[1]); 11318c2ecf20Sopenharmony_ci dao->ops->set_left_input(dao, rscs[0]); 11328c2ecf20Sopenharmony_ci dao->ops->set_right_input(dao, rscs[1]); 11338c2ecf20Sopenharmony_ci /* Restore PLL to atc->rsr if needed. */ 11348c2ecf20Sopenharmony_ci if (atc->pll_rate != atc->rsr) 11358c2ecf20Sopenharmony_ci err = atc_pll_init(atc, atc->rsr); 11368c2ecf20Sopenharmony_ci } 11378c2ecf20Sopenharmony_ci dao->ops->set_spos(dao, spos); 11388c2ecf20Sopenharmony_ci dao->ops->commit_write(dao); 11398c2ecf20Sopenharmony_ci mutex_unlock(&atc->atc_mutex); 11408c2ecf20Sopenharmony_ci 11418c2ecf20Sopenharmony_ci return err; 11428c2ecf20Sopenharmony_ci} 11438c2ecf20Sopenharmony_ci 11448c2ecf20Sopenharmony_cistatic int atc_release_resources(struct ct_atc *atc) 11458c2ecf20Sopenharmony_ci{ 11468c2ecf20Sopenharmony_ci int i; 11478c2ecf20Sopenharmony_ci struct daio_mgr *daio_mgr = NULL; 11488c2ecf20Sopenharmony_ci struct dao *dao = NULL; 11498c2ecf20Sopenharmony_ci struct daio *daio = NULL; 11508c2ecf20Sopenharmony_ci struct sum_mgr *sum_mgr = NULL; 11518c2ecf20Sopenharmony_ci struct src_mgr *src_mgr = NULL; 11528c2ecf20Sopenharmony_ci struct srcimp_mgr *srcimp_mgr = NULL; 11538c2ecf20Sopenharmony_ci struct srcimp *srcimp = NULL; 11548c2ecf20Sopenharmony_ci struct ct_mixer *mixer = NULL; 11558c2ecf20Sopenharmony_ci 11568c2ecf20Sopenharmony_ci /* disconnect internal mixer objects */ 11578c2ecf20Sopenharmony_ci if (atc->mixer) { 11588c2ecf20Sopenharmony_ci mixer = atc->mixer; 11598c2ecf20Sopenharmony_ci mixer->set_input_left(mixer, MIX_LINE_IN, NULL); 11608c2ecf20Sopenharmony_ci mixer->set_input_right(mixer, MIX_LINE_IN, NULL); 11618c2ecf20Sopenharmony_ci mixer->set_input_left(mixer, MIX_MIC_IN, NULL); 11628c2ecf20Sopenharmony_ci mixer->set_input_right(mixer, MIX_MIC_IN, NULL); 11638c2ecf20Sopenharmony_ci mixer->set_input_left(mixer, MIX_SPDIF_IN, NULL); 11648c2ecf20Sopenharmony_ci mixer->set_input_right(mixer, MIX_SPDIF_IN, NULL); 11658c2ecf20Sopenharmony_ci } 11668c2ecf20Sopenharmony_ci 11678c2ecf20Sopenharmony_ci if (atc->daios) { 11688c2ecf20Sopenharmony_ci daio_mgr = (struct daio_mgr *)atc->rsc_mgrs[DAIO]; 11698c2ecf20Sopenharmony_ci for (i = 0; i < atc->n_daio; i++) { 11708c2ecf20Sopenharmony_ci daio = atc->daios[i]; 11718c2ecf20Sopenharmony_ci if (daio->type < LINEIM) { 11728c2ecf20Sopenharmony_ci dao = container_of(daio, struct dao, daio); 11738c2ecf20Sopenharmony_ci dao->ops->clear_left_input(dao); 11748c2ecf20Sopenharmony_ci dao->ops->clear_right_input(dao); 11758c2ecf20Sopenharmony_ci } 11768c2ecf20Sopenharmony_ci daio_mgr->put_daio(daio_mgr, daio); 11778c2ecf20Sopenharmony_ci } 11788c2ecf20Sopenharmony_ci kfree(atc->daios); 11798c2ecf20Sopenharmony_ci atc->daios = NULL; 11808c2ecf20Sopenharmony_ci } 11818c2ecf20Sopenharmony_ci 11828c2ecf20Sopenharmony_ci if (atc->pcm) { 11838c2ecf20Sopenharmony_ci sum_mgr = atc->rsc_mgrs[SUM]; 11848c2ecf20Sopenharmony_ci for (i = 0; i < atc->n_pcm; i++) 11858c2ecf20Sopenharmony_ci sum_mgr->put_sum(sum_mgr, atc->pcm[i]); 11868c2ecf20Sopenharmony_ci 11878c2ecf20Sopenharmony_ci kfree(atc->pcm); 11888c2ecf20Sopenharmony_ci atc->pcm = NULL; 11898c2ecf20Sopenharmony_ci } 11908c2ecf20Sopenharmony_ci 11918c2ecf20Sopenharmony_ci if (atc->srcs) { 11928c2ecf20Sopenharmony_ci src_mgr = atc->rsc_mgrs[SRC]; 11938c2ecf20Sopenharmony_ci for (i = 0; i < atc->n_src; i++) 11948c2ecf20Sopenharmony_ci src_mgr->put_src(src_mgr, atc->srcs[i]); 11958c2ecf20Sopenharmony_ci 11968c2ecf20Sopenharmony_ci kfree(atc->srcs); 11978c2ecf20Sopenharmony_ci atc->srcs = NULL; 11988c2ecf20Sopenharmony_ci } 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_ci if (atc->srcimps) { 12018c2ecf20Sopenharmony_ci srcimp_mgr = atc->rsc_mgrs[SRCIMP]; 12028c2ecf20Sopenharmony_ci for (i = 0; i < atc->n_srcimp; i++) { 12038c2ecf20Sopenharmony_ci srcimp = atc->srcimps[i]; 12048c2ecf20Sopenharmony_ci srcimp->ops->unmap(srcimp); 12058c2ecf20Sopenharmony_ci srcimp_mgr->put_srcimp(srcimp_mgr, atc->srcimps[i]); 12068c2ecf20Sopenharmony_ci } 12078c2ecf20Sopenharmony_ci kfree(atc->srcimps); 12088c2ecf20Sopenharmony_ci atc->srcimps = NULL; 12098c2ecf20Sopenharmony_ci } 12108c2ecf20Sopenharmony_ci 12118c2ecf20Sopenharmony_ci return 0; 12128c2ecf20Sopenharmony_ci} 12138c2ecf20Sopenharmony_ci 12148c2ecf20Sopenharmony_cistatic int ct_atc_destroy(struct ct_atc *atc) 12158c2ecf20Sopenharmony_ci{ 12168c2ecf20Sopenharmony_ci int i = 0; 12178c2ecf20Sopenharmony_ci 12188c2ecf20Sopenharmony_ci if (!atc) 12198c2ecf20Sopenharmony_ci return 0; 12208c2ecf20Sopenharmony_ci 12218c2ecf20Sopenharmony_ci if (atc->timer) { 12228c2ecf20Sopenharmony_ci ct_timer_free(atc->timer); 12238c2ecf20Sopenharmony_ci atc->timer = NULL; 12248c2ecf20Sopenharmony_ci } 12258c2ecf20Sopenharmony_ci 12268c2ecf20Sopenharmony_ci atc_release_resources(atc); 12278c2ecf20Sopenharmony_ci 12288c2ecf20Sopenharmony_ci /* Destroy internal mixer objects */ 12298c2ecf20Sopenharmony_ci if (atc->mixer) 12308c2ecf20Sopenharmony_ci ct_mixer_destroy(atc->mixer); 12318c2ecf20Sopenharmony_ci 12328c2ecf20Sopenharmony_ci for (i = 0; i < NUM_RSCTYP; i++) { 12338c2ecf20Sopenharmony_ci if (rsc_mgr_funcs[i].destroy && atc->rsc_mgrs[i]) 12348c2ecf20Sopenharmony_ci rsc_mgr_funcs[i].destroy(atc->rsc_mgrs[i]); 12358c2ecf20Sopenharmony_ci 12368c2ecf20Sopenharmony_ci } 12378c2ecf20Sopenharmony_ci 12388c2ecf20Sopenharmony_ci if (atc->hw) 12398c2ecf20Sopenharmony_ci destroy_hw_obj(atc->hw); 12408c2ecf20Sopenharmony_ci 12418c2ecf20Sopenharmony_ci /* Destroy device virtual memory manager object */ 12428c2ecf20Sopenharmony_ci if (atc->vm) { 12438c2ecf20Sopenharmony_ci ct_vm_destroy(atc->vm); 12448c2ecf20Sopenharmony_ci atc->vm = NULL; 12458c2ecf20Sopenharmony_ci } 12468c2ecf20Sopenharmony_ci 12478c2ecf20Sopenharmony_ci kfree(atc); 12488c2ecf20Sopenharmony_ci 12498c2ecf20Sopenharmony_ci return 0; 12508c2ecf20Sopenharmony_ci} 12518c2ecf20Sopenharmony_ci 12528c2ecf20Sopenharmony_cistatic int atc_dev_free(struct snd_device *dev) 12538c2ecf20Sopenharmony_ci{ 12548c2ecf20Sopenharmony_ci struct ct_atc *atc = dev->device_data; 12558c2ecf20Sopenharmony_ci return ct_atc_destroy(atc); 12568c2ecf20Sopenharmony_ci} 12578c2ecf20Sopenharmony_ci 12588c2ecf20Sopenharmony_cistatic int atc_identify_card(struct ct_atc *atc, unsigned int ssid) 12598c2ecf20Sopenharmony_ci{ 12608c2ecf20Sopenharmony_ci const struct snd_pci_quirk *p; 12618c2ecf20Sopenharmony_ci const struct snd_pci_quirk *list; 12628c2ecf20Sopenharmony_ci u16 vendor_id, device_id; 12638c2ecf20Sopenharmony_ci 12648c2ecf20Sopenharmony_ci switch (atc->chip_type) { 12658c2ecf20Sopenharmony_ci case ATC20K1: 12668c2ecf20Sopenharmony_ci atc->chip_name = "20K1"; 12678c2ecf20Sopenharmony_ci list = subsys_20k1_list; 12688c2ecf20Sopenharmony_ci break; 12698c2ecf20Sopenharmony_ci case ATC20K2: 12708c2ecf20Sopenharmony_ci atc->chip_name = "20K2"; 12718c2ecf20Sopenharmony_ci list = subsys_20k2_list; 12728c2ecf20Sopenharmony_ci break; 12738c2ecf20Sopenharmony_ci default: 12748c2ecf20Sopenharmony_ci return -ENOENT; 12758c2ecf20Sopenharmony_ci } 12768c2ecf20Sopenharmony_ci if (ssid) { 12778c2ecf20Sopenharmony_ci vendor_id = ssid >> 16; 12788c2ecf20Sopenharmony_ci device_id = ssid & 0xffff; 12798c2ecf20Sopenharmony_ci } else { 12808c2ecf20Sopenharmony_ci vendor_id = atc->pci->subsystem_vendor; 12818c2ecf20Sopenharmony_ci device_id = atc->pci->subsystem_device; 12828c2ecf20Sopenharmony_ci } 12838c2ecf20Sopenharmony_ci p = snd_pci_quirk_lookup_id(vendor_id, device_id, list); 12848c2ecf20Sopenharmony_ci if (p) { 12858c2ecf20Sopenharmony_ci if (p->value < 0) { 12868c2ecf20Sopenharmony_ci dev_err(atc->card->dev, 12878c2ecf20Sopenharmony_ci "Device %04x:%04x is on the denylist\n", 12888c2ecf20Sopenharmony_ci vendor_id, device_id); 12898c2ecf20Sopenharmony_ci return -ENOENT; 12908c2ecf20Sopenharmony_ci } 12918c2ecf20Sopenharmony_ci atc->model = p->value; 12928c2ecf20Sopenharmony_ci } else { 12938c2ecf20Sopenharmony_ci if (atc->chip_type == ATC20K1) 12948c2ecf20Sopenharmony_ci atc->model = CT20K1_UNKNOWN; 12958c2ecf20Sopenharmony_ci else 12968c2ecf20Sopenharmony_ci atc->model = CT20K2_UNKNOWN; 12978c2ecf20Sopenharmony_ci } 12988c2ecf20Sopenharmony_ci atc->model_name = ct_subsys_name[atc->model]; 12998c2ecf20Sopenharmony_ci dev_info(atc->card->dev, "chip %s model %s (%04x:%04x) is found\n", 13008c2ecf20Sopenharmony_ci atc->chip_name, atc->model_name, 13018c2ecf20Sopenharmony_ci vendor_id, device_id); 13028c2ecf20Sopenharmony_ci return 0; 13038c2ecf20Sopenharmony_ci} 13048c2ecf20Sopenharmony_ci 13058c2ecf20Sopenharmony_ciint ct_atc_create_alsa_devs(struct ct_atc *atc) 13068c2ecf20Sopenharmony_ci{ 13078c2ecf20Sopenharmony_ci enum CTALSADEVS i; 13088c2ecf20Sopenharmony_ci int err; 13098c2ecf20Sopenharmony_ci 13108c2ecf20Sopenharmony_ci alsa_dev_funcs[MIXER].public_name = atc->chip_name; 13118c2ecf20Sopenharmony_ci 13128c2ecf20Sopenharmony_ci for (i = 0; i < NUM_CTALSADEVS; i++) { 13138c2ecf20Sopenharmony_ci if (!alsa_dev_funcs[i].create) 13148c2ecf20Sopenharmony_ci continue; 13158c2ecf20Sopenharmony_ci 13168c2ecf20Sopenharmony_ci err = alsa_dev_funcs[i].create(atc, i, 13178c2ecf20Sopenharmony_ci alsa_dev_funcs[i].public_name); 13188c2ecf20Sopenharmony_ci if (err) { 13198c2ecf20Sopenharmony_ci dev_err(atc->card->dev, 13208c2ecf20Sopenharmony_ci "Creating alsa device %d failed!\n", i); 13218c2ecf20Sopenharmony_ci return err; 13228c2ecf20Sopenharmony_ci } 13238c2ecf20Sopenharmony_ci } 13248c2ecf20Sopenharmony_ci 13258c2ecf20Sopenharmony_ci return 0; 13268c2ecf20Sopenharmony_ci} 13278c2ecf20Sopenharmony_ci 13288c2ecf20Sopenharmony_cistatic int atc_create_hw_devs(struct ct_atc *atc) 13298c2ecf20Sopenharmony_ci{ 13308c2ecf20Sopenharmony_ci struct hw *hw; 13318c2ecf20Sopenharmony_ci struct card_conf info = {0}; 13328c2ecf20Sopenharmony_ci int i, err; 13338c2ecf20Sopenharmony_ci 13348c2ecf20Sopenharmony_ci err = create_hw_obj(atc->pci, atc->chip_type, atc->model, &hw); 13358c2ecf20Sopenharmony_ci if (err) { 13368c2ecf20Sopenharmony_ci dev_err(atc->card->dev, "Failed to create hw obj!!!\n"); 13378c2ecf20Sopenharmony_ci return err; 13388c2ecf20Sopenharmony_ci } 13398c2ecf20Sopenharmony_ci hw->card = atc->card; 13408c2ecf20Sopenharmony_ci atc->hw = hw; 13418c2ecf20Sopenharmony_ci 13428c2ecf20Sopenharmony_ci /* Initialize card hardware. */ 13438c2ecf20Sopenharmony_ci info.rsr = atc->rsr; 13448c2ecf20Sopenharmony_ci info.msr = atc->msr; 13458c2ecf20Sopenharmony_ci info.vm_pgt_phys = atc_get_ptp_phys(atc, 0); 13468c2ecf20Sopenharmony_ci err = hw->card_init(hw, &info); 13478c2ecf20Sopenharmony_ci if (err < 0) 13488c2ecf20Sopenharmony_ci return err; 13498c2ecf20Sopenharmony_ci 13508c2ecf20Sopenharmony_ci for (i = 0; i < NUM_RSCTYP; i++) { 13518c2ecf20Sopenharmony_ci if (!rsc_mgr_funcs[i].create) 13528c2ecf20Sopenharmony_ci continue; 13538c2ecf20Sopenharmony_ci 13548c2ecf20Sopenharmony_ci err = rsc_mgr_funcs[i].create(atc->hw, &atc->rsc_mgrs[i]); 13558c2ecf20Sopenharmony_ci if (err) { 13568c2ecf20Sopenharmony_ci dev_err(atc->card->dev, 13578c2ecf20Sopenharmony_ci "Failed to create rsc_mgr %d!!!\n", i); 13588c2ecf20Sopenharmony_ci return err; 13598c2ecf20Sopenharmony_ci } 13608c2ecf20Sopenharmony_ci } 13618c2ecf20Sopenharmony_ci 13628c2ecf20Sopenharmony_ci return 0; 13638c2ecf20Sopenharmony_ci} 13648c2ecf20Sopenharmony_ci 13658c2ecf20Sopenharmony_cistatic int atc_get_resources(struct ct_atc *atc) 13668c2ecf20Sopenharmony_ci{ 13678c2ecf20Sopenharmony_ci struct daio_desc da_desc = {0}; 13688c2ecf20Sopenharmony_ci struct daio_mgr *daio_mgr; 13698c2ecf20Sopenharmony_ci struct src_desc src_dsc = {0}; 13708c2ecf20Sopenharmony_ci struct src_mgr *src_mgr; 13718c2ecf20Sopenharmony_ci struct srcimp_desc srcimp_dsc = {0}; 13728c2ecf20Sopenharmony_ci struct srcimp_mgr *srcimp_mgr; 13738c2ecf20Sopenharmony_ci struct sum_desc sum_dsc = {0}; 13748c2ecf20Sopenharmony_ci struct sum_mgr *sum_mgr; 13758c2ecf20Sopenharmony_ci int err, i, num_srcs, num_daios; 13768c2ecf20Sopenharmony_ci 13778c2ecf20Sopenharmony_ci num_daios = ((atc->model == CTSB1270) ? 8 : 7); 13788c2ecf20Sopenharmony_ci num_srcs = ((atc->model == CTSB1270) ? 6 : 4); 13798c2ecf20Sopenharmony_ci 13808c2ecf20Sopenharmony_ci atc->daios = kcalloc(num_daios, sizeof(void *), GFP_KERNEL); 13818c2ecf20Sopenharmony_ci if (!atc->daios) 13828c2ecf20Sopenharmony_ci return -ENOMEM; 13838c2ecf20Sopenharmony_ci 13848c2ecf20Sopenharmony_ci atc->srcs = kcalloc(num_srcs, sizeof(void *), GFP_KERNEL); 13858c2ecf20Sopenharmony_ci if (!atc->srcs) 13868c2ecf20Sopenharmony_ci return -ENOMEM; 13878c2ecf20Sopenharmony_ci 13888c2ecf20Sopenharmony_ci atc->srcimps = kcalloc(num_srcs, sizeof(void *), GFP_KERNEL); 13898c2ecf20Sopenharmony_ci if (!atc->srcimps) 13908c2ecf20Sopenharmony_ci return -ENOMEM; 13918c2ecf20Sopenharmony_ci 13928c2ecf20Sopenharmony_ci atc->pcm = kcalloc(2 * 4, sizeof(void *), GFP_KERNEL); 13938c2ecf20Sopenharmony_ci if (!atc->pcm) 13948c2ecf20Sopenharmony_ci return -ENOMEM; 13958c2ecf20Sopenharmony_ci 13968c2ecf20Sopenharmony_ci daio_mgr = (struct daio_mgr *)atc->rsc_mgrs[DAIO]; 13978c2ecf20Sopenharmony_ci da_desc.msr = atc->msr; 13988c2ecf20Sopenharmony_ci for (i = 0, atc->n_daio = 0; i < num_daios; i++) { 13998c2ecf20Sopenharmony_ci da_desc.type = (atc->model != CTSB073X) ? i : 14008c2ecf20Sopenharmony_ci ((i == SPDIFIO) ? SPDIFI1 : i); 14018c2ecf20Sopenharmony_ci err = daio_mgr->get_daio(daio_mgr, &da_desc, 14028c2ecf20Sopenharmony_ci (struct daio **)&atc->daios[i]); 14038c2ecf20Sopenharmony_ci if (err) { 14048c2ecf20Sopenharmony_ci dev_err(atc->card->dev, 14058c2ecf20Sopenharmony_ci "Failed to get DAIO resource %d!!!\n", 14068c2ecf20Sopenharmony_ci i); 14078c2ecf20Sopenharmony_ci return err; 14088c2ecf20Sopenharmony_ci } 14098c2ecf20Sopenharmony_ci atc->n_daio++; 14108c2ecf20Sopenharmony_ci } 14118c2ecf20Sopenharmony_ci 14128c2ecf20Sopenharmony_ci src_mgr = atc->rsc_mgrs[SRC]; 14138c2ecf20Sopenharmony_ci src_dsc.multi = 1; 14148c2ecf20Sopenharmony_ci src_dsc.msr = atc->msr; 14158c2ecf20Sopenharmony_ci src_dsc.mode = ARCRW; 14168c2ecf20Sopenharmony_ci for (i = 0, atc->n_src = 0; i < num_srcs; i++) { 14178c2ecf20Sopenharmony_ci err = src_mgr->get_src(src_mgr, &src_dsc, 14188c2ecf20Sopenharmony_ci (struct src **)&atc->srcs[i]); 14198c2ecf20Sopenharmony_ci if (err) 14208c2ecf20Sopenharmony_ci return err; 14218c2ecf20Sopenharmony_ci 14228c2ecf20Sopenharmony_ci atc->n_src++; 14238c2ecf20Sopenharmony_ci } 14248c2ecf20Sopenharmony_ci 14258c2ecf20Sopenharmony_ci srcimp_mgr = atc->rsc_mgrs[SRCIMP]; 14268c2ecf20Sopenharmony_ci srcimp_dsc.msr = 8; 14278c2ecf20Sopenharmony_ci for (i = 0, atc->n_srcimp = 0; i < num_srcs; i++) { 14288c2ecf20Sopenharmony_ci err = srcimp_mgr->get_srcimp(srcimp_mgr, &srcimp_dsc, 14298c2ecf20Sopenharmony_ci (struct srcimp **)&atc->srcimps[i]); 14308c2ecf20Sopenharmony_ci if (err) 14318c2ecf20Sopenharmony_ci return err; 14328c2ecf20Sopenharmony_ci 14338c2ecf20Sopenharmony_ci atc->n_srcimp++; 14348c2ecf20Sopenharmony_ci } 14358c2ecf20Sopenharmony_ci 14368c2ecf20Sopenharmony_ci sum_mgr = atc->rsc_mgrs[SUM]; 14378c2ecf20Sopenharmony_ci sum_dsc.msr = atc->msr; 14388c2ecf20Sopenharmony_ci for (i = 0, atc->n_pcm = 0; i < (2*4); i++) { 14398c2ecf20Sopenharmony_ci err = sum_mgr->get_sum(sum_mgr, &sum_dsc, 14408c2ecf20Sopenharmony_ci (struct sum **)&atc->pcm[i]); 14418c2ecf20Sopenharmony_ci if (err) 14428c2ecf20Sopenharmony_ci return err; 14438c2ecf20Sopenharmony_ci 14448c2ecf20Sopenharmony_ci atc->n_pcm++; 14458c2ecf20Sopenharmony_ci } 14468c2ecf20Sopenharmony_ci 14478c2ecf20Sopenharmony_ci return 0; 14488c2ecf20Sopenharmony_ci} 14498c2ecf20Sopenharmony_ci 14508c2ecf20Sopenharmony_cistatic void 14518c2ecf20Sopenharmony_ciatc_connect_dai(struct src_mgr *src_mgr, struct dai *dai, 14528c2ecf20Sopenharmony_ci struct src **srcs, struct srcimp **srcimps) 14538c2ecf20Sopenharmony_ci{ 14548c2ecf20Sopenharmony_ci struct rsc *rscs[2] = {NULL}; 14558c2ecf20Sopenharmony_ci struct src *src; 14568c2ecf20Sopenharmony_ci struct srcimp *srcimp; 14578c2ecf20Sopenharmony_ci int i = 0; 14588c2ecf20Sopenharmony_ci 14598c2ecf20Sopenharmony_ci rscs[0] = &dai->daio.rscl; 14608c2ecf20Sopenharmony_ci rscs[1] = &dai->daio.rscr; 14618c2ecf20Sopenharmony_ci for (i = 0; i < 2; i++) { 14628c2ecf20Sopenharmony_ci src = srcs[i]; 14638c2ecf20Sopenharmony_ci srcimp = srcimps[i]; 14648c2ecf20Sopenharmony_ci srcimp->ops->map(srcimp, src, rscs[i]); 14658c2ecf20Sopenharmony_ci src_mgr->src_disable(src_mgr, src); 14668c2ecf20Sopenharmony_ci } 14678c2ecf20Sopenharmony_ci 14688c2ecf20Sopenharmony_ci src_mgr->commit_write(src_mgr); /* Actually disable SRCs */ 14698c2ecf20Sopenharmony_ci 14708c2ecf20Sopenharmony_ci src = srcs[0]; 14718c2ecf20Sopenharmony_ci src->ops->set_pm(src, 1); 14728c2ecf20Sopenharmony_ci for (i = 0; i < 2; i++) { 14738c2ecf20Sopenharmony_ci src = srcs[i]; 14748c2ecf20Sopenharmony_ci src->ops->set_state(src, SRC_STATE_RUN); 14758c2ecf20Sopenharmony_ci src->ops->commit_write(src); 14768c2ecf20Sopenharmony_ci src_mgr->src_enable_s(src_mgr, src); 14778c2ecf20Sopenharmony_ci } 14788c2ecf20Sopenharmony_ci 14798c2ecf20Sopenharmony_ci dai->ops->set_srt_srcl(dai, &(srcs[0]->rsc)); 14808c2ecf20Sopenharmony_ci dai->ops->set_srt_srcr(dai, &(srcs[1]->rsc)); 14818c2ecf20Sopenharmony_ci 14828c2ecf20Sopenharmony_ci dai->ops->set_enb_src(dai, 1); 14838c2ecf20Sopenharmony_ci dai->ops->set_enb_srt(dai, 1); 14848c2ecf20Sopenharmony_ci dai->ops->commit_write(dai); 14858c2ecf20Sopenharmony_ci 14868c2ecf20Sopenharmony_ci src_mgr->commit_write(src_mgr); /* Synchronously enable SRCs */ 14878c2ecf20Sopenharmony_ci} 14888c2ecf20Sopenharmony_ci 14898c2ecf20Sopenharmony_cistatic void atc_connect_resources(struct ct_atc *atc) 14908c2ecf20Sopenharmony_ci{ 14918c2ecf20Sopenharmony_ci struct dai *dai; 14928c2ecf20Sopenharmony_ci struct dao *dao; 14938c2ecf20Sopenharmony_ci struct src *src; 14948c2ecf20Sopenharmony_ci struct sum *sum; 14958c2ecf20Sopenharmony_ci struct ct_mixer *mixer; 14968c2ecf20Sopenharmony_ci struct rsc *rscs[2] = {NULL}; 14978c2ecf20Sopenharmony_ci int i, j; 14988c2ecf20Sopenharmony_ci 14998c2ecf20Sopenharmony_ci mixer = atc->mixer; 15008c2ecf20Sopenharmony_ci 15018c2ecf20Sopenharmony_ci for (i = MIX_WAVE_FRONT, j = LINEO1; i <= MIX_SPDIF_OUT; i++, j++) { 15028c2ecf20Sopenharmony_ci mixer->get_output_ports(mixer, i, &rscs[0], &rscs[1]); 15038c2ecf20Sopenharmony_ci dao = container_of(atc->daios[j], struct dao, daio); 15048c2ecf20Sopenharmony_ci dao->ops->set_left_input(dao, rscs[0]); 15058c2ecf20Sopenharmony_ci dao->ops->set_right_input(dao, rscs[1]); 15068c2ecf20Sopenharmony_ci } 15078c2ecf20Sopenharmony_ci 15088c2ecf20Sopenharmony_ci dai = container_of(atc->daios[LINEIM], struct dai, daio); 15098c2ecf20Sopenharmony_ci atc_connect_dai(atc->rsc_mgrs[SRC], dai, 15108c2ecf20Sopenharmony_ci (struct src **)&atc->srcs[2], 15118c2ecf20Sopenharmony_ci (struct srcimp **)&atc->srcimps[2]); 15128c2ecf20Sopenharmony_ci src = atc->srcs[2]; 15138c2ecf20Sopenharmony_ci mixer->set_input_left(mixer, MIX_LINE_IN, &src->rsc); 15148c2ecf20Sopenharmony_ci src = atc->srcs[3]; 15158c2ecf20Sopenharmony_ci mixer->set_input_right(mixer, MIX_LINE_IN, &src->rsc); 15168c2ecf20Sopenharmony_ci 15178c2ecf20Sopenharmony_ci if (atc->model == CTSB1270) { 15188c2ecf20Sopenharmony_ci /* Titanium HD has a dedicated ADC for the Mic. */ 15198c2ecf20Sopenharmony_ci dai = container_of(atc->daios[MIC], struct dai, daio); 15208c2ecf20Sopenharmony_ci atc_connect_dai(atc->rsc_mgrs[SRC], dai, 15218c2ecf20Sopenharmony_ci (struct src **)&atc->srcs[4], 15228c2ecf20Sopenharmony_ci (struct srcimp **)&atc->srcimps[4]); 15238c2ecf20Sopenharmony_ci src = atc->srcs[4]; 15248c2ecf20Sopenharmony_ci mixer->set_input_left(mixer, MIX_MIC_IN, &src->rsc); 15258c2ecf20Sopenharmony_ci src = atc->srcs[5]; 15268c2ecf20Sopenharmony_ci mixer->set_input_right(mixer, MIX_MIC_IN, &src->rsc); 15278c2ecf20Sopenharmony_ci } 15288c2ecf20Sopenharmony_ci 15298c2ecf20Sopenharmony_ci dai = container_of(atc->daios[SPDIFIO], struct dai, daio); 15308c2ecf20Sopenharmony_ci atc_connect_dai(atc->rsc_mgrs[SRC], dai, 15318c2ecf20Sopenharmony_ci (struct src **)&atc->srcs[0], 15328c2ecf20Sopenharmony_ci (struct srcimp **)&atc->srcimps[0]); 15338c2ecf20Sopenharmony_ci 15348c2ecf20Sopenharmony_ci src = atc->srcs[0]; 15358c2ecf20Sopenharmony_ci mixer->set_input_left(mixer, MIX_SPDIF_IN, &src->rsc); 15368c2ecf20Sopenharmony_ci src = atc->srcs[1]; 15378c2ecf20Sopenharmony_ci mixer->set_input_right(mixer, MIX_SPDIF_IN, &src->rsc); 15388c2ecf20Sopenharmony_ci 15398c2ecf20Sopenharmony_ci for (i = MIX_PCMI_FRONT, j = 0; i <= MIX_PCMI_SURROUND; i++, j += 2) { 15408c2ecf20Sopenharmony_ci sum = atc->pcm[j]; 15418c2ecf20Sopenharmony_ci mixer->set_input_left(mixer, i, &sum->rsc); 15428c2ecf20Sopenharmony_ci sum = atc->pcm[j+1]; 15438c2ecf20Sopenharmony_ci mixer->set_input_right(mixer, i, &sum->rsc); 15448c2ecf20Sopenharmony_ci } 15458c2ecf20Sopenharmony_ci} 15468c2ecf20Sopenharmony_ci 15478c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 15488c2ecf20Sopenharmony_cistatic int atc_suspend(struct ct_atc *atc) 15498c2ecf20Sopenharmony_ci{ 15508c2ecf20Sopenharmony_ci struct hw *hw = atc->hw; 15518c2ecf20Sopenharmony_ci 15528c2ecf20Sopenharmony_ci snd_power_change_state(atc->card, SNDRV_CTL_POWER_D3hot); 15538c2ecf20Sopenharmony_ci 15548c2ecf20Sopenharmony_ci atc_release_resources(atc); 15558c2ecf20Sopenharmony_ci 15568c2ecf20Sopenharmony_ci hw->suspend(hw); 15578c2ecf20Sopenharmony_ci 15588c2ecf20Sopenharmony_ci return 0; 15598c2ecf20Sopenharmony_ci} 15608c2ecf20Sopenharmony_ci 15618c2ecf20Sopenharmony_cistatic int atc_hw_resume(struct ct_atc *atc) 15628c2ecf20Sopenharmony_ci{ 15638c2ecf20Sopenharmony_ci struct hw *hw = atc->hw; 15648c2ecf20Sopenharmony_ci struct card_conf info = {0}; 15658c2ecf20Sopenharmony_ci 15668c2ecf20Sopenharmony_ci /* Re-initialize card hardware. */ 15678c2ecf20Sopenharmony_ci info.rsr = atc->rsr; 15688c2ecf20Sopenharmony_ci info.msr = atc->msr; 15698c2ecf20Sopenharmony_ci info.vm_pgt_phys = atc_get_ptp_phys(atc, 0); 15708c2ecf20Sopenharmony_ci return hw->resume(hw, &info); 15718c2ecf20Sopenharmony_ci} 15728c2ecf20Sopenharmony_ci 15738c2ecf20Sopenharmony_cistatic int atc_resources_resume(struct ct_atc *atc) 15748c2ecf20Sopenharmony_ci{ 15758c2ecf20Sopenharmony_ci struct ct_mixer *mixer; 15768c2ecf20Sopenharmony_ci int err = 0; 15778c2ecf20Sopenharmony_ci 15788c2ecf20Sopenharmony_ci /* Get resources */ 15798c2ecf20Sopenharmony_ci err = atc_get_resources(atc); 15808c2ecf20Sopenharmony_ci if (err < 0) { 15818c2ecf20Sopenharmony_ci atc_release_resources(atc); 15828c2ecf20Sopenharmony_ci return err; 15838c2ecf20Sopenharmony_ci } 15848c2ecf20Sopenharmony_ci 15858c2ecf20Sopenharmony_ci /* Build topology */ 15868c2ecf20Sopenharmony_ci atc_connect_resources(atc); 15878c2ecf20Sopenharmony_ci 15888c2ecf20Sopenharmony_ci mixer = atc->mixer; 15898c2ecf20Sopenharmony_ci mixer->resume(mixer); 15908c2ecf20Sopenharmony_ci 15918c2ecf20Sopenharmony_ci return 0; 15928c2ecf20Sopenharmony_ci} 15938c2ecf20Sopenharmony_ci 15948c2ecf20Sopenharmony_cistatic int atc_resume(struct ct_atc *atc) 15958c2ecf20Sopenharmony_ci{ 15968c2ecf20Sopenharmony_ci int err = 0; 15978c2ecf20Sopenharmony_ci 15988c2ecf20Sopenharmony_ci /* Do hardware resume. */ 15998c2ecf20Sopenharmony_ci err = atc_hw_resume(atc); 16008c2ecf20Sopenharmony_ci if (err < 0) { 16018c2ecf20Sopenharmony_ci dev_err(atc->card->dev, 16028c2ecf20Sopenharmony_ci "pci_enable_device failed, disabling device\n"); 16038c2ecf20Sopenharmony_ci snd_card_disconnect(atc->card); 16048c2ecf20Sopenharmony_ci return err; 16058c2ecf20Sopenharmony_ci } 16068c2ecf20Sopenharmony_ci 16078c2ecf20Sopenharmony_ci err = atc_resources_resume(atc); 16088c2ecf20Sopenharmony_ci if (err < 0) 16098c2ecf20Sopenharmony_ci return err; 16108c2ecf20Sopenharmony_ci 16118c2ecf20Sopenharmony_ci snd_power_change_state(atc->card, SNDRV_CTL_POWER_D0); 16128c2ecf20Sopenharmony_ci 16138c2ecf20Sopenharmony_ci return 0; 16148c2ecf20Sopenharmony_ci} 16158c2ecf20Sopenharmony_ci#endif 16168c2ecf20Sopenharmony_ci 16178c2ecf20Sopenharmony_cistatic const struct ct_atc atc_preset = { 16188c2ecf20Sopenharmony_ci .map_audio_buffer = ct_map_audio_buffer, 16198c2ecf20Sopenharmony_ci .unmap_audio_buffer = ct_unmap_audio_buffer, 16208c2ecf20Sopenharmony_ci .pcm_playback_prepare = atc_pcm_playback_prepare, 16218c2ecf20Sopenharmony_ci .pcm_release_resources = atc_pcm_release_resources, 16228c2ecf20Sopenharmony_ci .pcm_playback_start = atc_pcm_playback_start, 16238c2ecf20Sopenharmony_ci .pcm_playback_stop = atc_pcm_stop, 16248c2ecf20Sopenharmony_ci .pcm_playback_position = atc_pcm_playback_position, 16258c2ecf20Sopenharmony_ci .pcm_capture_prepare = atc_pcm_capture_prepare, 16268c2ecf20Sopenharmony_ci .pcm_capture_start = atc_pcm_capture_start, 16278c2ecf20Sopenharmony_ci .pcm_capture_stop = atc_pcm_stop, 16288c2ecf20Sopenharmony_ci .pcm_capture_position = atc_pcm_capture_position, 16298c2ecf20Sopenharmony_ci .spdif_passthru_playback_prepare = spdif_passthru_playback_prepare, 16308c2ecf20Sopenharmony_ci .get_ptp_phys = atc_get_ptp_phys, 16318c2ecf20Sopenharmony_ci .select_line_in = atc_select_line_in, 16328c2ecf20Sopenharmony_ci .select_mic_in = atc_select_mic_in, 16338c2ecf20Sopenharmony_ci .select_digit_io = atc_select_digit_io, 16348c2ecf20Sopenharmony_ci .line_front_unmute = atc_line_front_unmute, 16358c2ecf20Sopenharmony_ci .line_surround_unmute = atc_line_surround_unmute, 16368c2ecf20Sopenharmony_ci .line_clfe_unmute = atc_line_clfe_unmute, 16378c2ecf20Sopenharmony_ci .line_rear_unmute = atc_line_rear_unmute, 16388c2ecf20Sopenharmony_ci .line_in_unmute = atc_line_in_unmute, 16398c2ecf20Sopenharmony_ci .mic_unmute = atc_mic_unmute, 16408c2ecf20Sopenharmony_ci .spdif_out_unmute = atc_spdif_out_unmute, 16418c2ecf20Sopenharmony_ci .spdif_in_unmute = atc_spdif_in_unmute, 16428c2ecf20Sopenharmony_ci .spdif_out_get_status = atc_spdif_out_get_status, 16438c2ecf20Sopenharmony_ci .spdif_out_set_status = atc_spdif_out_set_status, 16448c2ecf20Sopenharmony_ci .spdif_out_passthru = atc_spdif_out_passthru, 16458c2ecf20Sopenharmony_ci .capabilities = atc_capabilities, 16468c2ecf20Sopenharmony_ci .output_switch_get = atc_output_switch_get, 16478c2ecf20Sopenharmony_ci .output_switch_put = atc_output_switch_put, 16488c2ecf20Sopenharmony_ci .mic_source_switch_get = atc_mic_source_switch_get, 16498c2ecf20Sopenharmony_ci .mic_source_switch_put = atc_mic_source_switch_put, 16508c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 16518c2ecf20Sopenharmony_ci .suspend = atc_suspend, 16528c2ecf20Sopenharmony_ci .resume = atc_resume, 16538c2ecf20Sopenharmony_ci#endif 16548c2ecf20Sopenharmony_ci}; 16558c2ecf20Sopenharmony_ci 16568c2ecf20Sopenharmony_ci/** 16578c2ecf20Sopenharmony_ci * ct_atc_create - create and initialize a hardware manager 16588c2ecf20Sopenharmony_ci * @card: corresponding alsa card object 16598c2ecf20Sopenharmony_ci * @pci: corresponding kernel pci device object 16608c2ecf20Sopenharmony_ci * @rsr: reference sampling rate 16618c2ecf20Sopenharmony_ci * @msr: master sampling rate 16628c2ecf20Sopenharmony_ci * @chip_type: CHIPTYP enum values 16638c2ecf20Sopenharmony_ci * @ssid: vendor ID (upper 16 bits) and device ID (lower 16 bits) 16648c2ecf20Sopenharmony_ci * @ratc: return created object address in it 16658c2ecf20Sopenharmony_ci * 16668c2ecf20Sopenharmony_ci * Creates and initializes a hardware manager. 16678c2ecf20Sopenharmony_ci * 16688c2ecf20Sopenharmony_ci * Creates kmallocated ct_atc structure. Initializes hardware. 16698c2ecf20Sopenharmony_ci * Returns 0 if succeeds, or negative error code if fails. 16708c2ecf20Sopenharmony_ci */ 16718c2ecf20Sopenharmony_ci 16728c2ecf20Sopenharmony_ciint ct_atc_create(struct snd_card *card, struct pci_dev *pci, 16738c2ecf20Sopenharmony_ci unsigned int rsr, unsigned int msr, 16748c2ecf20Sopenharmony_ci int chip_type, unsigned int ssid, 16758c2ecf20Sopenharmony_ci struct ct_atc **ratc) 16768c2ecf20Sopenharmony_ci{ 16778c2ecf20Sopenharmony_ci struct ct_atc *atc; 16788c2ecf20Sopenharmony_ci static const struct snd_device_ops ops = { 16798c2ecf20Sopenharmony_ci .dev_free = atc_dev_free, 16808c2ecf20Sopenharmony_ci }; 16818c2ecf20Sopenharmony_ci int err; 16828c2ecf20Sopenharmony_ci 16838c2ecf20Sopenharmony_ci *ratc = NULL; 16848c2ecf20Sopenharmony_ci 16858c2ecf20Sopenharmony_ci atc = kzalloc(sizeof(*atc), GFP_KERNEL); 16868c2ecf20Sopenharmony_ci if (!atc) 16878c2ecf20Sopenharmony_ci return -ENOMEM; 16888c2ecf20Sopenharmony_ci 16898c2ecf20Sopenharmony_ci /* Set operations */ 16908c2ecf20Sopenharmony_ci *atc = atc_preset; 16918c2ecf20Sopenharmony_ci 16928c2ecf20Sopenharmony_ci atc->card = card; 16938c2ecf20Sopenharmony_ci atc->pci = pci; 16948c2ecf20Sopenharmony_ci atc->rsr = rsr; 16958c2ecf20Sopenharmony_ci atc->msr = msr; 16968c2ecf20Sopenharmony_ci atc->chip_type = chip_type; 16978c2ecf20Sopenharmony_ci 16988c2ecf20Sopenharmony_ci mutex_init(&atc->atc_mutex); 16998c2ecf20Sopenharmony_ci 17008c2ecf20Sopenharmony_ci /* Find card model */ 17018c2ecf20Sopenharmony_ci err = atc_identify_card(atc, ssid); 17028c2ecf20Sopenharmony_ci if (err < 0) { 17038c2ecf20Sopenharmony_ci dev_err(card->dev, "ctatc: Card not recognised\n"); 17048c2ecf20Sopenharmony_ci goto error1; 17058c2ecf20Sopenharmony_ci } 17068c2ecf20Sopenharmony_ci 17078c2ecf20Sopenharmony_ci /* Set up device virtual memory management object */ 17088c2ecf20Sopenharmony_ci err = ct_vm_create(&atc->vm, pci); 17098c2ecf20Sopenharmony_ci if (err < 0) 17108c2ecf20Sopenharmony_ci goto error1; 17118c2ecf20Sopenharmony_ci 17128c2ecf20Sopenharmony_ci /* Create all atc hw devices */ 17138c2ecf20Sopenharmony_ci err = atc_create_hw_devs(atc); 17148c2ecf20Sopenharmony_ci if (err < 0) 17158c2ecf20Sopenharmony_ci goto error1; 17168c2ecf20Sopenharmony_ci 17178c2ecf20Sopenharmony_ci err = ct_mixer_create(atc, (struct ct_mixer **)&atc->mixer); 17188c2ecf20Sopenharmony_ci if (err) { 17198c2ecf20Sopenharmony_ci dev_err(card->dev, "Failed to create mixer obj!!!\n"); 17208c2ecf20Sopenharmony_ci goto error1; 17218c2ecf20Sopenharmony_ci } 17228c2ecf20Sopenharmony_ci 17238c2ecf20Sopenharmony_ci /* Get resources */ 17248c2ecf20Sopenharmony_ci err = atc_get_resources(atc); 17258c2ecf20Sopenharmony_ci if (err < 0) 17268c2ecf20Sopenharmony_ci goto error1; 17278c2ecf20Sopenharmony_ci 17288c2ecf20Sopenharmony_ci /* Build topology */ 17298c2ecf20Sopenharmony_ci atc_connect_resources(atc); 17308c2ecf20Sopenharmony_ci 17318c2ecf20Sopenharmony_ci atc->timer = ct_timer_new(atc); 17328c2ecf20Sopenharmony_ci if (!atc->timer) { 17338c2ecf20Sopenharmony_ci err = -ENOMEM; 17348c2ecf20Sopenharmony_ci goto error1; 17358c2ecf20Sopenharmony_ci } 17368c2ecf20Sopenharmony_ci 17378c2ecf20Sopenharmony_ci err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, atc, &ops); 17388c2ecf20Sopenharmony_ci if (err < 0) 17398c2ecf20Sopenharmony_ci goto error1; 17408c2ecf20Sopenharmony_ci 17418c2ecf20Sopenharmony_ci *ratc = atc; 17428c2ecf20Sopenharmony_ci return 0; 17438c2ecf20Sopenharmony_ci 17448c2ecf20Sopenharmony_cierror1: 17458c2ecf20Sopenharmony_ci ct_atc_destroy(atc); 17468c2ecf20Sopenharmony_ci dev_err(card->dev, "Something wrong!!!\n"); 17478c2ecf20Sopenharmony_ci return err; 17488c2ecf20Sopenharmony_ci} 1749