[U-Boot] [PATCH v5 1/3] PXA: PXA27x Matrix keypad driver

From: Marek Vasut marek.vasut@gmail.com
Signed-off-by: Marek Vasut marek.vasut@gmail.com Signed-off-by: Vasily Khoruzhick anarsoul@gmail.com --- v2: use struct-based access to regs, minor cleanup v3: fix multiple keypresses handling, minor cleanup v4: another minor cleanup v5: fix indentation issues in scan_keys(), remove udelay, increase PXA_KEYPAD_TIMEOUT (due to removed udelay)
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 | 292 +++++++++++++++++++++++++++ 4 files changed, 378 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..1909417 --- /dev/null +++ b/arch/arm/include/asm/arch-pxa/regs-keypad.h @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2012 Vasily Khoruzhick anarsoul@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..0c9a905 --- /dev/null +++ b/drivers/input/pxa27x-mkp.c @@ -0,0 +1,292 @@ +/* + * PXA27x matrix keypad controller driver + * + * Copyright (C) 2010 Marek Vasut marek.vasut@gmail.com + * Copyright (C) 2012 Vasily Khoruzhick anarsoul@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 = (struct pxa_keypad_regs *)KEYPAD_BASE; + +/* 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 + +/* Number of cycles to wait */ +#define PXA_KEYPAD_TIMEOUT 100000 + +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; + int key; + for (col = 0; col < 8; col += 1) { + reg = kpasmkp[col >> 1]; + reg >>= 16 * (col % 2); + for (row = 0; row < 8; row++) { + if (!(reg & (1 << row))) + continue; + + 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 (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(®s->kpc) | KPC_AS, ®s->kpc); + + /* wait for scan to finish */ + while (timeout--) { + if (!(readl(®s->kpc) & KPC_AS)) + break; +#if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG) + WATCHDOG_RESET(); +#endif + } + + if (!timeout) + return; + + numkeys = (readl(®s->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(®s->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(®s->kpasmkp[i].kpasmkpx); + if (!(kpasmkp[i] & KPASMKPx_SO)) + break; +#if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG) + WATCHDOG_RESET(); +#endif + } + 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); + + } else { + key_counter = 0; + last_key_row = last_key_col = 0xff; + scan_keys(0, kpasmkp_diff); + } +} + +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; + + writel((CONFIG_PXA27X_MKP_MKP_ROWS << 26) | + (CONFIG_PXA27X_MKP_MKP_COLS << 23) | + (0xff << 13) | KPC_ME, ®s->kpc); + writel(CONFIG_PXA27X_MKP_DEBOUNCE, ®s->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; +}

