Signed-off-by: chandra shekhar <[EMAIL PROTECTED]>
---
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(-)
Index: linux-omap-2.6/arch/arm/mach-omap2/mcbsp.c
===================================================================
--- linux-omap-2.6.orig/arch/arm/mach-omap2/mcbsp.c 2008-06-16
16:04:58.000000000 +0530
+++ linux-omap-2.6/arch/arm/mach-omap2/mcbsp.c 2008-06-16 16:10:03.567491667
+0530
@@ -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 stereo 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 stereo 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,
Index: linux-omap-2.6/arch/arm/plat-omap/mcbsp.c
===================================================================
--- linux-omap-2.6.orig/arch/arm/plat-omap/mcbsp.c 2008-06-16
16:05:01.000000000 +0530
+++ linux-omap-2.6/arch/arm/plat-omap/mcbsp.c 2008-06-16 16:05:49.241714590
+0530
@@ -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;
Index: linux-omap-2.6/include/asm-arm/arch-omap/mcbsp.h
===================================================================
--- linux-omap-2.6.orig/include/asm-arm/arch-omap/mcbsp.h 2008-06-16
16:05:01.000000000 +0530
+++ linux-omap-2.6/include/asm-arm/arch-omap/mcbsp.h 2008-06-16
16:05:49.241714590 +0530
@@ -254,31 +254,56 @@
/********************** MACRO DEFINITIONS *********************************/
+/* McBSP interface operating mode */
+#define OMAP_MCBSP_MASTER 1
+#define OMAP_MCBSP_SLAVE 0
+
+#define OMAP_MCBSP_AUTO_RST_NONE (0x0)
+#define OMAP_MCBSP_AUTO_RRST (0x1<<1)
+#define OMAP_MCBSP_AUTO_XRST (0x1<<2)
+
+/* SRG ENABLE/DISABLE state */
+#define OMAP_MCBSP_ENABLE_FSG_SRG 1
+#define OMAP_MCBSP_DISABLE_FSG_SRG 2
+/* mono to mono mode*/
+#define OMAP_MCBSP_SKIP_NONE (0x0)
+/* mono to stereo mode */
+#define OMAP_MCBSP_SKIP_FIRST (0x1<<1)
+#define OMAP_MCBSP_SKIP_SECOND (0x1<<2)
+/* RRST STATE */
+#define OMAP_MCBSP_RRST_DISABLE 0
+#define OMAP_MCBSP_RRST_ENABLE 1
+/*XRST STATE */
+#define OMAP_MCBSP_XRST_DISABLE 0
+#define OMAP_MCBSP_XRST_ENABLE 1
+
/* we don't do multichannel for now */
struct omap_mcbsp_reg_cfg {
- u16 spcr2;
- u16 spcr1;
- u16 rcr2;
- u16 rcr1;
- u16 xcr2;
- u16 xcr1;
- u16 srgr2;
- u16 srgr1;
- u16 mcr2;
- u16 mcr1;
- u16 pcr0;
- u16 rcerc;
- u16 rcerd;
- u16 xcerc;
- u16 xcerd;
- u16 rcere;
- u16 rcerf;
- u16 xcere;
- u16 xcerf;
- u16 rcerg;
- u16 rcerh;
- u16 xcerg;
- u16 xcerh;
+ u32 spcr2;
+ u32 spcr1;
+ u32 rcr2;
+ u32 rcr1;
+ u32 xcr2;
+ u32 xcr1;
+ u32 srgr2;
+ u32 srgr1;
+ u32 mcr2;
+ u32 mcr1;
+ u32 pcr0;
+ u32 rcerc;
+ u32 rcerd;
+ u32 xcerc;
+ u32 xcerd;
+ u32 rcere;
+ u32 rcerf;
+ u32 xcere;
+ u32 xcerf;
+ u32 rcerg;
+ u32 rcerh;
+ u32 xcerg;
+ u32 xcerh;
+ u32 xccr;
+ u32 rccr;
};
typedef enum {
@@ -292,6 +317,7 @@
typedef int __bitwise omap_mcbsp_io_type_t;
#define OMAP_MCBSP_IRQ_IO ((__force omap_mcbsp_io_type_t) 1)
#define OMAP_MCBSP_POLL_IO ((__force omap_mcbsp_io_type_t) 2)
+typedef void (*omap_mcbsp_dma_cb) (u32 ch_status, void *arg);
typedef enum {
OMAP_MCBSP_WORD_8 = 0,
@@ -334,15 +360,29 @@
omap_mcbsp_word_length word_length;
};
+struct omap_mcbsp_dma_transfer_params {
+ /* Skip the alternate element use fro stereo mode */
+ u8 skip_alt;
+ /* Automagically handle Transfer [XR]RST? */
+ u8 auto_reset;
+ /* callback function executed for every tx/rx completion */
+ omap_mcbsp_dma_cb callback;
+ /* word length of data */
+ u32 word_length1;
+
+};
+
/* Platform specific configuration */
struct omap_mcbsp_ops {
void (*request)(unsigned int);
void (*free)(unsigned int);
int (*check)(unsigned int);
+ void (*config)(unsigned int, const struct omap_mcbsp_reg_cfg *config);
};
struct omap_mcbsp_platform_data {
u32 virt_base;
+ u32 phy_base;
u8 dma_rx_sync, dma_tx_sync;
u16 rx_irq, tx_irq;
struct omap_mcbsp_ops *ops;
@@ -378,6 +418,18 @@
spinlock_t lock;
struct omap_mcbsp_platform_data *pdata;
struct clk *clk;
+ u32 phy_base;
+ u8 auto_reset; /* Auto Reset */
+ u8 txskip_alt; /* Tx skip flags */
+ u8 rxskip_alt; /* Rx skip flags */
+ void *rx_cb_arg;
+ void *tx_cb_arg;
+ omap_mcbsp_dma_cb rx_callback;
+ omap_mcbsp_dma_cb tx_callback;
+ int rx_dma_chain_state;
+ int tx_dma_chain_state;
+ int interface_mode; /* Master / Slave */
+ int srg_enabled;
};
extern struct omap_mcbsp mcbsp[OMAP_MAX_MCBSP_COUNT];
@@ -405,4 +457,23 @@
int omap_mcbsp_pollwrite(unsigned int id, u16 buf);
int omap_mcbsp_set_io_type(unsigned int id, omap_mcbsp_io_type_t io_type);
+void omap_mcbsp_write(u32 io_base, u16 reg, u32 val);
+int omap_mcbsp_read(u32 io_base, u16 reg);
+
+int omap2_mcbsp_stop_datatx(unsigned int id);
+int omap2_mcbsp_stop_datarx(u32 id);
+int omap2_mcbsp_reset(unsigned int id);
+int omap2_mcbsp_transmitter_index(int id, int *ei, int *fi);
+int omap2_mcbsp_receiver_index(int id, int *ei, int *fi);
+int omap2_mcbsp_set_xrst(unsigned int id, u8 state);
+int omap2_mcbsp_set_rrst(unsigned int id, u8 state);
+int omap2_mcbsp_dma_recv_params(unsigned int id,
+ struct omap_mcbsp_dma_transfer_params *rp);
+int omap2_mcbsp_dma_trans_params(unsigned int id,
+ struct omap_mcbsp_dma_transfer_params *tp);
+int omap2_mcbsp_receive_data(unsigned int id, void *cbdata,
+ dma_addr_t buf_start_addr, u32 buf_size);
+int omap2_mcbsp_send_data(unsigned int id, void *cbdata,
+ dma_addr_t buf_start_addr, u32 buf_size);
+
#endif
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at http://vger.kernel.org/majordomo-info.html