From 75e45a284361b8b04d74bf7dd0d2300611171c27 Mon Sep 17 00:00:00 2001 From: "Ye.Li" Date: Tue, 24 Dec 2013 17:21:32 +0800 Subject: ENGR00292902 ARM:imx6sl:evk Add android fastboot supporting The imx6slevk has keyboards on the board, so add mxc_keyb driver to support the recovery keys pressing checking. The key mapping table is defined in "mx6slevkandroid.h" with CONFIG_MXC_KPD enabled. Signed-off-by: Ye.Li --- arch/arm/include/asm/arch-mx6/mx6sl_pins.h | 9 + arch/arm/include/asm/imx-common/mxc_key_defs.h | 55 +++ board/freescale/mx6slevk/mx6slevk.c | 87 ++++ boards.cfg | 1 + drivers/input/Makefile | 1 + drivers/input/mxc_keyb.c | 608 +++++++++++++++++++++++++ include/configs/mx6slevk.h | 4 + include/configs/mx6slevkandroid.h | 87 ++++ include/mxc_keyb.h | 217 +++++++++ 9 files changed, 1069 insertions(+) create mode 100644 arch/arm/include/asm/imx-common/mxc_key_defs.h create mode 100644 drivers/input/mxc_keyb.c create mode 100644 include/configs/mx6slevkandroid.h create mode 100644 include/mxc_keyb.h diff --git a/arch/arm/include/asm/arch-mx6/mx6sl_pins.h b/arch/arm/include/asm/arch-mx6/mx6sl_pins.h index c3a553a..34397ac 100644 --- a/arch/arm/include/asm/arch-mx6/mx6sl_pins.h +++ b/arch/arm/include/asm/arch-mx6/mx6sl_pins.h @@ -84,5 +84,14 @@ enum { MX6_PAD_EPDC_SDCE1__GPIO_1_28 = IOMUX_PAD(0x03F4, 0x0104, 5, 0x0000, 0, 0), MX6_PAD_EPDC_SDCE2__GPIO_1_29 = IOMUX_PAD(0x03F8, 0x0108, 5, 0x0000, 0, 0), MX6_PAD_EPDC_PWRCOM__ANATOP_USBOTG1_ID = IOMUX_PAD(0x03D0, 0x00E0, 4, 0x05DC, 0, 0), + + MX6_PAD_KEY_COL0__KPP_COL_0 = IOMUX_PAD(0x0474, 0x016C, 0, 0x0734, 0, 0), + MX6_PAD_KEY_COL1__KPP_COL_1 = IOMUX_PAD(0x0478, 0x0170, 0, 0x0738, 0, 0), + MX6_PAD_KEY_COL2__KPP_COL_2 = IOMUX_PAD(0x047C, 0x0174, 0, 0x073C, 0, 0), + MX6_PAD_KEY_COL3__KPP_COL_3 = IOMUX_PAD(0x0480, 0x0178, 0, 0x0740, 0, 0), + MX6_PAD_KEY_ROW0__KPP_ROW_0 = IOMUX_PAD(0x0494, 0x018C, 0, 0x0754, 0, 0), + MX6_PAD_KEY_ROW1__KPP_ROW_1 = IOMUX_PAD(0x0498, 0x0190, 0, 0x0758, 0, 0), + MX6_PAD_KEY_ROW2__KPP_ROW_2 = IOMUX_PAD(0x049C, 0x0194, 0, 0x075C, 0, 0), + MX6_PAD_KEY_ROW3__KPP_ROW_3 = IOMUX_PAD(0x04A0, 0x0198, 0, 0x0760, 0, 0), }; #endif /* __ASM_ARCH_MX6_MX6SL_PINS_H__ */ diff --git a/arch/arm/include/asm/imx-common/mxc_key_defs.h b/arch/arm/include/asm/imx-common/mxc_key_defs.h new file mode 100644 index 0000000..d38d3a9 --- /dev/null +++ b/arch/arm/include/asm/imx-common/mxc_key_defs.h @@ -0,0 +1,55 @@ +/* + * (C) Copyright 2009-2013 Freescale Semiconductor, Inc. + * + * Configuration settings for the MX51-3Stack Freescale board. + * + * 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 _MXC_KEYPAD_H_ +#define _MXC_KEYPAD_H_ + +#include + +#define KEY_1 2 +#define KEY_2 3 +#define KEY_3 4 +#define KEY_F1 59 +#define KEY_UP 103 +#define KEY_F2 60 + +#define KEY_4 5 +#define KEY_5 6 +#define KEY_6 7 +#define KEY_LEFT 105 +#define KEY_SELECT 0x161 +#define KEY_RIGHT 106 + +#define KEY_7 8 +#define KEY_8 9 +#define KEY_9 10 +#define KEY_F3 61 +#define KEY_DOWN 108 +#define KEY_F4 62 + +#define KEY_0 11 +#define KEY_OK 0x160 +#define KEY_ESC 1 +#define KEY_ENTER 28 +#define KEY_MENU 139 /* Menu (show menu) */ +#define KEY_BACK 158 /* AC Back */ + +#endif diff --git a/board/freescale/mx6slevk/mx6slevk.c b/board/freescale/mx6slevk/mx6slevk.c index b393698..bc119b3 100644 --- a/board/freescale/mx6slevk/mx6slevk.c +++ b/board/freescale/mx6slevk/mx6slevk.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -30,6 +31,12 @@ #include #include #endif +#ifdef CONFIG_FASTBOOT +#include +#ifdef CONFIG_ANDROID_RECOVERY +#include +#endif +#endif /*CONFIG_FASTBOOT*/ DECLARE_GLOBAL_DATA_PTR; @@ -625,6 +632,62 @@ u32 get_board_rev(void) return get_cpu_rev(); } +#ifdef CONFIG_FASTBOOT + +void board_fastboot_setup(void) +{ + /*current uboot BSP only supports USDHC2*/ + switch (get_boot_device()) { +#if defined(CONFIG_FASTBOOT_STORAGE_MMC) + case SD2_BOOT: + case MMC2_BOOT: + if (!getenv("fastboot_dev")) + setenv("fastboot_dev", "mmc0"); + if (!getenv("bootcmd")) + setenv("bootcmd", "booti mmc0"); + break; +#endif /*CONFIG_FASTBOOT_STORAGE_MMC*/ + default: + printf("unsupported boot devices\n"); + break; + } + +} + +#ifdef CONFIG_ANDROID_RECOVERY +int check_recovery_cmd_file(void) +{ + return recovery_check_and_clean_flag(); +} + +void board_recovery_setup(void) +{ + int bootdev = get_boot_device(); + + /*current uboot BSP only supports USDHC2*/ + switch (bootdev) { +#if defined(CONFIG_FASTBOOT_STORAGE_MMC) + case SD2_BOOT: + case MMC2_BOOT: + if (!getenv("bootcmd_android_recovery")) + setenv("bootcmd_android_recovery", + "booti mmc0 recovery"); + break; +#endif /*CONFIG_FASTBOOT_STORAGE_MMC*/ + default: + printf("Unsupported bootup device for recovery: dev: %d\n", + bootdev); + return; + } + + printf("setup env for recovery..\n"); + setenv("bootcmd", "run bootcmd_android_recovery"); +} + +#endif /*CONFIG_ANDROID_RECOVERY*/ + +#endif /*CONFIG_FASTBOOT*/ + int checkboard(void) { puts("Board: MX6SLEVK\n"); @@ -632,6 +695,30 @@ int checkboard(void) return 0; } +#ifdef CONFIG_MXC_KPD +#define MX6SL_KEYPAD_CTRL (PAD_CTL_HYS | PAD_CTL_PKE | PAD_CTL_PUE | \ + PAD_CTL_PUS_100K_UP | PAD_CTL_DSE_120ohm) + +iomux_v3_cfg_t const mxc_kpd_pads[] = { + (MX6_PAD_KEY_COL0__KPP_COL_0 | MUX_PAD_CTRL(NO_PAD_CTRL)), + (MX6_PAD_KEY_COL1__KPP_COL_1 | MUX_PAD_CTRL(NO_PAD_CTRL)), + (MX6_PAD_KEY_COL2__KPP_COL_2 | MUX_PAD_CTRL(NO_PAD_CTRL)), + (MX6_PAD_KEY_COL3__KPP_COL_3 | MUX_PAD_CTRL(NO_PAD_CTRL)), + + (MX6_PAD_KEY_ROW0__KPP_ROW_0 | MUX_PAD_CTRL(MX6SL_KEYPAD_CTRL)), + (MX6_PAD_KEY_ROW1__KPP_ROW_1 | MUX_PAD_CTRL(MX6SL_KEYPAD_CTRL)), + (MX6_PAD_KEY_ROW2__KPP_ROW_2 | MUX_PAD_CTRL(MX6SL_KEYPAD_CTRL)), + (MX6_PAD_KEY_ROW3__KPP_ROW_3 | MUX_PAD_CTRL(MX6SL_KEYPAD_CTRL)), +}; +int setup_mxc_kpd(void) +{ + imx_iomux_v3_setup_multiple_pads(mxc_kpd_pads, + ARRAY_SIZE(mxc_kpd_pads)); + + return 0; +} +#endif /*CONFIG_MXC_KPD*/ + #ifdef CONFIG_IMX_UDC iomux_v3_cfg_t const otg_udc_pads[] = { (MX6_PAD_EPDC_PWRCOM__ANATOP_USBOTG1_ID | MUX_PAD_CTRL(NO_PAD_CTRL)), diff --git a/boards.cfg b/boards.cfg index f1e87ac..1b0146d 100644 --- a/boards.cfg +++ b/boards.cfg @@ -286,6 +286,7 @@ mx6solosabreauto_nand arm armv7 mx6qsabreauto freesca mx6solosabreautoandroid arm armv7 mx6qsabreauto freescale mx6 mx6qsabreauto:IMX_CONFIG=board/freescale/mx6qsabreauto/mx6solo.cfg,MX6SOLO,DEFAULT_FDT_FILE="imx6dl-sabreauto.dtb",DDR_MB=1024,SYS_USE_SPINOR,SYS_NOSMP="nosmp",ANDROID_SUPPORT mx6solosabreautoandroid_nand arm armv7 mx6qsabreauto freescale mx6 mx6qsabreauto:IMX_CONFIG=board/freescale/mx6qsabreauto/mx6solo.cfg,MX6SOLO,DEFAULT_FDT_FILE="imx6dl-sabreauto.dtb",DDR_MB=1024,SYS_BOOT_NAND,SYS_NOSMP="nosmp",ANDROID_SUPPORT mx6slevk arm armv7 mx6slevk freescale mx6 mx6slevk:IMX_CONFIG=board/freescale/mx6slevk/imximage.cfg,MX6SL +mx6slevkandroid arm armv7 mx6slevk freescale mx6 mx6slevk:IMX_CONFIG=board/freescale/mx6slevk/imximage.cfg,MX6SL,ANDROID_SUPPORT eco5pk arm armv7 eco5pk 8dtech omap3 nitrogen6dl arm armv7 nitrogen6x boundary mx6 nitrogen6x:IMX_CONFIG=board/boundary/nitrogen6x/nitrogen6dl.cfg,MX6DL,DDR_MB=1024 nitrogen6dl2g arm armv7 nitrogen6x boundary mx6 nitrogen6x:IMX_CONFIG=board/boundary/nitrogen6x/nitrogen6dl2g.cfg,MX6DL,DDR_MB=2048 diff --git a/drivers/input/Makefile b/drivers/input/Makefile index 0805e86..a961de6 100644 --- a/drivers/input/Makefile +++ b/drivers/input/Makefile @@ -33,6 +33,7 @@ COBJS-$(CONFIG_PS2MULT) += ps2mult.o ps2ser.o endif COBJS-y += input.o COBJS-$(CONFIG_OF_CONTROL) += key_matrix.o +COBJS-$(CONFIG_MXC_KPD) += mxc_keyb.o COBJS := $(COBJS-y) SRCS := $(COBJS:.o=.c) diff --git a/drivers/input/mxc_keyb.c b/drivers/input/mxc_keyb.c new file mode 100644 index 0000000..c9bbebc --- /dev/null +++ b/drivers/input/mxc_keyb.c @@ -0,0 +1,608 @@ +/* + * Copyright 2004-2013 Freescale Semiconductor, Inc. All Rights Reserved. + * + * 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 + */ + +/*! + * @file mxc_keyb.c + * + * @brief Driver for the Freescale Semiconductor MXC keypad port. + * + * The keypad driver is designed as a standard Input driver which interacts + * with low level keypad port hardware. Upon opening, the Keypad driver + * initializes the keypad port. When the keypad interrupt happens the driver + * calles keypad polling timer and scans the keypad matrix for key + * press/release. If all key press/release happened it comes out of timer and + * waits for key press interrupt. The scancode for key press and release events + * are passed to Input subsytem. + * + * @ingroup keypad + */ + +#include +#include +#include +#include +#include +#include + +/* + * * Module header file + * */ +#include + +/*! + * Comment KPP_DEBUG to disable debug messages + */ + +#undef KPP_DEBUG + +#ifdef KPP_DEBUG +#define KPP_PRINTF(fmt, args...) printf(fmt , ##args) + +static void mxc_kpp_dump_regs() +{ + unsigned short t1, t2, t3; + + t1 = __raw_readw(KPCR); + t2 = __raw_readw(KPSR); + t3 = __raw_readw(KDDR); + /* + KPP_PRINTF("KPCR=0x%04x, KPSR=0x%04x, KDDR=0x%04x\n", + t1, t2, t3); + */ +} +#else +#define KPP_PRINTF(fmt, args...) +#endif + +static u16 mxc_key_mapping[] = CONFIG_MXC_KEYMAPPING; + +/*! + * This structure holds the keypad private data structure. + */ +static struct keypad_priv kpp_dev; + +/*! Indicates if the key pad device is enabled. */ + +/*! This static variable indicates whether a key event is pressed/released. */ +static unsigned short KPress; + +/*! cur_rcmap and prev_rcmap array is used to detect key press and release. */ +static unsigned short *cur_rcmap; /* max 64 bits (8x8 matrix) */ +static unsigned short *prev_rcmap; + +/*! + * Debounce polling period(10ms) in system ticks. + */ +/*static unsigned short KScanRate = (10 * CONFIG_SYS_HZ) / 1000;*/ + +/*! + * These arrays are used to store press and release scancodes. + */ +static short **press_scancode; +static short **release_scancode; + +static const unsigned short *mxckpd_keycodes; +static unsigned short mxckpd_keycodes_size; + +/*! + * This function is called to scan the keypad matrix to find out the key press + * and key release events. Make scancode and break scancode are generated for + * key press and key release events. + * + * The following scanning sequence are done for + * keypad row and column scanning, + * -# Write 1's to KPDR[15:8], setting column data to 1's + * -# Configure columns as totem pole outputs(for quick discharging of keypad + * capacitance) + * -# Configure columns as open-drain + * -# Write a single column to 0, others to 1. + * -# Sample row inputs and save data. Multiple key presses can be detected on + * a single column. + * -# Repeat steps the above steps for remaining columns. + * -# Return all columns to 0 in preparation for standby mode. + * -# Clear KPKD and KPKR status bit(s) by writing to a 1, + * Set the KPKR synchronizer chain by writing "1" to KRSS register, + * Clear the KPKD synchronizer chain by writing "1" to KDSC register + * + * @result Number of key pressed/released. + */ +static int mxc_kpp_scan_matrix(void) +{ + unsigned short reg_val; + int col, row; + short scancode = 0; + int keycnt = 0; /* How many keys are still pressed */ + + /* + * wmb() linux kernel function which guarantees orderings in write + * operations + */ + /* wmb(); */ + + /* save cur keypad matrix to prev */ + memcpy(prev_rcmap, cur_rcmap, kpp_dev.kpp_rows * sizeof(prev_rcmap[0])); + memset(cur_rcmap, 0, kpp_dev.kpp_rows * sizeof(cur_rcmap[0])); + + /*1. Disable both (depress and release) keypad interrupts.*/ + + /* KDIE has been disabled in mxc_kpp_getc before calling scan matrix. + * KRIE is always disabled in this driver. + */ + + for (col = 0; col < kpp_dev.kpp_cols; col++) { /* Col */ + /* 2. Write 1.s to KPDR[15:8] setting column data to 1.s */ + reg_val = __raw_readw(KPDR); + reg_val |= 0xff00; + __raw_writew(reg_val, KPDR); + + /* + * 3. Configure columns as totem pole outputs(for quick + * discharging of keypad capacitance) + */ + reg_val = __raw_readw(KPCR); + reg_val &= 0x00ff; + __raw_writew(reg_val, KPCR); + + udelay(2); + +#ifdef KPP_DEBUG + mxc_kpp_dump_regs(); +#endif + + /* + * 4. Configure columns as open-drain + */ + reg_val = __raw_readw(KPCR); + reg_val |= ((1 << kpp_dev.kpp_cols) - 1) << 8; + __raw_writew(reg_val, KPCR); + + /* + * 5. Write a single column to 0, others to 1. + * 6. Sample row inputs and save data. Multiple key presses + * can be detected on a single column. + * 7. Repeat steps 2 - 6 for remaining columns. + */ + + /* Col bit starts at 8th bit in KPDR */ + reg_val = __raw_readw(KPDR); + reg_val &= ~(1 << (8 + col)); + __raw_writew(reg_val, KPDR); + + /* Delay added to avoid propagating the 0 from column to row + * when scanning. */ + + udelay(5); + +#ifdef KPP_DEBUG + mxc_kpp_dump_regs(); +#endif + + /* Read row input */ + reg_val = __raw_readw(KPDR); + for (row = 0; row < kpp_dev.kpp_rows; row++) { /* sample row */ + if (TEST_BIT(reg_val, row) == 0) { + cur_rcmap[row] = BITSET(cur_rcmap[row], col); + keycnt++; + } + } + } + + /* + * 8. Return all columns to 0 in preparation for standby mode. + * 9. Clear KPKD and KPKR status bit(s) by writing to a .1., + * set the KPKR synchronizer chain by writing "1" to KRSS register, + * clear the KPKD synchronizer chain by writing "1" to KDSC register + */ + reg_val = 0x00; + __raw_writew(reg_val, KPDR); + reg_val = __raw_readw(KPDR); + reg_val = __raw_readw(KPSR); + reg_val |= KBD_STAT_KPKD | KBD_STAT_KPKR | KBD_STAT_KRSS | + KBD_STAT_KDSC; + __raw_writew(reg_val, KPSR); + +#ifdef KPP_DEBUG + mxc_kpp_dump_regs(); +#endif + + /* Check key press status change */ + + /* + * prev_rcmap array will contain the previous status of the keypad + * matrix. cur_rcmap array will contains the present status of the + * keypad matrix. If a bit is set in the array, that (row, col) bit is + * pressed, else it is not pressed. + * + * XORing these two variables will give us the change in bit for + * particular row and column. If a bit is set in XOR output, then that + * (row, col) has a change of status from the previous state. From + * the diff variable the key press and key release of row and column + * are found out. + * + * If the key press is determined then scancode for key pressed + * can be generated using the following statement: + * scancode = ((row * 8) + col); + * + * If the key release is determined then scancode for key release + * can be generated using the following statement: + * scancode = ((row * 8) + col) + MXC_KEYRELEASE; + */ + for (row = 0; row < kpp_dev.kpp_rows; row++) { + unsigned char diff; + + /* + * Calculate the change in the keypad row status + */ + diff = prev_rcmap[row] ^ cur_rcmap[row]; + + for (col = 0; col < kpp_dev.kpp_cols; col++) { + if ((diff >> col) & 0x1) { + /* There is a status change on col */ + if ((prev_rcmap[row] & BITSET(0, col)) == 0) { + /* + * Previous state is 0, so now + * a key is pressed + */ + scancode = + ((row * kpp_dev.kpp_cols) + + col); + KPress = 1; + kpp_dev.iKeyState = KStateUp; + + KPP_PRINTF("Press (%d, %d) scan=%d " + "Kpress=%d\n", + row, col, scancode, KPress); + press_scancode[row][col] = + (short)scancode; + } else { + /* + * Previous state is not 0, so + * now a key is released + */ + scancode = + (row * kpp_dev.kpp_cols) + + col + MXC_KEYRELEASE; + KPress = 0; + kpp_dev.iKeyState = KStateDown; + + KPP_PRINTF + ("Release (%d, %d) scan=%d Kpress=%d\n", + row, col, scancode, KPress); + release_scancode[row][col] = + (short)scancode; + keycnt++; + } + } + } + } + + return keycnt; +} + +static int mxc_kpp_reset(void) +{ + unsigned short reg_val; + int i; + + /* + * Stop scanning and wait for interrupt. + * Enable press interrupt and disable release interrupt. + */ + __raw_writew(0x00FF, KPDR); + reg_val = __raw_readw(KPSR); + reg_val |= (KBD_STAT_KPKR | KBD_STAT_KPKD); + reg_val |= KBD_STAT_KRSS | KBD_STAT_KDSC; + __raw_writew(reg_val, KPSR); + reg_val |= KBD_STAT_KDIE; + reg_val &= ~KBD_STAT_KRIE; + __raw_writew(reg_val, KPSR); + +#ifdef KPP_DEBUG + mxc_kpp_dump_regs(); +#endif + + /* + * No more keys pressed... make sure unwanted key codes are + * not given upstairs + */ + for (i = 0; i < kpp_dev.kpp_rows; i++) { + memset(press_scancode[i], -1, + sizeof(press_scancode[0][0]) * kpp_dev.kpp_cols); + memset(release_scancode[i], -1, + sizeof(release_scancode[0][0]) * + kpp_dev.kpp_cols); + } + + return 0; +} + +int mxc_kpp_getc(struct kpp_key_info **key_info) +{ + int col, row; + int key_cnt; + unsigned short reg_val; + short scancode = 0; + int index = 0; + struct kpp_key_info *keyi; + + reg_val = __raw_readw(KPSR); + + if (reg_val & KBD_STAT_KPKD) { + /* + * Disable key press(KDIE status bit) interrupt + */ + reg_val &= ~KBD_STAT_KDIE; + __raw_writew(reg_val, KPSR); + +#ifdef KPP_DEBUG + mxc_kpp_dump_regs(); +#endif + + key_cnt = mxc_kpp_scan_matrix(); + } else { + return 0; + } + + if (key_cnt <= 0) + return 0; + + *key_info = keyi = + (struct kpp_key_info *)malloc + (sizeof(struct kpp_key_info) * key_cnt); + + /* + * This switch case statement is the + * implementation of state machine of debounc + * logic for key press/release. + * The explaination of state machine is as + * follows: + * + * KStateUp State: + * This is in intial state of the state machine + * this state it checks for any key presses. + * The key press can be checked using the + * variable KPress. If KPress is set, then key + * press is identified and switches the to + * KStateFirstDown state for key press to + * debounce. + * + * KStateFirstDown: + * After debounce delay(10ms), if the KPress is + * still set then pass scancode generated to + * input device and change the state to + * KStateDown, else key press debounce is not + * satisfied so change the state to KStateUp. + * + * KStateDown: + * In this state it checks for any key release. + * If KPress variable is cleared, then key + * release is indicated and so, switch the + * state to KStateFirstUp else to state + * KStateDown. + * + * KStateFirstUp: + * After debounce delay(10ms), if the KPress is + * still reset then pass the key release + * scancode to input device and change + * the state to KStateUp else key release is + * not satisfied so change the state to + * KStateDown. + */ + + for (row = 0; row < kpp_dev.kpp_rows; row++) { + for (col = 0; col < kpp_dev.kpp_cols; col++) { + if ((press_scancode[row][col] != -1)) { + /* Still Down, so add scancode */ + scancode = + press_scancode[row][col]; + + keyi[index].val = mxckpd_keycodes[scancode]; + keyi[index++].evt = KDepress; + + KPP_PRINTF("KStateFirstDown: scan=%d val=%d\n", + scancode, mxckpd_keycodes[scancode]); + if (index >= key_cnt) + goto key_detect; + + kpp_dev.iKeyState = KStateDown; + press_scancode[row][col] = -1; + } + } + } + + for (row = 0; row < kpp_dev.kpp_rows; row++) { + for (col = 0; col < kpp_dev.kpp_cols; col++) { + if ((release_scancode[row][col] != -1)) { + scancode = + release_scancode[row][col]; + scancode = + scancode - MXC_KEYRELEASE; + + keyi[index].val = mxckpd_keycodes[scancode]; + keyi[index++].evt = KRelease; + + KPP_PRINTF("KStateFirstUp: scan=%d val=%d\n", + scancode, mxckpd_keycodes[scancode]); + if (index >= key_cnt) + goto key_detect; + + kpp_dev.iKeyState = KStateUp; + release_scancode[row][col] = -1; + } + } + } + +key_detect: + mxc_kpp_reset(); + return key_cnt; +} + +/*! + * This function is called to free the allocated memory for local arrays + */ +static void mxc_kpp_free_allocated(void) +{ + int i; + + if (press_scancode) { + for (i = 0; i < kpp_dev.kpp_rows; i++) { + if (press_scancode[i]) + free(press_scancode[i]); + } + free(press_scancode); + } + + if (release_scancode) { + for (i = 0; i < kpp_dev.kpp_rows; i++) { + if (release_scancode[i]) + free(release_scancode[i]); + } + free(release_scancode); + } + + if (cur_rcmap) + free(cur_rcmap); + + if (prev_rcmap) + free(prev_rcmap); +} + +/*! + * This function is called during the driver binding process. + * + * @param pdev the device structure used to store device specific + * information that is used by the suspend, resume and remove + * functions. + * + * @return The function returns 0 on successful registration. Otherwise returns + * specific error code. + */ +int mxc_kpp_init(void) +{ + int i; + int retval; + unsigned int reg_val; + + kpp_dev.kpp_cols = CONFIG_MXC_KPD_COLMAX; + kpp_dev.kpp_rows = CONFIG_MXC_KPD_ROWMAX; + + /* clock and IOMUX configuration for keypad */ + setup_mxc_kpd(); + + /* Configure keypad */ + + /* Enable number of rows in keypad (KPCR[7:0]) + * Configure keypad columns as open-drain (KPCR[15:8]) + * + * Configure the rows/cols in KPP + * LSB nibble in KPP is for 8 rows + * MSB nibble in KPP is for 8 cols + */ + reg_val = __raw_readw(KPCR); + reg_val |= (1 << kpp_dev.kpp_rows) - 1; /* LSB */ + reg_val |= ((1 << kpp_dev.kpp_cols) - 1) << 8; /* MSB */ + __raw_writew(reg_val, KPCR); + + /* Write 0's to KPDR[15:8] */ + reg_val = __raw_readw(KPDR); + reg_val &= 0x00ff; + __raw_writew(reg_val, KPDR); + + /* Configure columns as output, + * rows as input (KDDR[15:0]) */ + reg_val = __raw_readw(KDDR); + reg_val |= 0xff00; + reg_val &= 0xff00; + __raw_writew(reg_val, KDDR); + + /* Clear the KPKD Status Flag + * and Synchronizer chain. */ + reg_val = __raw_readw(KPSR); + reg_val &= ~(KBD_STAT_KPKR | KBD_STAT_KPKD); + reg_val |= KBD_STAT_KPKD; + reg_val |= KBD_STAT_KRSS | KBD_STAT_KDSC; + __raw_writew(reg_val, KPSR); + /* Set the KDIE control bit, and clear the KRIE + * control bit (avoid false release events). */ + reg_val |= KBD_STAT_KDIE; + reg_val &= ~KBD_STAT_KRIE; + __raw_writew(reg_val, KPSR); + +#ifdef KPP_DEBUG + mxc_kpp_dump_regs(); +#endif + + mxckpd_keycodes = mxc_key_mapping; + mxckpd_keycodes_size = kpp_dev.kpp_cols * kpp_dev.kpp_rows; + + if ((mxckpd_keycodes == (void *)0) + || (mxckpd_keycodes_size == 0)) { + retval = -ENODEV; + goto err; + } + + /* allocate required memory */ + press_scancode = (short **)malloc(kpp_dev.kpp_rows * sizeof(press_scancode[0])); + release_scancode = (short **)malloc(kpp_dev.kpp_rows * sizeof(release_scancode[0])); + + if (!press_scancode || !release_scancode) { + retval = -ENOMEM; + goto err; + } + + for (i = 0; i < kpp_dev.kpp_rows; i++) { + press_scancode[i] = (short *)malloc(kpp_dev.kpp_cols + * sizeof(press_scancode[0][0])); + release_scancode[i] = + (short *)malloc(kpp_dev.kpp_cols * sizeof(release_scancode[0][0])); + + if (!press_scancode[i] || !release_scancode[i]) { + retval = -ENOMEM; + goto err; + } + } + + cur_rcmap = + (unsigned short *)malloc(kpp_dev.kpp_rows * sizeof(cur_rcmap[0])); + prev_rcmap = + (unsigned short *)malloc(kpp_dev.kpp_rows * sizeof(prev_rcmap[0])); + + if (!cur_rcmap || !prev_rcmap) { + retval = -ENOMEM; + goto err; + } + + for (i = 0; i < kpp_dev.kpp_rows; i++) { + memset(press_scancode[i], -1, + sizeof(press_scancode[0][0]) * kpp_dev.kpp_cols); + memset(release_scancode[i], -1, + sizeof(release_scancode[0][0]) * kpp_dev.kpp_cols); + } + memset(cur_rcmap, 0, kpp_dev.kpp_rows * sizeof(cur_rcmap[0])); + memset(prev_rcmap, 0, kpp_dev.kpp_rows * sizeof(prev_rcmap[0])); + + return 0; + +err: + mxc_kpp_free_allocated(); + return retval; +} diff --git a/include/configs/mx6slevk.h b/include/configs/mx6slevk.h index 3623bad..e0a6146 100644 --- a/include/configs/mx6slevk.h +++ b/include/configs/mx6slevk.h @@ -267,4 +267,8 @@ #endif #endif /* CONFIG_SPLASH_SCREEN */ +#if defined(CONFIG_ANDROID_SUPPORT) +#include "mx6slevkandroid.h" +#endif + #endif /* __CONFIG_H */ diff --git a/include/configs/mx6slevkandroid.h b/include/configs/mx6slevkandroid.h new file mode 100644 index 0000000..dfdf9ee --- /dev/null +++ b/include/configs/mx6slevkandroid.h @@ -0,0 +1,87 @@ + +/* + * Copyright (C) 2013 Freescale Semiconductor, Inc. + * + * Configuration android settings for the MX6SL EVK Freescale board. + * + * 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 MX6SL_EVK_ANDROID_H +#define MX6SL_EVK_ANDROID_H + +#include + +#define CONFIG_USB_DEVICE +#define CONFIG_IMX_UDC 1 + +#define CONFIG_FASTBOOT 1 +#define CONFIG_FASTBOOT_VENDOR_ID 0x18d1 +#define CONFIG_FASTBOOT_PRODUCT_ID 0x0d02 +#define CONFIG_FASTBOOT_BCD_DEVICE 0x311 +#define CONFIG_FASTBOOT_MANUFACTURER_STR "Freescale" +#define CONFIG_FASTBOOT_PRODUCT_NAME_STR "i.mx6sl EVK Board" +#define CONFIG_FASTBOOT_INTERFACE_STR "Android fastboot" +#define CONFIG_FASTBOOT_CONFIGURATION_STR "Android fastboot" +#define CONFIG_FASTBOOT_SERIAL_NUM "12345" +#define CONFIG_FASTBOOT_SATA_NO 0 + +#if defined CONFIG_SYS_BOOT_NAND +#define CONFIG_FASTBOOT_STORAGE_NAND +#elif defined CONFIG_SYS_BOOT_SATA +#define CONFIG_FASTBOOT_STORAGE_SATA +#else +#define CONFIG_FASTBOOT_STORAGE_MMC +#endif + +/* For system.img growing up more than 256MB, more buffer needs +* to receive the system.img*/ +#define CONFIG_FASTBOOT_TRANSFER_BUF 0x8c000000 +#define CONFIG_FASTBOOT_TRANSFER_BUF_SIZE 0x19000000 /* 400M byte */ + + +#define CONFIG_CMD_BOOTI +#define CONFIG_ANDROID_RECOVERY +/* which mmc bus is your main storage ? */ +#define CONFIG_ANDROID_MAIN_MMC_BUS 2 +#define CONFIG_ANDROID_BOOT_PARTITION_MMC 1 +#define CONFIG_ANDROID_SYSTEM_PARTITION_MMC 5 +#define CONFIG_ANDROID_RECOVERY_PARTITION_MMC 2 +#define CONFIG_ANDROID_CACHE_PARTITION_MMC 6 + +/*keyboard mapping*/ +#define CONFIG_VOL_DOWN_KEY KEY_BACK +#define CONFIG_POWER_KEY KEY_5 + +#define CONFIG_MXC_KPD +#define CONFIG_MXC_KEYMAPPING \ + { \ + KEY_SELECT, KEY_BACK, KEY_1, KEY_2, \ + KEY_3, KEY_4, KEY_5, KEY_MENU, \ + KEY_6, KEY_7, KEY_8, KEY_9, \ + KEY_UP, KEY_LEFT, KEY_RIGHT, KEY_DOWN, \ + } +#define CONFIG_MXC_KPD_COLMAX 4 +#define CONFIG_MXC_KPD_ROWMAX 4 + + +#undef CONFIG_EXTRA_ENV_SETTINGS +#undef CONFIG_BOOTCOMMAND + +#define CONFIG_EXTRA_ENV_SETTINGS \ + "splashpos=m,m\0" + +#endif diff --git a/include/mxc_keyb.h b/include/mxc_keyb.h new file mode 100644 index 0000000..cce1fb7 --- /dev/null +++ b/include/mxc_keyb.h @@ -0,0 +1,217 @@ +/* + * Copyright 2004-2013 Freescale Semiconductor, Inc. All Rights Reserved. + * + * 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 + */ + +/*! + * @defgroup keypad Keypad Driver + */ + +/*! + * @file mxc_keyb.h + * + * @brief MXC keypad header file. + * + * @ingroup keypad + */ +#ifndef __MXC_KEYB_H__ +#define __MXC_KEYB_H__ + +/*! + * Keypad Module Name + */ +#define MOD_NAME "mxckpd" + +/*! + * Keypad irq number + */ +#define KPP_IRQ MXC_INT_KPP + +/*! + * XLATE mode selection + */ +#define KEYPAD_XLATE 0 + +/*! + * RAW mode selection + */ +#define KEYPAD_RAW 1 + +/*! + * Maximum number of keys. + */ +#define MAXROW 8 +#define MAXCOL 8 +#define MXC_MAXKEY (MAXROW * MAXCOL) + +/*! + * This define indicates break scancode for every key release. A constant + * of 128 is added to the key press scancode. + */ +#define MXC_KEYRELEASE 128 + +/* + * _reg_KPP_KPCR _reg_KPP_KPSR _reg_KPP_KDDR _reg_KPP_KPDR + * Keypad Control Register Address + */ +#define KPCR (KPP_BASE_ADDR + 0x00) + +/* + * Keypad Status Register Address + */ +#define KPSR (KPP_BASE_ADDR + 0x02) + +/* + * Keypad Data Direction Address + */ +#define KDDR (KPP_BASE_ADDR + 0x04) + +/* + * Keypad Data Register + */ +#define KPDR (KPP_BASE_ADDR + 0x06) + +/* + * Key Press Interrupt Status bit + */ +#define KBD_STAT_KPKD 0x01 + +/* + * Key Release Interrupt Status bit + */ +#define KBD_STAT_KPKR 0x02 + +/* + * Key Depress Synchronizer Chain Status bit + */ +#define KBD_STAT_KDSC 0x04 + +/* + * Key Release Synchronizer Status bit + */ +#define KBD_STAT_KRSS 0x08 + +/* + * Key Depress Interrupt Enable Status bit + */ +#define KBD_STAT_KDIE 0x100 + +/* + * Key Release Interrupt Enable + */ +#define KBD_STAT_KRIE 0x200 + +/* + * Keypad Clock Enable + */ +#define KBD_STAT_KPPEN 0x400 + +/*! + * Buffer size of keypad queue. Should be a power of 2. + */ +#define KPP_BUF_SIZE 128 + +/*! + * Test whether bit is set for integer c + */ +#define TEST_BIT(c, n) ((c) & (0x1 << (n))) + +/*! + * Set nth bit in the integer c + */ +#define BITSET(c, n) ((c) | (1 << (n))) + +/*! + * Reset nth bit in the integer c + */ +#define BITRESET(c, n) ((c) & ~(1 << (n))) + +enum KeyEvent { + KDepress, + KRelease +}; + +/*! + * This enum represents the keypad state machine to maintain debounce logic + * for key press/release. + */ +enum KeyState { + + /*! + * Key press state. + */ + KStateUp, + + /*! + * Key press debounce state. + */ + KStateFirstDown, + + /*! + * Key release state. + */ + KStateDown, + + /*! + * Key release debounce state. + */ + KStateFirstUp +}; + +/*! + * Keypad Private Data Structure + */ +struct keypad_priv { + + /*! + * Keypad state machine. + */ + enum KeyState iKeyState; + + /*! + * Number of rows configured in the keypad matrix + */ + unsigned long kpp_rows; + + /*! + * Number of Columns configured in the keypad matrix + */ + unsigned long kpp_cols; +}; + +/*! + * Keypad Data Structure + * */ +struct kpp_key_info { + enum KeyEvent evt; + unsigned short val; +}; + +int mxc_kpp_init(void); +int mxc_kpp_getc(struct kpp_key_info **); + +/*! + * These functions are used to configure and the GPIO pins for keypad to + * activate and deactivate it. + */ +void setup_mxc_kpd(void); + + +#endif /* __MXC_KEYB_H__ */ -- cgit v1.1