McBSP support for 34XX
Subsystems (3)
PATCH 3/4 McBSP support for 34XX
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(-)
arch/arm/mach-omap2/mcbsp.c +680 -0
@@ -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
@@ -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