summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Glass <sjg@chromium.org>2015-10-18 21:17:16 -0600
committerSimon Glass <sjg@chromium.org>2015-11-19 20:13:40 -0700
commitf77f5e9be79c89d5105995528a7436d3a2458116 (patch)
treefddeafcd717a1a1e3f42d9e2267d530a81fd991a
parentb206cd737214d5bce3446c1368add9201dbb1813 (diff)
dm: tegra: Convert keyboard driver to driver model
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>
-rw-r--r--arch/arm/mach-tegra/Kconfig1
-rw-r--r--drivers/input/tegra-kbc.c243
-rw-r--r--include/fdtdec.h1
-rw-r--r--lib/fdtdec.c1
4 files changed, 112 insertions, 134 deletions
diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig
index a5b7e0d22d..de2454e691 100644
--- a/arch/arm/mach-tegra/Kconfig
+++ b/arch/arm/mach-tegra/Kconfig
@@ -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"
diff --git a/drivers/input/tegra-kbc.c b/drivers/input/tegra-kbc.c
index 818ed8ccab..a7137f1d93 100644
--- a/drivers/input/tegra-kbc.c
+++ b/drivers/input/tegra-kbc.c
@@ -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),
+};
diff --git a/include/fdtdec.h b/include/fdtdec.h
index 3a6ff1f8ac..79826d78fa 100644
--- a/include/fdtdec.h
+++ b/include/fdtdec.h
@@ -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 */
diff --git a/lib/fdtdec.c b/lib/fdtdec.c
index f1849bcd37..e0e6bb48fa 100644
--- a/lib/fdtdec.c
+++ b/lib/fdtdec.c
@@ -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"),