From: Tom Warren <twarren.nvidia@gmail.com>
To: u-boot@lists.denx.de
Subject: [U-Boot] [PATCH V4 1/2] GPIO: Tegra2: add GPIO driver for Tegra2
Date: Thu, 16 Jun 2011 16:51:33 -0700 [thread overview]
Message-ID: <1308268294-14901-2-git-send-email-twarren@nvidia.com> (raw)
In-Reply-To: <1308268294-14901-1-git-send-email-twarren@nvidia.com>
Signed-off-by: Tom Warren <twarren@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
Changes in V3:
- use common cmd_gpio; remove redundant cmd processing code
- add gpio_request, gpio_free and gpio_toggle
- alias 'gpio_status' to 'gpio_info' for use in cmd_gpio
Changes in V4:
- update code as per Mike Frysinger's review comments
- rewrite gpio_info, aka gpio_status
arch/arm/include/asm/arch-tegra2/gpio.h | 250 +++++++++++++++++++++++++++++--
arch/arm/include/asm/gpio.h | 38 +++++
drivers/gpio/Makefile | 1 +
drivers/gpio/tegra2_gpio.c | 254 +++++++++++++++++++++++++++++++
4 files changed, 533 insertions(+), 10 deletions(-)
create mode 100644 arch/arm/include/asm/gpio.h
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..41e66fe 100644
--- a/arch/arm/include/asm/arch-tegra2/gpio.h
+++ b/arch/arm/include/asm/arch-tegra2/gpio.h
@@ -23,11 +23,13 @@
#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
index 0000000..eb071d1
--- /dev/null
+++ b/arch/arm/include/asm/gpio.h
@@ -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_ */
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..2cf5737
--- /dev/null
+++ b/drivers/gpio/tegra2_gpio.c
@@ -0,0 +1,254 @@
+/*
+ * 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 at 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);
+
+ /* 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;
+ }
+}
--
1.7.5.4
next prev parent reply other threads:[~2011-06-16 23:51 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-06-16 23:51 [U-Boot] [PATCH V4 0/2] GPIO: Tegra2: add GPIO driver for Tegra2 Tom Warren
2011-06-16 23:51 ` Tom Warren [this message]
2011-06-17 0:06 ` [U-Boot] [PATCH V4 1/2] " Mike Frysinger
2011-06-17 0:09 ` Tom Warren
2011-06-16 23:51 ` [U-Boot] [PATCH V4 2/2] arm: Tegra2: GPIO: enable GPIO for Tegra2 boards Tom Warren
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1308268294-14901-2-git-send-email-twarren@nvidia.com \
--to=twarren.nvidia@gmail.com \
--cc=u-boot@lists.denx.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.