From 30161e0af987cc12864a0d172a0787c07e156ca1 Mon Sep 17 00:00:00 2001 From: wangzijiao Date: Thu, 2 Aug 2018 15:50:03 +0800 Subject: [PATCH] add key driver --- .../linux-4.9/drivers/input/keyboard/Kconfig | 11 +- .../linux-4.9/drivers/input/keyboard/Makefile | 1 + .../drivers/input/keyboard/R16-keyboard-pv1.c | 418 ++++++++++++++++++ target/allwinner/mandolin-pv1/config-4.9 | 4 + 4 files changed, 433 insertions(+), 1 deletion(-) create mode 100755 lichee/linux-4.9/drivers/input/keyboard/R16-keyboard-pv1.c diff --git a/lichee/linux-4.9/drivers/input/keyboard/Kconfig b/lichee/linux-4.9/drivers/input/keyboard/Kconfig index b1c3d1135..30cc54efe 100644 --- a/lichee/linux-4.9/drivers/input/keyboard/Kconfig +++ b/lichee/linux-4.9/drivers/input/keyboard/Kconfig @@ -713,6 +713,8 @@ config KEYBOARD_CROS_EC To compile this driver as a module, choose M here: the module will be called cros_ec_keyb. + + config KEYBOARD_CAP11XX tristate "Microchip CAP11XX based touch sensors" depends on OF && I2C @@ -735,7 +737,14 @@ config KEYBOARD_BCM module will be called bcm-keypad. config KEYBOARD_SUNXI - tristate "softwinnner KEY BOARD support" + tristate "softwinnner KEY BOARD support!" + help + Say Y here to enable the keyboard, support 7 keys. + based on verify board. + + +config KEYBOARD_NETEASE_PV1 + tristate "KEYBOARD_NETEASE_PV1!" help Say Y here to enable the keyboard, support 7 keys. based on verify board. diff --git a/lichee/linux-4.9/drivers/input/keyboard/Makefile b/lichee/linux-4.9/drivers/input/keyboard/Makefile index b54e7d93b..1388f71bc 100644 --- a/lichee/linux-4.9/drivers/input/keyboard/Makefile +++ b/lichee/linux-4.9/drivers/input/keyboard/Makefile @@ -65,3 +65,4 @@ obj-$(CONFIG_KEYBOARD_TWL4030) += twl4030_keypad.o obj-$(CONFIG_KEYBOARD_XTKBD) += xtkbd.o obj-$(CONFIG_KEYBOARD_W90P910) += w90p910_keypad.o obj-$(CONFIG_KEYBOARD_SUNXI) += sunxi-keyboard.o +obj-$(CONFIG_KEYBOARD_NETEASE_PV1) += R16-keyboard-pv1.o diff --git a/lichee/linux-4.9/drivers/input/keyboard/R16-keyboard-pv1.c b/lichee/linux-4.9/drivers/input/keyboard/R16-keyboard-pv1.c new file mode 100755 index 000000000..61d0ccc2f --- /dev/null +++ b/lichee/linux-4.9/drivers/input/keyboard/R16-keyboard-pv1.c @@ -0,0 +1,418 @@ +/********************************************************************************* + * Copyright: (C) 2017 NetEase(Hangzhou) Network Co., Ltd. + * All rights reserved. + * + * Filename: R16-keyboard.c + * Description: This is the common button driver runs on S3C2440 + * + * Version: 1.0.0(8/3/2017) + * Author: Netease IHW + * ChangeLog: 1, Release initial version + * + ********************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define USED_SYSCONF 0 +#define DRV_NAME ("r16kbd") +#define GPIO_HOME_KEY GPIOL(9) +#define GPIO_MUTE_KEY GPIOL(9) +#if USED_SYSCONF +struct encoder_gkey_config { + u32 encoder1_gkey; + u32 encoder2_gkey; +}; +#else +#define GPIO_ENCODER1 GPIOL(11) +#define GPIO_ENCODER2 GPIOL(12) + +struct Volkey_status { + u8 nVolup; + u8 nVoldown; +}; + +#endif + +enum { + DEBUG_INIT = 1U << 0, + DEBUG_INT = 1U << 1, + DEBUG_DATA_INFO = 1U << 2, + DEBUG_SUSPEND = 1U << 3, +}; +static u32 debug_mask = 0; +#define dprintk(level_mask, fmt, arg...) \ + if (unlikely(debug_mask & level_mask)) \ + printk(fmt, ##arg) + +struct gpio_keys_button_data { + int last_state; + int count; + int threshold; + int can_sleep; +}; + +struct gpio_keys_polled_dev { + struct input_polled_dev *poll_dev; + struct device *dev; + struct gpio_keys_platform_data *pdata; + struct gpio_keys_button_data data[0]; +}; + +#if USED_SYSCONF +static struct encoder_gkey_config *r16_gkey; +#endif +static struct Volkey_status *sVolkey_status; +static struct input_dev *tymr16kbd_dev; +static struct input_polled_dev *poll_dev; +#define VOL_CONFIRM 5 +#define GPIO_BUTTON(gpio_num, ev_code, act_low, descr, wake, debounce) \ + { \ + .gpio = gpio_num, .type = EV_KEY, .code = ev_code, \ + .active_low = act_low, .desc = "btn " descr, .wakeup = wake, \ + .debounce_interval = debounce, \ + } + +static struct gpio_keys_button tym_r16_buttons[] = { + GPIO_BUTTON(GPIO_HOME_KEY, KEY_HOME, 1, "user-key-home", 0, 1), +}; + +struct rotary_encoder_data { + u8 encoder_state; +}; + +static struct gpio_keys_platform_data tym_r16_button_data = { + .buttons = tym_r16_buttons, + .nbuttons = ARRAY_SIZE(tym_r16_buttons), + .poll_interval = 50, + .name = "tymkey", +}; + +static void init_nVol(void) { + sVolkey_status->nVolup = 0; + sVolkey_status->nVoldown = 0; +} + +static irqreturn_t rotary_encoder_check_state_irq(int irq, void *dummy) { + int state_a, state_b; +#if USED_SYSCONF + state_a = !!gpio_get_value(r16_gkey->encoder1_gkey); + state_b = !!gpio_get_value(r16_gkey->encoder2_gkey); +#else + state_a = !!gpio_get_value(GPIO_ENCODER1); + state_b = !!gpio_get_value(GPIO_ENCODER2); +#endif + if (state_b != state_a) { + sVolkey_status->nVoldown++; + /*dprintk(DEBUG_INIT,"encoder check state v+ \n"); + input_event(tymr16kbd_dev, EV_KEY, KEY_VOLUMEDOWN, 2); + input_sync(tymr16kbd_dev);*/ + } else { + sVolkey_status->nVolup++; + /*dprintk(DEBUG_INIT,"encoder check state v- \n"); + input_event(tymr16kbd_dev, EV_KEY, KEY_VOLUMEUP, 2); + input_sync(tymr16kbd_dev);*/ + } + if (sVolkey_status->nVoldown > VOL_CONFIRM) { + init_nVol(); + dprintk(DEBUG_INIT, "encoder check state v+ \n"); + input_event(tymr16kbd_dev, EV_KEY, KEY_VOLUMEDOWN, 2); + input_sync(tymr16kbd_dev); + } + if (sVolkey_status->nVolup > VOL_CONFIRM) { + init_nVol(); + dprintk(DEBUG_INIT, "encoder check state v- \n"); + input_event(tymr16kbd_dev, EV_KEY, KEY_VOLUMEUP, 2); + input_sync(tymr16kbd_dev); + } + return IRQ_HANDLED; +} +static void gpio_keys_polled_check_state(struct input_dev *input, + struct gpio_keys_button *button, + struct gpio_keys_button_data *bdata) { + int state; + // dprintk(DEBUG_INIT,"gpio_keys_polled_check_state\n"); + if (bdata->can_sleep) + state = !!gpio_get_value_cansleep(button->gpio); + else + state = !!gpio_get_value(button->gpio); + if (state != bdata->last_state) { + unsigned int type = button->type ?: EV_KEY; + dprintk(DEBUG_INIT, "button->gpio, %d , state, %d \n", button->gpio, + state); + + input_event(input, type, button->code, !!(state ^ button->active_low)); + input_sync(input); + bdata->count = 0; + bdata->last_state = state; + } +} + +static void gpio_keys_polled_poll(struct input_polled_dev *dev) { + struct gpio_keys_polled_dev *bdev = dev->private; + struct gpio_keys_platform_data *pdata = bdev->pdata; + struct input_dev *input = dev->input; + int i; + // dprintk(DEBUG_INIT,"gpio_keys_polled_poll"); + for (i = 0; i < bdev->pdata->nbuttons; i++) { + struct gpio_keys_button_data *bdata = &bdev->data[i]; + gpio_keys_polled_check_state(input, &pdata->buttons[i], bdata); + } +} + +static void gpio_keys_polled_open(struct input_polled_dev *dev) { + struct gpio_keys_polled_dev *bdev = dev->private; + struct gpio_keys_platform_data *pdata = bdev->pdata; + + if (pdata->enable) + pdata->enable(bdev->dev); +} + +static void gpio_keys_polled_close(struct input_polled_dev *dev) { + struct gpio_keys_polled_dev *bdev = dev->private; + struct gpio_keys_platform_data *pdata = bdev->pdata; + + if (pdata->disable) + pdata->disable(bdev->dev); +} + +#if USED_SYSCONF +static int GPIO_fetch_sysconfig_para(void) { + int ret = -1; + int gpio_used = -1; + script_item_u val; + script_item_value_type_e type; + dprintk(DEBUG_INIT, "gpio fetch sysconfig para!\n"); + + r16_gkey = input_allocate_device(); + if (!r16_gkey) { + pr_err("tymkbd: not enough memory for input device\n"); + ret = -ENOMEM; + goto script_get_item_err; + } + + type = script_get_item("gkey_para", "gkey_used", &val); + if (SCIRPT_ITEM_VALUE_TYPE_INT != type) { + pr_err("%s: gkey_used script_get_item err. \n", __func__); + goto script_get_item_err; + } + gpio_used = val.val; + + if (1 == gpio_used) { + type = script_get_item("gkey_para", "gkey_encoder1", &val); + if (SCIRPT_ITEM_VALUE_TYPE_PIO != type) { + goto script_get_item_err; + } + r16_gkey->encoder1_gkey = val.gpio.gpio; + type = script_get_item("gkey_para", "gkey_encoder2", &val); + if (SCIRPT_ITEM_VALUE_TYPE_PIO != type) { + goto script_get_item_err; + } + r16_gkey->encoder2_gkey = val.gpio.gpio; + ret = 0; + } else { + pr_err("%s: gkey_unused. \n", __func__); + ret = -1; + } + +script_get_item_err: + printk("get gpio fetch sysconfig para error!\n"); + + return ret; +} +#endif + +static int __init r16_button_init(void) { +#if 1 + struct gpio_keys_polled_dev *bdev; + int i; + int error; + int virq; + dprintk(DEBUG_INIT, "r16_button_init\n"); +#if USED_SYSCONF + GPIO_fetch_sysconfig_para(); +#endif + sVolkey_status = kzalloc(sizeof(struct Volkey_status), GFP_KERNEL); + init_nVol(); + bdev = kzalloc(sizeof(struct gpio_keys_polled_dev) + + tym_r16_button_data.nbuttons * + sizeof(struct gpio_keys_button_data), + GFP_KERNEL); + if (!bdev) { + pr_err("no memory for private data\n"); + return -ENOMEM; + } + bdev->pdata = &tym_r16_button_data; + poll_dev = input_allocate_polled_device(); + if (!poll_dev) { + pr_err("no memory for polled device\n"); + goto err_free_bdev; + } + poll_dev->private = bdev; + poll_dev->poll = gpio_keys_polled_poll; + poll_dev->poll_interval = 50; + // poll_dev->open = gpio_keys_polled_open; + // poll_dev->close = gpio_keys_polled_close; + + tymr16kbd_dev = input_allocate_device(); + if (!tymr16kbd_dev) { + pr_err("tymkbd: not enough memory for input device\n"); + error = -ENOMEM; + goto fail1; + } + tymr16kbd_dev->name = DRV_NAME; + tymr16kbd_dev->phys = "r16kbd/input0"; + tymr16kbd_dev->id.bustype = BUS_HOST; + tymr16kbd_dev->id.vendor = 0x0001; + tymr16kbd_dev->id.product = 0x0001; + tymr16kbd_dev->id.version = 0x0100; + tymr16kbd_dev->evbit[0] = BIT_MASK(EV_KEY); + poll_dev->input = tymr16kbd_dev; + for (i = 0; i < tym_r16_button_data.nbuttons; i++) { + struct gpio_keys_button *button = &tym_r16_buttons[i]; + // struct gpio_keys_button_data *bdata = &bdev->data[i]; + unsigned int gpio = tym_r16_buttons[i].gpio; + unsigned int type = tym_r16_buttons[i].type ?: EV_KEY; + unsigned int desc = tym_r16_buttons[i].desc ?: DRV_NAME; + error = gpio_request(gpio, desc); + if (error) { + pr_err("unable to claim gpio %u, err=%d\n", gpio, error); + goto err_free_gpio; + } + + error = gpio_direction_input(gpio); + if (error) { + pr_err("unable to set direction on gpio %u, err=%d\n", gpio, error); + goto err_free_gpio; + } + + // bdata->can_sleep = gpio_cansleep(gpio); + // bdata->last_state = -1; + // bdata->threshold = + //DIV_ROUND_UP(button->debounce_interval, poll_dev->poll_interval); + + input_set_capability(tymr16kbd_dev, type, button->code); + } + + input_set_capability(tymr16kbd_dev, EV_KEY, KEY_VOLUMEUP); + input_set_capability(tymr16kbd_dev, EV_KEY, KEY_VOLUMEDOWN); + + error = input_register_polled_device(poll_dev); + if (error) { + pr_err("unable to register polled device, err=%d\n", error); + goto err_free_gpio; + } +/* + for (i = 0; i < tym_r16_button_data.nbuttons; i++) + gpio_keys_polled_check_state(tymr16kbd_dev, &tym_r16_buttons[i], + &bdev->data[i]); +*/ +#if USED_SYSCONF + gpio_request(r16_gkey->encoder2_gkey, "gpio_encoder2"); + gpio_direction_input(r16_gkey->encoder2_gkey); + + virq = gpio_to_irq(r16_gkey->encoder1_gkey); + if (request_irq(virq, rotary_encoder_check_state_irq, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "r16kbd", + NULL)) { + // err = -EBUSY; + pr_err("request irq failure. \n"); + goto fail2; + } + if (request_irq(virq, rotary_encoder_check_rising_state_irq, + IRQF_TRIGGER_RISING, "r16kbd", NULL)) { + // err = -EBUSY; + pr_err("request irq failure. \n"); + goto fail2; + } + + if (request_irq(virq, rotary_encoder_check_falling_state_irq, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "r16kbd", + NULL)) { + // err = -EBUSY; + pr_err("request irq failure. \n"); + goto fail2; + } +#else + gpio_request(GPIO_ENCODER2, "gpio_encoder2"); + gpio_direction_input(GPIO_ENCODER2); + + virq = gpio_to_irq(GPIO_ENCODER1); + if (request_irq(virq, rotary_encoder_check_state_irq, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "r16kbd", + NULL)) { + // err = -EBUSY; + pr_err("request irq failure. \n"); + goto fail2; + } +#endif + + dprintk(DEBUG_INIT, "Regist R16 %s device successfully.\n", DRV_NAME); + + return 0; + +err_free_gpio: + while (--i >= 0) + gpio_free(tym_r16_buttons[i].gpio); + + input_free_polled_device(poll_dev); + +err_free_bdev: + kfree(bdev); +fail1: + pr_err("sunxikbd_init failed. \n"); + +fail2: + kfree(sVolkey_status); + free_irq(virq, NULL); +#if USED_SYSCONF + gpio_free(r16_gkey->encoder2_gkey); +#else + gpio_free(GPIO_ENCODER2); +#endif + return error; +#endif +} + +static void r16_button_exit(void) { + int i; + int virq; + + input_unregister_polled_device(poll_dev); + + for (i = 0; i < tym_r16_button_data.nbuttons; i++) + gpio_free(tym_r16_button_data.buttons[i].gpio); + + input_free_polled_device(poll_dev); +#if USED_SYSCONF + gpio_free(r16_gkey->encoder2_gkey); + virq = gpio_to_irq(r16_gkey->encoder1_gkey); +#else + gpio_free(GPIO_ENCODER2); + virq = gpio_to_irq(GPIO_ENCODER1); +#endif + free_irq(virq, NULL); + kfree(sVolkey_status); + kfree(tymr16kbd_dev); + dprintk(DEBUG_INIT, "R16 %s platform device removed.\n", DRV_NAME); + return 0; +} + +module_init(r16_button_init); +module_exit(r16_button_exit); + +MODULE_AUTHOR("Netease IHW"); +MODULE_DESCRIPTION("Netease r16 button driver"); +MODULE_LICENSE("GPL"); diff --git a/target/allwinner/mandolin-pv1/config-4.9 b/target/allwinner/mandolin-pv1/config-4.9 index 317468594..a23e10cd5 100644 --- a/target/allwinner/mandolin-pv1/config-4.9 +++ b/target/allwinner/mandolin-pv1/config-4.9 @@ -454,6 +454,7 @@ CONFIG_INPUT_KEYBOARD=y # CONFIG_INPUT_KEYCOMBO is not set # CONFIG_INPUT_KEYRESET is not set # CONFIG_INPUT_MISC is not set +CONFIG_INPUT_POLLDEV=y # CONFIG_INPUT_SENSOR is not set CONFIG_INPUT_SENSORINIT=y CONFIG_INPUT_TOUCHSCREEN=y @@ -488,6 +489,9 @@ CONFIG_KERNEL_GZIP=y # CONFIG_KERNEL_MODE_NEON is not set # CONFIG_KERNEL_XZ is not set CONFIG_KEYBOARD_ATKBD=y +CONFIG_KEYBOARD_GPIO=y +CONFIG_KEYBOARD_GPIO_POLLED=y +CONFIG_KEYBOARD_NETEASE_PV1=y # CONFIG_KEYBOARD_SUN4I_LRADC is not set CONFIG_KEYBOARD_SUNXI=y # CONFIG_KS7010 is not set