---
 arch/arm/mach-pxa/Kconfig           |    5 +
 arch/arm/mach-pxa/Makefile          |    1 
 arch/arm/mach-pxa/pxa_keys.c        |  159 ++++++++++++++++++++++++++++++++++++
 include/asm-arm/arch-pxa/pxa_keys.h |   17 +++
 4 files changed, 182 insertions(+)

Index: git/arch/arm/mach-pxa/Makefile
===================================================================
--- git.orig/arch/arm/mach-pxa/Makefile	2006-12-30 15:46:25.000000000 +0000
+++ git/arch/arm/mach-pxa/Makefile	2006-12-30 18:01:14.000000000 +0000
@@ -31,6 +31,7 @@ obj-$(CONFIG_LEDS) += $(led-y)
 
 # Misc features
 obj-$(CONFIG_PM) += pm.o sleep.o
+obj-$(CONFIG_PXA_KEYS) += pxa_keys.o
 obj-$(CONFIG_PXA_SSP) += ssp.o
 
 ifeq ($(CONFIG_PXA27x),y)
Index: git/arch/arm/mach-pxa/Kconfig
===================================================================
--- git.orig/arch/arm/mach-pxa/Kconfig	2006-12-30 15:46:25.000000000 +0000
+++ git/arch/arm/mach-pxa/Kconfig	2006-12-30 18:01:13.000000000 +0000
@@ -153,5 +153,10 @@ config PXA_SSP
 	tristate
 	help
 	  Enable support for PXA2xx SSP ports
+
+config PXA_KEYS
+	tristate "PXA25x/27x simple keyboard driver"
+	depends on (PXA25x || PXA27x) && INPUT
+
 endif
 
Index: git/arch/arm/mach-pxa/pxa_keys.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ git/arch/arm/mach-pxa/pxa_keys.c	2006-12-30 17:59:17.000000000 +0000
@@ -0,0 +1,159 @@
+/*
+ * Driver interface for keys on PXA25x GPIO lines
+ *
+ * Copyright 2005 Phil Blundell
+ *
+ * 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/version.h>
+
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/pm.h>
+#include <linux/sysctl.h>
+#include <linux/proc_fs.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/input.h>
+
+#include <asm/arch/hardware.h>
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/pxa_keys.h>
+
+static irqreturn_t pxa_keys_isr(int irq, void *dev_id)
+{
+	int i;
+	struct pxa_keys_platform_data *k = dev_id;
+
+	if (k->suspended)
+		return IRQ_HANDLED;
+
+	for (i = 0; i < k->nbuttons; i++) {
+		int gpio = k->buttons[i].gpio;
+		if (irq == IRQ_GPIO(gpio)) {
+			int state = ((GPLR(gpio) & GPIO_bit(gpio)) ? 1 : 0) 
+				^ ((k->buttons[i].flags & PXAKEY_ACTIVE_LOW) != 0);
+			input_report_key (k->input, k->buttons[i].keycode, state);
+			if ((k->buttons[i].flags & PXAKEY_PWR_KEY)
+				&& time_after(jiffies, k->suspend_jiffies + HZ)) {
+					input_event(k->input, EV_PWR, k->buttons[i].keycode, state);
+				k->suspend_jiffies=jiffies;
+			}
+
+		}
+	}
+
+	return IRQ_HANDLED;
+}
+
+#ifdef CONFIG_PM
+static int pxa_keys_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct pxa_keys_platform_data *k = platform_get_drvdata(pdev);
+	k->suspended = 1;
+	return 0;
+}
+
+static int pxa_keys_resume(struct platform_device *pdev)
+{
+	struct pxa_keys_platform_data *k = platform_get_drvdata(pdev);
+
+	/* Upon resume, ignore the suspend key for a short while */
+	k->suspend_jiffies = jiffies;
+	k->suspended = 0;
+	return 0;
+}
+#else
+#define pxa_keys_suspend	NULL
+#define pxa_keys_resume		NULL
+#endif
+
+static int pxa_keys_probe(struct platform_device *pdev)
+{
+	struct pxa_keys_platform_data *k;
+	struct input_dev *input_dev;
+	int i;
+
+	k = pdev->dev.platform_data;
+	platform_set_drvdata(pdev, k);
+
+
+	input_dev = input_allocate_device();
+	if (!input_dev)
+		return -ENOMEM;
+	k->input = input_dev;
+
+	k->input->evbit[0] = BIT(EV_KEY) | BIT(EV_PWR) | BIT(EV_REP);
+	for (i = 0; i < k->nbuttons; i++) {
+		int code = k->buttons[i].keycode;
+		int irq = IRQ_GPIO(k->buttons[i].gpio);
+		int result;
+
+		result = request_irq(irq, pxa_keys_isr, 
+			IRQF_SAMPLE_RANDOM | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+			"pxa_keys", k);
+		if (result == 0)
+			set_bit(code, k->input->keybit);
+		else
+			printk("pxa_keys: unable to claim irq %d; error %d\n", irq, result);
+	}
+
+	k->input->name = pdev->name;
+	k->input->private = k;
+
+	k->suspend_jiffies = jiffies;
+	k->suspended = 0;
+
+	input_register_device(k->input);
+
+	return 0;
+}
+
+static int
+pxa_keys_remove(struct platform_device *pdev)
+{
+	struct pxa_keys_platform_data *k = pdev->dev.platform_data;
+	int i;
+	
+	for (i = 0; i < k->nbuttons; i++) {
+		int irq = IRQ_GPIO(k->buttons[i].gpio);
+		free_irq(irq, k);
+	}
+
+	input_unregister_device(k->input);
+
+	return 0;
+}
+
+struct platform_driver pxa_keys_device_driver = {
+	.probe    = pxa_keys_probe,
+	.remove   = pxa_keys_remove,
+	.suspend  = pxa_keys_suspend,
+	.resume   = pxa_keys_resume,
+	.driver		= {
+		.name     = "pxa2xx-keys",
+	},
+};
+
+static int pxa_keys_init(void)
+{
+	return platform_driver_register(&pxa_keys_device_driver);
+}
+
+static void pxa_keys_cleanup(void)
+{
+	platform_driver_unregister(&pxa_keys_device_driver);
+}
+
+module_init(pxa_keys_init);
+module_exit(pxa_keys_cleanup);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Phil Blundell <pb@handhelds.org>");
+MODULE_DESCRIPTION("Keyboard driver for PXA25x/PXA27x GPIOs");
Index: git/include/asm-arm/arch-pxa/pxa_keys.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ git/include/asm-arm/arch-pxa/pxa_keys.h	2006-12-30 17:56:24.000000000 +0000
@@ -0,0 +1,17 @@
+#include <linux/input.h>
+
+struct pxa_keys_button {
+	int keycode;
+	int gpio;
+	unsigned long flags;
+};
+#define PXAKEY_ACTIVE_LOW	(1 << 0)	/* Key is Active Low */
+#define PXAKEY_PWR_KEY		(1 << 1)	/* Key is a Power Key */
+
+struct pxa_keys_platform_data {
+	struct pxa_keys_button *buttons;
+	int nbuttons;
+	struct input_dev *input;
+	unsigned int suspended;
+	unsigned long suspend_jiffies;
+};
