diff -uprN linux-2.6.20-at92_e1.4/arch/arm/mach-at91rm9200/board-som9260m.c linux-2.6.20-at92_e1.4_spi/arch/arm/mach-at91rm9200/board-som9260m.c
--- linux-2.6.20-at92_e1.4/arch/arm/mach-at91rm9200/board-som9260m.c	2007-12-27 18:59:19.000000000 -0500
+++ linux-2.6.20-at92_e1.4_spi/arch/arm/mach-at91rm9200/board-som9260m.c	2007-12-27 19:02:05.000000000 -0500
@@ -28,6 +28,8 @@
 #include <linux/spi/spi.h>
 #include <linux/clk.h>
 #include <linux/ioex/ecoreex.h>
+#include <linux/class/spi.h>
+#include <linux/class/spi_interface.h>
 
 #include <asm/hardware.h>
 #include <asm/setup.h>
@@ -154,6 +156,38 @@ void __init at91_add_device_ssc_at73c213
 /*
  * SPI devices.
  */
+	
+/************************************************************
+ * mcp3208 atod interface over EMAC SPI class
+ */
+
+static struct spi_s mcp3208_spi = 
+{
+ .name = "mcp3208",
+ .subclass = 0,
+ .bsize = 16,
+ .tip = lsi2esc_spi_tip,
+ .xmit = lsi2esc_spi_xmit,
+ .confwrite = lsi2esc_spi_confwrite,
+ .confread = lsi2esc_spi_confread,
+ .speedread = lsi2esc_spi_speedread,
+ .speedwrite = lsi2esc_spi_speedwrite,
+};
+
+static struct spi_s fake_spi = 
+{
+ .name = "fake",
+ .subclass = 0,
+ .bsize = 16,
+ .tip = lsi2esc_spi_tip,
+ .xmit = lsi2esc_spi_xmit,
+ .confwrite = lsi2esc_spi_confwrite,
+ .confread = lsi2esc_spi_confread,
+ .speedread = lsi2esc_spi_speedread,
+ .speedwrite = lsi2esc_spi_speedwrite,
+};
+
+	
 static struct spi_board_info ek_spi_devices[] = {
 #if !defined(CONFIG_MMC_AT91)
 	{	/* DataFlash chip */
@@ -179,9 +213,24 @@ static struct spi_board_info ek_spi_devi
 		.bus_num	= 1,
 	},
 #endif
+#if defined(CONFIG_ARMSTRONG_HWMS)
+	{ /* mcp3208 ADC */
+	  .modalias = "lsi2esc", /* use the SPI class interface */
+	  .chip_select = 0,
+	  .max_speed_hz = 1e6,
+	  .bus_num = 1,
+	  .platform_data = &mcp3208_spi,
+	},
+	{ /*fake*/
+	  .modalias = "lsi2esc",
+	  .chip_select = 1,
+	  .max_speed_hz = 10 * 1000 * 1000,
+	  .bus_num = 0,
+	  .platform_data = &fake_spi,
+	},
+#endif
 };
 
-
 /*
  * MACB Ethernet device
  */
@@ -256,6 +305,9 @@ static struct at91_mmc_data __initdata e
 #define CS4_START ((unsigned long)0x50000000)
 #define CS4_END  ((unsigned long)0x5FFFFFFF)
 #define CS4_LEN  ((unsigned long)(CS0_END-CS0_START+1))
+/* key is defined, but may be overridden by the ecoreex driver
+ * based on the static key definition in the config file
+ */
 #define CPLDKEY 0xF
 
 static struct ecoreex_data som9260m_ecoreex_data = {
@@ -279,6 +331,8 @@ static struct platform_device som9260m_e
 	.resource	= &som9260m_ecoreex_resource,
 };
 
+
+
 /**
  * enable a generic memory map on cs4 and required module I/O
  */
diff -uprN linux-2.6.20-at92_e1.4/arch/arm/mach-ep93xx/ipac9302.c linux-2.6.20-at92_e1.4_spi/arch/arm/mach-ep93xx/ipac9302.c
--- linux-2.6.20-at92_e1.4/arch/arm/mach-ep93xx/ipac9302.c	2007-12-27 18:59:17.000000000 -0500
+++ linux-2.6.20-at92_e1.4_spi/arch/arm/mach-ep93xx/ipac9302.c	2007-12-27 19:01:30.000000000 -0500
@@ -21,6 +21,7 @@
 #include <linux/ioex/ecoreex.h>
 #include <linux/class/pwm.h>
 #include <linux/class/mmcprot.h>
+#include <linux/class/spi.h>
 #include <asm/io.h>
 #include <asm/hardware.h>
 #include <asm/mach-types.h>
@@ -86,6 +87,24 @@ static struct platform_device ipac9302_e
 	.num_resources	= 2,
 	.resource	= ipac9302_eth_resource,
 };
+
+/**
+ * Attempt to set a tip flag atomically, 
+ * if it is already set return an error indicating that
+ * the device is already held, note that this does not enforce any locking itself, only 
+ * provides the variable to do it, individual locking mechanisms must be implemented by the underlying
+ * driver/class layer, as the result of failing to obtain a lock will vary depending on the context.
+ */
+static ep93xx_spiconfig_t spiconfig = {.id		= 4,};
+/**
+ * SPI tip locking, the function provides locking with the
+ * other onboard spi devices (in this case the MMC)
+ * currently no chip select is implemented so it simply controls/reads the software lock.
+ */
+static int spitip(spi_t *s,int ofs){
+	return ep93xx_spitip(ofs,&spiconfig);
+}
+
 /************************************************************
  * MMC/SD Slot
  * MMC slot through the spi layer with some functions provided by the ecroeex.
@@ -93,8 +112,7 @@ static struct platform_device ipac9302_e
  * note that this requires ep93xx spi code to build
  */
 #ifdef CONFIG_MMCCLASS 
- 
-static ep93xx_spiconfig_t mmcspiconfig;//mmc spi configuration settings
+static ep93xx_spiconfig_t mmcspiconfig = {.id		= 5,};//mmc spi configuration settings
 
 #define MMCDR() 		(ioread32(EP93XX_GPIO_B_DR))
 #define MMCDDR()		(ioread32(EP93XX_GPIO_B_DDR))
@@ -103,19 +121,22 @@ static ep93xx_spiconfig_t mmcspiconfig;/
 #define MMCCSOFF() 		{iowrite32((MMCDR()|1),(void *)EP93XX_GPIO_B_DR);} 
 #define MMCCSSETUP()	{iowrite32(((MMCDDR())|1),(void *)EP93XX_GPIO_B_DDR);MMCCSOFF();}
 
-
 /**
  * set hardware up for an MMC transfer over the SPI
  * declare transfer in progress true/false 
  * (moves chip select, potentially turns off the clock)
  * This implementation simply flips on/off the MMC CS
+ * Note that the spi lines could be sitting at an invalid state when this is flipped.
+ * mmc configuration is therefore done prior to chip select assertionn
  */
 static int mmctip(mmcslot_t *s,int onoff){
-
-if(onoff){MMCCSON();}//ON
-else {MMCCSOFF();}//OFF
-
-return 0;
+if(onoff==1){
+	if(ep93xx_spitip(1,&mmcspiconfig)<0)return -1;//could not obtain lock, fail and return.
+	MMCCSON();//lock obtained, turn on the chip select
+	return 1;
+}
+if(onoff==0){MMCCSOFF();ep93xx_spitip(0,&mmcspiconfig);}//OFF
+return 0;//currently does not return status other than failure
 } 
 
 /**
@@ -126,7 +147,7 @@ return 0;
  * the mmc.
  */
 static int mmcexchange(mmcslot_t *s,u8 *mosi, u8 *miso, int size){
-	ep93xx_spiconfigure(&mmcspiconfig);//set mmc specific spi configuration
+	//ep93xx_spiconfigure(&mmcspiconfig);//set mmc specific spi configuration - done by tip
 	ep93xx_spi_transfer_blocking(mosi, miso, size);//blocking spi transfer the mmc information
 	return 0;
 }
@@ -141,7 +162,7 @@ static int mmcsetspeed(mmcslot_t *s,unsi
 
 static int mmcboardinit(void){
 	MMCCSSETUP();	
-	spi_setup_config(EP93XX_CP0_MOTO_MODE|BITSPERWORD(8),200000,&mmcspiconfig);
+	spi_setup_config(EP93XX_CP0_MOTO_MODE|BITSPERWORD(8),100000,&mmcspiconfig);
 	//spi_setup_config(EP93XX_CP0_TEXAS_MODE|BITSPERWORD(8),200000,&mmcspiconfig);
 	return 0;
 }
@@ -162,6 +183,7 @@ static struct platform_device mmcslot_de
 };
 
 #endif //CONFIG_MMCCLASS 
+ 
 /************************************************************
  * IOEX Device
  * Onboard EMAC I/O core platform device used by the ecoreex driver
@@ -227,6 +249,10 @@ static int ipac9302_classes(void)
 	ep93xx_atod_init();
 	ep93xx_atod_class_create("indexed_atod");
 #endif
+#ifdef CONFIG_SPICLASS 
+	spi_setup_config(EP93XX_CP0_MOTO_MODE|BITSPERWORD(8),200000,&spiconfig);
+	ep93xx_spi_class_create("ep93xx_spi",&spiconfig,spitip);
+#endif	
 	return 0;
 }
 
@@ -243,13 +269,13 @@ static struct platform_device boardspec_
  * Linux Board initialization routine 
  */
 static int chiprevision;
