Index: linux-2.6.21.7/drivers/pcmcia/Makefile
===================================================================
--- linux-2.6.21.7.orig/drivers/pcmcia/Makefile
+++ linux-2.6.21.7/drivers/pcmcia/Makefile
@@ -69,4 +69,4 @@ sa1100_cs-$(CONFIG_SA1100_SIMPAD)		+= sa
 pxa2xx_cs-$(CONFIG_ARCH_LUBBOCK)		+= pxa2xx_lubbock.o sa1111_generic.o
 pxa2xx_cs-$(CONFIG_MACH_MAINSTONE)		+= pxa2xx_mainstone.o
 pxa2xx_cs-$(CONFIG_PXA_SHARPSL)			+= pxa2xx_sharpsl.o
-
+pxa2xx_cs-$(CONFIG_ARCH_GUMSTIX)		+= pxa2xx_gumstix.o
Index: linux-2.6.21.7/drivers/pcmcia/pxa2xx_gumstix.c
===================================================================
--- /dev/null
+++ linux-2.6.21.7/drivers/pcmcia/pxa2xx_gumstix.c
@@ -0,0 +1,272 @@
+/*
+ * linux/drivers/pcmcia/pxa2xx_gumstix.c
+ *
+ * Gumstix PCMCIA specific routines. Based on Mainstone
+ *
+ * Copyright 2004, Craig Hughes <craig@gumstix.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+
+#include <pcmcia/ss.h>
+
+#include <asm/hardware.h>
+#include <asm/delay.h>
+#include <asm/arch/pxa-regs.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+
+#include <asm/arch/gumstix.h>
+
+#include "soc_common.h"
+
+static struct pcmcia_irqs gumstix_pcmcia_irqs0[] = {
+	{ 0, GUMSTIX_S0_nCD_IRQ,	"CF0 nCD"     },
+	{ 0, GUMSTIX_S0_nSTSCHG_IRQ,	"CF0 nSTSCHG" },
+};
+
+static struct pcmcia_irqs gumstix_pcmcia_irqs1[] = {
+	{ 1, GUMSTIX_S1_nCD_IRQ,	"CF1 nCD"     },
+	{ 1, GUMSTIX_S1_nSTSCHG_IRQ,	"CF1 nSTSCHG" },
+};
+
+static int net_cf_vx_mode = 0;
+
+static int gumstix_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
+{
+	if(skt->nr == 0)
+	{
+		pxa_gpio_mode(GPIO_GUMSTIX_nSTSCHG_0_MD);
+		pxa_gpio_mode(GPIO_GUMSTIX_nCD_0_MD);
+		if(net_cf_vx_mode)
+			pxa_gpio_mode(GPIO_GUMSTIX_PRDY_nBSY_0_OLD_MD);
+		else
+			pxa_gpio_mode(GPIO_GUMSTIX_PRDY_nBSY_0_MD);
+	} else {
+		pxa_gpio_mode(GPIO_GUMSTIX_nSTSCHG_1_MD);
+		pxa_gpio_mode(GPIO_GUMSTIX_nCD_1_MD);
+		pxa_gpio_mode(GPIO_GUMSTIX_PRDY_nBSY_1_MD);
+	}
+
+	pxa_gpio_mode(GPIO_GUMSTIX_nPOE_MD);
+	pxa_gpio_mode(GPIO_GUMSTIX_nPWE_MD);
+	pxa_gpio_mode(GPIO_GUMSTIX_nPIOR_MD);
+	pxa_gpio_mode(GPIO_GUMSTIX_nPIOW_MD);
+	pxa_gpio_mode(GPIO_GUMSTIX_nPCE_1_MD);
+	pxa_gpio_mode(GPIO_GUMSTIX_nPCE_2_MD);
+	pxa_gpio_mode(GPIO_GUMSTIX_pSKTSEL_MD);
+	pxa_gpio_mode(GPIO_GUMSTIX_nPREG_MD);
+	pxa_gpio_mode(GPIO_GUMSTIX_nPWAIT_MD);
+	pxa_gpio_mode(GPIO_GUMSTIX_nIOIS16_MD);                                                                                                                                                              
+
+	skt->irq = (skt->nr == 0) ? ((net_cf_vx_mode == 0) ? GUMSTIX_S0_PRDY_nBSY_IRQ : GUMSTIX_S0_PRDY_nBSY_OLD_IRQ) : GUMSTIX_S1_PRDY_nBSY_IRQ;
+
+	return (skt->nr == 0) ? soc_pcmcia_request_irqs(skt, gumstix_pcmcia_irqs0, ARRAY_SIZE(gumstix_pcmcia_irqs0)) :
+				soc_pcmcia_request_irqs(skt, gumstix_pcmcia_irqs1, ARRAY_SIZE(gumstix_pcmcia_irqs1));
+}
+
+static void gumstix_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
+{
+	if(skt->nr == 0)
+	{
+		soc_pcmcia_free_irqs(skt, gumstix_pcmcia_irqs0, ARRAY_SIZE(gumstix_pcmcia_irqs0));
+	} else {
+		soc_pcmcia_free_irqs(skt, gumstix_pcmcia_irqs1, ARRAY_SIZE(gumstix_pcmcia_irqs1));
+	}
+}
+
+static void gumstix_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
+				    struct pcmcia_state *state)
+{
+	unsigned int cd, prdy_nbsy, nbvd1;
+	if(skt->nr == 0)
+	{
+		cd = GPIO_GUMSTIX_nCD_0;
+		if(net_cf_vx_mode)
+			prdy_nbsy = GPIO_GUMSTIX_PRDY_nBSY_0_OLD;
+		else
+			prdy_nbsy = GPIO_GUMSTIX_PRDY_nBSY_0;
+		nbvd1 = GPIO_GUMSTIX_nBVD1_0;
+	} else {
+		cd = GPIO_GUMSTIX_nCD_1;
+		prdy_nbsy = GPIO_GUMSTIX_PRDY_nBSY_1;
+		nbvd1 = GPIO_GUMSTIX_nBVD1_1;
+	}
+	state->detect = !(GPLR(cd) & GPIO_bit(cd));
+	state->ready  = !!(GPLR(prdy_nbsy) & GPIO_bit(prdy_nbsy));
+	state->bvd1   = !!(GPLR(nbvd1) & GPIO_bit(nbvd1));
+	state->bvd2   = 1;
+	state->vs_3v  = 0;
+	state->vs_Xv  = 0;
+	state->wrprot = 0;
+}
+
+static int gumstix_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
+				       const socket_state_t *state)
+{
+	return 0;
+}
+
+static void gumstix_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
+{
+	if(skt->nr) {
+		soc_pcmcia_enable_irqs(skt, gumstix_pcmcia_irqs0, ARRAY_SIZE(gumstix_pcmcia_irqs0));
+	} else {
+		soc_pcmcia_enable_irqs(skt, gumstix_pcmcia_irqs1, ARRAY_SIZE(gumstix_pcmcia_irqs1));
+	}
+}
+
+static void gumstix_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
+{
+	if(skt->nr) {
+		soc_pcmcia_disable_irqs(skt, gumstix_pcmcia_irqs0, ARRAY_SIZE(gumstix_pcmcia_irqs0));
+	} else {
+		soc_pcmcia_disable_irqs(skt, gumstix_pcmcia_irqs1, ARRAY_SIZE(gumstix_pcmcia_irqs1));
+	}
+}
+
+static struct pcmcia_low_level gumstix_pcmcia_ops = {
+	.owner			= THIS_MODULE,
+	.hw_init		= gumstix_pcmcia_hw_init,
+	.hw_shutdown		= gumstix_pcmcia_hw_shutdown,
+	.socket_state		= gumstix_pcmcia_socket_state,
+	.configure_socket	= gumstix_pcmcia_configure_socket,
+	.socket_init		= gumstix_pcmcia_socket_init,
+	.socket_suspend		= gumstix_pcmcia_socket_suspend,
+	.nr			= 2,
+};
+
+static struct platform_device *gumstix_pcmcia_device;
+
+inline void __init gumstix_pcmcia_cpld_clk(void)
+{
+	GPCR(GPIO_GUMSTIX_nPOE) = GPIO_bit(GPIO_GUMSTIX_nPOE);
+	GPSR(GPIO_GUMSTIX_nPOE) = GPIO_bit(GPIO_GUMSTIX_nPOE);
+}
+
+inline unsigned char __init gumstix_pcmcia_cpld_read_bits(int bits)
+{
+	unsigned char result = 0;
+	unsigned int shift = 0;
+	while(bits--)
+	{
+		result |= !!(GPLR(GPIO_GUMSTIX_nCD_0) & GPIO_bit(GPIO_GUMSTIX_nCD_0)) << shift;
+		shift ++;
+		gumstix_pcmcia_cpld_clk();
+	}
+	printk("CPLD responded with: %02x\n",result);
+	return result;
+}
+
+/* We use the CPLD on the CF-CF card to read a value from a shift register.  If we can read that
+ * magic sequence, then we have 2 CF cards; otherwise we assume just one
+ * The CPLD will send the value of the shift register on GPIO11 (the CD line for slot 0)
+ * when RESET is held in reset.  We use GPIO48 (nPOE) as a clock signal,
+ * GPIO52/53 (card enable for both cards) to control read/write to the shift register
+ */
+static void __init gumstix_count_cards(void)
+{
+	pxa_gpio_mode(GPIO_GUMSTIX_nPOE | GPIO_OUT);
+	pxa_gpio_mode(GPIO_GUMSTIX_nPCE_1 | GPIO_OUT);
+	pxa_gpio_mode(GPIO_GUMSTIX_nPCE_2 | GPIO_OUT);
+	pxa_gpio_mode(GPIO_GUMSTIX_nCD_0 | GPIO_IN);
+	if(net_cf_vx_mode)
+		pxa_gpio_mode(GPIO_GUMSTIX_CF_OLD_RESET | GPIO_OUT);
+	else
+		pxa_gpio_mode(GPIO_GUMSTIX_CF_RESET  | GPIO_OUT);
+
+	// Enter reset
+	if(net_cf_vx_mode)
+		GPSR(GPIO_GUMSTIX_CF_OLD_RESET) = GPIO_bit(GPIO_GUMSTIX_CF_OLD_RESET);
+	else
+		GPSR(GPIO_GUMSTIX_CF_RESET) = GPIO_bit(GPIO_GUMSTIX_CF_RESET);
+
+	// Setup the shift register
+	GPSR(GPIO_GUMSTIX_nPCE_1) = GPIO_bit(GPIO_GUMSTIX_nPCE_1);
+	GPCR(GPIO_GUMSTIX_nPCE_2) = GPIO_bit(GPIO_GUMSTIX_nPCE_2);
+
+	// Tick the clock to program the shift register
+	gumstix_pcmcia_cpld_clk();
+
+	// Now set shift register into read mode
+	GPCR(GPIO_GUMSTIX_nPCE_1) = GPIO_bit(GPIO_GUMSTIX_nPCE_1);
+	GPSR(GPIO_GUMSTIX_nPCE_2) = GPIO_bit(GPIO_GUMSTIX_nPCE_2);
+
+	// We can read the bits now -- 0xC2 means "Dual compact flash"
+	if(gumstix_pcmcia_cpld_read_bits(8) != 0xC2)
+	{
+		// We do not have 2 CF slots
+		gumstix_pcmcia_ops.nr = 1;
+	}
+}
+
+#ifdef CONFIG_ARCH_GUMSTIX_VERDEX
+static void __init gumstix_check_if_netCF_vx(void)
+{
+	void *network_controller_memory = ioremap(0x04000300,16);
+	// Look for the special 91c111 value in the bank select register
+	if((0xff00 & readw(network_controller_memory+0x0e)) == 0x3300) {
+		printk("Detected netCF-vx board: using older GPIO configuration\n");
+		net_cf_vx_mode = 1;
+	} else {
+		printk("Not netCF-vx board: using newer GPIO configuration\n");
+		net_cf_vx_mode = 0;
+	}
+	iounmap(network_controller_memory);
+}
+#endif
+
+static int __init gumstix_pcmcia_init(void)
+{
+	int ret;
+
+#ifdef CONFIG_ARCH_GUMSTIX_VERDEX
+	gumstix_check_if_netCF_vx();
+#endif
+
+	gumstix_count_cards();
+
+	udelay(50);
+	if(net_cf_vx_mode)
+		GPCR(GPIO_GUMSTIX_CF_OLD_RESET) = GPIO_bit(GPIO_GUMSTIX_CF_OLD_RESET);
+	else
+		GPCR(GPIO_GUMSTIX_CF_RESET) = GPIO_bit(GPIO_GUMSTIX_CF_RESET);
+
+	gumstix_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1);
+	if (!gumstix_pcmcia_device)
+		return -ENOMEM;
+
+	gumstix_pcmcia_device->dev.platform_data = &gumstix_pcmcia_ops;
+
+	ret = platform_device_add(gumstix_pcmcia_device);
+	if (ret)
+		platform_device_put(gumstix_pcmcia_device);
+
+	return ret;
+}
+
+static void __exit gumstix_pcmcia_exit(void)
+{
+	/*
+	 * This call is supposed to free our gumstix_pcmcia_device.
+	 * Unfortunately platform_device don't have a free method, and
+	 * we can't assume it's free of any reference at this point so we
+	 * can't free it either.
+	 */
+	platform_device_unregister(gumstix_pcmcia_device);
+}
+
+fs_initcall(gumstix_pcmcia_init);
+module_exit(gumstix_pcmcia_exit);
+
+MODULE_LICENSE("GPL");
