Linux Audio

Check our new training course

Embedded Linux Audio

Check our new training course
with Creative Commons CC-BY-SA
lecture materials

Bootlin logo

Elixir Cross Referencer

Loading...
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
/*
 * Driver for Digigram VX soundcards
 *
 * Hardware core part
 *
 * Copyright (c) 2002 by Takashi Iwai <tiwai@suse.de>
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation; either version 2 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program; if not, write to the Free Software
 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 */

#ifndef __SOUND_VX_COMMON_H
#define __SOUND_VX_COMMON_H

#include <sound/pcm.h>
#include <sound/hwdep.h>
#include <linux/interrupt.h>

typedef struct snd_vx_core vx_core_t;
typedef struct vx_pipe vx_pipe_t;

#define VX_DRIVER_VERSION	0x010000	/* 1.0.0 */

/*
 */
#define SIZE_MAX_CMD    0x10
#define SIZE_MAX_STATUS 0x10

struct vx_rmh {
	u16	LgCmd;		/* length of the command to send (WORDs) */
	u16	LgStat;		/* length of the status received (WORDs) */
	u32	Cmd[SIZE_MAX_CMD];
	u32	Stat[SIZE_MAX_STATUS];
	u16	DspStat;	/* status type, RMP_SSIZE_XXX */
};
	
typedef u64 pcx_time_t;

#define VX_MAX_PIPES	16
#define VX_MAX_PERIODS	32
#define VX_MAX_CODECS	2

struct vx_ibl_info {
	int size;	/* the current IBL size (0 = query) in bytes */
	int max_size;	/* max. IBL size in bytes */
	int min_size;	/* min. IBL size in bytes */
	int granularity;	/* granularity */
};

struct vx_pipe {
	int number;
	unsigned int is_capture: 1;
	unsigned int data_mode: 1;
	unsigned int running: 1;
	unsigned int prepared: 1;
	int channels;
	unsigned int differed_type;
	pcx_time_t pcx_time;
	snd_pcm_substream_t *substream;

	int hbuf_size;		/* H-buffer size in bytes */
	int buffer_bytes;	/* the ALSA pcm buffer size in bytes */
	int period_bytes;	/* the ALSA pcm period size in bytes */
	int hw_ptr;		/* the current hardware pointer in bytes */
	int position;		/* the current position in frames (playback only) */
	int transferred;	/* the transferred size (per period) in frames */
	int align;		/* size of alignment */
	u64 cur_count;		/* current sample position (for playback) */

	unsigned int references;     /* an output pipe may be used for monitoring and/or playback */
	vx_pipe_t *monitoring_pipe;  /* pointer to the monitoring pipe (capture pipe only)*/

	struct tasklet_struct start_tq;
};

struct snd_vx_ops {
	/* low-level i/o */
	unsigned char (*in8)(vx_core_t *chip, int reg);
	unsigned int (*in32)(vx_core_t *chip, int reg);
	void (*out8)(vx_core_t *chip, int reg, unsigned char val);
	void (*out32)(vx_core_t *chip, int reg, unsigned int val);
	/* irq */
	int (*test_and_ack)(vx_core_t *chip);
	void (*validate_irq)(vx_core_t *chip, int enable);
	/* codec */
	void (*write_codec)(vx_core_t *chip, int codec, unsigned int data);
	void (*akm_write)(vx_core_t *chip, int reg, unsigned int data);
	void (*reset_codec)(vx_core_t *chip);
	void (*change_audio_source)(vx_core_t *chip, int src);
	void (*set_clock_source)(vx_core_t *chp, int src);
	/* chip init */
	int (*load_dsp)(vx_core_t *chip, const snd_hwdep_dsp_image_t *dsp);
	void (*reset_dsp)(vx_core_t *chip);
	void (*reset_board)(vx_core_t *chip, int cold_reset);
	int (*add_controls)(vx_core_t *chip);
	/* pcm */
	void (*dma_write)(vx_core_t *chip, snd_pcm_runtime_t *runtime,
			  vx_pipe_t *pipe, int count);
	void (*dma_read)(vx_core_t *chip, snd_pcm_runtime_t *runtime,
			  vx_pipe_t *pipe, int count);
};

struct snd_vx_hardware {
	const char *name;
	int type;	/* VX_TYPE_XXX */

