diff options
Diffstat (limited to 'common/soft_spi.c')
| -rw-r--r-- | common/soft_spi.c | 124 | 
1 files changed, 93 insertions, 31 deletions
| diff --git a/common/soft_spi.c b/common/soft_spi.c index e4250616c..c13165030 100644 --- a/common/soft_spi.c +++ b/common/soft_spi.c @@ -29,6 +29,8 @@  #if defined(CONFIG_SOFT_SPI) +#include <malloc.h> +  /*-----------------------------------------------------------------------   * Definitions   */ @@ -39,6 +41,15 @@  #define PRINTD(fmt,args...)  #endif +struct soft_spi_slave { +	struct spi_slave slave; +	unsigned int mode; +}; + +static inline struct soft_spi_slave *to_soft_spi(struct spi_slave *slave) +{ +	return container_of(slave, struct soft_spi_slave, slave); +}  /*=====================================================================*/  /*                         Public Functions                            */ @@ -56,6 +67,57 @@ void spi_init (void)  #endif  } +struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, +		unsigned int max_hz, unsigned int mode) +{ +	struct soft_spi_slave *ss; + +	if (!spi_cs_is_valid(bus, cs)) +		return NULL; + +	ss = malloc(sizeof(struct soft_spi_slave)); +	if (!ss) +		return NULL; + +	ss->slave.bus = bus; +	ss->slave.cs = cs; +	ss->mode = mode; + +	/* TODO: Use max_hz to limit the SCK rate */ + +	return &ss->slave; +} + +void spi_free_slave(struct spi_slave *slave) +{ +	struct soft_spi_slave *ss = to_soft_spi(slave); + +	free(ss); +} + +int spi_claim_bus(struct spi_slave *slave) +{ +#ifdef CFG_IMMR +	volatile immap_t *immr = (immap_t *)CFG_IMMR; +#endif +	struct soft_spi_slave *ss = to_soft_spi(slave); + +	/* +	 * Make sure the SPI clock is in idle state as defined for +	 * this slave. +	 */ +	if (ss->mode & SPI_CPOL) +		SPI_SCL(1); +	else +		SPI_SCL(0); + +	return 0; +} + +void spi_release_bus(struct spi_slave *slave) +{ +	/* Nothing to do */ +}  /*-----------------------------------------------------------------------   * SPI transfer @@ -68,50 +130,54 @@ void spi_init (void)   * and "din" can point to the same memory location, in which case the   * input data overwrites the output data (since both are buffered by   * temporary variables, this is OK). - * - * If the chipsel() function is not NULL, it is called with a parameter - * of '1' (chip select active) at the start of the transfer and again with - * a parameter of '0' at the end of the transfer. - * - * If the chipsel() function _is_ NULL, it the responsibility of the - * caller to make the appropriate chip select active before calling - * spi_xfer() and making it inactive after spi_xfer() returns.   */ -int  spi_xfer(spi_chipsel_type chipsel, int bitlen, uchar *dout, uchar *din) +int  spi_xfer(struct spi_slave *slave, unsigned int bitlen, +		const void *dout, void *din, unsigned long flags)  {  #ifdef CFG_IMMR  	volatile immap_t *immr = (immap_t *)CFG_IMMR;  #endif -	uchar tmpdin  = 0; -	uchar tmpdout = 0; -	int   j; +	struct soft_spi_slave *ss = to_soft_spi(slave); +	uchar		tmpdin  = 0; +	uchar		tmpdout = 0; +	const u8	*txd = dout; +	u8		*rxd = din; +	int		cpol = ss->mode & SPI_CPOL; +	int		cpha = ss->mode & SPI_CPHA; +	unsigned int	j; -	PRINTD("spi_xfer: chipsel %08X dout %08X din %08X bitlen %d\n", -		(int)chipsel, *(uint *)dout, *(uint *)din, bitlen); +	PRINTD("spi_xfer: slave %u:%u dout %08X din %08X bitlen %u\n", +		slave->bus, slave->cs, *(uint *)txd, *(uint *)rxd, bitlen); -	if(chipsel != NULL) { -		(*chipsel)(1);	/* select the target chip */ -	} +	if (flags & SPI_XFER_BEGIN) +		spi_cs_activate(slave);  	for(j = 0; j < bitlen; j++) {  		/*  		 * Check if it is time to work on a new byte.  		 */  		if((j % 8) == 0) { -			tmpdout = *dout++; +			tmpdout = *txd++;  			if(j != 0) { -				*din++ = tmpdin; +				*rxd++ = tmpdin;  			}  			tmpdin  = 0;  		} -		SPI_SCL(0); + +		if (!cpha) +			SPI_SCL(!cpol);  		SPI_SDA(tmpdout & 0x80);  		SPI_DELAY; -		SPI_SCL(1); +		if (cpha) +			SPI_SCL(!cpol); +		else +			SPI_SCL(cpol); +		tmpdin	<<= 1; +		tmpdin	|= SPI_READ; +		tmpdout	<<= 1;  		SPI_DELAY; -		tmpdin  <<= 1; -		tmpdin   |= SPI_READ; -		tmpdout <<= 1; +		if (cpha) +			SPI_SCL(cpol);  	}  	/*  	 * If the number of bits isn't a multiple of 8, shift the last @@ -120,14 +186,10 @@ int  spi_xfer(spi_chipsel_type chipsel, int bitlen, uchar *dout, uchar *din)  	 */  	if((bitlen % 8) != 0)  		tmpdin <<= 8 - (bitlen % 8); -	*din++ = tmpdin; - -	SPI_SCL(0);		/* SPI wants the clock left low for idle */ +	*rxd++ = tmpdin; -	if(chipsel != NULL) { -		(*chipsel)(0);	/* deselect the target chip */ - -	} +	if (flags & SPI_XFER_END) +		spi_cs_deactivate(slave);  	return(0);  } |