-const char *chip_revisions[] ={"A","B","C","D","D0","D1","E0","E1","E2",">E2"};
+const char *chip_revisions[] ={"A","B","C","D0","D1","E0","E1","E2",">E2"};
 
 /**
  * return sspclock, varies by chip revision number
  */
 u32 getsspclock(void){
-	if(chiprevision>7)return OSCCLOCK;
+	if(chiprevision>6)return OSCCLOCK;
 	return OSCCLOCK/2;
 }
 
@@ -263,7 +289,12 @@ static void __init ipac9302_init_machine
 	chiprevision = ep93xx_chip_revision();	
 	printk("ep9302 rev %s detected\n",chip_revisions[chiprevision]);
 	ep93xx_init_devices();
-	mmcboardinit();//initialize mmc hardware local to the processor.
+	/**initialize mmc hardware local to the processor, 
+	 * uses mmc driver as it's io extension declaration rather than boardspec
+	 * change this? Note that using the platform driver means that it can effectively only register 1 slot,
+	 * which seems quite reasonable, although artificially limiting.
+	 * */
+	mmcboardinit();
 	platform_device_register(&ipac9302_flash);
 	memcpy(ipac9302_eth_data.dev_addr,(void *)(EP93XX_ETHERNET_BASE + 0x50), 6);//MAC address
 	platform_device_register(&ipac9302_eth_device);
diff -uprN linux-2.6.20-at92_e1.4/arch/arm/mach-ep93xx/spi-ep93xx.c linux-2.6.20-at92_e1.4_spi/arch/arm/mach-ep93xx/spi-ep93xx.c
--- linux-2.6.20-at92_e1.4/arch/arm/mach-ep93xx/spi-ep93xx.c	2007-12-27 18:59:17.000000000 -0500
+++ linux-2.6.20-at92_e1.4_spi/arch/arm/mach-ep93xx/spi-ep93xx.c	2007-12-27 19:01:30.000000000 -0500
@@ -18,6 +18,7 @@
 #include <asm/hardware.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
+#include <linux/class/spi.h>
 #include "spi-ep93xx.h"
  
 /**
@@ -45,10 +46,35 @@ int spi_setup_config(int mode, u32 speed
 	c->cp0 = (div<<8)|(mode&EP93XX_CP0_MODEBITS);
 	c->cp1 = (EP93XX_CP1_MASTER|EP93XX_CP1_ENABLE);
 	c->prediv = prediv;
+	
+	EP93XXSPIDEBUG("%s\n",__FUNCTION__);
+	EP93XXSPIDEBUG("div=%d\n",div);
+	EP93XXSPIDEBUG("prediv=%d\n",prediv);
+	EP93XXSPIDEBUG("sspclock=%d\n",sspclock);
+	
+	//if a transfer is in progress for the device go ahead and reconfigure the hardware, otherwise it will be set on the next successful tip
+	if(ep93xx_spitip(TIPSTATUS,c))ep93xx_spiconfigure(c);
+	
 	return 0;	
 }
 
 /**
+ * convert register settings back to speed
+ */
+static u32 spi_getspeed(ep93xx_spiconfig_t *c){
+	u32 sspclock = getsspclock();//input clock determined by the mach
+	u8 prediv = c->prediv;
+	u8 div = (c->cp0>>8);
+	u32 denom = (1+div)*prediv;
+	EP93XXSPIDEBUG("%s\n",__FUNCTION__);
+	EP93XXSPIDEBUG("div=%d\n",div);
+	EP93XXSPIDEBUG("prediv=%d\n",prediv);
+	EP93XXSPIDEBUG("sspclock=%d\n",sspclock);
+	EP93XXSPIDEBUG("denom = %d\n",denom);
+	return(sspclock/denom);
+}
+
+/**
  * executes the initialization sequence detailed on page 498 of the ep9301 manual.
  */
 int ep93xx_spiconfigure(ep93xx_spiconfig_t *c){
@@ -58,10 +84,12 @@ int ep93xx_spiconfigure(ep93xx_spiconfig
 	iowrite16(0,(void *)EP93XX_SPI_CR1);//turn SPI off
 	iowrite16(c->cp1,(void *)EP93XX_SPI_CR1);//turn SPI on and set cp1 bits.
 	
-	//printk("cp0: %x\n",ioread16((void *)EP93XX_SPI_CR0));
-	///printk("cpsr: %x\n",ioread16((void *)EP93XX_SPI_CPSR));
-	//printk("cp1: %x\n",ioread16((void *)EP93XX_SPI_CR1));
+	//EP93XXSPIDEBUG("cp0: %x\n",ioread16((void *)EP93XX_SPI_CR0));
+	///EP93XXSPIDEBUG("cpsr: %x\n",ioread16((void *)EP93XX_SPI_CPSR));
+	//EP93XXSPIDEBUG("cp1: %x\n",ioread16((void *)EP93XX_SPI_CR1));
 	
+	//write out a blank value to set up the default states correctly.
+	//ep93xx_spi_transfer_blocking(NULL, NULL, 1);
 	return 0;
 } 
 
@@ -90,19 +118,19 @@ static inline int ep93xx_spi_rxpull(void
 		if(EP93XX_RXEMPTY)break;
 		ioread16(EP93XX_SPI_DR);
 		bytes++;
-		//printk("A SR:%x\n",ioread8(EP93XX_SPI_SR));
+		//EP93XXSPIDEBUG("A SR:%x\n",ioread8(EP93XX_SPI_SR));
 		}return bytes;}
 
 	if(BYTSPWORD(bpw)-1)while(count--){
 		if(EP93XX_RXEMPTY)break;
 		*((u16 *)rx++) = ioread16(EP93XX_SPI_DR);
-		//printk("B SR:%x\n",ioread8(EP93XX_SPI_SR));
+		//EP93XXSPIDEBUG("B SR:%x\n",ioread8(EP93XX_SPI_SR));
 		}
 	
 	else while(count--){
 		if(EP93XX_RXEMPTY)break;
 		*((u8 *)rx++) = ioread16(EP93XX_SPI_DR);
-		//printk("C SR:%x\n",ioread8(EP93XX_SPI_SR));
+		//EP93XXSPIDEBUG("C SR:%x\n",ioread8(EP93XX_SPI_SR));
 	}		
 	return (rx - start);
 }
@@ -119,19 +147,19 @@ static inline int ep93xx_spi_txpush(void
 		if(EP93XX_TXFULL)break;
 		iowrite16(0xFF,EP93XX_SPI_DR);
 		bytes++;
-		//printk("D SR:%x\n",ioread8(EP93XX_SPI_SR));
+		//EP93XXSPIDEBUG("D SR:%x\n",ioread8(EP93XX_SPI_SR));
 		}return bytes;}
 		
 	if(BYTSPWORD(bpw)-1)while(count--){
 		if(EP93XX_TXFULL)break;
 		iowrite16(*((u16 *)tx++),EP93XX_SPI_DR);
-		//printk("E SR:%x\n",ioread8(EP93XX_SPI_SR));
+		//EP93XXSPIDEBUG("E SR:%x\n",ioread8(EP93XX_SPI_SR));
 		}
 	
 	else while(count--){//count never filling up here? should probably be -- on all of the above.
 		if(EP93XX_TXFULL)break;
 		iowrite16(*((u8 *)tx++),EP93XX_SPI_DR);
-		//printk("F SR:%x\n",ioread8(EP93XX_SPI_SR));
+		//EP93XXSPIDEBUG("F SR:%x\n",ioread8(EP93XX_SPI_SR));
 	}
 	
 	return (tx - start);
