diff options
author | Shubhro <a0393217@ti.com> | 2010-02-11 14:42:29 +0530 |
---|---|---|
committer | Ricardo Perez Olivares <x0081762@ti.com> | 2010-02-11 03:39:56 -0600 |
commit | 0aa31d7a79909779d96a5ee2e80b8efd22d46221 (patch) | |
tree | 9716aced65c9006252930ade4f24c3346625b966 | |
parent | 1f430fc92eb18dd7326932a78127ba8e3ff34490 (diff) |
MCBSP DMAL24.4-pre-release24x-rtest
Signed-off-by: Shubhro <a0393217@ti.com>
-rw-r--r-- | arch/arm/mach-omap2/mcbsp.c | 943 | ||||
-rw-r--r-- | arch/arm/plat-omap/include/plat/clock.h | 2 | ||||
-rw-r--r-- | arch/arm/plat-omap/include/plat/mcbsp.h | 183 | ||||
-rw-r--r-- | arch/arm/plat-omap/mcbsp.c | 6 |
4 files changed, 1132 insertions, 2 deletions
diff --git a/arch/arm/mach-omap2/mcbsp.c b/arch/arm/mach-omap2/mcbsp.c index baa451733850..ead8e1f4788f 100644 --- a/arch/arm/mach-omap2/mcbsp.c +++ b/arch/arm/mach-omap2/mcbsp.c @@ -15,6 +15,7 @@ #include <linux/clk.h> #include <linux/err.h> #include <linux/io.h> +#include <linux/delay.h> #include <linux/platform_device.h> #include <mach/irqs.h> @@ -22,6 +23,117 @@ #include <plat/mux.h> #include <plat/cpu.h> #include <plat/mcbsp.h> +#include <plat/dma.h> + +#define OMAP_MCBSP_READ(base, reg) \ + omap_mcbsp_read(base, OMAP_MCBSP_REG_##reg) +#define OMAP_MCBSP_WRITE(base, reg, val) \ + omap_mcbsp_write(base, OMAP_MCBSP_REG_##reg, val) + +struct omap_mcbsp_reg_cfg mcbsp_cfg = {0}; + +struct mcbsp_internal_clk { + struct clk clk; + struct clk **childs; + int n_childs; +}; + +#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) || defined(CONFIG_ARCH_OMAP4) +static void omap_mcbsp_clk_init(struct mcbsp_internal_clk *mclk) +{ + const char *clk_names[] = { "mcbsp_ick", "mcbsp_fck" }; + int i; + + mclk->n_childs = ARRAY_SIZE(clk_names); + mclk->childs = kzalloc(mclk->n_childs * sizeof(struct clk *), + GFP_KERNEL); + + for (i = 0; i < mclk->n_childs; i++) { + /* We fake a platform device to get correct device id */ + struct platform_device pdev; + + pdev.dev.bus = &platform_bus_type; + pdev.id = mclk->clk.id; + mclk->childs[i] = clk_get(&pdev.dev, clk_names[i]); + if (IS_ERR(mclk->childs[i])) + printk(KERN_ERR "Could not get clock %s (%d).\n", + clk_names[i], mclk->clk.id); + } +} + +static int omap_mcbsp_clk_enable(struct clk *clk) +{ + struct mcbsp_internal_clk *mclk = container_of(clk, + struct mcbsp_internal_clk, clk); + int i; + for (i = 0; i < mclk->n_childs; i) + clk_enable(mclk->childs[i]); + return 0; +} + +static void omap_mcbsp_clk_disable(struct clk *clk) +{ + struct mcbsp_internal_clk *mclk = container_of(clk, + struct mcbsp_internal_clk, clk); + int i; + + for (i = 0; i < mclk->n_childs; i++) + clk_disable(mclk->childs[i]); +} + + +static struct mcbsp_internal_clk omap_mcbsp_clks[] = { + { + .clk = { + .name = "mcbsp_clk", + .id = 1, + .enable = omap_mcbsp_clk_enable, + .disable = omap_mcbsp_clk_disable, + }, + }, + { + .clk = { + .name = "mcbsp_clk", + .id = 2, + .enable = omap_mcbsp_clk_enable, + .disable = omap_mcbsp_clk_disable, + }, + }, + { + .clk = { + .name = "mcbsp_clk", + .id = 3, + .enable = omap_mcbsp_clk_enable, + .disable = omap_mcbsp_clk_disable, + }, + }, + { + .clk = { + .name = "mcbsp_clk", + .id = 4, + .enable = omap_mcbsp_clk_enable, + .disable = omap_mcbsp_clk_disable, + }, + }, + { + .clk = { + .name = "mcbsp_clk", + .id = 5, + .enable = omap_mcbsp_clk_enable, + .disable = omap_mcbsp_clk_disable, + }, + }, +}; + + +#define omap_mcbsp_clks_size ARRAY_SIZE(omap_mcbsp_clks) + +#else +#define omap_mcbsp_clks_size 0 +static struct mcbsp_internal_clk __initdata *omap_mcbsp_clks; +static inline void omap_mcbsp_clk_init(struct clk *clk) +{ } +#endif static void omap2_mcbsp2_mux_setup(void) { @@ -209,8 +321,839 @@ static struct omap_mcbsp_platform_data omap44xx_mcbsp_pdata[] = { }; #define OMAP44XX_MCBSP_PDATA_SZ ARRAY_SIZE(omap44xx_mcbsp_pdata) +static void omap2_mcbsp_free(unsigned int id) +{ + struct omap_mcbsp *mcbsp = mcbsp_ptr[id]; + + if (!cpu_is_omap2420()) { + if (mcbsp->dma_rx_lch != -1) { + omap_free_dma_chain(mcbsp->dma_rx_lch); + mcbsp->dma_rx_lch = -1; + } + + if (mcbsp->dma_tx_lch != -1) { + omap_free_dma_chain(mcbsp->dma_tx_lch); + mcbsp->dma_tx_lch = -1; + } + } + return; +} +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(io_base, XCCR, config->xccr); + OMAP_MCBSP_WRITE(io_base, RCCR, config->rccr); +} + +static void omap2_mcbsp_rx_dma_callback(int lch, u16 ch_status, void *data) +{ + struct omap_mcbsp *mcbsp_dma_rx = data; + void __iomem *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, SPCR1, + OMAP_MCBSP_READ(io_base, 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; + void __iomem *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, SPCR2, + OMAP_MCBSP_READ(io_base, 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 + */ +void omap2_mcbsp_set_srg_fsg(unsigned int id, u8 state) +{ + struct omap_mcbsp *mcbsp = mcbsp_ptr[id]; + void __iomem *io_base; + + io_base = mcbsp->io_base; + + if (state == OMAP_MCBSP_DISABLE_FSG_SRG) { + OMAP_MCBSP_WRITE(io_base, SPCR2, + OMAP_MCBSP_READ(io_base, SPCR2) & (~GRST)); + OMAP_MCBSP_WRITE(io_base, SPCR2, + OMAP_MCBSP_READ(io_base, SPCR2) & (~FRST)); + } else { + OMAP_MCBSP_WRITE(io_base, SPCR2, + OMAP_MCBSP_READ(io_base, SPCR2) | GRST); + OMAP_MCBSP_WRITE(io_base, SPCR2, + OMAP_MCBSP_READ(io_base, SPCR2) | FRST); + } + return; +} + +/* + * Stop transmitting data on a McBSP interface + * id : McBSP interface ID + */ +int omap2_mcbsp_stop_datatx(unsigned int id) +{ + 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 (mcbsp->dma_tx_lch != -1) { + if (omap_stop_dma_chain_transfers(mcbsp->dma_tx_lch) != 0) + return -EINVAL; + } + mcbsp->tx_dma_chain_state = 0; + OMAP_MCBSP_WRITE(io_base, SPCR2, + OMAP_MCBSP_READ(io_base, SPCR2) & (~XRST)); + + if (!mcbsp->rx_dma_chain_state) + omap2_mcbsp_set_srg_fsg(id, OMAP_MCBSP_DISABLE_FSG_SRG); + + 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) +{ + 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 (mcbsp->dma_rx_lch != -1) { + if (omap_stop_dma_chain_transfers(mcbsp->dma_rx_lch) != 0) + return -EINVAL; + } + OMAP_MCBSP_WRITE(io_base, SPCR1, + OMAP_MCBSP_READ(io_base, SPCR1) & (~RRST)); + + mcbsp->rx_dma_chain_state = 0; + if (!mcbsp->tx_dma_chain_state) + omap2_mcbsp_set_srg_fsg(id, OMAP_MCBSP_DISABLE_FSG_SRG); + + return 0; +} +EXPORT_SYMBOL(omap2_mcbsp_stop_datarx); + +/* + * 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) +{ + struct omap_mcbsp *mcbsp = mcbsp_ptr[id]; + int eix = 0, fix = 0; + + if (!omap_mcbsp_check_valid_id(id)) { + printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1); + return -ENODEV; + } + + if ((!ei) || (!fi)) { + printk(KERN_ERR "OMAP_McBSP: Invalid ei and fi params \n"); + goto txinx_err; + } + + if (mcbsp->dma_tx_lch == -1) { + printk(KERN_ERR "OMAP_McBSP: Transmitter not started\n"); + goto txinx_err; + } + + if (omap_get_dma_chain_index + (mcbsp->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) +{ + struct omap_mcbsp *mcbsp = mcbsp_ptr[id]; + int eix = 0, fix = 0; + + if (!omap_mcbsp_check_valid_id(id)) { + printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1); + return -ENODEV; + } + + if ((!ei) || (!fi)) { + printk(KERN_ERR "OMAP_McBSP: Invalid ei and fi params x\n"); + goto rxinx_err; + } + + /* Check if chain exists */ + if (mcbsp->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->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) +{ + 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_XRST_DISABLE) + OMAP_MCBSP_WRITE(io_base, SPCR2, + OMAP_MCBSP_READ(io_base, SPCR2) & (~XRST)); + else + OMAP_MCBSP_WRITE(io_base, SPCR2, + OMAP_MCBSP_READ(io_base, 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) +{ + 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(io_base, SPCR1, + OMAP_MCBSP_READ(io_base, SPCR1) & (~RRST)); + else + OMAP_MCBSP_WRITE(io_base, SPCR1, + OMAP_MCBSP_READ(io_base, 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) +{ + 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; +} +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_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; +} +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) +{ + 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 (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_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; +} +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) +{ + 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(io_base, SPCR2, + OMAP_MCBSP_READ(io_base, 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(io_base, SPCR2, + OMAP_MCBSP_READ(io_base, SPCR2) | XRST); + + return 0; +} +EXPORT_SYMBOL(omap2_mcbsp_send_data); + +void omap2_mcbsp_set_recv_param(struct omap_mcbsp_reg_cfg *mcbsp_cfg, + struct omap_mcbsp_cfg_param *rp) +{ + mcbsp_cfg->spcr1 = RJUST(rp->justification); + mcbsp_cfg->rcr2 = RCOMPAND(rp->reverse_compand) | + RDATDLY(rp->data_delay); + if (rp->phase == OMAP_MCBSP_FRAME_SINGLEPHASE) + mcbsp_cfg->rcr2 = mcbsp_cfg->rcr2 & ~(RPHASE); + else + mcbsp_cfg->rcr2 = mcbsp_cfg->rcr2 | (RPHASE) | + RWDLEN2(rp->word_length2) | RFRLEN2(rp->frame_length2); + mcbsp_cfg->rcr1 = RWDLEN1(rp->word_length1) | + RFRLEN1(rp->frame_length1); + if (rp->fsync_src == OMAP_MCBSP_RXFSYNC_INTERNAL) + mcbsp_cfg->pcr0 = mcbsp_cfg->pcr0 | FSRM; + if (rp->clk_mode == OMAP_MCBSP_CLKRXSRC_INTERNAL) + mcbsp_cfg->pcr0 = mcbsp_cfg->pcr0 | CLKRM; + if (rp->clk_polarity == OMAP_MCBSP_CLKR_POLARITY_RISING) + mcbsp_cfg->pcr0 = mcbsp_cfg->pcr0 | CLKRP; + if (rp->fs_polarity == OMAP_MCBSP_FS_ACTIVE_LOW) + mcbsp_cfg->pcr0 = mcbsp_cfg->pcr0 | FSRP; + return; +} + +/* + * Set McBSP transmit parameters + * id : McBSP interface ID + * mcbsp_cfg : McBSP register configuration + * tp : McBSP transmit parameters + */ + +void omap2_mcbsp_set_trans_param(struct omap_mcbsp_reg_cfg *mcbsp_cfg, + struct omap_mcbsp_cfg_param *tp) +{ + mcbsp_cfg->xcr2 = XCOMPAND(tp->reverse_compand) | + XDATDLY(tp->data_delay); + if (tp->phase == OMAP_MCBSP_FRAME_SINGLEPHASE) + mcbsp_cfg->xcr2 = mcbsp_cfg->xcr2 & ~(XPHASE); + else + mcbsp_cfg->xcr2 = mcbsp_cfg->xcr2 | (XPHASE) | + RWDLEN2(tp->word_length2) | RFRLEN2(tp->frame_length2); + mcbsp_cfg->xcr1 = XWDLEN1(tp->word_length1) | + XFRLEN1(tp->frame_length1); + if (tp->fs_polarity == OMAP_MCBSP_FS_ACTIVE_LOW) + mcbsp_cfg->pcr0 = mcbsp_cfg->pcr0 | FSXP; + if (tp->fsync_src == OMAP_MCBSP_TXFSYNC_INTERNAL) + mcbsp_cfg->pcr0 = mcbsp_cfg->pcr0 | FSXM; + if (tp->clk_mode == OMAP_MCBSP_CLKTXSRC_INTERNAL) + mcbsp_cfg->pcr0 = mcbsp_cfg->pcr0 | CLKXM; + if (tp->clk_polarity == OMAP_MCBSP_CLKX_POLARITY_FALLING) + mcbsp_cfg->pcr0 = mcbsp_cfg->pcr0 | CLKXP; + return; +} + + /* + * Set McBSP SRG configuration + * id : McBSP interface ID + * mcbsp_cfg : McBSP register configuration + * interface_mode : Master/Slave + * param : McBSP SRG and FSG configuration + */ + +void omap2_mcbsp_set_srg_cfg_param(unsigned int id, int interface_mode, + struct omap_mcbsp_reg_cfg *mcbsp_cfg, + struct omap_mcbsp_srg_fsg_cfg *param) +{ + struct omap_mcbsp *mcbsp = mcbsp_ptr[id]; + void __iomem *io_base; + u32 clk_rate, clkgdv; + io_base = mcbsp->io_base; + + mcbsp->interface_mode = interface_mode; + mcbsp_cfg->srgr1 = FWID(param->pulse_width); + + if (interface_mode == OMAP_MCBSP_MASTER) { + clk_rate = clk_get_rate(omap_mcbsp_clks[id].childs[1]); + clkgdv = clk_rate / (param->sample_rate * + (param->bits_per_sample - 1)); + mcbsp_cfg->srgr1 = mcbsp_cfg->srgr1 | CLKGDV(clkgdv); + } + if (param->dlb) + mcbsp_cfg->spcr1 = mcbsp_cfg->spcr1 & ~(ALB); + + if (param->sync_mode == OMAP_MCBSP_SRG_FREERUNNING) + mcbsp_cfg->spcr2 = mcbsp_cfg->spcr2 | FREE; + mcbsp_cfg->srgr2 = FPER(param->period)|(param->fsgm? FSGM : 0); + + switch (param->srg_src) { + + case OMAP_MCBSP_SRGCLKSRC_CLKS: + mcbsp_cfg->pcr0 = mcbsp_cfg->pcr0 & ~(SCLKME); + mcbsp_cfg->srgr2 = mcbsp_cfg->srgr2 & ~(CLKSM); + /* + * McBSP master operation at low voltage is only possible if + * CLKSP=0 In Master mode, if client driver tries to configiure + * input clock polarity as falling edge, we force it to Rising + */ + + if ((param->polarity == OMAP_MCBSP_CLKS_POLARITY_RISING) || + (interface_mode == OMAP_MCBSP_MASTER)) + mcbsp_cfg->srgr2 = mcbsp_cfg->srgr2 & ~(CLKSP); + else + mcbsp_cfg->srgr2 = mcbsp_cfg->srgr2 | (CLKSP); + break; + + + case OMAP_MCBSP_SRGCLKSRC_FCLK: + mcbsp_cfg->pcr0 = mcbsp_cfg->pcr0 & ~(SCLKME); + mcbsp_cfg->srgr2 = mcbsp_cfg->srgr2 | (CLKSM); + + break; + + case OMAP_MCBSP_SRGCLKSRC_CLKR: + mcbsp_cfg->pcr0 = mcbsp_cfg->pcr0 | (SCLKME); + mcbsp_cfg->srgr2 = mcbsp_cfg->srgr2 & ~(CLKSM); + if (param->polarity == OMAP_MCBSP_CLKR_POLARITY_FALLING) + mcbsp_cfg->pcr0 = mcbsp_cfg->pcr0 & ~(CLKRP); + else + mcbsp_cfg->pcr0 = mcbsp_cfg->pcr0 | (CLKRP); + + break; + + case OMAP_MCBSP_SRGCLKSRC_CLKX: + mcbsp_cfg->pcr0 = mcbsp_cfg->pcr0 | (SCLKME); + mcbsp_cfg->srgr2 = mcbsp_cfg->srgr2 | (CLKSM); + + if (param->polarity == OMAP_MCBSP_CLKX_POLARITY_RISING) + mcbsp_cfg->pcr0 = mcbsp_cfg->pcr0 & ~(CLKXP); + else + mcbsp_cfg->pcr0 = mcbsp_cfg->pcr0 | (CLKXP); + break; + + } + if (param->sync_mode == OMAP_MCBSP_SRG_FREERUNNING) + mcbsp_cfg->srgr2 = mcbsp_cfg->srgr2 & ~(GSYNC); + else if (param->sync_mode == OMAP_MCBSP_SRG_RUNNING) + mcbsp_cfg->srgr2 = mcbsp_cfg->srgr2 | (GSYNC); + + mcbsp_cfg->xccr = OMAP_MCBSP_READ(io_base, XCCR); + if (param->dlb) + mcbsp_cfg->xccr = mcbsp_cfg->xccr | (DILB); + mcbsp_cfg->rccr = OMAP_MCBSP_READ(io_base, RCCR); + + return; + } + +/* + * configure the McBSP registers + * id : McBSP interface ID + * interface_mode : Master/Slave + * rp : McBSP recv parameters + * tp : McBSP transmit parameters + * param : McBSP SRG and FSG configuration + */ +void omap2_mcbsp_params_cfg(unsigned int id, int interface_mode, + struct omap_mcbsp_cfg_param *rp, + struct omap_mcbsp_cfg_param *tp, + struct omap_mcbsp_srg_fsg_cfg *param) +{ + if (rp) + omap2_mcbsp_set_recv_param(&mcbsp_cfg, rp); + if (tp) + omap2_mcbsp_set_trans_param(&mcbsp_cfg, tp); + if (param) + omap2_mcbsp_set_srg_cfg_param(id, + interface_mode, &mcbsp_cfg, param); + omap_mcbsp_config(id, &mcbsp_cfg); + + return; +} +EXPORT_SYMBOL(omap2_mcbsp_params_cfg); + + static int __init omap2_mcbsp_init(void) { + int i; + + for (i = 0; i < omap_mcbsp_clks_size; i++) { + /* Once we call clk_get inside init, we do not register it */ + omap_mcbsp_clk_init(&omap_mcbsp_clks[i]); + clk_register(&omap_mcbsp_clks[i].clk); + } + if (cpu_is_omap2420()) omap_mcbsp_count = OMAP2420_MCBSP_PDATA_SZ; if (cpu_is_omap2430()) diff --git a/arch/arm/plat-omap/include/plat/clock.h b/arch/arm/plat-omap/include/plat/clock.h index 309b6d1dccdb..dc34717ed8bf 100644 --- a/arch/arm/plat-omap/include/plat/clock.h +++ b/arch/arm/plat-omap/include/plat/clock.h @@ -86,6 +86,8 @@ struct clk { int (*set_rate)(struct clk *, unsigned long); long (*round_rate)(struct clk *, unsigned long); void (*init)(struct clk *); + int (*enable)(struct clk *); + void (*disable)(struct clk *); __u8 enable_bit; __s8 usecount; #if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) || \ diff --git a/arch/arm/plat-omap/include/plat/mcbsp.h b/arch/arm/plat-omap/include/plat/mcbsp.h index 4f22e5bb7ff7..393e8eb38adf 100644 --- a/arch/arm/plat-omap/include/plat/mcbsp.h +++ b/arch/arm/plat-omap/include/plat/mcbsp.h @@ -29,6 +29,7 @@ #include <mach/hardware.h> #include <plat/clock.h> +#include <plat/dma.h> #define OMAP7XX_MCBSP1_BASE 0xfffb1000 #define OMAP7XX_MCBSP2_BASE 0xfffb1800 @@ -265,6 +266,95 @@ #define ENAWAKEUP 0x0004 #define SOFTRST 0x0002 +#define OMAP_MCBSP_WORDLEN_NONE 255 + +#define OMAP_MCBSP_MASTER 1 +#define OMAP_MCBSP_SLAVE 0 + +/* 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 + +#define OMAP_MCBSP_FRAME_SINGLEPHASE 1 +#define OMAP_MCBSP_FRAME_DUALPHASE 2 + +/* Sample Rate Generator Clock source */ +#define OMAP_MCBSP_SRGCLKSRC_CLKS 1 +#define OMAP_MCBSP_SRGCLKSRC_FCLK 2 +#define OMAP_MCBSP_SRGCLKSRC_CLKR 3 +#define OMAP_MCBSP_SRGCLKSRC_CLKX 4 +/* SRG input clock polarity */ +#define OMAP_MCBSP_CLKS_POLARITY_RISING 1 +#define OMAP_MCBSP_CLKS_POLARITY_FALLING 2 + +#define OMAP_MCBSP_CLKX_POLARITY_RISING 1 +#define OMAP_MCBSP_CLKX_POLARITY_FALLING 2 + +#define OMAP_MCBSP_CLKR_POLARITY_RISING 1 +#define OMAP_MCBSP_CLKR_POLARITY_FALLING 2 + +/* SRG Clock synchronization mode */ +#define OMAP_MCBSP_SRG_FREERUNNING 1 +#define OMAP_MCBSP_SRG_RUNNING 2 + +/* Frame Sync Source */ +#define OMAP_MCBSP_TXFSYNC_EXTERNAL 0 +#define OMAP_MCBSP_TXFSYNC_INTERNAL 1 + +#define OMAP_MCBSP_RXFSYNC_EXTERNAL 0 +#define OMAP_MCBSP_RXFSYNC_INTERNAL 1 + +#define OMAP_MCBSP_CLKRXSRC_EXTERNAL 1 +#define OMAP_MCBSP_CLKRXSRC_INTERNAL 2 + +#define OMAP_MCBSP_CLKTXSRC_EXTERNAL 1 +#define OMAP_MCBSP_CLKTXSRC_INTERNAL 2 + +/* Justification */ +#define OMAP_MCBSP_RJUST_ZEROMSB 0 +#define OMAP_MCBSP_RJUST_SIGNMSB 1 +#define OMAP_MCBSP_LJUST_ZEROLSB 2 + +#define OMAP_MCBSP_DATADELAY0 0 +#define OMAP_MCBSP_DATADELAY1 1 +#define OMAP_MCBSP_DATADELAY2 2 + +/* Reverse mode for 243X and 34XX */ +#define OMAP_MCBSP_MSBFIRST 0 +#define OMAP_MCBSP_LSBFIRST 1 + +/* Multi-Channel partition mode */ +#define OMAP_MCBSP_TWOPARTITION_MODE 0 +#define OMAP_MCBSP_EIGHTPARTITION_MODE 1 + +/* Rx Multichannel selection */ +#define OMAP_MCBSP_RXMUTICH_DISABLE 0 +#define OMAP_MCBSP_RXMUTICH_ENABLE 1 + +/* Tx Multichannel selection */ +#define OMAP_MCBSP_TXMUTICH_DISABLE 0 +#define OMAP_MCBSP_TXMUTICH_ENABLE 1 + +#define OMAP_MCBSP_FRAMELEN_N(NUM_WORDS) ((NUM_WORDS - 1) & 0x7F) + /********************** McBSP DMA operating modes **************************/ #define MCBSP_DMA_MODE_ELEMENT 0 #define MCBSP_DMA_MODE_THRESHOLD 1 @@ -321,6 +411,22 @@ typedef enum { 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) +#define omap_mcbsp_check_valid_id(id) (id < omap_mcbsp_count) +#define id_to_mcbsp_ptr(id) mcbsp_ptr[id]; + +typedef void (*omap_mcbsp_dma_cb) (u32 ch_status, void *arg); + +typedef struct omap_mcbsp_dma_transfer_parameters { + + /* 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; +} omap_mcbsp_dma_transfer_params; typedef enum { OMAP_MCBSP_WORD_8 = 0, @@ -410,12 +516,65 @@ struct omap_mcbsp { struct omap_mcbsp_platform_data *pdata; struct clk *iclk; struct clk *fclk; + + 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 */ + struct omap_dma_channel_params rx_params; /* Used For Rx FIFO */ + int rx_config_done; + #ifdef CONFIG_ARCH_OMAP34XX int dma_op_mode; u16 max_tx_thres; u16 max_rx_thres; #endif }; + +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; +}; + +struct omap_mcbsp_cfg_param { + u8 fsync_src; + u8 fs_polarity; + u8 clk_polarity; + u8 clk_mode; + u8 frame_length1; + u8 frame_length2; + u8 word_length1; + u8 word_length2; + u8 justification; + u8 reverse_compand; + u8 phase; + u8 data_delay; +}; + +struct omap_mcbsp_srg_fsg_cfg { + u32 period; /* Frame period */ + u32 pulse_width; /* Frame width */ + u8 fsgm; + u32 sample_rate; + u32 bits_per_sample; + u32 srg_src; + u8 sync_mode; /* SRG free running mode */ + u8 polarity; + u8 dlb; /* digital loopback mode */ +}; + extern struct omap_mcbsp **mcbsp_ptr; extern int omap_mcbsp_count; @@ -450,6 +609,30 @@ int omap_mcbsp_recv_buffer(unsigned int id, dma_addr_t buffer, unsigned int leng int omap_mcbsp_spi_master_xmit_word_poll(unsigned int id, u32 word); int omap_mcbsp_spi_master_recv_word_poll(unsigned int id, u32 * word); +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); +extern int omap2_mcbsp_set_xrst(unsigned int id, u8 state); +extern int omap2_mcbsp_set_rrst(unsigned int id, u8 state); +extern int omap2_mcbsp_dma_recv_params(unsigned int id, + struct omap_mcbsp_dma_transfer_params *rp); +extern int omap2_mcbsp_dma_trans_params(unsigned int id, + struct omap_mcbsp_dma_transfer_params *tp); +extern int omap2_mcbsp_receive_data(unsigned int id, void *cbdata, + dma_addr_t buf_start_addr, u32 buf_size); +extern int omap2_mcbsp_send_data(unsigned int id, void *cbdata, + dma_addr_t buf_start_addr, u32 buf_size); + +extern void omap_mcbsp_write(void __iomem *io_base, u16 reg, u32 val); +extern int omap_mcbsp_read(void __iomem *io_base, u16 reg); + +extern void omap2_mcbsp_params_cfg(unsigned int id, int interface_mode, + struct omap_mcbsp_cfg_param *rp, + struct omap_mcbsp_cfg_param *tp, + struct omap_mcbsp_srg_fsg_cfg *param); + /* SPI specific API */ void omap_mcbsp_set_spi_mode(unsigned int id, const struct omap_mcbsp_spi_cfg * spi_cfg); diff --git a/arch/arm/plat-omap/mcbsp.c b/arch/arm/plat-omap/mcbsp.c index 8eb8fb8654e6..7219b70079fe 100644 --- a/arch/arm/plat-omap/mcbsp.c +++ b/arch/arm/plat-omap/mcbsp.c @@ -37,6 +37,7 @@ void omap_mcbsp_write(void __iomem *io_base, u16 reg, u32 val) else __raw_writel(val, io_base + reg); } +EXPORT_SYMBOL(omap_mcbsp_write); int omap_mcbsp_read(void __iomem *io_base, u16 reg) { @@ -45,6 +46,7 @@ int omap_mcbsp_read(void __iomem *io_base, u16 reg) else return __raw_readl(io_base + reg); } +EXPORT_SYMBOL(omap_mcbsp_read); #define OMAP_MCBSP_READ(base, reg) \ omap_mcbsp_read(base, OMAP_MCBSP_REG_##reg) @@ -527,11 +529,11 @@ void omap_mcbsp_start(unsigned int id, int tx, int rx) /* Enable transmitter and receiver */ tx &= 1; w = OMAP_MCBSP_READ(io_base, SPCR2); - OMAP_MCBSP_WRITE(io_base, SPCR2, w | tx); + OMAP_MCBSP_WRITE(io_base, SPCR2, w | 1); rx &= 1; w = OMAP_MCBSP_READ(io_base, SPCR1); - OMAP_MCBSP_WRITE(io_base, SPCR1, w | rx); + OMAP_MCBSP_WRITE(io_base, SPCR1, w | 1); /* * Worst case: CLKSRG*2 = 8000khz: (1/8000) * 2 * 2 usec |