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 <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)
|
||||
{
|
||||
struct adc_key_priv *priv = dev_get_priv(dev);
|
||||
struct input_key *key = dev_get_platdata(dev);
|
||||
u32 adc_channels[2], i = 0, microvolt;
|
||||
int vref, err;
|
||||
struct input_key *key;
|
||||
u32 adc_channels[2], microvolt;
|
||||
int vref, ret;
|
||||
ofnode node;
|
||||
|
||||
/* Get vref */
|
||||
|
|
@ -39,90 +31,54 @@ static int adc_keys_ofdata_to_platdata(struct udevice *dev)
|
|||
}
|
||||
|
||||
/* Get IO channel */
|
||||
err = dev_read_u32_array(dev, "io-channels", adc_channels, 2);
|
||||
if (err) {
|
||||
printf("failed to read 'io-channels' of %s key, ret=%d\n",
|
||||
key->name, err);
|
||||
ret = dev_read_u32_array(dev, "io-channels", adc_channels, 2);
|
||||
if (ret) {
|
||||
printf("failed to read 'io-channels', ret=%d\n", ret);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Parse every adc key data */
|
||||
dev_for_each_subnode(node, dev) {
|
||||
key[i].name = ofnode_read_string(node, "label");
|
||||
key[i].vref = vref;
|
||||
key[i].margin = ADC_MARGIN;
|
||||
key[i].channel = adc_channels[1];
|
||||
if (ofnode_read_u32(node, "linux,code", &key[i].code)) {
|
||||
key = calloc(1, sizeof(struct input_key));
|
||||
if (!key)
|
||||
return -ENOMEM;
|
||||
|
||||
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",
|
||||
key[i].name, key[i].code);
|
||||
return -EINVAL;
|
||||
key->name, ret);
|
||||
free(key);
|
||||
continue;
|
||||
}
|
||||
if (ofnode_read_u32(node, "press-threshold-microvolt",
|
||||
µvolt)) {
|
||||
printf("%s: failed read 'press-threshold-microvolt', ret=%d\n",
|
||||
key[i].name, microvolt);
|
||||
return -EINVAL;
|
||||
|
||||
ret = ofnode_read_u32(node, "press-threshold-microvolt",
|
||||
µvolt);
|
||||
if (ret) {
|
||||
printf("%s: failed to read 'press-threshold-microvolt', ret=%d\n",
|
||||
key->name, ret);
|
||||
free(key);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* 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",
|
||||
__func__, key[i].name, key[i].code, key[i].vref,
|
||||
key[i].margin, key[i].channel, key[i].value);
|
||||
|
||||
/* 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;
|
||||
}
|
||||
debug("%s: name=%s: code=%d, vref=%d, channel=%d, microvolt=%d, adcval=%d\n",
|
||||
__func__, key->name, key->code, key->vref,
|
||||
key->channel, microvolt, key->adcval);
|
||||
}
|
||||
|
||||
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 = {
|
||||
.name = "adc_keys",
|
||||
.read = adc_keys_read,
|
||||
.name = "adc-keys",
|
||||
};
|
||||
|
||||
static const struct udevice_id adc_keys_ids[] = {
|
||||
|
|
@ -136,6 +92,4 @@ U_BOOT_DRIVER(adc_keys) = {
|
|||
.ops = &key_ops,
|
||||
.of_match = adc_keys_ids,
|
||||
.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-platform.h>
|
||||
|
||||
#define MAX_KEY_NR 10
|
||||
|
||||
struct gpio_key_priv {
|
||||
u32 key_nr;
|
||||
};
|
||||
|
||||
static void gpio_irq_handler(int irq, void *data)
|
||||
{
|
||||
struct udevice *dev = data;
|
||||
struct gpio_key_priv *priv = dev_get_priv(dev);
|
||||
struct input_key *key = dev_get_platdata(dev);
|
||||
int i;
|
||||
struct input_key *key = data;
|
||||
|
||||
for (i = 0; i < priv->key_nr; i++) {
|
||||
if (key[i].irq != irq)
|
||||
continue;
|
||||
if (key->irq != irq)
|
||||
return;
|
||||
|
||||
/* up event */
|
||||
if (irq_get_gpio_level(irq)) {
|
||||
key[i].up_t = key_get_timer(0);
|
||||
debug("%s: key down: %llu ms\n",
|
||||
key[i].name, key[i].down_t);
|
||||
/* down event */
|
||||
} else {
|
||||
key[i].down_t = key_get_timer(0);
|
||||
debug("%s: key up: %llu ms\n",
|
||||
key[i].name, key[i].up_t);
|
||||
}
|
||||
/* Must delay */
|
||||
mdelay(10);
|
||||
irq_revert_irq_type(irq);
|
||||
/* up event */
|
||||
if (irq_get_gpio_level(irq)) {
|
||||
key->up_t = key_timer(0);
|
||||
debug("%s: key down: %llu ms\n", key->name, key->down_t);
|
||||
/* down event */
|
||||
} else {
|
||||
key->down_t = key_timer(0);
|
||||
debug("%s: key up: %llu ms\n", key->name, key->up_t);
|
||||
}
|
||||
/* Must delay */
|
||||
mdelay(10);
|
||||
irq_revert_irq_type(irq);
|
||||
}
|
||||
|
||||
static int gpio_key_ofdata_to_platdata(struct udevice *dev)
|
||||
{
|
||||
struct gpio_key_priv *priv = dev_get_priv(dev);
|
||||
struct input_key *key = dev_get_platdata(dev);
|
||||
u32 gpios[2], i = 0;
|
||||
struct input_key *key;
|
||||
u32 gpios[2];
|
||||
ofnode node;
|
||||
int irq;
|
||||
int irq, ret;
|
||||
|
||||
dev_for_each_subnode(node, dev) {
|
||||
key[i].name = ofnode_read_string(node, "label");
|
||||
if (ofnode_read_u32(node, "linux,code", &key[i].code)) {
|
||||
printf("failed read 'linux,code' of %s key\n",
|
||||
key[i].name);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (ofnode_read_u32_array(node, "gpios", gpios, 2)) {
|
||||
printf("failed to read 'gpios' of %s key\n",
|
||||
key[i].name);
|
||||
return -EINVAL;
|
||||
key = calloc(1, sizeof(struct input_key));
|
||||
if (!key)
|
||||
return -ENOMEM;
|
||||
|
||||
key->parent = dev;
|
||||
key->type = GPIO_KEY;
|
||||
key->name = ofnode_read_string(node, "label");
|
||||
ret = ofnode_read_u32(node, "linux,code", &key->code);
|
||||
if (ret) {
|
||||
printf("%s: failed read 'linux,code', ret=%d\n",
|
||||
key->name, ret);
|
||||
free(key);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Must register as interrupt, be able to wakeup system */
|
||||
irq = phandle_gpio_to_irq(gpios[0], gpios[1]);
|
||||
if (irq < 0) {
|
||||
printf("failed to request irq for gpio, ret=%d\n", irq);
|
||||
return irq;
|
||||
}
|
||||
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);
|
||||
/* Only register power key as interrupt */
|
||||
if (key->code == KEY_POWER) {
|
||||
ret = ofnode_read_u32_array(node, "gpios", gpios, 2);
|
||||
if (ret) {
|
||||
printf("%s: failed to read 'gpios', ret=%d\n",
|
||||
key->name, ret);
|
||||
free(key);
|
||||
continue;
|
||||
}
|
||||
|
||||
debug("%s: name=%s: code=%d\n",
|
||||
__func__, key[i].name, key[i].code);
|
||||
/* Must register as interrupt, be able to wakeup system */
|
||||
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 */
|
||||
i++;
|
||||
priv->key_nr = i;
|
||||
if (i >= MAX_KEY_NR) {
|
||||
printf("Too many keys, Max support: %d\n", MAX_KEY_NR);
|
||||
return -EINVAL;
|
||||
key_add(key);
|
||||
}
|
||||
|
||||
debug("%s: name=%s: code=%d\n", __func__, key->name, key->code);
|
||||
}
|
||||
|
||||
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 = {
|
||||
.name = "gpio-keys",
|
||||
.read = gpio_key_read,
|
||||
};
|
||||
|
||||
static const struct udevice_id gpio_key_ids[] = {
|
||||
|
|
@ -133,6 +119,4 @@ U_BOOT_DRIVER(gpio_keys) = {
|
|||
.of_match = gpio_key_ids,
|
||||
.ops = &key_ops,
|
||||
.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+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <adc.h>
|
||||
#include <dm.h>
|
||||
#include <key.h>
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
|
||||
static LIST_HEAD(key_list);
|
||||
|
||||
static inline uint64_t arch_counter_get_cntpct(void)
|
||||
{
|
||||
|
|
@ -22,7 +24,7 @@ static inline uint64_t arch_counter_get_cntpct(void)
|
|||
return cval;
|
||||
}
|
||||
|
||||
uint64_t key_get_timer(uint64_t base)
|
||||
uint64_t key_timer(uint64_t base)
|
||||
{
|
||||
uint64_t cntpct;
|
||||
|
||||
|
|
@ -30,50 +32,51 @@ uint64_t key_get_timer(uint64_t base)
|
|||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
int max, min, margin = 30;
|
||||
int keyval;
|
||||
|
||||
/* Get min, max */
|
||||
max = key->value + key->margin;
|
||||
if (key->value > key->margin)
|
||||
min = key->value - key->margin;
|
||||
max = key->adcval + margin;
|
||||
if (key->adcval > margin)
|
||||
min = key->adcval - margin;
|
||||
else
|
||||
min = key->value;
|
||||
min = 0;
|
||||
|
||||
debug("%s: %s: max=%d, min=%d, adcval=%d\n",
|
||||
__func__, key->name, max, min, adcval);
|
||||
debug("%s: %s: val=%d, max=%d, min=%d, adcval=%d\n",
|
||||
__func__, key->name, key->adcval, max, min, adcval);
|
||||
|
||||
/* Check */
|
||||
if ((adcval <= max) && (adcval >= min)) {
|
||||
report = KEY_PRESS_DOWN;
|
||||
printf("%s key pressed..\n", key->name);
|
||||
keyval = KEY_PRESS_DOWN;
|
||||
debug("%s key pressed..\n", key->name);
|
||||
} 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",
|
||||
__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 */
|
||||
if (key->down_t == 0 && key->up_t != 0) {
|
||||
report = KEY_PRESS_NONE;
|
||||
keyval = KEY_PRESS_NONE;
|
||||
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 = 0;
|
||||
key->down_t = 0;
|
||||
report = KEY_PRESS_LONG_DOWN;
|
||||
printf("%s key long pressed(hold)..\n", key->name);
|
||||
keyval = KEY_PRESS_LONG_DOWN;
|
||||
debug("%s key long pressed..\n", key->name);
|
||||
} 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->down_t = 0;
|
||||
report = KEY_PRESS_LONG_DOWN;
|
||||
printf("%s key long pressed..\n", key->name);
|
||||
keyval = KEY_PRESS_LONG_DOWN;
|
||||
debug("%s key long pressed(hold)..\n", key->name);
|
||||
} else if ((key->up_t > key->down_t) &&
|
||||
(key->up_t - key->down_t) < KEY_LONG_DOWN_MS) {
|
||||
key->up_t = 0;
|
||||
key->down_t = 0;
|
||||
report = KEY_PRESS_DOWN;
|
||||
printf("%s key short pressed..\n", key->name);
|
||||
keyval = KEY_PRESS_DOWN;
|
||||
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 {
|
||||
report = KEY_PRESS_NONE;
|
||||
keyval = KEY_PRESS_NONE;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
struct udevice *dev;
|
||||
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;
|
||||
return KEY_NOT_EXIST;
|
||||
}
|
||||
|
||||
UCLASS_DRIVER(key) = {
|
||||
|
|
|
|||
|
|
@ -101,16 +101,6 @@ static struct reg_data rk805_init_reg[] = {
|
|||
{ 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)
|
||||
{
|
||||
struct udevice *dev = data;
|
||||
|
|
@ -145,13 +135,13 @@ static void pwrkey_irq_handler(int irq, void *data)
|
|||
|
||||
/* fall event */
|
||||
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);
|
||||
}
|
||||
|
||||
/* rise event */
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
@ -188,9 +178,17 @@ static int pwrkey_interrupt_init(struct udevice *dev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
key->name = "power";
|
||||
key->parent = dev;
|
||||
key->name = "rk8xx_pwrkey";
|
||||
key->code = KEY_POWER;
|
||||
key->type = GPIO_KEY;
|
||||
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_set_irq_type(irq, IRQ_TYPE_EDGE_FALLING);
|
||||
irq_handler_enable(irq);
|
||||
|
|
@ -200,7 +198,6 @@ static int pwrkey_interrupt_init(struct udevice *dev)
|
|||
|
||||
static const struct dm_key_ops key_ops = {
|
||||
.name = "rk8xx-pwrkey",
|
||||
.read = rk8xx_pwrkey_read,
|
||||
};
|
||||
|
||||
static int rk8xx_pwrkey_probe(struct udevice *dev)
|
||||
|
|
|
|||
|
|
@ -19,54 +19,33 @@
|
|||
#include <irq-generic.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)
|
||||
{
|
||||
struct udevice *dev = data;
|
||||
struct rk_key_priv *priv = dev_get_priv(dev);
|
||||
struct input_key *key = dev_get_platdata(dev);
|
||||
int i;
|
||||
struct input_key *key = data;
|
||||
|
||||
for (i = 0; i < priv->key_nr; i++) {
|
||||
if (key[i].irq != irq)
|
||||
continue;
|
||||
if (key->irq != irq)
|
||||
return;
|
||||
|
||||
/* up event */
|
||||
if (irq_get_gpio_level(irq)) {
|
||||
key[i].up_t = key_get_timer(0);
|
||||
debug("%s: key down: %llu ms\n",
|
||||
key[i].name, key[i].down_t);
|
||||
/* down event */
|
||||
} else {
|
||||
key[i].down_t = key_get_timer(0);
|
||||
debug("%s: key up: %llu ms\n",
|
||||
key[i].name, key[i].up_t);
|
||||
}
|
||||
/* Must delay */
|
||||
mdelay(10);
|
||||
irq_revert_irq_type(irq);
|
||||
/* up event */
|
||||
if (irq_get_gpio_level(irq)) {
|
||||
key->up_t = key_timer(0);
|
||||
debug("%s: key down: %llu ms\n", key->name, key->down_t);
|
||||
/* down event */
|
||||
} else {
|
||||
key->down_t = key_timer(0);
|
||||
debug("%s: key up: %llu ms\n", key->name, key->up_t);
|
||||
}
|
||||
/* Must delay */
|
||||
mdelay(10);
|
||||
irq_revert_irq_type(irq);
|
||||
}
|
||||
|
||||
static int rk_keys_ofdata_to_platdata(struct udevice *dev)
|
||||
{
|
||||
struct rk_key_priv *priv = dev_get_priv(dev);
|
||||
struct input_key *key = dev_get_platdata(dev);
|
||||
u32 adc_channels[2], gpios[2], adcval, i = 0;
|
||||
struct input_key *key;
|
||||
u32 adc_channels[2], gpios[2], adcval;
|
||||
int irq, ret;
|
||||
ofnode node;
|
||||
int irq;
|
||||
|
||||
/* Get IO channel */
|
||||
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) {
|
||||
key = calloc(1, sizeof(struct input_key));
|
||||
if (!key)
|
||||
return -ENOMEM;
|
||||
|
||||
/* This is an ACD key */
|
||||
if (!ofnode_read_u32(node, "rockchip,adc_value", &adcval)) {
|
||||
key[i].name = ofnode_read_string(node, "label");
|
||||
key[i].flag = ADC_KEY;
|
||||
key[i].margin = ADC_MARGIN;
|
||||
key[i].value = adcval;
|
||||
key[i].channel = adc_channels[1];
|
||||
if (ofnode_read_u32(node, "linux,code", &key[i].code)) {
|
||||
key->parent = dev;
|
||||
key->name = ofnode_read_string(node, "label");
|
||||
key->type = ADC_KEY;
|
||||
key->adcval = adcval;
|
||||
key->channel = adc_channels[1];
|
||||
if (ofnode_read_u32(node, "linux,code", &key->code)) {
|
||||
printf("%s: failed to read 'linux,code'\n",
|
||||
key[i].name);
|
||||
return -EINVAL;
|
||||
key->name);
|
||||
free(key);
|
||||
continue;
|
||||
}
|
||||
/* This is a GPIO key */
|
||||
} else {
|
||||
key[i].name = ofnode_read_string(node, "label");
|
||||
key[i].flag = GPIO_KEY;
|
||||
if (ofnode_read_u32_array(node, "gpios", gpios, 2)) {
|
||||
printf("%s: failed to read 'gpios'\n",
|
||||
key[i].name);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (ofnode_read_u32(node, "linux,code", &key[i].code)) {
|
||||
printf("%s: failed read 'linux,code'\n",
|
||||
key[i].name);
|
||||
return -EINVAL;
|
||||
key->parent = dev;
|
||||
key->type = GPIO_KEY;
|
||||
key->name = ofnode_read_string(node, "label");
|
||||
ret = ofnode_read_u32(node, "linux,code", &key->code);
|
||||
if (ret) {
|
||||
printf("%s: failed read 'linux,code', 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);
|
||||
return irq;
|
||||
/* Only register power key as interrupt */
|
||||
if (key->code == KEY_POWER) {
|
||||
ret = ofnode_read_u32_array(node, "gpios",
|
||||
gpios, 2);
|
||||
if (ret) {
|
||||
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",
|
||||
__func__, key[i].name, key[i].code, key[i].value,
|
||||
key[i].channel, key[i].flag, key[i].margin);
|
||||
|
||||
/* 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;
|
||||
}
|
||||
debug("%s: name=%s: code=%d, adcval=%d, channel=%d, type=%d\n",
|
||||
__func__, key->name, key->code, key->adcval,
|
||||
key->channel, key->type);
|
||||
}
|
||||
|
||||
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 = {
|
||||
.name = "rk-keys",
|
||||
.read = rk_keys_read,
|
||||
};
|
||||
|
||||
static const struct udevice_id rk_keys_ids[] = {
|
||||
|
|
@ -176,6 +144,4 @@ U_BOOT_DRIVER(rk_keys) = {
|
|||
.ops = &key_ops,
|
||||
.of_match = rk_keys_ids,
|
||||
.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_
|
||||
#define _KEY_H_
|
||||
|
||||
#include <asm-generic/gpio.h>
|
||||
#include <dt-bindings/input/linux-event-codes.h>
|
||||
|
||||
#define KEY_LONG_DOWN_MS 2000
|
||||
|
||||
enum {
|
||||
INVAL_KEY = 0x0,
|
||||
ADC_KEY = 0x1,
|
||||
GPIO_KEY = 0x2,
|
||||
};
|
||||
|
||||
enum key_state {
|
||||
KEY_PRESS_NONE, /* press without release */
|
||||
KEY_PRESS_DOWN, /* press -> release */
|
||||
|
|
@ -18,30 +25,44 @@ enum key_state {
|
|||
KEY_NOT_EXIST,
|
||||
};
|
||||
|
||||
struct dm_key_ops {
|
||||
const char *name;
|
||||
int (*read)(struct udevice *dev, int code);
|
||||
};
|
||||
|
||||
struct input_key {
|
||||
struct udevice *parent;
|
||||
struct list_head link;
|
||||
const char *name;
|
||||
u32 code;
|
||||
u32 channel;
|
||||
u32 value;
|
||||
u32 margin;
|
||||
u32 vref;
|
||||
int flag;
|
||||
u8 type;
|
||||
|
||||
/* ADC key */
|
||||
u32 adcval;
|
||||
u32 vref;
|
||||
u8 channel;
|
||||
|
||||
/* GPIO key */
|
||||
u32 irq;
|
||||
struct gpio_desc gpio;
|
||||
|
||||
/* Event */
|
||||
u64 up_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);
|
||||
|
||||
/* 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
|
||||
|
|
|
|||
Loading…
Reference in New Issue