xref: /kernel/linux/linux-5.10/sound/pci/ctxfi/ctatc.c (revision 8c2ecf20)
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