blob: 82b30d5ab682eb77ad93d5ee3b6caafbb214c7f3 [file] [log] [blame]
Tom Warrenb3878b82011-06-17 06:27:28 +00001/*
Allen Martin55d98a12012-08-31 08:30:00 +00002 * NVIDIA Tegra20 GPIO handling.
Tom Warrenc570d7a2012-05-22 12:19:25 +00003 * (C) Copyright 2010-2012
Tom Warrenb3878b82011-06-17 06:27:28 +00004 * NVIDIA Corporation <www.nvidia.com>
5 *
Wolfgang Denkd79de1d2013-07-08 09:37:19 +02006 * SPDX-License-Identifier: GPL-2.0+
Tom Warrenb3878b82011-06-17 06:27:28 +00007 */
8
9/*
10 * Based on (mostly copied from) kw_gpio.c based Linux 2.6 kernel driver.
11 * Tom Warren (twarren@nvidia.com)
12 */
13
14#include <common.h>
15#include <asm/io.h>
16#include <asm/bitops.h>
Tom Warrenab371962012-09-19 15:50:56 -070017#include <asm/arch/tegra.h>
Tom Warrenb3878b82011-06-17 06:27:28 +000018#include <asm/gpio.h>
19
20enum {
Tom Warren22562a42012-09-04 17:00:24 -070021 TEGRA_CMD_INFO,
22 TEGRA_CMD_PORT,
23 TEGRA_CMD_OUTPUT,
24 TEGRA_CMD_INPUT,
Tom Warrenb3878b82011-06-17 06:27:28 +000025};
26
27static struct gpio_names {
28 char name[GPIO_NAME_SIZE];
29} gpio_names[MAX_NUM_GPIOS];
30
31static char *get_name(int i)
32{
33 return *gpio_names[i].name ? gpio_names[i].name : "UNKNOWN";
34}
35
Joe Hershbergerf8928f12011-11-11 15:55:36 -060036/* Return config of pin 'gpio' as GPIO (1) or SFPIO (0) */
37static int get_config(unsigned gpio)
Tom Warrenb3878b82011-06-17 06:27:28 +000038{
Joe Hershbergerf8928f12011-11-11 15:55:36 -060039 struct gpio_ctlr *ctlr = (struct gpio_ctlr *)NV_PA_GPIO_BASE;
40 struct gpio_ctlr_bank *bank = &ctlr->gpio_bank[GPIO_BANK(gpio)];
Tom Warrenb3878b82011-06-17 06:27:28 +000041 u32 u;
42 int type;
43
Joe Hershbergerf8928f12011-11-11 15:55:36 -060044 u = readl(&bank->gpio_config[GPIO_PORT(gpio)]);
45 type = (u >> GPIO_BIT(gpio)) & 1;
Tom Warrenb3878b82011-06-17 06:27:28 +000046
47 debug("get_config: port = %d, bit = %d is %s\n",
Joe Hershbergerf8928f12011-11-11 15:55:36 -060048 GPIO_FULLPORT(gpio), GPIO_BIT(gpio), type ? "GPIO" : "SFPIO");
Tom Warrenb3878b82011-06-17 06:27:28 +000049
50 return type;
51}
52
Joe Hershbergerf8928f12011-11-11 15:55:36 -060053/* Config pin 'gpio' as GPIO or SFPIO, based on 'type' */
54static void set_config(unsigned gpio, int type)
Tom Warrenb3878b82011-06-17 06:27:28 +000055{
Joe Hershbergerf8928f12011-11-11 15:55:36 -060056 struct gpio_ctlr *ctlr = (struct gpio_ctlr *)NV_PA_GPIO_BASE;
57 struct gpio_ctlr_bank *bank = &ctlr->gpio_bank[GPIO_BANK(gpio)];
Tom Warrenb3878b82011-06-17 06:27:28 +000058 u32 u;
59
60 debug("set_config: port = %d, bit = %d, %s\n",
Joe Hershbergerf8928f12011-11-11 15:55:36 -060061 GPIO_FULLPORT(gpio), GPIO_BIT(gpio), type ? "GPIO" : "SFPIO");
Tom Warrenb3878b82011-06-17 06:27:28 +000062
Joe Hershbergerf8928f12011-11-11 15:55:36 -060063 u = readl(&bank->gpio_config[GPIO_PORT(gpio)]);
Tom Warrenb3878b82011-06-17 06:27:28 +000064 if (type) /* GPIO */
Joe Hershbergerf8928f12011-11-11 15:55:36 -060065 u |= 1 << GPIO_BIT(gpio);
Tom Warrenb3878b82011-06-17 06:27:28 +000066 else
Joe Hershbergerf8928f12011-11-11 15:55:36 -060067 u &= ~(1 << GPIO_BIT(gpio));
68 writel(u, &bank->gpio_config[GPIO_PORT(gpio)]);
Tom Warrenb3878b82011-06-17 06:27:28 +000069}
70
Joe Hershbergerf8928f12011-11-11 15:55:36 -060071/* Return GPIO pin 'gpio' direction - 0 = input or 1 = output */
72static int get_direction(unsigned gpio)
Tom Warrenb3878b82011-06-17 06:27:28 +000073{
Joe Hershbergerf8928f12011-11-11 15:55:36 -060074 struct gpio_ctlr *ctlr = (struct gpio_ctlr *)NV_PA_GPIO_BASE;
75 struct gpio_ctlr_bank *bank = &ctlr->gpio_bank[GPIO_BANK(gpio)];
Tom Warrenb3878b82011-06-17 06:27:28 +000076 u32 u;
77 int dir;
78
Joe Hershbergerf8928f12011-11-11 15:55:36 -060079 u = readl(&bank->gpio_dir_out[GPIO_PORT(gpio)]);
80 dir = (u >> GPIO_BIT(gpio)) & 1;
Tom Warrenb3878b82011-06-17 06:27:28 +000081
82 debug("get_direction: port = %d, bit = %d, %s\n",
Joe Hershbergerf8928f12011-11-11 15:55:36 -060083 GPIO_FULLPORT(gpio), GPIO_BIT(gpio), dir ? "OUT" : "IN");
Tom Warrenb3878b82011-06-17 06:27:28 +000084
85 return dir;
86}
87
Joe Hershbergerf8928f12011-11-11 15:55:36 -060088/* Config GPIO pin 'gpio' as input or output (OE) as per 'output' */
89static void set_direction(unsigned gpio, int output)
Tom Warrenb3878b82011-06-17 06:27:28 +000090{
Joe Hershbergerf8928f12011-11-11 15:55:36 -060091 struct gpio_ctlr *ctlr = (struct gpio_ctlr *)NV_PA_GPIO_BASE;
92 struct gpio_ctlr_bank *bank = &ctlr->gpio_bank[GPIO_BANK(gpio)];
Tom Warrenb3878b82011-06-17 06:27:28 +000093 u32 u;
94
95 debug("set_direction: port = %d, bit = %d, %s\n",
Joe Hershbergerf8928f12011-11-11 15:55:36 -060096 GPIO_FULLPORT(gpio), GPIO_BIT(gpio), output ? "OUT" : "IN");
Tom Warrenb3878b82011-06-17 06:27:28 +000097
Joe Hershbergerf8928f12011-11-11 15:55:36 -060098 u = readl(&bank->gpio_dir_out[GPIO_PORT(gpio)]);
Tom Warrenb3878b82011-06-17 06:27:28 +000099 if (output)
Joe Hershbergerf8928f12011-11-11 15:55:36 -0600100 u |= 1 << GPIO_BIT(gpio);
Tom Warrenb3878b82011-06-17 06:27:28 +0000101 else
Joe Hershbergerf8928f12011-11-11 15:55:36 -0600102 u &= ~(1 << GPIO_BIT(gpio));
103 writel(u, &bank->gpio_dir_out[GPIO_PORT(gpio)]);
Tom Warrenb3878b82011-06-17 06:27:28 +0000104}
105
Joe Hershbergerf8928f12011-11-11 15:55:36 -0600106/* set GPIO pin 'gpio' output bit as 0 or 1 as per 'high' */
107static void set_level(unsigned gpio, int high)
Tom Warrenb3878b82011-06-17 06:27:28 +0000108{
Joe Hershbergerf8928f12011-11-11 15:55:36 -0600109 struct gpio_ctlr *ctlr = (struct gpio_ctlr *)NV_PA_GPIO_BASE;
110 struct gpio_ctlr_bank *bank = &ctlr->gpio_bank[GPIO_BANK(gpio)];
Tom Warrenb3878b82011-06-17 06:27:28 +0000111 u32 u;
112
113 debug("set_level: port = %d, bit %d == %d\n",
Joe Hershbergerf8928f12011-11-11 15:55:36 -0600114 GPIO_FULLPORT(gpio), GPIO_BIT(gpio), high);
Tom Warrenb3878b82011-06-17 06:27:28 +0000115
Joe Hershbergerf8928f12011-11-11 15:55:36 -0600116 u = readl(&bank->gpio_out[GPIO_PORT(gpio)]);
Tom Warrenb3878b82011-06-17 06:27:28 +0000117 if (high)
Joe Hershbergerf8928f12011-11-11 15:55:36 -0600118 u |= 1 << GPIO_BIT(gpio);
Tom Warrenb3878b82011-06-17 06:27:28 +0000119 else
Joe Hershbergerf8928f12011-11-11 15:55:36 -0600120 u &= ~(1 << GPIO_BIT(gpio));
121 writel(u, &bank->gpio_out[GPIO_PORT(gpio)]);
Tom Warrenb3878b82011-06-17 06:27:28 +0000122}
123
124/*
125 * Generic_GPIO primitives.
126 */
127
Joe Hershbergerf8928f12011-11-11 15:55:36 -0600128int gpio_request(unsigned gpio, const char *label)
Tom Warrenb3878b82011-06-17 06:27:28 +0000129{
Joe Hershbergerf8928f12011-11-11 15:55:36 -0600130 if (gpio >= MAX_NUM_GPIOS)
Tom Warrenb3878b82011-06-17 06:27:28 +0000131 return -1;
132
Stephen Warrenedc513f2011-10-06 12:52:22 +0000133 if (label != NULL) {
Joe Hershbergerf8928f12011-11-11 15:55:36 -0600134 strncpy(gpio_names[gpio].name, label, GPIO_NAME_SIZE);
135 gpio_names[gpio].name[GPIO_NAME_SIZE - 1] = '\0';
Stephen Warrenedc513f2011-10-06 12:52:22 +0000136 }
Tom Warrenb3878b82011-06-17 06:27:28 +0000137
138 /* Configure as a GPIO */
Joe Hershbergerf8928f12011-11-11 15:55:36 -0600139 set_config(gpio, 1);
Tom Warrenb3878b82011-06-17 06:27:28 +0000140
141 return 0;
142}
143
Joe Hershbergerf8928f12011-11-11 15:55:36 -0600144int gpio_free(unsigned gpio)
Tom Warrenb3878b82011-06-17 06:27:28 +0000145{
Joe Hershbergerf8928f12011-11-11 15:55:36 -0600146 if (gpio >= MAX_NUM_GPIOS)
147 return -1;
148
149 gpio_names[gpio].name[0] = '\0';
150 /* Do not configure as input or change pin mux here */
151 return 0;
Tom Warrenb3878b82011-06-17 06:27:28 +0000152}
153
Joe Hershbergerf8928f12011-11-11 15:55:36 -0600154/* read GPIO OUT value of pin 'gpio' */
155static int gpio_get_output_value(unsigned gpio)
Tom Warrenb3878b82011-06-17 06:27:28 +0000156{
Joe Hershbergerf8928f12011-11-11 15:55:36 -0600157 struct gpio_ctlr *ctlr = (struct gpio_ctlr *)NV_PA_GPIO_BASE;
158 struct gpio_ctlr_bank *bank = &ctlr->gpio_bank[GPIO_BANK(gpio)];
Tom Warrenb3878b82011-06-17 06:27:28 +0000159 int val;
160
161 debug("gpio_get_output_value: pin = %d (port %d:bit %d)\n",
Joe Hershbergerf8928f12011-11-11 15:55:36 -0600162 gpio, GPIO_FULLPORT(gpio), GPIO_BIT(gpio));
Tom Warrenb3878b82011-06-17 06:27:28 +0000163
Joe Hershbergerf8928f12011-11-11 15:55:36 -0600164 val = readl(&bank->gpio_out[GPIO_PORT(gpio)]);
Tom Warrenb3878b82011-06-17 06:27:28 +0000165
Joe Hershbergerf8928f12011-11-11 15:55:36 -0600166 return (val >> GPIO_BIT(gpio)) & 1;
Tom Warrenb3878b82011-06-17 06:27:28 +0000167}
168
Joe Hershbergerf8928f12011-11-11 15:55:36 -0600169/* set GPIO pin 'gpio' as an input */
170int gpio_direction_input(unsigned gpio)
Tom Warrenb3878b82011-06-17 06:27:28 +0000171{
172 debug("gpio_direction_input: pin = %d (port %d:bit %d)\n",
Joe Hershbergerf8928f12011-11-11 15:55:36 -0600173 gpio, GPIO_FULLPORT(gpio), GPIO_BIT(gpio));
Tom Warrenb3878b82011-06-17 06:27:28 +0000174
175 /* Configure GPIO direction as input. */
Joe Hershbergerf8928f12011-11-11 15:55:36 -0600176 set_direction(gpio, 0);
Tom Warrenb3878b82011-06-17 06:27:28 +0000177
178 return 0;
179}
180
Joe Hershbergerf8928f12011-11-11 15:55:36 -0600181/* set GPIO pin 'gpio' as an output, with polarity 'value' */
182int gpio_direction_output(unsigned gpio, int value)
Tom Warrenb3878b82011-06-17 06:27:28 +0000183{
184 debug("gpio_direction_output: pin = %d (port %d:bit %d) = %s\n",
Joe Hershbergerf8928f12011-11-11 15:55:36 -0600185 gpio, GPIO_FULLPORT(gpio), GPIO_BIT(gpio),
186 value ? "HIGH" : "LOW");
Tom Warrenb3878b82011-06-17 06:27:28 +0000187
188 /* Configure GPIO output value. */
Joe Hershbergerf8928f12011-11-11 15:55:36 -0600189 set_level(gpio, value);
Tom Warrenb3878b82011-06-17 06:27:28 +0000190
191 /* Configure GPIO direction as output. */
Joe Hershbergerf8928f12011-11-11 15:55:36 -0600192 set_direction(gpio, 1);
Tom Warrenb3878b82011-06-17 06:27:28 +0000193
194 return 0;
195}
196
Joe Hershbergerf8928f12011-11-11 15:55:36 -0600197/* read GPIO IN value of pin 'gpio' */
198int gpio_get_value(unsigned gpio)
Tom Warrenb3878b82011-06-17 06:27:28 +0000199{
Joe Hershbergerf8928f12011-11-11 15:55:36 -0600200 struct gpio_ctlr *ctlr = (struct gpio_ctlr *)NV_PA_GPIO_BASE;
201 struct gpio_ctlr_bank *bank = &ctlr->gpio_bank[GPIO_BANK(gpio)];
Tom Warrenb3878b82011-06-17 06:27:28 +0000202 int val;
203
204 debug("gpio_get_value: pin = %d (port %d:bit %d)\n",
Joe Hershbergerf8928f12011-11-11 15:55:36 -0600205 gpio, GPIO_FULLPORT(gpio), GPIO_BIT(gpio));
Tom Warrenb3878b82011-06-17 06:27:28 +0000206
Joe Hershbergerf8928f12011-11-11 15:55:36 -0600207 val = readl(&bank->gpio_in[GPIO_PORT(gpio)]);
Tom Warrenb3878b82011-06-17 06:27:28 +0000208
Joe Hershbergerf8928f12011-11-11 15:55:36 -0600209 return (val >> GPIO_BIT(gpio)) & 1;
Tom Warrenb3878b82011-06-17 06:27:28 +0000210}
211
Joe Hershbergerf8928f12011-11-11 15:55:36 -0600212/* write GPIO OUT value to pin 'gpio' */
213int gpio_set_value(unsigned gpio, int value)
Tom Warrenb3878b82011-06-17 06:27:28 +0000214{
215 debug("gpio_set_value: pin = %d (port %d:bit %d), value = %d\n",
Joe Hershbergerf8928f12011-11-11 15:55:36 -0600216 gpio, GPIO_FULLPORT(gpio), GPIO_BIT(gpio), value);
Tom Warrenb3878b82011-06-17 06:27:28 +0000217
218 /* Configure GPIO output value. */
Joe Hershbergerf8928f12011-11-11 15:55:36 -0600219 set_level(gpio, value);
220
221 return 0;
Tom Warrenb3878b82011-06-17 06:27:28 +0000222}
223
224/*
225 * Display Tegra GPIO information
226 */
227void gpio_info(void)
228{
Joe Hershbergerf8928f12011-11-11 15:55:36 -0600229 unsigned c;
230 int type;
Tom Warrenb3878b82011-06-17 06:27:28 +0000231
232 for (c = 0; c < MAX_NUM_GPIOS; c++) {
233 type = get_config(c); /* GPIO, not SFPIO */
234 if (type) {
235 printf("GPIO_%d:\t%s is an %s, ", c,
236 get_name(c),
237 get_direction(c) ? "OUTPUT" : "INPUT");
238 if (get_direction(c))
239 printf("value = %d", gpio_get_output_value(c));
240 else
241 printf("value = %d", gpio_get_value(c));
242 printf("\n");
243 } else
244 continue;
245 }
246}