Input: matrix-keymap - wire up device tree support

When platform keymap is not supplied to matrix_keypad_build_keymap()
and device tree support is enabled, try locating specified property
and load keymap from it. If property name is not defined, try using
"linux,keymap".

Based on earlier patch by Viresh Kumar <viresh.kumar@st.com>

Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
This commit is contained in:
Dmitry Torokhov 2012-05-10 22:37:15 -07:00
parent 1932811f42
commit b45c8f35a7
3 changed files with 130 additions and 119 deletions

View file

@ -619,8 +619,8 @@ tegra_kbc_check_pin_cfg(const struct tegra_kbc_platform_data *pdata,
}
#ifdef CONFIG_OF
static struct tegra_kbc_platform_data * __devinit
tegra_kbc_dt_parse_pdata(struct platform_device *pdev)
static struct tegra_kbc_platform_data * __devinit tegra_kbc_dt_parse_pdata(
struct platform_device *pdev)
{
struct tegra_kbc_platform_data *pdata;
struct device_node *np = pdev->dev.of_node;
@ -660,10 +660,6 @@ tegra_kbc_dt_parse_pdata(struct platform_device *pdev)
pdata->pin_cfg[KBC_MAX_ROW + i].type = PIN_CFG_COL;
}
pdata->keymap_data = matrix_keyboard_of_fill_keymap(np, "linux,keymap");
/* FIXME: Add handling of linux,fn-keymap here */
return pdata;
}
#else
@ -674,10 +670,36 @@ static inline struct tegra_kbc_platform_data *tegra_kbc_dt_parse_pdata(
}
#endif
static int __devinit tegra_kbd_setup_keymap(struct tegra_kbc *kbc)
{
const struct tegra_kbc_platform_data *pdata = kbc->pdata;
const struct matrix_keymap_data *keymap_data = pdata->keymap_data;
unsigned int keymap_rows = KBC_MAX_KEY;
int retval;
if (keymap_data && pdata->use_fn_map)
keymap_rows *= 2;
retval = matrix_keypad_build_keymap(keymap_data, NULL,
keymap_rows, KBC_MAX_COL,
kbc->keycode, kbc->idev);
if (retval == -ENOSYS || retval == -ENOENT) {
/*
* If there is no OF support in kernel or keymap
* property is missing, use default keymap.
*/
retval = matrix_keypad_build_keymap(
&tegra_kbc_default_keymap_data, NULL,
keymap_rows, KBC_MAX_COL,
kbc->keycode, kbc->idev);
}
return retval;
}
static int __devinit tegra_kbc_probe(struct platform_device *pdev)
{
const struct tegra_kbc_platform_data *pdata = pdev->dev.platform_data;
const struct matrix_keymap_data *keymap_data;
struct tegra_kbc *kbc;
struct input_dev *input_dev;
struct resource *res;
@ -686,7 +708,6 @@ static int __devinit tegra_kbc_probe(struct platform_device *pdev)
int num_rows = 0;
unsigned int debounce_cnt;
unsigned int scan_time_rows;
unsigned int keymap_rows;
if (!pdata)
pdata = tegra_kbc_dt_parse_pdata(pdev);
@ -768,17 +789,9 @@ static int __devinit tegra_kbc_probe(struct platform_device *pdev)
input_dev->open = tegra_kbc_open;
input_dev->close = tegra_kbc_close;
keymap_rows = KBC_MAX_KEY;
if (pdata->use_fn_map)
keymap_rows *= 2;
keymap_data = pdata->keymap_data ?: &tegra_kbc_default_keymap_data;
err = matrix_keypad_build_keymap(keymap_data, NULL,
keymap_rows, KBC_MAX_COL,
kbc->keycode, input_dev);
err = tegra_kbd_setup_keymap(kbc);
if (err) {
dev_err(&pdev->dev, "failed to build keymap\n");
dev_err(&pdev->dev, "failed to setup keymap\n");
goto err_put_clk;
}
@ -805,9 +818,6 @@ static int __devinit tegra_kbc_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, kbc);
device_init_wakeup(&pdev->dev, pdata->wakeup);
if (!pdev->dev.platform_data)
matrix_keyboard_of_free_keymap(pdata->keymap_data);
return 0;
err_free_irq:
@ -822,10 +832,8 @@ static int __devinit tegra_kbc_probe(struct platform_device *pdev)
input_free_device(input_dev);
kfree(kbc);
err_free_pdata:
if (!pdev->dev.platform_data) {
matrix_keyboard_of_free_keymap(pdata->keymap_data);
if (!pdev->dev.platform_data)
kfree(pdata);
}
return err;
}

