[ALSA] azt2320 - Add PM support
[linux-2.6.git] / sound / isa / azt2320.c
1 /*
2     card-azt2320.c - driver for Aztech Systems AZT2320 based soundcards.
3     Copyright (C) 1999-2000 by Massimo Piccioni <dafastidio@libero.it>
4
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
18 */
19
20 /*
21     This driver should provide support for most Aztech AZT2320 based cards.
22     Several AZT2316 chips are also supported/tested, but autoprobe doesn't
23     work: all module option have to be set.
24
25     No docs available for us at Aztech headquarters !!!   Unbelievable ...
26     No other help obtained.
27
28     Thanks to Rainer Wiesner <rainer.wiesner@01019freenet.de> for the WSS
29     activation method (full-duplex audio!).
30 */
31
32 #include <sound/driver.h>
33 #include <asm/io.h>
34 #include <linux/delay.h>
35 #include <linux/init.h>
36 #include <linux/time.h>
37 #include <linux/wait.h>
38 #include <linux/pnp.h>
39 #include <linux/moduleparam.h>
40 #include <sound/core.h>
41 #include <sound/initval.h>
42 #include <sound/cs4231.h>
43 #include <sound/mpu401.h>
44 #include <sound/opl3.h>
45
46 #define PFX "azt2320: "
47
48 MODULE_AUTHOR("Massimo Piccioni <dafastidio@libero.it>");
49 MODULE_DESCRIPTION("Aztech Systems AZT2320");
50 MODULE_LICENSE("GPL");
51 MODULE_SUPPORTED_DEVICE("{{Aztech Systems,PRO16V},"
52                 "{Aztech Systems,AZT2320},"
53                 "{Aztech Systems,AZT3300},"
54                 "{Aztech Systems,AZT2320},"
55                 "{Aztech Systems,AZT3000}}");
56
57 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;      /* Index 0-MAX */
58 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;       /* ID for this card */
59 static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_ISAPNP; /* Enable this card */
60 static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;     /* PnP setup */
61 static long wss_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */
62 static long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */
63 static long fm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;  /* PnP setup */
64 static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;        /* Pnp setup */
65 static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;    /* Pnp setup */
66 static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;       /* PnP setup */
67 static int dma2[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;       /* PnP setup */
68
69 module_param_array(index, int, NULL, 0444);
70 MODULE_PARM_DESC(index, "Index value for azt2320 based soundcard.");
71 module_param_array(id, charp, NULL, 0444);
72 MODULE_PARM_DESC(id, "ID string for azt2320 based soundcard.");
73 module_param_array(enable, bool, NULL, 0444);
74 MODULE_PARM_DESC(enable, "Enable azt2320 based soundcard.");
75 module_param_array(port, long, NULL, 0444);
76 MODULE_PARM_DESC(port, "Port # for azt2320 driver.");
77 module_param_array(wss_port, long, NULL, 0444);
78 MODULE_PARM_DESC(wss_port, "WSS Port # for azt2320 driver.");
79 module_param_array(mpu_port, long, NULL, 0444);
80 MODULE_PARM_DESC(mpu_port, "MPU-401 port # for azt2320 driver.");
81 module_param_array(fm_port, long, NULL, 0444);
82 MODULE_PARM_DESC(fm_port, "FM port # for azt2320 driver.");
83 module_param_array(irq, int, NULL, 0444);
84 MODULE_PARM_DESC(irq, "IRQ # for azt2320 driver.");
85 module_param_array(mpu_irq, int, NULL, 0444);
86 MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for azt2320 driver.");
87 module_param_array(dma1, int, NULL, 0444);
88 MODULE_PARM_DESC(dma1, "1st DMA # for azt2320 driver.");
89 module_param_array(dma2, int, NULL, 0444);
90 MODULE_PARM_DESC(dma2, "2nd DMA # for azt2320 driver.");
91
92 struct snd_card_azt2320 {
93         int dev_no;
94         struct pnp_dev *dev;
95         struct pnp_dev *devmpu;
96         struct snd_cs4231 *chip;
97 };
98
99 static struct pnp_card_device_id snd_azt2320_pnpids[] = {
100         /* PRO16V */
101         { .id = "AZT1008", .devs = { { "AZT1008" }, { "AZT2001" }, } },
102         /* Aztech Sound Galaxy 16 */
103         { .id = "AZT2320", .devs = { { "AZT0001" }, { "AZT0002" }, } },
104         /* Packard Bell Sound III 336 AM/SP */
105         { .id = "AZT3000", .devs = { { "AZT1003" }, { "AZT2001" }, } },
106         /* AT3300 */
107         { .id = "AZT3002", .devs = { { "AZT1004" }, { "AZT2001" }, } },
108         /* --- */
109         { .id = "AZT3005", .devs = { { "AZT1003" }, { "AZT2001" }, } },
110         /* --- */
111         { .id = "AZT3011", .devs = { { "AZT1003" }, { "AZT2001" }, } },
112         { .id = "" }    /* end */
113 };
114
115 MODULE_DEVICE_TABLE(pnp_card, snd_azt2320_pnpids);
116
117 #define DRIVER_NAME     "snd-card-azt2320"
118
119 static int __devinit snd_card_azt2320_pnp(int dev, struct snd_card_azt2320 *acard,
120                                           struct pnp_card_link *card,
121                                           const struct pnp_card_device_id *id)
122 {
123         struct pnp_dev *pdev;
124         struct pnp_resource_table * cfg = kmalloc(sizeof(struct pnp_resource_table), GFP_KERNEL);
125         int err;
126
127         if (!cfg)
128                 return -ENOMEM;
129
130         acard->dev = pnp_request_card_device(card, id->devs[0].id, NULL);
131         if (acard->dev == NULL) {
132                 kfree(cfg);
133                 return -ENODEV;
134         }
135
136         acard->devmpu = pnp_request_card_device(card, id->devs[1].id, NULL);
137
138         pdev = acard->dev;
139         pnp_init_resource_table(cfg);
140
141         /* override resources */
142         if (port[dev] != SNDRV_AUTO_PORT)
143                 pnp_resource_change(&cfg->port_resource[0], port[dev], 16);
144         if (fm_port[dev] != SNDRV_AUTO_PORT)
145                 pnp_resource_change(&cfg->port_resource[1], fm_port[dev], 4);
146         if (wss_port[dev] != SNDRV_AUTO_PORT)
147                 pnp_resource_change(&cfg->port_resource[2], wss_port[dev], 4);
148         if (dma1[dev] != SNDRV_AUTO_DMA)
149                 pnp_resource_change(&cfg->dma_resource[0], dma1[dev], 1);
150         if (dma2[dev] != SNDRV_AUTO_DMA)
151                 pnp_resource_change(&cfg->dma_resource[1], dma2[dev], 1);
152         if (irq[dev] != SNDRV_AUTO_IRQ)
153                 pnp_resource_change(&cfg->irq_resource[0], irq[dev], 1);
154         if ((pnp_manual_config_dev(pdev, cfg, 0)) < 0)
155                 snd_printk(KERN_ERR PFX "AUDIO the requested resources are invalid, using auto config\n");
156
157         err = pnp_activate_dev(pdev);
158         if (err < 0) {
159                 snd_printk(KERN_ERR PFX "AUDIO pnp configure failure\n");
160                 kfree(cfg);
161                 return err;
162         }
163         port[dev] = pnp_port_start(pdev, 0);
164         fm_port[dev] = pnp_port_start(pdev, 1);
165         wss_port[dev] = pnp_port_start(pdev, 2);
166         dma1[dev] = pnp_dma(pdev, 0);
167         dma2[dev] = pnp_dma(pdev, 1);
168         irq[dev] = pnp_irq(pdev, 0);
169
170         pdev = acard->devmpu;
171         if (pdev != NULL) {
172                 pnp_init_resource_table(cfg);
173                 if (mpu_port[dev] != SNDRV_AUTO_PORT)
174                         pnp_resource_change(&cfg->port_resource[0], mpu_port[dev], 2);
175                 if (mpu_irq[dev] != SNDRV_AUTO_IRQ)
176                         pnp_resource_change(&cfg->irq_resource[0], mpu_irq[dev], 1);
177                 if ((pnp_manual_config_dev(pdev, cfg, 0)) < 0)
178                         snd_printk(KERN_ERR PFX "MPU401 the requested resources are invalid, using auto config\n");
179                 err = pnp_activate_dev(pdev);
180                 if (err < 0)
181                         goto __mpu_error;
182                 mpu_port[dev] = pnp_port_start(pdev, 0);
183                 mpu_irq[dev] = pnp_irq(pdev, 0);
184         } else {
185              __mpu_error:
186                 if (pdev) {
187                         pnp_release_card_device(pdev);
188                         snd_printk(KERN_ERR PFX "MPU401 pnp configure failure, skipping\n");
189                 }
190                 acard->devmpu = NULL;
191                 mpu_port[dev] = -1;
192         }
193
194         kfree (cfg);
195         return 0;
196 }
197
198 /* same of snd_sbdsp_command by Jaroslav Kysela */
199 static int __devinit snd_card_azt2320_command(unsigned long port, unsigned char val)
200 {
201         int i;
202         unsigned long limit;
203
204         limit = jiffies + HZ / 10;
205         for (i = 50000; i && time_after(limit, jiffies); i--)
206                 if (!(inb(port + 0x0c) & 0x80)) {
207                         outb(val, port + 0x0c);
208                         return 0;
209                 }
210         return -EBUSY;
211 }
212
213 static int __devinit snd_card_azt2320_enable_wss(unsigned long port)
214 {
215         int error;
216
217         if ((error = snd_card_azt2320_command(port, 0x09)))
218                 return error;
219         if ((error = snd_card_azt2320_command(port, 0x00)))
220                 return error;
221
222         mdelay(5);
223         return 0;
224 }
225
226 static int __devinit snd_card_azt2320_probe(int dev,
227                                             struct pnp_card_link *pcard,
228                                             const struct pnp_card_device_id *pid)
229 {
230         int error;
231         struct snd_card *card;
232         struct snd_card_azt2320 *acard;
233         struct snd_cs4231 *chip;
234         struct snd_opl3 *opl3;
235
236         if ((card = snd_card_new(index[dev], id[dev], THIS_MODULE,
237                                  sizeof(struct snd_card_azt2320))) == NULL)
238                 return -ENOMEM;
239         acard = (struct snd_card_azt2320 *)card->private_data;
240
241         if ((error = snd_card_azt2320_pnp(dev, acard, pcard, pid))) {
242                 snd_card_free(card);
243                 return error;
244         }
245         snd_card_set_dev(card, &pcard->card->dev);
246
247         if ((error = snd_card_azt2320_enable_wss(port[dev]))) {
248                 snd_card_free(card);
249                 return error;
250         }
251
252         if ((error = snd_cs4231_create(card, wss_port[dev], -1,
253                                        irq[dev],
254                                        dma1[dev],
255                                        dma2[dev],
256                                        CS4231_HW_DETECT, 0, &chip)) < 0) {
257                 snd_card_free(card);
258                 return error;
259         }
260
261         strcpy(card->driver, "AZT2320");
262         strcpy(card->shortname, "Aztech AZT2320");
263         sprintf(card->longname, "%s, WSS at 0x%lx, irq %i, dma %i&%i",
264                 card->shortname, chip->port, irq[dev], dma1[dev], dma2[dev]);
265
266         if ((error = snd_cs4231_pcm(chip, 0, NULL)) < 0) {
267                 snd_card_free(card);
268                 return error;
269         }
270         if ((error = snd_cs4231_mixer(chip)) < 0) {
271                 snd_card_free(card);
272                 return error;
273         }
274         if ((error = snd_cs4231_timer(chip, 0, NULL)) < 0) {
275                 snd_card_free(card);
276                 return error;
277         }
278
279         if (mpu_port[dev] > 0 && mpu_port[dev] != SNDRV_AUTO_PORT) {
280                 if (snd_mpu401_uart_new(card, 0, MPU401_HW_AZT2320,
281                                 mpu_port[dev], 0,
282                                 mpu_irq[dev], SA_INTERRUPT,
283                                 NULL) < 0)
284                         snd_printk(KERN_ERR PFX "no MPU-401 device at 0x%lx\n", mpu_port[dev]);
285         }
286
287         if (fm_port[dev] > 0 && fm_port[dev] != SNDRV_AUTO_PORT) {
288                 if (snd_opl3_create(card,
289                                     fm_port[dev], fm_port[dev] + 2,
290                                     OPL3_HW_AUTO, 0, &opl3) < 0) {
291                         snd_printk(KERN_ERR PFX "no OPL device at 0x%lx-0x%lx\n",
292                                    fm_port[dev], fm_port[dev] + 2);
293                 } else {
294                         if ((error = snd_opl3_timer_new(opl3, 1, 2)) < 0) {
295                                 snd_card_free(card);
296                                 return error;
297                         }
298                         if ((error = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) {
299                                 snd_card_free(card);
300                                 return error;
301                         }
302                 }
303         }
304
305         if ((error = snd_card_register(card)) < 0) {
306                 snd_card_free(card);
307                 return error;
308         }
309         pnp_set_card_drvdata(pcard, card);
310         return 0;
311 }
312
313 static int __devinit snd_azt2320_pnp_detect(struct pnp_card_link *card,
314                                             const struct pnp_card_device_id *id)
315 {
316         static int dev;
317         int res;
318
319         for ( ; dev < SNDRV_CARDS; dev++) {
320                 if (!enable[dev])
321                         continue;
322                 res = snd_card_azt2320_probe(dev, card, id);
323                 if (res < 0)
324                         return res;
325                 dev++;
326                 return 0;
327         }
328         return -ENODEV;
329 }
330
331 static void __devexit snd_azt2320_pnp_remove(struct pnp_card_link * pcard)
332 {
333         snd_card_free(pnp_get_card_drvdata(pcard));
334         pnp_set_card_drvdata(pcard, NULL);
335 }
336
337 #ifdef CONFIG_PM
338 static int snd_azt2320_pnp_suspend(struct pnp_card_link *pcard, pm_message_t state)
339 {
340         struct snd_card *card = pnp_get_card_drvdata(pcard);
341         struct snd_card_azt2320 *acard = card->private_data;
342         struct snd_cs4231 *chip = acard->chip;
343
344         snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
345         chip->suspend(chip);
346         return 0;
347 }
348
349 static int snd_azt2320_pnp_resume(struct pnp_card_link *pcard)
350 {
351         struct snd_card *card = pnp_get_card_drvdata(pcard);
352         struct snd_card_azt2320 *acard = card->private_data;
353         struct snd_cs4231 *chip = acard->chip;
354
355         chip->resume(chip);
356         snd_power_change_state(card, SNDRV_CTL_POWER_D0);
357         return 0;
358 }
359 #endif
360
361 static struct pnp_card_driver azt2320_pnpc_driver = {
362         .flags          = PNP_DRIVER_RES_DISABLE,
363         .name           = "azt2320",
364         .id_table       = snd_azt2320_pnpids,
365         .probe          = snd_azt2320_pnp_detect,
366         .remove         = __devexit_p(snd_azt2320_pnp_remove),
367 #ifdef CONFIG_PM
368         .suspend        = snd_azt2320_pnp_suspend,
369         .resume         = snd_azt2320_pnp_resume,
370 #endif
371 };
372
373 static int __init alsa_card_azt2320_init(void)
374 {
375         int cards;
376
377         cards = pnp_register_card_driver(&azt2320_pnpc_driver);
378         if (cards <= 0) {
379                 pnp_unregister_card_driver(&azt2320_pnpc_driver);
380 #ifdef MODULE
381                 snd_printk(KERN_ERR "no AZT2320 based soundcards found\n");
382 #endif
383                 return -ENODEV;
384         }
385         return 0;
386 }
387
388 static void __exit alsa_card_azt2320_exit(void)
389 {
390         pnp_unregister_card_driver(&azt2320_pnpc_driver);
391 }
392
393 module_init(alsa_card_azt2320_init)
394 module_exit(alsa_card_azt2320_exit)