mirror of
https://github.com/torvalds/linux.git
synced 2024-11-26 14:12:06 +00:00
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:
parent
0a085a9482
commit
e4156979c7
60
Documentation/devicetree/bindings/input/pxa27x-keypad.txt
Normal file
60
Documentation/devicetree/bindings/input/pxa27x-keypad.txt
Normal 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>;
|
||||||
|
};
|
@ -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,
|
||||||
|
Loading…
Reference in New Issue
Block a user