From 1b65a2504c96fe4251d4e096849d465952431590 Mon Sep 17 00:00:00 2001 From: LiXin Date: Mon, 1 Apr 2013 10:04:28 +0800 Subject: ARM: Hi4511 add kpc node to DTS Add KPC node to hi3620.dtsi and hi4511.dts Signed-off-by: LiXin --- arch/arm/boot/dts/hi3620.dtsi | 7 +++++++ arch/arm/boot/dts/hi4511.dts | 16 ++++++---------- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/arch/arm/boot/dts/hi3620.dtsi b/arch/arm/boot/dts/hi3620.dtsi index 33cb3c28f8a..dfe0b764f70 100644 --- a/arch/arm/boot/dts/hi3620.dtsi +++ b/arch/arm/boot/dts/hi3620.dtsi @@ -1348,5 +1348,12 @@ #size-cells = <0>; clocks = <&clk_mmc3>; }; + kpc: kpc@fc805000 { + compatible = "hisilicon,k3_keypad"; + reg = <0xfc805000 0x1000>; + interrupts = <0 10 4>; + clocks = <&clk_kpc>; + status = "disabled"; + }; }; }; diff --git a/arch/arm/boot/dts/hi4511.dts b/arch/arm/boot/dts/hi4511.dts index aad79d01119..a124213bde0 100644 --- a/arch/arm/boot/dts/hi4511.dts +++ b/arch/arm/boot/dts/hi4511.dts @@ -103,6 +103,12 @@ status = "ok"; }; + kpc: kpc@fc805000 { + pinctrl-names = "default"; + pinctrl-0 = <&kpc_pmx_func &kpc_cfg_func>; + status = "ok"; + }; + gpio0: gpio@fc806000 { status = "ok"; }; @@ -366,16 +372,6 @@ 0x114 0x0 /* KEY_OUT2 (IOMG67) */ >; }; - kpc_pmx_idle: pinmux_kpc_pins@1 { - pinctrl-single,pins = < - 0x12c 0x1 /* GPIO (IOMG73) */ - 0x130 0x1 /* GPIO (IOMG74) */ - 0x134 0x1 /* GPIO (IOMG75) */ - 0x10c 0x1 /* GPIO (IOMG65) */ - 0x110 0x1 /* GPIO (IOMG66) */ - 0x114 0x1 /* GPIO (IOMG67) */ - >; - }; gpio_key_func: pinmux_gpiokey_pins { pinctrl-single,pins = < 0x10c 0x1 /* KEY_OUT0/GPIO (IOMG65) */ -- cgit v1.2.3 From eec26bc7d69c5d8e83eee27163ac360ba5d4d155 Mon Sep 17 00:00:00 2001 From: LiXin Date: Mon, 1 Apr 2013 10:36:36 +0800 Subject: =?UTF-8?q?ARM:=20Hi3620=EF=BC=9A=20Add=20keypad=20driver=20to=20H?= =?UTF-8?q?i3620?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add Keypad Driver to Hi3620 platform. Signed-off-by: LiXin --- drivers/input/keyboard/Kconfig | 9 + drivers/input/keyboard/Makefile | 1 + drivers/input/keyboard/k3_keypad.c | 647 +++++++++++++++++++++++++++++++++++++ drivers/input/keyboard/k3_keypad.h | 44 +++ 4 files changed, 701 insertions(+) create mode 100755 drivers/input/keyboard/k3_keypad.c create mode 100644 drivers/input/keyboard/k3_keypad.h diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index 5a240c60342..f8889ee2d61 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -618,4 +618,13 @@ 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. endif diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile index 44e76002f54..635d2049da1 100644 --- a/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile @@ -54,3 +54,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 100755 index 00000000000..b8b1c682eb8 --- /dev/null +++ b/drivers/input/keyboard/k3_keypad.c @@ -0,0 +1,647 @@ +/* kernel/drivers/input/keyboard/k3_keypad.c + * + * K3 Keypad Driver + * Copyright (C) 2011 Hisilicon + * + * 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 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "k3_keypad.h" +#include + +/*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 */ +#define KPC_VAL_CTLREG (0x023) /* [8:0]: 0_0000_0011 */ +#define KPC_VAL_SHORT_INTERVAL (0x28) /* 120 x 250us = 30ms */ + +struct k3v2_keypad { + struct input_dev *input_dev; + void __iomem *base; + int irq; + struct clk *clk; + int rows; + int cols; + int row_shift; + unsigned short keycodes[KPC_MAX_ROWS * KPC_MAX_COLS]; /* Used for keymap*/ + unsigned char scancode_state[KPC_MAX_ROWS]; /* Used for result of keypad scan*/ + uint16_t keycode_state[KPC_MAX_ROWS * 2]; /* Used for store all keycode state*/ +}; + + +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){ + printk(KERN_ERR "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){ + printk(KERN_ERR "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; + const 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*/ +#if 0 + /* 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), +#endif + + /*row, col, key*/ + /* used for debug only.*/ + KEY(0, 0, KEY_MENU), + KEY(0, 1, KEY_BACK), + + KEY(1, 0, KEY_LEFT), + KEY(1, 1, KEY_RIGHT), + + KEY(2, 0, KEY_UP), + + KEY(2, 1, KEY_DOWN), + KEY(2, 2, DPAD_CENTER), + + KEY(0, 2, KEY_CAMERA_FOCUS), + KEY(1, 2, KEY_CAMERA), + + /* 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 uint16_t long_func_key2[] = {DPAD_CENTER, KEY_VOLUMEDOWN}; + +static struct keypad_remap_item remap_items[] = { + {KEY_HOME, 1, 1000/*ms*/, long_func_key1}, + /*{KEY_A, 2, 500, long_func_key2},*/ + /*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 = (struct keypad_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){ + printk(KERN_ERR "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_AUTHOR("Hisilicon K3 Driver Group"); +MODULE_DESCRIPTION("K3v2 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 00000000000..734d4c0d83f --- /dev/null +++ b/drivers/input/keyboard/k3_keypad.h @@ -0,0 +1,44 @@ +#ifndef _K3_KEYPAD_H_ +#define _K3_KEYPAD_H_ +#include + +#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 -- cgit v1.2.3 From 1c02813ecc3191ecec2d4794d39da1758446c195 Mon Sep 17 00:00:00 2001 From: LiXin Date: Mon, 1 Apr 2013 10:37:56 +0800 Subject: ARM: Hi3620: Add keypad configuration to hs_defconfig Add Keypad configuration to hs_defconfig Signed-off-by: LiXin --- arch/arm/configs/hs_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/configs/hs_defconfig b/arch/arm/configs/hs_defconfig index 3eb2cb11244..94cdfd4807e 100644 --- a/arch/arm/configs/hs_defconfig +++ b/arch/arm/configs/hs_defconfig @@ -860,6 +860,7 @@ CONFIG_INPUT_EVDEV=y 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 -- cgit v1.2.3 From ffbcffff5119ff419a54a1c20c9250301e7bff48 Mon Sep 17 00:00:00 2001 From: LiXin Date: Wed, 3 Apr 2013 09:46:35 +0800 Subject: ARM: Hi3620: Fix some coding style warnings Fix some warnings and errors regarding checkpatch.pl Signed-off-by: LiXin --- drivers/input/keyboard/k3_keypad.c | 36 +++++++++++++++++++++--------------- drivers/input/keyboard/k3_keypad.h | 9 ++++++--- 2 files changed, 27 insertions(+), 18 deletions(-) diff --git a/drivers/input/keyboard/k3_keypad.c b/drivers/input/keyboard/k3_keypad.c index b8b1c682eb8..c4944943fc7 100755 --- a/drivers/input/keyboard/k3_keypad.c +++ b/drivers/input/keyboard/k3_keypad.c @@ -45,7 +45,7 @@ #define KPC_BIT_PER_KEYROW (3) /*KPC clock frequency*/ -#define KPC_CLK_RATE (32768) +#define KPC_CLK_RATE (32768) /*KPC Register Offset*/ #define KPC_CONTROL_OFFSET (0x000) @@ -63,8 +63,10 @@ #define KPC_RELEASE_INT_BITPOS (30) /*REG config value */ -#define KPC_VAL_CTLREG (0x023) /* [8:0]: 0_0000_0011 */ -#define KPC_VAL_SHORT_INTERVAL (0x28) /* 120 x 250us = 30ms */ +/* [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; @@ -74,9 +76,12 @@ struct k3v2_keypad { int rows; int cols; int row_shift; - unsigned short keycodes[KPC_MAX_ROWS * KPC_MAX_COLS]; /* Used for keymap*/ - unsigned char scancode_state[KPC_MAX_ROWS]; /* Used for result of keypad scan*/ - uint16_t keycode_state[KPC_MAX_ROWS * 2]; /* Used for store all keycode state*/ + /* 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]; }; @@ -89,8 +94,8 @@ static int k3v2_keypad_open(struct input_dev *dev) struct pinctrl *block = NULL; int ret = 0; - if(keypad == NULL){ - printk(KERN_ERR "get invalid keypad pointer\n"); + if (keypad == NULL) { + dev_err(dev, "get invalid keypad pointer\n"); return -EINVAL; } @@ -105,7 +110,8 @@ static int k3v2_keypad_open(struct input_dev *dev) /*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); + writel(KPC_VAL_SHORT_INTERVAL, + keypad->base + KPC_INTERVAL_SHORT_OFFSET); enable_irq(keypad->irq); return ret; @@ -115,8 +121,8 @@ static void k3v2_keypad_close(struct input_dev *dev) { struct k3v2_keypad *keypad = input_get_drvdata(dev); - if(keypad == NULL){ - printk(KERN_ERR "get invalid keypad pointer\n"); + if (keypad == NULL) { + dev_err(dev, "get invalid keypad pointer\n"); return; } @@ -413,7 +419,7 @@ static const struct of_device_id keypad_match[] = { MODULE_DEVICE_TABLE(of, keypad_match); #endif -static int k3v2_keypad_probe(struct platform_device* pdev) +static int k3v2_keypad_probe(struct platform_device *pdev) { const struct k3v2_keypad_platdata *platdata; const struct matrix_keymap_data *keymap_data; @@ -450,7 +456,7 @@ static int k3v2_keypad_probe(struct platform_device* pdev) } keypad = kzalloc(sizeof(struct k3v2_keypad) , GFP_KERNEL); - if(!keypad) { + if (!keypad) { dev_err(&pdev->dev, "Failed to allocate struct k3v2_keypad!\n"); err = -ENOMEM; } @@ -578,8 +584,8 @@ static int k3v2_keypad_remove(struct platform_device* pdev) { struct k3v2_keypad *keypad = platform_get_drvdata(pdev); - if(keypad == NULL){ - printk(KERN_ERR "get invalid keypad pointer\n"); + if (keypad == NULL) { + dev_err(dev, "get invalid keypad pointer\n"); return -EINVAL; } diff --git a/drivers/input/keyboard/k3_keypad.h b/drivers/input/keyboard/k3_keypad.h index 734d4c0d83f..9e8ed9dcfe2 100644 --- a/drivers/input/keyboard/k3_keypad.h +++ b/drivers/input/keyboard/k3_keypad.h @@ -4,9 +4,12 @@ #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))) +#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 { -- cgit v1.2.3