From 5a54baa79344007142206f4dab5dd46d8ea1dc91 Mon Sep 17 00:00:00 2001 From: Joseph Chen Date: Wed, 3 Apr 2019 17:22:27 +0800 Subject: 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 --- drivers/input/Kconfig | 2 +- drivers/input/adc_key.c | 113 ++++++-------- drivers/input/gpio_key.c | 130 ++++------------ drivers/input/key-uclass.c | 349 +++++++++++++++++++++++++------------------ drivers/input/rk8xx_pwrkey.c | 34 ++--- drivers/input/rk_key.c | 156 +++++-------------- include/key.h | 26 ++-- 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 -#include -#include #include -#include -#include -#include -#include +#include #include -#include -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", - µvolt); - 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 -#include #include -#include #include -#include -#include -#include #include -#include -#include -#include -#include -#include - -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 #include #include +#include +#include -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 -#include #include -#include #include -#include -#include -#include #include -#include -#include -#include -#include -#include -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 -- cgit v1.2.3