	/* hardware specs */
	unsigned int num_codecs;
	unsigned int num_ins;
	unsigned int num_outs;
	unsigned int output_level_max;
};

/* hwdep id string */
#define SND_VX_HWDEP_ID		"VX Loader"

/* hardware type */
enum {
	/* VX222 PCI */
	VX_TYPE_BOARD,		/* old VX222 PCI */
	VX_TYPE_V2,		/* VX222 V2 PCI */
	VX_TYPE_MIC,		/* VX222 Mic PCI */
	/* VX-pocket */
	VX_TYPE_VXPOCKET,	/* VXpocket V2 */
	VX_TYPE_VXP440,		/* VXpocket 440 */
	VX_TYPE_NUMS
};

/* chip status */
enum {
	VX_STAT_XILINX_LOADED	= (1 << 0),	/* devices are registered */
	VX_STAT_DEVICE_INIT	= (1 << 1),	/* devices are registered */
	VX_STAT_CHIP_INIT	= (1 << 2),	/* all operational */
	VX_STAT_IN_SUSPEND	= (1 << 10),	/* in suspend phase */
	VX_STAT_IS_STALE	= (1 << 15)	/* device is stale */
};

/* min/max values for analog output for old codecs */
#define VX_ANALOG_OUT_LEVEL_MAX		0xe3

struct snd_vx_core {
	/* ALSA stuff */
	snd_card_t *card;
	snd_pcm_t *pcm[VX_MAX_CODECS];
	int type;	/* VX_TYPE_XXX */

	int irq;
	/* ports are defined externally */

	/* low-level functions */
	struct snd_vx_hardware *hw;
	struct snd_vx_ops *ops;

	spinlock_t lock;
	spinlock_t irq_lock;
	struct tasklet_struct tq;

	unsigned int chip_status;
	unsigned int pcm_running;

	snd_hwdep_t *hwdep;

	struct vx_rmh irq_rmh;	/* RMH used in interrupts */

	unsigned int audio_info; /* see VX_AUDIO_INFO */
	unsigned int audio_ins;
	unsigned int audio_outs;
	struct vx_pipe **playback_pipes;
	struct vx_pipe **capture_pipes;

	/* clock and audio sources */
	unsigned int audio_source;	/* current audio input source */
	unsigned int audio_source_target;
	unsigned int clock_source;	/* current clock source (INTERNAL_QUARTZ or UER_SYNC) */
	unsigned int freq;		/* current frequency */
	unsigned int freq_detected;	/* detected frequency from digital in */
	unsigned int uer_detected;	/* VX_UER_MODE_XXX */
	unsigned int uer_bits;	/* IEC958 status bits */
	struct vx_ibl_info ibl;	/* IBL information */

	/* mixer setting */
	int output_level[VX_MAX_CODECS][2];	/* analog output level */
	int audio_gain[2][4];			/* digital audio level (playback/capture) */
	unsigned char audio_active[4];		/* mute/unmute on digital playback */
	int audio_monitor[4];			/* playback hw-monitor level */
	unsigned char audio_monitor_active[4];	/* playback hw-monitor mute/unmute */

	struct semaphore mixer_mutex;
};


/*
 * constructor
 */
vx_core_t *snd_vx_create(snd_card_t *card, struct snd_vx_hardware *hw,
			 struct snd_vx_ops *ops, int extra_size);
int snd_vx_hwdep_new(vx_core_t *chip);
int snd_vx_load_boot_image(vx_core_t *chip, const snd_hwdep_dsp_image_t *boot);
int snd_vx_dsp_boot(vx_core_t *chip, const snd_hwdep_dsp_image_t *boot);
int snd_vx_dsp_load(vx_core_t *chip, const snd_hwdep_dsp_image_t *dsp);

/*
 * interrupt handler; exported for pcmcia
 */
irqreturn_t snd_vx_irq_handler(int irq, void *dev, struct pt_regs *regs);

/*
 * power-management routines
 */
#ifdef CONFIG_PM
void snd_vx_suspend(vx_core_t *chip);
void snd_vx_resume(vx_core_t *chip);
#endif


/*
 * lowlevel functions
 */
inline static int vx_test_and_ack(vx_core_t *chip)
{
	snd_assert(chip->ops->test_and_ack, return -ENXIO);
	return chip->ops->test_and_ack(chip);
}

