diff mbox

[v4] Input: matrix-keypad - Add device tree support

Message ID 1352280725-452-1-git-send-email-anilkumar@ti.com (mailing list archive)
State New, archived
Headers show

Commit Message

AnilKumar, Chimata Nov. 7, 2012, 9:32 a.m. UTC
Add device tree support to matrix keypad driver and usage details
are added to device tree documentation. Driver was tested on AM335x
EVM.

Signed-off-by: AnilKumar Ch <anilkumar@ti.com>
---
This patch was tested on AM335x-EVM and based on linux-next, cleanly
applies on top of input/next

Changes from v3:
	- Incorporated Stephen Warren's review comments on v3
	  * Added description to clustered-irq-flags binding

Changes from v2:
	- Incorporated Stephen Warren's review comments on v2
	  * Renamed the bindings file to gpio-matrix-keypad.txt
	  * Added description to clustered-irq binding

Changes from v1:
	- Incorporated Rob's review comments on v1
	  * Changed matix-keypad compatible to gpio-matrix-keypad
	  * Removed unnecessary props (num of gpios)
	  * Used of_match_ptr()
	- Removed first patch based on Dmitry's comments on v1

 .../bindings/input/gpio-matrix-keypad.txt          |   52 ++++++++++
 drivers/input/keyboard/matrix_keypad.c             |  107 +++++++++++++++++++-
 2 files changed, 158 insertions(+), 1 deletion(-)
 create mode 100644 Documentation/devicetree/bindings/input/gpio-matrix-keypad.txt

Comments

AnilKumar, Chimata Nov. 7, 2012, 9:38 a.m. UTC | #1
On Wed, Nov 07, 2012 at 15:02:05, AnilKumar, Chimata wrote:
> Add device tree support to matrix keypad driver and usage details
> are added to device tree documentation. Driver was tested on AM335x
> EVM.

+Stephen

ACK from the reviewers (Rob Herring and Stephen Warren) of earlier
versions will help to get this in.

Thanks
AnilKumar

