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