⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ibmcsiti.c

📁 tlv320aic23的源码
💻 C
📖 第 1 页 / 共 5 页
字号:
/*****************************************************************************/
/*
 *      ibmcsiti.c : IBM PPC 405LP Codec Serial Interface (CSI) +
 *                      Texas Instruments TLV320AIC23 stereo audio codec
 *                      for the Arctic-II reference board
 *
 *	Based on the ibmcsiti driver for IBM PPC 405LP CSI + TLV320AIC23 codec
 *
 *      Copyright (C) 2002 Ken Inoue and David Gibson, IBM Corporation
 *
 * 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
 *
 *  Supported devices:
 *  	/dev/dsp    standard /dev/dsp device, hopefully OSS compatible
 *  	/dev/mixer  standard /dev/mixer device, hopefully OSS compatible
 *
 * TODOs:
 * - Integration testing with ViaVoice embedded edition
 * - Sampling rate is fixed at 44.1 KHz.
 * - Sample format is limited to 16 bit big endian.
 *	(this is a deviation since an OSS DSP device is supposed to support 8 bit as default.)
 * - Drain DAC/ADC
 * - Fragment handling
 * - MMAP support
 * - Split CSI and codec drivers
 * - Module parameters
 * - Tune retry counts and jiffies
 * - Revisit inline functions
 * - Write ibmcsi.txt in the Documentation directory
 * - Anything else?
 */

#include <linux/version.h>
#include <linux/module.h>
#include <linux/string.h>
#include <linux/ioport.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/sound.h>
#include <linux/slab.h>
#include <linux/soundcard.h>
#include <linux/smp_lock.h>
#include <linux/i2c.h>
#include <asm/io.h>
#include <asm/dma.h>
#include <asm/delay.h>
#include <linux/init.h>
#include <linux/poll.h>
#include <linux/spinlock.h>
#include <asm/uaccess.h>
#include <asm/hardirq.h>
#include <asm/time.h>
#include <asm/ocp.h>

#include <platforms/ibm405lp.h>

#include "tlv320aic23.h"

/*****************************************************************************/
/* Start #defines that might belong in ibm405lp.h */

#define CSI0_IO_BASE 0xEF600900 /* CSI I/O base address */

#define CSI0_ER	        (CSI0_IO_BASE + 0)	/* Enable register */
#define CSI0_CFG	(CSI0_IO_BASE + 4)	/* Configuration register */
#define CSI0_SR         (CSI0_IO_BASE + 8)	/* Status register */
#define CSI0_TBUF	(CSI0_IO_BASE + 0x0C)	/* Transmit buffer */
#define CSI0_RBUF   	(CSI0_IO_BASE + 0x10)	/* Receive buffer */
#define CSI0_ID		(CSI0_IO_BASE + 0x14)	/* ID */
#define CSI0_SCR	(CSI0_IO_BASE + 0x18)	/* Sleep control register */

#define CSI0_EXTENT 28			/* I/O address extent */
#define CSI_ID_405LP	0x1107		/* CSI core ID (halfword) */


#define CSI_ER_ECSI	0x00000001	/* Enable the CSI */
#define CSI_ER_RXEN	0x00000002	/* Receive enable */
#define CSI_ER_TXEN	0x00000004	/* Transmit enable */

#define CSI_ER_ESLOT(n) (0x80000000 >> (n)) /* Enable (n)th slot */

#define CSI_SR_TOD	0x00000001	/* Transmit overrun */
#define CSI_SR_ROD	0x00000002	/* Receive overrun */
#define CSI_SR_CSIB	0x00008000	/* CSI Busy */

/************************************************************************/
/* DMA Channel Control register						*/
/* (DCRN_DMA0_CR0 through DCRN_DMA0_CR3)				*/
/************************************************************************/

