/* * Stop receving data on a McBSP interface * id : McBSP interface ID */ int omap2_mcbsp_stop_datarx(u32 id) { struct omap_mcbsp *mcbsp = mcbsp_ptr[id]; void __iomem *io_base; if (!omap_mcbsp_check_valid_id(id)) { printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1); return -ENODEV; } io_base = mcbsp->io_base; if (mcbsp->dma_rx_lch != -1) { if (omap_stop_dma_chain_transfers(mcbsp->dma_rx_lch) != 0) return -EINVAL; } OMAP_MCBSP_WRITE(mcbsp, SPCR1, OMAP_MCBSP_READ(mcbsp, SPCR1) & (~RRST)); mcbsp->rx_dma_chain_state = 0; if (!mcbsp->tx_dma_chain_state) omap2_mcbsp_set_srg_fsg(id, OMAP_MCBSP_DISABLE_FSG_SRG); return 0; }
/* * Reset Receiver * id : McBSP interface number * state : Disable (0)/ Enable (1) the receiver */ int omap2_mcbsp_set_rrst(unsigned int id, u8 state) { struct omap_mcbsp *mcbsp = mcbsp_ptr[id]; void __iomem *io_base; if (!omap_mcbsp_check_valid_id(id)) { printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1); return -ENODEV; } io_base = mcbsp->io_base; if (state == OMAP_MCBSP_RRST_DISABLE) OMAP_MCBSP_WRITE(mcbsp, SPCR1, OMAP_MCBSP_READ(mcbsp, SPCR1) & (~RRST)); else OMAP_MCBSP_WRITE(mcbsp, SPCR1, OMAP_MCBSP_READ(mcbsp, SPCR1) | RRST); udelay(10); return 0; }
/* * Enable/Disable the sample rate generator * id : McBSP interface ID * state : Enable/Disable */ void omap2_mcbsp_set_srg_fsg(unsigned int id, u8 state) { struct omap_mcbsp *mcbsp = mcbsp_ptr[id]; void __iomem *io_base; io_base = mcbsp->io_base; if (state == OMAP_MCBSP_DISABLE_FSG_SRG) { OMAP_MCBSP_WRITE(mcbsp, SPCR2, OMAP_MCBSP_READ(mcbsp, SPCR2) & (~GRST)); OMAP_MCBSP_WRITE(mcbsp, SPCR2, OMAP_MCBSP_READ(mcbsp, SPCR2) & (~FRST)); } else { OMAP_MCBSP_WRITE(mcbsp, SPCR2, OMAP_MCBSP_READ(mcbsp, SPCR2) | GRST); OMAP_MCBSP_WRITE(mcbsp, SPCR2, OMAP_MCBSP_READ(mcbsp, SPCR2) | FRST); } return; }
static void omap2_mcbsp_tx_dma_callback(int lch, u16 ch_status, void *data) { struct omap_mcbsp *mcbsp_dma_tx = data; void __iomem *io_base; io_base = mcbsp_dma_tx->io_base; /* If we are at the last transfer, Shut down the Transmitter */ if ((mcbsp_dma_tx->auto_reset & OMAP_MCBSP_AUTO_XRST) && (omap_dma_chain_status(mcbsp_dma_tx->dma_tx_lch) == OMAP_DMA_CHAIN_INACTIVE)) OMAP_MCBSP_WRITE(mcbsp_dma_tx, SPCR2, OMAP_MCBSP_READ(mcbsp_dma_tx, SPCR2) & (~XRST)); if (mcbsp_dma_tx->tx_callback != NULL) mcbsp_dma_tx->tx_callback(ch_status, mcbsp_dma_tx->tx_cb_arg); }
void omap2_mcbsp_set_srg_cfg_param(unsigned int id, int interface_mode, struct omap_mcbsp_reg_cfg *mcbsp_cfg, struct omap_mcbsp_srg_fsg_cfg *param) { struct omap_mcbsp *mcbsp = mcbsp_ptr[id]; void __iomem *io_base; u32 clk_rate, clkgdv; io_base = mcbsp->io_base; mcbsp->interface_mode = interface_mode; mcbsp_cfg->srgr1 = FWID(param->pulse_width); if (interface_mode == OMAP_MCBSP_MASTER) { clk_rate = clk_get_rate(mcbsp->fclk); clkgdv = clk_rate / (param->sample_rate * (param->bits_per_sample - 1)); if (clkgdv > 0xFF) clkgdv = 0xFF; mcbsp_cfg->srgr1 = mcbsp_cfg->srgr1 | CLKGDV(clkgdv); } if (param->dlb) mcbsp_cfg->spcr1 = mcbsp_cfg->spcr1 & ~(ALB); if (param->sync_mode == OMAP_MCBSP_SRG_FREERUNNING) mcbsp_cfg->spcr2 = mcbsp_cfg->spcr2 | FREE; mcbsp_cfg->srgr2 = FPER(param->period)|(param->fsgm? FSGM : 0); switch (param->srg_src) { case OMAP_MCBSP_SRGCLKSRC_CLKS: mcbsp_cfg->pcr0 = mcbsp_cfg->pcr0 & ~(SCLKME); mcbsp_cfg->srgr2 = mcbsp_cfg->srgr2 & ~(CLKSM); /* * McBSP master operation at low voltage is only possible if * CLKSP=0 In Master mode, if client driver tries to configiure * input clock polarity as falling edge, we force it to Rising */ if ((param->polarity == OMAP_MCBSP_CLKS_POLARITY_RISING) || (interface_mode == OMAP_MCBSP_MASTER)) mcbsp_cfg->srgr2 = mcbsp_cfg->srgr2 & ~(CLKSP); else mcbsp_cfg->srgr2 = mcbsp_cfg->srgr2 | (CLKSP); break; case OMAP_MCBSP_SRGCLKSRC_FCLK: mcbsp_cfg->pcr0 = mcbsp_cfg->pcr0 & ~(SCLKME); mcbsp_cfg->srgr2 = mcbsp_cfg->srgr2 | (CLKSM); break; case OMAP_MCBSP_SRGCLKSRC_CLKR: mcbsp_cfg->pcr0 = mcbsp_cfg->pcr0 | (SCLKME); mcbsp_cfg->srgr2 = mcbsp_cfg->srgr2 & ~(CLKSM); if (param->polarity == OMAP_MCBSP_CLKR_POLARITY_FALLING) mcbsp_cfg->pcr0 = mcbsp_cfg->pcr0 & ~(CLKRP); else mcbsp_cfg->pcr0 = mcbsp_cfg->pcr0 | (CLKRP); break; case OMAP_MCBSP_SRGCLKSRC_CLKX: mcbsp_cfg->pcr0 = mcbsp_cfg->pcr0 | (SCLKME); mcbsp_cfg->srgr2 = mcbsp_cfg->srgr2 | (CLKSM); if (param->polarity == OMAP_MCBSP_CLKX_POLARITY_RISING) mcbsp_cfg->pcr0 = mcbsp_cfg->pcr0 & ~(CLKXP); else mcbsp_cfg->pcr0 = mcbsp_cfg->pcr0 | (CLKXP); break; } if (param->sync_mode == OMAP_MCBSP_SRG_FREERUNNING) mcbsp_cfg->srgr2 = mcbsp_cfg->srgr2 & ~(GSYNC); else if (param->sync_mode == OMAP_MCBSP_SRG_RUNNING) mcbsp_cfg->srgr2 = mcbsp_cfg->srgr2 | (GSYNC); mcbsp_cfg->xccr = OMAP_MCBSP_READ(mcbsp, XCCR) & ~(XDISABLE); if (param->dlb) mcbsp_cfg->xccr = mcbsp_cfg->xccr | (DILB); mcbsp_cfg->rccr = OMAP_MCBSP_READ(mcbsp, RCCR) & ~(RDISABLE); return; }
/* * Start transmitting data through a McBSP interface * id : McBSP interface ID * cbdata : User data to be returned with callback * buf_start_addr : The source address [This should be physical address] * buf_size : Buffer size */ int omap2_mcbsp_send_data(unsigned int id, void *cbdata, dma_addr_t buf_start_addr, u32 buf_size) { struct omap_mcbsp *mcbsp; void __iomem *io_base; u8 enable_tx = 0; int e_count = 0; int f_count = 0; if (!omap_mcbsp_check_valid_id(id)) { printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1); return -ENODEV; } mcbsp = id_to_mcbsp_ptr(id); io_base = mcbsp->io_base; mcbsp->tx_cb_arg = cbdata; /* Auto RRST handling logic - disable the Reciever before 1st dma */ if ((mcbsp->auto_reset & OMAP_MCBSP_AUTO_XRST) && (omap_dma_chain_status(mcbsp->dma_tx_lch) == OMAP_DMA_CHAIN_INACTIVE)) { OMAP_MCBSP_WRITE(mcbsp, SPCR2, OMAP_MCBSP_READ(mcbsp, SPCR2) & (~XRST)); enable_tx = 1; } /* * for skip_first and second, we need to set e_count =2, and * f_count = number of frames = number of elements/e_count */ e_count = (buf_size / mcbsp->tx_word_length); if (mcbsp->txskip_alt != OMAP_MCBSP_SKIP_NONE) { /* * number of frames = total number of elements/element count, * However, with double indexing for data transfers, double I * the number of elements need to be transmitted */ f_count = e_count; e_count = 2; } else { f_count = 1; } /* * If the DMA is to be configured to skip the first byte, we need * to jump backwards, so we need to move one chunk forward and ask * dma if we dont want the client driver knowing abt this. */ if (mcbsp->txskip_alt == OMAP_MCBSP_SKIP_FIRST) buf_start_addr += mcbsp->tx_word_length; if (omap_dma_chain_a_transfer(mcbsp->dma_tx_lch, buf_start_addr, mcbsp->phys_base + OMAP_MCBSP_REG_DXR, e_count, f_count, mcbsp) < 0) return -EINVAL; if (mcbsp->tx_dma_chain_state == 0) { if (mcbsp->interface_mode == OMAP_MCBSP_MASTER) omap2_mcbsp_set_srg_fsg(id, OMAP_MCBSP_ENABLE_FSG_SRG); if (omap_start_dma_chain_transfers(mcbsp->dma_tx_lch) < 0) return -EINVAL; mcbsp->tx_dma_chain_state = 1; } /* Auto XRST handling logic - Enable the Reciever after 1st dma */ if (enable_tx && (omap_dma_chain_status(mcbsp->dma_tx_lch) == OMAP_DMA_CHAIN_ACTIVE)) OMAP_MCBSP_WRITE(mcbsp, SPCR2, OMAP_MCBSP_READ(mcbsp, SPCR2) | XRST); return 0; }
int omap2_mcbsp_receive_data(unsigned int id, void *cbdata, dma_addr_t buf_start_addr, u32 buf_size) { struct omap_mcbsp *mcbsp; void __iomem *io_base; int enable_rx = 0; int e_count = 0; int f_count = 0; if (!omap_mcbsp_check_valid_id(id)) { printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1); return -ENODEV; } mcbsp = id_to_mcbsp_ptr(id); io_base = mcbsp->io_base; mcbsp->rx_cb_arg = cbdata; /* Auto RRST handling logic - disable the Reciever before 1st dma */ if ((mcbsp->auto_reset & OMAP_MCBSP_AUTO_RRST) && (omap_dma_chain_status(mcbsp->dma_rx_lch) == OMAP_DMA_CHAIN_INACTIVE)) { OMAP_MCBSP_WRITE(io_base, SPCR1, OMAP_MCBSP_READ(io_base, SPCR1) & (~RRST)); enable_rx = 1; } /* * for skip_first and second, we need to set e_count =2, * and f_count = number of frames = number of elements/e_count */ e_count = (buf_size / mcbsp->rx_word_length); if (mcbsp->rxskip_alt != OMAP_MCBSP_SKIP_NONE) { /* * since the number of frames = total number of elements/element * count, However, with double indexing for data transfers, * double the number of elements need to be transmitted */ f_count = e_count; e_count = 2; } else { f_count = 1; } /* * If the DMA is to be configured to skip the first byte, we need * to jump backwards, so we need to move one chunk forward and * ask dma if we dont want the client driver knowing abt this. */ if (mcbsp->rxskip_alt == OMAP_MCBSP_SKIP_FIRST) buf_start_addr += mcbsp->rx_word_length; if (omap_dma_chain_a_transfer(mcbsp->dma_rx_lch, mcbsp->phys_base + OMAP_MCBSP_REG_DRR, buf_start_addr, e_count, f_count, mcbsp) < 0) { printk(KERN_ERR " Buffer chaining failed \n"); return -EINVAL; } if (mcbsp->rx_dma_chain_state == 0) { if (omap_start_dma_chain_transfers(mcbsp->dma_rx_lch) < 0) return -EINVAL; mcbsp->rx_dma_chain_state = 1; } /* Auto RRST handling logic - Enable the Reciever after 1st dma */ if (enable_rx && (omap_dma_chain_status(mcbsp->dma_rx_lch) == OMAP_DMA_CHAIN_ACTIVE)) OMAP_MCBSP_WRITE(io_base, SPCR1, OMAP_MCBSP_READ(io_base, SPCR1) | RRST); return 0; }