1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Generic driver for CS4231 chips 4 * Copyright (c) by Jaroslav Kysela <perex@perex.cz> 5 * Originally the CS4232/CS4232A driver, modified for use on CS4231 by 6 * Tugrul Galatali <galatalt@stuy.edu> 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/mpu401.h> 18 #include <sound/initval.h> 19 20 #define CRD_NAME "Generic CS4231" 21 #define DEV_NAME "cs4231" 22 23 MODULE_DESCRIPTION(CRD_NAME); 24 MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); 25 MODULE_LICENSE("GPL"); 26 27 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ 28 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ 29 static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */ 30 static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */ 31 static long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */ 32 static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* 5,7,9,11,12,15 */ 33 static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* 9,11,12,15 */ 34 static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 0,1,3,5,6,7 */ 35 static int dma2[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 0,1,3,5,6,7 */ 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(mpu_port, long, ioport, NULL, 0444); 46 MODULE_PARM_DESC(mpu_port, "MPU-401 port # for " CRD_NAME " driver."); 47 module_param_hw_array(irq, int, irq, NULL, 0444); 48 MODULE_PARM_DESC(irq, "IRQ # for " CRD_NAME " driver."); 49 module_param_hw_array(mpu_irq, int, irq, NULL, 0444); 50 MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for " CRD_NAME " driver."); 51 module_param_hw_array(dma1, int, dma, NULL, 0444); 52 MODULE_PARM_DESC(dma1, "DMA1 # for " CRD_NAME " driver."); 53 module_param_hw_array(dma2, int, dma, NULL, 0444); 54 MODULE_PARM_DESC(dma2, "DMA2 # for " CRD_NAME " driver."); 55 56 static int snd_cs4231_match(struct device *dev, unsigned int n) 57 { 58 if (!enable[n]) 59 return 0; 60 61 if (port[n] == SNDRV_AUTO_PORT) { 62 dev_err(dev, "please specify port\n"); 63 return 0; 64 } 65 if (irq[n] == SNDRV_AUTO_IRQ) { 66 dev_err(dev, "please specify irq\n"); 67 return 0; 68 } 69 if (dma1[n] == SNDRV_AUTO_DMA) { 70 dev_err(dev, "please specify dma1\n"); 71 return 0; 72 } 73 return 1; 74 } 75 76 static int snd_cs4231_probe(struct device *dev, unsigned int n) 77 { 78 struct snd_card *card; 79 struct snd_wss *chip; 80 int error; 81 82 error = snd_card_new(dev, index[n], id[n], THIS_MODULE, 0, &card); 83 if (error < 0) 84 return error; 85 86 error = snd_wss_create(card, port[n], -1, irq[n], dma1[n], dma2[n], 87 WSS_HW_DETECT, 0, &chip); 88 if (error < 0) 89 goto out; 90 91 card->private_data = chip; 92 93 error = snd_wss_pcm(chip, 0); 94 if (error < 0) 95 goto out; 96 97 strscpy(card->driver, "CS4231", sizeof(card->driver)); 98 strscpy(card->shortname, chip->pcm->name, sizeof(card->shortname)); 99 100 if (dma2[n] < 0) 101 snprintf(card->longname, sizeof(card->longname), 102 "%s at 0x%lx, irq %d, dma %d", 103 chip->pcm->name, chip->port, irq[n], dma1[n]); 104 else 105 snprintf(card->longname, sizeof(card->longname), 106 "%s at 0x%lx, irq %d, dma %d&%d", 107 chip->pcm->name, chip->port, irq[n], dma1[n], dma2[n]); 108 109 error = snd_wss_mixer(chip); 110 if (error < 0) 111 goto out; 112 113 error = snd_wss_timer(chip, 0); 114 if (error < 0) 115 goto out; 116 117 if (mpu_port[n] > 0 && mpu_port[n] != SNDRV_AUTO_PORT) { 118 if (mpu_irq[n] == SNDRV_AUTO_IRQ) 119 mpu_irq[n] = -1; 120 if (snd_mpu401_uart_new(card, 0, MPU401_HW_CS4232, 121 mpu_port[n], 0, mpu_irq[n], 122 NULL) < 0) 123 dev_warn(dev, "MPU401 not detected\n"); 124 } 125 126 error = snd_card_register(card); 127 if (error < 0) 128 goto out; 129 130 dev_set_drvdata(dev, card); 131 return 0; 132 133 out: snd_card_free(card); 134 return error; 135 } 136 137 static void snd_cs4231_remove(struct device *dev, unsigned int n) 138 { 139 snd_card_free(dev_get_drvdata(dev)); 140 } 141 142 #ifdef CONFIG_PM 143 static int snd_cs4231_suspend(struct device *dev, unsigned int n, pm_message_t state) 144 { 145 struct snd_card *card = dev_get_drvdata(dev); 146 struct snd_wss *chip = card->private_data; 147 148 snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); 149 chip->suspend(chip); 150 return 0; 151 } 152 153 static int snd_cs4231_resume(struct device *dev, unsigned int n) 154 { 155 struct snd_card *card = dev_get_drvdata(dev); 156 struct snd_wss *chip = card->private_data; 157 158 chip->resume(chip); 159 snd_power_change_state(card, SNDRV_CTL_POWER_D0); 160 return 0; 161 } 162 #endif 163 164 static struct isa_driver snd_cs4231_driver = { 165 .match = snd_cs4231_match, 166 .probe = snd_cs4231_probe, 167 .remove = snd_cs4231_remove, 168 #ifdef CONFIG_PM 169 .suspend = snd_cs4231_suspend, 170 .resume = snd_cs4231_resume, 171 #endif 172 .driver = { 173 .name = DEV_NAME 174 } 175 }; 176 177 module_isa_driver(snd_cs4231_driver, SNDRV_CARDS); 178