Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging-2.6
[pandora-kernel.git] / drivers / staging / tm6000 / tm6000-alsa.c
1 /*
2  *
3  *  Support for audio capture for tm5600/6000/6010
4  *    (c) 2007-2008 Mauro Carvalho Chehab <mchehab@redhat.com>
5  *
6  *  Based on cx88-alsa.c
7  *
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.
11  */
12
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>
18 #include <linux/slab.h>
19 #include <linux/vmalloc.h>
20
21 #include <asm/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
28
29 #include "tm6000.h"
30 #include "tm6000-regs.h"
31
32 #undef dprintk
33
34 #define dprintk(level, fmt, arg...) do {                                   \
35         if (debug >= level)                                                \
36                 printk(KERN_INFO "%s/1: " fmt, chip->core->name , ## arg); \
37         } while (0)
38
39 /****************************************************************************
40                         Module global static vars
41  ****************************************************************************/
42
43 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;      /* Index 0-MAX */
44
45 static int enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 1};
46
47 module_param_array(enable, bool, NULL, 0444);
48 MODULE_PARM_DESC(enable, "Enable tm6000x soundcard. default enabled.");
49
50 module_param_array(index, int, NULL, 0444);
51 MODULE_PARM_DESC(index, "Index value for tm6000x capture interface(s).");
52
53
54 /****************************************************************************
55                                 Module macros
56  ****************************************************************************/
57
58 MODULE_DESCRIPTION("ALSA driver module for tm5600/tm6000/tm6010 based TV cards");
59 MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
60 MODULE_LICENSE("GPL");
61 MODULE_SUPPORTED_DEVICE("{{Trident,tm5600},"
62                         "{{Trident,tm6000},"
63                         "{{Trident,tm6010}");
64 static unsigned int debug;
65 module_param(debug, int, 0644);
66 MODULE_PARM_DESC(debug, "enable debug messages");
67
68 /****************************************************************************
69                         Module specific funtions
70  ****************************************************************************/
71
72 /*
73  * BOARD Specific: Sets audio DMA
74  */
75
76 static int _tm6000_start_audio_dma(struct snd_tm6000_card *chip)
77 {
78         struct tm6000_core *core = chip->core;
79         int val;
80
81         dprintk(1, "Starting audio DMA\n");
82
83         /* Enables audio */
84         val = tm6000_get_reg(core, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, 0x0);
85         val |= 0x20;
86         tm6000_set_reg(core, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, val);
87
88         tm6000_set_audio_bitrate(core, 48000);
89
90         tm6000_set_reg(core, TM6010_REQ08_R01_A_INIT, 0x80);
91
92         return 0;
93 }
94
95 /*
96  * BOARD Specific: Resets audio DMA
97  */
98 static int _tm6000_stop_audio_dma(struct snd_tm6000_card *chip)
99 {
100         struct tm6000_core *core = chip->core;
101         int val;
102         dprintk(1, "Stopping audio DMA\n");
103
104         /* Enables audio */
105         val = tm6000_get_reg(core, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, 0x0);
106         val &= ~0x20;
107         tm6000_set_reg(core, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, val);
108
109         tm6000_set_reg(core, TM6010_REQ08_R01_A_INIT, 0);
110
111         return 0;
112 }
113
114 static void dsp_buffer_free(struct snd_pcm_substream *substream)
115 {
116         struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
117
118         dprintk(2, "Freeing buffer\n");
119
120         vfree(substream->runtime->dma_area);
121         substream->runtime->dma_area = NULL;
122         substream->runtime->dma_bytes = 0;
123 }
124
125 static int dsp_buffer_alloc(struct snd_pcm_substream *substream, int size)
126 {
127         struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
128
129         dprintk(2, "Allocating buffer\n");
130
131         if (substream->runtime->dma_area) {
132                 if (substream->runtime->dma_bytes > size)
133                         return 0;
134                 dsp_buffer_free(substream);
135         }
136
137         substream->runtime->dma_area = vmalloc(size);
138         if (!substream->runtime->dma_area)
139                 return -ENOMEM;
140
141         substream->runtime->dma_bytes = size;
142
143         return 0;
144 }
145
146
147 /****************************************************************************
148                                 ALSA PCM Interface
149  ****************************************************************************/
150
151 /*
152  * Digital hardware definition
153  */
154 #define DEFAULT_FIFO_SIZE       4096
155
156 static struct snd_pcm_hardware snd_tm6000_digital_hw = {
157         .info = SNDRV_PCM_INFO_MMAP |
158                 SNDRV_PCM_INFO_INTERLEAVED |
159                 SNDRV_PCM_INFO_BLOCK_TRANSFER |
160                 SNDRV_PCM_INFO_MMAP_VALID,
161         .formats = SNDRV_PCM_FMTBIT_S16_LE,
162
163         .rates =                SNDRV_PCM_RATE_CONTINUOUS,
164         .rate_min =             48000,
165         .rate_max =             48000,
166         .channels_min = 2,
167         .channels_max = 2,
168         .period_bytes_min = 64,
169         .period_bytes_max = 12544,
170         .periods_min = 1,
171         .periods_max = 98,
172         .buffer_bytes_max = 62720 * 8,
173 };
174
175 /*
176  * audio pcm capture open callback
177  */
178 static int snd_tm6000_pcm_open(struct snd_pcm_substream *substream)
179 {
180         struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
181         struct snd_pcm_runtime *runtime = substream->runtime;
182         int err;
183
184         err = snd_pcm_hw_constraint_pow2(runtime, 0,
185                                          SNDRV_PCM_HW_PARAM_PERIODS);
186         if (err < 0)
187                 goto _error;
188
189         chip->substream = substream;
190
191         runtime->hw = snd_tm6000_digital_hw;
192
193         return 0;
194 _error:
195         dprintk(1, "Error opening PCM!\n");
196         return err;
197 }
198
199 /*
200  * audio close callback
201  */
202 static int snd_tm6000_close(struct snd_pcm_substream *substream)
203 {
204         struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
205         struct tm6000_core *core = chip->core;
206
207         if (atomic_read(&core->stream_started) > 0) {
208                 atomic_set(&core->stream_started, 0);
209                 schedule_work(&core->wq_trigger);
210         }
211
212         return 0;
213 }
214
215 static int tm6000_fillbuf(struct tm6000_core *core, char *buf, int size)
216 {
217         struct snd_tm6000_card *chip = core->adev;
218         struct snd_pcm_substream *substream = chip->substream;
219         struct snd_pcm_runtime *runtime;
220         int period_elapsed = 0;
221         unsigned int stride, buf_pos;
222         int length;
223
224         if (atomic_read(&core->stream_started) == 0)
225                 return 0;
226
227         if (!size || !substream) {
228                 dprintk(1, "substream was NULL\n");
229                 return -EINVAL;
230         }
231
232         runtime = substream->runtime;
233         if (!runtime || !runtime->dma_area) {
234                 dprintk(1, "runtime was NULL\n");
235                 return -EINVAL;
236         }
237
238         buf_pos = chip->buf_pos;
239         stride = runtime->frame_bits >> 3;
240
241         if (stride == 0) {
242                 dprintk(1, "stride is zero\n");
243                 return -EINVAL;
244         }
245
246         length = size / stride;
247         if (length == 0) {
248                 dprintk(1, "%s: length was zero\n", __func__);
249                 return -EINVAL;
250         }
251
252         dprintk(1, "Copying %d bytes at %p[%d] - buf size=%d x %d\n", size,
253                 runtime->dma_area, buf_pos,
254                 (unsigned int)runtime->buffer_size, stride);
255
256         if (buf_pos + length >= runtime->buffer_size) {
257                 unsigned int cnt = runtime->buffer_size - buf_pos;
258                 memcpy(runtime->dma_area + buf_pos * stride, buf, cnt * stride);
259                 memcpy(runtime->dma_area, buf + cnt * stride,
260                         length * stride - cnt * stride);
261         } else
262                 memcpy(runtime->dma_area + buf_pos * stride, buf,
263                         length * stride);
264
265 #ifndef NO_PCM_LOCK
266        snd_pcm_stream_lock(substream);
267 #endif
268
269         chip->buf_pos += length;
270         if (chip->buf_pos >= runtime->buffer_size)
271                 chip->buf_pos -= runtime->buffer_size;
272
273         chip->period_pos += length;
274         if (chip->period_pos >= runtime->period_size) {
275                 chip->period_pos -= runtime->period_size;
276                 period_elapsed = 1;
277         }
278
279 #ifndef NO_PCM_LOCK
280        snd_pcm_stream_unlock(substream);
281 #endif
282
283         if (period_elapsed)
284                 snd_pcm_period_elapsed(substream);
285
286         return 0;
287 }
288
289 /*
290  * hw_params callback
291  */
292 static int snd_tm6000_hw_params(struct snd_pcm_substream *substream,
293                               struct snd_pcm_hw_params *hw_params)
294 {
295         int size, rc;
296
297         size = params_period_bytes(hw_params) * params_periods(hw_params);
298
299         rc = dsp_buffer_alloc(substream, size);
300         if (rc < 0)
301                 return rc;
302
303         return 0;
304 }
305
306 /*
307  * hw free callback
308  */
309 static int snd_tm6000_hw_free(struct snd_pcm_substream *substream)
310 {
311         struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
312         struct tm6000_core *core = chip->core;
313
314         if (atomic_read(&core->stream_started) > 0) {
315                 atomic_set(&core->stream_started, 0);
316                 schedule_work(&core->wq_trigger);
317         }
318
319         return 0;
320 }
321
322 /*
323  * prepare callback
324  */
325 static int snd_tm6000_prepare(struct snd_pcm_substream *substream)
326 {
327         struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
328
329         chip->buf_pos = 0;
330         chip->period_pos = 0;
331
332         return 0;
333 }
334
335
336 /*
337  * trigger callback
338  */
339 static void audio_trigger(struct work_struct *work)
340 {
341         struct tm6000_core *core = container_of(work, struct tm6000_core,
342                                                 wq_trigger);
343         struct snd_tm6000_card *chip = core->adev;
344
345         if (atomic_read(&core->stream_started)) {
346                 dprintk(1, "starting capture");
347                 _tm6000_start_audio_dma(chip);
348         } else {
349                 dprintk(1, "stopping capture");
350                 _tm6000_stop_audio_dma(chip);
351         }
352 }
353
354 static int snd_tm6000_card_trigger(struct snd_pcm_substream *substream, int cmd)
355 {
356         struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
357         struct tm6000_core *core = chip->core;
358         int err = 0;
359
360         switch (cmd) {
361         case SNDRV_PCM_TRIGGER_START:
362                 atomic_set(&core->stream_started, 1);
363                 break;
364         case SNDRV_PCM_TRIGGER_STOP:
365                 atomic_set(&core->stream_started, 0);
366                 break;
367         default:
368                 err = -EINVAL;
369                 break;
370         }
371         schedule_work(&core->wq_trigger);
372
373         return err;
374 }
375 /*
376  * pointer callback
377  */
378 static snd_pcm_uframes_t snd_tm6000_pointer(struct snd_pcm_substream *substream)
379 {
380         struct snd_tm6000_card *chip = snd_pcm_substream_chip(substream);
381
382         return chip->buf_pos;
383 }
384
385 /*
386  * operators
387  */
388 static struct snd_pcm_ops snd_tm6000_pcm_ops = {
389         .open = snd_tm6000_pcm_open,
390         .close = snd_tm6000_close,
391         .ioctl = snd_pcm_lib_ioctl,
392         .hw_params = snd_tm6000_hw_params,
393         .hw_free = snd_tm6000_hw_free,
394         .prepare = snd_tm6000_prepare,
395         .trigger = snd_tm6000_card_trigger,
396         .pointer = snd_tm6000_pointer,
397 };
398
399 /*
400  * create a PCM device
401  */
402
403 /* FIXME: Control interface - How to control volume/mute? */
404
405 /****************************************************************************
406                         Basic Flow for Sound Devices
407  ****************************************************************************/
408
409 /*
410  * Alsa Constructor - Component probe
411  */
412 int tm6000_audio_init(struct tm6000_core *dev)
413 {
414         struct snd_card         *card;
415         struct snd_tm6000_card  *chip;
416         int                     rc;
417         static int              devnr;
418         char                    component[14];
419         struct snd_pcm          *pcm;
420
421         if (!dev)
422                 return 0;
423
424         if (devnr >= SNDRV_CARDS)
425                 return -ENODEV;
426
427         if (!enable[devnr])
428                 return -ENOENT;
429
430         rc = snd_card_create(index[devnr], "tm6000", THIS_MODULE, 0, &card);
431         if (rc < 0) {
432                 snd_printk(KERN_ERR "cannot create card instance %d\n", devnr);
433                 return rc;
434         }
435         strcpy(card->driver, "tm6000-alsa");
436         strcpy(card->shortname, "TM5600/60x0");
437         sprintf(card->longname, "TM5600/60x0 Audio at bus %d device %d",
438                 dev->udev->bus->busnum, dev->udev->devnum);
439
440         sprintf(component, "USB%04x:%04x",
441                 le16_to_cpu(dev->udev->descriptor.idVendor),
442                 le16_to_cpu(dev->udev->descriptor.idProduct));
443         snd_component_add(card, component);
444         snd_card_set_dev(card, &dev->udev->dev);
445
446         chip = kzalloc(sizeof(struct snd_tm6000_card), GFP_KERNEL);
447         if (!chip) {
448                 rc = -ENOMEM;
449                 goto error;
450         }
451
452         chip->core = dev;
453         chip->card = card;
454         dev->adev = chip;
455         spin_lock_init(&chip->reg_lock);
456
457         rc = snd_pcm_new(card, "TM6000 Audio", 0, 0, 1, &pcm);
458         if (rc < 0)
459                 goto error_chip;
460
461         pcm->info_flags = 0;
462         pcm->private_data = chip;
463         strcpy(pcm->name, "Trident TM5600/60x0");
464
465         snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_tm6000_pcm_ops);
466
467         INIT_WORK(&dev->wq_trigger, audio_trigger);
468         rc = snd_card_register(card);
469         if (rc < 0)
470                 goto error_chip;
471
472         dprintk(1,"Registered audio driver for %s\n", card->longname);
473
474         return 0;
475
476 error_chip:
477         kfree(chip);
478         dev->adev = NULL;
479 error:
480         snd_card_free(card);
481         return rc;
482 }
483
484 static int tm6000_audio_fini(struct tm6000_core *dev)
485 {
486         struct snd_tm6000_card  *chip = dev->adev;
487
488         if (!dev)
489                 return 0;
490
491         if (!chip)
492                 return 0;
493
494         if (!chip->card)
495                 return 0;
496
497         snd_card_free(chip->card);
498         chip->card = NULL;
499         kfree(chip);
500         dev->adev = NULL;
501
502         return 0;
503 }
504
505 struct tm6000_ops audio_ops = {
506         .type   = TM6000_AUDIO,
507         .name   = "TM6000 Audio Extension",
508         .init   = tm6000_audio_init,
509         .fini   = tm6000_audio_fini,
510         .fillbuf = tm6000_fillbuf,
511 };
512
513 static int __init tm6000_alsa_register(void)
514 {
515         return tm6000_register_extension(&audio_ops);
516 }
517
518 static void __exit tm6000_alsa_unregister(void)
519 {
520         tm6000_unregister_extension(&audio_ops);
521 }
522
523 module_init(tm6000_alsa_register);
524 module_exit(tm6000_alsa_unregister);