[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