[U-Boot] [PATCH v2 07/28] dm: tegra: Convert keyboard driver to driver model

Simon Glass sjg at chromium.org
Mon Oct 19 05:17:16 CEST 2015


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 at chromium.org>
---

Changes in v2: None

 arch/arm/mach-tegra/Kconfig |   1 +
 drivers/input/tegra-kbc.c   | 243 ++++++++++++++++++++------------------------
 include/fdtdec.h            |   1 -
 lib/fdtdec.c                |   1 -
 4 files changed, 112 insertions(+), 134 deletions(-)

diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig
index a5b7e0d..de2454e 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 3310f84..a7137f1 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_FLAGS_SYSTEM;
-	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 2de6dda..0db5918 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 1a86369..22de5be 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"),
-- 
2.6.0.rc2.230.g3dd15c0



More information about the U-Boot mailing list