> 
> Signed-off-by: AnilKumar Ch <anilkumar@ti.com>
> ---
> This patch was tested on AM335x-EVM and based on linux-next, cleanly
> applies on top of input/next
> 
> Changes from v3:
> 	- Incorporated Stephen Warren's review comments on v3
> 	  * Added description to clustered-irq-flags binding
> 
> Changes from v2:
> 	- Incorporated Stephen Warren's review comments on v2
> 	  * Renamed the bindings file to gpio-matrix-keypad.txt
> 	  * Added description to clustered-irq binding
> 
> Changes from v1:
> 	- Incorporated Rob's review comments on v1
> 	  * Changed matix-keypad compatible to gpio-matrix-keypad
> 	  * Removed unnecessary props (num of gpios)
> 	  * Used of_match_ptr()
> 	- Removed first patch based on Dmitry's comments on v1
> 
>  .../bindings/input/gpio-matrix-keypad.txt          |   52 ++++++++++
>  drivers/input/keyboard/matrix_keypad.c             |  107 +++++++++++++++++++-
>  2 files changed, 158 insertions(+), 1 deletion(-)
>  create mode 100644 Documentation/devicetree/bindings/input/gpio-matrix-keypad.txt
> 
> diff --git a/Documentation/devicetree/bindings/input/gpio-matrix-keypad.txt b/Documentation/devicetree/bindings/input/gpio-matrix-keypad.txt
> new file mode 100644
> index 0000000..1acdfc4
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/input/gpio-matrix-keypad.txt
> @@ -0,0 +1,52 @@
> +* GPIO driven matrix keypad device tree bindings
> +
> +GPIO driven matrix keypad is used to interface a SoC with a matrix keypad.
> +The matrix keypad supports multiple row and column lines, a key can be
> +placed at each intersection of a unique row and a unique column. The matrix
> +keypad can sense a key-press and key-release by means of GPIO lines and
> +report the event using GPIO interrupts to the cpu.
> +
> +Required Properties:
> +- compatible:		Should be "gpio-matrix-keypad"
> +- row-gpios:		List of gpios used as row lines. The gpio specifier
> +			for this property depends on the gpio controller to
> +			which these row lines are connected.
> +- col-gpios:		List of gpios used as column lines. The gpio specifier
> +			for this property depends on the gpio controller to
> +			which these column lines are connected.
> +- linux,keymap:		The definition can be found at
> +			bindings/input/matrix-keymap.txt
> +
> +Optional Properties:
> +- linux,no-autorepeat:	do no enable autorepeat feature.
> +- linux,wakeup:		use any event on keypad as wakeup event.
> +- debounce-delay-ms:	debounce interval in milliseconds
> +- col-scan-delay-us:	delay, measured in microseconds, that is needed
> +			before we can scan keypad after activating column gpio
> +- clustered-irq:	have clustered irq number, that is needed if the irq
> +			is a combined irq source for the whole matrix keypad.
> +			This is useful if rows and columns of the keypad are
> +			connected to a GPIO expander.
> +- clustered-irq-flags:	clustered irq flags to specify the interrupt line
> +			behaviour among IRQF_TRIGGER_*
> +
> +Example:
> +	matrix-keypad {
> +		compatible = "gpio-matrix-keypad";
> +		debounce-delay-ms = <5>;
> +		col-scan-delay-us = <2>;
> +
> +		row-gpios = <&gpio2 25 0
> +			     &gpio2 26 0
> +			     &gpio2 27 0>;
> +
> +		col-gpios = <&gpio2 21 0
> +			     &gpio2 22 0>;
> +
> +		linux,keymap = <0x0000008B
> +				0x0100009E
> +				0x02000069
> +				0x0001006A
> +				0x0101001C
> +				0x0201006C>;
> +	};
> diff --git a/drivers/input/keyboard/matrix_keypad.c b/drivers/input/keyboard/matrix_keypad.c
> index 18b7237..960e9b05 100644
> --- a/drivers/input/keyboard/matrix_keypad.c
> +++ b/drivers/input/keyboard/matrix_keypad.c
> @@ -23,6 +23,9 @@
>  #include <linux/gpio.h>
>  #include <linux/input/matrix_keypad.h>
>  #include <linux/slab.h>
> +#include <linux/of.h>
> +#include <linux/of_gpio.h>
> +#include <linux/of_platform.h>
>  
>  struct matrix_keypad {
>  	const struct matrix_keypad_platform_data *pdata;
> @@ -394,6 +397,96 @@ static void matrix_keypad_free_gpio(struct matrix_keypad *keypad)
>  		gpio_free(pdata->col_gpios[i]);
>  }
>  
> +#ifdef CONFIG_OF
> +static
> +struct matrix_keypad_platform_data *matrix_keypad_parse_dt(struct device *dev)
> +{
> +	struct matrix_keypad_platform_data *pdata;
> +	struct matrix_keymap_data *keymap_data;
> +	struct device_node *np = dev->of_node;
> +	unsigned int *row_gpios;
> +	unsigned int *col_gpios;
> +	struct property *prop;
> +	int key_count = 0, length, row, col;
> +	uint32_t *keymap;
> +
> +	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
> +	if (!pdata) {
> +		dev_err(dev, "could not allocate memory for platform data\n");
> +		return NULL;
> +	}
> +
> +	pdata->num_row_gpios = of_gpio_named_count(np, "row-gpios");
> +	pdata->num_col_gpios = of_gpio_named_count(np, "col-gpios");
> +	if (!pdata->num_row_gpios || !pdata->num_col_gpios) {
> +		dev_err(dev, "number of keypad rows/columns not specified\n");
> +		return NULL;
> +	}
> +
> +	keymap_data = devm_kzalloc(dev, sizeof(*keymap_data), GFP_KERNEL);
> +	if (!keymap_data) {
> +		dev_err(dev, "could not allocate memory for keymap data\n");
> +		return NULL;
> +	}
> +	pdata->keymap_data = keymap_data;
> +
> +	prop = of_find_property(np, "linux,keymap", &length);
> +	if (!prop)
> +		return NULL;
> +
> +	key_count = length / sizeof(u32);
> +	keymap_data->keymap_size = key_count;
> +	keymap = devm_kzalloc(dev, sizeof(uint32_t) * key_count, GFP_KERNEL);
> +	if (!keymap) {
> +		dev_err(dev, "could not allocate memory for keymap\n");
> +		return NULL;
> +	}
> +	keymap_data->keymap = keymap;
> +
> +	of_property_read_u32_array(np, "linux,keymap", keymap, key_count);
> +
> +	if (of_get_property(np, "linux,no-autorepeat", NULL))
> +		pdata->no_autorepeat = true;
> +	if (of_get_property(np, "linux,wakeup", NULL))
> +		pdata->wakeup = true;
> +	if (of_get_property(np, "gpio-activelow", NULL))
> +		pdata->active_low = true;
> +
> +	of_property_read_u32(np, "debounce-delay-ms", &pdata->debounce_ms);
> +	of_property_read_u32(np, "col-scan-delay-us",
> +						&pdata->col_scan_delay_us);
> +	of_property_read_u32(np, "clustered-irq", &pdata->clustered_irq);
> +	of_property_read_u32(np, "clustered-irq-flags",
> +						&pdata->clustered_irq_flags);
> +
> +	row_gpios = devm_kzalloc(dev, sizeof(unsigned int) *
> +					pdata->num_row_gpios, GFP_KERNEL);
> +	col_gpios = devm_kzalloc(dev, sizeof(unsigned int) *
> +					pdata->num_col_gpios, GFP_KERNEL);
> +	if (!row_gpios || !col_gpios) {
> +		dev_err(dev, "could not allocate memory for gpios\n");
> +		return NULL;
> +	}
> +
> +	for (row = 0; row < pdata->num_row_gpios; row++)
> +		row_gpios[row] = of_get_named_gpio(np, "row-gpios", row);
> +
> +	for (col = 0; col < pdata->num_col_gpios; col++)
> +		col_gpios[col] = of_get_named_gpio(np, "col-gpios", col);
> +
> +	pdata->row_gpios = row_gpios;
> +	pdata->col_gpios = col_gpios;
> +
> +	return pdata;
> +}
> +#else
> +static
> +struct matrix_keypad_platform_data *matrix_keypad_parse_dt(struct device *dev)
> +{
> +	return NULL;
> +}
> +#endif
> +
>  static int __devinit matrix_keypad_probe(struct platform_device *pdev)
>  {
>  	const struct matrix_keypad_platform_data *pdata;
> @@ -404,7 +497,10 @@ static int __devinit matrix_keypad_probe(struct platform_device *pdev)
>  	size_t keymap_size;
>  	int err;
>  
> -	pdata = pdev->dev.platform_data;
> +	if (pdev->dev.of_node)
> +		pdata = matrix_keypad_parse_dt(&pdev->dev);
> +	else
> +		pdata = pdev->dev.platform_data;
>  	if (!pdata) {
>  		dev_err(&pdev->dev, "no platform data defined\n");
>  		return -EINVAL;
> @@ -488,6 +584,14 @@ static int __devexit matrix_keypad_remove(struct platform_device *pdev)
>  	return 0;
>  }
>  
> +#ifdef CONFIG_OF
> +static const struct of_device_id matrix_keypad_dt_match[] = {
> +	{ .compatible = "gpio-matrix-keypad" },
> +	{},
> +};
> +MODULE_DEVICE_TABLE(of, matrix_keypad_dt_match);
> +#endif
> +
>  static struct platform_driver matrix_keypad_driver = {
>  	.probe		= matrix_keypad_probe,
>  	.remove		= __devexit_p(matrix_keypad_remove),
> @@ -495,6 +599,7 @@ static struct platform_driver matrix_keypad_driver = {
>  		.name	= "matrix-keypad",
>  		.owner	= THIS_MODULE,
>  		.pm	= &matrix_keypad_pm_ops,
> +		.of_match_table = of_match_ptr(matrix_keypad_dt_match),
>  	},
>  };
>  module_platform_driver(matrix_keypad_driver);
> -- 
> 1.7.9.5
> 
> 

--
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
Stephen Warren Nov. 7, 2012, 4:57 p.m. UTC | #2
On 11/07/2012 02:38 AM, AnilKumar, Chimata wrote:
> On Wed, Nov 07, 2012 at 15:02:05, AnilKumar, Chimata wrote:
>> Add device tree support to matrix keypad driver and usage details
>> are added to device tree documentation. Driver was tested on AM335x
>> EVM.
> 
> +Stephen
> 
> ACK from the reviewers (Rob Herring and Stephen Warren) of earlier
> versions will help to get this in.

I thought I already asked a question about the clustered IRQ properties,
which don't make sense.
--
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
AnilKumar, Chimata Nov. 8, 2012, 5:23 a.m. UTC | #3
On Wed, Nov 07, 2012 at 22:27:10, Stephen Warren wrote:
> On 11/07/2012 02:38 AM, AnilKumar, Chimata wrote:
> > On Wed, Nov 07, 2012 at 15:02:05, AnilKumar, Chimata wrote:
> >> Add device tree support to matrix keypad driver and usage details
> >> are added to device tree documentation. Driver was tested on AM335x
> >> EVM.
> > 
> > +Stephen
> > 
> > ACK from the reviewers (Rob Herring and Stephen Warren) of earlier
> > versions will help to get this in.
> 
> I thought I already asked a question about the clustered IRQ properties,
> which don't make sense.

Hi Stephen,

In v4 I have added the details of clustered-irq properties

clustered-irq: have clustered irq number, that is needed if the irq
is a combined irq source for the whole matrix keypad. This is useful
if rows and columns of the keypad are connected to a GPIO expander.

clustered-irq-flags: clustered irq flags to specify the interrupt line
behavior among IRQF_TRIGGER_*.

These flags might vary depending on the hardware of the IO-expander
IRQ this flag is either IRQF_TRIGGER_RISING or IRQF_TRIGGER_FALLING or
IRQF_TRIGGER_HIGH or IRQF_TRIGGER_LOW or combinations.

The current matrix_keypad.c driver uses these parameters in this way

        if (pdata->clustered_irq > 0) {
                err = request_irq(pdata->clustered_irq,
                                matrix_keypad_interrupt,
                                pdata->clustered_irq_flags,
                                "matrix-keypad", keypad);
                if (err) {
                        dev_err(&pdev->dev,
                                "Unable to acquire clustered interrupt\n");
                        goto err_free_rows;
                }
        }

In my v5 version I will remove these parameters and we can add if actual users
come into existence. My thought process was if somebody uses these, might affect.

Thanks
AnilKumar
--
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
Stephen Warren Nov. 8, 2012, 4:55 p.m. UTC | #4
On 11/07/2012 02:32 AM, AnilKumar Ch wrote:
> Add device tree support to matrix keypad driver and usage details
> are added to device tree documentation. Driver was tested on AM335x
> EVM.

> diff --git a/Documentation/devicetree/bindings/input/gpio-matrix-keypad.txt b/Documentation/devicetree/bindings/input/gpio-matrix-keypad.txt

> +Optional Properties:

> +- clustered-irq:	have clustered irq number, that is needed if the irq
> +			is a combined irq source for the whole matrix keypad.
> +			This is useful if rows and columns of the keypad are
> +			connected to a GPIO expander.
> +- clustered-irq-flags:	clustered irq flags to specify the interrupt line
> +			behaviour among IRQF_TRIGGER_*

I still don't understand why there's a need for a clustered-irq-flags
property; if those flags are the flags for an interrupt, why aren't the
flags part of the clustered-irq interrupt specifier, just like any other
interrupt in DT?
--
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
AnilKumar, Chimata Nov. 9, 2012, 11:07 a.m. UTC | #5
On Thu, Nov 08, 2012 at 22:25:33, Stephen Warren wrote:
> On 11/07/2012 02:32 AM, AnilKumar Ch wrote:
> > Add device tree support to matrix keypad driver and usage details
> > are added to device tree documentation. Driver was tested on AM335x
> > EVM.
> 
> > diff --git a/Documentation/devicetree/bindings/input/gpio-matrix-keypad.txt b/Documentation/devicetree/bindings/input/gpio-matrix-keypad.txt
> 
> > +Optional Properties:
> 
> > +- clustered-irq:	have clustered irq number, that is needed if the irq
> > +			is a combined irq source for the whole matrix keypad.
> > +			This is useful if rows and columns of the keypad are
> > +			connected to a GPIO expander.
> > +- clustered-irq-flags:	clustered irq flags to specify the interrupt line
> > +			behavior among IRQF_TRIGGER_*
> 
> I still don't understand why there's a need for a clustered-irq-flags
> property; if those flags are the flags for an interrupt, why aren't the
> flags part of the clustered-irq interrupt specifier, just like any other
> interrupt in DT?

Exactly, I agree with you on this.

Honestly, I added clustered_xxx properties to DT considering the 
platform_data currently implemented in driver. And I do not have
hardware to  validate clustered_xxx execution flow.

I looked at the commit which adds support for clustered_irq,

Commit Description:
 
"This one adds support of a combined irq source for the whole matrix
keypad. This can be useful if all rows and columns of the keypad are
e.g. connected to a GPIO expander, which only has one interrupt line
for all events on every single GPIO."


So I believe this was meant for matrix keypad interfaced over I2C
expander, But I am not sure how it is being used.

The hardware is connected in any of the following methods, the driver
should supports the same.

i) gpio interrupt can be used as keypad interrupt, connection is
like this (MPU<===>IOEXP)
            |_______| (gpio line)