@@ -173,11 +201,11 @@ int ep93xx_spi_transfer_blocking(u8 *mos
 	unsigned count = 0;
 	unsigned words = 0;
 	if(!EP93XX_RXEMPTY){
-		printk("unknown remainder in queue, transaction cannot begin\n");	
+		printk("%s:unknown remainder in queue, transaction cannot begin\n",__FUNCTION__);	
 		return -1;
 	}
 	while(togo){//while transmission remaining
-		//printk("togo %u count %u\n",togo,count);
+		//EP93XXSPIDEBUG("togo %u count %u\n",togo,count);
 		words=ep93xx_spi_rxpull(miso,8,EP93XX_SPI_FIFO_SIZE);
 		count-=words;if(miso)miso+=words;
 		words=ep93xx_spi_txpush(mosi,8,MIN(togo,(EP93XX_SPI_FIFO_SIZE-count)));
@@ -192,3 +220,112 @@ int ep93xx_spi_transfer_blocking(u8 *mos
 	
 	return(size - togo*BYTSPWORD(8));
 }
+
+/************************************************************
+ * generic spi locking function, 
+ * specific chip selects, keys, and error handling are left to the mach
+ */
+#define LOCKBIT	   0
+static long spiv = 0;//atomic int controlling access to the processor's spi port
+int ep93xx_spitip(int ofs,ep93xx_spiconfig_t *c){
+	//EP93XXSPIDEBUG("%s:ofs=%x,spiv=%x\n",__FUNCTION__,ofs,(int)spiv);
+	if(ofs==0){
+		if(test_and_clear_bit(c->id,&spiv)==0)return -1;//lock not owned by spiclass, can't remove it
+		if(test_and_clear_bit(LOCKBIT,&spiv)==0){
+			printk("%s:BUG:id %x is attempting to unlock an open lock\n",__FUNCTION__,c->id);
+			return -1;//lock was already cleared by a another source.
+		}
+		return 0;//unlocked
+	}
+	if(ofs==1){
+		if(test_bit(c->id,&spiv))return 1;//allow recursive calls
+		if(test_and_set_bit(LOCKBIT,&spiv)!=0)return -1;//lock already held cannot take ownership
+		if(test_and_set_bit(c->id,&spiv)==1){
+			printk("%s:BUG:id %x is attempting to mark a lock which is already owned\n",__FUNCTION__,c->id);
+			return -1;
+		}
+	if(c)ep93xx_spiconfigure(c);//set configuration to the new device settings	
+	return 1;//lock obtained
+	}
+	return (test_bit(c->id,&spiv));//otherwise return bitmask ?ownership of the lock
+}
+
+
+#ifdef CONFIG_SPICLASS
+/************************************************************
+ * SPI class access
+ * class driver interface to the spi port
+ * currently no chip selects are implemented, 
+ * these must be handled through gpio methods for direct class access.
+ * known mach chip selects may automate this by wrapping the tip with chip selects (this is how the mmc works)
+ */
+
+static int spixmit(struct spi_s *s,u8 *mosi, u8 *miso, int size){
+	//ep93xx_spiconfig_t *c = container_of(s,ep93xx_spiconfig_t,s);
+	//ep93xx_spiconfigure(c);//set mmc specific spi configuration
+	ep93xx_spi_transfer_blocking(mosi, miso, size);//blocking spi transfer the mmc information
+	return 0;
+}
+
+static int spiconfwrite(struct spi_s *s,spi_control flags){
+	ep93xx_spiconfig_t *c = container_of(s,ep93xx_spiconfig_t,s);
+	c->cp0 = 0;
+	if(flags&SPICL_CPHA)c->cp0|=EP93XX_CP0_CPHA;
+	if(flags&SPICL_CPOL)c->cp0|=EP93XX_CP0_CPOL;
+	if(flags&SPICL_EIGHTBIT)c->cp0|=EP93XX_CP0_EIGHTBIT;
+	return 0;
+}
+
+static spi_control spiconfread(struct spi_s *s){
+	ep93xx_spiconfig_t *c = container_of(s,ep93xx_spiconfig_t,s);
+	spi_control flags = 0;
+	if(c->cp0&EP93XX_CP0_CPHA)flags |= SPICL_CPHA;
+	if(c->cp0&EP93XX_CP0_CPOL)flags |= SPICL_CPOL;
+	if((c->cp0&EP93XX_CP0_EIGHTBIT)==EP93XX_CP0_EIGHTBIT)flags |= SPICL_EIGHTBIT;
+	return flags;
+}
+
+/**
+ * change spi bitrate
+ */	
+static int spisetspeed(struct spi_s *s,spi_control speed){
+	ep93xx_spiconfig_t *c = container_of(s,ep93xx_spiconfig_t,s);
+	EP93XXSPIDEBUG("setting speed to %d\n",speed);
+	spi_setup_config(c->cp0,speed,c);//set configuration structure to the new speed.
+	return 0;
+}
+
+/**
+ * retrieve the spi bitrate
+ */	
+static spi_control spigetspeed(struct spi_s *s){
+	ep93xx_spiconfig_t *c = container_of(s,ep93xx_spiconfig_t,s);
+	return spi_getspeed(c);
+}
+
+
+/************************************************************************************
+ * ep93xx spi device, 
+ * creates a single instance of a device for accessing the 
+ * ep93xx ssp port through the generic spi class.
+ */
+struct class_device *ep93xx_spi_class_create(
+		const char *name,
+		ep93xx_spiconfig_t *c,
+		int (*tip)(struct spi_s *s,int ofs))
+{
+	spi_t *s = &c->s;
+	memset(s,0,sizeof(spi_t));
+	s->name = name;
+	s->subclass = SPI_SUBCLASS;
+    s->xmit = spixmit;
+    s->confwrite = spiconfwrite;
+    s->confread = spiconfread;
+    s->speedwrite = spisetspeed;
+    s->speedread = spigetspeed;
+    s->tip = tip;
+    
+    printk("registering spi device: %s\n",name);
+    return spi_register_class_device(s);
+}
+#endif
diff -uprN linux-2.6.20-at92_e1.4/arch/arm/mach-ep93xx/spi-ep93xx.h linux-2.6.20-at92_e1.4_spi/arch/arm/mach-ep93xx/spi-ep93xx.h
--- linux-2.6.20-at92_e1.4/arch/arm/mach-ep93xx/spi-ep93xx.h	2007-12-27 18:59:17.000000000 -0500
+++ linux-2.6.20-at92_e1.4_spi/arch/arm/mach-ep93xx/spi-ep93xx.h	2007-12-27 19:01:30.000000000 -0500
@@ -1,6 +1,16 @@
 #ifndef SPIEP93XX_H_
 #define SPIEP93XX_H_
 
+//#define EP93XXSPI_DEBUG
+
+#undef EP93XXSPIDEBUG
+#ifdef EP93XXSPI_DEBUG
+	#define EP93XXSPIDEBUG(x...)  {printk("%s(): %d ",__PRETTY_FUNCTION__, __LINE__);printk(x);}
+#else
+	#define EP93XXSPIDEBUG(x...)	do { } while (0)
+#endif 
+
+
  //CR0 bit settings
 #define EP93XX_CP0_MOTO_MODE	(0)
 #define EP93XX_CP0_TEXAS_MODE	(0x10)
@@ -23,11 +33,21 @@
 typedef struct ep93xx_spiconfig_s{
 	u8  prediv;
 	u16 cp0,cp1;
+	int id;//id number 1-31, this determines ownership for locking purposes
+#ifdef CONFIG_SPICLASS
+	struct spi_s s;
+#endif	
 }ep93xx_spiconfig_t;
 
+int ep93xx_spi_init(void);
 u32 getsspclock(void);
 int spi_setup_config(int mode, u32 speed_hz, ep93xx_spiconfig_t *c);
 int ep93xx_spiconfigure(ep93xx_spiconfig_t *c);
 int ep93xx_spi_transfer_blocking(u8 *mosi, u8 *miso, int size);
+int ep93xx_spitip(int ofs,ep93xx_spiconfig_t *c);
+
+#ifdef CONFIG_SPICLASS
+struct class_device *ep93xx_spi_class_create(const char *name,ep93xx_spiconfig_t *c,int (*tip)(struct spi_s *s,int ofs));
+#endif
 
 #endif /*SPIEP93XX_H_*/
diff -uprN linux-2.6.20-at92_e1.4/drivers/misc/classes/Kconfig linux-2.6.20-at92_e1.4_spi/drivers/misc/classes/Kconfig
--- linux-2.6.20-at92_e1.4/drivers/misc/classes/Kconfig	2007-12-27 18:59:17.000000000 -0500
+++ linux-2.6.20-at92_e1.4_spi/drivers/misc/classes/Kconfig	2007-12-27 19:02:05.000000000 -0500
@@ -26,7 +26,7 @@ config GPIOCLASS_RTDM 
 	  
 config GPIOCLASS_CHAR
 		depends on GPIOCLASS
-		bool "Char interface"
+		bool "char interface"
 		---help---
 		Enables a character device interface to the GPIO class.
 
@@ -56,7 +56,37 @@ config MMCCLASS
         A MMC/SD class for transferring MMC information to a block driver layer.
         Designed for providing board specific syncronizations 
         between periodic spi devices and mmc block devices.
-        This class allows the mach to orchistrate low level spi interactions.        
+        This class allows the mach to orchistrate low level spi interactions.   
+        
+config SPICLASS
+        bool "SPI class"
+        ---help---
+	  This is a set of classes for SPI interfaces.
+	  It allows the creation of spi classes which can be configured
+	  through sysfs.SPI devices typically contain a 
+	  speed and flags register, a method for locking the bus, 
+	  and a bidirectional "xmit" method     
+
+config SPICLASS_SYSFS
+		depends on SYSFS && SPICLASS
+        bool "sysfs interface"
+        ---help---
+	  enables a sysfs interface to the spi class
+
+config SPICLASS_CHAR
+		depends on SPICLASS
+		bool "char interface"
+		---help---
+		Enables a character device interface to the spi class.
+
+config LSI2ESC
+        depends on SPICLASS
+        bool "Linux SPI Interface to EMAC SPI Class interface"
+        ---help---
+        Enables a generic interface between the Linux SPI
+        driver and the EMAC SPI Class. Boards with an SPI controller
+        driver can use this to define generic access to a device
+        through the EMAC SPI class.
         
 endmenu
 
diff -uprN linux-2.6.20-at92_e1.4/drivers/misc/classes/Makefile linux-2.6.20-at92_e1.4_spi/drivers/misc/classes/Makefile
--- linux-2.6.20-at92_e1.4/drivers/misc/classes/Makefile	2007-12-27 18:59:17.000000000 -0500
+++ linux-2.6.20-at92_e1.4_spi/drivers/misc/classes/Makefile	2007-12-27 19:02:05.000000000 -0500
@@ -6,6 +6,8 @@ EXTRA_CFLAGS += -Iinclude/xenomai
 obj-$(CONFIG_GPIOCLASS)		+= gpio.o
 obj-$(CONFIG_PWMCLASS)		+= pwm.o
 obj-$(CONFIG_MMCCLASS)		+= mmc.o
+obj-$(CONFIG_SPICLASS)		+= spi.o
+obj-$(CONFIG_LSI2ESC)       += spi_interface.o
 mmc-y := mmcprot.o mmcblock.o
 obj-y += rtdm/
 obj-y += char/
diff -uprN linux-2.6.20-at92_e1.4/drivers/misc/classes/char/Makefile linux-2.6.20-at92_e1.4_spi/drivers/misc/classes/char/Makefile
--- linux-2.6.20-at92_e1.4/drivers/misc/classes/char/Makefile	2007-12-27 18:59:17.000000000 -0500
+++ linux-2.6.20-at92_e1.4_spi/drivers/misc/classes/char/Makefile	2007-12-27 19:01:30.000000000 -0500
@@ -3,3 +3,4 @@
 #
 
 obj-$(CONFIG_GPIOCLASS_CHAR)	+= gpio_char.o
+obj-$(CONFIG_SPICLASS_CHAR)		+= spi_char.o
\ No newline at end of file
diff -uprN linux-2.6.20-at92_e1.4/drivers/misc/classes/char/spi_char.c linux-2.6.20-at92_e1.4_spi/drivers/misc/classes/char/spi_char.c
--- linux-2.6.20-at92_e1.4/drivers/misc/classes/char/spi_char.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.20-at92_e1.4_spi/drivers/misc/classes/char/spi_char.c	2007-12-27 19:01:30.000000000 -0500
@@ -0,0 +1,223 @@
+/**
+ * A character device interface to spi devices. Part of the SPI class.
+ * 
+ */
+
+/* TODO: analyze these includes to weed out any that are unnecessary */
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <linux/cdev.h>
+#include <linux/class/spi.h>
+#include <linux/class/char/spi_char.h>
+#include <asm/uaccess.h>
+
+static int spi_major =    SPI_MAJOR;
+static int spi_minor =    0;
+static int spi_num_devs = SPI_MAX_DEVS;
+
+struct spi_char_dev {
+    spi_t *spi;
+    struct cdev cdev;
+};
+
+//#define DEBUG_SC
+
+#ifdef DEBUG_SC
+#define DPRINTK(string, args...) printk("spi_char: " string, ##args)
+#else
+#define DPRINTK(string, args...)
+#endif
+
+/* function prototypes */
+static int spi_char_ioctl(struct inode *inode, struct file *file,
+		unsigned int cmd, unsigned long arg);
+static int spi_char_open(struct inode *inode, struct file *file);
+static int spi_char_release(struct inode *inode, struct file *file);
+static int spi_char_setup_cdev(struct spi_char_dev *dev);
+
+/* struct for fops declarations */
+static const struct file_operations spi_char_fops =
+{ 
+    .ioctl   = spi_char_ioctl, 
+    .open    = spi_char_open,
+    .release = spi_char_release,
+};
+
+static int spi_char_open(struct inode *inode, struct file *file)
+{
+    struct spi_char_dev *dev; /* device information */
+    DPRINTK("spi_char_open\n");
+    /* TODO: This may or may not be necessary */
+    dev = container_of(inode->i_cdev, struct spi_char_dev, cdev);
+    file->private_data = dev;
+    return 0;
+}
+
+static int spi_char_release(struct inode *inode, struct file *file)
+{
+    DPRINTK("spi_char_release\n");
+    /* nothing to do here */
+    return 0;
+}
+
+static int spi_char_ioctl(struct inode *inode, struct file *file,
+        unsigned int cmd, unsigned long arg)
+{
+    struct spi_char_dev *dev = container_of(inode->i_cdev, struct spi_char_dev, cdev);
+    spi_t *spi = dev->spi;
+    spi_control kmem[1];
+    
+    /* make sure that this command is indeed one of spi_char's */
+    if (_IOC_TYPE(cmd) != CHAR_CLASS_SPI)
+        return -ENOTTY;
+    
+    switch(cmd)
+    {
+    case XMIT:{
+    	spi_transfer_t *t=NULL;
+    	spi_data *buf=NULL;
+    	int errval=0;
+        DPRINTK("XMIT ioctl\n");
+        if (!spi->xmit)return -EFAULT;//method not available
+        if (copy_from_user(t, (void *)arg, sizeof(spi_transfer_t)) != 0){errval=-EFAULT;goto cleanup;}
+        if(t->size==0)return 0;//not an error, but nothing to do
+        if((t->miso)||(t->mosi))buf = kmalloc(t->size,GFP_KERNEL);
+        if(t->mosi)if (copy_from_user(buf, t->mosi, t->size) != 0){errval=-EFAULT;goto cleanup;}
+        if(atomic_spi_xmit(spi,t->mosi?buf:NULL,t->miso?buf:NULL,t->size)!=0){errval=-EFAULT;goto cleanup;}
+        if(t->miso)if(copy_to_user(t->miso, buf, t->size)!= 0 ){errval=-EFAULT;goto cleanup;}
+cleanup:
+        if(buf)kfree(buf);
+        return errval;
+        break;
+    }
+    case CONFREAD:
+        DPRINTK("CONFREAD ioctl\n");
+        if (spi->confread)
+            kmem[0] = atomic_spi_conf_read(spi);
+        else
+            return -EFAULT;
+        return (copy_to_user((void *)arg, kmem, sizeof(spi_control)) == 0 ) ? 0 : -EFAULT;
+        break;
+    case CONFWRITE:
+        DPRINTK("CONFWRITE ioctl\n");
+        if (copy_from_user(kmem, (void *)arg, sizeof(spi_control)) != 0)
+            return -EFAULT;
+        if (spi->confwrite)
+            atomic_spi_conf_write(spi, kmem[0]);
+        else 
+            return -EFAULT;
+        return 0;
+        break;
+    case SPEEDREAD:
+        DPRINTK("SPEEDREAD ioctl\n");
+        if (spi->speedread)
+            kmem[0] = atomic_spi_speed_read(spi);
+        else
+            return -EFAULT;
+        return (copy_to_user((void *)arg, kmem, sizeof(spi_control)) == 0 ) ? 0 : -EFAULT;
+        break;
+    case SPEEDWRITE:
+        DPRINTK("SPEEDWRITE ioctl\n");
+        if (copy_from_user(kmem, (void *)arg, sizeof(spi_control)) != 0)
+            return -EFAULT;
+        if (spi->speedwrite)
+            atomic_spi_speed_write(spi, kmem[0]);
+        else {
+            DPRINTK("error: invalid speed write\n");
+            return -EFAULT;
+        }
+        return 0;
+        break;
+    case TIPREAD:
+        DPRINTK("TIPREAD ioctl\n");
+        if (spi->tip)
+            kmem[0] = atomic_spi_tip_read(spi);
+        else
+            return -EFAULT;
+        return (copy_to_user((void *)arg, kmem, sizeof(spi_control)) == 0 ) ? 0 : -EFAULT;
+        break;
+    case TIPWRITE:
+        DPRINTK("TIPWRITE ioctl\n");
+        if (copy_from_user(kmem, (void *)arg, sizeof(spi_control)) != 0)
+            return -EFAULT;
+        if (spi->tip)
+            atomic_spi_tip_write(spi, kmem[0]);
+        else {
+            DPRINTK("error: invalid speed write\n");
+            return -EFAULT;
+        }
+        return 0;
+        break;
+    default :
+        DPRINTK("ioctl: no such command\n");
+        return -ENOTTY;
+    } /* END switch(cmd) */
+    DPRINTK("Invalid state, broke out of switch\n");
+    return -EFAULT; /* Error, we should never reach here */    
+}
+
+/* initialize the character interface -- called by spi class on init */
+
+int spi_char_init(void)
+{
+    int result;
+    dev_t dev = 0;
+    DPRINTK("spi_char_init\n");
+    /* dynamic and static character device allocation */
+    if (spi_major) {
+        dev = MKDEV(spi_major, spi_minor);
+        result = register_chrdev_region(dev, spi_num_devs, "spi_char");
+    }
+    else {
+        result = alloc_chrdev_region(&dev, spi_minor, 
+                spi_num_devs, "spi_char");
+        spi_major = MAJOR(dev);
+    }
+    if (result < 0)
+        printk(KERN_WARNING "spi_char: can't get major %d, err %d\n", spi_major,result);
+    
+    return result;
+}
+
+/* registers the actual char device, called by create when invoked by spi class */
+
+static int spi_char_setup_cdev(struct spi_char_dev *dev)
+{
+    static int index = 0;
+    int err, devno = MKDEV(spi_major, spi_minor + index);
+    
+    DPRINTK("spi_char_setup_cdev\n");
+    
+    cdev_init(&dev->cdev, &spi_char_fops);
+    dev->cdev.owner = THIS_MODULE; /* not sure if this is still valid */
+    dev->cdev.ops = &spi_char_fops;
+    err = cdev_add(&dev->cdev, devno, 1);
+    if (err)
+        printk(KERN_NOTICE "spi_char: Error %d adding spi_char%d\n", err, index);
+    
+    index++;
+    return devno;
+}
+
+/* create and register a new char device */
+
+int spi_char_create(struct spi_s *spi)
+{
+    struct spi_char_dev *chardev = kmalloc(sizeof(struct spi_char_dev),GFP_KERNEL);
+    DPRINTK("spi_char_create\n");
+    if (!chardev) {
+        printk(KERN_NOTICE "Error allocating memory\n");
+        return -ENOMEM;
+    }
+    chardev->spi = spi;
+    
+    return spi_char_setup_cdev(chardev);
+}
diff -uprN linux-2.6.20-at92_e1.4/drivers/misc/classes/mmcprot.c linux-2.6.20-at92_e1.4_spi/drivers/misc/classes/mmcprot.c
--- linux-2.6.20-at92_e1.4/drivers/misc/classes/mmcprot.c	2007-12-27 18:59:17.000000000 -0500
+++ linux-2.6.20-at92_e1.4_spi/drivers/misc/classes/mmcprot.c	2007-12-27 19:01:30.000000000 -0500
@@ -18,6 +18,16 @@
 #define DRV_MODULE_NAME 	"mmc"
 #define DRV_MODULE_VERSION 	"1.0"
 
+//#define MMCHARDERROR
+#ifdef MMCHARDERROR
+//debugging error, hard lock to find signal error via scope
+#define MMCERROR(err)	{printk("%s:MMCERR %s()[%d]: ", KBUILD_MODNAME, __FUNCTION__, __LINE__); while (1);}
+#else
+//return an error value on invalid communication.
+#define MMCERROR(err)	{return -err;}
+#endif
+
+
 static void checkmedia(unsigned long ptr){
 	mmcslot_t *s  = (mmcslot_t *)ptr;
 	//MMCDEBUG("checking media\n");
@@ -196,7 +206,7 @@ static int busy_wait(mmcslot_t *s){
 		set_current_state(TASK_INTERRUPTIBLE);//may want to shorten this.
 	 	schedule_timeout(HZ/100 ? HZ/100 : 1);
 		}
-			return -1;//error
+			MMCERROR(1);//error
 	}
 
 /**
@@ -220,7 +230,7 @@ static int wait_for_Rxtoken(mmcslot_t *s
 	 	set_current_state(TASK_INTERRUPTIBLE);
 	 	schedule_timeout(HZ/100 ? HZ/100 : 1);
 	 	}
-		return -1;
+		MMCERROR(1);
 		
 		return 1;
 }
@@ -254,7 +264,7 @@ static int wait_for_Rxtoken(mmcslot_t *s
 		if((response&MMCCOM_PARAMETER)!=0)
 			printk("parameter\n");
 		
-		return -1;				
+		MMCERROR(1);				
 	}
 /**
  * interprete the data response and throw exceptions as appropriate
@@ -270,16 +280,16 @@ static int wait_for_Rxtoken(mmcslot_t *s
 			return 0;//data was accepted, no need to complain
 		case MMCDAT_CRC_ERR:
 			printk("CRC error\n");
-			return -1;
+			MMCERROR(1);
 		case MMCDAT_WRITE_ERR:
 			printk("Write error\n");
-			return -1;
+			MMCERROR(1);
 		default:
 			printk("Communications error\n");
-			return -1;
+			MMCERROR(1);
 		}
 		
-		return -1;
+		MMCERROR(1);
 	}	
 
 /**
@@ -302,7 +312,8 @@ int mmctransaction(mmcslot_t *s, int com
 						
 		packetize(writebuff,(COMMAND_LENGTH+Ncr_MAX+response),command,arg1,arg2);
 		
-		s->tip(s,TRUE);
+		if((s->tip(s,TRUE))<0)MMCERROR(1);//could not obtain the bus
+			
 		MMCDEBUG("xmit\n");s->exchange(s,writebuff, readbuff, framelen);
 				
 		MMCDEBUG("interprete\n");
@@ -314,7 +325,7 @@ int mmctransaction(mmcslot_t *s, int com
 		if(bytenum==(framelen)){
 			MMCDEBUG("no command response received\n");
 			s->tip(s,FALSE);
-			return -1;
+			MMCERROR(1);
 			}
 			
 		MMCDEBUG("get_response\n");
@@ -354,7 +365,7 @@ int mmcblockread(mmcslot_t *s, int comma
 				
 		packetize(commandbuffer,COMMAND_LENGTH,command,arg1,arg2);
 
-		s->tip(s,TRUE);
+		if((s->tip(s,TRUE))<0)MMCERROR(1);//could not obtain the bus
 		s->exchange(s,commandbuffer, frame, sizeof(commandbuffer));
 		
 		//new broken up method cannot grab response within single xmit as it can 
@@ -369,7 +380,7 @@ int mmcblockread(mmcslot_t *s, int comma
 		if(frame_index==(COMMAND_LENGTH+Ncr_MAX+response)){
 			printk("MMC READ:no command response received\n");
 			s->tip(s,FALSE);
-			return -1;
+			MMCERROR(1);
 			}
 			
 		Rx = get_response(response,frame,frame_index);
@@ -377,7 +388,7 @@ int mmcblockread(mmcslot_t *s, int comma
 		if(CommandResponse(Rx)<0){
 			printk("MMC_READ:command response error, Rx=%x\n",Rx);
 			s->tip(s,FALSE);
-			return -1;//error
+			MMCERROR(1);//error
 		}
 		
 		MMCDEBUG("wait for rx token\n");
@@ -385,7 +396,7 @@ int mmcblockread(mmcslot_t *s, int comma
 			if(wait_for_Rxtoken(s)<0){
 				printk("MMC_READ:No Rx token received\n");
 				s->tip(s,FALSE);
-				return -1;//error
+				MMCERROR(1);//error
 			}
 			
 			MMCDEBUG("exchange data block %u\n",block);	
@@ -435,7 +446,7 @@ int mmcblockwrite(mmcslot_t *s,int comma
 		//transmit command and the first and possibly only block	
 		packetize(commandbuffer,sizeof(commandbuffer),command,arg1,arg2);
 			
-		s->tip(s,TRUE);
+		if((s->tip(s,TRUE))<0)MMCERROR(1);//could not obtain the bus
 		//a simpler command exchange than read, is there a reason read doesn't use this?		
 		s->exchange(s,commandbuffer, NULL, COMMAND_LENGTH);
 		
@@ -448,7 +459,7 @@ int mmcblockwrite(mmcslot_t *s,int comma
 		if(index==(COMMAND_LENGTH+MAX_NWR+MAX_RESPONSE)){
 			printk("MMC BWRITE:no command response received\n");
 			s->tip(s,FALSE);
-			return -1;
+			MMCERROR(1);
 			}
 			
 		index = get_response(response,commandbuffer,index);
@@ -456,7 +467,7 @@ int mmcblockwrite(mmcslot_t *s,int comma
 		if((CommandResponse(index))<0){
 			printk("MMC BWRITE command response error\n");
 			s->tip(s,FALSE);
-			return -1;//error
+			MMCERROR(1);//error
 		}	
 		
 		s->exchange(s,NULL, NULL, 1);//NWR delay
@@ -475,7 +486,7 @@ int mmcblockwrite(mmcslot_t *s,int comma
 			if(DataResponse(dataresponse)<0){
 				 printk("MMC Data Response error\n");
 				s->tip(s,FALSE);
-				return -1;//error
+				MMCERROR(1);//error
 			}
 			MMCDEBUG("Block %u\n",block);					
 			busy_wait(s);//wait for completion
@@ -501,11 +512,13 @@ int mmcinit(mmcslot_t *s){
 		u8 RegisterBuff[16];
 		int response,iteration,mult;
 		
+		s->setspeed(s,100000);//set spi speed to low for initial configuration as an spi device
+		
 		s->card.blocklength = 512;/*default, change later if appropriate*/
 
 		s->tip(s,FALSE);
 		mdelay(1);//make sure transaction has been off for at least 1ms
-		s->tip(s,TRUE);
+		if((s->tip(s,TRUE))<0)MMCERROR(1);//could not obtain the bus, this may need to be a retry
 		s->exchange(s,NULL, NULL,72);//send string of NULLS (0xff for MMC/SD) to clear out the card
 		s->tip(s,FALSE);
 		
@@ -523,7 +536,7 @@ int mmcinit(mmcslot_t *s){
 		if(iteration==100){
 			s->state=INVALID;
 			s->tip(s,FALSE);
-			return -1;
+			MMCERROR(1);
 		}
 
 		MMCDEBUG("SEND_CID\n");
@@ -532,7 +545,7 @@ int mmcinit(mmcslot_t *s){
 			printk("MMC: no CID register found\n");
 			s->state=INVALID;
 			s->tip(s,FALSE);
-			return -1;
+			MMCERROR(1);
 		}
 		else
 			parse_CID(&s->card.CID,RegisterBuff);	
@@ -542,7 +555,7 @@ int mmcinit(mmcslot_t *s){
 		if(SEND_CSD(s,RegisterBuff)<0){
 			s->state=INVALID;
 			s->tip(s,FALSE);
-			return -1;
+			MMCERROR(1);
 		}
 			
 		parse_CSD(&s->card.CSD,RegisterBuff);		
diff -uprN linux-2.6.20-at92_e1.4/drivers/misc/classes/spi.c linux-2.6.20-at92_e1.4_spi/drivers/misc/classes/spi.c
--- linux-2.6.20-at92_e1.4/drivers/misc/classes/spi.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.20-at92_e1.4_spi/drivers/misc/classes/spi.c	2007-12-27 19:02:30.000000000 -0500
@@ -0,0 +1,211 @@
+/**
+ * A class for simple gpio ports
+ * Several types of general purpose devices are available 
+ * which all export the same basic functionity 
+ * through different underlying methods
+ * This class can also be used to export simple interfaces
+ * to an 8 bit port into user space
+ */
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/device.h>
+#include <linux/ctype.h>
+#include <linux/kdev_t.h>
+#include <linux/chelper.h>
+#include <linux/class/spi.h>
+#include <asm/io.h>
+
+#ifdef CONFIG_SPICLASS_RTDM
+#include <rtdm/rtdm_driver.h>
+#include <linux/class/rtdm/spi_rtdm.h>
+#define ATOMIC(a) RTDM_EXECUTE_ATOMICALLY(a)
+#else
+#define ATOMIC(a) a
+#endif //CONFIG_GPIOCLASS_RTDM
+
+#ifdef CONFIG_SPICLASS_CHAR
+#include <linux/class/char/spi_char.h>
+#endif
+
+/************************************************************
+ * the global device class
+ */
+static struct class *spiclass = NULL;
+
+struct class *spi_declare(void){
+	if(!spiclass){
+		printk("registering GPIO class\n");
+		spiclass=class_create(THIS_MODULE,"spi");
+#ifdef CONFIG_SPICLASS_CHAR
+		spi_char_init();
+#endif
+	}
+	return spiclass;
+}
+
+/***************************************************************************
+ * Atomic method wrappers
+ */
+int atomic_spi_tip(struct spi_s *s,int ofs){
+	spi_data retval;
+	ATOMIC(retval = s->tip(s,ofs);)
+	return retval;
+}
+
+int atomic_spi_xmit(struct spi_s *s,u8 *mosi, u8 *miso, int size){
+	ATOMIC(s->xmit(s,mosi, miso, size);)
+	return 0;
+}
+
+int atomic_spi_tip_write(struct spi_s *s,spi_control config){
+	ATOMIC(s->tip(s,(config>0));)
+	return 0;
+}
+
+spi_control atomic_spi_tip_read(struct spi_s *s){
+	spi_data retval;
+	ATOMIC(retval = s->tip(s,TIPSTATUS);)
+	return (retval>0);
+}
+
+int atomic_spi_conf_write(struct spi_s *s,spi_control config){
+	ATOMIC(s->confwrite(s, config);)
+	return 0;
+}
+
+spi_control atomic_spi_conf_read(struct spi_s *s){
+	spi_control retval;
+	ATOMIC(retval = s->confread(s);)
+	return retval;
+}
+
+int atomic_spi_speed_write(struct spi_s *s,spi_control speed){
+	ATOMIC(s->speedwrite(s, speed);)
+	return 0;
+}
+
+spi_control atomic_spi_speed_read(struct spi_s *s){
+	spi_control retval;
+	ATOMIC(retval = s->speedread(s);)
+	return retval;
+}
+
+
+/***************************************************************************
+ * gpio sysfs operations
+ */
+#ifdef CONFIG_SPICLASS_SYSFS
+#define SPIXMITDELIM ","
+
+static ssize_t spi_xmit_store(struct class_device *cls, const char *buf,size_t count){
+	spi_t *s = cls->class_data;
+	size_t size;	
+	//atomic_spi_tip(s,TIPON);
+	if(s->buf){kfree(s->buf);s->bsize=0;} /* this is not safe unless buf is set to NULL on init */
+	//worst case allocation, char-delim-char-delim = count/2 * 4 bytes per word
+	s->buf = kmalloc(count*2, GFP_KERNEL);
+	s->bsize = sfs_getstream(buf,count,&size,SPIXMITDELIM,s->buf);
+	{
+	int i;
+	printk("%s-data: ",__FUNCTION__);
+	for(i=0;i<s->bsize;i++)printk("0x%x ",s->buf[i]);
+	printk("\n");
+	}
+	atomic_spi_xmit(s,s->buf, s->buf, s->bsize);
+	//atomic_spi_tip(s,TIPOFF);
+
+	return size;
+}
+
+static ssize_t spi_xmit_show(struct class_device *cls, char *buf){
+	spi_t *s = cls->class_data;
+	int chars=0;
+	int i;
+	
+	for(i=0;i<s->bsize;i++){
+		if(chars>=(PAGE_SIZE-10)){
+			chars+=sprintf(&buf[chars],"...OVF");
+			return chars;
+		}
+		if(i)chars+=sprintf(&buf[chars],SPIXMITDELIM);
+		chars+=sprintf(&buf[chars],"%x",s->buf[i]);
+	}
+	chars+=sprintf(&buf[chars],"\n");
+	return chars;
+}
+
+static ssize_t spi_flags_store(struct class_device *cls, const char *buf,size_t count){
+	size_t size;
+	spi_t *s = cls->class_data;
+	spi_control data = sfs_getint(buf,count,&size);
+	atomic_spi_conf_write(s, data);
+	return size;
+}
+
+static ssize_t spi_flags_show(struct class_device *cls, char *buf){
+	spi_t *s = cls->class_data;
+	return sprintf(buf,"%x\r\n",atomic_spi_conf_read(s));
+}	
+
+static ssize_t spi_speed_store(struct class_device *cls, const char *buf,size_t count){
+	size_t size;
+	spi_t *s = cls->class_data;
+	spi_control data = sfs_getint(buf,count,&size);
+	atomic_spi_speed_write(s, data);
+	return size;
+}
+
+static ssize_t spi_speed_show(struct class_device *cls, char *buf){
+	spi_t *s = cls->class_data;
+	return sprintf(buf,"%d\r\n",atomic_spi_speed_read(s));
+}	
+
+static ssize_t spi_tip_store(struct class_device *cls, const char *buf,size_t count){
+	size_t size;
+	spi_t *s = cls->class_data;
+	spi_data data = sfs_getint(buf,count,&size);
+	atomic_spi_tip_write(s,data);
+	return size;
+}
+
+static ssize_t spi_tip_show(struct class_device *cls, char *buf){
+	spi_t *s = cls->class_data;
+	return sprintf(buf,"%x\r\n",(atomic_spi_tip_read(s)));
+}
+
+static CLASS_DEVICE_ATTR(xmit,S_IRUGO|S_IWUGO,spi_xmit_show,spi_xmit_store);
+static CLASS_DEVICE_ATTR(tip,S_IRUGO|S_IWUGO,spi_tip_show,spi_tip_store);
+static CLASS_DEVICE_ATTR(speed,S_IRUGO|S_IWUGO,spi_speed_show,spi_speed_store);
+static CLASS_DEVICE_ATTR(conf,S_IRUGO|S_IWUGO,spi_flags_show,spi_flags_store);
+#endif //CONFIG_SPICLASS_SYSFS
+/***************************************************************************
+* class instantiation
+*/
+struct class_device *spi_register_class_device(spi_t *s){		
+struct class *spi_master = spi_declare();
+struct class_device *dev;	
+dev_t devnum = MKDEV(0, 0);
+
+#ifdef CONFIG_SPICLASS_CHAR
+devnum = spi_char_create(s);
+#endif	
+	
+dev = class_device_create(spi_master, NULL, devnum, NULL, s->name);
+dev->class_data = s;
+
+s->bsize = 0;
+s->buf = NULL;
+
+#ifdef CONFIG_SPICLASS_SYSFS
+	if(s->xmit)class_device_create_file(dev,&class_device_attr_xmit);
+	if(s->tip)class_device_create_file(dev,&class_device_attr_tip);
+	if((s->speedwrite)&&(s->speedread))class_device_create_file(dev,&class_device_attr_speed);
+	if((s->confwrite)&&(s->confread))class_device_create_file(dev,&class_device_attr_conf);
+	#endif	 
+
+#ifdef CONFIG_SPICLASS_RTDM
+	rt_spi_device_create(s);
+#endif
+
+return dev;			
+}
diff -uprN linux-2.6.20-at92_e1.4/drivers/misc/classes/spi_interface.c linux-2.6.20-at92_e1.4_spi/drivers/misc/classes/spi_interface.c
--- linux-2.6.20-at92_e1.4/drivers/misc/classes/spi_interface.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.20-at92_e1.4_spi/drivers/misc/classes/spi_interface.c	2007-12-27 19:02:30.000000000 -0500
@@ -0,0 +1,214 @@
+#include <linux/class/spi_interface.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/spi/spi.h>
+
+/**
+ * Provides an interface betwee the Linux SPI interface and the
+ * EMAC SPI class (lsi2esc).
+ * 
+ * Copyright (C) 2007, EMAC Inc
+ */
+
+/**
+ * function to set/clear a transfer-in-progrees for
+ * the given device. This function should be implemented
+ * by the driver itself to make sure that the same device
+ * is being accessed and as such this function does nothing
+ */
+int lsi2esc_spi_tip(struct spi_s *s, int ofs)
+{
+    printk("lsi2esc_spi_tip\n");
+    return 0;
+}
+
+/**
+ * function to transfer data on the SPI bus
+ * Assumptions: MOSI and MISO can be the same buffer,
+ * if MOSI is NULL 0xFF is transmitted, if MISO is NULL
+ * received data is discarded, there is no limit on buffer
+ * size.
+ * @param s the EMAC SPI class device to tranfer data on
+ * @param mosi the transmit buffer (master->slave)
+ * @param miso the receive buffer (slave->master)
+ * @param size the size of the data to transfer
+ * @return 0 or negative error code
+ */ 
+int lsi2esc_spi_xmit(struct spi_s *s, u8 *mosi, u8 *miso, int size)
+{
+    int result = 0;
+    u8 *local_mosi = mosi;
+    u8 *local_miso = miso;
+    
+    printk("lsi2esc_spi_xmit\n");
+
+    if (!local_mosi) {
+        if (!(local_mosi = kmalloc(size, GFP_KERNEL)))
+            return -ENOMEM;
+        /* memset to 0xFF */
+        memset(local_mosi, 0xFF, size);
+    }
+    result = spi_write(s->lsi, local_mosi, size);
+    if ((result == 0) && local_miso) { /* success */
+        result = spi_read(s->lsi, local_miso, size);
+    }
+    if (!mosi)
+        kfree(local_mosi);
+    return result;
+}
+
+/**
+ * function to read the current configuration settings
+ * @param s the EMAC SPI class device to read from
+ * @return the current configuration
+ */
+spi_control lsi2esc_spi_confread(struct spi_s *s)
+{
+    spi_control flags = 0;
+    printk("lsi2esc_spi_confread\n");
+
+    flags = s->lsi->mode; /* SPI and SPICL same here */
+
+    printk("bits_per_word = %d\n", s->lsi->bits_per_word);
+    if (s->lsi->bits_per_word == 8)
+        flags |= SPICL_EIGHTBIT; /* actually does nothing */
+    else if (s->lsi->bits_per_word == 10)
+        flags |= SPICL_TENBIT;
+    else if (s->lsi->bits_per_word == 12)
+        flags |= SPICL_TWELVEBIT;
+    else if (s->lsi->bits_per_word == 16)
+        flags |= SPICL_SIXTEENBIT;
+    
+    return flags;
+}
+
+/**
+ * function to change the current configuration settings
+ * @param s the EMAC SPI class device to configure
+ * @param config the new configuration to write
+ * @return 0 or the result of spi_setup
+ */
+int lsi2esc_spi_confwrite(struct spi_s *s, spi_control config)
+{
+    printk("lsi2esc_spi_confwrite: %d\n", config);
+    
+    /* set the mode */
+    s->lsi->mode = 0;
+    if (config & SPI_CPOL)
+        s->lsi->mode |= SPI_CPOL;
+    if (config & SPI_CPHA)
+        s->lsi->mode |= SPI_CPHA;
+    
+    /* explicitly set the bits per word if specified
+     * otherwise leave unchanged */
+    if (config & SPICL_EIGHTBIT)
+        s->lsi->bits_per_word = 8;
+    else if (config & SPICL_TENBIT)
+        s->lsi->bits_per_word = 10;
+    else if (config & SPICL_TWELVEBIT)
+        s->lsi->bits_per_word = 12;
+    else if (config & SPICL_SIXTEENBIT)
+        s->lsi->bits_per_word = 16;
+    
+    return spi_setup(s->lsi);
+}
+
+/**
+ * function to get the current speed settings
+ * @param s the EMAC SPI class device
+ * @return the speed setting of the associated spi_device
+ */
+spi_control lsi2esc_spi_speedread(struct spi_s *s)
+{
+    printk("lsi2esc_spi_speedread\n");
+    return s->lsi->max_speed_hz;    
+}
+
+/**
+ * function to change the speed settings
+ * @param s the EMAC SPI class device
+ * @param speed the new speed to set
+ */
+int lsi2esc_spi_speedwrite(struct spi_s *s, spi_control speed)
+{
+    printk("lsi2esc_spi_speedwrite\n");
+    s->lsi->max_speed_hz = speed;
+    /* error checking and adjustment must be provided by
+     * the SPI controller driver to use this directly */
+    return spi_setup(s->lsi);
+}
+
+/******************************************************************************/
+
+/**
+ * The lsi2esc interface actually acts like an SPI protocol driver.
+ * It fakes as an SPI device, but performs generic access to SPI
+ * only through the EMAC class interface rather than device specific
+ * access. The following section provides the SPI protocol driver
+ * code.
+ */
+
+/**
+ * probe function to initialize the interface
+ */
+
+static int __devinit lsi2esc_probe(struct spi_device *spi)
+{
+    struct spi_s *esc;
+    /* the platform data of dev must be set to the spi_t in
+     * the board specific file */
+    /* kind of creates a loop... but thats OK */
+    esc = spi->dev.platform_data;
+    esc->lsi = spi;
+
+    if (!esc)
+        return -ENODEV;
+    if (!spi_register_class_device(esc))
+        return -ENOMEM;
+
+    return 0;    
+}
+
+/**
+ * remove function to provide a clean exit
+ */
+
+static int __devexit lsi2esc_remove(struct spi_device *spi)
+{
+    /* nothing to do here */
+    return 0;
+}
+
+static struct spi_driver lsi2esc_driver = {
+    .driver = {
+        .name   = "lsi2esc",
+        .bus    = &spi_bus_type,
+        .owner  = THIS_MODULE,
+    },
+    .probe  = lsi2esc_probe,
+    .remove = __devexit_p(lsi2esc_remove),
+};
+
+static __init int lsi2esc_init(void)
+{
+    printk("Registering LSI2ESC SPI driver\n");
+    return spi_register_driver(&lsi2esc_driver);
+}
+
+static __exit void lsi2esc_exit(void)
+{
+    spi_unregister_driver(&lsi2esc_driver);
+}
+
+module_init(lsi2esc_init);
+module_exit(lsi2esc_exit);
+
+MODULE_AUTHOR("EMAC.Inc (support@emacinc.com)");
+MODULE_DESCRIPTION("Generic EMAC SPI class to Linux SPI Interface Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+
+// EOF
diff -uprN linux-2.6.20-at92_e1.4/include/linux/chelper.h linux-2.6.20-at92_e1.4_spi/include/linux/chelper.h
--- linux-2.6.20-at92_e1.4/include/linux/chelper.h	2007-12-27 18:59:18.000000000 -0500
+++ linux-2.6.20-at92_e1.4_spi/include/linux/chelper.h	2007-12-27 19:01:30.000000000 -0500
@@ -15,6 +15,36 @@
 	if (*size != count)*size = -EINVAL;
 	return data;
  }
+
+ /** 
+  * converts a stream of separated integers into an allocated array.
+  * returns the number of integers converted
+  * stores the number of characters converted to integers in size
+  */
+ static inline  int sfs_getstream(const char *buf,size_t count,size_t *size,const char *delim,u8 *data){
+	char *tokenstring = strcpy(kmalloc(count,GFP_KERNEL),buf);
+	char *mark = tokenstring;
+	char *endp;
+	char *token;
+	int index=0;
+	
+	//printk("%s - mark:%s\n",__FUNCTION__,mark);
+	
+	while((token=strsep(&mark, delim))!=NULL){
+		//printk("mark:%s\n",mark);
+		data[index++] = simple_strtoul(token,&endp,0);
+	}
+		
+	*size = (size_t)(endp - tokenstring);
+	if (*endp && isspace(*endp))(*size)++;
+	if (*size != count)*size = -EINVAL;
+	
+	//printk("size = %d\n",*size);
+	
+	kfree(tokenstring);
+	return index;
+ }
+ 
  
 /**
  * depreciated
diff -uprN linux-2.6.20-at92_e1.4/include/linux/class/char/spi_char.h linux-2.6.20-at92_e1.4_spi/include/linux/class/char/spi_char.h
--- linux-2.6.20-at92_e1.4/include/linux/class/char/spi_char.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.20-at92_e1.4_spi/include/linux/class/char/spi_char.h	2007-12-27 19:01:30.000000000 -0500
@@ -0,0 +1,27 @@
+#ifndef SPI_CHAR_H_
+#define SPI_CHAR_H_
+
+#ifdef __KERNEL__
+int spi_char_init(void);
+int spi_char_create(struct spi_s *spi);
+
+#ifndef SPI_MAJOR
+#define SPI_MAJOR 0
+#endif
+
+/* we use the max_devs define to register a region on init */
+#define SPI_MAX_DEVS 15
+#endif /*__KERNEL__*/
+
+typedef struct spi_transfer_s{
+	spi_data *mosi;
+	spi_data *miso;
+	ssize_t size;
+}spi_transfer_t;
+
+/* This header defines the ioctl commands */
+#include <linux/class/rtdm/spi_rtdm.h>
+
+#define CHAR_CLASS_SPI RTDM_CLASS_SPI
+
+#endif /*SPI_CHAR_H_*/
diff -uprN linux-2.6.20-at92_e1.4/include/linux/class/gpio.h linux-2.6.20-at92_e1.4_spi/include/linux/class/gpio.h
--- linux-2.6.20-at92_e1.4/include/linux/class/gpio.h	2007-12-27 18:59:18.000000000 -0500
+++ linux-2.6.20-at92_e1.4_spi/include/linux/class/gpio.h	2007-12-27 19:00:54.000000000 -0500
@@ -95,6 +95,26 @@ static inline struct class_device *gpio_
     return gpio_register_class_device(gpio);
 }
 
+/* create a gpio_s struct and initialize for gpio port without registering it */
+
+static inline struct gpio_s *gpio_device_create_unregistered(void *data, void *ddr,const char *name){
+    gpio_t *gpio = kmalloc(sizeof(gpio_t),GFP_KERNEL);
+    memset(gpio,0,sizeof(gpio_t));
+    gpio->name = name;
+    gpio->subclass = GPIO_SUBCLASS;
+    gpio->ddr = ddr;
+    gpio->data = data;
+    gpio->shadow = 0;   
+    gpio->data_write = gpio_data_write8;
+    gpio->data_read = gpio_data_read8;
+    
+    if(ddr){
+        gpio->ddr_write = gpio_ddr_write8;
+        gpio->ddr_read = gpio_ddr_read8;
+    }
+    return gpio;
+}
+
 /************************************************************************************
  * shadow gpo ports, 
  * these ports are write only and have no register to read back the current state
@@ -120,6 +140,22 @@ static inline struct class_device *gpo_d
     return gpio_register_class_device(gpio);
 }
 
+static inline struct gpio_s *gpo_device_create_unregistered(void *data, const char *name)
+{
+    gpio_t *gpio = kmalloc(sizeof(gpio_t),GFP_KERNEL);
+    memset(gpio,0,sizeof(gpio_t));
+    gpio->name = name;
+    gpio->subclass = GPO_SUBCLASS;
+    gpio->data = data;
+    gpio->shadow = 0;
+    gpio->data_write = gpio_data_write8;
+    gpio->data_read = gpio_shadow_read8;
+    gpio->ddr_write = gpio_empty_write;
+    gpio->ddr_read = gpio_ff_read;
+    return gpio;
+}
+
+
 /************************************************************************************
  * gpi ports, gpi ports are functionally the same as gpio input only ports,
  * but their ddr ports are not implemented in hardware 
@@ -139,7 +175,24 @@ static inline struct class_device *gpi_d
     gpio->ddr_read = gpio_zero_read;
     printk("registering gpi device: %s\n",name);
     return gpio_register_class_device(gpio);
-}	
+}
+
+/* create a gpio_s struct and initialize for gpi port without registering it */
+
+static inline struct gpio_s *gpi_device_create_unregistered(void *data,const char *name){
+    gpio_t *gpio = kmalloc(sizeof(gpio_t),GFP_KERNEL);
+    memset(gpio,0,sizeof(gpio_t));
+    gpio->name = name;
+    gpio->subclass = GPI_SUBCLASS;
+    gpio->data = data;
+    gpio->shadow = 0;
+    gpio->data_write = gpio_empty_write;
+    gpio->data_read = gpio_data_read8;
+    gpio->ddr_write = gpio_empty_write;
+    gpio->ddr_read = gpio_zero_read;
+    return gpio;
+}   
+
 #endif
 
 #endif /*GPIO_H_*/
diff -uprN linux-2.6.20-at92_e1.4/include/linux/class/rtdm/spi_rtdm.h linux-2.6.20-at92_e1.4_spi/include/linux/class/rtdm/spi_rtdm.h
--- linux-2.6.20-at92_e1.4/include/linux/class/rtdm/spi_rtdm.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.20-at92_e1.4_spi/include/linux/class/rtdm/spi_rtdm.h	2007-12-27 19:01:30.000000000 -0500
@@ -0,0 +1,21 @@
+#ifndef SPI_RTDM_H_
+#define SPI_RTDM_H_
+
+#include <linux/ioctl.h>
+
+//arbitrary assignment, come back to this later
+#define RTDM_CLASS_SPI 0x90 
+
+#ifdef __KERNEL__	
+int rt_spi_device_create(struct spi_s *spi);
+#endif//__KERNEL__
+
+#define CONFREAD		_IOR(RTDM_CLASS_SPI,0,spi_control)
+#define CONFWRITE		_IOW(RTDM_CLASS_SPI,0,spi_control)
+#define SPEEDREAD		_IOR(RTDM_CLASS_SPI,1,spi_control)
+#define SPEEDWRITE		_IOW(RTDM_CLASS_SPI,1,spi_control)
+#define TIPREAD			_IOR(RTDM_CLASS_SPI,2,spi_control)
+#define TIPWRITE		_IOW(RTDM_CLASS_SPI,2,spi_control)
+#define XMIT			_IOW(RTDM_CLASS_SPI,3,spi_transfer_t)
+
+#endif //SPI_RTDM_H_
diff -uprN linux-2.6.20-at92_e1.4/include/linux/class/spi.h linux-2.6.20-at92_e1.4_spi/include/linux/class/spi.h
--- linux-2.6.20-at92_e1.4/include/linux/class/spi.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.20-at92_e1.4_spi/include/linux/class/spi.h	2007-12-27 19:02:05.000000000 -0500
@@ -0,0 +1,85 @@
+#ifndef SPI_H_
+#define SPI_H_
+#include <linux/autoconf.h>
+#include <linux/device.h>
+#if defined(CONFIG_LSI2ESC)
+#include <linux/spi/spi.h>
+#endif
+
+#ifdef CONFIG_SPICLASS	
+
+#define SPICL_CPHA			(0x01)
+#define SPICL_CPOL			(0x02)
+/* common bit settings -- should be mutually exclusive */
+/* it would be possible to let 8 bit mode be 0x00 and let
+ * this be the default, but this does not work well for the
+ * LSI2ESC interface as the default controller setting is to
+ * leave bits_per_word set to 0. Leave 8 bit as an explicit
+ * setting. */
+#define SPICL_EIGHTBIT		(0x04) /* 8 bit is default */
+#define SPICL_TENBIT        (0x08) /* 10 bits per transfer */ 
+#define SPICL_TWELVEBIT     (0x10) /* 12 bits per transfer */
+#define SPICL_SIXTEENBIT    (0x20) /* 16 bits per transfer */
+
+typedef u8 spi_data;
+typedef u32 spi_control;
+
+//control definitions for the tip function
+#define TIPOFF		0
+#define TIPON		1
+#define TIPSTATUS	2
+
+/**********************
+ * spi class structure
+ */
+typedef struct spi_s{
+	const char *name;
+	int subclass;
+	spi_data *buf; 
+	int bsize;
+	/* if the SPI interface is used there needs to be a pointer to
+	 * the associated spi_device struct used by the Linux SPI layer
+	 */
+#if defined(CONFIG_LSI2ESC)
+	struct spi_device *lsi;
+#endif
+	int (*tip)(struct spi_s *s,int ofs);//declare transfer in process, for locking purposes
+	int (*xmit)(struct spi_s *s,u8 *mosi, u8 *miso, int size);
+	int (*confwrite)(struct spi_s *s,spi_control config);
+	spi_control (*confread)(struct spi_s *s);
+	int (*speedwrite)(struct spi_s *s,spi_control speed);
+	spi_control (*speedread)(struct spi_s *s);
+}spi_t;
+
+#define SPI_BASECLASNUM	0xC0
+#define SPI_SUBCLASS 	(SPI_BASECLASNUM+0)
+
+/***************************************************************************
+ * initial class declaration, doesn't hurt to call it mulitiple times,
+ * automatically checked during device instantiation 
+ */
+struct class *spi_declare(void);
+
+/***************************************************************************
+* class instantiation
+*/
+struct class_device *spi_register_class_device(spi_t *s);
+
+
+/***************************************************************************
+ * atomic method wrappers
+ * these should be used for all method calls to maintain sychronization across the
+ * various interfaces
+ */
+int atomic_spi_xmit(struct spi_s *s,u8 *mosi, u8 *miso, int size);
+int atomic_spi_conf_write(struct spi_s *s,spi_control config);
+spi_control atomic_spi_conf_read(struct spi_s *s);
+int atomic_spi_speed_write(struct spi_s *s,spi_control config);
+spi_control atomic_spi_speed_read(struct spi_s *s);
+int atomic_spi_tip_write(struct spi_s *s,spi_control config);
+spi_control atomic_spi_tip_read(struct spi_s *s);
+
+
+#endif
+
+#endif /*SPI_H_*/
diff -uprN linux-2.6.20-at92_e1.4/include/linux/class/spi_interface.h linux-2.6.20-at92_e1.4_spi/include/linux/class/spi_interface.h
--- linux-2.6.20-at92_e1.4/include/linux/class/spi_interface.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.20-at92_e1.4_spi/include/linux/class/spi_interface.h	2007-12-27 19:02:05.000000000 -0500
@@ -0,0 +1,28 @@
+#ifndef SPI_INTERFACE_H_
+#define SPI_INTERFACE_H_
+
+/**
+ * Provides an interface between the SPI class
+ * driver and the Linux SPI layer for devices that
+ * already implement a device specific driver and
+ * register this interface in the mach.
+ * Naming convention:
+ * Linux SPI Interface: lsi
+ * EMAC SPI Class: esc
+ * -> lsi2esc
+ * 
+ * Copyright (C) 2007, EMAC Inc
+ */
+
+#include <linux/device.h>
+#include <linux/spi/spi.h>
+#include <linux/class/spi.h>
+
+int lsi2esc_spi_tip(struct spi_s *s,int ofs);
+int lsi2esc_spi_xmit(struct spi_s *s, u8 *mosi, u8 *miso, int size);
+int lsi2esc_spi_confwrite(struct spi_s *s, spi_control config);
+spi_control lsi2esc_spi_confread(struct spi_s *s);
+int lsi2esc_spi_speedwrite(struct spi_s *s, spi_control speed);
+spi_control lsi2esc_spi_speedread(struct spi_s *s);
+
+#endif /*SPI_INTERFACE_H_*/

