Signed-off-by: Tom Warren <twar...@nvidia.com> --- Changes in V2: - use 'gpio_pin' enum in gpio.h (Simon Glass review request) - change 'GPIO_PORT8' to 'GPIO_FULLPORT' (Simon Glass request) - change 'offset' to 'pin' globally
arch/arm/include/asm/arch-tegra2/gpio.h | 244 ++++++++++++++++++++++++- drivers/gpio/Makefile | 1 + drivers/gpio/tegra2_gpio.c | 299 +++++++++++++++++++++++++++++++ 3 files changed, 537 insertions(+), 7 deletions(-) create mode 100644 drivers/gpio/tegra2_gpio.c diff --git a/arch/arm/include/asm/arch-tegra2/gpio.h b/arch/arm/include/asm/arch-tegra2/gpio.h index 0fb8f0d..e55305a 100644 --- a/arch/arm/include/asm/arch-tegra2/gpio.h +++ b/arch/arm/include/asm/arch-tegra2/gpio.h @@ -45,15 +45,245 @@ struct gpio_ctlr { struct gpio_ctlr_bank gpio_bank[TEGRA_GPIO_BANKS]; }; -#define GPIO_BANK(x) ((x) >> 5) -#define GPIO_PORT(x) (((x) >> 3) & 0x3) -#define GPIO_BIT(x) ((x) & 0x7) +#define GPIO_BANK(x) ((x) >> 5) +#define GPIO_PORT(x) (((x) >> 3) & 0x3) +#define GPIO_FULLPORT(x) ((x) >> 3) +#define GPIO_BIT(x) ((x) & 0x7) + +enum gpio_pin { + GPIO_PA0 = 0, /* pin 0 */ + GPIO_PA1, + GPIO_PA2, + GPIO_PA3, + GPIO_PA4, + GPIO_PA5, + GPIO_PA6, + GPIO_PA7, + GPIO_PB0, /* pin 8 */ + GPIO_PB1, + GPIO_PB2, + GPIO_PB3, + GPIO_PB4, + GPIO_PB5, + GPIO_PB6, + GPIO_PB7, + GPIO_PC0, /* pin 16 */ + GPIO_PC1, + GPIO_PC2, + GPIO_PC3, + GPIO_PC4, + GPIO_PC5, + GPIO_PC6, + GPIO_PC7, + GPIO_PD0, /* pin 24 */ + GPIO_PD1, + GPIO_PD2, + GPIO_PD3, + GPIO_PD4, + GPIO_PD5, + GPIO_PD6, + GPIO_PD7, + GPIO_PE0, /* pin 32 */ + GPIO_PE1, + GPIO_PE2, + GPIO_PE3, + GPIO_PE4, + GPIO_PE5, + GPIO_PE6, + GPIO_PE7, + GPIO_PF0, /* pin 40 */ + GPIO_PF1, + GPIO_PF2, + GPIO_PF3, + GPIO_PF4, + GPIO_PF5, + GPIO_PF6, + GPIO_PF7, + GPIO_PG0, /* pin 48 */ + GPIO_PG1, + GPIO_PG2, + GPIO_PG3, + GPIO_PG4, + GPIO_PG5, + GPIO_PG6, + GPIO_PG7, + GPIO_PH0, /* pin 56 */ + GPIO_PH1, + GPIO_PH2, + GPIO_PH3, + GPIO_PH4, + GPIO_PH5, + GPIO_PH6, + GPIO_PH7, + GPIO_PI0, /* pin 64 */ + GPIO_PI1, + GPIO_PI2, + GPIO_PI3, + GPIO_PI4, + GPIO_PI5, + GPIO_PI6, + GPIO_PI7, + GPIO_PJ0, /* pin 72 */ + GPIO_PJ1, + GPIO_PJ2, + GPIO_PJ3, + GPIO_PJ4, + GPIO_PJ5, + GPIO_PJ6, + GPIO_PJ7, + GPIO_PK0, /* pin 80 */ + GPIO_PK1, + GPIO_PK2, + GPIO_PK3, + GPIO_PK4, + GPIO_PK5, + GPIO_PK6, + GPIO_PK7, + GPIO_PL0, /* pin 88 */ + GPIO_PL1, + GPIO_PL2, + GPIO_PL3, + GPIO_PL4, + GPIO_PL5, + GPIO_PL6, + GPIO_PL7, + GPIO_PM0, /* pin 96 */ + GPIO_PM1, + GPIO_PM2, + GPIO_PM3, + GPIO_PM4, + GPIO_PM5, + GPIO_PM6, + GPIO_PM7, + GPIO_PN0, /* pin 104 */ + GPIO_PN1, + GPIO_PN2, + GPIO_PN3, + GPIO_PN4, + GPIO_PN5, + GPIO_PN6, + GPIO_PN7, + GPIO_PO0, /* pin 112 */ + GPIO_PO1, + GPIO_PO2, + GPIO_PO3, + GPIO_PO4, + GPIO_PO5, + GPIO_PO6, + GPIO_PO7, + GPIO_PP0, /* pin 120 */ + GPIO_PP1, + GPIO_PP2, + GPIO_PP3, + GPIO_PP4, + GPIO_PP5, + GPIO_PP6, + GPIO_PP7, + GPIO_PQ0, /* pin 128 */ + GPIO_PQ1, + GPIO_PQ2, + GPIO_PQ3, + GPIO_PQ4, + GPIO_PQ5, + GPIO_PQ6, + GPIO_PQ7, + GPIO_PR0, /* pin 136 */ + GPIO_PR1, + GPIO_PR2, + GPIO_PR3, + GPIO_PR4, + GPIO_PR5, + GPIO_PR6, + GPIO_PR7, + GPIO_PS0, /* pin 144 */ + GPIO_PS1, + GPIO_PS2, + GPIO_PS3, + GPIO_PS4, + GPIO_PS5, + GPIO_PS6, + GPIO_PS7, + GPIO_PT0, /* pin 152 */ + GPIO_PT1, + GPIO_PT2, + GPIO_PT3, + GPIO_PT4, + GPIO_PT5, + GPIO_PT6, + GPIO_PT7, + GPIO_PU0, /* pin 160 */ + GPIO_PU1, + GPIO_PU2, + GPIO_PU3, + GPIO_PU4, + GPIO_PU5, + GPIO_PU6, + GPIO_PU7, + GPIO_PV0, /* pin 168 */ + GPIO_PV1, + GPIO_PV2, + GPIO_PV3, + GPIO_PV4, + GPIO_PV5, + GPIO_PV6, + GPIO_PV7, + GPIO_PW0, /* pin 176 */ + GPIO_PW1, + GPIO_PW2, + GPIO_PW3, + GPIO_PW4, + GPIO_PW5, + GPIO_PW6, + GPIO_PW7, + GPIO_PX0, /* pin 184 */ + GPIO_PX1, + GPIO_PX2, + GPIO_PX3, + GPIO_PX4, + GPIO_PX5, + GPIO_PX6, + GPIO_PX7, + GPIO_PY0, /* pin 192 */ + GPIO_PY1, + GPIO_PY2, + GPIO_PY3, + GPIO_PY4, + GPIO_PY5, + GPIO_PY6, + GPIO_PY7, + GPIO_PZ0, /* pin 200 */ + GPIO_PZ1, + GPIO_PZ2, + GPIO_PZ3, + GPIO_PZ4, + GPIO_PZ5, + GPIO_PZ6, + GPIO_PZ7, + GPIO_PAA0, /* pin 208 */ + GPIO_PAA1, + GPIO_PAA2, + GPIO_PAA3, + GPIO_PAA4, + GPIO_PAA5, + GPIO_PAA6, + GPIO_PAA7, + GPIO_PBB0, /* pin 216 */ + GPIO_PBB1, + GPIO_PBB2, + GPIO_PBB3, + GPIO_PBB4, + GPIO_PBB5, + GPIO_PBB6, + GPIO_PBB7, /* pin 223 */ +}; /* - * GPIO_PI3 = Port I = 8, bit = 3. - * Seaboard: used for UART/SPI selection - * Harmony: not used + * Tegra2-specific GPIO API */ -#define GPIO_PI3 ((8 << 3) | 3) + +int gpio_direction_input(int gp); +int gpio_direction_output(int gp, int value); +int gpio_get_value(int gp); +void gpio_set_value(int gp, int value); #endif /* TEGRA2_GPIO_H_ */ diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index a5fa2b5..1e3ae11 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -31,6 +31,7 @@ COBJS-$(CONFIG_MARVELL_MFP) += mvmfp.o COBJS-$(CONFIG_MXC_GPIO) += mxc_gpio.o COBJS-$(CONFIG_PCA953X) += pca953x.o COBJS-$(CONFIG_S5P) += s5p_gpio.o +COBJS-$(CONFIG_TEGRA2_GPIO) += tegra2_gpio.o COBJS := $(COBJS-y) SRCS := $(COBJS:.o=.c) diff --git a/drivers/gpio/tegra2_gpio.c b/drivers/gpio/tegra2_gpio.c new file mode 100644 index 0000000..9090579 --- /dev/null +++ b/drivers/gpio/tegra2_gpio.c @@ -0,0 +1,299 @@ +/* + * NVIDIA Tegra2 GPIO handling. + * (C) Copyright 2010,2011 + * NVIDIA Corporation <www.nvidia.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* + * Based on (mostly copied from) kw_gpio.c based Linux 2.6 kernel driver. + * Tom Warren (twar...@nvidia.com) + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/bitops.h> +#include <asm/arch/tegra2.h> +#include <asm/arch/gpio.h> + +enum { + TEGRA2_CMD_INFO, + TEGRA2_CMD_PORT, + TEGRA2_CMD_OUTPUT, + TEGRA2_CMD_INPUT, +}; + +/* Config pin 'gp' as GPIO or SFPIO, based on 'type' */ +void __set_config(int gp, int type) +{ + struct gpio_ctlr *gpio = (struct gpio_ctlr *)NV_PA_GPIO_BASE; + struct gpio_ctlr_bank *bank = &gpio->gpio_bank[GPIO_BANK(gp)]; + u32 u; + + debug("__set_config: port = %d, bit = %d, %s\n", + GPIO_FULLPORT(gp), GPIO_BIT(gp), type ? "GPIO" : "SFPIO"); + + u = readl(&bank->gpio_config[GPIO_PORT(gp)]); + if (type) /* GPIO */ + u |= 1 << GPIO_BIT(gp); + else + u &= ~(1 << GPIO_BIT(gp)); + writel(u, &bank->gpio_config[GPIO_PORT(gp)]); +} + +/* Config GPIO pin 'gp' as input or output (OE) as per 'output' */ +void __set_direction(int gp, int output) +{ + struct gpio_ctlr *gpio = (struct gpio_ctlr *)NV_PA_GPIO_BASE; + struct gpio_ctlr_bank *bank = &gpio->gpio_bank[GPIO_BANK(gp)]; + u32 u; + + debug("__set_direction: port = %d, bit = %d, %s\n", + GPIO_FULLPORT(gp), GPIO_BIT(gp), output ? "OUT" : "IN"); + + u = readl(&bank->gpio_dir_out[GPIO_PORT(gp)]); + if (output) + u |= 1 << GPIO_BIT(gp); + else + u &= ~(1 << GPIO_BIT(gp)); + writel(u, &bank->gpio_dir_out[GPIO_PORT(gp)]); +} + +/* set GPIO pin 'gp' output bit as 0 or 1 as per 'high' */ +void __set_level(int gp, int high) +{ + struct gpio_ctlr *gpio = (struct gpio_ctlr *)NV_PA_GPIO_BASE; + struct gpio_ctlr_bank *bank = &gpio->gpio_bank[GPIO_BANK(gp)]; + u32 u; + + debug("__set_level: port = %d, bit %d == %d\n", + GPIO_FULLPORT(gp), GPIO_BIT(gp), high); + + u = readl(&bank->gpio_out[GPIO_PORT(gp)]); + if (high) + u |= 1 << GPIO_BIT(gp); + else + u &= ~(1 << GPIO_BIT(gp)); + writel(u, &bank->gpio_out[GPIO_PORT(gp)]); +} + +/* + * GENERIC_GPIO primitives. + */ + +/* set GPIO pin 'gp' as an input */ +int gpio_direction_input(int gp) +{ + debug("gpio_direction_input: pin = %d (port %d:bit %d)\n", + gp, GPIO_FULLPORT(gp), GPIO_BIT(gp)); + + /* Configure as a GPIO */ + __set_config(gp, 1); + + /* Configure GPIO direction as input. */ + __set_direction(gp, 0); + + return 0; +} + +/* set GPIO pin 'gp' as an output, with polarity 'value' */ +int gpio_direction_output(int gp, int value) +{ + debug("gpio_direction_output: pin = %d (port %d:bit %d) = %s\n", + gp, GPIO_FULLPORT(gp), GPIO_BIT(gp), value ? "HIGH" : "LOW"); + + /* Configure as a GPIO */ + __set_config(gp, 1); + + /* Configure GPIO output value. */ + __set_level(gp, value); + + /* Configure GPIO direction as output. */ + __set_direction(gp, 1); + + return 0; +} + +/* read GPIO IN value of pin 'gp' */ +int gpio_get_value(int gp) +{ + struct gpio_ctlr *gpio = (struct gpio_ctlr *)NV_PA_GPIO_BASE; + struct gpio_ctlr_bank *bank = &gpio->gpio_bank[GPIO_BANK(gp)]; + int val; + + debug("gpio_get_value: pin = %d (port %d:bit %d)\n", + gp, GPIO_FULLPORT(gp), GPIO_BIT(gp)); + + val = readl(&bank->gpio_in[GPIO_PORT(gp)]); + + return (val >> GPIO_BIT(gp)) & 1; +} + +/* write GPIO OUT value to pin 'gp' */ +void gpio_set_value(int gp, int value) +{ + debug("gpio_set_value: pin = %d (port %d:bit %d), value = %d\n", + gp, GPIO_FULLPORT(gp), GPIO_BIT(gp), value); + + /* Configure GPIO output value. */ + __set_level(gp, value); +} + +#ifdef CONFIG_CMD_TEGRA2_GPIO_INFO +/* + * Display Tegra GPIO information + */ +static int gpio_info(int gp) +{ + struct gpio_ctlr *gpio = (struct gpio_ctlr *)NV_PA_GPIO_BASE; + struct gpio_ctlr_bank *bank = &gpio->gpio_bank[GPIO_BANK(gp)]; + int i, port; + u32 data; + + port = GPIO_FULLPORT(gp); /* 8-bit port # */ + + printf("Tegra2 GPIO port %d:\n\n", port); + printf("gpio bits: 76543210\n"); + printf("-------------------\n"); + + if (port < 0 || port > 27) + return -1; + + printf("GPIO_CNF: "); + data = readl(&bank->gpio_config[GPIO_PORT(gp)]); + for (i = 7; i >= 0; i--) + printf("%c", data & (1 << i) ? 'g' : 's'); + printf("\n"); + + printf("GPIO_OE: "); + data = readl(&bank->gpio_dir_out[GPIO_PORT(gp)]); + for (i = 7; i >= 0; i--) + printf("%c", data & (1 << i) ? 'o' : 'i'); + printf("\n"); + + printf("GPIO_IN: "); + data = readl(&bank->gpio_in[GPIO_PORT(gp)]); + for (i = 7; i >= 0; i--) + printf("%c", data & (1 << i) ? '1' : '0'); + printf("\n"); + + printf("GPIO_OUT: "); + data = readl(&bank->gpio_out[GPIO_PORT(gp)]); + for (i = 7; i >= 0; i--) + printf("%c", data & (1 << i) ? '1' : '0'); + printf("\n"); + + return 0; +} +#endif /* CONFIG_CMD_TEGRA2_GPIO_INFO */ + +cmd_tbl_t cmd_gpio[] = { + U_BOOT_CMD_MKENT(pin2port, 3, 0, (void *)TEGRA2_CMD_PORT, "", ""), + U_BOOT_CMD_MKENT(output, 4, 0, (void *)TEGRA2_CMD_OUTPUT, "", ""), + U_BOOT_CMD_MKENT(input, 3, 0, (void *)TEGRA2_CMD_INPUT, "", ""), +#ifdef CONFIG_CMD_TEGRA2_GPIO_INFO + U_BOOT_CMD_MKENT(info, 3, 0, (void *)TEGRA2_CMD_INFO, "", ""), +#endif +}; + +int do_gpio(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + static uint8_t pin; + int val, port, bit; + ulong ul_arg2, ul_arg3, ul_arg4; + cmd_tbl_t *c; + + ul_arg2 = ul_arg3 = ul_arg4 = 0; + + c = find_cmd_tbl(argv[1], cmd_gpio, ARRAY_SIZE(cmd_gpio)); + + /* All commands but "port" require 'maxargs' arguments */ + if (!c || !((argc == (c->maxargs)) || + (((int)c->cmd == TEGRA2_CMD_PORT) && + (argc == (c->maxargs - 1))))) { + cmd_usage(cmdtp); + return 1; + } + + /* arg2 used as pin */ + if (argc > 2) + ul_arg2 = simple_strtoul(argv[2], NULL, 10); + + /* arg3 used as output value, 0 or 1 */ + if (argc > 3) + ul_arg3 = simple_strtoul(argv[3], NULL, 10) & 0x1; + + switch ((int)c->cmd) { +#ifdef CONFIG_CMD_TEGRA2_GPIO_INFO + case TEGRA2_CMD_INFO: + if (argc == 3) + pin = (uint8_t)ul_arg2; + return gpio_info(pin); + +#endif + case TEGRA2_CMD_PORT: + if (argc == 3) + pin = (uint8_t)ul_arg2; + port = GPIO_FULLPORT(pin); + bit = GPIO_BIT(pin); + printf("pin %d = port # %d, bit # %d\n", + pin, port, bit); + return 0; + + case TEGRA2_CMD_INPUT: + /* arg2 = pin */ + port = GPIO_FULLPORT(pin); + bit = GPIO_BIT(pin); + gpio_direction_input(ul_arg2); + val = gpio_get_value(ul_arg2); + + printf("pin %lu (port:bit %d:%d) = %d\n", + ul_arg2, port, bit, val); + return 0; + + case TEGRA2_CMD_OUTPUT: + /* args = pin, value */ + port = GPIO_FULLPORT(pin); + bit = GPIO_BIT(pin); + gpio_direction_output(ul_arg2, ul_arg3); + printf("pin %lu (port:bit %d:%d) = %ld\n", + ul_arg2, port, bit, ul_arg3); + return 0; + + default: + /* We should never get here */ + return 1; + } +} + +U_BOOT_CMD( + gpio, 5, 1, do_gpio, + "GPIO access", + "pin2port pin\n" + " - show GPIO port:bit based on 'pin'\n" +#ifdef CONFIG_CMD_TEGRA2_GPIO_INFO + " info pin\n" + " - display info for all bits in port based on 'pin'\n" +#endif + " output pin 0|1\n" + " - using 'pin', set port:bit as output and drive low or high\n" + " input pin\n" + " - using 'pin', set port:bit as input and read value" +); -- 1.7.5 _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot