Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Driver for audio on multifunction CS5535/6 companion device
0004  * Copyright (C) Jaya Kumar
0005  *
0006  * Based on Jaroslav Kysela and Takashi Iwai's examples.
0007  * This work was sponsored by CIS(M) Sdn Bhd.
0008  */
0009 
0010 #include <linux/delay.h>
0011 #include <linux/interrupt.h>
0012 #include <linux/init.h>
0013 #include <linux/pci.h>
0014 #include <linux/slab.h>
0015 #include <linux/module.h>
0016 #include <linux/io.h>
0017 #include <sound/core.h>
0018 #include <sound/control.h>
0019 #include <sound/pcm.h>
0020 #include <sound/rawmidi.h>
0021 #include <sound/ac97_codec.h>
0022 #include <sound/initval.h>
0023 #include <sound/asoundef.h>
0024 #include "cs5535audio.h"
0025 
0026 #define DRIVER_NAME "cs5535audio"
0027 
0028 static char *ac97_quirk;
0029 module_param(ac97_quirk, charp, 0444);
0030 MODULE_PARM_DESC(ac97_quirk, "AC'97 board specific workarounds.");
0031 
0032 static const struct ac97_quirk ac97_quirks[] = {
0033 #if 0 /* Not yet confirmed if all 5536 boards are HP only */
0034     {
0035         .subvendor = PCI_VENDOR_ID_AMD, 
0036         .subdevice = PCI_DEVICE_ID_AMD_CS5536_AUDIO, 
0037         .name = "AMD RDK",     
0038         .type = AC97_TUNE_HP_ONLY
0039     },
0040 #endif
0041     {}
0042 };
0043 
0044 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
0045 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
0046 static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
0047 
0048 module_param_array(index, int, NULL, 0444);
0049 MODULE_PARM_DESC(index, "Index value for " DRIVER_NAME);
0050 module_param_array(id, charp, NULL, 0444);
0051 MODULE_PARM_DESC(id, "ID string for " DRIVER_NAME);
0052 module_param_array(enable, bool, NULL, 0444);
0053 MODULE_PARM_DESC(enable, "Enable " DRIVER_NAME);
0054 
0055 static const struct pci_device_id snd_cs5535audio_ids[] = {
0056     { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_AUDIO) },
0057     { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_AUDIO) },
0058     {}
0059 };
0060 
0061 MODULE_DEVICE_TABLE(pci, snd_cs5535audio_ids);
0062 
0063 static void wait_till_cmd_acked(struct cs5535audio *cs5535au, unsigned long timeout)
0064 {
0065     unsigned int tmp;
0066     do {
0067         tmp = cs_readl(cs5535au, ACC_CODEC_CNTL);
0068         if (!(tmp & CMD_NEW))
0069             break;
0070         udelay(1);
0071     } while (--timeout);
0072     if (!timeout)
0073         dev_err(cs5535au->card->dev,
0074             "Failure writing to cs5535 codec\n");
0075 }
0076 
0077 static unsigned short snd_cs5535audio_codec_read(struct cs5535audio *cs5535au,
0078                          unsigned short reg)
0079 {
0080     unsigned int regdata;
0081     unsigned int timeout;
0082     unsigned int val;
0083 
0084     regdata = ((unsigned int) reg) << 24;
0085     regdata |= ACC_CODEC_CNTL_RD_CMD;
0086     regdata |= CMD_NEW;
0087 
0088     cs_writel(cs5535au, ACC_CODEC_CNTL, regdata);
0089     wait_till_cmd_acked(cs5535au, 50);
0090 
0091     timeout = 50;
0092     do {
0093         val = cs_readl(cs5535au, ACC_CODEC_STATUS);
0094         if ((val & STS_NEW) && reg == (val >> 24))
0095             break;
0096         udelay(1);
0097     } while (--timeout);
0098     if (!timeout)
0099         dev_err(cs5535au->card->dev,
0100             "Failure reading codec reg 0x%x, Last value=0x%x\n",
0101             reg, val);
0102 
0103     return (unsigned short) val;
0104 }
0105 
0106 static void snd_cs5535audio_codec_write(struct cs5535audio *cs5535au,
0107                     unsigned short reg, unsigned short val)
0108 {
0109     unsigned int regdata;
0110 
0111     regdata = ((unsigned int) reg) << 24;
0112     regdata |= val;
0113     regdata &= CMD_MASK;
0114     regdata |= CMD_NEW;
0115     regdata &= ACC_CODEC_CNTL_WR_CMD;
0116 
0117     cs_writel(cs5535au, ACC_CODEC_CNTL, regdata);
0118     wait_till_cmd_acked(cs5535au, 50);
0119 }
0120 
0121 static void snd_cs5535audio_ac97_codec_write(struct snd_ac97 *ac97,
0122                          unsigned short reg, unsigned short val)
0123 {
0124     struct cs5535audio *cs5535au = ac97->private_data;
0125     snd_cs5535audio_codec_write(cs5535au, reg, val);
0126 }
0127 
0128 static unsigned short snd_cs5535audio_ac97_codec_read(struct snd_ac97 *ac97,
0129                               unsigned short reg)
0130 {
0131     struct cs5535audio *cs5535au = ac97->private_data;
0132     return snd_cs5535audio_codec_read(cs5535au, reg);
0133 }
0134 
0135 static int snd_cs5535audio_mixer(struct cs5535audio *cs5535au)
0136 {
0137     struct snd_card *card = cs5535au->card;
0138     struct snd_ac97_bus *pbus;
0139     struct snd_ac97_template ac97;
0140     int err;
0141     static const struct snd_ac97_bus_ops ops = {
0142         .write = snd_cs5535audio_ac97_codec_write,
0143         .read = snd_cs5535audio_ac97_codec_read,
0144     };
0145 
0146     err = snd_ac97_bus(card, 0, &ops, NULL, &pbus);
0147     if (err < 0)
0148         return err;
0149 
0150     memset(&ac97, 0, sizeof(ac97));
0151     ac97.scaps = AC97_SCAP_AUDIO | AC97_SCAP_SKIP_MODEM
0152             | AC97_SCAP_POWER_SAVE;
0153     ac97.private_data = cs5535au;
0154     ac97.pci = cs5535au->pci;
0155 
0156     /* set any OLPC-specific scaps */
0157     olpc_prequirks(card, &ac97);
0158 
0159     err = snd_ac97_mixer(pbus, &ac97, &cs5535au->ac97);
0160     if (err < 0) {
0161         dev_err(card->dev, "mixer failed\n");
0162         return err;
0163     }
0164 
0165     snd_ac97_tune_hardware(cs5535au->ac97, ac97_quirks, ac97_quirk);
0166 
0167     err = olpc_quirks(card, cs5535au->ac97);
0168     if (err < 0) {
0169         dev_err(card->dev, "olpc quirks failed\n");
0170         return err;
0171     }
0172 
0173     return 0;
0174 }
0175 
0176 static void process_bm0_irq(struct cs5535audio *cs5535au)
0177 {
0178     u8 bm_stat;
0179     spin_lock(&cs5535au->reg_lock);
0180     bm_stat = cs_readb(cs5535au, ACC_BM0_STATUS);
0181     spin_unlock(&cs5535au->reg_lock);
0182     if (bm_stat & EOP) {
0183         snd_pcm_period_elapsed(cs5535au->playback_substream);
0184     } else {
0185         dev_err(cs5535au->card->dev,
0186             "unexpected bm0 irq src, bm_stat=%x\n",
0187             bm_stat);
0188     }
0189 }
0190 
0191 static void process_bm1_irq(struct cs5535audio *cs5535au)
0192 {
0193     u8 bm_stat;
0194     spin_lock(&cs5535au->reg_lock);
0195     bm_stat = cs_readb(cs5535au, ACC_BM1_STATUS);
0196     spin_unlock(&cs5535au->reg_lock);
0197     if (bm_stat & EOP)
0198         snd_pcm_period_elapsed(cs5535au->capture_substream);
0199 }
0200 
0201 static irqreturn_t snd_cs5535audio_interrupt(int irq, void *dev_id)
0202 {
0203     u16 acc_irq_stat;
0204     unsigned char count;
0205     struct cs5535audio *cs5535au = dev_id;
0206 
0207     if (cs5535au == NULL)
0208         return IRQ_NONE;
0209 
0210     acc_irq_stat = cs_readw(cs5535au, ACC_IRQ_STATUS);
0211 
0212     if (!acc_irq_stat)
0213         return IRQ_NONE;
0214     for (count = 0; count < 4; count++) {
0215         if (acc_irq_stat & (1 << count)) {
0216             switch (count) {
0217             case IRQ_STS:
0218                 cs_readl(cs5535au, ACC_GPIO_STATUS);
0219                 break;
0220             case WU_IRQ_STS:
0221                 cs_readl(cs5535au, ACC_GPIO_STATUS);
0222                 break;
0223             case BM0_IRQ_STS:
0224                 process_bm0_irq(cs5535au);
0225                 break;
0226             case BM1_IRQ_STS:
0227                 process_bm1_irq(cs5535au);
0228                 break;
0229             default:
0230                 dev_err(cs5535au->card->dev,
0231                     "Unexpected irq src: 0x%x\n",
0232                     acc_irq_stat);
0233                 break;
0234             }
0235         }
0236     }
0237     return IRQ_HANDLED;
0238 }
0239 
0240 static void snd_cs5535audio_free(struct snd_card *card)
0241 {
0242     olpc_quirks_cleanup();
0243 }
0244 
0245 static int snd_cs5535audio_create(struct snd_card *card,
0246                   struct pci_dev *pci)
0247 {
0248     struct cs5535audio *cs5535au = card->private_data;
0249     int err;
0250 
0251     err = pcim_enable_device(pci);
0252     if (err < 0)
0253         return err;
0254 
0255     if (dma_set_mask_and_coherent(&pci->dev, DMA_BIT_MASK(32))) {
0256         dev_warn(card->dev, "unable to get 32bit dma\n");
0257         return -ENXIO;
0258     }
0259 
0260     spin_lock_init(&cs5535au->reg_lock);
0261     cs5535au->card = card;
0262     cs5535au->pci = pci;
0263     cs5535au->irq = -1;
0264 
0265     err = pci_request_regions(pci, "CS5535 Audio");
0266     if (err < 0)
0267         return err;
0268 
0269     cs5535au->port = pci_resource_start(pci, 0);
0270 
0271     if (devm_request_irq(&pci->dev, pci->irq, snd_cs5535audio_interrupt,
0272                  IRQF_SHARED, KBUILD_MODNAME, cs5535au)) {
0273         dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq);
0274         return -EBUSY;
0275     }
0276 
0277     cs5535au->irq = pci->irq;
0278     card->sync_irq = cs5535au->irq;
0279     pci_set_master(pci);
0280 
0281     return 0;
0282 }
0283 
0284 static int __snd_cs5535audio_probe(struct pci_dev *pci,
0285                    const struct pci_device_id *pci_id)
0286 {
0287     static int dev;
0288     struct snd_card *card;
0289     struct cs5535audio *cs5535au;
0290     int err;
0291 
0292     if (dev >= SNDRV_CARDS)
0293         return -ENODEV;
0294     if (!enable[dev]) {
0295         dev++;
0296         return -ENOENT;
0297     }
0298 
0299     err = snd_devm_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
0300                 sizeof(*cs5535au), &card);
0301     if (err < 0)
0302         return err;
0303     cs5535au = card->private_data;
0304     card->private_free = snd_cs5535audio_free;
0305 
0306     err = snd_cs5535audio_create(card, pci);
0307     if (err < 0)
0308         return err;
0309 
0310     err = snd_cs5535audio_mixer(cs5535au);
0311     if (err < 0)
0312         return err;
0313 
0314     err = snd_cs5535audio_pcm(cs5535au);
0315     if (err < 0)
0316         return err;
0317 
0318     strcpy(card->driver, DRIVER_NAME);
0319 
0320     strcpy(card->shortname, "CS5535 Audio");
0321     sprintf(card->longname, "%s %s at 0x%lx, irq %i",
0322         card->shortname, card->driver,
0323         cs5535au->port, cs5535au->irq);
0324 
0325     err = snd_card_register(card);
0326     if (err < 0)
0327         return err;
0328 
0329     pci_set_drvdata(pci, card);
0330     dev++;
0331     return 0;
0332 }
0333 
0334 static int snd_cs5535audio_probe(struct pci_dev *pci,
0335                  const struct pci_device_id *pci_id)
0336 {
0337     return snd_card_free_on_error(&pci->dev, __snd_cs5535audio_probe(pci, pci_id));
0338 }
0339 
0340 static struct pci_driver cs5535audio_driver = {
0341     .name = KBUILD_MODNAME,
0342     .id_table = snd_cs5535audio_ids,
0343     .probe = snd_cs5535audio_probe,
0344 #ifdef CONFIG_PM_SLEEP
0345     .driver = {
0346         .pm = &snd_cs5535audio_pm,
0347     },
0348 #endif
0349 };
0350 
0351 module_pci_driver(cs5535audio_driver);
0352 
0353 MODULE_AUTHOR("Jaya Kumar");
0354 MODULE_LICENSE("GPL");
0355 MODULE_DESCRIPTION("CS5535 Audio");