X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=drivers%2Fgpio%2Ftegra_gpio.c;h=8e880e276f0a9915a22095b043820996e3a32c81;hb=6d846c726b300fcb4e5b9228709e6752459e7553;hp=1cc4abb8a938b16ccc1322a6adcc903bc064b299;hpb=2a8c9c86b92a9ccee3c27286de317e19bb0530b3;p=u-boot diff --git a/drivers/gpio/tegra_gpio.c b/drivers/gpio/tegra_gpio.c index 1cc4abb8a9..8e880e276f 100644 --- a/drivers/gpio/tegra_gpio.c +++ b/drivers/gpio/tegra_gpio.c @@ -1,6 +1,6 @@ /* * NVIDIA Tegra20 GPIO handling. - * (C) Copyright 2010-2012 + * (C) Copyright 2010-2012,2015 * NVIDIA Corporation * * SPDX-License-Identifier: GPL-2.0+ @@ -21,15 +21,14 @@ #include #include #include +#include DECLARE_GLOBAL_DATA_PTR; -enum { - TEGRA_CMD_INFO, - TEGRA_CMD_PORT, - TEGRA_CMD_OUTPUT, - TEGRA_CMD_INPUT, -}; +static const int CONFIG_SFIO = 0; +static const int CONFIG_GPIO = 1; +static const int DIRECTION_INPUT = 0; +static const int DIRECTION_OUTPUT = 1; struct tegra_gpio_platdata { struct gpio_ctlr_bank *bank; @@ -39,12 +38,11 @@ struct tegra_gpio_platdata { /* 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_gpio; /* Port number for this port (0, 1,.., n-1) */ }; -/* Return config of pin 'gpio' as GPIO (1) or SFPIO (0) */ +/* Return config of pin 'gpio' as GPIO (1) or SFIO (0) */ static int get_config(unsigned gpio) { struct gpio_ctlr *ctlr = (struct gpio_ctlr *)NV_PA_GPIO_BASE; @@ -53,15 +51,15 @@ static int get_config(unsigned gpio) int type; u = readl(&bank->gpio_config[GPIO_PORT(gpio)]); - type = (u >> GPIO_BIT(gpio)) & 1; + type = (u >> GPIO_BIT(gpio)) & 1; debug("get_config: port = %d, bit = %d is %s\n", GPIO_FULLPORT(gpio), GPIO_BIT(gpio), type ? "GPIO" : "SFPIO"); - return type; + return type ? CONFIG_GPIO : CONFIG_SFIO; } -/* Config pin 'gpio' as GPIO or SFPIO, based on 'type' */ +/* Config pin 'gpio' as GPIO or SFIO, based on 'type' */ static void set_config(unsigned gpio, int type) { struct gpio_ctlr *ctlr = (struct gpio_ctlr *)NV_PA_GPIO_BASE; @@ -72,7 +70,7 @@ static void set_config(unsigned gpio, int type) GPIO_FULLPORT(gpio), GPIO_BIT(gpio), type ? "GPIO" : "SFPIO"); u = readl(&bank->gpio_config[GPIO_PORT(gpio)]); - if (type) /* GPIO */ + if (type != CONFIG_SFIO) u |= 1 << GPIO_BIT(gpio); else u &= ~(1 << GPIO_BIT(gpio)); @@ -93,7 +91,7 @@ static int get_direction(unsigned gpio) debug("get_direction: port = %d, bit = %d, %s\n", GPIO_FULLPORT(gpio), GPIO_BIT(gpio), dir ? "OUT" : "IN"); - return dir; + return dir ? DIRECTION_OUTPUT : DIRECTION_INPUT; } /* Config GPIO pin 'gpio' as input or output (OE) as per 'output' */ @@ -107,7 +105,7 @@ static void set_direction(unsigned gpio, int output) GPIO_FULLPORT(gpio), GPIO_BIT(gpio), output ? "OUT" : "IN"); u = readl(&bank->gpio_dir_out[GPIO_PORT(gpio)]); - if (output) + if (output != DIRECTION_INPUT) u |= 1 << GPIO_BIT(gpio); else u &= ~(1 << GPIO_BIT(gpio)); @@ -132,98 +130,20 @@ static void set_level(unsigned gpio, int high) writel(u, &bank->gpio_out[GPIO_PORT(gpio)]); } -static int check_reserved(struct udevice *dev, unsigned offset, - const char *func) -{ - struct tegra_port_info *state = dev_get_priv(dev); - struct gpio_dev_priv *uc_priv = dev->uclass_priv; - - if (!*state->label[offset]) { - printf("tegra_gpio: %s: error: gpio %s%d not reserved\n", - func, uc_priv->bank_name, offset); - return -EBUSY; - } - - return 0; -} - -/* set GPIO pin 'gpio' as an output, with polarity 'value' */ -int tegra_spl_gpio_direction_output(int gpio, int value) -{ - /* Configure as a GPIO */ - set_config(gpio, 1); - - /* Configure GPIO output value. */ - set_level(gpio, value); - - /* Configure GPIO direction as output. */ - set_direction(gpio, 1); - - return 0; -} - /* * Generic_GPIO primitives. */ -static int tegra_gpio_request(struct udevice *dev, unsigned offset, - const char *label) -{ - 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->base_gpio + offset, 1); - - return 0; -} - -static int tegra_gpio_free(struct udevice *dev, unsigned offset) -{ - struct tegra_port_info *state = dev_get_priv(dev); - int ret; - - ret = check_reserved(dev, offset, __func__); - if (ret) - return ret; - state->label[offset][0] = '\0'; - - return 0; -} - -/* read GPIO OUT value of pin 'gpio' */ -static int tegra_gpio_get_output_value(unsigned gpio) -{ - 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)); - - val = readl(&bank->gpio_out[GPIO_PORT(gpio)]); - - return (val >> GPIO_BIT(gpio)) & 1; -} - - /* set GPIO pin 'gpio' as an input */ static int tegra_gpio_direction_input(struct udevice *dev, unsigned offset) { 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(state->base_gpio + offset, 0); + set_direction(state->base_gpio + offset, DIRECTION_INPUT); + + /* Enable the pin as a GPIO */ + set_config(state->base_gpio + offset, 1); return 0; } @@ -234,17 +154,15 @@ static int tegra_gpio_direction_output(struct udevice *dev, unsigned offset, { struct tegra_port_info *state = dev_get_priv(dev); int gpio = state->base_gpio + offset; - int ret; - - ret = check_reserved(dev, offset, __func__); - if (ret) - return ret; /* Configure GPIO output value. */ set_level(gpio, value); /* Configure GPIO direction as output. */ - set_direction(gpio, 1); + set_direction(gpio, DIRECTION_OUTPUT); + + /* Enable the pin as a GPIO */ + set_config(state->base_gpio + offset, 1); return 0; } @@ -254,13 +172,8 @@ static int tegra_gpio_get_value(struct udevice *dev, unsigned offset) { struct tegra_port_info *state = dev_get_priv(dev); int gpio = state->base_gpio + offset; - int ret; int val; - 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)); @@ -274,11 +187,6 @@ static int tegra_gpio_set_value(struct udevice *dev, unsigned offset, int value) { struct tegra_port_info *state = dev_get_priv(dev); int gpio = state->base_gpio + 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); @@ -296,16 +204,18 @@ void gpio_config_table(const struct tegra_gpio_config *config, int len) for (i = 0; i < len; i++) { switch (config[i].init) { case TEGRA_GPIO_INIT_IN: - gpio_direction_input(config[i].gpio); + set_direction(config[i].gpio, DIRECTION_INPUT); break; case TEGRA_GPIO_INIT_OUT0: - gpio_direction_output(config[i].gpio, 0); + set_level(config[i].gpio, 0); + set_direction(config[i].gpio, DIRECTION_OUTPUT); break; case TEGRA_GPIO_INIT_OUT1: - gpio_direction_output(config[i].gpio, 1); + set_level(config[i].gpio, 1); + set_direction(config[i].gpio, DIRECTION_OUTPUT); break; } - set_config(config[i].gpio, 1); + set_config(config[i].gpio, CONFIG_GPIO); } } @@ -314,8 +224,6 @@ static int tegra_gpio_get_function(struct udevice *dev, unsigned offset) struct tegra_port_info *state = dev_get_priv(dev); int gpio = state->base_gpio + offset; - if (!*state->label[offset]) - return GPIOF_UNUSED; if (!get_config(gpio)) return GPIOF_FUNC; else if (get_direction(gpio)) @@ -324,50 +232,29 @@ static int tegra_gpio_get_function(struct udevice *dev, unsigned offset) return GPIOF_INPUT; } -static int tegra_gpio_get_state(struct udevice *dev, unsigned int offset, - char *buf, int bufsize) +static int tegra_gpio_xlate(struct udevice *dev, struct gpio_desc *desc, + struct fdtdec_phandle_args *args) { - struct gpio_dev_priv *uc_priv = dev->uclass_priv; - struct tegra_port_info *state = dev_get_priv(dev); - int gpio = state->base_gpio + offset; - const char *label; - int is_output; - int is_gpio; - int size; - - label = state->label[offset]; - is_gpio = get_config(gpio); /* 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(gpio); - - snprintf(buf, bufsize, "%s: %d [%c]%s%s", - is_output ? "out" : " in", - is_output ? - tegra_gpio_get_output_value(gpio) : - tegra_gpio_get_value(dev, offset), - *label ? 'x' : ' ', - *label ? " " : "", - label); - } else { - snprintf(buf, bufsize, "sfpio"); - } + int gpio, port, ret; + + gpio = args->args[0]; + port = gpio / TEGRA_GPIOS_PER_PORT; + ret = device_get_child(dev, port, &desc->dev); + if (ret) + return ret; + desc->offset = gpio % TEGRA_GPIOS_PER_PORT; + desc->flags = args->args[1] & GPIO_ACTIVE_LOW ? GPIOD_ACTIVE_LOW : 0; 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_function = tegra_gpio_get_function, - .get_state = tegra_gpio_get_state, + .xlate = tegra_gpio_xlate, }; /** @@ -402,7 +289,7 @@ static const struct udevice_id tegra_gpio_ids[] = { static int gpio_tegra_probe(struct udevice *dev) { - struct gpio_dev_priv *uc_priv = dev->uclass_priv; + struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); struct tegra_port_info *priv = dev->priv; struct tegra_gpio_platdata *plat = dev->platdata; @@ -430,12 +317,19 @@ static int gpio_tegra_bind(struct udevice *parent) 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; + /* TODO(sjg@chromium.org): Remove once SPL supports device tree */ +#ifdef CONFIG_SPL_BUILD + ctlr = (struct gpio_ctlr *)NV_PA_GPIO_BASE; + bank_count = TEGRA_GPIO_BANKS; +#else + { + int len; + /* * This driver does not make use of interrupts, other than to figure * out the number of GPIO banks @@ -443,8 +337,9 @@ static int gpio_tegra_bind(struct udevice *parent) 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"); + ctlr = (struct gpio_ctlr *)dev_get_addr(parent); + } +#endif for (bank = 0; bank < bank_count; bank++) { int port; @@ -480,4 +375,5 @@ U_BOOT_DRIVER(gpio_tegra) = { .probe = gpio_tegra_probe, .priv_auto_alloc_size = sizeof(struct tegra_port_info), .ops = &gpio_tegra_ops, + .flags = DM_FLAG_PRE_RELOC, };