diff --git a/arch/arm/mach-orion5x/ts78xx-fpga.h b/arch/arm/mach-orion5x/ts78xx-fpga.h
index 02a8428..43259ae 100644
--- a/arch/arm/mach-orion5x/ts78xx-fpga.h
+++ b/arch/arm/mach-orion5x/ts78xx-fpga.h
@@ -30,5 +30,47 @@ struct ts78xx_fpga_data {
 		struct ts78xx_fpga_device ts_rtc;
 		struct ts78xx_fpga_device ts_nand;
 		struct ts78xx_fpga_device ts_rng;
+		struct ts78xx_fpga_device ts_gpio;
 	} supports;
 };
+
+/* GPIO pins */
+#define TS_GPIO_A(x)	(x)			/* 0 -> 31 */
+#define TS_GPIO_B(x)	(TS_GPIO_A(31)+1+x)	/* 0 -> 31 */
+#define TS_GPIO_C(x)	(TS_GPIO_B(31)+1+x)	/* 0 -> 19 */
+#define TS_GPIO_D(x)	(TS_GPIO_C(31)+1+x)	/* 0 -> 19 */
+
+#define TS_GPIO_DIO(x)	(TS_GPIO_D(31)+1+x-1)	/* 1 -> 16 */
+#define TS_GPIO_LCD(x)	(TS_GPIO_DIO(16)+1+x-1)	/* 1 -> 14 */
+
+#define TS_GPIO_JMP(x)	(TS_GPIO_LCD(14)+1+x-1)	/* 1 ->  2 */
+
+#define	TS_GPIO_LED_GRN	(TS_GPIO_JMP(2)+1)
+
+#define	TS_GPIO_MAX	(TS_GPIO_LED_GRN+1)
+
+static const unsigned char ts78xx_ts_gpio_pin_invalid[] = {
+	TS_GPIO_A(31),
+	TS_GPIO_B(0), TS_GPIO_B(2), TS_GPIO_B(4),
+		TS_GPIO_B(8), TS_GPIO_B(9), TS_GPIO_B(28),
+		TS_GPIO_B(30),
+	TS_GPIO_C(0), TS_GPIO_C(19),
+	TS_GPIO_D(0), TS_GPIO_D(8), TS_GPIO_D(16),
+		TS_GPIO_D(18), TS_GPIO_D(19),
+	TS_GPIO_LCD(0), TS_GPIO_LCD(1)
+};
+
+struct ts78xx_ts_gpio {
+	struct gpio_chip chip;
+
+	struct {
+		DECLARE_BITMAP(valid, TS_GPIO_MAX);
+		DECLARE_BITMAP(alloc, TS_GPIO_MAX);
+	} pin;
+};
+
+/* SPI<->DIO mapping */
+#define TS_GPIO_SPI_FRAME	TS_GPIO_DIO(6)
+#define TS_GPIO_SPI_MISO	TS_GPIO_DIO(10)
+#define TS_GPIO_SPI_MISI	TS_GPIO_DIO(12)
+#define TS_GPIO_SPI_CLK		TS_GPIO_DIO(14)
diff --git a/arch/arm/mach-orion5x/ts78xx-setup.c b/arch/arm/mach-orion5x/ts78xx-setup.c
index a1578a0..5a31812 100644
--- a/arch/arm/mach-orion5x/ts78xx-setup.c
+++ b/arch/arm/mach-orion5x/ts78xx-setup.c
@@ -18,6 +18,10 @@
 #include <linux/mtd/nand.h>
 #include <linux/mtd/partitions.h>
 #include <linux/timeriomem-rng.h>
