This provides support for the GTA01 keyboard

Index: linux-2.6.21-moko/drivers/input/keyboard/Kconfig
===================================================================
--- linux-2.6.21-moko.orig/drivers/input/keyboard/Kconfig
+++ linux-2.6.21-moko/drivers/input/keyboard/Kconfig
@@ -229,4 +229,16 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called gpio-keys.
 
+config KEYBOARD_GTA01
+	tristate "FIC Neo1973 (GTA01) buttons"
+	depends on MACH_NEO1973_GTA01
+	default y
+	help
+	  Say Y here to enable the buttons on the FIC Neo1973 (GTA01)
+	  GSM phone.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called gta01kbd.
+
+
 endif
Index: linux-2.6.21-moko/drivers/input/keyboard/Makefile
===================================================================
--- linux-2.6.21-moko.orig/drivers/input/keyboard/Makefile
+++ linux-2.6.21-moko/drivers/input/keyboard/Makefile
@@ -13,6 +13,7 @@
 obj-$(CONFIG_KEYBOARD_NEWTON)		+= newtonkbd.o
 obj-$(CONFIG_KEYBOARD_STOWAWAY)		+= stowaway.o
 obj-$(CONFIG_KEYBOARD_CORGI)		+= corgikbd.o
+obj-$(CONFIG_KEYBOARD_GTA01)		+= gta01kbd.o
 obj-$(CONFIG_KEYBOARD_SPITZ)		+= spitzkbd.o
 obj-$(CONFIG_KEYBOARD_HIL)		+= hil_kbd.o
 obj-$(CONFIG_KEYBOARD_HIL_OLD)		+= hilkbd.o
