Thread (13 messages) flat view 13 messages, 5 authors, 2011-07-05

Re: [PATCH v5 1/2] Input: gpio_keys.c: Added support for device-tree platform data

From: Grant Likely <hidden>
Date: 2011-06-23 12:30:07

On Thu, Jun 23, 2011 at 4:04 AM, David Jander [off-list ref] wrote:
quoted hunk ↗ jump to hunk
This patch enables fetching configuration data which is normally provided via
platform_data from the device-tree instead.
If the device is configured from device-tree data, the platform_data struct
is not used, and button data needs to be allocated dynamically.
Big part of this patch deals with confining pdata usage to the probe function,
to make this possible.

Signed-off-by: David Jander <redacted>
---
 .../devicetree/bindings/gpio/gpio_keys.txt         |   37 +++++
 drivers/input/keyboard/gpio_keys.c                 |  146 ++++++++++++++++++--
 2 files changed, 168 insertions(+), 15 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/gpio/gpio_keys.txt
diff --git a/Documentation/devicetree/bindings/gpio/gpio_keys.txt b/Documentation/devicetree/bindings/gpio/gpio_keys.txt
new file mode 100644
index 0000000..a0fed97
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpio/gpio_keys.txt
@@ -0,0 +1,37 @@
+Device-Tree bindings for input/gpio_keys.c keyboard driver
+
+Required properties:
+       - compatible = "gpio-keys";
+
+Optional properties:
+       - autorepeat: Boolean, Enable auto repeat feature of Linux input
+         subsystem.
+
+Each button (key) is represented as a sub-node of "gpio-keys":
+Subnode properties:
+
+       - gpios: OF devcie-tree gpio specificatin.
+       - label: Descriptive name of the key.
+       - linux,code: Keycode to emit.
The fact that this is the Linux internal keycode definitions still
makes me nervous.  Is there no existing standard for keycodes emitted
by keyboard devices?
quoted hunk ↗ jump to hunk
+
+Optional subnode-properties:
+       - linux,input-type: Specify event type this button/key generates.
+         Default if unspecified is <1> == EV_KEY.
+       - debounce-interval: Debouncing interval time in milliseconds.
+         Default if unspecified is 5.
+       - gpio-key,wakeup: Boolean, button can wake-up the system.
+
+Example nodes:
+
+       gpio_keys {
+                       compatible = "gpio-keys";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       autorepeat;
+                       button@21 {
+                               label = "GPIO Key UP";
+                               linux,code = <103>;
+                               gpios = <&gpio1 0 1>;
+                       };
+                       ...
+
diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c
index 6e6145b..2db7db2 100644
--- a/drivers/input/keyboard/gpio_keys.c
+++ b/drivers/input/keyboard/gpio_keys.c
@@ -3,6 +3,9 @@
 *
 * Copyright 2005 Phil Blundell
 *
+ * Added OF support:
+ * Copyright 2010, 2011 David Jander [off-list ref]
+ *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
@@ -25,6 +28,8 @@
 #include <linux/gpio_keys.h>
 #include <linux/workqueue.h>
 #include <linux/gpio.h>
+#include <linux/of_platform.h>
+#include <linux/of_gpio.h>

 struct gpio_button_data {
       struct gpio_keys_button *button;
@@ -445,15 +450,111 @@ static void gpio_keys_close(struct input_dev *input)
               ddata->disable(input->dev.parent);
 }

+/*
+ * Handlers for alternative sources of platform_data
+ */
+#ifdef CONFIG_OF
+/*
+ * Translate OpenFirmware node properties into platform_data
+ */
+static int gpio_keys_get_devtree_pdata(struct device *dev,
+                           struct gpio_keys_platform_data *pdata)
+{
+       struct device_node *node, *pp;
+       int i;
+       struct gpio_keys_button *buttons;
+       const u32 *reg;
+       int len;
+
+       node = dev->of_node;
+       if (node == NULL)
+               return -ENODEV;
+
+       memset(pdata, 0, sizeof *pdata);
+
+       pdata->rep = !!of_get_property(node, "autorepeat", &len);
+
+       /* First count the subnodes */
+       pdata->nbuttons = 0;
+       pp = NULL;
+       while ((pp = of_get_next_child(node, pp)))
+               pdata->nbuttons++;
+
+       if (pdata->nbuttons == 0)
+               return -ENODEV;
+
+       buttons = kzalloc(pdata->nbuttons * (sizeof *buttons), GFP_KERNEL);
+       if (!buttons)
+               return -ENODEV;
+
+       pp = NULL;
+       i = 0;
+       while ((pp = of_get_next_child(node, pp))) {
+               const char *lbl;
+               enum of_gpio_flags flags;
+
+               if (!of_find_property(pp, "gpios", NULL)) {
+                       pdata->nbuttons--;
+                       dev_warn(dev, "Found button without gpios\n");
+                       continue;
+               }
+               buttons[i].gpio = of_get_gpio_flags(pp, 0, &flags);
+               buttons[i].active_low = !!(flags & OF_GPIO_ACTIVE_LOW);
+
+               reg = of_get_property(pp, "linux,code", &len);
+               if (!reg) {
+                       dev_err(dev, "Button without keycode: 0x%x\n", buttons[i].gpio);
+                       goto out_fail;
+               }
+               buttons[i].code = be32_to_cpup(reg);
+
+               lbl = of_get_property(pp, "label", &len);
+               buttons[i].desc = (char *)lbl;
+
+               reg = of_get_property(pp, "linux,input-type", &len);
+               buttons[i].type = reg ? be32_to_cpup(reg) : EV_KEY;
+
+               buttons[i].wakeup = !!of_get_property(pp, "gpio-key,wakeup", NULL);
+
+               reg = of_get_property(pp, "debounce-interval", &len);
+               buttons[i].debounce_interval = reg ? be32_to_cpup(reg) : 5;
+
+               i++;
+       }
+
+       pdata->buttons = buttons;
+
+       return 0;
+
+out_fail:
+       kfree(buttons);
+       return -ENODEV;
+}
+#else
+static int gpio_keys_get_devtree_pdata(struct device *dev,
+                           struct gpio_keys_platform_data *altp)
+{
+       return -ENODEV;
+}
+#endif
+
 static int __devinit gpio_keys_probe(struct platform_device *pdev)
 {
       struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
       struct gpio_keys_drvdata *ddata;
       struct device *dev = &pdev->dev;
+       struct gpio_keys_platform_data alt_pdata;
       struct input_dev *input;
       int i, error;
       int wakeup = 0;

+       if (!pdata) {
+               error = gpio_keys_get_devtree_pdata(dev, &alt_pdata);
+               if (error)
+                       return error;
+               pdata = &alt_pdata;
+       }
+
       ddata = kzalloc(sizeof(struct gpio_keys_drvdata) +
                       pdata->nbuttons * sizeof(struct gpio_button_data),
                       GFP_KERNEL);
@@ -550,7 +651,6 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
 static int __devexit gpio_keys_remove(struct platform_device *pdev)
 {
-       struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
       struct gpio_keys_drvdata *ddata = platform_get_drvdata(pdev);
       struct input_dev *input = ddata->input;
       int i;
@@ -559,31 +659,42 @@ static int __devexit gpio_keys_remove(struct platform_device *pdev)
       device_init_wakeup(&pdev->dev, 0);

-       for (i = 0; i < pdata->nbuttons; i++) {
-               int irq = gpio_to_irq(pdata->buttons[i].gpio);
+       for (i = 0; i < ddata->n_buttons; i++) {
+               int irq = gpio_to_irq(ddata->data[i].button->gpio);
               free_irq(irq, &ddata->data[i]);
               if (ddata->data[i].timer_debounce)
                       del_timer_sync(&ddata->data[i].timer);
               cancel_work_sync(&ddata->data[i].work);
-               gpio_free(pdata->buttons[i].gpio);
+               gpio_free(ddata->data[i].button->gpio);
       }

+       /*
+        * If we had no platform_data, we allocated buttons dynamically, and
+        * must free them here. ddata->data[0].button is the pointer to the
+        * beginning of the allocated array.
+        */
+       if (!pdev->dev.platform_data)
+               kfree(ddata->data[0].button);
+
       input_unregister_device(input);

       return 0;
 }

+static struct of_device_id gpio_keys_of_match[] = {
+       { .compatible = "gpio-keys", },
+       {},
+};
This gpio_keys_of_match[]...
quoted hunk ↗ jump to hunk
@@ -622,6 +731,12 @@ static const struct dev_pm_ops gpio_keys_pm_ops = {
 };
 #endif

+#ifdef CONFIG_OF
+MODULE_DEVICE_TABLE(of, gpio_keys_of_match);
+#else
+#define gpio_keys_of_match NULL
+#endif
...belongs inside this #ifdef CONFIG_OF block.

In fact, there should only need to be one #ifdef CONFIG_OF/#else block
in this .c file.

g.
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help