Browse Source

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>
scm-imx_v2016.03_4.1.15_2.0.0_ga
Simon Glass 5 years ago
parent
commit
f77f5e9be7
4 changed files with 112 additions and 134 deletions
  1. +1
    -0
      arch/arm/mach-tegra/Kconfig
  2. +111
    -132
      drivers/input/tegra-kbc.c
  3. +0
    -1
      include/fdtdec.h
  4. +0
    -1
      lib/fdtdec.c

+ 1
- 0
arch/arm/mach-tegra/Kconfig View 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"


+ 111
- 132
drivers/input/tegra-kbc.c View 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),
};

+ 0
- 1
include/fdtdec.h View 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 */


+ 0
- 1
lib/fdtdec.c View 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"),


Loading…
Cancel
Save