mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-09 04:10:18 +09:00
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 <xingyu.chen@amlogic.com>
This commit is contained in:
@@ -13456,7 +13456,8 @@ F: Documentation/devicetree/bindings/iio/adc/amlogic,meson-saradc.txt
|
||||
|
||||
AMLOGIC adc_keypad
|
||||
M: Xingyu Chen <xingyu.chen@amlogic.com>
|
||||
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 <yum.cai@amlogic.com>
|
||||
|
||||
@@ -28,12 +28,12 @@
|
||||
#include <linux/string.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/iio/consumer.h>
|
||||
#include <linux/amlogic/adc_keypad.h>
|
||||
#include <linux/input-polldev.h>
|
||||
#include <linux/amlogic/scpi_protocol.h>
|
||||
#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);
|
||||
}
|
||||
kp->report_code = code;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
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->count = 0;
|
||||
}
|
||||
kp->prev_code = code;
|
||||
}
|
||||
|
||||
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;
|
||||
goto err;
|
||||
}
|
||||
if (meson_adc_kp_get_devtree_pdata(pdev, kp) < 0) {
|
||||
meson_adc_kp_list_free(kp);
|
||||
state = -EINVAL;
|
||||
ret = meson_adc_kp_get_devtree_pdata(pdev, kp);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
/*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");
|
||||
|
||||
@@ -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;
|
||||
Reference in New Issue
Block a user