📄 omap-mcbsp.c
字号:
OMAP_MCBSP_WRITE(io_base, SRGR2, SRGR2_CLKSM | SRGR2_FSGM | SRGR2_FPER(bits_per_sample * 2 - 1));#else OMAP_MCBSP_WRITE(io_base, SRGR1, SRGR1_FWID(bits_per_sample - 1) | SRGR1_CLKGDV(clkgdv)); OMAP_MCBSP_WRITE(io_base, SRGR2, (SRGR2_GSYNC | SRGR2_CLKSP | SRGR2_FSGM | SRGR2_FPER(bits_per_sample * 2 - 1)));#endif /* end of #ifdef MCBSP_MASTER */ return (0);}/***************** INTERRUPT MODE *************/#ifdef MCBSP_IRQ_MODE/* NOTE: Legacy Code being carried forward. These functions are purely non-operational currently */static irqreturn_tomap_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_tomap_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);}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_omap1610() || cpu_is_omap1710()) { 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;}int omap_mcbsp_request(unsigned int id){ int err; if (omap_mcbsp_check(id) < 0) return -EINVAL; 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; 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]));}/* * 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. */intomap_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); 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); omap_set_dma_src_params(mcbsp[id].dma_tx_lch, OMAP_DMA_PORT_EMIFF, OMAP_DMA_AMODE_POST_INC, buffer); omap_start_dma(mcbsp[id].dma_tx_lch); wait_for_completion(&(mcbsp[id].tx_dma_completion)); return 0;}intomap_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); 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); omap_set_dma_dest_params(mcbsp[id].dma_rx_lch, OMAP_DMA_PORT_EMIFF, OMAP_DMA_AMODE_POST_INC, buffer); 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_begin(). */voidomap_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);}#endif /* End of #ifdef MCBSP_IRQ_MODE */#ifdef MCBSP_DIRECT_RWint omap_mcbsp_write(unsigned int id, u16 buf){ u32 base = mcbsp[id].virt_base; writew(buf, base + OMAP_MCBSP_REG_DXR1); // if frame sync error - clear the error if (readw(base + OMAP_MCBSP_REG_SPCR2) & SPCR2_XSYNCERR) { // clear error writew(readw(base + OMAP_MCBSP_REG_SPCR2) & (~SPCR2_XSYNCERR), base + OMAP_MCBSP_REG_SPCR2); // resend return -1; } else { // wait for transmit confirmation int attemps = 0; while (!(readw(base + OMAP_MCBSP_REG_SPCR2) & SPCR2_XRDY)) { if (attemps++ > 1000) { writew(readw(base + OMAP_MCBSP_REG_SPCR2) & (~SPCR2_XRST), base + OMAP_MCBSP_REG_SPCR2); udelay(10); writew(readw(base + OMAP_MCBSP_REG_SPCR2) | (SPCR2_XRST), base + OMAP_MCBSP_REG_SPCR2); udelay(10); printk(KERN_ERR " Could not write to McBSP Register\n"); return -2; } } } return 0;}int omap_mcbsp_read(unsigned int id, u16 * buf){ u32 base = mcbsp[id].virt_base; // if frame sync error - clear the error if (readw(base + OMAP_MCBSP_REG_SPCR1) & SPCR1_RSYNCERR) { // clear error writew(readw(base + OMAP_MCBSP_REG_SPCR1) & (~SPCR1_RSYNCERR), base + OMAP_MCBSP_REG_SPCR1); // resend return -1; } else { // wait for transmit confirmation int attemps = 0; while (!(readw(base + OMAP_MCBSP_REG_SPCR1) & SPCR1_RRDY)) { if (attemps++ > 1000) { writew(readw(base + OMAP_MCBSP_REG_SPCR1) & (~SPCR1_RRST), base + OMAP_MCBSP_REG_SPCR1); udelay(10); writew(readw(base + OMAP_MCBSP_REG_SPCR1) | (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;}#endif /* End of #ifdef MCBSP_DIRECT_RW *//***************** Module init */static int __init omap_mcbsp_init(void){ u8 count = 0; printk("Initializing OMAP McBSP system for ");#ifdef CONFIG_ARCH_OMAP16XX if (cpu_is_omap1610()) { mcbsp = mcbsp_1610; printk("OMAP 1610\n"); } if (cpu_is_omap1710()) { mcbsp = mcbsp_1710; printk("OMAP 1710\n"); }#endif#ifdef CONFIG_ARCH_OMAP24XX if (cpu_is_omap2420()) { mcbsp = mcbsp_2420; printk("OMAP 2420\n"); }#endif if (NULL == mcbsp) { printk(KERN_ERR "Unsupported processor- Cannot Initialize\n"); return -EPERM; } /* Initialize all other params of the structure */ for (; count < OMAP_MAX_MCBSP_COUNT; count++) { mcbsp[count].free = 1;#ifdef MCBSP_IRQ_MODE mcbsp[count].rx_word_length = 0; mcbsp[count].tx_word_length = 0; mcbsp[count].id = count + 1; spin_lock_init(&mcbsp[count].lock);#endif } /* End of for() */ return (0);} /* End of omap_mcbsp_init */arch_initcall(omap_mcbsp_init);EXPORT_SYMBOL(omap_mcbsp_begin);EXPORT_SYMBOL(omap_mcbsp_end);EXPORT_SYMBOL(omap_mcbsp_set_rate);#ifdef MCBSP_DIRECT_RWEXPORT_SYMBOL(omap_mcbsp_read);EXPORT_SYMBOL(omap_mcbsp_write);#endif#ifdef MCBSP_IRQ_MODEEXPORT_SYMBOL(omap_mcbsp_request);EXPORT_SYMBOL(omap_mcbsp_free);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);#endif /* End of #ifdef MCBSP_IRQ_MODE */MODULE_AUTHOR("MontaVista");MODULE_DESCRIPTION("McBsp Driver for OMAP 1610/1710/2420.");MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -