diff --git a/arch/arm/configs/hs_defconfig b/arch/arm/configs/hs_defconfig
index a146d21..8ac5ea0 100644
--- a/arch/arm/configs/hs_defconfig
+++ b/arch/arm/configs/hs_defconfig
@@ -857,6 +857,7 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
 CONFIG_INPUT_KEYBOARD=y
 # CONFIG_KEYBOARD_ADP5588 is not set
 # CONFIG_KEYBOARD_ADP5589 is not set
+# CONFIG_KEYBOARD_K3V200 is not set
 CONFIG_KEYBOARD_ATKBD=y
 # CONFIG_KEYBOARD_QT1070 is not set
 # CONFIG_KEYBOARD_QT2160 is not set
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index 7ac9c98..d85370b 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -629,6 +629,16 @@ config KEYBOARD_W90P910
 	  To compile this driver as a module, choose M here: the
 	  module will be called w90p910_keypad.
 
+config KEYBOARD_K3V200
+	tristate "K3V200 Matrix Keypad support"
+	depends on ARCH_HS
+	select INPUT_MATRIXKMAP
+	help
+	  Say Y here to enable the matrix keypad support for k3v200 platform.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called k3_keypad.
+
 config KEYBOARD_CROS_EC
 	tristate "ChromeOS EC keyboard"
 	select INPUT_MATRIXKMAP
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
index 0c43e8c..75048fa 100644
--- a/drivers/input/keyboard/Makefile
+++ b/drivers/input/keyboard/Makefile
@@ -56,3 +56,4 @@ obj-$(CONFIG_KEYBOARD_TNETV107X)	+= tnetv107x-keypad.o
 obj-$(CONFIG_KEYBOARD_TWL4030)		+= twl4030_keypad.o
 obj-$(CONFIG_KEYBOARD_XTKBD)		+= xtkbd.o
 obj-$(CONFIG_KEYBOARD_W90P910)		+= w90p910_keypad.o