+#include <linux/types.h>
+#include <linux/bitops.h>
+#include <linux/bitmap.h>
+#include <linux/gpio.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
@@ -352,6 +356,243 @@ static void ts78xx_ts_rng_unload(void)
 }
 
 /*****************************************************************************
+ * GPIO pins
+ ****************************************************************************/
+static struct ts78xx_ts_gpio ts78xx_ts_gpio;
+
+static int ts78xx_ts_gpio_request(struct gpio_chip *chip, unsigned int gpio)
+{
+	if (gpio >= TS_GPIO_MAX || !test_bit(gpio, ts78xx_ts_gpio.pin.valid)) {
+		printk(KERN_ERR "ts_gpio: requested invalid GPIO %u\n", gpio);
+		return -EINVAL;
+	}
+
+	if (test_and_set_bit(gpio, ts78xx_ts_gpio.pin.alloc)) {
+		printk(KERN_ERR "ts_gpio: requested allocated GPIO %u\n", gpio);
+		return -EBUSY;
+	}
+
+	return 0;
+}
+
+static void ts78xx_ts_gpio_free(struct gpio_chip *chip, unsigned int gpio)
+{
+	if (gpio >= TS_GPIO_MAX || !test_bit(gpio, ts78xx_ts_gpio.pin.valid))
+		return;
+
+	clear_bit(gpio, ts78xx_ts_gpio.pin.alloc);
+}
+
+static int ts78xx_ts_gpio_dir_in(struct gpio_chip *chip, unsigned int gpio)
+{
+	unsigned char offset, bit;
+	unsigned int cur;
+
+	if (gpio >= TS_GPIO_MAX)
+		return -EINVAL;
+	if (!test_bit(gpio, ts78xx_ts_gpio.pin.valid))
+		return -EINVAL;
+
+	switch (gpio) {
+	case TS_GPIO_A(0) ... TS_GPIO_A(31):
+	case TS_GPIO_B(0) ... TS_GPIO_B(31):
+	case TS_GPIO_C(0) ... TS_GPIO_C(19):
+	case TS_GPIO_D(0) ... TS_GPIO_D(19):
+		offset = 0x20 + ((gpio - TS_GPIO_A(0)) / 4);
+		bit = (gpio - TS_GPIO_A(0)) % 32;
+		break;
+	case TS_GPIO_DIO(1) ... TS_GPIO_DIO(16):
+	case TS_GPIO_LCD(1) ... TS_GPIO_LCD(14):
+	case TS_GPIO_JMP(1) ... TS_GPIO_JMP(2):
+		return 0;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	cur = __raw_readl(TS78XX_FPGA_REGS_VIRT_BASE + offset);
+
+	__raw_writel(cur & ~BIT(bit), TS78XX_FPGA_REGS_VIRT_BASE + offset);
+
+	return 0;
+}
+
+static int ts78xx_ts_gpio_get(struct gpio_chip *chip, unsigned int gpio)
+{
+	unsigned char offset, bit;
+
+	if (gpio >= TS_GPIO_MAX)
+		return -EINVAL;
+	if (!test_bit(gpio, ts78xx_ts_gpio.pin.valid))
+		return -EINVAL;
+
+	switch (gpio) {
+	case TS_GPIO_A(0) ... TS_GPIO_A(31):
+	case TS_GPIO_B(0) ... TS_GPIO_B(31):
+	case TS_GPIO_C(0) ... TS_GPIO_C(19):
+	case TS_GPIO_D(0) ... TS_GPIO_D(19):
+		offset = 0x10 + ((gpio - TS_GPIO_A(0)) / 4);
+		bit = (gpio - TS_GPIO_A(0)) % 32;
+		break;
+	case TS_GPIO_DIO(1) ... TS_GPIO_DIO(16):
+	case TS_GPIO_LCD(1) ... TS_GPIO_LCD(14):
+	case TS_GPIO_JMP(1) ... TS_GPIO_JMP(2):
+		offset = 0x04;
+		bit = gpio - TS_GPIO_DIO(1);
+		break;
+	case TS_GPIO_LED_GRN:
+		offset = 0x008;
+		bit = 30;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return __raw_readl(TS78XX_FPGA_REGS_VIRT_BASE + offset) & BIT(bit);
+}
+
+static int ts78xx_ts_gpio_dir_out(struct gpio_chip *chip, unsigned int gpio,
+			int val)
+{
+	unsigned char offset, bit;
+	unsigned int cur;
+
+	if (gpio >= TS_GPIO_MAX)
+		return -EINVAL;
+	if (!test_bit(gpio, ts78xx_ts_gpio.pin.valid))
+		return -EINVAL;
+	if (val)
+		return -EINVAL;
+
+	switch (gpio) {
+	case TS_GPIO_A(0) ... TS_GPIO_A(31):
+	case TS_GPIO_B(0) ... TS_GPIO_B(31):
+	case TS_GPIO_C(0) ... TS_GPIO_C(19):
+	case TS_GPIO_D(0) ... TS_GPIO_D(19):
+		offset = 0x20 + ((gpio - TS_GPIO_A(0)) / 4);
+		bit = (gpio - TS_GPIO_A(0)) % 32;
+		break;
+	case TS_GPIO_DIO(1) ... TS_GPIO_DIO(16):
+	case TS_GPIO_LCD(1) ... TS_GPIO_LCD(14):
+	case TS_GPIO_LED_GRN:
+		return 0;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	cur = __raw_readl(TS78XX_FPGA_REGS_VIRT_BASE + offset);
+
+	__raw_writel(cur & BIT(bit), TS78XX_FPGA_REGS_VIRT_BASE + offset);
+
+	return 0;
+}
+
+static void ts78xx_ts_gpio_set(struct gpio_chip *chip, unsigned int gpio,
+			int val)
+{
+	unsigned char offset, bit;
+	unsigned int cur;
+
+	if (gpio >= TS_GPIO_MAX)
+		return;
+	if (!test_bit(gpio, ts78xx_ts_gpio.pin.valid))
+		return;
+
+	switch (gpio) {
+	case TS_GPIO_A(0) ... TS_GPIO_A(31):
+	case TS_GPIO_B(0) ... TS_GPIO_B(31):
+	case TS_GPIO_C(0) ... TS_GPIO_C(19):
+	case TS_GPIO_D(0) ... TS_GPIO_D(19):
+		offset = 0x10 + ((gpio - TS_GPIO_A(0)) / 4);
+		bit = (gpio - TS_GPIO_A(0)) % 32;
+		break;
+	case TS_GPIO_DIO(1) ... TS_GPIO_DIO(16):
+	case TS_GPIO_LCD(1) ... TS_GPIO_LCD(14):
+		offset = 0x08;
+		bit = gpio - TS_GPIO_DIO(1);
+		break;
+	case TS_GPIO_LED_GRN:
+		offset = 0x08;
+		bit = 30;
+		break;
+	default:
+		return;
+	}
+
+	cur = __raw_readl(TS78XX_FPGA_REGS_VIRT_BASE + offset);
+
+	if (val == !(cur & BIT(bit)))
+		__raw_writel(cur ^ BIT(bit),
+			TS78XX_FPGA_REGS_VIRT_BASE + offset);
+}
+
+static struct ts78xx_ts_gpio ts78xx_ts_gpio = {
+	.chip = {
+		.label			= "ts78xx_gpio",
+		.owner			= THIS_MODULE,
+
+		.request		= ts78xx_ts_gpio_request,
+		.free			= ts78xx_ts_gpio_free,
+		.direction_input	= ts78xx_ts_gpio_dir_in,
+		.get			= ts78xx_ts_gpio_get,
+		.direction_output	= ts78xx_ts_gpio_dir_out,
+		.set			= ts78xx_ts_gpio_set,
+
+		.can_sleep		= 0,
+
+		.base			= -1,
+		.ngpio			= TS_GPIO_MAX,
+	},
+};
+
+static int ts78xx_ts_gpio_load(void)
+{
+	int rc;
+
+	if (ts78xx_fpga.supports.ts_gpio.init == 0) {
+		unsigned char i;
+
+		bitmap_zero(ts78xx_ts_gpio.pin.valid, TS_GPIO_MAX);
+		bitmap_zero(ts78xx_ts_gpio.pin.alloc, TS_GPIO_MAX);
+
+		/* poke the valid pins */
+		for (i = TS_GPIO_A(0); i <= TS_GPIO_A(31); i++)
+			set_bit(i, ts78xx_ts_gpio.pin.valid);
+		for (i = TS_GPIO_B(0); i <= TS_GPIO_B(31); i++)
+			set_bit(i, ts78xx_ts_gpio.pin.valid);
+		for (i = TS_GPIO_C(0); i <= TS_GPIO_C(19); i++)
+			set_bit(i, ts78xx_ts_gpio.pin.valid);
+		for (i = TS_GPIO_D(0); i <= TS_GPIO_D(19); i++)
+			set_bit(i, ts78xx_ts_gpio.pin.valid);
+		for (i = TS_GPIO_DIO(1); i <= TS_GPIO_DIO(16); i++)
+			set_bit(i, ts78xx_ts_gpio.pin.valid);
+		for (i = TS_GPIO_LCD(1); i <= TS_GPIO_LCD(14); i++)
+			set_bit(i, ts78xx_ts_gpio.pin.valid);
+		set_bit(TS_GPIO_JMP(1), ts78xx_ts_gpio.pin.valid);
+		set_bit(TS_GPIO_JMP(2), ts78xx_ts_gpio.pin.valid);
+		set_bit(TS_GPIO_LED_GRN, ts78xx_ts_gpio.pin.valid);
+
+		/* unpoke invalid pins */
+		for (i = 0; i < ARRAY_SIZE(ts78xx_ts_gpio_pin_invalid); i++)
+			clear_bit(ts78xx_ts_gpio_pin_invalid[i],
+					ts78xx_ts_gpio.pin.valid);
+
+		ts78xx_fpga.supports.ts_rng.init = 1;
+	}
+
+	rc = gpiochip_add(&ts78xx_ts_gpio.chip);
+
+	return rc;
+};
+
+/* FIXME: convert all unload's to return int */
+static void ts78xx_ts_gpio_unload(void)
+{
+	gpiochip_remove(&ts78xx_ts_gpio.chip);
+}
+
+/*****************************************************************************
  * FPGA 'hotplug' support code
  ****************************************************************************/
 static void ts78xx_fpga_devices_zero_init(void)
@@ -359,6 +600,7 @@ static void ts78xx_fpga_devices_zero_init(void)
 	ts78xx_fpga.supports.ts_rtc.init = 0;
 	ts78xx_fpga.supports.ts_nand.init = 0;
 	ts78xx_fpga.supports.ts_rng.init = 0;
+	ts78xx_fpga.supports.ts_gpio.init = 0;
 }
 
 static void ts78xx_fpga_supports(void)
@@ -373,11 +615,13 @@ static void ts78xx_fpga_supports(void)
 		ts78xx_fpga.supports.ts_rtc.present = 1;
 		ts78xx_fpga.supports.ts_nand.present = 1;
 		ts78xx_fpga.supports.ts_rng.present = 1;
+		ts78xx_fpga.supports.ts_gpio.present = 1;
 		break;
 	default:
 		ts78xx_fpga.supports.ts_rtc.present = 0;
 		ts78xx_fpga.supports.ts_nand.present = 0;
 		ts78xx_fpga.supports.ts_rng.present = 0;
+		ts78xx_fpga.supports.ts_gpio.present = 0;
 	}
 }
 
