cs4231.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,248 行 · 第 1/5 页

C
2,248
字号
/* * Driver for CS4231 sound chips found on Sparcs. * Copyright (C) 2002 David S. Miller <davem@redhat.com> * * Based entirely upon drivers/sbus/audio/cs4231.c which is: * Copyright (C) 1996, 1997, 1998, 1998 Derrick J Brashear (shadow@andrew.cmu.edu) * and also sound/isa/cs423x/cs4231_lib.c which is: * Copyright (c) by Jaroslav Kysela <perex@suse.cz> */#include <linux/config.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/slab.h>#include <linux/delay.h>#include <linux/init.h>#include <linux/interrupt.h>#include <linux/moduleparam.h>#include <sound/driver.h>#include <sound/core.h>#include <sound/pcm.h>#include <sound/info.h>#include <sound/control.h>#include <sound/timer.h>#include <sound/initval.h>#include <sound/pcm_params.h>#include <asm/io.h>#include <asm/irq.h>#ifdef CONFIG_SBUS#define SBUS_SUPPORT#endif#ifdef SBUS_SUPPORT#include <asm/sbus.h>#endif#if defined(CONFIG_PCI) && defined(CONFIG_SPARC64)#define EBUS_SUPPORT#endif#ifdef EBUS_SUPPORT#include <linux/pci.h>#include <asm/ebus.h>#endifstatic int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-MAX */static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;	/* Enable this card */static int boot_devs;module_param_array(index, int, boot_devs, 0444);MODULE_PARM_DESC(index, "Index value for Sun CS4231 soundcard.");module_param_array(id, charp, boot_devs, 0444);MODULE_PARM_DESC(id, "ID string for Sun CS4231 soundcard.");module_param_array(enable, bool, boot_devs, 0444);MODULE_PARM_DESC(enable, "Enable Sun CS4231 soundcard.");MODULE_AUTHOR("Jaroslav Kysela, Derrick J. Brashear and David S. Miller");MODULE_DESCRIPTION("Sun CS4231");MODULE_LICENSE("GPL");MODULE_SUPPORTED_DEVICE("{{Sun,CS4231}}");typedef struct snd_cs4231 {	spinlock_t		lock;	void __iomem		*port;#ifdef EBUS_SUPPORT	struct ebus_dma_info	eb2c;	struct ebus_dma_info	eb2p;#endif	u32			flags;#define CS4231_FLAG_EBUS	0x00000001#define CS4231_FLAG_PLAYBACK	0x00000002#define CS4231_FLAG_CAPTURE	0x00000004	snd_card_t		*card;	snd_pcm_t		*pcm;	snd_pcm_substream_t	*playback_substream;	unsigned int		p_periods_sent;	snd_pcm_substream_t	*capture_substream;	unsigned int		c_periods_sent;	snd_timer_t		*timer;	unsigned short mode;#define CS4231_MODE_NONE	0x0000#define CS4231_MODE_PLAY	0x0001#define CS4231_MODE_RECORD	0x0002#define CS4231_MODE_TIMER	0x0004#define CS4231_MODE_OPEN	(CS4231_MODE_PLAY|CS4231_MODE_RECORD|CS4231_MODE_TIMER)	unsigned char		image[32];	/* registers image */	int			mce_bit;	int			calibrate_mute;	struct semaphore	mce_mutex;	struct semaphore	open_mutex;	union {#ifdef SBUS_SUPPORT		struct sbus_dev		*sdev;#endif#ifdef EBUS_SUPPORT		struct pci_dev		*pdev;#endif	} dev_u;	unsigned int		irq[2];	unsigned int		regs_size;	struct snd_cs4231	*next;} cs4231_t;static cs4231_t *cs4231_list;/* Eventually we can use sound/isa/cs423x/cs4231_lib.c directly, but for * now....  -DaveM *//* IO ports */#define CS4231P(chip, x)	((chip)->port + c_d_c_CS4231##x)/* XXX offsets are different than PC ISA chips... */#define c_d_c_CS4231REGSEL	0x0#define c_d_c_CS4231REG		0x4#define c_d_c_CS4231STATUS	0x8#define c_d_c_CS4231PIO		0xc/* codec registers */#define CS4231_LEFT_INPUT	0x00	/* left input control */#define CS4231_RIGHT_INPUT	0x01	/* right input control */#define CS4231_AUX1_LEFT_INPUT	0x02	/* left AUX1 input control */#define CS4231_AUX1_RIGHT_INPUT	0x03	/* right AUX1 input control */#define CS4231_AUX2_LEFT_INPUT	0x04	/* left AUX2 input control */#define CS4231_AUX2_RIGHT_INPUT	0x05	/* right AUX2 input control */#define CS4231_LEFT_OUTPUT	0x06	/* left output control register */#define CS4231_RIGHT_OUTPUT	0x07	/* right output control register */#define CS4231_PLAYBK_FORMAT	0x08	/* clock and data format - playback - bits 7-0 MCE */#define CS4231_IFACE_CTRL	0x09	/* interface control - bits 7-2 MCE */#define CS4231_PIN_CTRL		0x0a	/* pin control */#define CS4231_TEST_INIT	0x0b	/* test and initialization */#define CS4231_MISC_INFO	0x0c	/* miscellaneaous information */#define CS4231_LOOPBACK		0x0d	/* loopback control */#define CS4231_PLY_UPR_CNT	0x0e	/* playback upper base count */#define CS4231_PLY_LWR_CNT	0x0f	/* playback lower base count */#define CS4231_ALT_FEATURE_1	0x10	/* alternate #1 feature enable */#define CS4231_ALT_FEATURE_2	0x11	/* alternate #2 feature enable */#define CS4231_LEFT_LINE_IN	0x12	/* left line input control */#define CS4231_RIGHT_LINE_IN	0x13	/* right line input control */#define CS4231_TIMER_LOW	0x14	/* timer low byte */#define CS4231_TIMER_HIGH	0x15	/* timer high byte */#define CS4231_LEFT_MIC_INPUT	0x16	/* left MIC input control register (InterWave only) */#define CS4231_RIGHT_MIC_INPUT	0x17	/* right MIC input control register (InterWave only) */#define CS4236_EXT_REG		0x17	/* extended register access */#define CS4231_IRQ_STATUS	0x18	/* irq status register */#define CS4231_LINE_LEFT_OUTPUT	0x19	/* left line output control register (InterWave only) */#define CS4231_VERSION		0x19	/* CS4231(A) - version values */#define CS4231_MONO_CTRL	0x1a	/* mono input/output control */#define CS4231_LINE_RIGHT_OUTPUT 0x1b	/* right line output control register (InterWave only) */#define CS4235_LEFT_MASTER	0x1b	/* left master output control */#define CS4231_REC_FORMAT	0x1c	/* clock and data format - record - bits 7-0 MCE */#define CS4231_PLY_VAR_FREQ	0x1d	/* playback variable frequency */#define CS4235_RIGHT_MASTER	0x1d	/* right master output control */#define CS4231_REC_UPR_CNT	0x1e	/* record upper count */#define CS4231_REC_LWR_CNT	0x1f	/* record lower count *//* definitions for codec register select port - CODECP( REGSEL ) */#define CS4231_INIT		0x80	/* CODEC is initializing */#define CS4231_MCE		0x40	/* mode change enable */#define CS4231_TRD		0x20	/* transfer request disable *//* definitions for codec status register - CODECP( STATUS ) */#define CS4231_GLOBALIRQ	0x01	/* IRQ is active *//* definitions for codec irq status */#define CS4231_PLAYBACK_IRQ	0x10#define CS4231_RECORD_IRQ	0x20#define CS4231_TIMER_IRQ	0x40#define CS4231_ALL_IRQS		0x70#define CS4231_REC_UNDERRUN	0x08#define CS4231_REC_OVERRUN	0x04#define CS4231_PLY_OVERRUN	0x02#define CS4231_PLY_UNDERRUN	0x01/* definitions for CS4231_LEFT_INPUT and CS4231_RIGHT_INPUT registers */#define CS4231_ENABLE_MIC_GAIN	0x20#define CS4231_MIXS_LINE	0x00#define CS4231_MIXS_AUX1	0x40#define CS4231_MIXS_MIC		0x80#define CS4231_MIXS_ALL		0xc0/* definitions for clock and data format register - CS4231_PLAYBK_FORMAT */#define CS4231_LINEAR_8		0x00	/* 8-bit unsigned data */#define CS4231_ALAW_8		0x60	/* 8-bit A-law companded */#define CS4231_ULAW_8		0x20	/* 8-bit U-law companded */#define CS4231_LINEAR_16	0x40	/* 16-bit twos complement data - little endian */#define CS4231_LINEAR_16_BIG	0xc0	/* 16-bit twos complement data - big endian */#define CS4231_ADPCM_16		0xa0	/* 16-bit ADPCM */#define CS4231_STEREO		0x10	/* stereo mode *//* bits 3-1 define frequency divisor */#define CS4231_XTAL1		0x00	/* 24.576 crystal */#define CS4231_XTAL2		0x01	/* 16.9344 crystal *//* definitions for interface control register - CS4231_IFACE_CTRL */#define CS4231_RECORD_PIO	0x80	/* record PIO enable */#define CS4231_PLAYBACK_PIO	0x40	/* playback PIO enable */#define CS4231_CALIB_MODE	0x18	/* calibration mode bits */#define CS4231_AUTOCALIB	0x08	/* auto calibrate */#define CS4231_SINGLE_DMA	0x04	/* use single DMA channel */#define CS4231_RECORD_ENABLE	0x02	/* record enable */#define CS4231_PLAYBACK_ENABLE	0x01	/* playback enable *//* definitions for pin control register - CS4231_PIN_CTRL */#define CS4231_IRQ_ENABLE	0x02	/* enable IRQ */#define CS4231_XCTL1		0x40	/* external control #1 */#define CS4231_XCTL0		0x80	/* external control #0 *//* definitions for test and init register - CS4231_TEST_INIT */#define CS4231_CALIB_IN_PROGRESS 0x20	/* auto calibrate in progress */#define CS4231_DMA_REQUEST	0x10	/* DMA request in progress *//* definitions for misc control register - CS4231_MISC_INFO */#define CS4231_MODE2		0x40	/* MODE 2 */#define CS4231_IW_MODE3		0x6c	/* MODE 3 - InterWave enhanced mode */#define CS4231_4236_MODE3	0xe0	/* MODE 3 - CS4236+ enhanced mode *//* definitions for alternate feature 1 register - CS4231_ALT_FEATURE_1 */#define	CS4231_DACZ		0x01	/* zero DAC when underrun */#define CS4231_TIMER_ENABLE	0x40	/* codec timer enable */#define CS4231_OLB		0x80	/* output level bit *//* SBUS DMA register defines.  */#define APCCSR	0x10UL	/* APC DMA CSR */#define APCCVA	0x20UL	/* APC Capture DMA Address */#define APCCC	0x24UL	/* APC Capture Count */#define APCCNVA	0x28UL	/* APC Capture DMA Next Address */#define APCCNC	0x2cUL	/* APC Capture Next Count */#define APCPVA	0x30UL	/* APC Play DMA Address */#define APCPC	0x34UL	/* APC Play Count */#define APCPNVA	0x38UL	/* APC Play DMA Next Address */#define APCPNC	0x3cUL	/* APC Play Next Count *//* APCCSR bits */#define APC_INT_PENDING 0x800000 /* Interrupt Pending */#define APC_PLAY_INT    0x400000 /* Playback interrupt */#define APC_CAPT_INT    0x200000 /* Capture interrupt */#define APC_GENL_INT    0x100000 /* General interrupt */#define APC_XINT_ENA    0x80000  /* General ext int. enable */#define APC_XINT_PLAY   0x40000  /* Playback ext intr */#define APC_XINT_CAPT   0x20000  /* Capture ext intr */#define APC_XINT_GENL   0x10000  /* Error ext intr */#define APC_XINT_EMPT   0x8000   /* Pipe empty interrupt (0 write to pva) */#define APC_XINT_PEMP   0x4000   /* Play pipe empty (pva and pnva not set) */#define APC_XINT_PNVA   0x2000   /* Playback NVA dirty */#define APC_XINT_PENA   0x1000   /* play pipe empty Int enable */#define APC_XINT_COVF   0x800    /* Cap data dropped on floor */#define APC_XINT_CNVA   0x400    /* Capture NVA dirty */#define APC_XINT_CEMP   0x200    /* Capture pipe empty (cva and cnva not set) */#define APC_XINT_CENA   0x100    /* Cap. pipe empty int enable */#define APC_PPAUSE      0x80     /* Pause the play DMA */#define APC_CPAUSE      0x40     /* Pause the capture DMA */#define APC_CDC_RESET   0x20     /* CODEC RESET */#define APC_PDMA_READY  0x08     /* Play DMA Go */#define APC_CDMA_READY  0x04     /* Capture DMA Go */#define APC_CHIP_RESET  0x01     /* Reset the chip *//* EBUS DMA register offsets  */#define EBDMA_CSR	0x00UL	/* Control/Status */#define EBDMA_ADDR	0x04UL	/* DMA Address */#define EBDMA_COUNT	0x08UL	/* DMA Count *//* *  Some variables */static unsigned char freq_bits[14] = {	/* 5510 */	0x00 | CS4231_XTAL2,	/* 6620 */	0x0E | CS4231_XTAL2,	/* 8000 */	0x00 | CS4231_XTAL1,	/* 9600 */	0x0E | CS4231_XTAL1,	/* 11025 */	0x02 | CS4231_XTAL2,	/* 16000 */	0x02 | CS4231_XTAL1,	/* 18900 */	0x04 | CS4231_XTAL2,	/* 22050 */	0x06 | CS4231_XTAL2,	/* 27042 */	0x04 | CS4231_XTAL1,	/* 32000 */	0x06 | CS4231_XTAL1,	/* 33075 */	0x0C | CS4231_XTAL2,	/* 37800 */	0x08 | CS4231_XTAL2,	/* 44100 */	0x0A | CS4231_XTAL2,	/* 48000 */	0x0C | CS4231_XTAL1};static unsigned int rates[14] = {	5510, 6620, 8000, 9600, 11025, 16000, 18900, 22050,	27042, 32000, 33075, 37800, 44100, 48000};static snd_pcm_hw_constraint_list_t hw_constraints_rates = {	.count	= 14,	.list	= rates,};static int snd_cs4231_xrate(snd_pcm_runtime_t *runtime){	return snd_pcm_hw_constraint_list(runtime, 0,					  SNDRV_PCM_HW_PARAM_RATE,					  &hw_constraints_rates);}static unsigned char snd_cs4231_original_image[32] ={	0x00,			/* 00/00 - lic */	0x00,			/* 01/01 - ric */	0x9f,			/* 02/02 - la1ic */	0x9f,			/* 03/03 - ra1ic */	0x9f,			/* 04/04 - la2ic */	0x9f,			/* 05/05 - ra2ic */	0xbf,			/* 06/06 - loc */	0xbf,			/* 07/07 - roc */	0x20,			/* 08/08 - pdfr */	CS4231_AUTOCALIB,	/* 09/09 - ic */	0x00,			/* 0a/10 - pc */	0x00,			/* 0b/11 - ti */	CS4231_MODE2,		/* 0c/12 - mi */	0x00,			/* 0d/13 - lbc */	0x00,			/* 0e/14 - pbru */	0x00,			/* 0f/15 - pbrl */	0x80,			/* 10/16 - afei */	0x01,			/* 11/17 - afeii */	0x9f,			/* 12/18 - llic */	0x9f,			/* 13/19 - rlic */	0x00,			/* 14/20 - tlb */	0x00,			/* 15/21 - thb */	0x00,			/* 16/22 - la3mic/reserved */	0x00,			/* 17/23 - ra3mic/reserved */	0x00,			/* 18/24 - afs */	0x00,			/* 19/25 - lamoc/version */	0x00,			/* 1a/26 - mioc */	0x00,			/* 1b/27 - ramoc/reserved */	0x20,			/* 1c/28 - cdfr */	0x00,			/* 1d/29 - res4 */	0x00,			/* 1e/30 - cbru */	0x00,			/* 1f/31 - cbrl */};static u8 __cs4231_readb(cs4231_t *cp, void __iomem *reg_addr){#ifdef EBUS_SUPPORT	if (cp->flags & CS4231_FLAG_EBUS) {		return readb(reg_addr);	} else {#endif#ifdef SBUS_SUPPORT		return sbus_readb(reg_addr);#endif#ifdef EBUS_SUPPORT	}#endif}static void __cs4231_writeb(cs4231_t *cp, u8 val, void __iomem *reg_addr){#ifdef EBUS_SUPPORT	if (cp->flags & CS4231_FLAG_EBUS) {		return writeb(val, reg_addr);	} else {#endif#ifdef SBUS_SUPPORT		return sbus_writeb(val, reg_addr);#endif#ifdef EBUS_SUPPORT	}#endif}/* *  Basic I/O functions */void snd_cs4231_outm(cs4231_t *chip, unsigned char reg,		     unsigned char mask, unsigned char value){	int timeout;	unsigned char tmp;	for (timeout = 250;	     timeout > 0 && (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT);	     timeout--)	     	udelay(100);#ifdef CONFIG_SND_DEBUG	if (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT)		snd_printk("outm: auto calibration time out - reg = 0x%x, value = 0x%x\n", reg, value);#endif	if (chip->calibrate_mute) {		chip->image[reg] &= mask;		chip->image[reg] |= value;	} else {		__cs4231_writeb(chip, chip->mce_bit | reg, CS4231P(chip, REGSEL));		mb();		tmp = (chip->image[reg] & mask) | value;		__cs4231_writeb(chip, tmp, CS4231P(chip, REG));		chip->image[reg] = tmp;		mb();	}}static void snd_cs4231_dout(cs4231_t *chip, unsigned char reg, unsigned char value){	int timeout;	for (timeout = 250;	     timeout > 0 && (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT);	     timeout--)	     	udelay(100);	__cs4231_writeb(chip, chip->mce_bit | reg, CS4231P(chip, REGSEL));	__cs4231_writeb(chip, value, CS4231P(chip, REG));	mb();}static void snd_cs4231_out(cs4231_t *chip, unsigned char reg, unsigned char value){	int timeout;	for (timeout = 250;	     timeout > 0 && (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT);	     timeout--)	     	udelay(100);#ifdef CONFIG_SND_DEBUG	if (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT)		snd_printk("out: auto calibration time out - reg = 0x%x, value = 0x%x\n", reg, value);#endif	__cs4231_writeb(chip, chip->mce_bit | reg, CS4231P(chip, REGSEL));	__cs4231_writeb(chip, value, CS4231P(chip, REG));	chip->image[reg] = value;	mb();#if 0

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?