@ -62,6 +62,7 @@
# define MXC_CSPICTRL_MAXBITS 0x1f
# define MXC_CSPIPERIOD_32KHZ (1 << 15)
# define MAX_SPI_BYTES 4
static unsigned long spi_bases [ ] = {
0x43fa4000 ,
@ -95,6 +96,7 @@ static unsigned long spi_bases[] = {
# define MXC_CSPICTRL_RXOVF (1 << 6)
# define MXC_CSPIPERIOD_32KHZ (1 << 15)
# define MAX_SPI_BYTES 32
/* Bit position inside CTRL register to be associated with SS */
# define MXC_CSPICTRL_CHAN 18
@ -252,13 +254,15 @@ static s32 spi_cfg(struct mxc_spi_slave *mxcs, unsigned int cs,
}
# endif
static u32 spi_xchg_single ( struct spi_slave * slave , u32 data , int bitlen ,
unsigned long flags )
int spi_xchg_single ( struct spi_slave * slave , unsigned int bitlen ,
const u8 * dout , u8 * din , unsigned long flags )
{
struct mxc_spi_slave * mxcs = to_mxc_spi_slave ( slave ) ;
int nbytes = ( bitlen + 7 ) / 8 ;
u32 data , cnt , i ;
if ( flags & SPI_XFER_BEGIN )
spi_cs_activate ( slave ) ;
debug ( " %s: bitlen %d dout 0x%x din 0x%x \n " ,
__func__ , bitlen , ( u32 ) dout , ( u32 ) din ) ;
mxcs - > ctrl_reg = ( mxcs - > ctrl_reg &
~ MXC_CSPICTRL_BITCOUNT ( MXC_CSPICTRL_MAXBITS ) ) |
@ -273,8 +277,46 @@ static u32 spi_xchg_single(struct spi_slave *slave, u32 data, int bitlen,
reg_write ( mxcs - > base + MXC_CSPISTAT ,
MXC_CSPICTRL_TC | MXC_CSPICTRL_RXOVF ) ;
/*
* The SPI controller works only with words ,
* check if less than a word is sent .
* Access to the FIFO is only 32 bit
*/
if ( bitlen % 32 ) {
data = 0 ;
cnt = ( bitlen % 32 ) / 8 ;
if ( dout ) {
for ( i = 0 ; i < cnt ; i + + ) {
data = ( data < < 8 ) | ( * dout + + & 0xFF ) ;
}
}
debug ( " Sending SPI 0x%x \n " , data ) ;
reg_write ( mxcs - > base + MXC_CSPITXDATA , data ) ;
nbytes - = cnt ;
}
data = 0 ;
while ( nbytes > 0 ) {
data = 0 ;
if ( dout ) {
/* Buffer is not 32-bit aligned */
if ( ( unsigned long ) dout & 0x03 ) {
data = 0 ;
for ( i = 0 ; i < 4 ; i + + , data < < = 8 ) {
data = ( data < < 8 ) | ( * dout + + & 0xFF ) ;
}
} else {
data = * ( u32 * ) dout ;
data = cpu_to_be32 ( data ) ;
}
dout + = 4 ;
}
debug ( " Sending SPI 0x%x \n " , data ) ;
reg_write ( mxcs - > base + MXC_CSPITXDATA , data ) ;
nbytes - = 4 ;
}
/* FIFO is written, now starts the transfer setting the XCH bit */
reg_write ( mxcs - > base + MXC_CSPICTRL , mxcs - > ctrl_reg |
@ -288,49 +330,78 @@ static u32 spi_xchg_single(struct spi_slave *slave, u32 data, int bitlen,
reg_write ( mxcs - > base + MXC_CSPISTAT ,
MXC_CSPICTRL_TC | MXC_CSPICTRL_RXOVF ) ;
nbytes = ( bitlen + 7 ) / 8 ;
cnt = nbytes % 32 ;
if ( bitlen % 32 ) {
data = reg_read ( mxcs - > base + MXC_CSPIRXDATA ) ;
debug ( " SPI Rx: 0x%x \n " , data ) ;
cnt = ( bitlen % 32 ) / 8 ;
debug ( " SPI Rx unaligned: 0x%x \n " , data ) ;
if ( din ) {
for ( i = 0 ; i < cnt ; i + + , data > > = 8 ) {
* din + + = data & 0xFF ;
}
}
nbytes - = cnt ;
}
if ( flags & SPI_XFER_END )
spi_cs_deactivate ( slave ) ;
while ( nbytes > 0 ) {
u32 tmp ;
tmp = reg_read ( mxcs - > base + MXC_CSPIRXDATA ) ;
data = cpu_to_be32 ( tmp ) ;
debug ( " SPI Rx: 0x%x 0x%x \n " , tmp , data ) ;
cnt = min ( nbytes , sizeof ( data ) ) ;
if ( din ) {
memcpy ( din , & data , cnt ) ;
din + = cnt ;
}
nbytes - = cnt ;
}
return data ;
return 0 ;
}
int spi_xfer ( struct spi_slave * slave , unsigned int bitlen , const void * dout ,
void * din , unsigned long flags )
{
int n_blks = ( bitlen + 31 ) / 32 ;
u32 * out_l , * in_l ;
int i ;
int n_bytes = ( bitlen + 7 ) / 8 ;
int n_bits ;
int ret ;
u32 blk_size ;
u8 * p_outbuf = ( u8 * ) dout ;
u8 * p_inbuf = ( u8 * ) din ;
if ( ( int ) dout & 3 | | ( int ) din & 3 ) {
printf ( " Error: unaligned buffers in: %p, out: %p \n " , din , dout ) ;
return 1 ;
}
if ( ! slave )
return - 1 ;
/* This driver is currently partly broken, alert the user */
if ( bitlen > 16 & & ( bitlen % 32 ) ) {
printf ( " Error: SPI transfer with bitlen=%d is broken. \n " ,
bitlen ) ;
return 1 ;
}
if ( flags & SPI_XFER_BEGIN )
spi_cs_activate ( slave ) ;
for ( i = 0 , in_l = ( u32 * ) din , out_l = ( u32 * ) dout ;
i < n_blks ;
i + + , in_l + + , out_l + + , bitlen - = 32 ) {
u32 data = spi_xchg_single ( slave , * out_l , bitlen , flags ) ;
while ( n_bytes > 0 ) {
/* Check if we're only transfering 8 or 16 bits */
if ( ! i ) {
if ( bitlen < 9 )
* ( u8 * ) din = data ;
else if ( bitlen < 17 )
* ( u16 * ) din = data ;
if ( n_bytes < MAX_SPI_BYTES )
blk_size = n_bytes ;
else
* in_l = data ;
blk_size = MAX_SPI_BYTES ;
n_bits = blk_size * 8 ;
ret = spi_xchg_single ( slave , n_bits , p_outbuf , p_inbuf , 0 ) ;
if ( ret )
return ret ;
if ( dout )
p_outbuf + = blk_size ;
if ( din )
p_inbuf + = blk_size ;
n_bytes - = blk_size ;
}
if ( flags & SPI_XFER_END ) {
spi_cs_deactivate ( slave ) ;
}
return 0 ;
@ -378,8 +449,10 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
return NULL ;
mxcs = malloc ( sizeof ( struct mxc_spi_slave ) ) ;
if ( ! mxcs )
if ( ! mxcs ) {
puts ( " mxc_spi: SPI Slave not allocated ! \n " ) ;
return NULL ;
}
ret = decode_cs ( mxcs , cs ) ;
if ( ret < 0 ) {