1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Generic driver for AD1848/AD1847/CS4248 chips (0.1 Alpha) 4 * Copyright (c) by Tugrul Galatali <galatalt@stuy.edu>, 5 * Jaroslav Kysela <perex@perex.cz> 6 * Based on card-4232.c by Jaroslav Kysela <perex@perex.cz> 7 */ 8 9 #include <linux/init.h> 10 #include <linux/err.h> 11 #include <linux/isa.h> 12 #include <linux/time.h> 13 #include <linux/wait.h> 14 #include <linux/module.h> 15 #include <sound/core.h> 16 #include <sound/wss.h> 17 #include <sound/initval.h> 18 19 #define CRD_NAME "Generic AD1848/AD1847/CS4248" 20 #define DEV_NAME "ad1848" 21 22 MODULE_DESCRIPTION(CRD_NAME); 23 MODULE_AUTHOR("Tugrul Galatali <galatalt@stuy.edu>, Jaroslav Kysela <perex@perex.cz>"); 24 MODULE_LICENSE("GPL"); 25 MODULE_SUPPORTED_DEVICE("{{Analog Devices,AD1848}," 26 "{Analog Devices,AD1847}," 27 "{Crystal Semiconductors,CS4248}}"); 28 29 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ 30 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ 31 static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */ 32 static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */ 33 static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* 5,7,9,11,12,15 */ 34 static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 0,1,3,5,6,7 */ 35 static bool thinkpad[SNDRV_CARDS]; /* Thinkpad special case */ 36 37 module_param_array(index, int, NULL, 0444); 38 MODULE_PARM_DESC(index, "Index value for " CRD_NAME " soundcard."); 39 module_param_array(id, charp, NULL, 0444); 40 MODULE_PARM_DESC(id, "ID string for " CRD_NAME " soundcard."); 41 module_param_array(enable, bool, NULL, 0444); 42 MODULE_PARM_DESC(enable, "Enable " CRD_NAME " soundcard."); 43 module_param_hw_array(port, long, ioport, NULL, 0444); 44 MODULE_PARM_DESC(port, "Port # for " CRD_NAME " driver."); 45 module_param_hw_array(irq, int, irq, NULL, 0444); 46 MODULE_PARM_DESC(irq, "IRQ # for " CRD_NAME " driver."); 47 module_param_hw_array(dma1, int, dma, NULL, 0444); 48 MODULE_PARM_DESC(dma1, "DMA1 # for " CRD_NAME " driver."); 49 module_param_array(thinkpad, bool, NULL, 0444); 50 MODULE_PARM_DESC(thinkpad, "Enable only for the onboard CS4248 of IBM Thinkpad 360/750/755 series."); 51 52 static int snd_ad1848_match(struct device *dev, unsigned int n) 53 { 54 if (!enable[n]) 55 return 0; 56 57 if (port[n] == SNDRV_AUTO_PORT) { 58 dev_err(dev, "please specify port\n"); 59 return 0; 60 } 61 if (irq[n] == SNDRV_AUTO_IRQ) { 62 dev_err(dev, "please specify irq\n"); 63 return 0; 64 } 65 if (dma1[n] == SNDRV_AUTO_DMA) { 66 dev_err(dev, "please specify dma1\n"); 67 return 0; 68 } 69 return 1; 70 } 71 72 static int snd_ad1848_probe(struct device *dev, unsigned int n) 73 { 74 struct snd_card *card; 75 struct snd_wss *chip; 76 int error; 77 78 error = snd_card_new(dev, index[n], id[n], THIS_MODULE, 0, &card); 79 if (error < 0) 80 return error; 81 82 error = snd_wss_create(card, port[n], -1, irq[n], dma1[n], -1, 83 thinkpad[n] ? WSS_HW_THINKPAD : WSS_HW_DETECT, 84 0, &chip); 85 if (error < 0) 86 goto out; 87 88 card->private_data = chip; 89 90 error = snd_wss_pcm(chip, 0); 91 if (error < 0) 92 goto out; 93 94 error = snd_wss_mixer(chip); 95 if (error < 0) 96 goto out; 97 98 strscpy(card->driver, "AD1848", sizeof(card->driver)); 99 strscpy(card->shortname, chip->pcm->name, sizeof(card->shortname)); 100 101 if (!thinkpad[n]) 102 snprintf(card->longname, sizeof(card->longname), 103 "%s at 0x%lx, irq %d, dma %d", 104 chip->pcm->name, chip->port, irq[n], dma1[n]); 105 else 106 snprintf(card->longname, sizeof(card->longname), 107 "%s at 0x%lx, irq %d, dma %d [Thinkpad]", 108 chip->pcm->name, chip->port, irq[n], dma1[n]); 109 110 error = snd_card_register(card); 111 if (error < 0) 112 goto out; 113 114 dev_set_drvdata(dev, card); 115 return 0; 116 117 out: snd_card_free(card); 118 return error; 119 } 120 121 static void snd_ad1848_remove(struct device *dev, unsigned int n) 122 { 123 snd_card_free(dev_get_drvdata(dev)); 124 } 125 126 #ifdef CONFIG_PM 127 static int snd_ad1848_suspend(struct device *dev, unsigned int n, pm_message_t state) 128 { 129 struct snd_card *card = dev_get_drvdata(dev); 130 struct snd_wss *chip = card->private_data; 131 132 snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); 133 chip->suspend(chip); 134 return 0; 135 } 136 137 static int snd_ad1848_resume(struct device *dev, unsigned int n) 138 { 139 struct snd_card *card = dev_get_drvdata(dev); 140 struct snd_wss *chip = card->private_data; 141 142 chip->resume(chip); 143 snd_power_change_state(card, SNDRV_CTL_POWER_D0); 144 return 0; 145 } 146 #endif 147 148 static struct isa_driver snd_ad1848_driver = { 149 .match = snd_ad1848_match, 150 .probe = snd_ad1848_probe, 151 .remove = snd_ad1848_remove, 152 #ifdef CONFIG_PM 153 .suspend = snd_ad1848_suspend, 154 .resume = snd_ad1848_resume, 155 #endif 156 .driver = { 157 .name = DEV_NAME 158 } 159 }; 160 161 module_isa_driver(snd_ad1848_driver, SNDRV_CARDS); 162