@ -1,4 +1,7 @@
/*
* Copyright ( C ) 2016 Jagan Teki < jteki @ openedev . com >
* Christophe Ricard < christophe . ricard @ gmail . com >
*
* Copyright ( C ) 2010 Dirk Behme < dirk . behme @ googlemail . com >
*
* Driver for McSPI controller on OMAP3 . Based on davinci_spi . c
@ -15,10 +18,13 @@
*/
# include <common.h>
# include <dm.h>
# include <spi.h>
# include <malloc.h>
# include <asm/io.h>
DECLARE_GLOBAL_DATA_PTR ;
# if defined(CONFIG_AM33XX) || defined(CONFIG_AM43XX)
# define OMAP3_MCSPI1_BASE 0x48030100
# define OMAP3_MCSPI2_BASE 0x481A0100
@ -65,6 +71,8 @@
# define OMAP3_MCSPI_CHCTRL_DIS (0 << 0)
# define OMAP3_MCSPI_WAKEUPENABLE_WKEN BIT(0)
# define MCSPI_PINDIR_D0_IN_D1_OUT 0
# define MCSPI_PINDIR_D0_OUT_D1_IN 1
# define OMAP3_MCSPI_MAX_FREQ 48000000
# define SPI_WAIT_TIMEOUT 10
@ -94,312 +102,124 @@ struct mcspi {
/* channel3: 0x68 - 0x78, bus 0 */
} ;
struct omap3_spi_slave {
struct spi_slave slave ;
struct omap3_spi_priv {
struct mcspi * regs ;
unsigned int cs ;
unsigned int freq ;
unsigned int mode ;
unsigned int wordlen ;
unsigned int pin_dir : 1 ;
} ;
static inline struct omap3_spi_slave * to_omap3_spi ( struct spi_slave * slave )
static void omap3_spi_write_chconf ( struct omap3_spi_priv * priv , int val )
{
return container_of ( slave , struct omap3_spi_slave , slave ) ;
}
static void spi_reset ( struct omap3_spi_slave * ds )
{
unsigned int tmp ;
writel ( OMAP3_MCSPI_SYSCONFIG_SOFTRESET , & ds - > regs - > sysconfig ) ;
do {
tmp = readl ( & ds - > regs - > sysstatus ) ;
} while ( ! ( tmp & OMAP3_MCSPI_SYSSTATUS_RESETDONE ) ) ;
writel ( OMAP3_MCSPI_SYSCONFIG_AUTOIDLE |
OMAP3_MCSPI_SYSCONFIG_ENAWAKEUP |
OMAP3_MCSPI_SYSCONFIG_SMARTIDLE ,
& ds - > regs - > sysconfig ) ;
writel ( OMAP3_MCSPI_WAKEUPENABLE_WKEN , & ds - > regs - > wakeupenable ) ;
}
static void omap3_spi_write_chconf ( struct omap3_spi_slave * ds , int val )
{
writel ( val , & ds - > regs - > channel [ ds - > slave . cs ] . chconf ) ;
writel ( val , & priv - > regs - > channel [ priv - > cs ] . chconf ) ;
/* Flash post writes to make immediate effect */
readl ( & ds - > regs - > channel [ ds - > slave . cs ] . chconf ) ;
readl ( & priv - > regs - > channel [ priv - > cs ] . chconf ) ;
}
static void omap3_spi_set_enable ( struct omap3_spi_slave * ds , int enable )
static void omap3_spi_set_enable ( struct omap3_spi_priv * priv , int enable )
{
writel ( enable , & ds - > regs - > channel [ ds - > slave . cs ] . chctrl ) ;
writel ( enable , & priv - > regs - > channel [ priv - > cs ] . chctrl ) ;
/* Flash post writes to make immediate effect */
readl ( & ds - > regs - > channel [ ds - > slave . cs ] . chctrl ) ;
}
void spi_init ( )
{
/* do nothing */
}
struct spi_slave * spi_setup_slave ( unsigned int bus , unsigned int cs ,
unsigned int max_hz , unsigned int mode )
{
struct omap3_spi_slave * ds ;
struct mcspi * regs ;
/*
* OMAP3 McSPI ( MultiChannel SPI ) has 4 busses ( modules )
* with different number of chip selects ( CS , channels ) :
* McSPI1 has 4 CS ( bus 0 , cs 0 - 3 )
* McSPI2 has 2 CS ( bus 1 , cs 0 - 1 )
* McSPI3 has 2 CS ( bus 2 , cs 0 - 1 )
* McSPI4 has 1 CS ( bus 3 , cs 0 )
*/
switch ( bus ) {
case 0 :
regs = ( struct mcspi * ) OMAP3_MCSPI1_BASE ;
break ;
# ifdef OMAP3_MCSPI2_BASE
case 1 :
regs = ( struct mcspi * ) OMAP3_MCSPI2_BASE ;
break ;
# endif
# ifdef OMAP3_MCSPI3_BASE
case 2 :
regs = ( struct mcspi * ) OMAP3_MCSPI3_BASE ;
break ;
# endif
# ifdef OMAP3_MCSPI4_BASE
case 3 :
regs = ( struct mcspi * ) OMAP3_MCSPI4_BASE ;
break ;
# endif
default :
printf ( " SPI error: unsupported bus %i. \
Supported busses 0 - 3 \ n " , bus);
return NULL ;
}
if ( ( ( bus = = 0 ) & & ( cs > 3 ) ) | |
( ( bus = = 1 ) & & ( cs > 1 ) ) | |
( ( bus = = 2 ) & & ( cs > 1 ) ) | |
( ( bus = = 3 ) & & ( cs > 0 ) ) ) {
printf ( " SPI error: unsupported chip select %i \
on bus % i \ n " , cs, bus);
return NULL ;
}
if ( max_hz > OMAP3_MCSPI_MAX_FREQ ) {
printf ( " SPI error: unsupported frequency %i Hz. \
Max frequency is 48 Mhz \ n " , max_hz);
return NULL ;
}
if ( mode > SPI_MODE_3 ) {
printf ( " SPI error: unsupported SPI mode %i \n " , mode ) ;
return NULL ;
}
ds = spi_alloc_slave ( struct omap3_spi_slave , bus , cs ) ;
if ( ! ds ) {
printf ( " SPI error: malloc of SPI structure failed \n " ) ;
return NULL ;
}
ds - > regs = regs ;
ds - > freq = max_hz ;
ds - > mode = mode ;
return & ds - > slave ;
}
void spi_free_slave ( struct spi_slave * slave )
{
struct omap3_spi_slave * ds = to_omap3_spi ( slave ) ;
free ( ds ) ;
readl ( & priv - > regs - > channel [ priv - > cs ] . chctrl ) ;
}
int spi_claim_bus ( struct spi_slave * slave )
{
struct omap3_spi_slave * ds = to_omap3_spi ( slave ) ;
unsigned int conf , div = 0 ;
/* McSPI global module configuration */
/*
* setup when switching from ( reset default ) slave mode
* to single - channel master mode
*/
spi_reset ( ds ) ;
conf = readl ( & ds - > regs - > modulctrl ) ;
conf & = ~ ( OMAP3_MCSPI_MODULCTRL_STEST | OMAP3_MCSPI_MODULCTRL_MS ) ;
conf | = OMAP3_MCSPI_MODULCTRL_SINGLE ;
writel ( conf , & ds - > regs - > modulctrl ) ;
/* McSPI individual channel configuration */
/* Calculate clock divisor. Valid range: 0x0 - 0xC ( /1 - /4096 ) */
if ( ds - > freq ) {
while ( div < = 0xC & & ( OMAP3_MCSPI_MAX_FREQ / ( 1 < < div ) )
> ds - > freq )
div + + ;
} else
div = 0xC ;
conf = readl ( & ds - > regs - > channel [ ds - > slave . cs ] . chconf ) ;
/* standard 4-wire master mode: SCK, MOSI/out, MISO/in, nCS
* REVISIT : this controller could support SPI_3WIRE mode .
*/
# ifdef CONFIG_OMAP3_SPI_D0_D1_SWAPPED
/*
* Some boards have D0 wired as MOSI / D1 as MISO instead of
* The normal D0 as MISO / D1 as MOSI .
*/
conf & = ~ OMAP3_MCSPI_CHCONF_DPE0 ;
conf | = OMAP3_MCSPI_CHCONF_IS | OMAP3_MCSPI_CHCONF_DPE1 ;
# else
conf & = ~ ( OMAP3_MCSPI_CHCONF_IS | OMAP3_MCSPI_CHCONF_DPE1 ) ;
conf | = OMAP3_MCSPI_CHCONF_DPE0 ;
# endif
/* wordlength */
conf & = ~ OMAP3_MCSPI_CHCONF_WL_MASK ;
conf | = ( ds - > slave . wordlen - 1 ) < < 7 ;
/* set chipselect polarity; manage with FORCE */
if ( ! ( ds - > mode & SPI_CS_HIGH ) )
conf | = OMAP3_MCSPI_CHCONF_EPOL ; /* active-low; normal */
else
conf & = ~ OMAP3_MCSPI_CHCONF_EPOL ;
/* set clock divisor */
conf & = ~ OMAP3_MCSPI_CHCONF_CLKD_MASK ;
conf | = div < < 2 ;
/* set SPI mode 0..3 */
if ( ds - > mode & SPI_CPOL )
conf | = OMAP3_MCSPI_CHCONF_POL ;
else
conf & = ~ OMAP3_MCSPI_CHCONF_POL ;
if ( ds - > mode & SPI_CPHA )
conf | = OMAP3_MCSPI_CHCONF_PHA ;
else
conf & = ~ OMAP3_MCSPI_CHCONF_PHA ;
/* Transmit & receive mode */
conf & = ~ OMAP3_MCSPI_CHCONF_TRM_MASK ;
omap3_spi_write_chconf ( ds , conf ) ;
return 0 ;
}
void spi_release_bus ( struct spi_slave * slave )
{
struct omap3_spi_slave * ds = to_omap3_spi ( slave ) ;
/* Reset the SPI hardware */
spi_reset ( ds ) ;
}
static int omap3_spi_write ( struct spi_slave * slave , unsigned int len ,
static int omap3_spi_write ( struct omap3_spi_priv * priv , unsigned int len ,
const void * txp , unsigned long flags )
{
struct omap3_spi_slave * ds = to_omap3_spi ( slave ) ;
int i ;
ulong start ;
int chconf = readl ( & ds - > regs - > channel [ ds - > slave . cs ] . chconf ) ;
int i , chconf ;
chconf = readl ( & priv - > regs - > channel [ priv - > cs ] . chconf ) ;
/* Enable the channel */
omap3_spi_set_enable ( ds , OMAP3_MCSPI_CHCTRL_EN ) ;
omap3_spi_set_enable ( priv , OMAP3_MCSPI_CHCTRL_EN ) ;
chconf & = ~ ( OMAP3_MCSPI_CHCONF_TRM_MASK | OMAP3_MCSPI_CHCONF_WL_MASK ) ;
chconf | = ( ds - > slave . wordlen - 1 ) < < 7 ;
chconf | = ( priv - > wordlen - 1 ) < < 7 ;
chconf | = OMAP3_MCSPI_CHCONF_TRM_TX_ONLY ;
chconf | = OMAP3_MCSPI_CHCONF_FORCE ;
omap3_spi_write_chconf ( ds , chconf ) ;
omap3_spi_write_chconf ( priv , chconf ) ;
for ( i = 0 ; i < len ; i + + ) {
/* wait till TX register is empty (TXS == 1) */
start = get_timer ( 0 ) ;
while ( ! ( readl ( & ds - > regs - > channel [ ds - > slave . cs ] . chstat ) &
while ( ! ( readl ( & priv - > regs - > channel [ priv - > cs ] . chstat ) &
OMAP3_MCSPI_CHSTAT_TXS ) ) {
if ( get_timer ( start ) > SPI_WAIT_TIMEOUT ) {
printf ( " SPI TXS timed out, status=0x%08x \n " ,
readl ( & ds - > regs - > channel [ ds - > slave . cs ] . chstat ) ) ;
readl ( & priv - > regs - > channel [ priv - > cs ] . chstat ) ) ;
return - 1 ;
}
}
/* Write the data */
unsigned int * tx = & ds - > regs - > channel [ ds - > slave . cs ] . tx ;
if ( ds - > slave . wordlen > 16 )
unsigned int * tx = & priv - > regs - > channel [ priv - > cs ] . tx ;
if ( priv - > wordlen > 16 )
writel ( ( ( u32 * ) txp ) [ i ] , tx ) ;
else if ( ds - > slave . wordlen > 8 )
else if ( priv - > wordlen > 8 )
writel ( ( ( u16 * ) txp ) [ i ] , tx ) ;
else
writel ( ( ( u8 * ) txp ) [ i ] , tx ) ;
}
/* wait to finish of transfer */
while ( ( readl ( & ds - > regs - > channel [ ds - > slave . cs ] . chstat ) &
( OMAP3_MCSPI_CHSTAT_EOT | OMAP3_MCSPI_CHSTAT_TXS ) ) ! =
( OMAP3_MCSPI_CHSTAT_EOT | OMAP3_MCSPI_CHSTAT_TXS ) ) ;
while ( ( readl ( & priv - > regs - > channel [ priv - > cs ] . chstat ) &
( OMAP3_MCSPI_CHSTAT_EOT | OMAP3_MCSPI_CHSTAT_TXS ) ) ! =
( OMAP3_MCSPI_CHSTAT_EOT | OMAP3_MCSPI_CHSTAT_TXS ) )
;
/* Disable the channel otherwise the next immediate RX will get affected */
omap3_spi_set_enable ( ds , OMAP3_MCSPI_CHCTRL_DIS ) ;
omap3_spi_set_enable ( priv , OMAP3_MCSPI_CHCTRL_DIS ) ;
if ( flags & SPI_XFER_END ) {
chconf & = ~ OMAP3_MCSPI_CHCONF_FORCE ;
omap3_spi_write_chconf ( ds , chconf ) ;
omap3_spi_write_chconf ( priv , chconf ) ;
}
return 0 ;
}
static int omap3_spi_read ( struct spi_slave * slave , unsigned int len ,
static int omap3_spi_read ( struct omap3_spi_priv * priv , unsigned int len ,
void * rxp , unsigned long flags )
{
struct omap3_spi_slave * ds = to_omap3_spi ( slave ) ;
int i ;
int i , chconf ;
ulong start ;
int chconf = readl ( & ds - > regs - > channel [ ds - > slave . cs ] . chconf ) ;
chconf = readl ( & priv - > regs - > channel [ priv - > cs ] . chconf ) ;
/* Enable the channel */
omap3_spi_set_enable ( ds , OMAP3_MCSPI_CHCTRL_EN ) ;
omap3_spi_set_enable ( priv , OMAP3_MCSPI_CHCTRL_EN ) ;
chconf & = ~ ( OMAP3_MCSPI_CHCONF_TRM_MASK | OMAP3_MCSPI_CHCONF_WL_MASK ) ;
chconf | = ( ds - > slave . wordlen - 1 ) < < 7 ;
chconf | = ( priv - > wordlen - 1 ) < < 7 ;
chconf | = OMAP3_MCSPI_CHCONF_TRM_RX_ONLY ;
chconf | = OMAP3_MCSPI_CHCONF_FORCE ;
omap3_spi_write_chconf ( ds , chconf ) ;
omap3_spi_write_chconf ( priv , chconf ) ;
writel ( 0 , & ds - > regs - > channel [ ds - > slave . cs ] . tx ) ;
writel ( 0 , & priv - > regs - > channel [ priv - > cs ] . tx ) ;
for ( i = 0 ; i < len ; i + + ) {
start = get_timer ( 0 ) ;
/* Wait till RX register contains data (RXS == 1) */
while ( ! ( readl ( & ds - > regs - > channel [ ds - > slave . cs ] . chstat ) &
while ( ! ( readl ( & priv - > regs - > channel [ priv - > cs ] . chstat ) &
OMAP3_MCSPI_CHSTAT_RXS ) ) {
if ( get_timer ( start ) > SPI_WAIT_TIMEOUT ) {
printf ( " SPI RXS timed out, status=0x%08x \n " ,
readl ( & ds - > regs - > channel [ ds - > slave . cs ] . chstat ) ) ;
readl ( & priv - > regs - > channel [ priv - > cs ] . chstat ) ) ;
return - 1 ;
}
}
/* Disable the channel to prevent furher receiving */
if ( i = = ( len - 1 ) )
omap3_spi_set_enable ( ds , OMAP3_MCSPI_CHCTRL_DIS ) ;
if ( i = = ( len - 1 ) )
omap3_spi_set_enable ( priv , OMAP3_MCSPI_CHCTRL_DIS ) ;
/* Read the data */
unsigned int * rx = & ds - > regs - > channel [ ds - > slave . cs ] . rx ;
if ( ds - > slave . wordlen > 16 )
unsigned int * rx = & priv - > regs - > channel [ priv - > cs ] . rx ;
if ( priv - > wordlen > 16 )
( ( u32 * ) rxp ) [ i ] = readl ( rx ) ;
else if ( ds - > slave . wordlen > 8 )
else if ( priv - > wordlen > 8 )
( ( u16 * ) rxp ) [ i ] = ( u16 ) readl ( rx ) ;
else
( ( u8 * ) rxp ) [ i ] = ( u8 ) readl ( rx ) ;
@ -407,133 +227,452 @@ static int omap3_spi_read(struct spi_slave *slave, unsigned int len,
if ( flags & SPI_XFER_END ) {
chconf & = ~ OMAP3_MCSPI_CHCONF_FORCE ;
omap3_spi_write_chconf ( ds , chconf ) ;
omap3_spi_write_chconf ( priv , chconf ) ;
}
return 0 ;
}
/*McSPI Transmit Receive Mode*/
static int omap3_spi_txrx ( struct spi_slave * slave , unsigned int len ,
static int omap3_spi_txrx ( struct omap3_spi_priv * priv , unsigned int len ,
const void * txp , void * rxp , unsigned long flags )
{
struct omap3_spi_slave * ds = to_omap3_spi ( slave ) ;
ulong start ;
int chconf = readl ( & ds - > regs - > channel [ ds - > slave . cs ] . chconf ) ;
int i = 0 ;
int chconf , i = 0 ;
chconf = readl ( & priv - > regs - > channel [ priv - > cs ] . chconf ) ;
/*Enable SPI channel*/
omap3_spi_set_enable ( ds , OMAP3_MCSPI_CHCTRL_EN ) ;
omap3_spi_set_enable ( priv , OMAP3_MCSPI_CHCTRL_EN ) ;
/*set TRANSMIT-RECEIVE Mode*/
chconf & = ~ ( OMAP3_MCSPI_CHCONF_TRM_MASK | OMAP3_MCSPI_CHCONF_WL_MASK ) ;
chconf | = ( ds - > slave . wordlen - 1 ) < < 7 ;
chconf | = ( priv - > wordlen - 1 ) < < 7 ;
chconf | = OMAP3_MCSPI_CHCONF_FORCE ;
omap3_spi_write_chconf ( ds , chconf ) ;
omap3_spi_write_chconf ( priv , chconf ) ;
/*Shift in and out 1 byte at time*/
for ( i = 0 ; i < len ; i + + ) {
/* Write: wait for TX empty (TXS == 1)*/
start = get_timer ( 0 ) ;
while ( ! ( readl ( & ds - > regs - > channel [ ds - > slave . cs ] . chstat ) &
while ( ! ( readl ( & priv - > regs - > channel [ priv - > cs ] . chstat ) &
OMAP3_MCSPI_CHSTAT_TXS ) ) {
if ( get_timer ( start ) > SPI_WAIT_TIMEOUT ) {
printf ( " SPI TXS timed out, status=0x%08x \n " ,
readl ( & ds - > regs - > channel [ ds - > slave . cs ] . chstat ) ) ;
readl ( & priv - > regs - > channel [ priv - > cs ] . chstat ) ) ;
return - 1 ;
}
}
/* Write the data */
unsigned int * tx = & ds - > regs - > channel [ ds - > slave . cs ] . tx ;
if ( ds - > slave . wordlen > 16 )
unsigned int * tx = & priv - > regs - > channel [ priv - > cs ] . tx ;
if ( priv - > wordlen > 16 )
writel ( ( ( u32 * ) txp ) [ i ] , tx ) ;
else if ( ds - > slave . wordlen > 8 )
else if ( priv - > wordlen > 8 )
writel ( ( ( u16 * ) txp ) [ i ] , tx ) ;
else
writel ( ( ( u8 * ) txp ) [ i ] , tx ) ;
/*Read: wait for RX containing data (RXS == 1)*/
start = get_timer ( 0 ) ;
while ( ! ( readl ( & ds - > regs - > channel [ ds - > slave . cs ] . chstat ) &
while ( ! ( readl ( & priv - > regs - > channel [ priv - > cs ] . chstat ) &
OMAP3_MCSPI_CHSTAT_RXS ) ) {
if ( get_timer ( start ) > SPI_WAIT_TIMEOUT ) {
printf ( " SPI RXS timed out, status=0x%08x \n " ,
readl ( & ds - > regs - > channel [ ds - > slave . cs ] . chstat ) ) ;
readl ( & priv - > regs - > channel [ priv - > cs ] . chstat ) ) ;
return - 1 ;
}
}
/* Read the data */
unsigned int * rx = & ds - > regs - > channel [ ds - > slave . cs ] . rx ;
if ( ds - > slave . wordlen > 16 )
unsigned int * rx = & priv - > regs - > channel [ priv - > cs ] . rx ;
if ( priv - > wordlen > 16 )
( ( u32 * ) rxp ) [ i ] = readl ( rx ) ;
else if ( ds - > slave . wordlen > 8 )
else if ( priv - > wordlen > 8 )
( ( u16 * ) rxp ) [ i ] = ( u16 ) readl ( rx ) ;
else
( ( u8 * ) rxp ) [ i ] = ( u8 ) readl ( rx ) ;
}
/* Disable the channel */
omap3_spi_set_enable ( ds , OMAP3_MCSPI_CHCTRL_DIS ) ;
omap3_spi_set_enable ( priv , OMAP3_MCSPI_CHCTRL_DIS ) ;
/*if transfer must be terminated disable the channel*/
if ( flags & SPI_XFER_END ) {
chconf & = ~ OMAP3_MCSPI_CHCONF_FORCE ;
omap3_spi_write_chconf ( ds , chconf ) ;
omap3_spi_write_chconf ( priv , chconf ) ;
}
return 0 ;
}
int spi_xfer ( struct spi_slave * slave , unsigned int bitlen ,
const void * dout , void * din , unsigned long flags )
static int _ spi_xfer( struct omap3_spi_priv * priv , unsigned int bitlen ,
const void * dout , void * din , unsigned long flags )
{
struct omap3_spi_slave * ds = to_omap3_spi ( slave ) ;
unsigned int len ;
int ret = - 1 ;
if ( ds - > slave . wordlen < 4 | | ds - > slave . wordlen > 32 ) {
printf ( " omap3_spi: invalid wordlen %d \n " , ds - > slave . wordlen ) ;
if ( priv - > wordlen < 4 | | priv - > wordlen > 32 ) {
printf ( " omap3_spi: invalid wordlen %d \n " , priv - > wordlen ) ;
return - 1 ;
}
if ( bitlen % ds - > slave . wordlen )
if ( bitlen % priv - > wordlen )
return - 1 ;
len = bitlen / ds - > slave . wordlen ;
len = bitlen / priv - > wordlen ;
if ( bitlen = = 0 ) { /* only change CS */
int chconf = readl ( & ds - > regs - > channel [ ds - > slave . cs ] . chconf ) ;
int chconf = readl ( & priv - > regs - > channel [ priv - > cs ] . chconf ) ;
if ( flags & SPI_XFER_BEGIN ) {
omap3_spi_set_enable ( ds , OMAP3_MCSPI_CHCTRL_EN ) ;
omap3_spi_set_enable ( priv , OMAP3_MCSPI_CHCTRL_EN ) ;
chconf | = OMAP3_MCSPI_CHCONF_FORCE ;
omap3_spi_write_chconf ( ds , chconf ) ;
omap3_spi_write_chconf ( priv , chconf ) ;
}
if ( flags & SPI_XFER_END ) {
chconf & = ~ OMAP3_MCSPI_CHCONF_FORCE ;
omap3_spi_write_chconf ( ds , chconf ) ;
omap3_spi_set_enable ( ds , OMAP3_MCSPI_CHCTRL_DIS ) ;
omap3_spi_write_chconf ( priv , chconf ) ;
omap3_spi_set_enable ( priv , OMAP3_MCSPI_CHCTRL_DIS ) ;
}
ret = 0 ;
} else {
if ( dout ! = NULL & & din ! = NULL )
ret = omap3_spi_txrx ( slave , len , dout , din , flags ) ;
ret = omap3_spi_txrx ( priv , len , dout , din , flags ) ;
else if ( dout ! = NULL )
ret = omap3_spi_write ( slave , len , dout , flags ) ;
ret = omap3_spi_write ( priv , len , dout , flags ) ;
else if ( din ! = NULL )
ret = omap3_spi_read ( slave , len , din , flags ) ;
ret = omap3_spi_read ( priv , len , din , flags ) ;
}
return ret ;
}
int spi_cs_is_valid ( unsigned int bus , unsigned int cs )
static void _omap3_spi_set_speed ( struct omap3_spi_priv * priv )
{
uint32_t confr , div = 0 ;
confr = readl ( & priv - > regs - > channel [ priv - > cs ] . chconf ) ;
/* Calculate clock divisor. Valid range: 0x0 - 0xC ( /1 - /4096 ) */
if ( priv - > freq ) {
while ( div < = 0xC & & ( OMAP3_MCSPI_MAX_FREQ / ( 1 < < div ) )
> priv - > freq )
div + + ;
} else {
div = 0xC ;
}
/* set clock divisor */
confr & = ~ OMAP3_MCSPI_CHCONF_CLKD_MASK ;
confr | = div < < 2 ;
omap3_spi_write_chconf ( priv , confr ) ;
}
static void _omap3_spi_set_mode ( struct omap3_spi_priv * priv )
{
uint32_t confr ;
confr = readl ( & priv - > regs - > channel [ priv - > cs ] . chconf ) ;
/* standard 4-wire master mode: SCK, MOSI/out, MISO/in, nCS
* REVISIT : this controller could support SPI_3WIRE mode .
*/
if ( priv - > pin_dir = = MCSPI_PINDIR_D0_IN_D1_OUT ) {
confr & = ~ ( OMAP3_MCSPI_CHCONF_IS | OMAP3_MCSPI_CHCONF_DPE1 ) ;
confr | = OMAP3_MCSPI_CHCONF_DPE0 ;
} else {
confr & = ~ OMAP3_MCSPI_CHCONF_DPE0 ;
confr | = OMAP3_MCSPI_CHCONF_IS | OMAP3_MCSPI_CHCONF_DPE1 ;
}
/* set SPI mode 0..3 */
confr & = ~ ( OMAP3_MCSPI_CHCONF_POL | OMAP3_MCSPI_CHCONF_PHA ) ;
if ( priv - > mode & SPI_CPHA )
confr | = OMAP3_MCSPI_CHCONF_PHA ;
if ( priv - > mode & SPI_CPOL )
confr | = OMAP3_MCSPI_CHCONF_POL ;
/* set chipselect polarity; manage with FORCE */
if ( ! ( priv - > mode & SPI_CS_HIGH ) )
confr | = OMAP3_MCSPI_CHCONF_EPOL ; /* active-low; normal */
else
confr & = ~ OMAP3_MCSPI_CHCONF_EPOL ;
/* Transmit & receive mode */
confr & = ~ OMAP3_MCSPI_CHCONF_TRM_MASK ;
omap3_spi_write_chconf ( priv , confr ) ;
}
static void _omap3_spi_set_wordlen ( struct omap3_spi_priv * priv )
{
unsigned int confr ;
/* McSPI individual channel configuration */
confr = readl ( & priv - > regs - > channel [ priv - > wordlen ] . chconf ) ;
/* wordlength */
confr & = ~ OMAP3_MCSPI_CHCONF_WL_MASK ;
confr | = ( priv - > wordlen - 1 ) < < 7 ;
omap3_spi_write_chconf ( priv , confr ) ;
}
static void spi_reset ( struct mcspi * regs )
{
unsigned int tmp ;
writel ( OMAP3_MCSPI_SYSCONFIG_SOFTRESET , & regs - > sysconfig ) ;
do {
tmp = readl ( & regs - > sysstatus ) ;
} while ( ! ( tmp & OMAP3_MCSPI_SYSSTATUS_RESETDONE ) ) ;
writel ( OMAP3_MCSPI_SYSCONFIG_AUTOIDLE |
OMAP3_MCSPI_SYSCONFIG_ENAWAKEUP |
OMAP3_MCSPI_SYSCONFIG_SMARTIDLE , & regs - > sysconfig ) ;
writel ( OMAP3_MCSPI_WAKEUPENABLE_WKEN , & regs - > wakeupenable ) ;
}
static void _omap3_spi_claim_bus ( struct omap3_spi_priv * priv )
{
unsigned int conf ;
spi_reset ( priv - > regs ) ;
/*
* setup when switching from ( reset default ) slave mode
* to single - channel master mode
*/
conf = readl ( & priv - > regs - > modulctrl ) ;
conf & = ~ ( OMAP3_MCSPI_MODULCTRL_STEST | OMAP3_MCSPI_MODULCTRL_MS ) ;
conf | = OMAP3_MCSPI_MODULCTRL_SINGLE ;
writel ( conf , & priv - > regs - > modulctrl ) ;
_omap3_spi_set_mode ( priv ) ;
_omap3_spi_set_speed ( priv ) ;
}
# ifndef CONFIG_DM_SPI
struct omap3_spi_slave {
struct spi_slave slave ;
struct omap3_spi_priv spi_priv ;
} ;
struct omap3_spi_priv * priv ;
static inline struct omap3_spi_slave * to_omap3_spi ( struct spi_slave * slave )
{
return container_of ( slave , struct omap3_spi_slave , slave ) ;
}
void spi_init ( void )
{
return 1 ;
/* do nothing */
}
void spi_cs_activate ( struct spi_slave * slave )
void spi_free_slav e ( struct spi_slave * slave )
{
struct omap3_spi_slave * ds = to_omap3_spi ( slave ) ;
free ( ds ) ;
}
int spi_claim_bus ( struct spi_slave * slave )
{
_omap3_spi_claim_bus ( priv ) ;
_omap3_spi_set_wordlen ( priv ) ;
_omap3_spi_set_mode ( priv ) ;
_omap3_spi_set_speed ( priv ) ;
return 0 ;
}
void spi_cs_deactivate ( struct spi_slave * slave )
void spi_release_bus ( struct spi_slave * slave )
{
/* Reset the SPI hardware */
spi_reset ( priv - > regs ) ;
}
struct spi_slave * spi_setup_slave ( unsigned int bus , unsigned int cs ,
unsigned int max_hz , unsigned int mode )
{
struct omap3_spi_slave * ds ;
struct mcspi * regs ;
/*
* OMAP3 McSPI ( MultiChannel SPI ) has 4 busses ( modules )
* with different number of chip selects ( CS , channels ) :
* McSPI1 has 4 CS ( bus 0 , cs 0 - 3 )
* McSPI2 has 2 CS ( bus 1 , cs 0 - 1 )
* McSPI3 has 2 CS ( bus 2 , cs 0 - 1 )
* McSPI4 has 1 CS ( bus 3 , cs 0 )
*/
switch ( bus ) {
case 0 :
regs = ( struct mcspi * ) OMAP3_MCSPI1_BASE ;
break ;
# ifdef OMAP3_MCSPI2_BASE
case 1 :
regs = ( struct mcspi * ) OMAP3_MCSPI2_BASE ;
break ;
# endif
# ifdef OMAP3_MCSPI3_BASE
case 2 :
regs = ( struct mcspi * ) OMAP3_MCSPI3_BASE ;
break ;
# endif
# ifdef OMAP3_MCSPI4_BASE
case 3 :
regs = ( struct mcspi * ) OMAP3_MCSPI4_BASE ;
break ;
# endif
default :
printf ( " SPI error: unsupported bus %i. Supported busses 0 - 3 \n " , bus ) ;
return NULL ;
}
if ( ( ( bus = = 0 ) & & ( cs > 3 ) ) | |
( ( bus = = 1 ) & & ( cs > 1 ) ) | |
( ( bus = = 2 ) & & ( cs > 1 ) ) | |
( ( bus = = 3 ) & & ( cs > 0 ) ) ) {
printf ( " SPI error: unsupported chip select %i on bus %i \n " , cs , bus ) ;
return NULL ;
}
if ( max_hz > OMAP3_MCSPI_MAX_FREQ ) {
printf ( " SPI error: unsupported frequency %i Hz. Max frequency is 48 Mhz \n " , max_hz ) ;
return NULL ;
}
if ( mode > SPI_MODE_3 ) {
printf ( " SPI error: unsupported SPI mode %i \n " , mode ) ;
return NULL ;
}
ds = spi_alloc_slave ( struct omap3_spi_slave , bus , cs ) ;
if ( ! ds ) {
printf ( " SPI error: malloc of SPI structure failed \n " ) ;
return NULL ;
}
priv = & ds - > spi_priv ;
priv - > regs = regs ;
priv - > cs = cs ;
priv - > freq = max_hz ;
priv - > mode = mode ;
priv - > wordlen = ds - > slave . wordlen ;
# ifdef CONFIG_OMAP3_SPI_D0_D1_SWAPPED
priv - > pin_dir = MCSPI_PINDIR_D0_OUT_D1_IN ;
# endif
return & ds - > slave ;
}
int spi_xfer ( struct spi_slave * slave , unsigned int bitlen ,
const void * dout , void * din , unsigned long flags )
{ return _spi_xfer ( priv , bitlen , dout , din , flags ) ; }
# else
static int omap3_spi_claim_bus ( struct udevice * dev )
{
struct udevice * bus = dev - > parent ;
struct omap3_spi_priv * priv = dev_get_priv ( bus ) ;
struct dm_spi_slave_platdata * slave_plat = dev_get_parent_platdata ( dev ) ;
priv - > cs = slave_plat - > cs ;
priv - > mode = slave_plat - > mode ;
priv - > freq = slave_plat - > max_hz ;
_omap3_spi_claim_bus ( priv ) ;
return 0 ;
}
static int omap3_spi_release_bus ( struct udevice * dev )
{
struct udevice * bus = dev - > parent ;
struct omap3_spi_priv * priv = dev_get_priv ( bus ) ;
/* Reset the SPI hardware */
spi_reset ( priv - > regs ) ;
return 0 ;
}
static int omap3_spi_set_wordlen ( struct udevice * dev , unsigned int wordlen )
{
struct udevice * bus = dev - > parent ;
struct omap3_spi_priv * priv = dev_get_priv ( bus ) ;
struct dm_spi_slave_platdata * slave_plat = dev_get_parent_platdata ( dev ) ;
priv - > cs = slave_plat - > cs ;
priv - > wordlen = wordlen ;
_omap3_spi_set_wordlen ( priv ) ;
return 0 ;
}
static int omap3_spi_probe ( struct udevice * dev )
{
struct omap3_spi_priv * priv = dev_get_priv ( dev ) ;
const void * blob = gd - > fdt_blob ;
int node = dev - > of_offset ;
priv - > regs = ( struct mcspi * ) dev_get_addr ( dev ) ;
priv - > pin_dir = fdtdec_get_uint ( blob , node , " ti,pindir-d0-out-d1-in " ,
MCSPI_PINDIR_D0_IN_D1_OUT ) ;
priv - > wordlen = SPI_DEFAULT_WORDLEN ;
return 0 ;
}
static int omap3_spi_xfer ( struct udevice * dev , unsigned int bitlen ,
const void * dout , void * din , unsigned long flags )
{
struct udevice * bus = dev - > parent ;
struct omap3_spi_priv * priv = dev_get_priv ( bus ) ;
return _spi_xfer ( priv , bitlen , dout , din , flags ) ;
}
static int omap3_spi_set_speed ( struct udevice * bus , unsigned int speed )
{
return 0 ;
}
static int omap3_spi_set_mode ( struct udevice * bus , uint mode )
{
return 0 ;
}
static const struct dm_spi_ops omap3_spi_ops = {
. claim_bus = omap3_spi_claim_bus ,
. release_bus = omap3_spi_release_bus ,
. set_wordlen = omap3_spi_set_wordlen ,
. xfer = omap3_spi_xfer ,
. set_speed = omap3_spi_set_speed ,
. set_mode = omap3_spi_set_mode ,
/*
* cs_info is not needed , since we require all chip selects to be
* in the device tree explicitly
*/
} ;
static const struct udevice_id omap3_spi_ids [ ] = {
{ . compatible = " ti,omap2-mcspi " } ,
{ . compatible = " ti,omap4-mcspi " } ,
{ }
} ;
U_BOOT_DRIVER ( omap3_spi ) = {
. name = " omap3_spi " ,
. id = UCLASS_SPI ,
. of_match = omap3_spi_ids ,
. probe = omap3_spi_probe ,
. ops = & omap3_spi_ops ,
. priv_auto_alloc_size = sizeof ( struct omap3_spi_priv ) ,
. probe = omap3_spi_probe ,
} ;
# endif