Skip to content

Commit

Permalink
Input: omap4-keypad - add device tree support
Browse files Browse the repository at this point in the history
Add device tree support for omap4 keypad driver and update the
Documentation with omap4 keypad device tree binding information.

Tested on omap4430 sdp.

Signed-off-by: Sourav Poddar <sourav.poddar@ti.com>
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
  • Loading branch information
Sourav Poddar authored and Dmitry Torokhov committed Jul 18, 2012
1 parent 8a90c03 commit 1398743
Show file tree
Hide file tree
Showing 2 changed files with 118 additions and 40 deletions.
31 changes: 31 additions & 0 deletions Documentation/devicetree/bindings/input/omap-keypad.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
* TI's Keypad Controller device tree bindings

TI's Keypad controller is used to interface a SoC with a matrix-type
keypad device. The keypad controller supports multiple row and column lines.
A key can be placed at each intersection of a unique row and a unique column.
The keypad controller can sense a key-press and key-release and report the
event using a interrupt to the cpu.

Required SoC Specific Properties:
- compatible: should be one of the following
- "ti,omap4-keypad": For controllers compatible with omap4 keypad
controller.

Required Board Specific Properties, in addition to those specified by
the shared matrix-keyboard bindings:
- keypad,num-rows: Number of row lines connected to the keypad
controller.

- keypad,num-columns: Number of column lines connected to the
keypad controller.

Optional Properties specific to linux:
- linux,keypad-no-autorepeat: do no enable autorepeat feature.

Example:
keypad@4ae1c000{
compatible = "ti,omap4-keypad";
keypad,num-rows = <2>;
keypad,num-columns = <8>;
linux,keypad-no-autorepeat;
};
127 changes: 87 additions & 40 deletions drivers/input/keyboard/omap4-keypad.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include <linux/platform_device.h>
#include <linux/errno.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/input.h>
#include <linux/slab.h>
#include <linux/pm_runtime.h>
Expand Down Expand Up @@ -84,8 +85,9 @@ struct omap4_keypad {
u32 reg_offset;
u32 irqreg_offset;
unsigned int row_shift;
bool no_autorepeat;
unsigned char key_state[8];
unsigned short keymap[];
unsigned short *keymap;
};

static int kbd_readl(struct omap4_keypad *keypad_data, u32 offset)
Expand Down Expand Up @@ -208,25 +210,51 @@ static void omap4_keypad_close(struct input_dev *input)
pm_runtime_put_sync(input->dev.parent);
}

#ifdef CONFIG_OF
static int __devinit omap4_keypad_parse_dt(struct device *dev,
struct omap4_keypad *keypad_data)
{
struct device_node *np = dev->of_node;

if (!np) {
dev_err(dev, "missing DT data");
return -EINVAL;
}

of_property_read_u32(np, "keypad,num-rows", &keypad_data->rows);
of_property_read_u32(np, "keypad,num-columns", &keypad_data->cols);
if (!keypad_data->rows || !keypad_data->cols) {
dev_err(dev, "number of keypad rows/columns not specified\n");
return -EINVAL;
}

if (of_get_property(np, "linux,input-no-autorepeat", NULL))
keypad_data->no_autorepeat = true;

return 0;
}
#else
static inline int omap4_keypad_parse_dt(struct device *dev,
struct omap4_keypad *keypad_data)
{
return -ENOSYS;
}
#endif

static int __devinit omap4_keypad_probe(struct platform_device *pdev)
{
const struct omap4_keypad_platform_data *pdata;
const struct omap4_keypad_platform_data *pdata =
dev_get_platdata(&pdev->dev);
const struct matrix_keymap_data *keymap_data =
pdata ? pdata->keymap_data : NULL;
struct omap4_keypad *keypad_data;
struct input_dev *input_dev;
struct resource *res;
resource_size_t size;
unsigned int row_shift, max_keys;
unsigned int max_keys;
int rev;
int irq;
int error;

/* platform data */
pdata = pdev->dev.platform_data;
if (!pdata) {
dev_err(&pdev->dev, "no platform data defined\n");
return -EINVAL;
}

res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pdev->dev, "no base address specified\n");
Expand All @@ -239,25 +267,24 @@ static int __devinit omap4_keypad_probe(struct platform_device *pdev)
return -EINVAL;
}

if (!pdata->keymap_data) {
dev_err(&pdev->dev, "no keymap data defined\n");
return -EINVAL;
}

row_shift = get_count_order(pdata->cols);
max_keys = pdata->rows << row_shift;

