diff options
author | Sesahgiri.Holi <seshagiri.holi@stericsson.com> | 2011-08-30 14:58:15 +0530 |
---|---|---|
committer | Preetham-rao K <preetham.rao@stericsson.com> | 2011-09-20 10:51:49 +0200 |
commit | f33d63c0fd8fb89a600e113a44591246e76995fb (patch) | |
tree | 254dd62739f01773ca937317a39a5373cbaf91b5 | |
parent | a30e5e18d11865a38ec8becc4159dc8a57c23e46 (diff) |
u-boot:u5500:Add keypad support in u-boot.
Add keypad support in u-boot to
program the device in service mode.
ST-Ericsson ID: 324044
ST-Ericsson Linux next: NA
ST-Ericsson FOSS-OUT ID: Trivial
Signed-off-by: Sesahgiri.Holi <seshagiri.holi@stericsson.com>
Change-Id: Ic051b19363b015c0db969fbe364916342041dda6
Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/29408
Reviewed-by: QATOOLS
Reviewed-by: QATEST
Reviewed-by: Preetham-rao K <preetham.rao@stericsson.com>
Tested-by: Preetham-rao K <preetham.rao@stericsson.com>
-rw-r--r-- | board/st-ericsson/u5500/u5500.c | 33 | ||||
-rw-r--r--[-rwxr-xr-x] | common/Makefile | 1 | ||||
-rw-r--r-- | common/cmd_keypad.c | 39 | ||||
-rw-r--r-- | cpu/arm_cortexa9/db5500/timer.c | 15 | ||||
-rw-r--r-- | drivers/input/Makefile | 1 | ||||
-rw-r--r-- | drivers/input/u5500_keypad.c | 241 | ||||
-rw-r--r-- | include/common.h | 3 | ||||
-rw-r--r-- | include/configs/u5500.h | 6 | ||||
-rw-r--r-- | include/u5500_keypad.h | 31 |
9 files changed, 367 insertions, 3 deletions
diff --git a/board/st-ericsson/u5500/u5500.c b/board/st-ericsson/u5500/u5500.c index 5c2c220f0..451cbac73 100644 --- a/board/st-ericsson/u5500/u5500.c +++ b/board/st-ericsson/u5500/u5500.c @@ -24,9 +24,11 @@ #include "db8500_pincfg.h" #include <u8500_mmc_host.h> - +#include <u5500_keypad.h> /* offset for GPIO ALTB register */ #define DB5500_GPIO_AFSLB 0x24 +/* BOOT ROM backup bit value to peripheral boot */ +#define PERIPHERAL_BOOT_MODE (1 << 29) #define BACKUPRAM_ROM_DEBUG_ADDR 0xFFC #define MMC_BLOCK_ID 0x20 @@ -64,7 +66,25 @@ static pin_cfg_t gpio_config[] = { GPIO25_MC2_DAT4 | PIN_INPUT_PULLUP, GPIO21_MC2_DAT5 | PIN_INPUT_PULLUP, GPIO26_MC2_DAT6 | PIN_INPUT_PULLUP, - GPIO22_MC2_DAT7 | PIN_INPUT_PULLUP + GPIO22_MC2_DAT7 | PIN_INPUT_PULLUP, + + /* Keypad GPIO */ + GPIO128_KP_I0 | PIN_INPUT_PULLUP, + GPIO129_KP_O0 | PIN_OUTPUT_HIGH, + GPIO130_KP_I1 | PIN_INPUT_PULLUP, + GPIO131_KP_O1 | PIN_OUTPUT_HIGH, + GPIO132_KP_I2 | PIN_INPUT_PULLUP, + GPIO133_KP_O2 | PIN_OUTPUT_HIGH, + GPIO134_KP_I3 | PIN_INPUT_PULLUP, + GPIO135_KP_O3 | PIN_OUTPUT_HIGH, + GPIO136_KP_I4 | PIN_INPUT_PULLUP, + GPIO137_KP_O4 | PIN_OUTPUT_HIGH, + GPIO138_KP_I5 | PIN_INPUT_PULLUP, + GPIO139_KP_O5 | PIN_OUTPUT_HIGH, + GPIO140_KP_I6 | PIN_INPUT_PULLUP, + GPIO141_KP_O6 | PIN_OUTPUT_HIGH, + GPIO142_KP_I7 | PIN_INPUT_PULLUP, + GPIO143_KP_O7 | PIN_OUTPUT_HIGH, }; static pin_cfg_t sdcard_gpio_config[] = { @@ -340,7 +360,14 @@ int board_late_init(void) ARRAY_SIZE(sdcard_gpio_config)); #endif - + /* init keypad */ + init_keypad(); return 0; } #endif /* BOARD_LATE_INIT */ +/* sets the peripheral boot mode */ +void set_to_peripheral_boot_mode(void) +{ + writel(PERIPHERAL_BOOT_MODE, + U5500_BACKUPRAM1_BASE + BACKUPRAM_ROM_DEBUG_ADDR); +} diff --git a/common/Makefile b/common/Makefile index 6c803ab53..7b9642dcd 100755..100644 --- a/common/Makefile +++ b/common/Makefile @@ -51,6 +51,7 @@ COBJS-y += cmd_version.o # environment COBJS-y += env_common.o +COBJS-$(CONFIG_CMD_KEYPAD_DETECT) += cmd_keypad.o COBJS-$(CONFIG_ENV_IS_IN_DATAFLASH) += env_dataflash.o COBJS-$(CONFIG_ENV_IS_IN_EEPROM) += env_eeprom.o COBJS-$(CONFIG_ENV_IS_EMBEDDED) += env_embedded.o diff --git a/common/cmd_keypad.c b/common/cmd_keypad.c new file mode 100644 index 000000000..426b24135 --- /dev/null +++ b/common/cmd_keypad.c @@ -0,0 +1,39 @@ +/* + * Copyright (C) ST-Ericsson SA 2011 + * Author: Seshagiri HOLI<seshagiri.holi@stericsson.com> for + * ST-Ericsson. + * License terms: GNU General Public License (GPL), version 2. + */ + +/* Support for key combination detection. */ +#include <common.h> +#include <linux/bitops.h> +#include <u5500_keypad.h> + +int do_keypress_wait(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + char *ep; + u32 delay = 0; + int ret = 0; + switch (argc) { + case 1: /* No Arguments passed */ + ret = wait_for_keypress_forever(); + break; + case 2: /*One arguments passed */ + delay = simple_strtoul(argv[1], &ep, 10); + ret = wait_for_keypress(delay); + break; + default: + cmd_usage(cmdtp); + break; + } + return ret; +} + +U_BOOT_CMD( + detect_keypress, 2, 0, do_keypress_wait, + "waits for keypress", + "<delay in msec>\n" + " Waits for keypress\n" + " If no arguments passed it will wait forever.\n" +); diff --git a/cpu/arm_cortexa9/db5500/timer.c b/cpu/arm_cortexa9/db5500/timer.c index e29cb6bf8..7ec5a449e 100644 --- a/cpu/arm_cortexa9/db5500/timer.c +++ b/cpu/arm_cortexa9/db5500/timer.c @@ -124,3 +124,18 @@ void __udelay(unsigned long usec) ; boottime_idle_add(usec); } + +ulong get_curr_timer(void) +{ + return READ_TIMER(); +} + +ulong usec2ticks(unsigned long usec) +{ + return USEC_TO_COUNT(usec); +} + +ulong ticks2usec(unsigned long ticks) +{ + return COUNT_TO_USEC(ticks); +} diff --git a/drivers/input/Makefile b/drivers/input/Makefile index 9a1440739..7bc1fe255 100644 --- a/drivers/input/Makefile +++ b/drivers/input/Makefile @@ -30,6 +30,7 @@ ifdef CONFIG_PS2KBD COBJS-y += keyboard.o pc_keyb.o COBJS-$(CONFIG_PS2MULT) += ps2mult.o ps2ser.o endif +COBJS-$(CONFIG_U5500_KEYPAD) += u5500_keypad.o COBJS := $(COBJS-y) SRCS := $(COBJS:.o=.c) diff --git a/drivers/input/u5500_keypad.c b/drivers/input/u5500_keypad.c new file mode 100644 index 000000000..041a64358 --- /dev/null +++ b/drivers/input/u5500_keypad.c @@ -0,0 +1,241 @@ +/* + * Copyright (C) ST-Ericsson SA 2011 + * Author: Seshagiri HOLI<seshagiri.holi@stericsson.com> for + * ST-Ericsson. + * License terms: GNU General Public License (GPL), version 2. + */ + +/* This has implementation for u5500 keypad drive .*/ +#include <common.h> +#include <asm/io.h> +#include <linux/bitops.h> +#include <u5500_keypad.h> + + +/* Key pad */ + +#define U5500_PER3_BASE 0x80140000 + +#define U5500_KEYPAD_BASE (U5500_PER3_BASE + 0x0000) +#define KEYPAD_CTRL_REG (U5500_KEYPAD_BASE + 0x0000) +#define KEYPAD_IRQ_CLEAR (U5500_KEYPAD_BASE + 0x0004) +#define KEYPAD_IRQ_EN (U5500_KEYPAD_BASE + 0x0008) +#define KEYPAD_IRQ_STATUS (U5500_KEYPAD_BASE + 0x000C) + +#define KEY_COLUMN_REG (U5500_KEYPAD_BASE + 0x0010) +#define KEY_ROW_REG (U5500_KEYPAD_BASE + 0x0014) +#define KEYPAD_ARRAY_01 (U5500_KEYPAD_BASE + 0x0018) + + +/* ctrl values */ +#define KEYPAD_SCAN_ENBLE 0x080 +#define KEYPAD_DEBOUNCE_HITS 0x070 +#define KEYPAD_SCAN_INTV 0x000 +#define KEYPAD_ARRAY_CHANGEBIT (1 << 15) + + +/* kernel code */ + + +#define KEYPAD_NUM_ARRAY_REGS 5 +#define KEYPAD_GND_ROW 8 +#define KEYPAD_MAX_ROWS 9 +#define KEYPAD_MAX_COLS 8 +#define NO_KEYSCAN 0 + +#define GET_INDEX_ROW_COL(row, col) (row + (col * KEYPAD_MAX_ROWS)) + +#define PERIOD (10 * 1000 * 1000) /* 10 seconds default*/ + +static int fun_handler_cam2_back(void); +static void keypad_scan(void); + +struct key_func_map_s{ + u16 key_combination; + int (*cmd)(void); +}; + +typedef struct key_func_map_s key_func_map_t; +/* key combination lookup table avoid duplicate key combinations */ + +static key_func_map_t key_func_map[] = { + {KEY_CAMERA_FOCUS | KEY_BACK, fun_handler_cam2_back} +}; + + +static u16 key_code[KEYPAD_MAX_ROWS * KEYPAD_MAX_COLS] = { + /* ROW -->*/ +/*C*/ 0, 0, 0, 0, KEY_CAMERA, 0 , 0, 0, KEY_END, +/*O*/ 0, 0, 0, 0, KEY_CAMERA_FOCUS, 0 , 0, 0, KEY_VOLUMEUP, +/*L*/ 0, 0, 0, 0, KEY_MENU, KEY_SEND, 0, 0, KEY_VOLUMEDOWN, +/*L*/ 0, 0, 0, KEY_BACK, KEY_HOME, 0, 0, 0, +/*U*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*M*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static u8 previous_set[KEYPAD_MAX_ROWS]; +static u32 pressed_key; + +static void keypad_report(int row, u8 curr, u8 previous) +{ + u8 changed = curr ^ previous; + + while (changed) { + u8 col = generic_ffs(changed) - 1; + u8 press = curr & BIT_MASK(col); + printf("ROW X COL = %d X %d pressed = %d - key_code= %d\n", + row, col, press, GET_INDEX_ROW_COL(row, col)); + if (press) + pressed_key |= key_code[GET_INDEX_ROW_COL(row, col)]; + else + pressed_key &= ~key_code[GET_INDEX_ROW_COL(row, col)]; + + changed &= ~BIT_MASK(col); + } +} + +void keypad_scan(void) +{ + u8 current_set[KEYPAD_MAX_ROWS]; + int tries = 100; + u32 changebit; + u32 data_reg; + u8 allrows; + u8 common; + int i; + + writel(0x01, KEYPAD_IRQ_CLEAR); + /* clear bit 1 in IRQ register of keypad */ +again: + if (!tries--) { + printf("values failed to stabilize\n"); + return; + } + + changebit = readl(KEYPAD_ARRAY_01) & KEYPAD_ARRAY_CHANGEBIT; + for (i = 0; i < KEYPAD_NUM_ARRAY_REGS; i++) { + data_reg = readl(KEYPAD_ARRAY_01 + 4 * i); + /* If the change bit changed, we need to reread the data */ + if (changebit != (data_reg & KEYPAD_ARRAY_CHANGEBIT)) + goto again; + + current_set[2 * i] = ~(data_reg & 0xff); + + /* Last array reg has only one valid set of columns */ + if (i != KEYPAD_NUM_ARRAY_REGS - 1) + current_set[2 * i + 1] = ~((data_reg & 0xff0000) >> 16); + } + + allrows = current_set[KEYPAD_GND_ROW]; + + /* + * Sometimes during a GND row release, an incorrect report is received + * where the ARRAY8 all rows setting does not match the other ARRAY* + * rows. Ignore this report; the correct one has been observed to + * follow it. + */ + common = 0xff; + for (i = 0; i < KEYPAD_GND_ROW; i++) + common &= current_set[i]; + + if ((allrows & common) != common) + return; + + for (i = 0; i < ARRAY_SIZE(current_set); i++) { + /* + * If there is an allrows press (GND row), we need to ignore + * the allrows values from the reset of the ARRAYs. + */ + if (i < KEYPAD_GND_ROW && allrows) + current_set[i] &= ~allrows; + + if (previous_set[i] == current_set[i]) + continue; + + keypad_report(i, current_set[i], previous_set[i]); + } + + /* update the reference set of array registers */ + memcpy(previous_set, current_set, sizeof(previous_set)); + + return; +} + +void init_keypad(void) +{ + /* Set control reg */ + writel(KEYPAD_SCAN_ENBLE + | KEYPAD_DEBOUNCE_HITS | KEYPAD_SCAN_INTV, KEYPAD_CTRL_REG); + /* set bit 1 in KEYPAD_IRQ_CLEAR register to clear IRQ */ + writel(0x01, KEYPAD_IRQ_CLEAR); + /* set bit 1 in KEYPAD_IRQ_EN register to enable IRQ */ + writel(0x01, KEYPAD_IRQ_EN); +} + +int fun_handler_cam2_back(void) +{ + set_to_peripheral_boot_mode(); + do_reset(NULL, 0, 0, NULL); + return 1; +} + +int look_up_key_comb(u16 key_comb, int *handled) +{ + int i; + int ret = 0; + for (i = 0; i < ARRAY_SIZE(key_func_map); i++) { + if (key_comb == key_func_map[i].key_combination) { + ret = key_func_map[i].cmd(); + *handled = 1; + break; + } + } + return ret; +} + +int wait_for_keypress_forever(void) +{ + int handled = 0; + int ret = 0; + ulong ini, end; + /* Reset KEY press */ + pressed_key = 0; + do { + ini = get_curr_timer(); + end = ini + (ulong)usec2ticks(PERIOD); + while ((signed)(end - get_curr_timer()) > 0) { + if (readl(KEYPAD_IRQ_STATUS)) + keypad_scan(); + } + ret = look_up_key_comb(pressed_key, &handled); + if (handled == 1) + break; + } while (1); + return ret; +} +int wait_for_keypress(ulong msec) +{ + ulong kv; + ulong ini, end; + int ret = 0; + int handled = 0; + pressed_key = 0;/* Reset KEY press */ + ulong usec = msec * 1000;/* milli sec to micro sec */ + + /* For delays mor than 10 sec we need loop for every chunks of 10 sec */ + do { + kv = usec > PERIOD ? PERIOD : usec; + ini = get_curr_timer(); + end = ini + (ulong)usec2ticks(kv); + while ((signed)(end - get_curr_timer()) > 0) { + if (readl(KEYPAD_IRQ_STATUS)) + keypad_scan(); + } + usec -= kv; + } while (usec); + look_up_key_comb(pressed_key, &handled); + return ret; +} + diff --git a/include/common.h b/include/common.h index e164e99db..730023b06 100644 --- a/include/common.h +++ b/include/common.h @@ -377,6 +377,8 @@ int board_late_init (void); int board_postclk_init (void); /* after clocks/timebase, before env/serial */ int board_early_init_r (void); void board_poweroff (void); +void set_to_peripheral_boot_mode(void); + #if defined(CONFIG_SYS_DRAM_TEST) int testdram(void); @@ -611,6 +613,7 @@ void wait_ticks (unsigned long); void __udelay (unsigned long); ulong usec2ticks (unsigned long usec); ulong ticks2usec (unsigned long ticks); +ulong get_curr_timer(void); int init_timebase (void); /* lib_generic/gunzip.c */ diff --git a/include/configs/u5500.h b/include/configs/u5500.h index e8ee4e6f1..3604df5f6 100644 --- a/include/configs/u5500.h +++ b/include/configs/u5500.h @@ -95,6 +95,8 @@ #define CONFIG_CMD_SOURCE #define CONFIG_CMD_TOC #define CONFIG_CMD_DATE +#define CONFIG_CMD_KEYPAD_DETECT + #define CONFIG_RTC_PL031_ST #define CONFIG_SYS_RTC_PL031_BASE U5500_RTC_BASE @@ -221,6 +223,10 @@ #define CONFIG_ENV_OFFSET_END 0x13FE0000 #define CONFIG_U8500_MMC 1 +/*----------------------------------------------------------------------- + * KEYPAD related configs + */ +#define CONFIG_U5500_KEYPAD 1 /*------------------------------------------------------------------------------ * base register values for U5500 */ diff --git a/include/u5500_keypad.h b/include/u5500_keypad.h new file mode 100644 index 000000000..6ef29cca1 --- /dev/null +++ b/include/u5500_keypad.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) ST-Ericsson SA 2011 + * Author: Seshagiri HOLI<seshagiri.holi@stericsson.com> for + * ST-Ericsson. + * License terms: GNU General Public License (GPL), version 2. + */ + + +#ifndef __U5500_KEYPAD_H__ +#define __U5500_KEYPAD_H__ + + +void init_keypad(void); +int wait_for_keypress_forever(void); +int wait_for_keypress(ulong msec); + +#define KEY_CAMERA 0x001 +#define KEY_CAMERA_FOCUS 0x002 +#define KEY_MENU 0x004 +#define KEY_BACK 0x008 +#define KEY_SEND 0x010 +#define KEY_HOME 0x020 +#define KEY_END 0x040 +#define KEY_VOLUMEUP 0x080 +#define KEY_VOLUMEDOWN 0x100 + + +#define KEYPAD_MAX_ROWS 9 +#define KEYPAD_MAX_COLS 8 + +#endif /* __U5500_KEYPAD_H__ */ |