18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci    card-azt2320.c - driver for Aztech Systems AZT2320 based soundcards.
48c2ecf20Sopenharmony_ci    Copyright (C) 1999-2000 by Massimo Piccioni <dafastidio@libero.it>
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci*/
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci/*
98c2ecf20Sopenharmony_ci    This driver should provide support for most Aztech AZT2320 based cards.
108c2ecf20Sopenharmony_ci    Several AZT2316 chips are also supported/tested, but autoprobe doesn't
118c2ecf20Sopenharmony_ci    work: all module option have to be set.
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci    No docs available for us at Aztech headquarters !!!   Unbelievable ...
148c2ecf20Sopenharmony_ci    No other help obtained.
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci    Thanks to Rainer Wiesner <rainer.wiesner@01019freenet.de> for the WSS
178c2ecf20Sopenharmony_ci    activation method (full-duplex audio!).
188c2ecf20Sopenharmony_ci*/
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci#include <linux/io.h>
218c2ecf20Sopenharmony_ci#include <linux/delay.h>
228c2ecf20Sopenharmony_ci#include <linux/init.h>
238c2ecf20Sopenharmony_ci#include <linux/time.h>
248c2ecf20Sopenharmony_ci#include <linux/wait.h>
258c2ecf20Sopenharmony_ci#include <linux/pnp.h>
268c2ecf20Sopenharmony_ci#include <linux/module.h>
278c2ecf20Sopenharmony_ci#include <sound/core.h>
288c2ecf20Sopenharmony_ci#include <sound/initval.h>
298c2ecf20Sopenharmony_ci#include <sound/wss.h>
308c2ecf20Sopenharmony_ci#include <sound/mpu401.h>
318c2ecf20Sopenharmony_ci#include <sound/opl3.h>
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci#define PFX "azt2320: "
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ciMODULE_AUTHOR("Massimo Piccioni <dafastidio@libero.it>");
368c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Aztech Systems AZT2320");
378c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
388c2ecf20Sopenharmony_ciMODULE_SUPPORTED_DEVICE("{{Aztech Systems,PRO16V},"
398c2ecf20Sopenharmony_ci		"{Aztech Systems,AZT2320},"
408c2ecf20Sopenharmony_ci		"{Aztech Systems,AZT3300},"
418c2ecf20Sopenharmony_ci		"{Aztech Systems,AZT2320},"
428c2ecf20Sopenharmony_ci		"{Aztech Systems,AZT3000}}");
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_cistatic int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-MAX */
458c2ecf20Sopenharmony_cistatic char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */
468c2ecf20Sopenharmony_cistatic bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_ISAPNP; /* Enable this card */
478c2ecf20Sopenharmony_cistatic long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;	/* PnP setup */
488c2ecf20Sopenharmony_cistatic long wss_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;	/* PnP setup */
498c2ecf20Sopenharmony_cistatic long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;	/* PnP setup */
508c2ecf20Sopenharmony_cistatic long fm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;	/* PnP setup */
518c2ecf20Sopenharmony_cistatic int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;	/* Pnp setup */
528c2ecf20Sopenharmony_cistatic int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;	/* Pnp setup */
538c2ecf20Sopenharmony_cistatic int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;	/* PnP setup */
548c2ecf20Sopenharmony_cistatic int dma2[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;	/* PnP setup */
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_cimodule_param_array(index, int, NULL, 0444);
578c2ecf20Sopenharmony_ciMODULE_PARM_DESC(index, "Index value for azt2320 based soundcard.");
588c2ecf20Sopenharmony_cimodule_param_array(id, charp, NULL, 0444);
598c2ecf20Sopenharmony_ciMODULE_PARM_DESC(id, "ID string for azt2320 based soundcard.");
608c2ecf20Sopenharmony_cimodule_param_array(enable, bool, NULL, 0444);
618c2ecf20Sopenharmony_ciMODULE_PARM_DESC(enable, "Enable azt2320 based soundcard.");
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_cistruct snd_card_azt2320 {
648c2ecf20Sopenharmony_ci	int dev_no;
658c2ecf20Sopenharmony_ci	struct pnp_dev *dev;
668c2ecf20Sopenharmony_ci	struct pnp_dev *devmpu;
678c2ecf20Sopenharmony_ci	struct snd_wss *chip;
688c2ecf20Sopenharmony_ci};
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_cistatic const struct pnp_card_device_id snd_azt2320_pnpids[] = {
718c2ecf20Sopenharmony_ci	/* PRO16V */
728c2ecf20Sopenharmony_ci	{ .id = "AZT1008", .devs = { { "AZT1008" }, { "AZT2001" }, } },
738c2ecf20Sopenharmony_ci	/* Aztech Sound Galaxy 16 */
748c2ecf20Sopenharmony_ci	{ .id = "AZT2320", .devs = { { "AZT0001" }, { "AZT0002" }, } },
758c2ecf20Sopenharmony_ci	/* Packard Bell Sound III 336 AM/SP */
768c2ecf20Sopenharmony_ci	{ .id = "AZT3000", .devs = { { "AZT1003" }, { "AZT2001" }, } },
778c2ecf20Sopenharmony_ci	/* AT3300 */
788c2ecf20Sopenharmony_ci	{ .id = "AZT3002", .devs = { { "AZT1004" }, { "AZT2001" }, } },
798c2ecf20Sopenharmony_ci	/* --- */
808c2ecf20Sopenharmony_ci	{ .id = "AZT3005", .devs = { { "AZT1003" }, { "AZT2001" }, } },
818c2ecf20Sopenharmony_ci	/* --- */
828c2ecf20Sopenharmony_ci	{ .id = "AZT3011", .devs = { { "AZT1003" }, { "AZT2001" }, } },
838c2ecf20Sopenharmony_ci	{ .id = "" }	/* end */
848c2ecf20Sopenharmony_ci};
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pnp_card, snd_azt2320_pnpids);
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci#define	DRIVER_NAME	"snd-card-azt2320"
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_cistatic int snd_card_azt2320_pnp(int dev, struct snd_card_azt2320 *acard,
918c2ecf20Sopenharmony_ci				struct pnp_card_link *card,
928c2ecf20Sopenharmony_ci				const struct pnp_card_device_id *id)
938c2ecf20Sopenharmony_ci{
948c2ecf20Sopenharmony_ci	struct pnp_dev *pdev;
958c2ecf20Sopenharmony_ci	int err;
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci	acard->dev = pnp_request_card_device(card, id->devs[0].id, NULL);
988c2ecf20Sopenharmony_ci	if (acard->dev == NULL)
998c2ecf20Sopenharmony_ci		return -ENODEV;
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	acard->devmpu = pnp_request_card_device(card, id->devs[1].id, NULL);
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	pdev = acard->dev;
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	err = pnp_activate_dev(pdev);
1068c2ecf20Sopenharmony_ci	if (err < 0) {
1078c2ecf20Sopenharmony_ci		snd_printk(KERN_ERR PFX "AUDIO pnp configure failure\n");
1088c2ecf20Sopenharmony_ci		return err;
1098c2ecf20Sopenharmony_ci	}
1108c2ecf20Sopenharmony_ci	port[dev] = pnp_port_start(pdev, 0);
1118c2ecf20Sopenharmony_ci	fm_port[dev] = pnp_port_start(pdev, 1);
1128c2ecf20Sopenharmony_ci	wss_port[dev] = pnp_port_start(pdev, 2);
1138c2ecf20Sopenharmony_ci	dma1[dev] = pnp_dma(pdev, 0);
1148c2ecf20Sopenharmony_ci	dma2[dev] = pnp_dma(pdev, 1);
1158c2ecf20Sopenharmony_ci	irq[dev] = pnp_irq(pdev, 0);
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	pdev = acard->devmpu;
1188c2ecf20Sopenharmony_ci	if (pdev != NULL) {
1198c2ecf20Sopenharmony_ci		err = pnp_activate_dev(pdev);
1208c2ecf20Sopenharmony_ci		if (err < 0)
1218c2ecf20Sopenharmony_ci			goto __mpu_error;
1228c2ecf20Sopenharmony_ci		mpu_port[dev] = pnp_port_start(pdev, 0);
1238c2ecf20Sopenharmony_ci		mpu_irq[dev] = pnp_irq(pdev, 0);
1248c2ecf20Sopenharmony_ci	} else {
1258c2ecf20Sopenharmony_ci	     __mpu_error:
1268c2ecf20Sopenharmony_ci	     	if (pdev) {
1278c2ecf20Sopenharmony_ci		     	pnp_release_card_device(pdev);
1288c2ecf20Sopenharmony_ci	     		snd_printk(KERN_ERR PFX "MPU401 pnp configure failure, skipping\n");
1298c2ecf20Sopenharmony_ci	     	}
1308c2ecf20Sopenharmony_ci	     	acard->devmpu = NULL;
1318c2ecf20Sopenharmony_ci	     	mpu_port[dev] = -1;
1328c2ecf20Sopenharmony_ci	}
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci	return 0;
1358c2ecf20Sopenharmony_ci}
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci/* same of snd_sbdsp_command by Jaroslav Kysela */
1388c2ecf20Sopenharmony_cistatic int snd_card_azt2320_command(unsigned long port, unsigned char val)
1398c2ecf20Sopenharmony_ci{
1408c2ecf20Sopenharmony_ci	int i;
1418c2ecf20Sopenharmony_ci	unsigned long limit;
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci	limit = jiffies + HZ / 10;
1448c2ecf20Sopenharmony_ci	for (i = 50000; i && time_after(limit, jiffies); i--)
1458c2ecf20Sopenharmony_ci		if (!(inb(port + 0x0c) & 0x80)) {
1468c2ecf20Sopenharmony_ci			outb(val, port + 0x0c);
1478c2ecf20Sopenharmony_ci			return 0;
1488c2ecf20Sopenharmony_ci		}
1498c2ecf20Sopenharmony_ci	return -EBUSY;
1508c2ecf20Sopenharmony_ci}
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_cistatic int snd_card_azt2320_enable_wss(unsigned long port)
1538c2ecf20Sopenharmony_ci{
1548c2ecf20Sopenharmony_ci	int error;
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci	if ((error = snd_card_azt2320_command(port, 0x09)))
1578c2ecf20Sopenharmony_ci		return error;
1588c2ecf20Sopenharmony_ci	if ((error = snd_card_azt2320_command(port, 0x00)))
1598c2ecf20Sopenharmony_ci		return error;
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	mdelay(5);
1628c2ecf20Sopenharmony_ci	return 0;
1638c2ecf20Sopenharmony_ci}
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_cistatic int snd_card_azt2320_probe(int dev,
1668c2ecf20Sopenharmony_ci				  struct pnp_card_link *pcard,
1678c2ecf20Sopenharmony_ci				  const struct pnp_card_device_id *pid)
1688c2ecf20Sopenharmony_ci{
1698c2ecf20Sopenharmony_ci	int error;
1708c2ecf20Sopenharmony_ci	struct snd_card *card;
1718c2ecf20Sopenharmony_ci	struct snd_card_azt2320 *acard;
1728c2ecf20Sopenharmony_ci	struct snd_wss *chip;
1738c2ecf20Sopenharmony_ci	struct snd_opl3 *opl3;
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	error = snd_card_new(&pcard->card->dev,
1768c2ecf20Sopenharmony_ci			     index[dev], id[dev], THIS_MODULE,
1778c2ecf20Sopenharmony_ci			     sizeof(struct snd_card_azt2320), &card);
1788c2ecf20Sopenharmony_ci	if (error < 0)
1798c2ecf20Sopenharmony_ci		return error;
1808c2ecf20Sopenharmony_ci	acard = card->private_data;
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	if ((error = snd_card_azt2320_pnp(dev, acard, pcard, pid))) {
1838c2ecf20Sopenharmony_ci		snd_card_free(card);
1848c2ecf20Sopenharmony_ci		return error;
1858c2ecf20Sopenharmony_ci	}
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci	if ((error = snd_card_azt2320_enable_wss(port[dev]))) {
1888c2ecf20Sopenharmony_ci		snd_card_free(card);
1898c2ecf20Sopenharmony_ci		return error;
1908c2ecf20Sopenharmony_ci	}
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	error = snd_wss_create(card, wss_port[dev], -1,
1938c2ecf20Sopenharmony_ci			       irq[dev],
1948c2ecf20Sopenharmony_ci			       dma1[dev], dma2[dev],
1958c2ecf20Sopenharmony_ci			       WSS_HW_DETECT, 0, &chip);
1968c2ecf20Sopenharmony_ci	if (error < 0) {
1978c2ecf20Sopenharmony_ci		snd_card_free(card);
1988c2ecf20Sopenharmony_ci		return error;
1998c2ecf20Sopenharmony_ci	}
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	strcpy(card->driver, "AZT2320");
2028c2ecf20Sopenharmony_ci	strcpy(card->shortname, "Aztech AZT2320");
2038c2ecf20Sopenharmony_ci	sprintf(card->longname, "%s, WSS at 0x%lx, irq %i, dma %i&%i",
2048c2ecf20Sopenharmony_ci		card->shortname, chip->port, irq[dev], dma1[dev], dma2[dev]);
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci	error = snd_wss_pcm(chip, 0);
2078c2ecf20Sopenharmony_ci	if (error < 0) {
2088c2ecf20Sopenharmony_ci		snd_card_free(card);
2098c2ecf20Sopenharmony_ci		return error;
2108c2ecf20Sopenharmony_ci	}
2118c2ecf20Sopenharmony_ci	error = snd_wss_mixer(chip);
2128c2ecf20Sopenharmony_ci	if (error < 0) {
2138c2ecf20Sopenharmony_ci		snd_card_free(card);
2148c2ecf20Sopenharmony_ci		return error;
2158c2ecf20Sopenharmony_ci	}
2168c2ecf20Sopenharmony_ci	error = snd_wss_timer(chip, 0);
2178c2ecf20Sopenharmony_ci	if (error < 0) {
2188c2ecf20Sopenharmony_ci		snd_card_free(card);
2198c2ecf20Sopenharmony_ci		return error;
2208c2ecf20Sopenharmony_ci	}
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci	if (mpu_port[dev] > 0 && mpu_port[dev] != SNDRV_AUTO_PORT) {
2238c2ecf20Sopenharmony_ci		if (snd_mpu401_uart_new(card, 0, MPU401_HW_AZT2320,
2248c2ecf20Sopenharmony_ci				mpu_port[dev], 0,
2258c2ecf20Sopenharmony_ci				mpu_irq[dev], NULL) < 0)
2268c2ecf20Sopenharmony_ci			snd_printk(KERN_ERR PFX "no MPU-401 device at 0x%lx\n", mpu_port[dev]);
2278c2ecf20Sopenharmony_ci	}
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci	if (fm_port[dev] > 0 && fm_port[dev] != SNDRV_AUTO_PORT) {
2308c2ecf20Sopenharmony_ci		if (snd_opl3_create(card,
2318c2ecf20Sopenharmony_ci				    fm_port[dev], fm_port[dev] + 2,
2328c2ecf20Sopenharmony_ci				    OPL3_HW_AUTO, 0, &opl3) < 0) {
2338c2ecf20Sopenharmony_ci			snd_printk(KERN_ERR PFX "no OPL device at 0x%lx-0x%lx\n",
2348c2ecf20Sopenharmony_ci				   fm_port[dev], fm_port[dev] + 2);
2358c2ecf20Sopenharmony_ci		} else {
2368c2ecf20Sopenharmony_ci			if ((error = snd_opl3_timer_new(opl3, 1, 2)) < 0) {
2378c2ecf20Sopenharmony_ci				snd_card_free(card);
2388c2ecf20Sopenharmony_ci				return error;
2398c2ecf20Sopenharmony_ci			}
2408c2ecf20Sopenharmony_ci			if ((error = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) {
2418c2ecf20Sopenharmony_ci				snd_card_free(card);
2428c2ecf20Sopenharmony_ci				return error;
2438c2ecf20Sopenharmony_ci			}
2448c2ecf20Sopenharmony_ci		}
2458c2ecf20Sopenharmony_ci	}
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	if ((error = snd_card_register(card)) < 0) {
2488c2ecf20Sopenharmony_ci		snd_card_free(card);
2498c2ecf20Sopenharmony_ci		return error;
2508c2ecf20Sopenharmony_ci	}
2518c2ecf20Sopenharmony_ci	pnp_set_card_drvdata(pcard, card);
2528c2ecf20Sopenharmony_ci	return 0;
2538c2ecf20Sopenharmony_ci}
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_cistatic unsigned int azt2320_devices;
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_cistatic int snd_azt2320_pnp_detect(struct pnp_card_link *card,
2588c2ecf20Sopenharmony_ci				  const struct pnp_card_device_id *id)
2598c2ecf20Sopenharmony_ci{
2608c2ecf20Sopenharmony_ci	static int dev;
2618c2ecf20Sopenharmony_ci	int res;
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	for ( ; dev < SNDRV_CARDS; dev++) {
2648c2ecf20Sopenharmony_ci		if (!enable[dev])
2658c2ecf20Sopenharmony_ci			continue;
2668c2ecf20Sopenharmony_ci		res = snd_card_azt2320_probe(dev, card, id);
2678c2ecf20Sopenharmony_ci		if (res < 0)
2688c2ecf20Sopenharmony_ci			return res;
2698c2ecf20Sopenharmony_ci		dev++;
2708c2ecf20Sopenharmony_ci		azt2320_devices++;
2718c2ecf20Sopenharmony_ci		return 0;
2728c2ecf20Sopenharmony_ci	}
2738c2ecf20Sopenharmony_ci        return -ENODEV;
2748c2ecf20Sopenharmony_ci}
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_cistatic void snd_azt2320_pnp_remove(struct pnp_card_link *pcard)
2778c2ecf20Sopenharmony_ci{
2788c2ecf20Sopenharmony_ci	snd_card_free(pnp_get_card_drvdata(pcard));
2798c2ecf20Sopenharmony_ci	pnp_set_card_drvdata(pcard, NULL);
2808c2ecf20Sopenharmony_ci}
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci#ifdef CONFIG_PM
2838c2ecf20Sopenharmony_cistatic int snd_azt2320_pnp_suspend(struct pnp_card_link *pcard, pm_message_t state)
2848c2ecf20Sopenharmony_ci{
2858c2ecf20Sopenharmony_ci	struct snd_card *card = pnp_get_card_drvdata(pcard);
2868c2ecf20Sopenharmony_ci	struct snd_card_azt2320 *acard = card->private_data;
2878c2ecf20Sopenharmony_ci	struct snd_wss *chip = acard->chip;
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
2908c2ecf20Sopenharmony_ci	chip->suspend(chip);
2918c2ecf20Sopenharmony_ci	return 0;
2928c2ecf20Sopenharmony_ci}
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_cistatic int snd_azt2320_pnp_resume(struct pnp_card_link *pcard)
2958c2ecf20Sopenharmony_ci{
2968c2ecf20Sopenharmony_ci	struct snd_card *card = pnp_get_card_drvdata(pcard);
2978c2ecf20Sopenharmony_ci	struct snd_card_azt2320 *acard = card->private_data;
2988c2ecf20Sopenharmony_ci	struct snd_wss *chip = acard->chip;
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci	chip->resume(chip);
3018c2ecf20Sopenharmony_ci	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
3028c2ecf20Sopenharmony_ci	return 0;
3038c2ecf20Sopenharmony_ci}
3048c2ecf20Sopenharmony_ci#endif
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_cistatic struct pnp_card_driver azt2320_pnpc_driver = {
3078c2ecf20Sopenharmony_ci	.flags          = PNP_DRIVER_RES_DISABLE,
3088c2ecf20Sopenharmony_ci	.name           = "azt2320",
3098c2ecf20Sopenharmony_ci	.id_table       = snd_azt2320_pnpids,
3108c2ecf20Sopenharmony_ci	.probe          = snd_azt2320_pnp_detect,
3118c2ecf20Sopenharmony_ci	.remove         = snd_azt2320_pnp_remove,
3128c2ecf20Sopenharmony_ci#ifdef CONFIG_PM
3138c2ecf20Sopenharmony_ci	.suspend	= snd_azt2320_pnp_suspend,
3148c2ecf20Sopenharmony_ci	.resume		= snd_azt2320_pnp_resume,
3158c2ecf20Sopenharmony_ci#endif
3168c2ecf20Sopenharmony_ci};
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_cistatic int __init alsa_card_azt2320_init(void)
3198c2ecf20Sopenharmony_ci{
3208c2ecf20Sopenharmony_ci	int err;
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	err = pnp_register_card_driver(&azt2320_pnpc_driver);
3238c2ecf20Sopenharmony_ci	if (err)
3248c2ecf20Sopenharmony_ci		return err;
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	if (!azt2320_devices) {
3278c2ecf20Sopenharmony_ci		pnp_unregister_card_driver(&azt2320_pnpc_driver);
3288c2ecf20Sopenharmony_ci#ifdef MODULE
3298c2ecf20Sopenharmony_ci		snd_printk(KERN_ERR "no AZT2320 based soundcards found\n");
3308c2ecf20Sopenharmony_ci#endif
3318c2ecf20Sopenharmony_ci		return -ENODEV;
3328c2ecf20Sopenharmony_ci	}
3338c2ecf20Sopenharmony_ci	return 0;
3348c2ecf20Sopenharmony_ci}
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_cistatic void __exit alsa_card_azt2320_exit(void)
3378c2ecf20Sopenharmony_ci{
3388c2ecf20Sopenharmony_ci	pnp_unregister_card_driver(&azt2320_pnpc_driver);
3398c2ecf20Sopenharmony_ci}
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_cimodule_init(alsa_card_azt2320_init)
3428c2ecf20Sopenharmony_cimodule_exit(alsa_card_azt2320_exit)
343