GPIO: Tegra2: add GPIO driver for Tegra2
authorTom Warren <twarren.nvidia@gmail.com>
Fri, 17 Jun 2011 06:27:28 +0000 (06:27 +0000)
committerAlbert ARIBAUD <albert.u.boot@aribaud.net>
Mon, 4 Jul 2011 08:55:26 +0000 (10:55 +0200)
Signed-off-by: Tom Warren <twarren@nvidia.com>
arch/arm/include/asm/arch-tegra2/gpio.h
arch/arm/include/asm/gpio.h [new file with mode: 0644]
drivers/gpio/Makefile
drivers/gpio/tegra2_gpio.c [new file with mode: 0644]

index 0fb8f0d40f45520083f167f06a6d3c5f86cb834f..41e66fe1b15a4b553cc74d208fc65e633a5b4990 100644 (file)
 #define _TEGRA2_GPIO_H_
 
 /*
- * The Tegra 2x GPIO controller has 222 GPIOs arranged in 8 banks of 4 ports,
+ * The Tegra 2x GPIO controller has 224 GPIOs arranged in 7 banks of 4 ports,
  * each with 8 GPIOs.
  */
-#define TEGRA_GPIO_PORTS 4   /* The number of ports per bank */
-#define TEGRA_GPIO_BANKS 8   /* The number of banks */
+#define TEGRA_GPIO_PORTS       4       /* number of ports per bank */
+#define TEGRA_GPIO_BANKS       7       /* number of banks */
+#define MAX_NUM_GPIOS          (TEGRA_GPIO_PORTS * TEGRA_GPIO_BANKS * 8)
+#define GPIO_NAME_SIZE         20      /* gpio_request max label len */
 
 /* GPIO Controller registers for a single bank */
 struct gpio_ctlr_bank {
@@ -45,15 +47,243 @@ 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)
 
+void gpio_info(void);
+
+#define gpio_status()  gpio_info()
 #endif /* TEGRA2_GPIO_H_ */
diff --git a/arch/arm/include/asm/gpio.h b/arch/arm/include/asm/gpio.h
new file mode 100644 (file)
index 0000000..eb071d1
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2011, NVIDIA Corp. All rights reserved.
+ * 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
+ */
+
+#ifndef _GPIO_H_
+#define _GPIO_H_
+
+#include <asm/arch/gpio.h>
+/*
+ * Generic GPIO API
+ */
+
+int gpio_request(int gp, const char *label);
+void gpio_free(int gp);
+void gpio_toggle_value(int gp);
+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 /* _GPIO_H_ */
index a5fa2b5d851c6d098280b048d9fb08ae87d78d97..1e3ae11347b0beff9350e1b4fa1db021d1bcd5dd 100644 (file)
@@ -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 (file)
index 0000000..f686e80
--- /dev/null
@@ -0,0 +1,255 @@
+/*
+ * 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 (twarren@nvidia.com)
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/bitops.h>
+#include <asm/arch/tegra2.h>
+#include <asm/gpio.h>
+
+enum {
+       TEGRA2_CMD_INFO,
+       TEGRA2_CMD_PORT,
+       TEGRA2_CMD_OUTPUT,
+       TEGRA2_CMD_INPUT,
+};
+
+static struct gpio_names {
+       char name[GPIO_NAME_SIZE];
+} gpio_names[MAX_NUM_GPIOS];
+
+static char *get_name(int i)
+{
+       return *gpio_names[i].name ? gpio_names[i].name : "UNKNOWN";
+}
+
+/* Return config of pin 'gp' as GPIO (1) or SFPIO (0) */
+static int get_config(int gp)
+{
+       struct gpio_ctlr *gpio = (struct gpio_ctlr *)NV_PA_GPIO_BASE;
+       struct gpio_ctlr_bank *bank = &gpio->gpio_bank[GPIO_BANK(gp)];
+       u32 u;
+       int type;
+
+       u = readl(&bank->gpio_config[GPIO_PORT(gp)]);
+       type =  (u >> GPIO_BIT(gp)) & 1;
+
+       debug("get_config: port = %d, bit = %d is %s\n",
+               GPIO_FULLPORT(gp), GPIO_BIT(gp), type ? "GPIO" : "SFPIO");
+
+       return type;
+}
+
+/* Config pin 'gp' as GPIO or SFPIO, based on 'type' */
+static 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)]);
+}
+
+/* Return GPIO pin 'gp' direction - 0 = input or 1 = output */
+static int get_direction(int gp)
+{
+       struct gpio_ctlr *gpio = (struct gpio_ctlr *)NV_PA_GPIO_BASE;
+       struct gpio_ctlr_bank *bank = &gpio->gpio_bank[GPIO_BANK(gp)];
+       u32 u;
+       int dir;
+
+       u = readl(&bank->gpio_dir_out[GPIO_PORT(gp)]);
+       dir =  (u >> GPIO_BIT(gp)) & 1;
+
+       debug("get_direction: port = %d, bit = %d, %s\n",
+               GPIO_FULLPORT(gp), GPIO_BIT(gp), dir ? "OUT" : "IN");
+
+       return dir;
+}
+
+/* Config GPIO pin 'gp' as input or output (OE) as per 'output' */
+static 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' */
+static 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.
+ */
+
+int gpio_request(int gp, const char *label)
+{
+       if (gp >= MAX_NUM_GPIOS)
+               return -1;
+
+       strncpy(gpio_names[gp].name, label, GPIO_NAME_SIZE);
+       gpio_names[gp].name[GPIO_NAME_SIZE - 1] = '\0';
+
+       /* Configure as a GPIO */
+       set_config(gp, 1);
+
+       return 0;
+}
+
+void gpio_free(int gp)
+{
+}
+
+/* read GPIO OUT value of pin 'gp' */
+static int gpio_get_output_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_output_value: pin = %d (port %d:bit %d)\n",
+               gp, GPIO_FULLPORT(gp), GPIO_BIT(gp));
+
+       val = readl(&bank->gpio_out[GPIO_PORT(gp)]);
+
+       return (val >> GPIO_BIT(gp)) & 1;
+}
+
+void gpio_toggle_value(int gp)
+{
+       gpio_set_value(gp, !gpio_get_output_value(gp));
+}
+
+/* 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 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 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);
+}
+
+/*
+ * Display Tegra GPIO information
+ */
+void gpio_info(void)
+{
+       int c, type;
+
+       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;
+       }
+}