83a3585ba2b051f7ac40c1ed27c952a380547068
[openembedded.git] / packages / linux / linux-ezx-2.6.21 / pxa-kbd.patch
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
5 @@ -42,6 +42,7 @@
6  #include <asm/arch/mmc.h>
7  #include <asm/arch/irda.h>
8  #include <asm/arch/i2c.h>
9 +#include <asm/arch/kbd.h>
10  
11  #include "generic.h"
12  
13 @@ -430,6 +431,30 @@
14         .id             = -1,
15  };
16  
17 +static struct resource pxa_kbd_resources[] = {
18 +       {
19 +               .start  = IRQ_KEYPAD,
20 +               .end    = IRQ_KEYPAD,
21 +               .flags  = IORESOURCE_IRQ,
22 +       }, {
23 +               .start  = 0x41500000,
24 +               .end    = 0x4150004c,
25 +               .flags  = IORESOURCE_MEM,
26 +       },
27 +};
28 +
29 +static struct platform_device kbd_device = {
30 +       .name           = "pxa-keyboard",
31 +       .id             = -1,
32 +       .resource       = pxa_kbd_resources,
33 +       .num_resources  = ARRAY_SIZE(pxa_kbd_resources),
34 +};
35 +
36 +void __init pxa_set_kbd_info(struct pxakbd_platform_data *info)
37 +{
38 +       kbd_device.dev.platform_data = info;
39 +}
40 +
41  static struct platform_device *devices[] __initdata = {
42         &pxamci_device,
43         &udc_device,
44 @@ -444,6 +469,7 @@
45  #endif
46         &i2s_device,
47         &pxartc_device,
48 +       &kbd_device,
49  };
50  
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
56 @@ -229,4 +229,11 @@
57           To compile this driver as a module, choose M here: the
58           module will be called gpio-keys.
59  
60 +config KEYBOARD_PXA
61 +       tristate "Intel PXA keyboard support"
62 +       depends on ARCH_PXA
63 +       help
64 +         This add support for a driver of the Intel PXA2xx keyboard
65 +         controller.
66 +
67  endif
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
72 @@ -19,4 +19,4 @@
73  obj-$(CONFIG_KEYBOARD_OMAP)            += omap-keypad.o
74  obj-$(CONFIG_KEYBOARD_AAED2000)                += aaed2000_kbd.o
75  obj-$(CONFIG_KEYBOARD_GPIO)            += gpio_keys.o
76 -
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
82 @@ -0,0 +1,28 @@
83 +/*
84 + *  kbd_pxa.h
85 + *
86 + *  Copyright (C) 2006 Harald Welte <laforge@openezx.org>
87 + *
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.
91 + *
92 + */
93 +#ifndef _KBD_PXA_H_
94 +#define _KBD_PXA_H_
95 +
96 +struct pxakbd_platform_data {
97 +       int (*init)(void);                      /* init gpio, etc. */
98 +       unsigned int scan_interval;
99 +       struct {
100 +               unsigned int rows;
101 +               unsigned int cols;
102 +               unsigned char *keycode;
103 +       } matrix;
104 +       struct {
105 +               unsigned int num;
106 +               unsigned char *keycode;
107 +       } direct;
108 +};
109 +
110 +#endif
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
115 @@ -0,0 +1,385 @@
116 +/*
117 + * Driver for Motorola EZX phone "keyboard"
118 + *
119 + * (C) 2006 by Harald Welte <laforge@openezx.org>
120 + *
121 + * May, 2007 - Daniel Ribeiro <drwyrm@gmail.com>
122 + *             pm callbacks
123 + */
124 +
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>
131 +
132 +#include <asm/hardware.h>
133 +#include <asm/io.h>
134 +#include <asm/irq.h>
135 +
136 +#include <asm/arch/kbd.h>
137 +#include <asm/arch/irqs.h>
138 +#include <asm/arch/pxa-regs.h>
139 +
140 +#if 0
141 +#define DEBUGP(x, args ...) printk(x, ## args)
142 +#else
143 +#define DEBUGP(x, args ...)
144 +#endif
145 +
146 +/* per-keyboard private data structure */
147 +struct pxakbd {
148 +       struct input_dev *input;
149 +       struct timer_list timer;
150 +       spinlock_t lock;
151 +
152 +       struct resource *res;
153 +       unsigned int irq;
154 +       u_int32_t kpc;
155 +       u_int32_t kpkdi;
156 +
157 +       struct pxakbd_platform_data *pd;
158 +};
159 +
160 +static int pxakbd_scan_direct(struct pxakbd *pxakbd)
161 +{
162 +       u_int32_t kpdk;
163 +       unsigned int i;
164 +       int num_pressed = 0;
165 +
166 +       kpdk = KPDK & 0x000000ff;
167 +       for (i = 0; i < pxakbd->pd->direct.num; i++) {
168 +               int pressed = 0;
169 +
170 +               if (kpdk & (1 << i)) {
171 +                       pressed = 1;
172 +                       num_pressed++;
173 +                       DEBUGP("pxakbd: pressed: direct %u\n", i);
174 +               }
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],
178 +                       pressed);
179 +               }
180 +       }
181 +       return num_pressed;
182 +}
183 +
184 +/* read the full 8x8 matrix from the PXA27x keypad controller */
185 +static void __read_matrix(u_int8_t *matrix)
186 +{
187 +       u_int32_t tmp;
188 +
189 +       tmp = KPASMKP0;
190 +       matrix[0] = tmp & 0x000000ff;
191 +       matrix[1] = (tmp & 0x00ff0000) >> 16;
192 +
193 +       tmp = KPASMKP1;
194 +       matrix[2] = tmp & 0x000000ff;
195 +       matrix[3] = (tmp & 0x00ff0000) >> 16;
196 +
197 +       tmp = KPASMKP2;
198 +       matrix[4] = tmp & 0x000000ff;
199 +       matrix[5] = (tmp & 0x00ff0000) >> 16;
200 +
201 +       tmp = KPASMKP3;
202 +       matrix[6] = tmp & 0x000000ff;
203 +       matrix[7] = (tmp & 0x00ff0000) >> 16;
204 +}
205 +
206 +/* compare current matrix with last, generate 'diff' events */
207 +static int __cmp_matrix_gen_events(struct pxakbd *pxakbd, u_int8_t *matrix)
208 +{
209 +       unsigned int i;
210 +       int num_pressed = 0;
211 +
212 +       /* iterate over the matrix */
213 +       for (i = 0; i < pxakbd->pd->matrix.rows; i++) {
214 +               unsigned int j;
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);
219 +
220 +                       if (pressed) {
221 +                               DEBUGP("pxakbd: pressed: %u/%u\n", i, j);
222 +                               num_pressed++;
223 +                       }
224 +
225 +                       input_report_key(pxakbd->input,
226 +                                        pxakbd->pd->matrix.keycode[scancode], pressed);
227 +               }
228 +       }
229 +
230 +       return num_pressed;
231 +}
232 +
233 +/* scan the matrix keypad */
234 +static int pxakbd_scan_matrix(struct pxakbd *pxakbd)
235 +{
236 +       int num_pressed;
237 +       u_int32_t kpas;
238 +       u_int8_t matrix[8];
239 +
240 +       kpas = KPAS;
241 +
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;
249 +
250 +               if (row == 0x0f || col == 0x0f) {
251 +                       printk(KERN_WARNING "pxakbd: col or row invalid!\n");
252 +                       return -1;
253 +               }
254 +
255 +               /* clear the matrix and set the single pressed key */
256 +               memset(matrix, 0, sizeof(matrix));
257 +               matrix[row] |= (1 << col);
258 +       } else {
259 +               /* multiple keys pressed */
260 +               __read_matrix(matrix);
261 +       }
262 +
263 +       num_pressed = __cmp_matrix_gen_events(pxakbd, matrix);
264 +
265 +       return num_pressed;
266 +}
267 +
268 +static void pxakbd_timer_callback(unsigned long data)
269 +{
270 +       unsigned long flags;
271 +       struct pxakbd *pxakbd = (struct pxakbd *) data;
272 +       unsigned int num_pressed;
273 +
274 +       spin_lock_irqsave(&pxakbd->lock, flags);
275 +
276 +       num_pressed = pxakbd_scan_direct(pxakbd);
277 +       num_pressed += pxakbd_scan_matrix(pxakbd);
278 +
279 +       spin_unlock_irqrestore(&pxakbd->lock, flags);
280 +
281 +       /* propagate events up the input stack */
282 +       input_sync(pxakbd->input);
283 +}
284 +
285 +static irqreturn_t pxakbd_interrupt(int irq, void *dummy)
286 +{
287 +       struct pxakbd *pxakbd = dummy;
288 +       u_int32_t kpc;
289 +       int handled = 0;
290 +       int num_pressed = 0;
291 +
292 +       /* read and clear interrupt */
293 +       kpc = KPC;
294 +
295 +       if (kpc & KPC_DI) {
296 +               num_pressed += pxakbd_scan_direct(pxakbd);
297 +               handled = 1;
298 +       }
299 +
300 +       if (kpc & KPC_MI) {
301 +               while (KPAS & KPAS_SO) {
302 +                       /* wait for scan to complete beforereading scan regs */
303 +                       cpu_relax();
304 +               }
305 +               num_pressed += pxakbd_scan_matrix(pxakbd);
306 +               handled = 1;
307 +       }
308 +
309 +       /* If any keys are currently pressed, we need to start the timer to detect
310 +        * key release. */
311 +       if (num_pressed)
312 +               mod_timer(&pxakbd->timer, jiffies + pxakbd->pd->scan_interval);
313 +
314 +       /* propagate events up the input stack */
315 +       input_sync(pxakbd->input);
316 +
317 +       return IRQ_RETVAL(handled);
318 +}
319 +
320 +static int __init pxakbd_probe(struct platform_device *pdev)
321 +{
322 +       struct pxakbd *pxakbd;
323 +       struct input_dev *input_dev;
324 +       struct resource *r;
325 +       int i;
326 +       int ret = -ENOMEM;
327 +
328 +       int rows, cols, n_direct;
329 +
330 +       pxakbd = kzalloc(sizeof(*pxakbd), GFP_KERNEL);
331 +       if (!pxakbd)
332 +               goto out;
333 +
334 +       input_dev = input_allocate_device();
335 +       if (!input_dev)
336 +               goto out_pxa;
337 +
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");
343 +               ret = -EBUSY;
344 +               goto out_idev;
345 +       }
346 +
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;
352 +       pxakbd->res = r;
353 +
354 +       rows = pxakbd->pd->matrix.rows;
355 +       cols = pxakbd->pd->matrix.cols;
356 +       n_direct = pxakbd->pd->direct.num;
357 +
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;
366 +
367 +       input_dev->evbit[0] = BIT(EV_KEY)|BIT(EV_REP);
368 +
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,
372 +                     GFP_KERNEL);
373 +       if (!input_dev->keycode){
374 +              ret = -ENOMEM;
375 +              goto out_idev;
376 +       }
377 +
378 +       memcpy(input_dev->keycode, pxakbd->pd->matrix.keycode, rows*cols);
379 +
380 +       memcpy(input_dev->keycode+(rows*cols),
381 +                     pxakbd->pd->direct.keycode,
382 +                     n_direct);
383 +
384 +       for (i = 0; i < rows*cols; i++)
385 +               set_bit(pxakbd->pd->matrix.keycode[i], input_dev->keybit);
386 +
387 +       for (i = 0; i < n_direct; i++)
388 +               set_bit(pxakbd->pd->direct.keycode[i], input_dev->keybit);
389 +
390 +       clear_bit(0, input_dev->keybit);
391 +
392 +       if (request_irq(pxakbd->irq, pxakbd_interrupt, 0, "pxakbd", pxakbd)) {
393 +               printk(KERN_ERR "pxakbd: can't request irq %d\n", pxakbd->irq);
394 +               ret = -EBUSY;
395 +               goto out_idev;
396 +       }
397 +
398 +       r = request_mem_region(r->start, 0x4c, "pxakbd");
399 +       if (!r) {
400 +               printk(KERN_ERR "pxakbd: can't request memregion\n");
401 +               ret = -EBUSY;
402 +               goto out_irq;
403 +       }
404 +
405 +       /* set up gpio */
406 +       pxakbd->pd->init();
407 +
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 */
415 +
416 +       pxa_set_cken(CKEN19_KEYPAD, 1);
417 +
418 +       KPC |= (KPC_DIE | KPC_MIE); /* enable matrix and direct keyboard */
419 +
420 +       KPKDI = 0x40;   /* matrix key debounce interval: 0x40 */
421 +
422 +       platform_set_drvdata(pdev, pxakbd);
423 +
424 +       return input_register_device(pxakbd->input);
425 +
426 +out_drvdata:
427 +       platform_set_drvdata(pdev, NULL);
428 +out_mem:
429 +       release_resource(r);
430 +out_irq:
431 +       free_irq(pxakbd->irq, pxakbd);
432 +out_idev:
433 +       kfree(input_dev->keycode);
434 +       input_free_device(input_dev);
435 +out_pxa:
436 +       kfree(pxakbd);
437 +out:
438 +       return ret;
439 +}
440 +
441 +static int pxakbd_remove(struct platform_device *pdev)
442 +{
443 +       struct pxakbd *pxakbd = platform_get_drvdata(pdev);
444 +
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);
450 +       kfree(pxakbd);
451 +
452 +       return 0;
453 +}
454 +
455 +static int pxakbd_suspend(struct platform_device *pdev, pm_message_t state)
456 +{
457 +       struct pxakbd *pxakbd = platform_get_drvdata(pdev);
458 +
459 +       pxakbd->kpc = KPC;
460 +       pxakbd->kpkdi = KPKDI;
461 +
462 +       return 0;
463 +}
464 +
465 +static int pxakbd_resume(struct platform_device *pdev)
466 +{
467 +       struct pxakbd *pxakbd = platform_get_drvdata(pdev);
468 +
469 +       KPC = pxakbd->kpc;
470 +       KPKDI = pxakbd->kpkdi;
471 +
472 +       return 0;
473 +}
474 +
475 +static struct platform_driver pxakbd_driver = {
476 +       .probe          = &pxakbd_probe,
477 +       .remove         = &pxakbd_remove,
478 +       .suspend        = &pxakbd_suspend,
479 +       .resume         = &pxakbd_resume,
480 +       .driver         = {
481 +               .name   = "pxa-keyboard",
482 +       },
483 +};
484 +
485 +static int __devinit pxakbd_init(void)
486 +{
487 +       return platform_driver_register(&pxakbd_driver);
488 +}
489 +
490 +static void __exit pxakbd_exit(void)
491 +{
492 +       platform_driver_unregister(&pxakbd_driver);
493 +}
494 +
495 +module_init(pxakbd_init);
496 +module_exit(pxakbd_exit);
497 +
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)
514  
515  /*
516   * UHC: USB Host Controller (OHCI-like) register definitions