Skip to contentSkip to conversation

PXA27x keyboard support

PATCH In review Rodolfo Giometti 3 participants 5 messages Feb 21, 2007 – Mar 7, 2007 5 messages not in the archive

Subsystems (2)
lore
Share & tools
lore

A message that is not in the archive (sent off-list or not yet received): [email protected]

A message that is not in the archive (sent off-list or not yet received): [email protected]

A message that is not in the archive (sent off-list or not yet received): [email protected]

A message that is not in the archive (sent off-list or not yet received): [email protected]

A message that is not in the archive (sent off-list or not yet received): [email protected]

#5 lore raw

Hello,

I'm working again on PXA27x keyboard support since I'd like to add backlight support.

Since my hardware doesn't support "direct interface" but only "matrix scan" what I can do is to integrate as much possible of the code of your patch into the new driver so if someone has a mainstone can do an easy port.

It could be acceptable?

Ciao,

Rodolfo

Signature · 4 lines
GNU/Linux Solutions                  e-mail:    [email protected]
Linux Device Driver                             [email protected]
Embedded Systems                     		[email protected]
UNIX programming                     phone:     +39 349 2432127
#6 lore raw
In reply to a message not in the archive
Quoted 5 lines · Dmitry Torokhov

I was about to apply the patch below from Nicolas Pitre when I saw your post. I like your idea of defining keyboard data at machine level and have driver adapt to the hardware, however Nicolas driver seems to have more features. If I could ask you to work out how both your and Nicolas drivers can be merged together taht woudl be great.

Hello, here my last patch for the PXA27x keyboard support updated to linux-2.6.21-rc1.

As already written I tried to add as mush possible from the Nicolas' patch but since I haven't a mainstone I can't fully test the keyboard hardware.

I know that this is not the best but I think it could be a good starting point for further improvements. :)

Machines should call the driver with the following code:

static struct pxa27x_keyboard_platform_data wwpc1100_kbd = {
        .nr_rows = 4,
        .nr_cols = 4,
        .keycodes = {
                {
                        /* row 0 */
                        KEY_ESC,
                        KEY_ENTER,
                        KEY_F1,
                        -1,
                }, {    /* row 1 */
                        KEY_F2,
                        KEY_F3,
                        KEY_F4,
                        -1,
                }, {    /* row 2 */
                        KEY_UP,
                        KEY_LEFT,
                        KEY_RIGHT,
                        -1,
                }, {    /* row 3 */
                        KEY_DOWN,
                        -1,
                        -1,
                        -1,
                },
        },
        .gpio_modes = {
                 GPIO100_KP_MKIN0,
                 GPIO101_KP_MKIN1,
                 GPIO102_KP_MKIN2,
                 GPIO97_KP_MKIN3,
                 GPIO103_KP_MKOUT0,
                 GPIO104_KP_MKOUT1,
                 GPIO105_KP_MKOUT2,
                 GPIO106_KP_MKOUT3,
         },
};
static struct platform_device wwpc1100_keyboard = {
        .name   = "pxa27x-keyboard",
        .id     = -1,
        .dev    =  {
                .platform_data  = &wwpc1100_kbd,
        },
};
static struct platform_device *platform_devices[] __initdata = {
        &wwpc1100_audio_device,
        &wwpc1100_keyboard,
        &wwpc1100_lcd_bl_device,
        &wwpc1100_keyb_bl_device,
};
Signature · 4 lines
GNU/Linux Solutions                  e-mail:    [email protected]
Linux Device Driver                             [email protected]
Embedded Systems                     		[email protected]
UNIX programming                     phone:     +39 349 2432127
drivers/input/keyboard/Kconfig +6 -0
index 6450968..18ce7b1 100644
@@ -203,6 +203,12 @@ config KEYBOARD_OMAP
 	  To compile this driver as a module, choose M here: the
 	  module will be called omap-keypad.
 
+config KEYBOARD_PXA27x
+	tristate "PXA27x keyboard support"
+	depends on PXA27x
+	help
+	  Enable support for PXA27x matrix keyboard controller
+
 config KEYBOARD_AAED2000
 	tristate "AAED-2000 keyboard"
 	depends on MACH_AAED2000
