[U-Boot] [PATCH] Add support for i.MX6SL EVK board keypad

nitin.garg at freescale.com nitin.garg at freescale.com
Sun Aug 31 23:31:32 CEST 2014


From: Nitin Garg <nitin.garg at freescale.com>

i.MX6sl evk has a keyboard on the board, so add mxc_keyb driver to
support keypad.

Signed-off-by: Nitin Garg <nitin.garg at freescale.com>
---
 drivers/input/Makefile   |    1 +
 drivers/input/mxc_keyb.c |  588 ++++++++++++++++++++++++++++++++++++++++++++++
 include/mxc_keyb.h       |  240 +++++++++++++++++++
 3 files changed, 829 insertions(+)
 create mode 100644 drivers/input/mxc_keyb.c
 create mode 100644 include/mxc_keyb.h

diff --git a/drivers/input/Makefile b/drivers/input/Makefile
index a8e9be2..8b1b86c 100644
--- a/drivers/input/Makefile
+++ b/drivers/input/Makefile
@@ -14,3 +14,4 @@ obj-$(CONFIG_PS2MULT) += ps2mult.o ps2ser.o
 endif
 obj-y += input.o
 obj-$(CONFIG_OF_CONTROL) += key_matrix.o
+obj-$(CONFIG_MXC_KPD) += mxc_keyb.o
diff --git a/drivers/input/mxc_keyb.c b/drivers/input/mxc_keyb.c
new file mode 100644
index 0000000..cc39208
--- /dev/null
+++ b/drivers/input/mxc_keyb.c
@@ -0,0 +1,588 @@
+/*
+ * Copyright (C) 2009-2014 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+/*!
+ * @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 <asm/errno.h>
+#include <linux/types.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;
+
+	/* 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
index 0000000..882fba2
--- /dev/null
+++ b/include/mxc_keyb.h
@@ -0,0 +1,240 @@
+/*
+ * Copyright (C) 2009-2014 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+/*!
+ * @defgroup keypad Keypad Driver
+ */
+
+/*!
+ * @file mxc_keyb.h
+ *
+ * @brief MXC keypad header file.
+ *
+ * @ingroup keypad
+ */
+#ifndef __MXC_KEYB_H__
+#define __MXC_KEYB_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 */
+
+/*!
+ * 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)))
+
+#ifndef CONFIG_MXC_KEYMAPPING
+#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, \
+	}
+#endif
+
+#ifndef CONFIG_MXC_KPD_COLMAX
+#define CONFIG_MXC_KPD_COLMAX 4
+#endif
+
+#ifndef CONFIG_MXC_KPD_ROWMAX
+#define CONFIG_MXC_KPD_ROWMAX 4
+#endif
+
+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 **);
+
+#endif				/* __MXC_KEYB_H__ */
-- 
1.7.9.5



More information about the U-Boot mailing list