It adds device tree probe support for gpio-keys driver.

One thing to note is that .enable/.disable hooks becomes unsupported
when the driver gets probed from device tree.  The reason why the
patch does not address that is primarily because there are only 2
out of over 120 boards using the hooks for the gpio-keys device.

board-4430sdp pulls up/down a gpio, while board-mop500 enables/disables
a regulator in that pair of hooks.  There is no common pattern at all,
so the patch leaves the hooks outside the device tree support.

Signed-off-by: Shawn Guo <[email protected]>
Cc: Grant Likely <[email protected]>
Cc: Phil Blundell <[email protected]>
Cc: Dmitry Torokhov <[email protected]>
---
 Documentation/devicetree/bindings/gpio/key.txt |   57 ++++++++++++++++
 drivers/input/keyboard/gpio_keys.c             |   83 +++++++++++++++++++++++-
 2 files changed, 139 insertions(+), 1 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/gpio/key.txt

diff --git a/Documentation/devicetree/bindings/gpio/key.txt 
b/Documentation/devicetree/bindings/gpio/key.txt
new file mode 100644
index 0000000..36296c1b
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpio/key.txt
@@ -0,0 +1,57 @@
+* Keys connected to GPIO lines
+
+Required properties:
+- compatible : Should be "gpio-keys"
+
+Optional properties:
+- keys-auto-repeat : Indicates the support of Auto-Repeat
+
+Each key is represented as a sub-node of the gpio-keys device.  Each
+node's name represents the name of the corresponding key.
+
+Key sub-node properties:
+
+Required properties:
+- gpios : Should specify the key's GPIO.  Active low key should be
+  indicated using flags in the GPIO specifier.
+- linux,key-code : Should specify the key code defined by linux in
+  include/linux/input.h
+
+Optional properties:
+- label : Contains the label for this key
+- key-debounce-internal : Specifies debounce interval in milliseconds
+- key-axis-value : Specifies axis value for an absolute change event
+- key-is-switch : Indicates the key is used as a switch event
+- key-is-active-low : Indicates the key is active low
+- key-can-wakeup-system : Indicates the key is a wake-up source
+- key-can-be-disabled : Indicates the key can be disabled
+
+Examples:
+
+gpio-keys {
+       compatible = "gpio-keys";
+
+       power {
+               label = "Power Button";
+               gpios = <&gpio0 8 0>;
+               linux,key-code = <116>; /* KEY_POWER */
+               key-is-active-low;
+               key-can-wakeup-system;
+       };
+
+       volume-up {
+               label = "Volume Up";
+               gpios = <&gpio1 14 0>;
+               linux,key-code = <115>; /* KEY_VOLUMEUP */
+               key-is-active-low;
+               key-can-wakeup-system;
+       };
+
+       volume-down {
+               label = "Volume Down";
+               gpios = <&gpio1 15 0>;
+               linux,key-code = <114>; /* KEY_VOLUMEDOWN */
+               key-is-active-low;
+               key-can-wakeup-system;
+       };
+};
diff --git a/drivers/input/keyboard/gpio_keys.c 
b/drivers/input/keyboard/gpio_keys.c
index 85b5685..2a79d40 100644
--- a/drivers/input/keyboard/gpio_keys.c
+++ b/drivers/input/keyboard/gpio_keys.c
@@ -25,6 +25,8 @@
 #include <linux/gpio_keys.h>
 #include <linux/workqueue.h>
 #include <linux/gpio.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
 
 struct gpio_button_data {
        struct gpio_keys_button button;
@@ -445,15 +447,93 @@ static void gpio_keys_close(struct input_dev *input)
                ddata->disable(input->dev.parent);
 }
 
+#ifdef CONFIG_OF_GPIO
+static const struct of_device_id gpio_keys_dt_ids[] = {
+       { .compatible = "gpio-keys", },
+       { /* sentinel */ }
+};
+
+static struct gpio_keys_platform_data * __devinit gpio_keys_probe_pdata_dt(
+                                               struct platform_device *pdev)
+{
+       struct device_node *np = pdev->dev.of_node, *child;
+       struct gpio_keys_platform_data *pdata;
+       struct gpio_keys_button *button;
+       int count = 0;
+
+       if (!np)
+               return ERR_PTR(-ENODEV);
+
+       /* count keys in this device, so we know how much to allocate */
+       for_each_child_of_node(np, child)
+               count++;
+       if (!count)
+               return ERR_PTR(-ENODEV);
+
+       pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata) +
+                            sizeof(*button) * count, GFP_KERNEL);
+       if (!pdata)
+               return ERR_PTR(-ENOMEM);
+
+       pdata->buttons = (struct gpio_keys_button *) (pdata + 1);
+       pdata->nbuttons = count;
+
+       if (of_get_property(np, "keys-auto-repeat", NULL))
+               pdata->rep = 1;
+
+       button = pdata->buttons;
+       for_each_child_of_node(np, child) {
+               enum of_gpio_flags flags;
+
+               button->gpio = of_get_gpio_flags(child, 0, &flags);
+               of_property_read_string(child, "label", &button->desc);
+               of_property_read_u32(child, "linux,key-code", &button->code);
+               of_property_read_u32(child, "key-debounce-internal",
+                                    &button->debounce_interval);
+               if (!of_property_read_u32(child, "key-axis-value",
+                                         &button->value))
+                       button->type = EV_ABS;
+               if (of_get_property(np, "key-is-switch", NULL))
+                       button->type = EV_SW;
+               if (of_get_property(np, "key-is-active-low", NULL))
+                       button->active_low = 1;
+               if (of_get_property(np, "key-can-wakeup-system", NULL))
+                       button->wakeup = 1;
+               if (of_get_property(np, "key-can-be-disabled", NULL))
+                       button->can_disable = 1;
+
+               button++;
+       }
+
+       return pdata;
+}
+#else /* CONFIG_OF_GPIO */
+#define of_gpio_keys_match NULL
+static inline struct gpio_keys_platform_data *gpio_keys_probe_pdata_dt(
+                                               struct platform_device *pdev)
+{
+       return ERR_PTR(-ENODEV);
+}
+#endif /* CONFIG_OF_GPIO */
+
 static int __devinit gpio_keys_probe(struct platform_device *pdev)
 {
-       struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
+       struct gpio_keys_platform_data *pdata;
        struct gpio_keys_drvdata *ddata;
        struct device *dev = &pdev->dev;
        struct input_dev *input;
        int i, error;
        int wakeup = 0;
 
+       pdata = gpio_keys_probe_pdata_dt(pdev);
+       if (IS_ERR(pdata))
+               pdata = pdev->dev.platform_data;
+
+       if (IS_ERR_OR_NULL(pdata)) {
+               dev_err(dev, "failed to get platform data\n");
+               return PTR_ERR(pdata);
+       }
+
        ddata = kzalloc(sizeof(struct gpio_keys_drvdata) +
                        pdata->nbuttons * sizeof(struct gpio_button_data),
                        GFP_KERNEL);
@@ -631,6 +711,7 @@ static struct platform_driver gpio_keys_device_driver = {
 #ifdef CONFIG_PM
                .pm     = &gpio_keys_pm_ops,
 #endif
+               .of_match_table = gpio_keys_dt_ids,
        }
 };
 
-- 
1.7.4.1

_______________________________________________
devicetree-discuss mailing list
[email protected]
https://lists.ozlabs.org/listinfo/devicetree-discuss

Reply via email to