dm: tegra: Convert keyboard driver to driver model
authorSimon Glass <sjg@chromium.org>
Mon, 19 Oct 2015 03:17:16 +0000 (21:17 -0600)
committerSimon Glass <sjg@chromium.org>
Fri, 20 Nov 2015 03:13:40 +0000 (20:13 -0700)
Adjust the tegra keyboard driver to support driver model, using the new
uclass. Make this the default for all Tegra boards so that those that use
a keyboard will build correctly with this driver.

Signed-off-by: Simon Glass <sjg@chromium.org>
arch/arm/mach-tegra/Kconfig
drivers/input/tegra-kbc.c
include/fdtdec.h
lib/fdtdec.c

index a5b7e0d22d29e034e5ee42f7dca52a3dc23911ed..de2454e691d23a83a38df01cfb6ca7f51302806f 100644 (file)
@@ -12,6 +12,7 @@ config TEGRA_ARMV7_COMMON
        select DM_I2C
        select DM_SPI
        select DM_GPIO
+       select DM_KEYBOARD
 
 choice
        prompt "Tegra SoC select"
index 818ed8ccab63b13ea872a4737a2b730b8f3bcf6d..a7137f1d9347f9e0bf53ab93d89fdf024d0d0186 100644 (file)
@@ -6,8 +6,10 @@
  */
 
 #include <common.h>
+#include <dm.h>
 #include <fdtdec.h>
 #include <input.h>
+#include <keyboard.h>
 #include <key_matrix.h>
 #include <stdio_dev.h>
 #include <tegra-kbc.h>
@@ -40,14 +42,13 @@ enum {
 };
 
 /* keyboard controller config and state */
-static struct keyb {
-       struct input_config input;      /* The input layer */
+struct tegra_kbd_priv {
+       struct input_config *input;     /* The input layer */
        struct key_matrix matrix;       /* The key matrix layer */
 
        struct kbc_tegra *kbc;          /* tegra keyboard controller */
        unsigned char inited;           /* 1 if keyboard has been inited */
        unsigned char first_scan;       /* 1 if this is our first key scan */
-       unsigned char created;          /* 1 if driver has been created */
 
        /*
         * After init we must wait a short time before polling the keyboard.
@@ -58,17 +59,17 @@ static struct keyb {
        unsigned int start_time_ms;     /* Time that we inited (in ms) */
        unsigned int last_poll_ms;      /* Time we should last polled */
        unsigned int next_repeat_ms;    /* Next time we repeat a key */
-} config;
+};
 
 /**
  * reads the keyboard fifo for current keypresses
  *
- * @param config       Keyboard config
+ * @param priv         Keyboard private data
  * @param fifo         Place to put fifo results
  * @param max_keycodes Maximum number of key codes to put in the fifo
  * @return number of items put into fifo
  */