drivers/input/keyboard/Makefile +1 -0
index 586a0fe..fc1d1f2 100644
@@ -17,6 +17,7 @@ obj-$(CONFIG_KEYBOARD_SPITZ)		+= spitzkbd.o
 obj-$(CONFIG_KEYBOARD_HIL)		+= hil_kbd.o
 obj-$(CONFIG_KEYBOARD_HIL_OLD)		+= hilkbd.o
 obj-$(CONFIG_KEYBOARD_OMAP)		+= omap-keypad.o
+obj-$(CONFIG_KEYBOARD_PXA27x)		+= pxa27x_keyboard.o
 obj-$(CONFIG_KEYBOARD_AAED2000)		+= aaed2000_kbd.o
 obj-$(CONFIG_KEYBOARD_GPIO)		+= gpio_keys.o
 
drivers/input/keyboard/pxa27x_keyboard.c new file +225 -0

225 lines not on this page · raw message

include/asm-arm/arch-pxa/pxa27x_keyboard.h new file +8 -0
new file mode 100644
index 0000000..f83cf33
@@ -0,0 +1,8 @@
+#define PXAKBD_MAXROW		8
+#define PXAKBD_MAXCOL		8
+
+struct pxa27x_keyboard_platform_data {
+	int nr_rows, nr_cols;
+	int keycodes[PXAKBD_MAXROW][PXAKBD_MAXCOL];
+	int gpio_modes[PXAKBD_MAXROW + PXAKBD_MAXCOL];
+};
#7 lore raw

Hi All!
I just made the AT91RM9200-EK board and successfully place the Uboot and Linux2.4
But now I want to go for Linux 2.6 version and also I successfully compiled the Linux 2.6 version and
Now I am trying to download into the board but I amgetting following error you can see at the last two lines
Anyone can help me out to solve this problem.
I am just attaching whole procees after Reset the board It starts Now...............

Low Level Init performed

boot 1.0 (Nov 25 2003 - 23:08:05)

Uncompressing image...

Low Level Init performed

boot 1.0 (Nov 25 2003 - 23:08:05)

Uncompressing image...

U-Boot 1.1.1 (Oct 2 2004 - 19:04:01)

U-Boot code: 21F00000 -> 21F16DF0 BSS: -> 21F1B4AC

RAM Configuration:
Bank #0: 20000000 32 MB
Atmel: AT49BV6416 (64Mbit)
Flash: 8 MB
DataFlash:AT45DB642

Nb pages:   8192                
Page Size:   1056                 
Size= 8650752 bytes                   
Logical address: 0xC0000000                           
Area 0: C0000000 to C0007FFF (RO)                                 
Area 1: C0008000 to C001FFFF (RO)                                 
Area 2: C0020000 to C0027FFF                            
Area 3: C0028000 to C083FFFF                            
In:    serial             
Out:   serial             
Err:   serial             

Uboot> setenv ramdisk tftp 0x00000000 ramdisk

Uboot> saveenv
Saving Environment to Flash...
Un-Protected 1 sectors
Erasing Flash...Erasing sector 7 ... ok.

Erased 1 sectors
Writing to Flash... done
Protected 1 sectors
Uboot> run ramdisk
TFTP from server 10.245.8.175; our IP address is 10.245.8.176

Filename 'ramdisk'.
Load address: 0x0
Loading: #################################################################

         #################################################################

         #################################################################

         ########               

done
Bytes transferred = 1112544 (10f9e0 hex)

Uboot> run kernel
TFTP from server 10.245.8.175; our IP address is 10.245.8.176

Filename 'zImage'.
Load address: 0x21000000
Loading: #################################################################

         #################################################################

         ############################                                     

done
Bytes transferred = 806672 (c4f10 hex)
Uboot> bootm 21000000
## Booting image at 21000000 ...
Bad Magic Number
Uboot> go 21000000
## Starting application at
Uncompressing Linux...................................................... done,

booting the kernel.
Linux version 2.6.10 ([email protected]) (gcc version 3.4.4) #1 Mon Feb

19 19:52:24 EST 2007
CPU: ARM920Tid(wb) [41129200] revision 0 (ARMv4T)

CPU: D VIVT write-back cache
CPU: I cache: 16384 bytes, associativity 64, 32 byte lines, 8 sets

CPU: D cache: 16384 bytes, associativity 64, 32 byte lines, 8 sets

Machine: ATMEL AT91RM9200
Warning: bad configuration page, trying to continue

