@ -9,6 +9,7 @@
*/
# include <common.h>
# include <dm.h>
# include <malloc.h>
# include <spi.h>
# include <asm/io.h>
@ -18,6 +19,83 @@
# endif
# include <asm/arch-mvebu/spi.h>
static void _spi_cs_activate ( struct kwspi_registers * reg )
{
setbits_le32 ( & reg - > ctrl , KWSPI_CSN_ACT ) ;
}
static void _spi_cs_deactivate ( struct kwspi_registers * reg )
{
clrbits_le32 ( & reg - > ctrl , KWSPI_CSN_ACT ) ;
}
static int _spi_xfer ( struct kwspi_registers * reg , unsigned int bitlen ,
const void * dout , void * din , unsigned long flags )
{
unsigned int tmpdout , tmpdin ;
int tm , isread = 0 ;
debug ( " spi_xfer: dout %p din %p bitlen %u \n " , dout , din , bitlen ) ;
if ( flags & SPI_XFER_BEGIN )
_spi_cs_activate ( reg ) ;
/*
* handle data in 8 - bit chunks
* TBD : 2 byte xfer mode to be enabled
*/
clrsetbits_le32 ( & reg - > cfg , KWSPI_XFERLEN_MASK , KWSPI_XFERLEN_1BYTE ) ;
while ( bitlen > 4 ) {
debug ( " loopstart bitlen %d \n " , bitlen ) ;
tmpdout = 0 ;
/* Shift data so it's msb-justified */
if ( dout )
tmpdout = * ( u32 * ) dout & 0xff ;
clrbits_le32 ( & reg - > irq_cause , KWSPI_SMEMRDIRQ ) ;
writel ( tmpdout , & reg - > dout ) ; /* Write the data out */
debug ( " *** spi_xfer: ... %08x written, bitlen %d \n " ,
tmpdout , bitlen ) ;
/*
* Wait for SPI transmit to get out
* or time out ( 1 second = 1000 ms )
* The NE event must be read and cleared first
*/
for ( tm = 0 , isread = 0 ; tm < KWSPI_TIMEOUT ; + + tm ) {
if ( readl ( & reg - > irq_cause ) & KWSPI_SMEMRDIRQ ) {
isread = 1 ;
tmpdin = readl ( & reg - > din ) ;
debug ( " spi_xfer: din %p..%08x read \n " ,
din , tmpdin ) ;
if ( din ) {
* ( ( u8 * ) din ) = ( u8 ) tmpdin ;
din + = 1 ;
}
if ( dout )
dout + = 1 ;
bitlen - = 8 ;
}
if ( isread )
break ;
}
if ( tm > = KWSPI_TIMEOUT )
printf ( " *** spi_xfer: Time out during SPI transfer \n " ) ;
debug ( " loopend bitlen %d \n " , bitlen ) ;
}
if ( flags & SPI_XFER_END )
_spi_cs_deactivate ( reg ) ;
return 0 ;
}
# ifndef CONFIG_DM_SPI
static struct kwspi_registers * spireg =
( struct kwspi_registers * ) MVEBU_SPI_BASE ;
@ -145,16 +223,6 @@ void spi_init(void)
{
}
static void _spi_cs_activate ( struct kwspi_registers * reg )
{
setbits_le32 ( & reg - > ctrl , KWSPI_CSN_ACT ) ;
}
static void _spi_cs_deactivate ( struct kwspi_registers * reg )
{
clrbits_le32 ( & reg - > ctrl , KWSPI_CSN_ACT ) ;
}
void spi_cs_activate ( struct spi_slave * slave )
{
_spi_cs_activate ( spireg ) ;
@ -165,73 +233,101 @@ void spi_cs_deactivate(struct spi_slave *slave)
_spi_cs_deactivate ( spireg ) ;
}
static int _ spi_xfer( struct kwspi_registers * reg , unsigned int bitlen ,
const void * dout , void * din , unsigned long flags )
int spi_xfer ( struct spi_slave * slave , unsigned int bitlen ,
const void * dout , void * din , unsigned long flags )
{
unsigned int tmp dout, tmp din;
int tm , isread = 0 ;
return _spi_xfer ( spireg , bitlen , dout , din , flags ) ;
}
debug ( " spi_xfer: dout %p din %p bitlen %u \n " , dout , din , bitlen ) ;
# else
if ( flags & SPI_XFER_BEGIN )
_spi_cs_activate ( reg ) ;
/* Here now the DM part */
/*
* handle data in 8 - bit chunks
* TBD : 2 byte xfer mode to be enabled
*/
clrsetbits_le32 ( & reg - > cfg , KWSPI_XFERLEN_MASK , KWSPI_XFERLEN_1BYTE ) ;
struct mvebu_spi_platdata {
struct kwspi_registers * spireg ;
} ;
while ( bitlen > 4 ) {
debug ( " loopstart bitlen %d \n " , bitlen ) ;
tmpdout = 0 ;
struct mvebu_spi_priv {
struct kwspi_registers * spireg ;
} ;
/* Shift data so it's msb-justified */
if ( dout )
tmpdout = * ( u32 * ) dout & 0xff ;
static int mvebu_spi_set_speed ( struct udevice * bus , uint hz )
{
struct mvebu_spi_platdata * plat = dev_get_platdata ( bus ) ;
struct kwspi_registers * reg = plat - > spireg ;
u32 data ;
clrbits_le32 ( & reg - > irq_cause , KWSPI_SMEMRDIRQ ) ;
writel ( tmpdout , & reg - > dout ) ; /* Write the data out */
debug ( " *** spi_xfer: ... %08x written, bitlen %d \n " ,
tmpdout , bitlen ) ;
/* calculate spi clock prescaller using max_hz */
data = ( ( CONFIG_SYS_TCLK / 2 ) / hz ) + 0x10 ;
data = data < KWSPI_CLKPRESCL_MIN ? KWSPI_CLKPRESCL_MIN : data ;
data = data > KWSPI_CLKPRESCL_MASK ? KWSPI_CLKPRESCL_MASK : data ;
/*
* Wait for SPI transmit to get out
* or time out ( 1 second = 1000 ms )
* The NE event must be read and cleared first
*/
for ( tm = 0 , isread = 0 ; tm < KWSPI_TIMEOUT ; + + tm ) {
if ( readl ( & reg - > irq_cause ) & KWSPI_SMEMRDIRQ ) {
isread = 1 ;
tmpdin = readl ( & reg - > din ) ;
debug ( " spi_xfer: din %p..%08x read \n " ,
din , tmpdin ) ;
/* program spi clock prescaler using max_hz */
writel ( KWSPI_ADRLEN_3BYTE | data , & reg - > cfg ) ;
debug ( " data = 0x%08x \n " , data ) ;
if ( din ) {
* ( ( u8 * ) din ) = ( u8 ) tmpdin ;
din + = 1 ;
}
if ( dout )
dout + = 1 ;
bitlen - = 8 ;
}
if ( isread )
break ;
}
if ( tm > = KWSPI_TIMEOUT )
printf ( " *** spi_xfer: Time out during SPI transfer \n " ) ;
return 0 ;
}
debug ( " loopend bitlen %d \n " , bitlen ) ;
}
static int mvebu_spi_set_mode ( struct udevice * bus , uint mode )
{
return 0 ;
}
if ( flags & SPI_XFER_END )
_spi_cs_deactivate ( reg ) ;
static int mvebu_spi_xfer ( struct udevice * dev , unsigned int bitlen ,
const void * dout , void * din , unsigned long flags )
{
struct udevice * bus = dev - > parent ;
struct mvebu_spi_platdata * plat = dev_get_platdata ( bus ) ;
return _spi_xfer ( plat - > spireg , bitlen , dout , din , flags ) ;
}
static int mvebu_spi_probe ( struct udevice * bus )
{
struct mvebu_spi_platdata * plat = dev_get_platdata ( bus ) ;
struct kwspi_registers * reg = plat - > spireg ;
writel ( KWSPI_SMEMRDY , & reg - > ctrl ) ;
writel ( KWSPI_SMEMRDIRQ , & reg - > irq_cause ) ;
writel ( KWSPI_IRQMASK , & reg - > irq_mask ) ;
return 0 ;
}
int spi_xfer ( struct spi_slave * slave , unsigned int bitlen ,
const void * dout , void * din , unsigned long flags )
static int mvebu_spi_ofdata_to_platdata ( struct udevice * bus )
{
return _spi_xfer ( spireg , bitlen , dout , din , flags ) ;
struct mvebu_spi_platdata * plat = dev_get_platdata ( bus ) ;
plat - > spireg = ( struct kwspi_registers * ) dev_get_addr ( bus ) ;
return 0 ;
}
static const struct dm_spi_ops mvebu_spi_ops = {
. xfer = mvebu_spi_xfer ,
. set_speed = mvebu_spi_set_speed ,
. set_mode = mvebu_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 mvebu_spi_ids [ ] = {
{ . compatible = " marvell,armada-380-spi " } ,
{ . compatible = " marvell,armada-xp-spi " } ,
{ }
} ;
U_BOOT_DRIVER ( mvebu_spi ) = {
. name = " mvebu_spi " ,
. id = UCLASS_SPI ,
. of_match = mvebu_spi_ids ,
. ops = & mvebu_spi_ops ,
. ofdata_to_platdata = mvebu_spi_ofdata_to_platdata ,
. platdata_auto_alloc_size = sizeof ( struct mvebu_spi_platdata ) ,
. priv_auto_alloc_size = sizeof ( struct mvebu_spi_priv ) ,
. probe = mvebu_spi_probe ,
} ;
# endif