Skip to contentSkip to conversation

McBSP support for 34XX

PATCH In review Chandra shekhar 1 participant 1 message Jun 16, 2008

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

PATCH 3/4 McBSP support for 34XX

---
 arch/arm/mach-omap2/mcbsp.c       |  680 ++++++++++++++++++++++++++++++++++++++
 arch/arm/plat-omap/mcbsp.c        |    5 
 include/asm-arm/arch-omap/mcbsp.h |  117 +++++-
 3 files changed, 779 insertions(+), 23 deletions(-)
arch/arm/mach-omap2/mcbsp.c +680 -0
Index: linux-omap-2.6/arch/arm/mach-omap2/mcbsp.c
===================================================================
@@ -16,6 +16,8 @@
 #include <linux/err.h>
 #include <linux/io.h>
 #include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
 
 #include <asm/arch/dma.h>
 #include <asm/arch/mux.h>
@@ -150,15 +152,687 @@
 	return 0;
 }
 
+static void omap2_mcbsp_free(unsigned int id)
+{
+	if (!cpu_is_omap2420()) {
+		if (mcbsp[id].dma_rx_lch != -1) {
+			omap_free_dma_chain(mcbsp[id].dma_rx_lch);
+			 mcbsp[id].dma_rx_lch = -1;
+		}
+
+		if (mcbsp[id].dma_tx_lch != -1) {
+			omap_free_dma_chain(mcbsp[id].dma_tx_lch);
+			mcbsp[id].dma_tx_lch = -1;
+		}
+	}
+	return;
+}
+void omap2_mcbsp_config(unsigned int id,
+			 const struct omap_mcbsp_reg_cfg *config)
+{
+	u32 io_base;
+	io_base = mcbsp[id].io_base;
+	omap_mcbsp_write(io_base, OMAP_MCBSP_REG_XCCR, config->xccr);
+	omap_mcbsp_write(io_base, OMAP_MCBSP_REG_RCCR, config->rccr);
+}
 static struct omap_mcbsp_ops omap2_mcbsp_ops = {
 	.request	= omap2_mcbsp_request,
 	.check		= omap2_mcbsp_check,
+	.free 		= omap2_mcbsp_free,
+	.config		= omap2_mcbsp_config,
 };
