📄 dbri.c
字号:
/* * Driver for DBRI sound chip found on Sparcs. * Copyright (C) 2004, 2005 Martin Habets (mhabets@users.sourceforge.net) * * Converted to ring buffered version by Krzysztof Helt (krzysztof.h1@wp.pl) * * Based entirely upon drivers/sbus/audio/dbri.c which is: * Copyright (C) 1997 Rudolf Koenig (rfkoenig@immd4.informatik.uni-erlangen.de) * Copyright (C) 1998, 1999 Brent Baccala (baccala@freesoft.org) * * This is the low level driver for the DBRI & MMCODEC duo used for ISDN & AUDIO * on Sun SPARCStation 10, 20, LX and Voyager models. * * - DBRI: AT&T T5900FX Dual Basic Rates ISDN Interface. It is a 32 channel * data time multiplexer with ISDN support (aka T7259) * Interfaces: SBus,ISDN NT & TE, CHI, 4 bits parallel. * CHI: (spelled ki) Concentration Highway Interface (AT&T or Intel bus ?). * Documentation: * - "STP 4000SBus Dual Basic Rate ISDN (DBRI) Transceiver" from * Sparc Technology Business (courtesy of Sun Support) * - Data sheet of the T7903, a newer but very similar ISA bus equivalent * available from the Lucent (formerly AT&T microelectronics) home * page. * - http://www.freesoft.org/Linux/DBRI/ * - MMCODEC: Crystal Semiconductor CS4215 16 bit Multimedia Audio Codec * Interfaces: CHI, Audio In & Out, 2 bits parallel * Documentation: from the Crystal Semiconductor home page. * * The DBRI is a 32 pipe machine, each pipe can transfer some bits between * memory and a serial device (long pipes, no. 0-15) or between two serial * devices (short pipes, no. 16-31), or simply send a fixed data to a serial * device (short pipes). * A timeslot defines the bit-offset and no. of bits read from a serial device. * The timeslots are linked to 6 circular lists, one for each direction for * each serial device (NT,TE,CHI). A timeslot is associated to 1 or 2 pipes * (the second one is a monitor/tee pipe, valid only for serial input). * * The mmcodec is connected via the CHI bus and needs the data & some * parameters (volume, output selection) time multiplexed in 8 byte * chunks. It also has a control mode, which serves for audio format setting. * * Looking at the CS4215 data sheet it is easy to set up 2 or 4 codecs on * the same CHI bus, so I thought perhaps it is possible to use the on-board * & the speakerbox codec simultaneously, giving 2 (not very independent :-) * audio devices. But the SUN HW group decided against it, at least on my * LX the speakerbox connector has at least 1 pin missing and 1 wrongly * connected. * * I've tried to stick to the following function naming conventions: * snd_* ALSA stuff * cs4215_* CS4215 codec specific stuff * dbri_* DBRI high-level stuff * other DBRI low-level stuff */#include <sound/driver.h>#include <linux/interrupt.h>#include <linux/delay.h>#include <linux/irq.h>#include <linux/io.h>#include <sound/core.h>#include <sound/pcm.h>#include <sound/pcm_params.h>#include <sound/info.h>#include <sound/control.h>#include <sound/initval.h>#include <linux/of.h>#include <asm/sbus.h>#include <asm/atomic.h>MODULE_AUTHOR("Rudolf Koenig, Brent Baccala and Martin Habets");MODULE_DESCRIPTION("Sun DBRI");MODULE_LICENSE("GPL");MODULE_SUPPORTED_DEVICE("{{Sun,DBRI}}");static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card *//* Enable this card */static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;module_param_array(index, int, NULL, 0444);MODULE_PARM_DESC(index, "Index value for Sun DBRI soundcard.");module_param_array(id, charp, NULL, 0444);MODULE_PARM_DESC(id, "ID string for Sun DBRI soundcard.");module_param_array(enable, bool, NULL, 0444);MODULE_PARM_DESC(enable, "Enable Sun DBRI soundcard.");#undef DBRI_DEBUG#define D_INT (1<<0)#define D_GEN (1<<1)#define D_CMD (1<<2)#define D_MM (1<<3)#define D_USR (1<<4)#define D_DESC (1<<5)static int dbri_debug;module_param(dbri_debug, int, 0644);MODULE_PARM_DESC(dbri_debug, "Debug value for Sun DBRI soundcard.");#ifdef DBRI_DEBUGstatic char *cmds[] = { "WAIT", "PAUSE", "JUMP", "IIQ", "REX", "SDP", "CDP", "DTS", "SSP", "CHI", "NT", "TE", "CDEC", "TEST", "CDM", "RESRV"};#define dprintk(a, x...) if (dbri_debug & a) printk(KERN_DEBUG x)#else#define dprintk(a, x...) do { } while (0)#endif /* DBRI_DEBUG */#define DBRI_CMD(cmd, intr, value) ((cmd << 28) | \ (intr << 27) | \ value)/*************************************************************************** CS4215 specific definitions and structures****************************************************************************/struct cs4215 { __u8 data[4]; /* Data mode: Time slots 5-8 */ __u8 ctrl[4]; /* Ctrl mode: Time slots 1-4 */ __u8 onboard; __u8 offset; /* Bit offset from frame sync to time slot 1 */ volatile __u32 status; volatile __u32 version; __u8 precision; /* In bits, either 8 or 16 */ __u8 channels; /* 1 or 2 */};/* * Control mode first *//* Time Slot 1, Status register */#define CS4215_CLB (1<<2) /* Control Latch Bit */#define CS4215_OLB (1<<3) /* 1: line: 2.0V, speaker 4V */ /* 0: line: 2.8V, speaker 8V */#define CS4215_MLB (1<<4) /* 1: Microphone: 20dB gain disabled */#define CS4215_RSRVD_1 (1<<5)/* Time Slot 2, Data Format Register */#define CS4215_DFR_LINEAR16 0#define CS4215_DFR_ULAW 1#define CS4215_DFR_ALAW 2#define CS4215_DFR_LINEAR8 3#define CS4215_DFR_STEREO (1<<2)static struct { unsigned short freq; unsigned char xtal; unsigned char csval;} CS4215_FREQ[] = { { 8000, (1 << 4), (0 << 3) }, { 16000, (1 << 4), (1 << 3) }, { 27429, (1 << 4), (2 << 3) }, /* Actually 24428.57 */ { 32000, (1 << 4), (3 << 3) }, /* { NA, (1 << 4), (4 << 3) }, */ /* { NA, (1 << 4), (5 << 3) }, */ { 48000, (1 << 4), (6 << 3) }, { 9600, (1 << 4), (7 << 3) }, { 5512, (2 << 4), (0 << 3) }, /* Actually 5512.5 */ { 11025, (2 << 4), (1 << 3) }, { 18900, (2 << 4), (2 << 3) }, { 22050, (2 << 4), (3 << 3) }, { 37800, (2 << 4), (4 << 3) }, { 44100, (2 << 4), (5 << 3) }, { 33075, (2 << 4), (6 << 3) }, { 6615, (2 << 4), (7 << 3) }, { 0, 0, 0}};#define CS4215_HPF (1<<7) /* High Pass Filter, 1: Enabled */#define CS4215_12_MASK 0xfcbf /* Mask off reserved bits in slot 1 & 2 *//* Time Slot 3, Serial Port Control register */#define CS4215_XEN (1<<0) /* 0: Enable serial output */#define CS4215_XCLK (1<<1) /* 1: Master mode: Generate SCLK */#define CS4215_BSEL_64 (0<<2) /* Bitrate: 64 bits per frame */#define CS4215_BSEL_128 (1<<2)#define CS4215_BSEL_256 (2<<2)#define CS4215_MCK_MAST (0<<4) /* Master clock */#define CS4215_MCK_XTL1 (1<<4) /* 24.576 MHz clock source */#define CS4215_MCK_XTL2 (2<<4) /* 16.9344 MHz clock source */#define CS4215_MCK_CLK1 (3<<4) /* Clockin, 256 x Fs */#define CS4215_MCK_CLK2 (4<<4) /* Clockin, see DFR *//* Time Slot 4, Test Register */#define CS4215_DAD (1<<0) /* 0:Digital-Dig loop, 1:Dig-Analog-Dig loop */#define CS4215_ENL (1<<1) /* Enable Loopback Testing *//* Time Slot 5, Parallel Port Register *//* Read only here and the same as the in data mode *//* Time Slot 6, Reserved *//* Time Slot 7, Version Register */#define CS4215_VERSION_MASK 0xf /* Known versions 0/C, 1/D, 2/E *//* Time Slot 8, Reserved *//* * Data mode *//* Time Slot 1-2: Left Channel Data, 2-3: Right Channel Data *//* Time Slot 5, Output Setting */#define CS4215_LO(v) v /* Left Output Attenuation 0x3f: -94.5 dB */#define CS4215_LE (1<<6) /* Line Out Enable */#define CS4215_HE (1<<7) /* Headphone Enable *//* Time Slot 6, Output Setting */#define CS4215_RO(v) v /* Right Output Attenuation 0x3f: -94.5 dB */#define CS4215_SE (1<<6) /* Speaker Enable */#define CS4215_ADI (1<<7) /* A/D Data Invalid: Busy in calibration *//* Time Slot 7, Input Setting */#define CS4215_LG(v) v /* Left Gain Setting 0xf: 22.5 dB */#define CS4215_IS (1<<4) /* Input Select: 1=Microphone, 0=Line */#define CS4215_OVR (1<<5) /* 1: Over range condition occurred */#define CS4215_PIO0 (1<<6) /* Parallel I/O 0 */#define CS4215_PIO1 (1<<7)/* Time Slot 8, Input Setting */#define CS4215_RG(v) v /* Right Gain Setting 0xf: 22.5 dB */#define CS4215_MA(v) (v<<4) /* Monitor Path Attenuation 0xf: mute *//*************************************************************************** DBRI specific definitions and structures****************************************************************************//* DBRI main registers */#define REG0 0x00 /* Status and Control */#define REG1 0x04 /* Mode and Interrupt */#define REG2 0x08 /* Parallel IO */#define REG3 0x0c /* Test */#define REG8 0x20 /* Command Queue Pointer */#define REG9 0x24 /* Interrupt Queue Pointer */#define DBRI_NO_CMDS 64#define DBRI_INT_BLK 64#define DBRI_NO_DESCS 64#define DBRI_NO_PIPES 32#define DBRI_MAX_PIPE (DBRI_NO_PIPES - 1)#define DBRI_REC 0#define DBRI_PLAY 1#define DBRI_NO_STREAMS 2/* One transmit/receive descriptor *//* When ba != 0 descriptor is used */struct dbri_mem { volatile __u32 word1; __u32 ba; /* Transmit/Receive Buffer Address */ __u32 nda; /* Next Descriptor Address */ volatile __u32 word4;};/* This structure is in a DMA region where it can accessed by both * the CPU and the DBRI */struct dbri_dma { s32 cmd[DBRI_NO_CMDS]; /* Place for commands */ volatile s32 intr[DBRI_INT_BLK]; /* Interrupt field */ struct dbri_mem desc[DBRI_NO_DESCS]; /* Xmit/receive descriptors */};#define dbri_dma_off(member, elem) \ ((u32)(unsigned long) \ (&(((struct dbri_dma *)0)->member[elem])))enum in_or_out { PIPEinput, PIPEoutput };struct dbri_pipe { u32 sdp; /* SDP command word */ int nextpipe; /* Next pipe in linked list */ int length; /* Length of timeslot (bits) */ int first_desc; /* Index of first descriptor */ int desc; /* Index of active descriptor */ volatile __u32 *recv_fixed_ptr; /* Ptr to receive fixed data */};/* Per stream (playback or record) information */struct dbri_streaminfo { struct snd_pcm_substream *substream; u32 dvma_buffer; /* Device view of ALSA DMA buffer */ int size; /* Size of DMA buffer */ size_t offset; /* offset in user buffer */ int pipe; /* Data pipe used */ int left_gain; /* mixer elements */ int right_gain;};/* This structure holds the information for both chips (DBRI & CS4215) */struct snd_dbri { int regs_size, irq; /* Needed for unload */ struct sbus_dev *sdev; /* SBUS device info */ spinlock_t lock; struct dbri_dma *dma; /* Pointer to our DMA block */ u32 dma_dvma; /* DBRI visible DMA address */ void __iomem *regs; /* dbri HW regs */ int dbri_irqp; /* intr queue pointer */ struct dbri_pipe pipes[DBRI_NO_PIPES]; /* DBRI's 32 data pipes */ int next_desc[DBRI_NO_DESCS]; /* Index of next desc, or -1 */ spinlock_t cmdlock; /* Protects cmd queue accesses */ s32 *cmdptr; /* Pointer to the last queued cmd */ int chi_bpf; struct cs4215 mm; /* mmcodec special info */ /* per stream (playback/record) info */ struct dbri_streaminfo stream_info[DBRI_NO_STREAMS];};#define DBRI_MAX_VOLUME 63 /* Output volume */#define DBRI_MAX_GAIN 15 /* Input gain *//* DBRI Reg0 - Status Control Register - defines. (Page 17) */#define D_P (1<<15) /* Program command & queue pointer valid */#define D_G (1<<14) /* Allow 4-Word SBus Burst */#define D_S (1<<13) /* Allow 16-Word SBus Burst */#define D_E (1<<12) /* Allow 8-Word SBus Burst */#define D_X (1<<7) /* Sanity Timer Disable */#define D_T (1<<6) /* Permit activation of the TE interface */#define D_N (1<<5) /* Permit activation of the NT interface */#define D_C (1<<4) /* Permit activation of the CHI interface */#define D_F (1<<3) /* Force Sanity Timer Time-Out */#define D_D (1<<2) /* Disable Master Mode */#define D_H (1<<1) /* Halt for Analysis */#define D_R (1<<0) /* Soft Reset *//* DBRI Reg1 - Mode and Interrupt Register - defines. (Page 18) */#define D_LITTLE_END (1<<8) /* Byte Order */#define D_BIG_END (0<<8) /* Byte Order */#define D_MRR (1<<4) /* Multiple Error Ack on SBus (read only) */#define D_MLE (1<<3) /* Multiple Late Error on SBus (read only) */#define D_LBG (1<<2) /* Lost Bus Grant on SBus (read only) */#define D_MBE (1<<1) /* Burst Error on SBus (read only) */#define D_IR (1<<0) /* Interrupt Indicator (read only) *//* DBRI Reg2 - Parallel IO Register - defines. (Page 18) */#define D_ENPIO3 (1<<7) /* Enable Pin 3 */#define D_ENPIO2 (1<<6) /* Enable Pin 2 */#define D_ENPIO1 (1<<5) /* Enable Pin 1 */#define D_ENPIO0 (1<<4) /* Enable Pin 0 */#define D_ENPIO (0xf0) /* Enable all the pins */#define D_PIO3 (1<<3) /* Pin 3: 1: Data mode, 0: Ctrl mode */#define D_PIO2 (1<<2) /* Pin 2: 1: Onboard PDN */#define D_PIO1 (1<<1) /* Pin 1: 0: Reset */#define D_PIO0 (1<<0) /* Pin 0: 1: Speakerbox PDN *//* DBRI Commands (Page 20) */#define D_WAIT 0x0 /* Stop execution */#define D_PAUSE 0x1 /* Flush long pipes */#define D_JUMP 0x2 /* New command queue */#define D_IIQ 0x3 /* Initialize Interrupt Queue */#define D_REX 0x4 /* Report command execution via interrupt */#define D_SDP 0x5 /* Setup Data Pipe */#define D_CDP 0x6 /* Continue Data Pipe (reread NULL Pointer) */#define D_DTS 0x7 /* Define Time Slot */#define D_SSP 0x8 /* Set short Data Pipe */#define D_CHI 0x9 /* Set CHI Global Mode */#define D_NT 0xa /* NT Command */#define D_TE 0xb /* TE Command */#define D_CDEC 0xc /* Codec setup */#define D_TEST 0xd /* No comment */#define D_CDM 0xe /* CHI Data mode command *//* Special bits for some commands */#define D_PIPE(v) ((v)<<0) /* Pipe No.: 0-15 long, 16-21 short *//* Setup Data Pipe *//* IRM */#define D_SDP_2SAME (1<<18) /* Report 2nd time in a row value received */#define D_SDP_CHANGE (2<<18) /* Report any changes */#define D_SDP_EVERY (3<<18) /* Report any changes */#define D_SDP_EOL (1<<17) /* EOL interrupt enable */#define D_SDP_IDLE (1<<16) /* HDLC idle interrupt enable *//* Pipe data MODE */#define D_SDP_MEM (0<<13) /* To/from memory */#define D_SDP_HDLC (2<<13)#define D_SDP_HDLC_D (3<<13) /* D Channel (prio control) */#define D_SDP_SER (4<<13) /* Serial to serial */#define D_SDP_FIXED (6<<13) /* Short only */#define D_SDP_MODE(v) ((v)&(7<<13))#define D_SDP_TO_SER (1<<12) /* Direction */#define D_SDP_FROM_SER (0<<12) /* Direction */#define D_SDP_MSB (1<<11) /* Bit order within Byte */#define D_SDP_LSB (0<<11) /* Bit order within Byte */#define D_SDP_P (1<<10) /* Pointer Valid */#define D_SDP_A (1<<8) /* Abort */#define D_SDP_C (1<<7) /* Clear *//* Define Time Slot */#define D_DTS_VI (1<<17) /* Valid Input Time-Slot Descriptor */#define D_DTS_VO (1<<16) /* Valid Output Time-Slot Descriptor */#define D_DTS_INS (1<<15) /* Insert Time Slot */#define D_DTS_DEL (0<<15) /* Delete Time Slot */#define D_DTS_PRVIN(v) ((v)<<10) /* Previous In Pipe */#define D_DTS_PRVOUT(v) ((v)<<5) /* Previous Out Pipe *//* Time Slot defines */#define D_TS_LEN(v) ((v)<<24) /* Number of bits in this time slot */#define D_TS_CYCLE(v) ((v)<<14) /* Bit Count at start of TS */#define D_TS_DI (1<<13) /* Data Invert */#define D_TS_1CHANNEL (0<<10) /* Single Channel / Normal mode */#define D_TS_MONITOR (2<<10) /* Monitor pipe */#define D_TS_NONCONTIG (3<<10) /* Non contiguous mode */#define D_TS_ANCHOR (7<<10) /* Starting short pipes */#define D_TS_MON(v) ((v)<<5) /* Monitor Pipe */#define D_TS_NEXT(v) ((v)<<0) /* Pipe no.: 0-15 long, 16-21 short *//* Concentration Highway Interface Modes */#define D_CHI_CHICM(v) ((v)<<16) /* Clock mode */#define D_CHI_IR (1<<15) /* Immediate Interrupt Report */#define D_CHI_EN (1<<14) /* CHIL Interrupt enabled */#define D_CHI_OD (1<<13) /* Open Drain Enable */#define D_CHI_FE (1<<12) /* Sample CHIFS on Rising Frame Edge */#define D_CHI_FD (1<<11) /* Frame Drive */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -