xref: /openbmc/linux/sound/pci/ctxfi/ctatc.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
15765e78eSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2a08b9f2fSAditya Srivastava /*
38cc72361SWai Yew CHAY  * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
48cc72361SWai Yew CHAY  *
58cc72361SWai Yew CHAY  * @File    ctatc.c
68cc72361SWai Yew CHAY  *
78cc72361SWai Yew CHAY  * @Brief
88cc72361SWai Yew CHAY  * This file contains the implementation of the device resource management
98cc72361SWai Yew CHAY  * object.
108cc72361SWai Yew CHAY  *
118cc72361SWai Yew CHAY  * @Author Liu Chun
128cc72361SWai Yew CHAY  * @Date Mar 28 2008
138cc72361SWai Yew CHAY  */
148cc72361SWai Yew CHAY 
158cc72361SWai Yew CHAY #include "ctatc.h"
168cc72361SWai Yew CHAY #include "ctpcm.h"
178cc72361SWai Yew CHAY #include "ctmixer.h"
188cc72361SWai Yew CHAY #include "ctsrc.h"
198cc72361SWai Yew CHAY #include "ctamixer.h"
208cc72361SWai Yew CHAY #include "ctdaio.h"
21b7bbf876STakashi Iwai #include "cttimer.h"
228cc72361SWai Yew CHAY #include <linux/delay.h>
235a0e3ad6STejun Heo #include <linux/slab.h>
248cc72361SWai Yew CHAY #include <sound/pcm.h>
258cc72361SWai Yew CHAY #include <sound/control.h>
268cc72361SWai Yew CHAY #include <sound/asoundef.h>
278cc72361SWai Yew CHAY 
288cc72361SWai Yew CHAY #define MONO_SUM_SCALE	0x19a8	/* 2^(-0.5) in 14-bit floating format */
298cc72361SWai Yew CHAY #define MAX_MULTI_CHN	8
308cc72361SWai Yew CHAY 
318cc72361SWai Yew CHAY #define IEC958_DEFAULT_CON ((IEC958_AES0_NONAUDIO \
328cc72361SWai Yew CHAY 			    | IEC958_AES0_CON_NOT_COPYRIGHT) \
338cc72361SWai Yew CHAY 			    | ((IEC958_AES1_CON_MIXER \
348cc72361SWai Yew CHAY 			    | IEC958_AES1_CON_ORIGINAL) << 8) \
358cc72361SWai Yew CHAY 			    | (0x10 << 16) \
368cc72361SWai Yew CHAY 			    | ((IEC958_AES3_CON_FS_48000) << 24))
378cc72361SWai Yew CHAY 
3888e540a8STakashi Iwai static const struct snd_pci_quirk subsys_20k1_list[] = {
39*1b073ebbSEdward Matijevic 	SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, 0x0021, "SB046x", CTSB046X),
409470195aSTakashi Iwai 	SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, 0x0022, "SB055x", CTSB055X),
419470195aSTakashi Iwai 	SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, 0x002f, "SB055x", CTSB055X),
429470195aSTakashi Iwai 	SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, 0x0029, "SB073x", CTSB073X),
439470195aSTakashi Iwai 	SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, 0x0031, "SB073x", CTSB073X),
4409521d2eSTakashi Iwai 	SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_CREATIVE, 0xf000, 0x6000,
4509521d2eSTakashi Iwai 			   "UAA", CTUAA),
469470195aSTakashi Iwai 	{ } /* terminator */
478cc72361SWai Yew CHAY };
488cc72361SWai Yew CHAY 
4988e540a8STakashi Iwai static const struct snd_pci_quirk subsys_20k2_list[] = {
509470195aSTakashi Iwai 	SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB0760,
519470195aSTakashi Iwai 		      "SB0760", CTSB0760),
5255309216SHarry Butterworth 	SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB1270,
5355309216SHarry Butterworth 		      "SB1270", CTSB1270),
549470195aSTakashi Iwai 	SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB08801,
559470195aSTakashi Iwai 		      "SB0880", CTSB0880),
569470195aSTakashi Iwai 	SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB08802,
579470195aSTakashi Iwai 		      "SB0880", CTSB0880),
589470195aSTakashi Iwai 	SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB08803,
599470195aSTakashi Iwai 		      "SB0880", CTSB0880),
6009521d2eSTakashi Iwai 	SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_CREATIVE, 0xf000,
6109521d2eSTakashi Iwai 			   PCI_SUBDEVICE_ID_CREATIVE_HENDRIX, "HENDRIX",
6209521d2eSTakashi Iwai 			   CTHENDRIX),
638cc72361SWai Yew CHAY 	{ } /* terminator */
648cc72361SWai Yew CHAY };
658cc72361SWai Yew CHAY 
669470195aSTakashi Iwai static const char *ct_subsys_name[NUM_CTCARDS] = {
67a8f4310bSTakashi Iwai 	/* 20k1 models */
68*1b073ebbSEdward Matijevic 	[CTSB046X]	= "SB046x",
699470195aSTakashi Iwai 	[CTSB055X]	= "SB055x",
709470195aSTakashi Iwai 	[CTSB073X]	= "SB073x",
719470195aSTakashi Iwai 	[CTUAA]		= "UAA",
729470195aSTakashi Iwai 	[CT20K1_UNKNOWN] = "Unknown",
73a8f4310bSTakashi Iwai 	/* 20k2 models */
74a8f4310bSTakashi Iwai 	[CTSB0760]	= "SB076x",
759470195aSTakashi Iwai 	[CTHENDRIX]	= "Hendrix",
769470195aSTakashi Iwai 	[CTSB0880]	= "SB0880",
7755309216SHarry Butterworth 	[CTSB1270]      = "SB1270",
78a8f4310bSTakashi Iwai 	[CT20K2_UNKNOWN] = "Unknown",
799470195aSTakashi Iwai };
809470195aSTakashi Iwai 
818cc72361SWai Yew CHAY static struct {
828cc72361SWai Yew CHAY 	int (*create)(struct ct_atc *atc,
838cc72361SWai Yew CHAY 			enum CTALSADEVS device, const char *device_name);
848cc72361SWai Yew CHAY 	int (*destroy)(void *alsa_dev);
858cc72361SWai Yew CHAY 	const char *public_name;
868cc72361SWai Yew CHAY } alsa_dev_funcs[NUM_CTALSADEVS] = {
878cc72361SWai Yew CHAY 	[FRONT]		= { .create = ct_alsa_pcm_create,
888cc72361SWai Yew CHAY 			    .destroy = NULL,
898cc72361SWai Yew CHAY 			    .public_name = "Front/WaveIn"},
908cc72361SWai Yew CHAY 	[SURROUND]	= { .create = ct_alsa_pcm_create,
918cc72361SWai Yew CHAY 			    .destroy = NULL,
928cc72361SWai Yew CHAY 			    .public_name = "Surround"},
938372d498STakashi Iwai 	[CLFE]		= { .create = ct_alsa_pcm_create,
948372d498STakashi Iwai 			    .destroy = NULL,
958372d498STakashi Iwai 			    .public_name = "Center/LFE"},
968372d498STakashi Iwai 	[SIDE]		= { .create = ct_alsa_pcm_create,
978372d498STakashi Iwai 			    .destroy = NULL,
988372d498STakashi Iwai 			    .public_name = "Side"},
998cc72361SWai Yew CHAY 	[IEC958]	= { .create = ct_alsa_pcm_create,
1008cc72361SWai Yew CHAY 			    .destroy = NULL,
1018cc72361SWai Yew CHAY 			    .public_name = "IEC958 Non-audio"},
1028cc72361SWai Yew CHAY 
1038cc72361SWai Yew CHAY 	[MIXER]		= { .create = ct_alsa_mix_create,
1048cc72361SWai Yew CHAY 			    .destroy = NULL,
1058cc72361SWai Yew CHAY 			    .public_name = "Mixer"}
1068cc72361SWai Yew CHAY };
1078cc72361SWai Yew CHAY 
10866640898SSudip Mukherjee typedef int (*create_t)(struct hw *, void **);
1098cc72361SWai Yew CHAY typedef int (*destroy_t)(void *);
1108cc72361SWai Yew CHAY 
1118cc72361SWai Yew CHAY static struct {
11266640898SSudip Mukherjee 	int (*create)(struct hw *hw, void **rmgr);
1138cc72361SWai Yew CHAY 	int (*destroy)(void *mgr);
1148cc72361SWai Yew CHAY } rsc_mgr_funcs[NUM_RSCTYP] = {
1158cc72361SWai Yew CHAY 	[SRC] 		= { .create 	= (create_t)src_mgr_create,
1168cc72361SWai Yew CHAY 			    .destroy 	= (destroy_t)src_mgr_destroy	},
1178cc72361SWai Yew CHAY 	[SRCIMP] 	= { .create 	= (create_t)srcimp_mgr_create,
1188cc72361SWai Yew CHAY 			    .destroy 	= (destroy_t)srcimp_mgr_destroy	},
1198cc72361SWai Yew CHAY 	[AMIXER]	= { .create	= (create_t)amixer_mgr_create,
1208cc72361SWai Yew CHAY 			    .destroy	= (destroy_t)amixer_mgr_destroy	},
1218cc72361SWai Yew CHAY 	[SUM]		= { .create	= (create_t)sum_mgr_create,
1228cc72361SWai Yew CHAY 			    .destroy	= (destroy_t)sum_mgr_destroy	},
1238cc72361SWai Yew CHAY 	[DAIO]		= { .create	= (create_t)daio_mgr_create,
1248cc72361SWai Yew CHAY 			    .destroy	= (destroy_t)daio_mgr_destroy	}
1258cc72361SWai Yew CHAY };
1268cc72361SWai Yew CHAY 
1278cc72361SWai Yew CHAY static int
1288cc72361SWai Yew CHAY atc_pcm_release_resources(struct ct_atc *atc, struct ct_atc_pcm *apcm);
1298cc72361SWai Yew CHAY 
1308cc72361SWai Yew CHAY /* *
1318cc72361SWai Yew CHAY  * Only mono and interleaved modes are supported now.
1328cc72361SWai Yew CHAY  * Always allocates a contiguous channel block.
1338cc72361SWai Yew CHAY  * */
1348cc72361SWai Yew CHAY 
ct_map_audio_buffer(struct ct_atc * atc,struct ct_atc_pcm * apcm)1358cc72361SWai Yew CHAY static int ct_map_audio_buffer(struct ct_atc *atc, struct ct_atc_pcm *apcm)
1368cc72361SWai Yew CHAY {
1378cc72361SWai Yew CHAY 	struct snd_pcm_runtime *runtime;
1388cc72361SWai Yew CHAY 	struct ct_vm *vm;
1398cc72361SWai Yew CHAY 
14035ebf6e7STakashi Iwai 	if (!apcm->substream)
1418cc72361SWai Yew CHAY 		return 0;
1428cc72361SWai Yew CHAY 
1438cc72361SWai Yew CHAY 	runtime = apcm->substream->runtime;
1448cc72361SWai Yew CHAY 	vm = atc->vm;
1458cc72361SWai Yew CHAY 
146c76157d9STakashi Iwai 	apcm->vm_block = vm->map(vm, apcm->substream, runtime->dma_bytes);
1478cc72361SWai Yew CHAY 
14835ebf6e7STakashi Iwai 	if (!apcm->vm_block)
1498cc72361SWai Yew CHAY 		return -ENOENT;
1508cc72361SWai Yew CHAY 
1518cc72361SWai Yew CHAY 	return 0;
1528cc72361SWai Yew CHAY }
1538cc72361SWai Yew CHAY 
ct_unmap_audio_buffer(struct ct_atc * atc,struct ct_atc_pcm * apcm)1548cc72361SWai Yew CHAY static void ct_unmap_audio_buffer(struct ct_atc *atc, struct ct_atc_pcm *apcm)
1558cc72361SWai Yew CHAY {
1568cc72361SWai Yew CHAY 	struct ct_vm *vm;
1578cc72361SWai Yew CHAY 
15835ebf6e7STakashi Iwai 	if (!apcm->vm_block)
1598cc72361SWai Yew CHAY 		return;
1608cc72361SWai Yew CHAY 
1618cc72361SWai Yew CHAY 	vm = atc->vm;
1628cc72361SWai Yew CHAY 
1638cc72361SWai Yew CHAY 	vm->unmap(vm, apcm->vm_block);
1648cc72361SWai Yew CHAY 
1658cc72361SWai Yew CHAY 	apcm->vm_block = NULL;
1668cc72361SWai Yew CHAY }
1678cc72361SWai Yew CHAY 
atc_get_ptp_phys(struct ct_atc * atc,int index)1688cc72361SWai Yew CHAY static unsigned long atc_get_ptp_phys(struct ct_atc *atc, int index)
1698cc72361SWai Yew CHAY {
17021956b61SJaroslav Kysela 	return atc->vm->get_ptp_phys(atc->vm, index);
1718cc72361SWai Yew CHAY }
1728cc72361SWai Yew CHAY 
convert_format(snd_pcm_format_t snd_format,struct snd_card * card)173a45c4d51SSudip Mukherjee static unsigned int convert_format(snd_pcm_format_t snd_format,
174a45c4d51SSudip Mukherjee 				   struct snd_card *card)
1758cc72361SWai Yew CHAY {
1768cc72361SWai Yew CHAY 	switch (snd_format) {
1778cc72361SWai Yew CHAY 	case SNDRV_PCM_FORMAT_U8:
1788cc72361SWai Yew CHAY 		return SRC_SF_U8;
1798cc72361SWai Yew CHAY 	case SNDRV_PCM_FORMAT_S16_LE:
1808cc72361SWai Yew CHAY 		return SRC_SF_S16;
1818cc72361SWai Yew CHAY 	case SNDRV_PCM_FORMAT_S24_3LE:
1828cc72361SWai Yew CHAY 		return SRC_SF_S24;
1838cc72361SWai Yew CHAY 	case SNDRV_PCM_FORMAT_S32_LE:
1848cc72361SWai Yew CHAY 		return SRC_SF_S32;
185d2b9b96cSTakashi Iwai 	case SNDRV_PCM_FORMAT_FLOAT_LE:
186d2b9b96cSTakashi Iwai 		return SRC_SF_F32;
1878cc72361SWai Yew CHAY 	default:
1880cae90a9SSudip Mukherjee 		dev_err(card->dev, "not recognized snd format is %d\n",
1898cc72361SWai Yew CHAY 			snd_format);
1908cc72361SWai Yew CHAY 		return SRC_SF_S16;
1918cc72361SWai Yew CHAY 	}
1928cc72361SWai Yew CHAY }
1938cc72361SWai Yew CHAY 
1948cc72361SWai Yew CHAY static unsigned int
atc_get_pitch(unsigned int input_rate,unsigned int output_rate)1958cc72361SWai Yew CHAY atc_get_pitch(unsigned int input_rate, unsigned int output_rate)
1968cc72361SWai Yew CHAY {
197514eef9cSTakashi Iwai 	unsigned int pitch;
198514eef9cSTakashi Iwai 	int b;
1998cc72361SWai Yew CHAY 
2008cc72361SWai Yew CHAY 	/* get pitch and convert to fixed-point 8.24 format. */
2018cc72361SWai Yew CHAY 	pitch = (input_rate / output_rate) << 24;
2028cc72361SWai Yew CHAY 	input_rate %= output_rate;
2038cc72361SWai Yew CHAY 	input_rate /= 100;
2048cc72361SWai Yew CHAY 	output_rate /= 100;
2058cc72361SWai Yew CHAY 	for (b = 31; ((b >= 0) && !(input_rate >> b)); )
2068cc72361SWai Yew CHAY 		b--;
2078cc72361SWai Yew CHAY 
2088cc72361SWai Yew CHAY 	if (b >= 0) {
2098cc72361SWai Yew CHAY 		input_rate <<= (31 - b);
2108cc72361SWai Yew CHAY 		input_rate /= output_rate;
2118cc72361SWai Yew CHAY 		b = 24 - (31 - b);
2128cc72361SWai Yew CHAY 		if (b >= 0)
2138cc72361SWai Yew CHAY 			input_rate <<= b;
2148cc72361SWai Yew CHAY 		else
2158cc72361SWai Yew CHAY 			input_rate >>= -b;
2168cc72361SWai Yew CHAY 
2178cc72361SWai Yew CHAY 		pitch |= input_rate;
2188cc72361SWai Yew CHAY 	}
2198cc72361SWai Yew CHAY 
2208cc72361SWai Yew CHAY 	return pitch;
2218cc72361SWai Yew CHAY }
2228cc72361SWai Yew CHAY 
select_rom(unsigned int pitch)2238cc72361SWai Yew CHAY static int select_rom(unsigned int pitch)
2248cc72361SWai Yew CHAY {
22535ebf6e7STakashi Iwai 	if (pitch > 0x00428f5c && pitch < 0x01b851ec) {
2268cc72361SWai Yew CHAY 		/* 0.26 <= pitch <= 1.72 */
2278cc72361SWai Yew CHAY 		return 1;
22835ebf6e7STakashi Iwai 	} else if (pitch == 0x01d66666 || pitch == 0x01d66667) {
2298cc72361SWai Yew CHAY 		/* pitch == 1.8375 */
2308cc72361SWai Yew CHAY 		return 2;
23135ebf6e7STakashi Iwai 	} else if (pitch == 0x02000000) {
2328cc72361SWai Yew CHAY 		/* pitch == 2 */
2338cc72361SWai Yew CHAY 		return 3;
23484ed1a19SRoel Kluin 	} else if (pitch <= 0x08000000) {
2358cc72361SWai Yew CHAY 		/* 0 <= pitch <= 8 */
2368cc72361SWai Yew CHAY 		return 0;
2378cc72361SWai Yew CHAY 	} else {
2388cc72361SWai Yew CHAY 		return -ENOENT;
2398cc72361SWai Yew CHAY 	}
2408cc72361SWai Yew CHAY }
2418cc72361SWai Yew CHAY 
atc_pcm_playback_prepare(struct ct_atc * atc,struct ct_atc_pcm * apcm)2428cc72361SWai Yew CHAY static int atc_pcm_playback_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm)
2438cc72361SWai Yew CHAY {
2448cc72361SWai Yew CHAY 	struct src_mgr *src_mgr = atc->rsc_mgrs[SRC];
2458cc72361SWai Yew CHAY 	struct amixer_mgr *amixer_mgr = atc->rsc_mgrs[AMIXER];
2468cc72361SWai Yew CHAY 	struct src_desc desc = {0};
2478cc72361SWai Yew CHAY 	struct amixer_desc mix_dsc = {0};
248514eef9cSTakashi Iwai 	struct src *src;
249514eef9cSTakashi Iwai 	struct amixer *amixer;
250514eef9cSTakashi Iwai 	int err;
2518cc72361SWai Yew CHAY 	int n_amixer = apcm->substream->runtime->channels, i = 0;
2528cc72361SWai Yew CHAY 	int device = apcm->substream->pcm->device;
253514eef9cSTakashi Iwai 	unsigned int pitch;
2548cc72361SWai Yew CHAY 
255822fa19bSTakashi Iwai 	/* first release old resources */
25629959a09SWai Yew CHAY 	atc_pcm_release_resources(atc, apcm);
257822fa19bSTakashi Iwai 
2588cc72361SWai Yew CHAY 	/* Get SRC resource */
2598cc72361SWai Yew CHAY 	desc.multi = apcm->substream->runtime->channels;
2608cc72361SWai Yew CHAY 	desc.msr = atc->msr;
2618cc72361SWai Yew CHAY 	desc.mode = MEMRD;
2628cc72361SWai Yew CHAY 	err = src_mgr->get_src(src_mgr, &desc, (struct src **)&apcm->src);
2638cc72361SWai Yew CHAY 	if (err)
2648cc72361SWai Yew CHAY 		goto error1;
2658cc72361SWai Yew CHAY 
2668cc72361SWai Yew CHAY 	pitch = atc_get_pitch(apcm->substream->runtime->rate,
2678cc72361SWai Yew CHAY 						(atc->rsr * atc->msr));
2688cc72361SWai Yew CHAY 	src = apcm->src;
2698cc72361SWai Yew CHAY 	src->ops->set_pitch(src, pitch);
2708cc72361SWai Yew CHAY 	src->ops->set_rom(src, select_rom(pitch));
271a45c4d51SSudip Mukherjee 	src->ops->set_sf(src, convert_format(apcm->substream->runtime->format,
272a45c4d51SSudip Mukherjee 					     atc->card));
2738cc72361SWai Yew CHAY 	src->ops->set_pm(src, (src->ops->next_interleave(src) != NULL));
2748cc72361SWai Yew CHAY 
2758cc72361SWai Yew CHAY 	/* Get AMIXER resource */
2768cc72361SWai Yew CHAY 	n_amixer = (n_amixer < 2) ? 2 : n_amixer;
2776396bb22SKees Cook 	apcm->amixers = kcalloc(n_amixer, sizeof(void *), GFP_KERNEL);
27835ebf6e7STakashi Iwai 	if (!apcm->amixers) {
2798cc72361SWai Yew CHAY 		err = -ENOMEM;
2808cc72361SWai Yew CHAY 		goto error1;
2818cc72361SWai Yew CHAY 	}
2828cc72361SWai Yew CHAY 	mix_dsc.msr = atc->msr;
2838cc72361SWai Yew CHAY 	for (i = 0, apcm->n_amixer = 0; i < n_amixer; i++) {
2848cc72361SWai Yew CHAY 		err = amixer_mgr->get_amixer(amixer_mgr, &mix_dsc,
2858cc72361SWai Yew CHAY 					(struct amixer **)&apcm->amixers[i]);
2868cc72361SWai Yew CHAY 		if (err)
2878cc72361SWai Yew CHAY 			goto error1;
2888cc72361SWai Yew CHAY 
2898cc72361SWai Yew CHAY 		apcm->n_amixer++;
2908cc72361SWai Yew CHAY 	}
2918cc72361SWai Yew CHAY 
2928cc72361SWai Yew CHAY 	/* Set up device virtual mem map */
2938cc72361SWai Yew CHAY 	err = ct_map_audio_buffer(atc, apcm);
2948cc72361SWai Yew CHAY 	if (err < 0)
2958cc72361SWai Yew CHAY 		goto error1;
2968cc72361SWai Yew CHAY 
2978cc72361SWai Yew CHAY 	/* Connect resources */
2988cc72361SWai Yew CHAY 	src = apcm->src;
2998cc72361SWai Yew CHAY 	for (i = 0; i < n_amixer; i++) {
3008cc72361SWai Yew CHAY 		amixer = apcm->amixers[i];
301635c265fSTakashi Iwai 		mutex_lock(&atc->atc_mutex);
3028cc72361SWai Yew CHAY 		amixer->ops->setup(amixer, &src->rsc,
3038cc72361SWai Yew CHAY 					INIT_VOL, atc->pcm[i+device*2]);
304635c265fSTakashi Iwai 		mutex_unlock(&atc->atc_mutex);
3058cc72361SWai Yew CHAY 		src = src->ops->next_interleave(src);
30635ebf6e7STakashi Iwai 		if (!src)
3078cc72361SWai Yew CHAY 			src = apcm->src;
3088cc72361SWai Yew CHAY 	}
3098cc72361SWai Yew CHAY 
310b7bbf876STakashi Iwai 	ct_timer_prepare(apcm->timer);
311b7bbf876STakashi Iwai 
3128cc72361SWai Yew CHAY 	return 0;
3138cc72361SWai Yew CHAY 
3148cc72361SWai Yew CHAY error1:
3158cc72361SWai Yew CHAY 	atc_pcm_release_resources(atc, apcm);
3168cc72361SWai Yew CHAY 	return err;
3178cc72361SWai Yew CHAY }
3188cc72361SWai Yew CHAY 
3198cc72361SWai Yew CHAY static int
atc_pcm_release_resources(struct ct_atc * atc,struct ct_atc_pcm * apcm)3208cc72361SWai Yew CHAY atc_pcm_release_resources(struct ct_atc *atc, struct ct_atc_pcm *apcm)
3218cc72361SWai Yew CHAY {
3228cc72361SWai Yew CHAY 	struct src_mgr *src_mgr = atc->rsc_mgrs[SRC];
3238cc72361SWai Yew CHAY 	struct srcimp_mgr *srcimp_mgr = atc->rsc_mgrs[SRCIMP];
3248cc72361SWai Yew CHAY 	struct amixer_mgr *amixer_mgr = atc->rsc_mgrs[AMIXER];
3258cc72361SWai Yew CHAY 	struct sum_mgr *sum_mgr = atc->rsc_mgrs[SUM];
326514eef9cSTakashi Iwai 	struct srcimp *srcimp;
327514eef9cSTakashi Iwai 	int i;
3288cc72361SWai Yew CHAY 
32935ebf6e7STakashi Iwai 	if (apcm->srcimps) {
3308cc72361SWai Yew CHAY 		for (i = 0; i < apcm->n_srcimp; i++) {
3318cc72361SWai Yew CHAY 			srcimp = apcm->srcimps[i];
3328cc72361SWai Yew CHAY 			srcimp->ops->unmap(srcimp);
3338cc72361SWai Yew CHAY 			srcimp_mgr->put_srcimp(srcimp_mgr, srcimp);
3348cc72361SWai Yew CHAY 			apcm->srcimps[i] = NULL;
3358cc72361SWai Yew CHAY 		}
3368cc72361SWai Yew CHAY 		kfree(apcm->srcimps);
3378cc72361SWai Yew CHAY 		apcm->srcimps = NULL;
3388cc72361SWai Yew CHAY 	}
3398cc72361SWai Yew CHAY 
34035ebf6e7STakashi Iwai 	if (apcm->srccs) {
3418cc72361SWai Yew CHAY 		for (i = 0; i < apcm->n_srcc; i++) {
3428cc72361SWai Yew CHAY 			src_mgr->put_src(src_mgr, apcm->srccs[i]);
3438cc72361SWai Yew CHAY 			apcm->srccs[i] = NULL;
3448cc72361SWai Yew CHAY 		}
3458cc72361SWai Yew CHAY 		kfree(apcm->srccs);
3468cc72361SWai Yew CHAY 		apcm->srccs = NULL;
3478cc72361SWai Yew CHAY 	}
3488cc72361SWai Yew CHAY 
34935ebf6e7STakashi Iwai 	if (apcm->amixers) {
3508cc72361SWai Yew CHAY 		for (i = 0; i < apcm->n_amixer; i++) {
3518cc72361SWai Yew CHAY 			amixer_mgr->put_amixer(amixer_mgr, apcm->amixers[i]);
3528cc72361SWai Yew CHAY 			apcm->amixers[i] = NULL;
3538cc72361SWai Yew CHAY 		}
3548cc72361SWai Yew CHAY 		kfree(apcm->amixers);
3558cc72361SWai Yew CHAY 		apcm->amixers = NULL;
3568cc72361SWai Yew CHAY 	}
3578cc72361SWai Yew CHAY 
35835ebf6e7STakashi Iwai 	if (apcm->mono) {
3598cc72361SWai Yew CHAY 		sum_mgr->put_sum(sum_mgr, apcm->mono);
3608cc72361SWai Yew CHAY 		apcm->mono = NULL;
3618cc72361SWai Yew CHAY 	}
3628cc72361SWai Yew CHAY 
36335ebf6e7STakashi Iwai 	if (apcm->src) {
3648cc72361SWai Yew CHAY 		src_mgr->put_src(src_mgr, apcm->src);
3658cc72361SWai Yew CHAY 		apcm->src = NULL;
3668cc72361SWai Yew CHAY 	}
3678cc72361SWai Yew CHAY 
36835ebf6e7STakashi Iwai 	if (apcm->vm_block) {
3698cc72361SWai Yew CHAY 		/* Undo device virtual mem map */
3708cc72361SWai Yew CHAY 		ct_unmap_audio_buffer(atc, apcm);
3718cc72361SWai Yew CHAY 		apcm->vm_block = NULL;
3728cc72361SWai Yew CHAY 	}
3738cc72361SWai Yew CHAY 
3748cc72361SWai Yew CHAY 	return 0;
3758cc72361SWai Yew CHAY }
3768cc72361SWai Yew CHAY 
atc_pcm_playback_start(struct ct_atc * atc,struct ct_atc_pcm * apcm)3778cc72361SWai Yew CHAY static int atc_pcm_playback_start(struct ct_atc *atc, struct ct_atc_pcm *apcm)
3788cc72361SWai Yew CHAY {
379514eef9cSTakashi Iwai 	unsigned int max_cisz;
3808cc72361SWai Yew CHAY 	struct src *src = apcm->src;
3818cc72361SWai Yew CHAY 
382c399f3beSTakashi Iwai 	if (apcm->started)
383c399f3beSTakashi Iwai 		return 0;
384c399f3beSTakashi Iwai 	apcm->started = 1;
385c399f3beSTakashi Iwai 
3868cc72361SWai Yew CHAY 	max_cisz = src->multi * src->rsc.msr;
3878cc72361SWai Yew CHAY 	max_cisz = 0x80 * (max_cisz < 8 ? max_cisz : 8);
3888cc72361SWai Yew CHAY 
3898cc72361SWai Yew CHAY 	src->ops->set_sa(src, apcm->vm_block->addr);
3908cc72361SWai Yew CHAY 	src->ops->set_la(src, apcm->vm_block->addr + apcm->vm_block->size);
3918cc72361SWai Yew CHAY 	src->ops->set_ca(src, apcm->vm_block->addr + max_cisz);
3928cc72361SWai Yew CHAY 	src->ops->set_cisz(src, max_cisz);
3938cc72361SWai Yew CHAY 
3948cc72361SWai Yew CHAY 	src->ops->set_bm(src, 1);
3958cc72361SWai Yew CHAY 	src->ops->set_state(src, SRC_STATE_INIT);
3968cc72361SWai Yew CHAY 	src->ops->commit_write(src);
3978cc72361SWai Yew CHAY 
398b7bbf876STakashi Iwai 	ct_timer_start(apcm->timer);
3998cc72361SWai Yew CHAY 	return 0;
4008cc72361SWai Yew CHAY }
4018cc72361SWai Yew CHAY 
atc_pcm_stop(struct ct_atc * atc,struct ct_atc_pcm * apcm)4028cc72361SWai Yew CHAY static int atc_pcm_stop(struct ct_atc *atc, struct ct_atc_pcm *apcm)
4038cc72361SWai Yew CHAY {
404514eef9cSTakashi Iwai 	struct src *src;
405514eef9cSTakashi Iwai 	int i;
4068cc72361SWai Yew CHAY 
407b7bbf876STakashi Iwai 	ct_timer_stop(apcm->timer);
408b7bbf876STakashi Iwai 
4098cc72361SWai Yew CHAY 	src = apcm->src;
4108cc72361SWai Yew CHAY 	src->ops->set_bm(src, 0);
4118cc72361SWai Yew CHAY 	src->ops->set_state(src, SRC_STATE_OFF);
4128cc72361SWai Yew CHAY 	src->ops->commit_write(src);
4138cc72361SWai Yew CHAY 
41435ebf6e7STakashi Iwai 	if (apcm->srccs) {
4158cc72361SWai Yew CHAY 		for (i = 0; i < apcm->n_srcc; i++) {
4168cc72361SWai Yew CHAY 			src = apcm->srccs[i];
4178cc72361SWai Yew CHAY 			src->ops->set_bm(src, 0);
4188cc72361SWai Yew CHAY 			src->ops->set_state(src, SRC_STATE_OFF);
4198cc72361SWai Yew CHAY 			src->ops->commit_write(src);
4208cc72361SWai Yew CHAY 		}
4218cc72361SWai Yew CHAY 	}
4228cc72361SWai Yew CHAY 
4238cc72361SWai Yew CHAY 	apcm->started = 0;
4248cc72361SWai Yew CHAY 
4258cc72361SWai Yew CHAY 	return 0;
4268cc72361SWai Yew CHAY }
4278cc72361SWai Yew CHAY 
4288cc72361SWai Yew CHAY static int
atc_pcm_playback_position(struct ct_atc * atc,struct ct_atc_pcm * apcm)4298cc72361SWai Yew CHAY atc_pcm_playback_position(struct ct_atc *atc, struct ct_atc_pcm *apcm)
4308cc72361SWai Yew CHAY {
4318cc72361SWai Yew CHAY 	struct src *src = apcm->src;
432514eef9cSTakashi Iwai 	u32 size, max_cisz;
433514eef9cSTakashi Iwai 	int position;
4348cc72361SWai Yew CHAY 
4355242bc76STakashi Iwai 	if (!src)
4365242bc76STakashi Iwai 		return 0;
4378cc72361SWai Yew CHAY 	position = src->ops->get_ca(src);
4388cc72361SWai Yew CHAY 
439e240a469SSarah Bessmer 	if (position < apcm->vm_block->addr) {
4402e6705c0STakashi Iwai 		dev_dbg(atc->card->dev,
4412e6705c0STakashi Iwai 			"bad ca - ca=0x%08x, vba=0x%08x, vbs=0x%08x\n",
4422e6705c0STakashi Iwai 			position, apcm->vm_block->addr, apcm->vm_block->size);
443e240a469SSarah Bessmer 		position = apcm->vm_block->addr;
444e240a469SSarah Bessmer 	}
445e240a469SSarah Bessmer 
4468cc72361SWai Yew CHAY 	size = apcm->vm_block->size;
4478cc72361SWai Yew CHAY 	max_cisz = src->multi * src->rsc.msr;
4488cc72361SWai Yew CHAY 	max_cisz = 128 * (max_cisz < 8 ? max_cisz : 8);
4498cc72361SWai Yew CHAY 
4508cc72361SWai Yew CHAY 	return (position + size - max_cisz - apcm->vm_block->addr) % size;
4518cc72361SWai Yew CHAY }
4528cc72361SWai Yew CHAY 
4538cc72361SWai Yew CHAY struct src_node_conf_t {
4548cc72361SWai Yew CHAY 	unsigned int pitch;
4558cc72361SWai Yew CHAY 	unsigned int msr:8;
4568cc72361SWai Yew CHAY 	unsigned int mix_msr:8;
4578cc72361SWai Yew CHAY 	unsigned int imp_msr:8;
4588cc72361SWai Yew CHAY 	unsigned int vo:1;
4598cc72361SWai Yew CHAY };
4608cc72361SWai Yew CHAY 
setup_src_node_conf(struct ct_atc * atc,struct ct_atc_pcm * apcm,struct src_node_conf_t * conf,int * n_srcc)4618cc72361SWai Yew CHAY static void setup_src_node_conf(struct ct_atc *atc, struct ct_atc_pcm *apcm,
4628cc72361SWai Yew CHAY 				struct src_node_conf_t *conf, int *n_srcc)
4638cc72361SWai Yew CHAY {
464514eef9cSTakashi Iwai 	unsigned int pitch;
4658cc72361SWai Yew CHAY 
4668cc72361SWai Yew CHAY 	/* get pitch and convert to fixed-point 8.24 format. */
4678cc72361SWai Yew CHAY 	pitch = atc_get_pitch((atc->rsr * atc->msr),
4688cc72361SWai Yew CHAY 				apcm->substream->runtime->rate);
4698cc72361SWai Yew CHAY 	*n_srcc = 0;
4708cc72361SWai Yew CHAY 
47155309216SHarry Butterworth 	if (1 == atc->msr) { /* FIXME: do we really need SRC here if pitch==1 */
4728cc72361SWai Yew CHAY 		*n_srcc = apcm->substream->runtime->channels;
4738cc72361SWai Yew CHAY 		conf[0].pitch = pitch;
4748cc72361SWai Yew CHAY 		conf[0].mix_msr = conf[0].imp_msr = conf[0].msr = 1;
4758cc72361SWai Yew CHAY 		conf[0].vo = 1;
47655309216SHarry Butterworth 	} else if (2 <= atc->msr) {
4778cc72361SWai Yew CHAY 		if (0x8000000 < pitch) {
4788cc72361SWai Yew CHAY 			/* Need two-stage SRCs, SRCIMPs and
4798cc72361SWai Yew CHAY 			 * AMIXERs for converting format */
4808cc72361SWai Yew CHAY 			conf[0].pitch = (atc->msr << 24);
4818cc72361SWai Yew CHAY 			conf[0].msr = conf[0].mix_msr = 1;
4828cc72361SWai Yew CHAY 			conf[0].imp_msr = atc->msr;
4838cc72361SWai Yew CHAY 			conf[0].vo = 0;
4848cc72361SWai Yew CHAY 			conf[1].pitch = atc_get_pitch(atc->rsr,
4858cc72361SWai Yew CHAY 					apcm->substream->runtime->rate);
4868cc72361SWai Yew CHAY 			conf[1].msr = conf[1].mix_msr = conf[1].imp_msr = 1;
4878cc72361SWai Yew CHAY 			conf[1].vo = 1;
4888cc72361SWai Yew CHAY 			*n_srcc = apcm->substream->runtime->channels * 2;
4898cc72361SWai Yew CHAY 		} else if (0x1000000 < pitch) {
4908cc72361SWai Yew CHAY 			/* Need one-stage SRCs, SRCIMPs and
4918cc72361SWai Yew CHAY 			 * AMIXERs for converting format */
4928cc72361SWai Yew CHAY 			conf[0].pitch = pitch;
4938cc72361SWai Yew CHAY 			conf[0].msr = conf[0].mix_msr
4948cc72361SWai Yew CHAY 				    = conf[0].imp_msr = atc->msr;
4958cc72361SWai Yew CHAY 			conf[0].vo = 1;
4968cc72361SWai Yew CHAY 			*n_srcc = apcm->substream->runtime->channels;
4978cc72361SWai Yew CHAY 		}
4988cc72361SWai Yew CHAY 	}
4998cc72361SWai Yew CHAY }
5008cc72361SWai Yew CHAY 
5018cc72361SWai Yew CHAY static int
atc_pcm_capture_get_resources(struct ct_atc * atc,struct ct_atc_pcm * apcm)5028cc72361SWai Yew CHAY atc_pcm_capture_get_resources(struct ct_atc *atc, struct ct_atc_pcm *apcm)
5038cc72361SWai Yew CHAY {
5048cc72361SWai Yew CHAY 	struct src_mgr *src_mgr = atc->rsc_mgrs[SRC];
5058cc72361SWai Yew CHAY 	struct srcimp_mgr *srcimp_mgr = atc->rsc_mgrs[SRCIMP];
5068cc72361SWai Yew CHAY 	struct amixer_mgr *amixer_mgr = atc->rsc_mgrs[AMIXER];
5078cc72361SWai Yew CHAY 	struct sum_mgr *sum_mgr = atc->rsc_mgrs[SUM];
5088cc72361SWai Yew CHAY 	struct src_desc src_dsc = {0};
509514eef9cSTakashi Iwai 	struct src *src;
5108cc72361SWai Yew CHAY 	struct srcimp_desc srcimp_dsc = {0};
511514eef9cSTakashi Iwai 	struct srcimp *srcimp;
5128cc72361SWai Yew CHAY 	struct amixer_desc mix_dsc = {0};
5138cc72361SWai Yew CHAY 	struct sum_desc sum_dsc = {0};
514514eef9cSTakashi Iwai 	unsigned int pitch;
515514eef9cSTakashi Iwai 	int multi, err, i;
516514eef9cSTakashi Iwai 	int n_srcimp, n_amixer, n_srcc, n_sum;
5178cc72361SWai Yew CHAY 	struct src_node_conf_t src_node_conf[2] = {{0} };
5188cc72361SWai Yew CHAY 
519822fa19bSTakashi Iwai 	/* first release old resources */
520a5990dc5STakashi Iwai 	atc_pcm_release_resources(atc, apcm);
521822fa19bSTakashi Iwai 
5228cc72361SWai Yew CHAY 	/* The numbers of converting SRCs and SRCIMPs should be determined
5238cc72361SWai Yew CHAY 	 * by pitch value. */
5248cc72361SWai Yew CHAY 
5258cc72361SWai Yew CHAY 	multi = apcm->substream->runtime->channels;
5268cc72361SWai Yew CHAY 
5278cc72361SWai Yew CHAY 	/* get pitch and convert to fixed-point 8.24 format. */
5288cc72361SWai Yew CHAY 	pitch = atc_get_pitch((atc->rsr * atc->msr),
5298cc72361SWai Yew CHAY 				apcm->substream->runtime->rate);
5308cc72361SWai Yew CHAY 
5318cc72361SWai Yew CHAY 	setup_src_node_conf(atc, apcm, src_node_conf, &n_srcc);
5328cc72361SWai Yew CHAY 	n_sum = (1 == multi) ? 1 : 0;
533514eef9cSTakashi Iwai 	n_amixer = n_sum * 2 + n_srcc;
534514eef9cSTakashi Iwai 	n_srcimp = n_srcc;
5358cc72361SWai Yew CHAY 	if ((multi > 1) && (0x8000000 >= pitch)) {
5368cc72361SWai Yew CHAY 		/* Need extra AMIXERs and SRCIMPs for special treatment
5378cc72361SWai Yew CHAY 		 * of interleaved recording of conjugate channels */
5388cc72361SWai Yew CHAY 		n_amixer += multi * atc->msr;
5398cc72361SWai Yew CHAY 		n_srcimp += multi * atc->msr;
5408cc72361SWai Yew CHAY 	} else {
5418cc72361SWai Yew CHAY 		n_srcimp += multi;
5428cc72361SWai Yew CHAY 	}
5438cc72361SWai Yew CHAY 
5448cc72361SWai Yew CHAY 	if (n_srcc) {
5456396bb22SKees Cook 		apcm->srccs = kcalloc(n_srcc, sizeof(void *), GFP_KERNEL);
54635ebf6e7STakashi Iwai 		if (!apcm->srccs)
5478cc72361SWai Yew CHAY 			return -ENOMEM;
5488cc72361SWai Yew CHAY 	}
5498cc72361SWai Yew CHAY 	if (n_amixer) {
5506396bb22SKees Cook 		apcm->amixers = kcalloc(n_amixer, sizeof(void *), GFP_KERNEL);
55135ebf6e7STakashi Iwai 		if (!apcm->amixers) {
5528cc72361SWai Yew CHAY 			err = -ENOMEM;
5538cc72361SWai Yew CHAY 			goto error1;
5548cc72361SWai Yew CHAY 		}
5558cc72361SWai Yew CHAY 	}
5566396bb22SKees Cook 	apcm->srcimps = kcalloc(n_srcimp, sizeof(void *), GFP_KERNEL);
55735ebf6e7STakashi Iwai 	if (!apcm->srcimps) {
5588cc72361SWai Yew CHAY 		err = -ENOMEM;
5598cc72361SWai Yew CHAY 		goto error1;
5608cc72361SWai Yew CHAY 	}
5618cc72361SWai Yew CHAY 
5628cc72361SWai Yew CHAY 	/* Allocate SRCs for sample rate conversion if needed */
5638cc72361SWai Yew CHAY 	src_dsc.multi = 1;
5648cc72361SWai Yew CHAY 	src_dsc.mode = ARCRW;
5658cc72361SWai Yew CHAY 	for (i = 0, apcm->n_srcc = 0; i < n_srcc; i++) {
5668cc72361SWai Yew CHAY 		src_dsc.msr = src_node_conf[i/multi].msr;
5678cc72361SWai Yew CHAY 		err = src_mgr->get_src(src_mgr, &src_dsc,
5688cc72361SWai Yew CHAY 					(struct src **)&apcm->srccs[i]);
5698cc72361SWai Yew CHAY 		if (err)
5708cc72361SWai Yew CHAY 			goto error1;
5718cc72361SWai Yew CHAY 
5728cc72361SWai Yew CHAY 		src = apcm->srccs[i];
5738cc72361SWai Yew CHAY 		pitch = src_node_conf[i/multi].pitch;
5748cc72361SWai Yew CHAY 		src->ops->set_pitch(src, pitch);
5758cc72361SWai Yew CHAY 		src->ops->set_rom(src, select_rom(pitch));
5768cc72361SWai Yew CHAY 		src->ops->set_vo(src, src_node_conf[i/multi].vo);
5778cc72361SWai Yew CHAY 
5788cc72361SWai Yew CHAY 		apcm->n_srcc++;
5798cc72361SWai Yew CHAY 	}
5808cc72361SWai Yew CHAY 
5818cc72361SWai Yew CHAY 	/* Allocate AMIXERs for routing SRCs of conversion if needed */
5828cc72361SWai Yew CHAY 	for (i = 0, apcm->n_amixer = 0; i < n_amixer; i++) {
5838cc72361SWai Yew CHAY 		if (i < (n_sum*2))
5848cc72361SWai Yew CHAY 			mix_dsc.msr = atc->msr;
5858cc72361SWai Yew CHAY 		else if (i < (n_sum*2+n_srcc))
5868cc72361SWai Yew CHAY 			mix_dsc.msr = src_node_conf[(i-n_sum*2)/multi].mix_msr;
5878cc72361SWai Yew CHAY 		else
5888cc72361SWai Yew CHAY 			mix_dsc.msr = 1;
5898cc72361SWai Yew CHAY 
5908cc72361SWai Yew CHAY 		err = amixer_mgr->get_amixer(amixer_mgr, &mix_dsc,
5918cc72361SWai Yew CHAY 					(struct amixer **)&apcm->amixers[i]);
5928cc72361SWai Yew CHAY 		if (err)
5938cc72361SWai Yew CHAY 			goto error1;
5948cc72361SWai Yew CHAY 
5958cc72361SWai Yew CHAY 		apcm->n_amixer++;
5968cc72361SWai Yew CHAY 	}
5978cc72361SWai Yew CHAY 
5988cc72361SWai Yew CHAY 	/* Allocate a SUM resource to mix all input channels together */
5998cc72361SWai Yew CHAY 	sum_dsc.msr = atc->msr;
6008cc72361SWai Yew CHAY 	err = sum_mgr->get_sum(sum_mgr, &sum_dsc, (struct sum **)&apcm->mono);
6018cc72361SWai Yew CHAY 	if (err)
6028cc72361SWai Yew CHAY 		goto error1;
6038cc72361SWai Yew CHAY 
6048cc72361SWai Yew CHAY 	pitch = atc_get_pitch((atc->rsr * atc->msr),
6058cc72361SWai Yew CHAY 				apcm->substream->runtime->rate);
6068cc72361SWai Yew CHAY 	/* Allocate SRCIMP resources */
6078cc72361SWai Yew CHAY 	for (i = 0, apcm->n_srcimp = 0; i < n_srcimp; i++) {
6088cc72361SWai Yew CHAY 		if (i < (n_srcc))
6098cc72361SWai Yew CHAY 			srcimp_dsc.msr = src_node_conf[i/multi].imp_msr;
6108cc72361SWai Yew CHAY 		else if (1 == multi)
6118cc72361SWai Yew CHAY 			srcimp_dsc.msr = (pitch <= 0x8000000) ? atc->msr : 1;
6128cc72361SWai Yew CHAY 		else
6138cc72361SWai Yew CHAY 			srcimp_dsc.msr = 1;
6148cc72361SWai Yew CHAY 
6158cc72361SWai Yew CHAY 		err = srcimp_mgr->get_srcimp(srcimp_mgr, &srcimp_dsc, &srcimp);
6168cc72361SWai Yew CHAY 		if (err)
6178cc72361SWai Yew CHAY 			goto error1;
6188cc72361SWai Yew CHAY 
6198cc72361SWai Yew CHAY 		apcm->srcimps[i] = srcimp;
6208cc72361SWai Yew CHAY 		apcm->n_srcimp++;
6218cc72361SWai Yew CHAY 	}
6228cc72361SWai Yew CHAY 
6238cc72361SWai Yew CHAY 	/* Allocate a SRC for writing data to host memory */
6248cc72361SWai Yew CHAY 	src_dsc.multi = apcm->substream->runtime->channels;
6258cc72361SWai Yew CHAY 	src_dsc.msr = 1;
6268cc72361SWai Yew CHAY 	src_dsc.mode = MEMWR;
6278cc72361SWai Yew CHAY 	err = src_mgr->get_src(src_mgr, &src_dsc, (struct src **)&apcm->src);
6288cc72361SWai Yew CHAY 	if (err)
6298cc72361SWai Yew CHAY 		goto error1;
6308cc72361SWai Yew CHAY 
6318cc72361SWai Yew CHAY 	src = apcm->src;
6328cc72361SWai Yew CHAY 	src->ops->set_pitch(src, pitch);
6338cc72361SWai Yew CHAY 
6348cc72361SWai Yew CHAY 	/* Set up device virtual mem map */
6358cc72361SWai Yew CHAY 	err = ct_map_audio_buffer(atc, apcm);
6368cc72361SWai Yew CHAY 	if (err < 0)
6378cc72361SWai Yew CHAY 		goto error1;
6388cc72361SWai Yew CHAY 
6398cc72361SWai Yew CHAY 	return 0;
6408cc72361SWai Yew CHAY 
6418cc72361SWai Yew CHAY error1:
6428cc72361SWai Yew CHAY 	atc_pcm_release_resources(atc, apcm);
6438cc72361SWai Yew CHAY 	return err;
6448cc72361SWai Yew CHAY }
6458cc72361SWai Yew CHAY 
atc_pcm_capture_prepare(struct ct_atc * atc,struct ct_atc_pcm * apcm)6468cc72361SWai Yew CHAY static int atc_pcm_capture_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm)
6478cc72361SWai Yew CHAY {
648514eef9cSTakashi Iwai 	struct src *src;
649514eef9cSTakashi Iwai 	struct amixer *amixer;
650514eef9cSTakashi Iwai 	struct srcimp *srcimp;
6518cc72361SWai Yew CHAY 	struct ct_mixer *mixer = atc->mixer;
652514eef9cSTakashi Iwai 	struct sum *mono;
6538cc72361SWai Yew CHAY 	struct rsc *out_ports[8] = {NULL};
654514eef9cSTakashi Iwai 	int err, i, j, n_sum, multi;
655514eef9cSTakashi Iwai 	unsigned int pitch;
6568cc72361SWai Yew CHAY 	int mix_base = 0, imp_base = 0;
6578cc72361SWai Yew CHAY 
65829959a09SWai Yew CHAY 	atc_pcm_release_resources(atc, apcm);
6598cc72361SWai Yew CHAY 
6608cc72361SWai Yew CHAY 	/* Get needed resources. */
6618cc72361SWai Yew CHAY 	err = atc_pcm_capture_get_resources(atc, apcm);
6628cc72361SWai Yew CHAY 	if (err)
6638cc72361SWai Yew CHAY 		return err;
6648cc72361SWai Yew CHAY 
6658cc72361SWai Yew CHAY 	/* Connect resources */
6668cc72361SWai Yew CHAY 	mixer->get_output_ports(mixer, MIX_PCMO_FRONT,
6678cc72361SWai Yew CHAY 				&out_ports[0], &out_ports[1]);
6688cc72361SWai Yew CHAY 
6698cc72361SWai Yew CHAY 	multi = apcm->substream->runtime->channels;
6708cc72361SWai Yew CHAY 	if (1 == multi) {
6718cc72361SWai Yew CHAY 		mono = apcm->mono;
6728cc72361SWai Yew CHAY 		for (i = 0; i < 2; i++) {
6738cc72361SWai Yew CHAY 			amixer = apcm->amixers[i];
6748cc72361SWai Yew CHAY 			amixer->ops->setup(amixer, out_ports[i],
6758cc72361SWai Yew CHAY 						MONO_SUM_SCALE, mono);
6768cc72361SWai Yew CHAY 		}
6778cc72361SWai Yew CHAY 		out_ports[0] = &mono->rsc;
6788cc72361SWai Yew CHAY 		n_sum = 1;
6798cc72361SWai Yew CHAY 		mix_base = n_sum * 2;
6808cc72361SWai Yew CHAY 	}
6818cc72361SWai Yew CHAY 
6828cc72361SWai Yew CHAY 	for (i = 0; i < apcm->n_srcc; i++) {
6838cc72361SWai Yew CHAY 		src = apcm->srccs[i];
6848cc72361SWai Yew CHAY 		srcimp = apcm->srcimps[imp_base+i];
6858cc72361SWai Yew CHAY 		amixer = apcm->amixers[mix_base+i];
6868cc72361SWai Yew CHAY 		srcimp->ops->map(srcimp, src, out_ports[i%multi]);
6878cc72361SWai Yew CHAY 		amixer->ops->setup(amixer, &src->rsc, INIT_VOL, NULL);
6888cc72361SWai Yew CHAY 		out_ports[i%multi] = &amixer->rsc;
6898cc72361SWai Yew CHAY 	}
6908cc72361SWai Yew CHAY 
6918cc72361SWai Yew CHAY 	pitch = atc_get_pitch((atc->rsr * atc->msr),
6928cc72361SWai Yew CHAY 				apcm->substream->runtime->rate);
6938cc72361SWai Yew CHAY 
6948cc72361SWai Yew CHAY 	if ((multi > 1) && (pitch <= 0x8000000)) {
6958cc72361SWai Yew CHAY 		/* Special connection for interleaved
6968cc72361SWai Yew CHAY 		 * recording with conjugate channels */
6978cc72361SWai Yew CHAY 		for (i = 0; i < multi; i++) {
6988cc72361SWai Yew CHAY 			out_ports[i]->ops->master(out_ports[i]);
6998cc72361SWai Yew CHAY 			for (j = 0; j < atc->msr; j++) {
7008cc72361SWai Yew CHAY 				amixer = apcm->amixers[apcm->n_srcc+j*multi+i];
7018cc72361SWai Yew CHAY 				amixer->ops->set_input(amixer, out_ports[i]);
7028cc72361SWai Yew CHAY 				amixer->ops->set_scale(amixer, INIT_VOL);
7038cc72361SWai Yew CHAY 				amixer->ops->set_sum(amixer, NULL);
7048cc72361SWai Yew CHAY 				amixer->ops->commit_raw_write(amixer);
7058cc72361SWai Yew CHAY 				out_ports[i]->ops->next_conj(out_ports[i]);
7068cc72361SWai Yew CHAY 
7078cc72361SWai Yew CHAY 				srcimp = apcm->srcimps[apcm->n_srcc+j*multi+i];
7088cc72361SWai Yew CHAY 				srcimp->ops->map(srcimp, apcm->src,
7098cc72361SWai Yew CHAY 							&amixer->rsc);
7108cc72361SWai Yew CHAY 			}
7118cc72361SWai Yew CHAY 		}
7128cc72361SWai Yew CHAY 	} else {
7138cc72361SWai Yew CHAY 		for (i = 0; i < multi; i++) {
7148cc72361SWai Yew CHAY 			srcimp = apcm->srcimps[apcm->n_srcc+i];
7158cc72361SWai Yew CHAY 			srcimp->ops->map(srcimp, apcm->src, out_ports[i]);
7168cc72361SWai Yew CHAY 		}
7178cc72361SWai Yew CHAY 	}
7188cc72361SWai Yew CHAY 
719b7bbf876STakashi Iwai 	ct_timer_prepare(apcm->timer);
720b7bbf876STakashi Iwai 
7218cc72361SWai Yew CHAY 	return 0;
7228cc72361SWai Yew CHAY }
7238cc72361SWai Yew CHAY 
atc_pcm_capture_start(struct ct_atc * atc,struct ct_atc_pcm * apcm)7248cc72361SWai Yew CHAY static int atc_pcm_capture_start(struct ct_atc *atc, struct ct_atc_pcm *apcm)
7258cc72361SWai Yew CHAY {
726514eef9cSTakashi Iwai 	struct src *src;
7278cc72361SWai Yew CHAY 	struct src_mgr *src_mgr = atc->rsc_mgrs[SRC];
728514eef9cSTakashi Iwai 	int i, multi;
7298cc72361SWai Yew CHAY 
7308cc72361SWai Yew CHAY 	if (apcm->started)
7318cc72361SWai Yew CHAY 		return 0;
7328cc72361SWai Yew CHAY 
7338cc72361SWai Yew CHAY 	apcm->started = 1;
7348cc72361SWai Yew CHAY 	multi = apcm->substream->runtime->channels;
7358cc72361SWai Yew CHAY 	/* Set up converting SRCs */
7368cc72361SWai Yew CHAY 	for (i = 0; i < apcm->n_srcc; i++) {
7378cc72361SWai Yew CHAY 		src = apcm->srccs[i];
7388cc72361SWai Yew CHAY 		src->ops->set_pm(src, ((i%multi) != (multi-1)));
7398cc72361SWai Yew CHAY 		src_mgr->src_disable(src_mgr, src);
7408cc72361SWai Yew CHAY 	}
7418cc72361SWai Yew CHAY 
7428cc72361SWai Yew CHAY 	/*  Set up recording SRC */
7438cc72361SWai Yew CHAY 	src = apcm->src;
744a45c4d51SSudip Mukherjee 	src->ops->set_sf(src, convert_format(apcm->substream->runtime->format,
745a45c4d51SSudip Mukherjee 					     atc->card));
7468cc72361SWai Yew CHAY 	src->ops->set_sa(src, apcm->vm_block->addr);
7478cc72361SWai Yew CHAY 	src->ops->set_la(src, apcm->vm_block->addr + apcm->vm_block->size);
7488cc72361SWai Yew CHAY 	src->ops->set_ca(src, apcm->vm_block->addr);
7498cc72361SWai Yew CHAY 	src_mgr->src_disable(src_mgr, src);
7508cc72361SWai Yew CHAY 
7518cc72361SWai Yew CHAY 	/* Disable relevant SRCs firstly */
7528cc72361SWai Yew CHAY 	src_mgr->commit_write(src_mgr);
7538cc72361SWai Yew CHAY 
7548cc72361SWai Yew CHAY 	/* Enable SRCs respectively */
7558cc72361SWai Yew CHAY 	for (i = 0; i < apcm->n_srcc; i++) {
7568cc72361SWai Yew CHAY 		src = apcm->srccs[i];
7578cc72361SWai Yew CHAY 		src->ops->set_state(src, SRC_STATE_RUN);
7588cc72361SWai Yew CHAY 		src->ops->commit_write(src);
7598cc72361SWai Yew CHAY 		src_mgr->src_enable_s(src_mgr, src);
7608cc72361SWai Yew CHAY 	}
7618cc72361SWai Yew CHAY 	src = apcm->src;
7628cc72361SWai Yew CHAY 	src->ops->set_bm(src, 1);
7638cc72361SWai Yew CHAY 	src->ops->set_state(src, SRC_STATE_RUN);
7648cc72361SWai Yew CHAY 	src->ops->commit_write(src);
7658cc72361SWai Yew CHAY 	src_mgr->src_enable_s(src_mgr, src);
7668cc72361SWai Yew CHAY 
7678cc72361SWai Yew CHAY 	/* Enable relevant SRCs synchronously */
7688cc72361SWai Yew CHAY 	src_mgr->commit_write(src_mgr);
7698cc72361SWai Yew CHAY 
770b7bbf876STakashi Iwai 	ct_timer_start(apcm->timer);
7718cc72361SWai Yew CHAY 	return 0;
7728cc72361SWai Yew CHAY }
7738cc72361SWai Yew CHAY 
7748cc72361SWai Yew CHAY static int
atc_pcm_capture_position(struct ct_atc * atc,struct ct_atc_pcm * apcm)7758cc72361SWai Yew CHAY atc_pcm_capture_position(struct ct_atc *atc, struct ct_atc_pcm *apcm)
7768cc72361SWai Yew CHAY {
7778cc72361SWai Yew CHAY 	struct src *src = apcm->src;
7788cc72361SWai Yew CHAY 
7795242bc76STakashi Iwai 	if (!src)
7805242bc76STakashi Iwai 		return 0;
7818cc72361SWai Yew CHAY 	return src->ops->get_ca(src) - apcm->vm_block->addr;
7828cc72361SWai Yew CHAY }
7838cc72361SWai Yew CHAY 
spdif_passthru_playback_get_resources(struct ct_atc * atc,struct ct_atc_pcm * apcm)7848cc72361SWai Yew CHAY static int spdif_passthru_playback_get_resources(struct ct_atc *atc,
7858cc72361SWai Yew CHAY 						 struct ct_atc_pcm *apcm)
7868cc72361SWai Yew CHAY {
7878cc72361SWai Yew CHAY 	struct src_mgr *src_mgr = atc->rsc_mgrs[SRC];
7888cc72361SWai Yew CHAY 	struct amixer_mgr *amixer_mgr = atc->rsc_mgrs[AMIXER];
7898cc72361SWai Yew CHAY 	struct src_desc desc = {0};
7908cc72361SWai Yew CHAY 	struct amixer_desc mix_dsc = {0};
791514eef9cSTakashi Iwai 	struct src *src;
792514eef9cSTakashi Iwai 	int err;
793514eef9cSTakashi Iwai 	int n_amixer = apcm->substream->runtime->channels, i;
794514eef9cSTakashi Iwai 	unsigned int pitch, rsr = atc->pll_rate;
7958cc72361SWai Yew CHAY 
796822fa19bSTakashi Iwai 	/* first release old resources */
797a5990dc5STakashi Iwai 	atc_pcm_release_resources(atc, apcm);
798822fa19bSTakashi Iwai 
7998cc72361SWai Yew CHAY 	/* Get SRC resource */
8008cc72361SWai Yew CHAY 	desc.multi = apcm->substream->runtime->channels;
8018cc72361SWai Yew CHAY 	desc.msr = 1;
8028cc72361SWai Yew CHAY 	while (apcm->substream->runtime->rate > (rsr * desc.msr))
8038cc72361SWai Yew CHAY 		desc.msr <<= 1;
8048cc72361SWai Yew CHAY 
8058cc72361SWai Yew CHAY 	desc.mode = MEMRD;
8068cc72361SWai Yew CHAY 	err = src_mgr->get_src(src_mgr, &desc, (struct src **)&apcm->src);
8078cc72361SWai Yew CHAY 	if (err)
8088cc72361SWai Yew CHAY 		goto error1;
8098cc72361SWai Yew CHAY 
8108cc72361SWai Yew CHAY 	pitch = atc_get_pitch(apcm->substream->runtime->rate, (rsr * desc.msr));
8118cc72361SWai Yew CHAY 	src = apcm->src;
8128cc72361SWai Yew CHAY 	src->ops->set_pitch(src, pitch);
8138cc72361SWai Yew CHAY 	src->ops->set_rom(src, select_rom(pitch));
814a45c4d51SSudip Mukherjee 	src->ops->set_sf(src, convert_format(apcm->substream->runtime->format,
815a45c4d51SSudip Mukherjee 					     atc->card));
8168cc72361SWai Yew CHAY 	src->ops->set_pm(src, (src->ops->next_interleave(src) != NULL));
8178cc72361SWai Yew CHAY 	src->ops->set_bp(src, 1);
8188cc72361SWai Yew CHAY 
8198cc72361SWai Yew CHAY 	/* Get AMIXER resource */
8208cc72361SWai Yew CHAY 	n_amixer = (n_amixer < 2) ? 2 : n_amixer;
8216396bb22SKees Cook 	apcm->amixers = kcalloc(n_amixer, sizeof(void *), GFP_KERNEL);
82235ebf6e7STakashi Iwai 	if (!apcm->amixers) {
8238cc72361SWai Yew CHAY 		err = -ENOMEM;
8248cc72361SWai Yew CHAY 		goto error1;
8258cc72361SWai Yew CHAY 	}
8268cc72361SWai Yew CHAY 	mix_dsc.msr = desc.msr;
8278cc72361SWai Yew CHAY 	for (i = 0, apcm->n_amixer = 0; i < n_amixer; i++) {
8288cc72361SWai Yew CHAY 		err = amixer_mgr->get_amixer(amixer_mgr, &mix_dsc,
8298cc72361SWai Yew CHAY 					(struct amixer **)&apcm->amixers[i]);
8308cc72361SWai Yew CHAY 		if (err)
8318cc72361SWai Yew CHAY 			goto error1;
8328cc72361SWai Yew CHAY 
8338cc72361SWai Yew CHAY 		apcm->n_amixer++;
8348cc72361SWai Yew CHAY 	}
8358cc72361SWai Yew CHAY 
8368cc72361SWai Yew CHAY 	/* Set up device virtual mem map */
8378cc72361SWai Yew CHAY 	err = ct_map_audio_buffer(atc, apcm);
8388cc72361SWai Yew CHAY 	if (err < 0)
8398cc72361SWai Yew CHAY 		goto error1;
8408cc72361SWai Yew CHAY 
8418cc72361SWai Yew CHAY 	return 0;
8428cc72361SWai Yew CHAY 
8438cc72361SWai Yew CHAY error1:
8448cc72361SWai Yew CHAY 	atc_pcm_release_resources(atc, apcm);
8458cc72361SWai Yew CHAY 	return err;
8468cc72361SWai Yew CHAY }
8478cc72361SWai Yew CHAY 
atc_pll_init(struct ct_atc * atc,int rate)848514eef9cSTakashi Iwai static int atc_pll_init(struct ct_atc *atc, int rate)
849514eef9cSTakashi Iwai {
850514eef9cSTakashi Iwai 	struct hw *hw = atc->hw;
851514eef9cSTakashi Iwai 	int err;
852514eef9cSTakashi Iwai 	err = hw->pll_init(hw, rate);
853514eef9cSTakashi Iwai 	atc->pll_rate = err ? 0 : rate;
854514eef9cSTakashi Iwai 	return err;
855514eef9cSTakashi Iwai }
856514eef9cSTakashi Iwai 
8578cc72361SWai Yew CHAY static int
spdif_passthru_playback_setup(struct ct_atc * atc,struct ct_atc_pcm * apcm)8588cc72361SWai Yew CHAY spdif_passthru_playback_setup(struct ct_atc *atc, struct ct_atc_pcm *apcm)
8598cc72361SWai Yew CHAY {
8608cc72361SWai Yew CHAY 	struct dao *dao = container_of(atc->daios[SPDIFOO], struct dao, daio);
8618cc72361SWai Yew CHAY 	unsigned int rate = apcm->substream->runtime->rate;
862514eef9cSTakashi Iwai 	unsigned int status;
86329959a09SWai Yew CHAY 	int err = 0;
864514eef9cSTakashi Iwai 	unsigned char iec958_con_fs;
8658cc72361SWai Yew CHAY 
8668cc72361SWai Yew CHAY 	switch (rate) {
8678cc72361SWai Yew CHAY 	case 48000:
8688cc72361SWai Yew CHAY 		iec958_con_fs = IEC958_AES3_CON_FS_48000;
8698cc72361SWai Yew CHAY 		break;
8708cc72361SWai Yew CHAY 	case 44100:
8718cc72361SWai Yew CHAY 		iec958_con_fs = IEC958_AES3_CON_FS_44100;
8728cc72361SWai Yew CHAY 		break;
8738cc72361SWai Yew CHAY 	case 32000:
8748cc72361SWai Yew CHAY 		iec958_con_fs = IEC958_AES3_CON_FS_32000;
8758cc72361SWai Yew CHAY 		break;
8768cc72361SWai Yew CHAY 	default:
8778cc72361SWai Yew CHAY 		return -ENOENT;
8788cc72361SWai Yew CHAY 	}
8798cc72361SWai Yew CHAY 
880635c265fSTakashi Iwai 	mutex_lock(&atc->atc_mutex);
8818cc72361SWai Yew CHAY 	dao->ops->get_spos(dao, &status);
8828cc72361SWai Yew CHAY 	if (((status >> 24) & IEC958_AES3_CON_FS) != iec958_con_fs) {
8834c1847e8SPrzemyslaw Bruski 		status &= ~(IEC958_AES3_CON_FS << 24);
8848cc72361SWai Yew CHAY 		status |= (iec958_con_fs << 24);
8858cc72361SWai Yew CHAY 		dao->ops->set_spos(dao, status);
8868cc72361SWai Yew CHAY 		dao->ops->commit_write(dao);
8878cc72361SWai Yew CHAY 	}
888514eef9cSTakashi Iwai 	if ((rate != atc->pll_rate) && (32000 != rate))
889514eef9cSTakashi Iwai 		err = atc_pll_init(atc, rate);
890635c265fSTakashi Iwai 	mutex_unlock(&atc->atc_mutex);
8918cc72361SWai Yew CHAY 
8928cc72361SWai Yew CHAY 	return err;
8938cc72361SWai Yew CHAY }
8948cc72361SWai Yew CHAY 
8958cc72361SWai Yew CHAY static int
spdif_passthru_playback_prepare(struct ct_atc * atc,struct ct_atc_pcm * apcm)8968cc72361SWai Yew CHAY spdif_passthru_playback_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm)
8978cc72361SWai Yew CHAY {
898514eef9cSTakashi Iwai 	struct src *src;
899514eef9cSTakashi Iwai 	struct amixer *amixer;
900514eef9cSTakashi Iwai 	struct dao *dao;
901514eef9cSTakashi Iwai 	int err;
902514eef9cSTakashi Iwai 	int i;
9038cc72361SWai Yew CHAY 
90429959a09SWai Yew CHAY 	atc_pcm_release_resources(atc, apcm);
9058cc72361SWai Yew CHAY 
9068cc72361SWai Yew CHAY 	/* Configure SPDIFOO and PLL to passthrough mode;
9078cc72361SWai Yew CHAY 	 * determine pll_rate. */
9088cc72361SWai Yew CHAY 	err = spdif_passthru_playback_setup(atc, apcm);
9098cc72361SWai Yew CHAY 	if (err)
9108cc72361SWai Yew CHAY 		return err;
9118cc72361SWai Yew CHAY 
9128cc72361SWai Yew CHAY 	/* Get needed resources. */
9138cc72361SWai Yew CHAY 	err = spdif_passthru_playback_get_resources(atc, apcm);
9148cc72361SWai Yew CHAY 	if (err)
9158cc72361SWai Yew CHAY 		return err;
9168cc72361SWai Yew CHAY 
9178cc72361SWai Yew CHAY 	/* Connect resources */
9188cc72361SWai Yew CHAY 	src = apcm->src;
9198cc72361SWai Yew CHAY 	for (i = 0; i < apcm->n_amixer; i++) {
9208cc72361SWai Yew CHAY 		amixer = apcm->amixers[i];
9218cc72361SWai Yew CHAY 		amixer->ops->setup(amixer, &src->rsc, INIT_VOL, NULL);
9228cc72361SWai Yew CHAY 		src = src->ops->next_interleave(src);
92335ebf6e7STakashi Iwai 		if (!src)
9248cc72361SWai Yew CHAY 			src = apcm->src;
9258cc72361SWai Yew CHAY 	}
9268cc72361SWai Yew CHAY 	/* Connect to SPDIFOO */
927635c265fSTakashi Iwai 	mutex_lock(&atc->atc_mutex);
9288cc72361SWai Yew CHAY 	dao = container_of(atc->daios[SPDIFOO], struct dao, daio);
9298cc72361SWai Yew CHAY 	amixer = apcm->amixers[0];
9308cc72361SWai Yew CHAY 	dao->ops->set_left_input(dao, &amixer->rsc);
9318cc72361SWai Yew CHAY 	amixer = apcm->amixers[1];
9328cc72361SWai Yew CHAY 	dao->ops->set_right_input(dao, &amixer->rsc);
933635c265fSTakashi Iwai 	mutex_unlock(&atc->atc_mutex);
9348cc72361SWai Yew CHAY 
935b7bbf876STakashi Iwai 	ct_timer_prepare(apcm->timer);
936b7bbf876STakashi Iwai 
9378cc72361SWai Yew CHAY 	return 0;
9388cc72361SWai Yew CHAY }
9398cc72361SWai Yew CHAY 
atc_select_line_in(struct ct_atc * atc)9408cc72361SWai Yew CHAY static int atc_select_line_in(struct ct_atc *atc)
9418cc72361SWai Yew CHAY {
9428cc72361SWai Yew CHAY 	struct hw *hw = atc->hw;
9438cc72361SWai Yew CHAY 	struct ct_mixer *mixer = atc->mixer;
944514eef9cSTakashi Iwai 	struct src *src;
9458cc72361SWai Yew CHAY 
9468cc72361SWai Yew CHAY 	if (hw->is_adc_source_selected(hw, ADC_LINEIN))
9478cc72361SWai Yew CHAY 		return 0;
9488cc72361SWai Yew CHAY 
9498cc72361SWai Yew CHAY 	mixer->set_input_left(mixer, MIX_MIC_IN, NULL);
9508cc72361SWai Yew CHAY 	mixer->set_input_right(mixer, MIX_MIC_IN, NULL);
9518cc72361SWai Yew CHAY 
9528cc72361SWai Yew CHAY 	hw->select_adc_source(hw, ADC_LINEIN);
9538cc72361SWai Yew CHAY 
9548cc72361SWai Yew CHAY 	src = atc->srcs[2];
9558cc72361SWai Yew CHAY 	mixer->set_input_left(mixer, MIX_LINE_IN, &src->rsc);
9568cc72361SWai Yew CHAY 	src = atc->srcs[3];
9578cc72361SWai Yew CHAY 	mixer->set_input_right(mixer, MIX_LINE_IN, &src->rsc);
9588cc72361SWai Yew CHAY 
9598cc72361SWai Yew CHAY 	return 0;
9608cc72361SWai Yew CHAY }
9618cc72361SWai Yew CHAY 
atc_select_mic_in(struct ct_atc * atc)9628cc72361SWai Yew CHAY static int atc_select_mic_in(struct ct_atc *atc)
9638cc72361SWai Yew CHAY {
9648cc72361SWai Yew CHAY 	struct hw *hw = atc->hw;
9658cc72361SWai Yew CHAY 	struct ct_mixer *mixer = atc->mixer;
966514eef9cSTakashi Iwai 	struct src *src;
9678cc72361SWai Yew CHAY 
9688cc72361SWai Yew CHAY 	if (hw->is_adc_source_selected(hw, ADC_MICIN))
9698cc72361SWai Yew CHAY 		return 0;
9708cc72361SWai Yew CHAY 
9718cc72361SWai Yew CHAY 	mixer->set_input_left(mixer, MIX_LINE_IN, NULL);
9728cc72361SWai Yew CHAY 	mixer->set_input_right(mixer, MIX_LINE_IN, NULL);
9738cc72361SWai Yew CHAY 
9748cc72361SWai Yew CHAY 	hw->select_adc_source(hw, ADC_MICIN);
9758cc72361SWai Yew CHAY 
9768cc72361SWai Yew CHAY 	src = atc->srcs[2];
9778cc72361SWai Yew CHAY 	mixer->set_input_left(mixer, MIX_MIC_IN, &src->rsc);
9788cc72361SWai Yew CHAY 	src = atc->srcs[3];
9798cc72361SWai Yew CHAY 	mixer->set_input_right(mixer, MIX_MIC_IN, &src->rsc);
9808cc72361SWai Yew CHAY 
9818cc72361SWai Yew CHAY 	return 0;
9828cc72361SWai Yew CHAY }
9838cc72361SWai Yew CHAY 
atc_capabilities(struct ct_atc * atc)984b028b818SHarry Butterworth static struct capabilities atc_capabilities(struct ct_atc *atc)
9858cc72361SWai Yew CHAY {
9868cc72361SWai Yew CHAY 	struct hw *hw = atc->hw;
9878cc72361SWai Yew CHAY 
988b028b818SHarry Butterworth 	return hw->capabilities(hw);
98955309216SHarry Butterworth }
99055309216SHarry Butterworth 
atc_output_switch_get(struct ct_atc * atc)99155309216SHarry Butterworth static int atc_output_switch_get(struct ct_atc *atc)
99255309216SHarry Butterworth {
99355309216SHarry Butterworth 	struct hw *hw = atc->hw;
99455309216SHarry Butterworth 
99555309216SHarry Butterworth 	return hw->output_switch_get(hw);
99655309216SHarry Butterworth }
99755309216SHarry Butterworth 
atc_output_switch_put(struct ct_atc * atc,int position)99855309216SHarry Butterworth static int atc_output_switch_put(struct ct_atc *atc, int position)
99955309216SHarry Butterworth {
100055309216SHarry Butterworth 	struct hw *hw = atc->hw;
100155309216SHarry Butterworth 
100255309216SHarry Butterworth 	return hw->output_switch_put(hw, position);
100355309216SHarry Butterworth }
100455309216SHarry Butterworth 
atc_mic_source_switch_get(struct ct_atc * atc)100555309216SHarry Butterworth static int atc_mic_source_switch_get(struct ct_atc *atc)
100655309216SHarry Butterworth {
100755309216SHarry Butterworth 	struct hw *hw = atc->hw;
100855309216SHarry Butterworth 
100955309216SHarry Butterworth 	return hw->mic_source_switch_get(hw);
101055309216SHarry Butterworth }
101155309216SHarry Butterworth 
atc_mic_source_switch_put(struct ct_atc * atc,int position)101255309216SHarry Butterworth static int atc_mic_source_switch_put(struct ct_atc *atc, int position)
101355309216SHarry Butterworth {
101455309216SHarry Butterworth 	struct hw *hw = atc->hw;
101555309216SHarry Butterworth 
101655309216SHarry Butterworth 	return hw->mic_source_switch_put(hw, position);
101755309216SHarry Butterworth }
101855309216SHarry Butterworth 
atc_select_digit_io(struct ct_atc * atc)10198cc72361SWai Yew CHAY static int atc_select_digit_io(struct ct_atc *atc)
10208cc72361SWai Yew CHAY {
10218cc72361SWai Yew CHAY 	struct hw *hw = atc->hw;
10228cc72361SWai Yew CHAY 
10238cc72361SWai Yew CHAY 	if (hw->is_adc_source_selected(hw, ADC_NONE))
10248cc72361SWai Yew CHAY 		return 0;
10258cc72361SWai Yew CHAY 
10268cc72361SWai Yew CHAY 	hw->select_adc_source(hw, ADC_NONE);
10278cc72361SWai Yew CHAY 
10288cc72361SWai Yew CHAY 	return 0;
10298cc72361SWai Yew CHAY }
10308cc72361SWai Yew CHAY 
atc_daio_unmute(struct ct_atc * atc,unsigned char state,int type)10318cc72361SWai Yew CHAY static int atc_daio_unmute(struct ct_atc *atc, unsigned char state, int type)
10328cc72361SWai Yew CHAY {
10338cc72361SWai Yew CHAY 	struct daio_mgr *daio_mgr = atc->rsc_mgrs[DAIO];
10348cc72361SWai Yew CHAY 
10358cc72361SWai Yew CHAY 	if (state)
10368cc72361SWai Yew CHAY 		daio_mgr->daio_enable(daio_mgr, atc->daios[type]);
10378cc72361SWai Yew CHAY 	else
10388cc72361SWai Yew CHAY 		daio_mgr->daio_disable(daio_mgr, atc->daios[type]);
10398cc72361SWai Yew CHAY 
10408cc72361SWai Yew CHAY 	daio_mgr->commit_write(daio_mgr);
10418cc72361SWai Yew CHAY 
10428cc72361SWai Yew CHAY 	return 0;
10438cc72361SWai Yew CHAY }
10448cc72361SWai Yew CHAY 
10458cc72361SWai Yew CHAY static int
atc_dao_get_status(struct ct_atc * atc,unsigned int * status,int type)10468cc72361SWai Yew CHAY atc_dao_get_status(struct ct_atc *atc, unsigned int *status, int type)
10478cc72361SWai Yew CHAY {
10488cc72361SWai Yew CHAY 	struct dao *dao = container_of(atc->daios[type], struct dao, daio);
10498cc72361SWai Yew CHAY 	return dao->ops->get_spos(dao, status);
10508cc72361SWai Yew CHAY }
10518cc72361SWai Yew CHAY 
10528cc72361SWai Yew CHAY static int
atc_dao_set_status(struct ct_atc * atc,unsigned int status,int type)10538cc72361SWai Yew CHAY atc_dao_set_status(struct ct_atc *atc, unsigned int status, int type)
10548cc72361SWai Yew CHAY {
10558cc72361SWai Yew CHAY 	struct dao *dao = container_of(atc->daios[type], struct dao, daio);
10568cc72361SWai Yew CHAY 
10578cc72361SWai Yew CHAY 	dao->ops->set_spos(dao, status);
10588cc72361SWai Yew CHAY 	dao->ops->commit_write(dao);
10598cc72361SWai Yew CHAY 	return 0;
10608cc72361SWai Yew CHAY }
10618cc72361SWai Yew CHAY 
atc_line_front_unmute(struct ct_atc * atc,unsigned char state)10628cc72361SWai Yew CHAY static int atc_line_front_unmute(struct ct_atc *atc, unsigned char state)
10638cc72361SWai Yew CHAY {
10648cc72361SWai Yew CHAY 	return atc_daio_unmute(atc, state, LINEO1);
10658cc72361SWai Yew CHAY }
10668cc72361SWai Yew CHAY 
atc_line_surround_unmute(struct ct_atc * atc,unsigned char state)10678cc72361SWai Yew CHAY static int atc_line_surround_unmute(struct ct_atc *atc, unsigned char state)
10688cc72361SWai Yew CHAY {
10693b04691cSSven Eckelmann 	return atc_daio_unmute(atc, state, LINEO2);
10708cc72361SWai Yew CHAY }
10718cc72361SWai Yew CHAY 
atc_line_clfe_unmute(struct ct_atc * atc,unsigned char state)10728cc72361SWai Yew CHAY static int atc_line_clfe_unmute(struct ct_atc *atc, unsigned char state)
10738cc72361SWai Yew CHAY {
10748cc72361SWai Yew CHAY 	return atc_daio_unmute(atc, state, LINEO3);
10758cc72361SWai Yew CHAY }
10768cc72361SWai Yew CHAY 
atc_line_rear_unmute(struct ct_atc * atc,unsigned char state)10778cc72361SWai Yew CHAY static int atc_line_rear_unmute(struct ct_atc *atc, unsigned char state)
10788cc72361SWai Yew CHAY {
10793b04691cSSven Eckelmann 	return atc_daio_unmute(atc, state, LINEO4);
10808cc72361SWai Yew CHAY }
10818cc72361SWai Yew CHAY 
atc_line_in_unmute(struct ct_atc * atc,unsigned char state)10828cc72361SWai Yew CHAY static int atc_line_in_unmute(struct ct_atc *atc, unsigned char state)
10838cc72361SWai Yew CHAY {
10848cc72361SWai Yew CHAY 	return atc_daio_unmute(atc, state, LINEIM);
10858cc72361SWai Yew CHAY }
10868cc72361SWai Yew CHAY 
atc_mic_unmute(struct ct_atc * atc,unsigned char state)108755309216SHarry Butterworth static int atc_mic_unmute(struct ct_atc *atc, unsigned char state)
108855309216SHarry Butterworth {
108955309216SHarry Butterworth 	return atc_daio_unmute(atc, state, MIC);
109055309216SHarry Butterworth }
109155309216SHarry Butterworth 
atc_spdif_out_unmute(struct ct_atc * atc,unsigned char state)10928cc72361SWai Yew CHAY static int atc_spdif_out_unmute(struct ct_atc *atc, unsigned char state)
10938cc72361SWai Yew CHAY {
10948cc72361SWai Yew CHAY 	return atc_daio_unmute(atc, state, SPDIFOO);
10958cc72361SWai Yew CHAY }
10968cc72361SWai Yew CHAY 
atc_spdif_in_unmute(struct ct_atc * atc,unsigned char state)10978cc72361SWai Yew CHAY static int atc_spdif_in_unmute(struct ct_atc *atc, unsigned char state)
10988cc72361SWai Yew CHAY {
10998cc72361SWai Yew CHAY 	return atc_daio_unmute(atc, state, SPDIFIO);
11008cc72361SWai Yew CHAY }
11018cc72361SWai Yew CHAY 
atc_spdif_out_get_status(struct ct_atc * atc,unsigned int * status)11028cc72361SWai Yew CHAY static int atc_spdif_out_get_status(struct ct_atc *atc, unsigned int *status)
11038cc72361SWai Yew CHAY {
11048cc72361SWai Yew CHAY 	return atc_dao_get_status(atc, status, SPDIFOO);
11058cc72361SWai Yew CHAY }
11068cc72361SWai Yew CHAY 
atc_spdif_out_set_status(struct ct_atc * atc,unsigned int status)11078cc72361SWai Yew CHAY static int atc_spdif_out_set_status(struct ct_atc *atc, unsigned int status)
11088cc72361SWai Yew CHAY {
11098cc72361SWai Yew CHAY 	return atc_dao_set_status(atc, status, SPDIFOO);
11108cc72361SWai Yew CHAY }
11118cc72361SWai Yew CHAY 
atc_spdif_out_passthru(struct ct_atc * atc,unsigned char state)11128cc72361SWai Yew CHAY static int atc_spdif_out_passthru(struct ct_atc *atc, unsigned char state)
11138cc72361SWai Yew CHAY {
11148cc72361SWai Yew CHAY 	struct dao_desc da_dsc = {0};
1115514eef9cSTakashi Iwai 	struct dao *dao;
1116514eef9cSTakashi Iwai 	int err;
11178cc72361SWai Yew CHAY 	struct ct_mixer *mixer = atc->mixer;
11188cc72361SWai Yew CHAY 	struct rsc *rscs[2] = {NULL};
11198cc72361SWai Yew CHAY 	unsigned int spos = 0;
11208cc72361SWai Yew CHAY 
1121635c265fSTakashi Iwai 	mutex_lock(&atc->atc_mutex);
11228cc72361SWai Yew CHAY 	dao = container_of(atc->daios[SPDIFOO], struct dao, daio);
11238cc72361SWai Yew CHAY 	da_dsc.msr = state ? 1 : atc->msr;
11248cc72361SWai Yew CHAY 	da_dsc.passthru = state ? 1 : 0;
11258cc72361SWai Yew CHAY 	err = dao->ops->reinit(dao, &da_dsc);
11268cc72361SWai Yew CHAY 	if (state) {
11278cc72361SWai Yew CHAY 		spos = IEC958_DEFAULT_CON;
11288cc72361SWai Yew CHAY 	} else {
11298cc72361SWai Yew CHAY 		mixer->get_output_ports(mixer, MIX_SPDIF_OUT,
11308cc72361SWai Yew CHAY 					&rscs[0], &rscs[1]);
11318cc72361SWai Yew CHAY 		dao->ops->set_left_input(dao, rscs[0]);
11328cc72361SWai Yew CHAY 		dao->ops->set_right_input(dao, rscs[1]);
11338cc72361SWai Yew CHAY 		/* Restore PLL to atc->rsr if needed. */
1134514eef9cSTakashi Iwai 		if (atc->pll_rate != atc->rsr)
1135514eef9cSTakashi Iwai 			err = atc_pll_init(atc, atc->rsr);
11368cc72361SWai Yew CHAY 	}
11378cc72361SWai Yew CHAY 	dao->ops->set_spos(dao, spos);
11388cc72361SWai Yew CHAY 	dao->ops->commit_write(dao);
1139635c265fSTakashi Iwai 	mutex_unlock(&atc->atc_mutex);
11408cc72361SWai Yew CHAY 
11418cc72361SWai Yew CHAY 	return err;
11428cc72361SWai Yew CHAY }
11438cc72361SWai Yew CHAY 
atc_release_resources(struct ct_atc * atc)114429959a09SWai Yew CHAY static int atc_release_resources(struct ct_atc *atc)
11458cc72361SWai Yew CHAY {
114629959a09SWai Yew CHAY 	int i;
114729959a09SWai Yew CHAY 	struct daio_mgr *daio_mgr = NULL;
114829959a09SWai Yew CHAY 	struct dao *dao = NULL;
114929959a09SWai Yew CHAY 	struct daio *daio = NULL;
115029959a09SWai Yew CHAY 	struct sum_mgr *sum_mgr = NULL;
115129959a09SWai Yew CHAY 	struct src_mgr *src_mgr = NULL;
115229959a09SWai Yew CHAY 	struct srcimp_mgr *srcimp_mgr = NULL;
115329959a09SWai Yew CHAY 	struct srcimp *srcimp = NULL;
115429959a09SWai Yew CHAY 	struct ct_mixer *mixer = NULL;
11558cc72361SWai Yew CHAY 
115629959a09SWai Yew CHAY 	/* disconnect internal mixer objects */
115735ebf6e7STakashi Iwai 	if (atc->mixer) {
11588cc72361SWai Yew CHAY 		mixer = atc->mixer;
11598cc72361SWai Yew CHAY 		mixer->set_input_left(mixer, MIX_LINE_IN, NULL);
11608cc72361SWai Yew CHAY 		mixer->set_input_right(mixer, MIX_LINE_IN, NULL);
11618cc72361SWai Yew CHAY 		mixer->set_input_left(mixer, MIX_MIC_IN, NULL);
11628cc72361SWai Yew CHAY 		mixer->set_input_right(mixer, MIX_MIC_IN, NULL);
11638cc72361SWai Yew CHAY 		mixer->set_input_left(mixer, MIX_SPDIF_IN, NULL);
11648cc72361SWai Yew CHAY 		mixer->set_input_right(mixer, MIX_SPDIF_IN, NULL);
11658cc72361SWai Yew CHAY 	}
11668cc72361SWai Yew CHAY 
116735ebf6e7STakashi Iwai 	if (atc->daios) {
11688cc72361SWai Yew CHAY 		daio_mgr = (struct daio_mgr *)atc->rsc_mgrs[DAIO];
11698cc72361SWai Yew CHAY 		for (i = 0; i < atc->n_daio; i++) {
11708cc72361SWai Yew CHAY 			daio = atc->daios[i];
11718cc72361SWai Yew CHAY 			if (daio->type < LINEIM) {
11728cc72361SWai Yew CHAY 				dao = container_of(daio, struct dao, daio);
11738cc72361SWai Yew CHAY 				dao->ops->clear_left_input(dao);
11748cc72361SWai Yew CHAY 				dao->ops->clear_right_input(dao);
11758cc72361SWai Yew CHAY 			}
11768cc72361SWai Yew CHAY 			daio_mgr->put_daio(daio_mgr, daio);
11778cc72361SWai Yew CHAY 		}
11788cc72361SWai Yew CHAY 		kfree(atc->daios);
117929959a09SWai Yew CHAY 		atc->daios = NULL;
11808cc72361SWai Yew CHAY 	}
11818cc72361SWai Yew CHAY 
118235ebf6e7STakashi Iwai 	if (atc->pcm) {
11838cc72361SWai Yew CHAY 		sum_mgr = atc->rsc_mgrs[SUM];
11848cc72361SWai Yew CHAY 		for (i = 0; i < atc->n_pcm; i++)
11858cc72361SWai Yew CHAY 			sum_mgr->put_sum(sum_mgr, atc->pcm[i]);
11868cc72361SWai Yew CHAY 
11878cc72361SWai Yew CHAY 		kfree(atc->pcm);
118829959a09SWai Yew CHAY 		atc->pcm = NULL;
11898cc72361SWai Yew CHAY 	}
11908cc72361SWai Yew CHAY 
119135ebf6e7STakashi Iwai 	if (atc->srcs) {
11928cc72361SWai Yew CHAY 		src_mgr = atc->rsc_mgrs[SRC];
11938cc72361SWai Yew CHAY 		for (i = 0; i < atc->n_src; i++)
11948cc72361SWai Yew CHAY 			src_mgr->put_src(src_mgr, atc->srcs[i]);
11958cc72361SWai Yew CHAY 
11968cc72361SWai Yew CHAY 		kfree(atc->srcs);
119729959a09SWai Yew CHAY 		atc->srcs = NULL;
11988cc72361SWai Yew CHAY 	}
11998cc72361SWai Yew CHAY 
120035ebf6e7STakashi Iwai 	if (atc->srcimps) {
12018cc72361SWai Yew CHAY 		srcimp_mgr = atc->rsc_mgrs[SRCIMP];
12028cc72361SWai Yew CHAY 		for (i = 0; i < atc->n_srcimp; i++) {
12038cc72361SWai Yew CHAY 			srcimp = atc->srcimps[i];
12048cc72361SWai Yew CHAY 			srcimp->ops->unmap(srcimp);
12058cc72361SWai Yew CHAY 			srcimp_mgr->put_srcimp(srcimp_mgr, atc->srcimps[i]);
12068cc72361SWai Yew CHAY 		}
12078cc72361SWai Yew CHAY 		kfree(atc->srcimps);
120829959a09SWai Yew CHAY 		atc->srcimps = NULL;
12098cc72361SWai Yew CHAY 	}
12108cc72361SWai Yew CHAY 
121129959a09SWai Yew CHAY 	return 0;
121229959a09SWai Yew CHAY }
121329959a09SWai Yew CHAY 
ct_atc_destroy(struct ct_atc * atc)121429959a09SWai Yew CHAY static int ct_atc_destroy(struct ct_atc *atc)
121529959a09SWai Yew CHAY {
121629959a09SWai Yew CHAY 	int i = 0;
121729959a09SWai Yew CHAY 
121835ebf6e7STakashi Iwai 	if (!atc)
121929959a09SWai Yew CHAY 		return 0;
122029959a09SWai Yew CHAY 
122129959a09SWai Yew CHAY 	if (atc->timer) {
122229959a09SWai Yew CHAY 		ct_timer_free(atc->timer);
122329959a09SWai Yew CHAY 		atc->timer = NULL;
122429959a09SWai Yew CHAY 	}
122529959a09SWai Yew CHAY 
122629959a09SWai Yew CHAY 	atc_release_resources(atc);
122729959a09SWai Yew CHAY 
122829959a09SWai Yew CHAY 	/* Destroy internal mixer objects */
122935ebf6e7STakashi Iwai 	if (atc->mixer)
123029959a09SWai Yew CHAY 		ct_mixer_destroy(atc->mixer);
123129959a09SWai Yew CHAY 
12328cc72361SWai Yew CHAY 	for (i = 0; i < NUM_RSCTYP; i++) {
123335ebf6e7STakashi Iwai 		if (rsc_mgr_funcs[i].destroy && atc->rsc_mgrs[i])
12348cc72361SWai Yew CHAY 			rsc_mgr_funcs[i].destroy(atc->rsc_mgrs[i]);
12358cc72361SWai Yew CHAY 
12368cc72361SWai Yew CHAY 	}
12378cc72361SWai Yew CHAY 
123835ebf6e7STakashi Iwai 	if (atc->hw)
1239b6bfe86fSSudip Mukherjee 		destroy_hw_obj(atc->hw);
12408cc72361SWai Yew CHAY 
12418cc72361SWai Yew CHAY 	/* Destroy device virtual memory manager object */
124235ebf6e7STakashi Iwai 	if (atc->vm) {
12438cc72361SWai Yew CHAY 		ct_vm_destroy(atc->vm);
12448cc72361SWai Yew CHAY 		atc->vm = NULL;
12458cc72361SWai Yew CHAY 	}
12468cc72361SWai Yew CHAY 
12478cc72361SWai Yew CHAY 	kfree(atc);
12488cc72361SWai Yew CHAY 
12498cc72361SWai Yew CHAY 	return 0;
12508cc72361SWai Yew CHAY }
12518cc72361SWai Yew CHAY 
atc_dev_free(struct snd_device * dev)12528cc72361SWai Yew CHAY static int atc_dev_free(struct snd_device *dev)
12538cc72361SWai Yew CHAY {
12548cc72361SWai Yew CHAY 	struct ct_atc *atc = dev->device_data;
12558cc72361SWai Yew CHAY 	return ct_atc_destroy(atc);
12568cc72361SWai Yew CHAY }
12578cc72361SWai Yew CHAY 
atc_identify_card(struct ct_atc * atc,unsigned int ssid)1258e23e7a14SBill Pemberton static int atc_identify_card(struct ct_atc *atc, unsigned int ssid)
12598cc72361SWai Yew CHAY {
12609470195aSTakashi Iwai 	const struct snd_pci_quirk *p;
12619470195aSTakashi Iwai 	const struct snd_pci_quirk *list;
1262408bffd0STakashi Iwai 	u16 vendor_id, device_id;
12638cc72361SWai Yew CHAY 
12649470195aSTakashi Iwai 	switch (atc->chip_type) {
12659470195aSTakashi Iwai 	case ATC20K1:
12669470195aSTakashi Iwai 		atc->chip_name = "20K1";
12679470195aSTakashi Iwai 		list = subsys_20k1_list;
12688cc72361SWai Yew CHAY 		break;
12699470195aSTakashi Iwai 	case ATC20K2:
12709470195aSTakashi Iwai 		atc->chip_name = "20K2";
12719470195aSTakashi Iwai 		list = subsys_20k2_list;
12728cc72361SWai Yew CHAY 		break;
12739470195aSTakashi Iwai 	default:
12748cc72361SWai Yew CHAY 		return -ENOENT;
12759470195aSTakashi Iwai 	}
1276408bffd0STakashi Iwai 	if (ssid) {
1277408bffd0STakashi Iwai 		vendor_id = ssid >> 16;
1278408bffd0STakashi Iwai 		device_id = ssid & 0xffff;
1279408bffd0STakashi Iwai 	} else {
1280408bffd0STakashi Iwai 		vendor_id = atc->pci->subsystem_vendor;
1281408bffd0STakashi Iwai 		device_id = atc->pci->subsystem_device;
1282408bffd0STakashi Iwai 	}
1283408bffd0STakashi Iwai 	p = snd_pci_quirk_lookup_id(vendor_id, device_id, list);
1284a8f4310bSTakashi Iwai 	if (p) {
1285a8f4310bSTakashi Iwai 		if (p->value < 0) {
12860cae90a9SSudip Mukherjee 			dev_err(atc->card->dev,
1287ba2b94eeSTakashi Iwai 				"Device %04x:%04x is on the denylist\n",
1288408bffd0STakashi Iwai 				vendor_id, device_id);
12899470195aSTakashi Iwai 			return -ENOENT;
1290a8f4310bSTakashi Iwai 		}
12919470195aSTakashi Iwai 		atc->model = p->value;
1292a8f4310bSTakashi Iwai 	} else {
1293a8f4310bSTakashi Iwai 		if (atc->chip_type == ATC20K1)
1294a8f4310bSTakashi Iwai 			atc->model = CT20K1_UNKNOWN;
1295a8f4310bSTakashi Iwai 		else
1296a8f4310bSTakashi Iwai 			atc->model = CT20K2_UNKNOWN;
1297a8f4310bSTakashi Iwai 	}
12989470195aSTakashi Iwai 	atc->model_name = ct_subsys_name[atc->model];
12992e6705c0STakashi Iwai 	dev_info(atc->card->dev, "chip %s model %s (%04x:%04x) is found\n",
13009470195aSTakashi Iwai 		   atc->chip_name, atc->model_name,
1301408bffd0STakashi Iwai 		   vendor_id, device_id);
13028cc72361SWai Yew CHAY 	return 0;
13038cc72361SWai Yew CHAY }
13048cc72361SWai Yew CHAY 
ct_atc_create_alsa_devs(struct ct_atc * atc)1305e23e7a14SBill Pemberton int ct_atc_create_alsa_devs(struct ct_atc *atc)
13068cc72361SWai Yew CHAY {
13078cc72361SWai Yew CHAY 	enum CTALSADEVS i;
13088cc72361SWai Yew CHAY 	int err;
13098cc72361SWai Yew CHAY 
13109470195aSTakashi Iwai 	alsa_dev_funcs[MIXER].public_name = atc->chip_name;
13118cc72361SWai Yew CHAY 
13128cc72361SWai Yew CHAY 	for (i = 0; i < NUM_CTALSADEVS; i++) {
131335ebf6e7STakashi Iwai 		if (!alsa_dev_funcs[i].create)
13148cc72361SWai Yew CHAY 			continue;
13158cc72361SWai Yew CHAY 
13168cc72361SWai Yew CHAY 		err = alsa_dev_funcs[i].create(atc, i,
13178cc72361SWai Yew CHAY 				alsa_dev_funcs[i].public_name);
13188cc72361SWai Yew CHAY 		if (err) {
13190cae90a9SSudip Mukherjee 			dev_err(atc->card->dev,
13200cae90a9SSudip Mukherjee 				"Creating alsa device %d failed!\n", i);
13218cc72361SWai Yew CHAY 			return err;
13228cc72361SWai Yew CHAY 		}
13238cc72361SWai Yew CHAY 	}
13248cc72361SWai Yew CHAY 
13258cc72361SWai Yew CHAY 	return 0;
13268cc72361SWai Yew CHAY }
13278cc72361SWai Yew CHAY 
atc_create_hw_devs(struct ct_atc * atc)1328e23e7a14SBill Pemberton static int atc_create_hw_devs(struct ct_atc *atc)
13298cc72361SWai Yew CHAY {
1330514eef9cSTakashi Iwai 	struct hw *hw;
13318cc72361SWai Yew CHAY 	struct card_conf info = {0};
1332514eef9cSTakashi Iwai 	int i, err;
13338cc72361SWai Yew CHAY 
13349470195aSTakashi Iwai 	err = create_hw_obj(atc->pci, atc->chip_type, atc->model, &hw);
13358cc72361SWai Yew CHAY 	if (err) {
13360cae90a9SSudip Mukherjee 		dev_err(atc->card->dev, "Failed to create hw obj!!!\n");
13378cc72361SWai Yew CHAY 		return err;
13388cc72361SWai Yew CHAY 	}
1339e5347f9aSSudip Mukherjee 	hw->card = atc->card;
13408cc72361SWai Yew CHAY 	atc->hw = hw;
13418cc72361SWai Yew CHAY 
13428cc72361SWai Yew CHAY 	/* Initialize card hardware. */
13438cc72361SWai Yew CHAY 	info.rsr = atc->rsr;
13448cc72361SWai Yew CHAY 	info.msr = atc->msr;
13458cc72361SWai Yew CHAY 	info.vm_pgt_phys = atc_get_ptp_phys(atc, 0);
13468cc72361SWai Yew CHAY 	err = hw->card_init(hw, &info);
13478cc72361SWai Yew CHAY 	if (err < 0)
13488cc72361SWai Yew CHAY 		return err;
13498cc72361SWai Yew CHAY 
13508cc72361SWai Yew CHAY 	for (i = 0; i < NUM_RSCTYP; i++) {
135135ebf6e7STakashi Iwai 		if (!rsc_mgr_funcs[i].create)
13528cc72361SWai Yew CHAY 			continue;
13538cc72361SWai Yew CHAY 
13548cc72361SWai Yew CHAY 		err = rsc_mgr_funcs[i].create(atc->hw, &atc->rsc_mgrs[i]);
13558cc72361SWai Yew CHAY 		if (err) {
13560cae90a9SSudip Mukherjee 			dev_err(atc->card->dev,
13570cae90a9SSudip Mukherjee 				"Failed to create rsc_mgr %d!!!\n", i);
13588cc72361SWai Yew CHAY 			return err;
13598cc72361SWai Yew CHAY 		}
13608cc72361SWai Yew CHAY 	}
13618cc72361SWai Yew CHAY 
13628cc72361SWai Yew CHAY 	return 0;
13638cc72361SWai Yew CHAY }
13648cc72361SWai Yew CHAY 
atc_get_resources(struct ct_atc * atc)136529959a09SWai Yew CHAY static int atc_get_resources(struct ct_atc *atc)
13668cc72361SWai Yew CHAY {
13678cc72361SWai Yew CHAY 	struct daio_desc da_desc = {0};
1368514eef9cSTakashi Iwai 	struct daio_mgr *daio_mgr;
13698cc72361SWai Yew CHAY 	struct src_desc src_dsc = {0};
1370514eef9cSTakashi Iwai 	struct src_mgr *src_mgr;
13718cc72361SWai Yew CHAY 	struct srcimp_desc srcimp_dsc = {0};
1372514eef9cSTakashi Iwai 	struct srcimp_mgr *srcimp_mgr;
13738cc72361SWai Yew CHAY 	struct sum_desc sum_dsc = {0};
1374514eef9cSTakashi Iwai 	struct sum_mgr *sum_mgr;
137555309216SHarry Butterworth 	int err, i, num_srcs, num_daios;
13768cc72361SWai Yew CHAY 
137755309216SHarry Butterworth 	num_daios = ((atc->model == CTSB1270) ? 8 : 7);
137855309216SHarry Butterworth 	num_srcs = ((atc->model == CTSB1270) ? 6 : 4);
137955309216SHarry Butterworth 
13806396bb22SKees Cook 	atc->daios = kcalloc(num_daios, sizeof(void *), GFP_KERNEL);
138135ebf6e7STakashi Iwai 	if (!atc->daios)
13828cc72361SWai Yew CHAY 		return -ENOMEM;
13838cc72361SWai Yew CHAY 
13846396bb22SKees Cook 	atc->srcs = kcalloc(num_srcs, sizeof(void *), GFP_KERNEL);
138535ebf6e7STakashi Iwai 	if (!atc->srcs)
13868cc72361SWai Yew CHAY 		return -ENOMEM;
13878cc72361SWai Yew CHAY 
13886396bb22SKees Cook 	atc->srcimps = kcalloc(num_srcs, sizeof(void *), GFP_KERNEL);
138935ebf6e7STakashi Iwai 	if (!atc->srcimps)
13908cc72361SWai Yew CHAY 		return -ENOMEM;
13918cc72361SWai Yew CHAY 
13926396bb22SKees Cook 	atc->pcm = kcalloc(2 * 4, sizeof(void *), GFP_KERNEL);
139335ebf6e7STakashi Iwai 	if (!atc->pcm)
13948cc72361SWai Yew CHAY 		return -ENOMEM;
13958cc72361SWai Yew CHAY 
13968cc72361SWai Yew CHAY 	daio_mgr = (struct daio_mgr *)atc->rsc_mgrs[DAIO];
13978cc72361SWai Yew CHAY 	da_desc.msr = atc->msr;
139855309216SHarry Butterworth 	for (i = 0, atc->n_daio = 0; i < num_daios; i++) {
139955309216SHarry Butterworth 		da_desc.type = (atc->model != CTSB073X) ? i :
140055309216SHarry Butterworth 			     ((i == SPDIFIO) ? SPDIFI1 : i);
14018cc72361SWai Yew CHAY 		err = daio_mgr->get_daio(daio_mgr, &da_desc,
14028cc72361SWai Yew CHAY 					(struct daio **)&atc->daios[i]);
14038cc72361SWai Yew CHAY 		if (err) {
14040cae90a9SSudip Mukherjee 			dev_err(atc->card->dev,
14050cae90a9SSudip Mukherjee 				"Failed to get DAIO resource %d!!!\n",
140662afa853SSudip Mukherjee 				i);
14078cc72361SWai Yew CHAY 			return err;
14088cc72361SWai Yew CHAY 		}
14098cc72361SWai Yew CHAY 		atc->n_daio++;
14108cc72361SWai Yew CHAY 	}
14118cc72361SWai Yew CHAY 
14128cc72361SWai Yew CHAY 	src_mgr = atc->rsc_mgrs[SRC];
14138cc72361SWai Yew CHAY 	src_dsc.multi = 1;
14148cc72361SWai Yew CHAY 	src_dsc.msr = atc->msr;
14158cc72361SWai Yew CHAY 	src_dsc.mode = ARCRW;
141655309216SHarry Butterworth 	for (i = 0, atc->n_src = 0; i < num_srcs; i++) {
14178cc72361SWai Yew CHAY 		err = src_mgr->get_src(src_mgr, &src_dsc,
14188cc72361SWai Yew CHAY 					(struct src **)&atc->srcs[i]);
14198cc72361SWai Yew CHAY 		if (err)
14208cc72361SWai Yew CHAY 			return err;
14218cc72361SWai Yew CHAY 
14228cc72361SWai Yew CHAY 		atc->n_src++;
14238cc72361SWai Yew CHAY 	}
14248cc72361SWai Yew CHAY 
14258cc72361SWai Yew CHAY 	srcimp_mgr = atc->rsc_mgrs[SRCIMP];
142655309216SHarry Butterworth 	srcimp_dsc.msr = 8;
142755309216SHarry Butterworth 	for (i = 0, atc->n_srcimp = 0; i < num_srcs; i++) {
14288cc72361SWai Yew CHAY 		err = srcimp_mgr->get_srcimp(srcimp_mgr, &srcimp_dsc,
14298cc72361SWai Yew CHAY 					(struct srcimp **)&atc->srcimps[i]);
14308cc72361SWai Yew CHAY 		if (err)
14318cc72361SWai Yew CHAY 			return err;
14328cc72361SWai Yew CHAY 
14338cc72361SWai Yew CHAY 		atc->n_srcimp++;
14348cc72361SWai Yew CHAY 	}
14358cc72361SWai Yew CHAY 
14368cc72361SWai Yew CHAY 	sum_mgr = atc->rsc_mgrs[SUM];
14378cc72361SWai Yew CHAY 	sum_dsc.msr = atc->msr;
14388cc72361SWai Yew CHAY 	for (i = 0, atc->n_pcm = 0; i < (2*4); i++) {
14398cc72361SWai Yew CHAY 		err = sum_mgr->get_sum(sum_mgr, &sum_dsc,
14408cc72361SWai Yew CHAY 					(struct sum **)&atc->pcm[i]);
14418cc72361SWai Yew CHAY 		if (err)
14428cc72361SWai Yew CHAY 			return err;
14438cc72361SWai Yew CHAY 
14448cc72361SWai Yew CHAY 		atc->n_pcm++;
14458cc72361SWai Yew CHAY 	}
14468cc72361SWai Yew CHAY 
14478cc72361SWai Yew CHAY 	return 0;
14488cc72361SWai Yew CHAY }
14498cc72361SWai Yew CHAY 
145029959a09SWai Yew CHAY static void
atc_connect_dai(struct src_mgr * src_mgr,struct dai * dai,struct src ** srcs,struct srcimp ** srcimps)14518cc72361SWai Yew CHAY atc_connect_dai(struct src_mgr *src_mgr, struct dai *dai,
14528cc72361SWai Yew CHAY 		struct src **srcs, struct srcimp **srcimps)
14538cc72361SWai Yew CHAY {
14548cc72361SWai Yew CHAY 	struct rsc *rscs[2] = {NULL};
1455514eef9cSTakashi Iwai 	struct src *src;
1456514eef9cSTakashi Iwai 	struct srcimp *srcimp;
14578cc72361SWai Yew CHAY 	int i = 0;
14588cc72361SWai Yew CHAY 
14598cc72361SWai Yew CHAY 	rscs[0] = &dai->daio.rscl;
14608cc72361SWai Yew CHAY 	rscs[1] = &dai->daio.rscr;
14618cc72361SWai Yew CHAY 	for (i = 0; i < 2; i++) {
14628cc72361SWai Yew CHAY 		src = srcs[i];
14638cc72361SWai Yew CHAY 		srcimp = srcimps[i];
14648cc72361SWai Yew CHAY 		srcimp->ops->map(srcimp, src, rscs[i]);
14658cc72361SWai Yew CHAY 		src_mgr->src_disable(src_mgr, src);
14668cc72361SWai Yew CHAY 	}
14678cc72361SWai Yew CHAY 
14688cc72361SWai Yew CHAY 	src_mgr->commit_write(src_mgr); /* Actually disable SRCs */
14698cc72361SWai Yew CHAY 
14708cc72361SWai Yew CHAY 	src = srcs[0];
14718cc72361SWai Yew CHAY 	src->ops->set_pm(src, 1);
14728cc72361SWai Yew CHAY 	for (i = 0; i < 2; i++) {
14738cc72361SWai Yew CHAY 		src = srcs[i];
14748cc72361SWai Yew CHAY 		src->ops->set_state(src, SRC_STATE_RUN);
14758cc72361SWai Yew CHAY 		src->ops->commit_write(src);
14768cc72361SWai Yew CHAY 		src_mgr->src_enable_s(src_mgr, src);
14778cc72361SWai Yew CHAY 	}
14788cc72361SWai Yew CHAY 
14798cc72361SWai Yew CHAY 	dai->ops->set_srt_srcl(dai, &(srcs[0]->rsc));
14808cc72361SWai Yew CHAY 	dai->ops->set_srt_srcr(dai, &(srcs[1]->rsc));
14818cc72361SWai Yew CHAY 
14828cc72361SWai Yew CHAY 	dai->ops->set_enb_src(dai, 1);
14838cc72361SWai Yew CHAY 	dai->ops->set_enb_srt(dai, 1);
14848cc72361SWai Yew CHAY 	dai->ops->commit_write(dai);
14858cc72361SWai Yew CHAY 
14868cc72361SWai Yew CHAY 	src_mgr->commit_write(src_mgr); /* Synchronously enable SRCs */
14878cc72361SWai Yew CHAY }
14888cc72361SWai Yew CHAY 
atc_connect_resources(struct ct_atc * atc)148929959a09SWai Yew CHAY static void atc_connect_resources(struct ct_atc *atc)
14908cc72361SWai Yew CHAY {
1491514eef9cSTakashi Iwai 	struct dai *dai;
1492514eef9cSTakashi Iwai 	struct dao *dao;
1493514eef9cSTakashi Iwai 	struct src *src;
1494514eef9cSTakashi Iwai 	struct sum *sum;
1495514eef9cSTakashi Iwai 	struct ct_mixer *mixer;
14968cc72361SWai Yew CHAY 	struct rsc *rscs[2] = {NULL};
1497514eef9cSTakashi Iwai 	int i, j;
14988cc72361SWai Yew CHAY 
14998cc72361SWai Yew CHAY 	mixer = atc->mixer;
15008cc72361SWai Yew CHAY 
15018cc72361SWai Yew CHAY 	for (i = MIX_WAVE_FRONT, j = LINEO1; i <= MIX_SPDIF_OUT; i++, j++) {
15028cc72361SWai Yew CHAY 		mixer->get_output_ports(mixer, i, &rscs[0], &rscs[1]);
15038cc72361SWai Yew CHAY 		dao = container_of(atc->daios[j], struct dao, daio);
15048cc72361SWai Yew CHAY 		dao->ops->set_left_input(dao, rscs[0]);
15058cc72361SWai Yew CHAY 		dao->ops->set_right_input(dao, rscs[1]);
15068cc72361SWai Yew CHAY 	}
15078cc72361SWai Yew CHAY 
15088cc72361SWai Yew CHAY 	dai = container_of(atc->daios[LINEIM], struct dai, daio);
15098cc72361SWai Yew CHAY 	atc_connect_dai(atc->rsc_mgrs[SRC], dai,
15108cc72361SWai Yew CHAY 			(struct src **)&atc->srcs[2],
15118cc72361SWai Yew CHAY 			(struct srcimp **)&atc->srcimps[2]);
15128cc72361SWai Yew CHAY 	src = atc->srcs[2];
15138cc72361SWai Yew CHAY 	mixer->set_input_left(mixer, MIX_LINE_IN, &src->rsc);
15148cc72361SWai Yew CHAY 	src = atc->srcs[3];
15158cc72361SWai Yew CHAY 	mixer->set_input_right(mixer, MIX_LINE_IN, &src->rsc);
15168cc72361SWai Yew CHAY 
151755309216SHarry Butterworth 	if (atc->model == CTSB1270) {
151855309216SHarry Butterworth 		/* Titanium HD has a dedicated ADC for the Mic. */
151955309216SHarry Butterworth 		dai = container_of(atc->daios[MIC], struct dai, daio);
152055309216SHarry Butterworth 		atc_connect_dai(atc->rsc_mgrs[SRC], dai,
152155309216SHarry Butterworth 			(struct src **)&atc->srcs[4],
152255309216SHarry Butterworth 			(struct srcimp **)&atc->srcimps[4]);
152355309216SHarry Butterworth 		src = atc->srcs[4];
152455309216SHarry Butterworth 		mixer->set_input_left(mixer, MIX_MIC_IN, &src->rsc);
152555309216SHarry Butterworth 		src = atc->srcs[5];
152655309216SHarry Butterworth 		mixer->set_input_right(mixer, MIX_MIC_IN, &src->rsc);
152755309216SHarry Butterworth 	}
152855309216SHarry Butterworth 
15298cc72361SWai Yew CHAY 	dai = container_of(atc->daios[SPDIFIO], struct dai, daio);
15308cc72361SWai Yew CHAY 	atc_connect_dai(atc->rsc_mgrs[SRC], dai,
15318cc72361SWai Yew CHAY 			(struct src **)&atc->srcs[0],
15328cc72361SWai Yew CHAY 			(struct srcimp **)&atc->srcimps[0]);
15338cc72361SWai Yew CHAY 
15348cc72361SWai Yew CHAY 	src = atc->srcs[0];
15358cc72361SWai Yew CHAY 	mixer->set_input_left(mixer, MIX_SPDIF_IN, &src->rsc);
15368cc72361SWai Yew CHAY 	src = atc->srcs[1];
15378cc72361SWai Yew CHAY 	mixer->set_input_right(mixer, MIX_SPDIF_IN, &src->rsc);
15388cc72361SWai Yew CHAY 
15398cc72361SWai Yew CHAY 	for (i = MIX_PCMI_FRONT, j = 0; i <= MIX_PCMI_SURROUND; i++, j += 2) {
15408cc72361SWai Yew CHAY 		sum = atc->pcm[j];
15418cc72361SWai Yew CHAY 		mixer->set_input_left(mixer, i, &sum->rsc);
15428cc72361SWai Yew CHAY 		sum = atc->pcm[j+1];
15438cc72361SWai Yew CHAY 		mixer->set_input_right(mixer, i, &sum->rsc);
15448cc72361SWai Yew CHAY 	}
15458cc72361SWai Yew CHAY }
15468cc72361SWai Yew CHAY 
1547c7561cd8STakashi Iwai #ifdef CONFIG_PM_SLEEP
atc_suspend(struct ct_atc * atc)154868cb2b55STakashi Iwai static int atc_suspend(struct ct_atc *atc)
154929959a09SWai Yew CHAY {
155029959a09SWai Yew CHAY 	struct hw *hw = atc->hw;
155129959a09SWai Yew CHAY 
155229959a09SWai Yew CHAY 	snd_power_change_state(atc->card, SNDRV_CTL_POWER_D3hot);
155329959a09SWai Yew CHAY 
155429959a09SWai Yew CHAY 	atc_release_resources(atc);
155529959a09SWai Yew CHAY 
155668cb2b55STakashi Iwai 	hw->suspend(hw);
155729959a09SWai Yew CHAY 
155829959a09SWai Yew CHAY 	return 0;
155929959a09SWai Yew CHAY }
156029959a09SWai Yew CHAY 
atc_hw_resume(struct ct_atc * atc)156129959a09SWai Yew CHAY static int atc_hw_resume(struct ct_atc *atc)
156229959a09SWai Yew CHAY {
156329959a09SWai Yew CHAY 	struct hw *hw = atc->hw;
156429959a09SWai Yew CHAY 	struct card_conf info = {0};
156529959a09SWai Yew CHAY 
156629959a09SWai Yew CHAY 	/* Re-initialize card hardware. */
156729959a09SWai Yew CHAY 	info.rsr = atc->rsr;
156829959a09SWai Yew CHAY 	info.msr = atc->msr;
156929959a09SWai Yew CHAY 	info.vm_pgt_phys = atc_get_ptp_phys(atc, 0);
157029959a09SWai Yew CHAY 	return hw->resume(hw, &info);
157129959a09SWai Yew CHAY }
157229959a09SWai Yew CHAY 
atc_resources_resume(struct ct_atc * atc)157329959a09SWai Yew CHAY static int atc_resources_resume(struct ct_atc *atc)
157429959a09SWai Yew CHAY {
157529959a09SWai Yew CHAY 	struct ct_mixer *mixer;
157629959a09SWai Yew CHAY 	int err = 0;
157729959a09SWai Yew CHAY 
157829959a09SWai Yew CHAY 	/* Get resources */
157929959a09SWai Yew CHAY 	err = atc_get_resources(atc);
158029959a09SWai Yew CHAY 	if (err < 0) {
158129959a09SWai Yew CHAY 		atc_release_resources(atc);
158229959a09SWai Yew CHAY 		return err;
158329959a09SWai Yew CHAY 	}
158429959a09SWai Yew CHAY 
158529959a09SWai Yew CHAY 	/* Build topology */
158629959a09SWai Yew CHAY 	atc_connect_resources(atc);
158729959a09SWai Yew CHAY 
158829959a09SWai Yew CHAY 	mixer = atc->mixer;
158929959a09SWai Yew CHAY 	mixer->resume(mixer);
159029959a09SWai Yew CHAY 
159129959a09SWai Yew CHAY 	return 0;
159229959a09SWai Yew CHAY }
159329959a09SWai Yew CHAY 
atc_resume(struct ct_atc * atc)159429959a09SWai Yew CHAY static int atc_resume(struct ct_atc *atc)
159529959a09SWai Yew CHAY {
159629959a09SWai Yew CHAY 	int err = 0;
159729959a09SWai Yew CHAY 
159829959a09SWai Yew CHAY 	/* Do hardware resume. */
159929959a09SWai Yew CHAY 	err = atc_hw_resume(atc);
160029959a09SWai Yew CHAY 	if (err < 0) {
16010cae90a9SSudip Mukherjee 		dev_err(atc->card->dev,
16020cae90a9SSudip Mukherjee 			"pci_enable_device failed, disabling device\n");
160329959a09SWai Yew CHAY 		snd_card_disconnect(atc->card);
160429959a09SWai Yew CHAY 		return err;
160529959a09SWai Yew CHAY 	}
160629959a09SWai Yew CHAY 
160729959a09SWai Yew CHAY 	err = atc_resources_resume(atc);
160829959a09SWai Yew CHAY 	if (err < 0)
160929959a09SWai Yew CHAY 		return err;
161029959a09SWai Yew CHAY 
161129959a09SWai Yew CHAY 	snd_power_change_state(atc->card, SNDRV_CTL_POWER_D0);
161229959a09SWai Yew CHAY 
161329959a09SWai Yew CHAY 	return 0;
161429959a09SWai Yew CHAY }
161529959a09SWai Yew CHAY #endif
161629959a09SWai Yew CHAY 
1617071f1344SJulia Lawall static const struct ct_atc atc_preset = {
16182a36f67fSTakashi Iwai 	.map_audio_buffer = ct_map_audio_buffer,
16192a36f67fSTakashi Iwai 	.unmap_audio_buffer = ct_unmap_audio_buffer,
16202a36f67fSTakashi Iwai 	.pcm_playback_prepare = atc_pcm_playback_prepare,
16212a36f67fSTakashi Iwai 	.pcm_release_resources = atc_pcm_release_resources,
16222a36f67fSTakashi Iwai 	.pcm_playback_start = atc_pcm_playback_start,
16232a36f67fSTakashi Iwai 	.pcm_playback_stop = atc_pcm_stop,
16242a36f67fSTakashi Iwai 	.pcm_playback_position = atc_pcm_playback_position,
16252a36f67fSTakashi Iwai 	.pcm_capture_prepare = atc_pcm_capture_prepare,
16262a36f67fSTakashi Iwai 	.pcm_capture_start = atc_pcm_capture_start,
16272a36f67fSTakashi Iwai 	.pcm_capture_stop = atc_pcm_stop,
16282a36f67fSTakashi Iwai 	.pcm_capture_position = atc_pcm_capture_position,
16292a36f67fSTakashi Iwai 	.spdif_passthru_playback_prepare = spdif_passthru_playback_prepare,
16302a36f67fSTakashi Iwai 	.get_ptp_phys = atc_get_ptp_phys,
16312a36f67fSTakashi Iwai 	.select_line_in = atc_select_line_in,
16322a36f67fSTakashi Iwai 	.select_mic_in = atc_select_mic_in,
16332a36f67fSTakashi Iwai 	.select_digit_io = atc_select_digit_io,
16342a36f67fSTakashi Iwai 	.line_front_unmute = atc_line_front_unmute,
16352a36f67fSTakashi Iwai 	.line_surround_unmute = atc_line_surround_unmute,
16362a36f67fSTakashi Iwai 	.line_clfe_unmute = atc_line_clfe_unmute,
16372a36f67fSTakashi Iwai 	.line_rear_unmute = atc_line_rear_unmute,
16382a36f67fSTakashi Iwai 	.line_in_unmute = atc_line_in_unmute,
163955309216SHarry Butterworth 	.mic_unmute = atc_mic_unmute,
16402a36f67fSTakashi Iwai 	.spdif_out_unmute = atc_spdif_out_unmute,
16412a36f67fSTakashi Iwai 	.spdif_in_unmute = atc_spdif_in_unmute,
16422a36f67fSTakashi Iwai 	.spdif_out_get_status = atc_spdif_out_get_status,
16432a36f67fSTakashi Iwai 	.spdif_out_set_status = atc_spdif_out_set_status,
16442a36f67fSTakashi Iwai 	.spdif_out_passthru = atc_spdif_out_passthru,
1645b028b818SHarry Butterworth 	.capabilities = atc_capabilities,
164655309216SHarry Butterworth 	.output_switch_get = atc_output_switch_get,
164755309216SHarry Butterworth 	.output_switch_put = atc_output_switch_put,
164855309216SHarry Butterworth 	.mic_source_switch_get = atc_mic_source_switch_get,
164955309216SHarry Butterworth 	.mic_source_switch_put = atc_mic_source_switch_put,
1650c7561cd8STakashi Iwai #ifdef CONFIG_PM_SLEEP
165129959a09SWai Yew CHAY 	.suspend = atc_suspend,
165229959a09SWai Yew CHAY 	.resume = atc_resume,
165329959a09SWai Yew CHAY #endif
16542a36f67fSTakashi Iwai };
16558cc72361SWai Yew CHAY 
16568cc72361SWai Yew CHAY /**
16578cc72361SWai Yew CHAY  *  ct_atc_create - create and initialize a hardware manager
16588cc72361SWai Yew CHAY  *  @card: corresponding alsa card object
16598cc72361SWai Yew CHAY  *  @pci: corresponding kernel pci device object
166048af5f94SPierre-Louis Bossart  *  @rsr: reference sampling rate
166148af5f94SPierre-Louis Bossart  *  @msr: master sampling rate
166248af5f94SPierre-Louis Bossart  *  @chip_type: CHIPTYP enum values
166348af5f94SPierre-Louis Bossart  *  @ssid: vendor ID (upper 16 bits) and device ID (lower 16 bits)
16648cc72361SWai Yew CHAY  *  @ratc: return created object address in it
16658cc72361SWai Yew CHAY  *
16668cc72361SWai Yew CHAY  *  Creates and initializes a hardware manager.
16678cc72361SWai Yew CHAY  *
16688cc72361SWai Yew CHAY  *  Creates kmallocated ct_atc structure. Initializes hardware.
166925985edcSLucas De Marchi  *  Returns 0 if succeeds, or negative error code if fails.
16708cc72361SWai Yew CHAY  */
16718cc72361SWai Yew CHAY 
ct_atc_create(struct snd_card * card,struct pci_dev * pci,unsigned int rsr,unsigned int msr,int chip_type,unsigned int ssid,struct ct_atc ** ratc)1672e23e7a14SBill Pemberton int ct_atc_create(struct snd_card *card, struct pci_dev *pci,
16739470195aSTakashi Iwai 		  unsigned int rsr, unsigned int msr,
1674408bffd0STakashi Iwai 		  int chip_type, unsigned int ssid,
1675408bffd0STakashi Iwai 		  struct ct_atc **ratc)
16768cc72361SWai Yew CHAY {
1677514eef9cSTakashi Iwai 	struct ct_atc *atc;
1678efb0ad25STakashi Iwai 	static const struct snd_device_ops ops = {
16798cc72361SWai Yew CHAY 		.dev_free = atc_dev_free,
16808cc72361SWai Yew CHAY 	};
1681514eef9cSTakashi Iwai 	int err;
16828cc72361SWai Yew CHAY 
16838cc72361SWai Yew CHAY 	*ratc = NULL;
16848cc72361SWai Yew CHAY 
16858cc72361SWai Yew CHAY 	atc = kzalloc(sizeof(*atc), GFP_KERNEL);
168635ebf6e7STakashi Iwai 	if (!atc)
16878cc72361SWai Yew CHAY 		return -ENOMEM;
16888cc72361SWai Yew CHAY 
16892a36f67fSTakashi Iwai 	/* Set operations */
16902a36f67fSTakashi Iwai 	*atc = atc_preset;
16912a36f67fSTakashi Iwai 
16928cc72361SWai Yew CHAY 	atc->card = card;
16938cc72361SWai Yew CHAY 	atc->pci = pci;
16948cc72361SWai Yew CHAY 	atc->rsr = rsr;
16958cc72361SWai Yew CHAY 	atc->msr = msr;
16969470195aSTakashi Iwai 	atc->chip_type = chip_type;
16978cc72361SWai Yew CHAY 
1698635c265fSTakashi Iwai 	mutex_init(&atc->atc_mutex);
16998cc72361SWai Yew CHAY 
17008cc72361SWai Yew CHAY 	/* Find card model */
1701408bffd0STakashi Iwai 	err = atc_identify_card(atc, ssid);
17028cc72361SWai Yew CHAY 	if (err < 0) {
17030cae90a9SSudip Mukherjee 		dev_err(card->dev, "ctatc: Card not recognised\n");
17048cc72361SWai Yew CHAY 		goto error1;
17058cc72361SWai Yew CHAY 	}
17068cc72361SWai Yew CHAY 
17078cc72361SWai Yew CHAY 	/* Set up device virtual memory management object */
170821956b61SJaroslav Kysela 	err = ct_vm_create(&atc->vm, pci);
17098cc72361SWai Yew CHAY 	if (err < 0)
17108cc72361SWai Yew CHAY 		goto error1;
17118cc72361SWai Yew CHAY 
17128cc72361SWai Yew CHAY 	/* Create all atc hw devices */
17138cc72361SWai Yew CHAY 	err = atc_create_hw_devs(atc);
17148cc72361SWai Yew CHAY 	if (err < 0)
17158cc72361SWai Yew CHAY 		goto error1;
17168cc72361SWai Yew CHAY 
171729959a09SWai Yew CHAY 	err = ct_mixer_create(atc, (struct ct_mixer **)&atc->mixer);
171829959a09SWai Yew CHAY 	if (err) {
17190cae90a9SSudip Mukherjee 		dev_err(card->dev, "Failed to create mixer obj!!!\n");
172029959a09SWai Yew CHAY 		goto error1;
172129959a09SWai Yew CHAY 	}
172229959a09SWai Yew CHAY 
17238cc72361SWai Yew CHAY 	/* Get resources */
17248cc72361SWai Yew CHAY 	err = atc_get_resources(atc);
17258cc72361SWai Yew CHAY 	if (err < 0)
17268cc72361SWai Yew CHAY 		goto error1;
17278cc72361SWai Yew CHAY 
17288cc72361SWai Yew CHAY 	/* Build topology */
17298cc72361SWai Yew CHAY 	atc_connect_resources(atc);
17308cc72361SWai Yew CHAY 
1731b7bbf876STakashi Iwai 	atc->timer = ct_timer_new(atc);
17324d8ce1c9SJulia Lawall 	if (!atc->timer) {
17334d8ce1c9SJulia Lawall 		err = -ENOMEM;
1734b7bbf876STakashi Iwai 		goto error1;
17354d8ce1c9SJulia Lawall 	}
1736b7bbf876STakashi Iwai 
17378cc72361SWai Yew CHAY 	err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, atc, &ops);
17388cc72361SWai Yew CHAY 	if (err < 0)
17398cc72361SWai Yew CHAY 		goto error1;
17408cc72361SWai Yew CHAY 
17418cc72361SWai Yew CHAY 	*ratc = atc;
17428cc72361SWai Yew CHAY 	return 0;
17438cc72361SWai Yew CHAY 
17448cc72361SWai Yew CHAY error1:
17458cc72361SWai Yew CHAY 	ct_atc_destroy(atc);
17460cae90a9SSudip Mukherjee 	dev_err(card->dev, "Something wrong!!!\n");
17478cc72361SWai Yew CHAY 	return err;
17488cc72361SWai Yew CHAY }
1749