Index: linux-2.6.15gum/arch/arm/Kconfig
===================================================================
--- linux-2.6.15gum.orig/arch/arm/Kconfig
+++ linux-2.6.15gum/arch/arm/Kconfig
@@ -316,6 +316,8 @@ config PCI_HOST_VIA82C505
 	depends on PCI && ARCH_SHARK
 	default y
 
+source "drivers/gpio/Kconfig"
+
 source "drivers/pci/Kconfig"
 
 source "drivers/pcmcia/Kconfig"
Index: linux-2.6.15gum/drivers/Makefile
===================================================================
--- linux-2.6.15gum.orig/drivers/Makefile
+++ linux-2.6.15gum/drivers/Makefile
@@ -70,3 +70,4 @@ obj-$(CONFIG_SGI_IOC4)		+= sn/
 obj-y				+= firmware/
 obj-$(CONFIG_CRYPTO)		+= crypto/
 obj-$(CONFIG_SUPERH)		+= sh/
+obj-$(CONFIG_PROC_GPIO)		+= gpio/
Index: linux-2.6.15gum/drivers/gpio/Kconfig
===================================================================
--- /dev/null
+++ linux-2.6.15gum/drivers/gpio/Kconfig
@@ -0,0 +1,6 @@
+config PROC_GPIO
+	tristate "GPIO /proc interface"
+	depends on PXA25x
+	help
+	  This enables an interface under /proc/gpio which allows reading or setting
+	  of any GPIO.  Currently only reading is supported.
Index: linux-2.6.15gum/drivers/gpio/Makefile
===================================================================
--- /dev/null
+++ linux-2.6.15gum/drivers/gpio/Makefile
@@ -0,0 +1,3 @@
+# Expose GPIOs under /proc
+obj-$(CONFIG_PROC_GPIO)			+= proc_gpio.o
+
Index: linux-2.6.15gum/drivers/gpio/proc_gpio.c
===================================================================
--- /dev/null
+++ linux-2.6.15gum/drivers/gpio/proc_gpio.c
@@ -0,0 +1,355 @@
+/*
+ *
+ *  PXA25x GPIOs exposed under /proc for reading and writing
+ *  They will show up under /proc/gpio/NN
+ *
+ *  Based on patch 1773/1 in the arm kernel patch repository at arm.linux.co.uk
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/proc_fs.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+
+#include <asm/hardware.h>
+#include <asm/arch/pxa-regs.h>
+#include <asm/uaccess.h>
+
+static struct proc_dir_entry *proc_gpio_parent;
+static struct proc_dir_entry *proc_gpios[85];
+
+typedef struct
+{
+	int	gpio;
+	char    name[32];
+} gpio_summary_type;
+
+static gpio_summary_type gpio_summaries[85] =
+{
+	{ 0,	"GPIO0" },
+	{ 1, 	"GPIO1" },
+	{ 2, 	"GPIO2" },
+	{ 3, 	"GPIO3" },
+	{ 4, 	"GPIO4" },
+	{ 5, 	"GPIO5" },
+	{ 6, 	"GPIO6" },
+	{ 7, 	"GPIO7" },
+	{ 8, 	"GPIO8" },
+	{ 9, 	"GPIO9" },
+	{ 10, 	"GPIO10" },
+	{ 11, 	"GPIO11" },
+	{ 12, 	"GPIO12" },
+	{ 13, 	"GPIO13" },
+	{ 14, 	"GPIO14" },
+	{ 15, 	"GPIO15" },
+	{ 16, 	"GPIO16" },
+	{ 17, 	"GPIO17" },
+	{ 18, 	"GPIO18" },
+	{ 19, 	"GPIO19" },
+	{ 20, 	"GPIO20" },
+	{ 21, 	"GPIO21" },
+	{ 22, 	"GPIO22" },
+	{ 23, 	"GPIO23" },
+	{ 24, 	"GPIO24" },
+	{ 25, 	"GPIO25" },
+	{ 26, 	"GPIO26" },
+	{ 27, 	"GPIO27" },
+	{ 28, 	"GPIO28" },
+	{ 29, 	"GPIO29" },
+	{ 30, 	"GPIO30" },
+	{ 31, 	"GPIO31" },
+	{ 32, 	"GPIO32" },
+	{ 33, 	"GPIO33" },
+	{ 34, 	"GPIO34" },
+	{ 35, 	"GPIO35" },
+	{ 36, 	"GPIO36" },
+	{ 37, 	"GPIO37" },
+	{ 38, 	"GPIO38" },
+	{ 39, 	"GPIO39" },
+	{ 40, 	"GPIO40" },
+	{ 41, 	"GPIO41" },
+	{ 42, 	"GPIO42" },
+	{ 43, 	"GPIO43" },
+	{ 44, 	"GPIO44" },
+	{ 45, 	"GPIO45" },
+	{ 46, 	"GPIO46" },
+	{ 47, 	"GPIO47" },
+	{ 48, 	"GPIO48" },
+	{ 49, 	"GPIO49" },
+	{ 50, 	"GPIO50" },
+	{ 51, 	"GPIO51" },
+	{ 52, 	"GPIO52" },
+	{ 53, 	"GPIO53" },
+	{ 54, 	"GPIO54" },
+	{ 55, 	"GPIO55" },
+	{ 56, 	"GPIO56" },
+	{ 57, 	"GPIO57" },
+	{ 58, 	"GPIO58" },
+	{ 59, 	"GPIO59" },
+	{ 60, 	"GPIO60" },
+	{ 61, 	"GPIO61" },
+	{ 62, 	"GPIO62" },
+	{ 63, 	"GPIO63" },
+	{ 64, 	"GPIO64" },
+	{ 65, 	"GPIO65" },
+	{ 66, 	"GPIO66" },
+	{ 67, 	"GPIO67" },
+	{ 68, 	"GPIO68" },
+	{ 69, 	"GPIO69" },
+	{ 70, 	"GPIO70" },
+	{ 71, 	"GPIO71" },
+	{ 72, 	"GPIO72" },
+	{ 73, 	"GPIO73" },
+	{ 74, 	"GPIO74" },
+	{ 75, 	"GPIO75" },
+	{ 76, 	"GPIO76" },
+	{ 77, 	"GPIO77" },
+	{ 78, 	"GPIO78" },
+	{ 79, 	"GPIO79" },
+	{ 80, 	"GPIO80" },
+	{ 81,	"GPIO81" },
+	{ 82,	"GPIO82" },
+	{ 83,	"GPIO83" },
+	{ 84,	"GPIO84" },
+};
+
+static int proc_gpio_write(struct file *file, const char __user *buf,
+                           unsigned long count, void *data)
+{
+	char *cur, lbuf[count + 1];
+	gpio_summary_type *summary = data;
+	u32 altfn, direction, setclear, gafr;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EACCES;
+
+	memset(lbuf, 0, count + 1);
+
+	if (copy_from_user(lbuf, buf, count))
+		return -EFAULT;
+
+	cur = lbuf;
+
+	// Initialize to current state
+	altfn = ((GAFR(summary->gpio) >> ((summary->gpio & 0x0f) << 0x01)) & 0x03);
+	direction = GPDR(summary->gpio) & GPIO_bit(summary->gpio);
+	setclear = GPLR(summary->gpio) & GPIO_bit(summary->gpio);
+	while(1)
+	{
+		// We accept options: {GPIO|AF1|AF2|AF3}, {set|clear}, {in|out}
+		// Anything else is an error
+		while(cur[0] && (isspace(cur[0]) || ispunct(cur[0]))) cur = &(cur[1]);
+
+		if('\0' == cur[0]) break;
+
+		// Ok, so now we're pointing at the start of something
+		switch(cur[0])
+		{
+			case 'G':
+				// Check that next is "PIO" -- '\0' will cause safe short-circuit if end of buf
+				if(!(cur[1] == 'P' && cur[2] == 'I' && cur[3] == 'O')) goto parse_error;
+				// Ok, so set this GPIO to GPIO (non-ALT) function
+				altfn = 0;
+				cur = &(cur[4]);
+				break;
+			case 'A':
+				if(!(cur[1] == 'F' && cur[2] >= '1' && cur[2] <= '3')) goto parse_error;
+				altfn = cur[2] - '0';
+				cur = &(cur[3]);
+				break;
+			case 's':
+				if(!(cur[1] == 'e' && cur[2] == 't')) goto parse_error;
+				setclear = 1;
+				cur = &(cur[3]);
+				break;
+			case 'c':
+				if(!(cur[1] == 'l' && cur[2] == 'e' && cur[3] == 'a' && cur[4] == 'r')) goto parse_error;
+				setclear = 0;
+				cur = &(cur[5]);
+				break;
+			case 'i':
+				if(!(cur[1] == 'n')) goto parse_error;
+				direction = 0;
+				cur = &(cur[2]);
+				break;
+			case 'o':
+				if(!(cur[1] == 'u' && cur[2] == 't')) goto parse_error;
+				direction = 1;
+				cur = &(cur[3]);
+				break;
+			default: goto parse_error;
+		}
+	}
+	// Ok, now set gpio mode and value
+	if(direction)
+		GPDR(summary->gpio) |= GPIO_bit(summary->gpio);
+	else
+		GPDR(summary->gpio) &= ~GPIO_bit(summary->gpio);
+
+	gafr = GAFR(summary->gpio) & ~(0x3 << (((summary->gpio) & 0xf)*2));
+	GAFR(summary->gpio) = gafr |  (altfn  << (((summary->gpio) & 0xf)*2));
+
+	if(direction && !altfn)
+	{
+		if(setclear) GPSR(summary->gpio) = GPIO_bit(summary->gpio);
+		else GPCR(summary->gpio) = GPIO_bit(summary->gpio);
+	}
+
+	printk(KERN_INFO "Set (%s,%s,%s) via /proc/gpio/%s\n",altfn ? (altfn == 1 ? "AF1" : (altfn == 2 ? "AF2" : "AF3")) : "GPIO",
+				direction ? "out" : "in",
+				setclear ? "set" : "clear",
+				summary->name);
+
+	return count;
+
+parse_error:
+	printk(KERN_CRIT "Parse error: Expect \"[GPIO|AF1|AF2|AF3]|[set|clear]|[in|out] ...\"\n");
+	return -EINVAL;
+}
+
+static int proc_gpio_read(char *page, char **start, off_t off,
+			int count, int *eof, void *data)
+{
+	char *p = page;
+	gpio_summary_type *summary = data;
+	int len, i, af;
+	i = summary->gpio;
+
+	p += sprintf(p, "%d\t%s\t%s\t%s\n", i,
+			(af = ((GAFR(i) >> ((i & 0x0f) << 0x01)) & 0x03)) ? (af == 1 ? "AF1" : (af == 2 ? "AF2" : "AF3")) : "GPIO",
+			(GPDR(i) & GPIO_bit(i)) ? "out" : "in",
+			(GPLR(i) & GPIO_bit(i)) ? "set" : "clear");
+
+	len = (p - page) - off;
+
+	if(len < 0)
+	{
+		len = 0;
+	}
+
+	*eof = (len <= count) ? 1 : 0;
+	*start = page + off;
+
+	return len;
+}
+
+static const char const *GAFR_DESC[] = { "GAFR0_L", "GAFR0_U", "GAFR1_L", "GAFR1_U", "GAFR2_L", "GAFR2_U" };
+
+static int proc_gafr_read(char *page, char **start, off_t off,
+			int count, int *eof, void *data)
+{
+	char *p = page;
+	int i, len;
+
+	for(i=0; i<=5; i++)
+	{
+		p += sprintf(p, "%s: %08x\n", GAFR_DESC[i], GAFR(i*16));
+	}
+
+	len = (p - page) - off;
+
+	if(len < 0)
+	{
+		len = 0;
+	}
+
+	*eof = (len <= count) ? 1 : 0;
+	*start = page + off;
+
+	return len;
+}
+
+static int proc_gpdr_read(char *page, char **start, off_t off,
+			int count, int *eof, void *data)
+{
+	char *p = page;
+	int i, len;
+
+	for(i=0; i<=2; i++)
+	{
+		p += sprintf(p, "GPDR%d: %08x\n", i, GPDR(i * 32));
+	}
+
+	len = (p - page) - off;
+
+	if(len < 0)
+	{
+		len = 0;
+	}
+
+	*eof = (len <= count) ? 1 : 0;
+	*start = page + off;
+
+	return len;
+}
+
+static int proc_gplr_read(char *page, char **start, off_t off,
+			int count, int *eof, void *data)
+{
+	char *p = page;
+	int i, len;
+
+	for(i=0; i<=2; i++)
+	{
+		p += sprintf(p, "GPLR%d: %08x\n", i, GPLR(i * 32));
+	}
+
+	len = (p - page) - off;
+
+	if(len < 0)
+	{
+		len = 0;
+	}
+
+	*eof = (len <= count) ? 1 : 0;
+	*start = page + off;
+
+	return len;
+}
+
+static int __init gpio_init(void)
+{
+	int i;
+
+	proc_gpio_parent = create_proc_entry("gpio", S_IFDIR | S_IRUGO | S_IXUGO, NULL);
+	if(!proc_gpio_parent) return 0;
+
+	for(i=0; i < 85; i++)
+	{
+		proc_gpios[i] = create_proc_entry(gpio_summaries[i].name, 0644, proc_gpio_parent);
+		if(proc_gpios[i])
+		{
+			proc_gpios[i]->data = &gpio_summaries[i];
+			proc_gpios[i]->read_proc = proc_gpio_read;
+			proc_gpios[i]->write_proc = proc_gpio_write;
+		}
+	}
+
+	create_proc_read_entry("GAFR", 0444, proc_gpio_parent, proc_gafr_read, NULL);
+	create_proc_read_entry("GPDR", 0444, proc_gpio_parent, proc_gpdr_read, NULL);
+	create_proc_read_entry("GPLR", 0444, proc_gpio_parent, proc_gplr_read, NULL);
+
+	return 0;
+}
+
+static void gpio_exit(void)
+{
+	int i;
+
+	remove_proc_entry("GAFR", proc_gpio_parent);
+	remove_proc_entry("GPDR", proc_gpio_parent);
+	remove_proc_entry("GPLR", proc_gpio_parent);
+
+	for(i=0; i < 85; i++)
+	{
+		if(proc_gpios[i]) remove_proc_entry(gpio_summaries[i].name, proc_gpio_parent);
+	}
+	if(proc_gpio_parent) remove_proc_entry("gpio", NULL);
+}
+
+module_init(gpio_init);
+module_exit(gpio_exit);
+MODULE_LICENSE("GPL");