#define DCRN_DMA_CR_CE                 0x80000000   /* Channel Enable */
#define DCRN_DMA_CR_CIE                0x40000000   /* Channel Interrupt Enable */
#define DCRN_DMA_CR_TD                 0x20000000   /* Transfer Direction */
#define DCRN_DMA_CR_PL                 0x10000000   /* Peripheral Location */
#define DCRN_DMA_CR_PW_8               0x00000000   /* 8 bit peripheral width */
#define DCRN_DMA_CR_PW_16              0x04000000   /* 16 bit peripheral width */
#define DCRN_DMA_CR_PW_32              0x08000000   /* 32 bit peripheral width */
#define DCRN_DMA_CR_PW_64              0x0c000000   /* 64 bit peripheral width */
#define DCRN_DMA_CR_DAI                0x02000000   /* Destination Addr Increment */
#define DCRN_DMA_CR_SAI                0x01000000   /* Source Address Increment */
#define DCRN_DMA_CR_BE                 0x00800000   /* Buffer Enable */
#define DCRN_DMA_CR_TM_BUFFERED        0x00000000   /* Buffered Transfer mode */
#define DCRN_DMA_CR_TM_SW_MEM_TO_MEM   0x00400000   /* Software started mem to mem */
#define DCRN_DMA_CR_TM_HW_MEM_TO_MEM   0x00600000   /* Hardware paced mem to mem */
#define DCRN_DMA_CR_PSC_0              0x00000000   /* 0 Peripheral Setup Cycles */
#define DCRN_DMA_CR_PSC_1              0x00080000   /* 1 Peripheral Setup Cycles */
#define DCRN_DMA_CR_PSC_2              0x00100000   /* 2 Peripheral Setup Cycles */
#define DCRN_DMA_CR_PSC_3              0x00180000   /* 3 Peripheral Setup Cycles */
#define DCRN_DMA_CR_PSC(n) (((n)&0x3)<<19)          /* n Peripheral setup cycles */
#define DCRN_DMA_CR_PWC(n) (((n)&0x3f)<<13)         /* n peripheral wait cycles */
#define DCRN_DMA_CR_PHC(n) (((n)&0x7)<<10)          /* n peripheral hold cycles   */
#define DCRN_DMA_CR_ETD                0x00000200   /* EOT/TC Pin Direction */
#define DCRN_DMA_CR_TCE                0x00000100   /* Terminal Count Enable */
#define DCRN_DMA_CR_CP_MASK            0x000000C0   /* Channel Priority */
#define DCRN_DMA_CR_CP(n) (((n)&0x3)<<6)
#define DCRN_DMA_CR_PF                 0x00000030   /* Memory read prefetch trans */
#define DCRN_DMA_CR_PF_1               0x00000000   /*   Prefetch 1 dword */
#define DCRN_DMA_CR_PF_2               0x00000010   /*   Prefetch 2 dword */
#define DCRN_DMA_CR_PF_4               0x00000020   /*   Prefetch 4 dword */
#define DCRN_DMA_CR_PCE                0x00000008   /* Parity check enable */
#define DCRN_DMA_CR_DEC                0x00000004   /* Address decrement */

/************************************************************************/
/* DMA Status Register							*/
/* (Device Control Register bus register DCRN_DMASR)			*/
/************************************************************************/
/* (n) = DMA channel number, 0-3 */

#define DCRN_DMA_SR_CS(n)	(0x80000000 >>(n))  /* Terminal count status */
#define DCRN_DMA_SR_TS(n)       (0x08000000 >>(n))  /* End Of Transfer status */
#define DCRN_DMA_SR_RI(n)	(0x00800000 >>(n))  /* Error status */
#define DCRN_DMA_SR_IR(n)	(0x00080000 >>(n))  /* Internal DMA request pending */
#define DCRN_DMA_SR_ER(n)	(0x00008000 >>(n))  /* External DMA request pending */
#define DCRN_DMA_SR_CB(n)	(0x00000800 >>(n))  /* Channel Busy */
#define DCRN_DMA_SR_SG(n)	(0x00000080 >>(n))  /* Scatter/gather status */

/* Status register bits for the (n)th channel (write to clear) */
#define DCRN_DMA_SR_ALL(n) (DCRN_DMA_SR_CS(n) | \
			DCRN_DMA_SR_TS(n) | \
			DCRN_DMA_SR_RI(n) | \
			DCRN_DMA_SR_IR(n) | \
			DCRN_DMA_SR_ER(n) | \
			DCRN_DMA_SR_CB(n) | \
			DCRN_DMA_SR_SG(n) )

/* DCRN_DMA0_SGC Scatter/Gather Command Register bits */ 
#define DCRN_DMA_SGC_SSG0 0x80000000
#define DCRN_DMA_SGC_SSG1 0x40000000
#define DCRN_DMA_SGC_SSG2 0x20000000
#define DCRN_DMA_SGC_SSG3 0x10000000

#define DCRN_DMA_SGC_EM0  0x00008000
#define DCRN_DMA_SGC_EM1  0x00004000
#define DCRN_DMA_SGC_EM2  0x00002000
#define DCRN_DMA_SGC_EM3  0x00001000

struct dma_sgdt { /* Must be word aligned */
	u32 ccw; /* Channel Control Word */
	u32 srcP;	/* Source address (physical) */
	u32 destP;	/* Destination address (physical) */
	u32 ctrl; /* MSB = link bit, lower halfword = count */
		/* Other 3 bits unused */ 
	u32 nextP;	/* Next scatter/gather descriptor list physical address */
	/* ------------------------------------- Private use ---------------*/
	struct dma_sgdt *prevV;	/* Prev scatter/gather descriptor list virtual address */
	struct dma_sgdt *nextV; /* Next */
	unsigned int dummy;	/* Reserved (for 16 byte alignment) */ 
}; 

