> From: Marek Vasut <marek.va...@gmail.com>
> 
> Signed-off-by: Marek Vasut <marek.va...@gmail.com>
> Signed-off-by: Vasily Khoruzhick <anars...@gmail.com>
> [vasily: adapted Marek's old version for newer u-boot,
>          fixed multiple keypresses handling]
> ---
> v2: use struct-based access to regs, minor cleanup
> v3: fix multiple keypresses handling, minor cleanup
> 
>  arch/arm/include/asm/arch-pxa/pxa-regs.h    |   52 -----
>  arch/arm/include/asm/arch-pxa/regs-keypad.h |   84 ++++++++
>  drivers/input/Makefile                      |    2 +
>  drivers/input/pxa27x-mkp.c                  |  301
> +++++++++++++++++++++++++++ 4 files changed, 387 insertions(+), 52
> deletions(-)
>  create mode 100644 arch/arm/include/asm/arch-pxa/regs-keypad.h
>  create mode 100644 drivers/input/pxa27x-mkp.c
> 
> diff --git a/arch/arm/include/asm/arch-pxa/pxa-regs.h
> b/arch/arm/include/asm/arch-pxa/pxa-regs.h index b81b42c..d562658 100644
> --- a/arch/arm/include/asm/arch-pxa/pxa-regs.h
> +++ b/arch/arm/include/asm/arch-pxa/pxa-regs.h
> @@ -2567,58 +2567,6 @@ typedef void           (*ExcpHndlr) (void) ;
>  #define OVL2C1_O2EN  (1<<31)         /* Enable bit for Overlay 2 */
>  #define CCR_CEN              (1<<31)         /* Enable bit for Cursor */
> 
> -/* Keypad controller */
> -
> -#define KPC          0x41500000 /* Keypad Interface Control register */
> -#define KPDK         0x41500008 /* Keypad Interface Direct Key register */
> -#define KPREC                0x41500010 /* Keypad Intefcace Rotary Encoder 
register */
> -#define KPMK         0x41500018 /* Keypad Intefcace Matrix Key register */
> -#define KPAS         0x41500020 /* Keypad Interface Automatic Scan register 
*/
> -#define KPASMKP0     0x41500028 /* Keypad Interface Automatic Scan Multiple
> Key Presser register 0 */ -#define KPASMKP1   0x41500030 /* Keypad Interface
> Automatic Scan Multiple Key Presser register 1 */ -#define
> KPASMKP2      0x41500038 /* Keypad Interface Automatic Scan Multiple Key
> Presser register 2 */ -#define KPASMKP3       0x41500040 /* Keypad Interface
> Automatic Scan Multiple Key Presser register 3 */ -#define
> KPKDI         0x41500048 /* Keypad Interface Key Debounce Interval register 
> */ 
-
> -#define KPC_AS               (0x1 << 30)  /* Automatic Scan bit */
> -#define KPC_ASACT    (0x1 << 29)  /* Automatic Scan on Activity */
> -#define KPC_MI               (0x1 << 22)  /* Matrix interrupt bit */
> -#define KPC_IMKP     (0x1 << 21)  /* Ignore Multiple Key Press */
> -#define KPC_MS7              (0x1 << 20)  /* Matrix scan line 7 */
> -#define KPC_MS6              (0x1 << 19)  /* Matrix scan line 6 */
> -#define KPC_MS5              (0x1 << 18)  /* Matrix scan line 5 */
> -#define KPC_MS4              (0x1 << 17)  /* Matrix scan line 4 */
> -#define KPC_MS3              (0x1 << 16)  /* Matrix scan line 3 */
> -#define KPC_MS2              (0x1 << 15)  /* Matrix scan line 2 */
> -#define KPC_MS1              (0x1 << 14)  /* Matrix scan line 1 */
> -#define KPC_MS0              (0x1 << 13)  /* Matrix scan line 0 */
> -#define KPC_ME               (0x1 << 12)  /* Matrix Keypad Enable */
> -#define KPC_MIE              (0x1 << 11)  /* Matrix Interrupt Enable */
> -#define KPC_DK_DEB_SEL       (0x1 <<  9)  /* Direct Key Debounce select */
> -#define KPC_DI               (0x1 <<  5)  /* Direct key interrupt bit */
> -#define KPC_DEE0     (0x1 <<  2)  /* Rotary Encoder 0 Enable */
> -#define KPC_DE               (0x1 <<  1)  /* Direct Keypad Enable */
> -#define KPC_DIE              (0x1 <<  0)  /* Direct Keypad interrupt Enable 
*/
> -
> -#define KPDK_DKP     (0x1 << 31)
> -#define KPDK_DK7     (0x1 <<  7)
> -#define KPDK_DK6     (0x1 <<  6)
> -#define KPDK_DK5     (0x1 <<  5)
> -#define KPDK_DK4     (0x1 <<  4)
> -#define KPDK_DK3     (0x1 <<  3)
> -#define KPDK_DK2     (0x1 <<  2)
> -#define KPDK_DK1     (0x1 <<  1)
> -#define KPDK_DK0     (0x1 <<  0)
> -
> -#define KPREC_OF1    (0x1 << 31)
> -#define kPREC_UF1    (0x1 << 30)
> -#define KPREC_OF0    (0x1 << 15)
> -#define KPREC_UF0    (0x1 << 14)
> -
> -#define KPMK_MKP     (0x1 << 31)
> -#define KPAS_SO              (0x1 << 31)
> -#define KPASMKPx_SO  (0x1 << 31)
> -
>  #define GPIO113_BIT  (1 << 17)/* GPIO113 in GPSR, GPCR, bit 17 */
>  #define PSLR         0x40F00034
>  #define PSTR         0x40F00038  /* Power Manager Standby Configuration Reg 
*/
> diff --git a/arch/arm/include/asm/arch-pxa/regs-keypad.h
> b/arch/arm/include/asm/arch-pxa/regs-keypad.h new file mode 100644
> index 0000000..f13da56
> --- /dev/null
> +++ b/arch/arm/include/asm/arch-pxa/regs-keypad.h
> @@ -0,0 +1,84 @@
> +/*
> + * Copyright (C) 2012 Vasily Khoruzhick <anars...@gmail.com>
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation; either version 2 of
> + * the License, or (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
> + * MA 02111-1307 USA
> + */
> +
> +#ifndef __REGS_KEYPAD_H__
> +#define __REGS_KEYPAD_H__
> +
> +#define KEYPAD_BASE  0x41500000
> +
> +struct kpasmkp_regs {
> +     uint32_t        kpasmkpx;
> +     uint32_t        reserved;
> +};
> +
> +struct pxa_keypad_regs {
> +     uint32_t                kpc;
> +     uint32_t                reserved_1;
> +     uint32_t                kpdk;
> +     uint32_t                reserved_2;
> +     uint32_t                kprec;
> +     uint32_t                reserved_3;
> +     uint32_t                kpmk;
> +     uint32_t                reserved_4;
> +     uint32_t                kpas;
> +     uint32_t                reserved_5;
> +     struct kpasmkp_regs     kpasmkp[4];
> +     uint32_t                kpkdi;
> +};
> +
> +#define KPC_AS               (0x1 << 30)  /* Automatic Scan bit */
> +#define KPC_ASACT    (0x1 << 29)  /* Automatic Scan on Activity */
> +#define KPC_MI               (0x1 << 22)  /* Matrix interrupt bit */
> +#define KPC_IMKP     (0x1 << 21)  /* Ignore Multiple Key Press */
> +#define KPC_MS7              (0x1 << 20)  /* Matrix scan line 7 */
> +#define KPC_MS6              (0x1 << 19)  /* Matrix scan line 6 */
> +#define KPC_MS5              (0x1 << 18)  /* Matrix scan line 5 */
> +#define KPC_MS4              (0x1 << 17)  /* Matrix scan line 4 */
> +#define KPC_MS3              (0x1 << 16)  /* Matrix scan line 3 */
> +#define KPC_MS2              (0x1 << 15)  /* Matrix scan line 2 */
> +#define KPC_MS1              (0x1 << 14)  /* Matrix scan line 1 */
> +#define KPC_MS0              (0x1 << 13)  /* Matrix scan line 0 */
> +#define KPC_ME               (0x1 << 12)  /* Matrix Keypad Enable */
> +#define KPC_MIE              (0x1 << 11)  /* Matrix Interrupt Enable */
> +#define KPC_DK_DEB_SEL       (0x1 <<  9)  /* Direct Key Debounce select */
> +#define KPC_DI               (0x1 <<  5)  /* Direct key interrupt bit */
> +#define KPC_DEE0     (0x1 <<  2)  /* Rotary Encoder 0 Enable */
> +#define KPC_DE               (0x1 <<  1)  /* Direct Keypad Enable */
> +#define KPC_DIE              (0x1 <<  0)  /* Direct Keypad interrupt Enable 
*/
> +
> +#define KPDK_DKP     (0x1 << 31)
> +#define KPDK_DK7     (0x1 <<  7)
> +#define KPDK_DK6     (0x1 <<  6)
> +#define KPDK_DK5     (0x1 <<  5)
> +#define KPDK_DK4     (0x1 <<  4)
> +#define KPDK_DK3     (0x1 <<  3)
> +#define KPDK_DK2     (0x1 <<  2)
> +#define KPDK_DK1     (0x1 <<  1)
> +#define KPDK_DK0     (0x1 <<  0)