Here I expect driver should have gpio_to_irq implementation, but
its missing from driver. So platform code must be doing it, but
surprisingly I couldn't able to find any platform which uses this.

ii) i2c interrupt can be used as keypad interrupt

Here driver is not using threaded irq.

As a reference I looked tca6416-keypad.c driver and it has right implementation,

if (pdata->irq_is_gpio)
	chip->irqnum = gpio_to_irq(client->irq);
else
	chip->irqnum = client->irq;


As per my understanding matrix-keypad driver has to change
accordingly to tca6416-keypad.c driver to handle clustered-irq.

So I left with below options,

1. Lets only support normal GPIO based matrix key-pad, without
clustered_irq support in DT.

2. Cleanup the driver to remove clustered_irq all together,
considering the fact that we do not have any platform in kernel
to use it. And once we get known platform in the future, we can
again add it.

I vote for option-1, what do you think?

Thanks
AnilKumar
--
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
Stephen Warren Nov. 9, 2012, 5:19 p.m. UTC | #6
On 11/09/2012 04:07 AM, AnilKumar, Chimata wrote:
> On Thu, Nov 08, 2012 at 22:25:33, Stephen Warren wrote:
>> On 11/07/2012 02:32 AM, AnilKumar Ch wrote:
>>> Add device tree support to matrix keypad driver and usage details
>>> are added to device tree documentation. Driver was tested on AM335x
>>> EVM.
>>
>>> diff --git a/Documentation/devicetree/bindings/input/gpio-matrix-keypad.txt b/Documentation/devicetree/bindings/input/gpio-matrix-keypad.txt
>>
>>> +Optional Properties:
>>
>>> +- clustered-irq:	have clustered irq number, that is needed if the irq
>>> +			is a combined irq source for the whole matrix keypad.
>>> +			This is useful if rows and columns of the keypad are
>>> +			connected to a GPIO expander.
>>> +- clustered-irq-flags:	clustered irq flags to specify the interrupt line
>>> +			behavior among IRQF_TRIGGER_*
>>
>> I still don't understand why there's a need for a clustered-irq-flags
>> property; if those flags are the flags for an interrupt, why aren't the
>> flags part of the clustered-irq interrupt specifier, just like any other
>> interrupt in DT?
> 
> Exactly, I agree with you on this.
> 
> Honestly, I added clustered_xxx properties to DT considering the 
> platform_data currently implemented in driver. And I do not have
> hardware to  validate clustered_xxx execution flow.
> 
> I looked at the commit which adds support for clustered_irq,
> 
> Commit Description:
>  
> "This one adds support of a combined irq source for the whole matrix
> keypad. This can be useful if all rows and columns of the keypad are
> e.g. connected to a GPIO expander, which only has one interrupt line
> for all events on every single GPIO."
> 
> 
> So I believe this was meant for matrix keypad interfaced over I2C
> expander, But I am not sure how it is being used.
> 
> The hardware is connected in any of the following methods, the driver
> should supports the same.
> 
> i) gpio interrupt can be used as keypad interrupt, connection is
> like this (MPU<===>IOEXP)
>             |_______| (gpio line)
> 
> Here I expect driver should have gpio_to_irq implementation, but
> its missing from driver. So platform code must be doing it, but
> surprisingly I couldn't able to find any platform which uses this.
> 
> ii) i2c interrupt can be used as keypad interrupt
> 
> Here driver is not using threaded irq.
> 
> As a reference I looked tca6416-keypad.c driver and it has right implementation,
> 
> if (pdata->irq_is_gpio)
> 	chip->irqnum = gpio_to_irq(client->irq);
> else
> 	chip->irqnum = client->irq;
> 
> 
> As per my understanding matrix-keypad driver has to change
> accordingly to tca6416-keypad.c driver to handle clustered-irq.