+static void omap2_mcbsp_rx_dma_callback(int lch, u16 ch_status, void *data)
+{
+	struct omap_mcbsp *mcbsp_dma_rx = data;
+	u32 io_base;
+	io_base = mcbsp_dma_rx->io_base;
+
+	/* If we are at the last transfer, Shut down the reciever */
+	if ((mcbsp_dma_rx->auto_reset & OMAP_MCBSP_AUTO_RRST)
+		&& (omap_dma_chain_status(mcbsp_dma_rx->dma_rx_lch) ==
+						 OMAP_DMA_CHAIN_INACTIVE))
+		omap_mcbsp_write(io_base, OMAP_MCBSP_REG_SPCR1,
+			omap_mcbsp_read(io_base,
+					 OMAP_MCBSP_REG_SPCR1) & (~RRST));
+
+	if (mcbsp_dma_rx->rx_callback != NULL)
+		mcbsp_dma_rx->rx_callback(ch_status, mcbsp_dma_rx->rx_cb_arg);
+
+}
+
+static void omap2_mcbsp_tx_dma_callback(int lch, u16 ch_status, void *data)
+{
+	struct omap_mcbsp *mcbsp_dma_tx = data;
+	u32 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(io_base, OMAP_MCBSP_REG_SPCR2,
+			omap_mcbsp_read(io_base,
+					 OMAP_MCBSP_REG_SPCR2) & (~XRST));
+
+	if (mcbsp_dma_tx->tx_callback != NULL)
+		mcbsp_dma_tx->tx_callback(ch_status, mcbsp_dma_tx->tx_cb_arg);
+}
+/*
+ * Enable/Disable the sample rate generator
+ * id		: McBSP interface ID
+ * state	: Enable/Disable
+ */
+int omap2_mcbsp_set_srg_fsg(unsigned int id, u8 state)
+{
+	u32 io_base;
+
+	if (omap2_mcbsp_check(id) < 0)
+		return -ENXIO;
+
+	io_base = mcbsp[id].io_base;
+
+	if (state == OMAP_MCBSP_DISABLE_FSG_SRG) {
+		omap_mcbsp_write(io_base, OMAP_MCBSP_REG_SPCR2,
+			omap_mcbsp_read(io_base,
+					 OMAP_MCBSP_REG_SPCR2) & (~GRST));
+		omap_mcbsp_write(io_base, OMAP_MCBSP_REG_SPCR2,
+			omap_mcbsp_read(io_base,
+					 OMAP_MCBSP_REG_SPCR2) & (~FRST));
+	} else {
+		omap_mcbsp_write(io_base, OMAP_MCBSP_REG_SPCR2,
+			omap_mcbsp_read(io_base, OMAP_MCBSP_REG_SPCR2) | GRST);
+		omap_mcbsp_write(io_base, OMAP_MCBSP_REG_SPCR2,
+			omap_mcbsp_read(io_base, OMAP_MCBSP_REG_SPCR2) | FRST);
+	}
+	return (0);
+}
+
+/*
+ * Stop transmitting data on a McBSP interface
+ * id		: McBSP interface ID
+ */
+int omap2_mcbsp_stop_datatx(unsigned int id)
+{
+	u32 io_base;
+
+	if (omap2_mcbsp_check(id) < 0)
+		return -ENXIO;
+	spin_lock(&mcbsp[id].lock);
+	io_base = mcbsp[id].io_base;
+
+	if (mcbsp[id].dma_tx_lch != -1) {
+		if (omap_stop_dma_chain_transfers(mcbsp[id].dma_tx_lch) != 0) {
+			spin_unlock(&mcbsp[id].lock);
+			return -EPERM;
+		}
+	}
+	mcbsp[id].tx_dma_chain_state = 0;
+	omap_mcbsp_write(io_base, OMAP_MCBSP_REG_SPCR2,
+		omap_mcbsp_read(io_base, OMAP_MCBSP_REG_SPCR2) & (~XRST));
+
+	if (!(--mcbsp[id].srg_enabled))
+		omap2_mcbsp_set_srg_fsg(id, OMAP_MCBSP_DISABLE_FSG_SRG);
+	spin_unlock(&mcbsp[id].lock);
+	return 0;
+}
+EXPORT_SYMBOL(omap2_mcbsp_stop_datatx);
+
+/*
+ * Stop receving data on a McBSP interface
+ * id		: McBSP interface ID
+ */
+int omap2_mcbsp_stop_datarx(u32 id)
+{
+
+	u32 io_base;
+
+	if (omap2_mcbsp_check(id) < 0)
+		return -ENXIO;
+	spin_lock(&mcbsp[id].lock);
+	io_base = mcbsp[id].io_base;
+
+	if (mcbsp[id].dma_rx_lch != -1) {
+		if (omap_stop_dma_chain_transfers(mcbsp[id].dma_rx_lch) != 0) {
+			spin_unlock(&mcbsp[id].lock);
+			return -EPERM;
+		}
+	}
+	omap_mcbsp_write(io_base, OMAP_MCBSP_REG_SPCR1,
+		omap_mcbsp_read(io_base, OMAP_MCBSP_REG_SPCR1) & (~RRST));
+	mcbsp[id].rx_dma_chain_state = 0;
+	if (!(--mcbsp[id].srg_enabled))
+		omap2_mcbsp_set_srg_fsg(id, OMAP_MCBSP_DISABLE_FSG_SRG);
+	spin_unlock(&mcbsp[id].lock);
+	return 0;
+}
+EXPORT_SYMBOL(omap2_mcbsp_stop_datarx);
+
+/*
+ * Interface Reset
+ * id	: McBSP interface ID
+ * Resets the McBSP interface
+ */
+int omap2_mcbsp_reset(unsigned int id)
+{
+	u32 io_base;
+	int counter = 0;
+	int wait_for_reset = 10000;
+
+	if (omap2_mcbsp_check(id) < 0)
+		return -ENXIO;
+
+	io_base = mcbsp[id].io_base;
+
+	omap_mcbsp_write(io_base, OMAP_MCBSP_REG_SYSCON,
+		omap_mcbsp_read(io_base, OMAP_MCBSP_REG_SYSCON) | (SOFTRST));
+
+	while (omap_mcbsp_read(io_base, OMAP_MCBSP_REG_SYSCON) & SOFTRST) {
+		if (!in_interrupt()) {
+			set_current_state(TASK_INTERRUPTIBLE);
+			schedule_timeout(10);
+		}
+		if (counter++ > wait_for_reset) {
+			printk(KERN_ERR "mcbsp[%d] Reset timeout\n", id);
+			spin_unlock(&mcbsp[id].lock);
+			return -ETIMEDOUT;
+		}
+	}
+	return 0;
+}
+EXPORT_SYMBOL(omap2_mcbsp_reset);
+
+/*
+ * Get the element index and frame index of transmitter
+ * id		: McBSP interface ID
+ * ei		: element index
+ * fi		: frame index
+ */
+int omap2_mcbsp_transmitter_index(int id, int *ei, int *fi)
+{
+	int eix = 0, fix = 0;
+
+	if (omap2_mcbsp_check(id) < 0)
+		return -ENXIO;
+
+	if ((!ei) || (!fi)) {
+		printk(KERN_ERR	"OMAP_McBSP: Invalid ei and fi params \n");
+		goto txinx_err;
+	}
+
+	if (mcbsp[id].dma_tx_lch == -1) {
+		printk(KERN_ERR "OMAP_McBSP: Transmitter not started\n");
+		goto txinx_err;
+	}
+
+	if (omap_get_dma_chain_index
+		(mcbsp[id].dma_tx_lch, &eix, &fix) != 0) {
+		printk(KERN_ERR "OMAP_McBSP: Getting chain index failed\n");
+		goto txinx_err;
+	}
+
+	*ei = eix;
+	*fi = fix;
+
+	return 0;
+
+txinx_err:
+	return -EINVAL;
+}
+EXPORT_SYMBOL(omap2_mcbsp_transmitter_index);
+
+/*
+ * Get the element index and frame index of receiver
+ * id	: McBSP interface ID
+ * ei		: element index
+ * fi		: frame index
+ */
+int omap2_mcbsp_receiver_index(int id, int *ei, int *fi)
+{
+	int eix = 0, fix = 0;
+
+	if (omap2_mcbsp_check(id) < 0)
+		return -ENXIO;
+
+	if ((!ei) || (!fi)) {
+		printk(KERN_ERR	"OMAP_McBSP: Invalid ei and fi params x\n");
+		goto rxinx_err;
+	}
+
+	/* Check if chain exists */
+	if (mcbsp[id].dma_rx_lch == -1) {
+		printk(KERN_ERR "OMAP_McBSP: Receiver not started\n");
+		goto rxinx_err;
+	}
+
+	/* Get dma_chain_index */
+	if (omap_get_dma_chain_index
+		(mcbsp[id].dma_rx_lch, &eix, &fix) != 0) {
+		printk(KERN_ERR "OMAP_McBSP: Getting chain index failed\n");
+		goto rxinx_err;
+	}
+
+	*ei = eix;
+	*fi = fix;
+	return 0;
+
+rxinx_err:
+	return -EINVAL;
+}
+EXPORT_SYMBOL(omap2_mcbsp_receiver_index);
+
+/*
+ * Basic Reset Transmitter
+ * id		: McBSP interface number
+ * state	: Disable (0)/ Enable (1) the transmitter
+ */
+int omap2_mcbsp_set_xrst(unsigned int id, u8 state)
+{
+	u32 io_base;
+	if (omap2_mcbsp_check(id) < 0)
+		return -ENXIO;
+
+	io_base = mcbsp[id].io_base;
+
+	if (state == OMAP_MCBSP_XRST_DISABLE)
+		omap_mcbsp_write(io_base, OMAP_MCBSP_REG_SPCR2,
+		      omap_mcbsp_read(io_base, OMAP_MCBSP_REG_SPCR2) & (~XRST));
+	else
+		omap_mcbsp_write(io_base, OMAP_MCBSP_REG_SPCR2,
+			omap_mcbsp_read(io_base, OMAP_MCBSP_REG_SPCR2) | XRST);
+	udelay(10);
+
+	return (0);
+}
+EXPORT_SYMBOL(omap2_mcbsp_set_xrst);
+
+/*
+ * Reset Receiver
+ * id		: McBSP interface number
+ * state	: Disable (0)/ Enable (1) the receiver
+ */
+int omap2_mcbsp_set_rrst(unsigned int id, u8 state)
+{
+	u32 io_base;
+	if (omap2_mcbsp_check(id) < 0)
+		return -ENXIO;
+
+	io_base = mcbsp[id].io_base;
+
+	if (state == OMAP_MCBSP_RRST_DISABLE)
+		omap_mcbsp_write(io_base, OMAP_MCBSP_REG_SPCR1,
+			omap_mcbsp_read(io_base,
+				 OMAP_MCBSP_REG_SPCR1) & (~RRST));
+	else
+		omap_mcbsp_write(io_base, OMAP_MCBSP_REG_SPCR1,
+		      omap_mcbsp_read(io_base, OMAP_MCBSP_REG_SPCR1) | RRST);
+	udelay(10);
+	return 0;
+}
+EXPORT_SYMBOL(omap2_mcbsp_set_rrst);
+
+/*
+ * 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)
+{
+	u32 io_base;
+	int err, chain_id = -1;
+	struct omap_dma_channel_params rx_params;
+	u32  dt = 0;
+
+	if (omap2_mcbsp_check(id) < 0)
+		return -EINVAL;
+	io_base = mcbsp[id].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[id].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- 24 bit data in mono mode*/
+	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[id].rxskip_alt = rp->skip_alt;
+	mcbsp[id].auto_reset &= ~OMAP_MCBSP_AUTO_RRST;
+	mcbsp[id].auto_reset |=	(rp->auto_reset & OMAP_MCBSP_AUTO_RRST);
+
+	mcbsp[id].rx_word_length = rx_params.data_type << 0x1;
+	if (rx_params.data_type == 0)
+		mcbsp[id].rx_word_length = 1;
+
+	mcbsp[id].rx_callback = rp->callback;
+	/* request for a chain of dma channels for data reception */
+	if (mcbsp[id].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 -EPERM;
+		}
+		mcbsp[id].dma_rx_lch = chain_id;
+		mcbsp[id].rx_dma_chain_state = 0;
+	} else {
+		/* DMA params already set, modify the same!! */
+		err = omap_modify_dma_chain_params(mcbsp[id].
+						 dma_rx_lch, rx_params);
+		if (err < 0)
+			return -EPERM;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(omap2_mcbsp_dma_recv_params);
+
+/*
+ * Configure the transmitter parameters
+ * id		: McBSP Interface ID
+ * tp		: DMA Transfer parameters
+ */
+
+int omap2_mcbsp_dma_trans_params(unsigned int id,
+			struct omap_mcbsp_dma_transfer_params *tp)
+{
+
+	struct omap_dma_channel_params tx_params;
+	int err = 0, chain_id = -1;
+	u32 io_base;
+	u32 dt = 0;
+
+	if (omap2_mcbsp_check(id) < 0)
+		return -EINVAL;
+	io_base = mcbsp[id].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[id].dma_tx_sync;
+	tx_params.src_or_dst_synch = 0;
+	/* Indexing is always in bytes - so multiply with dt */
+	mcbsp[id].tx_word_length = tx_params.data_type << 0x1;
+
+	if (tx_params.data_type == 0)
+		mcbsp[id].tx_word_length = 1;
+	dt = mcbsp[id].tx_word_length;
+
+	/* SKIP_FIRST and SKIP_SECOND- 24 bit data in mono mode*/
+	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;
+	}
+
+	tx_params.dst_amode = OMAP_DMA_AMODE_CONSTANT;
+	tx_params.dst_ei = 0;
+	mcbsp[id].txskip_alt = tp->skip_alt;
+	mcbsp[id].auto_reset &= ~OMAP_MCBSP_AUTO_XRST;
+	mcbsp[id].auto_reset |=
+		(tp->auto_reset & OMAP_MCBSP_AUTO_XRST);
+	mcbsp[id].tx_callback = tp->callback;
+
+	/* Based on Rjust we can do double indexing DMA params configuration */
+	if (mcbsp[id].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 -EPERM;
+		}
+		mcbsp[id].tx_dma_chain_state = 0;
+	mcbsp[id].dma_tx_lch = chain_id;
+	} else {
+		/* DMA params already set, modify the same!! */
+		err = omap_modify_dma_chain_params(mcbsp[id].
+						 dma_tx_lch, tx_params);
+		if (err < 0)
+			return -EPERM;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(omap2_mcbsp_dma_trans_params);
+
+/*
+ * Start receving data on a McBSP interface
+ * id			: McBSP interface ID
+ * cbdata		: User data to be returned with callback
+ * buf_start_addr	: The destination address [physical address]
+ * buf_size		: Buffer size
+ */
+
+int omap2_mcbsp_receive_data(unsigned int id, void *cbdata,
+			     dma_addr_t buf_start_addr, u32 buf_size)
+{
+	u32 io_base;
+	int enable_rx = 0;
+	int e_count = 0;
+	int f_count = 0;
+
+	if (omap2_mcbsp_check(id) < 0)
+		return -EINVAL;
+
+	spin_lock(&mcbsp[id].lock);
+	io_base = mcbsp[id].io_base;
+
+	mcbsp[id].rx_cb_arg = cbdata;
+
+	/* Auto RRST handling logic - disable the Reciever before 1st dma */
+	if ((mcbsp[id].auto_reset & OMAP_MCBSP_AUTO_RRST) &&
+		(omap_dma_chain_status(mcbsp[id].dma_rx_lch)
+				== OMAP_DMA_CHAIN_INACTIVE)) {
+		omap_mcbsp_write(io_base, OMAP_MCBSP_REG_SPCR1,
+			omap_mcbsp_read(io_base,
+				 OMAP_MCBSP_REG_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[id].rx_word_length);
+
+	if (mcbsp[id].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[id].rxskip_alt == OMAP_MCBSP_SKIP_FIRST)
+		buf_start_addr += mcbsp[id].rx_word_length;
+
+	if (omap_dma_chain_a_transfer(mcbsp[id]. dma_rx_lch,
+			mcbsp[id].phy_base + OMAP_MCBSP_REG_DRR, buf_start_addr,
+			e_count, f_count, &mcbsp[id]) < 0) {
+		spin_unlock(&mcbsp[id].lock);
+		printk(KERN_ERR " Buffer chaining failed \n");
+		return -EPERM;
+	}
+	if (mcbsp[id].rx_dma_chain_state == 0) {
+		if (mcbsp[id].interface_mode == OMAP_MCBSP_MASTER) {
+			omap2_mcbsp_set_srg_fsg(id, OMAP_MCBSP_ENABLE_FSG_SRG);
+			mcbsp[id].srg_enabled++ ;
+		}
+		if (omap_start_dma_chain_transfers(mcbsp[id].dma_rx_lch) < 0) {
+			spin_unlock(&mcbsp[id].lock);
+			return -EPERM;
+		}
+		mcbsp[id].rx_dma_chain_state = 1;
+	}
+	/* Auto RRST handling logic - Enable the Reciever after 1st dma */
+	if (enable_rx &&
+		(omap_dma_chain_status(mcbsp[id].dma_rx_lch)
+				== OMAP_DMA_CHAIN_ACTIVE))
+		omap_mcbsp_write(io_base, OMAP_MCBSP_REG_SPCR1,
+			omap_mcbsp_read(io_base, OMAP_MCBSP_REG_SPCR1) | RRST);
+
+	spin_unlock(&mcbsp[id].lock);
+	return 0;
+}
+EXPORT_SYMBOL(omap2_mcbsp_receive_data);
+
+/*
+ * 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)
+{
+	u32 io_base;
+	u8 enable_tx = 0;
+	int e_count = 0;
+	int f_count = 0;
+
+	/* Check if mcbsp interface is valid and is reserved */
+	if (omap2_mcbsp_check(id) < 0)
+		return -EINVAL;
+
+	spin_lock(&mcbsp[id].lock);
+	io_base = mcbsp[id].io_base;
+
+	mcbsp[id].tx_cb_arg = cbdata;
+
+	/* Auto RRST handling logic - disable the Reciever before 1st dma */
+	if ((mcbsp[id].auto_reset & OMAP_MCBSP_AUTO_XRST) &&
+			(omap_dma_chain_status(mcbsp[id].dma_tx_lch)
+				== OMAP_DMA_CHAIN_INACTIVE)) {
+		omap_mcbsp_write(io_base, OMAP_MCBSP_REG_SPCR2,
+			omap_mcbsp_read(io_base,
+				OMAP_MCBSP_REG_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[id].tx_word_length);
+	if (mcbsp[id].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[id].txskip_alt == OMAP_MCBSP_SKIP_FIRST)
+		buf_start_addr += mcbsp[id].tx_word_length;
+
+	if (omap_dma_chain_a_transfer(mcbsp[id].dma_tx_lch,
+		buf_start_addr,	mcbsp[id].phy_base + OMAP_MCBSP_REG_DXR,
+		e_count, f_count, &mcbsp[id]) < 0) {
+			spin_unlock(&mcbsp[id].lock);
+			return -EPERM;
+	}
+
+	if (mcbsp[id].tx_dma_chain_state == 0) {
+		if (mcbsp[id].interface_mode == OMAP_MCBSP_MASTER) {
+			omap2_mcbsp_set_srg_fsg(id, OMAP_MCBSP_ENABLE_FSG_SRG);
+			mcbsp[id].srg_enabled++ ;
+		}
+		if (omap_start_dma_chain_transfers(mcbsp[id].dma_tx_lch) < 0) {
+			spin_unlock(&mcbsp[id].lock);
+			return -EPERM;
+		}
+		mcbsp[id].tx_dma_chain_state = 1;
+	}
+
+	/* Auto XRST handling logic - Enable the Reciever after 1st dma */
+	if (enable_tx &&
+		(omap_dma_chain_status(mcbsp[id].dma_tx_lch)
+		== OMAP_DMA_CHAIN_ACTIVE))
+		omap_mcbsp_write(io_base, OMAP_MCBSP_REG_SPCR2,
+			omap_mcbsp_read(io_base, OMAP_MCBSP_REG_SPCR2) | XRST);
+
+	spin_unlock(&mcbsp[id].lock);
+	return 0;
+}
+EXPORT_SYMBOL(omap2_mcbsp_send_data);
 
 #ifdef CONFIG_ARCH_OMAP24XX
 static struct omap_mcbsp_platform_data omap24xx_mcbsp_pdata[] = {
 	{
 		.virt_base	= IO_ADDRESS(OMAP24XX_MCBSP1_BASE),
+		.phy_base	= OMAP24XX_MCBSP1_BASE,
 		.dma_rx_sync	= OMAP24XX_DMA_MCBSP1_RX,
 		.dma_tx_sync	= OMAP24XX_DMA_MCBSP1_TX,
 		.rx_irq		= INT_24XX_MCBSP1_IRQ_RX,
@@ -168,6 +842,7 @@
 	},
 	{
 		.virt_base	= IO_ADDRESS(OMAP24XX_MCBSP2_BASE),
+		.phy_base	= OMAP24XX_MCBSP2_BASE,
 		.dma_rx_sync	= OMAP24XX_DMA_MCBSP2_RX,
 		.dma_tx_sync	= OMAP24XX_DMA_MCBSP2_TX,
 		.rx_irq		= INT_24XX_MCBSP2_IRQ_RX,
@@ -186,6 +861,7 @@
 static struct omap_mcbsp_platform_data omap34xx_mcbsp_pdata[] = {
 	{
 		.virt_base	= IO_ADDRESS(OMAP34XX_MCBSP1_BASE),
+		.phy_base	= OMAP34XX_MCBSP1_BASE,
 		.dma_rx_sync	= OMAP24XX_DMA_MCBSP1_RX,
 		.dma_tx_sync	= OMAP24XX_DMA_MCBSP1_TX,
 		.rx_irq		= INT_24XX_MCBSP1_IRQ_RX,
@@ -195,6 +871,7 @@
 	},
 	{
 		.virt_base	= IO_ADDRESS(OMAP34XX_MCBSP2_BASE),
+		.phy_base	= OMAP34XX_MCBSP2_BASE,
 		.dma_rx_sync	= OMAP24XX_DMA_MCBSP2_RX,
 		.dma_tx_sync	= OMAP24XX_DMA_MCBSP2_TX,
 		.rx_irq		= INT_24XX_MCBSP2_IRQ_RX,
@@ -204,6 +881,7 @@
 	},
 	{
 		.virt_base	= IO_ADDRESS(OMAP34XX_MCBSP3_BASE),
+		.phy_base	= OMAP34XX_MCBSP3_BASE,
 		.dma_rx_sync	= OMAP24XX_DMA_MCBSP3_RX,
 		.dma_tx_sync	= OMAP24XX_DMA_MCBSP3_TX,
 		.ops		= &omap2_mcbsp_ops,
@@ -211,6 +889,7 @@
 	},
 	{
 		.virt_base	= IO_ADDRESS(OMAP34XX_MCBSP4_BASE),
+		.phy_base	= OMAP34XX_MCBSP4_BASE,
 		.dma_rx_sync	= OMAP24XX_DMA_MCBSP4_RX,
 		.dma_tx_sync	= OMAP24XX_DMA_MCBSP4_TX,
 		.ops		= &omap2_mcbsp_ops,
@@ -218,6 +897,7 @@
 	},
 	{
 		.virt_base	= IO_ADDRESS(OMAP34XX_MCBSP5_BASE),
+		.phy_base	= OMAP34XX_MCBSP5_BASE,
 		.dma_rx_sync	= OMAP24XX_DMA_MCBSP5_RX,
 		.dma_tx_sync	= OMAP24XX_DMA_MCBSP5_TX,
 		.ops		= &omap2_mcbsp_ops,
arch/arm/plat-omap/mcbsp.c +5 -0
Index: linux-omap-2.6/arch/arm/plat-omap/mcbsp.c
===================================================================
@@ -166,6 +166,10 @@
 	omap_mcbsp_write(io_base, OMAP_MCBSP_REG_MCR2, config->mcr2);
 	omap_mcbsp_write(io_base, OMAP_MCBSP_REG_MCR1, config->mcr1);
 	omap_mcbsp_write(io_base, OMAP_MCBSP_REG_PCR0, config->pcr0);
+	if (cpu_is_omap2430() || cpu_is_omap34xx()) {
+		if (mcbsp[id].pdata->ops->config)
+			mcbsp[id].pdata->ops->config(id, config);
+	}
 }
 EXPORT_SYMBOL(omap_mcbsp_config);
 
@@ -859,6 +863,7 @@
 	mcbsp[id].dma_rx_lch = -1;
 
 	mcbsp[id].io_base = pdata->virt_base;
+	mcbsp[id].phy_base = pdata->phy_base;
 	/* Default I/O is IRQ based */
 	mcbsp[id].io_type = OMAP_MCBSP_IRQ_IO;
 	mcbsp[id].tx_irq = pdata->tx_irq;
include/asm-arm/arch-omap/mcbsp.h +94 -23

156 lines not on this page · raw message