inline static void vx_validate_irq(vx_core_t *chip, int enable)
{
	snd_assert(chip->ops->validate_irq, return);
	chip->ops->validate_irq(chip, enable);
}

inline static unsigned char snd_vx_inb(vx_core_t *chip, int reg)
{
	snd_assert(chip->ops->in8, return 0);
	return chip->ops->in8(chip, reg);
}

inline static unsigned int snd_vx_inl(vx_core_t *chip, int reg)
{
	snd_assert(chip->ops->in32, return 0);
	return chip->ops->in32(chip, reg);
}

inline static void snd_vx_outb(vx_core_t *chip, int reg, unsigned char val)
{
	snd_assert(chip->ops->out8, return);
	chip->ops->out8(chip, reg, val);
}

inline static void snd_vx_outl(vx_core_t *chip, int reg, unsigned int val)
{
	snd_assert(chip->ops->out32, return);
	chip->ops->out32(chip, reg, val);
}

#define vx_inb(chip,reg)	snd_vx_inb(chip, VX_##reg)
#define vx_outb(chip,reg,val)	snd_vx_outb(chip, VX_##reg,val)
#define vx_inl(chip,reg)	snd_vx_inl(chip, VX_##reg)
#define vx_outl(chip,reg,val)	snd_vx_outl(chip, VX_##reg,val)

void snd_vx_delay(vx_core_t *chip, int msec);

static inline void vx_reset_dsp(vx_core_t *chip)
{
	snd_assert(chip->ops->reset_dsp, return);
	chip->ops->reset_dsp(chip);
}

int vx_send_msg(vx_core_t *chip, struct vx_rmh *rmh);
int vx_send_msg_nolock(vx_core_t *chip, struct vx_rmh *rmh);
int vx_send_rih(vx_core_t *chip, int cmd);
int vx_send_rih_nolock(vx_core_t *chip, int cmd);

void vx_reset_codec(vx_core_t *chip, int cold_reset);

/*
 * check the bit on the specified register
 * returns zero if a bit matches, or a negative error code.
 * exported for vxpocket driver
 */
int snd_vx_check_reg_bit(vx_core_t *chip, int reg, int mask, int bit, int time);
#define vx_check_isr(chip,mask,bit,time) snd_vx_check_reg_bit(chip, VX_ISR, mask, bit, time)
#define vx_wait_isr_bit(chip,bit) vx_check_isr(chip, bit, bit, 200)
#define vx_wait_for_rx_full(chip) vx_wait_isr_bit(chip, ISR_RX_FULL)


/*
 * pseudo-DMA transfer
 */
inline static void vx_pseudo_dma_write(vx_core_t *chip, snd_pcm_runtime_t *runtime,
				       vx_pipe_t *pipe, int count)
{
	snd_assert(chip->ops->dma_write, return);
	chip->ops->dma_write(chip, runtime, pipe, count);
}

inline static void vx_pseudo_dma_read(vx_core_t *chip, snd_pcm_runtime_t *runtime,
				      vx_pipe_t *pipe, int count)
{
	snd_assert(chip->ops->dma_read, return);
	chip->ops->dma_read(chip, runtime, pipe, count);
}



/* error with hardware code,
 * the return value is -(VX_ERR_MASK | actual-hw-error-code)
 */
#define VX_ERR_MASK	0x1000000
#define vx_get_error(err)	(-(err) & ~VX_ERR_MASK)


/*
 * pcm stuff
 */
int snd_vx_pcm_new(vx_core_t *chip);
void vx_pcm_update_intr(vx_core_t *chip, unsigned int events);

/*
 * mixer stuff
 */
int snd_vx_mixer_new(vx_core_t *chip);
void vx_toggle_dac_mute(vx_core_t *chip, int mute);
int vx_sync_audio_source(vx_core_t *chip);
int vx_set_monitor_level(vx_core_t *chip, int audio, int level, int active);

/*
 * IEC958 & clock stuff
 */
void vx_set_iec958_status(vx_core_t *chip, unsigned int bits);
int vx_set_clock(vx_core_t *chip, unsigned int freq);
void vx_change_clock_source(vx_core_t *chip, int source);
void vx_set_internal_clock(vx_core_t *chip, unsigned int freq);
int vx_change_frequency(vx_core_t *chip);


/*
 * hardware constants
 */

