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