-static int tegra_kbc_find_keys(struct keyb *config, int *fifo,
+static int tegra_kbc_find_keys(struct tegra_kbd_priv *priv, int *fifo,
                               int max_keycodes)
 {
        struct key_matrix_key keys[KBC_MAX_KPENT], *key;
@@ -78,7 +79,7 @@ static int tegra_kbc_find_keys(struct keyb *config, int *fifo,
        for (key = keys, i = 0; i < KBC_MAX_KPENT; i++, key++) {
                /* Get next word */
                if (!(i & 3))
-                       kp_ent = readl(&config->kbc->kp_ent[i / 4]);
+                       kp_ent = readl(&priv->kbc->kp_ent[i / 4]);
 
                key->valid = (kp_ent & KBC_KPENT_VALID) != 0;
                key->row = (kp_ent >> 3) & 0xf;
@@ -87,7 +88,7 @@ static int tegra_kbc_find_keys(struct keyb *config, int *fifo,
                /* Shift to get next entry */
                kp_ent >>= 8;
        }
-       return key_matrix_decode(&config->matrix, keys, KBC_MAX_KPENT, fifo,
+       return key_matrix_decode(&priv->matrix, keys, KBC_MAX_KPENT, fifo,
                                 max_keycodes);
 }
 
@@ -106,10 +107,10 @@ static int tegra_kbc_find_keys(struct keyb *config, int *fifo,
  * Note: if fifo_cnt is 0, we will tell the input layer that no keys are
  * pressed.
  *
- * @param config       Keyboard config
+ * @param priv         Keyboard private data
  * @param fifo_cnt     Number of entries in the keyboard fifo
  */
-static void process_fifo(struct keyb *config, int fifo_cnt)
+static void process_fifo(struct tegra_kbd_priv *priv, int fifo_cnt)
 {
        int fifo[KBC_MAX_KPENT];
        int cnt = 0;
@@ -117,9 +118,9 @@ static void process_fifo(struct keyb *config, int fifo_cnt)
        /* Always call input_send_keycodes() at least once */
        do {
                if (fifo_cnt)
-                       cnt = tegra_kbc_find_keys(config, fifo, KBC_MAX_KPENT);
+                       cnt = tegra_kbc_find_keys(priv, fifo, KBC_MAX_KPENT);
 
-               input_send_keycodes(&config->input, fifo, cnt);
+               input_send_keycodes(priv->input, fifo, cnt);
        } while (--fifo_cnt > 0);
 }
 
@@ -127,24 +128,24 @@ static void process_fifo(struct keyb *config, int fifo_cnt)
  * Check the keyboard controller and emit ASCII characters for any keys that
  * are pressed.
  *
- * @param config       Keyboard config
+ * @param priv         Keyboard private data
  */
-static void check_for_keys(struct keyb *config)
+static void check_for_keys(struct tegra_kbd_priv *priv)
 {
        int fifo_cnt;
 
-       if (!config->first_scan &&
-                       get_timer(config->last_poll_ms) < KBC_REPEAT_RATE_MS)
+       if (!priv->first_scan &&
+           get_timer(priv->last_poll_ms) < KBC_REPEAT_RATE_MS)
                return;
-       config->last_poll_ms = get_timer(0);
-       config->first_scan = 0;
+       priv->last_poll_ms = get_timer(0);
+       priv->first_scan = 0;
 
        /*
         * Once we get here we know the keyboard has been scanned. So if there
         * scan waiting for us, we know that nothing is held down.
         */
-       fifo_cnt = (readl(&config->kbc->interrupt) >> 4) & 0xf;
-       process_fifo(config, fifo_cnt);
+       fifo_cnt = (readl(&priv->kbc->interrupt) >> 4) & 0xf;
+       process_fifo(priv, fifo_cnt);
 }
 
 /**
@@ -153,22 +154,22 @@ static void check_for_keys(struct keyb *config)
  * Wkup mode to Continous polling mode and the repoll time. We can
  * deduct the time that's already elapsed.
  *
- * @param config       Keyboard config
+ * @param priv         Keyboard private data
  */
-static void kbd_wait_for_fifo_init(struct keyb *config)
+static void kbd_wait_for_fifo_init(struct tegra_kbd_priv *priv)
 {
-       if (!config->inited) {
+       if (!priv->inited) {
                unsigned long elapsed_time;
                long delay_ms;
 
-               elapsed_time = get_timer(config->start_time_ms);
-               delay_ms = config->init_dly_ms - elapsed_time;
+               elapsed_time = get_timer(priv->start_time_ms);
+               delay_ms = priv->init_dly_ms - elapsed_time;
                if (delay_ms > 0) {
                        udelay(delay_ms * 1000);
                        debug("%s: delay %ldms\n", __func__, delay_ms);
                }
 
-               config->inited = 1;
+               priv->inited = 1;
        }
 }
 
@@ -183,38 +184,16 @@ static void kbd_wait_for_fifo_init(struct keyb *config)
  */
 static int tegra_kbc_check(struct input_config *input)
 {
-       kbd_wait_for_fifo_init(&config);
-       check_for_keys(&config);
-
-       return 1;
-}
+       struct tegra_kbd_priv *priv = dev_get_priv(input->dev);
 
-/**
- * Test if keys are available to be read
- *
- * @return 0 if no keys available, 1 if keys are available
- */
-static int kbd_tstc(struct stdio_dev *dev)
-{
-       /* Just get input to do this for us */
-       return input_tstc(&config.input);
-}
+       kbd_wait_for_fifo_init(priv);
+       check_for_keys(priv);
 
-/**
- * Read a key
- *
- * TODO: U-Boot wants 0 for no key, but Ctrl-@ is a valid key...
- *
- * @return ASCII key code, or 0 if no key, or -1 if error
- */
-static int kbd_getc(struct stdio_dev *dev)
-{
-       /* Just get input to do this for us */
-       return input_getc(&config.input);
+       return 1;
 }
 
 /* configures keyboard GPIO registers to use the rows and columns */
-static void config_kbc_gpio(struct kbc_tegra *kbc)
+static void config_kbc_gpio(struct tegra_kbd_priv *priv, struct kbc_tegra *kbc)
 {
        int i;
 
@@ -233,10 +212,10 @@ static void config_kbc_gpio(struct kbc_tegra *kbc)
                row_cfg &= ~r_mask;
                col_cfg &= ~c_mask;
 
-               if (i < config.matrix.num_rows) {
+               if (i < priv->matrix.num_rows) {
                        row_cfg |= ((i << 1) | 1) << r_shift;
                } else {
-                       col_cfg |= (((i - config.matrix.num_rows) << 1) | 1)
+                       col_cfg |= (((i - priv->matrix.num_rows) << 1) | 1)
                                        << c_shift;
                }
 
@@ -248,9 +227,9 @@ static void config_kbc_gpio(struct kbc_tegra *kbc)
 /**
  * Start up the keyboard device
  */
-static void tegra_kbc_open(void)
+static void tegra_kbc_open(struct tegra_kbd_priv *priv)
 {
-       struct kbc_tegra *kbc = config.kbc;
+       struct kbc_tegra *kbc = priv->kbc;
        unsigned int scan_period;
        u32 val;
 
@@ -265,16 +244,32 @@ static void tegra_kbc_open(void)
         * Before reading from the keyboard we must wait for the init_dly
         * plus the rpt_delay, plus 2ms for the row scan time.
         */
-       config.init_dly_ms = scan_period * 2 + 2;
+       priv->init_dly_ms = scan_period * 2 + 2;
 
        val = KBC_DEBOUNCE_COUNT << KBC_DEBOUNCE_CNT_SHIFT;
        val |= 1 << KBC_FIFO_TH_CNT_SHIFT;      /* fifo interrupt threshold */
        val |= KBC_CONTROL_KBC_EN;              /* enable */
        writel(val, &kbc->control);
 
-       config.start_time_ms = get_timer(0);
-       config.last_poll_ms = config.next_repeat_ms = get_timer(0);
-       config.first_scan = 1;
+       priv->start_time_ms = get_timer(0);
+       priv->last_poll_ms = get_timer(0);
+       priv->next_repeat_ms = priv->last_poll_ms;
+       priv->first_scan = 1;
+}
+
+static int tegra_kbd_start(struct udevice *dev)
+{
+       struct tegra_kbd_priv *priv = dev_get_priv(dev);
+
+       /* Set up pin mux and enable the clock */
+       funcmux_select(PERIPH_ID_KBC, FUNCMUX_DEFAULT);
+       clock_enable(PERIPH_ID_KBC);
+       config_kbc_gpio(priv, priv->kbc);
+
+       tegra_kbc_open(priv);
+       debug("%s: Tegra keyboard ready\n", __func__);
+
+       return 0;
 }
 
 /**
@@ -289,89 +284,73 @@ static void tegra_kbc_open(void)
  *
  * @return 0 if ok, -ve on error
  */
-static int init_tegra_keyboard(struct stdio_dev *dev)
+static int tegra_kbd_probe(struct udevice *dev)
 {
-       /* check if already created */
-       if (config.created)
-               return 0;
-
-#if CONFIG_IS_ENABLED(OF_CONTROL)
-       int     node;
-
-       node = fdtdec_next_compatible(gd->fdt_blob, 0,
-                                         COMPAT_NVIDIA_TEGRA20_KBC);
-       if (node < 0) {
-               debug("%s: cannot locate keyboard node\n", __func__);
-               return node;
-       }
-       config.kbc = (struct kbc_tegra *)fdtdec_get_addr(gd->fdt_blob,
-                      node, "reg");
-       if ((fdt_addr_t)config.kbc == FDT_ADDR_T_NONE) {
+       struct tegra_kbd_priv *priv = dev_get_priv(dev);
+       struct keyboard_priv *uc_priv = dev_get_uclass_priv(dev);
+       struct stdio_dev *sdev = &uc_priv->sdev;
+       struct input_config *input = &uc_priv->input;
+       int node = dev->of_offset;
+       int ret;
+
+       priv->kbc = (struct kbc_tegra *)dev_get_addr(dev);
+       if ((fdt_addr_t)priv->kbc == FDT_ADDR_T_NONE) {
                debug("%s: No keyboard register found\n", __func__);
-               return -1;
+               return -EINVAL;
        }
-       input_set_delays(&config.input, KBC_REPEAT_DELAY_MS,
-                       KBC_REPEAT_RATE_MS);
+       input_set_delays(input, KBC_REPEAT_DELAY_MS, KBC_REPEAT_RATE_MS);
 
        /* Decode the keyboard matrix information (16 rows, 8 columns) */
-       if (key_matrix_init(&config.matrix, 16, 8, 1)) {
-               debug("%s: Could not init key matrix\n", __func__);
-               return -1;
+       ret = key_matrix_init(&priv->matrix, 16, 8, 1);
+       if (ret) {
+               debug("%s: Could not init key matrix: %d\n", __func__, ret);
+               return ret;
        }
-       if (key_matrix_decode_fdt(&config.matrix, gd->fdt_blob, node)) {
-               debug("%s: Could not decode key matrix from fdt\n", __func__);
-               return -1;
+       ret = key_matrix_decode_fdt(&priv->matrix, gd->fdt_blob, node);
+       if (ret) {
+               debug("%s: Could not decode key matrix from fdt: %d\n",
+                     __func__, ret);
+               return ret;
        }
-       if (config.matrix.fn_keycode) {
-               if (input_add_table(&config.input, KEY_FN, -1,
-                                   config.matrix.fn_keycode,
-                                   config.matrix.key_count))
-                       return -1;
+       if (priv->matrix.fn_keycode) {
+               ret = input_add_table(input, KEY_FN, -1,
+                                     priv->matrix.fn_keycode,
+                                     priv->matrix.key_count);
+               if (ret) {
+                       debug("%s: input_add_table() failed\n", __func__);
+                       return ret;
+               }
        }
-#else
-#error "Tegra keyboard driver requires FDT definitions"
-#endif
-
-       /* Set up pin mux and enable the clock */
-       funcmux_select(PERIPH_ID_KBC, FUNCMUX_DEFAULT);
-       clock_enable(PERIPH_ID_KBC);
-       config_kbc_gpio(config.kbc);
 
-       tegra_kbc_open();
-       config.created = 1;
-       debug("%s: Tegra keyboard ready\n", __func__);
+       /* Register the device. init_tegra_keyboard() will be called soon */
+       priv->input = input;
+       input->dev = dev;
+       input->read_keys = tegra_kbc_check;
+       input_add_tables(input);
+       strcpy(sdev->name, "tegra-kbc");
+       ret = input_stdio_register(sdev);
+       if (ret) {
+               debug("%s: input_stdio_register() failed\n", __func__);
+               return ret;
+       }
 
        return 0;
 }
 
-int drv_keyboard_init(void)
-{
-       struct stdio_dev dev;
-       char *stdinname = getenv("stdin");
-       int error;
-
-       if (input_init(&config.input, 0)) {
-               debug("%s: Cannot set up input\n", __func__);
-               return -1;
-       }
-       config.input.read_keys = tegra_kbc_check;
-       input_add_tables(input);
+static const struct keyboard_ops tegra_kbd_ops = {
+       .start  = tegra_kbd_start,
+};
 
-       memset(&dev, '\0', sizeof(dev));
-       strcpy(dev.name, "tegra-kbc");
-       dev.flags = DEV_FLAGS_INPUT;
-       dev.getc = kbd_getc;
-       dev.tstc = kbd_tstc;
-       dev.start = init_tegra_keyboard;
+static const struct udevice_id tegra_kbd_ids[] = {
+       { .compatible = "nvidia,tegra20-kbc" },
+       { }
+};
 
-       /* Register the device. init_tegra_keyboard() will be called soon */
-       error = input_stdio_register(&dev);
-       if (error)
-               return error;
-#ifdef CONFIG_CONSOLE_MUX
-       error = iomux_doenv(stdin, stdinname);
-       if (error)
-               return error;
-#endif
-       return 0;
-}
+U_BOOT_DRIVER(tegra_kbd) = {
+       .name   = "tegra_kbd",
+       .id     = UCLASS_KEYBOARD,
+       .of_match = tegra_kbd_ids,
+       .probe = tegra_kbd_probe,
+       .ops    = &tegra_kbd_ops,
+       .priv_auto_alloc_size = sizeof(struct tegra_kbd_priv),
+};
index 3a6ff1f8aca127ecd59c69bab16660adc5005a63..79826d78fad2244b6a517f5db5a5291ad6316652 100644 (file)
@@ -118,7 +118,6 @@ enum fdt_compat_id {
        COMPAT_UNKNOWN,
        COMPAT_NVIDIA_TEGRA20_EMC,      /* Tegra20 memory controller */
        COMPAT_NVIDIA_TEGRA20_EMC_TABLE, /* Tegra20 memory timing table */
-       COMPAT_NVIDIA_TEGRA20_KBC,      /* Tegra20 Keyboard */
        COMPAT_NVIDIA_TEGRA20_NAND,     /* Tegra2 NAND controller */
        COMPAT_NVIDIA_TEGRA20_PWM,      /* Tegra 2 PWM controller */
        COMPAT_NVIDIA_TEGRA124_DC,      /* Tegra 124 Display controller */
index f1849bcd37f7e2b3b87ec627309b430614ff888a..e0e6bb48fa40424c2cd278e67ea7c3c000a8329b 100644 (file)
@@ -24,7 +24,6 @@ static const char * const compat_names[COMPAT_COUNT] = {
        COMPAT(UNKNOWN, "<none>"),
        COMPAT(NVIDIA_TEGRA20_EMC, "nvidia,tegra20-emc"),
        COMPAT(NVIDIA_TEGRA20_EMC_TABLE, "nvidia,tegra20-emc-table"),
-       COMPAT(NVIDIA_TEGRA20_KBC, "nvidia,tegra20-kbc"),
        COMPAT(NVIDIA_TEGRA20_NAND, "nvidia,tegra20-nand"),
        COMPAT(NVIDIA_TEGRA20_PWM, "nvidia,tegra20-pwm"),
        COMPAT(NVIDIA_TEGRA124_DC, "nvidia,tegra124-dc"),