📄 mcbsp.c
字号:
} } } return 0;}int omap_mcbsp_pollread(unsigned int id, u16 * buf){ u32 base = mcbsp[id].io_base; /* if frame sync error - clear the error */ if (readw(base + OMAP_MCBSP_REG_SPCR1) & RSYNC_ERR) { /* clear error */ writew(readw(base + OMAP_MCBSP_REG_SPCR1) & (~RSYNC_ERR), base + OMAP_MCBSP_REG_SPCR1); /* resend */ return -1; } else { /* wait for recieve confirmation */ int attemps = 0; while (!(readw(base + OMAP_MCBSP_REG_SPCR1) & RRDY)) { if (attemps++ > 1000) { writew(readw(base + OMAP_MCBSP_REG_SPCR1) & (~RRST), base + OMAP_MCBSP_REG_SPCR1); udelay(10); writew(readw(base + OMAP_MCBSP_REG_SPCR1) | (RRST), base + OMAP_MCBSP_REG_SPCR1); udelay(10); printk(KERN_ERR " Could not read from McBSP Register\n"); return -2; } } } *buf = readw(base + OMAP_MCBSP_REG_DRR1); return 0;}/* * IRQ based word transmission. */void omap_mcbsp_xmit_word(unsigned int id, u32 word){ u32 io_base; omap_mcbsp_word_length word_length = mcbsp[id].tx_word_length; if (omap_mcbsp_check(id) < 0) return; io_base = mcbsp[id].io_base; wait_for_completion(&(mcbsp[id].tx_irq_completion)); if (word_length > OMAP_MCBSP_WORD_16) OMAP_MCBSP_WRITE(io_base, DXR2, word >> 16); OMAP_MCBSP_WRITE(io_base, DXR1, word & 0xffff);}u32 omap_mcbsp_recv_word(unsigned int id){ u32 io_base; u16 word_lsb, word_msb = 0; omap_mcbsp_word_length word_length = mcbsp[id].rx_word_length; if (omap_mcbsp_check(id) < 0) return -EINVAL; io_base = mcbsp[id].io_base; wait_for_completion(&(mcbsp[id].rx_irq_completion)); if (word_length > OMAP_MCBSP_WORD_16) word_msb = OMAP_MCBSP_READ(io_base, DRR2); word_lsb = OMAP_MCBSP_READ(io_base, DRR1); return (word_lsb | (word_msb << 16));}/* * Simple DMA based buffer rx/tx routines. * Nothing fancy, just a single buffer tx/rx through DMA. * The DMA resources are released once the transfer is done. * For anything fancier, you should use your own customized DMA * routines and callbacks. */int omap_mcbsp_xmit_buffer(unsigned int id, dma_addr_t buffer, unsigned int length){ int dma_tx_ch; if (omap_mcbsp_check(id) < 0) return -EINVAL; if (omap_request_dma(mcbsp[id].dma_tx_sync, "McBSP TX", omap_mcbsp_tx_dma_callback, &mcbsp[id], &dma_tx_ch)) { printk("OMAP-McBSP: Unable to request DMA channel for McBSP%d TX. Trying IRQ based TX\n", id+1); return -EAGAIN; } mcbsp[id].dma_tx_lch = dma_tx_ch; DBG("TX DMA on channel %d\n", dma_tx_ch); init_completion(&(mcbsp[id].tx_dma_completion)); omap_set_dma_transfer_params(mcbsp[id].dma_tx_lch, OMAP_DMA_DATA_TYPE_S16, length >> 1, 1, OMAP_DMA_SYNC_ELEMENT, 0, 0); omap_set_dma_dest_params(mcbsp[id].dma_tx_lch, OMAP_DMA_PORT_TIPB, OMAP_DMA_AMODE_CONSTANT, mcbsp[id].io_base + OMAP_MCBSP_REG_DXR1, 0, 0); omap_set_dma_src_params(mcbsp[id].dma_tx_lch, OMAP_DMA_PORT_EMIFF, OMAP_DMA_AMODE_POST_INC, buffer, 0, 0); omap_start_dma(mcbsp[id].dma_tx_lch); wait_for_completion(&(mcbsp[id].tx_dma_completion)); return 0;}int omap_mcbsp_recv_buffer(unsigned int id, dma_addr_t buffer, unsigned int length){ int dma_rx_ch; if (omap_mcbsp_check(id) < 0) return -EINVAL; if (omap_request_dma(mcbsp[id].dma_rx_sync, "McBSP RX", omap_mcbsp_rx_dma_callback, &mcbsp[id], &dma_rx_ch)) { printk("Unable to request DMA channel for McBSP%d RX. Trying IRQ based RX\n", id+1); return -EAGAIN; } mcbsp[id].dma_rx_lch = dma_rx_ch; DBG("RX DMA on channel %d\n", dma_rx_ch); init_completion(&(mcbsp[id].rx_dma_completion)); omap_set_dma_transfer_params(mcbsp[id].dma_rx_lch, OMAP_DMA_DATA_TYPE_S16, length >> 1, 1, OMAP_DMA_SYNC_ELEMENT, 0, 0); omap_set_dma_src_params(mcbsp[id].dma_rx_lch, OMAP_DMA_PORT_TIPB, OMAP_DMA_AMODE_CONSTANT, mcbsp[id].io_base + OMAP_MCBSP_REG_DRR1, 0, 0); omap_set_dma_dest_params(mcbsp[id].dma_rx_lch, OMAP_DMA_PORT_EMIFF, OMAP_DMA_AMODE_POST_INC, buffer, 0, 0); omap_start_dma(mcbsp[id].dma_rx_lch); wait_for_completion(&(mcbsp[id].rx_dma_completion)); return 0;}/* * SPI wrapper. * Since SPI setup is much simpler than the generic McBSP one, * this wrapper just need an omap_mcbsp_spi_cfg structure as an input. * Once this is done, you can call omap_mcbsp_start(). */void omap_mcbsp_set_spi_mode(unsigned int id, const struct omap_mcbsp_spi_cfg * spi_cfg){ struct omap_mcbsp_reg_cfg mcbsp_cfg; if (omap_mcbsp_check(id) < 0) return; memset(&mcbsp_cfg, 0, sizeof(struct omap_mcbsp_reg_cfg)); /* SPI has only one frame */ mcbsp_cfg.rcr1 |= (RWDLEN1(spi_cfg->word_length) | RFRLEN1(0)); mcbsp_cfg.xcr1 |= (XWDLEN1(spi_cfg->word_length) | XFRLEN1(0)); /* Clock stop mode */ if (spi_cfg->clk_stp_mode == OMAP_MCBSP_CLK_STP_MODE_NO_DELAY) mcbsp_cfg.spcr1 |= (1 << 12); else mcbsp_cfg.spcr1 |= (3 << 11); /* Set clock parities */ if (spi_cfg->rx_clock_polarity == OMAP_MCBSP_CLK_RISING) mcbsp_cfg.pcr0 |= CLKRP; else mcbsp_cfg.pcr0 &= ~CLKRP; if (spi_cfg->tx_clock_polarity == OMAP_MCBSP_CLK_RISING) mcbsp_cfg.pcr0 &= ~CLKXP; else mcbsp_cfg.pcr0 |= CLKXP; /* Set SCLKME to 0 and CLKSM to 1 */ mcbsp_cfg.pcr0 &= ~SCLKME; mcbsp_cfg.srgr2 |= CLKSM; /* Set FSXP */ if (spi_cfg->fsx_polarity == OMAP_MCBSP_FS_ACTIVE_HIGH) mcbsp_cfg.pcr0 &= ~FSXP; else mcbsp_cfg.pcr0 |= FSXP; if (spi_cfg->spi_mode == OMAP_MCBSP_SPI_MASTER) { mcbsp_cfg.pcr0 |= CLKXM; mcbsp_cfg.srgr1 |= CLKGDV(spi_cfg->clk_div -1); mcbsp_cfg.pcr0 |= FSXM; mcbsp_cfg.srgr2 &= ~FSGM; mcbsp_cfg.xcr2 |= XDATDLY(1); mcbsp_cfg.rcr2 |= RDATDLY(1); } else { mcbsp_cfg.pcr0 &= ~CLKXM; mcbsp_cfg.srgr1 |= CLKGDV(1); mcbsp_cfg.pcr0 &= ~FSXM; mcbsp_cfg.xcr2 &= ~XDATDLY(3); mcbsp_cfg.rcr2 &= ~RDATDLY(3); } mcbsp_cfg.xcr2 &= ~XPHASE; mcbsp_cfg.rcr2 &= ~RPHASE; omap_mcbsp_config(id, &mcbsp_cfg);}/* * McBSP1 and McBSP3 are directly mapped on 1610 and 1510. * 730 has only 2 McBSP, and both of them are MPU peripherals. */struct omap_mcbsp_info { u32 virt_base; u8 dma_rx_sync, dma_tx_sync; u16 rx_irq, tx_irq;};#ifdef CONFIG_ARCH_OMAP730static const struct omap_mcbsp_info mcbsp_730[] = { [0] = { .virt_base = io_p2v(OMAP730_MCBSP1_BASE), .dma_rx_sync = OMAP_DMA_MCBSP1_RX, .dma_tx_sync = OMAP_DMA_MCBSP1_TX, .rx_irq = INT_730_McBSP1RX, .tx_irq = INT_730_McBSP1TX }, [1] = { .virt_base = io_p2v(OMAP730_MCBSP2_BASE), .dma_rx_sync = OMAP_DMA_MCBSP3_RX, .dma_tx_sync = OMAP_DMA_MCBSP3_TX, .rx_irq = INT_730_McBSP2RX, .tx_irq = INT_730_McBSP2TX },};#endif#ifdef CONFIG_ARCH_OMAP15XXstatic const struct omap_mcbsp_info mcbsp_1510[] = { [0] = { .virt_base = OMAP1510_MCBSP1_BASE, .dma_rx_sync = OMAP_DMA_MCBSP1_RX, .dma_tx_sync = OMAP_DMA_MCBSP1_TX, .rx_irq = INT_McBSP1RX, .tx_irq = INT_McBSP1TX }, [1] = { .virt_base = io_p2v(OMAP1510_MCBSP2_BASE), .dma_rx_sync = OMAP_DMA_MCBSP2_RX, .dma_tx_sync = OMAP_DMA_MCBSP2_TX, .rx_irq = INT_1510_SPI_RX, .tx_irq = INT_1510_SPI_TX }, [2] = { .virt_base = OMAP1510_MCBSP3_BASE, .dma_rx_sync = OMAP_DMA_MCBSP3_RX, .dma_tx_sync = OMAP_DMA_MCBSP3_TX, .rx_irq = INT_McBSP3RX, .tx_irq = INT_McBSP3TX },};#endif#if defined(CONFIG_ARCH_OMAP16XX)static const struct omap_mcbsp_info mcbsp_1610[] = { [0] = { .virt_base = OMAP1610_MCBSP1_BASE, .dma_rx_sync = OMAP_DMA_MCBSP1_RX, .dma_tx_sync = OMAP_DMA_MCBSP1_TX, .rx_irq = INT_McBSP1RX, .tx_irq = INT_McBSP1TX }, [1] = { .virt_base = io_p2v(OMAP1610_MCBSP2_BASE), .dma_rx_sync = OMAP_DMA_MCBSP2_RX, .dma_tx_sync = OMAP_DMA_MCBSP2_TX, .rx_irq = INT_1610_McBSP2_RX, .tx_irq = INT_1610_McBSP2_TX }, [2] = { .virt_base = OMAP1610_MCBSP3_BASE, .dma_rx_sync = OMAP_DMA_MCBSP3_RX, .dma_tx_sync = OMAP_DMA_MCBSP3_TX, .rx_irq = INT_McBSP3RX, .tx_irq = INT_McBSP3TX },};#endifstatic int __init omap_mcbsp_init(void){ int mcbsp_count = 0, i; static const struct omap_mcbsp_info *mcbsp_info; printk("Initializing OMAP McBSP system\n"); mcbsp_dsp_ck = clk_get(0, "dsp_ck"); if (IS_ERR(mcbsp_dsp_ck)) { printk(KERN_ERR "mcbsp: could not acquire dsp_ck handle.\n"); return PTR_ERR(mcbsp_dsp_ck); } mcbsp_api_ck = clk_get(0, "api_ck"); if (IS_ERR(mcbsp_api_ck)) { printk(KERN_ERR "mcbsp: could not acquire api_ck handle.\n"); return PTR_ERR(mcbsp_api_ck); } mcbsp_dspxor_ck = clk_get(0, "dspxor_ck"); if (IS_ERR(mcbsp_dspxor_ck)) { printk(KERN_ERR "mcbsp: could not acquire dspxor_ck handle.\n"); return PTR_ERR(mcbsp_dspxor_ck); }#ifdef CONFIG_ARCH_OMAP730 if (cpu_is_omap730()) { mcbsp_info = mcbsp_730; mcbsp_count = ARRAY_SIZE(mcbsp_730); }#endif#ifdef CONFIG_ARCH_OMAP15XX if (cpu_is_omap1510()) { mcbsp_info = mcbsp_1510; mcbsp_count = ARRAY_SIZE(mcbsp_1510); }#endif#if defined(CONFIG_ARCH_OMAP16XX) if (cpu_is_omap16xx()) { mcbsp_info = mcbsp_1610; mcbsp_count = ARRAY_SIZE(mcbsp_1610); }#endif for (i = 0; i < OMAP_MAX_MCBSP_COUNT ; i++) { if (i >= mcbsp_count) { mcbsp[i].io_base = 0; mcbsp[i].free = 0; continue; } mcbsp[i].id = i + 1; mcbsp[i].free = 1; mcbsp[i].dma_tx_lch = -1; mcbsp[i].dma_rx_lch = -1; mcbsp[i].io_base = mcbsp_info[i].virt_base; mcbsp[i].tx_irq = mcbsp_info[i].tx_irq; mcbsp[i].rx_irq = mcbsp_info[i].rx_irq; mcbsp[i].dma_rx_sync = mcbsp_info[i].dma_rx_sync; mcbsp[i].dma_tx_sync = mcbsp_info[i].dma_tx_sync; spin_lock_init(&mcbsp[i].lock); } return 0;}arch_initcall(omap_mcbsp_init);EXPORT_SYMBOL(omap_mcbsp_config);EXPORT_SYMBOL(omap_mcbsp_request);EXPORT_SYMBOL(omap_mcbsp_free);EXPORT_SYMBOL(omap_mcbsp_start);EXPORT_SYMBOL(omap_mcbsp_stop);EXPORT_SYMBOL(omap_mcbsp_xmit_word);EXPORT_SYMBOL(omap_mcbsp_recv_word);EXPORT_SYMBOL(omap_mcbsp_xmit_buffer);EXPORT_SYMBOL(omap_mcbsp_recv_buffer);EXPORT_SYMBOL(omap_mcbsp_set_spi_mode);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -