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>
2008-07-03 12:24:39 +03:00
# include <linux/platform_device.h>
2005-07-10 19:58:15 +01:00
# include <linux/wait.h>
# include <linux/completion.h>
# include <linux/interrupt.h>
# include <linux/err.h>
2006-01-07 16:15:52 +00:00
# include <linux/clk.h>
2007-02-12 10:50:53 -08:00
# include <linux/delay.h>
2008-07-03 12:24:39 +03:00
# include <linux/io.h>
2005-07-10 19:58:15 +01:00
2008-08-05 16:14:15 +01:00
# include <mach/dma.h>
# include <mach/mcbsp.h>
2005-07-10 19:58:15 +01:00
2008-10-08 10:01:39 +03:00
struct omap_mcbsp * * mcbsp_ptr ;
int omap_mcbsp_count ;
2008-07-03 12:24:39 +03:00
2008-10-08 10:01:39 +03:00
void omap_mcbsp_write ( void __iomem * io_base , u16 reg , u32 val )
{
if ( cpu_class_is_omap1 ( ) | | cpu_is_omap2420 ( ) )
__raw_writew ( ( u16 ) val , io_base + reg ) ;
else
__raw_writel ( val , io_base + reg ) ;
}
int omap_mcbsp_read ( void __iomem * io_base , u16 reg )
{
if ( cpu_class_is_omap1 ( ) | | cpu_is_omap2420 ( ) )
return __raw_readw ( io_base + reg ) ;
else
return __raw_readl ( io_base + reg ) ;
}
# 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 )
# define omap_mcbsp_check_valid_id(id) (id < omap_mcbsp_count)
# define id_to_mcbsp_ptr(id) mcbsp_ptr[id];
2005-07-10 19:58:15 +01:00
static void omap_mcbsp_dump_reg ( u8 id )
{
2008-10-08 10:01:39 +03:00
struct omap_mcbsp * mcbsp = id_to_mcbsp_ptr ( id ) ;
dev_dbg ( mcbsp - > dev , " **** McBSP%d regs **** \n " , mcbsp - > id ) ;
dev_dbg ( mcbsp - > dev , " DRR2: 0x%04x \n " ,
OMAP_MCBSP_READ ( mcbsp - > io_base , DRR2 ) ) ;
dev_dbg ( mcbsp - > dev , " DRR1: 0x%04x \n " ,
OMAP_MCBSP_READ ( mcbsp - > io_base , DRR1 ) ) ;
dev_dbg ( mcbsp - > dev , " DXR2: 0x%04x \n " ,
OMAP_MCBSP_READ ( mcbsp - > io_base , DXR2 ) ) ;
dev_dbg ( mcbsp - > dev , " DXR1: 0x%04x \n " ,
OMAP_MCBSP_READ ( mcbsp - > io_base , DXR1 ) ) ;
dev_dbg ( mcbsp - > dev , " SPCR2: 0x%04x \n " ,
OMAP_MCBSP_READ ( mcbsp - > io_base , SPCR2 ) ) ;
dev_dbg ( mcbsp - > dev , " SPCR1: 0x%04x \n " ,
OMAP_MCBSP_READ ( mcbsp - > io_base , SPCR1 ) ) ;
dev_dbg ( mcbsp - > dev , " RCR2: 0x%04x \n " ,
OMAP_MCBSP_READ ( mcbsp - > io_base , RCR2 ) ) ;
dev_dbg ( mcbsp - > dev , " RCR1: 0x%04x \n " ,
OMAP_MCBSP_READ ( mcbsp - > io_base , RCR1 ) ) ;
dev_dbg ( mcbsp - > dev , " XCR2: 0x%04x \n " ,
OMAP_MCBSP_READ ( mcbsp - > io_base , XCR2 ) ) ;
dev_dbg ( mcbsp - > dev , " XCR1: 0x%04x \n " ,
OMAP_MCBSP_READ ( mcbsp - > io_base , XCR1 ) ) ;
dev_dbg ( mcbsp - > dev , " SRGR2: 0x%04x \n " ,
OMAP_MCBSP_READ ( mcbsp - > io_base , SRGR2 ) ) ;
dev_dbg ( mcbsp - > dev , " SRGR1: 0x%04x \n " ,
OMAP_MCBSP_READ ( mcbsp - > io_base , SRGR1 ) ) ;
dev_dbg ( mcbsp - > dev , " PCR0: 0x%04x \n " ,
OMAP_MCBSP_READ ( mcbsp - > io_base , PCR0 ) ) ;
dev_dbg ( mcbsp - > dev , " *********************** \n " ) ;
2005-07-10 19:58:15 +01:00
}
2006-10-06 10:53:39 -07:00
static irqreturn_t omap_mcbsp_tx_irq_handler ( int irq , void * dev_id )
2005-07-10 19:58:15 +01:00
{
2007-10-26 05:40:25 -04:00
struct omap_mcbsp * mcbsp_tx = dev_id ;
2009-05-25 11:08:42 -07:00
u16 irqst_spcr2 ;
2005-07-10 19:58:15 +01:00
2009-05-25 11:08:42 -07:00
irqst_spcr2 = OMAP_MCBSP_READ ( mcbsp_tx - > io_base , SPCR2 ) ;
dev_dbg ( mcbsp_tx - > dev , " TX IRQ callback : 0x%x \n " , irqst_spcr2 ) ;
2005-07-10 19:58:15 +01:00
2009-05-25 11:08:42 -07:00
if ( irqst_spcr2 & XSYNC_ERR ) {
dev_err ( mcbsp_tx - > dev , " TX Frame Sync Error! : 0x%x \n " ,
irqst_spcr2 ) ;
/* Writing zero to XSYNC_ERR clears the IRQ */
OMAP_MCBSP_WRITE ( mcbsp_tx - > io_base , SPCR2 ,
irqst_spcr2 & ~ ( XSYNC_ERR ) ) ;
} else {
complete ( & mcbsp_tx - > tx_irq_completion ) ;
}
2008-07-03 12:24:39 +03:00
2005-07-10 19:58:15 +01:00
return IRQ_HANDLED ;
}
2006-10-06 10:53:39 -07:00
static irqreturn_t omap_mcbsp_rx_irq_handler ( int irq , void * dev_id )
2005-07-10 19:58:15 +01:00
{
2007-10-26 05:40:25 -04:00
struct omap_mcbsp * mcbsp_rx = dev_id ;
2009-05-25 11:08:42 -07:00
u16 irqst_spcr1 ;
irqst_spcr1 = OMAP_MCBSP_READ ( mcbsp_rx - > io_base , SPCR1 ) ;
dev_dbg ( mcbsp_rx - > dev , " RX IRQ callback : 0x%x \n " , irqst_spcr1 ) ;
if ( irqst_spcr1 & RSYNC_ERR ) {
dev_err ( mcbsp_rx - > dev , " RX Frame Sync Error! : 0x%x \n " ,
irqst_spcr1 ) ;
/* Writing zero to RSYNC_ERR clears the IRQ */
OMAP_MCBSP_WRITE ( mcbsp_rx - > io_base , SPCR1 ,
irqst_spcr1 & ~ ( RSYNC_ERR ) ) ;
} else {
complete ( & mcbsp_rx - > tx_irq_completion ) ;
}
2008-07-03 12:24:39 +03:00
2005-07-10 19:58:15 +01:00
return IRQ_HANDLED ;
}
static void omap_mcbsp_tx_dma_callback ( int lch , u16 ch_status , void * data )
{
2007-10-26 05:40:25 -04:00
struct omap_mcbsp * mcbsp_dma_tx = data ;
2005-07-10 19:58:15 +01:00
2008-07-03 12:24:39 +03:00
dev_dbg ( mcbsp_dma_tx - > dev , " TX DMA callback : 0x%x \n " ,
OMAP_MCBSP_READ ( mcbsp_dma_tx - > io_base , SPCR2 ) ) ;
2005-07-10 19:58:15 +01:00
/* 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 )
{
2007-10-26 05:40:25 -04:00
struct omap_mcbsp * mcbsp_dma_rx = data ;
2005-07-10 19:58:15 +01:00
2008-07-03 12:24:39 +03:00
dev_dbg ( mcbsp_dma_rx - > dev , " RX DMA callback : 0x%x \n " ,
OMAP_MCBSP_READ ( mcbsp_dma_rx - > io_base , SPCR2 ) ) ;
2005-07-10 19:58:15 +01:00
/* 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 ( ) .
*/
2008-07-03 12:24:39 +03:00
void omap_mcbsp_config ( unsigned int id , const struct omap_mcbsp_reg_cfg * config )
2005-07-10 19:58:15 +01:00
{
2008-10-08 10:01:39 +03:00
struct omap_mcbsp * mcbsp ;
2008-09-04 14:25:42 +01:00
void __iomem * io_base ;
2005-07-10 19:58:15 +01:00
2008-07-03 12:24:39 +03:00
if ( ! omap_mcbsp_check_valid_id ( id ) ) {
printk ( KERN_ERR " %s: Invalid id (%d) \n " , __func__ , id + 1 ) ;
return ;
}
2008-10-08 10:01:39 +03:00
mcbsp = id_to_mcbsp_ptr ( id ) ;
2008-07-03 12:24:39 +03:00
2008-10-08 10:01:39 +03:00
io_base = mcbsp - > io_base ;
dev_dbg ( mcbsp - > dev , " Configuring McBSP%d phys_base: 0x%08lx \n " ,
mcbsp - > id , mcbsp - > phys_base ) ;
2005-07-10 19:58:15 +01:00
/* 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 ) ;
2009-01-15 13:09:54 +02:00
if ( cpu_is_omap2430 ( ) | | cpu_is_omap34xx ( ) ) {
OMAP_MCBSP_WRITE ( io_base , XCCR , config - > xccr ) ;
OMAP_MCBSP_WRITE ( io_base , RCCR , config - > rccr ) ;
}
2005-07-10 19:58:15 +01:00
}
2008-07-03 12:24:39 +03:00
EXPORT_SYMBOL ( omap_mcbsp_config ) ;
2005-07-10 19:58:15 +01:00
2006-04-02 17:46:27 +01:00
/*
* We can choose between IRQ based or polled IO .
* This needs to be called before omap_mcbsp_request ( ) .
*/
int omap_mcbsp_set_io_type ( unsigned int id , omap_mcbsp_io_type_t io_type )
{
2008-10-08 10:01:39 +03:00
struct omap_mcbsp * mcbsp ;
2008-07-03 12:24:39 +03:00
if ( ! omap_mcbsp_check_valid_id ( id ) ) {
printk ( KERN_ERR " %s: Invalid id (%d) \n " , __func__ , id + 1 ) ;
return - ENODEV ;
}
2008-10-08 10:01:39 +03:00
mcbsp = id_to_mcbsp_ptr ( id ) ;
2006-04-02 17:46:27 +01:00
2008-10-08 10:01:39 +03:00
spin_lock ( & mcbsp - > lock ) ;
2006-04-02 17:46:27 +01:00
2008-10-08 10:01:39 +03:00
if ( ! mcbsp - > free ) {
dev_err ( mcbsp - > dev , " McBSP%d is currently in use \n " ,
mcbsp - > id ) ;
spin_unlock ( & mcbsp - > lock ) ;
2006-04-02 17:46:27 +01:00
return - EINVAL ;
}
2008-10-08 10:01:39 +03:00
mcbsp - > io_type = io_type ;
2006-04-02 17:46:27 +01:00
2008-10-08 10:01:39 +03:00
spin_unlock ( & mcbsp - > lock ) ;
2006-04-02 17:46:27 +01:00
return 0 ;
}
2008-07-03 12:24:39 +03:00
EXPORT_SYMBOL ( omap_mcbsp_set_io_type ) ;
2005-07-10 19:58:15 +01:00
int omap_mcbsp_request ( unsigned int id )
{
2008-10-08 10:01:39 +03:00
struct omap_mcbsp * mcbsp ;
2005-07-10 19:58:15 +01:00
int err ;
2008-07-03 12:24:39 +03:00
if ( ! omap_mcbsp_check_valid_id ( id ) ) {
printk ( KERN_ERR " %s: Invalid id (%d) \n " , __func__ , id + 1 ) ;
return - ENODEV ;
2006-04-02 17:46:27 +01:00
}
2008-10-08 10:01:39 +03:00
mcbsp = id_to_mcbsp_ptr ( id ) ;
2008-07-03 12:24:39 +03:00
2008-10-08 10:01:39 +03:00
spin_lock ( & mcbsp - > lock ) ;
if ( ! mcbsp - > free ) {
dev_err ( mcbsp - > dev , " McBSP%d is currently in use \n " ,
mcbsp - > id ) ;
spin_unlock ( & mcbsp - > lock ) ;
2009-01-23 10:26:46 +00:00
return - EBUSY ;
2005-07-10 19:58:15 +01:00
}
2008-10-08 10:01:39 +03:00
mcbsp - > free = 0 ;
spin_unlock ( & mcbsp - > lock ) ;
2005-07-10 19:58:15 +01:00
2009-01-23 10:26:46 +00:00
if ( mcbsp - > pdata & & mcbsp - > pdata - > ops & & mcbsp - > pdata - > ops - > request )
mcbsp - > pdata - > ops - > request ( id ) ;
clk_enable ( mcbsp - > iclk ) ;
clk_enable ( mcbsp - > fclk ) ;
2008-10-08 10:01:41 +03:00
/*
* Make sure that transmitter , receiver and sample - rate generator are
* not running before activating IRQs .
*/
OMAP_MCBSP_WRITE ( mcbsp - > io_base , SPCR1 , 0 ) ;
OMAP_MCBSP_WRITE ( mcbsp - > io_base , SPCR2 , 0 ) ;
2008-10-08 10:01:39 +03:00
if ( mcbsp - > io_type = = OMAP_MCBSP_IRQ_IO ) {
2006-04-02 17:46:27 +01:00
/* We need to get IRQs here */
2008-10-08 10:01:41 +03:00
init_completion ( & mcbsp - > tx_irq_completion ) ;
2008-10-08 10:01:39 +03:00
err = request_irq ( mcbsp - > tx_irq , omap_mcbsp_tx_irq_handler ,
0 , " McBSP " , ( void * ) mcbsp ) ;
2006-04-02 17:46:27 +01:00
if ( err ! = 0 ) {
2008-10-08 10:01:39 +03:00
dev_err ( mcbsp - > dev , " Unable to request TX IRQ %d "
" for McBSP%d \n " , mcbsp - > tx_irq ,
mcbsp - > id ) ;
2006-04-02 17:46:27 +01:00
return err ;
}
2005-07-10 19:58:15 +01:00
2008-10-08 10:01:41 +03:00
init_completion ( & mcbsp - > rx_irq_completion ) ;
2008-10-08 10:01:39 +03:00
err = request_irq ( mcbsp - > rx_irq , omap_mcbsp_rx_irq_handler ,
0 , " McBSP " , ( void * ) mcbsp ) ;
2006-04-02 17:46:27 +01:00
if ( err ! = 0 ) {
2008-10-08 10:01:39 +03:00
dev_err ( mcbsp - > dev , " Unable to request RX IRQ %d "
" for McBSP%d \n " , mcbsp - > rx_irq ,
mcbsp - > id ) ;
free_irq ( mcbsp - > tx_irq , ( void * ) mcbsp ) ;
2006-04-02 17:46:27 +01:00
return err ;
}
2005-07-10 19:58:15 +01:00
}
return 0 ;
}
2008-07-03 12:24:39 +03:00
EXPORT_SYMBOL ( omap_mcbsp_request ) ;
2005-07-10 19:58:15 +01:00
void omap_mcbsp_free ( unsigned int id )
{
2008-10-08 10:01:39 +03:00
struct omap_mcbsp * mcbsp ;
2008-07-03 12:24:39 +03:00
if ( ! omap_mcbsp_check_valid_id ( id ) ) {
printk ( KERN_ERR " %s: Invalid id (%d) \n " , __func__ , id + 1 ) ;
2005-07-10 19:58:15 +01:00
return ;
2006-04-02 17:46:27 +01:00
}
2008-10-08 10:01:39 +03:00
mcbsp = id_to_mcbsp_ptr ( id ) ;
2008-07-03 12:24:39 +03:00
2008-10-08 10:01:39 +03:00
if ( mcbsp - > pdata & & mcbsp - > pdata - > ops & & mcbsp - > pdata - > ops - > free )
mcbsp - > pdata - > ops - > free ( id ) ;
2008-07-03 12:24:39 +03:00
2009-01-23 10:26:46 +00:00
clk_disable ( mcbsp - > fclk ) ;
clk_disable ( mcbsp - > iclk ) ;
if ( mcbsp - > io_type = = OMAP_MCBSP_IRQ_IO ) {
/* Free IRQs */
free_irq ( mcbsp - > rx_irq , ( void * ) mcbsp ) ;
free_irq ( mcbsp - > tx_irq , ( void * ) mcbsp ) ;
}
2005-07-10 19:58:15 +01:00
2008-10-08 10:01:39 +03:00
spin_lock ( & mcbsp - > lock ) ;
if ( mcbsp - > free ) {
dev_err ( mcbsp - > dev , " McBSP%d was not reserved \n " ,
mcbsp - > id ) ;
spin_unlock ( & mcbsp - > lock ) ;
2005-07-10 19:58:15 +01:00
return ;
}
2008-10-08 10:01:39 +03:00
mcbsp - > free = 1 ;
spin_unlock ( & mcbsp - > lock ) ;
2005-07-10 19:58:15 +01:00
}
2008-07-03 12:24:39 +03:00
EXPORT_SYMBOL ( omap_mcbsp_free ) ;
2005-07-10 19:58:15 +01:00
/*
* 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 )
{
2008-10-08 10:01:39 +03:00
struct omap_mcbsp * mcbsp ;
2008-09-04 14:25:42 +01:00
void __iomem * io_base ;
2005-07-10 19:58:15 +01:00
u16 w ;
2008-07-03 12:24:39 +03:00
if ( ! omap_mcbsp_check_valid_id ( id ) ) {
printk ( KERN_ERR " %s: Invalid id (%d) \n " , __func__ , id + 1 ) ;
2005-07-10 19:58:15 +01:00
return ;
2008-07-03 12:24:39 +03:00
}
2008-10-08 10:01:39 +03:00
mcbsp = id_to_mcbsp_ptr ( id ) ;
io_base = mcbsp - > io_base ;
2005-07-10 19:58:15 +01:00
2008-10-08 10:01:39 +03:00
mcbsp - > rx_word_length = ( OMAP_MCBSP_READ ( io_base , RCR1 ) > > 5 ) & 0x7 ;
mcbsp - > tx_word_length = ( OMAP_MCBSP_READ ( io_base , XCR1 ) > > 5 ) & 0x7 ;
2005-07-10 19:58:15 +01:00
/* 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 ) ;
}
2008-07-03 12:24:39 +03:00
EXPORT_SYMBOL ( omap_mcbsp_start ) ;
2005-07-10 19:58:15 +01:00
void omap_mcbsp_stop ( unsigned int id )
{
2008-10-08 10:01:39 +03:00
struct omap_mcbsp * mcbsp ;
2008-09-04 14:25:42 +01:00
void __iomem * io_base ;
2005-07-10 19:58:15 +01:00
u16 w ;
2008-07-03 12:24:39 +03:00
if ( ! omap_mcbsp_check_valid_id ( id ) ) {
printk ( KERN_ERR " %s: Invalid id (%d) \n " , __func__ , id + 1 ) ;
2005-07-10 19:58:15 +01:00
return ;
2008-07-03 12:24:39 +03:00
}
2005-07-10 19:58:15 +01:00
2008-10-08 10:01:39 +03:00
mcbsp = id_to_mcbsp_ptr ( id ) ;
io_base = mcbsp - > io_base ;
2005-07-10 19:58:15 +01:00
2008-07-03 12:24:39 +03:00
/* Reset transmitter */
2005-07-10 19:58:15 +01:00
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 ) ) ;
}
2008-07-03 12:24:39 +03:00
EXPORT_SYMBOL ( omap_mcbsp_stop ) ;
2005-07-10 19:58:15 +01:00
2005-07-10 19:58:18 +01:00
/* polled mcbsp i/o operations */
int omap_mcbsp_pollwrite ( unsigned int id , u16 buf )
{
2008-10-08 10:01:39 +03:00
struct omap_mcbsp * mcbsp ;
2008-09-04 14:25:42 +01:00
void __iomem * base ;
2008-07-03 12:24:39 +03:00
if ( ! omap_mcbsp_check_valid_id ( id ) ) {
printk ( KERN_ERR " %s: Invalid id (%d) \n " , __func__ , id + 1 ) ;
return - ENODEV ;
}
2008-10-08 10:01:39 +03:00
mcbsp = id_to_mcbsp_ptr ( id ) ;
base = mcbsp - > io_base ;
2005-07-10 19:58:18 +01:00
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 ) ;
2008-10-08 10:01:39 +03:00
dev_err ( mcbsp - > dev , " Could not write to "
" McBSP%d Register \n " , mcbsp - > id ) ;
2005-07-10 19:58:18 +01:00
return - 2 ;
}
}
}
2008-07-03 12:24:39 +03:00
2005-07-10 19:58:18 +01:00
return 0 ;
}
2008-07-03 12:24:39 +03:00
EXPORT_SYMBOL ( omap_mcbsp_pollwrite ) ;
2005-07-10 19:58:18 +01:00
2008-07-03 12:24:39 +03:00
int omap_mcbsp_pollread ( unsigned int id , u16 * buf )
2005-07-10 19:58:18 +01:00
{
2008-10-08 10:01:39 +03:00
struct omap_mcbsp * mcbsp ;
2008-09-04 14:25:42 +01:00
void __iomem * base ;
2008-07-03 12:24:39 +03:00
if ( ! omap_mcbsp_check_valid_id ( id ) ) {
printk ( KERN_ERR " %s: Invalid id (%d) \n " , __func__ , id + 1 ) ;
return - ENODEV ;
}
2008-10-08 10:01:39 +03:00
mcbsp = id_to_mcbsp_ptr ( id ) ;
2008-07-03 12:24:39 +03:00
2008-10-08 10:01:39 +03:00
base = mcbsp - > io_base ;
2005-07-10 19:58:18 +01:00
/* 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 ) ;
2008-10-08 10:01:39 +03:00
dev_err ( mcbsp - > dev , " Could not read from "
" McBSP%d Register \n " , mcbsp - > id ) ;
2005-07-10 19:58:18 +01:00
return - 2 ;
}
}
}
* buf = readw ( base + OMAP_MCBSP_REG_DRR1 ) ;
2008-07-03 12:24:39 +03:00
2005-07-10 19:58:18 +01:00
return 0 ;
}
2008-07-03 12:24:39 +03:00
EXPORT_SYMBOL ( omap_mcbsp_pollread ) ;
2005-07-10 19:58:18 +01:00
2005-07-10 19:58:15 +01:00
/*
* IRQ based word transmission .
*/
void omap_mcbsp_xmit_word ( unsigned int id , u32 word )
{
2008-10-08 10:01:39 +03:00
struct omap_mcbsp * mcbsp ;
2008-09-04 14:25:42 +01:00
void __iomem * io_base ;
2008-07-03 12:24:39 +03:00
omap_mcbsp_word_length word_length ;
2005-07-10 19:58:15 +01:00
2008-07-03 12:24:39 +03:00
if ( ! omap_mcbsp_check_valid_id ( id ) ) {
printk ( KERN_ERR " %s: Invalid id (%d) \n " , __func__ , id + 1 ) ;
2005-07-10 19:58:15 +01:00
return ;
2008-07-03 12:24:39 +03:00
}
2005-07-10 19:58:15 +01:00
2008-10-08 10:01:39 +03:00
mcbsp = id_to_mcbsp_ptr ( id ) ;
io_base = mcbsp - > io_base ;
word_length = mcbsp - > tx_word_length ;
2005-07-10 19:58:15 +01:00
2008-10-08 10:01:39 +03:00
wait_for_completion ( & mcbsp - > tx_irq_completion ) ;
2005-07-10 19:58:15 +01:00
if ( word_length > OMAP_MCBSP_WORD_16 )
OMAP_MCBSP_WRITE ( io_base , DXR2 , word > > 16 ) ;
OMAP_MCBSP_WRITE ( io_base , DXR1 , word & 0xffff ) ;
}
2008-07-03 12:24:39 +03:00
EXPORT_SYMBOL ( omap_mcbsp_xmit_word ) ;
2005-07-10 19:58:15 +01:00
u32 omap_mcbsp_recv_word ( unsigned int id )
{
2008-10-08 10:01:39 +03:00
struct omap_mcbsp * mcbsp ;
2008-09-04 14:25:42 +01:00
void __iomem * io_base ;
2005-07-10 19:58:15 +01:00
u16 word_lsb , word_msb = 0 ;
2008-07-03 12:24:39 +03:00
omap_mcbsp_word_length word_length ;
2005-07-10 19:58:15 +01:00
2008-07-03 12:24:39 +03:00
if ( ! omap_mcbsp_check_valid_id ( id ) ) {
printk ( KERN_ERR " %s: Invalid id (%d) \n " , __func__ , id + 1 ) ;
return - ENODEV ;
}
2008-10-08 10:01:39 +03:00
mcbsp = id_to_mcbsp_ptr ( id ) ;
2005-07-10 19:58:15 +01:00
2008-10-08 10:01:39 +03:00
word_length = mcbsp - > rx_word_length ;
io_base = mcbsp - > io_base ;
2005-07-10 19:58:15 +01:00
2008-10-08 10:01:39 +03:00
wait_for_completion ( & mcbsp - > rx_irq_completion ) ;
2005-07-10 19:58:15 +01:00
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 ) ) ;
}
2008-07-03 12:24:39 +03:00
EXPORT_SYMBOL ( omap_mcbsp_recv_word ) ;
2005-07-10 19:58:15 +01:00
2006-04-02 17:46:27 +01:00
int omap_mcbsp_spi_master_xmit_word_poll ( unsigned int id , u32 word )
{
2008-10-08 10:01:39 +03:00
struct omap_mcbsp * mcbsp ;
2008-09-04 14:25:42 +01:00
void __iomem * io_base ;
2008-07-03 12:24:39 +03:00
omap_mcbsp_word_length tx_word_length ;
omap_mcbsp_word_length rx_word_length ;
2006-04-02 17:46:27 +01:00
u16 spcr2 , spcr1 , attempts = 0 , word_lsb , word_msb = 0 ;
2008-07-03 12:24:39 +03:00
if ( ! omap_mcbsp_check_valid_id ( id ) ) {
printk ( KERN_ERR " %s: Invalid id (%d) \n " , __func__ , id + 1 ) ;
return - ENODEV ;
}
2008-10-08 10:01:39 +03:00
mcbsp = id_to_mcbsp_ptr ( id ) ;
io_base = mcbsp - > io_base ;
tx_word_length = mcbsp - > tx_word_length ;
rx_word_length = mcbsp - > rx_word_length ;
2008-07-03 12:24:39 +03:00
2006-04-02 17:46:27 +01:00
if ( tx_word_length ! = rx_word_length )
return - EINVAL ;
/* First we wait for the transmitter to be ready */
spcr2 = OMAP_MCBSP_READ ( io_base , SPCR2 ) ;
while ( ! ( spcr2 & XRDY ) ) {
spcr2 = OMAP_MCBSP_READ ( io_base , SPCR2 ) ;
if ( attempts + + > 1000 ) {
/* We must reset the transmitter */
OMAP_MCBSP_WRITE ( io_base , SPCR2 , spcr2 & ( ~ XRST ) ) ;
udelay ( 10 ) ;
OMAP_MCBSP_WRITE ( io_base , SPCR2 , spcr2 | XRST ) ;
udelay ( 10 ) ;
2008-10-08 10:01:39 +03:00
dev_err ( mcbsp - > dev , " McBSP%d transmitter not "
" ready \n " , mcbsp - > id ) ;
2006-04-02 17:46:27 +01:00
return - EAGAIN ;
}
}
/* Now we can push the data */
if ( tx_word_length > OMAP_MCBSP_WORD_16 )
OMAP_MCBSP_WRITE ( io_base , DXR2 , word > > 16 ) ;
OMAP_MCBSP_WRITE ( io_base , DXR1 , word & 0xffff ) ;
/* We wait for the receiver to be ready */
spcr1 = OMAP_MCBSP_READ ( io_base , SPCR1 ) ;
while ( ! ( spcr1 & RRDY ) ) {
spcr1 = OMAP_MCBSP_READ ( io_base , SPCR1 ) ;
if ( attempts + + > 1000 ) {
/* We must reset the receiver */
OMAP_MCBSP_WRITE ( io_base , SPCR1 , spcr1 & ( ~ RRST ) ) ;
udelay ( 10 ) ;
OMAP_MCBSP_WRITE ( io_base , SPCR1 , spcr1 | RRST ) ;
udelay ( 10 ) ;
2008-10-08 10:01:39 +03:00
dev_err ( mcbsp - > dev , " McBSP%d receiver not "
" ready \n " , mcbsp - > id ) ;
2006-04-02 17:46:27 +01:00
return - EAGAIN ;
}
}
/* Receiver is ready, let's read the dummy data */
if ( rx_word_length > OMAP_MCBSP_WORD_16 )
word_msb = OMAP_MCBSP_READ ( io_base , DRR2 ) ;
word_lsb = OMAP_MCBSP_READ ( io_base , DRR1 ) ;
return 0 ;
}
2008-07-03 12:24:39 +03:00
EXPORT_SYMBOL ( omap_mcbsp_spi_master_xmit_word_poll ) ;
2006-04-02 17:46:27 +01:00
2008-07-03 12:24:39 +03:00
int omap_mcbsp_spi_master_recv_word_poll ( unsigned int id , u32 * word )
2006-04-02 17:46:27 +01:00
{
2008-10-08 10:01:39 +03:00
struct omap_mcbsp * mcbsp ;
2008-09-04 14:25:42 +01:00
u32 clock_word = 0 ;
void __iomem * io_base ;
2008-07-03 12:24:39 +03:00
omap_mcbsp_word_length tx_word_length ;
omap_mcbsp_word_length rx_word_length ;
2006-04-02 17:46:27 +01:00
u16 spcr2 , spcr1 , attempts = 0 , word_lsb , word_msb = 0 ;
2008-07-03 12:24:39 +03:00
if ( ! omap_mcbsp_check_valid_id ( id ) ) {
printk ( KERN_ERR " %s: Invalid id (%d) \n " , __func__ , id + 1 ) ;
return - ENODEV ;
}
2008-10-08 10:01:39 +03:00
mcbsp = id_to_mcbsp_ptr ( id ) ;
io_base = mcbsp - > io_base ;
tx_word_length = mcbsp - > tx_word_length ;
rx_word_length = mcbsp - > rx_word_length ;
2008-07-03 12:24:39 +03:00
2006-04-02 17:46:27 +01:00
if ( tx_word_length ! = rx_word_length )
return - EINVAL ;
/* First we wait for the transmitter to be ready */
spcr2 = OMAP_MCBSP_READ ( io_base , SPCR2 ) ;
while ( ! ( spcr2 & XRDY ) ) {
spcr2 = OMAP_MCBSP_READ ( io_base , SPCR2 ) ;
if ( attempts + + > 1000 ) {
/* We must reset the transmitter */
OMAP_MCBSP_WRITE ( io_base , SPCR2 , spcr2 & ( ~ XRST ) ) ;
udelay ( 10 ) ;
OMAP_MCBSP_WRITE ( io_base , SPCR2 , spcr2 | XRST ) ;
udelay ( 10 ) ;
2008-10-08 10:01:39 +03:00
dev_err ( mcbsp - > dev , " McBSP%d transmitter not "
" ready \n " , mcbsp - > id ) ;
2006-04-02 17:46:27 +01:00
return - EAGAIN ;
}
}
/* We first need to enable the bus clock */
if ( tx_word_length > OMAP_MCBSP_WORD_16 )
OMAP_MCBSP_WRITE ( io_base , DXR2 , clock_word > > 16 ) ;
OMAP_MCBSP_WRITE ( io_base , DXR1 , clock_word & 0xffff ) ;
/* We wait for the receiver to be ready */
spcr1 = OMAP_MCBSP_READ ( io_base , SPCR1 ) ;
while ( ! ( spcr1 & RRDY ) ) {
spcr1 = OMAP_MCBSP_READ ( io_base , SPCR1 ) ;
if ( attempts + + > 1000 ) {
/* We must reset the receiver */
OMAP_MCBSP_WRITE ( io_base , SPCR1 , spcr1 & ( ~ RRST ) ) ;
udelay ( 10 ) ;
OMAP_MCBSP_WRITE ( io_base , SPCR1 , spcr1 | RRST ) ;
udelay ( 10 ) ;
2008-10-08 10:01:39 +03:00
dev_err ( mcbsp - > dev , " McBSP%d receiver not "
" ready \n " , mcbsp - > id ) ;
2006-04-02 17:46:27 +01:00
return - EAGAIN ;
}
}
/* Receiver is ready, there is something for us */
if ( rx_word_length > OMAP_MCBSP_WORD_16 )
word_msb = OMAP_MCBSP_READ ( io_base , DRR2 ) ;
word_lsb = OMAP_MCBSP_READ ( io_base , DRR1 ) ;
word [ 0 ] = ( word_lsb | ( word_msb < < 16 ) ) ;
return 0 ;
}
2008-07-03 12:24:39 +03:00
EXPORT_SYMBOL ( omap_mcbsp_spi_master_recv_word_poll ) ;
2006-04-02 17:46:27 +01:00
2005-07-10 19:58:15 +01:00
/*
* 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 .
*/
2008-07-03 12:24:39 +03:00
int omap_mcbsp_xmit_buffer ( unsigned int id , dma_addr_t buffer ,
unsigned int length )
2005-07-10 19:58:15 +01:00
{
2008-10-08 10:01:39 +03:00
struct omap_mcbsp * mcbsp ;
2005-07-10 19:58:15 +01:00
int dma_tx_ch ;
2006-04-02 17:46:27 +01:00
int src_port = 0 ;
int dest_port = 0 ;
int sync_dev = 0 ;
2005-07-10 19:58:15 +01:00
2008-07-03 12:24:39 +03:00
if ( ! omap_mcbsp_check_valid_id ( id ) ) {
printk ( KERN_ERR " %s: Invalid id (%d) \n " , __func__ , id + 1 ) ;
return - ENODEV ;
}
2008-10-08 10:01:39 +03:00
mcbsp = id_to_mcbsp_ptr ( id ) ;
2005-07-10 19:58:15 +01:00
2008-10-08 10:01:39 +03:00
if ( omap_request_dma ( mcbsp - > dma_tx_sync , " McBSP TX " ,
2008-07-03 12:24:39 +03:00
omap_mcbsp_tx_dma_callback ,
2008-10-08 10:01:39 +03:00
mcbsp ,
2008-07-03 12:24:39 +03:00
& dma_tx_ch ) ) {
2008-10-08 10:01:39 +03:00
dev_err ( mcbsp - > dev , " Unable to request DMA channel for "
2008-07-03 12:24:39 +03:00
" McBSP%d TX. Trying IRQ based TX \n " ,
2008-10-08 10:01:39 +03:00
mcbsp - > id ) ;
2005-07-10 19:58:15 +01:00
return - EAGAIN ;
}
2008-10-08 10:01:39 +03:00
mcbsp - > dma_tx_lch = dma_tx_ch ;
2005-07-10 19:58:15 +01:00
2008-10-08 10:01:39 +03:00
dev_err ( mcbsp - > dev , " McBSP%d TX DMA on channel %d \n " , mcbsp - > id ,
2008-07-03 12:24:39 +03:00
dma_tx_ch ) ;
2005-07-10 19:58:15 +01:00
2008-10-08 10:01:39 +03:00
init_completion ( & mcbsp - > tx_dma_completion ) ;
2005-07-10 19:58:15 +01:00
2006-04-02 17:46:27 +01:00
if ( cpu_class_is_omap1 ( ) ) {
src_port = OMAP_DMA_PORT_TIPB ;
dest_port = OMAP_DMA_PORT_EMIFF ;
}
2008-07-03 12:24:39 +03:00
if ( cpu_class_is_omap2 ( ) )
2008-10-08 10:01:39 +03:00
sync_dev = mcbsp - > dma_tx_sync ;
2006-04-02 17:46:27 +01:00
2008-10-08 10:01:39 +03:00
omap_set_dma_transfer_params ( mcbsp - > dma_tx_lch ,
2005-07-10 19:58:15 +01:00
OMAP_DMA_DATA_TYPE_S16 ,
length > > 1 , 1 ,
2005-11-10 14:26:50 +00:00
OMAP_DMA_SYNC_ELEMENT ,
2006-04-02 17:46:27 +01:00
sync_dev , 0 ) ;
2005-07-10 19:58:15 +01:00
2008-10-08 10:01:39 +03:00
omap_set_dma_dest_params ( mcbsp - > dma_tx_lch ,
2006-04-02 17:46:27 +01:00
src_port ,
2005-07-10 19:58:15 +01:00
OMAP_DMA_AMODE_CONSTANT ,
2008-10-08 10:01:39 +03:00
mcbsp - > phys_base + OMAP_MCBSP_REG_DXR1 ,
2005-11-10 14:26:50 +00:00
0 , 0 ) ;
2005-07-10 19:58:15 +01:00
2008-10-08 10:01:39 +03:00
omap_set_dma_src_params ( mcbsp - > dma_tx_lch ,
2006-04-02 17:46:27 +01:00
dest_port ,
2005-07-10 19:58:15 +01:00
OMAP_DMA_AMODE_POST_INC ,
2005-11-10 14:26:50 +00:00
buffer ,
0 , 0 ) ;
2005-07-10 19:58:15 +01:00
2008-10-08 10:01:39 +03:00
omap_start_dma ( mcbsp - > dma_tx_lch ) ;
wait_for_completion ( & mcbsp - > tx_dma_completion ) ;
2008-07-03 12:24:39 +03:00
2005-07-10 19:58:15 +01:00
return 0 ;
}
2008-07-03 12:24:39 +03:00
EXPORT_SYMBOL ( omap_mcbsp_xmit_buffer ) ;
2005-07-10 19:58:15 +01:00
2008-07-03 12:24:39 +03:00
int omap_mcbsp_recv_buffer ( unsigned int id , dma_addr_t buffer ,
unsigned int length )
2005-07-10 19:58:15 +01:00
{
2008-10-08 10:01:39 +03:00
struct omap_mcbsp * mcbsp ;
2005-07-10 19:58:15 +01:00
int dma_rx_ch ;
2006-04-02 17:46:27 +01:00
int src_port = 0 ;
int dest_port = 0 ;
int sync_dev = 0 ;
2005-07-10 19:58:15 +01:00
2008-07-03 12:24:39 +03:00
if ( ! omap_mcbsp_check_valid_id ( id ) ) {
printk ( KERN_ERR " %s: Invalid id (%d) \n " , __func__ , id + 1 ) ;
return - ENODEV ;
}
2008-10-08 10:01:39 +03:00
mcbsp = id_to_mcbsp_ptr ( id ) ;
2005-07-10 19:58:15 +01:00
2008-10-08 10:01:39 +03:00
if ( omap_request_dma ( mcbsp - > dma_rx_sync , " McBSP RX " ,
2008-07-03 12:24:39 +03:00
omap_mcbsp_rx_dma_callback ,
2008-10-08 10:01:39 +03:00
mcbsp ,
2008-07-03 12:24:39 +03:00
& dma_rx_ch ) ) {
2008-10-08 10:01:39 +03:00
dev_err ( mcbsp - > dev , " Unable to request DMA channel for "
2008-07-03 12:24:39 +03:00
" McBSP%d RX. Trying IRQ based RX \n " ,
2008-10-08 10:01:39 +03:00
mcbsp - > id ) ;
2005-07-10 19:58:15 +01:00
return - EAGAIN ;
}
2008-10-08 10:01:39 +03:00
mcbsp - > dma_rx_lch = dma_rx_ch ;
2005-07-10 19:58:15 +01:00
2008-10-08 10:01:39 +03:00
dev_err ( mcbsp - > dev , " McBSP%d RX DMA on channel %d \n " , mcbsp - > id ,
2008-07-03 12:24:39 +03:00
dma_rx_ch ) ;
2005-07-10 19:58:15 +01:00
2008-10-08 10:01:39 +03:00
init_completion ( & mcbsp - > rx_dma_completion ) ;
2005-07-10 19:58:15 +01:00
2006-04-02 17:46:27 +01:00
if ( cpu_class_is_omap1 ( ) ) {
src_port = OMAP_DMA_PORT_TIPB ;
dest_port = OMAP_DMA_PORT_EMIFF ;
}
2008-07-03 12:24:39 +03:00
if ( cpu_class_is_omap2 ( ) )
2008-10-08 10:01:39 +03:00
sync_dev = mcbsp - > dma_rx_sync ;
2006-04-02 17:46:27 +01:00
2008-10-08 10:01:39 +03:00
omap_set_dma_transfer_params ( mcbsp - > dma_rx_lch ,
2008-07-03 12:24:39 +03:00
OMAP_DMA_DATA_TYPE_S16 ,
length > > 1 , 1 ,
OMAP_DMA_SYNC_ELEMENT ,
sync_dev , 0 ) ;
2005-07-10 19:58:15 +01:00
2008-10-08 10:01:39 +03:00
omap_set_dma_src_params ( mcbsp - > dma_rx_lch ,
2006-04-02 17:46:27 +01:00
src_port ,
2005-07-10 19:58:15 +01:00
OMAP_DMA_AMODE_CONSTANT ,
2008-10-08 10:01:39 +03:00
mcbsp - > phys_base + OMAP_MCBSP_REG_DRR1 ,
2005-11-10 14:26:50 +00:00
0 , 0 ) ;
2005-07-10 19:58:15 +01:00
2008-10-08 10:01:39 +03:00
omap_set_dma_dest_params ( mcbsp - > dma_rx_lch ,
2008-07-03 12:24:39 +03:00
dest_port ,
OMAP_DMA_AMODE_POST_INC ,
buffer ,
0 , 0 ) ;
2005-07-10 19:58:15 +01:00
2008-10-08 10:01:39 +03:00
omap_start_dma ( mcbsp - > dma_rx_lch ) ;
wait_for_completion ( & mcbsp - > rx_dma_completion ) ;
2008-07-03 12:24:39 +03:00
2005-07-10 19:58:15 +01:00
return 0 ;
}
2008-07-03 12:24:39 +03:00
EXPORT_SYMBOL ( omap_mcbsp_recv_buffer ) ;
2005-07-10 19:58:15 +01:00
/*
* 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 ( ) .
*/
2008-07-03 12:24:39 +03:00
void omap_mcbsp_set_spi_mode ( unsigned int id ,
const struct omap_mcbsp_spi_cfg * spi_cfg )
2005-07-10 19:58:15 +01:00
{
2008-10-08 10:01:39 +03:00
struct omap_mcbsp * mcbsp ;
2005-07-10 19:58:15 +01:00
struct omap_mcbsp_reg_cfg mcbsp_cfg ;
2008-07-03 12:24:39 +03:00
if ( ! omap_mcbsp_check_valid_id ( id ) ) {
printk ( KERN_ERR " %s: Invalid id (%d) \n " , __func__ , id + 1 ) ;
2005-07-10 19:58:15 +01:00
return ;
2008-07-03 12:24:39 +03:00
}
2008-10-08 10:01:39 +03:00
mcbsp = id_to_mcbsp_ptr ( id ) ;
2005-07-10 19:58:15 +01:00
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 ) ) ;
2008-07-03 12:24:39 +03:00
/* Clock stop mode */
2005-07-10 19:58:15 +01:00
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 ;
2008-07-03 12:24:39 +03:00
mcbsp_cfg . srgr1 | = CLKGDV ( spi_cfg - > clk_div - 1 ) ;
2005-07-10 19:58:15 +01:00
mcbsp_cfg . pcr0 | = FSXM ;
mcbsp_cfg . srgr2 & = ~ FSGM ;
mcbsp_cfg . xcr2 | = XDATDLY ( 1 ) ;
mcbsp_cfg . rcr2 | = RDATDLY ( 1 ) ;
2008-07-03 12:24:39 +03:00
} else {
2005-07-10 19:58:15 +01:00
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 ) ;
}
2008-07-03 12:24:39 +03:00
EXPORT_SYMBOL ( omap_mcbsp_set_spi_mode ) ;
2005-07-10 19:58:15 +01:00
/*
* McBSP1 and McBSP3 are directly mapped on 1610 and 1510.
* 730 has only 2 McBSP , and both of them are MPU peripherals .
*/
2008-10-08 10:01:39 +03:00
static int __devinit omap_mcbsp_probe ( struct platform_device * pdev )
2008-07-03 12:24:39 +03:00
{
struct omap_mcbsp_platform_data * pdata = pdev - > dev . platform_data ;
2008-10-08 10:01:39 +03:00
struct omap_mcbsp * mcbsp ;
2008-07-03 12:24:39 +03:00
int id = pdev - > id - 1 ;
int ret = 0 ;
2005-07-10 19:58:15 +01:00
2008-07-03 12:24:39 +03:00
if ( ! pdata ) {
dev_err ( & pdev - > dev , " McBSP device initialized without "
" platform data \n " ) ;
ret = - EINVAL ;
goto exit ;
}
dev_dbg ( & pdev - > dev , " Initializing OMAP McBSP (%d). \n " , pdev - > id ) ;
2008-10-08 10:01:39 +03:00
if ( id > = omap_mcbsp_count ) {
2008-07-03 12:24:39 +03:00
dev_err ( & pdev - > dev , " Invalid McBSP device id (%d) \n " , id ) ;
ret = - EINVAL ;
goto exit ;
}
2008-10-08 10:01:39 +03:00
mcbsp = kzalloc ( sizeof ( struct omap_mcbsp ) , GFP_KERNEL ) ;
if ( ! mcbsp ) {
ret = - ENOMEM ;
goto exit ;
}
spin_lock_init ( & mcbsp - > lock ) ;
mcbsp - > id = id + 1 ;
mcbsp - > free = 1 ;
mcbsp - > dma_tx_lch = - 1 ;
mcbsp - > dma_rx_lch = - 1 ;
2008-07-03 12:24:39 +03:00
2008-10-08 10:01:39 +03:00
mcbsp - > phys_base = pdata - > phys_base ;
mcbsp - > io_base = ioremap ( pdata - > phys_base , SZ_4K ) ;
if ( ! mcbsp - > io_base ) {
2008-09-04 14:25:42 +01:00
ret = - ENOMEM ;
goto err_ioremap ;
}
2008-07-03 12:24:39 +03:00
/* Default I/O is IRQ based */
2008-10-08 10:01:39 +03:00
mcbsp - > io_type = OMAP_MCBSP_IRQ_IO ;
mcbsp - > tx_irq = pdata - > tx_irq ;
mcbsp - > rx_irq = pdata - > rx_irq ;
mcbsp - > dma_rx_sync = pdata - > dma_rx_sync ;
mcbsp - > dma_tx_sync = pdata - > dma_tx_sync ;
2008-07-03 12:24:39 +03:00
2009-01-23 10:26:46 +00:00
mcbsp - > iclk = clk_get ( & pdev - > dev , " ick " ) ;
if ( IS_ERR ( mcbsp - > iclk ) ) {
ret = PTR_ERR ( mcbsp - > iclk ) ;
dev_err ( & pdev - > dev , " unable to get ick: %d \n " , ret ) ;
goto err_iclk ;
}
2009-01-29 08:57:12 -08:00
2009-01-23 10:26:46 +00:00
mcbsp - > fclk = clk_get ( & pdev - > dev , " fck " ) ;
if ( IS_ERR ( mcbsp - > fclk ) ) {
ret = PTR_ERR ( mcbsp - > fclk ) ;
dev_err ( & pdev - > dev , " unable to get fck: %d \n " , ret ) ;
goto err_fclk ;
2008-07-03 12:24:39 +03:00
}
2008-10-08 10:01:39 +03:00
mcbsp - > pdata = pdata ;
mcbsp - > dev = & pdev - > dev ;
2009-01-23 10:26:46 +00:00
mcbsp_ptr [ id ] = mcbsp ;
2008-10-08 10:01:39 +03:00
platform_set_drvdata ( pdev , mcbsp ) ;
2008-09-04 14:25:42 +01:00
return 0 ;
2008-07-03 12:24:39 +03:00
2009-01-23 10:26:46 +00:00
err_fclk :
clk_put ( mcbsp - > iclk ) ;
err_iclk :
2008-10-08 10:01:39 +03:00
iounmap ( mcbsp - > io_base ) ;
2008-09-04 14:25:42 +01:00
err_ioremap :
2009-01-23 10:26:46 +00:00
kfree ( mcbsp ) ;
2008-07-03 12:24:39 +03:00
exit :
return ret ;
}
2006-04-02 17:46:27 +01:00
2008-10-08 10:01:39 +03:00
static int __devexit omap_mcbsp_remove ( struct platform_device * pdev )
2005-07-10 19:58:15 +01:00
{
2008-07-03 12:24:39 +03:00
struct omap_mcbsp * mcbsp = platform_get_drvdata ( pdev ) ;
2005-07-10 19:58:15 +01:00
2008-07-03 12:24:39 +03:00
platform_set_drvdata ( pdev , NULL ) ;
if ( mcbsp ) {
2005-07-10 19:58:15 +01:00
2008-07-03 12:24:39 +03:00
if ( mcbsp - > pdata & & mcbsp - > pdata - > ops & &
mcbsp - > pdata - > ops - > free )
mcbsp - > pdata - > ops - > free ( mcbsp - > id ) ;
2005-07-10 19:58:15 +01:00
2009-01-23 10:26:46 +00:00
clk_disable ( mcbsp - > fclk ) ;
clk_disable ( mcbsp - > iclk ) ;
clk_put ( mcbsp - > fclk ) ;
clk_put ( mcbsp - > iclk ) ;
2008-07-03 12:24:39 +03:00
2008-09-04 14:25:42 +01:00
iounmap ( mcbsp - > io_base ) ;
2009-01-23 10:26:46 +00:00
mcbsp - > fclk = NULL ;
mcbsp - > iclk = NULL ;
2008-07-03 12:24:39 +03:00
mcbsp - > free = 0 ;
mcbsp - > dev = NULL ;
2005-07-10 19:58:15 +01:00
}
return 0 ;
}
2008-07-03 12:24:39 +03:00
static struct platform_driver omap_mcbsp_driver = {
. probe = omap_mcbsp_probe ,
2008-10-08 10:01:39 +03:00
. remove = __devexit_p ( omap_mcbsp_remove ) ,
2008-07-03 12:24:39 +03:00
. driver = {
. name = " omap-mcbsp " ,
} ,
} ;
int __init omap_mcbsp_init ( void )
{
/* Register the McBSP driver */
return platform_driver_register ( & omap_mcbsp_driver ) ;
}