MLK-12527-1 mxc_keyb: Add MXC keyboard driver
authorYe Li <ye.li@nxp.com>
Wed, 9 Mar 2016 12:59:43 +0000 (20:59 +0800)
committerYe Li <ye.li@nxp.com>
Thu, 29 Apr 2021 05:03:37 +0000 (22:03 -0700)
The i.MX6SL EVK needs this driver in android fastboot support. Add
this driver to u-boot.

To use the driver, user must define:

CONFIG_MXC_KPD          Enable the driver
CONFIG_MXC_KEYMAPPING   Key mapping matrix
CONFIG_MXC_KPD_COLMAX   The column size of key mapping matrix
CONFIG_MXC_KPD_ROWMAX   The row size of the key mapping matrix

Signed-off-by: Ye Li <ye.li@nxp.com>
(cherry picked from commit 5096e572667ff41217deb4ba9b1bd15e93fa6b59)
(cherry picked from commit e84160eaf5c057da45a227039c6f8a7911f43a82)
(cherry picked from commit 7f8757016e97adeacba256bd0cb6ad8882f6a51e)
(cherry picked from commit 79f5e8a3cc9bb1460dd06fa4909ff200d147377c)
(cherry picked from commit d62830ee536b70d2ac75a6ac692c67ee151d65e2)

arch/arm/include/asm/mach-imx/mxc_key_defs.h [new file with mode: 0644]
drivers/input/Makefile
drivers/input/mxc_keyb.c [new file with mode: 0644]
include/mxc_keyb.h [new file with mode: 0644]
scripts/config_whitelist.txt

diff --git a/arch/arm/include/asm/mach-imx/mxc_key_defs.h b/arch/arm/include/asm/mach-imx/mxc_key_defs.h
new file mode 100644 (file)
index 0000000..3c0f4ce
--- /dev/null
@@ -0,0 +1,38 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2009-2014 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ */
+
+#ifndef _MXC_KEYPAD_H_
+#define _MXC_KEYPAD_H_
+
+#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
index e440c92..e45b6d1 100644 (file)
@@ -14,4 +14,5 @@ obj-$(CONFIG_I8042_KEYB) += i8042.o
 obj-$(CONFIG_TEGRA_KEYBOARD) += input.o tegra-kbc.o
 obj-$(CONFIG_TWL4030_INPUT) += twl4030.o
 obj-$(CONFIG_TWL6030_INPUT) += twl6030.o
+obj-$(CONFIG_MXC_KPD) += mxc_keyb.o
 endif
diff --git a/drivers/input/mxc_keyb.c b/drivers/input/mxc_keyb.c
new file mode 100644 (file)
index 0000000..09b8ec1
--- /dev/null
@@ -0,0 +1,592 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2009-2014 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ */
+
+/*!
+ * @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 <asm/io.h>
+#include <common.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <asm/mach-imx/mxc_key_defs.h>
+#include <malloc.h>
+
+/*
+ *  * Module header file
+ *   */
+#include <mxc_keyb.h>
+
+/*!
+ * 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/mxc_keyb.h b/include/mxc_keyb.h
new file mode 100644 (file)
index 0000000..c432977
--- /dev/null
@@ -0,0 +1,201 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2009-2014 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ */
+
+/*!
+ * @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__ */
index 37f9552..c1505a6 100644 (file)
@@ -1099,6 +1099,10 @@ CONFIG_MX6DL_LPDDR2
 CONFIG_MX6DQ_LPDDR2
 CONFIG_MXC_EPDC
 CONFIG_MXC_GPT_HCLK
+CONFIG_MXC_KEYMAPPING
+CONFIG_MXC_KPD
+CONFIG_MXC_KPD_COLMAX
+CONFIG_MXC_KPD_ROWMAX
 CONFIG_MXC_MCI_REGS_BASE
 CONFIG_MXC_NAND_HWECC
 CONFIG_MXC_NAND_IP_REGS_BASE
@@ -1273,6 +1277,7 @@ CONFIG_POWER_FSL
 CONFIG_POWER_FSL_MC13892
 CONFIG_POWER_HI6553
 CONFIG_POWER_I2C
+CONFIG_POWER_KEY
 CONFIG_POWER_LTC3676
 CONFIG_POWER_LTC3676_I2C_ADDR
 CONFIG_POWER_MAX77696
@@ -3958,6 +3963,7 @@ CONFIG_VIDEO_VADC
 CONFIG_VID_FLS_ENV
 CONFIG_VM86
 CONFIG_VOIPAC_LCD
+CONFIG_VOL_DOWN_KEY
 CONFIG_VOL_MONITOR_INA220
 CONFIG_VOL_MONITOR_IR36021_READ
 CONFIG_VOL_MONITOR_IR36021_SET