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