From e249bb4c5955fae0d8be42aa0a8e54d47c8cec4e Mon Sep 17 00:00:00 2001 From: "xingyu.chen" Date: Sat, 8 Jul 2017 11:11:49 +0800 Subject: [PATCH] adc_keypad: optimize the driver PD#146614: adc_keypad: optimize the driver 1. replace the input device with the input poll-device 2. move "adc_keypad.h" to driver directory "amlogic/input/keyboard/" Change-Id: I532c920e41bc3ee9048768b0db9d90eb55d962ce Signed-off-by: xingyu.chen --- MAINTAINERS | 3 +- drivers/amlogic/input/keyboard/adc_keypad.c | 236 ++++++++++----------- .../amlogic/input/keyboard}/adc_keypad.h | 8 +- 3 files changed, 122 insertions(+), 125 deletions(-) rename {include/linux/amlogic => drivers/amlogic/input/keyboard}/adc_keypad.h (92%) diff --git a/MAINTAINERS b/MAINTAINERS index 938a276..ab180e1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -13456,7 +13456,8 @@ F: Documentation/devicetree/bindings/iio/adc/amlogic,meson-saradc.txt AMLOGIC adc_keypad M: Xingyu Chen -F: drivers/amlogic/input/keyboard/* +F: drivers/amlogic/input/keyboard/adc_keypad.c +F: drivers/amlogic/input/keyboard/adc_keypad.h AMLOGIC EFUSE DRIVER M: Yun Cai diff --git a/drivers/amlogic/input/keyboard/adc_keypad.c b/drivers/amlogic/input/keyboard/adc_keypad.c index e63173c..225bd6e 100644 --- a/drivers/amlogic/input/keyboard/adc_keypad.c +++ b/drivers/amlogic/input/keyboard/adc_keypad.c @@ -28,12 +28,12 @@ #include #include #include -#include +#include #include +#include "adc_keypad.h" -#define POLL_PERIOD_WHEN_KEY_DOWN 20 /* unit msec */ -#define POLL_PERIOD_WHEN_KEY_UP 50 -#define KEY_JITTER_COUNT 1 /* 1 * POLL_PERIOD_WHEN_KEY_DOWN msec */ +#define POLL_INTERVAL_DEFAULT 20 +#define KEY_JITTER_COUNT 1 #define TMP_BUF_MAX 128 static char adc_key_mode_name[MAX_NAME_LEN] = "abcdef"; @@ -65,55 +65,39 @@ static int meson_adc_kp_search_key(struct meson_adc_kp *kp) return KEY_RESERVED; } -static void meson_adc_kp_work(struct meson_adc_kp *kp) +static void meson_adc_kp_poll(struct input_polled_dev *dev) { + struct meson_adc_kp *kp = dev->private; + int code = meson_adc_kp_search_key(kp); - if (code) - kp->poll_period = POLL_PERIOD_WHEN_KEY_DOWN; - if ((!code) && (!kp->report_code)) { - if (kp->poll_period < POLL_PERIOD_WHEN_KEY_UP) - kp->poll_period++; - return; - } else if (code != kp->code) { - kp->code = code; - kp->count = 0; - } else if (kp->count < KEY_JITTER_COUNT) { - kp->count++; - } else { - if ((kp->report_code != code) && keypad_enable_flag) { - if (!code) { /* key up */ - dev_info(&kp->input->dev, - "key %d up\n", kp->report_code); - input_report_key(kp->input, kp->report_code, 0); - input_sync(kp->input); - } else if (!kp->report_code) { /* key down */ - input_report_key(kp->input, code, 1); - input_sync(kp->input); - } else { - dev_info(&kp->input->dev, - "key %d up(f)\n", kp->report_code); - input_report_key(kp->input, kp->report_code, 0); - input_report_key(kp->input, code, 1); - input_sync(kp->input); + if (kp->report_code && kp->report_code != code) { + dev_info(&kp->poll_dev->input->dev, + "key %d up\n", kp->report_code); + input_report_key(kp->poll_dev->input, kp->report_code, 0); + input_sync(kp->poll_dev->input); + kp->report_code = 0; + } + + if (code) { + if (kp->count > 0 && code != kp->prev_code) + kp->count = 0; + + if (kp->count < KEY_JITTER_COUNT) + kp->count++; + else { + if (keypad_enable_flag && kp->report_code != code) { + dev_info(&kp->poll_dev->input->dev, + "key %d down\n", code); + input_report_key(kp->poll_dev->input, code, 1); + input_sync(kp->poll_dev->input); + kp->report_code = code; } - kp->report_code = code; + kp->count = 0; } + kp->prev_code = code; } -} -static void update_work_func(struct work_struct *work) -{ - struct meson_adc_kp *kp = container_of(work, - struct meson_adc_kp, work_update); - meson_adc_kp_work(kp); -} - -static void meson_adc_kp_timer_sr(unsigned long data) -{ - struct meson_adc_kp *kp = (struct meson_adc_kp *)data; - schedule_work(&(kp->work_update)); - mod_timer(&kp->timer, jiffies+msecs_to_jiffies(kp->poll_period)); } #ifdef CONFIG_AMLOGIC_LEGACY_EARLY_SUSPEND @@ -121,15 +105,17 @@ static void meson_adc_kp_early_suspend(struct early_suspend *h) { struct meson_adc_kp *kp = container_of(h, struct meson_adc_kp, early_suspend); - del_timer_sync(&kp->timer); - cancel_work_sync(&kp->work_update); + + cancel_delayed_work_sync(&kp->poll_dev->work); } static void meson_adc_kp_late_resume(struct early_suspend *h) { struct meson_adc_kp *kp = container_of(h, struct meson_adc_kp, early_suspend); - mod_timer(&kp->timer, jiffies+msecs_to_jiffies(kp->poll_period)); + + queue_delayed_work(system_freezable_wq, &kp->poll_dev->work, + msecs_to_jiffies(kp->poll_dev->poll_interval)); } #endif @@ -191,6 +177,7 @@ static int meson_adc_kp_get_devtree_pdata(struct platform_device *pdev, { int ret; int count; + int value; int state = 0; unsigned char cnt; const char *uname; @@ -210,6 +197,12 @@ static int meson_adc_kp_get_devtree_pdata(struct platform_device *pdev, return -ENODATA; } + ret = of_property_read_u32(pdev->dev.of_node, "poll-interval", &value); + if (ret) + kp->poll_period = POLL_INTERVAL_DEFAULT; + else + kp->poll_period = value; + for (cnt = 0; cnt < count; cnt++) { ret = of_parse_phandle_with_args(pdev->dev.of_node, "io-channels", "#io-channel-cells", cnt, &chanspec); @@ -304,10 +297,7 @@ static int meson_adc_kp_get_devtree_pdata(struct platform_device *pdev, state = -EINVAL; goto err; } - mutex_lock(&kp->kp_lock); - set_bit(key->code, kp->input->keybit); /*set event code*/ list_add_tail(&key->list, &kp->adckey_head); - mutex_unlock(&kp->kp_lock); } meson_adc_kp_get_valid_chan(kp); return 0; @@ -330,44 +320,6 @@ static void meson_adc_kp_list_free(struct meson_adc_kp *kp) mutex_unlock(&kp->kp_lock); } -static int kp_input_dev_register(struct platform_device *pdev, - struct meson_adc_kp *kp) -{ - /*alloc input device*/ - kp->input = input_allocate_device(); - if (!kp->input) { - dev_err(&pdev->dev, "alloc input device failed!\n"); - return -ENOMEM; - } - - /* init input device */ - set_bit(EV_KEY, kp->input->evbit); - set_bit(EV_REP, kp->input->evbit); - kp->input->name = "adc_keypad"; - kp->input->phys = "adc_keypad/input0"; - kp->input->dev.parent = &pdev->dev; - - kp->input->id.bustype = BUS_ISA; - kp->input->id.vendor = 0x0001; - kp->input->id.product = 0x0001; - kp->input->id.version = 0x0100; - - kp->input->rep[REP_DELAY] = 0xffffffff; - kp->input->rep[REP_PERIOD] = 0xffffffff; - - kp->input->keycodesize = sizeof(unsigned short); - kp->input->keycodemax = 0x1ff; - - /*register input device*/ - if (input_register_device(kp->input) < 0) { - dev_err(&pdev->dev, - "unable to register keypad input device.\n"); - return -EINVAL; - } - - return 0; -} - static ssize_t table_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -511,12 +463,12 @@ static ssize_t table_store(struct device *dev, struct device_attribute *attr, dev_info(dev, "del older key => %s:%d:%d:%d:%d\n", key->name, key->code, key->chan, key->value, key->tolerance); - clear_bit(key->code, kp->input->keybit); + clear_bit(key->code, kp->poll_dev->input->keybit); list_del(&key->list); kfree(key); } } - set_bit(dkey->code, kp->input->keybit); + set_bit(dkey->code, kp->poll_dev->input->keybit); list_add_tail(&dkey->list, &kp->adckey_head); dev_info(dev, "add newer key => %s:%d:%d:%d:%d\n", dkey->name, dkey->code, dkey->chan, dkey->value, dkey->tolerance); @@ -532,10 +484,21 @@ err: static DEVICE_ATTR_RW(table); +static void meson_adc_kp_init_keybit(struct meson_adc_kp *kp) + +{ + struct adc_key *key; + + list_for_each_entry(key, &kp->adckey_head, list) + set_bit(key->code, + kp->poll_dev->input->keybit); /*set event code*/ +} + static int meson_adc_kp_probe(struct platform_device *pdev) { struct meson_adc_kp *kp; - int state = 0; + struct input_dev *input; + int ret = 0; send_data_to_bl301(); kernel_keypad_enable_mode_enable(); @@ -548,39 +511,70 @@ static int meson_adc_kp_probe(struct platform_device *pdev) mutex_init(&kp->kp_lock); INIT_LIST_HEAD(&kp->adckey_head); kp->report_code = 0; - kp->code = 0; - kp->poll_period = POLL_PERIOD_WHEN_KEY_UP; + kp->prev_code = 0; kp->count = 0; - INIT_WORK(&(kp->work_update), update_work_func); - setup_timer(&kp->timer, meson_adc_kp_timer_sr, (unsigned long)kp); - if (kp_input_dev_register(pdev, kp) < 0) { - state = -EINVAL; + ret = meson_adc_kp_get_devtree_pdata(pdev, kp); + if (ret) goto err; - } - if (meson_adc_kp_get_devtree_pdata(pdev, kp) < 0) { - meson_adc_kp_list_free(kp); - state = -EINVAL; + + /*alloc input poll device*/ + kp->poll_dev = devm_input_allocate_polled_device(&pdev->dev); + if (!kp->poll_dev) { + dev_err(&pdev->dev, "alloc input poll device failed!\n"); + ret = -ENOMEM; goto err; } + + kp->poll_dev->poll = meson_adc_kp_poll; + kp->poll_dev->poll_interval = kp->poll_period; + kp->poll_dev->private = kp; + input = kp->poll_dev->input; + + set_bit(EV_KEY, input->evbit); + set_bit(EV_REP, input->evbit); + meson_adc_kp_init_keybit(kp); + + input->name = "adc_keypad"; + input->phys = "adc_keypad/input0"; + input->dev.parent = &pdev->dev; + + input->id.bustype = BUS_ISA; + input->id.vendor = 0x0001; + input->id.product = 0x0001; + input->id.version = 0x0100; + + input->rep[REP_DELAY] = 0xffffffff; + input->rep[REP_PERIOD] = 0xffffffff; + + input->keycodesize = sizeof(unsigned short); + input->keycodemax = 0x1ff; + #ifdef CONFIG_AMLOGIC_LEGACY_EARLY_SUSPEND kp->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN; kp->early_suspend.suspend = meson_adc_kp_early_suspend; kp->early_suspend.resume = meson_adc_kp_late_resume; register_early_suspend(&kp->early_suspend); #endif - if (sysfs_create_file(&pdev->dev.kobj, &dev_attr_table.attr) < 0) { + ret = sysfs_create_file(&pdev->dev.kobj, &dev_attr_table.attr); + if (ret) { dev_err(&pdev->dev, "create sysfs file failed!\n"); - state = -EINVAL; goto err; } - /*enable timer*/ - mod_timer(&kp->timer, jiffies+msecs_to_jiffies(100)); - return 0; + + /*register input poll device*/ + ret = input_register_polled_device(kp->poll_dev); + if (ret) { + dev_err(&pdev->dev, + "unable to register keypad input poll device.\n"); + goto err; + } + + return ret; + err: - if (kp->input) - input_free_device(kp->input); + meson_adc_kp_list_free(kp); kfree(kp); - return state; + return ret; } static int meson_adc_kp_remove(struct platform_device *pdev) @@ -591,10 +585,6 @@ static int meson_adc_kp_remove(struct platform_device *pdev) #ifdef CONFIG_AMLOGIC_LEGACY_EARLY_SUSPEND unregister_early_suspend(&kp->early_suspend); #endif - del_timer_sync(&kp->timer); - cancel_work_sync(&kp->work_update); - input_unregister_device(kp->input); - input_free_device(kp->input); meson_adc_kp_list_free(kp); kfree(kp); return 0; @@ -612,10 +602,10 @@ static int meson_adc_kp_resume(struct platform_device *pdev) if (get_resume_method() == POWER_KEY_WAKEUP) { dev_info(&pdev->dev, "adc keypad wakeup\n"); - input_report_key(kp->input, KEY_POWER, 1); - input_sync(kp->input); - input_report_key(kp->input, KEY_POWER, 0); - input_sync(kp->input); + input_report_key(kp->poll_dev->input, KEY_POWER, 1); + input_sync(kp->poll_dev->input); + input_report_key(kp->poll_dev->input, KEY_POWER, 0); + input_sync(kp->poll_dev->input); } return 0; } @@ -646,6 +636,12 @@ static void __exit meson_adc_kp_exit(void) platform_driver_unregister(&kp_driver); } +/* + * Note: If the driver is compiled as a module, the __setup() do nothing + * __setup() is defined in include/linux/init.h + */ +#ifndef MODULE + static int __init adc_key_mode_para_setup(char *s) { if (s) @@ -664,6 +660,8 @@ static int __init kernel_keypad_enable_setup(char *s) } __setup("kernelkey_enable=", kernel_keypad_enable_setup); +#endif + late_initcall(meson_adc_kp_init); module_exit(meson_adc_kp_exit); MODULE_AUTHOR("Amlogic"); diff --git a/include/linux/amlogic/adc_keypad.h b/drivers/amlogic/input/keyboard/adc_keypad.h similarity index 92% rename from include/linux/amlogic/adc_keypad.h rename to drivers/amlogic/input/keyboard/adc_keypad.h index c6c8dc5..2f9c901 100644 --- a/include/linux/amlogic/adc_keypad.h +++ b/drivers/amlogic/input/keyboard/adc_keypad.h @@ -1,5 +1,5 @@ /* - * include/linux/amlogic/adc_keypad.h + * drivers/amlogic/input/keyboard/adc_keypad.h * * Copyright (C) 2017 Amlogic, Inc. All rights reserved. * @@ -56,13 +56,11 @@ struct meson_adc_kp { unsigned char chan_num; /*number of channel exclude duplicate*/ unsigned char count; unsigned int report_code; - unsigned int code; + unsigned int prev_code; unsigned int poll_period; /*key scan period*/ struct mutex kp_lock; struct list_head adckey_head; - struct input_dev *input; - struct timer_list timer; - struct work_struct work_update; + struct input_polled_dev *poll_dev; struct iio_channel *pchan[SARADC_CH_NUM]; #ifdef CONFIG_AMLOGIC_LEGACY_EARLY_SUSPEND struct early_suspend early_suspend; -- 2.7.4