1 Index: linux-2.6.21/arch/arm/mach-pxa/generic.c
2 ===================================================================
3 --- linux-2.6.21.orig/arch/arm/mach-pxa/generic.c 2007-05-17 20:04:53.000000000 +0200
4 +++ linux-2.6.21/arch/arm/mach-pxa/generic.c 2007-05-17 20:06:02.000000000 +0200
6 #include <asm/arch/mmc.h>
7 #include <asm/arch/irda.h>
8 #include <asm/arch/i2c.h>
9 +#include <asm/arch/kbd.h>
17 +static struct resource pxa_kbd_resources[] = {
19 + .start = IRQ_KEYPAD,
21 + .flags = IORESOURCE_IRQ,
23 + .start = 0x41500000,
25 + .flags = IORESOURCE_MEM,
29 +static struct platform_device kbd_device = {
30 + .name = "pxa-keyboard",
32 + .resource = pxa_kbd_resources,
33 + .num_resources = ARRAY_SIZE(pxa_kbd_resources),
36 +void __init pxa_set_kbd_info(struct pxakbd_platform_data *info)
38 + kbd_device.dev.platform_data = info;
41 static struct platform_device *devices[] __initdata = {
51 static int __init pxa_init(void)
52 Index: linux-2.6.21/drivers/input/keyboard/Kconfig
53 ===================================================================
54 --- linux-2.6.21.orig/drivers/input/keyboard/Kconfig 2007-05-17 20:04:53.000000000 +0200
55 +++ linux-2.6.21/drivers/input/keyboard/Kconfig 2007-05-17 20:06:02.000000000 +0200
57 To compile this driver as a module, choose M here: the
58 module will be called gpio-keys.
61 + tristate "Intel PXA keyboard support"
64 + This add support for a driver of the Intel PXA2xx keyboard
68 Index: linux-2.6.21/drivers/input/keyboard/Makefile
69 ===================================================================
70 --- linux-2.6.21.orig/drivers/input/keyboard/Makefile 2007-05-17 20:04:53.000000000 +0200
71 +++ linux-2.6.21/drivers/input/keyboard/Makefile 2007-05-17 20:06:02.000000000 +0200
73 obj-$(CONFIG_KEYBOARD_OMAP) += omap-keypad.o
74 obj-$(CONFIG_KEYBOARD_AAED2000) += aaed2000_kbd.o
75 obj-$(CONFIG_KEYBOARD_GPIO) += gpio_keys.o
77 +obj-$(CONFIG_KEYBOARD_PXA) += pxakbd.o
78 Index: linux-2.6.21/include/asm-arm/arch-pxa/kbd.h
79 ===================================================================
80 --- /dev/null 1970-01-01 00:00:00.000000000 +0000
81 +++ linux-2.6.21/include/asm-arm/arch-pxa/kbd.h 2007-05-17 20:06:02.000000000 +0200
86 + * Copyright (C) 2006 Harald Welte <laforge@openezx.org>
88 + * This program is free software; you can redistribute it and/or modify
89 + * it under the terms of the GNU General Public License version 2 as
90 + * published by the Free Software Foundation.
96 +struct pxakbd_platform_data {
97 + int (*init)(void); /* init gpio, etc. */
98 + unsigned int scan_interval;
102 + unsigned char *keycode;
106 + unsigned char *keycode;
111 Index: linux-2.6.21/drivers/input/keyboard/pxakbd.c
112 ===================================================================
113 --- /dev/null 1970-01-01 00:00:00.000000000 +0000
114 +++ linux-2.6.21/drivers/input/keyboard/pxakbd.c 2007-05-18 16:59:36.000000000 +0200
117 + * Driver for Motorola EZX phone "keyboard"
119 + * (C) 2006 by Harald Welte <laforge@openezx.org>
121 + * May, 2007 - Daniel Ribeiro <drwyrm@gmail.com>
125 +#include <linux/kernel.h>
126 +#include <linux/module.h>
127 +#include <linux/interrupt.h>
128 +#include <linux/input.h>
129 +#include <linux/spinlock.h>
130 +#include <linux/platform_device.h>
132 +#include <asm/hardware.h>
134 +#include <asm/irq.h>
136 +#include <asm/arch/kbd.h>
137 +#include <asm/arch/irqs.h>
138 +#include <asm/arch/pxa-regs.h>
141 +#define DEBUGP(x, args ...) printk(x, ## args)
143 +#define DEBUGP(x, args ...)
146 +/* per-keyboard private data structure */
148 + struct input_dev *input;
149 + struct timer_list timer;
152 + struct resource *res;
157 + struct pxakbd_platform_data *pd;
160 +static int pxakbd_scan_direct(struct pxakbd *pxakbd)
164 + int num_pressed = 0;
166 + kpdk = KPDK & 0x000000ff;
167 + for (i = 0; i < pxakbd->pd->direct.num; i++) {
170 + if (kpdk & (1 << i)) {
173 + DEBUGP("pxakbd: pressed: direct %u\n", i);
175 + if (pxakbd->pd->direct.keycode[i] != KEY_RESERVED) {
176 + DEBUGP( "pxakbd: sending to input layer: keycode = %d, pressed = %d\n", pxakbd->pd->direct.keycode[i], pressed );
177 + input_report_key(pxakbd->input, pxakbd->pd->direct.keycode[i],
181 + return num_pressed;
184 +/* read the full 8x8 matrix from the PXA27x keypad controller */
185 +static void __read_matrix(u_int8_t *matrix)
190 + matrix[0] = tmp & 0x000000ff;
191 + matrix[1] = (tmp & 0x00ff0000) >> 16;
194 + matrix[2] = tmp & 0x000000ff;
195 + matrix[3] = (tmp & 0x00ff0000) >> 16;
198 + matrix[4] = tmp & 0x000000ff;
199 + matrix[5] = (tmp & 0x00ff0000) >> 16;
202 + matrix[6] = tmp & 0x000000ff;
203 + matrix[7] = (tmp & 0x00ff0000) >> 16;
206 +/* compare current matrix with last, generate 'diff' events */
207 +static int __cmp_matrix_gen_events(struct pxakbd *pxakbd, u_int8_t *matrix)
210 + int num_pressed = 0;
212 + /* iterate over the matrix */
213 + for (i = 0; i < pxakbd->pd->matrix.rows; i++) {
215 + for (j = 0; j < pxakbd->pd->matrix.cols; j++) {
216 + u_int32_t scancode =
217 + (i * pxakbd->pd->matrix.cols) + j;
218 + int pressed = matrix[i] & (1 << j);
221 + DEBUGP("pxakbd: pressed: %u/%u\n", i, j);
225 + input_report_key(pxakbd->input,
226 + pxakbd->pd->matrix.keycode[scancode], pressed);
230 + return num_pressed;
233 +/* scan the matrix keypad */
234 +static int pxakbd_scan_matrix(struct pxakbd *pxakbd)
238 + u_int8_t matrix[8];
242 + if ((kpas & KPAS_MUKP) == KPAS_MUKP_NONE) {
243 + /* no keys pressed */
244 + memset(matrix, 0, sizeof(matrix));
245 + } else if ((kpas & KPAS_MUKP) == KPAS_MUKP_ONE) {
246 + /* one key pressed */
247 + u_int8_t row = (kpas & KPAS_RP) >> 4;
248 + u_int8_t col = kpas & KPAS_CP;
250 + if (row == 0x0f || col == 0x0f) {
251 + printk(KERN_WARNING "pxakbd: col or row invalid!\n");
255 + /* clear the matrix and set the single pressed key */
256 + memset(matrix, 0, sizeof(matrix));
257 + matrix[row] |= (1 << col);
259 + /* multiple keys pressed */
260 + __read_matrix(matrix);
263 + num_pressed = __cmp_matrix_gen_events(pxakbd, matrix);
265 + return num_pressed;
268 +static void pxakbd_timer_callback(unsigned long data)
270 + unsigned long flags;
271 + struct pxakbd *pxakbd = (struct pxakbd *) data;
272 + unsigned int num_pressed;
274 + spin_lock_irqsave(&pxakbd->lock, flags);
276 + num_pressed = pxakbd_scan_direct(pxakbd);
277 + num_pressed += pxakbd_scan_matrix(pxakbd);
279 + spin_unlock_irqrestore(&pxakbd->lock, flags);
281 + /* propagate events up the input stack */
282 + input_sync(pxakbd->input);
285 +static irqreturn_t pxakbd_interrupt(int irq, void *dummy)
287 + struct pxakbd *pxakbd = dummy;
290 + int num_pressed = 0;
292 + /* read and clear interrupt */
295 + if (kpc & KPC_DI) {
296 + num_pressed += pxakbd_scan_direct(pxakbd);
300 + if (kpc & KPC_MI) {
301 + while (KPAS & KPAS_SO) {
302 + /* wait for scan to complete beforereading scan regs */
305 + num_pressed += pxakbd_scan_matrix(pxakbd);
309 + /* If any keys are currently pressed, we need to start the timer to detect
312 + mod_timer(&pxakbd->timer, jiffies + pxakbd->pd->scan_interval);
314 + /* propagate events up the input stack */
315 + input_sync(pxakbd->input);
317 + return IRQ_RETVAL(handled);
320 +static int __init pxakbd_probe(struct platform_device *pdev)
322 + struct pxakbd *pxakbd;
323 + struct input_dev *input_dev;
324 + struct resource *r;
328 + int rows, cols, n_direct;
330 + pxakbd = kzalloc(sizeof(*pxakbd), GFP_KERNEL);
334 + input_dev = input_allocate_device();
338 + spin_lock_init(&pxakbd->lock);
339 + pxakbd->irq = platform_get_irq(pdev, 0);
340 + r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
341 + if (!r || pxakbd->irq == NO_IRQ) {
342 + printk(KERN_ERR "pxakbd: invalid resources\n");
347 + pxakbd->input = input_dev;
348 + init_timer(&pxakbd->timer);
349 + pxakbd->timer.function = pxakbd_timer_callback;
350 + pxakbd->timer.data = (unsigned long) pxakbd;
351 + pxakbd->pd = pdev->dev.platform_data;
354 + rows = pxakbd->pd->matrix.rows;
355 + cols = pxakbd->pd->matrix.cols;
356 + n_direct = pxakbd->pd->direct.num;
358 + input_dev->name = "pxa-keyboard";
359 + input_dev->phys = "pxakbd/input0";
360 + input_dev->id.bustype = BUS_HOST;
361 + input_dev->id.vendor = 0x0001;
362 + input_dev->id.product = 0x0001;
363 + input_dev->id.version = 0x0001;
364 + input_dev->cdev.dev = &pdev->dev;
365 + input_dev->private = pxakbd;
367 + input_dev->evbit[0] = BIT(EV_KEY)|BIT(EV_REP);
369 + input_dev->keycodesize = sizeof(unsigned char);
370 + input_dev->keycodemax = (rows*cols)+n_direct;
371 + input_dev->keycode = kmalloc(input_dev->keycodemax*input_dev->keycodesize,
373 + if (!input_dev->keycode){
378 + memcpy(input_dev->keycode, pxakbd->pd->matrix.keycode, rows*cols);
380 + memcpy(input_dev->keycode+(rows*cols),
381 + pxakbd->pd->direct.keycode,
384 + for (i = 0; i < rows*cols; i++)
385 + set_bit(pxakbd->pd->matrix.keycode[i], input_dev->keybit);
387 + for (i = 0; i < n_direct; i++)
388 + set_bit(pxakbd->pd->direct.keycode[i], input_dev->keybit);
390 + clear_bit(0, input_dev->keybit);
392 + if (request_irq(pxakbd->irq, pxakbd_interrupt, 0, "pxakbd", pxakbd)) {
393 + printk(KERN_ERR "pxakbd: can't request irq %d\n", pxakbd->irq);
398 + r = request_mem_region(r->start, 0x4c, "pxakbd");
400 + printk(KERN_ERR "pxakbd: can't request memregion\n");
406 + pxakbd->pd->init();
408 + /* set keypad control register */
409 + KPC = (KPC_ASACT | /* automatic scan on activity */
410 + KPC_ME | KPC_DE | /* matrix and direct keypad enabled */
411 + ((pxakbd->pd->matrix.cols-1)<<23) | /* columns */
412 + ((pxakbd->pd->matrix.rows-1)<<26) | /* rows */
413 + ((pxakbd->pd->direct.num-1)<<6) | /* direct keys */
414 + KPC_MS_ALL); /* scan all columns */
416 + pxa_set_cken(CKEN19_KEYPAD, 1);
418 + KPC |= (KPC_DIE | KPC_MIE); /* enable matrix and direct keyboard */
420 + KPKDI = 0x40; /* matrix key debounce interval: 0x40 */
422 + platform_set_drvdata(pdev, pxakbd);
424 + return input_register_device(pxakbd->input);
427 + platform_set_drvdata(pdev, NULL);
429 + release_resource(r);
431 + free_irq(pxakbd->irq, pxakbd);
433 + kfree(input_dev->keycode);
434 + input_free_device(input_dev);
441 +static int pxakbd_remove(struct platform_device *pdev)
443 + struct pxakbd *pxakbd = platform_get_drvdata(pdev);
445 + kfree(pxakbd->input->keycode);
446 + input_unregister_device(pxakbd->input);
447 + platform_set_drvdata(pdev, NULL);
448 + release_resource(pxakbd->res);
449 + free_irq(pxakbd->irq, pxakbd);
455 +static int pxakbd_suspend(struct platform_device *pdev, pm_message_t state)
457 + struct pxakbd *pxakbd = platform_get_drvdata(pdev);
460 + pxakbd->kpkdi = KPKDI;
465 +static int pxakbd_resume(struct platform_device *pdev)
467 + struct pxakbd *pxakbd = platform_get_drvdata(pdev);
470 + KPKDI = pxakbd->kpkdi;
475 +static struct platform_driver pxakbd_driver = {
476 + .probe = &pxakbd_probe,
477 + .remove = &pxakbd_remove,
478 + .suspend = &pxakbd_suspend,
479 + .resume = &pxakbd_resume,
481 + .name = "pxa-keyboard",
485 +static int __devinit pxakbd_init(void)
487 + return platform_driver_register(&pxakbd_driver);
490 +static void __exit pxakbd_exit(void)
492 + platform_driver_unregister(&pxakbd_driver);
495 +module_init(pxakbd_init);
496 +module_exit(pxakbd_exit);
498 +MODULE_AUTHOR("Harald Welte <laforge@openezx.org>");
499 +MODULE_DESCRIPTION("Driver for Intel PXA27x keypad controller");
500 +MODULE_LICENSE("GPL");
501 Index: linux-2.6.21/include/asm-arm/arch-pxa/pxa-regs.h
502 ===================================================================
503 --- linux-2.6.21.orig/include/asm-arm/arch-pxa/pxa-regs.h 2007-05-17 20:06:01.000000000 +0200
504 +++ linux-2.6.21/include/asm-arm/arch-pxa/pxa-regs.h 2007-05-17 20:06:02.000000000 +0200
505 @@ -2165,6 +2165,11 @@
506 #define KPMK_MKP (0x1 << 31)
507 #define KPAS_SO (0x1 << 31)
508 #define KPASMKPx_SO (0x1 << 31)
509 +#define KPAS_RP (0x000000f0)
510 +#define KPAS_CP (0x0000000f)
511 +#define KPAS_MUKP (0x7c000000)
512 +#define KPAS_MUKP_ONE (0x04000000)
513 +#define KPAS_MUKP_NONE (0x00000000)
516 * UHC: USB Host Controller (OHCI-like) register definitions