From patchwork Mon May 5 16:09:10 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 345771 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from theia.denx.de (theia.denx.de [85.214.87.163]) by ozlabs.org (Postfix) with ESMTP id C492914032C for ; Tue, 6 May 2014 02:12:04 +1000 (EST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id AEBB44B800; Mon, 5 May 2014 18:11:39 +0200 (CEST) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id IOAh+YTg7nf7; Mon, 5 May 2014 18:11:39 +0200 (CEST) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id F2EA64B85B; Mon, 5 May 2014 18:10:03 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 4D31A4B83F for ; Mon, 5 May 2014 18:09:56 +0200 (CEST) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id FLMw7gQBJHlv for ; Mon, 5 May 2014 18:09:52 +0200 (CEST) X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 NOT_IN_BL_NJABL=-1.5 (only DNSBL check requested) Received: from mail-ie0-f202.google.com (mail-ie0-f202.google.com [209.85.223.202]) by theia.denx.de (Postfix) with ESMTPS id 4AFD54B81A for ; Mon, 5 May 2014 18:09:31 +0200 (CEST) Received: by mail-ie0-f202.google.com with SMTP id lx4so1625900iec.5 for ; Mon, 05 May 2014 09:09:30 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=q6uBXoL1AqunYy5n/t3H7SExUfR2BahC88dgYAmsobg=; b=TNPOy1tjI5i6DOvisH79N+B7y03zsZe8cUDwgA0QLZACs+xXhJl1hpNw2iL5wmvKWN OPqzBnOik4SWfZisSjSXHgAWi6pnAPkPbyyVMPPELGSReV1YBPXlqfATyysfPDIv3f8X O24IaNex2LPW7JYGdeSErifBs2hxohBSp/oyLa90f13QOKYW7522TAhd7Zy+wa9P+0F0 r20X08yU24mzJIKrvmiV14SM5YQknvkWn2olSGK7k8te4OhMKxN/c/Y7uLHwoheQXhZg /HDhsHFvGs/5yEzRfjAk7jJKsQRXZoNQY+aSA6F1wHVkXP7eUHGbnpUPZdkmqO1PFMAf cUUQ== X-Gm-Message-State: ALoCoQkfSU034P9azgXJvXU2xJJFVKA7YcPtXtbOEa4+dMV+Yh0GGLBPU6OCJsc+JCW1zZ5EZpTK X-Received: by 10.182.254.10 with SMTP id ae10mr17766909obd.43.1399306170332; Mon, 05 May 2014 09:09:30 -0700 (PDT) Received: from corp2gmr1-2.hot.corp.google.com (corp2gmr1-2.hot.corp.google.com [172.24.189.93]) by gmr-mx.google.com with ESMTPS id r79si379691yhj.2.2014.05.05.09.09.30 for (version=TLSv1.1 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 05 May 2014 09:09:30 -0700 (PDT) Received: from kaki.bld.corp.google.com (kaki.bld.corp.google.com [172.29.216.32]) by corp2gmr1-2.hot.corp.google.com (Postfix) with ESMTP id 256FA5A42DB; Mon, 5 May 2014 09:09:30 -0700 (PDT) Received: by kaki.bld.corp.google.com (Postfix, from userid 121222) id 036D7222653; Mon, 5 May 2014 10:09:29 -0600 (MDT) From: Simon Glass To: U-Boot Mailing List Date: Mon, 5 May 2014 10:09:10 -0600 Message-Id: <1399306150-932-14-git-send-email-sjg@chromium.org> X-Mailer: git-send-email 1.9.1.423.g4596e3a In-Reply-To: <1399306150-932-1-git-send-email-sjg@chromium.org> References: <1399306150-932-1-git-send-email-sjg@chromium.org> Cc: u-boot-review@google.com, Stephen Warren , Tom Warren Subject: [U-Boot] [RFC PATCH v2 13/13] tegra: Convert tegra GPIO driver to use driver model X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.11 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: u-boot-bounces@lists.denx.de Errors-To: u-boot-bounces@lists.denx.de This is an implementation of GPIOs for Tegra that uses driver model. It has been tested on trimslice and also using the new iotrace feature. The implementation uses a top-level GPIO device (which has no actual GPIOS). Under this all the banks are created as separate GPIO devices. The GPIOs are named as per the Tegra datasheet/header files: A0..A7, B0..B7, ..., Z0..Z7, AA0..AA7, etc. Since driver model is not yet available before relocation, or in SPL, a special function is provided for seaboard's SPL code. This series is marked RFC since the Tegra driver may need further discussion. Signed-off-by: Simon Glass --- Changes in v2: - Split out driver model changes into separate patches - Correct bugs found during testing arch/arm/include/asm/arch-tegra/gpio.h | 14 +- board/nvidia/seaboard/seaboard.c | 2 +- drivers/gpio/tegra_gpio.c | 393 +++++++++++++++++++++++++-------- include/configs/tegra-common.h | 2 + 4 files changed, 309 insertions(+), 102 deletions(-) diff --git a/arch/arm/include/asm/arch-tegra/gpio.h b/arch/arm/include/asm/arch-tegra/gpio.h index d97190d..80e4a73 100644 --- a/arch/arm/include/asm/arch-tegra/gpio.h +++ b/arch/arm/include/asm/arch-tegra/gpio.h @@ -6,6 +6,8 @@ #ifndef _TEGRA_GPIO_H_ #define _TEGRA_GPIO_H_ +#define TEGRA_GPIOS_PER_PORT 8 +#define TEGRA_PORTS_PER_BANK 4 #define MAX_NUM_GPIOS (TEGRA_GPIO_PORTS * TEGRA_GPIO_BANKS * 8) #define GPIO_NAME_SIZE 20 /* gpio_request max label len */ @@ -14,11 +16,13 @@ #define GPIO_FULLPORT(x) ((x) >> 3) #define GPIO_BIT(x) ((x) & 0x7) -/* - * Tegra-specific GPIO API +/** + * tegra_spl_gpio_direction_output() - set the output value of a GPIO + * + * This function is only used from SPL on seaboard, which needs to enable a + * GPIO to get the UART running. It could be done in U-Boot rather than SPL, + * but for now, this gets it working */ +int tegra_spl_gpio_direction_output(int gpio, int value); -void gpio_info(void); - -#define gpio_status() gpio_info() #endif /* TEGRA_GPIO_H_ */ diff --git a/board/nvidia/seaboard/seaboard.c b/board/nvidia/seaboard/seaboard.c index ef4e481..e27efcd 100644 --- a/board/nvidia/seaboard/seaboard.c +++ b/board/nvidia/seaboard/seaboard.c @@ -22,7 +22,7 @@ void gpio_early_init_uart(void) #ifndef CONFIG_SPL_BUILD gpio_request(GPIO_PI3, NULL); #endif - gpio_direction_output(GPIO_PI3, 0); + tegra_spl_gpio_direction_output(GPIO_PI3, 0); } #endif diff --git a/drivers/gpio/tegra_gpio.c b/drivers/gpio/tegra_gpio.c index 82b30d5..4cca266 100644 --- a/drivers/gpio/tegra_gpio.c +++ b/drivers/gpio/tegra_gpio.c @@ -12,10 +12,17 @@ */ #include +#include +#include +#include +#include #include #include #include #include +#include + +DECLARE_GLOBAL_DATA_PTR; enum { TEGRA_CMD_INFO, @@ -24,24 +31,30 @@ enum { TEGRA_CMD_INPUT, }; -static struct gpio_names { - char name[GPIO_NAME_SIZE]; -} gpio_names[MAX_NUM_GPIOS]; +struct tegra_gpio_platdata { + struct gpio_ctlr_bank *bank; + const char *port_name; /* Name of port, e.g. "B" */ + int base_port; /* Port number for this port (0, 1,.., n-1) */ +}; -static char *get_name(int i) -{ - return *gpio_names[i].name ? gpio_names[i].name : "UNKNOWN"; -} +/* Information about each port at run-time */ +struct tegra_port_info { + char label[TEGRA_GPIOS_PER_PORT][GPIO_NAME_SIZE]; + struct gpio_ctlr_bank *bank; + int base_port; /* Port number for this port (0, 1,.., n-1) */ +}; + +#define GPIO_NUM(state, offset) \ + (((state)->base_port * TEGRA_GPIOS_PER_PORT) + (offset)) /* Return config of pin 'gpio' as GPIO (1) or SFPIO (0) */ -static int get_config(unsigned gpio) +static int get_config(struct tegra_port_info *state, int offset) { - struct gpio_ctlr *ctlr = (struct gpio_ctlr *)NV_PA_GPIO_BASE; - struct gpio_ctlr_bank *bank = &ctlr->gpio_bank[GPIO_BANK(gpio)]; + int gpio = GPIO_NUM(state, offset); u32 u; int type; - u = readl(&bank->gpio_config[GPIO_PORT(gpio)]); + u = readl(&state->bank->gpio_config[GPIO_PORT(gpio)]); type = (u >> GPIO_BIT(gpio)) & 1; debug("get_config: port = %d, bit = %d is %s\n", @@ -51,32 +64,32 @@ static int get_config(unsigned gpio) } /* Config pin 'gpio' as GPIO or SFPIO, based on 'type' */ -static void set_config(unsigned gpio, int type) +static void set_config(struct tegra_port_info *state, int offset, int type) { - struct gpio_ctlr *ctlr = (struct gpio_ctlr *)NV_PA_GPIO_BASE; - struct gpio_ctlr_bank *bank = &ctlr->gpio_bank[GPIO_BANK(gpio)]; + int gpio = GPIO_NUM(state, offset); u32 u; debug("set_config: port = %d, bit = %d, %s\n", - GPIO_FULLPORT(gpio), GPIO_BIT(gpio), type ? "GPIO" : "SFPIO"); + GPIO_FULLPORT(gpio), + GPIO_BIT(gpio), + type ? "GPIO" : "SFPIO"); - u = readl(&bank->gpio_config[GPIO_PORT(gpio)]); + u = readl(&state->bank->gpio_config[GPIO_PORT(gpio)]); if (type) /* GPIO */ u |= 1 << GPIO_BIT(gpio); else u &= ~(1 << GPIO_BIT(gpio)); - writel(u, &bank->gpio_config[GPIO_PORT(gpio)]); + writel(u, &state->bank->gpio_config[GPIO_PORT(gpio)]); } /* Return GPIO pin 'gpio' direction - 0 = input or 1 = output */ -static int get_direction(unsigned gpio) +static int get_direction(struct tegra_port_info *state, int offset) { - struct gpio_ctlr *ctlr = (struct gpio_ctlr *)NV_PA_GPIO_BASE; - struct gpio_ctlr_bank *bank = &ctlr->gpio_bank[GPIO_BANK(gpio)]; + int gpio = GPIO_NUM(state, offset); u32 u; int dir; - u = readl(&bank->gpio_dir_out[GPIO_PORT(gpio)]); + u = readl(&state->bank->gpio_dir_out[GPIO_PORT(gpio)]); dir = (u >> GPIO_BIT(gpio)) & 1; debug("get_direction: port = %d, bit = %d, %s\n", @@ -86,161 +99,349 @@ static int get_direction(unsigned gpio) } /* Config GPIO pin 'gpio' as input or output (OE) as per 'output' */ -static void set_direction(unsigned gpio, int output) +static void set_direction(struct tegra_port_info *state, int offset, + int output) { - struct gpio_ctlr *ctlr = (struct gpio_ctlr *)NV_PA_GPIO_BASE; - struct gpio_ctlr_bank *bank = &ctlr->gpio_bank[GPIO_BANK(gpio)]; + int gpio = GPIO_NUM(state, offset); u32 u; - debug("set_direction: port = %d, bit = %d, %s\n", - GPIO_FULLPORT(gpio), GPIO_BIT(gpio), output ? "OUT" : "IN"); + debug("%s: port = %d, bit = %d, %s\n", __func__, + GPIO_FULLPORT(gpio), GPIO_BIT(gpio), output ? "OUT" : "IN"); - u = readl(&bank->gpio_dir_out[GPIO_PORT(gpio)]); + u = readl(&state->bank->gpio_dir_out[GPIO_PORT(gpio)]); if (output) u |= 1 << GPIO_BIT(gpio); else u &= ~(1 << GPIO_BIT(gpio)); - writel(u, &bank->gpio_dir_out[GPIO_PORT(gpio)]); + writel(u, &state->bank->gpio_dir_out[GPIO_PORT(gpio)]); } /* set GPIO pin 'gpio' output bit as 0 or 1 as per 'high' */ -static void set_level(unsigned gpio, int high) +static void set_level(struct tegra_port_info *state, int offset, int high) { - struct gpio_ctlr *ctlr = (struct gpio_ctlr *)NV_PA_GPIO_BASE; - struct gpio_ctlr_bank *bank = &ctlr->gpio_bank[GPIO_BANK(gpio)]; + int gpio = GPIO_NUM(state, offset); u32 u; - debug("set_level: port = %d, bit %d == %d\n", - GPIO_FULLPORT(gpio), GPIO_BIT(gpio), high); + debug("%s: port = %d, bit %d == %d\n", __func__, + GPIO_FULLPORT(gpio), GPIO_BIT(gpio), high); - u = readl(&bank->gpio_out[GPIO_PORT(gpio)]); + u = readl(&state->bank->gpio_out[GPIO_PORT(gpio)]); if (high) u |= 1 << GPIO_BIT(gpio); else u &= ~(1 << GPIO_BIT(gpio)); - writel(u, &bank->gpio_out[GPIO_PORT(gpio)]); + writel(u, &state->bank->gpio_out[GPIO_PORT(gpio)]); +} + +/* read GPIO OUT value of pin 'gpio' */ +static int get_output_value(struct tegra_port_info *state, int offset) +{ + int gpio = GPIO_NUM(state, offset); + int val; + + debug("gpio_get_output_value: pin = %d (port %d:bit %d)\n", + gpio, GPIO_FULLPORT(gpio), GPIO_BIT(gpio)); + + val = readl(&state->bank->gpio_out[GPIO_PORT(gpio)]); + + return (val >> GPIO_BIT(gpio)) & 1; } +#ifdef CONFIG_SPL +/* set GPIO pin 'gpio' as an output, with polarity 'value' */ +int tegra_spl_gpio_direction_output(int gpio, int value) +{ + struct gpio_ctlr *ctlr = (struct gpio_ctlr *)NV_PA_GPIO_BASE; + struct tegra_port_info state; + + state.bank = &ctlr->gpio_bank[GPIO_BANK(gpio)]; + state.base_port = GPIO_FULLPORT(gpio); + + /* Configure GPIO output value. */ + set_level(&state, GPIO_BIT(gpio), value); + + /* Configure GPIO direction as output. */ + set_direction(&state, GPIO_BIT(gpio), value); + + return 0; +} +#endif /* CONFIG_SPL */ + /* * Generic_GPIO primitives. */ -int gpio_request(unsigned gpio, const char *label) +static int check_reserved(struct device *dev, unsigned offset, + const char *func) { - if (gpio >= MAX_NUM_GPIOS) - return -1; + struct tegra_port_info *state = dev_get_priv(dev); + struct gpio_dev_priv *uc_priv = dev->uclass_priv; - if (label != NULL) { - strncpy(gpio_names[gpio].name, label, GPIO_NAME_SIZE); - gpio_names[gpio].name[GPIO_NAME_SIZE - 1] = '\0'; + if (!*state->label[offset]) { + printf("tegra_gpio: %s: error: gpio %s%d not reserved\n", + func, uc_priv->bank_name, offset); + return -EPERM; } - /* Configure as a GPIO */ - set_config(gpio, 1); - return 0; } -int gpio_free(unsigned gpio) +static int tegra_gpio_request(struct device *dev, unsigned offset, + const char *label) { - if (gpio >= MAX_NUM_GPIOS) - return -1; + struct tegra_port_info *state = dev_get_priv(dev); + + if (*state->label[offset]) + return -EBUSY; + + strncpy(state->label[offset], label, GPIO_NAME_SIZE); + state->label[offset][GPIO_NAME_SIZE - 1] = '\0'; + + /* Configure as a GPIO */ + set_config(state, offset, 1); - gpio_names[gpio].name[0] = '\0'; - /* Do not configure as input or change pin mux here */ return 0; } -/* read GPIO OUT value of pin 'gpio' */ -static int gpio_get_output_value(unsigned gpio) +static int tegra_gpio_free(struct device *dev, unsigned offset) { - struct gpio_ctlr *ctlr = (struct gpio_ctlr *)NV_PA_GPIO_BASE; - struct gpio_ctlr_bank *bank = &ctlr->gpio_bank[GPIO_BANK(gpio)]; - int val; - - debug("gpio_get_output_value: pin = %d (port %d:bit %d)\n", - gpio, GPIO_FULLPORT(gpio), GPIO_BIT(gpio)); + struct tegra_port_info *state = dev_get_priv(dev); + int ret; - val = readl(&bank->gpio_out[GPIO_PORT(gpio)]); + ret = check_reserved(dev, offset, __func__); + if (ret) + return ret; + state->label[offset][0] = '\0'; - return (val >> GPIO_BIT(gpio)) & 1; + return 0; } /* set GPIO pin 'gpio' as an input */ -int gpio_direction_input(unsigned gpio) +static int tegra_gpio_direction_input(struct device *dev, unsigned offset) { - debug("gpio_direction_input: pin = %d (port %d:bit %d)\n", - gpio, GPIO_FULLPORT(gpio), GPIO_BIT(gpio)); + struct tegra_port_info *state = dev_get_priv(dev); + int ret; + + ret = check_reserved(dev, offset, __func__); + if (ret) + return ret; /* Configure GPIO direction as input. */ - set_direction(gpio, 0); + set_direction(state, offset, 0); return 0; } /* set GPIO pin 'gpio' as an output, with polarity 'value' */ -int gpio_direction_output(unsigned gpio, int value) +static int tegra_gpio_direction_output(struct device *dev, unsigned offset, + int value) { - debug("gpio_direction_output: pin = %d (port %d:bit %d) = %s\n", - gpio, GPIO_FULLPORT(gpio), GPIO_BIT(gpio), - value ? "HIGH" : "LOW"); + struct tegra_port_info *state = dev_get_priv(dev); + int ret; + + ret = check_reserved(dev, offset, __func__); + if (ret) + return ret; /* Configure GPIO output value. */ - set_level(gpio, value); + set_level(state, offset, value); /* Configure GPIO direction as output. */ - set_direction(gpio, 1); + set_direction(state, offset, 1); return 0; } /* read GPIO IN value of pin 'gpio' */ -int gpio_get_value(unsigned gpio) +static int tegra_gpio_get_value(struct device *dev, unsigned offset) { - struct gpio_ctlr *ctlr = (struct gpio_ctlr *)NV_PA_GPIO_BASE; - struct gpio_ctlr_bank *bank = &ctlr->gpio_bank[GPIO_BANK(gpio)]; + struct tegra_port_info *state = dev_get_priv(dev); + int gpio = GPIO_NUM(state, offset); + int ret; int val; - debug("gpio_get_value: pin = %d (port %d:bit %d)\n", - gpio, GPIO_FULLPORT(gpio), GPIO_BIT(gpio)); + ret = check_reserved(dev, offset, __func__); + if (ret) + return ret; + + debug("%s: pin = %d (port %d:bit %d)\n", __func__, + gpio, GPIO_FULLPORT(gpio), GPIO_BIT(gpio)); - val = readl(&bank->gpio_in[GPIO_PORT(gpio)]); + val = readl(&state->bank->gpio_in[GPIO_PORT(gpio)]); return (val >> GPIO_BIT(gpio)) & 1; } /* write GPIO OUT value to pin 'gpio' */ -int gpio_set_value(unsigned gpio, int value) +static int tegra_gpio_set_value(struct device *dev, unsigned offset, int value) { + struct tegra_port_info *state = dev_get_priv(dev); + int gpio = GPIO_NUM(state, offset); + int ret; + + ret = check_reserved(dev, offset, __func__); + if (ret) + return ret; + debug("gpio_set_value: pin = %d (port %d:bit %d), value = %d\n", - gpio, GPIO_FULLPORT(gpio), GPIO_BIT(gpio), value); + gpio, GPIO_FULLPORT(gpio), GPIO_BIT(gpio), value); /* Configure GPIO output value. */ - set_level(gpio, value); + set_level(state, offset, value); return 0; } -/* - * Display Tegra GPIO information +static int tegra_gpio_get_state(struct device *dev, unsigned int offset, + char *buf, int bufsize) +{ + struct gpio_dev_priv *uc_priv = dev->uclass_priv; + struct tegra_port_info *state = dev_get_priv(dev); + const char *label; + int is_output; + int is_gpio; + int size; + + label = state->label[offset]; + is_gpio = get_config(state, offset); /* GPIO, not SFPIO */ + size = snprintf(buf, bufsize, "%s%d: ", + uc_priv->bank_name ? uc_priv->bank_name : "", offset); + buf += size; + bufsize -= size; + if (is_gpio) { + is_output = get_direction(state, offset); + + snprintf(buf, bufsize, "%s: %d [%c]%s%s", + is_output ? "out" : " in", + is_output ? + get_output_value(state, offset) : + tegra_gpio_get_value(dev, offset), + *label ? 'x' : ' ', + *label ? " " : "", + label); + } else { + snprintf(buf, bufsize, "sfpio"); + } + + return 0; +} + +static const struct dm_gpio_ops gpio_tegra_ops = { + .request = tegra_gpio_request, + .free = tegra_gpio_free, + .direction_input = tegra_gpio_direction_input, + .direction_output = tegra_gpio_direction_output, + .get_value = tegra_gpio_get_value, + .set_value = tegra_gpio_set_value, + .get_state = tegra_gpio_get_state, +}; + +/** + * Returns the name of a GPIO port + * + * GPIOs are named A, B, C, ..., Z, AA, BB, CC, ... + * + * @base_port: Base port number (0, 1..n-1) + * @return allocated string containing the name */ -void gpio_info(void) +static char *gpio_port_name(int base_port) { - unsigned c; - int type; + char *name, *s; + + name = malloc(3); + if (name) { + s = name; + *s++ = 'A' + (base_port % 26); + if (base_port >= 26) + *s++ = *name; + *s = '\0'; + } + + return name; +} + +static const struct device_id tegra_gpio_ids[] = { + { .compatible = "nvidia,tegra30-gpio" }, + { .compatible = "nvidia,tegra20-gpio" }, + { } +}; + +static int gpio_tegra_probe(struct device *dev) +{ + struct gpio_dev_priv *uc_priv = dev->uclass_priv; + struct tegra_port_info *priv = dev->priv; + struct tegra_gpio_platdata *plat = dev->platdata; + + /* Only child devices have ports */ + if (!plat) + return 0; + + priv->bank = plat->bank; + priv->base_port = plat->base_port; - for (c = 0; c < MAX_NUM_GPIOS; c++) { - type = get_config(c); /* GPIO, not SFPIO */ - if (type) { - printf("GPIO_%d:\t%s is an %s, ", c, - get_name(c), - get_direction(c) ? "OUTPUT" : "INPUT"); - if (get_direction(c)) - printf("value = %d", gpio_get_output_value(c)); - else - printf("value = %d", gpio_get_value(c)); - printf("\n"); - } else - continue; + uc_priv->gpio_count = TEGRA_GPIOS_PER_PORT; + uc_priv->bank_name = plat->port_name; + + return 0; +} + +/** + * We have a top-level GPIO device with no actual GPIOs. It has a child + * device for each Tegra port. + */ +static int gpio_tegra_bind(struct device *parent) +{ + struct tegra_gpio_platdata *plat = parent->platdata; + struct gpio_ctlr *ctlr; + int bank_count; + int bank; + int ret; + int len; + + /* If this is a child device, there is nothing to do here */ + if (plat) + return 0; + + /* + * This driver does not make use of interrupts, other than to figure + * out the number of GPIO banks + */ + if (!fdt_getprop(gd->fdt_blob, parent->of_offset, "interrupts", &len)) + return -EINVAL; + bank_count = len / 3 / sizeof(u32); + ctlr = (struct gpio_ctlr *)fdtdec_get_addr(gd->fdt_blob, + parent->of_offset, "reg"); + for (bank = 0; bank < bank_count; bank++) { + int port; + + for (port = 0; port < TEGRA_PORTS_PER_BANK; port++) { + struct tegra_gpio_platdata *plat; + struct device *dev; + + plat = calloc(1, sizeof(*plat)); + if (!plat) + return -ENOMEM; + plat->bank = &ctlr->gpio_bank[bank]; + plat->base_port = bank * TEGRA_PORTS_PER_BANK + port; + plat->port_name = gpio_port_name(plat->base_port); + + ret = device_bind(parent, parent->driver, + plat->port_name, plat, -1, &dev); + if (ret) + return ret; + dev->of_offset = parent->of_offset; + } } + + return 0; } + +U_BOOT_DRIVER(gpio_tegra) = { + .name = "gpio_tegra", + .id = UCLASS_GPIO, + .of_match = tegra_gpio_ids, + .bind = gpio_tegra_bind, + .probe = gpio_tegra_probe, + .priv_auto_alloc_size = sizeof(struct tegra_port_info), + .ops = &gpio_tegra_ops, +}; diff --git a/include/configs/tegra-common.h b/include/configs/tegra-common.h index 3943249..7222ba6 100644 --- a/include/configs/tegra-common.h +++ b/include/configs/tegra-common.h @@ -20,6 +20,8 @@ #include /* get chip and board defs */ #define CONFIG_DM +#define CONFIG_DM_GPIO +#define CONFIG_CMD_DM #define CONFIG_SYS_TIMER_RATE 1000000 #define CONFIG_SYS_TIMER_COUNTER NV_PA_TMRUS_BASE