@ -26,6 +26,206 @@
DECLARE_GLOBAL_DATA_PTR ;
# ifndef CONFIG_DM_SPI
static int spi_has_wdrbt ( struct atmel_spi_slave * slave )
{
unsigned int ver ;
ver = spi_readl ( slave , VERSION ) ;
return ( ATMEL_SPI_VERSION_REV ( ver ) > = 0x210 ) ;
}
void spi_init ( )
{
}
struct spi_slave * spi_setup_slave ( unsigned int bus , unsigned int cs ,
unsigned int max_hz , unsigned int mode )
{
struct atmel_spi_slave * as ;
unsigned int scbr ;
u32 csrx ;
void * regs ;
if ( ! spi_cs_is_valid ( bus , cs ) )
return NULL ;
switch ( bus ) {
case 0 :
regs = ( void * ) ATMEL_BASE_SPI0 ;
break ;
# ifdef ATMEL_BASE_SPI1
case 1 :
regs = ( void * ) ATMEL_BASE_SPI1 ;
break ;
# endif
# ifdef ATMEL_BASE_SPI2
case 2 :
regs = ( void * ) ATMEL_BASE_SPI2 ;
break ;
# endif
# ifdef ATMEL_BASE_SPI3
case 3 :
regs = ( void * ) ATMEL_BASE_SPI3 ;
break ;
# endif
default :
return NULL ;
}
scbr = ( get_spi_clk_rate ( bus ) + max_hz - 1 ) / max_hz ;
if ( scbr > ATMEL_SPI_CSRx_SCBR_MAX )
/* Too low max SCK rate */
return NULL ;
if ( scbr < 1 )
scbr = 1 ;
csrx = ATMEL_SPI_CSRx_SCBR ( scbr ) ;
csrx | = ATMEL_SPI_CSRx_BITS ( ATMEL_SPI_BITS_8 ) ;
if ( ! ( mode & SPI_CPHA ) )
csrx | = ATMEL_SPI_CSRx_NCPHA ;
if ( mode & SPI_CPOL )
csrx | = ATMEL_SPI_CSRx_CPOL ;
as = spi_alloc_slave ( struct atmel_spi_slave , bus , cs ) ;
if ( ! as )
return NULL ;
as - > regs = regs ;
as - > mr = ATMEL_SPI_MR_MSTR | ATMEL_SPI_MR_MODFDIS
| ATMEL_SPI_MR_PCS ( ~ ( 1 < < cs ) & 0xf ) ;
if ( spi_has_wdrbt ( as ) )
as - > mr | = ATMEL_SPI_MR_WDRBT ;
spi_writel ( as , CSR ( cs ) , csrx ) ;
return & as - > slave ;
}
void spi_free_slave ( struct spi_slave * slave )
{
struct atmel_spi_slave * as = to_atmel_spi ( slave ) ;
free ( as ) ;
}
int spi_claim_bus ( struct spi_slave * slave )
{
struct atmel_spi_slave * as = to_atmel_spi ( slave ) ;
/* Enable the SPI hardware */
spi_writel ( as , CR , ATMEL_SPI_CR_SPIEN ) ;
/*
* Select the slave . This should set SCK to the correct
* initial state , etc .
*/
spi_writel ( as , MR , as - > mr ) ;
return 0 ;
}
void spi_release_bus ( struct spi_slave * slave )
{
struct atmel_spi_slave * as = to_atmel_spi ( slave ) ;
/* Disable the SPI hardware */
spi_writel ( as , CR , ATMEL_SPI_CR_SPIDIS ) ;
}
int spi_xfer ( struct spi_slave * slave , unsigned int bitlen ,
const void * dout , void * din , unsigned long flags )
{
struct atmel_spi_slave * as = to_atmel_spi ( slave ) ;
unsigned int len_tx ;
unsigned int len_rx ;
unsigned int len ;
u32 status ;
const u8 * txp = dout ;
u8 * rxp = din ;
u8 value ;
if ( bitlen = = 0 )
/* Finish any previously submitted transfers */
goto out ;
/*
* TODO : The controller can do non - multiple - of - 8 bit
* transfers , but this driver currently doesn ' t support it .
*
* It ' s also not clear how such transfers are supposed to be
* represented as a stream of bytes . . . this is a limitation of
* the current SPI interface .
*/
if ( bitlen % 8 ) {
/* Errors always terminate an ongoing transfer */
flags | = SPI_XFER_END ;
goto out ;
}
len = bitlen / 8 ;
/*
* The controller can do automatic CS control , but it is
* somewhat quirky , and it doesn ' t really buy us much anyway
* in the context of U - Boot .
*/
if ( flags & SPI_XFER_BEGIN ) {
spi_cs_activate ( slave ) ;
/*
* sometimes the RDR is not empty when we get here ,
* in theory that should not happen , but it DOES happen .
* Read it here to be on the safe side .
* That also clears the OVRES flag . Required if the
* following loop exits due to OVRES !
*/
spi_readl ( as , RDR ) ;
}
for ( len_tx = 0 , len_rx = 0 ; len_rx < len ; ) {
status = spi_readl ( as , SR ) ;
if ( status & ATMEL_SPI_SR_OVRES )
return - 1 ;
if ( len_tx < len & & ( status & ATMEL_SPI_SR_TDRE ) ) {
if ( txp )
value = * txp + + ;
else
value = 0 ;
spi_writel ( as , TDR , value ) ;
len_tx + + ;
}
if ( status & ATMEL_SPI_SR_RDRF ) {
value = spi_readl ( as , RDR ) ;
if ( rxp )
* rxp + + = value ;
len_rx + + ;
}
}
out :
if ( flags & SPI_XFER_END ) {
/*
* Wait until the transfer is completely done before
* we deactivate CS .
*/
do {
status = spi_readl ( as , SR ) ;
} while ( ! ( status & ATMEL_SPI_SR_TXEMPTY ) ) ;
spi_cs_deactivate ( slave ) ;
}
return 0 ;
}
# else
# define MAX_CS_COUNT 4
struct atmel_spi_platdata {
@ -315,3 +515,4 @@ U_BOOT_DRIVER(atmel_spi) = {
. priv_auto_alloc_size = sizeof ( struct atmel_spi_priv ) ,
. probe = atmel_spi_probe ,
} ;
# endif