summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoseph Chen <chenjh@rock-chips.com>2019-04-03 17:22:27 +0800
committerJianhong Chen <chenjh@rock-chips.com>2019-04-09 10:54:14 +0800
commit5a54baa79344007142206f4dab5dd46d8ea1dc91 (patch)
treecc780aabeb9c7932bf2afc0177f4ff26e3c19081
parenta0ceee92279dd8ae8d6561b24ca83eb310975159 (diff)
dm: key: refactor code
- use standard dm framework to implement all key drivers; - all key node to be children and attach to key bus; - dm key uclass takes over most work; - reduce a lot of driver code size; Change-Id: I9ea4515249d493eb4434890b90350f694c07404f Signed-off-by: Joseph Chen <chenjh@rock-chips.com>
-rw-r--r--drivers/input/Kconfig2
-rw-r--r--drivers/input/adc_key.c113
-rw-r--r--drivers/input/gpio_key.c130
-rw-r--r--drivers/input/key-uclass.c349
-rw-r--r--drivers/input/rk8xx_pwrkey.c34
-rw-r--r--drivers/input/rk_key.c156
-rw-r--r--include/key.h26
7 files changed, 350 insertions, 460 deletions
diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig
index 7d48cfe526..e49f23c2d2 100644
--- a/drivers/input/Kconfig
+++ b/drivers/input/Kconfig
@@ -47,7 +47,7 @@ config I8042_KEYB
config RK8XX_PWRKEY
bool "Enable RK805/816/817 pwrkey support"
- depends on DM_KEY && PMIC_RK8XX
+ depends on DM_KEY && PMIC_RK8XX && IRQ
help
This adds a driver for the RK805/816/817 pwrkey support.
diff --git a/drivers/input/adc_key.c b/drivers/input/adc_key.c
index 65645d01bc..d3d7df911c 100644
--- a/drivers/input/adc_key.c
+++ b/drivers/input/adc_key.c
@@ -4,92 +4,77 @@
* SPDX-License-Identifier: GPL-2.0+
*/
-#include <dm.h>
-#include <dm/read.h>
-#include <adc.h>
#include <common.h>
-#include <console.h>
-#include <errno.h>
-#include <fdtdec.h>
-#include <malloc.h>
+#include <dm.h>
#include <key.h>
-#include <linux/input.h>
-static int adc_keys_ofdata_to_platdata(struct udevice *dev)
+static int adc_key_ofdata_to_platdata(struct udevice *dev)
{
- struct input_key *key;
- u32 adc_channels[2], microvolt;
+ struct dm_key_uclass_platdata *uc_key;
+ u32 chn[2], mV;
int vref, ret;
- ofnode node;
- /* Get vref */
- vref = dev_read_u32_default(dev, "keyup-threshold-microvolt", -1);
- if (vref < 0) {
- printf("failed to read 'keyup-threshold-microvolt', ret=%d\n",
- vref);
- return -EINVAL;
- }
+ uc_key = dev_get_uclass_platdata(dev);
+ if (!uc_key)
+ return -ENXIO;
- /* Get IO channel */
- ret = dev_read_u32_array(dev, "io-channels", adc_channels, 2);
+ uc_key->type = ADC_KEY;
+ uc_key->name = dev_read_string(dev, "label");
+ ret = dev_read_u32_array(dev_get_parent(dev),
+ "io-channels", chn, ARRAY_SIZE(chn));
if (ret) {
- printf("failed to read 'io-channels', ret=%d\n", ret);
+ printf("%s: read 'io-channels' failed, ret=%d\n",
+ uc_key->name, ret);
return -EINVAL;
}
- /* Parse every adc key data */
- dev_for_each_subnode(node, dev) {
- 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->name, ret);
- free(key);
- continue;
- }
-
- ret = ofnode_read_u32(node, "press-threshold-microvolt",
- &microvolt);
- if (ret) {
- printf("%s: failed to read 'press-threshold-microvolt', ret=%d\n",
- key->name, ret);
- free(key);
- continue;
- }
+ vref = dev_read_u32_default(dev_get_parent(dev),
+ "keyup-threshold-microvolt", -ENODATA);
+ if (vref < 0) {
+ printf("%s: read 'keyup-threshold-microvolt' failed, ret=%d\n",
+ uc_key->name, vref);
+ return -EINVAL;
+ }
- /* Convert microvolt to adc value */
- key->adcval = microvolt / (key->vref / 1024);
- key_add(key);
+ uc_key->code = dev_read_u32_default(dev, "linux,code", -ENODATA);
+ if (uc_key->code < 0) {
+ printf("%s: read 'linux,code' failed\n", uc_key->name);
+ 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);
+ mV = dev_read_u32_default(dev, "press-threshold-microvolt", -ENODATA);
+ if (mV < 0) {
+ printf("%s: read 'press-threshold-microvolt' failed\n",
+ uc_key->name);
+ return -EINVAL;
}
+ uc_key->channel = chn[1];
+ uc_key->adcval = mV / (vref / 1024);
+
return 0;
}
-static const struct dm_key_ops key_ops = {
- .name = "adc-keys",
+U_BOOT_DRIVER(adc_key) = {
+ .name = "adc_key",
+ .id = UCLASS_KEY,
+ .ofdata_to_platdata = adc_key_ofdata_to_platdata,
};
-static const struct udevice_id adc_keys_ids[] = {
+/* Key Bus */
+static int adc_key_bus_bind(struct udevice *dev)
+{
+ return key_bind_children(dev, "adc_key");
+}
+
+static const struct udevice_id adc_key_bus_match[] = {
{ .compatible = "adc-keys" },
{ },
};
-U_BOOT_DRIVER(adc_keys) = {
- .name = "adc-keys",
- .id = UCLASS_KEY,
- .ops = &key_ops,
- .of_match = adc_keys_ids,
- .ofdata_to_platdata = adc_keys_ofdata_to_platdata,
+U_BOOT_DRIVER(adc_key_bus) = {
+ .name = "adc_key_bus",
+ .id = UCLASS_SIMPLE_BUS,
+ .of_match = adc_key_bus_match,
+ .bind = adc_key_bus_bind,
};
diff --git a/drivers/input/gpio_key.c b/drivers/input/gpio_key.c
index 34db0d868d..053c159080 100644
--- a/drivers/input/gpio_key.c
+++ b/drivers/input/gpio_key.c
@@ -4,119 +4,55 @@
* SPDX-License-Identifier: GPL-2.0+
*/
-#include <dm.h>
-#include <adc.h>
#include <common.h>
-#include <console.h>
#include <dm.h>
-#include <errno.h>
-#include <fdtdec.h>
-#include <malloc.h>
#include <key.h>
-#include <linux/input.h>
-#include <errno.h>
-#include <dm/read.h>
-#include <irq-generic.h>
-#include <irq-platform.h>
-
-static void gpio_irq_handler(int irq, void *data)
-{
- struct input_key *key = data;
-
- if (key->irq != irq)
- return;
-
- /* 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 input_key *key;
- u32 gpios[2];
- ofnode node;
- int irq, ret;
-
- dev_for_each_subnode(node, dev) {
- 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;
- }
-
- /* 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;
- }
-
- /* 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);
- }
-
- key_add(key);
- }
+ struct dm_key_uclass_platdata *uc_key;
+
+ uc_key = dev_get_uclass_platdata(dev);
+ if (!uc_key)
+ return -ENXIO;
+
+ uc_key->type = GPIO_KEY;
+ uc_key->name = dev_read_string(dev, "label");
+ uc_key->code = dev_read_u32_default(dev, "linux,code", -ENODATA);
+ if (uc_key->code < 0) {
+ printf("%s: read 'linux,code' failed\n", uc_key->name);
+ return -EINVAL;
+ }
- debug("%s: name=%s: code=%d\n", __func__, key->name, key->code);
+ if (dev_read_u32_array(dev, "gpios",
+ uc_key->gpios, ARRAY_SIZE(uc_key->gpios))) {
+ printf("%s: read 'gpios' failed\n", uc_key->name);
+ return -EINVAL;
}
return 0;
}
-static const struct dm_key_ops key_ops = {
- .name = "gpio-keys",
+U_BOOT_DRIVER(gpio_key) = {
+ .name = "gpio_key",
+ .id = UCLASS_KEY,
+ .ofdata_to_platdata = gpio_key_ofdata_to_platdata,
};
-static const struct udevice_id gpio_key_ids[] = {
+/* Key Bus */
+static int gpio_key_bus_bind(struct udevice *dev)
+{
+ return key_bind_children(dev, "gpio_key");
+}
+
+static const struct udevice_id gpio_key_bus_match[] = {
{ .compatible = "gpio-keys" },
{ },
};
-U_BOOT_DRIVER(gpio_keys) = {
- .name = "gpio-keys",
- .id = UCLASS_KEY,
- .of_match = gpio_key_ids,
- .ops = &key_ops,
- .ofdata_to_platdata = gpio_key_ofdata_to_platdata,
+U_BOOT_DRIVER(gpio_key_bus) = {
+ .name = "gpio_key_bus",
+ .id = UCLASS_SIMPLE_BUS,
+ .of_match = gpio_key_bus_match,
+ .bind = gpio_key_bus_bind,
};
diff --git a/drivers/input/key-uclass.c b/drivers/input/key-uclass.c
index 7f369665b2..1a370a5fa9 100644
--- a/drivers/input/key-uclass.c
+++ b/drivers/input/key-uclass.c
@@ -8,15 +8,12 @@
#include <adc.h>
#include <dm.h>
#include <key.h>
+#include <dm/lists.h>
+#include <irq-generic.h>
-static LIST_HEAD(key_list);
-
-const char *evt_name[] = {
- "Not down",
- "Down",
- "Long down",
- "Not exist",
-};
+#define KEY_WARN(fmt, args...) printf("Key Warn: "fmt, ##args)
+#define KEY_ERR(fmt, args...) printf("Key Error: "fmt, ##args)
+#define KEY_DBG(fmt, args...) debug("Key Debug: "fmt, ##args)
static inline uint64_t arch_counter_get_cntpct(void)
{
@@ -26,7 +23,7 @@ static inline uint64_t arch_counter_get_cntpct(void)
#ifdef CONFIG_ARM64
asm volatile("mrs %0, cntpct_el0" : "=r" (cval));
#else
- asm volatile ("mrrc p15, 0, %Q0, %R0, c14" : "=r" (cval));
+ asm volatile("mrrc p15, 0, %Q0, %R0, c14" : "=r" (cval));
#endif
return cval;
}
@@ -39,197 +36,263 @@ uint64_t key_timer(uint64_t base)
return (cntpct > base) ? (cntpct - base) : 0;
}
-/*
- * 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)
+static int key_adc_event(struct dm_key_uclass_platdata *uc_key, int adcval)
{
- int max, min, margin = 30;
- int keyval;
-
- /* Get min, max */
- max = key->adcval + margin;
- if (key->adcval > margin)
- min = key->adcval - margin;
- else
- min = 0;
-
- debug("%s: '%s' configure adc=%d: range[%d~%d]; hw adcval=%d\n",
- __func__, key->name, key->adcval, min, max, adcval);
-
- /* Check */
- if ((adcval <= max) && (adcval >= min)) {
- keyval = KEY_PRESS_DOWN;
- debug("%s key pressed..\n", key->name);
- } else {
- keyval = KEY_PRESS_NONE;
- }
-
- return keyval;
+ return (adcval <= uc_key->max && adcval >= uc_key->min) ?
+ KEY_PRESS_DOWN : KEY_PRESS_NONE;
}
-static int key_read_gpio_simple_event(struct input_key *key)
+static int key_gpio_event(struct dm_key_uclass_platdata *uc_key)
{
- if (!dm_gpio_is_valid(&key->gpio)) {
- printf("%s: invalid gpio\n", key->name);
+ if (!dm_gpio_is_valid(&uc_key->gpio)) {
+ KEY_ERR("'%s' Invalid gpio\n", uc_key->name);
return KEY_PRESS_NONE;
}
- return dm_gpio_get_value(&key->gpio) ? KEY_PRESS_DOWN : KEY_PRESS_NONE;
+ return dm_gpio_get_value(&uc_key->gpio) ?
+ KEY_PRESS_DOWN : KEY_PRESS_NONE;
}
-static int key_read_gpio_complex_event(struct input_key *key)
+static int key_gpio_interrupt_event(struct dm_key_uclass_platdata *uc_key)
{
- int keyval;
+ int event;
debug("%s: %s: up=%llu, down=%llu, delta=%llu\n",
- __func__, key->name, key->up_t, key->down_t,
- key->up_t - key->down_t);
+ __func__, uc_key->name, uc_key->rise_ms, uc_key->fall_ms,
+ uc_key->rise_ms - uc_key->fall_ms);
/* Possible this is machine power-on long pressed, so ignore this */
- if (key->down_t == 0 && key->up_t != 0) {
- keyval = KEY_PRESS_NONE;
+ if (uc_key->fall_ms == 0 && uc_key->rise_ms != 0) {
+ event = KEY_PRESS_NONE;
goto out;
}
- 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;
- keyval = KEY_PRESS_LONG_DOWN;
- debug("%s key long pressed..\n", key->name);
- } else if (key->down_t &&
- key_timer(key->down_t) >= KEY_LONG_DOWN_MS) {
- key->up_t = 0;
- key->down_t = 0;
- 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;
- keyval = KEY_PRESS_DOWN;
- debug("%s key short pressed..\n", key->name);
+ if ((uc_key->rise_ms > uc_key->fall_ms) &&
+ (uc_key->rise_ms - uc_key->fall_ms) >= KEY_LONG_DOWN_MS) {
+ uc_key->rise_ms = 0;
+ uc_key->fall_ms = 0;
+ event = KEY_PRESS_LONG_DOWN;
+ KEY_DBG("%s key long pressed..\n", uc_key->name);
+ } else if (uc_key->fall_ms &&
+ key_timer(uc_key->fall_ms) >= KEY_LONG_DOWN_MS) {
+ uc_key->rise_ms = 0;
+ uc_key->fall_ms = 0;
+ event = KEY_PRESS_LONG_DOWN;
+ KEY_DBG("%s key long pressed(hold)..\n", uc_key->name);
+ } else if ((uc_key->rise_ms > uc_key->fall_ms) &&
+ (uc_key->rise_ms - uc_key->fall_ms) < KEY_LONG_DOWN_MS) {
+ uc_key->rise_ms = 0;
+ uc_key->fall_ms = 0;
+ event = KEY_PRESS_DOWN;
+ KEY_DBG("%s key short pressed..\n", uc_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 if (uc_key->rise_ms && uc_key->fall_ms &&
+ (uc_key->rise_ms == uc_key->fall_ms)) {
+ uc_key->rise_ms = 0;
+ uc_key->fall_ms = 0;
+ event = KEY_PRESS_DOWN;
+ KEY_DBG("%s key short pressed..\n", uc_key->name);
} else {
- keyval = KEY_PRESS_NONE;
+ event = KEY_PRESS_NONE;
}
out:
- return keyval;
+ return event;
+}
+
+int key_is_pressed(int event)
+{
+ return (event == KEY_PRESS_DOWN || event == KEY_PRESS_LONG_DOWN);
}
-static int key_read_gpio_interrupt_event(struct input_key *key)
+static int key_core_read(struct dm_key_uclass_platdata *uc_key)
{
- debug("%s: %s\n", __func__, key->name);
+ unsigned int adcval;
+
+ if (uc_key->type == ADC_KEY) {
+ if (adc_channel_single_shot("saradc",
+ uc_key->channel, &adcval)) {
+ KEY_ERR("%s failed to read saradc\n", uc_key->name);
+ return KEY_NOT_EXIST;
+ }
- return key_read_gpio_complex_event(key);
+ return key_adc_event(uc_key, adcval);
+ }
+
+ return (uc_key->code == KEY_POWER) ?
+ key_gpio_interrupt_event(uc_key) :
+ key_gpio_event(uc_key);
}
-int key_is_pressed(int keyval)
+int key_read(int code)
{
- return (keyval == KEY_PRESS_DOWN || keyval == KEY_PRESS_LONG_DOWN);
+ struct dm_key_uclass_platdata *uc_key;
+ struct udevice *dev;
+ struct uclass *uc;
+ bool allow_pre_reloc = false;
+ int ret, event = KEY_NOT_EXIST;
+
+ ret = uclass_get(UCLASS_KEY, &uc);
+ if (ret)
+ return ret;
+
+try_again:
+ for (uclass_first_device(UCLASS_KEY, &dev);
+ dev;
+ uclass_next_device(&dev)) {
+ uc_key = dev_get_uclass_platdata(dev);
+
+ if (!allow_pre_reloc && uc_key->pre_reloc)
+ continue;
+
+ if (uc_key->code != code)
+ continue;
+
+ event = key_core_read(uc_key);
+ if (key_is_pressed(event))
+ return event;
+ }
+
+ /* If not find valid key node from kernel, try from u-boot */
+ if (event == KEY_NOT_EXIST && !allow_pre_reloc) {
+ allow_pre_reloc = true;
+ goto try_again;
+ }
+
+ return event;
}
-void key_add(struct input_key *key)
+#ifdef CONFIG_IRQ
+static void gpio_irq_handler(int irq, void *data)
{
- if (!key)
- return;
+ struct dm_key_uclass_platdata *uc_key = data;
- if (!key->parent) {
- printf("Err: Can't find key(code=%d) device\n", key->code);
+ if (uc_key->irq != irq)
return;
+
+ if (irq_get_gpio_level(irq)) {
+ uc_key->rise_ms = key_timer(0);
+ KEY_DBG("%s: key dn: %llu ms\n", uc_key->name, uc_key->fall_ms);
+ } else {
+ uc_key->fall_ms = key_timer(0);
+ KEY_DBG("%s: key up: %llu ms\n", uc_key->name, uc_key->rise_ms);
}
- key->pre_reloc = dev_read_bool(key->parent, "u-boot,dm-pre-reloc");
- list_add_tail(&key->link, &key_list);
+ /* Must delay */
+ mdelay(10);
+ irq_revert_irq_type(irq);
}
+#endif
-static int __key_read(struct input_key *key)
+int key_bind_children(struct udevice *dev, const char *drv_name)
{
- unsigned int adcval;
- int keyval = KEY_NOT_EXIST;
+ const char *name;
+ ofnode node;
int ret;
- /* Is a adc key? */
- if (key->type & ADC_KEY) {
- ret = adc_channel_single_shot("saradc",
- key->channel, &adcval);
+ dev_for_each_subnode(node, dev) {
+ /*
+ * If this node has "compatible" property, this is not
+ * a amp subnode, but a normal device. skip.
+ */
+ ofnode_get_property(node, "compatible", &ret);
+ if (ret >= 0)
+ continue;
+
+ if (ret != -FDT_ERR_NOTFOUND)
+ return ret;
+
+ name = ofnode_get_name(node);
+ if (!name)
+ return -EINVAL;
+ ret = device_bind_driver_to_node(dev, drv_name, name,
+ node, NULL);
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__);
+ return ret;
}
- debug("%s: '%s'(code=%d) is %s\n",
- __func__, key->name, key->code, evt_name[keyval]);
-
- return keyval;
+ return 0;
}
-int key_read(int code)
+static int key_post_probe(struct udevice *dev)
{
- struct udevice *dev;
- struct input_key *key;
- static int initialized;
- int keyval = KEY_NOT_EXIST;
-
- /* Initialize all key drivers */
- if (!initialized) {
- for (uclass_first_device(UCLASS_KEY, &dev);
- dev;
- uclass_next_device(&dev)) {
- debug("%s: have found key driver '%s'\n\n",
- __func__, dev->name);
- }
- }
+ struct dm_key_uclass_platdata *uc_key;
+ int margin = 30;
+ int ret;
- /* The key from kernel dtb has higher priority */
- debug("Reading key from kernel\n");
- list_for_each_entry(key, &key_list, link) {
- if (key->pre_reloc || (key->code != code))
- continue;
+ uc_key = dev_get_uclass_platdata(dev);
+ if (!uc_key)
+ return -ENXIO;
+
+ /* True from U-Boot key node */
+ uc_key->pre_reloc = dev_read_bool(dev, "u-boot,dm-pre-reloc");
- keyval = __key_read(key);
- if (key_is_pressed(keyval))
- return keyval;
+ if (uc_key->type == ADC_KEY) {
+ uc_key->max = uc_key->adcval + margin;
+ uc_key->min = uc_key->adcval > margin ?
+ uc_key->adcval - margin : 0;
+ } else {
+ if (uc_key->code == KEY_POWER) {
+ /* The gpio irq has been setup by key driver */
+ if (uc_key->irq)
+ goto finish;
+#ifdef CONFIG_IRQ
+ int irq;
+
+ irq = phandle_gpio_to_irq(uc_key->gpios[0],
+ uc_key->gpios[1]);
+ if (irq < 0) {
+ KEY_ERR("%s: failed to request irq, ret=%d\n",
+ uc_key->name, irq);
+ return irq;
+ }
+
+ uc_key->irq = irq;
+ irq_install_handler(irq, gpio_irq_handler, uc_key);
+ irq_set_irq_type(irq, IRQ_TYPE_EDGE_FALLING);
+ irq_handler_enable(irq);
+#else
+ KEY_WARN("%s: no IRQ framework available\n", uc_key->name);
+#endif
+ } else {
+ ret = gpio_request_by_name(dev, "gpios", 0,
+ &uc_key->gpio, GPIOD_IS_IN);
+ if (ret) {
+ KEY_ERR("%s: failed to request gpio, ret=%d\n",
+ uc_key->name, ret);
+ return ret;
+ }
+ }
}
- /* If not found any key from kernel dtb, reading from U-Boot dtb */
- if (keyval == KEY_NOT_EXIST) {
- debug("Reading key from U-Boot\n");
- list_for_each_entry(key, &key_list, link) {
- if (!key->pre_reloc || (key->code != code))
- continue;
+finish:
+#ifdef DEBUG
+ printf("[%s] (%s, %s, %s):\n", uc_key->name,
+ uc_key->type == ADC_KEY ? "ADC" : "GPIO",
+ uc_key->pre_reloc ? "U-Boot" : "Kernel",
+ dev->parent->name);
+
+ if (uc_key->type == ADC_KEY) {
+ printf(" adcval: %d (%d, %d)\n", uc_key->adcval,
+ uc_key->min, uc_key->max);
+ printf(" channel: %d\n\n", uc_key->channel);
+ } else {
+ const char *gpio_name =
+ ofnode_get_name(ofnode_get_by_phandle(uc_key->gpios[0]));
- keyval = __key_read(key);
- if (key_is_pressed(keyval))
- return keyval;
- }
+ printf(" irq: %d\n", uc_key->irq);
+ printf(" gpio[0]: %s\n", gpio_name);
+ printf(" gpio[1]: %d\n\n", uc_key->gpios[1]);
}
+#endif
- return keyval;
+ return 0;
}
UCLASS_DRIVER(key) = {
.id = UCLASS_KEY,
.name = "key",
+ .post_probe = key_post_probe,
+ .per_device_platdata_auto_alloc_size =
+ sizeof(struct dm_key_uclass_platdata),
};
diff --git a/drivers/input/rk8xx_pwrkey.c b/drivers/input/rk8xx_pwrkey.c
index fc3ee631e5..14fe5bce3f 100644
--- a/drivers/input/rk8xx_pwrkey.c
+++ b/drivers/input/rk8xx_pwrkey.c
@@ -105,7 +105,7 @@ static void pwrkey_irq_handler(int irq, void *data)
{
struct udevice *dev = data;
struct rk8xx_key_priv *priv = dev_get_priv(dev);
- struct input_key *key = dev_get_platdata(dev);
+ struct dm_key_uclass_platdata *uc_key = dev_get_uclass_platdata(dev);
int ret, val, i;
debug("%s: irq = %d\n", __func__, irq);
@@ -135,14 +135,14 @@ static void pwrkey_irq_handler(int irq, void *data)
/* fall event */
if (val & priv->pwron_fall_int) {
- key->down_t = key_timer(0);
- debug("%s: key down: %llu ms\n", __func__, key->down_t);
+ uc_key->fall_ms = key_timer(0);
+ debug("%s: key down: %llu ms\n", __func__, uc_key->fall_ms);
}
/* rise event */
if (val & priv->pwron_rise_int) {
- key->up_t = key_timer(0);
- debug("%s: key up: %llu ms\n", __func__, key->up_t);
+ uc_key->rise_ms = key_timer(0);
+ debug("%s: key up: %llu ms\n", __func__, uc_key->rise_ms);
}
/* clear intertup */
@@ -162,33 +162,31 @@ static void pwrkey_irq_handler(int irq, void *data)
static int pwrkey_interrupt_init(struct udevice *dev)
{
- struct input_key *key = dev_get_platdata(dev);
+ struct dm_key_uclass_platdata *uc_key = dev_get_uclass_platdata(dev);
u32 interrupt[2], phandle;
int irq, ret;
phandle = dev_read_u32_default(dev->parent, "interrupt-parent", -1);
if (phandle < 0) {
- printf("failed get 'interrupt-parent', ret=%d\n", phandle);
+ printf("read 'interrupt-parent' failed, ret=%d\n", phandle);
return phandle;
}
ret = dev_read_u32_array(dev->parent, "interrupts", interrupt, 2);
if (ret) {
- printf("failed get 'interrupt', ret=%d\n", ret);
+ printf("read 'interrupt' failed, ret=%d\n", ret);
return ret;
}
- key->parent = dev;
- key->name = "rk8xx_pwrkey";
- key->code = KEY_POWER;
- key->type = GPIO_KEY;
+ uc_key->name = "rk8xx_pwr";
+ uc_key->type = GPIO_KEY;
+ uc_key->code = KEY_POWER;
irq = phandle_gpio_to_irq(phandle, interrupt[0]);
if (irq < 0) {
- printf("%s: failed to request irq, ret=%d\n", key->name, irq);
+ printf("%s: request irq failed, ret=%d\n", uc_key->name, irq);
return irq;
}
- key->irq = irq;
- key_add(key);
+ uc_key->irq = irq;
irq_install_handler(irq, pwrkey_irq_handler, dev);
irq_set_irq_type(irq, IRQ_TYPE_EDGE_FALLING);
irq_handler_enable(irq);
@@ -196,10 +194,6 @@ static int pwrkey_interrupt_init(struct udevice *dev)
return 0;
}
-static const struct dm_key_ops key_ops = {
- .name = "rk8xx-pwrkey",
-};
-
static int rk8xx_pwrkey_probe(struct udevice *dev)
{
struct rk8xx_priv *rk8xx = dev_get_priv(dev->parent);
@@ -270,8 +264,6 @@ static int rk8xx_pwrkey_probe(struct udevice *dev)
U_BOOT_DRIVER(rk8xx_pwrkey) = {
.name = "rk8xx_pwrkey",
.id = UCLASS_KEY,
- .ops = &key_ops,
.probe = rk8xx_pwrkey_probe,
- .platdata_auto_alloc_size = sizeof(struct input_key),
.priv_auto_alloc_size = sizeof(struct rk8xx_key_priv),
};
diff --git a/drivers/input/rk_key.c b/drivers/input/rk_key.c
index 44f2b5d4a7..2619a8e3b0 100644
--- a/drivers/input/rk_key.c
+++ b/drivers/input/rk_key.c
@@ -4,145 +4,65 @@
* SPDX-License-Identifier: GPL-2.0+
*/
-#include <dm.h>
-#include <adc.h>
#include <common.h>
-#include <console.h>
#include <dm.h>
-#include <errno.h>
-#include <fdtdec.h>
-#include <malloc.h>
#include <key.h>
-#include <linux/input.h>
-#include <errno.h>
-#include <dm/read.h>
-#include <irq-generic.h>
-#include <irq-platform.h>
-static void gpio_irq_handler(int irq, void *data)
+static int rk_key_ofdata_to_platdata(struct udevice *dev)
{
- struct input_key *key = data;
+ struct dm_key_uclass_platdata *uc_key;
+ u32 chn[2];
- if (key->irq != irq)
- return;
+ uc_key = dev_get_uclass_platdata(dev);
+ if (!uc_key)
+ return -ENXIO;
- /* 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);
-}
+ uc_key->name = dev_read_string(dev, "label");
+ uc_key->code = dev_read_u32_default(dev, "linux,code", -ENODATA);
-static int rk_keys_ofdata_to_platdata(struct udevice *dev)
-{
- struct input_key *key;
- u32 adc_channels[2], gpios[2], adcval;
- int irq, ret;
- ofnode node;
-
- /* Get IO channel */
- if (dev_read_u32_array(dev, "io-channels", adc_channels, 2)) {
- printf("%s: failed to read 'io-channels'\n", __func__);
+ if (dev_read_u32_array(dev_get_parent(dev), "io-channels", chn, 2)) {
+ printf("%s: read 'io-channels' failed\n", uc_key->name);
return -EINVAL;
}
- 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->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->name);
- free(key);
- continue;
- }
- key_add(key);
- /* This is a GPIO key */
- } else {
- 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;
- }
-
- /* 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);
- }
+ if (dev_read_bool(dev, "rockchip,adc_value")) {
+ uc_key->type = ADC_KEY;
+ uc_key->channel = chn[1];
+ uc_key->adcval =
+ dev_read_u32_default(dev, "rockchip,adc_value", 0);
+ } else {
+ uc_key->type = GPIO_KEY;
+ if (dev_read_u32_array(dev, "gpios",
+ uc_key->gpios,
+ ARRAY_SIZE(uc_key->gpios))) {
+ printf("%s: read 'gpios' failed\n", uc_key->name);
+ 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 const struct dm_key_ops key_ops = {
- .name = "rk-keys",
+U_BOOT_DRIVER(rk_key) = {
+ .name = "rk_key",
+ .id = UCLASS_KEY,
+ .ofdata_to_platdata = rk_key_ofdata_to_platdata,
};
-static const struct udevice_id rk_keys_ids[] = {
+/* Key Bus */
+static int rk_key_bus_bind(struct udevice *dev)
+{
+ return key_bind_children(dev, "rk_key");
+}
+
+static const struct udevice_id rk_key_bus_match[] = {
{ .compatible = "rockchip,key" },
{ },
};
-U_BOOT_DRIVER(rk_keys) = {
- .name = "rk-keys",
- .id = UCLASS_KEY,
- .ops = &key_ops,
- .of_match = rk_keys_ids,
- .ofdata_to_platdata = rk_keys_ofdata_to_platdata,
+U_BOOT_DRIVER(rk_key_bus) = {
+ .name = "rk_key_bus",
+ .id = UCLASS_SIMPLE_BUS,
+ .of_match = rk_key_bus_match,
+ .bind = rk_key_bus_bind,
};
diff --git a/include/key.h b/include/key.h
index f85e1f3164..c9e11bd874 100644
--- a/include/key.h
+++ b/include/key.h
@@ -18,49 +18,43 @@ enum {
GPIO_KEY = 0x2,
};
-enum key_state {
+enum key_event {
KEY_PRESS_NONE, /* press without release */
KEY_PRESS_DOWN, /* press -> release */
KEY_PRESS_LONG_DOWN,
KEY_NOT_EXIST,
};
-struct input_key {
- struct udevice *parent;
- struct list_head link;
+struct dm_key_uclass_platdata {
const char *name;
bool pre_reloc;
u32 code;
u8 type;
/* ADC key */
- u32 adcval;
- u32 vref;
u8 channel;
+ u32 adcval;
+ u32 min;
+ u32 max;
/* GPIO key */
u32 irq;
+ u32 gpios[2];
struct gpio_desc gpio;
- /* Event */
- u64 up_t;
- u64 down_t;
-};
-
-struct dm_key_ops {
- const char *name;
+ u64 rise_ms;
+ u64 fall_ms;
};
/* 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);
+int key_bind_children(struct udevice *dev, const char *drv_name);
+
#endif