That sounds correct.

> So I left with below options,
> 
> 1. Lets only support normal GPIO based matrix key-pad, without
> clustered_irq support in DT.
> 
> 2. Cleanup the driver to remove clustered_irq all together,
> considering the fact that we do not have any platform in kernel
> to use it. And once we get known platform in the future, we can
> again add it.
> 
> I vote for option-1, what do you think?

I think that's fine.

The only issue is that it means the DT binding will not be complete the
first time around, and will probably need to be extended in the future.
I know that some people will want to see the binding be complete right
from the very start, to make sure the binding has been fully thought
through. However, it seems clear that the binding can be extended in a
backwards-compatible fashion to support clustered IRQs later, so I don't
think there's any issue here myself.
--
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
diff mbox

Patch

diff --git a/Documentation/devicetree/bindings/input/gpio-matrix-keypad.txt b/Documentation/devicetree/bindings/input/gpio-matrix-keypad.txt
new file mode 100644
index 0000000..1acdfc4
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/gpio-matrix-keypad.txt
@@ -0,0 +1,52 @@ 
+* GPIO driven matrix keypad device tree bindings
+
+GPIO driven matrix keypad is used to interface a SoC with a matrix keypad.
+The matrix keypad supports multiple row and column lines, a key can be
+placed at each intersection of a unique row and a unique column. The matrix
+keypad can sense a key-press and key-release by means of GPIO lines and
+report the event using GPIO interrupts to the cpu.
+
+Required Properties:
+- compatible:		Should be "gpio-matrix-keypad"
+- row-gpios:		List of gpios used as row lines. The gpio specifier
+			for this property depends on the gpio controller to
+			which these row lines are connected.
+- col-gpios:		List of gpios used as column lines. The gpio specifier
+			for this property depends on the gpio controller to
+			which these column lines are connected.
+- linux,keymap:		The definition can be found at
+			bindings/input/matrix-keymap.txt
+
+Optional Properties:
+- linux,no-autorepeat:	do no enable autorepeat feature.
+- linux,wakeup:		use any event on keypad as wakeup event.
+- debounce-delay-ms:	debounce interval in milliseconds
+- col-scan-delay-us:	delay, measured in microseconds, that is needed
+			before we can scan keypad after activating column gpio
+- clustered-irq:	have clustered irq number, that is needed if the irq
+			is a combined irq source for the whole matrix keypad.
+			This is useful if rows and columns of the keypad are
+			connected to a GPIO expander.
+- clustered-irq-flags:	clustered irq flags to specify the interrupt line
+			behaviour among IRQF_TRIGGER_*
+
+Example:
+	matrix-keypad {
+		compatible = "gpio-matrix-keypad";
+		debounce-delay-ms = <5>;
+		col-scan-delay-us = <2>;
+
+		row-gpios = <&gpio2 25 0
+			     &gpio2 26 0
+			     &gpio2 27 0>;
+
+		col-gpios = <&gpio2 21 0
+			     &gpio2 22 0>;
+
+		linux,keymap = <0x0000008B
+				0x0100009E
+				0x02000069
+				0x0001006A
+				0x0101001C
+				0x0201006C>;
+	};
diff --git a/drivers/input/keyboard/matrix_keypad.c b/drivers/input/keyboard/matrix_keypad.c
index 18b7237..960e9b05 100644
--- a/drivers/input/keyboard/matrix_keypad.c
+++ b/drivers/input/keyboard/matrix_keypad.c
@@ -23,6 +23,9 @@ 
 #include <linux/gpio.h>
 #include <linux/input/matrix_keypad.h>
 #include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/of_platform.h>
 
 struct matrix_keypad {
 	const struct matrix_keypad_platform_data *pdata;
@@ -394,6 +397,96 @@  static void matrix_keypad_free_gpio(struct matrix_keypad *keypad)
 		gpio_free(pdata->col_gpios[i]);
 }
 
