All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH RESEND V2] input: gpio_keys_polled: convert to dt
@ 2012-07-09 18:31 ` Alexandre Pereira da Silva
  0 siblings, 0 replies; 4+ messages in thread
From: Alexandre Pereira da Silva @ 2012-07-09 18:31 UTC (permalink / raw)
  Cc: Alexandre Pereira da Silva, Grant Likely, Rob Herring,
	Rob Landley, Dmitry Torokhov, Tobias Klauser, David Jander,
	JJ Ding, devicetree-discuss, linux-doc, linux-kernel,
	linux-input

Signed-off-by: Alexandre Pereira da Silva <aletes.xgr@gmail.com>

---
Applies to v3.5-rc6

Changes since v1:
* Add biding documentation
* Fix sizeof in memset
* Cleanup dt properties extraction
* Use for_each macro
* Fix memleak on buttons

Thanks Rob Herring, Dmitry Torokhov and Roland Stiege for reviewing and 
improvements suggestions.

 .../devicetree/bindings/input/gpio-keys-polled.txt |   38 ++++++
 drivers/input/keyboard/gpio_keys_polled.c          |  131 ++++++++++++++++++--
 2 files changed, 158 insertions(+), 11 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/input/gpio-keys-polled.txt

diff --git a/Documentation/devicetree/bindings/input/gpio-keys-polled.txt b/Documentation/devicetree/bindings/input/gpio-keys-polled.txt
new file mode 100644
index 0000000..313abef
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/gpio-keys-polled.txt
@@ -0,0 +1,38 @@
+Device-Tree bindings for input/gpio_keys_polled.c keyboard driver
+
+Required properties:
+	- compatible = "gpio-keys-polled";
+	- poll-interval: Poll interval time in milliseconds
+
+Optional properties:
+	- autorepeat: Boolean, Enable auto repeat feature of Linux input
+	  subsystem.
+
+Each button (key) is represented as a sub-node of "gpio-keys-polled":
+Subnode properties:
+
+	- gpios: OF device-tree gpio specification.
+	- label: Descriptive name of the key.
+	- linux,code: Keycode to emit.
+
+Optional subnode-properties:
+	- linux,input-type: Specify event type this button/key generates.
+	  If not specified defaults to <1> == EV_KEY.
+	- debounce-interval: Debouncing interval time in milliseconds.
+	  If not specified defaults to 5.
+	- gpio-key,wakeup: Boolean, button can wake-up the system.
+
+Example nodes:
+
+	gpio_keys_polled {
+			compatible = "gpio-keys-polled";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			poll-interval = <100>;
+			autorepeat;
+			button@21 {
+				label = "GPIO Key UP";
+				linux,code = <103>;
+				gpios = <&gpio1 0 1>;
+			};
+			...
diff --git a/drivers/input/keyboard/gpio_keys_polled.c b/drivers/input/keyboard/gpio_keys_polled.c
index 20c8ab1..e5cb3ef 100644
--- a/drivers/input/keyboard/gpio_keys_polled.c
+++ b/drivers/input/keyboard/gpio_keys_polled.c
@@ -25,6 +25,8 @@
 #include <linux/platform_device.h>
 #include <linux/gpio.h>
 #include <linux/gpio_keys.h>
+#include <linux/of_platform.h>
+#include <linux/of_gpio.h>
 
 #define DRV_NAME	"gpio-keys-polled"
 
@@ -38,7 +40,7 @@ struct gpio_keys_button_data {
 struct gpio_keys_polled_dev {
 	struct input_polled_dev *poll_dev;
 	struct device *dev;
-	struct gpio_keys_platform_data *pdata;
+	struct gpio_keys_platform_data pdata;
 	struct gpio_keys_button_data data[0];
 };
 
@@ -67,11 +69,11 @@ static void gpio_keys_polled_check_state(struct input_dev *input,
 static void gpio_keys_polled_poll(struct input_polled_dev *dev)
 {
 	struct gpio_keys_polled_dev *bdev = dev->private;
-	struct gpio_keys_platform_data *pdata = bdev->pdata;
+	struct gpio_keys_platform_data *pdata = &bdev->pdata;
 	struct input_dev *input = dev->input;
 	int i;
 
-	for (i = 0; i < bdev->pdata->nbuttons; i++) {
+	for (i = 0; i < pdata->nbuttons; i++) {
 		struct gpio_keys_button_data *bdata = &bdev->data[i];
 
 		if (bdata->count < bdata->threshold)
@@ -85,7 +87,7 @@ static void gpio_keys_polled_poll(struct input_polled_dev *dev)
 static void gpio_keys_polled_open(struct input_polled_dev *dev)
 {
 	struct gpio_keys_polled_dev *bdev = dev->private;
-	struct gpio_keys_platform_data *pdata = bdev->pdata;
+	struct gpio_keys_platform_data *pdata = &bdev->pdata;
 
 	if (pdata->enable)
 		pdata->enable(bdev->dev);
@@ -94,31 +96,125 @@ static void gpio_keys_polled_open(struct input_polled_dev *dev)
 static void gpio_keys_polled_close(struct input_polled_dev *dev)
 {
 	struct gpio_keys_polled_dev *bdev = dev->private;
-	struct gpio_keys_platform_data *pdata = bdev->pdata;
+	struct gpio_keys_platform_data *pdata = &bdev->pdata;
 
 	if (pdata->disable)
 		pdata->disable(bdev->dev);
 }
+#ifdef CONFIG_OF
+static int gpio_keys_polled_get_devtree_pdata(struct device *dev,
+			    struct gpio_keys_platform_data *pdata)
+{
+	struct device_node *node, *pp;
+	int i;
+	struct gpio_keys_button *buttons;
+
+	node = dev->of_node;
+	if (node == NULL)
+		return -ENODEV;
+
+	memset(pdata, 0, sizeof(*pdata));
+
+	pdata->rep = !!of_get_property(node, "autorepeat", NULL);
+
+	of_property_read_u32(node, "poll-interval", &pdata->poll_interval);
+
+	pdata->nbuttons = of_get_child_count(node);
+	if (pdata->nbuttons == 0)
+		return -ENODEV;
+
+	buttons = kzalloc(pdata->nbuttons * (sizeof *buttons), GFP_KERNEL);
+	if (!buttons)
+		return -ENOMEM;
+
+	i = 0;
+	for_each_child_of_node(node, pp) {
+		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;
+
+		if (of_property_read_u32(pp, "linux,code", &buttons[i].code)) {
+			dev_err(dev, "Button without keycode: 0x%x\n",
+				buttons[i].gpio);
+			goto out_fail;
+		}
+
+		buttons[i].desc = of_get_property(pp, "label", NULL);
+
+		if (of_property_read_u32(pp, "linux,input-type",
+			&buttons[i].type))
+			buttons[i].type = EV_KEY;
+
+		buttons[i].wakeup = !!of_get_property(pp, "gpio-key,wakeup",
+			NULL);
+
+		if (of_property_read_u32(pp, "debounce-interval",
+			&buttons[i].debounce_interval))
+			buttons[i].debounce_interval = 5;
+
+		i++;
+	}
+
+	pdata->buttons = buttons;
+
+	return 0;
+
+out_fail:
+	kfree(buttons);
+	return -ENODEV;
+}
+
+static struct of_device_id gpio_keys_polled_of_match[] = {
+	{ .compatible = "gpio-keys-polled", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, gpio_keys_polled_of_match);
+
+#else
+
+static int gpio_keys_polled_get_devtree_pdata(struct device *dev,
+			    struct gpio_keys_platform_data *altp)
+{
+	return -ENODEV;
+}
+#endif
 
 static int __devinit gpio_keys_polled_probe(struct platform_device *pdev)
 {
 	struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
 	struct device *dev = &pdev->dev;
+	struct gpio_keys_platform_data alt_pdata;
 	struct gpio_keys_polled_dev *bdev;
 	struct input_polled_dev *poll_dev;
 	struct input_dev *input;
 	int error;
 	int i;
 
-	if (!pdata || !pdata->poll_interval)
-		return -EINVAL;
+	if (!pdata) {
+		error = gpio_keys_polled_get_devtree_pdata(dev, &alt_pdata);
+		if (error)
+			return error;
+		pdata = &alt_pdata;
+	}
+
+	if (!pdata->poll_interval) {
+		error = -EINVAL;
+		goto err_free_buttons;
+	}
 
 	bdev = kzalloc(sizeof(struct gpio_keys_polled_dev) +
 		       pdata->nbuttons * sizeof(struct gpio_keys_button_data),
 		       GFP_KERNEL);
 	if (!bdev) {
 		dev_err(dev, "no memory for private data\n");
-		return -ENOMEM;
+		error = -ENOMEM;
+		goto err_free_buttons;
 	}
 
 	poll_dev = input_allocate_polled_device();
@@ -184,7 +280,7 @@ static int __devinit gpio_keys_polled_probe(struct platform_device *pdev)
 
 	bdev->poll_dev = poll_dev;
 	bdev->dev = dev;
-	bdev->pdata = pdata;
+	bdev->pdata = *pdata;
 	platform_set_drvdata(pdev, bdev);
 
 	error = input_register_polled_device(poll_dev);
@@ -209,15 +305,19 @@ err_free_gpio:
 
 err_free_bdev:
 	kfree(bdev);
-
 	platform_set_drvdata(pdev, NULL);
+
+err_free_buttons:
+	/* If we have no platform_data, we allocated buttons dynamically. */
+	if (!pdev->dev.platform_data)
+		kfree(pdata->buttons);
 	return error;
 }
 
 static int __devexit gpio_keys_polled_remove(struct platform_device *pdev)
 {
 	struct gpio_keys_polled_dev *bdev = platform_get_drvdata(pdev);
-	struct gpio_keys_platform_data *pdata = bdev->pdata;
+	struct gpio_keys_platform_data *pdata = &bdev->pdata;
 	int i;
 
 	input_unregister_polled_device(bdev->poll_dev);
@@ -227,6 +327,14 @@ static int __devexit gpio_keys_polled_remove(struct platform_device *pdev)
 
 	input_free_polled_device(bdev->poll_dev);
 
+	/*
+	 * If we had no platform_data, we allocated buttons dynamically, and
+	 * must free them here. pdata->buttons is the pointer to the
+	 * beginning of the allocated array.
+	 */
+	if (!pdev->dev.platform_data)
+		kfree(pdata->buttons);
+
 	kfree(bdev);
 	platform_set_drvdata(pdev, NULL);
 
@@ -239,6 +347,7 @@ static struct platform_driver gpio_keys_polled_driver = {
 	.driver	= {
 		.name	= DRV_NAME,
 		.owner	= THIS_MODULE,
+		.of_match_table = of_match_ptr(gpio_keys_polled_of_match),
 	},
 };
 module_platform_driver(gpio_keys_polled_driver);
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH RESEND V2] input: gpio_keys_polled: convert to dt
@ 2012-07-09 18:31 ` Alexandre Pereira da Silva
  0 siblings, 0 replies; 4+ messages in thread
