[U-Boot] [PATCH] GPIO: Tegra2: add GPIO driver for Seaboard and Harmony

Tom Warren twarren.nvidia at gmail.com
Mon Apr 18 23:11:48 CEST 2011


Signed-off-by: Tom Warren <twarren at nvidia.com>
---
 arch/arm/include/asm/arch-tegra2/gpio.h |  236 ++++++++++++++++++++++++-
 drivers/gpio/Makefile                   |    1 +
 drivers/gpio/tegra2_gpio.c              |  301 +++++++++++++++++++++++++++++++
 include/configs/harmony.h               |    3 +
 include/configs/seaboard.h              |    3 +
 5 files changed, 540 insertions(+), 4 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..0d7d7f8 100644
--- a/arch/arm/include/asm/arch-tegra2/gpio.h
+++ b/arch/arm/include/asm/arch-tegra2/gpio.h
@@ -47,13 +47,241 @@ struct gpio_ctlr {
 
 #define GPIO_BANK(x)	((x) >> 5)
 #define GPIO_PORT(x)	(((x) >> 3) & 0x3)
+#define GPIO_PORT8(x)	((x) >> 3)
 #define GPIO_BIT(x)	((x) & 0x7)
 
+#define GPIO_PA0    0		/* port A (0), pin 0 */
+#define GPIO_PA1    1
+#define GPIO_PA2    2
+#define GPIO_PA3    3
+#define GPIO_PA4    4
+#define GPIO_PA5    5
+#define GPIO_PA6    6
+#define GPIO_PA7    7
+#define GPIO_PB0    8
+#define GPIO_PB1    9
+#define GPIO_PB2    10
+#define GPIO_PB3    11
+#define GPIO_PB4    12
+#define GPIO_PB5    13
+#define GPIO_PB6    14
+#define GPIO_PB7    15
+#define GPIO_PC0    16
+#define GPIO_PC1    17
+#define GPIO_PC2    18
+#define GPIO_PC3    19
+#define GPIO_PC4    20
+#define GPIO_PC5    21
+#define GPIO_PC6    22
+#define GPIO_PC7    23
+#define GPIO_PD0    24
+#define GPIO_PD1    25
+#define GPIO_PD2    26
+#define GPIO_PD3    27
+#define GPIO_PD4    28
+#define GPIO_PD5    29
+#define GPIO_PD6    30
+#define GPIO_PD7    31
+#define GPIO_PE0    32
+#define GPIO_PE1    33
+#define GPIO_PE2    34
+#define GPIO_PE3    35
+#define GPIO_PE4    36
+#define GPIO_PE5    37
+#define GPIO_PE6    38
+#define GPIO_PE7    39
+#define GPIO_PF0    40
+#define GPIO_PF1    41
+#define GPIO_PF2    42
+#define GPIO_PF3    43
+#define GPIO_PF4    44
+#define GPIO_PF5    45
+#define GPIO_PF6    46
+#define GPIO_PF7    47
+#define GPIO_PG0    48
+#define GPIO_PG1    49
+#define GPIO_PG2    50
+#define GPIO_PG3    51
+#define GPIO_PG4    52
+#define GPIO_PG5    53
+#define GPIO_PG6    54
+#define GPIO_PG7    55
+#define GPIO_PH0    56
+#define GPIO_PH1    57
+#define GPIO_PH2    58
+#define GPIO_PH3    59
+#define GPIO_PH4    60
+#define GPIO_PH5    61
+#define GPIO_PH6    62
+#define GPIO_PH7    63
+#define GPIO_PI0    64
+#define GPIO_PI1    65
+#define GPIO_PI2    66
+#define GPIO_PI3    67
+#define GPIO_PI4    68
+#define GPIO_PI5    69
+#define GPIO_PI6    70
+#define GPIO_PI7    71
+#define GPIO_PJ0    72
+#define GPIO_PJ1    73
+#define GPIO_PJ2    74
+#define GPIO_PJ3    75
+#define GPIO_PJ4    76
+#define GPIO_PJ5    77
+#define GPIO_PJ6    78
+#define GPIO_PJ7    79
+#define GPIO_PK0    80
+#define GPIO_PK1    81
+#define GPIO_PK2    82
+#define GPIO_PK3    83
+#define GPIO_PK4    84
+#define GPIO_PK5    85
+#define GPIO_PK6    86
+#define GPIO_PK7    87
+#define GPIO_PL0    88
+#define GPIO_PL1    89
+#define GPIO_PL2    90
+#define GPIO_PL3    91
+#define GPIO_PL4    92
+#define GPIO_PL5    93
+#define GPIO_PL6    94
+#define GPIO_PL7    95
+#define GPIO_PM0    96
+#define GPIO_PM1    97
+#define GPIO_PM2    98
+#define GPIO_PM3    99
+#define GPIO_PM4    100
+#define GPIO_PM5    101
+#define GPIO_PM6    102
+#define GPIO_PM7    103
+#define GPIO_PN0    104
+#define GPIO_PN1    105
+#define GPIO_PN2    106
+#define GPIO_PN3    107
+#define GPIO_PN4    108
+#define GPIO_PN5    109
+#define GPIO_PN6    110
+#define GPIO_PN7    111
+#define GPIO_PO0    112
+#define GPIO_PO1    113
+#define GPIO_PO2    114
+#define GPIO_PO3    115
+#define GPIO_PO4    116
+#define GPIO_PO5    117
+#define GPIO_PO6    118
+#define GPIO_PO7    119
+#define GPIO_PP0    120
+#define GPIO_PP1    121
+#define GPIO_PP2    122
+#define GPIO_PP3    123
+#define GPIO_PP4    124
+#define GPIO_PP5    125
+#define GPIO_PP6    126
+#define GPIO_PP7    127
+#define GPIO_PQ0    128
+#define GPIO_PQ1    129
+#define GPIO_PQ2    130
+#define GPIO_PQ3    131
+#define GPIO_PQ4    132
+#define GPIO_PQ5    133
+#define GPIO_PQ6    134
+#define GPIO_PQ7    135
+#define GPIO_PR0    136
+#define GPIO_PR1    137
+#define GPIO_PR2    138
+#define GPIO_PR3    139
+#define GPIO_PR4    140
+#define GPIO_PR5    141
+#define GPIO_PR6    142
+#define GPIO_PR7    143
+#define GPIO_PS0    144
+#define GPIO_PS1    145
+#define GPIO_PS2    146
+#define GPIO_PS3    147
+#define GPIO_PS4    148
+#define GPIO_PS5    149
+#define GPIO_PS6    150
+#define GPIO_PS7    151
+#define GPIO_PT0    152
+#define GPIO_PT1    153
+#define GPIO_PT2    154
+#define GPIO_PT3    155
+#define GPIO_PT4    156
+#define GPIO_PT5    157
+#define GPIO_PT6    158
+#define GPIO_PT7    159
+#define GPIO_PU0    160
+#define GPIO_PU1    161
+#define GPIO_PU2    162
+#define GPIO_PU3    163
+#define GPIO_PU4    164
+#define GPIO_PU5    165
+#define GPIO_PU6    166
+#define GPIO_PU7    167
+#define GPIO_PV0    168
+#define GPIO_PV1    169
+#define GPIO_PV2    170
+#define GPIO_PV3    171
+#define GPIO_PV4    172
+#define GPIO_PV5    173
+#define GPIO_PV6    174
+#define GPIO_PV7    175
+#define GPIO_PW0    176
+#define GPIO_PW1    177
+#define GPIO_PW2    178
+#define GPIO_PW3    179
+#define GPIO_PW4    180
+#define GPIO_PW5    181
+#define GPIO_PW6    182
+#define GPIO_PW7    183
+#define GPIO_PX0    184
+#define GPIO_PX1    185
+#define GPIO_PX2    186
+#define GPIO_PX3    187
+#define GPIO_PX4    188
+#define GPIO_PX5    189
+#define GPIO_PX6    190
+#define GPIO_PX7    191
+#define GPIO_PY0    192
+#define GPIO_PY1    193
+#define GPIO_PY2    194
+#define GPIO_PY3    195
+#define GPIO_PY4    196
+#define GPIO_PY5    197
+#define GPIO_PY6    198
+#define GPIO_PY7    199
+#define GPIO_PZ0    200
+#define GPIO_PZ1    201
+#define GPIO_PZ2    202
+#define GPIO_PZ3    203
+#define GPIO_PZ4    204
+#define GPIO_PZ5    205
+#define GPIO_PZ6    206
+#define GPIO_PZ7    207
+#define GPIO_PAA0   208
+#define GPIO_PAA1   209
+#define GPIO_PAA2   210
+#define GPIO_PAA3   211
+#define GPIO_PAA4   212
+#define GPIO_PAA5   213
+#define GPIO_PAA6   214
+#define GPIO_PAA7   215
+#define GPIO_PBA0   216
+#define GPIO_PBB1   217
+#define GPIO_PBB2   218
+#define GPIO_PBB3   219
+#define GPIO_PBB4   220
+#define GPIO_PBB5   221
+#define GPIO_PBB6   222
+#define GPIO_PBB7   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..c3753a8
--- /dev/null
+++ b/drivers/gpio/tegra2_gpio.c
@@ -0,0 +1,301 @@
+/*
+ * drivers/gpio/tegra2_gpio.c
+ *
+ * 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/arch/gpio.h>
+
+enum {
+	TEGRA2_CMD_INFO,
+	TEGRA2_CMD_PORT,
+	TEGRA2_CMD_OUTPUT,
+	TEGRA2_CMD_INPUT,
+};
+
+/* Config port '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_PORT8(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 port '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_PORT8(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 port '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_PORT8(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 port 'gp' as an input */
+int gpio_direction_input(int gp)
+{
+	debug("gpio_direction_input: offset = %d (port %d:bit %d)\n",
+		gp, GPIO_PORT8(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 port 'gp' as an output, with polarity 'value' */
+int gpio_direction_output(int gp, int value)
+{
+	debug("gpio_direction_output: offset = %d (port %d:bit %d) = %s\n",
+		gp, GPIO_PORT8(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 port '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: offset = %d (port %d:bit %d)\n",
+		gp, GPIO_PORT8(gp), GPIO_BIT(gp));
+
+	val = readl(&bank->gpio_in[GPIO_PORT(gp)]);
+
+	return (val >> GPIO_BIT(gp)) & 1;
+}
+
+/* write GPIO OUT value to port 'gp' */
+void gpio_set_value(int gp, int value)
+{
+	debug("gpio_set_value: offset = %d (port %d:bit %d), value = %d\n",
+		gp, GPIO_PORT8(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_PORT8(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(offset2port, 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 offset;
+	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 offset */
+	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)
+			offset = (uint8_t)ul_arg2;
+		return gpio_info(offset);
+
+#endif
+	case TEGRA2_CMD_PORT:
+		if (argc == 3)
+			offset = (uint8_t)ul_arg2;
+		port = GPIO_PORT8(offset);
+		bit = GPIO_BIT(offset);
+		printf("Offset %d = port # %d, bit # %d\n",
+			offset, port, bit);
+		return 0;
+
+	case TEGRA2_CMD_INPUT:
+		/* arg2 = offset */
+		port = GPIO_PORT8(offset);
+		bit = GPIO_BIT(offset);
+		gpio_direction_input(ul_arg2);
+		val = gpio_get_value(ul_arg2);
+
+		printf("Offset %lu (port:bit %d:%d) = %d\n",
+			ul_arg2, port, bit, val);
+		return 0;
+
+	case TEGRA2_CMD_OUTPUT:
+		/* args = offset, value */
+		port = GPIO_PORT8(offset);
+		bit = GPIO_BIT(offset);
+		gpio_direction_output(ul_arg2, ul_arg3);
+		printf("Offset %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",
+	"offset2port offset\n"
+	"	- show GPIO port:bit based on 'offset'\n"
+#ifdef CONFIG_CMD_TEGRA2_GPIO_INFO
+	"     info offset\n"
+	"	- display info for all bits in port based on 'offset'\n"
+#endif
+	"     output offset 0|1\n"
+	"	- using 'offset', set port:bit as output and drive low or high\n"
+	"     input offset\n"
+	"	- using 'offset', set port:bit as input and read value"
+);
diff --git a/include/configs/harmony.h b/include/configs/harmony.h
index 34bd899..5e660e0 100644
--- a/include/configs/harmony.h
+++ b/include/configs/harmony.h
@@ -47,4 +47,7 @@
 #define CONFIG_SYS_BOARD_ODMDATA	0x300d8011 /* lp1, 1GB */
 
 #define CONFIG_BOARD_EARLY_INIT_F
+
+#define CONFIG_TEGRA2_GPIO
+#define CONFIG_CMD_TEGRA2_GPIO_INFO
 #endif /* __CONFIG_H */
diff --git a/include/configs/seaboard.h b/include/configs/seaboard.h
index 06ce3e2..4e8ef07 100644
--- a/include/configs/seaboard.h
+++ b/include/configs/seaboard.h
@@ -41,4 +41,7 @@
 #define CONFIG_SYS_BOARD_ODMDATA	0x300d8011 /* lp1, 1GB */
 
 #define CONFIG_BOARD_EARLY_INIT_F
+
+#define CONFIG_TEGRA2_GPIO
+#define CONFIG_CMD_TEGRA2_GPIO_INFO
 #endif /* __CONFIG_H */
-- 
1.7.4.3



More information about the U-Boot mailing list