+obj-$(CONFIG_KEYBOARD_K3V200)		+= k3_keypad.o
diff --git a/drivers/input/keyboard/k3_keypad.c b/drivers/input/keyboard/k3_keypad.c
new file mode 100644
index 0000000..84fbf95
--- /dev/null
+++ b/drivers/input/keyboard/k3_keypad.c
@@ -0,0 +1,680 @@
+
+/*
+ * Hisilicon hi3620 keypda driver
+ *
+ * Copyright (c) 2012-2013 Hisilicon Limited.
+ * Copyright (c) 2012-2013 Linaro Limited.
+ *
+ * Author: Xin Li <li.xin@linaro.org>
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/input.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <asm/irq.h>
+#include <linux/gpio.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/of.h>
+#include "k3_keypad.h"
+#include <linux/input/matrix_keypad.h>
+
+/*The switch to support long-press key and combo key*/
+#define ADVANCED_FUNCTION_SUPPORT
+
+#define KPC_MAX_ROWS                                    (8)
+#define KPC_MAX_COLS                                    (8)
+#define KEY_RELEASE                                     (0)
+#define KEY_PRESS                                       (1)
+#define KPC_BIT_PER_KEY                                 (6)
+#define KPC_BIT_PER_KEYROW                              (3)
+
+/*KPC clock frequency*/
+#define KPC_CLK_RATE					(32768)
+
+/*KPC Register Offset*/
+#define KPC_CONTROL_OFFSET                              (0x000)
+#define KPC_INTERVAL_SHORT_OFFSET                       (0x004)
+#define KPC_INT_STATUS_OFFSET                           (0x01C)
+#define KPC_INT_CLR_OFFSET                              (0x058)
+#define KPC_RELEASE_INT_CLR_OFFSET                      (0x06C)
+
+/*BITMASK in KPC_INT_STATUS REG */
+#define KEY_NUM_BITMASK                                 (0x3C0000)
+#define KEY_NUM_BITPOS                                  (18)
+#define KEY_VALUE_BITMASK                               (0xFFF)
+#define KEY_VALUE_BITPOS                                (0)
+#define KPC_RELEASE_INT_BITMASK                         (0x40000000)
+#define KPC_RELEASE_INT_BITPOS                          (30)
+
+/*REG config value */
+/* [8:0]: 0_0000_0011    */
+#define KPC_VAL_CTLREG                                  (0x023)
+/* 120 x 250us = 30ms    */
+#define KPC_VAL_SHORT_INTERVAL                          (0x28)
+
+struct k3v2_keypad {
+	struct input_dev *input_dev;
+	void __iomem     *base;
+	int				 irq;
+	struct clk       *clk;
+	int               rows;
+	int               cols;
+	int               row_shift;
+	/* Used for keymap*/
+	unsigned short    keycodes[KPC_MAX_ROWS * KPC_MAX_COLS];
+	/* Used for result of keypad scan*/
+	unsigned char     scancode_state[KPC_MAX_ROWS];
+	/* Used for store all keycode state*/
+	uint16_t          keycode_state[KPC_MAX_ROWS * 2];
+};
+
+
+static struct keypad_remap *keypad_long_remap;
+static struct keypad_remap_state *g_long_remap_state;
+
+static int k3v2_keypad_open(struct input_dev *dev)
+{
+	struct k3v2_keypad *keypad = input_get_drvdata(dev);
+	struct pinctrl *block = NULL;
+	int ret = 0;
+
+	if (keypad == NULL) {
+		dev_err(&dev->dev, "get invalid keypad pointer\n");
+		return -EINVAL;
+	}
+
+	block = devm_pinctrl_get_select_default(&dev->dev);
+	if (!block) {
+		dev_warn(&keypad->input_dev->dev, "Failed to get KPC GPIO BLOCK\n");
+		ret = -EINVAL;
+	}
+	/*Clean interrupt*/
+	writel(0x1, keypad->base + KPC_INT_CLR_OFFSET);
+	writel(0x1, keypad->base + KPC_RELEASE_INT_CLR_OFFSET);
+	/*config KPC_CONTROL REG*/
+	writel(KPC_VAL_CTLREG, keypad->base + KPC_CONTROL_OFFSET);
+	/*config KPC_INTERVAL_SHORT REG*/
+	writel(KPC_VAL_SHORT_INTERVAL,
+	       keypad->base + KPC_INTERVAL_SHORT_OFFSET);
+
+	enable_irq(keypad->irq);
+	return ret;
+}
+
+static void k3v2_keypad_close(struct input_dev *dev)
+{
+	struct k3v2_keypad *keypad = input_get_drvdata(dev);
+
+	if (keypad == NULL) {
+		dev_err(&dev->dev, "get invalid keypad pointer\n");
+		return;
+	}
+
+	disable_irq(keypad->irq);
+}
+
+/* Update the new_keycode_state*/
+static void
+k3v2_keypad_update_keycode(struct k3v2_keypad *keypad,
+			   unsigned char *new_scancode_state,
+			   uint16_t *new_keycode_state)
+{
+	int row = 0;
+	int col = 0;
+	int r = 0;
+	int c = 0;
+	int index = 0;
+	uint8_t keycode = 0;
+
+	for (row = 0; row < KPC_MAX_ROWS; row++) {
+		for (col = 0; col < KPC_MAX_COLS; col++) {
+			if (new_scancode_state[row] & (1 << col)) {
+				index = MATRIX_SCAN_CODE(row, col,
+							 keypad->row_shift);
+				keycode = keypad->keycodes[index];
+				c = keycode & 0x0F;
+				r = keycode >> 4;
+				new_keycode_state[r] |= (1 << c);
+			}
+		}
+	}
+}
+
+/*Remap long-press func key or combo keys to target keys.*/
+static void
+k3v2_keypad_remap_keycode(struct k3v2_keypad *keypad,
+			  struct keypad_remap_state *remap_state,
+			  uint16_t *new_keycode_state)
+{
+	int i = 0;
+	int j = 0;
+
+	unsigned long current_time = jiffies_to_msecs(jiffies);
+
+	if (!remap_state)
+		return;
+
+	for (i = 0; i < keypad_long_remap->count; i++) {
+
+		int down_num = 0;
+		uint16_t keycode;
+		unsigned char key_down_state = 0;
+		struct keypad_remap_item *item = &keypad_long_remap->items[i];
+		struct keypad_remap_state *state = &remap_state[i];
+
+		for (j = 0; j < item->keynum; j++) {
+			keycode = item->keycodes[j];
+			if (KEYPAD_CHECK_KEYCODE(new_keycode_state, keycode)
+						 != 0) {
+				key_down_state |= (1 << j);
+				down_num++;
+			}
+		}
+		/*the number of down keys are enough to remap.*/
+		if (down_num >= item->keynum) {
+			if (item->keynum > 1) {
+				/*clean all mapping keys in new_keycode_state*/
+				for (j = 0; j < item->keynum; j++) {
+					keycode = item->keycodes[j];
+					KEYPAD_CLR_KEYCODE(new_keycode_state,
+							   keycode);
+				}
+				/*set the remapped keycode*/
+				keycode = item->target_keycode;
+				KEYPAD_SET_KEYCODE(new_keycode_state, keycode);
+				state->pending = false;
+				state->remapped = true;
+			} else {
+				/*start pending period*/
+				if ((state->pending == false) &&
+				    (state->remapped == false)) {
+					state->pending = true;
+					state->time = current_time +
+						      item->delay;
+				}
+				KEYPAD_CLR_KEYCODE(new_keycode_state,
+						   item->keycodes[0]);
+				/*if pending, then check if it is timeout*/
+				if (state->pending == true) {
+					/*
+					 * it behinds timeout,
+					 * then set the remapped keycode
+					 */
+					if (current_time >= state->time) {
+						keycode = item->target_keycode;
+						KEYPAD_SET_KEYCODE(
+							new_keycode_state,
+							keycode);
+
+						state->pending = false;
+						state->remapped = true;
+					}
+				} else if (state->remapped == true) {
+					keycode = item->target_keycode;
+					KEYPAD_SET_KEYCODE(new_keycode_state,
+							   keycode);
+				}
+			}
+		}
+		/*keys down, but not enough number for combo keys*/
+		else if (down_num > 0) {
+			if ((state->remapped == true) ||
+			    (state->pending == false) ||
+			    (current_time < state->time)) {
+
+				if ((state->pending == false) &&
+				    (state->remapped == false)) {
+					state->pending = true;
+					state->time = current_time +
+						      item->delay;
+				}
+
+				for (j = 0; j < item->keynum; j++) {
+					keycode = item->keycodes[j];
+					KEYPAD_CLR_KEYCODE(new_keycode_state,
+							   keycode);
+				}
+			}
+		} else {
+			/*All keys are up.
+			 *If pending, set the cleaned remapping keys back.
+			 *Then call timer to report again.*/
+			if (state->pending) {
+				for (j = 0; j < item->keynum; j++) {
+					if (((state->down_state) &
+					    (1 << j)) != 0) {
+						keycode = item->keycodes[j];
+						input_report_key(
+							keypad->input_dev,
+							keycode, 1);
+						input_report_key(
+							keypad->input_dev,
+							keycode, 0);
+						input_sync(keypad->input_dev);
+					}
+				}
+				state->pending = false;
+			}
+			state->remapped = false;
+		}
+		/*save keys*/
+		state->down_state = key_down_state;
+	}
+}
+
+static void k3v2_keypad_report_keycode(struct k3v2_keypad *keypad,
+				       uint16_t *new_keycode_state)
+{
+	int row = 0;
+	int col = 0;
+	unsigned int keycode = 0;
+	unsigned int  pressed = 0;
+	uint16_t changed = 0;
+
+	for (row = 0; row < KPC_MAX_ROWS * 2; row++) {
+		changed = keypad->keycode_state[row] ^ new_keycode_state[row];
+		if (0 == changed)
+			continue;
+		for (col = 0; col < KPC_MAX_COLS * 2; col++) {
+			if (changed & (1 << col)) {
+				keycode = (row << 4) | (col & 0x0F);
+				pressed = (new_keycode_state[row] &
+					   (1 << col)) >> col;
+				dev_dbg(&keypad->input_dev->dev,
+					"row = %d, col = %d, keycode = %d, press = %d\n",
+					row, col, keycode, pressed);
+				input_report_key(keypad->input_dev,
+						 keycode, pressed);
+			}
+		}
+	}
+	input_sync(keypad->input_dev);
+}
+
+
+static irqreturn_t k3v2_keypad_irq_handler(int irq, void *dev_id)
+{
+	struct k3v2_keypad  *keypad       = dev_id;
+	unsigned int         reg          = 0;
+	unsigned int         key_num      = 0;
+	unsigned int         key_val      = 0;
+
+	int                  row          = 0;
+	int                  col          = 0;
+	int                  i            = 0;
+#ifndef ADVANCED_FUNCTION_SUPPORT
+	unsigned int  changed;
+	unsigned int  pressed;
+	unsigned int  val = 0;
+#endif /* #ifndef ADVANCED_FUNCTION_SUPPORT */
+	unsigned char new_scancode_state[ARRAY_SIZE(keypad->scancode_state)];
+	uint16_t      new_keycode_state[ARRAY_SIZE(keypad->keycode_state)];
+
+	memset(new_scancode_state, 0, sizeof(new_scancode_state));
+	memset(new_keycode_state, 0, sizeof(new_keycode_state));
+
+	reg = readl(keypad->base + KPC_INT_STATUS_OFFSET);
+	key_num =  (reg & KEY_NUM_BITMASK)   >> KEY_NUM_BITPOS;
+	key_val =  (reg & KEY_VALUE_BITMASK) >> KEY_VALUE_BITPOS;
+
+	for (i = 0; i < key_num; i++) {
+		row = (key_val >> (i*KPC_BIT_PER_KEY)) & 0x7;
+		col = (key_val >> (i*KPC_BIT_PER_KEY + KPC_BIT_PER_KEYROW)) &
+			0x7;
+		new_scancode_state[row] |= (1 << col);
+	}
+
+#ifndef ADVANCED_FUNCTION_SUPPORT
+	for (row = 0; row < keypad->rows; row++) {
+		changed = new_scancode_state[row] ^ keypad->scancode_state[row];
+		if (!changed)
+			continue;
+
+		for (col = 0; col < keypad->cols; col++) {
+			if (changed & (1 << col)) {
+				val = MATRIX_SCAN_CODE(row, col,
+						       keypad->row_shift);
+				pressed = (new_scancode_state[row] &
+					   (1 << col)) >> col;
+				input_report_key(keypad->input_dev,
+						 keypad->keycodes[val],
+						 pressed);
+				dev_dbg(&keypad->input_dev->dev,
+					"key_num = %d, row = %d, col = %d, press = %d\n",
+					key_num, row, col, pressed);
+			}
+		}
+	}
+	input_sync(keypad->input_dev);
+	memcpy(keypad->scancode_state, new_scancode_state,
+	       sizeof(new_scancode_state));
+#else
+	k3v2_keypad_update_keycode(keypad, new_scancode_state,
+				   new_keycode_state);
+	k3v2_keypad_remap_keycode(keypad, g_long_remap_state,
+				  new_keycode_state);
+	k3v2_keypad_report_keycode(keypad, new_keycode_state);
+	memcpy(keypad->scancode_state, new_scancode_state,
+	       sizeof(new_scancode_state));
+	memcpy(keypad->keycode_state, new_keycode_state,
+	       sizeof(new_keycode_state));
+#endif
+
+	/*Clean interrupt*/
+	writel(0x1, keypad->base + KPC_INT_CLR_OFFSET);
+	writel(0x1, keypad->base + KPC_RELEASE_INT_CLR_OFFSET);
+	return IRQ_HANDLED;
+}
+
+#ifdef CONFIG_OF
+/* Keypad device and platform data start, use KPC realizing keypad. */
+static const uint32_t default_keymap[] = {
+	/*row, col, key*/
+	/* used for truly platform.*/
+	KEY(0, 0, KEY_MENU),
+	KEY(1, 0, KEY_SEND),
+	KEY(2, 0, KEY_VOLUMEUP),
+
+	KEY(0, 1, KEY_HOME),
+	KEY(1, 1, KEY_END),
+	KEY(2, 1, KEY_VOLUMEDOWN),
+
+	KEY(0, 2, KEY_CAMERA_FOCUS),
+	KEY(1, 2, KEY_CAMERA),
+	KEY(2, 2, DPAD_CENTER),
+
+	/* TODO: add your keys below*/
+
+	/*Used for software function, not physical connection!*/
+
+};
+
+static struct matrix_keymap_data hisik3_keymap_data = {
+	.keymap = default_keymap,
+	.keymap_size = ARRAY_SIZE(default_keymap),
+};
+static uint16_t long_func_key1[] = {KEY_BACK};
+
+static struct keypad_remap_item remap_items[] = {
+	{KEY_HOME, 1, 1000/*ms*/, long_func_key1},
+	/*TODO: add your remap_item here*/
+};
+
+static struct keypad_remap hisik3_keypad_long_remap = {
+	.count = ARRAY_SIZE(remap_items),
+	.items = remap_items,
+};
+
+static struct k3v2_keypad_platdata hisik3_keypad_platdata = {
+	.keymap_data = &hisik3_keymap_data,
+	.keypad_remap = &hisik3_keypad_long_remap,
+	.rows = 8,
+	.cols = 8,
+	.row_shift = 3,
+};
+
+static const struct of_device_id keypad_match[] = {
+	{ .compatible = "hisilicon,k3_keypad",
+	  .data = &hisik3_keypad_platdata,
+	},
+	{},
+};
+MODULE_DEVICE_TABLE(of, keypad_match);
+#endif
+
+static int k3v2_keypad_probe(struct platform_device *pdev)
+{
+	const struct k3v2_keypad_platdata *platdata;
+	const struct matrix_keymap_data   *keymap_data;
+	struct k3v2_keypad                *keypad;
+	struct resource                   *res;
+	struct input_dev                  *input_dev;
+	int      err;
+#ifdef CONFIG_OF
+	const struct of_device_id *match;
+
+	match = of_match_node(keypad_match, pdev->dev.of_node);
+	platdata = match->data;
+#else
+	platdata = pdev->dev.platform_data;
+#endif
+	if (!platdata) {
+		dev_err(&pdev->dev, "platform data is null!\n");
+		return -EINVAL;
+	}
+	keymap_data = platdata->keymap_data;
+	if (!keymap_data) {
+		dev_err(&pdev->dev, "keymap data is null!\n");
+		return -EINVAL;
+	}
+
+	if (!platdata->rows || platdata->rows > KPC_MAX_ROWS) {
+		dev_err(&pdev->dev, "keypad rows is null or bigger than the max rows!\n");
+		return -EINVAL;
+	}
+
+	if (!platdata->cols || platdata->cols > KPC_MAX_COLS) {
+		dev_err(&pdev->dev, "keypad cols is null or bigger than the max cols!\n");
+		return -EINVAL;
+	}
+
+	keypad = kzalloc(sizeof(struct k3v2_keypad) , GFP_KERNEL);
+	if (!keypad) {
+		dev_err(&pdev->dev, "Failed to allocate struct k3v2_keypad!\n");
+		err = -ENOMEM;
+	}
+
+	input_dev = input_allocate_device();
+	if (!input_dev) {
+		dev_err(&pdev->dev, "Failed to allocate struct k3v2_keypad or input_dev!\n");
+		err = -ENOMEM;
+		goto err_alloc_input_device;
+	}
+
+	keypad_long_remap = platdata->keypad_remap;
+	if (!keypad_long_remap) {
+		dev_err(&pdev->dev, "Failed to get_keypad_long_remap!\n");
+		err = -EINVAL;
+		goto err_get_keypad_remap;
+	}
+
+	g_long_remap_state = kzalloc(keypad_long_remap->count *
+				     sizeof(struct keypad_remap_state),
+				     GFP_KERNEL);
+	if (!g_long_remap_state) {
+		dev_err(&pdev->dev, "Failed to allocate g_long_remap_state!\n");
+		err = -ENOMEM;
+		goto err_alloc_remap_state;
+	}
+	/*Get REG_BASE_KPC address*/
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "Failed to get KPC base address!\n");
+		err = -ENODEV;
+		goto err_get_base;
+	}
+
+	keypad->base = ioremap(res->start, resource_size(res));
+	if (!keypad->base) {
+		dev_err(&pdev->dev, "Failed to remap KPC base address!\n");
+		err = -EBUSY;
+		goto err_ioremap_base;
+	}
+
+	/*get clock*/
+	keypad->clk = clk_get(&pdev->dev, NULL);
+	if (IS_ERR(keypad->clk)) {
+		dev_err(&pdev->dev, "Failed to get clk_kpc!\n");
+		err = -ENODEV;
+		goto err_get_clk;
+	}
+	err = clk_set_rate(keypad->clk, KPC_CLK_RATE);
+	if (err < 0) {
+		dev_err(&pdev->dev, "Failed to set clk rate!\n");
+		goto err_set_clk;
+	}
+	clk_prepare_enable(keypad->clk);
+
+	keypad->input_dev = input_dev;
+	keypad->row_shift = platdata->row_shift;
+	keypad->rows = platdata->rows;
+	keypad->cols = platdata->cols;
+
+	input_dev->name = pdev->name;
+	input_dev->id.bustype = BUS_HOST;
+	input_dev->dev.parent = &pdev->dev;
+	input_set_drvdata(input_dev, keypad);
+	set_bit(EV_KEY, input_dev->evbit);
+	set_bit(EV_SYN, input_dev->evbit);
+	input_dev->keycode = keypad->keycodes;
+	input_dev->keycodesize = sizeof(keypad->keycodes[0]);
+	input_dev->open = k3v2_keypad_open;
+	input_dev->close = k3v2_keypad_close;
+
+	matrix_keypad_build_keymap(keymap_data, "keypad_default_keymap",
+				   keypad->rows, keypad->cols,
+				   input_dev->keycode, input_dev);
+
+	keypad->irq = platform_get_irq(pdev, 0);
+	if (keypad->irq < 0) {
+		dev_err(&pdev->dev, "Failed to get irq!\n");
+		err = keypad->irq;
+		goto err_get_irq;
+
+	}
+
+	err = request_irq(keypad->irq, k3v2_keypad_irq_handler,
+			  IRQF_NO_SUSPEND, pdev->name, keypad);
+	if (err) {
+		dev_err(&pdev->dev, "Failed to request interupt handler!\n");
+		goto err_request_irq;
+	}
+
+	disable_irq(keypad->irq);
+
+	err = input_register_device(keypad->input_dev);
+	if (err) {
+		dev_err(&pdev->dev, "Failed to register input device!\n");
+		goto err_register_device;
+	}
+
+	device_init_wakeup(&pdev->dev, true);
+	platform_set_drvdata(pdev, keypad);
+	dev_info(&pdev->dev, "k3v2 keypad probe successfully!\n");
+
+	return 0;
+
+err_register_device:
+	free_irq(keypad->irq, keypad);
+err_request_irq:
+err_get_irq:
+	clk_disable_unprepare(keypad->clk);
+err_set_clk:
+	clk_put(keypad->clk);
+err_get_clk:
+	iounmap(keypad->base);
+err_ioremap_base:
+err_get_base:
+	kfree(g_long_remap_state);
+err_alloc_remap_state:
+err_get_keypad_remap:
+	input_free_device(input_dev);
+err_alloc_input_device:
+	kfree(keypad);
+
+	pr_info("K3v2 keypad probe failed! ret = %d\n", err);
+	return err;
+}
+
+static int k3v2_keypad_remove(struct platform_device *pdev)
+{
+	struct k3v2_keypad *keypad =  platform_get_drvdata(pdev);
+
+	if (keypad == NULL) {
+		dev_err(&pdev->dev, "get invalid keypad pointer\n");
+		return -EINVAL;
+	}
+
+	free_irq(keypad->irq, keypad);
+	iounmap(keypad->base);
+
+	clk_disable_unprepare(keypad->clk);
+	clk_put(keypad->clk);
+
+	input_unregister_device(keypad->input_dev);
+	platform_set_drvdata(pdev, NULL);
+	kfree(keypad);
+
+	if (!g_long_remap_state)
+		kfree(g_long_remap_state);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int k3v2_keypad_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	pr_info("[keypad]suspend successfully\n");
+	return 0;
+}
+
+static int k3v2_keypad_resume(struct platform_device *pdev)
+{
+	pr_info("[keypad]resume successfully\n");
+	return 0;
+}
+#endif
+
+
+
+struct platform_driver k3v2_keypad_driver = {
+	.probe = k3v2_keypad_probe,
+	.remove = k3v2_keypad_remove,
+	.driver = {
+		.name = "k3_keypad",
+		.owner = THIS_MODULE,
+		.of_match_table = of_match_ptr(keypad_match),
+	},
+#ifdef CONFIG_PM
+	.suspend = k3v2_keypad_suspend,
+	.resume = k3v2_keypad_resume,
+#endif
+};
+
+static int __init k3v2_keypad_init(void)
+{
+	pr_info("k3v2 keypad init!\n");
+	return platform_driver_register(&k3v2_keypad_driver);
+}
+
+static void __exit k3v2_keypad_exit(void)
+{
+	platform_driver_unregister(&k3v2_keypad_driver);
+}
+
+module_init(k3v2_keypad_init);
+module_exit(k3v2_keypad_exit);
+MODULE_DESCRIPTION("Hi3620 keypad platform driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/keyboard/k3_keypad.h b/drivers/input/keyboard/k3_keypad.h
new file mode 100644
index 0000000..8183021
--- /dev/null
+++ b/drivers/input/keyboard/k3_keypad.h
@@ -0,0 +1,47 @@
+#ifndef _K3_KEYPAD_H_
+#define _K3_KEYPAD_H_
+#include <linux/input/matrix_keypad.h>
+
+#define DPAD_CENTER 232
+
+#define KEYPAD_CHECK_KEYCODE(map, keycode)	\
+	(map[(keycode) >> 4] & (1 << ((keycode) & 0x0F)))
+#define KEYPAD_SET_KEYCODE(map, keycode)	\
+	(map[(keycode) >> 4] |= (1 << ((keycode) & 0x0F)))
+#define KEYPAD_CLR_KEYCODE(map, keycode)	\
+	(map[(keycode) >> 4] &= ~(1 << ((keycode) & 0x0F)))
+
+
+struct k3v2_keypad_platdata {
+	struct matrix_keymap_data	*keymap_data;
+	struct keypad_remap		*keypad_remap;
+	unsigned int			rows;
+	unsigned int			cols;
+	unsigned int			row_shift;
+};
+
+/*
+ * target_keycode: target keycode remapped to
+ * keynum        : number of keycodes to remap
+ * delay         : timeout for pending
+ */
+struct keypad_remap_item {
+	uint16_t target_keycode;
+	uint16_t keynum;
+	uint16_t delay;
+	uint16_t *keycodes;
+};
+
+struct keypad_remap_state {
+	bool pending;
+	bool remapped;
+	unsigned int time;
+	unsigned char down_state;
+};
+
+struct keypad_remap {
+	int count;
+	struct keypad_remap_item *items;
+};
+
+#endif