Memory policy: ECC disabled, Data cache writeback

Built 1 zonelists
Kernel command line: mem=32M console=ttyS0,115200 initrd=0x20410000,3145728 root

=/dev/ram0 rw
PID hash table entries: 256 (order: 8, 4096 bytes)

Console: colour dummy device 80x30
Dentry cache hash table entries: 8192 (order: 3, 32768 bytes)

Inode-cache hash table entries: 4096 (order: 2, 16384 bytes)

Memory: 32MB = 32MB total
Memory: 27600KB available (1324K code, 290K data, 80K init)

Mount-cache hash table entries: 512 (order: 0, 4096 bytes)

CPU: Testing write buffer coherency: ok

checking if image is initramfs...it isn't (bad gzip magic numbers); looks like a

n initrd
Freeing initrd memory: 3072K
NET: Registered protocol family 16
usbcore: registered new driver hub
NetWinder Floating Point Emulator V0.97 (double precision)

devfs: 2004-01-31 Richard Gooch ([email protected])

devfs: boot_options: 0x1
AT91 Watchdog Timer enabled (5 seconds)

AT91 SPI driver loaded
ttyS0 at MMIO 0xfefff200 (irq = 1) is a AT91_SERIAL

ttyS1 at MMIO 0xfefc4000 (irq = 7)
ttyS1 at MMIO 0xfefc4000 (irq = 7)
io scheduler anticipatory registered
RAMDISK driver initialized: 16 RAM disks of 8192K size 1024 blocksize eth%d: Link now 100-HalfDuplex
eth%d: AT91 ethernet at 0xfefbc000 int=24 100-HalfDuplex (00:50:ba:89:69:24) eth%d: Davicom 9196 PHY (Copper)
elevator: using anticipatory as default io scheduler
physmap flash device: 200000 at 10000000
phys_mapped_flash: Found 1 x16 devices at 0x0 in 16-bit bank
Amd/Fujitsu Extended Query Table at 0x0041
phys_mapped_flash: CFI does not contain boot bank location. Assuming top. number of CFI chips: 1
cfi_cmdset_0002: Disabling erase-suspend-program due to code brokenness.
at91_dataflash: Atmel AT45DB642 detected [spi0] (8650752 bytes)
mice: PS/2 mouse device common for all mice
i2c /dev entries driver
Found AT91 i2c
NET: Registered protocol family 2
IP: routing cache hash table of 512 buckets, 4Kbytes
TCP: Hash tables configured (established 2048 bind 4096)
NET: Registered protocol family 1
NET: Registered protocol family 17
RAMDISK: Couldn't find valid RAM disk image starting at 0.

Kernel panic - not syncing: VFS: Unable to mount root fs on

unknown-block(1,0)

Regards,
Milind Dere.

-----Original Message-----
From: [email protected] [mailto:[email protected]] On Behalf Of Rodolfo Giometti
Sent: Friday, February 23, 2007 4:17 AM
To: Dmitry Torokhov
Cc: [email protected]; Nicolas Pitre; [email protected]
Subject: Re: [PATCH] PXA27x keyboard support

Quoted 5 lines · Dmitry Torokhov

I was about to apply the patch below from Nicolas Pitre when I saw your post. I like your idea of defining keyboard data at machine level and have driver adapt to the hardware, however Nicolas driver seems to have more features. If I could ask you to work out how both your and Nicolas drivers can be merged together taht woudl be great.

Hello, here my last patch for the PXA27x keyboard support updated to linux-2.6.21-rc1.

As already written I tried to add as mush possible from the Nicolas' patch but since I haven't a mainstone I can't fully test the keyboard hardware.

I know that this is not the best but I think it could be a good starting point for further improvements. :)

Machines should call the driver with the following code:

