| From 7cd14b1171f859b60c5be3a241e580ba721f49db Mon Sep 17 00:00:00 2001 |
| From: Dmitry Torokhov <dmitry.torokhov@gmail.com> |
| Date: Wed, 19 Oct 2016 19:34:48 -0700 |
| Subject: [PATCH 016/299] Input: gpio_keys - switch to using generic device |
| properties |
| |
| Make use of the device property API in this driver so that both OF based |
| systems and ACPI based systems can use this driver. |
| |
| Suggested-by: Geert Uytterhoeven <geert+renesas@glider.be> |
| Suggested-by: Mika Westerberg <mika.westerberg@linux.intel.com> |
| Tested-by: Mika Westerberg <mika.westerberg@linux.intel.com> |
| Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com> |
| (cherry picked from commit 700a38b27eefc582099fdf69effacfad0ad738a4) |
| Signed-off-by: Simon Horman <horms+renesas@verge.net.au> |
| --- |
| drivers/input/keyboard/gpio_keys.c | 143 ++++++++++++++++++------------------- |
| 1 file changed, 70 insertions(+), 73 deletions(-) |
| |
| --- a/drivers/input/keyboard/gpio_keys.c |
| +++ b/drivers/input/keyboard/gpio_keys.c |
| @@ -28,8 +28,6 @@ |
| #include <linux/gpio.h> |
| #include <linux/gpio/consumer.h> |
| #include <linux/of.h> |
| -#include <linux/of_platform.h> |
| -#include <linux/of_gpio.h> |
| #include <linux/of_irq.h> |
| #include <linux/spinlock.h> |
| |
| @@ -468,7 +466,8 @@ static void gpio_keys_quiesce_key(void * |
| static int gpio_keys_setup_key(struct platform_device *pdev, |
| struct input_dev *input, |
| struct gpio_button_data *bdata, |
| - const struct gpio_keys_button *button) |
| + const struct gpio_keys_button *button, |
| + struct fwnode_handle *child) |
| { |
| const char *desc = button->desc ? button->desc : "gpio_keys"; |
| struct device *dev = &pdev->dev; |
| @@ -481,11 +480,28 @@ static int gpio_keys_setup_key(struct pl |
| bdata->button = button; |
| spin_lock_init(&bdata->lock); |
| |
| - /* |
| - * Legacy GPIO number, so request the GPIO here and |
| - * convert it to descriptor. |
| - */ |
| - if (gpio_is_valid(button->gpio)) { |
| + if (child) { |
| + bdata->gpiod = devm_get_gpiod_from_child(dev, NULL, child); |
| + if (IS_ERR(bdata->gpiod)) { |
| + error = PTR_ERR(bdata->gpiod); |
| + if (error == -ENOENT) { |
| + /* |
| + * GPIO is optional, we may be dealing with |
| + * purely interrupt-driven setup. |
| + */ |
| + bdata->gpiod = NULL; |
| + } else { |
| + if (error != -EPROBE_DEFER) |
| + dev_err(dev, "failed to get gpio: %d\n", |
| + error); |
| + return error; |
| + } |
| + } |
| + } else if (gpio_is_valid(button->gpio)) { |
| + /* |
| + * Legacy GPIO number, so request the GPIO here and |
| + * convert it to descriptor. |
| + */ |
| unsigned flags = GPIOF_IN; |
| |
| if (button->active_low) |
| @@ -502,7 +518,9 @@ static int gpio_keys_setup_key(struct pl |
| bdata->gpiod = gpio_to_desc(button->gpio); |
| if (!bdata->gpiod) |
| return -EINVAL; |
| + } |
| |
| + if (bdata->gpiod) { |
| if (button->debounce_interval) { |
| error = gpiod_set_debounce(bdata->gpiod, |
| button->debounce_interval * 1000); |
| @@ -533,9 +551,10 @@ static int gpio_keys_setup_key(struct pl |
| |
| } else { |
| if (!button->irq) { |
| - dev_err(dev, "No IRQ specified\n"); |
| + dev_err(dev, "Found button without gpio or irq\n"); |
| return -EINVAL; |
| } |
| + |
| bdata->irq = button->irq; |
| |
| if (button->type && button->type != EV_KEY) { |
| @@ -627,24 +646,18 @@ static void gpio_keys_close(struct input |
| * Handlers for alternative sources of platform_data |
| */ |
| |
| -#ifdef CONFIG_OF |
| /* |
| - * Translate OpenFirmware node properties into platform_data |
| + * Translate properties into platform_data |
| */ |
| static struct gpio_keys_platform_data * |
| gpio_keys_get_devtree_pdata(struct device *dev) |
| { |
| - struct device_node *node, *pp; |
| struct gpio_keys_platform_data *pdata; |
| struct gpio_keys_button *button; |
| - int error; |
| + struct fwnode_handle *child; |
| int nbuttons; |
| |
| - node = dev->of_node; |
| - if (!node) |
| - return ERR_PTR(-ENODEV); |
| - |
| - nbuttons = of_get_available_child_count(node); |
| + nbuttons = device_get_child_node_count(dev); |
| if (nbuttons == 0) |
| return ERR_PTR(-ENODEV); |
| |
| @@ -659,64 +672,43 @@ gpio_keys_get_devtree_pdata(struct devic |
| pdata->buttons = button; |
| pdata->nbuttons = nbuttons; |
| |
| - pdata->rep = !!of_get_property(node, "autorepeat", NULL); |
| - |
| - of_property_read_string(node, "label", &pdata->name); |
| - |
| - for_each_available_child_of_node(node, pp) { |
| - enum of_gpio_flags flags; |
| - |
| - button->gpio = of_get_gpio_flags(pp, 0, &flags); |
| - if (button->gpio < 0) { |
| - error = button->gpio; |
| - if (error != -ENOENT) { |
| - if (error != -EPROBE_DEFER) |
| - dev_err(dev, |
| - "Failed to get gpio flags, error: %d\n", |
| - error); |
| - of_node_put(pp); |
| - return ERR_PTR(error); |
| - } |
| - } else { |
| - button->active_low = flags & OF_GPIO_ACTIVE_LOW; |
| - } |
| - |
| - button->irq = irq_of_parse_and_map(pp, 0); |
| + pdata->rep = device_property_read_bool(dev, "autorepeat"); |
| |
| - if (!gpio_is_valid(button->gpio) && !button->irq) { |
| - dev_err(dev, "Found button without gpios or irqs\n"); |
| - of_node_put(pp); |
| - return ERR_PTR(-EINVAL); |
| - } |
| + device_property_read_string(dev, "label", &pdata->name); |
| |
| - if (of_property_read_u32(pp, "linux,code", &button->code)) { |
| - dev_err(dev, "Button without keycode: 0x%x\n", |
| - button->gpio); |
| - of_node_put(pp); |
| + device_for_each_child_node(dev, child) { |
| + if (is_of_node(child)) |
| + button->irq = |
| + irq_of_parse_and_map(to_of_node(child), 0); |
| + |
| + if (fwnode_property_read_u32(child, "linux,code", |
| + &button->code)) { |
| + dev_err(dev, "Button without keycode\n"); |
| + fwnode_handle_put(child); |
| return ERR_PTR(-EINVAL); |
| } |
| |
| - button->desc = of_get_property(pp, "label", NULL); |
| + fwnode_property_read_string(child, "label", &button->desc); |
| |
| - if (of_property_read_u32(pp, "linux,input-type", &button->type)) |
| + if (fwnode_property_read_u32(child, "linux,input-type", |
| + &button->type)) |
| button->type = EV_KEY; |
| |
| - button->wakeup = of_property_read_bool(pp, "wakeup-source") || |
| - /* legacy name */ |
| - of_property_read_bool(pp, "gpio-key,wakeup"); |
| + button->wakeup = |
| + fwnode_property_read_bool(child, "wakeup-source") || |
| + /* legacy name */ |
| + fwnode_property_read_bool(child, "gpio-key,wakeup"); |
| |
| - button->can_disable = !!of_get_property(pp, "linux,can-disable", NULL); |
| + button->can_disable = |
| + fwnode_property_read_bool(child, "linux,can-disable"); |
| |
| - if (of_property_read_u32(pp, "debounce-interval", |
| + if (fwnode_property_read_u32(child, "debounce-interval", |
| &button->debounce_interval)) |
| button->debounce_interval = 5; |
| |
| button++; |
| } |
| |
| - if (pdata->nbuttons == 0) |
| - return ERR_PTR(-EINVAL); |
| - |
| return pdata; |
| } |
| |
| @@ -726,20 +718,11 @@ static const struct of_device_id gpio_ke |
| }; |
| MODULE_DEVICE_TABLE(of, gpio_keys_of_match); |
| |
| -#else |
| - |
| -static inline struct gpio_keys_platform_data * |
| -gpio_keys_get_devtree_pdata(struct device *dev) |
| -{ |
| - return ERR_PTR(-ENODEV); |
| -} |
| - |
| -#endif |
| - |
| static int gpio_keys_probe(struct platform_device *pdev) |
| { |
| struct device *dev = &pdev->dev; |
| const struct gpio_keys_platform_data *pdata = dev_get_platdata(dev); |
| + struct fwnode_handle *child = NULL; |
| struct gpio_keys_drvdata *ddata; |
| struct input_dev *input; |
| size_t size; |
| @@ -792,14 +775,28 @@ static int gpio_keys_probe(struct platfo |
| const struct gpio_keys_button *button = &pdata->buttons[i]; |
| struct gpio_button_data *bdata = &ddata->data[i]; |
| |
| - error = gpio_keys_setup_key(pdev, input, bdata, button); |
| - if (error) |
| + if (!dev_get_platdata(dev)) { |
| + child = device_get_next_child_node(&pdev->dev, child); |
| + if (!child) { |
| + dev_err(&pdev->dev, |
| + "missing child device node for entry %d\n", |
| + i); |
| + return -EINVAL; |
| + } |
| + } |
| + |
| + error = gpio_keys_setup_key(pdev, input, bdata, button, child); |
| + if (error) { |
| + fwnode_handle_put(child); |
| return error; |
| + } |
| |
| if (button->wakeup) |
| wakeup = 1; |
| } |
| |
| + fwnode_handle_put(child); |
| + |
| error = sysfs_create_group(&pdev->dev.kobj, &gpio_keys_attr_group); |
| if (error) { |
| dev_err(dev, "Unable to export keys/switches, error: %d\n", |
| @@ -889,7 +886,7 @@ static struct platform_driver gpio_keys_ |
| .driver = { |
| .name = "gpio-keys", |
| .pm = &gpio_keys_pm_ops, |
| - .of_match_table = of_match_ptr(gpio_keys_of_match), |
| + .of_match_table = gpio_keys_of_match, |
| } |
| }; |
| |