Signed-off-by: Vasily Khoruzhick anarsoul@gmail.com --- v2: remove usbtty stuff from EXTRA_ENV_SETTINGS v3: shift+backspace should produce backspace code v4: no change v5: prettify CONFIG_PXA27X_MKP_KEYMAP
include/configs/zipitz2.h | 82 ++++++++++++++++++++++++++++++++++++++++++--- 1 files changed, 77 insertions(+), 5 deletions(-)
diff --git a/include/configs/zipitz2.h b/include/configs/zipitz2.h index 26204af..615f9bc 100644 --- a/include/configs/zipitz2.h +++ b/include/configs/zipitz2.h @@ -80,6 +80,12 @@ #define CONFIG_CMD_MMC #define CONFIG_CMD_SPI
+#define CONFIG_EXTRA_ENV_SETTINGS \ + "stdout=lcd\0" \ + "stdin=pxa27x-mkp\0" \ + "stderr=lcd\0" \ + "" +#define CONFIG_KEYBOARD /* * MMC Card Configuration */ @@ -206,15 +212,81 @@ unsigned char zipitz2_spi_read(void); #define CONFIG_SYS_FLASH_PROTECTION
/* + * Matrix keypad + */ +#ifdef CONFIG_KEYBOARD +#define CONFIG_PXA27X_MKP + +#define CONFIG_PXA27X_MKP_MKP_COLS 7 +#define CONFIG_PXA27X_MKP_MKP_ROWS 6 + +#define CONFIG_PXA27X_MKP_DEBOUNCE 30 +#define CONFIG_PXA27X_MKP_DELAY 30000 + +#define CONFIG_PXA27X_MKP_MOD_SHIFT {5, 3} +#define CONFIG_PXA27X_MKP_MOD_ALT {5, 2} +#define CONFIG_PXA27X_MKP_MOD_CTRL {5, 4} + +#define CONFIG_PXA27X_MKP_KEYMAP \ + { 1, 1, 'q', 'Q', '1', 0xff }, \ + { 2, 1, 'i', 'I', '8', 0xff }, \ + { 3, 1, 'g', 'G', '"', 0xff }, \ + { 4, 1, 'x', 'X', '/', 0xff }, \ + { 5, 1, '\r', 0xff, 0xff, 0xff }, \ + { 6, 1, '-', 0xff, 0xff, 0xff }, \ + \ + { 1, 2, 'w', 'W', '2', 0xff }, \ + { 2, 2, 'o', 'O', '9', 0xff }, \ + { 3, 2, 'h', 'H', ''', 0xff }, \ + { 4, 2, 'c', 'C', '+', 0xff }, \ + \ + { 1, 3, 'e', 'E', '3', 0xff }, \ + { 2, 3, 'p', 'P', '0', 0xff }, \ + { 3, 3, 'j', 'J', '[', 0xff }, \ + { 4, 3, 'v', 'V', '*', 0xff }, \ + \ + { 0, 4, '\e', 0xff, '|', 0xff }, \ + { 1, 4, 'r', 'R', '4', 0xff }, \ + { 2, 4, 'a', 'A', '$', 0xff }, \ + { 3, 4, 'k', 'K', ']', 0xff }, \ + { 4, 4, 'b', 'B', '=', 0xff }, \ + \ + { 0, 5, '\t', 0xff, 0xff, 0xff }, \ + { 1, 5, 't', 'T', '5', 0xff }, \ + { 2, 5, 's', 'S', '#', 0xff }, \ + { 3, 5, 'l', 'L', '-', 0xff }, \ + { 4, 5, 'n', 'N', '_', 0xff }, \ + { 5, 5, ' ', 0xff, 0xff, 0xff }, \ + \ + { 1, 6, 'y', 'Y', '6', 0xff }, \ + { 2, 6, 'd', 'D', '&', 0xff }, \ + { 3, 6, '\b', '\b', '\', 0xff }, \ + { 4, 6, 'm', 'M', '?', 0xff }, \ + { 5, 6, ',', '(', '<', '{' }, \ + \ + { 1, 7, 'u', 'U', '7', 0xff }, \ + { 2, 7, 'f', 'F', '@', 0xff }, \ + { 3, 7, 'z', 'Z', '!', 0xff }, \ + { 4, 7, ';', '~', ':', 0xff }, \ + { 5, 7, '.', ')', '>', '}' }, \ + \ + { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } + +#define CONFIG_SYS_CONSOLE_ENV_OVERWRITE +#define CONFIG_SYS_CONSOLE_IS_IN_ENV + +#endif + +/* * GPIO settings */ #define CONFIG_SYS_GAFR0_L_VAL 0x02000140 -#define CONFIG_SYS_GAFR0_U_VAL 0x59188000 -#define CONFIG_SYS_GAFR1_L_VAL 0x63900002 +#define CONFIG_SYS_GAFR0_U_VAL 0x59188005 +#define CONFIG_SYS_GAFR1_L_VAL 0x639420a2 #define CONFIG_SYS_GAFR1_U_VAL 0xaaa03950 #define CONFIG_SYS_GAFR2_L_VAL 0x0aaaaaaa #define CONFIG_SYS_GAFR2_U_VAL 0x29000308 -#define CONFIG_SYS_GAFR3_L_VAL 0x54000000 +#define CONFIG_SYS_GAFR3_L_VAL 0x56aa9500 #define CONFIG_SYS_GAFR3_U_VAL 0x000000d5 #define CONFIG_SYS_GPCR0_VAL 0x00000000 #define CONFIG_SYS_GPCR1_VAL 0x00000020 @@ -222,7 +294,7 @@ unsigned char zipitz2_spi_read(void); #define CONFIG_SYS_GPCR3_VAL 0x00000000 #define CONFIG_SYS_GPDR0_VAL 0xdafcee00 #define CONFIG_SYS_GPDR1_VAL 0xffa3aaab -#define CONFIG_SYS_GPDR2_VAL 0x8fe9ffff +#define CONFIG_SYS_GPDR2_VAL 0x8fe1ffff #define CONFIG_SYS_GPDR3_VAL 0x001b1f8a #define CONFIG_SYS_GPSR0_VAL 0x06080400 #define CONFIG_SYS_GPSR1_VAL 0x007f0000 @@ -234,7 +306,7 @@ unsigned char zipitz2_spi_read(void); /* * Clock settings */ -#define CONFIG_SYS_CKEN 0x00511220 +#define CONFIG_SYS_CKEN 0x00591220 #define CONFIG_SYS_CCCR 0x00000190
/*

Signed-off-by: Vasily Khoruzhick anarsoul@gmail.com --- v2: mmcinfo is necessary to scan card for partitions v3: replace mmcinfo with mmc rescan v4: mmc rescan does not take extra argument in recent u-boot, so remove it. v5: remove spaces from CONFIG_BOOTCOMMAND
board/zipitz2/zipitz2.c | 8 ++++++++ include/configs/zipitz2.h | 6 ++++-- 2 files changed, 12 insertions(+), 2 deletions(-)
diff --git a/board/zipitz2/zipitz2.c b/board/zipitz2/zipitz2.c index b093c2f..4075fb6 100644 --- a/board/zipitz2/zipitz2.c +++ b/board/zipitz2/zipitz2.c @@ -79,6 +79,14 @@ void dram_init_banksize(void) gd->bd->bi_dram[0].size = PHYS_SDRAM_1_SIZE; }
+#ifdef CONFIG_CMD_MMC +int board_mmc_init(bd_t *bis) +{ + pxa_mmc_register(0); + return 0; +} +#endif + #ifdef CONFIG_CMD_SPI
struct { diff --git a/include/configs/zipitz2.h b/include/configs/zipitz2.h index 615f9bc..6dae630 100644 --- a/include/configs/zipitz2.h +++ b/include/configs/zipitz2.h @@ -45,7 +45,8 @@ #define CONFIG_ARCH_CPU_INIT
#define CONFIG_BOOTCOMMAND \ - "if mmc init && fatload mmc 0 0xa0000000 uboot.script ; then " \ + "if mmc rescan && ext2load mmc 0 0xa0000000 boot/uboot.script ;"\ + "then " \ "source 0xa0000000; " \ "else " \ "bootm 0x60000; " \ @@ -91,7 +92,8 @@ */ #ifdef CONFIG_CMD_MMC #define CONFIG_MMC -#define CONFIG_PXA_MMC +#define CONFIG_GENERIC_MMC +#define CONFIG_PXA_MMC_GENERIC #define CONFIG_SYS_MMC_BASE 0xF0000000 #define CONFIG_CMD_FAT #define CONFIG_CMD_EXT2

