2005-07-10 19:58:15 +01:00
/*
* linux / arch / arm / plat - omap / mcbsp . c
*
* Copyright ( C ) 2004 Nokia Corporation
* Author : Samuel Ortiz < samuel . ortiz @ nokia . com >
*
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*
* Multichannel mode not supported .
*/
# include <linux/module.h>
# include <linux/init.h>
# include <linux/device.h>
# include <linux/wait.h>
# include <linux/completion.h>
# include <linux/interrupt.h>
# include <linux/err.h>
# include <asm/delay.h>
# include <asm/io.h>
# include <asm/irq.h>
# include <asm/arch/dma.h>
# include <asm/arch/mux.h>
# include <asm/arch/irqs.h>
# include <asm/arch/mcbsp.h>
# include <asm/hardware/clock.h>
# ifdef CONFIG_MCBSP_DEBUG
# define DBG(x...) printk(x)
# else
# define DBG(x...) do { } while (0)
# endif
struct omap_mcbsp {
u32 io_base ;
u8 id ;
u8 free ;
omap_mcbsp_word_length rx_word_length ;
omap_mcbsp_word_length tx_word_length ;
/* IRQ based TX/RX */
int rx_irq ;
int tx_irq ;
/* DMA stuff */
u8 dma_rx_sync ;
short dma_rx_lch ;
u8 dma_tx_sync ;
short dma_tx_lch ;
/* Completion queues */
struct completion tx_irq_completion ;
struct completion rx_irq_completion ;
struct completion tx_dma_completion ;
struct completion rx_dma_completion ;
spinlock_t lock ;
} ;
static struct omap_mcbsp mcbsp [ OMAP_MAX_MCBSP_COUNT ] ;
static struct clk * mcbsp_dsp_ck = 0 ;
static struct clk * mcbsp_api_ck = 0 ;
2005-07-10 19:58:18 +01:00
static struct clk * mcbsp_dspxor_ck = 0 ;
2005-07-10 19:58:15 +01:00
static void omap_mcbsp_dump_reg ( u8 id )
{
DBG ( " **** MCBSP%d regs **** \n " , mcbsp [ id ] . id ) ;
DBG ( " DRR2: 0x%04x \n " , OMAP_MCBSP_READ ( mcbsp [ id ] . io_base , DRR2 ) ) ;
DBG ( " DRR1: 0x%04x \n " , OMAP_MCBSP_READ ( mcbsp [ id ] . io_base , DRR1 ) ) ;
DBG ( " DXR2: 0x%04x \n " , OMAP_MCBSP_READ ( mcbsp [ id ] . io_base , DXR2 ) ) ;
DBG ( " DXR1: 0x%04x \n " , OMAP_MCBSP_READ ( mcbsp [ id ] . io_base , DXR1 ) ) ;
DBG ( " SPCR2: 0x%04x \n " , OMAP_MCBSP_READ ( mcbsp [ id ] . io_base , SPCR2 ) ) ;
DBG ( " SPCR1: 0x%04x \n " , OMAP_MCBSP_READ ( mcbsp [ id ] . io_base , SPCR1 ) ) ;
DBG ( " RCR2: 0x%04x \n " , OMAP_MCBSP_READ ( mcbsp [ id ] . io_base , RCR2 ) ) ;
DBG ( " RCR1: 0x%04x \n " , OMAP_MCBSP_READ ( mcbsp [ id ] . io_base , RCR1 ) ) ;
DBG ( " XCR2: 0x%04x \n " , OMAP_MCBSP_READ ( mcbsp [ id ] . io_base , XCR2 ) ) ;
DBG ( " XCR1: 0x%04x \n " , OMAP_MCBSP_READ ( mcbsp [ id ] . io_base , XCR1 ) ) ;
DBG ( " SRGR2: 0x%04x \n " , OMAP_MCBSP_READ ( mcbsp [ id ] . io_base , SRGR2 ) ) ;
DBG ( " SRGR1: 0x%04x \n " , OMAP_MCBSP_READ ( mcbsp [ id ] . io_base , SRGR1 ) ) ;
DBG ( " PCR0: 0x%04x \n " , OMAP_MCBSP_READ ( mcbsp [ id ] . io_base , PCR0 ) ) ;
DBG ( " *********************** \n " ) ;
}
static irqreturn_t omap_mcbsp_tx_irq_handler ( int irq , void * dev_id , struct pt_regs * regs )
{
struct omap_mcbsp * mcbsp_tx = ( struct omap_mcbsp * ) ( dev_id ) ;
DBG ( " TX IRQ callback : 0x%x \n " , OMAP_MCBSP_READ ( mcbsp_tx - > io_base , SPCR2 ) ) ;
complete ( & mcbsp_tx - > tx_irq_completion ) ;
return IRQ_HANDLED ;
}
static irqreturn_t omap_mcbsp_rx_irq_handler ( int irq , void * dev_id , struct pt_regs * regs )
{
struct omap_mcbsp * mcbsp_rx = ( struct omap_mcbsp * ) ( dev_id ) ;
DBG ( " RX IRQ callback : 0x%x \n " , OMAP_MCBSP_READ ( mcbsp_rx - > io_base , SPCR2 ) ) ;
complete ( & mcbsp_rx - > rx_irq_completion ) ;
return IRQ_HANDLED ;
}
static void omap_mcbsp_tx_dma_callback ( int lch , u16 ch_status , void * data )
{
struct omap_mcbsp * mcbsp_dma_tx = ( struct omap_mcbsp * ) ( data ) ;
DBG ( " TX DMA callback : 0x%x \n " , OMAP_MCBSP_READ ( mcbsp_dma_tx - > io_base , SPCR2 ) ) ;
/* We can free the channels */
omap_free_dma ( mcbsp_dma_tx - > dma_tx_lch ) ;
mcbsp_dma_tx - > dma_tx_lch = - 1 ;
complete ( & mcbsp_dma_tx - > tx_dma_completion ) ;
}
static void omap_mcbsp_rx_dma_callback ( int lch , u16 ch_status , void * data )
{
struct omap_mcbsp * mcbsp_dma_rx = ( struct omap_mcbsp * ) ( data ) ;
DBG ( " RX DMA callback : 0x%x \n " , OMAP_MCBSP_READ ( mcbsp_dma_rx - > io_base , SPCR2 ) ) ;
/* We can free the channels */
omap_free_dma ( mcbsp_dma_rx - > dma_rx_lch ) ;
mcbsp_dma_rx - > dma_rx_lch = - 1 ;
complete ( & mcbsp_dma_rx - > rx_dma_completion ) ;
}
/*
* omap_mcbsp_config simply write a config to the
* appropriate McBSP .
* You either call this function or set the McBSP registers
* by yourself before calling omap_mcbsp_start ( ) .
*/
void omap_mcbsp_config ( unsigned int id , const struct omap_mcbsp_reg_cfg * config )
{
u32 io_base = mcbsp [ id ] . io_base ;
DBG ( " OMAP-McBSP: McBSP%d io_base: 0x%8x \n " , id + 1 , io_base ) ;
/* We write the given config */
OMAP_MCBSP_WRITE ( io_base , SPCR2 , config - > spcr2 ) ;
OMAP_MCBSP_WRITE ( io_base , SPCR1 , config - > spcr1 ) ;
OMAP_MCBSP_WRITE ( io_base , RCR2 , config - > rcr2 ) ;
OMAP_MCBSP_WRITE ( io_base , RCR1 , config - > rcr1 ) ;
OMAP_MCBSP_WRITE ( io_base , XCR2 , config - > xcr2 ) ;
OMAP_MCBSP_WRITE ( io_base , XCR1 , config - > xcr1 ) ;
OMAP_MCBSP_WRITE ( io_base , SRGR2 , config - > srgr2 ) ;
OMAP_MCBSP_WRITE ( io_base , SRGR1 , config - > srgr1 ) ;
OMAP_MCBSP_WRITE ( io_base , MCR2 , config - > mcr2 ) ;
OMAP_MCBSP_WRITE ( io_base , MCR1 , config - > mcr1 ) ;
OMAP_MCBSP_WRITE ( io_base , PCR0 , config - > pcr0 ) ;
}
static int omap_mcbsp_check ( unsigned int id )
{
if ( cpu_is_omap730 ( ) ) {
if ( id > OMAP_MAX_MCBSP_COUNT - 1 ) {
printk ( KERN_ERR " OMAP-McBSP: McBSP%d doesn't exist \n " , id + 1 ) ;
return - 1 ;
}
return 0 ;
}
2005-07-10 19:58:18 +01:00
if ( cpu_is_omap1510 ( ) | | cpu_is_omap16xx ( ) ) {
2005-07-10 19:58:15 +01:00
if ( id > OMAP_MAX_MCBSP_COUNT ) {
printk ( KERN_ERR " OMAP-McBSP: McBSP%d doesn't exist \n " , id + 1 ) ;
return - 1 ;
}
return 0 ;
}
return - 1 ;
}
# define EN_XORPCK 1
# define DSP_RSTCT2 0xe1008014
static void omap_mcbsp_dsp_request ( void )
{
2005-07-10 19:58:18 +01:00
if ( cpu_is_omap1510 ( ) | | cpu_is_omap16xx ( ) ) {
clk_use ( mcbsp_dsp_ck ) ;
clk_use ( mcbsp_api_ck ) ;
2005-07-10 19:58:15 +01:00
/* enable 12MHz clock to mcbsp 1 & 3 */
2005-07-10 19:58:18 +01:00
clk_use ( mcbsp_dspxor_ck ) ;
2005-07-10 19:58:15 +01:00
__raw_writew ( __raw_readw ( DSP_RSTCT2 ) | 1 | 1 < < 1 ,
DSP_RSTCT2 ) ;
}
}
static void omap_mcbsp_dsp_free ( void )
{
2005-07-10 19:58:18 +01:00
if ( cpu_is_omap1510 ( ) | | cpu_is_omap16xx ( ) ) {
clk_unuse ( mcbsp_dspxor_ck ) ;
clk_unuse ( mcbsp_dsp_ck ) ;
clk_unuse ( mcbsp_api_ck ) ;
}
2005-07-10 19:58:15 +01:00
}
int omap_mcbsp_request ( unsigned int id )
{
int err ;
if ( omap_mcbsp_check ( id ) < 0 )
return - EINVAL ;
/*
* On 1510 , 1610 and 1710 , McBSP1 and McBSP3
* are DSP public peripherals .
*/
if ( id = = OMAP_MCBSP1 | | id = = OMAP_MCBSP3 )
omap_mcbsp_dsp_request ( ) ;
spin_lock ( & mcbsp [ id ] . lock ) ;
if ( ! mcbsp [ id ] . free ) {
printk ( KERN_ERR " OMAP-McBSP: McBSP%d is currently in use \n " , id + 1 ) ;
spin_unlock ( & mcbsp [ id ] . lock ) ;
return - 1 ;
}
mcbsp [ id ] . free = 0 ;
spin_unlock ( & mcbsp [ id ] . lock ) ;
/* We need to get IRQs here */
err = request_irq ( mcbsp [ id ] . tx_irq , omap_mcbsp_tx_irq_handler , 0 ,
" McBSP " ,
( void * ) ( & mcbsp [ id ] ) ) ;
if ( err ! = 0 ) {
printk ( KERN_ERR " OMAP-McBSP: Unable to request TX IRQ %d for McBSP%d \n " ,
mcbsp [ id ] . tx_irq , mcbsp [ id ] . id ) ;
return err ;
}
init_completion ( & ( mcbsp [ id ] . tx_irq_completion ) ) ;
err = request_irq ( mcbsp [ id ] . rx_irq , omap_mcbsp_rx_irq_handler , 0 ,
" McBSP " ,
( void * ) ( & mcbsp [ id ] ) ) ;
if ( err ! = 0 ) {
printk ( KERN_ERR " OMAP-McBSP: Unable to request RX IRQ %d for McBSP%d \n " ,
mcbsp [ id ] . rx_irq , mcbsp [ id ] . id ) ;
free_irq ( mcbsp [ id ] . tx_irq , ( void * ) ( & mcbsp [ id ] ) ) ;
return err ;
}
init_completion ( & ( mcbsp [ id ] . rx_irq_completion ) ) ;
return 0 ;
}
void omap_mcbsp_free ( unsigned int id )
{
if ( omap_mcbsp_check ( id ) < 0 )
return ;
if ( id = = OMAP_MCBSP1 | | id = = OMAP_MCBSP3 )
omap_mcbsp_dsp_free ( ) ;
spin_lock ( & mcbsp [ id ] . lock ) ;
if ( mcbsp [ id ] . free ) {
printk ( KERN_ERR " OMAP-McBSP: McBSP%d was not reserved \n " , id + 1 ) ;
spin_unlock ( & mcbsp [ id ] . lock ) ;
return ;
}
mcbsp [ id ] . free = 1 ;
spin_unlock ( & mcbsp [ id ] . lock ) ;
/* Free IRQs */
free_irq ( mcbsp [ id ] . rx_irq , ( void * ) ( & mcbsp [ id ] ) ) ;
free_irq ( mcbsp [ id ] . tx_irq , ( void * ) ( & mcbsp [ id ] ) ) ;
}
/*
* Here we start the McBSP , by enabling the sample
* generator , both transmitter and receivers ,
* and the frame sync .
*/
void omap_mcbsp_start ( unsigned int id )
{
u32 io_base ;
u16 w ;
if ( omap_mcbsp_check ( id ) < 0 )
return ;
io_base = mcbsp [ id ] . io_base ;
mcbsp [ id ] . rx_word_length = ( ( OMAP_MCBSP_READ ( io_base , RCR1 ) > > 5 ) & 0x7 ) ;
mcbsp [ id ] . tx_word_length = ( ( OMAP_MCBSP_READ ( io_base , XCR1 ) > > 5 ) & 0x7 ) ;
/* Start the sample generator */
w = OMAP_MCBSP_READ ( io_base , SPCR2 ) ;
OMAP_MCBSP_WRITE ( io_base , SPCR2 , w | ( 1 < < 6 ) ) ;
/* Enable transmitter and receiver */
w = OMAP_MCBSP_READ ( io_base , SPCR2 ) ;
OMAP_MCBSP_WRITE ( io_base , SPCR2 , w | 1 ) ;
w = OMAP_MCBSP_READ ( io_base , SPCR1 ) ;
OMAP_MCBSP_WRITE ( io_base , SPCR1 , w | 1 ) ;
udelay ( 100 ) ;
/* Start frame sync */
w = OMAP_MCBSP_READ ( io_base , SPCR2 ) ;
OMAP_MCBSP_WRITE ( io_base , SPCR2 , w | ( 1 < < 7 ) ) ;
/* Dump McBSP Regs */
omap_mcbsp_dump_reg ( id ) ;
}
void omap_mcbsp_stop ( unsigned int id )
{
u32 io_base ;
u16 w ;
if ( omap_mcbsp_check ( id ) < 0 )
return ;
io_base = mcbsp [ id ] . io_base ;
/* Reset transmitter */
w = OMAP_MCBSP_READ ( io_base , SPCR2 ) ;
OMAP_MCBSP_WRITE ( io_base , SPCR2 , w & ~ ( 1 ) ) ;
/* Reset receiver */
w = OMAP_MCBSP_READ ( io_base , SPCR1 ) ;
OMAP_MCBSP_WRITE ( io_base , SPCR1 , w & ~ ( 1 ) ) ;
/* Reset the sample rate generator */
w = OMAP_MCBSP_READ ( io_base , SPCR2 ) ;
OMAP_MCBSP_WRITE ( io_base , SPCR2 , w & ~ ( 1 < < 6 ) ) ;
}
2005-07-10 19:58:18 +01:00
/* polled mcbsp i/o operations */
int omap_mcbsp_pollwrite ( unsigned int id , u16 buf )
{
u32 base = mcbsp [ id ] . io_base ;
writew ( buf , base + OMAP_MCBSP_REG_DXR1 ) ;
/* if frame sync error - clear the error */
if ( readw ( base + OMAP_MCBSP_REG_SPCR2 ) & XSYNC_ERR ) {
/* clear error */
writew ( readw ( base + OMAP_MCBSP_REG_SPCR2 ) & ( ~ XSYNC_ERR ) ,
base + OMAP_MCBSP_REG_SPCR2 ) ;
/* resend */
return - 1 ;
} else {
/* wait for transmit confirmation */
int attemps = 0 ;
while ( ! ( readw ( base + OMAP_MCBSP_REG_SPCR2 ) & XRDY ) ) {
if ( attemps + + > 1000 ) {
writew ( readw ( base + OMAP_MCBSP_REG_SPCR2 ) &
( ~ XRST ) ,
base + OMAP_MCBSP_REG_SPCR2 ) ;
udelay ( 10 ) ;
writew ( readw ( base + OMAP_MCBSP_REG_SPCR2 ) |
( XRST ) ,
base + OMAP_MCBSP_REG_SPCR2 ) ;
udelay ( 10 ) ;
printk ( KERN_ERR
" Could not write to McBSP Register \n " ) ;
return - 2 ;
}
}
}
return 0 ;
}
int omap_mcbsp_pollread ( unsigned int id , u16 * buf )
{
u32 base = mcbsp [ id ] . io_base ;
/* if frame sync error - clear the error */
if ( readw ( base + OMAP_MCBSP_REG_SPCR1 ) & RSYNC_ERR ) {
/* clear error */
writew ( readw ( base + OMAP_MCBSP_REG_SPCR1 ) & ( ~ RSYNC_ERR ) ,
base + OMAP_MCBSP_REG_SPCR1 ) ;
/* resend */
return - 1 ;
} else {
/* wait for recieve confirmation */
int attemps = 0 ;
while ( ! ( readw ( base + OMAP_MCBSP_REG_SPCR1 ) & RRDY ) ) {
if ( attemps + + > 1000 ) {
writew ( readw ( base + OMAP_MCBSP_REG_SPCR1 ) &
( ~ RRST ) ,
base + OMAP_MCBSP_REG_SPCR1 ) ;
udelay ( 10 ) ;
writew ( readw ( base + OMAP_MCBSP_REG_SPCR1 ) |
( RRST ) ,
base + OMAP_MCBSP_REG_SPCR1 ) ;
udelay ( 10 ) ;
printk ( KERN_ERR
" Could not read from McBSP Register \n " ) ;
return - 2 ;
}
}
}
* buf = readw ( base + OMAP_MCBSP_REG_DRR1 ) ;
return 0 ;
}
2005-07-10 19:58:15 +01:00
/*
* IRQ based word transmission .
*/
void omap_mcbsp_xmit_word ( unsigned int id , u32 word )
{
u32 io_base ;
omap_mcbsp_word_length word_length = mcbsp [ id ] . tx_word_length ;
if ( omap_mcbsp_check ( id ) < 0 )
return ;
io_base = mcbsp [ id ] . io_base ;
wait_for_completion ( & ( mcbsp [ id ] . tx_irq_completion ) ) ;
if ( word_length > OMAP_MCBSP_WORD_16 )
OMAP_MCBSP_WRITE ( io_base , DXR2 , word > > 16 ) ;
OMAP_MCBSP_WRITE ( io_base , DXR1 , word & 0xffff ) ;
}
u32 omap_mcbsp_recv_word ( unsigned int id )
{
u32 io_base ;
u16 word_lsb , word_msb = 0 ;
omap_mcbsp_word_length word_length = mcbsp [ id ] . rx_word_length ;
if ( omap_mcbsp_check ( id ) < 0 )
return - EINVAL ;
io_base = mcbsp [ id ] . io_base ;
wait_for_completion ( & ( mcbsp [ id ] . rx_irq_completion ) ) ;
if ( word_length > OMAP_MCBSP_WORD_16 )
word_msb = OMAP_MCBSP_READ ( io_base , DRR2 ) ;
word_lsb = OMAP_MCBSP_READ ( io_base , DRR1 ) ;
return ( word_lsb | ( word_msb < < 16 ) ) ;
}
/*
* Simple DMA based buffer rx / tx routines .
* Nothing fancy , just a single buffer tx / rx through DMA .
* The DMA resources are released once the transfer is done .
* For anything fancier , you should use your own customized DMA
* routines and callbacks .
*/
int omap_mcbsp_xmit_buffer ( unsigned int id , dma_addr_t buffer , unsigned int length )
{
int dma_tx_ch ;
if ( omap_mcbsp_check ( id ) < 0 )
return - EINVAL ;
if ( omap_request_dma ( mcbsp [ id ] . dma_tx_sync , " McBSP TX " , omap_mcbsp_tx_dma_callback ,
& mcbsp [ id ] ,
& dma_tx_ch ) ) {
printk ( " OMAP-McBSP: Unable to request DMA channel for McBSP%d TX. Trying IRQ based TX \n " , id + 1 ) ;
return - EAGAIN ;
}
mcbsp [ id ] . dma_tx_lch = dma_tx_ch ;
DBG ( " TX DMA on channel %d \n " , dma_tx_ch ) ;
init_completion ( & ( mcbsp [ id ] . tx_dma_completion ) ) ;
omap_set_dma_transfer_params ( mcbsp [ id ] . dma_tx_lch ,
OMAP_DMA_DATA_TYPE_S16 ,
length > > 1 , 1 ,
OMAP_DMA_SYNC_ELEMENT ) ;
omap_set_dma_dest_params ( mcbsp [ id ] . dma_tx_lch ,
OMAP_DMA_PORT_TIPB ,
OMAP_DMA_AMODE_CONSTANT ,
mcbsp [ id ] . io_base + OMAP_MCBSP_REG_DXR1 ) ;
omap_set_dma_src_params ( mcbsp [ id ] . dma_tx_lch ,
OMAP_DMA_PORT_EMIFF ,
OMAP_DMA_AMODE_POST_INC ,
buffer ) ;
omap_start_dma ( mcbsp [ id ] . dma_tx_lch ) ;
wait_for_completion ( & ( mcbsp [ id ] . tx_dma_completion ) ) ;
return 0 ;
}
int omap_mcbsp_recv_buffer ( unsigned int id , dma_addr_t buffer , unsigned int length )
{
int dma_rx_ch ;
if ( omap_mcbsp_check ( id ) < 0 )
return - EINVAL ;
if ( omap_request_dma ( mcbsp [ id ] . dma_rx_sync , " McBSP RX " , omap_mcbsp_rx_dma_callback ,
& mcbsp [ id ] ,
& dma_rx_ch ) ) {
printk ( " Unable to request DMA channel for McBSP%d RX. Trying IRQ based RX \n " , id + 1 ) ;
return - EAGAIN ;
}
mcbsp [ id ] . dma_rx_lch = dma_rx_ch ;
DBG ( " RX DMA on channel %d \n " , dma_rx_ch ) ;
init_completion ( & ( mcbsp [ id ] . rx_dma_completion ) ) ;
omap_set_dma_transfer_params ( mcbsp [ id ] . dma_rx_lch ,
OMAP_DMA_DATA_TYPE_S16 ,
length > > 1 , 1 ,
OMAP_DMA_SYNC_ELEMENT ) ;
omap_set_dma_src_params ( mcbsp [ id ] . dma_rx_lch ,
OMAP_DMA_PORT_TIPB ,
OMAP_DMA_AMODE_CONSTANT ,
mcbsp [ id ] . io_base + OMAP_MCBSP_REG_DRR1 ) ;
omap_set_dma_dest_params ( mcbsp [ id ] . dma_rx_lch ,
OMAP_DMA_PORT_EMIFF ,
OMAP_DMA_AMODE_POST_INC ,
buffer ) ;
omap_start_dma ( mcbsp [ id ] . dma_rx_lch ) ;
wait_for_completion ( & ( mcbsp [ id ] . rx_dma_completion ) ) ;
return 0 ;
}
/*
* SPI wrapper .
* Since SPI setup is much simpler than the generic McBSP one ,
* this wrapper just need an omap_mcbsp_spi_cfg structure as an input .
* Once this is done , you can call omap_mcbsp_start ( ) .
*/
void omap_mcbsp_set_spi_mode ( unsigned int id , const struct omap_mcbsp_spi_cfg * spi_cfg )
{
struct omap_mcbsp_reg_cfg mcbsp_cfg ;
if ( omap_mcbsp_check ( id ) < 0 )
return ;
memset ( & mcbsp_cfg , 0 , sizeof ( struct omap_mcbsp_reg_cfg ) ) ;
/* SPI has only one frame */
mcbsp_cfg . rcr1 | = ( RWDLEN1 ( spi_cfg - > word_length ) | RFRLEN1 ( 0 ) ) ;
mcbsp_cfg . xcr1 | = ( XWDLEN1 ( spi_cfg - > word_length ) | XFRLEN1 ( 0 ) ) ;
/* Clock stop mode */
if ( spi_cfg - > clk_stp_mode = = OMAP_MCBSP_CLK_STP_MODE_NO_DELAY )
mcbsp_cfg . spcr1 | = ( 1 < < 12 ) ;
else
mcbsp_cfg . spcr1 | = ( 3 < < 11 ) ;
/* Set clock parities */
if ( spi_cfg - > rx_clock_polarity = = OMAP_MCBSP_CLK_RISING )
mcbsp_cfg . pcr0 | = CLKRP ;
else
mcbsp_cfg . pcr0 & = ~ CLKRP ;
if ( spi_cfg - > tx_clock_polarity = = OMAP_MCBSP_CLK_RISING )
mcbsp_cfg . pcr0 & = ~ CLKXP ;
else
mcbsp_cfg . pcr0 | = CLKXP ;
/* Set SCLKME to 0 and CLKSM to 1 */
mcbsp_cfg . pcr0 & = ~ SCLKME ;
mcbsp_cfg . srgr2 | = CLKSM ;
/* Set FSXP */
if ( spi_cfg - > fsx_polarity = = OMAP_MCBSP_FS_ACTIVE_HIGH )
mcbsp_cfg . pcr0 & = ~ FSXP ;
else
mcbsp_cfg . pcr0 | = FSXP ;
if ( spi_cfg - > spi_mode = = OMAP_MCBSP_SPI_MASTER ) {
mcbsp_cfg . pcr0 | = CLKXM ;
mcbsp_cfg . srgr1 | = CLKGDV ( spi_cfg - > clk_div - 1 ) ;
mcbsp_cfg . pcr0 | = FSXM ;
mcbsp_cfg . srgr2 & = ~ FSGM ;
mcbsp_cfg . xcr2 | = XDATDLY ( 1 ) ;
mcbsp_cfg . rcr2 | = RDATDLY ( 1 ) ;
}
else {
mcbsp_cfg . pcr0 & = ~ CLKXM ;
mcbsp_cfg . srgr1 | = CLKGDV ( 1 ) ;
mcbsp_cfg . pcr0 & = ~ FSXM ;
mcbsp_cfg . xcr2 & = ~ XDATDLY ( 3 ) ;
mcbsp_cfg . rcr2 & = ~ RDATDLY ( 3 ) ;
}
mcbsp_cfg . xcr2 & = ~ XPHASE ;
mcbsp_cfg . rcr2 & = ~ RPHASE ;
omap_mcbsp_config ( id , & mcbsp_cfg ) ;
}
/*
* McBSP1 and McBSP3 are directly mapped on 1610 and 1510.
* 730 has only 2 McBSP , and both of them are MPU peripherals .
*/
struct omap_mcbsp_info {
u32 virt_base ;
u8 dma_rx_sync , dma_tx_sync ;
u16 rx_irq , tx_irq ;
} ;
# ifdef CONFIG_ARCH_OMAP730
static const struct omap_mcbsp_info mcbsp_730 [ ] = {
[ 0 ] = { . virt_base = io_p2v ( OMAP730_MCBSP1_BASE ) ,
. dma_rx_sync = OMAP_DMA_MCBSP1_RX ,
. dma_tx_sync = OMAP_DMA_MCBSP1_TX ,
. rx_irq = INT_730_McBSP1RX ,
. tx_irq = INT_730_McBSP1TX } ,
[ 1 ] = { . virt_base = io_p2v ( OMAP730_MCBSP2_BASE ) ,
. dma_rx_sync = OMAP_DMA_MCBSP3_RX ,
. dma_tx_sync = OMAP_DMA_MCBSP3_TX ,
. rx_irq = INT_730_McBSP2RX ,
. tx_irq = INT_730_McBSP2TX } ,
} ;
# endif
# ifdef CONFIG_ARCH_OMAP1510
static const struct omap_mcbsp_info mcbsp_1510 [ ] = {
[ 0 ] = { . virt_base = OMAP1510_MCBSP1_BASE ,
. dma_rx_sync = OMAP_DMA_MCBSP1_RX ,
. dma_tx_sync = OMAP_DMA_MCBSP1_TX ,
. rx_irq = INT_McBSP1RX ,
. tx_irq = INT_McBSP1TX } ,
[ 1 ] = { . virt_base = io_p2v ( OMAP1510_MCBSP2_BASE ) ,
. dma_rx_sync = OMAP_DMA_MCBSP2_RX ,
. dma_tx_sync = OMAP_DMA_MCBSP2_TX ,
. rx_irq = INT_1510_SPI_RX ,
. tx_irq = INT_1510_SPI_TX } ,
[ 2 ] = { . virt_base = OMAP1510_MCBSP3_BASE ,
. dma_rx_sync = OMAP_DMA_MCBSP3_RX ,
. dma_tx_sync = OMAP_DMA_MCBSP3_TX ,
. rx_irq = INT_McBSP3RX ,
. tx_irq = INT_McBSP3TX } ,
} ;
# endif
# if defined(CONFIG_ARCH_OMAP16XX)
static const struct omap_mcbsp_info mcbsp_1610 [ ] = {
[ 0 ] = { . virt_base = OMAP1610_MCBSP1_BASE ,
. dma_rx_sync = OMAP_DMA_MCBSP1_RX ,
. dma_tx_sync = OMAP_DMA_MCBSP1_TX ,
. rx_irq = INT_McBSP1RX ,
. tx_irq = INT_McBSP1TX } ,
[ 1 ] = { . virt_base = io_p2v ( OMAP1610_MCBSP2_BASE ) ,
. dma_rx_sync = OMAP_DMA_MCBSP2_RX ,
. dma_tx_sync = OMAP_DMA_MCBSP2_TX ,
. rx_irq = INT_1610_McBSP2_RX ,
. tx_irq = INT_1610_McBSP2_TX } ,
[ 2 ] = { . virt_base = OMAP1610_MCBSP3_BASE ,
. dma_rx_sync = OMAP_DMA_MCBSP3_RX ,
. dma_tx_sync = OMAP_DMA_MCBSP3_TX ,
. rx_irq = INT_McBSP3RX ,
. tx_irq = INT_McBSP3TX } ,
} ;
# endif
static int __init omap_mcbsp_init ( void )
{
int mcbsp_count = 0 , i ;
static const struct omap_mcbsp_info * mcbsp_info ;
printk ( " Initializing OMAP McBSP system \n " ) ;
mcbsp_dsp_ck = clk_get ( 0 , " dsp_ck " ) ;
if ( IS_ERR ( mcbsp_dsp_ck ) ) {
printk ( KERN_ERR " mcbsp: could not acquire dsp_ck handle. \n " ) ;
return PTR_ERR ( mcbsp_dsp_ck ) ;
}
mcbsp_api_ck = clk_get ( 0 , " api_ck " ) ;
2005-07-10 19:58:18 +01:00
if ( IS_ERR ( mcbsp_api_ck ) ) {
2005-07-10 19:58:15 +01:00
printk ( KERN_ERR " mcbsp: could not acquire api_ck handle. \n " ) ;
return PTR_ERR ( mcbsp_api_ck ) ;
}
2005-07-10 19:58:18 +01:00
mcbsp_dspxor_ck = clk_get ( 0 , " dspxor_ck " ) ;
if ( IS_ERR ( mcbsp_dspxor_ck ) ) {
printk ( KERN_ERR " mcbsp: could not acquire dspxor_ck handle. \n " ) ;
return PTR_ERR ( mcbsp_dspxor_ck ) ;
}
2005-07-10 19:58:15 +01:00
# ifdef CONFIG_ARCH_OMAP730
if ( cpu_is_omap730 ( ) ) {
mcbsp_info = mcbsp_730 ;
mcbsp_count = ARRAY_SIZE ( mcbsp_730 ) ;
}
# endif
# ifdef CONFIG_ARCH_OMAP1510
if ( cpu_is_omap1510 ( ) ) {
mcbsp_info = mcbsp_1510 ;
mcbsp_count = ARRAY_SIZE ( mcbsp_1510 ) ;
}
# endif
# if defined(CONFIG_ARCH_OMAP16XX)
2005-07-10 19:58:18 +01:00
if ( cpu_is_omap16xx ( ) ) {
2005-07-10 19:58:15 +01:00
mcbsp_info = mcbsp_1610 ;
mcbsp_count = ARRAY_SIZE ( mcbsp_1610 ) ;
}
# endif
for ( i = 0 ; i < OMAP_MAX_MCBSP_COUNT ; i + + ) {
if ( i > = mcbsp_count ) {
mcbsp [ i ] . io_base = 0 ;
mcbsp [ i ] . free = 0 ;
continue ;
}
mcbsp [ i ] . id = i + 1 ;
mcbsp [ i ] . free = 1 ;
mcbsp [ i ] . dma_tx_lch = - 1 ;
mcbsp [ i ] . dma_rx_lch = - 1 ;
mcbsp [ i ] . io_base = mcbsp_info [ i ] . virt_base ;
mcbsp [ i ] . tx_irq = mcbsp_info [ i ] . tx_irq ;
mcbsp [ i ] . rx_irq = mcbsp_info [ i ] . rx_irq ;
mcbsp [ i ] . dma_rx_sync = mcbsp_info [ i ] . dma_rx_sync ;
mcbsp [ i ] . dma_tx_sync = mcbsp_info [ i ] . dma_tx_sync ;
spin_lock_init ( & mcbsp [ i ] . lock ) ;
}
return 0 ;
}
arch_initcall ( omap_mcbsp_init ) ;
EXPORT_SYMBOL ( omap_mcbsp_config ) ;
EXPORT_SYMBOL ( omap_mcbsp_request ) ;
EXPORT_SYMBOL ( omap_mcbsp_free ) ;
EXPORT_SYMBOL ( omap_mcbsp_start ) ;
EXPORT_SYMBOL ( omap_mcbsp_stop ) ;
EXPORT_SYMBOL ( omap_mcbsp_xmit_word ) ;
EXPORT_SYMBOL ( omap_mcbsp_recv_word ) ;
EXPORT_SYMBOL ( omap_mcbsp_xmit_buffer ) ;
EXPORT_SYMBOL ( omap_mcbsp_recv_buffer ) ;
EXPORT_SYMBOL ( omap_mcbsp_set_spi_mode ) ;