2005-07-10 22:58:15 +04: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 13:24:39 +04:00
# include <linux/platform_device.h>
2005-07-10 22:58:15 +04:00
# include <linux/wait.h>
# include <linux/completion.h>
# include <linux/interrupt.h>
# include <linux/err.h>
2006-01-07 19:15:52 +03:00
# include <linux/clk.h>
2007-02-12 21:50:53 +03:00
# include <linux/delay.h>
2008-07-03 13:24:39 +04:00
# include <linux/io.h>
2005-07-10 22:58:15 +04:00
2008-08-05 19:14:15 +04:00
# include <mach/dma.h>
# include <mach/mcbsp.h>
2005-07-10 22:58:15 +04:00
2008-10-08 11:01:39 +04:00
struct omap_mcbsp * * mcbsp_ptr ;
int omap_mcbsp_count ;
2008-07-03 13:24:39 +04:00
2008-10-08 11:01:39 +04: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 22:58:15 +04:00
static void omap_mcbsp_dump_reg ( u8 id )
{
2008-10-08 11:01:39 +04: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 22:58:15 +04:00
}
2006-10-06 21:53:39 +04:00
static irqreturn_t omap_mcbsp_tx_irq_handler ( int irq , void * dev_id )
2005-07-10 22:58:15 +04:00
{
2007-10-26 13:40:25 +04:00
struct omap_mcbsp * mcbsp_tx = dev_id ;
2009-05-25 22:08:42 +04:00
u16 irqst_spcr2 ;
2005-07-10 22:58:15 +04:00
2009-05-25 22:08:42 +04: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 22:58:15 +04:00
2009-05-25 22:08:42 +04: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 13:24:39 +04:00
2005-07-10 22:58:15 +04:00
return IRQ_HANDLED ;
}
2006-10-06 21:53:39 +04:00
static irqreturn_t omap_mcbsp_rx_irq_handler ( int irq , void * dev_id )
2005-07-10 22:58:15 +04:00
{
2007-10-26 13:40:25 +04:00
struct omap_mcbsp * mcbsp_rx = dev_id ;
2009-05-25 22:08:42 +04: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 13:24:39 +04:00
2005-07-10 22:58:15 +04:00
return IRQ_HANDLED ;
}
static void omap_mcbsp_tx_dma_callback ( int lch , u16 ch_status , void * data )
{
2007-10-26 13:40:25 +04:00
struct omap_mcbsp * mcbsp_dma_tx = data ;
2005-07-10 22:58:15 +04:00
2008-07-03 13:24:39 +04: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 22:58:15 +04: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 13:40:25 +04:00
struct omap_mcbsp * mcbsp_dma_rx = data ;
2005-07-10 22:58:15 +04:00
2008-07-03 13:24:39 +04: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 22:58:15 +04: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 13:24:39 +04:00
void omap_mcbsp_config ( unsigned int id , const struct omap_mcbsp_reg_cfg * config )
2005-07-10 22:58:15 +04:00
{
2008-10-08 11:01:39 +04:00
struct omap_mcbsp * mcbsp ;
2008-09-04 17:25:42 +04:00
void __iomem * io_base ;
2005-07-10 22:58:15 +04:00
2008-07-03 13:24:39 +04:00
if ( ! omap_mcbsp_check_valid_id ( id ) ) {
printk ( KERN_ERR " %s: Invalid id (%d) \n " , __func__ , id + 1 ) ;
return ;
}
2008-10-08 11:01:39 +04:00
mcbsp = id_to_mcbsp_ptr ( id ) ;
2008-07-03 13:24:39 +04:00
2008-10-08 11:01:39 +04: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 22:58:15 +04: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 14:09:54 +03: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 22:58:15 +04:00
}
2008-07-03 13:24:39 +04:00
EXPORT_SYMBOL ( omap_mcbsp_config ) ;
2005-07-10 22:58:15 +04:00
2009-08-20 17:18:10 +04:00
# ifdef CONFIG_ARCH_OMAP34XX
/*
* omap_mcbsp_set_tx_threshold configures how to deal
* with transmit threshold . the threshold value and handler can be
* configure in here .
*/
void omap_mcbsp_set_tx_threshold ( unsigned int id , u16 threshold )
{
struct omap_mcbsp * mcbsp ;
void __iomem * io_base ;
if ( ! cpu_is_omap34xx ( ) )
return ;
if ( ! omap_mcbsp_check_valid_id ( id ) ) {
printk ( KERN_ERR " %s: Invalid id (%d) \n " , __func__ , id + 1 ) ;
return ;
}
mcbsp = id_to_mcbsp_ptr ( id ) ;
io_base = mcbsp - > io_base ;
OMAP_MCBSP_WRITE ( io_base , THRSH2 , threshold ) ;
}
EXPORT_SYMBOL ( omap_mcbsp_set_tx_threshold ) ;
/*
* omap_mcbsp_set_rx_threshold configures how to deal
* with receive threshold . the threshold value and handler can be
* configure in here .
*/
void omap_mcbsp_set_rx_threshold ( unsigned int id , u16 threshold )
{
struct omap_mcbsp * mcbsp ;
void __iomem * io_base ;
if ( ! cpu_is_omap34xx ( ) )
return ;
if ( ! omap_mcbsp_check_valid_id ( id ) ) {
printk ( KERN_ERR " %s: Invalid id (%d) \n " , __func__ , id + 1 ) ;
return ;
}
mcbsp = id_to_mcbsp_ptr ( id ) ;
io_base = mcbsp - > io_base ;
OMAP_MCBSP_WRITE ( io_base , THRSH1 , threshold ) ;
}
EXPORT_SYMBOL ( omap_mcbsp_set_rx_threshold ) ;
2009-08-20 17:18:11 +04:00
/*
* omap_mcbsp_get_max_tx_thres just return the current configured
* maximum threshold for transmission
*/
u16 omap_mcbsp_get_max_tx_threshold ( unsigned int id )
{
struct omap_mcbsp * mcbsp ;
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 ) ;
return mcbsp - > max_tx_thres ;
}
EXPORT_SYMBOL ( omap_mcbsp_get_max_tx_threshold ) ;
/*
* omap_mcbsp_get_max_rx_thres just return the current configured
* maximum threshold for reception
*/
u16 omap_mcbsp_get_max_rx_threshold ( unsigned int id )
{
struct omap_mcbsp * mcbsp ;
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 ) ;
return mcbsp - > max_rx_thres ;
}
EXPORT_SYMBOL ( omap_mcbsp_get_max_rx_threshold ) ;
2009-08-20 17:18:14 +04:00
/*
* omap_mcbsp_get_dma_op_mode just return the current configured
* operating mode for the mcbsp channel
*/
int omap_mcbsp_get_dma_op_mode ( unsigned int id )
{
struct omap_mcbsp * mcbsp ;
int dma_op_mode ;
if ( ! omap_mcbsp_check_valid_id ( id ) ) {
printk ( KERN_ERR " %s: Invalid id (%u) \n " , __func__ , id + 1 ) ;
return - ENODEV ;
}
mcbsp = id_to_mcbsp_ptr ( id ) ;
spin_lock_irq ( & mcbsp - > lock ) ;
dma_op_mode = mcbsp - > dma_op_mode ;
spin_unlock_irq ( & mcbsp - > lock ) ;
return dma_op_mode ;
}
EXPORT_SYMBOL ( omap_mcbsp_get_dma_op_mode ) ;
2009-08-20 17:18:15 +04:00
static inline void omap34xx_mcbsp_request ( struct omap_mcbsp * mcbsp )
{
/*
* Enable wakup behavior , smart idle and all wakeups
* REVISIT : some wakeups may be unnecessary
*/
if ( cpu_is_omap34xx ( ) ) {
u16 syscon ;
syscon = OMAP_MCBSP_READ ( mcbsp - > io_base , SYSCON ) ;
2009-08-20 17:18:17 +04:00
syscon & = ~ ( ENAWAKEUP | SIDLEMODE ( 0x03 ) | CLOCKACTIVITY ( 0x03 ) ) ;
2009-08-20 17:18:18 +04:00
spin_lock_irq ( & mcbsp - > lock ) ;
2009-08-20 17:18:19 +04:00
if ( mcbsp - > dma_op_mode = = MCBSP_DMA_MODE_THRESHOLD ) {
syscon | = ( ENAWAKEUP | SIDLEMODE ( 0x02 ) |
CLOCKACTIVITY ( 0x02 ) ) ;
OMAP_MCBSP_WRITE ( mcbsp - > io_base , WAKEUPEN ,
XRDYEN | RRDYEN ) ;
} else {
2009-08-20 17:18:18 +04:00
syscon | = SIDLEMODE ( 0x01 ) ;
2009-08-20 17:18:19 +04:00
}
2009-08-20 17:18:18 +04:00
spin_unlock_irq ( & mcbsp - > lock ) ;
2009-08-20 17:18:15 +04:00
OMAP_MCBSP_WRITE ( mcbsp - > io_base , SYSCON , syscon ) ;
}
}
static inline void omap34xx_mcbsp_free ( struct omap_mcbsp * mcbsp )
{
/*
* Disable wakup behavior , smart idle and all wakeups
*/
if ( cpu_is_omap34xx ( ) ) {
u16 syscon ;
syscon = OMAP_MCBSP_READ ( mcbsp - > io_base , SYSCON ) ;
2009-08-20 17:18:17 +04:00
syscon & = ~ ( ENAWAKEUP | SIDLEMODE ( 0x03 ) | CLOCKACTIVITY ( 0x03 ) ) ;
2009-08-20 17:18:15 +04:00
OMAP_MCBSP_WRITE ( mcbsp - > io_base , SYSCON , syscon ) ;
2009-08-20 17:18:16 +04:00
OMAP_MCBSP_WRITE ( mcbsp - > io_base , WAKEUPEN , 0 ) ;
2009-08-20 17:18:15 +04:00
}
}
# else
static inline void omap34xx_mcbsp_request ( struct omap_mcbsp * mcbsp ) { }
static inline void omap34xx_mcbsp_free ( struct omap_mcbsp * mcbsp ) { }
2009-08-20 17:18:10 +04:00
# endif
2006-04-02 20:46:27 +04: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 11:01:39 +04:00
struct omap_mcbsp * mcbsp ;
2008-07-03 13:24:39 +04:00
if ( ! omap_mcbsp_check_valid_id ( id ) ) {
printk ( KERN_ERR " %s: Invalid id (%d) \n " , __func__ , id + 1 ) ;
return - ENODEV ;
}
2008-10-08 11:01:39 +04:00
mcbsp = id_to_mcbsp_ptr ( id ) ;
2006-04-02 20:46:27 +04:00
2008-10-08 11:01:39 +04:00
spin_lock ( & mcbsp - > lock ) ;
2006-04-02 20:46:27 +04:00
2008-10-08 11:01:39 +04:00
if ( ! mcbsp - > free ) {
dev_err ( mcbsp - > dev , " McBSP%d is currently in use \n " ,
mcbsp - > id ) ;
spin_unlock ( & mcbsp - > lock ) ;
2006-04-02 20:46:27 +04:00
return - EINVAL ;
}
2008-10-08 11:01:39 +04:00
mcbsp - > io_type = io_type ;
2006-04-02 20:46:27 +04:00
2008-10-08 11:01:39 +04:00
spin_unlock ( & mcbsp - > lock ) ;
2006-04-02 20:46:27 +04:00
return 0 ;
}
2008-07-03 13:24:39 +04:00
EXPORT_SYMBOL ( omap_mcbsp_set_io_type ) ;
2005-07-10 22:58:15 +04:00
int omap_mcbsp_request ( unsigned int id )
{
2008-10-08 11:01:39 +04:00
struct omap_mcbsp * mcbsp ;
2005-07-10 22:58:15 +04:00
int err ;
2008-07-03 13:24:39 +04:00
if ( ! omap_mcbsp_check_valid_id ( id ) ) {
printk ( KERN_ERR " %s: Invalid id (%d) \n " , __func__ , id + 1 ) ;
return - ENODEV ;
2006-04-02 20:46:27 +04:00
}
2008-10-08 11:01:39 +04:00
mcbsp = id_to_mcbsp_ptr ( id ) ;
2008-07-03 13:24:39 +04:00
2008-10-08 11:01:39 +04: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 13:26:46 +03:00
return - EBUSY ;
2005-07-10 22:58:15 +04:00
}
2008-10-08 11:01:39 +04:00
mcbsp - > free = 0 ;
spin_unlock ( & mcbsp - > lock ) ;
2005-07-10 22:58:15 +04:00
2009-01-23 13:26:46 +03:00
if ( mcbsp - > pdata & & mcbsp - > pdata - > ops & & mcbsp - > pdata - > ops - > request )
mcbsp - > pdata - > ops - > request ( id ) ;
clk_enable ( mcbsp - > iclk ) ;
clk_enable ( mcbsp - > fclk ) ;
2009-08-20 17:18:15 +04:00
/* Do procedure specific to omap34xx arch, if applicable */
omap34xx_mcbsp_request ( mcbsp ) ;
2008-10-08 11:01:41 +04: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 11:01:39 +04:00
if ( mcbsp - > io_type = = OMAP_MCBSP_IRQ_IO ) {
2006-04-02 20:46:27 +04:00
/* We need to get IRQs here */
2008-10-08 11:01:41 +04:00
init_completion ( & mcbsp - > tx_irq_completion ) ;
2008-10-08 11:01:39 +04:00
err = request_irq ( mcbsp - > tx_irq , omap_mcbsp_tx_irq_handler ,
0 , " McBSP " , ( void * ) mcbsp ) ;
2006-04-02 20:46:27 +04:00
if ( err ! = 0 ) {
2008-10-08 11:01:39 +04:00
dev_err ( mcbsp - > dev , " Unable to request TX IRQ %d "
" for McBSP%d \n " , mcbsp - > tx_irq ,
mcbsp - > id ) ;
2006-04-02 20:46:27 +04:00
return err ;
}
2005-07-10 22:58:15 +04:00
2008-10-08 11:01:41 +04:00
init_completion ( & mcbsp - > rx_irq_completion ) ;
2008-10-08 11:01:39 +04:00
err = request_irq ( mcbsp - > rx_irq , omap_mcbsp_rx_irq_handler ,
0 , " McBSP " , ( void * ) mcbsp ) ;
2006-04-02 20:46:27 +04:00
if ( err ! = 0 ) {
2008-10-08 11:01:39 +04: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 20:46:27 +04:00
return err ;
}
2005-07-10 22:58:15 +04:00
}
return 0 ;
}
2008-07-03 13:24:39 +04:00
EXPORT_SYMBOL ( omap_mcbsp_request ) ;
2005-07-10 22:58:15 +04:00
void omap_mcbsp_free ( unsigned int id )
{
2008-10-08 11:01:39 +04:00
struct omap_mcbsp * mcbsp ;
2008-07-03 13:24:39 +04:00
if ( ! omap_mcbsp_check_valid_id ( id ) ) {
printk ( KERN_ERR " %s: Invalid id (%d) \n " , __func__ , id + 1 ) ;
2005-07-10 22:58:15 +04:00
return ;
2006-04-02 20:46:27 +04:00
}
2008-10-08 11:01:39 +04:00
mcbsp = id_to_mcbsp_ptr ( id ) ;
2008-07-03 13:24:39 +04:00
2008-10-08 11:01:39 +04:00
if ( mcbsp - > pdata & & mcbsp - > pdata - > ops & & mcbsp - > pdata - > ops - > free )
mcbsp - > pdata - > ops - > free ( id ) ;
2008-07-03 13:24:39 +04:00
2009-08-20 17:18:15 +04:00
/* Do procedure specific to omap34xx arch, if applicable */
omap34xx_mcbsp_free ( mcbsp ) ;
2009-01-23 13:26:46 +03: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 22:58:15 +04:00
2008-10-08 11:01:39 +04: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 22:58:15 +04:00
return ;
}
2008-10-08 11:01:39 +04:00
mcbsp - > free = 1 ;
spin_unlock ( & mcbsp - > lock ) ;
2005-07-10 22:58:15 +04:00
}
2008-07-03 13:24:39 +04:00
EXPORT_SYMBOL ( omap_mcbsp_free ) ;
2005-07-10 22:58:15 +04:00
/*
2009-08-07 10:59:47 +04:00
* Here we start the McBSP , by enabling transmitter , receiver or both .
* If no transmitter or receiver is active prior calling , then sample - rate
* generator and frame sync are started .
2005-07-10 22:58:15 +04:00
*/
2009-08-07 10:59:47 +04:00
void omap_mcbsp_start ( unsigned int id , int tx , int rx )
2005-07-10 22:58:15 +04:00
{
2008-10-08 11:01:39 +04:00
struct omap_mcbsp * mcbsp ;
2008-09-04 17:25:42 +04:00
void __iomem * io_base ;
2009-08-07 10:59:47 +04:00
int idle ;
2005-07-10 22:58:15 +04:00
u16 w ;
2008-07-03 13:24:39 +04:00
if ( ! omap_mcbsp_check_valid_id ( id ) ) {
printk ( KERN_ERR " %s: Invalid id (%d) \n " , __func__ , id + 1 ) ;
2005-07-10 22:58:15 +04:00
return ;
2008-07-03 13:24:39 +04:00
}
2008-10-08 11:01:39 +04:00
mcbsp = id_to_mcbsp_ptr ( id ) ;
io_base = mcbsp - > io_base ;
2005-07-10 22:58:15 +04:00
2008-10-08 11:01:39 +04: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 22:58:15 +04:00
2009-08-07 10:59:47 +04:00
idle = ! ( ( OMAP_MCBSP_READ ( io_base , SPCR2 ) |
OMAP_MCBSP_READ ( io_base , SPCR1 ) ) & 1 ) ;
if ( idle ) {
/* Start the sample generator */
w = OMAP_MCBSP_READ ( io_base , SPCR2 ) ;
OMAP_MCBSP_WRITE ( io_base , SPCR2 , w | ( 1 < < 6 ) ) ;
}
2005-07-10 22:58:15 +04:00
/* Enable transmitter and receiver */
w = OMAP_MCBSP_READ ( io_base , SPCR2 ) ;
2009-08-07 10:59:47 +04:00
OMAP_MCBSP_WRITE ( io_base , SPCR2 , w | ( tx & 1 ) ) ;
2005-07-10 22:58:15 +04:00
w = OMAP_MCBSP_READ ( io_base , SPCR1 ) ;
2009-08-07 10:59:47 +04:00
OMAP_MCBSP_WRITE ( io_base , SPCR1 , w | ( rx & 1 ) ) ;
2005-07-10 22:58:15 +04:00
2009-08-20 17:18:09 +04:00
/*
* Worst case : CLKSRG * 2 = 8000 khz : ( 1 / 8000 ) * 2 * 2 usec
* REVISIT : 100u s may give enough time for two CLKSRG , however
* due to some unknown PM related , clock gating etc . reason it
* is now at 500u s .
*/
udelay ( 500 ) ;
2005-07-10 22:58:15 +04:00
2009-08-07 10:59:47 +04:00
if ( idle ) {
/* Start frame sync */
w = OMAP_MCBSP_READ ( io_base , SPCR2 ) ;
OMAP_MCBSP_WRITE ( io_base , SPCR2 , w | ( 1 < < 7 ) ) ;
}
2005-07-10 22:58:15 +04:00
/* Dump McBSP Regs */
omap_mcbsp_dump_reg ( id ) ;
}
2008-07-03 13:24:39 +04:00
EXPORT_SYMBOL ( omap_mcbsp_start ) ;
2005-07-10 22:58:15 +04:00
2009-08-07 10:59:47 +04:00
void omap_mcbsp_stop ( unsigned int id , int tx , int rx )
2005-07-10 22:58:15 +04:00
{
2008-10-08 11:01:39 +04:00
struct omap_mcbsp * mcbsp ;
2008-09-04 17:25:42 +04:00
void __iomem * io_base ;
2009-08-07 10:59:47 +04:00
int idle ;
2005-07-10 22:58:15 +04:00
u16 w ;
2008-07-03 13:24:39 +04:00
if ( ! omap_mcbsp_check_valid_id ( id ) ) {
printk ( KERN_ERR " %s: Invalid id (%d) \n " , __func__ , id + 1 ) ;
2005-07-10 22:58:15 +04:00
return ;
2008-07-03 13:24:39 +04:00
}
2005-07-10 22:58:15 +04:00
2008-10-08 11:01:39 +04:00
mcbsp = id_to_mcbsp_ptr ( id ) ;
io_base = mcbsp - > io_base ;
2005-07-10 22:58:15 +04:00
2008-07-03 13:24:39 +04:00
/* Reset transmitter */
2005-07-10 22:58:15 +04:00
w = OMAP_MCBSP_READ ( io_base , SPCR2 ) ;
2009-08-07 10:59:47 +04:00
OMAP_MCBSP_WRITE ( io_base , SPCR2 , w & ~ ( tx & 1 ) ) ;
2005-07-10 22:58:15 +04:00
/* Reset receiver */
w = OMAP_MCBSP_READ ( io_base , SPCR1 ) ;
2009-08-07 10:59:47 +04:00
OMAP_MCBSP_WRITE ( io_base , SPCR1 , w & ~ ( rx & 1 ) ) ;
2005-07-10 22:58:15 +04:00
2009-08-07 10:59:47 +04:00
idle = ! ( ( OMAP_MCBSP_READ ( io_base , SPCR2 ) |
OMAP_MCBSP_READ ( io_base , SPCR1 ) ) & 1 ) ;
if ( idle ) {
/* Reset the sample rate generator */
w = OMAP_MCBSP_READ ( io_base , SPCR2 ) ;
OMAP_MCBSP_WRITE ( io_base , SPCR2 , w & ~ ( 1 < < 6 ) ) ;
}
2005-07-10 22:58:15 +04:00
}
2008-07-03 13:24:39 +04:00
EXPORT_SYMBOL ( omap_mcbsp_stop ) ;
2005-07-10 22:58:15 +04:00
2009-08-20 17:18:07 +04:00
void omap_mcbsp_xmit_enable ( unsigned int id , u8 enable )
{
struct omap_mcbsp * mcbsp ;
void __iomem * io_base ;
u16 w ;
if ( ! ( cpu_is_omap2430 ( ) | | cpu_is_omap34xx ( ) ) )
return ;
if ( ! omap_mcbsp_check_valid_id ( id ) ) {
printk ( KERN_ERR " %s: Invalid id (%d) \n " , __func__ , id + 1 ) ;
return ;
}
mcbsp = id_to_mcbsp_ptr ( id ) ;
io_base = mcbsp - > io_base ;
w = OMAP_MCBSP_READ ( io_base , XCCR ) ;
if ( enable )
OMAP_MCBSP_WRITE ( io_base , XCCR , w & ~ ( XDISABLE ) ) ;
else
OMAP_MCBSP_WRITE ( io_base , XCCR , w | XDISABLE ) ;
}
EXPORT_SYMBOL ( omap_mcbsp_xmit_enable ) ;
void omap_mcbsp_recv_enable ( unsigned int id , u8 enable )
{
struct omap_mcbsp * mcbsp ;
void __iomem * io_base ;
u16 w ;
if ( ! ( cpu_is_omap2430 ( ) | | cpu_is_omap34xx ( ) ) )
return ;
if ( ! omap_mcbsp_check_valid_id ( id ) ) {
printk ( KERN_ERR " %s: Invalid id (%d) \n " , __func__ , id + 1 ) ;
return ;
}
mcbsp = id_to_mcbsp_ptr ( id ) ;
io_base = mcbsp - > io_base ;
w = OMAP_MCBSP_READ ( io_base , RCCR ) ;
if ( enable )
OMAP_MCBSP_WRITE ( io_base , RCCR , w & ~ ( RDISABLE ) ) ;
else
OMAP_MCBSP_WRITE ( io_base , RCCR , w | RDISABLE ) ;
}
EXPORT_SYMBOL ( omap_mcbsp_recv_enable ) ;
2005-07-10 22:58:18 +04:00
/* polled mcbsp i/o operations */
int omap_mcbsp_pollwrite ( unsigned int id , u16 buf )
{
2008-10-08 11:01:39 +04:00
struct omap_mcbsp * mcbsp ;
2008-09-04 17:25:42 +04:00
void __iomem * base ;
2008-07-03 13:24:39 +04:00
if ( ! omap_mcbsp_check_valid_id ( id ) ) {
printk ( KERN_ERR " %s: Invalid id (%d) \n " , __func__ , id + 1 ) ;
return - ENODEV ;
}
2008-10-08 11:01:39 +04:00
mcbsp = id_to_mcbsp_ptr ( id ) ;
base = mcbsp - > io_base ;
2005-07-10 22:58:18 +04: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 11:01:39 +04:00
dev_err ( mcbsp - > dev , " Could not write to "
" McBSP%d Register \n " , mcbsp - > id ) ;
2005-07-10 22:58:18 +04:00
return - 2 ;
}
}
}
2008-07-03 13:24:39 +04:00
2005-07-10 22:58:18 +04:00
return 0 ;
}
2008-07-03 13:24:39 +04:00
EXPORT_SYMBOL ( omap_mcbsp_pollwrite ) ;
2005-07-10 22:58:18 +04:00
2008-07-03 13:24:39 +04:00
int omap_mcbsp_pollread ( unsigned int id , u16 * buf )
2005-07-10 22:58:18 +04:00
{
2008-10-08 11:01:39 +04:00
struct omap_mcbsp * mcbsp ;
2008-09-04 17:25:42 +04:00
void __iomem * base ;
2008-07-03 13:24:39 +04:00
if ( ! omap_mcbsp_check_valid_id ( id ) ) {
printk ( KERN_ERR " %s: Invalid id (%d) \n " , __func__ , id + 1 ) ;
return - ENODEV ;
}
2008-10-08 11:01:39 +04:00
mcbsp = id_to_mcbsp_ptr ( id ) ;
2008-07-03 13:24:39 +04:00
2008-10-08 11:01:39 +04:00
base = mcbsp - > io_base ;
2005-07-10 22:58:18 +04: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 11:01:39 +04:00
dev_err ( mcbsp - > dev , " Could not read from "
" McBSP%d Register \n " , mcbsp - > id ) ;
2005-07-10 22:58:18 +04:00
return - 2 ;
}
}
}
* buf = readw ( base + OMAP_MCBSP_REG_DRR1 ) ;
2008-07-03 13:24:39 +04:00
2005-07-10 22:58:18 +04:00
return 0 ;
}
2008-07-03 13:24:39 +04:00
EXPORT_SYMBOL ( omap_mcbsp_pollread ) ;
2005-07-10 22:58:18 +04:00
2005-07-10 22:58:15 +04:00
/*
* IRQ based word transmission .
*/
void omap_mcbsp_xmit_word ( unsigned int id , u32 word )
{
2008-10-08 11:01:39 +04:00
struct omap_mcbsp * mcbsp ;
2008-09-04 17:25:42 +04:00
void __iomem * io_base ;
2008-07-03 13:24:39 +04:00
omap_mcbsp_word_length word_length ;
2005-07-10 22:58:15 +04:00
2008-07-03 13:24:39 +04:00
if ( ! omap_mcbsp_check_valid_id ( id ) ) {
printk ( KERN_ERR " %s: Invalid id (%d) \n " , __func__ , id + 1 ) ;
2005-07-10 22:58:15 +04:00
return ;
2008-07-03 13:24:39 +04:00
}
2005-07-10 22:58:15 +04:00
2008-10-08 11:01:39 +04:00
mcbsp = id_to_mcbsp_ptr ( id ) ;
io_base = mcbsp - > io_base ;
word_length = mcbsp - > tx_word_length ;
2005-07-10 22:58:15 +04:00
2008-10-08 11:01:39 +04:00
wait_for_completion ( & mcbsp - > tx_irq_completion ) ;
2005-07-10 22:58:15 +04: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 13:24:39 +04:00
EXPORT_SYMBOL ( omap_mcbsp_xmit_word ) ;
2005-07-10 22:58:15 +04:00
u32 omap_mcbsp_recv_word ( unsigned int id )
{
2008-10-08 11:01:39 +04:00
struct omap_mcbsp * mcbsp ;
2008-09-04 17:25:42 +04:00
void __iomem * io_base ;
2005-07-10 22:58:15 +04:00
u16 word_lsb , word_msb = 0 ;
2008-07-03 13:24:39 +04:00
omap_mcbsp_word_length word_length ;
2005-07-10 22:58:15 +04:00
2008-07-03 13:24:39 +04:00
if ( ! omap_mcbsp_check_valid_id ( id ) ) {
printk ( KERN_ERR " %s: Invalid id (%d) \n " , __func__ , id + 1 ) ;
return - ENODEV ;
}
2008-10-08 11:01:39 +04:00
mcbsp = id_to_mcbsp_ptr ( id ) ;
2005-07-10 22:58:15 +04:00
2008-10-08 11:01:39 +04:00
word_length = mcbsp - > rx_word_length ;
io_base = mcbsp - > io_base ;
2005-07-10 22:58:15 +04:00
2008-10-08 11:01:39 +04:00
wait_for_completion ( & mcbsp - > rx_irq_completion ) ;
2005-07-10 22:58:15 +04: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 13:24:39 +04:00
EXPORT_SYMBOL ( omap_mcbsp_recv_word ) ;
2005-07-10 22:58:15 +04:00
2006-04-02 20:46:27 +04:00
int omap_mcbsp_spi_master_xmit_word_poll ( unsigned int id , u32 word )
{
2008-10-08 11:01:39 +04:00
struct omap_mcbsp * mcbsp ;
2008-09-04 17:25:42 +04:00
void __iomem * io_base ;
2008-07-03 13:24:39 +04:00
omap_mcbsp_word_length tx_word_length ;
omap_mcbsp_word_length rx_word_length ;
2006-04-02 20:46:27 +04:00
u16 spcr2 , spcr1 , attempts = 0 , word_lsb , word_msb = 0 ;
2008-07-03 13:24:39 +04:00
if ( ! omap_mcbsp_check_valid_id ( id ) ) {
printk ( KERN_ERR " %s: Invalid id (%d) \n " , __func__ , id + 1 ) ;
return - ENODEV ;
}
2008-10-08 11:01:39 +04: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 13:24:39 +04:00
2006-04-02 20:46:27 +04: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 11:01:39 +04:00
dev_err ( mcbsp - > dev , " McBSP%d transmitter not "
" ready \n " , mcbsp - > id ) ;
2006-04-02 20:46:27 +04: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 11:01:39 +04:00
dev_err ( mcbsp - > dev , " McBSP%d receiver not "
" ready \n " , mcbsp - > id ) ;
2006-04-02 20:46:27 +04: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 13:24:39 +04:00
EXPORT_SYMBOL ( omap_mcbsp_spi_master_xmit_word_poll ) ;
2006-04-02 20:46:27 +04:00
2008-07-03 13:24:39 +04:00
int omap_mcbsp_spi_master_recv_word_poll ( unsigned int id , u32 * word )
2006-04-02 20:46:27 +04:00
{
2008-10-08 11:01:39 +04:00
struct omap_mcbsp * mcbsp ;
2008-09-04 17:25:42 +04:00
u32 clock_word = 0 ;
void __iomem * io_base ;
2008-07-03 13:24:39 +04:00
omap_mcbsp_word_length tx_word_length ;
omap_mcbsp_word_length rx_word_length ;
2006-04-02 20:46:27 +04:00
u16 spcr2 , spcr1 , attempts = 0 , word_lsb , word_msb = 0 ;
2008-07-03 13:24:39 +04:00
if ( ! omap_mcbsp_check_valid_id ( id ) ) {
printk ( KERN_ERR " %s: Invalid id (%d) \n " , __func__ , id + 1 ) ;
return - ENODEV ;
}
2008-10-08 11:01:39 +04: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 13:24:39 +04:00
2006-04-02 20:46:27 +04: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 11:01:39 +04:00
dev_err ( mcbsp - > dev , " McBSP%d transmitter not "
" ready \n " , mcbsp - > id ) ;
2006-04-02 20:46:27 +04: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 11:01:39 +04:00
dev_err ( mcbsp - > dev , " McBSP%d receiver not "
" ready \n " , mcbsp - > id ) ;
2006-04-02 20:46:27 +04: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 13:24:39 +04:00
EXPORT_SYMBOL ( omap_mcbsp_spi_master_recv_word_poll ) ;
2006-04-02 20:46:27 +04:00
2005-07-10 22:58:15 +04: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 13:24:39 +04:00
int omap_mcbsp_xmit_buffer ( unsigned int id , dma_addr_t buffer ,
unsigned int length )
2005-07-10 22:58:15 +04:00
{
2008-10-08 11:01:39 +04:00
struct omap_mcbsp * mcbsp ;
2005-07-10 22:58:15 +04:00
int dma_tx_ch ;
2006-04-02 20:46:27 +04:00
int src_port = 0 ;
int dest_port = 0 ;
int sync_dev = 0 ;
2005-07-10 22:58:15 +04:00
2008-07-03 13:24:39 +04:00
if ( ! omap_mcbsp_check_valid_id ( id ) ) {
printk ( KERN_ERR " %s: Invalid id (%d) \n " , __func__ , id + 1 ) ;
return - ENODEV ;
}
2008-10-08 11:01:39 +04:00
mcbsp = id_to_mcbsp_ptr ( id ) ;
2005-07-10 22:58:15 +04:00
2008-10-08 11:01:39 +04:00
if ( omap_request_dma ( mcbsp - > dma_tx_sync , " McBSP TX " ,
2008-07-03 13:24:39 +04:00
omap_mcbsp_tx_dma_callback ,
2008-10-08 11:01:39 +04:00
mcbsp ,
2008-07-03 13:24:39 +04:00
& dma_tx_ch ) ) {
2008-10-08 11:01:39 +04:00
dev_err ( mcbsp - > dev , " Unable to request DMA channel for "
2008-07-03 13:24:39 +04:00
" McBSP%d TX. Trying IRQ based TX \n " ,
2008-10-08 11:01:39 +04:00
mcbsp - > id ) ;
2005-07-10 22:58:15 +04:00
return - EAGAIN ;
}
2008-10-08 11:01:39 +04:00
mcbsp - > dma_tx_lch = dma_tx_ch ;
2005-07-10 22:58:15 +04:00
2008-10-08 11:01:39 +04:00
dev_err ( mcbsp - > dev , " McBSP%d TX DMA on channel %d \n " , mcbsp - > id ,
2008-07-03 13:24:39 +04:00
dma_tx_ch ) ;
2005-07-10 22:58:15 +04:00
2008-10-08 11:01:39 +04:00
init_completion ( & mcbsp - > tx_dma_completion ) ;
2005-07-10 22:58:15 +04:00
2006-04-02 20:46:27 +04:00
if ( cpu_class_is_omap1 ( ) ) {
src_port = OMAP_DMA_PORT_TIPB ;
dest_port = OMAP_DMA_PORT_EMIFF ;
}
2008-07-03 13:24:39 +04:00
if ( cpu_class_is_omap2 ( ) )
2008-10-08 11:01:39 +04:00
sync_dev = mcbsp - > dma_tx_sync ;
2006-04-02 20:46:27 +04:00
2008-10-08 11:01:39 +04:00
omap_set_dma_transfer_params ( mcbsp - > dma_tx_lch ,
2005-07-10 22:58:15 +04:00
OMAP_DMA_DATA_TYPE_S16 ,
length > > 1 , 1 ,
2005-11-10 17:26:50 +03:00
OMAP_DMA_SYNC_ELEMENT ,
2006-04-02 20:46:27 +04:00
sync_dev , 0 ) ;
2005-07-10 22:58:15 +04:00
2008-10-08 11:01:39 +04:00
omap_set_dma_dest_params ( mcbsp - > dma_tx_lch ,
2006-04-02 20:46:27 +04:00
src_port ,
2005-07-10 22:58:15 +04:00
OMAP_DMA_AMODE_CONSTANT ,
2008-10-08 11:01:39 +04:00
mcbsp - > phys_base + OMAP_MCBSP_REG_DXR1 ,
2005-11-10 17:26:50 +03:00
0 , 0 ) ;
2005-07-10 22:58:15 +04:00
2008-10-08 11:01:39 +04:00
omap_set_dma_src_params ( mcbsp - > dma_tx_lch ,
2006-04-02 20:46:27 +04:00
dest_port ,
2005-07-10 22:58:15 +04:00
OMAP_DMA_AMODE_POST_INC ,
2005-11-10 17:26:50 +03:00
buffer ,
0 , 0 ) ;
2005-07-10 22:58:15 +04:00
2008-10-08 11:01:39 +04:00
omap_start_dma ( mcbsp - > dma_tx_lch ) ;
wait_for_completion ( & mcbsp - > tx_dma_completion ) ;
2008-07-03 13:24:39 +04:00
2005-07-10 22:58:15 +04:00
return 0 ;
}
2008-07-03 13:24:39 +04:00
EXPORT_SYMBOL ( omap_mcbsp_xmit_buffer ) ;
2005-07-10 22:58:15 +04:00
2008-07-03 13:24:39 +04:00
int omap_mcbsp_recv_buffer ( unsigned int id , dma_addr_t buffer ,
unsigned int length )
2005-07-10 22:58:15 +04:00
{
2008-10-08 11:01:39 +04:00
struct omap_mcbsp * mcbsp ;
2005-07-10 22:58:15 +04:00
int dma_rx_ch ;
2006-04-02 20:46:27 +04:00
int src_port = 0 ;
int dest_port = 0 ;
int sync_dev = 0 ;
2005-07-10 22:58:15 +04:00
2008-07-03 13:24:39 +04:00
if ( ! omap_mcbsp_check_valid_id ( id ) ) {
printk ( KERN_ERR " %s: Invalid id (%d) \n " , __func__ , id + 1 ) ;
return - ENODEV ;
}
2008-10-08 11:01:39 +04:00
mcbsp = id_to_mcbsp_ptr ( id ) ;
2005-07-10 22:58:15 +04:00
2008-10-08 11:01:39 +04:00
if ( omap_request_dma ( mcbsp - > dma_rx_sync , " McBSP RX " ,
2008-07-03 13:24:39 +04:00
omap_mcbsp_rx_dma_callback ,
2008-10-08 11:01:39 +04:00
mcbsp ,
2008-07-03 13:24:39 +04:00
& dma_rx_ch ) ) {
2008-10-08 11:01:39 +04:00
dev_err ( mcbsp - > dev , " Unable to request DMA channel for "
2008-07-03 13:24:39 +04:00
" McBSP%d RX. Trying IRQ based RX \n " ,
2008-10-08 11:01:39 +04:00
mcbsp - > id ) ;
2005-07-10 22:58:15 +04:00
return - EAGAIN ;
}
2008-10-08 11:01:39 +04:00
mcbsp - > dma_rx_lch = dma_rx_ch ;
2005-07-10 22:58:15 +04:00
2008-10-08 11:01:39 +04:00
dev_err ( mcbsp - > dev , " McBSP%d RX DMA on channel %d \n " , mcbsp - > id ,
2008-07-03 13:24:39 +04:00
dma_rx_ch ) ;
2005-07-10 22:58:15 +04:00
2008-10-08 11:01:39 +04:00
init_completion ( & mcbsp - > rx_dma_completion ) ;
2005-07-10 22:58:15 +04:00
2006-04-02 20:46:27 +04:00
if ( cpu_class_is_omap1 ( ) ) {
src_port = OMAP_DMA_PORT_TIPB ;
dest_port = OMAP_DMA_PORT_EMIFF ;
}
2008-07-03 13:24:39 +04:00
if ( cpu_class_is_omap2 ( ) )
2008-10-08 11:01:39 +04:00
sync_dev = mcbsp - > dma_rx_sync ;
2006-04-02 20:46:27 +04:00
2008-10-08 11:01:39 +04:00
omap_set_dma_transfer_params ( mcbsp - > dma_rx_lch ,
2008-07-03 13:24:39 +04:00
OMAP_DMA_DATA_TYPE_S16 ,
length > > 1 , 1 ,
OMAP_DMA_SYNC_ELEMENT ,
sync_dev , 0 ) ;
2005-07-10 22:58:15 +04:00
2008-10-08 11:01:39 +04:00
omap_set_dma_src_params ( mcbsp - > dma_rx_lch ,
2006-04-02 20:46:27 +04:00
src_port ,
2005-07-10 22:58:15 +04:00
OMAP_DMA_AMODE_CONSTANT ,
2008-10-08 11:01:39 +04:00
mcbsp - > phys_base + OMAP_MCBSP_REG_DRR1 ,
2005-11-10 17:26:50 +03:00
0 , 0 ) ;
2005-07-10 22:58:15 +04:00
2008-10-08 11:01:39 +04:00
omap_set_dma_dest_params ( mcbsp - > dma_rx_lch ,
2008-07-03 13:24:39 +04:00
dest_port ,
OMAP_DMA_AMODE_POST_INC ,
buffer ,
0 , 0 ) ;
2005-07-10 22:58:15 +04:00
2008-10-08 11:01:39 +04:00
omap_start_dma ( mcbsp - > dma_rx_lch ) ;
wait_for_completion ( & mcbsp - > rx_dma_completion ) ;
2008-07-03 13:24:39 +04:00
2005-07-10 22:58:15 +04:00
return 0 ;
}
2008-07-03 13:24:39 +04:00
EXPORT_SYMBOL ( omap_mcbsp_recv_buffer ) ;
2005-07-10 22:58:15 +04: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 13:24:39 +04:00
void omap_mcbsp_set_spi_mode ( unsigned int id ,
const struct omap_mcbsp_spi_cfg * spi_cfg )
2005-07-10 22:58:15 +04:00
{
2008-10-08 11:01:39 +04:00
struct omap_mcbsp * mcbsp ;
2005-07-10 22:58:15 +04:00
struct omap_mcbsp_reg_cfg mcbsp_cfg ;
2008-07-03 13:24:39 +04:00
if ( ! omap_mcbsp_check_valid_id ( id ) ) {
printk ( KERN_ERR " %s: Invalid id (%d) \n " , __func__ , id + 1 ) ;
2005-07-10 22:58:15 +04:00
return ;
2008-07-03 13:24:39 +04:00
}
2008-10-08 11:01:39 +04:00
mcbsp = id_to_mcbsp_ptr ( id ) ;
2005-07-10 22:58:15 +04: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 13:24:39 +04:00
/* Clock stop mode */
2005-07-10 22:58:15 +04: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 13:24:39 +04:00
mcbsp_cfg . srgr1 | = CLKGDV ( spi_cfg - > clk_div - 1 ) ;
2005-07-10 22:58:15 +04:00
mcbsp_cfg . pcr0 | = FSXM ;
mcbsp_cfg . srgr2 & = ~ FSGM ;
mcbsp_cfg . xcr2 | = XDATDLY ( 1 ) ;
mcbsp_cfg . rcr2 | = RDATDLY ( 1 ) ;
2008-07-03 13:24:39 +04:00
} else {
2005-07-10 22:58:15 +04: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 13:24:39 +04:00
EXPORT_SYMBOL ( omap_mcbsp_set_spi_mode ) ;
2005-07-10 22:58:15 +04:00
2009-08-20 17:18:11 +04:00
# ifdef CONFIG_ARCH_OMAP34XX
# define max_thres(m) (mcbsp->pdata->buffer_size)
# define valid_threshold(m, val) ((val) <= max_thres(m))
# define THRESHOLD_PROP_BUILDER(prop) \
static ssize_t prop # # _show ( struct device * dev , \
struct device_attribute * attr , char * buf ) \
{ \
struct omap_mcbsp * mcbsp = dev_get_drvdata ( dev ) ; \
\
return sprintf ( buf , " %u \n " , mcbsp - > prop ) ; \
} \
\
static ssize_t prop # # _store ( struct device * dev , \
struct device_attribute * attr , \
const char * buf , size_t size ) \
{ \
struct omap_mcbsp * mcbsp = dev_get_drvdata ( dev ) ; \
unsigned long val ; \
int status ; \
\
status = strict_strtoul ( buf , 0 , & val ) ; \
if ( status ) \
return status ; \
\
if ( ! valid_threshold ( mcbsp , val ) ) \
return - EDOM ; \
\
mcbsp - > prop = val ; \
return size ; \
} \
\
static DEVICE_ATTR ( prop , 0644 , prop # # _show , prop # # _store ) ;
THRESHOLD_PROP_BUILDER ( max_tx_thres ) ;
THRESHOLD_PROP_BUILDER ( max_rx_thres ) ;
2009-08-20 17:18:14 +04:00
static ssize_t dma_op_mode_show ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
struct omap_mcbsp * mcbsp = dev_get_drvdata ( dev ) ;
int dma_op_mode ;
spin_lock_irq ( & mcbsp - > lock ) ;
dma_op_mode = mcbsp - > dma_op_mode ;
spin_unlock_irq ( & mcbsp - > lock ) ;
return sprintf ( buf , " current mode: %d \n "
" possible mode values are: \n "
" %d - %s \n "
" %d - %s \n "
" %d - %s \n " ,
dma_op_mode ,
MCBSP_DMA_MODE_ELEMENT , " element mode " ,
MCBSP_DMA_MODE_THRESHOLD , " threshold mode " ,
MCBSP_DMA_MODE_FRAME , " frame mode " ) ;
}
static ssize_t dma_op_mode_store ( struct device * dev ,
struct device_attribute * attr ,
const char * buf , size_t size )
{
struct omap_mcbsp * mcbsp = dev_get_drvdata ( dev ) ;
unsigned long val ;
int status ;
status = strict_strtoul ( buf , 0 , & val ) ;
if ( status )
return status ;
spin_lock_irq ( & mcbsp - > lock ) ;
if ( ! mcbsp - > free ) {
size = - EBUSY ;
goto unlock ;
}
if ( val > MCBSP_DMA_MODE_FRAME | | val < MCBSP_DMA_MODE_ELEMENT ) {
size = - EINVAL ;
goto unlock ;
}
mcbsp - > dma_op_mode = val ;
unlock :
spin_unlock_irq ( & mcbsp - > lock ) ;
return size ;
}
static DEVICE_ATTR ( dma_op_mode , 0644 , dma_op_mode_show , dma_op_mode_store ) ;
2009-08-20 17:18:13 +04:00
static const struct attribute * additional_attrs [ ] = {
2009-08-20 17:18:11 +04:00
& dev_attr_max_tx_thres . attr ,
& dev_attr_max_rx_thres . attr ,
2009-08-20 17:18:14 +04:00
& dev_attr_dma_op_mode . attr ,
2009-08-20 17:18:11 +04:00
NULL ,
} ;
2009-08-20 17:18:13 +04:00
static const struct attribute_group additional_attr_group = {
. attrs = ( struct attribute * * ) additional_attrs ,
2009-08-20 17:18:11 +04:00
} ;
2009-08-20 17:18:13 +04:00
static inline int __devinit omap_additional_add ( struct device * dev )
2009-08-20 17:18:11 +04:00
{
2009-08-20 17:18:13 +04:00
return sysfs_create_group ( & dev - > kobj , & additional_attr_group ) ;
2009-08-20 17:18:11 +04:00
}
2009-08-20 17:18:13 +04:00
static inline void __devexit omap_additional_remove ( struct device * dev )
2009-08-20 17:18:11 +04:00
{
2009-08-20 17:18:13 +04:00
sysfs_remove_group ( & dev - > kobj , & additional_attr_group ) ;
2009-08-20 17:18:11 +04:00
}
static inline void __devinit omap34xx_device_init ( struct omap_mcbsp * mcbsp )
{
2009-08-20 17:18:14 +04:00
mcbsp - > dma_op_mode = MCBSP_DMA_MODE_ELEMENT ;
2009-08-20 17:18:11 +04:00
if ( cpu_is_omap34xx ( ) ) {
mcbsp - > max_tx_thres = max_thres ( mcbsp ) ;
mcbsp - > max_rx_thres = max_thres ( mcbsp ) ;
2009-08-20 17:18:14 +04:00
/*
* REVISIT : Set dmap_op_mode to THRESHOLD as default
* for mcbsp2 instances .
*/
2009-08-20 17:18:13 +04:00
if ( omap_additional_add ( mcbsp - > dev ) )
2009-08-20 17:18:11 +04:00
dev_warn ( mcbsp - > dev ,
2009-08-20 17:18:13 +04:00
" Unable to create additional controls \n " ) ;
2009-08-20 17:18:11 +04:00
} else {
mcbsp - > max_tx_thres = - EINVAL ;
mcbsp - > max_rx_thres = - EINVAL ;
}
}
static inline void __devexit omap34xx_device_exit ( struct omap_mcbsp * mcbsp )
{
if ( cpu_is_omap34xx ( ) )
2009-08-20 17:18:13 +04:00
omap_additional_remove ( mcbsp - > dev ) ;
2009-08-20 17:18:11 +04:00
}
# else
static inline void __devinit omap34xx_device_init ( struct omap_mcbsp * mcbsp ) { }
static inline void __devexit omap34xx_device_exit ( struct omap_mcbsp * mcbsp ) { }
# endif /* CONFIG_ARCH_OMAP34XX */
2005-07-10 22:58:15 +04: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 11:01:39 +04:00
static int __devinit omap_mcbsp_probe ( struct platform_device * pdev )
2008-07-03 13:24:39 +04:00
{
struct omap_mcbsp_platform_data * pdata = pdev - > dev . platform_data ;
2008-10-08 11:01:39 +04:00
struct omap_mcbsp * mcbsp ;
2008-07-03 13:24:39 +04:00
int id = pdev - > id - 1 ;
int ret = 0 ;
2005-07-10 22:58:15 +04:00
2008-07-03 13:24:39 +04: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 11:01:39 +04:00
if ( id > = omap_mcbsp_count ) {
2008-07-03 13:24:39 +04:00
dev_err ( & pdev - > dev , " Invalid McBSP device id (%d) \n " , id ) ;
ret = - EINVAL ;
goto exit ;
}
2008-10-08 11:01:39 +04: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 13:24:39 +04:00
2008-10-08 11:01:39 +04:00
mcbsp - > phys_base = pdata - > phys_base ;
mcbsp - > io_base = ioremap ( pdata - > phys_base , SZ_4K ) ;
if ( ! mcbsp - > io_base ) {
2008-09-04 17:25:42 +04:00
ret = - ENOMEM ;
goto err_ioremap ;
}
2008-07-03 13:24:39 +04:00
/* Default I/O is IRQ based */
2008-10-08 11:01:39 +04: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 13:24:39 +04:00
2009-01-23 13:26:46 +03: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 19:57:12 +03:00
2009-01-23 13:26:46 +03: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 13:24:39 +04:00
}
2008-10-08 11:01:39 +04:00
mcbsp - > pdata = pdata ;
mcbsp - > dev = & pdev - > dev ;
2009-01-23 13:26:46 +03:00
mcbsp_ptr [ id ] = mcbsp ;
2008-10-08 11:01:39 +04:00
platform_set_drvdata ( pdev , mcbsp ) ;
2009-08-20 17:18:11 +04:00
/* Initialize mcbsp properties for OMAP34XX if needed / applicable */
omap34xx_device_init ( mcbsp ) ;
2008-09-04 17:25:42 +04:00
return 0 ;
2008-07-03 13:24:39 +04:00
2009-01-23 13:26:46 +03:00
err_fclk :
clk_put ( mcbsp - > iclk ) ;
err_iclk :
2008-10-08 11:01:39 +04:00
iounmap ( mcbsp - > io_base ) ;
2008-09-04 17:25:42 +04:00
err_ioremap :
2009-01-23 13:26:46 +03:00
kfree ( mcbsp ) ;
2008-07-03 13:24:39 +04:00
exit :
return ret ;
}
2006-04-02 20:46:27 +04:00
2008-10-08 11:01:39 +04:00
static int __devexit omap_mcbsp_remove ( struct platform_device * pdev )
2005-07-10 22:58:15 +04:00
{
2008-07-03 13:24:39 +04:00
struct omap_mcbsp * mcbsp = platform_get_drvdata ( pdev ) ;
2005-07-10 22:58:15 +04:00
2008-07-03 13:24:39 +04:00
platform_set_drvdata ( pdev , NULL ) ;
if ( mcbsp ) {
2005-07-10 22:58:15 +04:00
2008-07-03 13:24:39 +04:00
if ( mcbsp - > pdata & & mcbsp - > pdata - > ops & &
mcbsp - > pdata - > ops - > free )
mcbsp - > pdata - > ops - > free ( mcbsp - > id ) ;
2005-07-10 22:58:15 +04:00
2009-08-20 17:18:11 +04:00
omap34xx_device_exit ( mcbsp ) ;
2009-01-23 13:26:46 +03:00
clk_disable ( mcbsp - > fclk ) ;
clk_disable ( mcbsp - > iclk ) ;
clk_put ( mcbsp - > fclk ) ;
clk_put ( mcbsp - > iclk ) ;
2008-07-03 13:24:39 +04:00
2008-09-04 17:25:42 +04:00
iounmap ( mcbsp - > io_base ) ;
2009-01-23 13:26:46 +03:00
mcbsp - > fclk = NULL ;
mcbsp - > iclk = NULL ;
2008-07-03 13:24:39 +04:00
mcbsp - > free = 0 ;
mcbsp - > dev = NULL ;
2005-07-10 22:58:15 +04:00
}
return 0 ;
}
2008-07-03 13:24:39 +04:00
static struct platform_driver omap_mcbsp_driver = {
. probe = omap_mcbsp_probe ,
2008-10-08 11:01:39 +04:00
. remove = __devexit_p ( omap_mcbsp_remove ) ,
2008-07-03 13:24:39 +04:00
. driver = {
. name = " omap-mcbsp " ,
} ,
} ;
int __init omap_mcbsp_init ( void )
{
/* Register the McBSP driver */
return platform_driver_register ( & omap_mcbsp_driver ) ;
}