dm: key: optimise framework and update drivers
1. dm key framework takes over more generic jobs; 2. key drivers remove unused codes and match new framework; 3. only power key is registered as interrupt key; Change-Id: Icdda86f588af721b685f801ed251581f2fd85793 Signed-off-by: Joseph Chen <chenjh@rock-chips.com>
This commit is contained in:
parent
99b8866017
commit
64048c537e
|
|
@ -15,19 +15,11 @@
|
||||||
#include <key.h>
|
#include <key.h>
|
||||||
#include <linux/input.h>
|
#include <linux/input.h>
|
||||||
|
|
||||||
#define ADC_MARGIN 30
|
|
||||||
#define MAX_KEY_NR 10
|
|
||||||
|
|
||||||
struct adc_key_priv {
|
|
||||||
u32 key_nr;
|
|
||||||
};
|
|
||||||
|
|
||||||
static int adc_keys_ofdata_to_platdata(struct udevice *dev)
|
static int adc_keys_ofdata_to_platdata(struct udevice *dev)
|
||||||
{
|
{
|
||||||
struct adc_key_priv *priv = dev_get_priv(dev);
|
struct input_key *key;
|
||||||
struct input_key *key = dev_get_platdata(dev);
|
u32 adc_channels[2], microvolt;
|
||||||
u32 adc_channels[2], i = 0, microvolt;
|
int vref, ret;
|
||||||
int vref, err;
|
|
||||||
ofnode node;
|
ofnode node;
|
||||||
|
|
||||||
/* Get vref */
|
/* Get vref */
|
||||||
|
|
@ -39,90 +31,54 @@ static int adc_keys_ofdata_to_platdata(struct udevice *dev)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get IO channel */
|
/* Get IO channel */
|
||||||
err = dev_read_u32_array(dev, "io-channels", adc_channels, 2);
|
ret = dev_read_u32_array(dev, "io-channels", adc_channels, 2);
|
||||||
if (err) {
|
if (ret) {
|
||||||
printf("failed to read 'io-channels' of %s key, ret=%d\n",
|
printf("failed to read 'io-channels', ret=%d\n", ret);
|
||||||
key->name, err);
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Parse every adc key data */
|
/* Parse every adc key data */
|
||||||
dev_for_each_subnode(node, dev) {
|
dev_for_each_subnode(node, dev) {
|
||||||
key[i].name = ofnode_read_string(node, "label");
|
key = calloc(1, sizeof(struct input_key));
|
||||||
key[i].vref = vref;
|
if (!key)
|
||||||
key[i].margin = ADC_MARGIN;
|
return -ENOMEM;
|
||||||
key[i].channel = adc_channels[1];
|
|
||||||
if (ofnode_read_u32(node, "linux,code", &key[i].code)) {
|
key->parent = dev;
|
||||||
|
key->type = ADC_KEY;
|
||||||
|
key->vref = vref;
|
||||||
|
key->channel = adc_channels[1];
|
||||||
|
key->name = ofnode_read_string(node, "label");
|
||||||
|
ret = ofnode_read_u32(node, "linux,code", &key->code);
|
||||||
|
if (ret) {
|
||||||
printf("%s: failed to read 'linux,code', ret=%d\n",
|
printf("%s: failed to read 'linux,code', ret=%d\n",
|
||||||
key[i].name, key[i].code);
|
key->name, ret);
|
||||||
return -EINVAL;
|
free(key);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
if (ofnode_read_u32(node, "press-threshold-microvolt",
|
|
||||||
µvolt)) {
|
ret = ofnode_read_u32(node, "press-threshold-microvolt",
|
||||||
printf("%s: failed read 'press-threshold-microvolt', ret=%d\n",
|
µvolt);
|
||||||
key[i].name, microvolt);
|
if (ret) {
|
||||||
return -EINVAL;
|
printf("%s: failed to read 'press-threshold-microvolt', ret=%d\n",
|
||||||
|
key->name, ret);
|
||||||
|
free(key);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Convert microvolt to adc value */
|
/* Convert microvolt to adc value */
|
||||||
key[i].value = microvolt / (key[i].vref / 1024);
|
key->adcval = microvolt / (key->vref / 1024);
|
||||||
|
key_add(key);
|
||||||
|
|
||||||
debug("%s: name=%s: code=%d, vref=%d, margin=%d, channel=%d, val=%d\n",
|
debug("%s: name=%s: code=%d, vref=%d, channel=%d, microvolt=%d, adcval=%d\n",
|
||||||
__func__, key[i].name, key[i].code, key[i].vref,
|
__func__, key->name, key->code, key->vref,
|
||||||
key[i].margin, key[i].channel, key[i].value);
|
key->channel, microvolt, key->adcval);
|
||||||
|
|
||||||
/* Next node */
|
|
||||||
i++;
|
|
||||||
priv->key_nr = i;
|
|
||||||
if (i >= MAX_KEY_NR) {
|
|
||||||
printf("Too many keys, Max support: %d\n", MAX_KEY_NR);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int adc_keys_read(struct udevice *dev, int code)
|
|
||||||
{
|
|
||||||
struct adc_key_priv *priv = dev_get_priv(dev);
|
|
||||||
struct input_key *key = dev_get_platdata(dev);
|
|
||||||
int report = KEY_NOT_EXIST;
|
|
||||||
int max, min, i = 0;
|
|
||||||
unsigned int adcval;
|
|
||||||
|
|
||||||
for (i = 0; i < priv->key_nr; i++) {
|
|
||||||
if (key[i].code != code)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (adc_channel_single_shot("saradc",
|
|
||||||
key[i].channel, &adcval)) {
|
|
||||||
printf("%s: failed to read saradc\n", key[i].name);
|
|
||||||
} else {
|
|
||||||
/* Get min, max */
|
|
||||||
max = key[i].value + key[i].margin;
|
|
||||||
if (key[i].value > key[i].margin)
|
|
||||||
min = key[i].value - key[i].margin;
|
|
||||||
else
|
|
||||||
min = key[i].value;
|
|
||||||
|
|
||||||
/* Check */
|
|
||||||
if ((adcval <= max) && (adcval >= min)) {
|
|
||||||
report = KEY_PRESS_DOWN;
|
|
||||||
printf("'%s' key pressed down\n",
|
|
||||||
key[i].name);
|
|
||||||
} else {
|
|
||||||
report = KEY_PRESS_NONE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return report;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct dm_key_ops key_ops = {
|
static const struct dm_key_ops key_ops = {
|
||||||
.name = "adc_keys",
|
.name = "adc-keys",
|
||||||
.read = adc_keys_read,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct udevice_id adc_keys_ids[] = {
|
static const struct udevice_id adc_keys_ids[] = {
|
||||||
|
|
@ -136,6 +92,4 @@ U_BOOT_DRIVER(adc_keys) = {
|
||||||
.ops = &key_ops,
|
.ops = &key_ops,
|
||||||
.of_match = adc_keys_ids,
|
.of_match = adc_keys_ids,
|
||||||
.ofdata_to_platdata = adc_keys_ofdata_to_platdata,
|
.ofdata_to_platdata = adc_keys_ofdata_to_platdata,
|
||||||
.platdata_auto_alloc_size = sizeof(struct input_key) * MAX_KEY_NR,
|
|
||||||
.priv_auto_alloc_size = sizeof(struct adc_key_priv),
|
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -19,107 +19,93 @@
|
||||||
#include <irq-generic.h>
|
#include <irq-generic.h>
|
||||||
#include <irq-platform.h>
|
#include <irq-platform.h>
|
||||||
|
|
||||||
#define MAX_KEY_NR 10
|
|
||||||
|
|
||||||
struct gpio_key_priv {
|
|
||||||
u32 key_nr;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void gpio_irq_handler(int irq, void *data)
|
static void gpio_irq_handler(int irq, void *data)
|
||||||
{
|
{
|
||||||
struct udevice *dev = data;
|
struct input_key *key = data;
|
||||||
struct gpio_key_priv *priv = dev_get_priv(dev);
|
|
||||||
struct input_key *key = dev_get_platdata(dev);
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < priv->key_nr; i++) {
|
if (key->irq != irq)
|
||||||
if (key[i].irq != irq)
|
return;
|
||||||
continue;
|
|
||||||
|
|
||||||
/* up event */
|
/* up event */
|
||||||
if (irq_get_gpio_level(irq)) {
|
if (irq_get_gpio_level(irq)) {
|
||||||
key[i].up_t = key_get_timer(0);
|
key->up_t = key_timer(0);
|
||||||
debug("%s: key down: %llu ms\n",
|
debug("%s: key down: %llu ms\n", key->name, key->down_t);
|
||||||
key[i].name, key[i].down_t);
|
/* down event */
|
||||||
/* down event */
|
} else {
|
||||||
} else {
|
key->down_t = key_timer(0);
|
||||||
key[i].down_t = key_get_timer(0);
|
debug("%s: key up: %llu ms\n", key->name, key->up_t);
|
||||||
debug("%s: key up: %llu ms\n",
|
|
||||||
key[i].name, key[i].up_t);
|
|
||||||
}
|
|
||||||
/* Must delay */
|
|
||||||
mdelay(10);
|
|
||||||
irq_revert_irq_type(irq);
|
|
||||||
}
|
}
|
||||||
|
/* Must delay */
|
||||||
|
mdelay(10);
|
||||||
|
irq_revert_irq_type(irq);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int gpio_key_ofdata_to_platdata(struct udevice *dev)
|
static int gpio_key_ofdata_to_platdata(struct udevice *dev)
|
||||||
{
|
{
|
||||||
struct gpio_key_priv *priv = dev_get_priv(dev);
|
struct input_key *key;
|
||||||
struct input_key *key = dev_get_platdata(dev);
|
u32 gpios[2];
|
||||||
u32 gpios[2], i = 0;
|
|
||||||
ofnode node;
|
ofnode node;
|
||||||
int irq;
|
int irq, ret;
|
||||||
|
|
||||||
dev_for_each_subnode(node, dev) {
|
dev_for_each_subnode(node, dev) {
|
||||||
key[i].name = ofnode_read_string(node, "label");
|
key = calloc(1, sizeof(struct input_key));
|
||||||
if (ofnode_read_u32(node, "linux,code", &key[i].code)) {
|
if (!key)
|
||||||
printf("failed read 'linux,code' of %s key\n",
|
return -ENOMEM;
|
||||||
key[i].name);
|
|
||||||
return -EINVAL;
|
key->parent = dev;
|
||||||
}
|
key->type = GPIO_KEY;
|
||||||
if (ofnode_read_u32_array(node, "gpios", gpios, 2)) {
|
key->name = ofnode_read_string(node, "label");
|
||||||
printf("failed to read 'gpios' of %s key\n",
|
ret = ofnode_read_u32(node, "linux,code", &key->code);
|
||||||
key[i].name);
|
if (ret) {
|
||||||
return -EINVAL;
|
printf("%s: failed read 'linux,code', ret=%d\n",
|
||||||
|
key->name, ret);
|
||||||
|
free(key);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Must register as interrupt, be able to wakeup system */
|
/* Only register power key as interrupt */
|
||||||
irq = phandle_gpio_to_irq(gpios[0], gpios[1]);
|
if (key->code == KEY_POWER) {
|
||||||
if (irq < 0) {
|
ret = ofnode_read_u32_array(node, "gpios", gpios, 2);
|
||||||
printf("failed to request irq for gpio, ret=%d\n", irq);
|
if (ret) {
|
||||||
return irq;
|
printf("%s: failed to read 'gpios', ret=%d\n",
|
||||||
}
|
key->name, ret);
|
||||||
key[i].irq = irq;
|
free(key);
|
||||||
irq_install_handler(irq, gpio_irq_handler, dev);
|
continue;
|
||||||
irq_handler_enable(irq);
|
}
|
||||||
irq_set_irq_type(irq, IRQ_TYPE_EDGE_FALLING);
|
|
||||||
|
|
||||||
debug("%s: name=%s: code=%d\n",
|
/* Must register as interrupt, be able to wakeup system */
|
||||||
__func__, key[i].name, key[i].code);
|
irq = phandle_gpio_to_irq(gpios[0], gpios[1]);
|
||||||
|
if (irq < 0) {
|
||||||
|
printf("%s: failed to request irq, ret=%d\n",
|
||||||
|
key->name, irq);
|
||||||
|
free(key);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
key->irq = irq;
|
||||||
|
key_add(key);
|
||||||
|
irq_install_handler(irq, gpio_irq_handler, key);
|
||||||
|
irq_set_irq_type(irq, IRQ_TYPE_EDGE_FALLING);
|
||||||
|
irq_handler_enable(irq);
|
||||||
|
} else {
|
||||||
|
ret = gpio_request_by_name_nodev(node, "gpios", 0,
|
||||||
|
&key->gpio,
|
||||||
|
GPIOD_IS_IN);
|
||||||
|
if (ret) {
|
||||||
|
printf("%s: failed to request gpio, ret=%d\n",
|
||||||
|
key->name, ret);
|
||||||
|
}
|
||||||
|
|
||||||
/* Next node */
|
key_add(key);
|
||||||
i++;
|
|
||||||
priv->key_nr = i;
|
|
||||||
if (i >= MAX_KEY_NR) {
|
|
||||||
printf("Too many keys, Max support: %d\n", MAX_KEY_NR);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
debug("%s: name=%s: code=%d\n", __func__, key->name, key->code);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int gpio_key_read(struct udevice *dev, int code)
|
|
||||||
{
|
|
||||||
struct gpio_key_priv *priv = dev_get_priv(dev);
|
|
||||||
struct input_key *key = dev_get_platdata(dev);
|
|
||||||
u32 report = KEY_NOT_EXIST;
|
|
||||||
int i = 0;
|
|
||||||
|
|
||||||
for (i = 0; i < priv->key_nr; i++) {
|
|
||||||
if (key[i].code != code)
|
|
||||||
continue;
|
|
||||||
report = key_parse_gpio_event(&key[i]);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return report;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct dm_key_ops key_ops = {
|
static const struct dm_key_ops key_ops = {
|
||||||
.name = "gpio-keys",
|
.name = "gpio-keys",
|
||||||
.read = gpio_key_read,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct udevice_id gpio_key_ids[] = {
|
static const struct udevice_id gpio_key_ids[] = {
|
||||||
|
|
@ -133,6 +119,4 @@ U_BOOT_DRIVER(gpio_keys) = {
|
||||||
.of_match = gpio_key_ids,
|
.of_match = gpio_key_ids,
|
||||||
.ops = &key_ops,
|
.ops = &key_ops,
|
||||||
.ofdata_to_platdata = gpio_key_ofdata_to_platdata,
|
.ofdata_to_platdata = gpio_key_ofdata_to_platdata,
|
||||||
.platdata_auto_alloc_size = sizeof(struct input_key) * MAX_KEY_NR,
|
|
||||||
.priv_auto_alloc_size = sizeof(struct gpio_key_priv),
|
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -4,10 +4,12 @@
|
||||||
* SPDX-License-Identifier: GPL-2.0+
|
* SPDX-License-Identifier: GPL-2.0+
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <common.h>
|
||||||
|
#include <adc.h>
|
||||||
#include <dm.h>
|
#include <dm.h>
|
||||||
#include <key.h>
|
#include <key.h>
|
||||||
#include <common.h>
|
|
||||||
#include <dm.h>
|
static LIST_HEAD(key_list);
|
||||||
|
|
||||||
static inline uint64_t arch_counter_get_cntpct(void)
|
static inline uint64_t arch_counter_get_cntpct(void)
|
||||||
{
|
{
|
||||||
|
|
@ -22,7 +24,7 @@ static inline uint64_t arch_counter_get_cntpct(void)
|
||||||
return cval;
|
return cval;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t key_get_timer(uint64_t base)
|
uint64_t key_timer(uint64_t base)
|
||||||
{
|
{
|
||||||
uint64_t cntpct;
|
uint64_t cntpct;
|
||||||
|
|
||||||
|
|
@ -30,50 +32,51 @@ uint64_t key_get_timer(uint64_t base)
|
||||||
return (cntpct > base) ? (cntpct - base) : 0;
|
return (cntpct > base) ? (cntpct - base) : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int key_state_valid(int state)
|
/*
|
||||||
|
* What's simple and complex event mean?
|
||||||
|
*
|
||||||
|
* simple event: key press down or none;
|
||||||
|
* complext event: key press down, long down or none;
|
||||||
|
*/
|
||||||
|
static int key_read_adc_simple_event(struct input_key *key, unsigned int adcval)
|
||||||
{
|
{
|
||||||
return (state >= KEY_PRESS_NONE && state < KEY_NOT_EXIST);
|
int max, min, margin = 30;
|
||||||
}
|
int keyval;
|
||||||
|
|
||||||
static int key_read(struct udevice *dev, int code)
|
|
||||||
{
|
|
||||||
const struct dm_key_ops *ops = dev_get_driver_ops(dev);
|
|
||||||
|
|
||||||
if (!ops || !ops->read)
|
|
||||||
return -ENOSYS;
|
|
||||||
|
|
||||||
return ops->read(dev, code);
|
|
||||||
}
|
|
||||||
|
|
||||||
int key_parse_adc_event(struct input_key *key, unsigned int adcval)
|
|
||||||
{
|
|
||||||
int report = KEY_NOT_EXIST;
|
|
||||||
int max, min;
|
|
||||||
|
|
||||||
/* Get min, max */
|
/* Get min, max */
|
||||||
max = key->value + key->margin;
|
max = key->adcval + margin;
|
||||||
if (key->value > key->margin)
|
if (key->adcval > margin)
|
||||||
min = key->value - key->margin;
|
min = key->adcval - margin;
|
||||||
else
|
else
|
||||||
min = key->value;
|
min = 0;
|
||||||
|
|
||||||
debug("%s: %s: max=%d, min=%d, adcval=%d\n",
|
debug("%s: %s: val=%d, max=%d, min=%d, adcval=%d\n",
|
||||||
__func__, key->name, max, min, adcval);
|
__func__, key->name, key->adcval, max, min, adcval);
|
||||||
|
|
||||||
/* Check */
|
/* Check */
|
||||||
if ((adcval <= max) && (adcval >= min)) {
|
if ((adcval <= max) && (adcval >= min)) {
|
||||||
report = KEY_PRESS_DOWN;
|
keyval = KEY_PRESS_DOWN;
|
||||||
printf("%s key pressed..\n", key->name);
|
debug("%s key pressed..\n", key->name);
|
||||||
} else {
|
} else {
|
||||||
report = KEY_PRESS_NONE;
|
keyval = KEY_PRESS_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return report;
|
return keyval;
|
||||||
}
|
}
|
||||||
|
|
||||||
int key_parse_gpio_event(struct input_key *key)
|
static int key_read_gpio_simple_event(struct input_key *key)
|
||||||
{
|
{
|
||||||
u32 report = KEY_NOT_EXIST;
|
if (!dm_gpio_is_valid(&key->gpio)) {
|
||||||
|
printf("%s: invalid gpio\n", key->name);
|
||||||
|
return KEY_PRESS_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return dm_gpio_get_value(&key->gpio) ? KEY_PRESS_DOWN : KEY_PRESS_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int key_read_gpio_complex_event(struct input_key *key)
|
||||||
|
{
|
||||||
|
int keyval;
|
||||||
|
|
||||||
debug("%s: %s: up=%llu, down=%llu, delta=%llu\n",
|
debug("%s: %s: up=%llu, down=%llu, delta=%llu\n",
|
||||||
__func__, key->name, key->up_t, key->down_t,
|
__func__, key->name, key->up_t, key->down_t,
|
||||||
|
|
@ -81,7 +84,7 @@ int key_parse_gpio_event(struct input_key *key)
|
||||||
|
|
||||||
/* Possible this is machine power-on long pressed, so ignore this */
|
/* Possible this is machine power-on long pressed, so ignore this */
|
||||||
if (key->down_t == 0 && key->up_t != 0) {
|
if (key->down_t == 0 && key->up_t != 0) {
|
||||||
report = KEY_PRESS_NONE;
|
keyval = KEY_PRESS_NONE;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -89,45 +92,113 @@ int key_parse_gpio_event(struct input_key *key)
|
||||||
(key->up_t - key->down_t) >= KEY_LONG_DOWN_MS) {
|
(key->up_t - key->down_t) >= KEY_LONG_DOWN_MS) {
|
||||||
key->up_t = 0;
|
key->up_t = 0;
|
||||||
key->down_t = 0;
|
key->down_t = 0;
|
||||||
report = KEY_PRESS_LONG_DOWN;
|
keyval = KEY_PRESS_LONG_DOWN;
|
||||||
printf("%s key long pressed(hold)..\n", key->name);
|
debug("%s key long pressed..\n", key->name);
|
||||||
} else if (key->down_t &&
|
} else if (key->down_t &&
|
||||||
key_get_timer(key->down_t) >= KEY_LONG_DOWN_MS) {
|
key_timer(key->down_t) >= KEY_LONG_DOWN_MS) {
|
||||||
key->up_t = 0;
|
key->up_t = 0;
|
||||||
key->down_t = 0;
|
key->down_t = 0;
|
||||||
report = KEY_PRESS_LONG_DOWN;
|
keyval = KEY_PRESS_LONG_DOWN;
|
||||||
printf("%s key long pressed..\n", key->name);
|
debug("%s key long pressed(hold)..\n", key->name);
|
||||||
} else if ((key->up_t > key->down_t) &&
|
} else if ((key->up_t > key->down_t) &&
|
||||||
(key->up_t - key->down_t) < KEY_LONG_DOWN_MS) {
|
(key->up_t - key->down_t) < KEY_LONG_DOWN_MS) {
|
||||||
key->up_t = 0;
|
key->up_t = 0;
|
||||||
key->down_t = 0;
|
key->down_t = 0;
|
||||||
report = KEY_PRESS_DOWN;
|
keyval = KEY_PRESS_DOWN;
|
||||||
printf("%s key short pressed..\n", key->name);
|
debug("%s key short pressed..\n", key->name);
|
||||||
|
/* Possible in charge animation, we enable irq after fuel gauge updated */
|
||||||
|
} else if (key->up_t && key->down_t && (key->up_t == key->down_t)){
|
||||||
|
key->up_t = 0;
|
||||||
|
key->down_t = 0;
|
||||||
|
keyval = KEY_PRESS_DOWN;
|
||||||
|
debug("%s key short pressed..\n", key->name);
|
||||||
} else {
|
} else {
|
||||||
report = KEY_PRESS_NONE;
|
keyval = KEY_PRESS_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
return report;
|
return keyval;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int key_read_gpio_interrupt_event(struct input_key *key)
|
||||||
|
{
|
||||||
|
debug("%s: %s\n", __func__, key->name);
|
||||||
|
|
||||||
|
return key_read_gpio_complex_event(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
int key_is_pressed(int keyval)
|
||||||
|
{
|
||||||
|
return (keyval == KEY_PRESS_DOWN || keyval == KEY_PRESS_LONG_DOWN);
|
||||||
|
}
|
||||||
|
|
||||||
|
void key_add(struct input_key *key)
|
||||||
|
{
|
||||||
|
if (!key)
|
||||||
|
return;
|
||||||
|
|
||||||
|
list_add_tail(&key->link, &key_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
int key_read(int code)
|
||||||
|
{
|
||||||
|
struct udevice *dev;
|
||||||
|
struct input_key *key;
|
||||||
|
static int initialized;
|
||||||
|
unsigned int adcval;
|
||||||
|
int keyval = KEY_NOT_EXIST;
|
||||||
|
int found = 0, ret;
|
||||||
|
|
||||||
|
/* Initialize all key drivers */
|
||||||
|
if (!initialized) {
|
||||||
|
for (uclass_first_device(UCLASS_KEY, &dev);
|
||||||
|
dev;
|
||||||
|
uclass_next_device(&dev)) {
|
||||||
|
debug("%s: dev.name = %s\n", __func__, dev->name);
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Search on the key list */
|
||||||
|
list_for_each_entry(key, &key_list, link) {
|
||||||
|
if (key->code == code) {
|
||||||
|
found = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
/* Is a adc key? */
|
||||||
|
if (key->type & ADC_KEY) {
|
||||||
|
ret = adc_channel_single_shot("saradc", key->channel, &adcval);
|
||||||
|
if (ret)
|
||||||
|
printf("%s: failed to read saradc, ret=%d\n",
|
||||||
|
key->name, ret);
|
||||||
|
else
|
||||||
|
keyval = key_read_adc_simple_event(key, adcval);
|
||||||
|
/* Is a gpio key? */
|
||||||
|
} else if (key->type & GPIO_KEY) {
|
||||||
|
/* All pwrkey must register as an interrupt event */
|
||||||
|
if (key->code == KEY_POWER) {
|
||||||
|
keyval = key_read_gpio_interrupt_event(key);
|
||||||
|
} else {
|
||||||
|
keyval = key_read_gpio_simple_event(key);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
printf("%s: invalid key type!\n", __func__);
|
||||||
|
}
|
||||||
|
|
||||||
|
debug("%s: key.name=%s, code=%d, keyval=%d\n",
|
||||||
|
__func__, key->name, key->code, keyval);
|
||||||
|
|
||||||
|
out:
|
||||||
|
return keyval;
|
||||||
}
|
}
|
||||||
|
|
||||||
int platform_key_read(int code)
|
int platform_key_read(int code)
|
||||||
{
|
{
|
||||||
struct udevice *dev;
|
return KEY_NOT_EXIST;
|
||||||
int report = KEY_NOT_EXIST;
|
|
||||||
|
|
||||||
for (uclass_first_device(UCLASS_KEY, &dev);
|
|
||||||
dev;
|
|
||||||
uclass_next_device(&dev)) {
|
|
||||||
debug("key dev.name = %s, code = %d\n", dev->name, code);
|
|
||||||
report = key_read(dev, code);
|
|
||||||
if (key_state_valid(report)) {
|
|
||||||
debug("key dev.name = %s, state=%d\n", dev->name, report);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return report;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
UCLASS_DRIVER(key) = {
|
UCLASS_DRIVER(key) = {
|
||||||
|
|
|
||||||
|
|
@ -101,16 +101,6 @@ static struct reg_data rk805_init_reg[] = {
|
||||||
{ RK805_INT_STS_REG, 0xff },
|
{ RK805_INT_STS_REG, 0xff },
|
||||||
};
|
};
|
||||||
|
|
||||||
static int rk8xx_pwrkey_read(struct udevice *dev, int code)
|
|
||||||
{
|
|
||||||
struct input_key *key = dev_get_platdata(dev);
|
|
||||||
|
|
||||||
if (key->code != code)
|
|
||||||
return KEY_NOT_EXIST;
|
|
||||||
|
|
||||||
return key_parse_gpio_event(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void pwrkey_irq_handler(int irq, void *data)
|
static void pwrkey_irq_handler(int irq, void *data)
|
||||||
{
|
{
|
||||||
struct udevice *dev = data;
|
struct udevice *dev = data;
|
||||||
|
|
@ -145,13 +135,13 @@ static void pwrkey_irq_handler(int irq, void *data)
|
||||||
|
|
||||||
/* fall event */
|
/* fall event */
|
||||||
if (val & priv->pwron_fall_int) {
|
if (val & priv->pwron_fall_int) {
|
||||||
key->down_t = key_get_timer(0);
|
key->down_t = key_timer(0);
|
||||||
debug("%s: key down: %llu ms\n", __func__, key->down_t);
|
debug("%s: key down: %llu ms\n", __func__, key->down_t);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* rise event */
|
/* rise event */
|
||||||
if (val & priv->pwron_rise_int) {
|
if (val & priv->pwron_rise_int) {
|
||||||
key->up_t = key_get_timer(0);
|
key->up_t = key_timer(0);
|
||||||
debug("%s: key up: %llu ms\n", __func__, key->up_t);
|
debug("%s: key up: %llu ms\n", __func__, key->up_t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -188,9 +178,17 @@ static int pwrkey_interrupt_init(struct udevice *dev)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
key->name = "power";
|
key->parent = dev;
|
||||||
|
key->name = "rk8xx_pwrkey";
|
||||||
key->code = KEY_POWER;
|
key->code = KEY_POWER;
|
||||||
|
key->type = GPIO_KEY;
|
||||||
irq = phandle_gpio_to_irq(phandle, interrupt[0]);
|
irq = phandle_gpio_to_irq(phandle, interrupt[0]);
|
||||||
|
if (irq < 0) {
|
||||||
|
printf("%s: failed to request irq, ret=%d\n", key->name, irq);
|
||||||
|
return irq;
|
||||||
|
}
|
||||||
|
key->irq = irq;
|
||||||
|
key_add(key);
|
||||||
irq_install_handler(irq, pwrkey_irq_handler, dev);
|
irq_install_handler(irq, pwrkey_irq_handler, dev);
|
||||||
irq_set_irq_type(irq, IRQ_TYPE_EDGE_FALLING);
|
irq_set_irq_type(irq, IRQ_TYPE_EDGE_FALLING);
|
||||||
irq_handler_enable(irq);
|
irq_handler_enable(irq);
|
||||||
|
|
@ -200,7 +198,6 @@ static int pwrkey_interrupt_init(struct udevice *dev)
|
||||||
|
|
||||||
static const struct dm_key_ops key_ops = {
|
static const struct dm_key_ops key_ops = {
|
||||||
.name = "rk8xx-pwrkey",
|
.name = "rk8xx-pwrkey",
|
||||||
.read = rk8xx_pwrkey_read,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static int rk8xx_pwrkey_probe(struct udevice *dev)
|
static int rk8xx_pwrkey_probe(struct udevice *dev)
|
||||||
|
|
|
||||||
|
|
@ -19,54 +19,33 @@
|
||||||
#include <irq-generic.h>
|
#include <irq-generic.h>
|
||||||
#include <irq-platform.h>
|
#include <irq-platform.h>
|
||||||
|
|
||||||
#define ADC_MARGIN 30
|
|
||||||
#define MAX_KEY_NR 10
|
|
||||||
|
|
||||||
struct rk_key_priv {
|
|
||||||
u32 key_nr;
|
|
||||||
};
|
|
||||||
|
|
||||||
enum {
|
|
||||||
INVAL_KEY = 0,
|
|
||||||
ADC_KEY,
|
|
||||||
GPIO_KEY,
|
|
||||||
};
|
|
||||||
|
|
||||||
static void gpio_irq_handler(int irq, void *data)
|
static void gpio_irq_handler(int irq, void *data)
|
||||||
{
|
{
|
||||||
struct udevice *dev = data;
|
struct input_key *key = data;
|
||||||
struct rk_key_priv *priv = dev_get_priv(dev);
|
|
||||||
struct input_key *key = dev_get_platdata(dev);
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < priv->key_nr; i++) {
|
if (key->irq != irq)
|
||||||
if (key[i].irq != irq)
|
return;
|
||||||
continue;
|
|
||||||
|
|
||||||
/* up event */
|
/* up event */
|
||||||
if (irq_get_gpio_level(irq)) {
|
if (irq_get_gpio_level(irq)) {
|
||||||
key[i].up_t = key_get_timer(0);
|
key->up_t = key_timer(0);
|
||||||
debug("%s: key down: %llu ms\n",
|
debug("%s: key down: %llu ms\n", key->name, key->down_t);
|
||||||
key[i].name, key[i].down_t);
|
/* down event */
|
||||||
/* down event */
|
} else {
|
||||||
} else {
|
key->down_t = key_timer(0);
|
||||||
key[i].down_t = key_get_timer(0);
|
debug("%s: key up: %llu ms\n", key->name, key->up_t);
|
||||||
debug("%s: key up: %llu ms\n",
|
|
||||||
key[i].name, key[i].up_t);
|
|
||||||
}
|
|
||||||
/* Must delay */
|
|
||||||
mdelay(10);
|
|
||||||
irq_revert_irq_type(irq);
|
|
||||||
}
|
}
|
||||||
|
/* Must delay */
|
||||||
|
mdelay(10);
|
||||||
|
irq_revert_irq_type(irq);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int rk_keys_ofdata_to_platdata(struct udevice *dev)
|
static int rk_keys_ofdata_to_platdata(struct udevice *dev)
|
||||||
{
|
{
|
||||||
struct rk_key_priv *priv = dev_get_priv(dev);
|
struct input_key *key;
|
||||||
struct input_key *key = dev_get_platdata(dev);
|
u32 adc_channels[2], gpios[2], adcval;
|
||||||
u32 adc_channels[2], gpios[2], adcval, i = 0;
|
int irq, ret;
|
||||||
ofnode node;
|
ofnode node;
|
||||||
int irq;
|
|
||||||
|
|
||||||
/* Get IO channel */
|
/* Get IO channel */
|
||||||
if (dev_read_u32_array(dev, "io-channels", adc_channels, 2)) {
|
if (dev_read_u32_array(dev, "io-channels", adc_channels, 2)) {
|
||||||
|
|
@ -75,94 +54,83 @@ static int rk_keys_ofdata_to_platdata(struct udevice *dev)
|
||||||
}
|
}
|
||||||
|
|
||||||
dev_for_each_subnode(node, dev) {
|
dev_for_each_subnode(node, dev) {
|
||||||
|
key = calloc(1, sizeof(struct input_key));
|
||||||
|
if (!key)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
/* This is an ACD key */
|
/* This is an ACD key */
|
||||||
if (!ofnode_read_u32(node, "rockchip,adc_value", &adcval)) {
|
if (!ofnode_read_u32(node, "rockchip,adc_value", &adcval)) {
|
||||||
key[i].name = ofnode_read_string(node, "label");
|
key->parent = dev;
|
||||||
key[i].flag = ADC_KEY;
|
key->name = ofnode_read_string(node, "label");
|
||||||
key[i].margin = ADC_MARGIN;
|
key->type = ADC_KEY;
|
||||||
key[i].value = adcval;
|
key->adcval = adcval;
|
||||||
key[i].channel = adc_channels[1];
|
key->channel = adc_channels[1];
|
||||||
if (ofnode_read_u32(node, "linux,code", &key[i].code)) {
|
if (ofnode_read_u32(node, "linux,code", &key->code)) {
|
||||||
printf("%s: failed to read 'linux,code'\n",
|
printf("%s: failed to read 'linux,code'\n",
|
||||||
key[i].name);
|
key->name);
|
||||||
return -EINVAL;
|
free(key);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
/* This is a GPIO key */
|
/* This is a GPIO key */
|
||||||
} else {
|
} else {
|
||||||
key[i].name = ofnode_read_string(node, "label");
|
key->parent = dev;
|
||||||
key[i].flag = GPIO_KEY;
|
key->type = GPIO_KEY;
|
||||||
if (ofnode_read_u32_array(node, "gpios", gpios, 2)) {
|
key->name = ofnode_read_string(node, "label");
|
||||||
printf("%s: failed to read 'gpios'\n",
|
ret = ofnode_read_u32(node, "linux,code", &key->code);
|
||||||
key[i].name);
|
if (ret) {
|
||||||
return -EINVAL;
|
printf("%s: failed read 'linux,code', ret=%d\n",
|
||||||
}
|
key->name, ret);
|
||||||
if (ofnode_read_u32(node, "linux,code", &key[i].code)) {
|
free(key);
|
||||||
printf("%s: failed read 'linux,code'\n",
|
continue;
|
||||||
key[i].name);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Request irq */
|
/* Only register power key as interrupt */
|
||||||
irq = phandle_gpio_to_irq(gpios[0], gpios[1]);
|
if (key->code == KEY_POWER) {
|
||||||
if (irq < 0) {
|
ret = ofnode_read_u32_array(node, "gpios",
|
||||||
printf("%s: failed to request irq, ret=%d\n",
|
gpios, 2);
|
||||||
__func__, irq);
|
if (ret) {
|
||||||
return irq;
|
printf("%s: failed to read 'gpios', ret=%d\n",
|
||||||
|
key->name, ret);
|
||||||
|
free(key);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Request irq */
|
||||||
|
irq = phandle_gpio_to_irq(gpios[0], gpios[1]);
|
||||||
|
if (irq < 0) {
|
||||||
|
printf("%s: failed to request irq, ret=%d\n",
|
||||||
|
__func__, irq);
|
||||||
|
free(key);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
key->irq = irq;
|
||||||
|
key_add(key);
|
||||||
|
irq_install_handler(irq, gpio_irq_handler, key);
|
||||||
|
irq_set_irq_type(irq, IRQ_TYPE_EDGE_FALLING);
|
||||||
|
irq_handler_enable(irq);
|
||||||
|
} else {
|
||||||
|
ret = gpio_request_by_name_nodev(node, "gpios",
|
||||||
|
0, &key->gpio, GPIOD_IS_IN);
|
||||||
|
if (ret) {
|
||||||
|
printf("%s: failed to request gpio, ret=%d\n",
|
||||||
|
key->name, ret);
|
||||||
|
free(key);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
key_add(key);
|
||||||
}
|
}
|
||||||
key[i].irq = irq;
|
|
||||||
irq_install_handler(irq, gpio_irq_handler, dev);
|
|
||||||
irq_handler_enable(irq);
|
|
||||||
irq_set_irq_type(irq, IRQ_TYPE_EDGE_FALLING);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
debug("%s: name=%s: code=%d, val=%d, channel=%d, flag=%d, margin=%d\n",
|
debug("%s: name=%s: code=%d, adcval=%d, channel=%d, type=%d\n",
|
||||||
__func__, key[i].name, key[i].code, key[i].value,
|
__func__, key->name, key->code, key->adcval,
|
||||||
key[i].channel, key[i].flag, key[i].margin);
|
key->channel, key->type);
|
||||||
|
|
||||||
/* Next node */
|
|
||||||
i++;
|
|
||||||
priv->key_nr = i;
|
|
||||||
if (i >= MAX_KEY_NR) {
|
|
||||||
printf("Too many keys, Max support: %d\n", MAX_KEY_NR);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int rk_keys_read(struct udevice *dev, int code)
|
|
||||||
{
|
|
||||||
struct rk_key_priv *priv = dev_get_priv(dev);
|
|
||||||
struct input_key *key = dev_get_platdata(dev);
|
|
||||||
int report = KEY_NOT_EXIST;
|
|
||||||
int i = 0;
|
|
||||||
unsigned int adcval;
|
|
||||||
|
|
||||||
for (i = 0; i < priv->key_nr; i++) {
|
|
||||||
if (key[i].code != code)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (key[i].flag == ADC_KEY) {
|
|
||||||
if (adc_channel_single_shot("saradc",
|
|
||||||
key[i].channel, &adcval)) {
|
|
||||||
printf("%s: failed to read saradc\n",
|
|
||||||
key[i].name);
|
|
||||||
} else {
|
|
||||||
report = key_parse_adc_event(&key[i], adcval);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
report = key_parse_gpio_event(&key[i]);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return report;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct dm_key_ops key_ops = {
|
static const struct dm_key_ops key_ops = {
|
||||||
.name = "rk-keys",
|
.name = "rk-keys",
|
||||||
.read = rk_keys_read,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct udevice_id rk_keys_ids[] = {
|
static const struct udevice_id rk_keys_ids[] = {
|
||||||
|
|
@ -176,6 +144,4 @@ U_BOOT_DRIVER(rk_keys) = {
|
||||||
.ops = &key_ops,
|
.ops = &key_ops,
|
||||||
.of_match = rk_keys_ids,
|
.of_match = rk_keys_ids,
|
||||||
.ofdata_to_platdata = rk_keys_ofdata_to_platdata,
|
.ofdata_to_platdata = rk_keys_ofdata_to_platdata,
|
||||||
.platdata_auto_alloc_size = sizeof(struct input_key) * MAX_KEY_NR,
|
|
||||||
.priv_auto_alloc_size = sizeof(struct rk_key_priv),
|
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -7,10 +7,17 @@
|
||||||
#ifndef _KEY_H_
|
#ifndef _KEY_H_
|
||||||
#define _KEY_H_
|
#define _KEY_H_
|
||||||
|
|
||||||
|
#include <asm-generic/gpio.h>
|
||||||
#include <dt-bindings/input/linux-event-codes.h>
|
#include <dt-bindings/input/linux-event-codes.h>
|
||||||
|
|
||||||
#define KEY_LONG_DOWN_MS 2000
|
#define KEY_LONG_DOWN_MS 2000
|
||||||
|
|
||||||
|
enum {
|
||||||
|
INVAL_KEY = 0x0,
|
||||||
|
ADC_KEY = 0x1,
|
||||||
|
GPIO_KEY = 0x2,
|
||||||
|
};
|
||||||
|
|
||||||
enum key_state {
|
enum key_state {
|
||||||
KEY_PRESS_NONE, /* press without release */
|
KEY_PRESS_NONE, /* press without release */
|
||||||
KEY_PRESS_DOWN, /* press -> release */
|
KEY_PRESS_DOWN, /* press -> release */
|
||||||
|
|
@ -18,30 +25,44 @@ enum key_state {
|
||||||
KEY_NOT_EXIST,
|
KEY_NOT_EXIST,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct dm_key_ops {
|
|
||||||
const char *name;
|
|
||||||
int (*read)(struct udevice *dev, int code);
|
|
||||||
};
|
|
||||||
|
|
||||||
struct input_key {
|
struct input_key {
|
||||||
|
struct udevice *parent;
|
||||||
|
struct list_head link;
|
||||||
const char *name;
|
const char *name;
|
||||||
u32 code;
|
u32 code;
|
||||||
u32 channel;
|
u8 type;
|
||||||
u32 value;
|
|
||||||
u32 margin;
|
|
||||||
u32 vref;
|
|
||||||
int flag;
|
|
||||||
|
|
||||||
|
/* ADC key */
|
||||||
|
u32 adcval;
|
||||||
|
u32 vref;
|
||||||
|
u8 channel;
|
||||||
|
|
||||||
|
/* GPIO key */
|
||||||
u32 irq;
|
u32 irq;
|
||||||
|
struct gpio_desc gpio;
|
||||||
|
|
||||||
|
/* Event */
|
||||||
u64 up_t;
|
u64 up_t;
|
||||||
u64 down_t;
|
u64 down_t;
|
||||||
};
|
};
|
||||||
|
|
||||||
uint64_t key_get_timer(uint64_t base);
|
struct dm_key_ops {
|
||||||
|
const char *name;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Use it instead of get_timer() in key interrupt handler */
|
||||||
|
uint64_t key_timer(uint64_t base);
|
||||||
|
|
||||||
|
/* Reister you key to dm key framework */
|
||||||
|
void key_add(struct input_key *key);
|
||||||
|
|
||||||
|
/* Confirm if your key value is a press event */
|
||||||
|
int key_is_pressed(int keyval);
|
||||||
|
|
||||||
|
/* Read key */
|
||||||
|
int key_read(int code);
|
||||||
|
|
||||||
|
/* deprecated */
|
||||||
int platform_key_read(int code);
|
int platform_key_read(int code);
|
||||||
|
|
||||||
/* General interface for adc or gpio interrupt key event parse */
|
|
||||||
int key_parse_gpio_event(struct input_key *key);
|
|
||||||
int key_parse_adc_event(struct input_key *key, unsigned int adcval);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue