int omap_st_is_enabled(unsigned int id) { struct omap_mcbsp *mcbsp; struct omap_mcbsp_st_data *st_data; 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); st_data = mcbsp->st_data; if (!st_data) return -ENODEV; return st_data->enabled; }
int omap2_mcbsp_set_clks_src(u8 id, u8 fck_src_id) { struct omap_mcbsp *mcbsp; struct clk *fck_src; char *fck_src_name; int r; if (!omap_mcbsp_check_valid_id(id)) { pr_err("%s: Invalid id (%d)\n", __func__, id + 1); return -EINVAL; } mcbsp = id_to_mcbsp_ptr(id); if (fck_src_id == MCBSP_CLKS_PAD_SRC) fck_src_name = "pad_fck"; else if (fck_src_id == MCBSP_CLKS_PRCM_SRC) fck_src_name = "prcm_fck"; else return -EINVAL; fck_src = clk_get(mcbsp->dev, fck_src_name); if (IS_ERR_OR_NULL(fck_src)) { pr_err("omap-mcbsp: %s: could not clk_get() %s\n", "clks", fck_src_name); return -EINVAL; } clk_disable(mcbsp->fclk); r = clk_set_parent(mcbsp->fclk, fck_src); if (IS_ERR_VALUE(r)) { pr_err("omap-mcbsp: %s: could not clk_set_parent() to %s\n", "clks", fck_src_name); clk_put(fck_src); return -EINVAL; } clk_enable(mcbsp->fclk); clk_put(fck_src); return 0; }
/* * omap_mcbsp_get_tx_delay returns the number of used slots in the McBSP FIFO */ u16 omap_mcbsp_get_tx_delay(unsigned int id) { struct omap_mcbsp *mcbsp; u16 buffstat; 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); if (mcbsp->pdata->buffer_size == 0) return 0; /* Returns the number of free locations in the buffer */ buffstat = MCBSP_READ(mcbsp, XBUFFSTAT); /* Number of slots are different in McBSP ports */ return mcbsp->pdata->buffer_size - buffstat; }
/* * 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; }
/* * omap_mcbsp_get_rx_delay returns the number of free slots in the McBSP FIFO * to reach the threshold value (when the DMA will be triggered to read it) */ u16 omap_mcbsp_get_rx_delay(unsigned int id) { struct omap_mcbsp *mcbsp; u16 buffstat, threshold; 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); /* Returns the number of used locations in the buffer */ buffstat = MCBSP_READ(mcbsp, RBUFFSTAT); /* RX threshold */ threshold = MCBSP_READ(mcbsp, THRSH1); /* Return the number of location till we reach the threshold limit */ if (threshold <= buffstat) return 0; else return threshold - buffstat; }
int omap_st_enable(unsigned int id) { struct omap_mcbsp *mcbsp; struct omap_mcbsp_st_data *st_data; 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); st_data = mcbsp->st_data; if (!st_data) return -ENODEV; spin_lock_irq(&mcbsp->lock); st_data->enabled = 1; omap_st_start(mcbsp); spin_unlock_irq(&mcbsp->lock); return 0; }
int omap2_mcbsp_set_clks_src(u8 id, u8 fck_src_id) { struct omap_mcbsp *mcbsp; const char *src; if (!omap_mcbsp_check_valid_id(id)) { pr_err("%s: Invalid id (%d)\n", __func__, id + 1); return -EINVAL; } mcbsp = id_to_mcbsp_ptr(id); if (fck_src_id == MCBSP_CLKS_PAD_SRC) src = "clks_ext"; else if (fck_src_id == MCBSP_CLKS_PRCM_SRC) src = "clks_fclk"; else return -EINVAL; if (mcbsp->pdata->set_clk_src) return mcbsp->pdata->set_clk_src(mcbsp->dev, mcbsp->fclk, src); else return -EINVAL; }
void omap_mcbsp_free(unsigned int id) { struct omap_mcbsp *mcbsp; void *reg_cache; if (!omap_mcbsp_check_valid_id(id)) { printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1); return; } mcbsp = id_to_mcbsp_ptr(id); if (mcbsp->pdata && mcbsp->pdata->ops && mcbsp->pdata->ops->free) mcbsp->pdata->ops->free(id); /* Disable wakeup behavior */ if (mcbsp->pdata->has_wakeup) MCBSP_WRITE(mcbsp, WAKEUPEN, 0); pm_runtime_put_sync(mcbsp->dev); if (mcbsp->rx_irq) free_irq(mcbsp->rx_irq, (void *)mcbsp); free_irq(mcbsp->tx_irq, (void *)mcbsp); reg_cache = mcbsp->reg_cache; spin_lock(&mcbsp->lock); if (mcbsp->free) dev_err(mcbsp->dev, "McBSP%d was not reserved\n", mcbsp->id); else mcbsp->free = true; mcbsp->reg_cache = NULL; spin_unlock(&mcbsp->lock); if (reg_cache) kfree(reg_cache); }
void omap_mcbsp_free(unsigned int id) { struct omap_mcbsp *mcbsp; void *reg_cache; if (!omap_mcbsp_check_valid_id(id)) { printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1); return; } mcbsp = id_to_mcbsp_ptr(id); if (mcbsp->pdata && mcbsp->pdata->ops && mcbsp->pdata->ops->free) mcbsp->pdata->ops->free(id); /* Do procedure specific to omap34xx arch, if applicable */ omap34xx_mcbsp_free(mcbsp); pm_runtime_put_sync(mcbsp->dev); if (mcbsp->rx_irq) free_irq(mcbsp->rx_irq, (void *)mcbsp); free_irq(mcbsp->tx_irq, (void *)mcbsp); reg_cache = mcbsp->reg_cache; spin_lock(&mcbsp->lock); if (mcbsp->free) dev_err(mcbsp->dev, "McBSP%d was not reserved\n", mcbsp->id); else mcbsp->free = true; mcbsp->reg_cache = NULL; spin_unlock(&mcbsp->lock); if (reg_cache) kfree(reg_cache); }
/* * Here we start the McBSP, by enabling transmitter, receiver or both. * If no transmitter or receiver is active prior calling, then sample-rate * generator and frame sync are started. */ void omap_mcbsp_start(unsigned int id, int tx, int rx) { struct omap_mcbsp *mcbsp; int enable_srg = 0; u16 w; if (!omap_mcbsp_check_valid_id(id)) { printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1); return; } mcbsp = id_to_mcbsp_ptr(id); if (cpu_is_omap34xx()) omap_st_start(mcbsp); /* Only enable SRG, if McBSP is master */ w = MCBSP_READ_CACHE(mcbsp, PCR0); if (w & (FSXM | FSRM | CLKXM | CLKRM)) enable_srg = !((MCBSP_READ_CACHE(mcbsp, SPCR2) | MCBSP_READ_CACHE(mcbsp, SPCR1)) & 1); if (enable_srg) { /* Start the sample generator */ w = MCBSP_READ_CACHE(mcbsp, SPCR2); MCBSP_WRITE(mcbsp, SPCR2, w | (1 << 6)); } /* Enable transmitter and receiver */ tx &= 1; w = MCBSP_READ_CACHE(mcbsp, SPCR2); MCBSP_WRITE(mcbsp, SPCR2, w | tx); rx &= 1; w = MCBSP_READ_CACHE(mcbsp, SPCR1); MCBSP_WRITE(mcbsp, SPCR1, w | rx); /* * Worst case: CLKSRG*2 = 8000khz: (1/8000) * 2 * 2 usec * REVISIT: 100us may give enough time for two CLKSRG, however * due to some unknown PM related, clock gating etc. reason it * is now at 500us. */ udelay(500); if (enable_srg) { /* Start frame sync */ w = MCBSP_READ_CACHE(mcbsp, SPCR2); MCBSP_WRITE(mcbsp, SPCR2, w | (1 << 7)); } if (cpu_is_omap2430() || cpu_is_omap34xx() || cpu_is_omap44xx()) { /* Release the transmitter and receiver */ w = MCBSP_READ_CACHE(mcbsp, XCCR); w &= ~(tx ? XDISABLE : 0); MCBSP_WRITE(mcbsp, XCCR, w); w = MCBSP_READ_CACHE(mcbsp, RCCR); w &= ~(rx ? RDISABLE : 0); MCBSP_WRITE(mcbsp, RCCR, w); } /* Dump McBSP Regs */ omap_mcbsp_dump_reg(id); }
int omap_mcbsp_request(unsigned int id) { struct omap_mcbsp *mcbsp; void *reg_cache; int err; 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); reg_cache = kzalloc(omap_mcbsp_cache_size, GFP_KERNEL); if (!reg_cache) { return -ENOMEM; } spin_lock(&mcbsp->lock); if (!mcbsp->free) { dev_err(mcbsp->dev, "McBSP%d is currently in use\n", mcbsp->id); err = -EBUSY; goto err_kfree; } mcbsp->free = false; mcbsp->reg_cache = reg_cache; spin_unlock(&mcbsp->lock); if (mcbsp->pdata && mcbsp->pdata->ops && mcbsp->pdata->ops->request) mcbsp->pdata->ops->request(id); pm_runtime_get_sync(mcbsp->dev); /* Do procedure specific to omap34xx arch, if applicable */ omap34xx_mcbsp_request(mcbsp); /* * Make sure that transmitter, receiver and sample-rate generator are * not running before activating IRQs. */ MCBSP_WRITE(mcbsp, SPCR1, 0); MCBSP_WRITE(mcbsp, SPCR2, 0); err = request_irq(mcbsp->tx_irq, omap_mcbsp_tx_irq_handler, 0, "McBSP", (void *)mcbsp); if (err != 0) { dev_err(mcbsp->dev, "Unable to request TX IRQ %d " "for McBSP%d\n", mcbsp->tx_irq, mcbsp->id); goto err_clk_disable; } if (mcbsp->rx_irq) { err = request_irq(mcbsp->rx_irq, omap_mcbsp_rx_irq_handler, 0, "McBSP", (void *)mcbsp); if (err != 0) { dev_err(mcbsp->dev, "Unable to request RX IRQ %d " "for McBSP%d\n", mcbsp->rx_irq, mcbsp->id); goto err_free_irq; } } return 0; err_free_irq: free_irq(mcbsp->tx_irq, (void *)mcbsp); err_clk_disable: if (mcbsp->pdata && mcbsp->pdata->ops && mcbsp->pdata->ops->free) mcbsp->pdata->ops->free(id); /* Do procedure specific to omap34xx arch, if applicable */ omap34xx_mcbsp_free(mcbsp); pm_runtime_put_sync(mcbsp->dev); spin_lock(&mcbsp->lock); mcbsp->free = true; mcbsp->reg_cache = NULL; err_kfree: spin_unlock(&mcbsp->lock); kfree(reg_cache); return err; }
/* * 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_dma_trans_params(unsigned int id, struct omap_mcbsp_dma_transfer_params *tp) { struct omap_mcbsp *mcbsp; struct omap_dma_channel_params tx_params; int err = 0, chain_id = -1; void __iomem *io_base; u32 dt = 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; dt = tp->word_length1; if ((dt != OMAP_MCBSP_WORD_8) && (dt != OMAP_MCBSP_WORD_16) && (dt != OMAP_MCBSP_WORD_32)) return -EINVAL; if (dt == OMAP_MCBSP_WORD_8) tx_params.data_type = OMAP_DMA_DATA_TYPE_S8; else if (dt == OMAP_MCBSP_WORD_16) tx_params.data_type = OMAP_DMA_DATA_TYPE_S16; else if (dt == OMAP_MCBSP_WORD_32) tx_params.data_type = OMAP_DMA_DATA_TYPE_S32; else return -EINVAL; tx_params.read_prio = DMA_CH_PRIO_HIGH; tx_params.write_prio = DMA_CH_PRIO_HIGH; tx_params.sync_mode = OMAP_DMA_SYNC_ELEMENT; tx_params.dst_fi = 0; tx_params.trigger = mcbsp->dma_tx_sync; tx_params.src_or_dst_synch = 0; tx_params.dst_amode = OMAP_DMA_AMODE_CONSTANT; tx_params.dst_ei = 0; /* Indexing is always in bytes - so multiply with dt */ mcbsp->tx_word_length = tx_params.data_type << 0x1; if (tx_params.data_type == 0) mcbsp->tx_word_length = 1; dt = mcbsp->tx_word_length; /* SKIP_FIRST and SKIP_SECOND- skip alternate data in 24 bit mono */ if (tp->skip_alt == OMAP_MCBSP_SKIP_SECOND) { tx_params.src_amode = OMAP_DMA_AMODE_DOUBLE_IDX; tx_params.src_ei = (1); tx_params.src_fi = (1) + ((-1) * dt); } else if (tp->skip_alt == OMAP_MCBSP_SKIP_FIRST) { tx_params.src_amode = OMAP_DMA_AMODE_DOUBLE_IDX; tx_params.src_ei = 1 + (-2) * dt; tx_params.src_fi = 1 + (2) * dt; } else { tx_params.src_amode = OMAP_DMA_AMODE_POST_INC; tx_params.src_ei = 0; tx_params.src_fi = 0; } mcbsp->txskip_alt = tp->skip_alt; mcbsp->auto_reset &= ~OMAP_MCBSP_AUTO_XRST; mcbsp->auto_reset |= (tp->auto_reset & OMAP_MCBSP_AUTO_XRST); mcbsp->tx_callback = tp->callback; /* Based on Rjust we can do double indexing DMA params configuration */ if (mcbsp->dma_tx_lch == -1) { err = omap_request_dma_chain(id, "McBSP TX", omap2_mcbsp_tx_dma_callback, &chain_id, 2, OMAP_DMA_DYNAMIC_CHAIN, tx_params); if (err < 0) { printk(KERN_ERR "Transmit path configuration failed \n"); return -EINVAL; } mcbsp->tx_dma_chain_state = 0; mcbsp->dma_tx_lch = chain_id; } else { /* DMA params already set, modify the same!! */ err = omap_modify_dma_chain_params(mcbsp->dma_tx_lch, tx_params); if (err < 0) return -EINVAL; } return 0; }
/* * Configure the receiver parameters * id : McBSP Interface ID * rp : DMA Receive parameters */ int omap2_mcbsp_dma_recv_params(unsigned int id, struct omap_mcbsp_dma_transfer_params *rp) { struct omap_mcbsp *mcbsp; void __iomem *io_base; int err, chain_id = -1; struct omap_dma_channel_params rx_params; u32 dt = 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; dt = rp->word_length1; if (dt == OMAP_MCBSP_WORD_8) rx_params.data_type = OMAP_DMA_DATA_TYPE_S8; else if (dt == OMAP_MCBSP_WORD_16) rx_params.data_type = OMAP_DMA_DATA_TYPE_S16; else if (dt == OMAP_MCBSP_WORD_32) rx_params.data_type = OMAP_DMA_DATA_TYPE_S32; else return -EINVAL; rx_params.read_prio = DMA_CH_PRIO_HIGH; rx_params.write_prio = DMA_CH_PRIO_HIGH; rx_params.sync_mode = OMAP_DMA_SYNC_ELEMENT; rx_params.src_fi = 0; rx_params.trigger = mcbsp->dma_rx_sync; rx_params.src_or_dst_synch = 0x01; rx_params.src_amode = OMAP_DMA_AMODE_CONSTANT; rx_params.src_ei = 0x0; /* Indexing is always in bytes - so multiply with dt */ dt = (rx_params.data_type == OMAP_DMA_DATA_TYPE_S8) ? 1 : (rx_params.data_type == OMAP_DMA_DATA_TYPE_S16) ? 2 : 4; /* SKIP_FIRST and SKIP_SECOND- skip alternate data in 24 bit mono */ if (rp->skip_alt == OMAP_MCBSP_SKIP_SECOND) { rx_params.dst_amode = OMAP_DMA_AMODE_DOUBLE_IDX; rx_params.dst_ei = (1); rx_params.dst_fi = (1) + ((-1) * dt); } else if (rp->skip_alt == OMAP_MCBSP_SKIP_FIRST) { rx_params.dst_amode = OMAP_DMA_AMODE_DOUBLE_IDX; rx_params.dst_ei = 1 + (-2) * dt; rx_params.dst_fi = 1 + (2) * dt; } else { rx_params.dst_amode = OMAP_DMA_AMODE_POST_INC; rx_params.dst_ei = 0; rx_params.dst_fi = 0; } mcbsp->rxskip_alt = rp->skip_alt; mcbsp->auto_reset &= ~OMAP_MCBSP_AUTO_RRST; mcbsp->auto_reset |= (rp->auto_reset & OMAP_MCBSP_AUTO_RRST); mcbsp->rx_word_length = rx_params.data_type << 0x1; if (rx_params.data_type == 0) mcbsp->rx_word_length = 1; mcbsp->rx_callback = rp->callback; /* request for a chain of dma channels for data reception */ if (mcbsp->dma_rx_lch == -1) { err = omap_request_dma_chain(id, "McBSP RX", omap2_mcbsp_rx_dma_callback, &chain_id, 2, OMAP_DMA_DYNAMIC_CHAIN, rx_params); if (err < 0) { printk(KERN_ERR "Receive path configuration failed \n"); return -EINVAL; } mcbsp->dma_rx_lch = chain_id; mcbsp->rx_dma_chain_state = 0; } else { /* DMA params already set, modify the same!! */ err = omap_modify_dma_chain_params(mcbsp->dma_rx_lch, rx_params); if (err < 0) return -EINVAL; } 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; }