xref: /openbmc/linux/sound/pci/cs5535audio/cs5535audio.c (revision 9b4ffa48ae855c8657a36014c5b0243ff69f4722)
1*9b4ffa48SJaya Kumar /*
2*9b4ffa48SJaya Kumar  * Driver for audio on multifunction CS5535 companion device
3*9b4ffa48SJaya Kumar  * Copyright (C) Jaya Kumar
4*9b4ffa48SJaya Kumar  *
5*9b4ffa48SJaya Kumar  * Based on Jaroslav Kysela and Takashi Iwai's examples.
6*9b4ffa48SJaya Kumar  * This work was sponsored by CIS(M) Sdn Bhd.
7*9b4ffa48SJaya Kumar  *
8*9b4ffa48SJaya Kumar  * This program is free software; you can redistribute it and/or modify
9*9b4ffa48SJaya Kumar  * it under the terms of the GNU General Public License as published by
10*9b4ffa48SJaya Kumar  * the Free Software Foundation; either version 2 of the License, or
11*9b4ffa48SJaya Kumar  * (at your option) any later version.
12*9b4ffa48SJaya Kumar  *
13*9b4ffa48SJaya Kumar  * This program is distributed in the hope that it will be useful,
14*9b4ffa48SJaya Kumar  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15*9b4ffa48SJaya Kumar  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16*9b4ffa48SJaya Kumar  * GNU General Public License for more details.
17*9b4ffa48SJaya Kumar  *
18*9b4ffa48SJaya Kumar  * You should have received a copy of the GNU General Public License
19*9b4ffa48SJaya Kumar  * along with this program; if not, write to the Free Software
20*9b4ffa48SJaya Kumar  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
21*9b4ffa48SJaya Kumar  *
22*9b4ffa48SJaya Kumar  */
23*9b4ffa48SJaya Kumar 
24*9b4ffa48SJaya Kumar #include <linux/delay.h>
25*9b4ffa48SJaya Kumar #include <linux/interrupt.h>
26*9b4ffa48SJaya Kumar #include <linux/init.h>
27*9b4ffa48SJaya Kumar #include <linux/pci.h>
28*9b4ffa48SJaya Kumar #include <linux/slab.h>
29*9b4ffa48SJaya Kumar #include <linux/moduleparam.h>
30*9b4ffa48SJaya Kumar #include <asm/io.h>
31*9b4ffa48SJaya Kumar #include <sound/driver.h>
32*9b4ffa48SJaya Kumar #include <sound/core.h>
33*9b4ffa48SJaya Kumar #include <sound/control.h>
34*9b4ffa48SJaya Kumar #include <sound/pcm.h>
35*9b4ffa48SJaya Kumar #include <sound/rawmidi.h>
36*9b4ffa48SJaya Kumar #include <sound/ac97_codec.h>
37*9b4ffa48SJaya Kumar #include <sound/initval.h>
38*9b4ffa48SJaya Kumar #include <sound/asoundef.h>
39*9b4ffa48SJaya Kumar #include "cs5535audio.h"
40*9b4ffa48SJaya Kumar 
41*9b4ffa48SJaya Kumar #define DRIVER_NAME "cs5535audio"
42*9b4ffa48SJaya Kumar 
43*9b4ffa48SJaya Kumar 
44*9b4ffa48SJaya Kumar static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
45*9b4ffa48SJaya Kumar static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
46*9b4ffa48SJaya Kumar static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
47*9b4ffa48SJaya Kumar 
48*9b4ffa48SJaya Kumar static struct pci_device_id snd_cs5535audio_ids[] = {
49*9b4ffa48SJaya Kumar 	{ PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_AUDIO, PCI_ANY_ID,
50*9b4ffa48SJaya Kumar 		PCI_ANY_ID, 0, 0, 0, },
51*9b4ffa48SJaya Kumar 	{}
52*9b4ffa48SJaya Kumar };
53*9b4ffa48SJaya Kumar 
54*9b4ffa48SJaya Kumar MODULE_DEVICE_TABLE(pci, snd_cs5535audio_ids);
55*9b4ffa48SJaya Kumar 
56*9b4ffa48SJaya Kumar static void wait_till_cmd_acked(cs5535audio_t *cs5535au, unsigned long timeout)
57*9b4ffa48SJaya Kumar {
58*9b4ffa48SJaya Kumar 	unsigned long tmp;
59*9b4ffa48SJaya Kumar 	do {
60*9b4ffa48SJaya Kumar 		tmp = cs_readl(cs5535au, ACC_CODEC_CNTL);
61*9b4ffa48SJaya Kumar 		if (!(tmp & CMD_NEW))
62*9b4ffa48SJaya Kumar 			break;
63*9b4ffa48SJaya Kumar 		msleep(10);
64*9b4ffa48SJaya Kumar 	} while (--timeout);
65*9b4ffa48SJaya Kumar 	if (!timeout)
66*9b4ffa48SJaya Kumar 		snd_printk(KERN_ERR "Failure writing to cs5535 codec\n");
67*9b4ffa48SJaya Kumar }
68*9b4ffa48SJaya Kumar 
69*9b4ffa48SJaya Kumar static unsigned short snd_cs5535audio_codec_read(cs5535audio_t *cs5535au,
70*9b4ffa48SJaya Kumar 							unsigned short reg)
71*9b4ffa48SJaya Kumar {
72*9b4ffa48SJaya Kumar 	unsigned long regdata;
73*9b4ffa48SJaya Kumar 	unsigned long timeout;
74*9b4ffa48SJaya Kumar 	unsigned long val;
75*9b4ffa48SJaya Kumar 
76*9b4ffa48SJaya Kumar 	regdata = ((unsigned long) reg) << 24;
77*9b4ffa48SJaya Kumar 	regdata |= ACC_CODEC_CNTL_RD_CMD;
78*9b4ffa48SJaya Kumar 	regdata |= CMD_NEW;
79*9b4ffa48SJaya Kumar 
80*9b4ffa48SJaya Kumar 	cs_writel(cs5535au, ACC_CODEC_CNTL, regdata);
81*9b4ffa48SJaya Kumar 	wait_till_cmd_acked(cs5535au, 500);
82*9b4ffa48SJaya Kumar 
83*9b4ffa48SJaya Kumar 	timeout = 50;
84*9b4ffa48SJaya Kumar 	do {
85*9b4ffa48SJaya Kumar 		val = cs_readl(cs5535au, ACC_CODEC_STATUS);
86*9b4ffa48SJaya Kumar 		if (	(val & STS_NEW) &&
87*9b4ffa48SJaya Kumar 			((unsigned long) reg == ((0xFF000000 & val)>>24)) )
88*9b4ffa48SJaya Kumar 			break;
89*9b4ffa48SJaya Kumar 		msleep(10);
90*9b4ffa48SJaya Kumar 	} while (--timeout);
91*9b4ffa48SJaya Kumar 	if (!timeout)
92*9b4ffa48SJaya Kumar 		snd_printk(KERN_ERR "Failure reading cs5535 codec\n");
93*9b4ffa48SJaya Kumar 
94*9b4ffa48SJaya Kumar 	return ((unsigned short) val);
95*9b4ffa48SJaya Kumar }
96*9b4ffa48SJaya Kumar 
97*9b4ffa48SJaya Kumar static void snd_cs5535audio_codec_write(cs5535audio_t *cs5535au,
98*9b4ffa48SJaya Kumar 				   unsigned short reg, unsigned short val)
99*9b4ffa48SJaya Kumar {
100*9b4ffa48SJaya Kumar 	unsigned long regdata;
101*9b4ffa48SJaya Kumar 
102*9b4ffa48SJaya Kumar 	regdata = ((unsigned long) reg) << 24;
103*9b4ffa48SJaya Kumar 	regdata |= (unsigned long) val;
104*9b4ffa48SJaya Kumar 	regdata &= CMD_MASK;
105*9b4ffa48SJaya Kumar 	regdata |= CMD_NEW;
106*9b4ffa48SJaya Kumar 	regdata &= ACC_CODEC_CNTL_WR_CMD;
107*9b4ffa48SJaya Kumar 
108*9b4ffa48SJaya Kumar 	cs_writel(cs5535au, ACC_CODEC_CNTL, regdata);
109*9b4ffa48SJaya Kumar 	wait_till_cmd_acked(cs5535au, 50);
110*9b4ffa48SJaya Kumar }
111*9b4ffa48SJaya Kumar 
112*9b4ffa48SJaya Kumar static void snd_cs5535audio_ac97_codec_write(ac97_t *ac97,
113*9b4ffa48SJaya Kumar 				   unsigned short reg, unsigned short val)
114*9b4ffa48SJaya Kumar {
115*9b4ffa48SJaya Kumar 	cs5535audio_t *cs5535au = ac97->private_data;
116*9b4ffa48SJaya Kumar 	snd_cs5535audio_codec_write(cs5535au, reg, val);
117*9b4ffa48SJaya Kumar }
118*9b4ffa48SJaya Kumar 
119*9b4ffa48SJaya Kumar static unsigned short snd_cs5535audio_ac97_codec_read(ac97_t *ac97,
120*9b4ffa48SJaya Kumar 					    unsigned short reg)
121*9b4ffa48SJaya Kumar {
122*9b4ffa48SJaya Kumar 	cs5535audio_t *cs5535au = ac97->private_data;
123*9b4ffa48SJaya Kumar 	return snd_cs5535audio_codec_read(cs5535au, reg);
124*9b4ffa48SJaya Kumar }
125*9b4ffa48SJaya Kumar 
126*9b4ffa48SJaya Kumar static void snd_cs5535audio_mixer_free_ac97(ac97_t *ac97)
127*9b4ffa48SJaya Kumar {
128*9b4ffa48SJaya Kumar 	cs5535audio_t *cs5535audio = ac97->private_data;
129*9b4ffa48SJaya Kumar 	cs5535audio->ac97 = NULL;
130*9b4ffa48SJaya Kumar }
131*9b4ffa48SJaya Kumar 
132*9b4ffa48SJaya Kumar static int snd_cs5535audio_mixer(cs5535audio_t *cs5535au)
133*9b4ffa48SJaya Kumar {
134*9b4ffa48SJaya Kumar 	snd_card_t *card = cs5535au->card;
135*9b4ffa48SJaya Kumar 	ac97_bus_t *pbus;
136*9b4ffa48SJaya Kumar 	ac97_template_t ac97;
137*9b4ffa48SJaya Kumar 	int err;
138*9b4ffa48SJaya Kumar 	static ac97_bus_ops_t ops = {
139*9b4ffa48SJaya Kumar 		.write = snd_cs5535audio_ac97_codec_write,
140*9b4ffa48SJaya Kumar 		.read = snd_cs5535audio_ac97_codec_read,
141*9b4ffa48SJaya Kumar 	};
142*9b4ffa48SJaya Kumar 
143*9b4ffa48SJaya Kumar 	if ((err = snd_ac97_bus(card, 0, &ops, NULL, &pbus)) < 0)
144*9b4ffa48SJaya Kumar 		return err;
145*9b4ffa48SJaya Kumar 
146*9b4ffa48SJaya Kumar 	memset(&ac97, 0, sizeof(ac97));
147*9b4ffa48SJaya Kumar 	ac97.scaps = AC97_SCAP_AUDIO|AC97_SCAP_SKIP_MODEM;
148*9b4ffa48SJaya Kumar 	ac97.private_data = cs5535au;
149*9b4ffa48SJaya Kumar 	ac97.pci = cs5535au->pci;
150*9b4ffa48SJaya Kumar 	ac97.private_free = snd_cs5535audio_mixer_free_ac97;
151*9b4ffa48SJaya Kumar 
152*9b4ffa48SJaya Kumar 	if ((err = snd_ac97_mixer(pbus, &ac97, &cs5535au->ac97)) < 0) {
153*9b4ffa48SJaya Kumar 		snd_printk("mixer failed\n");
154*9b4ffa48SJaya Kumar 		return err;
155*9b4ffa48SJaya Kumar 	}
156*9b4ffa48SJaya Kumar 
157*9b4ffa48SJaya Kumar 	return 0;
158*9b4ffa48SJaya Kumar }
159*9b4ffa48SJaya Kumar 
160*9b4ffa48SJaya Kumar static void process_bm0_irq(cs5535audio_t *cs5535au)
161*9b4ffa48SJaya Kumar {
162*9b4ffa48SJaya Kumar 	u8 bm_stat;
163*9b4ffa48SJaya Kumar 	spin_lock(&cs5535au->reg_lock);
164*9b4ffa48SJaya Kumar 	bm_stat = cs_readb(cs5535au, ACC_BM0_STATUS);
165*9b4ffa48SJaya Kumar 	spin_unlock(&cs5535au->reg_lock);
166*9b4ffa48SJaya Kumar 	if (bm_stat & EOP) {
167*9b4ffa48SJaya Kumar 		cs5535audio_dma_t *dma;
168*9b4ffa48SJaya Kumar 		dma = cs5535au->playback_substream->runtime->private_data;
169*9b4ffa48SJaya Kumar 		snd_pcm_period_elapsed(cs5535au->playback_substream);
170*9b4ffa48SJaya Kumar 	} else {
171*9b4ffa48SJaya Kumar 		snd_printk(KERN_ERR "unexpected bm0 irq src, bm_stat=%x\n",
172*9b4ffa48SJaya Kumar 					bm_stat);
173*9b4ffa48SJaya Kumar 	}
174*9b4ffa48SJaya Kumar }
175*9b4ffa48SJaya Kumar 
176*9b4ffa48SJaya Kumar static void process_bm1_irq(cs5535audio_t *cs5535au)
177*9b4ffa48SJaya Kumar {
178*9b4ffa48SJaya Kumar 	u8 bm_stat;
179*9b4ffa48SJaya Kumar 	spin_lock(&cs5535au->reg_lock);
180*9b4ffa48SJaya Kumar 	bm_stat = cs_readb(cs5535au, ACC_BM1_STATUS);
181*9b4ffa48SJaya Kumar 	spin_unlock(&cs5535au->reg_lock);
182*9b4ffa48SJaya Kumar 	if (bm_stat & EOP) {
183*9b4ffa48SJaya Kumar 		cs5535audio_dma_t *dma;
184*9b4ffa48SJaya Kumar 		dma = cs5535au->capture_substream->runtime->private_data;
185*9b4ffa48SJaya Kumar 		snd_pcm_period_elapsed(cs5535au->capture_substream);
186*9b4ffa48SJaya Kumar 	}
187*9b4ffa48SJaya Kumar }
188*9b4ffa48SJaya Kumar 
189*9b4ffa48SJaya Kumar static irqreturn_t snd_cs5535audio_interrupt(int irq, void *dev_id,
190*9b4ffa48SJaya Kumar 						struct pt_regs *regs)
191*9b4ffa48SJaya Kumar {
192*9b4ffa48SJaya Kumar 	u16 acc_irq_stat;
193*9b4ffa48SJaya Kumar 	u8 bm_stat;
194*9b4ffa48SJaya Kumar 	unsigned char count;
195*9b4ffa48SJaya Kumar 	cs5535audio_t *cs5535au = dev_id;
196*9b4ffa48SJaya Kumar 
197*9b4ffa48SJaya Kumar 	if (cs5535au == NULL)
198*9b4ffa48SJaya Kumar 		return IRQ_NONE;
199*9b4ffa48SJaya Kumar 
200*9b4ffa48SJaya Kumar 	acc_irq_stat = cs_readw(cs5535au, ACC_IRQ_STATUS);
201*9b4ffa48SJaya Kumar 
202*9b4ffa48SJaya Kumar 	if (!acc_irq_stat)
203*9b4ffa48SJaya Kumar 		return IRQ_NONE;
204*9b4ffa48SJaya Kumar 	for (count=0; count < 10; count++) {
205*9b4ffa48SJaya Kumar 		if (acc_irq_stat & (1<<count)) {
206*9b4ffa48SJaya Kumar 			switch (count) {
207*9b4ffa48SJaya Kumar 			case IRQ_STS:
208*9b4ffa48SJaya Kumar 				cs_readl(cs5535au, ACC_GPIO_STATUS);
209*9b4ffa48SJaya Kumar 				break;
210*9b4ffa48SJaya Kumar 			case WU_IRQ_STS:
211*9b4ffa48SJaya Kumar 				cs_readl(cs5535au, ACC_GPIO_STATUS);
212*9b4ffa48SJaya Kumar 				break;
213*9b4ffa48SJaya Kumar 			case BM0_IRQ_STS:
214*9b4ffa48SJaya Kumar 				process_bm0_irq(cs5535au);
215*9b4ffa48SJaya Kumar 				break;
216*9b4ffa48SJaya Kumar 			case BM1_IRQ_STS:
217*9b4ffa48SJaya Kumar 				process_bm1_irq(cs5535au);
218*9b4ffa48SJaya Kumar 				break;
219*9b4ffa48SJaya Kumar 			case BM2_IRQ_STS:
220*9b4ffa48SJaya Kumar 				bm_stat = cs_readb(cs5535au, ACC_BM2_STATUS);
221*9b4ffa48SJaya Kumar 				break;
222*9b4ffa48SJaya Kumar 			case BM3_IRQ_STS:
223*9b4ffa48SJaya Kumar 				bm_stat = cs_readb(cs5535au, ACC_BM3_STATUS);
224*9b4ffa48SJaya Kumar 				break;
225*9b4ffa48SJaya Kumar 			case BM4_IRQ_STS:
226*9b4ffa48SJaya Kumar 				bm_stat = cs_readb(cs5535au, ACC_BM4_STATUS);
227*9b4ffa48SJaya Kumar 				break;
228*9b4ffa48SJaya Kumar 			case BM5_IRQ_STS:
229*9b4ffa48SJaya Kumar 				bm_stat = cs_readb(cs5535au, ACC_BM5_STATUS);
230*9b4ffa48SJaya Kumar 				break;
231*9b4ffa48SJaya Kumar 			case BM6_IRQ_STS:
232*9b4ffa48SJaya Kumar 				bm_stat = cs_readb(cs5535au, ACC_BM6_STATUS);
233*9b4ffa48SJaya Kumar 				break;
234*9b4ffa48SJaya Kumar 			case BM7_IRQ_STS:
235*9b4ffa48SJaya Kumar 				bm_stat = cs_readb(cs5535au, ACC_BM7_STATUS);
236*9b4ffa48SJaya Kumar 				break;
237*9b4ffa48SJaya Kumar 			default:
238*9b4ffa48SJaya Kumar 				snd_printk(KERN_ERR "Unexpected irq src\n");
239*9b4ffa48SJaya Kumar 				break;
240*9b4ffa48SJaya Kumar 			}
241*9b4ffa48SJaya Kumar 		}
242*9b4ffa48SJaya Kumar 	}
243*9b4ffa48SJaya Kumar 	return IRQ_HANDLED;
244*9b4ffa48SJaya Kumar }
245*9b4ffa48SJaya Kumar 
246*9b4ffa48SJaya Kumar static int snd_cs5535audio_free(cs5535audio_t *cs5535au)
247*9b4ffa48SJaya Kumar {
248*9b4ffa48SJaya Kumar 	synchronize_irq(cs5535au->irq);
249*9b4ffa48SJaya Kumar 	pci_set_power_state(cs5535au->pci, 3);
250*9b4ffa48SJaya Kumar 
251*9b4ffa48SJaya Kumar 	if (cs5535au->irq >= 0)
252*9b4ffa48SJaya Kumar 		free_irq(cs5535au->irq, cs5535au);
253*9b4ffa48SJaya Kumar 
254*9b4ffa48SJaya Kumar 	pci_release_regions(cs5535au->pci);
255*9b4ffa48SJaya Kumar 	pci_disable_device(cs5535au->pci);
256*9b4ffa48SJaya Kumar 	kfree(cs5535au);
257*9b4ffa48SJaya Kumar 	return 0;
258*9b4ffa48SJaya Kumar }
259*9b4ffa48SJaya Kumar 
260*9b4ffa48SJaya Kumar static int snd_cs5535audio_dev_free(snd_device_t *device)
261*9b4ffa48SJaya Kumar {
262*9b4ffa48SJaya Kumar 	cs5535audio_t *cs5535au = device->device_data;
263*9b4ffa48SJaya Kumar 	return snd_cs5535audio_free(cs5535au);
264*9b4ffa48SJaya Kumar }
265*9b4ffa48SJaya Kumar 
266*9b4ffa48SJaya Kumar static int __devinit snd_cs5535audio_create(snd_card_t *card,
267*9b4ffa48SJaya Kumar 				     struct pci_dev *pci,
268*9b4ffa48SJaya Kumar 				     cs5535audio_t **rcs5535au)
269*9b4ffa48SJaya Kumar {
270*9b4ffa48SJaya Kumar 	cs5535audio_t *cs5535au;
271*9b4ffa48SJaya Kumar 
272*9b4ffa48SJaya Kumar 	int err;
273*9b4ffa48SJaya Kumar 	static snd_device_ops_t ops = {
274*9b4ffa48SJaya Kumar 		.dev_free =	snd_cs5535audio_dev_free,
275*9b4ffa48SJaya Kumar 	};
276*9b4ffa48SJaya Kumar 
277*9b4ffa48SJaya Kumar 	*rcs5535au = NULL;
278*9b4ffa48SJaya Kumar 	if ((err = pci_enable_device(pci)) < 0)
279*9b4ffa48SJaya Kumar 		return err;
280*9b4ffa48SJaya Kumar 
281*9b4ffa48SJaya Kumar 	if (pci_set_dma_mask(pci, DMA_32BIT_MASK) < 0 ||
282*9b4ffa48SJaya Kumar 		pci_set_consistent_dma_mask(pci, DMA_32BIT_MASK) < 0) {
283*9b4ffa48SJaya Kumar 		printk(KERN_WARNING "unable to get 32bit dma\n");
284*9b4ffa48SJaya Kumar 		err = -ENXIO;
285*9b4ffa48SJaya Kumar 		goto pcifail;
286*9b4ffa48SJaya Kumar 	}
287*9b4ffa48SJaya Kumar 
288*9b4ffa48SJaya Kumar 	cs5535au = kzalloc(sizeof(*cs5535au), GFP_KERNEL);
289*9b4ffa48SJaya Kumar 	if (cs5535au == NULL) {
290*9b4ffa48SJaya Kumar 		err = -ENOMEM;
291*9b4ffa48SJaya Kumar 		goto pcifail;
292*9b4ffa48SJaya Kumar 	}
293*9b4ffa48SJaya Kumar 
294*9b4ffa48SJaya Kumar 	spin_lock_init(&cs5535au->reg_lock);
295*9b4ffa48SJaya Kumar 	cs5535au->card = card;
296*9b4ffa48SJaya Kumar 	cs5535au->pci = pci;
297*9b4ffa48SJaya Kumar 	cs5535au->irq = -1;
298*9b4ffa48SJaya Kumar 
299*9b4ffa48SJaya Kumar 	if ((err = pci_request_regions(pci, "CS5535 Audio")) < 0) {
300*9b4ffa48SJaya Kumar 		kfree(cs5535au);
301*9b4ffa48SJaya Kumar 		goto pcifail;
302*9b4ffa48SJaya Kumar 	}
303*9b4ffa48SJaya Kumar 
304*9b4ffa48SJaya Kumar 	cs5535au->port = pci_resource_start(pci, 0);
305*9b4ffa48SJaya Kumar 
306*9b4ffa48SJaya Kumar 	if (request_irq(pci->irq, snd_cs5535audio_interrupt,
307*9b4ffa48SJaya Kumar 		SA_INTERRUPT|SA_SHIRQ, "CS5535 Audio", cs5535au)) {
308*9b4ffa48SJaya Kumar 		snd_printk("unable to grab IRQ %d\n", pci->irq);
309*9b4ffa48SJaya Kumar 		err = -EBUSY;
310*9b4ffa48SJaya Kumar 		goto sndfail;
311*9b4ffa48SJaya Kumar 	}
312*9b4ffa48SJaya Kumar 
313*9b4ffa48SJaya Kumar 	cs5535au->irq = pci->irq;
314*9b4ffa48SJaya Kumar 	pci_set_master(pci);
315*9b4ffa48SJaya Kumar 
316*9b4ffa48SJaya Kumar 	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL,
317*9b4ffa48SJaya Kumar 					cs5535au, &ops)) < 0)
318*9b4ffa48SJaya Kumar 		goto sndfail;
319*9b4ffa48SJaya Kumar 
320*9b4ffa48SJaya Kumar 	snd_card_set_dev(card, &pci->dev);
321*9b4ffa48SJaya Kumar 
322*9b4ffa48SJaya Kumar 	*rcs5535au = cs5535au;
323*9b4ffa48SJaya Kumar 	return 0;
324*9b4ffa48SJaya Kumar 
325*9b4ffa48SJaya Kumar sndfail: /* leave the device alive, just kill the snd */
326*9b4ffa48SJaya Kumar 	snd_cs5535audio_free(cs5535au);
327*9b4ffa48SJaya Kumar 	return err;
328*9b4ffa48SJaya Kumar 
329*9b4ffa48SJaya Kumar pcifail:
330*9b4ffa48SJaya Kumar 	pci_disable_device(pci);
331*9b4ffa48SJaya Kumar 	return err;
332*9b4ffa48SJaya Kumar }
333*9b4ffa48SJaya Kumar 
334*9b4ffa48SJaya Kumar static int __devinit snd_cs5535audio_probe(struct pci_dev *pci,
335*9b4ffa48SJaya Kumar 					const struct pci_device_id *pci_id)
336*9b4ffa48SJaya Kumar {
337*9b4ffa48SJaya Kumar 	static int dev;
338*9b4ffa48SJaya Kumar 	snd_card_t *card;
339*9b4ffa48SJaya Kumar 	cs5535audio_t *cs5535au;
340*9b4ffa48SJaya Kumar 	int err;
341*9b4ffa48SJaya Kumar 
342*9b4ffa48SJaya Kumar 	if (dev >= SNDRV_CARDS)
343*9b4ffa48SJaya Kumar 		return -ENODEV;
344*9b4ffa48SJaya Kumar 	if (!enable[dev]) {
345*9b4ffa48SJaya Kumar 		dev++;
346*9b4ffa48SJaya Kumar 		return -ENOENT;
347*9b4ffa48SJaya Kumar 	}
348*9b4ffa48SJaya Kumar 
349*9b4ffa48SJaya Kumar 	card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
350*9b4ffa48SJaya Kumar 	if (card == NULL)
351*9b4ffa48SJaya Kumar 		return -ENOMEM;
352*9b4ffa48SJaya Kumar 
353*9b4ffa48SJaya Kumar 	if ((err = snd_cs5535audio_create(card, pci, &cs5535au)) < 0)
354*9b4ffa48SJaya Kumar 		goto probefail_out;
355*9b4ffa48SJaya Kumar 
356*9b4ffa48SJaya Kumar 	if ((err = snd_cs5535audio_mixer(cs5535au)) < 0)
357*9b4ffa48SJaya Kumar 		goto probefail_out;
358*9b4ffa48SJaya Kumar 
359*9b4ffa48SJaya Kumar 	if ((err = snd_cs5535audio_pcm(cs5535au)) < 0)
360*9b4ffa48SJaya Kumar 		goto probefail_out;
361*9b4ffa48SJaya Kumar 
362*9b4ffa48SJaya Kumar 	strcpy(card->driver, DRIVER_NAME);
363*9b4ffa48SJaya Kumar 
364*9b4ffa48SJaya Kumar 	strcpy(card->shortname, "CS5535 Audio");
365*9b4ffa48SJaya Kumar 	sprintf(card->longname, "%s %s at 0x%lx, irq %i",
366*9b4ffa48SJaya Kumar 		card->shortname, card->driver,
367*9b4ffa48SJaya Kumar 		cs5535au->port, cs5535au->irq);
368*9b4ffa48SJaya Kumar 
369*9b4ffa48SJaya Kumar 	if ((err = snd_card_register(card)) < 0)
370*9b4ffa48SJaya Kumar 		goto probefail_out;
371*9b4ffa48SJaya Kumar 
372*9b4ffa48SJaya Kumar 	pci_set_drvdata(pci, card);
373*9b4ffa48SJaya Kumar 	dev++;
374*9b4ffa48SJaya Kumar 	return 0;
375*9b4ffa48SJaya Kumar 
376*9b4ffa48SJaya Kumar probefail_out:
377*9b4ffa48SJaya Kumar 	snd_card_free(card);
378*9b4ffa48SJaya Kumar 	return err;
379*9b4ffa48SJaya Kumar }
380*9b4ffa48SJaya Kumar 
381*9b4ffa48SJaya Kumar static void __devexit snd_cs5535audio_remove(struct pci_dev *pci)
382*9b4ffa48SJaya Kumar {
383*9b4ffa48SJaya Kumar 	snd_card_free(pci_get_drvdata(pci));
384*9b4ffa48SJaya Kumar 	pci_set_drvdata(pci, NULL);
385*9b4ffa48SJaya Kumar }
386*9b4ffa48SJaya Kumar 
387*9b4ffa48SJaya Kumar static struct pci_driver driver = {
388*9b4ffa48SJaya Kumar 	.name = DRIVER_NAME,
389*9b4ffa48SJaya Kumar 	.id_table = snd_cs5535audio_ids,
390*9b4ffa48SJaya Kumar 	.probe = snd_cs5535audio_probe,
391*9b4ffa48SJaya Kumar 	.remove = __devexit_p(snd_cs5535audio_remove),
392*9b4ffa48SJaya Kumar };
393*9b4ffa48SJaya Kumar 
394*9b4ffa48SJaya Kumar static int __init alsa_card_cs5535audio_init(void)
395*9b4ffa48SJaya Kumar {
396*9b4ffa48SJaya Kumar 	return pci_module_init(&driver);
397*9b4ffa48SJaya Kumar }
398*9b4ffa48SJaya Kumar 
399*9b4ffa48SJaya Kumar static void __exit alsa_card_cs5535audio_exit(void)
400*9b4ffa48SJaya Kumar {
401*9b4ffa48SJaya Kumar 	pci_unregister_driver(&driver);
402*9b4ffa48SJaya Kumar }
403*9b4ffa48SJaya Kumar 
404*9b4ffa48SJaya Kumar module_init(alsa_card_cs5535audio_init)
405*9b4ffa48SJaya Kumar module_exit(alsa_card_cs5535audio_exit)
406*9b4ffa48SJaya Kumar 
407*9b4ffa48SJaya Kumar MODULE_AUTHOR("Jaya Kumar");
408*9b4ffa48SJaya Kumar MODULE_LICENSE("GPL");
409*9b4ffa48SJaya Kumar MODULE_DESCRIPTION("CS5535 Audio");
410*9b4ffa48SJaya Kumar MODULE_SUPPORTED_DEVICE("CS5535 Audio");
411