Index: linux-2.6.21-moko/drivers/input/keyboard/gta01kbd.c
===================================================================
--- /dev/null
+++ linux-2.6.21-moko/drivers/input/keyboard/gta01kbd.c
@@ -0,0 +1,249 @@
+/*
+ * Keyboard driver for FIC GTA01 (Neo1973) GSM phone
+ *
+ * (C) 2006 by OpenMoko, Inc.
+ * Author: Harald Welte <laforge@openmoko.org>
+ * All rights reserved.
+ *
+ * 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/delay.h>
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/jiffies.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+
+#include <asm/hardware.h>
+#include <asm/arch/gta01.h>
+
+struct gta01kbd {
+	struct input_dev *input;
+	unsigned int suspended;
+	unsigned long suspend_jiffies;
+};
+
+static irqreturn_t gta01kbd_aux_irq(int irq, void *dev_id)
+{
+	struct gta01kbd *gta01kbd_data = dev_id;
+
+	/* FIXME: use GPIO from platform_dev resources */
+	if (s3c2410_gpio_getpin(GTA01_GPIO_AUX_KEY))
+		input_report_key(gta01kbd_data->input, KEY_PHONE, 0);
+	else
+		input_report_key(gta01kbd_data->input, KEY_PHONE, 1);
+
+	input_sync(gta01kbd_data->input);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t gta01kbd_hold_irq(int irq, void *dev_id)
+{
+	struct gta01kbd *gta01kbd_data = dev_id;
+
+	/* FIXME: use GPIO from platform_dev resources */
+	if (s3c2410_gpio_getpin(GTA01_GPIO_HOLD_KEY))
+		input_report_key(gta01kbd_data->input, KEY_PAUSE, 1);
+	else
+		input_report_key(gta01kbd_data->input, KEY_PAUSE, 0);
+
+	input_sync(gta01kbd_data->input);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t gta01kbd_headphone_irq(int irq, void *dev_id)
+{
+	struct gta01kbd *gta01kbd_data = dev_id;
+
+	/* FIXME: use GPIO from platform_dev resources */
+	if (s3c2410_gpio_getpin(GTA01_GPIO_JACK_INSERT))
+		input_report_switch(gta01kbd_data->input, SW_HEADPHONE_INSERT, 1);
+	else
+		input_report_switch(gta01kbd_data->input, SW_HEADPHONE_INSERT, 0);
+
+	input_sync(gta01kbd_data->input);
+
+	return IRQ_HANDLED;
+}
+
+#ifdef CONFIG_PM
+static int gta01kbd_suspend(struct platform_device *dev, pm_message_t state)
+{
+	struct gta01kbd *gta01kbd = platform_get_drvdata(dev);
+
+	gta01kbd->suspended = 1;
+
+	return 0;
+}
+
+static int gta01kbd_resume(struct platform_device *dev)
+{
+	struct gta01kbd *gta01kbd = platform_get_drvdata(dev);
+
+	gta01kbd->suspended = 0;
+
+	return 0;
+}
+#else
+#define gta01kbd_suspend	NULL
+#define gta01kbd_resume		NULL
+#endif
+
+static int gta01kbd_probe(struct platform_device *pdev)
+{
+	struct gta01kbd *gta01kbd;
+	struct input_dev *input_dev;
+	int irq_aux, irq_hold, irq_jack;
+
+	gta01kbd = kzalloc(sizeof(struct gta01kbd), GFP_KERNEL);
+	input_dev = input_allocate_device();
+	if (!gta01kbd || !input_dev) {
+		kfree(gta01kbd);
+		input_free_device(input_dev);
+		return -ENOMEM;
+	}
+
+	if (pdev->resource[0].flags != 0)
+		return -EINVAL;
+
+	irq_aux = s3c2410_gpio_getirq(pdev->resource[0].start);
+	if (irq_aux < 0)
+		return -EINVAL;
+
+	irq_hold = s3c2410_gpio_getirq(pdev->resource[1].start);
+	if (irq_hold < 0)
+		return -EINVAL;
+
+	irq_jack = s3c2410_gpio_getirq(pdev->resource[2].start);
+	if (irq_jack < 0)
+		return -EINVAL;
+
+	platform_set_drvdata(pdev, gta01kbd);
+
+	gta01kbd->input = input_dev;
+
+#if 0
+	spin_lock_init(&gta01kbd->lock);
+	/* Init Keyboard rescan timer */
+	init_timer(&corgikbd->timer);
+	corgikbd->timer.function = corgikbd_timer_callback;
+	corgikbd->timer.data = (unsigned long) corgikbd;
+
+	/* Init Hinge Timer */
+	init_timer(&corgikbd->htimer);
+	corgikbd->htimer.function = corgikbd_hinge_timer;
+	corgikbd->htimer.data = (unsigned long) corgikbd;
+
+	corgikbd->suspend_jiffies=jiffies;
+#endif
+
+	input_dev->name = "Neo1973 Buttons";
+	input_dev->phys = "gta01kbd/input0";
+	input_dev->id.bustype = BUS_HOST;
+	input_dev->id.vendor = 0x0001;
+	input_dev->id.product = 0x0001;
+	input_dev->id.version = 0x0100;
+	input_dev->cdev.dev = &pdev->dev;
+	input_dev->private = gta01kbd;
+
+	input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_SW);
+	set_bit(SW_HEADPHONE_INSERT, input_dev->swbit);
+	set_bit(KEY_PHONE, input_dev->keybit);
+	set_bit(KEY_PAUSE, input_dev->keybit);
+
+	input_register_device(gta01kbd->input);
+
+	if (request_irq(irq_aux, gta01kbd_aux_irq,
+			SA_INTERRUPT | SA_TRIGGER_RISING | SA_TRIGGER_FALLING,
+			"Neo1973 AUX button", gta01kbd)) {
+		dev_err(&pdev->dev, "Can't get IRQ %u\n", irq_aux);
+		goto out_aux;
+	}
+	enable_irq_wake(irq_aux);
+
+	if (request_irq(irq_hold, gta01kbd_hold_irq,
+			SA_INTERRUPT | SA_TRIGGER_RISING | SA_TRIGGER_FALLING,
+			"Neo1973 HOLD button", gta01kbd)) {
+		dev_err(&pdev->dev, "Can't get IRQ %u\n", irq_hold);
+		goto out_hold;
+	}
+	enable_irq_wake(irq_hold);
+
+	if (request_irq(irq_jack, gta01kbd_headphone_irq,
+			SA_INTERRUPT | SA_TRIGGER_RISING | SA_TRIGGER_FALLING,
+			"Neo1973 Headphone Jack", gta01kbd)) {
+		dev_err(&pdev->dev, "Can't get IRQ %u\n", irq_jack);
+		goto out_jack;
+	}
+	enable_irq_wake(irq_jack);
+#if 0
+	mod_timer(&corgikbd->htimer, jiffies + msecs_to_jiffies(HINGE_SCAN_INTERVAL));
+#endif
+	return 0;
+
+out_jack:
+	free_irq(irq_hold, gta01kbd);
+out_hold:
+	free_irq(irq_aux, gta01kbd);
+out_aux:
+	input_unregister_device(gta01kbd->input);
+	input_free_device(gta01kbd->input);
+	platform_set_drvdata(pdev, NULL);
+	kfree(gta01kbd);
+
+	return -ENODEV;
+}
+
+static int gta01kbd_remove(struct platform_device *pdev)
+{
+	struct gta01kbd *gta01kbd = platform_get_drvdata(pdev);
+
+	free_irq(s3c2410_gpio_getirq(pdev->resource[2].start), gta01kbd);
+	free_irq(s3c2410_gpio_getirq(pdev->resource[1].start), gta01kbd);
+	free_irq(s3c2410_gpio_getirq(pdev->resource[0].start), gta01kbd);
+#if 0
+	del_timer_sync(&corgikbd->htimer);
+	del_timer_sync(&corgikbd->timer);
+#endif
+	input_unregister_device(gta01kbd->input);
+	input_free_device(gta01kbd->input);
+	platform_set_drvdata(pdev, NULL);
+	kfree(gta01kbd);
+
+	return 0;
+}
+
+static struct platform_driver gta01kbd_driver = {
+	.probe		= gta01kbd_probe,
+	.remove		= gta01kbd_remove,
+	.suspend	= gta01kbd_suspend,
+	.resume		= gta01kbd_resume,
+	.driver		= {
+		.name	= "gta01-button",
+	},
+};
+
+static int __devinit gta01kbd_init(void)
+{
+	return platform_driver_register(&gta01kbd_driver);
+}
+
+static void __exit gta01kbd_exit(void)
+{
+	platform_driver_unregister(&gta01kbd_driver);
+}
+
+module_init(gta01kbd_init);
+module_exit(gta01kbd_exit);
+
+MODULE_AUTHOR("Harald Welte <laforge@openmoko.org>");
+MODULE_DESCRIPTION("FIC Neo1973 (GTA01) Buttons Driver");
+MODULE_LICENSE("GPL");