static struct pxa27x_keyboard_platform_data wwpc1100_kbd = {
        .nr_rows = 4,
        .nr_cols = 4,
        .keycodes = {
                {
                        /* row 0 */
                        KEY_ESC,
                        KEY_ENTER,
                        KEY_F1,
                        -1,
                }, {    /* row 1 */
                        KEY_F2,
                        KEY_F3,
                        KEY_F4,
                        -1,
                }, {    /* row 2 */
                        KEY_UP,
                        KEY_LEFT,
                        KEY_RIGHT,
                        -1,
                }, {    /* row 3 */
                        KEY_DOWN,
                        -1,
                        -1,
                        -1,
                },
        },
        .gpio_modes = {
                 GPIO100_KP_MKIN0,
                 GPIO101_KP_MKIN1,
                 GPIO102_KP_MKIN2,
                 GPIO97_KP_MKIN3,
                 GPIO103_KP_MKOUT0,
                 GPIO104_KP_MKOUT1,
                 GPIO105_KP_MKOUT2,
                 GPIO106_KP_MKOUT3,
         },
};
static struct platform_device wwpc1100_keyboard = {
        .name   = "pxa27x-keyboard",
        .id     = -1,
        .dev    =  {
                .platform_data  = &wwpc1100_kbd,
        },
};
static struct platform_device *platform_devices[] __initdata = {
        &wwpc1100_audio_device,
        &wwpc1100_keyboard,
        &wwpc1100_lcd_bl_device,
        &wwpc1100_keyb_bl_device,
};
Signature · 4 lines
GNU/Linux Solutions                  e-mail:    [email protected]
Linux Device Driver                             [email protected]
Embedded Systems                     		[email protected]
UNIX programming                     phone:     +39 349 2432127
#8 lore raw

PATCH 1/1 INPUT/keyboard: PXA27x keyboard support

In reply to Rodolfo Giometti

Hello, here my last patch for the PXA27x keyboard support updated to linux-2.6.21-rc2.

I added power management support (suspend/resume code).

Machines should call the driver with the following code:

static struct pxa27x_keyboard_platform_data wwpc1100_kbd = {
        .nr_rows = 4,
        .nr_cols = 4,
        .keycodes = {
                {
                        /* row 0 */
                        KEY_ESC,
                        KEY_ENTER,
                        KEY_F1,
                        -1,
                }, {    /* row 1 */
                        KEY_F2,
                        KEY_F3,
                        KEY_F4,
                        -1,
                }, {    /* row 2 */
                        KEY_UP,
                        KEY_LEFT,
                        KEY_RIGHT,
                        -1,
                }, {    /* row 3 */
                        KEY_DOWN,
                        -1,
                        -1,
                        -1,
                },
        },
        .gpio_modes = {
                 GPIO100_KP_MKIN0,
                 GPIO101_KP_MKIN1,
                 GPIO102_KP_MKIN2,
                 GPIO97_KP_MKIN3,
                 GPIO103_KP_MKOUT0,
                 GPIO104_KP_MKOUT1,
                 GPIO105_KP_MKOUT2,
                 GPIO106_KP_MKOUT3,
         },
};
static struct platform_device wwpc1100_keyboard = {
        .name   = "pxa27x-keyboard",
        .id     = -1,
        .dev    =  {
                .platform_data  = &wwpc1100_kbd,
        },
};
static struct platform_device *platform_devices[] __initdata = {
        &wwpc1100_audio_device,
        &wwpc1100_keyboard,
        &wwpc1100_lcd_bl_device,
        &wwpc1100_keyb_bl_device,
};

---

drivers/input/keyboard/Kconfig +6 -0
index 6450968..18ce7b1 100644
@@ -203,6 +203,12 @@ config KEYBOARD_OMAP
 	  To compile this driver as a module, choose M here: the
 	  module will be called omap-keypad.
 
+config KEYBOARD_PXA27x
+	tristate "PXA27x keyboard support"
+	depends on PXA27x
+	help
+	  Enable support for PXA27x matrix keyboard controller
+
 config KEYBOARD_AAED2000
 	tristate "AAED-2000 keyboard"
 	depends on MACH_AAED2000
drivers/input/keyboard/Makefile +1 -0
index 586a0fe..fc1d1f2 100644
@@ -17,6 +17,7 @@ obj-$(CONFIG_KEYBOARD_SPITZ)		+= spitzkbd.o
 obj-$(CONFIG_KEYBOARD_HIL)		+= hil_kbd.o
 obj-$(CONFIG_KEYBOARD_HIL_OLD)		+= hilkbd.o
 obj-$(CONFIG_KEYBOARD_OMAP)		+= omap-keypad.o
+obj-$(CONFIG_KEYBOARD_PXA27x)		+= pxa27x_keyboard.o
 obj-$(CONFIG_KEYBOARD_AAED2000)		+= aaed2000_kbd.o
 obj-$(CONFIG_KEYBOARD_GPIO)		+= gpio_keys.o
 