+#ifdef CONFIG_OF
+static
+struct matrix_keypad_platform_data *matrix_keypad_parse_dt(struct device *dev)
+{
+	struct matrix_keypad_platform_data *pdata;
+	struct matrix_keymap_data *keymap_data;
+	struct device_node *np = dev->of_node;
+	unsigned int *row_gpios;
+	unsigned int *col_gpios;
+	struct property *prop;
+	int key_count = 0, length, row, col;
+	uint32_t *keymap;
+
+	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata) {
+		dev_err(dev, "could not allocate memory for platform data\n");
+		return NULL;
+	}
+
+	pdata->num_row_gpios = of_gpio_named_count(np, "row-gpios");
+	pdata->num_col_gpios = of_gpio_named_count(np, "col-gpios");
+	if (!pdata->num_row_gpios || !pdata->num_col_gpios) {
+		dev_err(dev, "number of keypad rows/columns not specified\n");
+		return NULL;
+	}
+
+	keymap_data = devm_kzalloc(dev, sizeof(*keymap_data), GFP_KERNEL);
+	if (!keymap_data) {
+		dev_err(dev, "could not allocate memory for keymap data\n");
+		return NULL;
+	}
+	pdata->keymap_data = keymap_data;
+
+	prop = of_find_property(np, "linux,keymap", &length);
+	if (!prop)
+		return NULL;
+
+	key_count = length / sizeof(u32);
+	keymap_data->keymap_size = key_count;
+	keymap = devm_kzalloc(dev, sizeof(uint32_t) * key_count, GFP_KERNEL);
+	if (!keymap) {
+		dev_err(dev, "could not allocate memory for keymap\n");
+		return NULL;
+	}
+	keymap_data->keymap = keymap;
+
+	of_property_read_u32_array(np, "linux,keymap", keymap, key_count);
+
+	if (of_get_property(np, "linux,no-autorepeat", NULL))
+		pdata->no_autorepeat = true;
+	if (of_get_property(np, "linux,wakeup", NULL))
+		pdata->wakeup = true;
+	if (of_get_property(np, "gpio-activelow", NULL))
+		pdata->active_low = true;
+
+	of_property_read_u32(np, "debounce-delay-ms", &pdata->debounce_ms);
+	of_property_read_u32(np, "col-scan-delay-us",
+						&pdata->col_scan_delay_us);
+	of_property_read_u32(np, "clustered-irq", &pdata->clustered_irq);
+	of_property_read_u32(np, "clustered-irq-flags",
+						&pdata->clustered_irq_flags);
+
+	row_gpios = devm_kzalloc(dev, sizeof(unsigned int) *
+					pdata->num_row_gpios, GFP_KERNEL);
+	col_gpios = devm_kzalloc(dev, sizeof(unsigned int) *
+					pdata->num_col_gpios, GFP_KERNEL);
+	if (!row_gpios || !col_gpios) {
+		dev_err(dev, "could not allocate memory for gpios\n");
+		return NULL;
+	}
+
+	for (row = 0; row < pdata->num_row_gpios; row++)
+		row_gpios[row] = of_get_named_gpio(np, "row-gpios", row);
+
+	for (col = 0; col < pdata->num_col_gpios; col++)
+		col_gpios[col] = of_get_named_gpio(np, "col-gpios", col);
+
+	pdata->row_gpios = row_gpios;
+	pdata->col_gpios = col_gpios;
+
+	return pdata;
+}
+#else
+static
+struct matrix_keypad_platform_data *matrix_keypad_parse_dt(struct device *dev)
+{
+	return NULL;
+}
+#endif
+
 static int __devinit matrix_keypad_probe(struct platform_device *pdev)
 {
 	const struct matrix_keypad_platform_data *pdata;
@@ -404,7 +497,10 @@  static int __devinit matrix_keypad_probe(struct platform_device *pdev)
 	size_t keymap_size;
 	int err;
 
-	pdata = pdev->dev.platform_data;
+	if (pdev->dev.of_node)
+		pdata = matrix_keypad_parse_dt(&pdev->dev);
+	else
+		pdata = pdev->dev.platform_data;
 	if (!pdata) {
 		dev_err(&pdev->dev, "no platform data defined\n");
 		return -EINVAL;
@@ -488,6 +584,14 @@  static int __devexit matrix_keypad_remove(struct platform_device *pdev)
 	return 0;
 }
 
+#ifdef CONFIG_OF
+static const struct of_device_id matrix_keypad_dt_match[] = {
+	{ .compatible = "gpio-matrix-keypad" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, matrix_keypad_dt_match);
+#endif
+
 static struct platform_driver matrix_keypad_driver = {
 	.probe		= matrix_keypad_probe,
 	.remove		= __devexit_p(matrix_keypad_remove),
@@ -495,6 +599,7 @@  static struct platform_driver matrix_keypad_driver = {
 		.name	= "matrix-keypad",
 		.owner	= THIS_MODULE,
 		.pm	= &matrix_keypad_pm_ops,
+		.of_match_table = of_match_ptr(matrix_keypad_dt_match),
 	},
 };
 module_platform_driver(matrix_keypad_driver);