Drop those two spaces here

> +
> +#define KPREC_OF1    (0x1 << 31)
> +#define kPREC_UF1    (0x1 << 30)
> +#define KPREC_OF0    (0x1 << 15)
> +#define KPREC_UF0    (0x1 << 14)
> +
> +#define KPMK_MKP     (0x1 << 31)
> +#define KPAS_SO              (0x1 << 31)
> +#define KPASMKPx_SO  (0x1 << 31)
> +
> +#endif
> diff --git a/drivers/input/Makefile b/drivers/input/Makefile
> index 1f4dad3..792d29d 100644
> --- a/drivers/input/Makefile
> +++ b/drivers/input/Makefile
> @@ -31,6 +31,8 @@ COBJS-y += keyboard.o pc_keyb.o
>  COBJS-$(CONFIG_PS2MULT) += ps2mult.o ps2ser.o
>  endif
> 
> +COBJS-$(CONFIG_PXA27X_MKP) += pxa27x-mkp.o
> +
>  COBJS        := $(COBJS-y)
>  SRCS := $(COBJS:.o=.c)
>  OBJS := $(addprefix $(obj),$(COBJS))
> diff --git a/drivers/input/pxa27x-mkp.c b/drivers/input/pxa27x-mkp.c
> new file mode 100644
> index 0000000..013b6fe
> --- /dev/null
> +++ b/drivers/input/pxa27x-mkp.c
> @@ -0,0 +1,301 @@
> +/*
> + * PXA27x matrix keypad controller driver
> + *
> + * Copyright (C) 2010 Marek Vasut <marek.va...@gmail.com>
> + * Copyright (C) 2012 Vasily Khoruzhick <anars...@gmail.com>
> + *
> + * See file CREDITS for list of people who contributed to this
> + * project.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation; either version 2 of
> + * the License, or (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
> + * MA 02111-1307 USA
> + */
> +
> +#include <common.h>
> +#include <stdio_dev.h>
> +#include <asm/arch/regs-keypad.h>
> +#include <asm/io.h>
> +
> +#define      DEVNAME         "pxa27x-mkp"
> +
> +struct {
> +     char    row;
> +     char    col;
> +     char    key;
> +     char    shift;
> +     char    alt;
> +     char    ctrl;
> +} keymap[] = {
> +     CONFIG_PXA27X_MKP_KEYMAP,
> +};
> +
> +static unsigned char queue[64] = {0};
> +static int queue_len;
> +static struct pxa_keypad_regs *regs;