#define vx_has_new_dsp(chip)	((chip)->type != VX_TYPE_BOARD)
#define vx_is_pcmcia(chip)	((chip)->type >= VX_TYPE_VXPOCKET)

/* audio input source */
enum {
	VX_AUDIO_SRC_DIGITAL,
	VX_AUDIO_SRC_LINE,
	VX_AUDIO_SRC_MIC
};

/* clock source */
enum {
	INTERNAL_QUARTZ,
	UER_SYNC
};

/* SPDIF/UER type */
enum {
	VX_UER_MODE_CONSUMER,
	VX_UER_MODE_PROFESSIONAL,
	VX_UER_MODE_NOT_PRESENT,
};

/* register indices */
enum {
	VX_ICR,
	VX_CVR,
	VX_ISR,
	VX_IVR,
	VX_RXH,
	VX_TXH = VX_RXH,
	VX_RXM,
	VX_TXM = VX_RXM,
	VX_RXL,
	VX_TXL = VX_RXL,
	VX_DMA,
	VX_CDSP,
	VX_RFREQ,
	VX_RUER_V2,
	VX_GAIN,
	VX_DATA = VX_GAIN,
	VX_MEMIRQ,
	VX_ACQ,
	VX_BIT0,
	VX_BIT1,
	VX_MIC0,
	VX_MIC1,
	VX_MIC2,
	VX_MIC3,
	VX_PLX0,
	VX_PLX1,
	VX_PLX2,

	VX_LOFREQ,  // V2: ACQ, VP: RFREQ
	VX_HIFREQ,  // V2: BIT0, VP: RUER_V2
	VX_CSUER,   // V2: BIT1, VP: BIT0
	VX_RUER,    // V2: RUER_V2, VP: BIT1

	VX_REG_MAX,

	/* aliases for VX board */
	VX_RESET_DMA = VX_ISR,
	VX_CFG = VX_RFREQ,
	VX_STATUS = VX_MEMIRQ,
	VX_SELMIC = VX_MIC0,
	VX_COMPOT = VX_MIC1,
	VX_SCOMPR = VX_MIC2,
	VX_GLIMIT = VX_MIC3,
	VX_INTCSR = VX_PLX0,
	VX_CNTRL = VX_PLX1,
	VX_GPIOC = VX_PLX2,

	/* aliases for VXPOCKET board */
	VX_MICRO = VX_MEMIRQ,
	VX_CODEC2 = VX_MEMIRQ,
	VX_DIALOG = VX_ACQ,

};

/* RMH status type */
enum {
	RMH_SSIZE_FIXED = 0,	/* status size given by the driver (in LgStat) */
	RMH_SSIZE_ARG = 1,	/* status size given in the LSB byte */
	RMH_SSIZE_MASK = 2,	/* status size given in bitmask */
};


/* bits for ICR register */
#define ICR_HF1		0x10
#define ICR_HF0		0x08
#define ICR_TREQ	0x02	/* Interrupt mode + HREQ set on for transfer (->DSP) request */
#define ICR_RREQ	0x01	/* Interrupt mode + RREQ set on for transfer (->PC) request */

/* bits for CVR register */
#define CVR_HC		0x80

/* bits for ISR register */
#define ISR_HF3		0x10
#define ISR_HF2		0x08
#define ISR_CHK		0x10
#define ISR_ERR		0x08
#define ISR_TX_READY	0x04
#define ISR_TX_EMPTY	0x02
#define ISR_RX_FULL	0x01

/* Constants used to access the DATA register */
#define VX_DATA_CODEC_MASK	0x80
#define VX_DATA_XICOR_MASK	0x80

/* Constants used to access the CSUER register (both for VX2 and VXP) */
#define VX_SUER_FREQ_MASK		0x0c
#define VX_SUER_FREQ_32KHz_MASK		0x0c
#define VX_SUER_FREQ_44KHz_MASK		0x00
#define VX_SUER_FREQ_48KHz_MASK		0x04
#define VX_SUER_DATA_PRESENT_MASK	0x02
#define VX_SUER_CLOCK_PRESENT_MASK	0x01

#define VX_CUER_HH_BITC_SEL_MASK	0x08
#define VX_CUER_MH_BITC_SEL_MASK	0x04
#define VX_CUER_ML_BITC_SEL_MASK	0x02
#define VX_CUER_LL_BITC_SEL_MASK	0x01

