1b285192aSMauro Carvalho Chehab /* 2b285192aSMauro Carvalho Chehab * Driver for the Conexant CX25821 PCIe bridge 3b285192aSMauro Carvalho Chehab * 4b285192aSMauro Carvalho Chehab * Copyright (C) 2009 Conexant Systems Inc. 5b285192aSMauro Carvalho Chehab * Authors <shu.lin@conexant.com>, <hiep.huynh@conexant.com> 6b285192aSMauro Carvalho Chehab * Based on SAA713x ALSA driver and CX88 driver 7b285192aSMauro Carvalho Chehab * 8b285192aSMauro Carvalho Chehab * This program is free software; you can redistribute it and/or modify 9b285192aSMauro Carvalho Chehab * it under the terms of the GNU General Public License as published by 10b285192aSMauro Carvalho Chehab * the Free Software Foundation, version 2 11b285192aSMauro Carvalho Chehab * 12b285192aSMauro Carvalho Chehab * This program is distributed in the hope that it will be useful, 13b285192aSMauro Carvalho Chehab * but WITHOUT ANY WARRANTY; without even the implied warranty of 14b285192aSMauro Carvalho Chehab * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15b285192aSMauro Carvalho Chehab * GNU General Public License for more details. 16b285192aSMauro Carvalho Chehab * 17b285192aSMauro Carvalho Chehab * You should have received a copy of the GNU General Public License 18b285192aSMauro Carvalho Chehab * along with this program; if not, write to the Free Software 19b285192aSMauro Carvalho Chehab * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20b285192aSMauro Carvalho Chehab * 21b285192aSMauro Carvalho Chehab */ 22b285192aSMauro Carvalho Chehab 23b285192aSMauro Carvalho Chehab #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 24b285192aSMauro Carvalho Chehab 25b285192aSMauro Carvalho Chehab #include <linux/module.h> 26b285192aSMauro Carvalho Chehab #include <linux/init.h> 27b285192aSMauro Carvalho Chehab #include <linux/device.h> 28b285192aSMauro Carvalho Chehab #include <linux/interrupt.h> 29b285192aSMauro Carvalho Chehab #include <linux/vmalloc.h> 30b285192aSMauro Carvalho Chehab #include <linux/dma-mapping.h> 31b285192aSMauro Carvalho Chehab #include <linux/pci.h> 32b285192aSMauro Carvalho Chehab #include <linux/slab.h> 33b285192aSMauro Carvalho Chehab 34b285192aSMauro Carvalho Chehab #include <linux/delay.h> 35b285192aSMauro Carvalho Chehab #include <sound/core.h> 36b285192aSMauro Carvalho Chehab #include <sound/pcm.h> 37b285192aSMauro Carvalho Chehab #include <sound/pcm_params.h> 38b285192aSMauro Carvalho Chehab #include <sound/control.h> 39b285192aSMauro Carvalho Chehab #include <sound/initval.h> 40b285192aSMauro Carvalho Chehab #include <sound/tlv.h> 41b285192aSMauro Carvalho Chehab 42b285192aSMauro Carvalho Chehab #include "cx25821.h" 43b285192aSMauro Carvalho Chehab #include "cx25821-reg.h" 44b285192aSMauro Carvalho Chehab 45b285192aSMauro Carvalho Chehab #define AUDIO_SRAM_CHANNEL SRAM_CH08 46b285192aSMauro Carvalho Chehab 47b285192aSMauro Carvalho Chehab #define dprintk(level, fmt, arg...) \ 48b285192aSMauro Carvalho Chehab do { \ 49b285192aSMauro Carvalho Chehab if (debug >= level) \ 50b285192aSMauro Carvalho Chehab pr_info("%s/1: " fmt, chip->dev->name, ##arg); \ 51b285192aSMauro Carvalho Chehab } while (0) 52b285192aSMauro Carvalho Chehab #define dprintk_core(level, fmt, arg...) \ 53b285192aSMauro Carvalho Chehab do { \ 54b285192aSMauro Carvalho Chehab if (debug >= level) \ 55b285192aSMauro Carvalho Chehab printk(KERN_DEBUG "%s/1: " fmt, chip->dev->name, ##arg); \ 56b285192aSMauro Carvalho Chehab } while (0) 57b285192aSMauro Carvalho Chehab 58b285192aSMauro Carvalho Chehab /**************************************************************************** 59b285192aSMauro Carvalho Chehab Data type declarations - Can be moded to a header file later 60b285192aSMauro Carvalho Chehab ****************************************************************************/ 61b285192aSMauro Carvalho Chehab 62b285192aSMauro Carvalho Chehab static int devno; 63b285192aSMauro Carvalho Chehab 64b285192aSMauro Carvalho Chehab struct cx25821_audio_buffer { 65b285192aSMauro Carvalho Chehab unsigned int bpl; 66b285192aSMauro Carvalho Chehab struct btcx_riscmem risc; 67b285192aSMauro Carvalho Chehab struct videobuf_dmabuf dma; 68b285192aSMauro Carvalho Chehab }; 69b285192aSMauro Carvalho Chehab 70b285192aSMauro Carvalho Chehab struct cx25821_audio_dev { 71b285192aSMauro Carvalho Chehab struct cx25821_dev *dev; 72b285192aSMauro Carvalho Chehab struct cx25821_dmaqueue q; 73b285192aSMauro Carvalho Chehab 74b285192aSMauro Carvalho Chehab /* pci i/o */ 75b285192aSMauro Carvalho Chehab struct pci_dev *pci; 76b285192aSMauro Carvalho Chehab 77b285192aSMauro Carvalho Chehab /* audio controls */ 78b285192aSMauro Carvalho Chehab int irq; 79b285192aSMauro Carvalho Chehab 80b285192aSMauro Carvalho Chehab struct snd_card *card; 81b285192aSMauro Carvalho Chehab 82b285192aSMauro Carvalho Chehab unsigned long iobase; 83b285192aSMauro Carvalho Chehab spinlock_t reg_lock; 84b285192aSMauro Carvalho Chehab atomic_t count; 85b285192aSMauro Carvalho Chehab 86b285192aSMauro Carvalho Chehab unsigned int dma_size; 87b285192aSMauro Carvalho Chehab unsigned int period_size; 88b285192aSMauro Carvalho Chehab unsigned int num_periods; 89b285192aSMauro Carvalho Chehab 90b285192aSMauro Carvalho Chehab struct videobuf_dmabuf *dma_risc; 91b285192aSMauro Carvalho Chehab 92b285192aSMauro Carvalho Chehab struct cx25821_audio_buffer *buf; 93b285192aSMauro Carvalho Chehab 94b285192aSMauro Carvalho Chehab struct snd_pcm_substream *substream; 95b285192aSMauro Carvalho Chehab }; 96b285192aSMauro Carvalho Chehab 97b285192aSMauro Carvalho Chehab 98b285192aSMauro Carvalho Chehab /**************************************************************************** 99b285192aSMauro Carvalho Chehab Module global static vars 100b285192aSMauro Carvalho Chehab ****************************************************************************/ 101b285192aSMauro Carvalho Chehab 102b285192aSMauro Carvalho Chehab static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ 103b285192aSMauro Carvalho Chehab static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ 104b285192aSMauro Carvalho Chehab static bool enable[SNDRV_CARDS] = { 1, [1 ... (SNDRV_CARDS - 1)] = 1 }; 105b285192aSMauro Carvalho Chehab 106b285192aSMauro Carvalho Chehab module_param_array(enable, bool, NULL, 0444); 107b285192aSMauro Carvalho Chehab MODULE_PARM_DESC(enable, "Enable cx25821 soundcard. default enabled."); 108b285192aSMauro Carvalho Chehab 109b285192aSMauro Carvalho Chehab module_param_array(index, int, NULL, 0444); 110b285192aSMauro Carvalho Chehab MODULE_PARM_DESC(index, "Index value for cx25821 capture interface(s)."); 111b285192aSMauro Carvalho Chehab 112b285192aSMauro Carvalho Chehab /**************************************************************************** 113b285192aSMauro Carvalho Chehab Module macros 114b285192aSMauro Carvalho Chehab ****************************************************************************/ 115b285192aSMauro Carvalho Chehab 116b285192aSMauro Carvalho Chehab MODULE_DESCRIPTION("ALSA driver module for cx25821 based capture cards"); 117b285192aSMauro Carvalho Chehab MODULE_AUTHOR("Hiep Huynh"); 118b285192aSMauro Carvalho Chehab MODULE_LICENSE("GPL"); 119b285192aSMauro Carvalho Chehab MODULE_SUPPORTED_DEVICE("{{Conexant,25821}"); /* "{{Conexant,23881}," */ 120b285192aSMauro Carvalho Chehab 121b285192aSMauro Carvalho Chehab static unsigned int debug; 122b285192aSMauro Carvalho Chehab module_param(debug, int, 0644); 123b285192aSMauro Carvalho Chehab MODULE_PARM_DESC(debug, "enable debug messages"); 124b285192aSMauro Carvalho Chehab 125b285192aSMauro Carvalho Chehab /**************************************************************************** 126b285192aSMauro Carvalho Chehab Module specific funtions 127b285192aSMauro Carvalho Chehab ****************************************************************************/ 128b285192aSMauro Carvalho Chehab /* Constants taken from cx88-reg.h */ 129b285192aSMauro Carvalho Chehab #define AUD_INT_DN_RISCI1 (1 << 0) 130b285192aSMauro Carvalho Chehab #define AUD_INT_UP_RISCI1 (1 << 1) 131b285192aSMauro Carvalho Chehab #define AUD_INT_RDS_DN_RISCI1 (1 << 2) 132b285192aSMauro Carvalho Chehab #define AUD_INT_DN_RISCI2 (1 << 4) /* yes, 3 is skipped */ 133b285192aSMauro Carvalho Chehab #define AUD_INT_UP_RISCI2 (1 << 5) 134b285192aSMauro Carvalho Chehab #define AUD_INT_RDS_DN_RISCI2 (1 << 6) 135b285192aSMauro Carvalho Chehab #define AUD_INT_DN_SYNC (1 << 12) 136b285192aSMauro Carvalho Chehab #define AUD_INT_UP_SYNC (1 << 13) 137b285192aSMauro Carvalho Chehab #define AUD_INT_RDS_DN_SYNC (1 << 14) 138b285192aSMauro Carvalho Chehab #define AUD_INT_OPC_ERR (1 << 16) 139b285192aSMauro Carvalho Chehab #define AUD_INT_BER_IRQ (1 << 20) 140b285192aSMauro Carvalho Chehab #define AUD_INT_MCHG_IRQ (1 << 21) 141b285192aSMauro Carvalho Chehab #define GP_COUNT_CONTROL_RESET 0x3 142b285192aSMauro Carvalho Chehab 143b285192aSMauro Carvalho Chehab #define PCI_MSK_AUD_EXT (1 << 4) 144b285192aSMauro Carvalho Chehab #define PCI_MSK_AUD_INT (1 << 3) 145b285192aSMauro Carvalho Chehab /* 146b285192aSMauro Carvalho Chehab * BOARD Specific: Sets audio DMA 147b285192aSMauro Carvalho Chehab */ 148b285192aSMauro Carvalho Chehab 149b285192aSMauro Carvalho Chehab static int _cx25821_start_audio_dma(struct cx25821_audio_dev *chip) 150b285192aSMauro Carvalho Chehab { 151b285192aSMauro Carvalho Chehab struct cx25821_audio_buffer *buf = chip->buf; 152b285192aSMauro Carvalho Chehab struct cx25821_dev *dev = chip->dev; 153bfef0d35SHans Verkuil const struct sram_channel *audio_ch = 154b285192aSMauro Carvalho Chehab &cx25821_sram_channels[AUDIO_SRAM_CHANNEL]; 155b285192aSMauro Carvalho Chehab u32 tmp = 0; 156b285192aSMauro Carvalho Chehab 157b285192aSMauro Carvalho Chehab /* enable output on the GPIO 0 for the MCLK ADC (Audio) */ 158b285192aSMauro Carvalho Chehab cx25821_set_gpiopin_direction(chip->dev, 0, 0); 159b285192aSMauro Carvalho Chehab 160b285192aSMauro Carvalho Chehab /* Make sure RISC/FIFO are off before changing FIFO/RISC settings */ 161b285192aSMauro Carvalho Chehab cx_clear(AUD_INT_DMA_CTL, 162b285192aSMauro Carvalho Chehab FLD_AUD_DST_A_RISC_EN | FLD_AUD_DST_A_FIFO_EN); 163b285192aSMauro Carvalho Chehab 164b285192aSMauro Carvalho Chehab /* setup fifo + format - out channel */ 165b285192aSMauro Carvalho Chehab cx25821_sram_channel_setup_audio(chip->dev, audio_ch, buf->bpl, 166b285192aSMauro Carvalho Chehab buf->risc.dma); 167b285192aSMauro Carvalho Chehab 168b285192aSMauro Carvalho Chehab /* sets bpl size */ 169b285192aSMauro Carvalho Chehab cx_write(AUD_A_LNGTH, buf->bpl); 170b285192aSMauro Carvalho Chehab 171b285192aSMauro Carvalho Chehab /* reset counter */ 172b285192aSMauro Carvalho Chehab /* GP_COUNT_CONTROL_RESET = 0x3 */ 173b285192aSMauro Carvalho Chehab cx_write(AUD_A_GPCNT_CTL, GP_COUNT_CONTROL_RESET); 174b285192aSMauro Carvalho Chehab atomic_set(&chip->count, 0); 175b285192aSMauro Carvalho Chehab 176b285192aSMauro Carvalho Chehab /* Set the input mode to 16-bit */ 177b285192aSMauro Carvalho Chehab tmp = cx_read(AUD_A_CFG); 178b285192aSMauro Carvalho Chehab cx_write(AUD_A_CFG, tmp | FLD_AUD_DST_PK_MODE | FLD_AUD_DST_ENABLE | 179b285192aSMauro Carvalho Chehab FLD_AUD_CLK_ENABLE); 180b285192aSMauro Carvalho Chehab 181b285192aSMauro Carvalho Chehab /* 182b285192aSMauro Carvalho Chehab pr_info("DEBUG: Start audio DMA, %d B/line, cmds_start(0x%x)= %d lines/FIFO, %d periods, %d byte buffer\n", 183b285192aSMauro Carvalho Chehab buf->bpl, audio_ch->cmds_start, 184b285192aSMauro Carvalho Chehab cx_read(audio_ch->cmds_start + 12)>>1, 185b285192aSMauro Carvalho Chehab chip->num_periods, buf->bpl * chip->num_periods); 186b285192aSMauro Carvalho Chehab */ 187b285192aSMauro Carvalho Chehab 188b285192aSMauro Carvalho Chehab /* Enables corresponding bits at AUD_INT_STAT */ 189b285192aSMauro Carvalho Chehab cx_write(AUD_A_INT_MSK, FLD_AUD_DST_RISCI1 | FLD_AUD_DST_OF | 190b285192aSMauro Carvalho Chehab FLD_AUD_DST_SYNC | FLD_AUD_DST_OPC_ERR); 191b285192aSMauro Carvalho Chehab 192b285192aSMauro Carvalho Chehab /* Clean any pending interrupt bits already set */ 193b285192aSMauro Carvalho Chehab cx_write(AUD_A_INT_STAT, ~0); 194b285192aSMauro Carvalho Chehab 195b285192aSMauro Carvalho Chehab /* enable audio irqs */ 196b285192aSMauro Carvalho Chehab cx_set(PCI_INT_MSK, chip->dev->pci_irqmask | PCI_MSK_AUD_INT); 197b285192aSMauro Carvalho Chehab 198b285192aSMauro Carvalho Chehab /* Turn on audio downstream fifo and risc enable 0x101 */ 199b285192aSMauro Carvalho Chehab tmp = cx_read(AUD_INT_DMA_CTL); 200b285192aSMauro Carvalho Chehab cx_set(AUD_INT_DMA_CTL, tmp | 201b285192aSMauro Carvalho Chehab (FLD_AUD_DST_A_RISC_EN | FLD_AUD_DST_A_FIFO_EN)); 202b285192aSMauro Carvalho Chehab 203b285192aSMauro Carvalho Chehab mdelay(100); 204b285192aSMauro Carvalho Chehab return 0; 205b285192aSMauro Carvalho Chehab } 206b285192aSMauro Carvalho Chehab 207b285192aSMauro Carvalho Chehab /* 208b285192aSMauro Carvalho Chehab * BOARD Specific: Resets audio DMA 209b285192aSMauro Carvalho Chehab */ 210b285192aSMauro Carvalho Chehab static int _cx25821_stop_audio_dma(struct cx25821_audio_dev *chip) 211b285192aSMauro Carvalho Chehab { 212b285192aSMauro Carvalho Chehab struct cx25821_dev *dev = chip->dev; 213b285192aSMauro Carvalho Chehab 214b285192aSMauro Carvalho Chehab /* stop dma */ 215b285192aSMauro Carvalho Chehab cx_clear(AUD_INT_DMA_CTL, 216b285192aSMauro Carvalho Chehab FLD_AUD_DST_A_RISC_EN | FLD_AUD_DST_A_FIFO_EN); 217b285192aSMauro Carvalho Chehab 218b285192aSMauro Carvalho Chehab /* disable irqs */ 219b285192aSMauro Carvalho Chehab cx_clear(PCI_INT_MSK, PCI_MSK_AUD_INT); 220b285192aSMauro Carvalho Chehab cx_clear(AUD_A_INT_MSK, AUD_INT_OPC_ERR | AUD_INT_DN_SYNC | 221b285192aSMauro Carvalho Chehab AUD_INT_DN_RISCI2 | AUD_INT_DN_RISCI1); 222b285192aSMauro Carvalho Chehab 223b285192aSMauro Carvalho Chehab return 0; 224b285192aSMauro Carvalho Chehab } 225b285192aSMauro Carvalho Chehab 226b285192aSMauro Carvalho Chehab #define MAX_IRQ_LOOP 50 227b285192aSMauro Carvalho Chehab 228b285192aSMauro Carvalho Chehab /* 229b285192aSMauro Carvalho Chehab * BOARD Specific: IRQ dma bits 230b285192aSMauro Carvalho Chehab */ 231b285192aSMauro Carvalho Chehab static char *cx25821_aud_irqs[32] = { 232b285192aSMauro Carvalho Chehab "dn_risci1", "up_risci1", "rds_dn_risc1", /* 0-2 */ 233b285192aSMauro Carvalho Chehab NULL, /* reserved */ 234b285192aSMauro Carvalho Chehab "dn_risci2", "up_risci2", "rds_dn_risc2", /* 4-6 */ 235b285192aSMauro Carvalho Chehab NULL, /* reserved */ 236b285192aSMauro Carvalho Chehab "dnf_of", "upf_uf", "rds_dnf_uf", /* 8-10 */ 237b285192aSMauro Carvalho Chehab NULL, /* reserved */ 238b285192aSMauro Carvalho Chehab "dn_sync", "up_sync", "rds_dn_sync", /* 12-14 */ 239b285192aSMauro Carvalho Chehab NULL, /* reserved */ 240b285192aSMauro Carvalho Chehab "opc_err", "par_err", "rip_err", /* 16-18 */ 241b285192aSMauro Carvalho Chehab "pci_abort", "ber_irq", "mchg_irq" /* 19-21 */ 242b285192aSMauro Carvalho Chehab }; 243b285192aSMauro Carvalho Chehab 244b285192aSMauro Carvalho Chehab /* 245b285192aSMauro Carvalho Chehab * BOARD Specific: Threats IRQ audio specific calls 246b285192aSMauro Carvalho Chehab */ 247b285192aSMauro Carvalho Chehab static void cx25821_aud_irq(struct cx25821_audio_dev *chip, u32 status, 248b285192aSMauro Carvalho Chehab u32 mask) 249b285192aSMauro Carvalho Chehab { 250b285192aSMauro Carvalho Chehab struct cx25821_dev *dev = chip->dev; 251b285192aSMauro Carvalho Chehab 252b285192aSMauro Carvalho Chehab if (0 == (status & mask)) 253b285192aSMauro Carvalho Chehab return; 254b285192aSMauro Carvalho Chehab 255b285192aSMauro Carvalho Chehab cx_write(AUD_A_INT_STAT, status); 256b285192aSMauro Carvalho Chehab if (debug > 1 || (status & mask & ~0xff)) 257b285192aSMauro Carvalho Chehab cx25821_print_irqbits(dev->name, "irq aud", cx25821_aud_irqs, 258b285192aSMauro Carvalho Chehab ARRAY_SIZE(cx25821_aud_irqs), status, mask); 259b285192aSMauro Carvalho Chehab 260b285192aSMauro Carvalho Chehab /* risc op code error */ 261b285192aSMauro Carvalho Chehab if (status & AUD_INT_OPC_ERR) { 262b285192aSMauro Carvalho Chehab pr_warn("WARNING %s/1: Audio risc op code error\n", dev->name); 263b285192aSMauro Carvalho Chehab 264b285192aSMauro Carvalho Chehab cx_clear(AUD_INT_DMA_CTL, 265b285192aSMauro Carvalho Chehab FLD_AUD_DST_A_RISC_EN | FLD_AUD_DST_A_FIFO_EN); 266b285192aSMauro Carvalho Chehab cx25821_sram_channel_dump_audio(dev, 267b285192aSMauro Carvalho Chehab &cx25821_sram_channels[AUDIO_SRAM_CHANNEL]); 268b285192aSMauro Carvalho Chehab } 269b285192aSMauro Carvalho Chehab if (status & AUD_INT_DN_SYNC) { 270b285192aSMauro Carvalho Chehab pr_warn("WARNING %s: Downstream sync error!\n", dev->name); 271b285192aSMauro Carvalho Chehab cx_write(AUD_A_GPCNT_CTL, GP_COUNT_CONTROL_RESET); 272b285192aSMauro Carvalho Chehab return; 273b285192aSMauro Carvalho Chehab } 274b285192aSMauro Carvalho Chehab 275b285192aSMauro Carvalho Chehab /* risc1 downstream */ 276b285192aSMauro Carvalho Chehab if (status & AUD_INT_DN_RISCI1) { 277b285192aSMauro Carvalho Chehab atomic_set(&chip->count, cx_read(AUD_A_GPCNT)); 278b285192aSMauro Carvalho Chehab snd_pcm_period_elapsed(chip->substream); 279b285192aSMauro Carvalho Chehab } 280b285192aSMauro Carvalho Chehab } 281b285192aSMauro Carvalho Chehab 282b285192aSMauro Carvalho Chehab /* 283b285192aSMauro Carvalho Chehab * BOARD Specific: Handles IRQ calls 284b285192aSMauro Carvalho Chehab */ 285b285192aSMauro Carvalho Chehab static irqreturn_t cx25821_irq(int irq, void *dev_id) 286b285192aSMauro Carvalho Chehab { 287b285192aSMauro Carvalho Chehab struct cx25821_audio_dev *chip = dev_id; 288b285192aSMauro Carvalho Chehab struct cx25821_dev *dev = chip->dev; 289b285192aSMauro Carvalho Chehab u32 status, pci_status; 290b285192aSMauro Carvalho Chehab u32 audint_status, audint_mask; 291b285192aSMauro Carvalho Chehab int loop, handled = 0; 292b285192aSMauro Carvalho Chehab 293b285192aSMauro Carvalho Chehab audint_status = cx_read(AUD_A_INT_STAT); 294b285192aSMauro Carvalho Chehab audint_mask = cx_read(AUD_A_INT_MSK); 295b285192aSMauro Carvalho Chehab status = cx_read(PCI_INT_STAT); 296b285192aSMauro Carvalho Chehab 297b285192aSMauro Carvalho Chehab for (loop = 0; loop < 1; loop++) { 298b285192aSMauro Carvalho Chehab status = cx_read(PCI_INT_STAT); 299b285192aSMauro Carvalho Chehab if (0 == status) { 300b285192aSMauro Carvalho Chehab status = cx_read(PCI_INT_STAT); 301b285192aSMauro Carvalho Chehab audint_status = cx_read(AUD_A_INT_STAT); 302b285192aSMauro Carvalho Chehab audint_mask = cx_read(AUD_A_INT_MSK); 303b285192aSMauro Carvalho Chehab 304b285192aSMauro Carvalho Chehab if (status) { 305b285192aSMauro Carvalho Chehab handled = 1; 306b285192aSMauro Carvalho Chehab cx_write(PCI_INT_STAT, status); 307b285192aSMauro Carvalho Chehab 308b285192aSMauro Carvalho Chehab cx25821_aud_irq(chip, audint_status, 309b285192aSMauro Carvalho Chehab audint_mask); 310b285192aSMauro Carvalho Chehab break; 311b285192aSMauro Carvalho Chehab } else { 312b285192aSMauro Carvalho Chehab goto out; 313b285192aSMauro Carvalho Chehab } 314b285192aSMauro Carvalho Chehab } 315b285192aSMauro Carvalho Chehab 316b285192aSMauro Carvalho Chehab handled = 1; 317b285192aSMauro Carvalho Chehab cx_write(PCI_INT_STAT, status); 318b285192aSMauro Carvalho Chehab 319b285192aSMauro Carvalho Chehab cx25821_aud_irq(chip, audint_status, audint_mask); 320b285192aSMauro Carvalho Chehab } 321b285192aSMauro Carvalho Chehab 322b285192aSMauro Carvalho Chehab pci_status = cx_read(PCI_INT_STAT); 323b285192aSMauro Carvalho Chehab 324b285192aSMauro Carvalho Chehab if (handled) 325b285192aSMauro Carvalho Chehab cx_write(PCI_INT_STAT, pci_status); 326b285192aSMauro Carvalho Chehab 327b285192aSMauro Carvalho Chehab out: 328b285192aSMauro Carvalho Chehab return IRQ_RETVAL(handled); 329b285192aSMauro Carvalho Chehab } 330b285192aSMauro Carvalho Chehab 331b285192aSMauro Carvalho Chehab static int dsp_buffer_free(struct cx25821_audio_dev *chip) 332b285192aSMauro Carvalho Chehab { 333b285192aSMauro Carvalho Chehab BUG_ON(!chip->dma_size); 334b285192aSMauro Carvalho Chehab 335b285192aSMauro Carvalho Chehab dprintk(2, "Freeing buffer\n"); 336b285192aSMauro Carvalho Chehab videobuf_dma_unmap(&chip->pci->dev, chip->dma_risc); 337b285192aSMauro Carvalho Chehab videobuf_dma_free(chip->dma_risc); 338b285192aSMauro Carvalho Chehab btcx_riscmem_free(chip->pci, &chip->buf->risc); 339b285192aSMauro Carvalho Chehab kfree(chip->buf); 340b285192aSMauro Carvalho Chehab 341b285192aSMauro Carvalho Chehab chip->dma_risc = NULL; 342b285192aSMauro Carvalho Chehab chip->dma_size = 0; 343b285192aSMauro Carvalho Chehab 344b285192aSMauro Carvalho Chehab return 0; 345b285192aSMauro Carvalho Chehab } 346b285192aSMauro Carvalho Chehab 347b285192aSMauro Carvalho Chehab /**************************************************************************** 348b285192aSMauro Carvalho Chehab ALSA PCM Interface 349b285192aSMauro Carvalho Chehab ****************************************************************************/ 350b285192aSMauro Carvalho Chehab 351b285192aSMauro Carvalho Chehab /* 352b285192aSMauro Carvalho Chehab * Digital hardware definition 353b285192aSMauro Carvalho Chehab */ 354b285192aSMauro Carvalho Chehab #define DEFAULT_FIFO_SIZE 384 355b285192aSMauro Carvalho Chehab static struct snd_pcm_hardware snd_cx25821_digital_hw = { 356b285192aSMauro Carvalho Chehab .info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | 357b285192aSMauro Carvalho Chehab SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID, 358b285192aSMauro Carvalho Chehab .formats = SNDRV_PCM_FMTBIT_S16_LE, 359b285192aSMauro Carvalho Chehab 360b285192aSMauro Carvalho Chehab .rates = SNDRV_PCM_RATE_48000, 361b285192aSMauro Carvalho Chehab .rate_min = 48000, 362b285192aSMauro Carvalho Chehab .rate_max = 48000, 363b285192aSMauro Carvalho Chehab .channels_min = 2, 364b285192aSMauro Carvalho Chehab .channels_max = 2, 365b285192aSMauro Carvalho Chehab /* Analog audio output will be full of clicks and pops if there 366b285192aSMauro Carvalho Chehab are not exactly four lines in the SRAM FIFO buffer. */ 367b285192aSMauro Carvalho Chehab .period_bytes_min = DEFAULT_FIFO_SIZE / 3, 368b285192aSMauro Carvalho Chehab .period_bytes_max = DEFAULT_FIFO_SIZE / 3, 369b285192aSMauro Carvalho Chehab .periods_min = 1, 370b285192aSMauro Carvalho Chehab .periods_max = AUDIO_LINE_SIZE, 371b285192aSMauro Carvalho Chehab /* 128 * 128 = 16384 = 1024 * 16 */ 372b285192aSMauro Carvalho Chehab .buffer_bytes_max = (AUDIO_LINE_SIZE * AUDIO_LINE_SIZE), 373b285192aSMauro Carvalho Chehab }; 374b285192aSMauro Carvalho Chehab 375b285192aSMauro Carvalho Chehab /* 376b285192aSMauro Carvalho Chehab * audio pcm capture open callback 377b285192aSMauro Carvalho Chehab */ 378b285192aSMauro Carvalho Chehab static int snd_cx25821_pcm_open(struct snd_pcm_substream *substream) 379b285192aSMauro Carvalho Chehab { 380b285192aSMauro Carvalho Chehab struct cx25821_audio_dev *chip = snd_pcm_substream_chip(substream); 381b285192aSMauro Carvalho Chehab struct snd_pcm_runtime *runtime = substream->runtime; 382b285192aSMauro Carvalho Chehab int err; 383b285192aSMauro Carvalho Chehab unsigned int bpl = 0; 384b285192aSMauro Carvalho Chehab 385b285192aSMauro Carvalho Chehab if (!chip) { 386b285192aSMauro Carvalho Chehab pr_err("DEBUG: cx25821 can't find device struct. Can't proceed with open\n"); 387b285192aSMauro Carvalho Chehab return -ENODEV; 388b285192aSMauro Carvalho Chehab } 389b285192aSMauro Carvalho Chehab 390b285192aSMauro Carvalho Chehab err = snd_pcm_hw_constraint_pow2(runtime, 0, 391b285192aSMauro Carvalho Chehab SNDRV_PCM_HW_PARAM_PERIODS); 392b285192aSMauro Carvalho Chehab if (err < 0) 393b285192aSMauro Carvalho Chehab goto _error; 394b285192aSMauro Carvalho Chehab 395b285192aSMauro Carvalho Chehab chip->substream = substream; 396b285192aSMauro Carvalho Chehab 397b285192aSMauro Carvalho Chehab runtime->hw = snd_cx25821_digital_hw; 398b285192aSMauro Carvalho Chehab 399b285192aSMauro Carvalho Chehab if (cx25821_sram_channels[AUDIO_SRAM_CHANNEL].fifo_size != 400b285192aSMauro Carvalho Chehab DEFAULT_FIFO_SIZE) { 401b285192aSMauro Carvalho Chehab /* since there are 3 audio Clusters */ 402b285192aSMauro Carvalho Chehab bpl = cx25821_sram_channels[AUDIO_SRAM_CHANNEL].fifo_size / 3; 403b285192aSMauro Carvalho Chehab bpl &= ~7; /* must be multiple of 8 */ 404b285192aSMauro Carvalho Chehab 405b285192aSMauro Carvalho Chehab if (bpl > AUDIO_LINE_SIZE) 406b285192aSMauro Carvalho Chehab bpl = AUDIO_LINE_SIZE; 407b285192aSMauro Carvalho Chehab 408b285192aSMauro Carvalho Chehab runtime->hw.period_bytes_min = bpl; 409b285192aSMauro Carvalho Chehab runtime->hw.period_bytes_max = bpl; 410b285192aSMauro Carvalho Chehab } 411b285192aSMauro Carvalho Chehab 412b285192aSMauro Carvalho Chehab return 0; 413b285192aSMauro Carvalho Chehab _error: 414b285192aSMauro Carvalho Chehab dprintk(1, "Error opening PCM!\n"); 415b285192aSMauro Carvalho Chehab return err; 416b285192aSMauro Carvalho Chehab } 417b285192aSMauro Carvalho Chehab 418b285192aSMauro Carvalho Chehab /* 419b285192aSMauro Carvalho Chehab * audio close callback 420b285192aSMauro Carvalho Chehab */ 421b285192aSMauro Carvalho Chehab static int snd_cx25821_close(struct snd_pcm_substream *substream) 422b285192aSMauro Carvalho Chehab { 423b285192aSMauro Carvalho Chehab return 0; 424b285192aSMauro Carvalho Chehab } 425b285192aSMauro Carvalho Chehab 426b285192aSMauro Carvalho Chehab /* 427b285192aSMauro Carvalho Chehab * hw_params callback 428b285192aSMauro Carvalho Chehab */ 429b285192aSMauro Carvalho Chehab static int snd_cx25821_hw_params(struct snd_pcm_substream *substream, 430b285192aSMauro Carvalho Chehab struct snd_pcm_hw_params *hw_params) 431b285192aSMauro Carvalho Chehab { 432b285192aSMauro Carvalho Chehab struct cx25821_audio_dev *chip = snd_pcm_substream_chip(substream); 433b285192aSMauro Carvalho Chehab struct videobuf_dmabuf *dma; 434b285192aSMauro Carvalho Chehab 435b285192aSMauro Carvalho Chehab struct cx25821_audio_buffer *buf; 436b285192aSMauro Carvalho Chehab int ret; 437b285192aSMauro Carvalho Chehab 438b285192aSMauro Carvalho Chehab if (substream->runtime->dma_area) { 439b285192aSMauro Carvalho Chehab dsp_buffer_free(chip); 440b285192aSMauro Carvalho Chehab substream->runtime->dma_area = NULL; 441b285192aSMauro Carvalho Chehab } 442b285192aSMauro Carvalho Chehab 443b285192aSMauro Carvalho Chehab chip->period_size = params_period_bytes(hw_params); 444b285192aSMauro Carvalho Chehab chip->num_periods = params_periods(hw_params); 445b285192aSMauro Carvalho Chehab chip->dma_size = chip->period_size * params_periods(hw_params); 446b285192aSMauro Carvalho Chehab 447b285192aSMauro Carvalho Chehab BUG_ON(!chip->dma_size); 448b285192aSMauro Carvalho Chehab BUG_ON(chip->num_periods & (chip->num_periods - 1)); 449b285192aSMauro Carvalho Chehab 450b285192aSMauro Carvalho Chehab buf = kzalloc(sizeof(*buf), GFP_KERNEL); 451b285192aSMauro Carvalho Chehab if (NULL == buf) 452b285192aSMauro Carvalho Chehab return -ENOMEM; 453b285192aSMauro Carvalho Chehab 454b285192aSMauro Carvalho Chehab if (chip->period_size > AUDIO_LINE_SIZE) 455b285192aSMauro Carvalho Chehab chip->period_size = AUDIO_LINE_SIZE; 456b285192aSMauro Carvalho Chehab 457b285192aSMauro Carvalho Chehab buf->bpl = chip->period_size; 458b285192aSMauro Carvalho Chehab 459b285192aSMauro Carvalho Chehab dma = &buf->dma; 460b285192aSMauro Carvalho Chehab videobuf_dma_init(dma); 461b285192aSMauro Carvalho Chehab ret = videobuf_dma_init_kernel(dma, PCI_DMA_FROMDEVICE, 462b285192aSMauro Carvalho Chehab (PAGE_ALIGN(chip->dma_size) >> PAGE_SHIFT)); 463b285192aSMauro Carvalho Chehab if (ret < 0) 464b285192aSMauro Carvalho Chehab goto error; 465b285192aSMauro Carvalho Chehab 466b285192aSMauro Carvalho Chehab ret = videobuf_dma_map(&chip->pci->dev, dma); 467b285192aSMauro Carvalho Chehab if (ret < 0) 468b285192aSMauro Carvalho Chehab goto error; 469b285192aSMauro Carvalho Chehab 470b285192aSMauro Carvalho Chehab ret = cx25821_risc_databuffer_audio(chip->pci, &buf->risc, dma->sglist, 471b285192aSMauro Carvalho Chehab chip->period_size, chip->num_periods, 1); 472b285192aSMauro Carvalho Chehab if (ret < 0) { 473b285192aSMauro Carvalho Chehab pr_info("DEBUG: ERROR after cx25821_risc_databuffer_audio()\n"); 474b285192aSMauro Carvalho Chehab goto error; 475b285192aSMauro Carvalho Chehab } 476b285192aSMauro Carvalho Chehab 477b285192aSMauro Carvalho Chehab /* Loop back to start of program */ 478b285192aSMauro Carvalho Chehab buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC); 479b285192aSMauro Carvalho Chehab buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma); 480b285192aSMauro Carvalho Chehab buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */ 481b285192aSMauro Carvalho Chehab 482b285192aSMauro Carvalho Chehab chip->buf = buf; 483b285192aSMauro Carvalho Chehab chip->dma_risc = dma; 484b285192aSMauro Carvalho Chehab 485b285192aSMauro Carvalho Chehab substream->runtime->dma_area = chip->dma_risc->vaddr; 486b285192aSMauro Carvalho Chehab substream->runtime->dma_bytes = chip->dma_size; 487b285192aSMauro Carvalho Chehab substream->runtime->dma_addr = 0; 488b285192aSMauro Carvalho Chehab 489b285192aSMauro Carvalho Chehab return 0; 490b285192aSMauro Carvalho Chehab 491b285192aSMauro Carvalho Chehab error: 492b285192aSMauro Carvalho Chehab kfree(buf); 493b285192aSMauro Carvalho Chehab return ret; 494b285192aSMauro Carvalho Chehab } 495b285192aSMauro Carvalho Chehab 496b285192aSMauro Carvalho Chehab /* 497b285192aSMauro Carvalho Chehab * hw free callback 498b285192aSMauro Carvalho Chehab */ 499b285192aSMauro Carvalho Chehab static int snd_cx25821_hw_free(struct snd_pcm_substream *substream) 500b285192aSMauro Carvalho Chehab { 501b285192aSMauro Carvalho Chehab struct cx25821_audio_dev *chip = snd_pcm_substream_chip(substream); 502b285192aSMauro Carvalho Chehab 503b285192aSMauro Carvalho Chehab if (substream->runtime->dma_area) { 504b285192aSMauro Carvalho Chehab dsp_buffer_free(chip); 505b285192aSMauro Carvalho Chehab substream->runtime->dma_area = NULL; 506b285192aSMauro Carvalho Chehab } 507b285192aSMauro Carvalho Chehab 508b285192aSMauro Carvalho Chehab return 0; 509b285192aSMauro Carvalho Chehab } 510b285192aSMauro Carvalho Chehab 511b285192aSMauro Carvalho Chehab /* 512b285192aSMauro Carvalho Chehab * prepare callback 513b285192aSMauro Carvalho Chehab */ 514b285192aSMauro Carvalho Chehab static int snd_cx25821_prepare(struct snd_pcm_substream *substream) 515b285192aSMauro Carvalho Chehab { 516b285192aSMauro Carvalho Chehab return 0; 517b285192aSMauro Carvalho Chehab } 518b285192aSMauro Carvalho Chehab 519b285192aSMauro Carvalho Chehab /* 520b285192aSMauro Carvalho Chehab * trigger callback 521b285192aSMauro Carvalho Chehab */ 522b285192aSMauro Carvalho Chehab static int snd_cx25821_card_trigger(struct snd_pcm_substream *substream, 523b285192aSMauro Carvalho Chehab int cmd) 524b285192aSMauro Carvalho Chehab { 525b285192aSMauro Carvalho Chehab struct cx25821_audio_dev *chip = snd_pcm_substream_chip(substream); 526b285192aSMauro Carvalho Chehab int err = 0; 527b285192aSMauro Carvalho Chehab 528b285192aSMauro Carvalho Chehab /* Local interrupts are already disabled by ALSA */ 529b285192aSMauro Carvalho Chehab spin_lock(&chip->reg_lock); 530b285192aSMauro Carvalho Chehab 531b285192aSMauro Carvalho Chehab switch (cmd) { 532b285192aSMauro Carvalho Chehab case SNDRV_PCM_TRIGGER_START: 533b285192aSMauro Carvalho Chehab err = _cx25821_start_audio_dma(chip); 534b285192aSMauro Carvalho Chehab break; 535b285192aSMauro Carvalho Chehab case SNDRV_PCM_TRIGGER_STOP: 536b285192aSMauro Carvalho Chehab err = _cx25821_stop_audio_dma(chip); 537b285192aSMauro Carvalho Chehab break; 538b285192aSMauro Carvalho Chehab default: 539b285192aSMauro Carvalho Chehab err = -EINVAL; 540b285192aSMauro Carvalho Chehab break; 541b285192aSMauro Carvalho Chehab } 542b285192aSMauro Carvalho Chehab 543b285192aSMauro Carvalho Chehab spin_unlock(&chip->reg_lock); 544b285192aSMauro Carvalho Chehab 545b285192aSMauro Carvalho Chehab return err; 546b285192aSMauro Carvalho Chehab } 547b285192aSMauro Carvalho Chehab 548b285192aSMauro Carvalho Chehab /* 549b285192aSMauro Carvalho Chehab * pointer callback 550b285192aSMauro Carvalho Chehab */ 551b285192aSMauro Carvalho Chehab static snd_pcm_uframes_t snd_cx25821_pointer(struct snd_pcm_substream 552b285192aSMauro Carvalho Chehab *substream) 553b285192aSMauro Carvalho Chehab { 554b285192aSMauro Carvalho Chehab struct cx25821_audio_dev *chip = snd_pcm_substream_chip(substream); 555b285192aSMauro Carvalho Chehab struct snd_pcm_runtime *runtime = substream->runtime; 556b285192aSMauro Carvalho Chehab u16 count; 557b285192aSMauro Carvalho Chehab 558b285192aSMauro Carvalho Chehab count = atomic_read(&chip->count); 559b285192aSMauro Carvalho Chehab 560b285192aSMauro Carvalho Chehab return runtime->period_size * (count & (runtime->periods - 1)); 561b285192aSMauro Carvalho Chehab } 562b285192aSMauro Carvalho Chehab 563b285192aSMauro Carvalho Chehab /* 564b285192aSMauro Carvalho Chehab * page callback (needed for mmap) 565b285192aSMauro Carvalho Chehab */ 566b285192aSMauro Carvalho Chehab static struct page *snd_cx25821_page(struct snd_pcm_substream *substream, 567b285192aSMauro Carvalho Chehab unsigned long offset) 568b285192aSMauro Carvalho Chehab { 569b285192aSMauro Carvalho Chehab void *pageptr = substream->runtime->dma_area + offset; 570b285192aSMauro Carvalho Chehab 571b285192aSMauro Carvalho Chehab return vmalloc_to_page(pageptr); 572b285192aSMauro Carvalho Chehab } 573b285192aSMauro Carvalho Chehab 574b285192aSMauro Carvalho Chehab /* 575b285192aSMauro Carvalho Chehab * operators 576b285192aSMauro Carvalho Chehab */ 577b285192aSMauro Carvalho Chehab static struct snd_pcm_ops snd_cx25821_pcm_ops = { 578b285192aSMauro Carvalho Chehab .open = snd_cx25821_pcm_open, 579b285192aSMauro Carvalho Chehab .close = snd_cx25821_close, 580b285192aSMauro Carvalho Chehab .ioctl = snd_pcm_lib_ioctl, 581b285192aSMauro Carvalho Chehab .hw_params = snd_cx25821_hw_params, 582b285192aSMauro Carvalho Chehab .hw_free = snd_cx25821_hw_free, 583b285192aSMauro Carvalho Chehab .prepare = snd_cx25821_prepare, 584b285192aSMauro Carvalho Chehab .trigger = snd_cx25821_card_trigger, 585b285192aSMauro Carvalho Chehab .pointer = snd_cx25821_pointer, 586b285192aSMauro Carvalho Chehab .page = snd_cx25821_page, 587b285192aSMauro Carvalho Chehab }; 588b285192aSMauro Carvalho Chehab 589b285192aSMauro Carvalho Chehab /* 590b285192aSMauro Carvalho Chehab * ALSA create a PCM device: Called when initializing the board. 591b285192aSMauro Carvalho Chehab * Sets up the name and hooks up the callbacks 592b285192aSMauro Carvalho Chehab */ 593b285192aSMauro Carvalho Chehab static int snd_cx25821_pcm(struct cx25821_audio_dev *chip, int device, 594b285192aSMauro Carvalho Chehab char *name) 595b285192aSMauro Carvalho Chehab { 596b285192aSMauro Carvalho Chehab struct snd_pcm *pcm; 597b285192aSMauro Carvalho Chehab int err; 598b285192aSMauro Carvalho Chehab 599b285192aSMauro Carvalho Chehab err = snd_pcm_new(chip->card, name, device, 0, 1, &pcm); 600b285192aSMauro Carvalho Chehab if (err < 0) { 601b285192aSMauro Carvalho Chehab pr_info("ERROR: FAILED snd_pcm_new() in %s\n", __func__); 602b285192aSMauro Carvalho Chehab return err; 603b285192aSMauro Carvalho Chehab } 604b285192aSMauro Carvalho Chehab pcm->private_data = chip; 605b285192aSMauro Carvalho Chehab pcm->info_flags = 0; 606b285192aSMauro Carvalho Chehab strcpy(pcm->name, name); 607b285192aSMauro Carvalho Chehab snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_cx25821_pcm_ops); 608b285192aSMauro Carvalho Chehab 609b285192aSMauro Carvalho Chehab return 0; 610b285192aSMauro Carvalho Chehab } 611b285192aSMauro Carvalho Chehab 612b285192aSMauro Carvalho Chehab /**************************************************************************** 613b285192aSMauro Carvalho Chehab Basic Flow for Sound Devices 614b285192aSMauro Carvalho Chehab ****************************************************************************/ 615b285192aSMauro Carvalho Chehab 616b285192aSMauro Carvalho Chehab /* 617b285192aSMauro Carvalho Chehab * PCI ID Table - 14f1:8801 and 14f1:8811 means function 1: Audio 618b285192aSMauro Carvalho Chehab * Only boards with eeprom and byte 1 at eeprom=1 have it 619b285192aSMauro Carvalho Chehab */ 620b285192aSMauro Carvalho Chehab 621b285192aSMauro Carvalho Chehab static DEFINE_PCI_DEVICE_TABLE(cx25821_audio_pci_tbl) = { 622b285192aSMauro Carvalho Chehab {0x14f1, 0x0920, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 623b285192aSMauro Carvalho Chehab {0,} 624b285192aSMauro Carvalho Chehab }; 625b285192aSMauro Carvalho Chehab 626b285192aSMauro Carvalho Chehab MODULE_DEVICE_TABLE(pci, cx25821_audio_pci_tbl); 627b285192aSMauro Carvalho Chehab 628b285192aSMauro Carvalho Chehab /* 629b285192aSMauro Carvalho Chehab * Alsa Constructor - Component probe 630b285192aSMauro Carvalho Chehab */ 631b285192aSMauro Carvalho Chehab static int cx25821_audio_initdev(struct cx25821_dev *dev) 632b285192aSMauro Carvalho Chehab { 633b285192aSMauro Carvalho Chehab struct snd_card *card; 634b285192aSMauro Carvalho Chehab struct cx25821_audio_dev *chip; 635b285192aSMauro Carvalho Chehab int err; 636b285192aSMauro Carvalho Chehab 637b285192aSMauro Carvalho Chehab if (devno >= SNDRV_CARDS) { 638b285192aSMauro Carvalho Chehab pr_info("DEBUG ERROR: devno >= SNDRV_CARDS %s\n", __func__); 639b285192aSMauro Carvalho Chehab return -ENODEV; 640b285192aSMauro Carvalho Chehab } 641b285192aSMauro Carvalho Chehab 642b285192aSMauro Carvalho Chehab if (!enable[devno]) { 643b285192aSMauro Carvalho Chehab ++devno; 644b285192aSMauro Carvalho Chehab pr_info("DEBUG ERROR: !enable[devno] %s\n", __func__); 645b285192aSMauro Carvalho Chehab return -ENOENT; 646b285192aSMauro Carvalho Chehab } 647b285192aSMauro Carvalho Chehab 648b285192aSMauro Carvalho Chehab err = snd_card_create(index[devno], id[devno], THIS_MODULE, 649b285192aSMauro Carvalho Chehab sizeof(struct cx25821_audio_dev), &card); 650b285192aSMauro Carvalho Chehab if (err < 0) { 651b285192aSMauro Carvalho Chehab pr_info("DEBUG ERROR: cannot create snd_card_new in %s\n", 652b285192aSMauro Carvalho Chehab __func__); 653b285192aSMauro Carvalho Chehab return err; 654b285192aSMauro Carvalho Chehab } 655b285192aSMauro Carvalho Chehab 656b285192aSMauro Carvalho Chehab strcpy(card->driver, "cx25821"); 657b285192aSMauro Carvalho Chehab 658b285192aSMauro Carvalho Chehab /* Card "creation" */ 659b285192aSMauro Carvalho Chehab chip = card->private_data; 660b285192aSMauro Carvalho Chehab spin_lock_init(&chip->reg_lock); 661b285192aSMauro Carvalho Chehab 662b285192aSMauro Carvalho Chehab chip->dev = dev; 663b285192aSMauro Carvalho Chehab chip->card = card; 664b285192aSMauro Carvalho Chehab chip->pci = dev->pci; 665b285192aSMauro Carvalho Chehab chip->iobase = pci_resource_start(dev->pci, 0); 666b285192aSMauro Carvalho Chehab 667b285192aSMauro Carvalho Chehab chip->irq = dev->pci->irq; 668b285192aSMauro Carvalho Chehab 669b285192aSMauro Carvalho Chehab err = request_irq(dev->pci->irq, cx25821_irq, 670b285192aSMauro Carvalho Chehab IRQF_SHARED, chip->dev->name, chip); 671b285192aSMauro Carvalho Chehab 672b285192aSMauro Carvalho Chehab if (err < 0) { 673b285192aSMauro Carvalho Chehab pr_err("ERROR %s: can't get IRQ %d for ALSA\n", chip->dev->name, 674b285192aSMauro Carvalho Chehab dev->pci->irq); 675b285192aSMauro Carvalho Chehab goto error; 676b285192aSMauro Carvalho Chehab } 677b285192aSMauro Carvalho Chehab 678b285192aSMauro Carvalho Chehab err = snd_cx25821_pcm(chip, 0, "cx25821 Digital"); 679b285192aSMauro Carvalho Chehab if (err < 0) { 680b285192aSMauro Carvalho Chehab pr_info("DEBUG ERROR: cannot create snd_cx25821_pcm %s\n", 681b285192aSMauro Carvalho Chehab __func__); 682b285192aSMauro Carvalho Chehab goto error; 683b285192aSMauro Carvalho Chehab } 684b285192aSMauro Carvalho Chehab 685b285192aSMauro Carvalho Chehab snd_card_set_dev(card, &chip->pci->dev); 686b285192aSMauro Carvalho Chehab 687b285192aSMauro Carvalho Chehab strcpy(card->shortname, "cx25821"); 688b285192aSMauro Carvalho Chehab sprintf(card->longname, "%s at 0x%lx irq %d", chip->dev->name, 689b285192aSMauro Carvalho Chehab chip->iobase, chip->irq); 690b285192aSMauro Carvalho Chehab strcpy(card->mixername, "CX25821"); 691b285192aSMauro Carvalho Chehab 692b285192aSMauro Carvalho Chehab pr_info("%s/%i: ALSA support for cx25821 boards\n", card->driver, 693b285192aSMauro Carvalho Chehab devno); 694b285192aSMauro Carvalho Chehab 695b285192aSMauro Carvalho Chehab err = snd_card_register(card); 696b285192aSMauro Carvalho Chehab if (err < 0) { 697b285192aSMauro Carvalho Chehab pr_info("DEBUG ERROR: cannot register sound card %s\n", 698b285192aSMauro Carvalho Chehab __func__); 699b285192aSMauro Carvalho Chehab goto error; 700b285192aSMauro Carvalho Chehab } 701b285192aSMauro Carvalho Chehab 702a8f35ce3SHans Verkuil dev->card = card; 703b285192aSMauro Carvalho Chehab devno++; 704b285192aSMauro Carvalho Chehab return 0; 705b285192aSMauro Carvalho Chehab 706b285192aSMauro Carvalho Chehab error: 707b285192aSMauro Carvalho Chehab snd_card_free(card); 708b285192aSMauro Carvalho Chehab return err; 709b285192aSMauro Carvalho Chehab } 710b285192aSMauro Carvalho Chehab 711b285192aSMauro Carvalho Chehab /**************************************************************************** 712b285192aSMauro Carvalho Chehab LINUX MODULE INIT 713b285192aSMauro Carvalho Chehab ****************************************************************************/ 714a8f35ce3SHans Verkuil 715a8f35ce3SHans Verkuil static int cx25821_alsa_exit_callback(struct device *dev, void *data) 716a8f35ce3SHans Verkuil { 717a8f35ce3SHans Verkuil struct v4l2_device *v4l2_dev = dev_get_drvdata(dev); 718a8f35ce3SHans Verkuil struct cx25821_dev *cxdev = get_cx25821(v4l2_dev); 719a8f35ce3SHans Verkuil 720a8f35ce3SHans Verkuil snd_card_free(cxdev->card); 721a8f35ce3SHans Verkuil return 0; 722a8f35ce3SHans Verkuil } 723a8f35ce3SHans Verkuil 724b285192aSMauro Carvalho Chehab static void cx25821_audio_fini(void) 725b285192aSMauro Carvalho Chehab { 726a8f35ce3SHans Verkuil struct device_driver *drv = driver_find("cx25821", &pci_bus_type); 727a8f35ce3SHans Verkuil int ret; 728a8f35ce3SHans Verkuil 729a8f35ce3SHans Verkuil ret = driver_for_each_device(drv, NULL, NULL, cx25821_alsa_exit_callback); 730a8f35ce3SHans Verkuil } 731a8f35ce3SHans Verkuil 732a8f35ce3SHans Verkuil static int cx25821_alsa_init_callback(struct device *dev, void *data) 733a8f35ce3SHans Verkuil { 734a8f35ce3SHans Verkuil struct v4l2_device *v4l2_dev = dev_get_drvdata(dev); 735a8f35ce3SHans Verkuil struct cx25821_dev *cxdev = get_cx25821(v4l2_dev); 736a8f35ce3SHans Verkuil 737a8f35ce3SHans Verkuil cx25821_audio_initdev(cxdev); 738a8f35ce3SHans Verkuil return 0; 739b285192aSMauro Carvalho Chehab } 740b285192aSMauro Carvalho Chehab 741b285192aSMauro Carvalho Chehab /* 742b285192aSMauro Carvalho Chehab * Module initializer 743b285192aSMauro Carvalho Chehab * 744b285192aSMauro Carvalho Chehab * Loops through present saa7134 cards, and assigns an ALSA device 745b285192aSMauro Carvalho Chehab * to each one 746b285192aSMauro Carvalho Chehab * 747b285192aSMauro Carvalho Chehab */ 748b285192aSMauro Carvalho Chehab static int cx25821_alsa_init(void) 749b285192aSMauro Carvalho Chehab { 750a8f35ce3SHans Verkuil struct device_driver *drv = driver_find("cx25821", &pci_bus_type); 751b285192aSMauro Carvalho Chehab 752a8f35ce3SHans Verkuil return driver_for_each_device(drv, NULL, NULL, cx25821_alsa_init_callback); 753b285192aSMauro Carvalho Chehab 754b285192aSMauro Carvalho Chehab } 755b285192aSMauro Carvalho Chehab 756b285192aSMauro Carvalho Chehab late_initcall(cx25821_alsa_init); 757b285192aSMauro Carvalho Chehab module_exit(cx25821_audio_fini); 758