Input: pxa27x-keypad - add device tree support

Signed-off-by: Chao Xie <chao.xie@marvell.com>
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
This commit is contained in:
Chao Xie 2013-05-05 20:25:10 -07:00 committed by Dmitry Torokhov
parent 0a085a9482
commit e4156979c7
2 changed files with 302 additions and 4 deletions

View File

@ -0,0 +1,60 @@
* Marvell PXA Keypad controller
Required Properties
- compatible : should be "marvell,pxa27x-keypad"
- reg : Address and length of the register set for the device
- interrupts : The interrupt for the keypad controller
- marvell,debounce-interval : How long time the key will be
recognized when it is pressed. It is a u32 value, and bit[31:16]
is debounce interval for direct key and bit[15:0] is debounce
interval for matrix key. The value is in binary number of 2ms
Optional Properties For Matrix Keyes
Please refer to matrix-keymap.txt
Optional Properties for Direct Keyes
- marvell,direct-key-count : How many direct keyes are used.
- marvell,direct-key-mask : The mask indicates which keyes
are used. If bit[X] of the mask is set, the direct key X
is used.
- marvell,direct-key-low-active : Direct key status register
tells the level of pins that connects to the direct keyes.
When this property is set, it means that when the pin level
is low, the key is pressed(active).
- marvell,direct-key-map : It is a u16 array. Each item indicates
the linux key-code for the direct key.
Optional Properties For Rotary
- marvell,rotary0 : It is a u32 value. Bit[31:16] is the
linux key-code for rotary up. Bit[15:0] is the linux key-code
for rotary down. It is for rotary 0.
- marvell,rotary1 : Same as marvell,rotary0. It is for rotary 1.
- marvell,rotary-rel-key : When rotary is used for relative axes
in the device, the value indicates the key-code for relative
axes measurement in the device. It is a u32 value. Bit[31:16]
is for rotary 1, and Bit[15:0] is for rotary 0.
Examples:
keypad: keypad@d4012000 {
keypad,num-rows = <3>;
keypad,num-columns = <5>;
linux,keymap = <0x0000000e /* KEY_BACKSPACE */
0x0001006b /* KEY_END */
0x00020061 /* KEY_RIGHTCTRL */
0x0003000b /* KEY_0 */
0x00040002 /* KEY_1 */
0x0100008b /* KEY_MENU */
0x01010066 /* KEY_HOME */
0x010200e7 /* KEY_SEND */
0x01030009 /* KEY_8 */
0x0104000a /* KEY_9 */
0x02000160 /* KEY_OK */
0x02010003 /* KEY_2 */
0x02020004 /* KEY_3 */
0x02030005 /* KEY_4 */
0x02040006>; /* KEY_5 */
marvell,rotary0 = <0x006c0067>; /* KEY_UP & KEY_DOWN */
marvell,direct-key-count = <1>;
marvell,direct-key-map = <0x001c>;
marvell,debounce-interval = <0x001e001e>;
};

View File