From: Alexandre Pereira da Silva @ 2012-07-09 18:31 UTC (permalink / raw)
  Cc: Alexandre Pereira da Silva, Grant Likely, Rob Herring,
	Rob Landley, Dmitry Torokhov, Tobias Klauser, David Jander,
	JJ Ding, devicetree-discuss, linux-doc, linux-kernel,
	linux-input

Signed-off-by: Alexandre Pereira da Silva <aletes.xgr@gmail.com>

---
Applies to v3.5-rc6

Changes since v1:
* Add biding documentation
* Fix sizeof in memset
* Cleanup dt properties extraction
* Use for_each macro
* Fix memleak on buttons

Thanks Rob Herring, Dmitry Torokhov and Roland Stiege for reviewing and 
improvements suggestions.

 .../devicetree/bindings/input/gpio-keys-polled.txt |   38 ++++++
 drivers/input/keyboard/gpio_keys_polled.c          |  131 ++++++++++++++++++--
 2 files changed, 158 insertions(+), 11 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/input/gpio-keys-polled.txt

diff --git a/Documentation/devicetree/bindings/input/gpio-keys-polled.txt b/Documentation/devicetree/bindings/input/gpio-keys-polled.txt
new file mode 100644
index 0000000..313abef
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/gpio-keys-polled.txt
@@ -0,0 +1,38 @@
+Device-Tree bindings for input/gpio_keys_polled.c keyboard driver
+
+Required properties:
+	- compatible = "gpio-keys-polled";
+	- poll-interval: Poll interval time in milliseconds
+
+Optional properties:
+	- autorepeat: Boolean, Enable auto repeat feature of Linux input
+	  subsystem.
+
+Each button (key) is represented as a sub-node of "gpio-keys-polled":
+Subnode properties:
+
+	- gpios: OF device-tree gpio specification.
+	- label: Descriptive name of the key.
+	- linux,code: Keycode to emit.
+
+Optional subnode-properties:
+	- linux,input-type: Specify event type this button/key generates.
+	  If not specified defaults to <1> == EV_KEY.
+	- debounce-interval: Debouncing interval time in milliseconds.
+	  If not specified defaults to 5.
+	- gpio-key,wakeup: Boolean, button can wake-up the system.
+
+Example nodes:
+
+	gpio_keys_polled {
+			compatible = "gpio-keys-polled";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			poll-interval = <100>;
+			autorepeat;
+			button@21 {
+				label = "GPIO Key UP";
+				linux,code = <103>;
+				gpios = <&gpio1 0 1>;
+			};
+			...
diff --git a/drivers/input/keyboard/gpio_keys_polled.c b/drivers/input/keyboard/gpio_keys_polled.c
index 20c8ab1..e5cb3ef 100644
--- a/drivers/input/keyboard/gpio_keys_polled.c
+++ b/drivers/input/keyboard/gpio_keys_polled.c
@@ -25,6 +25,8 @@
 #include <linux/platform_device.h>
 #include <linux/gpio.h>
 #include <linux/gpio_keys.h>
+#include <linux/of_platform.h>
+#include <linux/of_gpio.h>
 
 #define DRV_NAME	"gpio-keys-polled"
 
@@ -38,7 +40,7 @@ struct gpio_keys_button_data {
 struct gpio_keys_polled_dev {
 	struct input_polled_dev *poll_dev;
 	struct device *dev;
-	struct gpio_keys_platform_data *pdata;
+	struct gpio_keys_platform_data pdata;
 	struct gpio_keys_button_data data[0];
 };
 
@@ -67,11 +69,11 @@ static void gpio_keys_polled_check_state(struct input_dev *input,
 static void gpio_keys_polled_poll(struct input_polled_dev *dev)
 {
 	struct gpio_keys_polled_dev *bdev = dev->private;
-	struct gpio_keys_platform_data *pdata = bdev->pdata;
+	struct gpio_keys_platform_data *pdata = &bdev->pdata;
 	struct input_dev *input = dev->input;
 	int i;
 
-	for (i = 0; i < bdev->pdata->nbuttons; i++) {
+	for (i = 0; i < pdata->nbuttons; i++) {
 		struct gpio_keys_button_data *bdata = &bdev->data[i];
 
 		if (bdata->count < bdata->threshold)
@@ -85,7 +87,7 @@ static void gpio_keys_polled_poll(struct input_polled_dev *dev)
 static void gpio_keys_polled_open(struct input_polled_dev *dev)
 {
 	struct gpio_keys_polled_dev *bdev = dev->private;
-	struct gpio_keys_platform_data *pdata = bdev->pdata;
+	struct gpio_keys_platform_data *pdata = &bdev->pdata;
 
 	if (pdata->enable)
 		pdata->enable(bdev->dev);
@@ -94,31 +96,125 @@ static void gpio_keys_polled_open(struct input_polled_dev *dev)
 static void gpio_keys_polled_close(struct input_polled_dev *dev)
 {
 	struct gpio_keys_polled_dev *bdev = dev->private;
-	struct gpio_keys_platform_data *pdata = bdev->pdata;
+	struct gpio_keys_platform_data *pdata = &bdev->pdata;
 
 	if (pdata->disable)
 		pdata->disable(bdev->dev);
 }
+#ifdef CONFIG_OF
+static int gpio_keys_polled_get_devtree_pdata(struct device *dev,
+			    struct gpio_keys_platform_data *pdata)
+{
+	struct device_node *node, *pp;
+	int i;
+	struct gpio_keys_button *buttons;
+
+	node = dev->of_node;
+	if (node == NULL)
+		return -ENODEV;
+
+	memset(pdata, 0, sizeof(*pdata));
+
+	pdata->rep = !!of_get_property(node, "autorepeat", NULL);
+
+	of_property_read_u32(node, "poll-interval", &pdata->poll_interval);
+
+	pdata->nbuttons = of_get_child_count(node);
+	if (pdata->nbuttons == 0)
+		return -ENODEV;
+
+	buttons = kzalloc(pdata->nbuttons * (sizeof *buttons), GFP_KERNEL);
+	if (!buttons)
+		return -ENOMEM;
+
+	i = 0;
+	for_each_child_of_node(node, pp) {
+		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;
+
+		if (of_property_read_u32(pp, "linux,code", &buttons[i].code)) {
+			dev_err(dev, "Button without keycode: 0x%x\n",
+				buttons[i].gpio);
+			goto out_fail;
+		}
+
+		buttons[i].desc = of_get_property(pp, "label", NULL);
+
+		if (of_property_read_u32(pp, "linux,input-type",
+			&buttons[i].type))
+			buttons[i].type = EV_KEY;
+
+		buttons[i].wakeup = !!of_get_property(pp, "gpio-key,wakeup",
+			NULL);
+
+		if (of_property_read_u32(pp, "debounce-interval",
+			&buttons[i].debounce_interval))
+			buttons[i].debounce_interval = 5;
+
+		i++;
+	}
+
+	pdata->buttons = buttons;
+
+	return 0;
+
+out_fail:
+	kfree(buttons);
+	return -ENODEV;
+}
+
+static struct of_device_id gpio_keys_polled_of_match[] = {
+	{ .compatible = "gpio-keys-polled", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, gpio_keys_polled_of_match);
+
+#else
+
+static int gpio_keys_polled_get_devtree_pdata(struct device *dev,
+			    struct gpio_keys_platform_data *altp)
+{
+	return -ENODEV;
+}
+#endif
 
 static int __devinit gpio_keys_polled_probe(struct platform_device *pdev)
 {
 	struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
 	struct device *dev = &pdev->dev;
+	struct gpio_keys_platform_data alt_pdata;
 	struct gpio_keys_polled_dev *bdev;
 	struct input_polled_dev *poll_dev;
 	struct input_dev *input;
 	int error;
 	int i;
 
-	if (!pdata || !pdata->poll_interval)
-		return -EINVAL;
+	if (!pdata) {
+		error = gpio_keys_polled_get_devtree_pdata(dev, &alt_pdata);
+		if (error)
+			return error;
+		pdata = &alt_pdata;
+	}
+
+	if (!pdata->poll_interval) {
+		error = -EINVAL;
+		goto err_free_buttons;
+	}
 
 	bdev = kzalloc(sizeof(struct gpio_keys_polled_dev) +
 		       pdata->nbuttons * sizeof(struct gpio_keys_button_data),
 		       GFP_KERNEL);
 	if (!bdev) {
 		dev_err(dev, "no memory for private data\n");
-		return -ENOMEM;
+		error = -ENOMEM;
+		goto err_free_buttons;
 	}
 
 	poll_dev = input_allocate_polled_device();
@@ -184,7 +280,7 @@ static int __devinit gpio_keys_polled_probe(struct platform_device *pdev)
 
 	bdev->poll_dev = poll_dev;
 	bdev->dev = dev;
-	bdev->pdata = pdata;
+	bdev->pdata = *pdata;
 	platform_set_drvdata(pdev, bdev);
 
 	error = input_register_polled_device(poll_dev);
@@ -209,15 +305,19 @@ err_free_gpio:
 
 err_free_bdev:
 	kfree(bdev);
-
 	platform_set_drvdata(pdev, NULL);
+
+err_free_buttons:
+	/* If we have no platform_data, we allocated buttons dynamically. */
+	if (!pdev->dev.platform_data)
+		kfree(pdata->buttons);
 	return error;
 }
 
 static int __devexit gpio_keys_polled_remove(struct platform_device *pdev)
 {
 	struct gpio_keys_polled_dev *bdev = platform_get_drvdata(pdev);
-	struct gpio_keys_platform_data *pdata = bdev->pdata;
+	struct gpio_keys_platform_data *pdata = &bdev->pdata;
 	int i;
 
 	input_unregister_polled_device(bdev->poll_dev);
@@ -227,6 +327,14 @@ static int __devexit gpio_keys_polled_remove(struct platform_device *pdev)
 
 	input_free_polled_device(bdev->poll_dev);
 
+	/*
+	 * If we had no platform_data, we allocated buttons dynamically, and
+	 * must free them here. pdata->buttons is the pointer to the
+	 * beginning of the allocated array.
+	 */
+	if (!pdev->dev.platform_data)
+		kfree(pdata->buttons);
+
 	kfree(bdev);
 	platform_set_drvdata(pdev, NULL);
 
@@ -239,6 +347,7 @@ static struct platform_driver gpio_keys_polled_driver = {
 	.driver	= {
 		.name	= DRV_NAME,
 		.owner	= THIS_MODULE,
+		.of_match_table = of_match_ptr(gpio_keys_polled_of_match),
 	},
 };
 module_platform_driver(gpio_keys_polled_driver);
-- 
1.7.10


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH RESEND V2] input: gpio_keys_polled: convert to dt
  2012-07-09 18:31 ` Alexandre Pereira da Silva
  (?)
@ 2012-07-19  7:27 ` Dmitry Torokhov
  2012-07-19 14:50   ` Alexandre Pereira da Silva
  -1 siblings, 1 reply; 4+ messages in thread
From: Dmitry Torokhov @ 2012-07-19  7:27 UTC (permalink / raw)
  To: Alexandre Pereira da Silva
  Cc: Grant Likely, Rob Herring, Rob Landley, Tobias Klauser,
	David Jander, JJ Ding, devicetree-discuss, linux-doc,
	linux-kernel, linux-input

Hi Alexandre,

On Mon, Jul 09, 2012 at 03:31:43PM -0300, Alexandre Pereira da Silva wrote:
> @@ -38,7 +40,7 @@ struct gpio_keys_button_data {
>  struct gpio_keys_polled_dev {
>  	struct input_polled_dev *poll_dev;
>  	struct device *dev;
> -	struct gpio_keys_platform_data *pdata;
> +	struct gpio_keys_platform_data pdata;
>  	struct gpio_keys_button_data data[0];
>  };

Instead of using a copy of pdata how about the patch below?

Thanks.

-- 
Dmitry


Input: gpio_keys_polled - convert to dt

From: Alexandre Pereira da Silva <aletes.xgr@gmail.com>

Signed-off-by: Alexandre Pereira da Silva <aletes.xgr@gmail.com>
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
---

 .../devicetree/bindings/input/gpio-keys-polled.txt |   38 ++++++
 drivers/input/keyboard/gpio_keys_polled.c          |  124 +++++++++++++++++++-
 2 files changed, 157 insertions(+), 5 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/input/gpio-keys-polled.txt


diff --git a/Documentation/devicetree/bindings/input/gpio-keys-polled.txt b/Documentation/devicetree/bindings/input/gpio-keys-polled.txt
new file mode 100644
index 0000000..313abef
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/gpio-keys-polled.txt
@@ -0,0 +1,38 @@
+Device-Tree bindings for input/gpio_keys_polled.c keyboard driver
+
+Required properties:
+	- compatible = "gpio-keys-polled";
+	- poll-interval: Poll interval time in milliseconds
+
+Optional properties:
+	- autorepeat: Boolean, Enable auto repeat feature of Linux input
+	  subsystem.
+
+Each button (key) is represented as a sub-node of "gpio-keys-polled":
+Subnode properties:
+
+	- gpios: OF device-tree gpio specification.
+	- label: Descriptive name of the key.
+	- linux,code: Keycode to emit.
+
+Optional subnode-properties:
+	- linux,input-type: Specify event type this button/key generates.
+	  If not specified defaults to <1> == EV_KEY.
+	- debounce-interval: Debouncing interval time in milliseconds.
+	  If not specified defaults to 5.
+	- gpio-key,wakeup: Boolean, button can wake-up the system.
+
+Example nodes:
+
+	gpio_keys_polled {
+			compatible = "gpio-keys-polled";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			poll-interval = <100>;
+			autorepeat;
+			button@21 {
+				label = "GPIO Key UP";
+				linux,code = <103>;
+				gpios = <&gpio1 0 1>;
+			};
+			...
diff --git a/drivers/input/keyboard/gpio_keys_polled.c b/drivers/input/keyboard/gpio_keys_polled.c
index 2619297..5a8856e6 100644
--- a/drivers/input/keyboard/gpio_keys_polled.c
+++ b/drivers/input/keyboard/gpio_keys_polled.c
@@ -25,6 +25,8 @@
 #include <linux/platform_device.h>
 #include <linux/gpio.h>
 #include <linux/gpio_keys.h>
+#include <linux/of_platform.h>
+#include <linux/of_gpio.h>
 
 #define DRV_NAME	"gpio-keys-polled"
 
@@ -100,6 +102,96 @@ static void gpio_keys_polled_close(struct input_polled_dev *dev)
 		pdata->disable(bdev->dev);
 }
 
+#ifdef CONFIG_OF
+static struct gpio_keys_platform_data * __devinit
+gpio_keys_polled_get_devtree_pdata(struct device *dev)
+{
+	struct device_node *node, *pp;
+	struct gpio_keys_platform_data *pdata;
+	struct gpio_keys_button *button;
+	int error;
+	int nbuttons;
+	int i;
+
+	node = dev->of_node;
+	if (!node) {
+		error = -ENODEV;
+		goto err_out;
+	}
+
+	nbuttons = of_get_child_count(node);
+	if (nbuttons == 0) {
+		error = -ENODEV;
+		goto err_out;
+	}
+
+	pdata = kzalloc(sizeof(*pdata) + nbuttons * (sizeof *button),
+			GFP_KERNEL);
+	if (!pdata) {
+		error = -ENOMEM;
+		goto err_out;
+	}
+
+	pdata->rep = !!of_get_property(node, "autorepeat", NULL);
+	of_property_read_u32(node, "poll-interval", &pdata->poll_interval);
+
+	i = 0;
+	for_each_child_of_node(node, pp) {
+		enum of_gpio_flags flags;
+
+		if (!of_find_property(pp, "gpios", NULL)) {
+			pdata->nbuttons--;
+			dev_warn(dev, "Found button without gpios\n");
+			continue;
+		}
+
+		button = &pdata->buttons[i++];
+
+		button->gpio = of_get_gpio_flags(pp, 0, &flags);
+		button->active_low = flags & OF_GPIO_ACTIVE_LOW;
+
+		if (of_property_read_u32(pp, "linux,code", &button->code)) {
+			dev_err(dev, "Button without keycode: 0x%x\n",
+				button->gpio);
+			error = -EINVAL;
+			goto err_free_pdata;
+		}
+
+		button->desc = of_get_property(pp, "label", NULL);
+
+		if (of_property_read_u32(pp, "linux,input-type", &button->type))
+			button->type = EV_KEY;
+
+		button->wakeup = !!of_get_property(pp, "gpio-key,wakeup", NULL);
+
+		if (of_property_read_u32(pp, "debounce-interval",
+					 &button->debounce_interval))
+			button->debounce_interval = 5;
+	}
+
+	return pdata;
+
+err_free_pdata:
+	kfree(pdata);
+err_out:
+	return ERR_PTR(error);
+}
+
+static struct of_device_id gpio_keys_polled_of_match[] = {
+	{ .compatible = "gpio-keys-polled", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, gpio_keys_polled_of_match);
+
+#else
+
+static inline struct gpio_keys_platform_data *
+gpio_keys_polled_get_devtree_pdata(struct device *dev)
+{
+	return ERR_PTR(-ENODEV);
+}
+#endif
+
 static int __devinit gpio_keys_polled_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
@@ -110,15 +202,24 @@ static int __devinit gpio_keys_polled_probe(struct platform_device *pdev)
 	int error;
 	int i;
 
-	if (!pdata || !pdata->poll_interval)
-		return -EINVAL;
+	if (!pdata) {
+		pdata = gpio_keys_polled_get_devtree_pdata(dev);
+		if (IS_ERR(pdata))
+			return PTR_ERR(pdata);
+	}
+
+	if (!pdata->poll_interval) {
+		error = -EINVAL;
+		goto err_free_pdata;
+	}
 
 	bdev = kzalloc(sizeof(struct gpio_keys_polled_dev) +
 		       pdata->nbuttons * sizeof(struct gpio_keys_button_data),
 		       GFP_KERNEL);
 	if (!bdev) {
 		dev_err(dev, "no memory for private data\n");
-		return -ENOMEM;
+		error = -ENOMEM;
+		goto err_free_pdata;
 	}
 
 	poll_dev = input_allocate_polled_device();
@@ -197,7 +298,7 @@ static int __devinit gpio_keys_polled_probe(struct platform_device *pdev)
 	/* report initial state of the buttons */
 	for (i = 0; i < pdata->nbuttons; i++)
 		gpio_keys_polled_check_state(input, &pdata->buttons[i],
-					 &bdev->data[i]);
+					     &bdev->data[i]);
 
 	return 0;
 
@@ -209,8 +310,13 @@ err_free_gpio:
 
 err_free_bdev:
 	kfree(bdev);
-
 	platform_set_drvdata(pdev, NULL);
+
+err_free_pdata:
+	/* If we have no platform_data, we allocated pdata dynamically.  */
+	if (!dev_get_platdata(&pdev->dev))
+		kfree(pdata);
+
 	return error;
 }
 
@@ -227,6 +333,13 @@ static int __devexit gpio_keys_polled_remove(struct platform_device *pdev)
 
 	input_free_polled_device(bdev->poll_dev);
 
+	/*
+	 * If we had no platform_data, we allocated pdata dynamically and
+	 * must free it here.
+	 */
+	if (!dev_get_platdata(&pdev->dev))
+		kfree(pdata);
+
 	kfree(bdev);
 	platform_set_drvdata(pdev, NULL);
 
@@ -239,6 +352,7 @@ static struct platform_driver gpio_keys_polled_driver = {
 	.driver	= {
 		.name	= DRV_NAME,
 		.owner	= THIS_MODULE,
+		.of_match_table = of_match_ptr(gpio_keys_polled_of_match),
 	},
 };
 module_platform_driver(gpio_keys_polled_driver);

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH RESEND V2] input: gpio_keys_polled: convert to dt
  2012-07-19  7:27 ` Dmitry Torokhov
@ 2012-07-19 14:50   ` Alexandre Pereira da Silva
  0 siblings, 0 replies; 4+ messages in thread
From: Alexandre Pereira da Silva @ 2012-07-19 14:50 UTC (permalink / raw)
  To: Dmitry Torokhov
  Cc: Grant Likely, Rob Herring, Rob Landley, Tobias Klauser,
	David Jander, JJ Ding, devicetree-discuss, linux-doc,
	linux-kernel, linux-input

Hi, Dmitry

On Thu, Jul 19, 2012 at 4:27 AM, Dmitry Torokhov
<dmitry.torokhov@gmail.com> wrote:
> Hi Alexandre,
>
> On Mon, Jul 09, 2012 at 03:31:43PM -0300, Alexandre Pereira da Silva wrote:
>> @@ -38,7 +40,7 @@ struct gpio_keys_button_data {
>>  struct gpio_keys_polled_dev {
>>       struct input_polled_dev *poll_dev;
>>       struct device *dev;
>> -     struct gpio_keys_platform_data *pdata;
>> +     struct gpio_keys_platform_data pdata;
>>       struct gpio_keys_button_data data[0];
>>  };
>
> Instead of using a copy of pdata how about the patch below?

This solution looks fine to me.

> Thanks.
>
> --
> Dmitry
>
>
> Input: gpio_keys_polled - convert to dt
>
> From: Alexandre Pereira da Silva <aletes.xgr@gmail.com>
>
> Signed-off-by: Alexandre Pereira da Silva <aletes.xgr@gmail.com>
> Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
> ---
>
>  .../devicetree/bindings/input/gpio-keys-polled.txt |   38 ++++++
>  drivers/input/keyboard/gpio_keys_polled.c          |  124 +++++++++++++++++++-
>  2 files changed, 157 insertions(+), 5 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/input/gpio-keys-polled.txt
>
>
> diff --git a/Documentation/devicetree/bindings/input/gpio-keys-polled.txt b/Documentation/devicetree/bindings/input/gpio-keys-polled.txt
> new file mode 100644
> index 0000000..313abef
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/input/gpio-keys-polled.txt
> @@ -0,0 +1,38 @@
> +Device-Tree bindings for input/gpio_keys_polled.c keyboard driver
> +
> +Required properties:
> +       - compatible = "gpio-keys-polled";
> +       - poll-interval: Poll interval time in milliseconds
> +
> +Optional properties:
> +       - autorepeat: Boolean, Enable auto repeat feature of Linux input
> +         subsystem.
> +
> +Each button (key) is represented as a sub-node of "gpio-keys-polled":
> +Subnode properties:
> +
> +       - gpios: OF device-tree gpio specification.
> +       - label: Descriptive name of the key.
> +       - linux,code: Keycode to emit.
> +
> +Optional subnode-properties:
> +       - linux,input-type: Specify event type this button/key generates.
> +         If not specified defaults to <1> == EV_KEY.
> +       - debounce-interval: Debouncing interval time in milliseconds.
> +         If not specified defaults to 5.
> +       - gpio-key,wakeup: Boolean, button can wake-up the system.
> +
> +Example nodes:
> +
> +       gpio_keys_polled {
> +                       compatible = "gpio-keys-polled";
> +                       #address-cells = <1>;
> +                       #size-cells = <0>;
> +                       poll-interval = <100>;
> +                       autorepeat;
> +                       button@21 {
> +                               label = "GPIO Key UP";
> +                               linux,code = <103>;
> +                               gpios = <&gpio1 0 1>;
> +                       };
> +                       ...
> diff --git a/drivers/input/keyboard/gpio_keys_polled.c b/drivers/input/keyboard/gpio_keys_polled.c
> index 2619297..5a8856e6 100644
> --- a/drivers/input/keyboard/gpio_keys_polled.c
> +++ b/drivers/input/keyboard/gpio_keys_polled.c
> @@ -25,6 +25,8 @@
>  #include <linux/platform_device.h>
>  #include <linux/gpio.h>
>  #include <linux/gpio_keys.h>
> +#include <linux/of_platform.h>
> +#include <linux/of_gpio.h>
>
>  #define DRV_NAME       "gpio-keys-polled"
>
> @@ -100,6 +102,96 @@ static void gpio_keys_polled_close(struct input_polled_dev *dev)
>                 pdata->disable(bdev->dev);
>  }
>
> +#ifdef CONFIG_OF
> +static struct gpio_keys_platform_data * __devinit
> +gpio_keys_polled_get_devtree_pdata(struct device *dev)
> +{
> +       struct device_node *node, *pp;
> +       struct gpio_keys_platform_data *pdata;
> +       struct gpio_keys_button *button;
> +       int error;
> +       int nbuttons;
> +       int i;
> +
> +       node = dev->of_node;
> +       if (!node) {
> +               error = -ENODEV;
> +               goto err_out;
> +       }
> +
> +       nbuttons = of_get_child_count(node);
> +       if (nbuttons == 0) {
> +               error = -ENODEV;
> +               goto err_out;
> +       }
> +
> +       pdata = kzalloc(sizeof(*pdata) + nbuttons * (sizeof *button),
> +                       GFP_KERNEL);
> +       if (!pdata) {
> +               error = -ENOMEM;
> +               goto err_out;
> +       }
> +
> +       pdata->rep = !!of_get_property(node, "autorepeat", NULL);
> +       of_property_read_u32(node, "poll-interval", &pdata->poll_interval);
> +
> +       i = 0;
> +       for_each_child_of_node(node, pp) {
> +               enum of_gpio_flags flags;
> +
> +               if (!of_find_property(pp, "gpios", NULL)) {
> +                       pdata->nbuttons--;
> +                       dev_warn(dev, "Found button without gpios\n");
> +                       continue;
> +               }
> +
> +               button = &pdata->buttons[i++];
> +
> +               button->gpio = of_get_gpio_flags(pp, 0, &flags);
> +               button->active_low = flags & OF_GPIO_ACTIVE_LOW;
> +
> +               if (of_property_read_u32(pp, "linux,code", &button->code)) {
> +                       dev_err(dev, "Button without keycode: 0x%x\n",
> +                               button->gpio);
> +                       error = -EINVAL;
> +                       goto err_free_pdata;
> +               }
> +
> +               button->desc = of_get_property(pp, "label", NULL);
> +
> +               if (of_property_read_u32(pp, "linux,input-type", &button->type))
> +                       button->type = EV_KEY;
> +
> +               button->wakeup = !!of_get_property(pp, "gpio-key,wakeup", NULL);
> +
> +               if (of_property_read_u32(pp, "debounce-interval",
> +                                        &button->debounce_interval))
> +                       button->debounce_interval = 5;
> +       }
> +
> +       return pdata;
> +
> +err_free_pdata:
> +       kfree(pdata);
> +err_out:
> +       return ERR_PTR(error);
> +}
> +
> +static struct of_device_id gpio_keys_polled_of_match[] = {
> +       { .compatible = "gpio-keys-polled", },
> +       { },
> +};
> +MODULE_DEVICE_TABLE(of, gpio_keys_polled_of_match);
> +
> +#else
> +
> +static inline struct gpio_keys_platform_data *
> +gpio_keys_polled_get_devtree_pdata(struct device *dev)
> +{
> +       return ERR_PTR(-ENODEV);
> +}
> +#endif
> +
>  static int __devinit gpio_keys_polled_probe(struct platform_device *pdev)
>  {
>         struct device *dev = &pdev->dev;
> @@ -110,15 +202,24 @@ static int __devinit gpio_keys_polled_probe(struct platform_device *pdev)
>         int error;
>         int i;
>
> -       if (!pdata || !pdata->poll_interval)
> -               return -EINVAL;
> +       if (!pdata) {
> +               pdata = gpio_keys_polled_get_devtree_pdata(dev);
> +               if (IS_ERR(pdata))
> +                       return PTR_ERR(pdata);
> +       }
> +
> +       if (!pdata->poll_interval) {
> +               error = -EINVAL;
> +               goto err_free_pdata;
> +       }
>
>         bdev = kzalloc(sizeof(struct gpio_keys_polled_dev) +
>                        pdata->nbuttons * sizeof(struct gpio_keys_button_data),
>                        GFP_KERNEL);
>         if (!bdev) {
>                 dev_err(dev, "no memory for private data\n");
> -               return -ENOMEM;
> +               error = -ENOMEM;
> +               goto err_free_pdata;
>         }
>
>         poll_dev = input_allocate_polled_device();
> @@ -197,7 +298,7 @@ static int __devinit gpio_keys_polled_probe(struct platform_device *pdev)
>         /* report initial state of the buttons */
>         for (i = 0; i < pdata->nbuttons; i++)
>                 gpio_keys_polled_check_state(input, &pdata->buttons[i],
> -                                        &bdev->data[i]);
> +                                            &bdev->data[i]);
>
>         return 0;
>
> @@ -209,8 +310,13 @@ err_free_gpio:
>
>  err_free_bdev:
>         kfree(bdev);
> -
>         platform_set_drvdata(pdev, NULL);
> +
> +err_free_pdata:
> +       /* If we have no platform_data, we allocated pdata dynamically.  */
> +       if (!dev_get_platdata(&pdev->dev))
> +               kfree(pdata);
> +
>         return error;
>  }
>
> @@ -227,6 +333,13 @@ static int __devexit gpio_keys_polled_remove(struct platform_device *pdev)
>
>         input_free_polled_device(bdev->poll_dev);
>
> +       /*
> +        * If we had no platform_data, we allocated pdata dynamically and
> +        * must free it here.
> +        */
> +       if (!dev_get_platdata(&pdev->dev))
> +               kfree(pdata);
> +
>         kfree(bdev);
>         platform_set_drvdata(pdev, NULL);
>
> @@ -239,6 +352,7 @@ static struct platform_driver gpio_keys_polled_driver = {
>         .driver = {
>                 .name   = DRV_NAME,
>                 .owner  = THIS_MODULE,
> +               .of_match_table = of_match_ptr(gpio_keys_polled_of_match),
>         },
>  };
>  module_platform_driver(gpio_keys_polled_driver);

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2012-07-19 14:50 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-07-09 18:31 [PATCH RESEND V2] input: gpio_keys_polled: convert to dt Alexandre Pereira da Silva
2012-07-09 18:31 ` Alexandre Pereira da Silva
2012-07-19  7:27 ` Dmitry Torokhov
2012-07-19 14:50   ` Alexandre Pereira da Silva

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.