From: Marek Vasut marek.vasut@gmail.com
Signed-off-by: Marek Vasut marek.vasut@gmail.com Signed-off-by: Vasily Khoruzhick anarsoul@gmail.com
v2: use struct-based access to regs, minor cleanup v3: fix multiple keypresses handling, minor cleanup v4: another minor cleanup v5: fix indentation issues in scan_keys(), remove udelay, increase PXA_KEYPAD_TIMEOUT (due to removed udelay)
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 | 292 +++++++++++++++++++++++++++ 4 files changed, 378 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..1909417 --- /dev/null +++ b/arch/arm/include/asm/arch-pxa/regs-keypad.h @@ -0,0 +1,84 @@ +/*
- Copyright (C) 2012 Vasily Khoruzhick anarsoul@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..0c9a905 --- /dev/null +++ b/drivers/input/pxa27x-mkp.c @@ -0,0 +1,292 @@ +/*
- PXA27x matrix keypad controller driver
- Copyright (C) 2010 Marek Vasut marek.vasut@gmail.com
- Copyright (C) 2012 Vasily Khoruzhick anarsoul@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 = (struct pxa_keypad_regs *)KEYPAD_BASE; + +/* 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
+/* Number of cycles to wait */ +#define PXA_KEYPAD_TIMEOUT 100000
+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;
- int key;
- for (col = 0; col < 8; col += 1) {
reg = kpasmkp[col >> 1];
reg >>= 16 * (col % 2);
for (row = 0; row < 8; row++) {
if (!(reg & (1 << row)))
continue;
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 (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(®s->kpc) | KPC_AS, ®s->kpc);
- /* wait for scan to finish */
- while (timeout--) {
if (!(readl(®s->kpc) & KPC_AS))
break;
+#if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG)
WATCHDOG_RESET();
+#endif
- }
- if (!timeout)
return;
- numkeys = (readl(®s->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(®s->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(®s->kpasmkp[i].kpasmkpx);
if (!(kpasmkp[i] & KPASMKPx_SO))
break;
+#if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG)
Remove this above
WATCHDOG_RESET();
+#endif
}
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);
- } else {
key_counter = 0;
last_key_row = last_key_col = 0xff;
scan_keys(0, kpasmkp_diff);
- }
+}
+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;
- writel((CONFIG_PXA27X_MKP_MKP_ROWS << 26) |
(CONFIG_PXA27X_MKP_MKP_COLS << 23) |
(0xff << 13) | KPC_ME, ®s->kpc);
- writel(CONFIG_PXA27X_MKP_DEBOUNCE, ®s->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;
+}
participants (2)
-
Marek Vasut
-
Vasily Khoruzhick