diff -Naur linux-2.6.25/arch/arm/mach-ep93xx/emac9307.c linux-2.6.25.ep93xx/arch/arm/mach-ep93xx/emac9307.c
--- linux-2.6.25/arch/arm/mach-ep93xx/emac9307.c	1969-12-31 18:00:00.000000000 -0600
+++ linux-2.6.25.ep93xx/arch/arm/mach-ep93xx/emac9307.c	2009-03-26 15:35:30.000000000 -0500
@@ -0,0 +1,622 @@
+/*
+ * arch/arm/mach-ep93xx/emac9307.c
+ * EMAC EDB9307 based product support.
+ *
+ * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org>
+ *
+ * Copyright (C) 2008 EMAC Inc. <support@emacinc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/mtd/physmap.h>
+#include <linux/platform_device.h>
+#include <linux/ioex/ecoreex.h>
+#include <linux/class/gpio.h>
+#include <linux/class/mmcprot.h>
+#include <linux/class/spi.h>
+#include <linux/class/spi_interface.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/arch/ep93xx_util.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/mmc_spi.h>
+#include <linux/mmc/host.h>
+#include <linux/jiffies.h>
+#include <linux/ioex/pb1010.h>
+
+#include <asm/arch/gpio.h>
+
+#define CS0CONFIG *((u32 *)(SMCBCR0))
+#define CS1CONFIG *((u32 *)(SMCBCR1))
+#define CS2CONFIG *((u32 *)(SMCBCR2))
+#define CS3CONFIG *((u32 *)(SMCBCR3))
+
+static struct physmap_flash_data emac9307_flash_data = {
+	.width		= 2,
+};
+
+static struct resource emac9307_flash_resource[] = {
+	{
+	.start		= 0x60000000,
+#ifdef CONFIG_MACH_EMAC9307_16
+	.end		= 0x60ffffff,
+#else	
+	.end		= 0x61ffffff,
+#endif
+	.flags		= IORESOURCE_MEM,
+	}
+};
+
+#ifdef CONFIG_MACH_EMAC9307_64
+static struct resource emac9307_aux_resource[] = {
+	{
+	.start		= 0x62000000,
+	.end		= 0x63ffffff,
+	.flags		= IORESOURCE_MEM,
+	}
+};
+#endif
+
+static struct platform_device emac9307_flash = {
+	.name		= "physmap-flash",
+	.id		= 0,
+	.dev		= {
+		.platform_data	= &emac9307_flash_data,
+	},
+//#if defined(CONFIG_MACH_EMAC9307_64)
+//	.num_resources	= 2,	
+//#else	
+	.num_resources	= 1,
+//#endif	
+	.resource	= emac9307_flash_resource,
+};
+
+#ifdef CONFIG_MACH_EMAC9307_64
+static struct platform_device emac9307_aux = {
+	.name		= "physmap-flash",
+	.id		= 1,
+	.dev 		= {
+		.platform_data = &emac9307_flash_data,
+	},
+	.num_resources	= 1,
+	.resource	= emac9307_aux_resource,
+};
+#endif
+
+#ifdef CONFIG_PB1014
+static struct physmap_flash_data pb1014_flash_data = {
+	.width		= 2,
+};
+
+static struct resource pb1014_flash_resource[] = {
+	{
+	.start		= 0x20000000,
+	.end		= 0x21ffffff,
+	.flags		= IORESOURCE_MEM,
+	}
+};
+
+static struct platform_device pb1014_flash = {
+	.name		= "physmap-flash",
+	.id 		= 2,
+	.dev		= {
+		.platform_data = &pb1014_flash_data,
+	},
+	.num_resources	= 1,
+	.resource	= pb1014_flash_resource,
+
+};
+#endif
+
+static struct ep93xx_eth_data emac9307_eth_data = {
+	.phy_id			= 1,
+};
+
+static struct resource emac9307_eth_resource[] = {
+	{
+		.start	= EP93XX_ETHERNET_PHYS_BASE,
+		.end	= EP93XX_ETHERNET_PHYS_BASE + 0xffff,
+		.flags	= IORESOURCE_MEM,
+	}, {
+		.start	= IRQ_EP93XX_ETHERNET,
+		.end	= IRQ_EP93XX_ETHERNET,
+		.flags	= IORESOURCE_IRQ,
+	}
+};
+
+static struct platform_device emac9307_eth_device = {
+	.name		= "ep93xx-eth",
+	.id		= -1,
+	.dev		= {
+		.platform_data	= &emac9307_eth_data,
+	},
+	.num_resources	= 2,
+	.resource	= emac9307_eth_resource,
+};
+
+static struct resource ep93xx_spi_resources[] = {
+      [0] = {
+              .start  = EP93XX_SPI_BASE_PHYS,
+              .end    = EP93XX_SPI_BASE_PHYS + 0x0fff,
+              .flags  = IORESOURCE_MEM,
+      },
+      [1] = {
+              .start  = IRQ_EP93XX_SSP,
+              .end    = IRQ_EP93XX_SSP,
+              .flags  = IORESOURCE_IRQ,
+      },
+};
+
+static struct platform_device ep93xx_spi_device = {
+      .name           = "ep93xx-spi",
+      .id             = 0,
+      .dev            = {
+              .bus_id         = "apb:spi",
+      },
+      .resource       = ep93xx_spi_resources,
+      .num_resources  = ARRAY_SIZE(ep93xx_spi_resources),
+};
+
+#if defined(CONFIG_SPI)
+
+#ifdef CONFIG_MACH_PPCE7
+#define EP93XX_MMC_SPI_CHIP_SELECT	EP93XX_GPIO_LINE_B(7)
+#define EP93XX_MMC_SPI_CARD_PRESENT	EP93XX_GPIO_LINE_D(6)
+#else
+#define EP93XX_MMC_SPI_CHIP_SELECT	EP93XX_GPIO_LINE_D(6)
+#define EP93XX_MMC_SPI_CARD_PRESENT	EP93XX_GPIO_LINE_B(7)
+#endif
+
+#define EP93XX_MMC_SPI_POWER 		EP93XX_GPIO_LINE_D(7)
+#define EP93XX_MMC_SPI_WRITE_PROT	EP93XX_GPIO_LINE_C(7)
+#define EP93XX_MMC_SPI_CARD_DETECT	EP93XX_MMC_SPI_WRITE_PROT
+#define EP93XX_MMC_SPI_CARD_DETECT2	EP93XX_MMC_SPI_CARD_PRESENT
+
+/**
+ * Initializes SPI system to communicate with MMC/SD card
+ */
+int ep93xx_mmc_spi_init (struct device *pdev, irqreturn_t (*card_det_irq_handler)(int, void *),
+		void *mmc)
+{
+//	int rv;
+
+	// Make sure chip select is disabled at first
+	gpio_line_config (EP93XX_MMC_SPI_CHIP_SELECT, GPIO_OUT);
+	gpio_line_set (EP93XX_MMC_SPI_CHIP_SELECT, EP93XX_GPIO_HIGH);
+	
+	// Enable Power to the MMC device
+	gpio_line_config (EP93XX_MMC_SPI_POWER, GPIO_OUT);
+	gpio_line_set (EP93XX_MMC_SPI_POWER, EP93XX_GPIO_LOW);
+
+	// Make the WP and CD lines inputs
+	gpio_line_config (EP93XX_MMC_SPI_WRITE_PROT, GPIO_IN);
+	gpio_line_config (EP93XX_MMC_SPI_CARD_PRESENT, GPIO_IN);
+
+// Example of how to better use an interrupt enabled line
+//	if ((rv = request_irq (IRQ_EP93XX_GPIO(EP93XX_MMC_SPI_CARD_DETECT2),
+//					card_det_irq_handler,
+//					// IRQF_DISABLED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, /* flags */
+//					IRQF_DISABLED | IRQF_TRIGGER_FALLING, /* flags */
+//					"ep93xx-mmc-spi", 	/* devname */
+//					mmc 			/* void *devid */
+//			      )) == 0)
+//	{
+//		dev_info (pdev, "MMC/SD card detection IRQ %i assigned.\n",
+//				IRQ_EP93XX_GPIO(EP93XX_MMC_SPI_CARD_DETECT2));
+//	}
+//	else
+//	{
+//		dev_err (pdev, "Cannot assign MMC/SD card detection IRQ (%i)!\n",
+//				IRQ_EP93XX_GPIO(EP93XX_MMC_SPI_CARD_DETECT2));
+//		return rv;
+//	}	
+
+	// Make sure the EEPROM is not chip selected
+	gpio_line_config (EP93XX_GPIO_LINE_A(7), GPIO_OUT);
+	gpio_line_set (EP93XX_GPIO_LINE_A(7), EP93XX_GPIO_HIGH);
+	return 0;
+}
+
+void ep93xx_mmc_spi_exit (struct device *pdev, void *mmc)
+{
+}
+
+void ep93xx_mmc_spi_setpower (struct device *pdev, unsigned int vdd)
+{
+	if (( 1 << vdd) & MMC_VDD_33_34)
+		gpio_line_set (EP93XX_MMC_SPI_POWER, EP93XX_GPIO_LOW);
+	else
+		gpio_line_set (EP93XX_MMC_SPI_POWER, EP93XX_GPIO_HIGH);
+}
+
+int ep93xx_mmc_spi_get_cd (struct device *dev)
+{
+	return gpio_get_value(EP93XX_MMC_SPI_CARD_PRESENT);
+}
+
+
+int ep93xx_mmc_spi_get_ro (struct device *dev)
+{
+	return gpio_get_value(EP93XX_MMC_SPI_WRITE_PROT);
+}
+
+static struct mmc_spi_platform_data ep93xx_spi_pdata = {
+	.init = &ep93xx_mmc_spi_init,
+	.exit = &ep93xx_mmc_spi_exit,
+	.get_ro = &ep93xx_mmc_spi_get_ro,
+	.setpower = &ep93xx_mmc_spi_setpower,
+	.get_cd = &ep93xx_mmc_spi_get_cd,
+	.detect_delay = 500,			/* card detection delay in msec */
+	.ocr_mask = MMC_VDD_33_34,
+};
+
+static struct spi_s at25fs010_spi = 
+{
+	.name = "sst25vf020",
+	.subclass = 0,
+	.tip = lsi2esc_spi_tip,
+	.xmit = lsi2esc_spi_xmit,
+	.confwrite = lsi2esc_spi_confwrite,
+	.confread = lsi2esc_spi_confread,
+	.speedread = lsi2esc_spi_speedread,
+	.speedwrite = lsi2esc_spi_speedwrite,
+};
+
+#ifdef CONFIG_MACH_SOM9307M_SOFTRONICS
+static struct spi_s lm1971_spi =
+{
+	.name = "lm1971",
+	.subclass = 0,
+	.tip = lsi2esc_spi_tip,
+	.xmit = lsi2esc_spi_xmit,
+	.confwrite = lsi2esc_spi_confwrite,
+	.confread = lsi2esc_spi_confread,
+	.speedread = lsi2esc_spi_speedread,
+	.speedwrite = lsi2esc_spi_speedwrite,
+};
+#endif
+
+static struct spi_board_info ep93xx_spi_board_info[] = {
+	{	/* SEEPROM */
+		.modalias	= "lsi2esc",
+		.chip_select	= EP93XX_GPIO_LINE_A(7),
+		.max_speed_hz	= 7.4E6,
+		.bus_num	= 0,
+		.mode = SPI_MODE_0,
+		.platform_data = &at25fs010_spi,
+	},
+	{	/* MMC/SD */
+		.modalias = "mmc_spi",
+		.max_speed_hz = 7.4E6,				/* max spi clock (SCK) speed in HZ */
+		.bus_num = 0,
+		.chip_select = EP93XX_MMC_SPI_CHIP_SELECT,	/* SD's Chip select */
+		.platform_data = (void*) &ep93xx_spi_pdata,
+		.controller_data = NULL,
+		.mode = SPI_MODE_0,
+	},
+	{	/* CS4271 codec */
+		.modalias	= "cs4271",
+#ifdef CONFIG_MACH_PPCE7
+		.chip_select	= EP93XX_GPIO_LINE_A(3),
+#else
+		.chip_select	= EP93XX_GPIO_LINE_B(0),
+#endif
+		.max_speed_hz	= 6 * 1000 * 1000,
+		.bus_num	= 0,
+		.mode = SPI_MODE_3,
+	},
+#ifdef CONFIG_MACH_SOM9307M_SOFTRONICS
+	{	/* LM1971 */
+		.modalias	= "lsi2esc",
+		.chip_select	= EP93XX_GPIO_LINE_A(4),
+		.max_speed_hz	= 7.4E6,
+		.bus_num	= 0,
+		.mode = SPI_MODE_0,
+		.platform_data = &lm1971_spi,
+	},
+#endif
+};
+#endif
+
+#ifdef CONFIG_MACH_SOM9307M_SOM200
+#define CS1_START ((unsigned long)0x10000000)
+#define CS1_END  ((unsigned long)0x1FFFFFFF)
+#define CPLDKEY 0xF
+
+static struct ecoreex_data som9307m_ecoreex_data = {
+	.key_offset	= CPLDKEY,
+};
+
+static struct resource som9307m_ecoreex_resource = {
+	.start	= CS1_START,
+	.end	= CS1_END,
+	.flags	= IORESOURCE_MEM,
+};
+
+static struct platform_device som9307m_ecoreex_device = {
+	.name		= "ecoreex",
+	.id		= -1,
+	.dev		= {
+		.platform_data	= &som9307m_ecoreex_data,
+	},
+	.num_resources	= 1,
+	.resource	= &som9307m_ecoreex_resource,
+};
+
+static inline void som9307_add_device_ecoreex(void)
+{
+	CS1CONFIG=CS1CONFIG&0xCfffffff;//force 8 bit addressing on CS1
+	platform_device_register(&som9307m_ecoreex_device);
+}
+#else
+#define som9307_add_device_ecoreex()
+#endif
+
+#ifdef CONFIG_MACH_SOM9307M_SOFTRONICS
+#define CS2_START ((unsigned long)0x20000000)
+#define CS2_END  ((unsigned long)0x2FFFFFFF)
+
+static struct pb1010_data sc2l_pb1010_data = {};
+
+static struct resource sc2l_pb1010_resource[] = {
+	{
+		.name	= "CS2",
+		.start	= CS2_START,
+		.end	= CS2_END,        
+ 		.flags	= (IORESOURCE_MEM|IORESOURCE_MEM_8BIT),
+	}
+};
+
+static struct platform_device sc2l_pb1010_device = {
+	.name		= "pb1010",
+	.id		= -1,
+	.dev		= {
+		.platform_data	= &sc2l_pb1010_data,
+	},
+	.num_resources	= 1,
+	.resource	= sc2l_pb1010_resource,
+};
+
+#endif
+
+#ifdef CONFIG_MACH_SOM9307M_SMI
+/************************************************************
+ * IOEX Device
+ * Onboard EMAC I/O core platform device. 
+ * Currently this a separate module is used for the pb1010, though if it implements
+ * a key it potentially fit within the ecoreex frame.
+ */
+#define CS0_START ((unsigned long)0x10000)
+#define CS0_END  ((unsigned long)0xFFFFFFF)
+#define CS1_START ((unsigned long)0x10000000)
+#define CS1_END  ((unsigned long)0x1FFFFFFF)
+#define CS3_START ((unsigned long)0x30000000)
+#define CS3_END  ((unsigned long)0x3FFFFFFF)
+
+#define CPLDKEY 0xF
+
+//pb1010 data strucure currently unused, will contain key location if implemented.
+static struct pb1010_data sc2l_pb1010_data = {};
+
+static struct resource sc2l_pb1010_resource[] = {
+{
+		.name	= "CS0",
+		.start	= CS0_START,
+		.end	= CS0_END,        
+ 		.flags	= (IORESOURCE_MEM|IORESOURCE_MEM_8BIT),
+}
+#ifdef CONFIG_PB1014
+,
+{
+		.name	= "CS1",		
+		.start	= CS1_START,
+		.end	= CS1_END,
+ 		.flags	= (IORESOURCE_MEM|IORESOURCE_MEM_16BIT),
+},
+{
+		.name	= "CS3",	
+		.start	= CS3_START,
+		.end	= CS3_END,
+ 		.flags	= (IORESOURCE_MEM|IORESOURCE_MEM_16BIT),
+}
+#endif
+};
+
+static struct platform_device sc2l_pb1010_device = {
+	.name		= "pb1010",
+	.id		= -1,
+	.dev		= {
+		.platform_data	= &sc2l_pb1010_data,
+	},
+#ifdef CONFIG_PB1014
+	.num_resources	= 3,
+#else
+	.num_resources	= 1,
+#endif	
+	.resource	= sc2l_pb1010_resource,
+};
+
+#endif //CONFIG_MACH_SOM9307M_SMI
+
+static int rowcal_write(gpio_t *gpio, gpio_data data){
+	u8 portc = inl(GPIO_PCDR)&0xF0;
+	u8 portd = inl(GPIO_PDDR)&0xF0; 
+	
+	portc|=data&0x0f;
+	portd|=data>>4;
+    
+	outl(portc, GPIO_PCDR); 
+	outl(portd, GPIO_PDDR); 
+	return 0;
+}
+
+static int rowcal_ddrwrite(gpio_t *gpio, gpio_data data){
+	u8 portc = inl(GPIO_PCDDR)&0xF0;
+	u8 portd = inl(GPIO_PDDDR)&0xF0; 
+	
+	portc|=data&0x0F;
+	portd|=(data>>4)&0x0F;
+    
+	outl(portc, GPIO_PCDDR); 
+	outl(portd, GPIO_PDDDR); 
+	return 0;
+}
+
+static gpio_data rowcal_read(gpio_t *gpio){
+	u8 portc = inl(GPIO_PCDR)&0x0F;
+	u8 portd = inl(GPIO_PDDR)&0x0F; 	
+	u8 rowcol = (portd<<4)|portc;
+	return rowcol;
+}
+
+static gpio_data rowcal_ddrread(gpio_t *gpio){
+	u8 portc = inl(GPIO_PCDDR)&0x0F;
+	u8 portd = inl(GPIO_PDDDR)&0x0F; 	
+	u8 rowcol = (portd<<4)|portc;
+	return rowcol;
+}
+
+static inline struct class_device *rowcal_create(void){
+	gpio_t *gpio = kmalloc(sizeof(gpio_t),GFP_KERNEL);
+	memset(gpio,0,sizeof(gpio_t));
+	gpio->name = "rowcol";
+	gpio->subclass = GPIO_SUBCLASS;
+	gpio->data_write = rowcal_write;
+	gpio->data_read = rowcal_read;
+	gpio->ddr_write = rowcal_ddrwrite;
+	gpio->ddr_read = rowcal_ddrread;
+    
+	printk("registering indexed gpio device: %s\n",gpio->name);
+	return gpio_register_class_device(gpio);
+}
+
+#ifdef CONFIG_MACH_PPCE7
+static struct platform_device ppce7_bl_device = {
+	.name		= "ppce7-bl",
+	.id		= -1,
+};
+#endif
+
+#ifdef CONFIG_MACH_SOM9307M
+static struct platform_device som9307_bl_device = {
+	.name		= "som9307-bl",
+	.id		= -1,
+};
+#endif
+
+/************************************************************
+ * device registrations from the arch go here, 
+ * which are called by the boardspec ioex driver
+ */
+static int som9307_classes(void)
+{
+#ifdef CONFIG_ROWCOL_GPIO	
+	rowcal_create();
+#endif
+	return 0;
+}
+
+static struct platform_device boardspec_device = {
+	.name = "boardspec",
+	.id = 1,
+	.dev		= {
+		.platform_data	= &som9307_classes,
+	},
+};
+
+static void init_row_col_2_gpio(void)
+{
+	/* Turning keypad into GPIO pins */
+	u32 devicecfg = ioread32((void *)EP93XX_SYSCON_DEVICE_CONFIG);
+	devicecfg|=SYSCON_DEVCFG_GONK; 
+	EP93XX_SYSUNLOCK();
+	iowrite32(devicecfg,(void *)EP93XX_SYSCON_DEVICE_CONFIG); 
+}
+
+static void __init emac9307_init_machine(void)
+{
+	init_row_col_2_gpio();
+	ep93xx_init_devices();
+
+	platform_device_register(&emac9307_flash);
+#ifdef CONFIG_MACH_EMAC9307_64
+	platform_device_register(&emac9307_aux);
+#endif
+#ifdef  CONFIG_PB1014 
+	platform_device_register(&pb1014_flash);
+#endif
+
+	memcpy(emac9307_eth_data.dev_addr, (void *)(EP93XX_ETHERNET_BASE + 0x50), 6);
+	platform_device_register(&emac9307_eth_device);
+	
+	platform_device_register(&ep93xx_spi_device);
+	spi_register_board_info(ep93xx_spi_board_info, ARRAY_SIZE(ep93xx_spi_board_info));
+
+#ifdef CONFIG_MACH_SOM9307M_SMI
+	CS0CONFIG=CS0CONFIG&0xCfffffff;//force 8 bit addressing on CS0
+	CS1CONFIG=(CS1CONFIG&0xCfffffff)|(0x10000000);//force 16 bit addressing on CS1
+	CS2CONFIG=(CS2CONFIG&0xCfffffff)|(0x10000000);//force 16 bit addressing on CS2
+	CS3CONFIG=(CS3CONFIG&0xCfffffff)|(0x10000000);//force 16 bit addressing on CS3
+
+	CS1CONFIG=(CS1CONFIG&0xfffffC1f)|(0x0D<<5);//140ns WS1 CS1
+	CS2CONFIG=(CS2CONFIG&0xfffffC1f)|(0x0D<<5);//140ns WS1 CS2
+	CS3CONFIG=(CS3CONFIG&0xfffffC1f)|(0x08<<5);//90ns WS1 CS3
+
+	platform_device_register(&sc2l_pb1010_device);
+#endif	
+
+#ifdef CONFIG_MACH_SOM9307M_SOFTRONICS
+	CS2CONFIG=CS2CONFIG&0xCfffffff;//force 8 bit addressing on CS2
+	platform_device_register(&sc2l_pb1010_device);
+#endif
+	
+	som9307_add_device_ecoreex();
+	platform_device_register(&boardspec_device);
+
+#ifdef CONFIG_MACH_PPCE7
+	platform_device_register(&ppce7_bl_device);
+#endif
+
+#ifdef CONFIG_MACH_SOM9307M
+	platform_device_register(&som9307_bl_device);
+#endif
+}
+
+#ifdef CONFIG_MACH_PPCE7
+MACHINE_START(EDB9315A, "EMAC Inc. PPC-E7 SBC")
+	.phys_io	= EP93XX_APB_PHYS_BASE,
+	.io_pg_offst	= ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc,
+	.boot_params	= 0xc0000100,
+	.map_io		= ep93xx_map_io,
+	.init_irq	= ep93xx_init_irq,
+	.timer		= &ep93xx_timer,
+	.init_machine	= emac9307_init_machine,
+MACHINE_END
+#endif
+
+#ifdef CONFIG_MACH_SOM9307M
+MACHINE_START(EDB9315A, "EMAC Inc. SOM-9307M")
+	.phys_io	= EP93XX_APB_PHYS_BASE,
+	.io_pg_offst	= ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc,
+	.boot_params	= 0xc0000100,
+	.map_io		= ep93xx_map_io,
+	.init_irq	= ep93xx_init_irq,
+	.timer		= &ep93xx_timer,
+	.init_machine	= emac9307_init_machine,
+MACHINE_END
+#endif
+
diff -Naur linux-2.6.25/arch/arm/mach-ep93xx/emac-thermotron.c linux-2.6.25.ep93xx/arch/arm/mach-ep93xx/emac-thermotron.c
--- linux-2.6.25/arch/arm/mach-ep93xx/emac-thermotron.c	1969-12-31 18:00:00.000000000 -0600
+++ linux-2.6.25.ep93xx/arch/arm/mach-ep93xx/emac-thermotron.c	2008-08-22 09:52:32.000000000 -0500
@@ -0,0 +1,105 @@
+/*
+ * arch/arm/mach-ep93xx/emac-thermotron.c
+ * Support for EMAC Thermotron Custom SBC.
+ * Based on the thermo design and edb9315a.c
+ *
+ * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org>
+ * Copyright (C) 2008 EMAC Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/mtd/physmap.h>
+#include <linux/class/gpio.h>
+#include <linux/platform_device.h>
+#include <asm/io.h>
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/arch/ep93xx_util.h>
+
+static struct physmap_flash_data thermo_flash_data = {
+	.width		= 2,
+};
+
+static struct resource thermo_flash_resource[] = {
+	{
+	.start		= 0x60000000,
+	.end		= 0x61ffffff,
+	.flags		= IORESOURCE_MEM,
+	}
+};
+
+static struct platform_device thermo_flash = {
+	.name		= "physmap-flash",
+	.id		= 0,
+	.dev		= {
+		.platform_data	= &thermo_flash_data,
+	},
+	.num_resources	= 1,
+	.resource	= thermo_flash_resource,
+};
+
+static struct ep93xx_eth_data thermo_eth_data = {
+	.phy_id			= 1,
+};
+
+static struct resource thermo_eth_resource[] = {
+	{
+		.start	= EP93XX_ETHERNET_PHYS_BASE,
+		.end	= EP93XX_ETHERNET_PHYS_BASE + 0xffff,
+		.flags	= IORESOURCE_MEM,
+	}, {
+		.start	= IRQ_EP93XX_ETHERNET,
+		.end	= IRQ_EP93XX_ETHERNET,
+		.flags	= IORESOURCE_IRQ,
+	}
+};
+
+static struct platform_device thermo_eth_device = {
+	.name		= "ep93xx-eth",
+	.id		= -1,
+	.dev		= {
+		.platform_data	= &thermo_eth_data,
+	},
+	.num_resources	= 2,
+	.resource	= thermo_eth_resource,
+};
+
+static struct platform_device thermo_bl_device = {
+    .name   = "thermo-bl",
+    .id     = -1,
+};
+
+static void __init thermo_init_machine(void)
+{
+	ep93xx_init_devices();
+	platform_device_register(&thermo_flash);
+
+	memcpy(thermo_eth_data.dev_addr,
+		(void *)(EP93XX_ETHERNET_BASE + 0x50), 6);
+	platform_device_register(&thermo_eth_device);
+
+    platform_device_register(&thermo_bl_device);
+
+}
+
+MACHINE_START(EDB9315A, "EMAC Inc Thermotron Custom SBC")
+	/* Maintainer: EMAC Inc */
+	.phys_io	= EP93XX_APB_PHYS_BASE,
+	.io_pg_offst	= ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc,
+	.boot_params	= 0xc0000100,
+	.map_io		= ep93xx_map_io,
+	.init_irq	= ep93xx_init_irq,
+	.timer		= &ep93xx_timer,
+	.init_machine	= thermo_init_machine,
+MACHINE_END
diff -Naur linux-2.6.25/arch/arm/mach-ep93xx/ipac9302.c linux-2.6.25.ep93xx/arch/arm/mach-ep93xx/ipac9302.c
--- linux-2.6.25/arch/arm/mach-ep93xx/ipac9302.c	1969-12-31 18:00:00.000000000 -0600
+++ linux-2.6.25.ep93xx/arch/arm/mach-ep93xx/ipac9302.c	2008-08-18 14:05:42.000000000 -0500
@@ -0,0 +1,395 @@
+/*
+ * arch/arm/mach-ep93xx/ipac9302.c
+ * EMAC.Inc iPAC-9302 Support.
+ *
+ * Copyright (C) 2007 EMAC.Inc <support@emacinc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/mtd/physmap.h>
+#include <linux/platform_device.h>
+#include <linux/ioex/ecoreex.h>
+#include <linux/class/pwm.h>
+#include <linux/class/mmcprot.h>
+#include <linux/class/spi.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/arch/ep93xx_util.h>
+#include "spi-ep93xx.h"
+#include "atod-ep93xx.h"
+
+#define OSCCLOCK		14745600
+
+/************************************************************
+ * Flash Device
+ * Flash platform device used by the MTD platform driver
+ */
+
+static struct physmap_flash_data ipac9302_flash_data = {
+	.width		= 2,
+};
+
+
+#ifdef CONFIG_MACH_IPAC9302_16
+static struct resource ipac9302_flash_resource[] = {
+	{
+	.start		= 0x60000000,
+	.end		= 0x60ffffff,
+	.flags		= IORESOURCE_MEM,
+	}
+};
+
+#define NUM_RESOURCES 1
+#endif
+
+#ifdef CONFIG_MACH_IPAC9302_32
+static struct resource ipac9302_flash_resource[] = {
+	{
+	.start		= 0x60000000,
+	.end		= 0x61ffffff,
+	.flags		= IORESOURCE_MEM,
+	}
+};
+
+#define NUM_RESOURCES 1
+#endif
+
+#ifdef CONFIG_MACH_IPAC9302_64
+static struct resource ipac9302_flash_resource[] = {
+	{
+	.start		= 0x60000000,
+	.end		= 0x61ffffff,
+	.flags		= IORESOURCE_MEM,
+	},
+	{
+	.start		= 0x62000000,
+	.end		= 0x63ffffff,
+	.flags		= IORESOURCE_MEM,
+	}
+};
+
+#define NUM_RESOURCES 2
+#endif
+
+
+static struct platform_device ipac9302_flash = {
+	.name		= "physmap-flash",
+	.id		= 0,
+	.dev		= {
+		.platform_data	= &ipac9302_flash_data,
+	},
+	.num_resources	= NUM_RESOURCES,
+	.resource	= ipac9302_flash_resource,
+};
+
+/************************************************************
+ * Ethernet Device
+ * Ethernet platform device used bye the ep93xx ethernet platform driver
+ */
+ 
+static struct ep93xx_eth_data ipac9302_eth_data = {
+	.phy_id			= 1,
+};
+
+static struct resource ipac9302_eth_resource[] = {
+	{
+		.start	= EP93XX_ETHERNET_PHYS_BASE,
+		.end	= EP93XX_ETHERNET_PHYS_BASE + 0xffff,
+		.flags	= IORESOURCE_MEM,
+	}, {
+		.start	= IRQ_EP93XX_ETHERNET,
+		.end	= IRQ_EP93XX_ETHERNET,
+		.flags	= IORESOURCE_IRQ,
+	}
+};
+
+static struct platform_device ipac9302_eth_device = {
+	.name		= "ep93xx-eth",
+	.id		= -1,
+	.dev		= {
+		.platform_data	= &ipac9302_eth_data,
+	},
+	.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);
+}
+
+/************************************************************
+ * Serial EEPROM
+ * CS Resides at EGPIO[7]
+ * EGPIO[7] = Port A bit 8 
+ * Port A Mask = 0x80
+ */
+#define EEPDR() 	(ioread32(EP93XX_GPIO_A_DR))
+#define EEPDDR()	(ioread32(EP93XX_GPIO_A_DDR))
+
+#define EEPCSON() 	{iowrite32((EEPDR()&(~0x80)),(void *)EP93XX_GPIO_A_DR);} 
+#define EEPCSOFF() 	{iowrite32((EEPDR()|0x80),(void *)EP93XX_GPIO_A_DR);}
+#define EEPCSSETUP()	{iowrite32(((EEPDDR())|0x80),(void *)EP93XX_GPIO_A_DDR);EEPCSOFF();}
+
+static ep93xx_spiconfig_t eepconfig = {.id		= 6,};
+
+/**
+ * Serial EEPROM Transfer in Progress
+ */
+static int eeptip(spi_t *s,int ofs){
+	int retval;
+
+	if(ofs == 0) EEPCSOFF();
+	if((retval = ep93xx_spitip(ofs,&eepconfig))<0) return -1;
+	if(ofs == 1) { udelay(100); EEPCSON(); }
+	
+	return retval;
+}
+
+/************************************************************
+ * MMC/SD Slot
+ * MMC slot through the spi layer with some functions provided by the ecroeex.
+ * card detect/write protect functions are provided by ecoreex.
+ * note that this requires ep93xx spi code to build
+ */
+#ifdef CONFIG_MMCCLASS 
+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))
+
+#define MMCCSON() 		{iowrite32((MMCDR()&(~1)),(void *)EP93XX_GPIO_B_DR);} 
+#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==1){
+	if(ep93xx_spitip(1,&mmcspiconfig)<0)return -1;//could not obtain lock, fail and return.
+	udelay(100);//ensure a short delay between toggles.
+	MMCCSON();//lock obtained, turn on the chip select
+	return 1;
+}
+
+if(onoff==2){//obtain the lock but don't move the chip select (MMC/SD weirdness)
+	if(ep93xx_spitip(1,&mmcspiconfig)<0)return -1;//could not obtain lock, fail and return.
+	return 1;
+}
+
+if(onoff==0){MMCCSOFF();ep93xx_spitip(0,&mmcspiconfig);}//OFF
+return 0;//currently does not return status other than failure
+} 
+
+/**
+ * mmc specific bidirectional transfer, miso and mosi may be the same
+ * passing NULL to mosi transfers 0xff.
+ * This call is non-preemptive, so should never interrupt another spi call.
+ * real time spi devices may need to get and restore spi state before stealing it away from
+ * the mmc.
+ */
+static int mmcexchange(mmcslot_t *s,u8 *mosi, u8 *miso, int size){
+	//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;
+}
+
+/**
+ * change mmc spi bitrate
+ */	
+static int mmcsetspeed(mmcslot_t *s,unsigned long speed){
+	spi_setup_config(mmcspiconfig.cp0,speed,&mmcspiconfig);
+	return 0;
+}
+
+static int mmcboardinit(void){
+	MMCCSSETUP();	
+	spi_setup_config(EP93XX_CP0_MOTO_MODE|BITSPERWORD(8),100000,&mmcspiconfig);
+	//spi_setup_config(EP93XX_CP0_TEXAS_MODE|BITSPERWORD(8),200000,&mmcspiconfig);
+	return 0;
+}
+ 
+static mmcslot_t mmcslot = {
+	.slotnumber = 0,
+	.name = "mmca",
+	.tip = mmctip,
+	.exchange = mmcexchange,
+	.setspeed = mmcsetspeed,
+};
+
+static struct platform_device mmcslot_device = {
+	.name = "mmc",
+	.dev		= {
+		.platform_data	= &mmcslot,
+	},
+};
+
+#endif //CONFIG_MMCCLASS 
+ 
+/************************************************************
+ * IOEX Device
+ * Onboard EMAC I/O core platform device used by the ecoreex driver
+ */
+#define CS0_START ((unsigned long)0x10000)
+#define CS0_END  ((unsigned long)0xFFFFFFF)
+#define CS0_LEN  ((unsigned long)(CS0_END-CS0_START+1))
+#define CPLDKEY 0xF
+
+static struct ecoreex_data ipac9302_ecoreex_data = {
+	.key_offset	= CPLDKEY,
+	.read_periodusa	= NULL, //virtual clock A defined as user settable
+	.mmcslot = &mmcslot,//allow the ecroeex to fill out mmc functions not currently implemented
+};
+
+static struct resource ipac9302_ecoreex_resource = {
+		.start	= CS0_START,
+		.end	= CS0_END,
+		.flags	= IORESOURCE_MEM,
+};
+
+static struct platform_device ipac9302_ecoreex_device = {
+	.name		= "ecoreex",
+	.id		= -1,
+	.dev		= {
+		.platform_data	= &ipac9302_ecoreex_data,
+	},
+	.num_resources	= 1,
+	.resource	= &ipac9302_ecoreex_resource,
+};
+
+/************************************************************
+ * ep93xx pwm1 initialization routine (generic)
+ * TODO:move routines to generic ep93xx code.
+ */
+#ifdef CONFIG_EP93XX_PWM 
+#include <asm/mach/ep93xx_pwm.h>
+
+static void ep93xx_pwm1_enable(void){
+	u32 devicecfg = ioread32((void *)EP93XX_SYSCON_DEVICE_CONFIG);
+	devicecfg|=EP93XX_SYSCON_DEVICE_CONFIG_PONG;
+	EP93XX_SYSUNLOCK();
+	iowrite32(devicecfg,(void *)EP93XX_SYSCON_DEVICE_CONFIG);
+}
+
+static inline void ep93xx_pwm_map(int num, const char *name){			
+	pwm_declare();	
+	ep93xx_pwm_device_create(EP93XX_PWM(num),name);		
+}
+#endif
+
+/************************************************************
+ * device registrations from the arch go here, 
+ * which are called by the boardspec ioex driver
+ */
+static int ipac9302_classes(void)
+{
+#ifdef CONFIG_EP93XX_PWM
+	ep93xx_pwm1_enable();
+	ep93xx_pwm_map(1,"ep93xx_pwm1");
+#endif	
+#ifdef CONFIG_EP93XX_ATOD 
+	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);
+
+	EEPCSSETUP();
+	spi_setup_config(EP93XX_CP0_MOTO_MODE|BITSPERWORD(8),200000,&eepconfig);
+	ep93xx_spi_class_create("sst25vf020",&eepconfig,eeptip);	
+#endif	
+	return 0;
+}
+
+static struct platform_device boardspec_device = {
+	.name = "boardspec",
+	.id = 1,
+	.dev		= {
+		.platform_data	= &ipac9302_classes,
+	},
+};
+
+
+/************************************************************
+ * Linux Board initialization routine 
+ */
+static int chiprevision;
+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>6)return OSCCLOCK;
+	return OSCCLOCK/2;
+}
+
+#define EP93XX_REVISION_OFFSET	28
+
+static inline int ep93xx_chip_revision(void){
+	return(ioread32(EP93XX_SYSCON_CHIPID)>>EP93XX_REVISION_OFFSET);	
+}
+ 
+static void __init ipac9302_init_machine(void){	
+	chiprevision = ep93xx_chip_revision();	
+	printk("ep9302 rev %s detected\n",chip_revisions[chiprevision]);
+	ep93xx_init_devices();
+	/**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);
+	platform_device_register(&ipac9302_ecoreex_device);	
+	platform_device_register(&boardspec_device);
+	platform_device_register(&mmcslot_device);
+
+}
+
+/************************************************************
+ * standard mach structure for the iPac board
+ */
+MACHINE_START(IPAC9302, "EMAC.Inc iPac 9302 SBC")
+	.phys_io		= EP93XX_APB_PHYS_BASE,
+	.io_pg_offst	= ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc,
+	.boot_params	= 0xc0000100,
+	.map_io			= ep93xx_map_io,
+	.init_irq		= ep93xx_init_irq,
+	.timer			= &ep93xx_timer,
+	.init_machine	= ipac9302_init_machine,
+MACHINE_END
diff -Naur linux-2.6.25/include/linux/class/gpio.h linux-2.6.25.ep93xx/include/linux/class/gpio.h
--- linux-2.6.25/include/linux/class/gpio.h	1969-12-31 18:00:00.000000000 -0600
+++ linux-2.6.25.ep93xx/include/linux/class/gpio.h	2008-08-18 14:05:42.000000000 -0500
@@ -0,0 +1,198 @@
+#ifndef GPIO_H_
+#define GPIO_H_
+
+#include <linux/autoconf.h>
+#include <linux/device.h>
+
+#ifdef CONFIG_GPIOCLASS	
+
+typedef u32 gpio_data;
+
+/**********************
+ * gpio class structure
+ */
+typedef struct gpio_s{
+	const char *name;
+	int subclass;
+	gpio_data index;
+	gpio_data range;
+	void *ddr;
+	void *data;
+	gpio_data shadow;
+	gpio_data (*data_read)(struct gpio_s *gpio);
+	int (*data_write)(struct gpio_s *gpio,gpio_data data);
+	gpio_data (*ddr_read)(struct gpio_s *gpio);	
+	int (*ddr_write)(struct gpio_s *gpio,gpio_data data);
+	gpio_data (*index_read)(struct gpio_s *gpio);	
+	int (*index_write)(struct gpio_s *gpio,gpio_data data);
+}gpio_t;
+
+#define GPIO_BASECLASNUM	0xA0
+#define GPIO_SUBCLASS 	(GPIO_BASECLASNUM+0)
+#define GPI_SUBCLASS 	(GPIO_BASECLASNUM+1)
+#define GPO_SUBCLASS 	(GPIO_BASECLASNUM+2)
+
+/***************************************************************************
+ * typical low level methods for accessing 8 bit ports
+ */
+int  gpio_ddr_write8(gpio_t *gpio, gpio_data data);
+int  gpio_data_write8(gpio_t *gpio, gpio_data data);
+int  gpio_index_write(gpio_t *gpio, gpio_data data);
+int  gpio_empty_write(gpio_t *gpio, gpio_data data);
+gpio_data gpio_ddr_read8(gpio_t *gpio);
+gpio_data gpio_data_read8(gpio_t *gpio);
+gpio_data gpio_index_read(gpio_t *gpio);
+gpio_data gpio_shadow_read8(gpio_t *gpio);
+gpio_data gpio_ff_read(gpio_t *gpio);
+gpio_data gpio_zero_read(gpio_t *gpio);
+
+/***************************************************************************
+ * initial class declaration, doesn't hurt to call it mulitiple times,
+ * automatically checked during device instantiation 
+ */
+struct class *gpio_declare(void);
+
+/***************************************************************************
+* class instantiation
+*/
+struct class_device *gpio_register_class_device(gpio_t *gpio);
+
+
+/***************************************************************************
+ * atomic method wrappers
+ * these should be used for all method calls to maintain sychronization across the
+ * various interfaces
+ */
+int atomic_gpio_ddr_write(gpio_t *gpio,gpio_data data);
+gpio_data atomic_gpio_ddr_read(gpio_t *gpio);
+int atomic_gpio_data_write(gpio_t *gpio,gpio_data data);
+gpio_data atomic_gpio_data_read(gpio_t *gpio);
+int atomic_gpio_index_write(gpio_t *gpio,gpio_data data);
+gpio_data atomic_gpio_index_read(gpio_t *gpio);
+
+
+/************************************************************************************
+ * full gpio ports, 
+ * bit configurable gpio ports with a bidirectional data register
+ * if the data register or ddr are NULL their interfaces are not created.
+ */
+static inline struct class_device *gpio_device_create(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;
+	}
+	printk("registering gpio device: %s\n",name);
+    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
+ * a shadow port is therefore created to keep track of the current state in software.
+ * this is not as complete an implementation from a hardware standpoint as a user can only
+ * see the hardware changes if a rogue process if it "plays fair" and modifies the shadow register.
+ * It is, however, much cheaper from a gate implementation standpoint and probably just fine for
+ * most applications.
+ */
+ 
+static inline struct class_device *gpo_device_create(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;
+    printk("registering gpo device: %s\n",name);
+    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 
+ * and are assumed based upon the PLD key. 
+ * This is a cheaper gate implementation. 
+ */
+static inline struct class_device *gpi_device_create(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;
+    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 -Naur linux-2.6.25/include/linux/class/mmcblock.h linux-2.6.25.ep93xx/include/linux/class/mmcblock.h
--- linux-2.6.25/include/linux/class/mmcblock.h	1969-12-31 18:00:00.000000000 -0600
+++ linux-2.6.25.ep93xx/include/linux/class/mmcblock.h	2008-08-18 14:05:42.000000000 -0500
@@ -0,0 +1,19 @@
+#ifndef MMCBLOCK_H_
+#define MMCBLOCK_H_
+
+//#define MMCB_DEBUG 
+ 
+#undef MMCBDEBUG
+#ifdef MMCB_DEBUG
+	#define MMCBDEBUG(x...)  {printk("%s(): %d ",__PRETTY_FUNCTION__, __LINE__);printk(x);}
+#else
+	#define MMCBDEBUG(x...)	do { } while (0)
+#endif 
+
+int mmc_bdriver_init(void);
+void mmc_bdriver_exit(void);
+int mmc_diskize(mmcslot_t *s);
+void checkmedia_start(mmcslot_t *s);
+void checkmedia_stop(mmcslot_t *s);
+
+#endif /*MMCBLOCK_H_*/
diff -Naur linux-2.6.25/include/linux/class/mmcprot.h linux-2.6.25.ep93xx/include/linux/class/mmcprot.h
--- linux-2.6.25/include/linux/class/mmcprot.h	1969-12-31 18:00:00.000000000 -0600
+++ linux-2.6.25.ep93xx/include/linux/class/mmcprot.h	2008-08-18 14:05:42.000000000 -0500
@@ -0,0 +1,513 @@
+#ifndef MMCPROT_H_
+#define MMCPROT_H_
+
+#include <linux/types.h>
+#include <linux/timer.h>
+
+#define INVALID		0
+#define VALID		1
+#define CHANGED		2
+#define READY		4
+
+#define TRUE		1
+#define FALSE		(!TRUE)
+
+/**
+ * Debug statement defines
+ */
+ 
+//#define MMC_DEBUG 
+//#define MMCI_DEBUG 
+
+#undef MMCDEBUG
+#ifdef MMC_DEBUG
+#define MMCDEBUG(fmt, args...) printk(fmt"\n", ## args)
+#else 
+#define MMCDEBUG(fmt, args...) 
+#endif
+
+#undef MMCIDEBUG
+#ifdef MMCI_DEBUG
+#define MMCIDEBUG(fmt, args...) printk(fmt"\n", ## args)
+#else 
+#define MMCIDEBUG(fmt, args...) 
+#endif
+
+
+
+//packet defines
+#define MAX_RESPONSE 5
+#define CRC_LENGTH  2	
+#define START_TOKEN_LENGTH 1
+#define BR_STOP_TOKEN 0xFD
+#define DATA_RESPONSE_LENGTH  1
+#define MAX_NWR 8
+#define COMMAND_LENGTH  6
+#define Ncr_MAX  8
+		
+//command response defines		
+#define MMCCOM_IDLE  0x01
+#define MMCCOM_ERASE_RES  0x02
+#define MMCCOM_ILLEGAL  0x04
+#define MMCCOM_CRC  0x08
+#define MMCCOM_ERASE_SEQ  0x10
+#define MMCCOM_ADDRESS  0x20
+#define MMCCOM_PARAMETER  0x40
+
+//data responses
+#define MMCDAT_D_RESPONSE_MASK  0x1F
+#define MMCDAT_DATA_ACC  0x05
+#define MMCDAT_CRC_ERR 0x0B
+#define MMCDAT_WRITE_ERR 0x0D	
+
+typedef struct CSD_register{
+		int	SPEC_VERS;
+		int MMC_SPEC_VERS;
+		int	TAAC;
+		int	NSAC;
+		int	TRAN_SPEED;
+		int	CCC;
+		int	READ_BL_LEN;
+		int	READ_BL_PARTIAL;
+		int	WRITE_BLK_MISALIGN;
+		int	READ_BLK_MISALIGN;
+		int	DSR_IMP;
+		int	C_SIZE;
+		int	VDD_R_CURR_MIN;
+		int	VDD_R_CURR_MAX;
+		int	VDD_W_CURR_MIN;
+		int	VDD_W_CURR_MAX;
+		int	C_SIZE_MULT;
+		int	ERASE_GRP_SIZE;
+		int	ERASE_GRP_MULT;
+		int	WP_GRP_SIZE;
+		int	WP_GRP_ENABLE;
+		int	DEFAULT_ECC;
+		int	R2W_FACTOR;
+		int	WRITE_BL_LEN;
+		int	WRITE_BL_PARTIAL;
+		int	FILE_FORMAT_GRP;
+		int	COPY;
+		int	PERM_WRITE_PROTECT;
+		int	TMP_WRITE_PROTECT;
+		int	FILE_FORMAT;
+		int	ECC;
+		int	CRC;	
+	}CSD_register;	
+
+typedef struct CID_register{
+		int Manufacturer_ID; 
+		int OEM_Application_ID; 
+		char Product_name[7]; 
+		int Product_revision;
+		long Product_serial_number; 
+		int Manufacturing_date; 			   							  		
+	}CID_register;
+
+typedef struct cardinfo_s {
+	unsigned int blocklength;
+	unsigned int sectors;
+	unsigned long size;
+	unsigned long speed;//maximum clock speed of the card
+	unsigned int media_detect;
+	unsigned int sdhc;
+	CSD_register CSD;
+	CID_register CID;
+}cardinfo_t;
+
+#define MAXSLOTNUM 4
+
+enum MMCMETHODS {
+    MMCCD		= 0,
+	MMCWP,
+	MMCTP,
+	MMCEX,
+	MMCSS,
+};
+
+typedef struct mmcslot_s {
+	int slotnumber;
+	const char *name;
+	int users;
+	int state;
+	cardinfo_t card;
+	spinlock_t lock;
+	struct gendisk *disk;
+	struct timer_list timer;
+	int (*carddetect)(struct mmcslot_s *s);
+	int (*writeprotect)(struct mmcslot_s *s);
+	int (*tip)(struct mmcslot_s *s,int onoff);//declare transfer in progress true/false (moves chip select, potentially turns off the clock)
+	int (*exchange)(struct mmcslot_s *s,u8 *mosi, u8 *miso, int size);//bidirectional transfer
+	int (*setspeed)(struct mmcslot_s *s,unsigned long speed);
+	void *pd[5];//individual private data pointers for methods
+}mmcslot_t;
+
+
+/**
+ * Prototypes for the core functions
+ */
+int mmcinit(mmcslot_t *s);
+mmcslot_t *mmcgetslot(int i);
+int mmcreleaseslot(mmcslot_t *s);
+int mmctransaction(mmcslot_t *s, int command, int arg1, int arg2,int blocking,int response);
+int mmcblockread(mmcslot_t *s, int command, int arg1, int arg2,int response, u8 *data,int blocksize, int blocknum,int Nac);
+int mmcblockwrite(mmcslot_t *s,int command, int arg1, int arg2, int response, u8 *data, int blocksize, int blocknum,int Nwr);
+
+#define CARDREGTOP 15
+
+static inline void print_csd(CSD_register *reg){
+			printk("SPEC_VERS %x\n",reg->SPEC_VERS);
+			printk("MMC_SPEC_VERS %x\n",reg->MMC_SPEC_VERS);
+			printk("TAAC %x\n",reg->TAAC);
+			printk("NSAC %x\n",reg->NSAC);
+			printk("TRAN_SPEED %x\n",reg->TRAN_SPEED);
+			printk("CCC %x\n",reg->CCC);
+			printk("READ_BL_LEN %x\n",reg->READ_BL_LEN);
+			printk("READ_BL_PARTIAL %x\n",reg->READ_BL_PARTIAL);
+			printk("WRITE_BLK_MISALIGN %x\n",reg->WRITE_BLK_MISALIGN);
+			printk("READ_BLK_MISALIGN %x\n",reg->READ_BLK_MISALIGN);
+			printk("DSR_IMP %x\n",reg->DSR_IMP);
+			printk("C_SIZE %x\n",reg->C_SIZE);
+			printk("DD_R_CURR_MIN %x\n",reg->VDD_R_CURR_MIN);
+			printk("VDD_R_CURR_MAX %x\n",reg->VDD_R_CURR_MAX);
+			printk("VDD_W_CURR_MIN %x\n",reg->VDD_W_CURR_MIN);
+			printk("VDD_W_CURR_MAX %x\n",reg->VDD_W_CURR_MAX);
+			printk("C_SIZE_MULT %x\n",reg->C_SIZE_MULT);
+			printk("ERASE_GRP_SIZE %x\n",reg->ERASE_GRP_SIZE);
+			printk("ERASE_GRP_MULT %x\n",reg->ERASE_GRP_MULT);
+			printk("WP_GRP_SIZE %x\n",reg->WP_GRP_SIZE);
+			printk("WP_GRP_ENABLE %x\n",reg->WP_GRP_ENABLE);
+			printk("DEFAULT_ECC %x\n",reg->DEFAULT_ECC);
+			printk("R2W_FACTOR %x\n",reg->R2W_FACTOR);
+			printk("WRITE_BL_LEN %x\n",reg->WRITE_BL_LEN);
+			printk("WRITE_BL_PARTIAL %x\n",reg->WRITE_BL_PARTIAL);
+			printk("FILE_FORMAT_GRP %x\n",reg->FILE_FORMAT_GRP);
+			printk("COPY %x\n",reg->COPY);
+			printk("PERM_WRITE_PROTECT %x\n",reg->PERM_WRITE_PROTECT);
+			printk("TMP_WRITE_PROTECT %x\n",reg->TMP_WRITE_PROTECT);
+			printk("FILE_FORMAT %x\n",reg->FILE_FORMAT);
+			printk("ECC %x\n",reg->ECC);
+			printk("CRC %x\n",reg->CRC);
+}
+
+static inline void print_csd_raw(u8 *CSD){
+	int i;
+	for(i=0;i<=CARDREGTOP;i++){
+		int start = i*8;
+		printk("bits %d-%d CSD[CARDREGTOP-%d]=%x\n",start,start+7,i,CSD[CARDREGTOP-i]);
+	}
+}
+
+static inline int parse_CSD(CSD_register *reg, u8 *CSD){
+		reg->SPEC_VERS= (CSD[CARDREGTOP-15]&0xC0)>>6;	
+		reg->MMC_SPEC_VERS= (CSD[CARDREGTOP-15]&0x3C)>>2;
+		reg->TAAC= CSD[CARDREGTOP-14];
+		reg->NSAC= CSD[CARDREGTOP-13];
+		reg->TRAN_SPEED= CSD[CARDREGTOP-12];
+		reg->CCC= ((CSD[CARDREGTOP-11])<<4)|((CSD[CARDREGTOP-10]&0xf0)>>4);
+		reg->READ_BL_LEN= (CSD[CARDREGTOP-10]&0x0f);
+		reg->READ_BL_PARTIAL= (CSD[CARDREGTOP-9]&0x80>>7);
+		reg->WRITE_BLK_MISALIGN= (CSD[CARDREGTOP-9]&0x40>>6);
+		reg->READ_BLK_MISALIGN= (CSD[CARDREGTOP-9]&0x20>>5);
+		reg->DSR_IMP= (CSD[CARDREGTOP-9]&0x10>>4);
+		reg->C_SIZE= ((CSD[CARDREGTOP-9]&0x03)<<10)|(CSD[CARDREGTOP-8]<<2)|((CSD[CARDREGTOP-7]&0xC0)>>6);		
+		reg->VDD_R_CURR_MIN= (CSD[CARDREGTOP-7]&0x38)>>3;
+		reg->VDD_R_CURR_MAX= (CSD[CARDREGTOP-7]&0x07);
+		reg->VDD_W_CURR_MIN= (CSD[CARDREGTOP-6]&0xE0)>>5;
+		reg->VDD_W_CURR_MAX= (CSD[CARDREGTOP-6]&0x1C)>>2;
+		reg->C_SIZE_MULT= ((CSD[CARDREGTOP-6]&0x03)<<1)|((CSD[CARDREGTOP-5]&0x80)>>7);
+		reg->ERASE_GRP_SIZE= (CSD[CARDREGTOP-5]&0x7c)>>2;
+		reg->ERASE_GRP_MULT= ((CSD[CARDREGTOP-5]&0x03)<<3)|((CSD[CARDREGTOP-4]&0xe0)>>5);
+		reg->WP_GRP_SIZE= (CSD[CARDREGTOP-4]&0x1f);
+		reg->WP_GRP_ENABLE= (CSD[CARDREGTOP-3]&0x80)>>7;;
+		reg->DEFAULT_ECC= (CSD[CARDREGTOP-3]&0x60)>>5;
+		reg->R2W_FACTOR= (CSD[CARDREGTOP-3]&0x8c)>>2;
+		reg->WRITE_BL_LEN= ((CSD[CARDREGTOP-3]&0x03)<<2)|((CSD[CARDREGTOP-2]&0xc0)>>6);
+		reg->WRITE_BL_PARTIAL= (CSD[CARDREGTOP-2]&0x20)>>5;
+		reg->FILE_FORMAT_GRP= (CSD[CARDREGTOP-1]&0x80)>>7;
+		reg->COPY= (CSD[CARDREGTOP-1]&0x40)>>6;
+		reg->PERM_WRITE_PROTECT= (CSD[CARDREGTOP-1]&0x20)>>5;
+		reg->TMP_WRITE_PROTECT= (CSD[CARDREGTOP-1]&0x10)>>4;
+		reg->FILE_FORMAT= (CSD[CARDREGTOP-1]&0x0C)>>2 ;
+		reg->ECC= CSD[CARDREGTOP-1]&0x03;
+		reg->CRC= CSD[CARDREGTOP-0]&0xfe;	
+		
+		//print_csd_raw(CSD);
+		//print_csd(reg);
+		
+		return 0;
+	}
+
+
+static inline long UNSTUFF8(u8 *buffer,int offset,int size){	
+	long e=0;
+	int i = CARDREGTOP-offset/8;
+	int bitpos=offset%8;//marker for keeping track of a bit position.
+	long temp,pull;
+	//initially bitpos is used to denote the start bit of the first register
+	e=buffer[i--]>>bitpos;//starting with partial register offset chunk
+	//bitposition now used to denote the location of the last bit in the final register
+	e&=0xff>>(8-((size>8)?8:size));
+	bitpos=8-bitpos;
+	//from here out starting offsets within registers will be zero
+	while(bitpos<size){
+		pull = size-bitpos;if(pull>8)pull=8;
+		temp=buffer[i--]&(0xff>>(8-pull));//and any unused out
+		temp<<=bitpos;
+		e|=temp;
+		bitpos+=pull;
+	}
+	return e;
+}
+
+
+static inline int parse_CSD_SDHC(CSD_register *reg, u8 *CSD){
+	reg->SPEC_VERS= 			UNSTUFF8(CSD,126,2);
+	reg->MMC_SPEC_VERS= 		UNSTUFF8(CSD,122,4);
+	reg->TAAC= 					UNSTUFF8(CSD,112,8);
+	reg->NSAC= 					UNSTUFF8(CSD,104,8);
+	reg->TRAN_SPEED= 			UNSTUFF8(CSD,96,8);
+	reg->CCC= 					UNSTUFF8(CSD,84,12);
+	reg->READ_BL_LEN= 			UNSTUFF8(CSD,80,4);
+	reg->READ_BL_PARTIAL= 		UNSTUFF8(CSD,79,1);
+	reg->WRITE_BLK_MISALIGN= 	UNSTUFF8(CSD,78,1);
+	reg->READ_BLK_MISALIGN= 	UNSTUFF8(CSD,77,1);
+	reg->DSR_IMP= 				UNSTUFF8(CSD,76,1);
+	reg->C_SIZE= 				UNSTUFF8(CSD,48,22);
+
+	reg->ERASE_GRP_SIZE=		UNSTUFF8(CSD,46,1);//ERASE BLK LEN
+	reg->ERASE_GRP_MULT= 		UNSTUFF8(CSD,39,7);//ERASE SECTOR SIZE in new spec
+	reg->WP_GRP_SIZE= 			UNSTUFF8(CSD,32,7);
+	reg->WP_GRP_ENABLE= 		UNSTUFF8(CSD,31,1);
+			
+	reg->R2W_FACTOR = 			UNSTUFF8(CSD,26,3);
+	reg->WRITE_BL_LEN= 			UNSTUFF8(CSD,22,4);
+	reg->WRITE_BL_PARTIAL= 		UNSTUFF8(CSD,21,1);
+	reg->FILE_FORMAT_GRP= 		UNSTUFF8(CSD,15,1);
+	reg->COPY= 					UNSTUFF8(CSD,14,1);
+	reg->PERM_WRITE_PROTECT= 	UNSTUFF8(CSD,13,1);
+	reg->TMP_WRITE_PROTECT= 	UNSTUFF8(CSD,12,1);
+	reg->FILE_FORMAT= 			UNSTUFF8(CSD,10,2);
+
+	//printk("CSD SDHC parsed\n");
+	//print_csd_raw(CSD);
+	//print_csd(reg);
+		return 0;
+	}
+
+static inline int parse_CID(CID_register *reg,u8 *CID){
+		reg->Manufacturer_ID = 		CID[CARDREGTOP-15];
+		reg->OEM_Application_ID =  	UNSTUFF8(CID,104,16);	
+		reg->Product_name[5] = 		CID[CARDREGTOP-7];
+		reg->Product_name[4] = 		CID[CARDREGTOP-8];
+		reg->Product_name[3] = 		CID[CARDREGTOP-9];
+		reg->Product_name[2] = 		CID[CARDREGTOP-10];
+		reg->Product_name[1] = 		CID[CARDREGTOP-11];
+		reg->Product_name[0] = 		CID[CARDREGTOP-12];
+		reg->Product_name[6] = 0;	//NULL termination for string manipulation
+		reg->Product_revision = 	CID[CARDREGTOP-6];
+		reg->Product_serial_number= UNSTUFF8(CID,24,32);	
+		reg->Manufacturing_date = 	CID[CARDREGTOP-1]; 
+		return 0;
+	}
+
+
+/**
+ * MMC Commands
+ * -----------------------------------------------------------------------------
+ */
+
+/**
+ * resets the MultiMedia card
+ */
+#define GO_IDLE_STATE(dev)	mmctransaction(dev,0,0,0,0,1)												
+/**
+ * activates the card's initialization process
+ * @return command response
+ */
+#define	SEND_OP_COND(dev)	mmctransaction(dev,1,0,0,0,1)
+#define	SEND_OP_COND_SDHC(dev)	mmctransaction(dev,1,0xC000,0,0,1)
+/**
+ * Returns the protocol version of the card
+ * To support SD 2.0 cards this must be sent before calling
+ * SD_APP_OP_COND 
+ *     [31:12] Reserved (0)
+ *     [11:8] Host Voltage Supply Flags
+ *     [7:0] Check Pattern (0xAA) 
+ */
+#define SEND_IF_COND(dev)  mmctransaction(dev,8,0,0x1aa,0,7)   /* bcr  [11:0] See below   R7  */
+/**
+ * Asks the selected card to send its cardspecific data (CSD)
+ * @param data a 16 bit array to store the CSD register in
+ * @return the command response
+ */
+#define SEND_CSD(dev,data)  mmcblockread(dev,9,0,0,1,data,16,1,8 )
+/**
+ * asks the selected card to send its card identification (CID)
+ * @param data data a 16 bit array to store the CID register in
+ * @return
+ */
+#define SEND_CID(dev,data)  mmcblockread(dev,10,0,0,1,data,16,1, 8)
+/**
+ * Stop transmission on multiple block read 
+ * automatically called by the READ_MULTIPLE_BLOCK function
+ * @return command response
+ */
+#define STOP_TRANSMISSION(dev) mmctransaction(dev,12,0,0,0,1)
+/**
+ * Asks the selected card to send its status register
+ * This is an untested command 
+ * @return command response(in this case status)
+ */
+#define SEND_STATUS(dev) mmctransaction(dev,13,0,0,0,2)
+/**
+ * selects a block length (in bytes) for all following 
+ * block operations (read and write)1
+ * this is an untested command
+ * @param arg1 top half of block length
+ * @param arg2 bottom half of block length
+ * @return command response
+ */
+#define SET_BLOCKLEN(dev,arg1,arg2) mmctransaction(dev,16,arg1,arg2,0,1)
+/**
+ * reads a block of the size selected by the SET_BLOCKLEN command2
+ * changing the block size outside of the default has not been tested
+ * @param address the byte address to start the read at(block aligned)
+ * @param data array to move the data into
+ * @param blocksize size of the blocks. If it hasn't been modified with SET_BLOCKLEN this will be BLOCKLEN
+ * @return 1
+ */
+#define READ_SINGLE_BLOCK(dev,address,data,blocksize) mmcblockread(dev,17,(int)(address>>16),(int)(address&0xffff),1, data,blocksize,1,8 )
+/**
+ * continuously transfers data blocks from card to host until interrupted by a 
+ * stop command or the requested number of data blocks transmitted
+ * Currently this command is implemented to automatically stop transmission after the 
+ * number of blocks specified by blocknum is read
+ * @param address starting block aligned byte address
+ * @param data array to transfer the data into linearly
+ * @param blocksize size of the blocks. If it hasn't been modified with 
+ * SET_BLOCKLEN this will be BLOCKLEN
+ * @param blocknum number of blocks to read
+ * @return the number of blocks read
+ */
+#define READ_MULTIPLE_BLOCK(dev,address,data,blocksize,blocknum) mmcblockread(dev,18,(int)(address>>16),(int)(address&0xffff),1,data,blocksize,blocknum,8)
+/**
+ * Defines the number of blocks which are going to be transferred in the immediately exceeding multiple block read or write command.
+ * this command is untested, and probably won't work with the current read/write
+ * implementation
+ * @param number of blocks
+ * @return command response
+ */
+#define SET_BLOCK_COUNT(dev,arg1) mmctransaction(dev,23,arg1,0,0,1)
+/**
+ * writes a block of the size selected by the SET_BLOCKLEN command
+ * if BLOCKLEN has not been set, then the default is used (read from the CSD)
+ * @param address starting block aligned byte address
+ * @param data linear data array to write
+ * @param blocksize size of the blocks. 
+ * @return 1
+ */
+#define	WRITE_BLOCK(dev,address,data,blocksize)	mmcblockwrite(dev,24,(int)(address>>16),(int)(address&0xffff),1,data,blocksize,1,1)
+/**
+ * continuously writes blocks of data until a "Stop Tran" Token or the requested number of blocks received.
+ * stop tran is automatically thrown by the method when the requested
+ * number of blocks has been written
+ * @param address address starting block aligned byte address
+ * @param data linear data array to write
+ * @param blocksize size of the blocks. If it hasn't been modified with SET_BLOCKLEN this will be BLOCKLEN
+ * @param blocknum number of blocks to write
+ * @return number of blocks written
+ */
+#define WRITE_MULTIPLE_BLOCK(dev,address, data, blocksize, blocknum) mmcblockwrite(dev,25,(int)(address>>16),(int)(address&0xffff),1,data,blocksize,blocknum,1)
+/**
+ * programming of the programmable bits of the CSD
+ * not currently supported
+ * probably a write_block method, but more research will
+ * be needed.
+ * @return command response
+ */
+#define PROGRAM_CSD(dev) mmctransaction(dev,27,0,0,0,1)
+/**
+ * if the card has write protection this command sets the write protection bit of the addressed group.
+ * The properties of write protection are coded in the card specific data (WP_GRP_SIZE).
+ * untested
+ * @param arg1 high address bits
+ * @param arg2 low address bits
+ * @return command response
+ */
+#define SET_WRITE_PROT(dev,arg1, arg2) mmctransaction(dev,28,arg1,arg2,0,1)
+/**
+ * if the card has write protection this command clears the write protection bit of the addressed group
+ * untested
+ * @param arg1 high address bits
+ * @param arg2 low address bits
+ * @return command response
+ */
+#define CLR_WRITE_PROT(dev,arg1, arg2) mmctransaction(dev,29,arg1,arg2,true,1)
+/**
+ * "if the card has write protection this command asks the card to send the status of the write protection bits 
+ * untested
+ * @param arg1 high address bits
+ * @param arg2 low address bits
+ * @return command response
+ */
+#define SEND_WRITE_PROT(dev,arg1, arg2) mmctransaction(dev,30,arg1,arg2,0,1)
+/**
+ * sets the address of the first erase group within a range to be selected for erase
+ * untested
+ * @param arg1 high address bits
+ * @param arg2 low address bits
+ * @return command response
+ */
+#define TAG_ERASE_GROUP_START(dev,arg1, arg2) mmctransaction(dev,35,arg1,arg2,0,1)
+/**
+ * erases all previously selected erase groups  
+ * untested
+ * @param arg1 high address bits
+ * @param arg2 low address bits
+ * @return command response
+ */
+#define	ERASE(dev,arg1,arg2) mmctransaction(dev,38,arg1,arg2,1,1)	
+/**
+ * used to Set/Reset the Password or lock/unlock the card. 
+ * The size of the Data Block is defined by the SET_BLOCK_LEN command.
+ * untested 
+ * @param arg1 high address bits
+ * @param arg2 low address bits
+ * @return command response
+ */
+#define	LOCK_UNLOCK(dev,arg1,arg2) mmctransaction(dev,42,arg1,arg2,1,1)
+/**
+ * defines to the card that the next command is an application specific command 
+ * rather than a standard command
+ * untested
+ * @param arg1 see data sheet
+ * @return command response
+ */
+#define	APP_CMD(dev,arg1) mmctransaction(dev,55,arg1,0,false,1)
+/**
+ * used either to transfer a data block to the card or to get a data block from 
+ * the card for general purpose / application specific commands. The size of the 
+ * data block is defined by the SET_BLOCK_LEN command.
+ * untested
+ * @param arg1 high address bits
+ * @param arg2 low address bits
+ * @return command response
+ */
+#define GEN_CMD(dev,arg1, arg2)	mmctransaction(dev,56,arg1,arg2,true,1)
+/**
+ * reads the OCR register of a card 
+ * untested as status bits are returned in the command response of all mmctransactions
+ * @return command response
+ */
+#define READ_OCR(dev) mmctransaction(dev,58,0,0,0,5)
+/**
+ * "turns the CRC option on or off. A ?1? in the CRC option bit will turn the option on, a ?0? will turn it off"
+ * CRC's are currently unsupported, turning on the CRC option will break all further mmctransaction until a reset
+ * @param arg1 see data sheet
+ * @param arg2 see data sheet
+ * @return command response
+ */
+#define CRC_ON_OFF(dev,arg1,arg2) mmctransaction(dev,59,arg1,arg2,0,1)
+
+#endif /*MMCPROT_H_*/
diff -Naur linux-2.6.25/include/linux/class/pwm.h linux-2.6.25.ep93xx/include/linux/class/pwm.h
--- linux-2.6.25/include/linux/class/pwm.h	1969-12-31 18:00:00.000000000 -0600
+++ linux-2.6.25.ep93xx/include/linux/class/pwm.h	2008-08-18 14:05:42.000000000 -0500
@@ -0,0 +1,69 @@
+#ifndef PWM_H_
+#define PWM_H_
+#include <linux/autoconf.h>
+#include <linux/device.h>
+
+
+#ifdef CONFIG_PWMCLASS
+
+//SUBCLASS assignment currently unused and arbitrary
+#define PWMD_SUBCLASS 77 
+
+typedef u32 pwm_data;
+
+/**********************
+ * pwm class structure
+ */
+typedef struct pwm_s{
+	const char *name;
+	int subclass;
+	void *widthus;
+	void *periodus;
+	void *control;
+	pwm_data widthus_shadow;
+	pwm_data periodus_shadow;
+	pwm_data (*widthus_read)(struct pwm_s *pwm);//width us
+	int (*widthus_write)(struct pwm_s *pwm,pwm_data data);
+	pwm_data (*periodus_read)(struct pwm_s *pwm);	//period us
+	int (*periodus_write)(struct pwm_s *pwm,pwm_data data);
+	pwm_data (*invert_read)(struct pwm_s *pwm);	//pulse inversion
+	int (*invert_write)(struct pwm_s *pwm,pwm_data data);
+	pwm_data (*read_pwmclock)(struct pwm_s *pwm);
+	int (*write_pwmclock)(struct pwm_s *pwm,pwm_data data);
+}pwm_t;
+
+
+struct class *pwm_declare(void);
+struct class_device *pwm_register_class_device(pwm_t *pwm);
+
+/***************************************************************************
+ * typical low level methods
+ */
+int  pwm_widthus_write8(pwm_t *pwm, pwm_data data);
+int  pwm_widthus_write16(pwm_t *pwm, pwm_data data);
+int  pwm_periodus_write8(pwm_t *pwm, pwm_data data);
+int  pwm_periodus_write16(pwm_t *pwm, pwm_data data);
+int  pwm_empty_write(pwm_t *pwm, pwm_data data);
+pwm_data pwm_widthus_read8(pwm_t *pwm);
+pwm_data pwm_widthus_read16(pwm_t *pwm);
+pwm_data pwm_periodus_read8(pwm_t *pwm);
+pwm_data pwm_periodus_read16(pwm_t *pwm);
+pwm_data pwm_ff_read(pwm_t *pwm);
+pwm_data pwm_zero_read(pwm_t *pwm);
+pwm_data pwm_widthusshadow_read(pwm_t *pwm);
+
+/***************************************************************************
+ * atomic method wrappers
+ * these should be used for all method calls to maintain sychronization across the
+ * various interfaces
+ */
+int atomic_pwm_widthus_write(pwm_t *pwm,pwm_data data);
+int atomic_pwm_periodus_write(pwm_t *pwm,pwm_data data);
+int atomic_pwm_invert_write(pwm_t *pwm,pwm_data data);
+pwm_data atomic_pwm_widthus_read(pwm_t *pwm);
+pwm_data atomic_pwm_periodus_read(pwm_t *pwm);
+pwm_data atomic_pwm_invert_read(pwm_t *pwm);
+
+#endif //CONFIG_PWMCLASS
+
+#endif /*PWM_H_*/
diff -Naur linux-2.6.25/include/linux/class/spi.h linux-2.6.25.ep93xx/include/linux/class/spi.h
--- linux-2.6.25/include/linux/class/spi.h	1969-12-31 18:00:00.000000000 -0600
+++ linux-2.6.25.ep93xx/include/linux/class/spi.h	2008-08-18 14:05:42.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 -Naur linux-2.6.25/include/linux/class/spi_interface.h linux-2.6.25.ep93xx/include/linux/class/spi_interface.h
--- linux-2.6.25/include/linux/class/spi_interface.h	1969-12-31 18:00:00.000000000 -0600
+++ linux-2.6.25.ep93xx/include/linux/class/spi_interface.h	2008-08-18 14:05:42.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_*/
diff -Naur linux-2.6.25/include/linux/ioex/ecoreex.h linux-2.6.25.ep93xx/include/linux/ioex/ecoreex.h
--- linux-2.6.25/include/linux/ioex/ecoreex.h	1969-12-31 18:00:00.000000000 -0600
+++ linux-2.6.25.ep93xx/include/linux/ioex/ecoreex.h	2008-12-08 12:37:17.000000000 -0600
@@ -0,0 +1,62 @@
+#ifndef ECOREEX_H_
+#define ECOREEX_H_
+
+#include <linux/class/pwm.h>
+#include <linux/class/gpio.h>
+#include <linux/class/mmcprot.h>
+#include <asm/io.h>
+
+#ifdef CONFIG_ECOREEX_KEY
+#define VERSION_KEY CONFIG_ECOREEX_STATIC_KEY
+#else
+#define VERSION_KEY -1
+#endif
+
+/* Use this structure to specify read/write commands
+ * that differ from the direct ioread/write functions
+ * in the gpio class. If these members are not specified,
+ * the corresponding gpio function will be used as the
+ * default
+ */
+struct ecoreex_access_s
+{
+    gpio_data (*ecoreex_data_read)(struct gpio_s *gpio);
+    int (*ecoreex_data_write)(struct gpio_s *gpio,gpio_data data);
+    gpio_data (*ecoreex_ddr_read)(struct gpio_s *gpio); 
+    int (*ecoreex_ddr_write)(struct gpio_s *gpio,gpio_data data);
+    gpio_data (*ecoreex_index_read)(struct gpio_s *gpio);   
+    int (*ecoreex_index_write)(struct gpio_s *gpio,gpio_data data);
+    u8 (*ecoreex_key_read)(u8 index, u8 *virt_addr); /* function to read the key offset -- defaults to ioread8 */
+};
+
+struct ecoreex_data
+{
+    int key_offset;
+#ifdef CONFIG_PWMCLASS
+    __u32 (*read_periodusa)(pwm_t *pwm);//a pwm input clock, defined as a period to minimize calculation
+#endif
+    mmcslot_t *mmcslot;//structure for implementing mmc connections.
+    unsigned int irq;
+    struct ecoreex_access_s *e_access;  
+};
+
+static inline u8 ecoreex_default_key_read(u8 index, u8 *virt_addr)
+{
+    return ioread8(&(virt_addr[index]));
+}
+
+static inline int ecoreex_setup_data_access(struct ecoreex_access_s *e_access, struct gpio_s *gpio)
+{
+    if (!e_access || !gpio) return -1;
+    if (e_access->ecoreex_data_read) gpio->data_read = e_access->ecoreex_data_read;
+    if (e_access->ecoreex_data_write) gpio->data_write = e_access->ecoreex_data_write;
+    if (e_access->ecoreex_ddr_read) gpio->ddr_read = e_access->ecoreex_ddr_read;
+    if (e_access->ecoreex_ddr_write) gpio->ddr_write = e_access->ecoreex_ddr_write;
+    if (e_access->ecoreex_index_read) gpio->index_read = e_access->ecoreex_index_read;
+    if (e_access->ecoreex_index_write) gpio->index_write = e_access->ecoreex_index_write;
+    if (!e_access->ecoreex_key_read) e_access->ecoreex_key_read = ecoreex_default_key_read;
+    
+    return 0;
+}
+
+#endif /*ECOREEX_H_*/
diff -Naur linux-2.6.25/include/linux/ioex/pb1010.h linux-2.6.25.ep93xx/include/linux/ioex/pb1010.h
--- linux-2.6.25/include/linux/ioex/pb1010.h	1969-12-31 18:00:00.000000000 -0600
+++ linux-2.6.25.ep93xx/include/linux/ioex/pb1010.h	2008-08-18 14:05:42.000000000 -0500
@@ -0,0 +1,8 @@
+#ifndef PB1010_H_
+#define PB1010_H_
+
+struct pb1010_data{
+	int	key_offset;
+};
+
+#endif /*ECOREEX_H_*/
diff -Naur linux-2.6.25/include/linux/ioex/pwmd.h linux-2.6.25.ep93xx/include/linux/ioex/pwmd.h
--- linux-2.6.25/include/linux/ioex/pwmd.h	1969-12-31 18:00:00.000000000 -0600
+++ linux-2.6.25.ep93xx/include/linux/ioex/pwmd.h	2008-08-18 14:05:42.000000000 -0500
@@ -0,0 +1,6 @@
+#ifndef PWMD_H_
+#define PWMD_H_
+
+struct class_device *pwmd_device_create(void *widthus,const char *name,pwm_data (*read_pwmclock)(pwm_t *pwm));
+
+#endif /*PWMD_H_*/
diff -Naur linux-2.6.25/include/linux/spi/mmc_spi.h linux-2.6.25.ep93xx/include/linux/spi/mmc_spi.h
--- linux-2.6.25/include/linux/spi/mmc_spi.h	2008-04-16 21:49:44.000000000 -0500
+++ linux-2.6.25.ep93xx/include/linux/spi/mmc_spi.h	2008-08-18 14:05:42.000000000 -0500
@@ -1,6 +1,11 @@
 #ifndef __LINUX_SPI_MMC_SPI_H
 #define __LINUX_SPI_MMC_SPI_H
 
+#include <asm/param.h> /* for HZ */
+
+#define MMC_SPI_POLL_INT HZ
+
+
 struct device;
 struct mmc_host;
 
@@ -20,7 +25,8 @@
 
 	/* sense switch on sd cards */
 	int (*get_ro)(struct device *);
-
+	/* for card detection polling */
+	int (*get_cd)(struct device *);
 	/* how long to debounce card detect, in msecs */
 	u16 detect_delay;
 
