📄 mcbsp.c
字号:
/* * 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 + -