static void _sys_clkout_en(int en) { struct clk *sys_clkout; struct omap_mcbsp *mcbsp; // TODO: port properly. mcbsp = id_to_mcbsp_ptr(0); sys_clkout = clk_get(NULL, sysclock_name); if (!IS_ERR(sys_clkout)) { if (en) { if (use_mcbsp1_fclk) { clk_enable(mcbsp->fclk); } if (clk_enable(sys_clkout) != 0) { printk(KERN_ERR "failed to enable %s\n", sysclock_name); } } else { clk_disable(sys_clkout); if (use_mcbsp1_fclk) { clk_disable(mcbsp->fclk); } } clk_put(sys_clkout); } }
/** * omap_mcbsp_dma_reg_params - returns the address of mcbsp data register * @id - mcbsp id * @stream - indicates the direction of data flow (rx or tx) * * Returns the address of mcbsp data transmit register or data receive register * to be used by DMA for transferring/receiving data based on the value of * @stream for the requested mcbsp given by @id */ int omap_mcbsp_dma_reg_params(unsigned int id, unsigned int stream) { struct omap_mcbsp *mcbsp; int data_reg; 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); data_reg = mcbsp->phys_dma_base; if (mcbsp->mcbsp_config_type < MCBSP_CONFIG_TYPE2) { if (stream) data_reg += OMAP_MCBSP_REG_DRR1; else data_reg += OMAP_MCBSP_REG_DXR1; } else { if (stream) data_reg += OMAP_MCBSP_REG_DRR; else data_reg += OMAP_MCBSP_REG_DXR; } return data_reg; }
/* * 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) { struct omap_mcbsp *mcbsp; 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); dev_dbg(mcbsp->dev, "Configuring McBSP%d phys_base: 0x%08lx\n", mcbsp->id, mcbsp->phys_base); /* We write the given config */ MCBSP_WRITE(mcbsp, SPCR2, config->spcr2); MCBSP_WRITE(mcbsp, SPCR1, config->spcr1); MCBSP_WRITE(mcbsp, RCR2, config->rcr2); MCBSP_WRITE(mcbsp, RCR1, config->rcr1); MCBSP_WRITE(mcbsp, XCR2, config->xcr2); MCBSP_WRITE(mcbsp, XCR1, config->xcr1); MCBSP_WRITE(mcbsp, SRGR2, config->srgr2); MCBSP_WRITE(mcbsp, SRGR1, config->srgr1); MCBSP_WRITE(mcbsp, MCR2, config->mcr2); MCBSP_WRITE(mcbsp, MCR1, config->mcr1); MCBSP_WRITE(mcbsp, PCR0, config->pcr0); if (cpu_is_omap2430() || cpu_is_omap34xx() || cpu_is_omap44xx()) { MCBSP_WRITE(mcbsp, XCCR, config->xccr); MCBSP_WRITE(mcbsp, RCCR, config->rccr); } }
/** * omap_mcbsp_dma_reg_params - returns the address of mcbsp data register * @id - mcbsp id * @stream - indicates the direction of data flow (rx or tx) * * Returns the address of mcbsp data transmit register or data receive register * to be used by DMA for transferring/receiving data based on the value of * @stream for the requested mcbsp given by @id */ int omap_mcbsp_dma_reg_params(unsigned int id, unsigned int stream) { struct omap_mcbsp *mcbsp; int data_reg; 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->reg_size == 2) { if (stream) data_reg = OMAP_MCBSP_REG_DRR1; else data_reg = OMAP_MCBSP_REG_DXR1; } else { if (stream) data_reg = OMAP_MCBSP_REG_DRR; else data_reg = OMAP_MCBSP_REG_DXR; } return mcbsp->phys_dma_base + data_reg * mcbsp->pdata->reg_step; }
static void omap_mcbsp_dump_reg(u8 id) { struct omap_mcbsp *mcbsp = id_to_mcbsp_ptr(id); dev_dbg(mcbsp->dev, "**** McBSP%d regs ****\n", mcbsp->id); dev_dbg(mcbsp->dev, "DRR2: 0x%04x\n", MCBSP_READ(mcbsp, DRR2)); dev_dbg(mcbsp->dev, "DRR1: 0x%04x\n", MCBSP_READ(mcbsp, DRR1)); dev_dbg(mcbsp->dev, "DXR2: 0x%04x\n", MCBSP_READ(mcbsp, DXR2)); dev_dbg(mcbsp->dev, "DXR1: 0x%04x\n", MCBSP_READ(mcbsp, DXR1)); dev_dbg(mcbsp->dev, "SPCR2: 0x%04x\n", MCBSP_READ(mcbsp, SPCR2)); dev_dbg(mcbsp->dev, "SPCR1: 0x%04x\n", MCBSP_READ(mcbsp, SPCR1)); dev_dbg(mcbsp->dev, "RCR2: 0x%04x\n", MCBSP_READ(mcbsp, RCR2)); dev_dbg(mcbsp->dev, "RCR1: 0x%04x\n", MCBSP_READ(mcbsp, RCR1)); dev_dbg(mcbsp->dev, "XCR2: 0x%04x\n", MCBSP_READ(mcbsp, XCR2)); dev_dbg(mcbsp->dev, "XCR1: 0x%04x\n", MCBSP_READ(mcbsp, XCR1)); dev_dbg(mcbsp->dev, "SRGR2: 0x%04x\n", MCBSP_READ(mcbsp, SRGR2)); dev_dbg(mcbsp->dev, "SRGR1: 0x%04x\n", MCBSP_READ(mcbsp, SRGR1)); dev_dbg(mcbsp->dev, "PCR0: 0x%04x\n", MCBSP_READ(mcbsp, PCR0)); dev_dbg(mcbsp->dev, "***********************\n"); }
int omap_st_get_chgain(unsigned int id, int channel, s16 *chgain) { struct omap_mcbsp *mcbsp; struct omap_mcbsp_st_data *st_data; int ret = 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); st_data = mcbsp->st_data; if (!st_data) return -ENOENT; spin_lock_irq(&mcbsp->lock); if (channel == 0) *chgain = st_data->ch0gain; else if (channel == 1) *chgain = st_data->ch1gain; else ret = -EINVAL; spin_unlock_irq(&mcbsp->lock); return ret; }
void omap2_mcbsp_config(unsigned int id, const struct omap_mcbsp_reg_cfg *config) { struct omap_mcbsp *mcbsp; void __iomem *io_base; mcbsp = id_to_mcbsp_ptr(id); io_base = mcbsp->io_base; OMAP_MCBSP_WRITE(mcbsp, XCCR, config->xccr); OMAP_MCBSP_WRITE(mcbsp, RCCR, config->rccr); }
/* * omap_mcbsp_get_max_rx_thres just return the current configured * maximum threshold for reception */ u16 omap_mcbsp_get_max_rx_threshold(unsigned int id) { struct omap_mcbsp *mcbsp; 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); return mcbsp->max_rx_thres; }
u16 omap_mcbsp_get_fifo_size(unsigned int id) { struct omap_mcbsp *mcbsp; 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); return mcbsp->pdata->buffer_size; }
/** * omap_mcbsp_dma_params - returns the dma channel number * @id - mcbsp id * @stream - indicates the direction of data flow (rx or tx) * * Returns the dma channel number for the rx channel or tx channel * based on the value of @stream for the requested mcbsp given by @id */ int omap_mcbsp_dma_ch_params(unsigned int id, unsigned int stream) { struct omap_mcbsp *mcbsp; 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 (stream) return mcbsp->dma_rx_sync; else return mcbsp->dma_tx_sync; }
/* * omap_mcbsp_get_dma_op_mode just return the current configured * operating mode for the mcbsp channel */ int omap_mcbsp_get_dma_op_mode(unsigned int id) { struct omap_mcbsp *mcbsp; int dma_op_mode; if (!omap_mcbsp_check_valid_id(id)) { printk(KERN_ERR "%s: Invalid id (%u)\n", __func__, id + 1); return -ENODEV; } mcbsp = id_to_mcbsp_ptr(id); dma_op_mode = mcbsp->dma_op_mode; return dma_op_mode; }
/* * omap_mcbsp_set_rx_threshold configures the receive threshold in words. * The threshold parameter is 1 based, and it is converted (threshold - 1) * for the THRSH1 register. */ void omap_mcbsp_set_rx_threshold(unsigned int id, u16 threshold) { struct omap_mcbsp *mcbsp; 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->buffer_size == 0) return; if (threshold && threshold <= mcbsp->max_rx_thres) MCBSP_WRITE(mcbsp, THRSH1, threshold - 1); }
void omap2_mcbsp1_mux_fsr_src(u8 mux) { struct omap_mcbsp *mcbsp; const char *src; if (mux == FSR_SRC_FSR) src = "fsr"; else if (mux == FSR_SRC_FSX) src = "fsx"; else return; mcbsp = id_to_mcbsp_ptr(0); if (mcbsp->pdata->mux_signal) mcbsp->pdata->mux_signal(mcbsp->dev, "fsr", src); }
void omap2_mcbsp1_mux_clkr_src(u8 mux) { struct omap_mcbsp *mcbsp; const char *src; if (mux == CLKR_SRC_CLKR) src = "clkr"; else if (mux == CLKR_SRC_CLKX) src = "clkx"; else return; mcbsp = id_to_mcbsp_ptr(0); if (mcbsp->pdata->mux_signal) mcbsp->pdata->mux_signal(mcbsp->dev, "clkr", src); }
/* * omap_mcbsp_set_rx_threshold configures the transmit threshold in words. * The threshold parameter is 1 based, and it is converted (threshold - 1) * for the THRSH2 register. */ void omap_mcbsp_set_tx_threshold(unsigned int id, u16 threshold) { struct omap_mcbsp *mcbsp; if (!cpu_is_omap34xx() && !cpu_is_omap44xx()) return; 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 (threshold && threshold <= mcbsp->max_tx_thres) MCBSP_WRITE(mcbsp, THRSH2, threshold - 1); }
/* * 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); /* 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; }
void omap_mcbsp_stop(unsigned int id, int tx, int rx) { struct omap_mcbsp *mcbsp; int idle; 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); /* Reset transmitter */ tx &= 1; if (cpu_is_omap2430() || cpu_is_omap34xx() || cpu_is_omap44xx()) { w = MCBSP_READ_CACHE(mcbsp, XCCR); w |= (tx ? XDISABLE : 0); MCBSP_WRITE(mcbsp, XCCR, w); } w = MCBSP_READ_CACHE(mcbsp, SPCR2); MCBSP_WRITE(mcbsp, SPCR2, w & ~tx); /* Reset receiver */ rx &= 1; if (cpu_is_omap2430() || cpu_is_omap34xx() || cpu_is_omap44xx()) { w = MCBSP_READ_CACHE(mcbsp, RCCR); w |= (rx ? RDISABLE : 0); MCBSP_WRITE(mcbsp, RCCR, w); } w = MCBSP_READ_CACHE(mcbsp, SPCR1); MCBSP_WRITE(mcbsp, SPCR1, w & ~rx); idle = !((MCBSP_READ_CACHE(mcbsp, SPCR2) | MCBSP_READ_CACHE(mcbsp, SPCR1)) & 1); if (idle) { /* Reset the sample rate generator */ w = MCBSP_READ_CACHE(mcbsp, SPCR2); MCBSP_WRITE(mcbsp, SPCR2, w & ~(1 << 6)); } if (cpu_is_omap34xx()) omap_st_stop(mcbsp); }
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_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 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; }
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; }
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); }
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; }
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; }
/* * 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; }
/* * 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; }
/* * 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; }