You can as well assign it here.

> +
> +/* autorepeat stuff */
> +static int last_key_row = 0xff, last_key_col = 0xff;
> +static char key_counter;
> +
> +/* number of key scans before autorepeat kicks in */
> +#ifndef CONFIG_PXA27X_KEY_REPEAT_FIRST
> +#define      CONFIG_PXA27X_KEY_REPEAT_FIRST  12
> +#endif
> +#ifndef CONFIG_PXA27X_KEY_REPEAT_NEXT
> +#define      CONFIG_PXA27X_KEY_REPEAT_NEXT   2
> +#endif
> +
> +/* 100 milliseconds (in wait cycles below it's 100 x 10uS waits) */
> +#define PXA_KEYPAD_TIMEOUT   10000
> +
> +enum {
> +     MOD_NONE,
> +     MOD_SHIFT,
> +     MOD_ALT,
> +     MOD_CTRL,
> +};
> +
> +static int kbd_get_mdf(int row, int col)
> +{
> +     char mod_shift[2] = CONFIG_PXA27X_MKP_MOD_SHIFT;
> +     char mod_alt[2] = CONFIG_PXA27X_MKP_MOD_ALT;
> +     char mod_ctrl[2] = CONFIG_PXA27X_MKP_MOD_CTRL;
> +
> +     if (mod_shift[0] == row && mod_shift[1] == col)
> +             return MOD_SHIFT;
> +     if (mod_alt[0] == row && mod_alt[1] == col)
> +             return MOD_ALT;
> +     if (mod_ctrl[0] == row && mod_ctrl[1] == col)
> +             return MOD_CTRL;
> +     return MOD_NONE;
> +}
> +
> +static int kbd_lookup(int row, int col, int mod)
> +{
> +     int i = 0;
> +     char key = 0xff;
> +
> +     while (!(keymap[i].col == 0xff && keymap[i].row == 0xff)) {
> +             if (keymap[i].row != row || keymap[i].col != col) {
> +                     i++;
> +                     continue;
> +             }
> +             switch (mod) {
> +             case MOD_NONE:
> +                     key = keymap[i].key;
> +                     break;
> +             case MOD_SHIFT:
> +                     key = keymap[i].shift;
> +                     break;
> +             case MOD_ALT:
> +                     key = keymap[i].alt;
> +                     break;
> +             case MOD_CTRL:
> +                     key = keymap[i].ctrl;
> +                     break;
> +             }
> +             if (key == 0xff) {
> +                     i++;
> +                     continue;
> +             }
> +
> +             if (row != last_key_row || col != last_key_col) {
> +                     queue[queue_len++] = key;
> +                     last_key_row = row;
> +                     last_key_col = col;
> +                     key_counter = 0;
> +             } else /* same key as before */
> +                     if (key_counter < CONFIG_PXA27X_KEY_REPEAT_FIRST) {
> +                             /* ignore key press */
> +                             key_counter++;
> +                     } else {
> +                             /* ok, autorepeat */
> +                             queue[queue_len++] = key;
> +                             key_counter = CONFIG_PXA27X_KEY_REPEAT_FIRST
> +                                     - CONFIG_PXA27X_KEY_REPEAT_NEXT;
> +                     }
> +             i++;
> +     }
> +     return key;
> +}
> +
> +static int scan_keys(int scan_modif, uint32_t kpasmkp[4])
> +{
> +     uint32_t reg = 0;
> +     int col, row;
> +     static int mod = MOD_NONE;

Are you sure you know what you're doing using all those static vars all around?

> +     int key;
> +     for (col = 0; col < 8; col += 2) {
> +             reg = kpasmkp[col >> 1];
> +             for (row = 0; row < 8; row++) {
> +                     if (reg & (1 << row)) {
> +                             if (scan_modif) {
> +                                     mod = kbd_get_mdf(row, col);
> +                                     if (mod != MOD_NONE)
> +                                             return mod;
> +                             } else {
> +                                     key = kbd_lookup(row, col, mod);
> +                                     if (key != 0xff)
> +                                             return key;
> +                             }
> +                     }
> +                     if ((reg >> 16) & (1 << row)) {
> +                             if (scan_modif) {
> +                                     mod = kbd_get_mdf(row, col + 1);
> +                                     if (mod != MOD_NONE)
> +                                             return mod;
> +                             } else {
> +                                     key = kbd_lookup(row, col + 1, mod);
> +                                     if (key != 0xff)
> +                                             return key;
> +                             }

Can you do some elegant solution of this code duplication?

> +                     }
> +             }
> +     }

Newline

> +     if (scan_modif)
> +             return MOD_NONE;
> +     else
> +             return 0xff;
> +}
> +
> +static void kbd_read(void)
> +{
> +     uint32_t reg;
> +     int col, row, i, have_new_key = 0;
> +     int numkeys;
> +     int mod = MOD_NONE;
> +     unsigned int timeout = PXA_KEYPAD_TIMEOUT;
> +     static uint32_t kpasmkp_old[4];
> +     uint32_t kpasmkp[4], kpasmkp_diff[4];
> +
> +     /* start one automatic scan */
> +     writel(readl(&regs->kpc) | KPC_AS, &regs->kpc);
> +
> +     /* wait for scan to finish */
> +     while (timeout--) {
> +             if (!(readl(&regs->kpc) & KPC_AS))
> +                     break;
> +             udelay(10);

Use WATCHDOG_RESET()

> +     }
> +
> +     if (!timeout)
> +             return;
> +
> +     numkeys = (readl(&regs->kpas) >> 26) & 0x1f;
> +     switch (numkeys) {
> +     case 0:
> +             /* no key pressed, clear autorepeat counter */
> +             key_counter = 0;
> +             last_key_row = last_key_col = 0xff;
> +             for (i = 0; i < ARRAY_SIZE(kpasmkp); i++)
> +                     kpasmkp[i] = 0;
> +             break;
> +     case 1:
> +             reg = readl(&regs->kpas) & 0xff;
> +             col = reg & 0x0f;
> +             row = reg >> 4;
> +             for (i = 0; i < ARRAY_SIZE(kpasmkp); i++)
> +                     kpasmkp[i] = 0;
> +             kpasmkp[col >> 1] |= (1 << (row + 16 * (col % 2)));
> +
> +             break;
> +     default:
> +             for (i = 0; i < ARRAY_SIZE(kpasmkp); i++) {
> +                     timeout = PXA_KEYPAD_TIMEOUT;
> +                     while (timeout--) {
> +                             kpasmkp[i] = readl(&regs->kpasmkp[i].kpasmkpx);
> +                             if (!(kpasmkp[i] & KPASMKPx_SO))
> +                                     break;
> +                             udelay(10);
> +                     }
> +                     if (!timeout)
> +                             kpasmkp[i] = 0;
> +             }
> +             break;
> +     }
> +
> +     /* Find new keypress */
> +     for (i = 0; i < ARRAY_SIZE(kpasmkp); i++) {
> +             kpasmkp_diff[i] = (kpasmkp_old[i] ^ kpasmkp[i]) &
> +                     kpasmkp[i];
> +             if (kpasmkp_diff[i])
> +                     have_new_key = 1;
> +             kpasmkp_old[i] = kpasmkp[i];
> +     }
> +
> +     if (!numkeys)
> +             return;
> +
> +     /* Scan for modifiers */
> +     mod = scan_keys(1, kpasmkp);
> +     if (!have_new_key) {
> +             /* Check if old key is still pressed */
> +             if (kpasmkp[last_key_col >> 1] &
> +                (1 << (last_key_row + 16 * (last_key_col % 2))))
> +                     kbd_lookup(last_key_row, last_key_col, mod);
> +             serial_printf("No new key\n");
> +
> +     } else {
> +             key_counter = 0;
> +             last_key_row = last_key_col = 0xff;
> +             scan_keys(0, kpasmkp_diff);
> +             serial_printf("New key\n");

What's this dammit? And above too! Use debug() if you need it.

> +     }
> +}
> +
> +static int kbd_getc(void)
> +{
> +     if (!queue_len) {
> +             kbd_read();
> +             udelay(CONFIG_PXA27X_MKP_DELAY);
> +     }
> +
> +     if (queue_len)
> +             return queue[--queue_len];
> +     else
> +             return 0;
> +}
> +
> +static int kbd_testc(void)
> +{
> +     if (!queue_len)
> +             kbd_read();
> +     return queue_len;
> +}
> +
> +int drv_keyboard_init(void)
> +{
> +     int error = 0;
> +     struct stdio_dev kbddev;
> +
> +     regs = (struct pxa_keypad_regs *)KEYPAD_BASE;

See above

> +     queue_len = 0;
> +
> +     writel((CONFIG_PXA27X_MKP_MKP_ROWS << 26) |
> +             (CONFIG_PXA27X_MKP_MKP_COLS << 23) |
> +             (0xff << 13) | KPC_ME, &regs->kpc);
> +     writel(CONFIG_PXA27X_MKP_DEBOUNCE, &regs->kpkdi);
> +
> +     memset(&kbddev, 0, sizeof(kbddev));
> +     strcpy(kbddev.name, DEVNAME);
> +     kbddev.flags =  DEV_FLAGS_INPUT | DEV_FLAGS_SYSTEM;
> +     kbddev.putc = NULL ;
> +     kbddev.puts = NULL ;
> +     kbddev.getc = kbd_getc ;
> +     kbddev.tstc = kbd_testc ;

Drop spaces before semicolon

> +
> +     error = stdio_register(&kbddev);
> +     return error;
> +}
_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot

Reply via email to