Patchwork [U-Boot,V5,1/2] GPIO: Tegra2: add GPIO driver for Tegra2

login
register
mail settings
Submitter Tom Warren
Date June 17, 2011, 4:27 p.m.
Message ID <1308328049-4390-2-git-send-email-twarren@nvidia.com>
Download mbox | patch
Permalink /patch/100828/
State Accepted
Commit 4e5ae09e56a205685824ebebc91fc43c8b0b973a
Delegated to: Albert ARIBAUD
Headers show

Comments

Tom Warren - June 17, 2011, 4:27 p.m.
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
Changes in V5:
	- NUL-terminate the name string in gpio_request

 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              |  255 +++++++++++++++++++++++++++++++
 4 files changed, 534 insertions(+), 10 deletions(-)
 create mode 100644 arch/arm/include/asm/gpio.h
 create mode 100644 drivers/gpio/tegra2_gpio.c
Tom Warren - June 24, 2011, 5:58 p.m.
On Fri, Jun 17, 2011 at 9:27 AM, Tom Warren <twarren.nvidia@gmail.com> wrote:
> 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
> Changes in V5:
>        - NUL-terminate the name string in gpio_request
>
>  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              |  255 +++++++++++++++++++++++++++++++
>  4 files changed, 534 insertions(+), 10 deletions(-)
>  create mode 100644 arch/arm/include/asm/gpio.h
>  create mode 100644 drivers/gpio/tegra2_gpio.c
>
<snip>
Has this patch been accepted? or is there anymore feedback?

Mike gave it an 'otherwise, looks fine' prior to the ASCIIZ fix in V5.

Thanks,

Tom
Albert ARIBAUD - June 26, 2011, 2:31 p.m.
Hi Tom,

Le 24/06/2011 19:58, Tom Warren a écrit :
> On Fri, Jun 17, 2011 at 9:27 AM, Tom Warren<twarren.nvidia@gmail.com>  wrote:
>> 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
>> Changes in V5:
>>         - NUL-terminate the name string in gpio_request
>>
>>   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              |  255 +++++++++++++++++++++++++++++++
>>   4 files changed, 534 insertions(+), 10 deletions(-)
>>   create mode 100644 arch/arm/include/asm/gpio.h
>>   create mode 100644 drivers/gpio/tegra2_gpio.c
>>
> <snip>
> Has this patch been accepted? or is there anymore feedback?
>
> Mike gave it an 'otherwise, looks fine' prior to the ASCIIZ fix in V5.

Seems like no other comments have been made, so:

Applied to u-boot-arm/next, to be moved to master after 2011-06 release.

> Thanks,
>
> Tom

Amicalement,

Patch

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..f686e80
--- /dev/null
+++ b/drivers/gpio/tegra2_gpio.c
@@ -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;
+	}
+}