3 * Support for audio capture for tm5600/6000/6010
4 * (c) 2007-2008 Mauro Carvalho Chehab <mchehab@redhat.com>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
13 #include <linux/module.h>
14 #include <linux/init.h>
15 #include <linux/device.h>
16 #include <linux/interrupt.h>
17 #include <linux/usb.h>
19 #include <asm/delay.h>
20 #include <sound/core.h>
21 #include <sound/pcm.h>
22 #include <sound/pcm_params.h>
23 #include <sound/control.h>
24 #include <sound/initval.h>
28 #include "tm6000-regs.h"
32 #define dprintk(level, fmt, arg...) do { \
34 printk(KERN_INFO "%s/1: " fmt, chip->core->name , ## arg); \
37 /****************************************************************************
38 Data type declarations - Can be moded to a header file later
39 ****************************************************************************/
41 struct snd_tm6000_card
{
42 struct snd_card
*card
;
48 unsigned int period_size
;
49 unsigned int num_periods
;
51 struct tm6000_core
*core
;
52 struct tm6000_buffer
*buf
;
56 struct snd_pcm_substream
*substream
;
60 /****************************************************************************
61 Module global static vars
62 ****************************************************************************/
64 static int index
[SNDRV_CARDS
] = SNDRV_DEFAULT_IDX
; /* Index 0-MAX */
65 static char *id
[SNDRV_CARDS
] = SNDRV_DEFAULT_STR
; /* ID for this card */
66 static int enable
[SNDRV_CARDS
] = {1, [1 ... (SNDRV_CARDS
- 1)] = 1};
68 module_param_array(enable
, bool, NULL
, 0444);
69 MODULE_PARM_DESC(enable
, "Enable tm6000x soundcard. default enabled.");
71 module_param_array(index
, int, NULL
, 0444);
72 MODULE_PARM_DESC(index
, "Index value for tm6000x capture interface(s).");
75 /****************************************************************************
77 ****************************************************************************/
79 MODULE_DESCRIPTION("ALSA driver module for tm5600/tm6000/tm6010 based TV cards");
80 MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
81 MODULE_LICENSE("GPL");
82 MODULE_SUPPORTED_DEVICE("{{Trident,tm5600},"
85 static unsigned int debug
;
86 module_param(debug
, int, 0644);
87 MODULE_PARM_DESC(debug
, "enable debug messages");
89 /****************************************************************************
90 Module specific funtions
91 ****************************************************************************/
94 * BOARD Specific: Sets audio DMA
97 static int _tm6000_start_audio_dma(struct snd_tm6000_card
*chip
)
99 struct tm6000_core
*core
= chip
->core
;
103 val
= tm6000_get_reg(core
, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF
, 0x0);
105 tm6000_set_reg(core
, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF
, val
);
107 tm6000_set_reg(core
, TM6010_REQ08_R01_A_INIT
, 0x80);
113 * BOARD Specific: Resets audio DMA
115 static int _tm6000_stop_audio_dma(struct snd_tm6000_card
*chip
)
117 struct tm6000_core
*core
= chip
->core
;
119 dprintk(1, "Stopping audio DMA\n");
122 val
= tm6000_get_reg(core
, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF
, 0x0);
124 tm6000_set_reg(core
, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF
, val
);
126 tm6000_set_reg(core
, TM6010_REQ08_R01_A_INIT
, 0);
131 static int dsp_buffer_free(struct snd_tm6000_card
*chip
)
133 BUG_ON(!chip
->bufsize
);
135 dprintk(2, "Freeing buffer\n");
137 /* FIXME: Frees buffer */
144 /****************************************************************************
146 ****************************************************************************/
149 * Digital hardware definition
151 #define DEFAULT_FIFO_SIZE 4096
153 static struct snd_pcm_hardware snd_tm6000_digital_hw
= {
154 .info
= SNDRV_PCM_INFO_MMAP
|
155 SNDRV_PCM_INFO_INTERLEAVED
|
156 SNDRV_PCM_INFO_BLOCK_TRANSFER
|
157 SNDRV_PCM_INFO_MMAP_VALID
,
158 .formats
= SNDRV_PCM_FMTBIT_S16_LE
,
160 .rates
= SNDRV_PCM_RATE_44100
| SNDRV_PCM_RATE_48000
,
165 .period_bytes_min
= DEFAULT_FIFO_SIZE
/4,
166 .period_bytes_max
= DEFAULT_FIFO_SIZE
/4,
169 .buffer_bytes_max
= (1024*1024),
173 * audio pcm capture open callback
175 static int snd_tm6000_pcm_open(struct snd_pcm_substream
*substream
)
177 struct snd_tm6000_card
*chip
= snd_pcm_substream_chip(substream
);
178 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
181 err
= snd_pcm_hw_constraint_pow2(runtime
, 0,
182 SNDRV_PCM_HW_PARAM_PERIODS
);
186 chip
->substream
= substream
;
188 runtime
->hw
= snd_tm6000_digital_hw
;
192 dprintk(1, "Error opening PCM!\n");
197 * audio close callback
199 static int snd_tm6000_close(struct snd_pcm_substream
*substream
)
207 static int snd_tm6000_hw_params(struct snd_pcm_substream
*substream
,
208 struct snd_pcm_hw_params
*hw_params
)
210 struct snd_tm6000_card
*chip
= snd_pcm_substream_chip(substream
);
212 if (substream
->runtime
->dma_area
) {
213 dsp_buffer_free(chip
);
214 substream
->runtime
->dma_area
= NULL
;
217 chip
->period_size
= params_period_bytes(hw_params
);
218 chip
->num_periods
= params_periods(hw_params
);
219 chip
->bufsize
= chip
->period_size
* params_periods(hw_params
);
221 BUG_ON(!chip
->bufsize
);
223 dprintk(1, "Setting buffer\n");
225 /* FIXME: Allocate buffer for audio */
234 static int snd_tm6000_hw_free(struct snd_pcm_substream
*substream
)
237 struct snd_tm6000_card
*chip
= snd_pcm_substream_chip(substream
);
239 if (substream
->runtime
->dma_area
) {
240 dsp_buffer_free(chip
);
241 substream
->runtime
->dma_area
= NULL
;
250 static int snd_tm6000_prepare(struct snd_pcm_substream
*substream
)
259 static int snd_tm6000_card_trigger(struct snd_pcm_substream
*substream
, int cmd
)
261 struct snd_tm6000_card
*chip
= snd_pcm_substream_chip(substream
);
264 spin_lock(&chip
->reg_lock
);
267 case SNDRV_PCM_TRIGGER_START
:
268 err
= _tm6000_start_audio_dma(chip
);
270 case SNDRV_PCM_TRIGGER_STOP
:
271 err
= _tm6000_stop_audio_dma(chip
);
278 spin_unlock(&chip
->reg_lock
);
286 static snd_pcm_uframes_t
snd_tm6000_pointer(struct snd_pcm_substream
*substream
)
288 struct snd_tm6000_card
*chip
= snd_pcm_substream_chip(substream
);
289 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
292 count
= atomic_read(&chip
->count
);
294 return runtime
->period_size
* (count
& (runtime
->periods
-1));
300 static struct snd_pcm_ops snd_tm6000_pcm_ops
= {
301 .open
= snd_tm6000_pcm_open
,
302 .close
= snd_tm6000_close
,
303 .ioctl
= snd_pcm_lib_ioctl
,
304 .hw_params
= snd_tm6000_hw_params
,
305 .hw_free
= snd_tm6000_hw_free
,
306 .prepare
= snd_tm6000_prepare
,
307 .trigger
= snd_tm6000_card_trigger
,
308 .pointer
= snd_tm6000_pointer
,
312 * create a PCM device
314 static int __devinit
snd_tm6000_pcm(struct snd_tm6000_card
*chip
,
315 int device
, char *name
)
320 err
= snd_pcm_new(chip
->card
, name
, device
, 0, 1, &pcm
);
323 pcm
->private_data
= chip
;
324 strcpy(pcm
->name
, name
);
325 snd_pcm_set_ops(pcm
, SNDRV_PCM_STREAM_CAPTURE
, &snd_tm6000_pcm_ops
);
330 /* FIXME: Control interface - How to control volume/mute? */
332 /****************************************************************************
333 Basic Flow for Sound Devices
334 ****************************************************************************/
337 * Alsa Constructor - Component probe
340 int tm6000_audio_init(struct tm6000_core
*dev
, int idx
)
342 struct snd_card
*card
;
343 struct snd_tm6000_card
*chip
;
347 if (idx
>= SNDRV_CARDS
)
353 rc
= snd_card_create(index
[idx
], id
[idx
], THIS_MODULE
, 0, &card
);
355 snd_printk(KERN_ERR
"cannot create card instance %d\n", idx
);
359 chip
= kzalloc(sizeof(*chip
), GFP_KERNEL
);
368 strcpy(card
->driver
, "tm6000-alsa");
369 sprintf(component
, "USB%04x:%04x",
370 le16_to_cpu(dev
->udev
->descriptor
.idVendor
),
371 le16_to_cpu(dev
->udev
->descriptor
.idProduct
));
372 snd_component_add(card
, component
);
374 if (dev
->udev
->descriptor
.iManufacturer
)
375 len
= usb_string(dev
->udev
,
376 dev
->udev
->descriptor
.iManufacturer
,
377 card
->longname
, sizeof(card
->longname
));
382 strlcat(card
->longname
, " ", sizeof(card
->longname
));
384 strlcat(card
->longname
, card
->shortname
, sizeof(card
->longname
));
386 len
= strlcat(card
->longname
, " at ", sizeof(card
->longname
));
388 if (len
< sizeof(card
->longname
))
389 usb_make_path(dev
->udev
, card
->longname
+ len
,
390 sizeof(card
->longname
) - len
);
392 strlcat(card
->longname
,
393 dev
->udev
->speed
== USB_SPEED_LOW
? ", low speed" :
394 dev
->udev
->speed
== USB_SPEED_FULL
? ", full speed" :
396 sizeof(card
->longname
));
398 rc
= snd_tm6000_pcm(chip
, 0, "tm6000 Digital");
402 rc
= snd_card_register(card
);
413 EXPORT_SYMBOL_GPL(tm6000_audio_init
);