Esempio n. 1
0
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;
}
Esempio n. 2
0
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;
}
Esempio n. 3
0
File: mcbsp.c Progetto: 08opt/linux
/*
 * 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;
}
Esempio n. 4
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;
}
Esempio n. 5
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;
}
Esempio n. 6
0
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;
}
Esempio n. 7
0
File: mcbsp.c Progetto: 08opt/linux
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;
}
Esempio n. 8
0
File: mcbsp.c Progetto: 08opt/linux
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);
}
Esempio n. 9
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);

	/* 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);
}
Esempio n. 10
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);
}
Esempio n. 11
0
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;
}
Esempio n. 12
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;
}
Esempio n. 13
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;
}
Esempio n. 14
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;
}
Esempio n. 15
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;
}