/* End ibm405lp.h candidates */


/*****************************************************************************/
/* Driver specific defines 						     */
/*****************************************************************************/

/* The DMA channels for the CSI are hardcoded in the 405LP chip, so we
 * hardcode them.  If a future chip adopts programmable channel
 * assignment, I expect access to DMA channels would be handled by a
 * separate driver.
 */

#define IBMCSI_TXDMA 	0	/* Transmit from CSI to codec : channel 0 */
#define IBMCSI_RXDMA	1	/* Receive from codec to CSI  : channel 1 */

#define IBMCSI_TXDMA_IRQ	5
#define IBMCSI_RXDMA_IRQ	6

#define IBMCSI_DMA_SR	DCRN_DMASR

/* Transmit (playback) DMA registers	*/
#define IBMCSI_TXDMA_CR	DCRN_DMACR0
#define IBMCSI_TXDMA_DA	DCRN_DMADA0
#define IBMCSI_TXDMA_SA	DCRN_DMASA0
#define IBMCSI_TXDMA_CT	DCRN_DMACT0

/* Receive (capture) DMA registers	*/
#define IBMCSI_RXDMA_CR	DCRN_DMACR1
#define IBMCSI_RXDMA_DA	DCRN_DMADA1
#define IBMCSI_RXDMA_SA	DCRN_DMASA1
#define IBMCSI_RXDMA_CT	DCRN_DMACT1


#define IBMCSI_TXDMA_CONFIG (	    	/* Channel disabled */ \
		DCRN_DMA_CR_CIE |    	/* Channel interrupt enabled */ \
				    	/* Memory to peripheral */ \
      		DCRN_DMA_CR_PL	|   	/* Peripheral on OPB */ \
		DCRN_DMA_CR_PW_32 |  	/* 32 bit wide peripheral */ \
					/* Dest address not incremented */ \
		DCRN_DMA_CR_SAI	| 	/* Source address incremented */ \
					/* Peripheral transfer mode */ \
					/* Peripheral setup cycle 0 */ \
		DCRN_DMA_CR_PWC(2) |	/* Peripheral wait cycle 3 */ \
					/* Peripheral hold cycle 0 */ \
		DCRN_DMA_CR_ETD |	/* EOTn = TC */ \
		DCRN_DMA_CR_TCE )	/* Terminal count enable */

#define IBMCSI_TXDMA_GO (IBMCSI_TXDMA_CONFIG | DCRN_DMA_CR_CE)	 /* For int */
#define IBMCSI_TXDMA_GO_NOI (IBMCSI_TXDMA_GO & ~DCRN_DMA_CR_CIE) /* For polling	*/

#define IBMCSI_RXDMA_CONFIG (		/* Channel disabled */ \
		DCRN_DMA_CR_CIE |    	/* Channel interrupt enabled */ \
		DCRN_DMA_CR_TD  |   	/* Peripheral to memory */ \
		DCRN_DMA_CR_PL	|   	/* Peripheral on OPB */ \
		DCRN_DMA_CR_PW_32 |  	/* 32 bit wide peripheral */ \
		DCRN_DMA_CR_DAI |   	/* Dest address incremented */ \
		                   	/* Source address not incremented */ \
				    	/* Peripheral transfer mode */ \
				    	/* Peripheral setup cycle 0 */ \
		DCRN_DMA_CR_PWC(2) |	/* Peripheral wait cycle 3 */ \
			            	/* Peripheral hold cycle 0 */ \
		DCRN_DMA_CR_ETD |   	/* EOTn = TC */ \
		DCRN_DMA_CR_TCE ) 	/* Terminal count enable */

#define IBMCSI_RXDMA_GO (IBMCSI_RXDMA_CONFIG | DCRN_DMA_CR_CE)
#define IBMCSI_RXDMA_GO_NOI (IBMCSI_RXDMA_GO & ~DCRN_DMA_CR_CIE)

#define IBMCSI_DEFAULT_SAMPLING_RATE 44100

#define IBMCSI_TI_CFG 0x00400010		 /* 64 bits per frame mode */

#define DAC_TIMER_PERIOD (HZ/50)
#define ADC_TIMER_PERIOD (HZ/50)

#define TX_SG DCRN_ASG0
#define RX_SG DCRN_ASG1

#define TX_SG_ENABLE  	DCRN_DMA_SGC_SSG0
#define TX_SG_MASK 	DCRN_DMA_SGC_EM0

#define RX_SG_ENABLE  	DCRN_DMA_SGC_SSG1
#define RX_SG_MASK 	DCRN_DMA_SGC_EM1


/*****************************************************************************/