#define XX_UER_CBITS_OFFSET_MASK	0x1f


/* bits for audio_info */
#define VX_AUDIO_INFO_REAL_TIME	(1<<0)	/* real-time processing available */
#define VX_AUDIO_INFO_OFFLINE	(1<<1)	/* offline processing available */
#define VX_AUDIO_INFO_MPEG1	(1<<5)
#define VX_AUDIO_INFO_MPEG2	(1<<6)
#define VX_AUDIO_INFO_LINEAR_8	(1<<7)
#define VX_AUDIO_INFO_LINEAR_16	(1<<8)
#define VX_AUDIO_INFO_LINEAR_24	(1<<9)

/* DSP Interrupt Request values */
#define VXP_IRQ_OFFSET		0x40 /* add 0x40 offset for vxpocket and vx222/v2 */
/* call with vx_send_irq_dsp() */
#define IRQ_MESS_WRITE_END          0x30
#define IRQ_MESS_WRITE_NEXT         0x32
#define IRQ_MESS_READ_NEXT          0x34
#define IRQ_MESS_READ_END           0x36
#define IRQ_MESSAGE                 0x38
#define IRQ_RESET_CHK               0x3A
#define IRQ_CONNECT_STREAM_NEXT     0x26
#define IRQ_CONNECT_STREAM_END      0x28
#define IRQ_PAUSE_START_CONNECT     0x2A
#define IRQ_END_CONNECTION          0x2C

/* Is there async. events pending ( IT Source Test ) */
#define ASYNC_EVENTS_PENDING            0x008000
#define HBUFFER_EVENTS_PENDING          0x004000   // Not always accurate
#define NOTIF_EVENTS_PENDING            0x002000
#define TIME_CODE_EVENT_PENDING         0x001000
#define FREQUENCY_CHANGE_EVENT_PENDING  0x000800
#define END_OF_BUFFER_EVENTS_PENDING    0x000400
#define FATAL_DSP_ERROR                 0xff0000

/* Stream Format Header Defines */ 
#define HEADER_FMT_BASE			0xFED00000
#define HEADER_FMT_MONO			0x000000C0
#define HEADER_FMT_INTEL		0x00008000
#define HEADER_FMT_16BITS		0x00002000
#define HEADER_FMT_24BITS		0x00004000
#define HEADER_FMT_UPTO11		0x00000200	/* frequency is less or equ. to 11k.*/
#define HEADER_FMT_UPTO32		0x00000100	/* frequency is over 11k and less then 32k.*/

/* Constants used to access the Codec */
#define XX_CODEC_SELECTOR               0x20
/* codec commands */
#define XX_CODEC_ADC_CONTROL_REGISTER   0x01
#define XX_CODEC_DAC_CONTROL_REGISTER   0x02
#define XX_CODEC_LEVEL_LEFT_REGISTER    0x03
#define XX_CODEC_LEVEL_RIGHT_REGISTER   0x04
#define XX_CODEC_PORT_MODE_REGISTER     0x05
#define XX_CODEC_STATUS_REPORT_REGISTER 0x06
#define XX_CODEC_CLOCK_CONTROL_REGISTER 0x07

/*
 * Audio-level control values
 */
#define CVAL_M110DB		0x000	/* -110dB */
#define CVAL_M99DB		0x02C
#define CVAL_M21DB		0x163
#define CVAL_M18DB		0x16F
#define CVAL_M10DB		0x18F
#define CVAL_0DB		0x1B7
#define CVAL_18DB		0x1FF	/* +18dB */
#define CVAL_MAX		0x1FF

#define AUDIO_IO_HAS_MUTE_LEVEL			0x400000
#define AUDIO_IO_HAS_MUTE_MONITORING_1		0x200000
#define AUDIO_IO_HAS_MUTE_MONITORING_2		0x100000
#define VALID_AUDIO_IO_DIGITAL_LEVEL		0x01
#define VALID_AUDIO_IO_MONITORING_LEVEL		0x02
#define VALID_AUDIO_IO_MUTE_LEVEL		0x04
#define VALID_AUDIO_IO_MUTE_MONITORING_1	0x08
#define VALID_AUDIO_IO_MUTE_MONITORING_2	0x10


#endif /* __SOUND_VX_COMMON_H */