Skip to content

Commit

Permalink
Input: pxa27x-keypad - add device tree support
Browse files Browse the repository at this point in the history
Signed-off-by: Chao Xie <chao.xie@marvell.com>
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
  • Loading branch information
Chao Xie authored and Dmitry Torokhov committed Jun 19, 2013
1 parent 0a085a9 commit e415697
Show file tree
Hide file tree
Showing 2 changed files with 302 additions and 4 deletions.
60 changes: 60 additions & 0 deletions Documentation/devicetree/bindings/input/pxa27x-keypad.txt
Original file line number Diff line number Diff line change
@@ -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>;
};
246 changes: 242 additions & 4 deletions drivers/input/keyboard/pxa27x_keypad.c
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,229 @@ struct pxa27x_keypad {
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)
{
struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
Expand Down Expand Up @@ -492,15 +715,15 @@ static const struct dev_pm_ops pxa27x_keypad_pm_ops = {
static int pxa27x_keypad_probe(struct platform_device *pdev)
{
struct pxa27x_keypad_platform_data *pdata = pdev->dev.platform_data;
struct device_node *np = pdev->dev.of_node;
struct pxa27x_keypad *keypad;
struct input_dev *input_dev;
struct resource *res;
int irq, error;

if (pdata == NULL) {
dev_err(&pdev->dev, "no platform data defined\n");
/* Driver need build keycode from device tree or pdata */
if (!np && !pdata)
return -EINVAL;
}

irq = platform_get_irq(pdev, 0);
if (irq < 0) {
Expand Down Expand Up @@ -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_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) {
dev_err(&pdev->dev, "failed to build keycode\n");
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) ||
(pdata->enable_rotary1 && keypad->rotary_rel_code[1] != -1)) {
input_dev->evbit[0] |= BIT_MASK(EV_REL);
Expand Down Expand Up @@ -628,11 +857,20 @@ static int pxa27x_keypad_remove(struct platform_device *pdev)
/* work with hotplug and coldplug */
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 = {
.probe = pxa27x_keypad_probe,
.remove = pxa27x_keypad_remove,
.driver = {
.name = "pxa27x-keypad",
.of_match_table = of_match_ptr(pxa27x_keypad_dt_match),
.owner = THIS_MODULE,
#ifdef CONFIG_PM
.pm = &pxa27x_keypad_pm_ops,
Expand Down

0 comments on commit e415697

Please sign in to comment.