drivers/input/keyboard/pxa27x_keyboard.c new file +257 -0

257 lines not on this page · raw message

include/asm-arm/arch-pxa/pxa27x_keyboard.h new file +13 -0
new file mode 100644
index 0000000..3aaff92
@@ -0,0 +1,13 @@
+#define PXAKBD_MAXROW		8
+#define PXAKBD_MAXCOL		8
+
+struct pxa27x_keyboard_platform_data {
+	int nr_rows, nr_cols;
+	int keycodes[PXAKBD_MAXROW][PXAKBD_MAXCOL];
+	int gpio_modes[PXAKBD_MAXROW + PXAKBD_MAXCOL];
+
+#ifdef CONFIG_PM
+	u32 reg_kpc;
+	u32 reg_kprec;
+#endif
+};
#9 lore raw

Re: [PATCH] INPUT/keyboard: PXA27x keyboard support

Hi Rodolfo,

Quoted 4 lines · Rodolfo Giometti

Hello, here my last patch for the PXA27x keyboard support updated to linux-2.6.21-rc2.

I added power management support (suspend/resume code).

The patch has bunch of issues that are hard to list because it was sent as an attachment... Examples are: REL_WHEEL does not belong to evbit, using input_free_device() is not allowed after input_unregister_device(), etc. I tried to fix everything I notoiced; if you could try the patch below and verify that it still works I will apply it to teh input tree.

Thanks.

Signature · 329 lines
Dmitry

From: Rodolfo Giometti <[email protected]>

Input: add support for PXA27x keyboard controller

Signed-off-by: Rodolfo Giometti <[email protected]>
Signed-off-by: Dmitry Torokhov <[email protected]>
---

 drivers/input/keyboard/Kconfig             |    9 +
 drivers/input/keyboard/Makefile            |    1 
 drivers/input/keyboard/pxa27x_keyboard.c   |  258 +++++++++++++++++++++++++++++
 include/asm-arm/arch-pxa/pxa27x_keyboard.h |   13 +
 4 files changed, 281 insertions(+)

Index: work/drivers/input/keyboard/Kconfig
===================================================================
--- work.orig/drivers/input/keyboard/Kconfig
+++ work/drivers/input/keyboard/Kconfig
@@ -203,6 +203,15 @@ config KEYBOARD_OMAP
 	  To compile this driver as a module, choose M here: the
 	  module will be called omap-keypad.
 
+config KEYBOARD_PXA27x
+	tristate "PXA27x keyboard support"
+	depends on PXA27x
+	help
+	  Enable support for PXA27x matrix keyboard controller
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called pxa27x_keyboard.
+
 config KEYBOARD_AAED2000
 	tristate "AAED-2000 keyboard"
 	depends on MACH_AAED2000
Index: work/drivers/input/keyboard/Makefile
===================================================================
--- work.orig/drivers/input/keyboard/Makefile
+++ work/drivers/input/keyboard/Makefile
@@ -17,6 +17,7 @@ obj-$(CONFIG_KEYBOARD_SPITZ)		+= spitzkb
 obj-$(CONFIG_KEYBOARD_HIL)		+= hil_kbd.o
 obj-$(CONFIG_KEYBOARD_HIL_OLD)		+= hilkbd.o
 obj-$(CONFIG_KEYBOARD_OMAP)		+= omap-keypad.o
+obj-$(CONFIG_KEYBOARD_PXA27x)		+= pxa27x_keyboard.o
 obj-$(CONFIG_KEYBOARD_AAED2000)		+= aaed2000_kbd.o
 obj-$(CONFIG_KEYBOARD_GPIO)		+= gpio_keys.o
 
