xref: /OK3568_Linux_fs/kernel/sound/pci/aw2/aw2-alsa.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*****************************************************************************
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * Copyright (C) 2008 Cedric Bregardis <cedric.bregardis@free.fr> and
5*4882a593Smuzhiyun  * Jean-Christian Hassler <jhassler@free.fr>
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * This file is part of the Audiowerk2 ALSA driver
8*4882a593Smuzhiyun  *
9*4882a593Smuzhiyun  *****************************************************************************/
10*4882a593Smuzhiyun #include <linux/init.h>
11*4882a593Smuzhiyun #include <linux/pci.h>
12*4882a593Smuzhiyun #include <linux/dma-mapping.h>
13*4882a593Smuzhiyun #include <linux/slab.h>
14*4882a593Smuzhiyun #include <linux/interrupt.h>
15*4882a593Smuzhiyun #include <linux/delay.h>
16*4882a593Smuzhiyun #include <linux/io.h>
17*4882a593Smuzhiyun #include <linux/module.h>
18*4882a593Smuzhiyun #include <sound/core.h>
19*4882a593Smuzhiyun #include <sound/initval.h>
20*4882a593Smuzhiyun #include <sound/pcm.h>
21*4882a593Smuzhiyun #include <sound/pcm_params.h>
22*4882a593Smuzhiyun #include <sound/control.h>
23*4882a593Smuzhiyun 
24*4882a593Smuzhiyun #include "saa7146.h"
25*4882a593Smuzhiyun #include "aw2-saa7146.h"
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun MODULE_AUTHOR("Cedric Bregardis <cedric.bregardis@free.fr>, "
28*4882a593Smuzhiyun 	      "Jean-Christian Hassler <jhassler@free.fr>");
29*4882a593Smuzhiyun MODULE_DESCRIPTION("Emagic Audiowerk 2 sound driver");
30*4882a593Smuzhiyun MODULE_LICENSE("GPL");
31*4882a593Smuzhiyun 
32*4882a593Smuzhiyun /*********************************
33*4882a593Smuzhiyun  * DEFINES
34*4882a593Smuzhiyun  ********************************/
35*4882a593Smuzhiyun #define CTL_ROUTE_ANALOG 0
36*4882a593Smuzhiyun #define CTL_ROUTE_DIGITAL 1
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun /*********************************
39*4882a593Smuzhiyun  * TYPEDEFS
40*4882a593Smuzhiyun  ********************************/
41*4882a593Smuzhiyun   /* hardware definition */
42*4882a593Smuzhiyun static const struct snd_pcm_hardware snd_aw2_playback_hw = {
43*4882a593Smuzhiyun 	.info = (SNDRV_PCM_INFO_MMAP |
44*4882a593Smuzhiyun 		 SNDRV_PCM_INFO_INTERLEAVED |
45*4882a593Smuzhiyun 		 SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID),
46*4882a593Smuzhiyun 	.formats = SNDRV_PCM_FMTBIT_S16_LE,
47*4882a593Smuzhiyun 	.rates = SNDRV_PCM_RATE_44100,
48*4882a593Smuzhiyun 	.rate_min = 44100,
49*4882a593Smuzhiyun 	.rate_max = 44100,
50*4882a593Smuzhiyun 	.channels_min = 2,
51*4882a593Smuzhiyun 	.channels_max = 4,
52*4882a593Smuzhiyun 	.buffer_bytes_max = 32768,
53*4882a593Smuzhiyun 	.period_bytes_min = 4096,
54*4882a593Smuzhiyun 	.period_bytes_max = 32768,
55*4882a593Smuzhiyun 	.periods_min = 1,
56*4882a593Smuzhiyun 	.periods_max = 1024,
57*4882a593Smuzhiyun };
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun static const struct snd_pcm_hardware snd_aw2_capture_hw = {
60*4882a593Smuzhiyun 	.info = (SNDRV_PCM_INFO_MMAP |
61*4882a593Smuzhiyun 		 SNDRV_PCM_INFO_INTERLEAVED |
62*4882a593Smuzhiyun 		 SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID),
63*4882a593Smuzhiyun 	.formats = SNDRV_PCM_FMTBIT_S16_LE,
64*4882a593Smuzhiyun 	.rates = SNDRV_PCM_RATE_44100,
65*4882a593Smuzhiyun 	.rate_min = 44100,
66*4882a593Smuzhiyun 	.rate_max = 44100,
67*4882a593Smuzhiyun 	.channels_min = 2,
68*4882a593Smuzhiyun 	.channels_max = 2,
69*4882a593Smuzhiyun 	.buffer_bytes_max = 32768,
70*4882a593Smuzhiyun 	.period_bytes_min = 4096,
71*4882a593Smuzhiyun 	.period_bytes_max = 32768,
72*4882a593Smuzhiyun 	.periods_min = 1,
73*4882a593Smuzhiyun 	.periods_max = 1024,
74*4882a593Smuzhiyun };
75*4882a593Smuzhiyun 
76*4882a593Smuzhiyun struct aw2_pcm_device {
77*4882a593Smuzhiyun 	struct snd_pcm *pcm;
78*4882a593Smuzhiyun 	unsigned int stream_number;
79*4882a593Smuzhiyun 	struct aw2 *chip;
80*4882a593Smuzhiyun };
81*4882a593Smuzhiyun 
82*4882a593Smuzhiyun struct aw2 {
83*4882a593Smuzhiyun 	struct snd_aw2_saa7146 saa7146;
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun 	struct pci_dev *pci;
86*4882a593Smuzhiyun 	int irq;
87*4882a593Smuzhiyun 	spinlock_t reg_lock;
88*4882a593Smuzhiyun 	struct mutex mtx;
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun 	unsigned long iobase_phys;
91*4882a593Smuzhiyun 	void __iomem *iobase_virt;
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun 	struct snd_card *card;
94*4882a593Smuzhiyun 
95*4882a593Smuzhiyun 	struct aw2_pcm_device device_playback[NB_STREAM_PLAYBACK];
96*4882a593Smuzhiyun 	struct aw2_pcm_device device_capture[NB_STREAM_CAPTURE];
97*4882a593Smuzhiyun };
98*4882a593Smuzhiyun 
99*4882a593Smuzhiyun /*********************************
100*4882a593Smuzhiyun  * FUNCTION DECLARATIONS
101*4882a593Smuzhiyun  ********************************/
102*4882a593Smuzhiyun static int snd_aw2_dev_free(struct snd_device *device);
103*4882a593Smuzhiyun static int snd_aw2_create(struct snd_card *card,
104*4882a593Smuzhiyun 			  struct pci_dev *pci, struct aw2 **rchip);
105*4882a593Smuzhiyun static int snd_aw2_probe(struct pci_dev *pci,
106*4882a593Smuzhiyun 			 const struct pci_device_id *pci_id);
107*4882a593Smuzhiyun static void snd_aw2_remove(struct pci_dev *pci);
108*4882a593Smuzhiyun static int snd_aw2_pcm_playback_open(struct snd_pcm_substream *substream);
109*4882a593Smuzhiyun static int snd_aw2_pcm_playback_close(struct snd_pcm_substream *substream);
110*4882a593Smuzhiyun static int snd_aw2_pcm_capture_open(struct snd_pcm_substream *substream);
111*4882a593Smuzhiyun static int snd_aw2_pcm_capture_close(struct snd_pcm_substream *substream);
112*4882a593Smuzhiyun static int snd_aw2_pcm_prepare_playback(struct snd_pcm_substream *substream);
113*4882a593Smuzhiyun static int snd_aw2_pcm_prepare_capture(struct snd_pcm_substream *substream);
114*4882a593Smuzhiyun static int snd_aw2_pcm_trigger_playback(struct snd_pcm_substream *substream,
115*4882a593Smuzhiyun 					int cmd);
116*4882a593Smuzhiyun static int snd_aw2_pcm_trigger_capture(struct snd_pcm_substream *substream,
117*4882a593Smuzhiyun 				       int cmd);
118*4882a593Smuzhiyun static snd_pcm_uframes_t snd_aw2_pcm_pointer_playback(struct snd_pcm_substream
119*4882a593Smuzhiyun 						      *substream);
120*4882a593Smuzhiyun static snd_pcm_uframes_t snd_aw2_pcm_pointer_capture(struct snd_pcm_substream
121*4882a593Smuzhiyun 						     *substream);
122*4882a593Smuzhiyun static int snd_aw2_new_pcm(struct aw2 *chip);
123*4882a593Smuzhiyun 
124*4882a593Smuzhiyun static int snd_aw2_control_switch_capture_info(struct snd_kcontrol *kcontrol,
125*4882a593Smuzhiyun 					       struct snd_ctl_elem_info *uinfo);
126*4882a593Smuzhiyun static int snd_aw2_control_switch_capture_get(struct snd_kcontrol *kcontrol,
127*4882a593Smuzhiyun 					      struct snd_ctl_elem_value
128*4882a593Smuzhiyun 					      *ucontrol);
129*4882a593Smuzhiyun static int snd_aw2_control_switch_capture_put(struct snd_kcontrol *kcontrol,
130*4882a593Smuzhiyun 					      struct snd_ctl_elem_value
131*4882a593Smuzhiyun 					      *ucontrol);
132*4882a593Smuzhiyun 
133*4882a593Smuzhiyun /*********************************
134*4882a593Smuzhiyun  * VARIABLES
135*4882a593Smuzhiyun  ********************************/
136*4882a593Smuzhiyun static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
137*4882a593Smuzhiyun static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
138*4882a593Smuzhiyun static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
139*4882a593Smuzhiyun 
140*4882a593Smuzhiyun module_param_array(index, int, NULL, 0444);
141*4882a593Smuzhiyun MODULE_PARM_DESC(index, "Index value for Audiowerk2 soundcard.");
142*4882a593Smuzhiyun module_param_array(id, charp, NULL, 0444);
143*4882a593Smuzhiyun MODULE_PARM_DESC(id, "ID string for the Audiowerk2 soundcard.");
144*4882a593Smuzhiyun module_param_array(enable, bool, NULL, 0444);
145*4882a593Smuzhiyun MODULE_PARM_DESC(enable, "Enable Audiowerk2 soundcard.");
146*4882a593Smuzhiyun 
147*4882a593Smuzhiyun static const struct pci_device_id snd_aw2_ids[] = {
148*4882a593Smuzhiyun 	{PCI_VENDOR_ID_PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7146, 0, 0,
149*4882a593Smuzhiyun 	 0, 0, 0},
150*4882a593Smuzhiyun 	{0}
151*4882a593Smuzhiyun };
152*4882a593Smuzhiyun 
153*4882a593Smuzhiyun MODULE_DEVICE_TABLE(pci, snd_aw2_ids);
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun /* pci_driver definition */
156*4882a593Smuzhiyun static struct pci_driver aw2_driver = {
157*4882a593Smuzhiyun 	.name = KBUILD_MODNAME,
158*4882a593Smuzhiyun 	.id_table = snd_aw2_ids,
159*4882a593Smuzhiyun 	.probe = snd_aw2_probe,
160*4882a593Smuzhiyun 	.remove = snd_aw2_remove,
161*4882a593Smuzhiyun };
162*4882a593Smuzhiyun 
163*4882a593Smuzhiyun module_pci_driver(aw2_driver);
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun /* operators for playback PCM alsa interface */
166*4882a593Smuzhiyun static const struct snd_pcm_ops snd_aw2_playback_ops = {
167*4882a593Smuzhiyun 	.open = snd_aw2_pcm_playback_open,
168*4882a593Smuzhiyun 	.close = snd_aw2_pcm_playback_close,
169*4882a593Smuzhiyun 	.prepare = snd_aw2_pcm_prepare_playback,
170*4882a593Smuzhiyun 	.trigger = snd_aw2_pcm_trigger_playback,
171*4882a593Smuzhiyun 	.pointer = snd_aw2_pcm_pointer_playback,
172*4882a593Smuzhiyun };
173*4882a593Smuzhiyun 
174*4882a593Smuzhiyun /* operators for capture PCM alsa interface */
175*4882a593Smuzhiyun static const struct snd_pcm_ops snd_aw2_capture_ops = {
176*4882a593Smuzhiyun 	.open = snd_aw2_pcm_capture_open,
177*4882a593Smuzhiyun 	.close = snd_aw2_pcm_capture_close,
178*4882a593Smuzhiyun 	.prepare = snd_aw2_pcm_prepare_capture,
179*4882a593Smuzhiyun 	.trigger = snd_aw2_pcm_trigger_capture,
180*4882a593Smuzhiyun 	.pointer = snd_aw2_pcm_pointer_capture,
181*4882a593Smuzhiyun };
182*4882a593Smuzhiyun 
183*4882a593Smuzhiyun static const struct snd_kcontrol_new aw2_control = {
184*4882a593Smuzhiyun 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
185*4882a593Smuzhiyun 	.name = "PCM Capture Route",
186*4882a593Smuzhiyun 	.index = 0,
187*4882a593Smuzhiyun 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
188*4882a593Smuzhiyun 	.private_value = 0xffff,
189*4882a593Smuzhiyun 	.info = snd_aw2_control_switch_capture_info,
190*4882a593Smuzhiyun 	.get = snd_aw2_control_switch_capture_get,
191*4882a593Smuzhiyun 	.put = snd_aw2_control_switch_capture_put
192*4882a593Smuzhiyun };
193*4882a593Smuzhiyun 
194*4882a593Smuzhiyun /*********************************
195*4882a593Smuzhiyun  * FUNCTION IMPLEMENTATIONS
196*4882a593Smuzhiyun  ********************************/
197*4882a593Smuzhiyun 
198*4882a593Smuzhiyun /* component-destructor */
snd_aw2_dev_free(struct snd_device * device)199*4882a593Smuzhiyun static int snd_aw2_dev_free(struct snd_device *device)
200*4882a593Smuzhiyun {
201*4882a593Smuzhiyun 	struct aw2 *chip = device->device_data;
202*4882a593Smuzhiyun 
203*4882a593Smuzhiyun 	/* Free hardware */
204*4882a593Smuzhiyun 	snd_aw2_saa7146_free(&chip->saa7146);
205*4882a593Smuzhiyun 
206*4882a593Smuzhiyun 	/* release the irq */
207*4882a593Smuzhiyun 	if (chip->irq >= 0)
208*4882a593Smuzhiyun 		free_irq(chip->irq, (void *)chip);
209*4882a593Smuzhiyun 	/* release the i/o ports & memory */
210*4882a593Smuzhiyun 	iounmap(chip->iobase_virt);
211*4882a593Smuzhiyun 	pci_release_regions(chip->pci);
212*4882a593Smuzhiyun 	/* disable the PCI entry */
213*4882a593Smuzhiyun 	pci_disable_device(chip->pci);
214*4882a593Smuzhiyun 	/* release the data */
215*4882a593Smuzhiyun 	kfree(chip);
216*4882a593Smuzhiyun 
217*4882a593Smuzhiyun 	return 0;
218*4882a593Smuzhiyun }
219*4882a593Smuzhiyun 
220*4882a593Smuzhiyun /* chip-specific constructor */
snd_aw2_create(struct snd_card * card,struct pci_dev * pci,struct aw2 ** rchip)221*4882a593Smuzhiyun static int snd_aw2_create(struct snd_card *card,
222*4882a593Smuzhiyun 			  struct pci_dev *pci, struct aw2 **rchip)
223*4882a593Smuzhiyun {
224*4882a593Smuzhiyun 	struct aw2 *chip;
225*4882a593Smuzhiyun 	int err;
226*4882a593Smuzhiyun 	static const struct snd_device_ops ops = {
227*4882a593Smuzhiyun 		.dev_free = snd_aw2_dev_free,
228*4882a593Smuzhiyun 	};
229*4882a593Smuzhiyun 
230*4882a593Smuzhiyun 	*rchip = NULL;
231*4882a593Smuzhiyun 
232*4882a593Smuzhiyun 	/* initialize the PCI entry */
233*4882a593Smuzhiyun 	err = pci_enable_device(pci);
234*4882a593Smuzhiyun 	if (err < 0)
235*4882a593Smuzhiyun 		return err;
236*4882a593Smuzhiyun 	pci_set_master(pci);
237*4882a593Smuzhiyun 
238*4882a593Smuzhiyun 	/* check PCI availability (32bit DMA) */
239*4882a593Smuzhiyun 	if ((dma_set_mask(&pci->dev, DMA_BIT_MASK(32)) < 0) ||
240*4882a593Smuzhiyun 	    (dma_set_coherent_mask(&pci->dev, DMA_BIT_MASK(32)) < 0)) {
241*4882a593Smuzhiyun 		dev_err(card->dev, "Impossible to set 32bit mask DMA\n");
242*4882a593Smuzhiyun 		pci_disable_device(pci);
243*4882a593Smuzhiyun 		return -ENXIO;
244*4882a593Smuzhiyun 	}
245*4882a593Smuzhiyun 	chip = kzalloc(sizeof(*chip), GFP_KERNEL);
246*4882a593Smuzhiyun 	if (chip == NULL) {
247*4882a593Smuzhiyun 		pci_disable_device(pci);
248*4882a593Smuzhiyun 		return -ENOMEM;
249*4882a593Smuzhiyun 	}
250*4882a593Smuzhiyun 
251*4882a593Smuzhiyun 	/* initialize the stuff */
252*4882a593Smuzhiyun 	chip->card = card;
253*4882a593Smuzhiyun 	chip->pci = pci;
254*4882a593Smuzhiyun 	chip->irq = -1;
255*4882a593Smuzhiyun 
256*4882a593Smuzhiyun 	/* (1) PCI resource allocation */
257*4882a593Smuzhiyun 	err = pci_request_regions(pci, "Audiowerk2");
258*4882a593Smuzhiyun 	if (err < 0) {
259*4882a593Smuzhiyun 		pci_disable_device(pci);
260*4882a593Smuzhiyun 		kfree(chip);
261*4882a593Smuzhiyun 		return err;
262*4882a593Smuzhiyun 	}
263*4882a593Smuzhiyun 	chip->iobase_phys = pci_resource_start(pci, 0);
264*4882a593Smuzhiyun 	chip->iobase_virt =
265*4882a593Smuzhiyun 		ioremap(chip->iobase_phys,
266*4882a593Smuzhiyun 				pci_resource_len(pci, 0));
267*4882a593Smuzhiyun 
268*4882a593Smuzhiyun 	if (chip->iobase_virt == NULL) {
269*4882a593Smuzhiyun 		dev_err(card->dev, "unable to remap memory region");
270*4882a593Smuzhiyun 		pci_release_regions(pci);
271*4882a593Smuzhiyun 		pci_disable_device(pci);
272*4882a593Smuzhiyun 		kfree(chip);
273*4882a593Smuzhiyun 		return -ENOMEM;
274*4882a593Smuzhiyun 	}
275*4882a593Smuzhiyun 
276*4882a593Smuzhiyun 	/* (2) initialization of the chip hardware */
277*4882a593Smuzhiyun 	snd_aw2_saa7146_setup(&chip->saa7146, chip->iobase_virt);
278*4882a593Smuzhiyun 
279*4882a593Smuzhiyun 	if (request_irq(pci->irq, snd_aw2_saa7146_interrupt,
280*4882a593Smuzhiyun 			IRQF_SHARED, KBUILD_MODNAME, chip)) {
281*4882a593Smuzhiyun 		dev_err(card->dev, "Cannot grab irq %d\n", pci->irq);
282*4882a593Smuzhiyun 
283*4882a593Smuzhiyun 		iounmap(chip->iobase_virt);
284*4882a593Smuzhiyun 		pci_release_regions(chip->pci);
285*4882a593Smuzhiyun 		pci_disable_device(chip->pci);
286*4882a593Smuzhiyun 		kfree(chip);
287*4882a593Smuzhiyun 		return -EBUSY;
288*4882a593Smuzhiyun 	}
289*4882a593Smuzhiyun 	chip->irq = pci->irq;
290*4882a593Smuzhiyun 	card->sync_irq = chip->irq;
291*4882a593Smuzhiyun 
292*4882a593Smuzhiyun 	err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
293*4882a593Smuzhiyun 	if (err < 0) {
294*4882a593Smuzhiyun 		free_irq(chip->irq, (void *)chip);
295*4882a593Smuzhiyun 		iounmap(chip->iobase_virt);
296*4882a593Smuzhiyun 		pci_release_regions(chip->pci);
297*4882a593Smuzhiyun 		pci_disable_device(chip->pci);
298*4882a593Smuzhiyun 		kfree(chip);
299*4882a593Smuzhiyun 		return err;
300*4882a593Smuzhiyun 	}
301*4882a593Smuzhiyun 
302*4882a593Smuzhiyun 	*rchip = chip;
303*4882a593Smuzhiyun 
304*4882a593Smuzhiyun 	dev_info(card->dev,
305*4882a593Smuzhiyun 		 "Audiowerk 2 sound card (saa7146 chipset) detected and managed\n");
306*4882a593Smuzhiyun 	return 0;
307*4882a593Smuzhiyun }
308*4882a593Smuzhiyun 
309*4882a593Smuzhiyun /* constructor */
snd_aw2_probe(struct pci_dev * pci,const struct pci_device_id * pci_id)310*4882a593Smuzhiyun static int snd_aw2_probe(struct pci_dev *pci,
311*4882a593Smuzhiyun 			 const struct pci_device_id *pci_id)
312*4882a593Smuzhiyun {
313*4882a593Smuzhiyun 	static int dev;
314*4882a593Smuzhiyun 	struct snd_card *card;
315*4882a593Smuzhiyun 	struct aw2 *chip;
316*4882a593Smuzhiyun 	int err;
317*4882a593Smuzhiyun 
318*4882a593Smuzhiyun 	/* (1) Continue if device is not enabled, else inc dev */
319*4882a593Smuzhiyun 	if (dev >= SNDRV_CARDS)
320*4882a593Smuzhiyun 		return -ENODEV;
321*4882a593Smuzhiyun 	if (!enable[dev]) {
322*4882a593Smuzhiyun 		dev++;
323*4882a593Smuzhiyun 		return -ENOENT;
324*4882a593Smuzhiyun 	}
325*4882a593Smuzhiyun 
326*4882a593Smuzhiyun 	/* (2) Create card instance */
327*4882a593Smuzhiyun 	err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
328*4882a593Smuzhiyun 			   0, &card);
329*4882a593Smuzhiyun 	if (err < 0)
330*4882a593Smuzhiyun 		return err;
331*4882a593Smuzhiyun 
332*4882a593Smuzhiyun 	/* (3) Create main component */
333*4882a593Smuzhiyun 	err = snd_aw2_create(card, pci, &chip);
334*4882a593Smuzhiyun 	if (err < 0) {
335*4882a593Smuzhiyun 		snd_card_free(card);
336*4882a593Smuzhiyun 		return err;
337*4882a593Smuzhiyun 	}
338*4882a593Smuzhiyun 
339*4882a593Smuzhiyun 	/* initialize mutex */
340*4882a593Smuzhiyun 	mutex_init(&chip->mtx);
341*4882a593Smuzhiyun 	/* init spinlock */
342*4882a593Smuzhiyun 	spin_lock_init(&chip->reg_lock);
343*4882a593Smuzhiyun 	/* (4) Define driver ID and name string */
344*4882a593Smuzhiyun 	strcpy(card->driver, "aw2");
345*4882a593Smuzhiyun 	strcpy(card->shortname, "Audiowerk2");
346*4882a593Smuzhiyun 
347*4882a593Smuzhiyun 	sprintf(card->longname, "%s with SAA7146 irq %i",
348*4882a593Smuzhiyun 		card->shortname, chip->irq);
349*4882a593Smuzhiyun 
350*4882a593Smuzhiyun 	/* (5) Create other components */
351*4882a593Smuzhiyun 	snd_aw2_new_pcm(chip);
352*4882a593Smuzhiyun 
353*4882a593Smuzhiyun 	/* (6) Register card instance */
354*4882a593Smuzhiyun 	err = snd_card_register(card);
355*4882a593Smuzhiyun 	if (err < 0) {
356*4882a593Smuzhiyun 		snd_card_free(card);
357*4882a593Smuzhiyun 		return err;
358*4882a593Smuzhiyun 	}
359*4882a593Smuzhiyun 
360*4882a593Smuzhiyun 	/* (7) Set PCI driver data */
361*4882a593Smuzhiyun 	pci_set_drvdata(pci, card);
362*4882a593Smuzhiyun 
363*4882a593Smuzhiyun 	dev++;
364*4882a593Smuzhiyun 	return 0;
365*4882a593Smuzhiyun }
366*4882a593Smuzhiyun 
367*4882a593Smuzhiyun /* destructor */
snd_aw2_remove(struct pci_dev * pci)368*4882a593Smuzhiyun static void snd_aw2_remove(struct pci_dev *pci)
369*4882a593Smuzhiyun {
370*4882a593Smuzhiyun 	snd_card_free(pci_get_drvdata(pci));
371*4882a593Smuzhiyun }
372*4882a593Smuzhiyun 
373*4882a593Smuzhiyun /* open callback */
snd_aw2_pcm_playback_open(struct snd_pcm_substream * substream)374*4882a593Smuzhiyun static int snd_aw2_pcm_playback_open(struct snd_pcm_substream *substream)
375*4882a593Smuzhiyun {
376*4882a593Smuzhiyun 	struct snd_pcm_runtime *runtime = substream->runtime;
377*4882a593Smuzhiyun 
378*4882a593Smuzhiyun 	dev_dbg(substream->pcm->card->dev, "Playback_open\n");
379*4882a593Smuzhiyun 	runtime->hw = snd_aw2_playback_hw;
380*4882a593Smuzhiyun 	return 0;
381*4882a593Smuzhiyun }
382*4882a593Smuzhiyun 
383*4882a593Smuzhiyun /* close callback */
snd_aw2_pcm_playback_close(struct snd_pcm_substream * substream)384*4882a593Smuzhiyun static int snd_aw2_pcm_playback_close(struct snd_pcm_substream *substream)
385*4882a593Smuzhiyun {
386*4882a593Smuzhiyun 	return 0;
387*4882a593Smuzhiyun 
388*4882a593Smuzhiyun }
389*4882a593Smuzhiyun 
snd_aw2_pcm_capture_open(struct snd_pcm_substream * substream)390*4882a593Smuzhiyun static int snd_aw2_pcm_capture_open(struct snd_pcm_substream *substream)
391*4882a593Smuzhiyun {
392*4882a593Smuzhiyun 	struct snd_pcm_runtime *runtime = substream->runtime;
393*4882a593Smuzhiyun 
394*4882a593Smuzhiyun 	dev_dbg(substream->pcm->card->dev, "Capture_open\n");
395*4882a593Smuzhiyun 	runtime->hw = snd_aw2_capture_hw;
396*4882a593Smuzhiyun 	return 0;
397*4882a593Smuzhiyun }
398*4882a593Smuzhiyun 
399*4882a593Smuzhiyun /* close callback */
snd_aw2_pcm_capture_close(struct snd_pcm_substream * substream)400*4882a593Smuzhiyun static int snd_aw2_pcm_capture_close(struct snd_pcm_substream *substream)
401*4882a593Smuzhiyun {
402*4882a593Smuzhiyun 	/* TODO: something to do ? */
403*4882a593Smuzhiyun 	return 0;
404*4882a593Smuzhiyun }
405*4882a593Smuzhiyun 
406*4882a593Smuzhiyun /* prepare callback for playback */
snd_aw2_pcm_prepare_playback(struct snd_pcm_substream * substream)407*4882a593Smuzhiyun static int snd_aw2_pcm_prepare_playback(struct snd_pcm_substream *substream)
408*4882a593Smuzhiyun {
409*4882a593Smuzhiyun 	struct aw2_pcm_device *pcm_device = snd_pcm_substream_chip(substream);
410*4882a593Smuzhiyun 	struct aw2 *chip = pcm_device->chip;
411*4882a593Smuzhiyun 	struct snd_pcm_runtime *runtime = substream->runtime;
412*4882a593Smuzhiyun 	unsigned long period_size, buffer_size;
413*4882a593Smuzhiyun 
414*4882a593Smuzhiyun 	mutex_lock(&chip->mtx);
415*4882a593Smuzhiyun 
416*4882a593Smuzhiyun 	period_size = snd_pcm_lib_period_bytes(substream);
417*4882a593Smuzhiyun 	buffer_size = snd_pcm_lib_buffer_bytes(substream);
418*4882a593Smuzhiyun 
419*4882a593Smuzhiyun 	snd_aw2_saa7146_pcm_init_playback(&chip->saa7146,
420*4882a593Smuzhiyun 					  pcm_device->stream_number,
421*4882a593Smuzhiyun 					  runtime->dma_addr, period_size,
422*4882a593Smuzhiyun 					  buffer_size);
423*4882a593Smuzhiyun 
424*4882a593Smuzhiyun 	/* Define Interrupt callback */
425*4882a593Smuzhiyun 	snd_aw2_saa7146_define_it_playback_callback(pcm_device->stream_number,
426*4882a593Smuzhiyun 						    (snd_aw2_saa7146_it_cb)
427*4882a593Smuzhiyun 						    snd_pcm_period_elapsed,
428*4882a593Smuzhiyun 						    (void *)substream);
429*4882a593Smuzhiyun 
430*4882a593Smuzhiyun 	mutex_unlock(&chip->mtx);
431*4882a593Smuzhiyun 
432*4882a593Smuzhiyun 	return 0;
433*4882a593Smuzhiyun }
434*4882a593Smuzhiyun 
435*4882a593Smuzhiyun /* prepare callback for capture */
snd_aw2_pcm_prepare_capture(struct snd_pcm_substream * substream)436*4882a593Smuzhiyun static int snd_aw2_pcm_prepare_capture(struct snd_pcm_substream *substream)
437*4882a593Smuzhiyun {
438*4882a593Smuzhiyun 	struct aw2_pcm_device *pcm_device = snd_pcm_substream_chip(substream);
439*4882a593Smuzhiyun 	struct aw2 *chip = pcm_device->chip;
440*4882a593Smuzhiyun 	struct snd_pcm_runtime *runtime = substream->runtime;
441*4882a593Smuzhiyun 	unsigned long period_size, buffer_size;
442*4882a593Smuzhiyun 
443*4882a593Smuzhiyun 	mutex_lock(&chip->mtx);
444*4882a593Smuzhiyun 
445*4882a593Smuzhiyun 	period_size = snd_pcm_lib_period_bytes(substream);
446*4882a593Smuzhiyun 	buffer_size = snd_pcm_lib_buffer_bytes(substream);
447*4882a593Smuzhiyun 
448*4882a593Smuzhiyun 	snd_aw2_saa7146_pcm_init_capture(&chip->saa7146,
449*4882a593Smuzhiyun 					 pcm_device->stream_number,
450*4882a593Smuzhiyun 					 runtime->dma_addr, period_size,
451*4882a593Smuzhiyun 					 buffer_size);
452*4882a593Smuzhiyun 
453*4882a593Smuzhiyun 	/* Define Interrupt callback */
454*4882a593Smuzhiyun 	snd_aw2_saa7146_define_it_capture_callback(pcm_device->stream_number,
455*4882a593Smuzhiyun 						   (snd_aw2_saa7146_it_cb)
456*4882a593Smuzhiyun 						   snd_pcm_period_elapsed,
457*4882a593Smuzhiyun 						   (void *)substream);
458*4882a593Smuzhiyun 
459*4882a593Smuzhiyun 	mutex_unlock(&chip->mtx);
460*4882a593Smuzhiyun 
461*4882a593Smuzhiyun 	return 0;
462*4882a593Smuzhiyun }
463*4882a593Smuzhiyun 
464*4882a593Smuzhiyun /* playback trigger callback */
snd_aw2_pcm_trigger_playback(struct snd_pcm_substream * substream,int cmd)465*4882a593Smuzhiyun static int snd_aw2_pcm_trigger_playback(struct snd_pcm_substream *substream,
466*4882a593Smuzhiyun 					int cmd)
467*4882a593Smuzhiyun {
468*4882a593Smuzhiyun 	int status = 0;
469*4882a593Smuzhiyun 	struct aw2_pcm_device *pcm_device = snd_pcm_substream_chip(substream);
470*4882a593Smuzhiyun 	struct aw2 *chip = pcm_device->chip;
471*4882a593Smuzhiyun 	spin_lock(&chip->reg_lock);
472*4882a593Smuzhiyun 	switch (cmd) {
473*4882a593Smuzhiyun 	case SNDRV_PCM_TRIGGER_START:
474*4882a593Smuzhiyun 		snd_aw2_saa7146_pcm_trigger_start_playback(&chip->saa7146,
475*4882a593Smuzhiyun 							   pcm_device->
476*4882a593Smuzhiyun 							   stream_number);
477*4882a593Smuzhiyun 		break;
478*4882a593Smuzhiyun 	case SNDRV_PCM_TRIGGER_STOP:
479*4882a593Smuzhiyun 		snd_aw2_saa7146_pcm_trigger_stop_playback(&chip->saa7146,
480*4882a593Smuzhiyun 							  pcm_device->
481*4882a593Smuzhiyun 							  stream_number);
482*4882a593Smuzhiyun 		break;
483*4882a593Smuzhiyun 	default:
484*4882a593Smuzhiyun 		status = -EINVAL;
485*4882a593Smuzhiyun 	}
486*4882a593Smuzhiyun 	spin_unlock(&chip->reg_lock);
487*4882a593Smuzhiyun 	return status;
488*4882a593Smuzhiyun }
489*4882a593Smuzhiyun 
490*4882a593Smuzhiyun /* capture trigger callback */
snd_aw2_pcm_trigger_capture(struct snd_pcm_substream * substream,int cmd)491*4882a593Smuzhiyun static int snd_aw2_pcm_trigger_capture(struct snd_pcm_substream *substream,
492*4882a593Smuzhiyun 				       int cmd)
493*4882a593Smuzhiyun {
494*4882a593Smuzhiyun 	int status = 0;
495*4882a593Smuzhiyun 	struct aw2_pcm_device *pcm_device = snd_pcm_substream_chip(substream);
496*4882a593Smuzhiyun 	struct aw2 *chip = pcm_device->chip;
497*4882a593Smuzhiyun 	spin_lock(&chip->reg_lock);
498*4882a593Smuzhiyun 	switch (cmd) {
499*4882a593Smuzhiyun 	case SNDRV_PCM_TRIGGER_START:
500*4882a593Smuzhiyun 		snd_aw2_saa7146_pcm_trigger_start_capture(&chip->saa7146,
501*4882a593Smuzhiyun 							  pcm_device->
502*4882a593Smuzhiyun 							  stream_number);
503*4882a593Smuzhiyun 		break;
504*4882a593Smuzhiyun 	case SNDRV_PCM_TRIGGER_STOP:
505*4882a593Smuzhiyun 		snd_aw2_saa7146_pcm_trigger_stop_capture(&chip->saa7146,
506*4882a593Smuzhiyun 							 pcm_device->
507*4882a593Smuzhiyun 							 stream_number);
508*4882a593Smuzhiyun 		break;
509*4882a593Smuzhiyun 	default:
510*4882a593Smuzhiyun 		status = -EINVAL;
511*4882a593Smuzhiyun 	}
512*4882a593Smuzhiyun 	spin_unlock(&chip->reg_lock);
513*4882a593Smuzhiyun 	return status;
514*4882a593Smuzhiyun }
515*4882a593Smuzhiyun 
516*4882a593Smuzhiyun /* playback pointer callback */
snd_aw2_pcm_pointer_playback(struct snd_pcm_substream * substream)517*4882a593Smuzhiyun static snd_pcm_uframes_t snd_aw2_pcm_pointer_playback(struct snd_pcm_substream
518*4882a593Smuzhiyun 						      *substream)
519*4882a593Smuzhiyun {
520*4882a593Smuzhiyun 	struct aw2_pcm_device *pcm_device = snd_pcm_substream_chip(substream);
521*4882a593Smuzhiyun 	struct aw2 *chip = pcm_device->chip;
522*4882a593Smuzhiyun 	unsigned int current_ptr;
523*4882a593Smuzhiyun 
524*4882a593Smuzhiyun 	/* get the current hardware pointer */
525*4882a593Smuzhiyun 	struct snd_pcm_runtime *runtime = substream->runtime;
526*4882a593Smuzhiyun 	current_ptr =
527*4882a593Smuzhiyun 		snd_aw2_saa7146_get_hw_ptr_playback(&chip->saa7146,
528*4882a593Smuzhiyun 						    pcm_device->stream_number,
529*4882a593Smuzhiyun 						    runtime->dma_area,
530*4882a593Smuzhiyun 						    runtime->buffer_size);
531*4882a593Smuzhiyun 
532*4882a593Smuzhiyun 	return bytes_to_frames(substream->runtime, current_ptr);
533*4882a593Smuzhiyun }
534*4882a593Smuzhiyun 
535*4882a593Smuzhiyun /* capture pointer callback */
snd_aw2_pcm_pointer_capture(struct snd_pcm_substream * substream)536*4882a593Smuzhiyun static snd_pcm_uframes_t snd_aw2_pcm_pointer_capture(struct snd_pcm_substream
537*4882a593Smuzhiyun 						     *substream)
538*4882a593Smuzhiyun {
539*4882a593Smuzhiyun 	struct aw2_pcm_device *pcm_device = snd_pcm_substream_chip(substream);
540*4882a593Smuzhiyun 	struct aw2 *chip = pcm_device->chip;
541*4882a593Smuzhiyun 	unsigned int current_ptr;
542*4882a593Smuzhiyun 
543*4882a593Smuzhiyun 	/* get the current hardware pointer */
544*4882a593Smuzhiyun 	struct snd_pcm_runtime *runtime = substream->runtime;
545*4882a593Smuzhiyun 	current_ptr =
546*4882a593Smuzhiyun 		snd_aw2_saa7146_get_hw_ptr_capture(&chip->saa7146,
547*4882a593Smuzhiyun 						   pcm_device->stream_number,
548*4882a593Smuzhiyun 						   runtime->dma_area,
549*4882a593Smuzhiyun 						   runtime->buffer_size);
550*4882a593Smuzhiyun 
551*4882a593Smuzhiyun 	return bytes_to_frames(substream->runtime, current_ptr);
552*4882a593Smuzhiyun }
553*4882a593Smuzhiyun 
554*4882a593Smuzhiyun /* create a pcm device */
snd_aw2_new_pcm(struct aw2 * chip)555*4882a593Smuzhiyun static int snd_aw2_new_pcm(struct aw2 *chip)
556*4882a593Smuzhiyun {
557*4882a593Smuzhiyun 	struct snd_pcm *pcm_playback_ana;
558*4882a593Smuzhiyun 	struct snd_pcm *pcm_playback_num;
559*4882a593Smuzhiyun 	struct snd_pcm *pcm_capture;
560*4882a593Smuzhiyun 	struct aw2_pcm_device *pcm_device;
561*4882a593Smuzhiyun 	int err = 0;
562*4882a593Smuzhiyun 
563*4882a593Smuzhiyun 	/* Create new Alsa PCM device */
564*4882a593Smuzhiyun 
565*4882a593Smuzhiyun 	err = snd_pcm_new(chip->card, "Audiowerk2 analog playback", 0, 1, 0,
566*4882a593Smuzhiyun 			  &pcm_playback_ana);
567*4882a593Smuzhiyun 	if (err < 0) {
568*4882a593Smuzhiyun 		dev_err(chip->card->dev, "snd_pcm_new error (0x%X)\n", err);
569*4882a593Smuzhiyun 		return err;
570*4882a593Smuzhiyun 	}
571*4882a593Smuzhiyun 
572*4882a593Smuzhiyun 	/* Creation ok */
573*4882a593Smuzhiyun 	pcm_device = &chip->device_playback[NUM_STREAM_PLAYBACK_ANA];
574*4882a593Smuzhiyun 
575*4882a593Smuzhiyun 	/* Set PCM device name */
576*4882a593Smuzhiyun 	strcpy(pcm_playback_ana->name, "Analog playback");
577*4882a593Smuzhiyun 	/* Associate private data to PCM device */
578*4882a593Smuzhiyun 	pcm_playback_ana->private_data = pcm_device;
579*4882a593Smuzhiyun 	/* set operators of PCM device */
580*4882a593Smuzhiyun 	snd_pcm_set_ops(pcm_playback_ana, SNDRV_PCM_STREAM_PLAYBACK,
581*4882a593Smuzhiyun 			&snd_aw2_playback_ops);
582*4882a593Smuzhiyun 	/* store PCM device */
583*4882a593Smuzhiyun 	pcm_device->pcm = pcm_playback_ana;
584*4882a593Smuzhiyun 	/* give base chip pointer to our internal pcm device
585*4882a593Smuzhiyun 	   structure */
586*4882a593Smuzhiyun 	pcm_device->chip = chip;
587*4882a593Smuzhiyun 	/* Give stream number to PCM device */
588*4882a593Smuzhiyun 	pcm_device->stream_number = NUM_STREAM_PLAYBACK_ANA;
589*4882a593Smuzhiyun 
590*4882a593Smuzhiyun 	/* pre-allocation of buffers */
591*4882a593Smuzhiyun 	/* Preallocate continuous pages. */
592*4882a593Smuzhiyun 	snd_pcm_set_managed_buffer_all(pcm_playback_ana,
593*4882a593Smuzhiyun 				       SNDRV_DMA_TYPE_DEV,
594*4882a593Smuzhiyun 				       &chip->pci->dev,
595*4882a593Smuzhiyun 				       64 * 1024, 64 * 1024);
596*4882a593Smuzhiyun 
597*4882a593Smuzhiyun 	err = snd_pcm_new(chip->card, "Audiowerk2 digital playback", 1, 1, 0,
598*4882a593Smuzhiyun 			  &pcm_playback_num);
599*4882a593Smuzhiyun 
600*4882a593Smuzhiyun 	if (err < 0) {
601*4882a593Smuzhiyun 		dev_err(chip->card->dev, "snd_pcm_new error (0x%X)\n", err);
602*4882a593Smuzhiyun 		return err;
603*4882a593Smuzhiyun 	}
604*4882a593Smuzhiyun 	/* Creation ok */
605*4882a593Smuzhiyun 	pcm_device = &chip->device_playback[NUM_STREAM_PLAYBACK_DIG];
606*4882a593Smuzhiyun 
607*4882a593Smuzhiyun 	/* Set PCM device name */
608*4882a593Smuzhiyun 	strcpy(pcm_playback_num->name, "Digital playback");
609*4882a593Smuzhiyun 	/* Associate private data to PCM device */
610*4882a593Smuzhiyun 	pcm_playback_num->private_data = pcm_device;
611*4882a593Smuzhiyun 	/* set operators of PCM device */
612*4882a593Smuzhiyun 	snd_pcm_set_ops(pcm_playback_num, SNDRV_PCM_STREAM_PLAYBACK,
613*4882a593Smuzhiyun 			&snd_aw2_playback_ops);
614*4882a593Smuzhiyun 	/* store PCM device */
615*4882a593Smuzhiyun 	pcm_device->pcm = pcm_playback_num;
616*4882a593Smuzhiyun 	/* give base chip pointer to our internal pcm device
617*4882a593Smuzhiyun 	   structure */
618*4882a593Smuzhiyun 	pcm_device->chip = chip;
619*4882a593Smuzhiyun 	/* Give stream number to PCM device */
620*4882a593Smuzhiyun 	pcm_device->stream_number = NUM_STREAM_PLAYBACK_DIG;
621*4882a593Smuzhiyun 
622*4882a593Smuzhiyun 	/* pre-allocation of buffers */
623*4882a593Smuzhiyun 	/* Preallocate continuous pages. */
624*4882a593Smuzhiyun 	snd_pcm_set_managed_buffer_all(pcm_playback_num,
625*4882a593Smuzhiyun 				       SNDRV_DMA_TYPE_DEV,
626*4882a593Smuzhiyun 				       &chip->pci->dev,
627*4882a593Smuzhiyun 				       64 * 1024, 64 * 1024);
628*4882a593Smuzhiyun 
629*4882a593Smuzhiyun 	err = snd_pcm_new(chip->card, "Audiowerk2 capture", 2, 0, 1,
630*4882a593Smuzhiyun 			  &pcm_capture);
631*4882a593Smuzhiyun 
632*4882a593Smuzhiyun 	if (err < 0) {
633*4882a593Smuzhiyun 		dev_err(chip->card->dev, "snd_pcm_new error (0x%X)\n", err);
634*4882a593Smuzhiyun 		return err;
635*4882a593Smuzhiyun 	}
636*4882a593Smuzhiyun 
637*4882a593Smuzhiyun 	/* Creation ok */
638*4882a593Smuzhiyun 	pcm_device = &chip->device_capture[NUM_STREAM_CAPTURE_ANA];
639*4882a593Smuzhiyun 
640*4882a593Smuzhiyun 	/* Set PCM device name */
641*4882a593Smuzhiyun 	strcpy(pcm_capture->name, "Capture");
642*4882a593Smuzhiyun 	/* Associate private data to PCM device */
643*4882a593Smuzhiyun 	pcm_capture->private_data = pcm_device;
644*4882a593Smuzhiyun 	/* set operators of PCM device */
645*4882a593Smuzhiyun 	snd_pcm_set_ops(pcm_capture, SNDRV_PCM_STREAM_CAPTURE,
646*4882a593Smuzhiyun 			&snd_aw2_capture_ops);
647*4882a593Smuzhiyun 	/* store PCM device */
648*4882a593Smuzhiyun 	pcm_device->pcm = pcm_capture;
649*4882a593Smuzhiyun 	/* give base chip pointer to our internal pcm device
650*4882a593Smuzhiyun 	   structure */
651*4882a593Smuzhiyun 	pcm_device->chip = chip;
652*4882a593Smuzhiyun 	/* Give stream number to PCM device */
653*4882a593Smuzhiyun 	pcm_device->stream_number = NUM_STREAM_CAPTURE_ANA;
654*4882a593Smuzhiyun 
655*4882a593Smuzhiyun 	/* pre-allocation of buffers */
656*4882a593Smuzhiyun 	/* Preallocate continuous pages. */
657*4882a593Smuzhiyun 	snd_pcm_set_managed_buffer_all(pcm_capture,
658*4882a593Smuzhiyun 				       SNDRV_DMA_TYPE_DEV,
659*4882a593Smuzhiyun 				       &chip->pci->dev,
660*4882a593Smuzhiyun 				       64 * 1024, 64 * 1024);
661*4882a593Smuzhiyun 
662*4882a593Smuzhiyun 	/* Create control */
663*4882a593Smuzhiyun 	err = snd_ctl_add(chip->card, snd_ctl_new1(&aw2_control, chip));
664*4882a593Smuzhiyun 	if (err < 0) {
665*4882a593Smuzhiyun 		dev_err(chip->card->dev, "snd_ctl_add error (0x%X)\n", err);
666*4882a593Smuzhiyun 		return err;
667*4882a593Smuzhiyun 	}
668*4882a593Smuzhiyun 
669*4882a593Smuzhiyun 	return 0;
670*4882a593Smuzhiyun }
671*4882a593Smuzhiyun 
snd_aw2_control_switch_capture_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)672*4882a593Smuzhiyun static int snd_aw2_control_switch_capture_info(struct snd_kcontrol *kcontrol,
673*4882a593Smuzhiyun 					       struct snd_ctl_elem_info *uinfo)
674*4882a593Smuzhiyun {
675*4882a593Smuzhiyun 	static const char * const texts[2] = {
676*4882a593Smuzhiyun 		"Analog", "Digital"
677*4882a593Smuzhiyun 	};
678*4882a593Smuzhiyun 	return snd_ctl_enum_info(uinfo, 1, 2, texts);
679*4882a593Smuzhiyun }
680*4882a593Smuzhiyun 
snd_aw2_control_switch_capture_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)681*4882a593Smuzhiyun static int snd_aw2_control_switch_capture_get(struct snd_kcontrol *kcontrol,
682*4882a593Smuzhiyun 					      struct snd_ctl_elem_value
683*4882a593Smuzhiyun 					      *ucontrol)
684*4882a593Smuzhiyun {
685*4882a593Smuzhiyun 	struct aw2 *chip = snd_kcontrol_chip(kcontrol);
686*4882a593Smuzhiyun 	if (snd_aw2_saa7146_is_using_digital_input(&chip->saa7146))
687*4882a593Smuzhiyun 		ucontrol->value.enumerated.item[0] = CTL_ROUTE_DIGITAL;
688*4882a593Smuzhiyun 	else
689*4882a593Smuzhiyun 		ucontrol->value.enumerated.item[0] = CTL_ROUTE_ANALOG;
690*4882a593Smuzhiyun 	return 0;
691*4882a593Smuzhiyun }
692*4882a593Smuzhiyun 
snd_aw2_control_switch_capture_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)693*4882a593Smuzhiyun static int snd_aw2_control_switch_capture_put(struct snd_kcontrol *kcontrol,
694*4882a593Smuzhiyun 					      struct snd_ctl_elem_value
695*4882a593Smuzhiyun 					      *ucontrol)
696*4882a593Smuzhiyun {
697*4882a593Smuzhiyun 	struct aw2 *chip = snd_kcontrol_chip(kcontrol);
698*4882a593Smuzhiyun 	int changed = 0;
699*4882a593Smuzhiyun 	int is_disgital =
700*4882a593Smuzhiyun 	    snd_aw2_saa7146_is_using_digital_input(&chip->saa7146);
701*4882a593Smuzhiyun 
702*4882a593Smuzhiyun 	if (((ucontrol->value.integer.value[0] == CTL_ROUTE_DIGITAL)
703*4882a593Smuzhiyun 	     && !is_disgital)
704*4882a593Smuzhiyun 	    || ((ucontrol->value.integer.value[0] == CTL_ROUTE_ANALOG)
705*4882a593Smuzhiyun 		&& is_disgital)) {
706*4882a593Smuzhiyun 		snd_aw2_saa7146_use_digital_input(&chip->saa7146, !is_disgital);
707*4882a593Smuzhiyun 		changed = 1;
708*4882a593Smuzhiyun 	}
709*4882a593Smuzhiyun 	return changed;
710*4882a593Smuzhiyun }
711