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

📄 mcbsp.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * linux/arch/arm/plat-omap/mcbsp.c * * Copyright (C) 2004 Nokia Corporation * Author: Samuel Ortiz <samuel.ortiz@nokia.com> * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Multichannel mode not supported. */#include <linux/module.h>#include <linux/init.h>#include <linux/device.h>#include <linux/wait.h>#include <linux/completion.h>#include <linux/interrupt.h>#include <linux/err.h>#include <asm/delay.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/arch/dma.h>#include <asm/arch/mux.h>#include <asm/arch/irqs.h>#include <asm/arch/dsp_common.h>#include <asm/arch/mcbsp.h>#include <asm/hardware/clock.h>#ifdef CONFIG_MCBSP_DEBUG#define DBG(x...)	printk(x)#else#define DBG(x...)	do { } while (0)#endifstruct omap_mcbsp {	u32                          io_base;	u8                           id;	u8                           free;	omap_mcbsp_word_length       rx_word_length;	omap_mcbsp_word_length       tx_word_length;	/* IRQ based TX/RX */	int                          rx_irq;	int                          tx_irq;	/* DMA stuff */	u8                           dma_rx_sync;	short                        dma_rx_lch;	u8                           dma_tx_sync;	short                        dma_tx_lch;	/* Completion queues */	struct completion            tx_irq_completion;	struct completion            rx_irq_completion;	struct completion            tx_dma_completion;	struct completion            rx_dma_completion;	spinlock_t                   lock;};static struct omap_mcbsp mcbsp[OMAP_MAX_MCBSP_COUNT];static struct clk *mcbsp_dsp_ck = 0;static struct clk *mcbsp_api_ck = 0;static struct clk *mcbsp_dspxor_ck = 0;static void omap_mcbsp_dump_reg(u8 id){	DBG("**** MCBSP%d regs ****\n", mcbsp[id].id);	DBG("DRR2:  0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, DRR2));	DBG("DRR1:  0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, DRR1));	DBG("DXR2:  0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, DXR2));	DBG("DXR1:  0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, DXR1));	DBG("SPCR2: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, SPCR2));	DBG("SPCR1: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, SPCR1));	DBG("RCR2:  0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, RCR2));	DBG("RCR1:  0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, RCR1));	DBG("XCR2:  0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, XCR2));	DBG("XCR1:  0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, XCR1));	DBG("SRGR2: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, SRGR2));	DBG("SRGR1: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, SRGR1));	DBG("PCR0:  0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, PCR0));	DBG("***********************\n");}static irqreturn_t omap_mcbsp_tx_irq_handler(int irq, void *dev_id, struct pt_regs *regs){	struct omap_mcbsp * mcbsp_tx = (struct omap_mcbsp *)(dev_id);	DBG("TX IRQ callback : 0x%x\n", OMAP_MCBSP_READ(mcbsp_tx->io_base, SPCR2));	complete(&mcbsp_tx->tx_irq_completion);	return IRQ_HANDLED;}static irqreturn_t omap_mcbsp_rx_irq_handler(int irq, void *dev_id, struct pt_regs *regs){	struct omap_mcbsp * mcbsp_rx = (struct omap_mcbsp *)(dev_id);	DBG("RX IRQ callback : 0x%x\n", OMAP_MCBSP_READ(mcbsp_rx->io_base, SPCR2));	complete(&mcbsp_rx->rx_irq_completion);	return IRQ_HANDLED;}static void omap_mcbsp_tx_dma_callback(int lch, u16 ch_status, void *data){	struct omap_mcbsp * mcbsp_dma_tx = (struct omap_mcbsp *)(data);	DBG("TX DMA callback : 0x%x\n", OMAP_MCBSP_READ(mcbsp_dma_tx->io_base, SPCR2));	/* We can free the channels */	omap_free_dma(mcbsp_dma_tx->dma_tx_lch);	mcbsp_dma_tx->dma_tx_lch = -1;	complete(&mcbsp_dma_tx->tx_dma_completion);}static void omap_mcbsp_rx_dma_callback(int lch, u16 ch_status, void *data){	struct omap_mcbsp * mcbsp_dma_rx = (struct omap_mcbsp *)(data);	DBG("RX DMA callback : 0x%x\n", OMAP_MCBSP_READ(mcbsp_dma_rx->io_base, SPCR2));	/* We can free the channels */	omap_free_dma(mcbsp_dma_rx->dma_rx_lch);	mcbsp_dma_rx->dma_rx_lch = -1;	complete(&mcbsp_dma_rx->rx_dma_completion);}/* * omap_mcbsp_config simply write a config to the * appropriate McBSP. * You either call this function or set the McBSP registers * by yourself before calling omap_mcbsp_start(). */void omap_mcbsp_config(unsigned int id, const struct omap_mcbsp_reg_cfg * config){	u32 io_base = mcbsp[id].io_base;	DBG("OMAP-McBSP: McBSP%d  io_base: 0x%8x\n", id+1, io_base);	/* We write the given config */	OMAP_MCBSP_WRITE(io_base, SPCR2, config->spcr2);	OMAP_MCBSP_WRITE(io_base, SPCR1, config->spcr1);	OMAP_MCBSP_WRITE(io_base, RCR2, config->rcr2);	OMAP_MCBSP_WRITE(io_base, RCR1, config->rcr1);	OMAP_MCBSP_WRITE(io_base, XCR2, config->xcr2);	OMAP_MCBSP_WRITE(io_base, XCR1, config->xcr1);	OMAP_MCBSP_WRITE(io_base, SRGR2, config->srgr2);	OMAP_MCBSP_WRITE(io_base, SRGR1, config->srgr1);	OMAP_MCBSP_WRITE(io_base, MCR2, config->mcr2);	OMAP_MCBSP_WRITE(io_base, MCR1, config->mcr1);	OMAP_MCBSP_WRITE(io_base, PCR0, config->pcr0);}static int omap_mcbsp_check(unsigned int id){	if (cpu_is_omap730()) {		if (id > OMAP_MAX_MCBSP_COUNT - 1) {		       printk(KERN_ERR "OMAP-McBSP: McBSP%d doesn't exist\n", id + 1);		       return -1;		}		return 0;	}	if (cpu_is_omap1510() || cpu_is_omap16xx()) {		if (id > OMAP_MAX_MCBSP_COUNT) {			printk(KERN_ERR "OMAP-McBSP: McBSP%d doesn't exist\n", id + 1);			return -1;		}		return 0;	}	return -1;}static void omap_mcbsp_dsp_request(void){	if (cpu_is_omap1510() || cpu_is_omap16xx()) {		clk_use(mcbsp_dsp_ck);		clk_use(mcbsp_api_ck);		/* enable 12MHz clock to mcbsp 1 & 3 */		clk_use(mcbsp_dspxor_ck);		/*		 * DSP external peripheral reset		 * FIXME: This should be moved to dsp code		 */		__raw_writew(__raw_readw(DSP_RSTCT2) | 1 | 1 << 1,			     DSP_RSTCT2);	}}static void omap_mcbsp_dsp_free(void){	if (cpu_is_omap1510() || cpu_is_omap16xx()) {		clk_unuse(mcbsp_dspxor_ck);		clk_unuse(mcbsp_dsp_ck);		clk_unuse(mcbsp_api_ck);	}}int omap_mcbsp_request(unsigned int id){	int err;	if (omap_mcbsp_check(id) < 0)		return -EINVAL;	/*	 * On 1510, 1610 and 1710, McBSP1 and McBSP3	 * are DSP public peripherals.	 */	if (id == OMAP_MCBSP1 || id == OMAP_MCBSP3)		omap_mcbsp_dsp_request();	spin_lock(&mcbsp[id].lock);	if (!mcbsp[id].free) {		printk (KERN_ERR "OMAP-McBSP: McBSP%d is currently in use\n", id + 1);		spin_unlock(&mcbsp[id].lock);		return -1;	}	mcbsp[id].free = 0;	spin_unlock(&mcbsp[id].lock);	/* We need to get IRQs here */	err = request_irq(mcbsp[id].tx_irq, omap_mcbsp_tx_irq_handler, 0,			  "McBSP",			  (void *) (&mcbsp[id]));	if (err != 0) {		printk(KERN_ERR "OMAP-McBSP: Unable to request TX IRQ %d for McBSP%d\n",		       mcbsp[id].tx_irq, mcbsp[id].id);		return err;	}	init_completion(&(mcbsp[id].tx_irq_completion));	err = request_irq(mcbsp[id].rx_irq, omap_mcbsp_rx_irq_handler, 0,			  "McBSP",			  (void *) (&mcbsp[id]));	if (err != 0) {		printk(KERN_ERR "OMAP-McBSP: Unable to request RX IRQ %d for McBSP%d\n",		       mcbsp[id].rx_irq, mcbsp[id].id);		free_irq(mcbsp[id].tx_irq, (void *) (&mcbsp[id]));		return err;	}	init_completion(&(mcbsp[id].rx_irq_completion));	return 0;}void omap_mcbsp_free(unsigned int id){	if (omap_mcbsp_check(id) < 0)		return;	if (id == OMAP_MCBSP1 || id == OMAP_MCBSP3)		omap_mcbsp_dsp_free();	spin_lock(&mcbsp[id].lock);	if (mcbsp[id].free) {		printk (KERN_ERR "OMAP-McBSP: McBSP%d was not reserved\n", id + 1);		spin_unlock(&mcbsp[id].lock);		return;	}	mcbsp[id].free = 1;	spin_unlock(&mcbsp[id].lock);	/* Free IRQs */	free_irq(mcbsp[id].rx_irq, (void *) (&mcbsp[id]));	free_irq(mcbsp[id].tx_irq, (void *) (&mcbsp[id]));}/* * Here we start the McBSP, by enabling the sample * generator, both transmitter and receivers, * and the frame sync. */void omap_mcbsp_start(unsigned int id){	u32 io_base;	u16 w;	if (omap_mcbsp_check(id) < 0)		return;	io_base = mcbsp[id].io_base;	mcbsp[id].rx_word_length = ((OMAP_MCBSP_READ(io_base, RCR1) >> 5) & 0x7);	mcbsp[id].tx_word_length = ((OMAP_MCBSP_READ(io_base, XCR1) >> 5) & 0x7);	/* Start the sample generator */	w = OMAP_MCBSP_READ(io_base, SPCR2);	OMAP_MCBSP_WRITE(io_base, SPCR2, w | (1 << 6));	/* Enable transmitter and receiver */	w = OMAP_MCBSP_READ(io_base, SPCR2);	OMAP_MCBSP_WRITE(io_base, SPCR2, w | 1);	w = OMAP_MCBSP_READ(io_base, SPCR1);	OMAP_MCBSP_WRITE(io_base, SPCR1, w | 1);	udelay(100);	/* Start frame sync */	w = OMAP_MCBSP_READ(io_base, SPCR2);	OMAP_MCBSP_WRITE(io_base, SPCR2, w | (1 << 7));	/* Dump McBSP Regs */	omap_mcbsp_dump_reg(id);}void omap_mcbsp_stop(unsigned int id){	u32 io_base;	u16 w;	if (omap_mcbsp_check(id) < 0)		return;	io_base = mcbsp[id].io_base;        /* Reset transmitter */	w = OMAP_MCBSP_READ(io_base, SPCR2);	OMAP_MCBSP_WRITE(io_base, SPCR2, w & ~(1));	/* Reset receiver */	w = OMAP_MCBSP_READ(io_base, SPCR1);	OMAP_MCBSP_WRITE(io_base, SPCR1, w & ~(1));	/* Reset the sample rate generator */	w = OMAP_MCBSP_READ(io_base, SPCR2);	OMAP_MCBSP_WRITE(io_base, SPCR2, w & ~(1 << 6));}/* polled mcbsp i/o operations */int omap_mcbsp_pollwrite(unsigned int id, u16 buf){	u32 base = mcbsp[id].io_base;	writew(buf, base + OMAP_MCBSP_REG_DXR1);	/* if frame sync error - clear the error */	if (readw(base + OMAP_MCBSP_REG_SPCR2) & XSYNC_ERR) {		/* clear error */		writew(readw(base + OMAP_MCBSP_REG_SPCR2) & (~XSYNC_ERR),		       base + OMAP_MCBSP_REG_SPCR2);		/* resend */		return -1;	} else {		/* wait for transmit confirmation */		int attemps = 0;		while (!(readw(base + OMAP_MCBSP_REG_SPCR2) & XRDY)) {			if (attemps++ > 1000) {				writew(readw(base + OMAP_MCBSP_REG_SPCR2) &				       (~XRST),				       base + OMAP_MCBSP_REG_SPCR2);				udelay(10);				writew(readw(base + OMAP_MCBSP_REG_SPCR2) |				       (XRST),				       base + OMAP_MCBSP_REG_SPCR2);				udelay(10);				printk(KERN_ERR				       " Could not write to McBSP Register\n");				return -2;

⌨️ 快捷键说明

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