#undef OSS_DOCUMENTED_MIXER_SEMANTICS /* FIXME: does this have any effect? */

#define DBG(x) {}
/*#define DBG(x) {x}*/

#define IBMCSI_MAGIC 0xB31BCB /* Copied from the Austin Research version */
/* TODO: verify this value is legitimate */

#define DMABUF_DEFAULTORDER (16-PAGE_SHIFT) /* FIXME: check out this value */
#define DMABUF_MINORDER 1			/* FIXME: ditto */

#define IBMCSI_WRITE(reg, val) (__raw_writel(val, reg))
#define IBMCSI_READ(reg)	(__raw_readl(reg))

#define VALIDATE_STATE(s)				\
({							\
	if (!(s) || (s)->magic != IBMCSI_MAGIC) {	\
		printk(KERN_ERR "ibmcsi: invalid signature (magic) in private data\n");\
		return -ENXIO;				\
	}						\
})


/*****************************************************************************/
/* Static variables, globals and structs 				     */
/*****************************************************************************/

static const unsigned sample_shift[] = {0, 1, 1, 2};
static LIST_HEAD(devs);

/*
 * Private data structure for the devices supported by this driver
 */
struct ibmcsiti_state {
	unsigned int magic; /* Magic signature value for sanity check */

   	unsigned int state; /* Driver state (DAC/ADC running, Halt, etc.) */

	struct i2c_client *i2c;

 	/* For multi-device support; not used for the 405LP */
   	struct list_head devs;

	/* DSP device variables */
	int dev_dsp; /* unit number of our registered DSP device */
	int outstereo; /* are we in stereo output mode? */

	spinlock_t lock;

	struct semaphore dsp_sem;
	struct semaphore open_sem;

	mode_t open_mode;
	wait_queue_head_t open_wait;

	/* Mixer device variables */
	int dev_mixer; /* unit number of our registered mixer device */
	struct semaphore mix_sem;

   	/* Buffers */
   	unsigned char *write_line;
	dma_addr_t dma_write_line;
	unsigned char *read_line;
	dma_addr_t dma_read_line;

	/* Control blocks for audio playback (dac) and capture (adc) */
	struct dmabuf {
		/* The important ones... */
	      	void *rawbuf;		/* DMA buffer logical address */
		dma_addr_t dmaaddr;	/* DMA buffer physical address */
		unsigned hwptr, swptr;	/* Offsets from rawbuf for data. HWPTR = DMAC, SWPTR = driver */
		int count;

		wait_queue_head_t wait;

		/* And the rest, inherited from sample drivers... */
		unsigned fragsize;
		unsigned dmasize;
		unsigned fragsamples;

	      	unsigned buforder;
		unsigned numfrag;
		unsigned fragshift;
	
		/* OSS stuff */
		unsigned mapped:1;
		unsigned ready:1;
		unsigned endcleared:1;
		unsigned enabled:1;
		unsigned ossfragshift;
		int ossmaxfrags;
		unsigned subdivision;

      		unsigned total_bytes;
		unsigned error; 		/* Over/underrun */
		unsigned sg_count;
	} dma_dac, dma_adc;

	/* FIXME: should move the following to dma_dac/dma_adc (trivial) */
	struct timer_list dac_timer;
	struct timer_list adc_timer;
	struct dma_sgdt *dac_free_sgdt_q;
	struct dma_sgdt *adc_free_sgdt_q;
	struct dma_sgdt *dac_active_sgdt_q;
	struct dma_sgdt *adc_active_sgdt_q;

	struct dma_sgdt *dac_sgdt_lastV; /* Anchors */
	struct dma_sgdt *adc_sgdt_lastV;

	struct dma_sgdt *adc_hw_prev_sgdt; 
	struct dma_sgdt *adc_sw_prev_sgdt;

	/* Local copy of TI codec settings (the registers being write only) */
	u16 codec_reg[TLV320_REG_EXTENT]; /* the registers are
					   * actually 9-bits each */
};

/* Driver state flags */
#define IBMCSI_DAC_RUNNING 	0x00010000
#define IBMCSI_ADC_RUNNING	0x00020000
#define IBMCSI_HALT		0x00040000

/************************************************************************/
/* Misc function prototypes						*/
/************************************************************************/

static int __init init_ibmcsiti(void);		/* Driver initialization */
static void __exit cleanup_ibmcsiti(void); 	/* Driver exit cleanup */

static int ibmcsi_i2c_attach_adapter(struct i2c_adapter *);
static int ibmcsi_i2c_detach_client(struct i2c_client *);
static int ibmcsi_i2c_detect_client(struct i2c_adapter *, int address,
				    unsigned short flags, int kind);
static void ibmcsi_i2c_inc_use(struct i2c_client *);

⌨️ 快捷键说明

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