diff options
Diffstat (limited to 'common')
| -rw-r--r-- | common/cmd_df.c | 37 | ||||
| -rw-r--r-- | common/cmd_spi.c | 42 | ||||
| -rw-r--r-- | common/soft_spi.c | 124 | 
3 files changed, 155 insertions, 48 deletions
| diff --git a/common/cmd_df.c b/common/cmd_df.c new file mode 100644 index 000000000..5f650442c --- /dev/null +++ b/common/cmd_df.c @@ -0,0 +1,37 @@ +/* + * Command for accessing DataFlash. + * + * Copyright (C) 2008 Atmel Corporation + */ +#include <common.h> +#include <df.h> + +static int do_df(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ +	const char *cmd; + +	/* need at least two arguments */ +	if (argc < 2) +		goto usage; + +	cmd = argv[1]; + +	if (strcmp(cmd, "init") == 0) { +		df_init(0, 0, 1000000); +		return 0; +	} + +	if (strcmp(cmd, "info") == 0) { +		df_show_info(); +		return 0; +	} + +usage: +	printf("Usage:\n%s\n", cmdtp->usage); +	return 1; +} + +U_BOOT_CMD( +	sf,	2,	1,	do_serial_flash, +	"sf	- Serial flash sub-system\n", +	"probe [bus:]cs		- init flash device on given SPI bus and CS\n") diff --git a/common/cmd_spi.c b/common/cmd_spi.c index 760442214..40ee7e7dd 100644 --- a/common/cmd_spi.c +++ b/common/cmd_spi.c @@ -37,20 +37,20 @@  #   define MAX_SPI_BYTES 32	/* Maximum number of bytes we can handle */  #endif -/* - * External table of chip select functions (see the appropriate board - * support for the actual definition of the table). - */ -extern spi_chipsel_type spi_chipsel[]; -extern int spi_chipsel_cnt; +#ifndef CONFIG_DEFAULT_SPI_BUS +#   define CONFIG_DEFAULT_SPI_BUS	0 +#endif +#ifndef CONFIG_DEFAULT_SPI_MODE +#   define CONFIG_DEFAULT_SPI_MODE	SPI_MODE_0 +#endif  /*   * Values from last command.   */ -static int   device; -static int   bitlen; -static uchar dout[MAX_SPI_BYTES]; -static uchar din[MAX_SPI_BYTES]; +static unsigned int	device; +static int   		bitlen; +static uchar 		dout[MAX_SPI_BYTES]; +static uchar 		din[MAX_SPI_BYTES];  /*   * SPI read/write @@ -65,6 +65,7 @@ static uchar din[MAX_SPI_BYTES];  int do_spi (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])  { +	struct spi_slave *slave;  	char  *cp = 0;  	uchar tmp;  	int   j; @@ -101,19 +102,24 @@ int do_spi (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])  		}  	} -	if ((device < 0) || (device >=  spi_chipsel_cnt)) { -		printf("Invalid device %d, giving up.\n", device); -		return 1; -	}  	if ((bitlen < 0) || (bitlen >  (MAX_SPI_BYTES * 8))) {  		printf("Invalid bitlen %d, giving up.\n", bitlen);  		return 1;  	} -	debug ("spi_chipsel[%d] = %08X\n", -		device, (uint)spi_chipsel[device]); +	/* FIXME: Make these parameters run-time configurable */ +	slave = spi_setup_slave(CONFIG_DEFAULT_SPI_BUS, device, 1000000, +			CONFIG_DEFAULT_SPI_MODE); +	if (!slave) { +		printf("Invalid device %d, giving up.\n", device); +		return 1; +	} + +	debug ("spi chipsel = %08X\n", device); -	if(spi_xfer(spi_chipsel[device], bitlen, dout, din) != 0) { +	spi_claim_bus(slave); +	if(spi_xfer(slave, bitlen, dout, din, +				SPI_XFER_BEGIN | SPI_XFER_END) != 0) {  		printf("Error with the SPI transaction.\n");  		rcode = 1;  	} else { @@ -123,6 +129,8 @@ int do_spi (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])  		}  		printf("\n");  	} +	spi_release_bus(slave); +	spi_free_slave(slave);  	return rcode;  } 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);  } |