keypad_data = kzalloc(sizeof(struct omap4_keypad) +
max_keys * sizeof(keypad_data->keymap[0]),
GFP_KERNEL);
keypad_data = kzalloc(sizeof(struct omap4_keypad), GFP_KERNEL);
if (!keypad_data) {
dev_err(&pdev->dev, "keypad_data memory allocation failed\n");
return -ENOMEM;
}

size = resource_size(res);
keypad_data->irq = irq;

if (pdata) {
keypad_data->rows = pdata->rows;
keypad_data->cols = pdata->cols;
} else {
error = omap4_keypad_parse_dt(&pdev->dev, keypad_data);
if (error)
return error;
}

res = request_mem_region(res->start, size, pdev->name);
res = request_mem_region(res->start, resource_size(res), pdev->name);
if (!res) {
dev_err(&pdev->dev, "can't request mem region\n");
error = -EBUSY;
Expand All @@ -271,15 +298,11 @@ static int __devinit omap4_keypad_probe(struct platform_device *pdev)
goto err_release_mem;
}

keypad_data->irq = irq;
keypad_data->row_shift = row_shift;
keypad_data->rows = pdata->rows;
keypad_data->cols = pdata->cols;

/*
* Enable clocks for the keypad module so that we can read
* revision register.
*/
* Enable clocks for the keypad module so that we can read
* revision register.
*/
pm_runtime_enable(&pdev->dev);
error = pm_runtime_get_sync(&pdev->dev);
if (error) {
Expand Down Expand Up @@ -322,19 +345,30 @@ static int __devinit omap4_keypad_probe(struct platform_device *pdev)
input_dev->open = omap4_keypad_open;
input_dev->close = omap4_keypad_close;

error = matrix_keypad_build_keymap(pdata->keymap_data, NULL,
pdata->rows, pdata->cols,
input_set_capability(input_dev, EV_MSC, MSC_SCAN);
if (!keypad_data->no_autorepeat)
__set_bit(EV_REP, input_dev->evbit);

input_set_drvdata(input_dev, keypad_data);

keypad_data->row_shift = get_count_order(keypad_data->cols);
max_keys = keypad_data->rows << keypad_data->row_shift;
keypad_data->keymap = kzalloc(max_keys * sizeof(keypad_data->keymap[0]),
GFP_KERNEL);
if (!keypad_data->keymap) {
dev_err(&pdev->dev, "Not enough memory for keymap\n");
error = -ENOMEM;
goto err_free_input;
}

error = matrix_keypad_build_keymap(keymap_data, NULL,
keypad_data->rows, keypad_data->cols,
keypad_data->keymap, input_dev);
if (error) {
dev_err(&pdev->dev, "failed to build keymap\n");
goto err_free_input;
goto err_free_keymap;
}

__set_bit(EV_REP, input_dev->evbit);
input_set_capability(input_dev, EV_MSC, MSC_SCAN);

input_set_drvdata(input_dev, keypad_data);

error = request_irq(keypad_data->irq, omap4_keypad_interrupt,
IRQF_TRIGGER_RISING,
"omap4-keypad", keypad_data);
Expand All @@ -357,14 +391,16 @@ static int __devinit omap4_keypad_probe(struct platform_device *pdev)
err_pm_disable:
pm_runtime_disable(&pdev->dev);
free_irq(keypad_data->irq, keypad_data);
err_free_keymap:
kfree(keypad_data->keymap);
err_free_input:
input_free_device(input_dev);
err_pm_put_sync:
pm_runtime_put_sync(&pdev->dev);
err_unmap:
iounmap(keypad_data->base);
err_release_mem:
release_mem_region(res->start, size);
release_mem_region(res->start, resource_size(res));
err_free_keypad:
kfree(keypad_data);
return error;
Expand All @@ -386,18 +422,29 @@ static int __devexit omap4_keypad_remove(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
release_mem_region(res->start, resource_size(res));

kfree(keypad_data->keymap);
kfree(keypad_data);

platform_set_drvdata(pdev, NULL);

return 0;
}

#ifdef CONFIG_OF
static const struct of_device_id omap_keypad_dt_match[] = {
{ .compatible = "ti,omap4-keypad" },
{},
};
MODULE_DEVICE_TABLE(of, omap_keypad_dt_match);
#endif

static struct platform_driver omap4_keypad_driver = {
.probe = omap4_keypad_probe,
.remove = __devexit_p(omap4_keypad_remove),
.driver = {
.name = "omap4-keypad",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(omap_keypad_dt_match),
},
};
module_platform_driver(omap4_keypad_driver);
Expand Down

0 comments on commit 1398743

Please sign in to comment.