595 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 *4 * Support for CX23885 analog audio capture5 *6 * (c) 2008 Mijhail Moreyra <mijhail.moreyra@gmail.com>7 * Adapted from cx88-alsa.c8 * (c) 2009 Steven Toth <stoth@kernellabs.com>9 */10 11#include "cx23885.h"12#include "cx23885-reg.h"13 14#include <linux/module.h>15#include <linux/init.h>16#include <linux/device.h>17#include <linux/interrupt.h>18#include <linux/vmalloc.h>19#include <linux/dma-mapping.h>20#include <linux/pci.h>21 22#include <asm/delay.h>23 24#include <sound/core.h>25#include <sound/pcm.h>26#include <sound/pcm_params.h>27#include <sound/control.h>28#include <sound/initval.h>29 30#include <sound/tlv.h>31 32#define AUDIO_SRAM_CHANNEL SRAM_CH0733 34#define dprintk(level, fmt, arg...) do { \35 if (audio_debug + 1 > level) \36 printk(KERN_DEBUG pr_fmt("%s: alsa: " fmt), \37 chip->dev->name, ##arg); \38} while(0)39 40/****************************************************************************41 Module global static vars42 ****************************************************************************/43 44static unsigned int disable_analog_audio;45module_param(disable_analog_audio, int, 0644);46MODULE_PARM_DESC(disable_analog_audio, "disable analog audio ALSA driver");47 48static unsigned int audio_debug;49module_param(audio_debug, int, 0644);50MODULE_PARM_DESC(audio_debug, "enable debug messages [analog audio]");51 52/****************************************************************************53 Board specific functions54 ****************************************************************************/55 56/* Constants taken from cx88-reg.h */57#define AUD_INT_DN_RISCI1 (1 << 0)58#define AUD_INT_UP_RISCI1 (1 << 1)59#define AUD_INT_RDS_DN_RISCI1 (1 << 2)60#define AUD_INT_DN_RISCI2 (1 << 4) /* yes, 3 is skipped */61#define AUD_INT_UP_RISCI2 (1 << 5)62#define AUD_INT_RDS_DN_RISCI2 (1 << 6)63#define AUD_INT_DN_SYNC (1 << 12)64#define AUD_INT_UP_SYNC (1 << 13)65#define AUD_INT_RDS_DN_SYNC (1 << 14)66#define AUD_INT_OPC_ERR (1 << 16)67#define AUD_INT_BER_IRQ (1 << 20)68#define AUD_INT_MCHG_IRQ (1 << 21)69#define GP_COUNT_CONTROL_RESET 0x370 71static int cx23885_alsa_dma_init(struct cx23885_audio_dev *chip,72 unsigned long nr_pages)73{74 struct cx23885_audio_buffer *buf = chip->buf;75 struct page *pg;76 int i;77 78 buf->vaddr = vmalloc_32(nr_pages << PAGE_SHIFT);79 if (NULL == buf->vaddr) {80 dprintk(1, "vmalloc_32(%lu pages) failed\n", nr_pages);81 return -ENOMEM;82 }83 84 dprintk(1, "vmalloc is at addr %p, size=%lu\n",85 buf->vaddr, nr_pages << PAGE_SHIFT);86 87 memset(buf->vaddr, 0, nr_pages << PAGE_SHIFT);88 buf->nr_pages = nr_pages;89 90 buf->sglist = vzalloc(array_size(sizeof(*buf->sglist), buf->nr_pages));91 if (NULL == buf->sglist)92 goto vzalloc_err;93 94 sg_init_table(buf->sglist, buf->nr_pages);95 for (i = 0; i < buf->nr_pages; i++) {96 pg = vmalloc_to_page(buf->vaddr + i * PAGE_SIZE);97 if (NULL == pg)98 goto vmalloc_to_page_err;99 sg_set_page(&buf->sglist[i], pg, PAGE_SIZE, 0);100 }101 return 0;102 103vmalloc_to_page_err:104 vfree(buf->sglist);105 buf->sglist = NULL;106vzalloc_err:107 vfree(buf->vaddr);108 buf->vaddr = NULL;109 return -ENOMEM;110}111 112static int cx23885_alsa_dma_map(struct cx23885_audio_dev *dev)113{114 struct cx23885_audio_buffer *buf = dev->buf;115 116 buf->sglen = dma_map_sg(&dev->pci->dev, buf->sglist,117 buf->nr_pages, DMA_FROM_DEVICE);118 119 if (0 == buf->sglen) {120 pr_warn("%s: cx23885_alsa_map_sg failed\n", __func__);121 return -ENOMEM;122 }123 return 0;124}125 126static int cx23885_alsa_dma_unmap(struct cx23885_audio_dev *dev)127{128 struct cx23885_audio_buffer *buf = dev->buf;129 130 if (!buf->sglen)131 return 0;132 133 dma_unmap_sg(&dev->pci->dev, buf->sglist, buf->nr_pages, DMA_FROM_DEVICE);134 buf->sglen = 0;135 return 0;136}137 138static int cx23885_alsa_dma_free(struct cx23885_audio_buffer *buf)139{140 vfree(buf->sglist);141 buf->sglist = NULL;142 vfree(buf->vaddr);143 buf->vaddr = NULL;144 return 0;145}146 147/*148 * BOARD Specific: Sets audio DMA149 */150 151static int cx23885_start_audio_dma(struct cx23885_audio_dev *chip)152{153 struct cx23885_audio_buffer *buf = chip->buf;154 struct cx23885_dev *dev = chip->dev;155 struct sram_channel *audio_ch =156 &dev->sram_channels[AUDIO_SRAM_CHANNEL];157 158 dprintk(1, "%s()\n", __func__);159 160 /* Make sure RISC/FIFO are off before changing FIFO/RISC settings */161 cx_clear(AUD_INT_DMA_CTL, 0x11);162 163 /* setup fifo + format - out channel */164 cx23885_sram_channel_setup(chip->dev, audio_ch, buf->bpl,165 buf->risc.dma);166 167 /* sets bpl size */168 cx_write(AUD_INT_A_LNGTH, buf->bpl);169 170 /* This is required to get good audio (1 seems to be ok) */171 cx_write(AUD_INT_A_MODE, 1);172 173 /* reset counter */174 cx_write(AUD_INT_A_GPCNT_CTL, GP_COUNT_CONTROL_RESET);175 atomic_set(&chip->count, 0);176 177 dprintk(1, "Start audio DMA, %d B/line, %d lines/FIFO, %d periods, %d byte buffer\n",178 buf->bpl, cx_read(audio_ch->cmds_start+12)>>1,179 chip->num_periods, buf->bpl * chip->num_periods);180 181 /* Enables corresponding bits at AUD_INT_STAT */182 cx_write(AUDIO_INT_INT_MSK, AUD_INT_OPC_ERR | AUD_INT_DN_SYNC |183 AUD_INT_DN_RISCI1);184 185 /* Clean any pending interrupt bits already set */186 cx_write(AUDIO_INT_INT_STAT, ~0);187 188 /* enable audio irqs */189 cx_set(PCI_INT_MSK, chip->dev->pci_irqmask | PCI_MSK_AUD_INT);190 191 /* start dma */192 cx_set(DEV_CNTRL2, (1<<5)); /* Enables Risc Processor */193 cx_set(AUD_INT_DMA_CTL, 0x11); /* audio downstream FIFO and194 RISC enable */195 if (audio_debug)196 cx23885_sram_channel_dump(chip->dev, audio_ch);197 198 return 0;199}200 201/*202 * BOARD Specific: Resets audio DMA203 */204static int cx23885_stop_audio_dma(struct cx23885_audio_dev *chip)205{206 struct cx23885_dev *dev = chip->dev;207 dprintk(1, "Stopping audio DMA\n");208 209 /* stop dma */210 cx_clear(AUD_INT_DMA_CTL, 0x11);211 212 /* disable irqs */213 cx_clear(PCI_INT_MSK, PCI_MSK_AUD_INT);214 cx_clear(AUDIO_INT_INT_MSK, AUD_INT_OPC_ERR | AUD_INT_DN_SYNC |215 AUD_INT_DN_RISCI1);216 217 if (audio_debug)218 cx23885_sram_channel_dump(chip->dev,219 &dev->sram_channels[AUDIO_SRAM_CHANNEL]);220 221 return 0;222}223 224/*225 * BOARD Specific: Handles audio IRQ226 */227int cx23885_audio_irq(struct cx23885_dev *dev, u32 status, u32 mask)228{229 struct cx23885_audio_dev *chip = dev->audio_dev;230 231 if (0 == (status & mask))232 return 0;233 234 cx_write(AUDIO_INT_INT_STAT, status);235 236 /* risc op code error */237 if (status & AUD_INT_OPC_ERR) {238 pr_warn("%s/1: Audio risc op code error\n",239 dev->name);240 cx_clear(AUD_INT_DMA_CTL, 0x11);241 cx23885_sram_channel_dump(dev,242 &dev->sram_channels[AUDIO_SRAM_CHANNEL]);243 }244 if (status & AUD_INT_DN_SYNC) {245 dprintk(1, "Downstream sync error\n");246 cx_write(AUD_INT_A_GPCNT_CTL, GP_COUNT_CONTROL_RESET);247 return 1;248 }249 /* risc1 downstream */250 if (status & AUD_INT_DN_RISCI1) {251 atomic_set(&chip->count, cx_read(AUD_INT_A_GPCNT));252 snd_pcm_period_elapsed(chip->substream);253 }254 /* FIXME: Any other status should deserve a special handling? */255 256 return 1;257}258 259static int dsp_buffer_free(struct cx23885_audio_dev *chip)260{261 struct cx23885_riscmem *risc;262 263 BUG_ON(!chip->dma_size);264 265 dprintk(2, "Freeing buffer\n");266 cx23885_alsa_dma_unmap(chip);267 cx23885_alsa_dma_free(chip->buf);268 risc = &chip->buf->risc;269 dma_free_coherent(&chip->pci->dev, risc->size, risc->cpu, risc->dma);270 kfree(chip->buf);271 272 chip->buf = NULL;273 chip->dma_size = 0;274 275 return 0;276}277 278/****************************************************************************279 ALSA PCM Interface280 ****************************************************************************/281 282/*283 * Digital hardware definition284 */285#define DEFAULT_FIFO_SIZE 4096286 287static const struct snd_pcm_hardware snd_cx23885_digital_hw = {288 .info = SNDRV_PCM_INFO_MMAP |289 SNDRV_PCM_INFO_INTERLEAVED |290 SNDRV_PCM_INFO_BLOCK_TRANSFER |291 SNDRV_PCM_INFO_MMAP_VALID,292 .formats = SNDRV_PCM_FMTBIT_S16_LE,293 294 .rates = SNDRV_PCM_RATE_48000,295 .rate_min = 48000,296 .rate_max = 48000,297 .channels_min = 2,298 .channels_max = 2,299 /* Analog audio output will be full of clicks and pops if there300 are not exactly four lines in the SRAM FIFO buffer. */301 .period_bytes_min = DEFAULT_FIFO_SIZE/4,302 .period_bytes_max = DEFAULT_FIFO_SIZE/4,303 .periods_min = 1,304 .periods_max = 1024,305 .buffer_bytes_max = (1024*1024),306};307 308/*309 * audio pcm capture open callback310 */311static int snd_cx23885_pcm_open(struct snd_pcm_substream *substream)312{313 struct cx23885_audio_dev *chip = snd_pcm_substream_chip(substream);314 struct snd_pcm_runtime *runtime = substream->runtime;315 int err;316 317 if (!chip) {318 pr_err("BUG: cx23885 can't find device struct. Can't proceed with open\n");319 return -ENODEV;320 }321 322 err = snd_pcm_hw_constraint_pow2(runtime, 0,323 SNDRV_PCM_HW_PARAM_PERIODS);324 if (err < 0)325 goto _error;326 327 chip->substream = substream;328 329 runtime->hw = snd_cx23885_digital_hw;330 331 if (chip->dev->sram_channels[AUDIO_SRAM_CHANNEL].fifo_size !=332 DEFAULT_FIFO_SIZE) {333 unsigned int bpl = chip->dev->334 sram_channels[AUDIO_SRAM_CHANNEL].fifo_size / 4;335 bpl &= ~7; /* must be multiple of 8 */336 runtime->hw.period_bytes_min = bpl;337 runtime->hw.period_bytes_max = bpl;338 }339 340 return 0;341_error:342 dprintk(1, "Error opening PCM!\n");343 return err;344}345 346/*347 * audio close callback348 */349static int snd_cx23885_close(struct snd_pcm_substream *substream)350{351 return 0;352}353 354 355/*356 * hw_params callback357 */358static int snd_cx23885_hw_params(struct snd_pcm_substream *substream,359 struct snd_pcm_hw_params *hw_params)360{361 struct cx23885_audio_dev *chip = snd_pcm_substream_chip(substream);362 struct cx23885_audio_buffer *buf;363 int ret;364 365 if (substream->runtime->dma_area) {366 dsp_buffer_free(chip);367 substream->runtime->dma_area = NULL;368 }369 370 chip->period_size = params_period_bytes(hw_params);371 chip->num_periods = params_periods(hw_params);372 chip->dma_size = chip->period_size * params_periods(hw_params);373 374 BUG_ON(!chip->dma_size);375 BUG_ON(chip->num_periods & (chip->num_periods-1));376 377 buf = kzalloc(sizeof(*buf), GFP_KERNEL);378 if (NULL == buf)379 return -ENOMEM;380 381 buf->bpl = chip->period_size;382 chip->buf = buf;383 384 ret = cx23885_alsa_dma_init(chip,385 (PAGE_ALIGN(chip->dma_size) >> PAGE_SHIFT));386 if (ret < 0)387 goto error;388 389 ret = cx23885_alsa_dma_map(chip);390 if (ret < 0)391 goto error;392 393 ret = cx23885_risc_databuffer(chip->pci, &buf->risc, buf->sglist,394 chip->period_size, chip->num_periods, 1);395 if (ret < 0)396 goto error;397 398 /* Loop back to start of program */399 buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP|RISC_IRQ1|RISC_CNT_INC);400 buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma);401 buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */402 403 substream->runtime->dma_area = chip->buf->vaddr;404 substream->runtime->dma_bytes = chip->dma_size;405 substream->runtime->dma_addr = 0;406 407 return 0;408 409error:410 kfree(buf);411 chip->buf = NULL;412 return ret;413}414 415/*416 * hw free callback417 */418static int snd_cx23885_hw_free(struct snd_pcm_substream *substream)419{420 421 struct cx23885_audio_dev *chip = snd_pcm_substream_chip(substream);422 423 if (substream->runtime->dma_area) {424 dsp_buffer_free(chip);425 substream->runtime->dma_area = NULL;426 }427 428 return 0;429}430 431/*432 * prepare callback433 */434static int snd_cx23885_prepare(struct snd_pcm_substream *substream)435{436 return 0;437}438 439/*440 * trigger callback441 */442static int snd_cx23885_card_trigger(struct snd_pcm_substream *substream,443 int cmd)444{445 struct cx23885_audio_dev *chip = snd_pcm_substream_chip(substream);446 int err;447 448 /* Local interrupts are already disabled by ALSA */449 spin_lock(&chip->lock);450 451 switch (cmd) {452 case SNDRV_PCM_TRIGGER_START:453 err = cx23885_start_audio_dma(chip);454 break;455 case SNDRV_PCM_TRIGGER_STOP:456 err = cx23885_stop_audio_dma(chip);457 break;458 default:459 err = -EINVAL;460 break;461 }462 463 spin_unlock(&chip->lock);464 465 return err;466}467 468/*469 * pointer callback470 */471static snd_pcm_uframes_t snd_cx23885_pointer(472 struct snd_pcm_substream *substream)473{474 struct cx23885_audio_dev *chip = snd_pcm_substream_chip(substream);475 struct snd_pcm_runtime *runtime = substream->runtime;476 u16 count;477 478 count = atomic_read(&chip->count);479 480 return runtime->period_size * (count & (runtime->periods-1));481}482 483/*484 * page callback (needed for mmap)485 */486static struct page *snd_cx23885_page(struct snd_pcm_substream *substream,487 unsigned long offset)488{489 void *pageptr = substream->runtime->dma_area + offset;490 return vmalloc_to_page(pageptr);491}492 493/*494 * operators495 */496static const struct snd_pcm_ops snd_cx23885_pcm_ops = {497 .open = snd_cx23885_pcm_open,498 .close = snd_cx23885_close,499 .hw_params = snd_cx23885_hw_params,500 .hw_free = snd_cx23885_hw_free,501 .prepare = snd_cx23885_prepare,502 .trigger = snd_cx23885_card_trigger,503 .pointer = snd_cx23885_pointer,504 .page = snd_cx23885_page,505};506 507/*508 * create a PCM device509 */510static int snd_cx23885_pcm(struct cx23885_audio_dev *chip, int device,511 char *name)512{513 int err;514 struct snd_pcm *pcm;515 516 err = snd_pcm_new(chip->card, name, device, 0, 1, &pcm);517 if (err < 0)518 return err;519 pcm->private_data = chip;520 strscpy(pcm->name, name, sizeof(pcm->name));521 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_cx23885_pcm_ops);522 523 return 0;524}525 526/****************************************************************************527 Basic Flow for Sound Devices528 ****************************************************************************/529 530/*531 * Alsa Constructor - Component probe532 */533 534struct cx23885_audio_dev *cx23885_audio_register(struct cx23885_dev *dev)535{536 struct snd_card *card;537 struct cx23885_audio_dev *chip;538 int err;539 540 if (disable_analog_audio)541 return NULL;542 543 if (dev->sram_channels[AUDIO_SRAM_CHANNEL].cmds_start == 0) {544 pr_warn("%s(): Missing SRAM channel configuration for analog TV Audio\n",545 __func__);546 return NULL;547 }548 549 err = snd_card_new(&dev->pci->dev,550 SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,551 THIS_MODULE, sizeof(struct cx23885_audio_dev), &card);552 if (err < 0)553 goto error_msg;554 555 chip = (struct cx23885_audio_dev *) card->private_data;556 chip->dev = dev;557 chip->pci = dev->pci;558 chip->card = card;559 spin_lock_init(&chip->lock);560 561 err = snd_cx23885_pcm(chip, 0, "CX23885 Digital");562 if (err < 0)563 goto error;564 565 strscpy(card->driver, "CX23885", sizeof(card->driver));566 sprintf(card->shortname, "Conexant CX23885");567 sprintf(card->longname, "%s at %s", card->shortname, dev->name);568 569 err = snd_card_register(card);570 if (err < 0)571 goto error;572 573 dprintk(0, "registered ALSA audio device\n");574 575 return chip;576 577error:578 snd_card_free(card);579error_msg:580 pr_err("%s(): Failed to register analog audio adapter\n",581 __func__);582 583 return NULL;584}585 586/*587 * ALSA destructor588 */589void cx23885_audio_unregister(struct cx23885_dev *dev)590{591 struct cx23885_audio_dev *chip = dev->audio_dev;592 593 snd_card_free(chip->card);594}595