aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSesahgiri.Holi <seshagiri.holi@stericsson.com>2011-08-30 14:58:15 +0530
committerPreetham-rao K <preetham.rao@stericsson.com>2011-09-20 10:51:49 +0200
commitf33d63c0fd8fb89a600e113a44591246e76995fb (patch)
tree254dd62739f01773ca937317a39a5373cbaf91b5
parenta30e5e18d11865a38ec8becc4159dc8a57c23e46 (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.c33
-rw-r--r--[-rwxr-xr-x]common/Makefile1
-rw-r--r--common/cmd_keypad.c39
-rw-r--r--cpu/arm_cortexa9/db5500/timer.c15
-rw-r--r--drivers/input/Makefile1
-rw-r--r--drivers/input/u5500_keypad.c241
-rw-r--r--include/common.h3
-rw-r--r--include/configs/u5500.h6
-rw-r--r--include/u5500_keypad.h31
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__ */