Index: work/drivers/input/keyboard/pxa27x_keyboard.c
===================================================================
--- /dev/null
+++ work/drivers/input/keyboard/pxa27x_keyboard.c
@@ -0,0 +1,258 @@
+/*
+ * linux/drivers/input/keyboard/pxa27x_keyboard.c
+ *
+ * Driver for the pxa27x matrix keyboard controller.
+ *
+ * Created:	Feb 22, 2007
+ * Author:	Rodolfo Giometti <[email protected]>
+ *
+ * Based on a previous implementations by Kevin O'Connor
+ * <kevin_at_koconnor.net> and Alex Osborne <[email protected]> and
+ * on some suggestions by Nicolas Pitre <[email protected]>.
+ *
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+
+#include <asm/arch/hardware.h>
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/irqs.h>
+#include <asm/arch/pxa27x_keyboard.h>
+
+#define DRIVER_NAME		"pxa27x-keyboard"
+
+#define KPASMKP(col)		(col/2 == 0 ? KPASMKP0 : \
+				 col/2 == 1 ? KPASMKP1 : \
+				 col/2 == 2 ? KPASMKP2 : KPASMKP3)
+#define KPASMKPx_MKC(row, col)	(1 << (row + 16 * (col % 2)))
+
+static irqreturn_t pxakbd_irq_handler(int irq, void *dev_id)
+{
+	struct platform_device *pdev = dev_id;
+	struct pxa27x_keyboard_platform_data *pdev = dev->platform_data;
+	struct input_dev *input_dev = platform_get_drvdata(pdev);
+	unsigned long kpc = KPC;
+	int p, row, col, rel;
+
+	if (kpc & KPC_DI) {
+		unsigned long kpdk = KPDK;
+
+		if (!(kpdk & KPDK_DKP)) {
+			/* better luck next time */
+		} else if (kpc & KPC_REE0) {
+			unsigned long kprec = KPREC;
+			KPREC = 0x7f;
+
+			if (kprec & KPREC_OF0)
+				rel = (kprec & 0xff) + 0x7f;
+			else if (kprec & KPREC_UF0)
+				rel = (kprec & 0xff) - 0x7f - 0xff;
+			else
+				rel = (kprec & 0xff) - 0x7f;
+
+			if (rel) {
+				input_report_rel(input_dev, REL_WHEEL, rel);
+				input_sync(input_dev);
+			}
+		}
+	}
+
+	if (kpc & KPC_MI) {
+		/* report the status of every button */
+		for (row = 0; row < pdev->nr_rows; row++) {
+			for (col = 0; col < pdev->nr_cols; col++) {
+				p = KPASMKP(col) & KPASMKPx_MKC(row, col) ?
+					1 : 0;
+				pr_debug("keycode %x - pressed %x\n",
+						pdev->keycodes[row][col], p);
+				input_report_key(input_dev,
+						pdev->keycodes[row][col], p);
+			}
+		}
+		input_sync(input_dev);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int pxakbd_open(struct input_dev *dev)
+{
+	/* Set keypad control register */
+	KPC |= (KPC_ASACT |
+		KPC_MS_ALL |
+		(2<<6) | KPC_REE0 | KPC_DK_DEB_SEL |
+		KPC_ME | KPC_MIE | KPC_DE | KPC_DIE);
+
+	KPC &= ~KPC_AS;         /* disable automatic scan */
+	KPC &= ~KPC_IMKP;       /* do not ignore multiple keypresses */
+
+	/* Set rotary count to mid-point value */
+	KPREC = 0x7F;
+
+	/* Enable unit clock */
+	pxa_set_cken(CKEN19_KEYPAD, 1);
+
+	return 0;
+}
+
+static void pxakbd_close(struct input_dev *dev)
+{
+	/* Disable clock unit */
+	pxa_set_cken(CKEN19_KEYPAD, 0);
+}
+
+#ifdef CONFIG_PM
+static int pxakbd_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct pxa27x_keyboard_platform_data *pdata = pdev->dev.platform_data;
+
+	/* Save controller status */
+	pdata->reg_kpc = KPC;
+	pdata->reg_kprec = KPREC;
+
+	return 0;
+}
+
+static int pxakbd_resume(struct platform_device *pdev)
+{
+	struct pxa27x_keyboard_platform_data *pdata = pdev->dev.platform_data;
+	struct input_dev *input_dev = platform_get_drvdata(pdev);
+
+	mutex_lock(&input_dev->mutex);
+
+	if (input_dev->users) {
+		/* Restore controller status */
+		KPC = pdata->reg_kpc;
+		KPREC = pdata->reg_kprec;
+
+		/* Enable unit clock */
+		pxa_set_cken(CKEN19_KEYPAD, 1);
+	}
+
+	mutex_unlock(&input_dev->mutex);
+
+	return 0;
+}
+#else
+#define pxakbd_suspend	NULL
+#define pxakbd_resume	NULL
+#endif
+
+static int __devinit pxakbd_probe(struct platform_device *pdev)
+{
+	struct pxa27x_keyboard_platform_data *pdata = pdev->dev.platform_data;
+	struct input_dev *input_dev;
+	int i, row, col, error;
+
+	/* Create and register the input driver. */
+	input_dev = input_allocate_device();
+	if (!input_dev) {
+		printk(KERN_ERR "Cannot request keypad device\n");
+		return -ENOMEM;
+	}
+
+	input_dev->name = DRIVER_NAME;
+	input_dev->id.bustype = BUS_HOST;
+	input_dev->open = pxakbd_open;
+	input_dev->close = pxakbd_close;
+	input_dev->cdev.dev = &pdev->dev;
+
+	input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_REL);
+	input_dev->relbit[LONG(REL_WHEEL)] = BIT(REL_WHEEL);
+	for (row = 0; row < pdata->nr_rows; row++) {
+		for (col = 0; col < pdata->nr_cols; col++) {
+			int code = pdata->keycodes[row][col];
+			if (code > 0)
+				set_bit(code, input_dev->keybit);
+		}
+	}
+
+	error = request_irq(IRQ_KEYPAD, pxakbd_irq_handler, SA_INTERRUPT,
+			    DRIVER_NAME, pdev);
+	if (error) {
+		printk(KERN_ERR "Cannot request keypad IRQ\n");
+		pxa_set_cken(CKEN19_KEYPAD, 0);
+		goto err_free_dev;
+	}
+
+	platform_set_drvdata(pdev, input_dev);
+
+	/* Register the input device */
+	error = input_register_device(input_dev);
+	if (error)
+		goto err_free_irq;
+
+	/* Setup GPIOs. */
+	for (i = 0; i < pdata->nr_rows + pdata->nr_cols; i++)
+		pxa_gpio_mode(pdata->gpio_modes[i]);
+
+	/*
+	 * Store rows/cols info into keyboard registers.
+	 */
+
+	KPC |= (pdata->nr_rows - 1) << 26;
+	KPC |= (pdata->nr_cols - 1) << 23;
+
+	for (col = 0; col < pdata->nr_cols; col++)
+		KPC |= KPC_MS0 << col;
+
+	return 0;
+
+ err_free_irq:
+	platform_set_drvdata(pdev, NULL);
+	free_irq(IRQ_KEYPAD, pdev);
+ err_free_dev:
+	input_free_device(input_dev);
+	return error;
+}
+
+static int __devexit pxakbd_remove(struct platform_device *pdev)
+{
+	struct input_dev *input_dev = platform_get_drvdata(pdev);
+
+	input_unregister_device(input_dev);
+	free_irq(IRQ_KEYPAD, pdev);
+	platform_set_drvdata(pdev, NULL);
+
+	return 0;
+}
+
+static struct platform_driver pxakbd_driver = {
+	.probe		= pxakbd_probe,
+	.remove		= __devexit_p(pxakbd_remove),
+	.suspend	= pxakbd_suspend,
+	.resume		= pxakbd_resume,
+	.driver		= {
+		.name	= DRIVER_NAME,
+	},
+};
+
+static int __init pxakbd_init(void)
+{
+	return platform_driver_register(&pxakbd_driver);
+}
+
+static void __exit pxakbd_exit(void)
+{
+	platform_driver_unregister(&pxakbd_driver);
+}
+
+module_init(pxakbd_init);
+module_exit(pxakbd_exit);
+
+MODULE_DESCRIPTION("PXA27x Matrix Keyboard Driver");
+MODULE_LICENSE("GPL");
Index: work/include/asm-arm/arch-pxa/pxa27x_keyboard.h
===================================================================
--- /dev/null
+++ work/include/asm-arm/arch-pxa/pxa27x_keyboard.h
@@ -0,0 +1,13 @@
+#define PXAKBD_MAXROW		8
+#define PXAKBD_MAXCOL		8
+
+struct pxa27x_keyboard_platform_data {
+	int nr_rows, nr_cols;
+	int keycodes[PXAKBD_MAXROW][PXAKBD_MAXCOL];
+	int gpio_modes[PXAKBD_MAXROW + PXAKBD_MAXCOL];
+
+#ifdef CONFIG_PM
+	u32 reg_kpc;
+	u32 reg_kprec;
+#endif
+};