cs4231.c (4919B)
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 23MODULE_DESCRIPTION(CRD_NAME); 24MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); 25MODULE_LICENSE("GPL"); 26 27static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ 28static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ 29static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */ 30static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */ 31static long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */ 32static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* 5,7,9,11,12,15 */ 33static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* 9,11,12,15 */ 34static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 0,1,3,5,6,7 */ 35static int dma2[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 0,1,3,5,6,7 */ 36 37module_param_array(index, int, NULL, 0444); 38MODULE_PARM_DESC(index, "Index value for " CRD_NAME " soundcard."); 39module_param_array(id, charp, NULL, 0444); 40MODULE_PARM_DESC(id, "ID string for " CRD_NAME " soundcard."); 41module_param_array(enable, bool, NULL, 0444); 42MODULE_PARM_DESC(enable, "Enable " CRD_NAME " soundcard."); 43module_param_hw_array(port, long, ioport, NULL, 0444); 44MODULE_PARM_DESC(port, "Port # for " CRD_NAME " driver."); 45module_param_hw_array(mpu_port, long, ioport, NULL, 0444); 46MODULE_PARM_DESC(mpu_port, "MPU-401 port # for " CRD_NAME " driver."); 47module_param_hw_array(irq, int, irq, NULL, 0444); 48MODULE_PARM_DESC(irq, "IRQ # for " CRD_NAME " driver."); 49module_param_hw_array(mpu_irq, int, irq, NULL, 0444); 50MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for " CRD_NAME " driver."); 51module_param_hw_array(dma1, int, dma, NULL, 0444); 52MODULE_PARM_DESC(dma1, "DMA1 # for " CRD_NAME " driver."); 53module_param_hw_array(dma2, int, dma, NULL, 0444); 54MODULE_PARM_DESC(dma2, "DMA2 # for " CRD_NAME " driver."); 55 56static 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 76static 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_devm_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 return error; 90 91 card->private_data = chip; 92 93 error = snd_wss_pcm(chip, 0); 94 if (error < 0) 95 return error; 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 return error; 112 113 error = snd_wss_timer(chip, 0); 114 if (error < 0) 115 return error; 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 return error; 129 130 dev_set_drvdata(dev, card); 131 return 0; 132} 133 134#ifdef CONFIG_PM 135static int snd_cs4231_suspend(struct device *dev, unsigned int n, pm_message_t state) 136{ 137 struct snd_card *card = dev_get_drvdata(dev); 138 struct snd_wss *chip = card->private_data; 139 140 snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); 141 chip->suspend(chip); 142 return 0; 143} 144 145static int snd_cs4231_resume(struct device *dev, unsigned int n) 146{ 147 struct snd_card *card = dev_get_drvdata(dev); 148 struct snd_wss *chip = card->private_data; 149 150 chip->resume(chip); 151 snd_power_change_state(card, SNDRV_CTL_POWER_D0); 152 return 0; 153} 154#endif 155 156static struct isa_driver snd_cs4231_driver = { 157 .match = snd_cs4231_match, 158 .probe = snd_cs4231_probe, 159#ifdef CONFIG_PM 160 .suspend = snd_cs4231_suspend, 161 .resume = snd_cs4231_resume, 162#endif 163 .driver = { 164 .name = DEV_NAME 165 } 166}; 167 168module_isa_driver(snd_cs4231_driver, SNDRV_CARDS);