diff --git a/board/amcc/taihu/taihu.c b/board/amcc/taihu/taihu.c
index eedde597b81cc1e7024b7f67314a7d39afa0ce66..891b4d924980fc6d8fbf3919198b5899b06b79ec 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 6c825969d38c796b97a01e95615cbab638c6b6f6..e18e68e8cec3f17622a005530bb3ebdbe2bf405c 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 25209e0546404c6a097691db9fbb52dbf31bcec9..e85a0fc4dbe9404af8f2d89a58a65be281d7394e 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 2ec3a728d74ea5cb0a5ce9c43e60ecf57d48bd53..3ee8ba588dc20a8597c7642c2731ed024fa7e5ab 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 0000000000000000000000000000000000000000..5f650442c018edb81aacc6c22ddbe0f49682087f
--- /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 76044221416c9fbd194828b6f4c6bd35fdd461fd..40ee7e7dd3c7daa08270fbfc72d0d7967d92077c 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 e4250616c2858943110fcabefa56513a32eee634..c13165030db6e5edb71ef78491039977d3ef0ae0 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 f37146b7939b75093376f8f86755015cd3a53d1a..6408180147a9fd39ca87d0136d1cbf6bbd14e3e7 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 1c8ac7f2927997989bf4a1738e7616e9e5d70290..29854fc7c4cf6f4e67b645b5333e11a45beeec62 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 35b1b8b254dd218ab6c7b93abe71ace1b12cc242..b6e15014bb68e67f22c2e1b3340a7a23f5ed5ed6 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 *)&reg, (uchar *)&day1);
+		err = spi_xfer(slave, 32, (uchar *)&reg, (uchar *)&day1,
+				SPI_XFER_BEGIN | SPI_XFER_END);
 
 		if (err)
 			return err;
 
 		reg = 0x28000000;
-		err = spi_xfer(0, 32, (uchar *)&reg, (uchar *)&time);
+		err = spi_xfer(slave, 32, (uchar *)&reg, (uchar *)&time,
+				SPI_XFER_BEGIN | SPI_XFER_END);
 
 		if (err)
 			return err;
 
 		reg = 0x2c000000;
-		err = spi_xfer(0, 32, (uchar *)&reg, (uchar *)&day2);
+		err = spi_xfer(slave, 32, (uchar *)&reg, (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 *)&reg, (uchar *)&day);
+	spi_xfer(slave, 32, (uchar *)&reg, (uchar *)&day,
+			SPI_XFER_BEGIN | SPI_XFER_END);
 
 	reg = 0x28000000 | time | 0x80000000;
-	spi_xfer(0, 32, (uchar *)&reg, (uchar *)&time);
+	spi_xfer(slave, 32, (uchar *)&reg, (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 2fe838c45d59f441b355ed10eb4ff5a357c89aff..136fb50052f1902c1cc285f0dfe46b880a3cbe8e 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 c166ec5023953eec7635ce5c7c7e0dc55f082b33..5957ada3a4a626aba3584093d2018ae0e88a3946 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 4281d73c90b47e370ba103aa44fee04cd559fc52..ec4ed1eeb674191b01effb27aa21c9b98b444e64 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 2ea48a6da9ace3d03cbf40f78c3c705a386aecf7..37ba872a43923249c8149aeb3236fd639187286d 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 3a55a68c4d1c25a0b8f2aed23e5b442440128c3c..7744c2e36b057c02e9d22be42be6a6dd6a1f330d 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_ */