View file

@ -17,15 +17,91 @@
*
*/
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/input.h>
#include <linux/of.h>
#include <linux/export.h>
#include <linux/gfp.h>
#include <linux/slab.h>
#include <linux/input/matrix_keypad.h>
static bool matrix_keypad_map_key(struct input_dev *input_dev,
unsigned int rows, unsigned int cols,
unsigned int row_shift, unsigned int key)
{
unsigned char *keymap = input_dev->keycode;
unsigned int row = KEY_ROW(key);
unsigned int col = KEY_COL(key);
unsigned short code = KEY_VAL(key);
if (row >= rows || col >= cols) {
dev_err(input_dev->dev.parent,
"%s: invalid keymap entry 0x%x (row: %d, col: %d, rows: %d, cols: %d)\n",
__func__, key, row, col, rows, cols);
return false;
}
keymap[MATRIX_SCAN_CODE(row, col, row_shift)] = code;
__set_bit(code, input_dev->keybit);
return true;
}
#ifdef CONFIG_OF
static int matrix_keypad_parse_of_keymap(const char *propname,
unsigned int rows, unsigned int cols,
struct input_dev *input_dev)
{
struct device *dev = input_dev->dev.parent;
struct device_node *np = dev->of_node;
unsigned int row_shift = get_count_order(cols);
unsigned int max_keys = rows << row_shift;
unsigned int proplen, i, size;
const __be32 *prop;
if (!np)
return -ENOENT;
if (!propname)
propname = "linux,keymap";
prop = of_get_property(np, propname, &proplen);
if (!prop) {
dev_err(dev, "OF: %s property not defined in %s\n",
propname, np->full_name);
return -ENOENT;
}
if (proplen % sizeof(u32)) {
dev_err(dev, "OF: Malformed keycode property %s in %s\n",
propname, np->full_name);
return -EINVAL;
}
size = proplen / sizeof(u32);
if (size > max_keys) {
dev_err(dev, "OF: %s size overflow\n", propname);
return -EINVAL;
}
for (i = 0; i < size; i++) {
unsigned int key = be32_to_cpup(prop + i);
if (!matrix_keypad_map_key(input_dev, rows, cols,
row_shift, key))
return -EINVAL;
}
return 0;
}
#else
static int matrix_keypad_parse_of_keymap(const char *propname,
unsigned int rows, unsigned int cols,
struct input_dev *input_dev)
{
return -ENOSYS;
}
#endif
/**
* matrix_keypad_build_keymap - convert platform keymap into matrix keymap
@ -41,6 +117,13 @@
* This function converts platform keymap (encoded with KEY() macro) into
* an array of keycodes that is suitable for using in a standard matrix
* keyboard driver that uses row and col as indices.
*
* If @keymap_data is not supplied and device tree support is enabled
* it will attempt load the keymap from property specified by @keymap_name
* argument (or "linux,keymap" if @keymap_name is %NULL).
*
* Callers are expected to set up input_dev->dev.parent before calling this
* function.
*/
int matrix_keypad_build_keymap(const struct matrix_keymap_data *keymap_data,
const char *keymap_name,
@ -50,6 +133,7 @@ int matrix_keypad_build_keymap(const struct matrix_keymap_data *keymap_data,
{
unsigned int row_shift = get_count_order(cols);
int i;
int error;
input_dev->keycode = keymap;
input_dev->keycodesize = sizeof(*keymap);
@ -57,86 +141,23 @@ int matrix_keypad_build_keymap(const struct matrix_keymap_data *keymap_data,
__set_bit(EV_KEY, input_dev->evbit);
for (i = 0; i < keymap_data->keymap_size; i++) {
unsigned int key = keymap_data->keymap[i];
unsigned int row = KEY_ROW(key);
unsigned int col = KEY_COL(key);
unsigned short code = KEY_VAL(key);
if (keymap_data) {
for (i = 0; i < keymap_data->keymap_size; i++) {
unsigned int key = keymap_data->keymap[i];
if (row >= rows || col >= cols) {
dev_err(input_dev->dev.parent,
"%s: invalid keymap entry %d (row: %d, col: %d, rows: %d, cols: %d)\n",
__func__, i, row, col, rows, cols);
return -EINVAL;
if (!matrix_keypad_map_key(input_dev, rows, cols,
row_shift, key))
return -EINVAL;
}
keymap[MATRIX_SCAN_CODE(row, col, row_shift)] = code;
__set_bit(code, input_dev->keybit);
} else {
error = matrix_keypad_parse_of_keymap(keymap_name, rows, cols,
input_dev);
if (error)
return error;
}
__clear_bit(KEY_RESERVED, input_dev->keybit);
return 0;
}
EXPORT_SYMBOL(matrix_keypad_build_keymap);
#ifdef CONFIG_OF
struct matrix_keymap_data *
matrix_keyboard_of_fill_keymap(struct device_node *np,
const char *propname)
{
struct matrix_keymap_data *kd;
u32 *keymap;
int proplen, i;
const __be32 *prop;
if (!np)
return NULL;
if (!propname)
propname = "linux,keymap";
prop = of_get_property(np, propname, &proplen);
if (!prop)
return NULL;
if (proplen % sizeof(u32)) {
pr_warn("Malformed keymap property %s in %s\n",
propname, np->full_name);
return NULL;
}
kd = kzalloc(sizeof(*kd), GFP_KERNEL);
if (!kd)
return NULL;
kd->keymap = keymap = kzalloc(proplen, GFP_KERNEL);
if (!kd->keymap) {
kfree(kd);
return NULL;
}
kd->keymap_size = proplen / sizeof(u32);
for (i = 0; i < kd->keymap_size; i++) {
u32 tmp = be32_to_cpup(prop + i);
int key_code, row, col;
row = (tmp >> 24) & 0xff;
col = (tmp >> 16) & 0xff;
key_code = tmp & 0xffff;
keymap[i] = KEY(row, col, key_code);
}
return kd;
}
EXPORT_SYMBOL_GPL(matrix_keyboard_of_fill_keymap);
void matrix_keyboard_of_free_keymap(const struct matrix_keymap_data *kd)
{
if (kd) {
kfree(kd->keymap);
kfree(kd);
}
}
EXPORT_SYMBOL_GPL(matrix_keyboard_of_free_keymap);
#endif

View file

@ -81,22 +81,4 @@ int matrix_keypad_build_keymap(const struct matrix_keymap_data *keymap_data,
unsigned short *keymap,
struct input_dev *input_dev);
#ifdef CONFIG_OF
struct matrix_keymap_data *
matrix_keyboard_of_fill_keymap(struct device_node *np, const char *propname);
void matrix_keyboard_of_free_keymap(const struct matrix_keymap_data *kd);
#else
static inline struct matrix_keymap_data *
matrix_keyboard_of_fill_keymap(struct device_node *np, const char *propname)
{
return NULL;
}
static inline void
matrix_keyboard_of_free_keymap(const struct matrix_keymap_data *kd)
{
}
#endif
#endif /* _MATRIX_KEYPAD_H */