}
 
 #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;
                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
 }
 #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;
        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);
        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;
        }
 
        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:
        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;
 }
 
  *
  */
 
+#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
  * 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,
 {
        unsigned int row_shift = get_count_order(cols);
        int i;
+       int error;
 
        input_dev->keycode = keymap;
        input_dev->keycodesize = sizeof(*keymap);
 
        __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