diff options
| -rw-r--r-- | board/amcc/taihu/taihu.c | 16 | ||||
| -rw-r--r-- | board/freescale/mpc8349emds/mpc8349emds.c | 25 | ||||
| -rw-r--r-- | board/sacsng/sacsng.c | 35 | ||||
| -rw-r--r-- | board/ssv/adnpesc1/adnpesc1.c | 27 | ||||
| -rw-r--r-- | common/cmd_df.c | 37 | ||||
| -rw-r--r-- | common/cmd_spi.c | 42 | ||||
| -rw-r--r-- | common/soft_spi.c | 124 | ||||
| -rw-r--r-- | cpu/nios/spi.c | 79 | ||||
| -rw-r--r-- | drivers/rtc/ds1306.c | 67 | ||||
| -rw-r--r-- | drivers/rtc/mc13783-rtc.c | 43 | ||||
| -rw-r--r-- | drivers/spi/mpc8xxx_spi.c | 54 | ||||
| -rw-r--r-- | drivers/spi/mxc_spi.c | 88 | ||||
| -rw-r--r-- | include/configs/imx31_litekit.h | 3 | ||||
| -rw-r--r-- | include/configs/mx31ads.h | 3 | ||||
| -rw-r--r-- | include/spi.h | 150 | 
15 files changed, 584 insertions, 209 deletions
| diff --git a/board/amcc/taihu/taihu.c b/board/amcc/taihu/taihu.c index eedde597b..891b4d924 100644 --- a/board/amcc/taihu/taihu.c +++ b/board/amcc/taihu/taihu.c @@ -165,16 +165,20 @@ unsigned char spi_read(void)  	return (unsigned char)gpio_read_in_bit(SPI_DIN_GPIO15);  } -void taihu_spi_chipsel(int cs) +int spi_cs_is_valid(unsigned int bus, unsigned int cs)  { -	gpio_write_bit(SPI_CS_GPIO0, cs); +	return bus == 0 && cs == 0;  } -spi_chipsel_type spi_chipsel[]= { -	taihu_spi_chipsel -}; +void spi_cs_activate(struct spi_slave *slave) +{ +	gpio_write_bit(SPI_CS_GPIO0, 1); +} -int spi_chipsel_cnt = sizeof(spi_chipsel) / sizeof(spi_chipsel[0]); +void spi_cs_deactivate(struct spi_slave *slave) +{ +	gpio_write_bit(SPI_CS_GPIO0, 0); +}  #ifdef CONFIG_PCI  static unsigned char int_lines[32] = { diff --git a/board/freescale/mpc8349emds/mpc8349emds.c b/board/freescale/mpc8349emds/mpc8349emds.c index 6c825969d..e18e68e8c 100644 --- a/board/freescale/mpc8349emds/mpc8349emds.c +++ b/board/freescale/mpc8349emds/mpc8349emds.c @@ -257,25 +257,24 @@ void sdram_init(void)  #define SPI_CS_MASK	0x80000000 -void spi_eeprom_chipsel(int cs) +int spi_cs_is_valid(unsigned int bus, unsigned int cs) +{ +	return bus == 0 && cs == 0; +} + +void spi_cs_activate(struct spi_slave *slave)  {  	volatile gpio83xx_t *iopd = &((immap_t *)CFG_IMMR)->gpio[0]; -	if (cs) -		iopd->dat &= ~SPI_CS_MASK; -	else -		iopd->dat |=  SPI_CS_MASK; +	iopd->dat &= ~SPI_CS_MASK;  } -/* - * The SPI command uses this table of functions for controlling the SPI - * chip selects. - */ -spi_chipsel_type spi_chipsel[] = { -	spi_eeprom_chipsel, -}; -int spi_chipsel_cnt = sizeof(spi_chipsel) / sizeof(spi_chipsel[0]); +void spi_cs_deactivate(struct spi_slave *slave) +{ +	volatile gpio83xx_t *iopd = &((immap_t *)CFG_IMMR)->gpio[0]; +	iopd->dat |=  SPI_CS_MASK; +}  #endif /* CONFIG_HARD_SPI */  #if defined(CONFIG_OF_BOARD_SETUP) diff --git a/board/sacsng/sacsng.c b/board/sacsng/sacsng.c index 25209e054..e85a0fc4d 100644 --- a/board/sacsng/sacsng.c +++ b/board/sacsng/sacsng.c @@ -842,37 +842,30 @@ void show_boot_progress (int status)  #define SPI_ADC_CS_MASK	0x00000800  #define SPI_DAC_CS_MASK	0x00001000 -void spi_adc_chipsel(int cs) +static const u32 cs_mask[] = { +    SPI_ADC_CS_MASK, +    SPI_DAC_CS_MASK, +}; + +int spi_cs_is_valid(unsigned int bus, unsigned int cs) +{ +    return bus == 0 && cs < sizeof(cs_mask) / sizeof(cs_mask[0]); +} + +void spi_cs_activate(struct spi_slave *slave)  {      volatile ioport_t *iopd = ioport_addr((immap_t *)CFG_IMMR, 3 /* port D */); -    if(cs) -	iopd->pdat &= ~SPI_ADC_CS_MASK;	/* activate the chip select */ -    else -	iopd->pdat |=  SPI_ADC_CS_MASK;	/* deactivate the chip select */ +    iopd->pdat &= ~cs_mask[slave->cs];  } -void spi_dac_chipsel(int cs) +void spi_cs_deactivate(struct spi_slave *slave)  {      volatile ioport_t *iopd = ioport_addr((immap_t *)CFG_IMMR, 3 /* port D */); -    if(cs) -	iopd->pdat &= ~SPI_DAC_CS_MASK;	/* activate the chip select */ -    else -	iopd->pdat |=  SPI_DAC_CS_MASK;	/* deactivate the chip select */ +    iopd->pdat |= cs_mask[slave->cs];  } -/* - * The SPI command uses this table of functions for controlling the SPI - * chip selects: it calls the appropriate function to control the SPI - * chip selects. - */ -spi_chipsel_type spi_chipsel[] = { -	spi_adc_chipsel, -	spi_dac_chipsel -}; -int spi_chipsel_cnt = sizeof(spi_chipsel) / sizeof(spi_chipsel[0]); -  #endif  #endif /* CONFIG_MISC_INIT_R */ diff --git a/board/ssv/adnpesc1/adnpesc1.c b/board/ssv/adnpesc1/adnpesc1.c index 2ec3a728d..3ee8ba588 100644 --- a/board/ssv/adnpesc1/adnpesc1.c +++ b/board/ssv/adnpesc1/adnpesc1.c @@ -69,25 +69,24 @@ long int initdram (int board_type)  #define	SPI_RTC_CS_MASK	0x00000001 -void spi_rtc_chipsel(int cs) +int spi_cs_is_valid(unsigned int bus, unsigned int cs) +{ +	return bus == 0 && cs == 0; +} + +void spi_cs_activate(struct spi_slave *slave)  {  	nios_spi_t *spi = (nios_spi_t *)CFG_NIOS_SPIBASE; -	if (cs) -		spi->slaveselect = SPI_RTC_CS_MASK;	/* activate (1) */ -	else -		spi->slaveselect = 0;			/* deactivate (0) */ +	spi->slaveselect = SPI_RTC_CS_MASK;	/* activate (1) */  } -/* - * The SPI command uses this table of functions for controlling the SPI - * chip selects: it calls the appropriate function to control the SPI - * chip selects. - */ -spi_chipsel_type spi_chipsel[] = { -	spi_rtc_chipsel -}; -int spi_chipsel_cnt = sizeof(spi_chipsel) / sizeof(spi_chipsel[0]); +void spi_cs_deactivate(struct spi_slave *slave) +{ +	nios_spi_t *spi = (nios_spi_t *)CFG_NIOS_SPIBASE; + +	spi->slaveselect = 0;			/* deactivate (0) */ +}  #endif 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);  } diff --git a/cpu/nios/spi.c b/cpu/nios/spi.c index f37146b79..640818014 100644 --- a/cpu/nios/spi.c +++ b/cpu/nios/spi.c @@ -63,10 +63,10 @@ static char quickhex (int i)  	return hex_digit[i];  } -static void memdump (void *pv, int num) +static void memdump (const void *pv, int num)  {  	int i; -	unsigned char *pc = (unsigned char *) pv; +	const unsigned char *pc = (const unsigned char *) pv;  	for (i = 0; i < num; i++)  		printf ("%c%c ", quickhex (pc[i] >> 4), quickhex (pc[i] & 0x0f)); @@ -83,26 +83,64 @@ static void memdump (void *pv, int num)  #endif  /* DEBUG */ +struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, +		unsigned int max_hz, unsigned int mode) +{ +	struct spi_slave *slave; + +	if (!spi_cs_is_valid(bus, cs)) +		return NULL; + +	slave = malloc(sizeof(struct spi_slave)); +	if (!slave) +		return NULL; + +	slave->bus = bus; +	slave->cs = cs; + +	/* TODO: Add support for different modes and speeds */ + +	return slave; +} + +void spi_free_slave(struct spi_slave *slave) +{ +	free(slave); +} + +int spi_claim_bus(struct spi_slave *slave) +{ +	return 0; +} + +void spi_release_bus(struct spi_slave *slave) +{ + +} +  /*   * SPI transfer:   *   * See include/spi.h and http://www.altera.com/literature/ds/ds_nios_spi.pdf   * for more informations.   */ -int spi_xfer(spi_chipsel_type chipsel, int bitlen, uchar *dout, uchar *din) +int spi_xfer(struct spi_slave *slave, int bitlen, const void *dout, +		void *din, unsigned long flags)  { +	const u8 *txd = dout; +	u8 *rxd = din;  	int j; -	DPRINT(("spi_xfer: chipsel %08X dout %08X din %08X bitlen %d\n", -		(int)chipsel, *(uint *)dout, *(uint *)din, bitlen)); +	DPRINT(("spi_xfer: slave %u:%u dout %08X din %08X bitlen %d\n", +		slave->bus, slave->cs, *(uint *)dout, *(uint *)din, bitlen)); -	memdump((void*)dout, (bitlen + 7) / 8); +	memdump(dout, (bitlen + 7) / 8); -	if(chipsel != NULL) { -		chipsel(1);	/* select the target chip */ -	} +	if (flags & SPI_XFER_BEGIN) +		spi_cs_activate(slave); -	if (bitlen > CFG_NIOS_SPIBITS) {	/* leave chip select active */ +	if (!(flags & SPI_XFER_END) || bitlen > CFG_NIOS_SPIBITS) { +		/* leave chip select active */  		spi->control |= NIOS_SPI_SSO;  	} @@ -114,11 +152,11 @@ int spi_xfer(spi_chipsel_type chipsel, int bitlen, uchar *dout, uchar *din)  		while ((spi->status & NIOS_SPI_TRDY) == 0)  			; -		spi->txdata = (unsigned)(dout[j]); +		spi->txdata = (unsigned)(txd[j]);  		while ((spi->status & NIOS_SPI_RRDY) == 0)  			; -		din[j] = (unsigned char)(spi->rxdata & 0xff); +		rxd[j] = (unsigned char)(spi->rxdata & 0xff);  #elif	(CFG_NIOS_SPIBITS == 16)  		j++, j++) { @@ -126,15 +164,15 @@ int spi_xfer(spi_chipsel_type chipsel, int bitlen, uchar *dout, uchar *din)  		while ((spi->status & NIOS_SPI_TRDY) == 0)  			;  		if ((j+1) < ((bitlen + 7) / 8)) -			spi->txdata = (unsigned)((dout[j] << 8) | dout[j+1]); +			spi->txdata = (unsigned)((txd[j] << 8) | txd[j+1]);  		else -			spi->txdata = (unsigned)(dout[j] << 8); +			spi->txdata = (unsigned)(txd[j] << 8);  		while ((spi->status & NIOS_SPI_RRDY) == 0)  			; -		din[j] = (unsigned char)((spi->rxdata >> 8) & 0xff); +		rxd[j] = (unsigned char)((spi->rxdata >> 8) & 0xff);  		if ((j+1) < ((bitlen + 7) / 8)) -			din[j+1] = (unsigned char)(spi->rxdata & 0xff); +			rxd[j+1] = (unsigned char)(spi->rxdata & 0xff);  #else  #error "*** unsupported value of CFG_NIOS_SPIBITS ***" @@ -142,15 +180,14 @@ int spi_xfer(spi_chipsel_type chipsel, int bitlen, uchar *dout, uchar *din)  	} -	if (bitlen > CFG_NIOS_SPIBITS) { +	if (bitlen > CFG_NIOS_SPIBITS && (flags & SPI_XFER_END)) {  		spi->control &= ~NIOS_SPI_SSO;  	} -	if(chipsel != NULL) { -		chipsel(0);	/* deselect the target chip */ -	} +	if (flags & SPI_XFER_END) +		spi_cs_deactivate(slave); -	memdump((void*)din, (bitlen + 7) / 8); +	memdump(din, (bitlen + 7) / 8);  	return 0;  } diff --git a/drivers/rtc/ds1306.c b/drivers/rtc/ds1306.c index 1c8ac7f29..29854fc7c 100644 --- a/drivers/rtc/ds1306.c +++ b/drivers/rtc/ds1306.c @@ -62,13 +62,6 @@  #define	RTC_USER_RAM_BASE	0x20 -/* - * 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; -  static unsigned int bin2bcd (unsigned int n);  static unsigned char bcd2bin (unsigned char c); @@ -305,11 +298,29 @@ void rtc_reset (void)  static unsigned char rtc_read (unsigned char reg);  static void rtc_write (unsigned char reg, unsigned char val); +static struct spi_slave *slave; +  /* read clock time from DS1306 and return it in *tmp */  int rtc_get (struct rtc_time *tmp)  {  	unsigned char sec, min, hour, mday, wday, mon, year; +	/* +	 * Assuming Vcc = 2.0V (lowest speed) +	 * +	 * REVISIT: If we add an rtc_init() function we can do this +	 * step just once. +	 */ +	if (!slave) { +		slave = spi_setup_slave(0, CFG_SPI_RTC_DEVID, 600000, +				SPI_MODE_3 | SPI_CS_HIGH); +		if (!slave) +			return; +	} + +	if (spi_claim_bus(slave)) +		return; +  	sec = rtc_read (RTC_SECONDS);  	min = rtc_read (RTC_MINUTES);  	hour = rtc_read (RTC_HOURS); @@ -318,6 +329,8 @@ int rtc_get (struct rtc_time *tmp)  	mon = rtc_read (RTC_MONTH);  	year = rtc_read (RTC_YEAR); +	spi_release_bus(slave); +  	debug ("Get RTC year: %02x mon: %02x mday: %02x wday: %02x "  	       "hr: %02x min: %02x sec: %02x\n",  	       year, mon, mday, wday, hour, min, sec); @@ -360,6 +373,17 @@ int rtc_get (struct rtc_time *tmp)  /* set clock time from *tmp in DS1306 RTC */  void rtc_set (struct rtc_time *tmp)  { +	/* Assuming Vcc = 2.0V (lowest speed) */ +	if (!slave) { +		slave = spi_setup_slave(0, CFG_SPI_RTC_DEVID, 600000, +				SPI_MODE_3 | SPI_CS_HIGH); +		if (!slave) +			return; +	} + +	if (spi_claim_bus(slave)) +		return; +  	debug ("Set DATE: %4d-%02d-%02d (wday=%d)  TIME: %2d:%02d:%02d\n",  	       tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,  	       tmp->tm_hour, tmp->tm_min, tmp->tm_sec); @@ -371,6 +395,8 @@ void rtc_set (struct rtc_time *tmp)  	rtc_write (RTC_DATE_OF_MONTH, bin2bcd (tmp->tm_mday));  	rtc_write (RTC_MONTH, bin2bcd (tmp->tm_mon));  	rtc_write (RTC_YEAR, bin2bcd (tmp->tm_year - 2000)); + +	spi_release_bus(slave);  }  /* ------------------------------------------------------------------------- */ @@ -378,6 +404,17 @@ void rtc_set (struct rtc_time *tmp)  /* reset the DS1306 */  void rtc_reset (void)  { +	/* Assuming Vcc = 2.0V (lowest speed) */ +	if (!slave) { +		slave = spi_setup_slave(0, CFG_SPI_RTC_DEVID, 600000, +				SPI_MODE_3 | SPI_CS_HIGH); +		if (!slave) +			return; +	} + +	if (spi_claim_bus(slave)) +		return; +  	/* clear the control register */  	rtc_write (RTC_CONTROL, 0x00);	/* 1st step: reset WP */  	rtc_write (RTC_CONTROL, 0x00);	/* 2nd step: reset 1Hz, AIE1, AIE0 */ @@ -391,22 +428,18 @@ void rtc_reset (void)  	rtc_write (RTC_HOURS_ALARM1, 0x00);  	rtc_write (RTC_DAY_OF_WEEK_ALARM0, 0x00);  	rtc_write (RTC_DAY_OF_WEEK_ALARM1, 0x00); + +	spi_release_bus(slave);  }  /* ------------------------------------------------------------------------- */  static unsigned char rtc_read (unsigned char reg)  { -	unsigned char dout[2];	/* SPI Output Data Bytes */ -	unsigned char din[2];	/* SPI Input Data Bytes */ - -	dout[0] = reg; +	int ret; -	if (spi_xfer (spi_chipsel[CFG_SPI_RTC_DEVID], 16, dout, din) != 0) { -		return 0; -	} else { -		return din[1]; -	} +	ret = spi_w8r8(slave, reg); +	return ret < 0 ? 0 : ret;  }  /* ------------------------------------------------------------------------- */ @@ -419,7 +452,7 @@ static void rtc_write (unsigned char reg, unsigned char val)  	dout[0] = 0x80 | reg;  	dout[1] = val; -	spi_xfer (spi_chipsel[CFG_SPI_RTC_DEVID], 16, dout, din); +	spi_xfer (slave, 16, dout, din, SPI_XFER_BEGIN | SPI_XFER_END);  }  #endif /* end of code exclusion (see #ifdef CONFIG_SXNI855T above) */ diff --git a/drivers/rtc/mc13783-rtc.c b/drivers/rtc/mc13783-rtc.c index 35b1b8b25..b6e15014b 100644 --- a/drivers/rtc/mc13783-rtc.c +++ b/drivers/rtc/mc13783-rtc.c @@ -24,34 +24,50 @@  #include <rtc.h>  #include <spi.h> +static struct spi_slave *slave; +  int rtc_get(struct rtc_time *rtc)  {  	u32 day1, day2, time;  	u32 reg;  	int err, tim, i = 0; -	spi_select(1, 0, SPI_MODE_2 | SPI_CS_HIGH); +	if (!slave) { +		/* FIXME: Verify the max SCK rate */ +		slave = spi_setup_slave(1, 0, 1000000, +				SPI_MODE_2 | SPI_CS_HIGH); +		if (!slave) +			return -1; +	} + +	if (spi_claim_bus(slave)) +		return -1;  	do {  		reg = 0x2c000000; -		err = spi_xfer(0, 32, (uchar *)®, (uchar *)&day1); +		err = spi_xfer(slave, 32, (uchar *)®, (uchar *)&day1, +				SPI_XFER_BEGIN | SPI_XFER_END);  		if (err)  			return err;  		reg = 0x28000000; -		err = spi_xfer(0, 32, (uchar *)®, (uchar *)&time); +		err = spi_xfer(slave, 32, (uchar *)®, (uchar *)&time, +				SPI_XFER_BEGIN | SPI_XFER_END);  		if (err)  			return err;  		reg = 0x2c000000; -		err = spi_xfer(0, 32, (uchar *)®, (uchar *)&day2); +		err = spi_xfer(slave, 32, (uchar *)®, (uchar *)&day2, +				SPI_XFER_BEGIN | SPI_XFER_END);  		if (err)  			return err;  	} while (day1 != day2 && i++ < 3); +	spi_release_bus(slave); +  	tim = day1 * 86400 + time;  	to_tm(tim, rtc); @@ -65,16 +81,31 @@ void rtc_set(struct rtc_time *rtc)  {  	u32 time, day, reg; +	if (!slave) { +		/* FIXME: Verify the max SCK rate */ +		slave = spi_setup_slave(1, 0, 1000000, +				SPI_MODE_2 | SPI_CS_HIGH); +		if (!slave) +			return; +	} +  	time = mktime(rtc->tm_year, rtc->tm_mon, rtc->tm_mday,  		      rtc->tm_hour, rtc->tm_min, rtc->tm_sec);  	day = time / 86400;  	time %= 86400; +	if (spi_claim_bus(slave)) +		return; +  	reg = 0x2c000000 | day | 0x80000000; -	spi_xfer(0, 32, (uchar *)®, (uchar *)&day); +	spi_xfer(slave, 32, (uchar *)®, (uchar *)&day, +			SPI_XFER_BEGIN | SPI_XFER_END);  	reg = 0x28000000 | time | 0x80000000; -	spi_xfer(0, 32, (uchar *)®, (uchar *)&time); +	spi_xfer(slave, 32, (uchar *)®, (uchar *)&time, +			SPI_XFER_BEGIN | SPI_XFER_END); + +	spi_release_bus(slave);  }  void rtc_reset(void) diff --git a/drivers/spi/mpc8xxx_spi.c b/drivers/spi/mpc8xxx_spi.c index 2fe838c45..136fb5005 100644 --- a/drivers/spi/mpc8xxx_spi.c +++ b/drivers/spi/mpc8xxx_spi.c @@ -24,6 +24,7 @@  #include <common.h>  #if defined(CONFIG_MPC8XXX_SPI) && defined(CONFIG_HARD_SPI) +#include <malloc.h>  #include <spi.h>  #include <asm/mpc8xxx_spi.h> @@ -37,6 +38,34 @@  #define SPI_TIMEOUT	1000 +struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, +		unsigned int max_hz, unsigned int mode) +{ +	struct spi_slave *slave; + +	if (!spi_cs_is_valid(bus, cs)) +		return NULL; + +	slave = malloc(sizeof(struct spi_slave)); +	if (!slave) +		return NULL; + +	slave->bus = bus; +	slave->cs = cs; + +	/* +	 * TODO: Some of the code in spi_init() should probably move +	 * here, or into spi_claim_bus() below. +	 */ + +	return slave; +} + +void spi_free_slave(struct spi_slave *slave) +{ +	free(slave); +} +  void spi_init(void)  {  	volatile spi8xxx_t *spi = &((immap_t *) (CFG_IMMR))->spi; @@ -53,7 +82,18 @@ void spi_init(void)  	spi->com = 0;		/* LST bit doesn't do anything, so disregard */  } -int spi_xfer(spi_chipsel_type chipsel, int bitlen, uchar *dout, uchar *din) +int spi_claim_bus(struct spi_slave *slave) +{ +	return 0; +} + +void spi_release_bus(struct spi_slave *slave) +{ + +} + +int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout, +		void *din, unsigned long flags)  {  	volatile spi8xxx_t *spi = &((immap_t *) (CFG_IMMR))->spi;  	unsigned int tmpdout, tmpdin, event; @@ -61,11 +101,11 @@ int spi_xfer(spi_chipsel_type chipsel, int bitlen, uchar *dout, uchar *din)  	int tm, isRead = 0;  	unsigned char charSize = 32; -	debug("spi_xfer: chipsel %08X dout %08X din %08X bitlen %d\n", -	      (int)chipsel, *(uint *) dout, *(uint *) din, bitlen); +	debug("spi_xfer: slave %u:%u dout %08X din %08X bitlen %u\n", +	      slave->bus, slave->cs, *(uint *) dout, *(uint *) din, bitlen); -	if (chipsel != NULL) -		(*chipsel) (1);	/* select the target chip */ +	if (flags & SPI_XFER_BEGIN) +		spi_cs_activate(slave);  	spi->event = 0xffffffff;	/* Clear all SPI events */ @@ -135,8 +175,8 @@ int spi_xfer(spi_chipsel_type chipsel, int bitlen, uchar *dout, uchar *din)  		debug("*** spi_xfer: transfer ended. Value=%08x\n", tmpdin);  	} -	if (chipsel != NULL) -		(*chipsel) (0);	/* deselect the target chip */ +	if (flags & SPI_XFER_END) +		spi_cs_deactivate(slave);  	return 0;  } diff --git a/drivers/spi/mxc_spi.c b/drivers/spi/mxc_spi.c index c166ec502..5957ada3a 100644 --- a/drivers/spi/mxc_spi.c +++ b/drivers/spi/mxc_spi.c @@ -19,6 +19,7 @@   */  #include <common.h> +#include <malloc.h>  #include <spi.h>  #include <asm/io.h> @@ -61,17 +62,18 @@ static unsigned long spi_bases[] = {  	0x53f84000,  }; -static unsigned long spi_base; -  #endif -spi_chipsel_type spi_chipsel[] = { -	(spi_chipsel_type)0, -	(spi_chipsel_type)1, -	(spi_chipsel_type)2, -	(spi_chipsel_type)3, +struct mxc_spi_slave { +	struct spi_slave slave; +	unsigned long	base; +	u32		ctrl_reg;  }; -int spi_chipsel_cnt = sizeof(spi_chipsel) / sizeof(spi_chipsel[0]); + +static inline struct mxc_spi_slave *to_mxc_spi_slave(struct spi_slave *slave) +{ +	return container_of(slave, struct mxc_spi_slave, slave); +}  static inline u32 reg_read(unsigned long addr)  { @@ -83,30 +85,31 @@ static inline void reg_write(unsigned long addr, u32 val)  	*(volatile unsigned long*)addr = val;  } -static u32 spi_xchg_single(u32 data, int bitlen) +static u32 spi_xchg_single(struct spi_slave *slave, u32 data, int bitlen)  { - -	unsigned int cfg_reg = reg_read(spi_base + MXC_CSPICTRL); +	struct mxc_spi_slave *mxcs = to_mxc_spi_slave(slave); +	unsigned int cfg_reg = reg_read(mxcs->base + MXC_CSPICTRL);  	if (MXC_CSPICTRL_BITCOUNT(bitlen - 1) != (cfg_reg & MXC_CSPICTRL_BITCOUNT(31))) {  		cfg_reg = (cfg_reg & ~MXC_CSPICTRL_BITCOUNT(31)) |  			MXC_CSPICTRL_BITCOUNT(bitlen - 1); -		reg_write(spi_base + MXC_CSPICTRL, cfg_reg); +		reg_write(mxcs->base + MXC_CSPICTRL, cfg_reg);  	} -	reg_write(spi_base + MXC_CSPITXDATA, data); +	reg_write(mxcs->base + MXC_CSPITXDATA, data);  	cfg_reg |= MXC_CSPICTRL_XCH; -	reg_write(spi_base + MXC_CSPICTRL, cfg_reg); +	reg_write(mxcs->base + MXC_CSPICTRL, cfg_reg); -	while (reg_read(spi_base + MXC_CSPICTRL) & MXC_CSPICTRL_XCH) +	while (reg_read(mxcs->base + MXC_CSPICTRL) & MXC_CSPICTRL_XCH)  		; -	return reg_read(spi_base + MXC_CSPIRXDATA); +	return reg_read(mxcs->base + MXC_CSPIRXDATA);  } -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)  {  	int n_blks = (bitlen + 31) / 32;  	u32 *out_l, *in_l; @@ -117,13 +120,10 @@ int spi_xfer(spi_chipsel_type chipsel, int bitlen, uchar *dout, uchar *din)  		return 1;  	} -	if (!spi_base) -		spi_select(CONFIG_MXC_SPI_IFACE, (int)chipsel, SPI_MODE_2 | SPI_CS_HIGH); -  	for (i = 0, in_l = (u32 *)din, out_l = (u32 *)dout;  	     i < n_blks;  	     i++, in_l++, out_l++, bitlen -= 32) -		*in_l = spi_xchg_single(*out_l, bitlen); +		*in_l = spi_xchg_single(slave, *out_l, bitlen);  	return 0;  } @@ -132,17 +132,17 @@ void spi_init(void)  {  } -int spi_select(unsigned int bus, unsigned int dev, unsigned long mode) +struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, +			unsigned int max_hz, unsigned int mode)  {  	unsigned int ctrl_reg; +	struct mxc_spi_slave *mxcs;  	if (bus >= sizeof(spi_bases) / sizeof(spi_bases[0]) || -	    dev > 3) -		return 1; - -	spi_base = spi_bases[bus]; +	    cs > 3) +		return NULL; -	ctrl_reg = MXC_CSPICTRL_CHIPSELECT(dev) | +	ctrl_reg = MXC_CSPICTRL_CHIPSELECT(cs) |  		MXC_CSPICTRL_BITCOUNT(31) |  		MXC_CSPICTRL_DATARATE(7) | /* FIXME: calculate data rate */  		MXC_CSPICTRL_EN | @@ -155,12 +155,38 @@ int spi_select(unsigned int bus, unsigned int dev, unsigned long mode)  	if (mode & SPI_CS_HIGH)  		ctrl_reg |= MXC_CSPICTRL_SSPOL; -	reg_write(spi_base + MXC_CSPIRESET, 1); +	mxcs = malloc(sizeof(struct mxc_spi_slave)); +	if (!mxcs) +		return NULL; + +	mxcs->slave.bus = bus; +	mxcs->slave.cs = cs; +	mxcs->base = spi_bases[bus]; +	mxcs->ctrl_reg = ctrl_reg; + +	return &mxcs->slave; +} + +void spi_free_slave(struct spi_slave *slave) +{ +	free(slave); +} + +int spi_claim_bus(struct spi_slave *slave) +{ +	struct mxc_spi_slave *mxcs = to_mxc_spi_slave(slave); + +	reg_write(mxcs->base + MXC_CSPIRESET, 1);  	udelay(1); -	reg_write(spi_base + MXC_CSPICTRL, ctrl_reg); -	reg_write(spi_base + MXC_CSPIPERIOD, +	reg_write(mxcs->base + MXC_CSPICTRL, mxcs->ctrl_reg); +	reg_write(mxcs->base + MXC_CSPIPERIOD,  		  MXC_CSPIPERIOD_32KHZ); -	reg_write(spi_base + MXC_CSPIINT, 0); +	reg_write(mxcs->base + MXC_CSPIINT, 0);  	return 0;  } + +void spi_release_bus(struct spi_slave *slave) +{ +	/* TODO: Shut the controller down */ +} diff --git a/include/configs/imx31_litekit.h b/include/configs/imx31_litekit.h index 4281d73c9..ec4ed1eeb 100644 --- a/include/configs/imx31_litekit.h +++ b/include/configs/imx31_litekit.h @@ -65,7 +65,8 @@  #define CONFIG_HARD_SPI		1  #define CONFIG_MXC_SPI		1 -#define CONFIG_MXC_SPI_IFACE	1 +#define CONFIG_DEFAULT_SPI_BUS	1 +#define CONFIG_DEFAULT_SPI_MODE	(SPI_MODE_2 | SPI_CS_HIGH)  #define CONFIG_RTC_MC13783	1 diff --git a/include/configs/mx31ads.h b/include/configs/mx31ads.h index 2ea48a6da..37ba872a4 100644 --- a/include/configs/mx31ads.h +++ b/include/configs/mx31ads.h @@ -62,7 +62,8 @@  #define CONFIG_HARD_SPI		1  #define CONFIG_MXC_SPI		1 -#define CONFIG_MXC_SPI_IFACE	1	/* Default SPI interface number */ +#define CONFIG_DEFAULT_SPI_BUS	1 +#define CONFIG_DEFAULT_SPI_MODE	(SPI_MODE_2 | SPI_CS_HIGH)  #define CONFIG_RTC_MC13783	1 diff --git a/include/spi.h b/include/spi.h index 3a55a68c4..7744c2e36 100644 --- a/include/spi.h +++ b/include/spi.h @@ -31,22 +31,87 @@  #define	SPI_MODE_1	(0|SPI_CPHA)  #define	SPI_MODE_2	(SPI_CPOL|0)  #define	SPI_MODE_3	(SPI_CPOL|SPI_CPHA) -#define	SPI_CS_HIGH	0x04			/* chipselect active high? */ +#define	SPI_CS_HIGH	0x04			/* CS active high */  #define	SPI_LSB_FIRST	0x08			/* per-word bits-on-wire */  #define	SPI_3WIRE	0x10			/* SI/SO signals shared */  #define	SPI_LOOP	0x20			/* loopback mode */ -/* - * The function call pointer type used to drive the chip select. - */ -typedef void (*spi_chipsel_type)(int cs); +/* SPI transfer flags */ +#define SPI_XFER_BEGIN	0x01			/* Assert CS before transfer */ +#define SPI_XFER_END	0x02			/* Deassert CS after transfer */ +/*----------------------------------------------------------------------- + * Representation of a SPI slave, i.e. what we're communicating with. + * + * Drivers are expected to extend this with controller-specific data. + * + *   bus:	ID of the bus that the slave is attached to. + *   cs:	ID of the chip select connected to the slave. + */ +struct spi_slave { +	unsigned int	bus; +	unsigned int	cs; +};  /*-----------------------------------------------------------------------   * Initialization, must be called once on start up. + * + * TODO: I don't think we really need this.   */  void spi_init(void); +/*----------------------------------------------------------------------- + * Set up communications parameters for a SPI slave. + * + * This must be called once for each slave. Note that this function + * usually doesn't touch any actual hardware, it only initializes the + * contents of spi_slave so that the hardware can be easily + * initialized later. + * + *   bus:     Bus ID of the slave chip. + *   cs:      Chip select ID of the slave chip on the specified bus. + *   max_hz:  Maximum SCK rate in Hz. + *   mode:    Clock polarity, clock phase and other parameters. + * + * Returns: A spi_slave reference that can be used in subsequent SPI + * calls, or NULL if one or more of the parameters are not supported. + */ +struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, +		unsigned int max_hz, unsigned int mode); + +/*----------------------------------------------------------------------- + * Free any memory associated with a SPI slave. + * + *   slave:	The SPI slave + */ +void spi_free_slave(struct spi_slave *slave); + +/*----------------------------------------------------------------------- + * Claim the bus and prepare it for communication with a given slave. + * + * This must be called before doing any transfers with a SPI slave. It + * will enable and initialize any SPI hardware as necessary, and make + * sure that the SCK line is in the correct idle state. It is not + * allowed to claim the same bus for several slaves without releasing + * the bus in between. + * + *   slave:	The SPI slave + * + * Returns: 0 if the bus was claimed successfully, or a negative value + * if it wasn't. + */ +int spi_claim_bus(struct spi_slave *slave); + +/*----------------------------------------------------------------------- + * Release the SPI bus + * + * This must be called once for every call to spi_claim_bus() after + * all transfers have finished. It may disable any SPI hardware as + * appropriate. + * + *   slave:	The SPI slave + */ +void spi_release_bus(struct spi_slave *slave);  /*-----------------------------------------------------------------------   * SPI transfer @@ -60,28 +125,67 @@ void spi_init(void);   * 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. - *   * spi_xfer() interface: - *   chipsel: Routine to call to set/clear the chip select: - *              if chipsel is NULL, it is not used. - *              if(cs),  make the chip select active (typically '0'). - *              if(!cs), make the chip select inactive (typically '1'). - *   dout:    Pointer to a string of bits to send out.  The bits are - *              held in a byte array and are sent MSB first. - *   din:     Pointer to a string of bits that will be filled in. - *   bitlen:  How many bits to write and read. + *   slave:	The SPI slave which will be sending/receiving the data. + *   bitlen:	How many bits to write and read. + *   dout:	Pointer to a string of bits to send out.  The bits are + *		held in a byte array and are sent MSB first. + *   din:	Pointer to a string of bits that will be filled in. + *   flags:	A bitwise combination of SPI_XFER_* flags.   *   *   Returns: 0 on success, not 0 on failure   */ -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); + +/*----------------------------------------------------------------------- + * Determine if a SPI chipselect is valid. + * This function is provided by the board if the low-level SPI driver + * needs it to determine if a given chipselect is actually valid. + * + * Returns: 1 if bus:cs identifies a valid chip on this board, 0 + * otherwise. + */ +int  spi_cs_is_valid(unsigned int bus, unsigned int cs); + +/*----------------------------------------------------------------------- + * Activate a SPI chipselect. + * This function is provided by the board code when using a driver + * that can't control its chipselects automatically (e.g. + * common/soft_spi.c). When called, it should activate the chip select + * to the device identified by "slave". + */ +void spi_cs_activate(struct spi_slave *slave); + +/*----------------------------------------------------------------------- + * Deactivate a SPI chipselect. + * This function is provided by the board code when using a driver + * that can't control its chipselects automatically (e.g. + * common/soft_spi.c). When called, it should deactivate the chip + * select to the device identified by "slave". + */ +void spi_cs_deactivate(struct spi_slave *slave); + +/*----------------------------------------------------------------------- + * Write 8 bits, then read 8 bits. + *   slave:	The SPI slave we're communicating with + *   byte:	Byte to be written + * + * Returns: The value that was read, or a negative value on error. + * + * TODO: This function probably shouldn't be inlined. + */ +static inline int spi_w8r8(struct spi_slave *slave, unsigned char byte) +{ +	unsigned char dout[2]; +	unsigned char din[2]; +	int ret; + +	dout[0] = byte; +	dout[1] = 0; -int spi_select(unsigned int bus, unsigned int dev, unsigned long mode); +	ret = spi_xfer(slave, 16, dout, din, SPI_XFER_BEGIN | SPI_XFER_END); +	return ret < 0 ? ret : din[1]; +}  #endif	/* _SPI_H_ */ |