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]
---
v2: use struct-based access to regs, 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                  |  245 +++++++++++++++++++++++++++
 4 files changed, 331 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)
+
+#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..f72db41
--- /dev/null
+++ b/drivers/input/pxa27x-mkp.c
@@ -0,0 +1,245 @@
+/*
+ * PXA27x matrix keypad controller driver
+ *
+ * Copyright (C) 2010 Marek Vasut <marek.va...@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;
+
+/* autorepeat stuff */
+static unsigned char last_key = 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
+
+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 void kbd_lookup(int row, int col, int mod)
+{
+       int i = 0;
+       static char key = 0xff;
+
+       while (!(keymap[i].col == 0xff && keymap[i].row == 0xff)) {
+               if (keymap[i].row == row && keymap[i].col == col) {
+                       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)
+                               continue;
+
+                       if (key != last_key) {
+                               queue[queue_len++] = key;
+                               last_key = key;
+                               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++;
+       }
+}
+
+static void scan_keys(int modif)
+{
+       uint32_t reg;
+       int col, row;
+       int mod = MOD_NONE;
+       for (col = 0; col < 8; col += 2) {
+               while ((reg = readl(&regs->kpasmkp[col >> 1].kpasmkpx))
+                       & KPASMKPx_SO)
+                       ;
+               for (row = 0; row < 8; row++) {
+                       if (reg & (1 << row)) {
+                               if (modif) {
+                                       mod = kbd_get_mdf(row, col);
+                                       if (mod != MOD_NONE)
+                                               return;
+                               } else
+                                       kbd_lookup(row, col, mod);
+                       }
+                       if ((reg >> 16) & (1 << row)) {
+                               if (modif) {
+                                       mod = kbd_get_mdf(row, col + 1);
+                                       if (mod != MOD_NONE)
+                                               return;
+                               } else
+                                       kbd_lookup(row, col + 1, mod);
+                       }
+               }
+       }
+}
+
+static void kbd_read(void)
+{
+       uint32_t reg;
+       int col, row;
+       int modif = 0;
+       int numkeys;
+       int mod = MOD_NONE;
+
+       /* start one automatic scan */
+       writel(readl(&regs->kpc) | KPC_AS, &regs->kpc);
+
+       /* wait for scan to finish */
+       while (readl(&regs->kpc) & KPC_AS)
+               ;
+
+       numkeys = (readl(&regs->kpas) >> 26) & 0x1f;
+       switch (numkeys) {
+       case 0:
+               /* no key pressed, clear autorepeat counter */
+               last_key = 0xff;
+               key_counter = 0;
+               break;
+       case 1:
+               reg = readl(&regs->kpas) & 0xff;
+               col = reg & 0x0f;
+               row = reg >> 4;
+               if (kbd_get_mdf(row, col) != MOD_NONE) {
+                       /* modifier only */
+                       last_key = 0xff;
+                       /* no real key, clear autorepeat counter */
+                       key_counter = 0;
+               } else
+                       kbd_lookup(row, col, mod);
+               break;
+       default:
+               /* multiple keys pressed, check KPASMKPx registers */
+               /* First scan for modifiers */
+               scan_keys(1);
+               /* Second for other keys */
+               scan_keys(0);
+               break;
+       }
+}
+
+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;
+       if (!keymap)
+               return -1;
+
+       regs = (struct pxa_keypad_regs *)KEYPAD_BASE;
+       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 ;
+
+       error = stdio_register(&kbddev);
+       return error;
+}
-- 
1.7.8.3

_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot

Reply via email to