@ -118,6 +118,229 @@ struct pxa27x_keypad {
unsigned int direct_key_mask; unsigned int direct_key_mask;
}; };
#ifdef CONFIG_OF
static int pxa27x_keypad_matrix_key_parse_dt(struct pxa27x_keypad *keypad)
{
struct input_dev *input_dev = keypad->input_dev;
struct device *dev = input_dev->dev.parent;
struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
u32 rows, cols;
int error;
error = matrix_keypad_parse_of_params(dev, &rows, &cols);
if (error)
return error;
if (rows > MAX_MATRIX_KEY_ROWS || cols > MAX_MATRIX_KEY_COLS) {
dev_err(dev, "rows or cols exceeds maximum value\n");
return -EINVAL;
}
pdata->matrix_key_rows = rows;
pdata->matrix_key_cols = cols;
error = matrix_keypad_build_keymap(NULL, NULL,
pdata->matrix_key_rows,
pdata->matrix_key_cols,
keypad->keycodes, input_dev);
if (error)
return error;
return 0;
}
static int pxa27x_keypad_direct_key_parse_dt(struct pxa27x_keypad *keypad)
{
struct input_dev *input_dev = keypad->input_dev;
struct device *dev = input_dev->dev.parent;
struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
struct device_node *np = dev->of_node;
const __be16 *prop;
unsigned short code;
unsigned int proplen, size;
int i;
int error;
error = of_property_read_u32(np, "marvell,direct-key-count",
&pdata->direct_key_num);
if (error) {
/*
* If do not have marvel,direct-key-count defined,
* it means direct key is not supported.
*/
return error == -EINVAL ? 0 : error;
}
error = of_property_read_u32(np, "marvell,direct-key-mask",
&pdata->direct_key_mask);
if (error) {
if (error != -EINVAL)
return error;
/*
* If marvell,direct-key-mask is not defined, driver will use
* default value. Default value is set when configure the keypad.
*/
pdata->direct_key_mask = 0;
}
pdata->direct_key_low_active = of_property_read_bool(np,
"marvell,direct-key-low-active");
prop = of_get_property(np, "marvell,direct-key-map", &proplen);
if (!prop)
return -EINVAL;
if (proplen % sizeof(u16))
return -EINVAL;
size = proplen / sizeof(u16);
/* Only MAX_DIRECT_KEY_NUM is accepted.*/
if (size > MAX_DIRECT_KEY_NUM)
return -EINVAL;
for (i = 0; i < size; i++) {
code = be16_to_cpup(prop + i);
keypad->keycodes[MAX_MATRIX_KEY_NUM + i] = code;
__set_bit(code, input_dev->keybit);
}
return 0;
}
static int pxa27x_keypad_rotary_parse_dt(struct pxa27x_keypad *keypad)
{
const __be32 *prop;
int i, relkey_ret;
unsigned int code, proplen;
const char *rotaryname[2] = {
"marvell,rotary0", "marvell,rotary1"};
const char relkeyname[] = {"marvell,rotary-rel-key"};
struct input_dev *input_dev = keypad->input_dev;
struct device *dev = input_dev->dev.parent;
struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
struct device_node *np = dev->of_node;
relkey_ret = of_property_read_u32(np, relkeyname, &code);
/* if can read correct rotary key-code, we do not need this. */
if (relkey_ret == 0) {
unsigned short relcode;
/* rotary0 taks lower half, rotary1 taks upper half. */
relcode = code & 0xffff;
pdata->rotary0_rel_code = (code & 0xffff);
__set_bit(relcode, input_dev->relbit);
relcode = code >> 16;
pdata->rotary1_rel_code = relcode;
__set_bit(relcode, input_dev->relbit);
}
for (i = 0; i < 2; i++) {
prop = of_get_property(np, rotaryname[i], &proplen);
/*
* If the prop is not set, it means keypad does not need
* initialize the rotaryX.
*/
if (!prop)
continue;
code = be32_to_cpup(prop);
/*
* Not all up/down key code are valid.
* Now we depends on direct-rel-code.
*/
if ((!(code & 0xffff) || !(code >> 16)) && relkey_ret) {
return relkey_ret;
} else {
unsigned int n = MAX_MATRIX_KEY_NUM + (i << 1);
unsigned short keycode;
keycode = code & 0xffff;
keypad->keycodes[n] = keycode;
__set_bit(keycode, input_dev->keybit);
keycode = code >> 16;
keypad->keycodes[n + 1] = keycode;
__set_bit(keycode, input_dev->keybit);
if (i == 0)
pdata->rotary0_rel_code = -1;
else
pdata->rotary1_rel_code = -1;
}
if (i == 0)
pdata->enable_rotary0 = 1;
else
pdata->enable_rotary1 = 1;
}
keypad->rotary_rel_code[0] = pdata->rotary0_rel_code;
keypad->rotary_rel_code[1] = pdata->rotary1_rel_code;
return 0;
}
static int pxa27x_keypad_build_keycode_from_dt(struct pxa27x_keypad *keypad)
{
struct input_dev *input_dev = keypad->input_dev;
struct device *dev = input_dev->dev.parent;
struct device_node *np = dev->of_node;
int error;
keypad->pdata = devm_kzalloc(dev, sizeof(*keypad->pdata),
GFP_KERNEL);
if (!keypad->pdata) {
dev_err(dev, "failed to allocate memory for pdata\n");
return -ENOMEM;
}
error = pxa27x_keypad_matrix_key_parse_dt(keypad);
if (error) {
dev_err(dev, "failed to parse matrix key\n");
return error;
}
error = pxa27x_keypad_direct_key_parse_dt(keypad);
if (error) {
dev_err(dev, "failed to parse direct key\n");
return error;
}
error = pxa27x_keypad_rotary_parse_dt(keypad);
if (error) {
dev_err(dev, "failed to parse rotary key\n");
return error;
}
error = of_property_read_u32(np, "marvell,debounce-interval",
&keypad->pdata->debounce_interval);
if (error) {
dev_err(dev, "failed to parse debpunce-interval\n");
return error;
}
/*
* The keycodes may not only includes matrix key but also the direct
* key or rotary key.
*/
input_dev->keycodemax = ARRAY_SIZE(keypad->keycodes);
return 0;
}
#else
static int pxa27x_keypad_build_keycode_from_dt(struct pxa27x_keypad *keypad)
{
dev_info(keypad->input_dev->dev.parent, "missing platform data\n");
return -EINVAL;
}
#endif
static int pxa27x_keypad_build_keycode(struct pxa27x_keypad *keypad) static int pxa27x_keypad_build_keycode(struct pxa27x_keypad *keypad)
{ {
struct pxa27x_keypad_platform_data *pdata = keypad->pdata; struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
@ -492,15 +715,15 @@ static const struct dev_pm_ops pxa27x_keypad_pm_ops = {
static int pxa27x_keypad_probe(struct platform_device *pdev) static int pxa27x_keypad_probe(struct platform_device *pdev)
{ {
struct pxa27x_keypad_platform_data *pdata = pdev->dev.platform_data; struct pxa27x_keypad_platform_data *pdata = pdev->dev.platform_data;
struct device_node *np = pdev->dev.of_node;
struct pxa27x_keypad *keypad; struct pxa27x_keypad *keypad;
struct input_dev *input_dev; struct input_dev *input_dev;
struct resource *res; struct resource *res;
int irq, error; int irq, error;
if (pdata == NULL) { /* Driver need build keycode from device tree or pdata */
dev_err(&pdev->dev, "no platform data defined\n"); if (!np && !pdata)
return -EINVAL; return -EINVAL;
}
irq = platform_get_irq(pdev, 0); irq = platform_get_irq(pdev, 0);
if (irq < 0) { if (irq < 0) {
@ -562,12 +785,18 @@ static int pxa27x_keypad_probe(struct platform_device *pdev)
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP); input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
input_set_capability(input_dev, EV_MSC, MSC_SCAN); input_set_capability(input_dev, EV_MSC, MSC_SCAN);
error = pxa27x_keypad_build_keycode(keypad); if (pdata)
error = pxa27x_keypad_build_keycode(keypad);
else
error = pxa27x_keypad_build_keycode_from_dt(keypad);
if (error) { if (error) {
dev_err(&pdev->dev, "failed to build keycode\n"); dev_err(&pdev->dev, "failed to build keycode\n");
goto failed_put_clk; goto failed_put_clk;
} }
/* If device tree is supported, pdata will be allocated. */
pdata = keypad->pdata;
if ((pdata->enable_rotary0 && keypad->rotary_rel_code[0] != -1) || if ((pdata->enable_rotary0 && keypad->rotary_rel_code[0] != -1) ||
(pdata->enable_rotary1 && keypad->rotary_rel_code[1] != -1)) { (pdata->enable_rotary1 && keypad->rotary_rel_code[1] != -1)) {
input_dev->evbit[0] |= BIT_MASK(EV_REL); input_dev->evbit[0] |= BIT_MASK(EV_REL);
@ -628,11 +857,20 @@ static int pxa27x_keypad_remove(struct platform_device *pdev)
/* work with hotplug and coldplug */ /* work with hotplug and coldplug */
MODULE_ALIAS("platform:pxa27x-keypad"); MODULE_ALIAS("platform:pxa27x-keypad");
#ifdef CONFIG_OF
static const struct of_device_id pxa27x_keypad_dt_match[] = {
{ .compatible = "marvell,pxa27x-keypad" },
{},
};
MODULE_DEVICE_TABLE(of, pxa27x_keypad_dt_match);
#endif
static struct platform_driver pxa27x_keypad_driver = { static struct platform_driver pxa27x_keypad_driver = {
.probe = pxa27x_keypad_probe, .probe = pxa27x_keypad_probe,
.remove = pxa27x_keypad_remove, .remove = pxa27x_keypad_remove,
.driver = { .driver = {
.name = "pxa27x-keypad", .name = "pxa27x-keypad",
.of_match_table = of_match_ptr(pxa27x_keypad_dt_match),
.owner = THIS_MODULE, .owner = THIS_MODULE,
#ifdef CONFIG_PM #ifdef CONFIG_PM
.pm = &pxa27x_keypad_pm_ops, .pm = &pxa27x_keypad_pm_ops,