@@ -409,6 +653,14 @@ static int ts78xx_fpga_load_devices(void)
 		}
 		ret |= tmp;
 	}
+	if (ts78xx_fpga.supports.ts_gpio.present == 1) {
+		tmp = ts78xx_ts_gpio_load();
+		if (tmp) {
+			printk(KERN_INFO "TS-78xx: GPIO not registered\n");
+			ts78xx_fpga.supports.ts_gpio.present = 0;
+		}
+		ret |= tmp;
+	}
 
 	return ret;
 }
@@ -423,6 +675,8 @@ static int ts78xx_fpga_unload_devices(void)
 		ts78xx_ts_nand_unload();
 	if (ts78xx_fpga.supports.ts_rng.present == 1)
 		ts78xx_ts_rng_unload();
+	if (ts78xx_fpga.supports.ts_gpio.present == 1)
+		ts78xx_ts_gpio_unload();
 
 	return ret;
 }
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 51a8d41..0f5d313 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1150,7 +1150,7 @@ static void gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip)
 			chip->get
 				? (chip->get(chip, i) ? "hi" : "lo")
 				: "?  ");
-
+printk(KERN_ERR "gpio_to_irq(%u) = %d\n", gpio, gpio_to_irq(gpio));
 		if (!is_out) {
 			int		irq = gpio_to_irq(gpio);
 			struct irq_desc	*desc = irq_to_desc(irq);
