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

Reply via email to