]>
Commit | Line | Data |
---|---|---|
4e5ae09e | 1 | /* |
00a2749d | 2 | * NVIDIA Tegra20 GPIO handling. |
52a8b820 | 3 | * (C) Copyright 2010-2012 |
4e5ae09e TW |
4 | * NVIDIA Corporation <www.nvidia.com> |
5 | * | |
1a459660 | 6 | * SPDX-License-Identifier: GPL-2.0+ |
4e5ae09e TW |
7 | */ |
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> | |
150c2493 | 17 | #include <asm/arch/tegra.h> |
4e5ae09e TW |
18 | #include <asm/gpio.h> |
19 | ||
20 | enum { | |
29f3e3f2 TW |
21 | TEGRA_CMD_INFO, |
22 | TEGRA_CMD_PORT, | |
23 | TEGRA_CMD_OUTPUT, | |
24 | TEGRA_CMD_INPUT, | |
4e5ae09e TW |
25 | }; |
26 | ||
27 | static struct gpio_names { | |
28 | char name[GPIO_NAME_SIZE]; | |
29 | } gpio_names[MAX_NUM_GPIOS]; | |
30 | ||
31 | static char *get_name(int i) | |
32 | { | |
33 | return *gpio_names[i].name ? gpio_names[i].name : "UNKNOWN"; | |
34 | } | |
35 | ||
365d6070 JH |
36 | /* Return config of pin 'gpio' as GPIO (1) or SFPIO (0) */ |
37 | static int get_config(unsigned gpio) | |
4e5ae09e | 38 | { |
365d6070 JH |
39 | struct gpio_ctlr *ctlr = (struct gpio_ctlr *)NV_PA_GPIO_BASE; |
40 | struct gpio_ctlr_bank *bank = &ctlr->gpio_bank[GPIO_BANK(gpio)]; | |
4e5ae09e TW |
41 | u32 u; |
42 | int type; | |
43 | ||
365d6070 JH |
44 | u = readl(&bank->gpio_config[GPIO_PORT(gpio)]); |
45 | type = (u >> GPIO_BIT(gpio)) & 1; | |
4e5ae09e TW |
46 | |
47 | debug("get_config: port = %d, bit = %d is %s\n", | |
365d6070 | 48 | GPIO_FULLPORT(gpio), GPIO_BIT(gpio), type ? "GPIO" : "SFPIO"); |
4e5ae09e TW |
49 | |
50 | return type; | |
51 | } | |
52 | ||
365d6070 JH |
53 | /* Config pin 'gpio' as GPIO or SFPIO, based on 'type' */ |
54 | static void set_config(unsigned gpio, int type) | |
4e5ae09e | 55 | { |
365d6070 JH |
56 | struct gpio_ctlr *ctlr = (struct gpio_ctlr *)NV_PA_GPIO_BASE; |
57 | struct gpio_ctlr_bank *bank = &ctlr->gpio_bank[GPIO_BANK(gpio)]; | |
4e5ae09e TW |
58 | u32 u; |
59 | ||
60 | debug("set_config: port = %d, bit = %d, %s\n", | |
365d6070 | 61 | GPIO_FULLPORT(gpio), GPIO_BIT(gpio), type ? "GPIO" : "SFPIO"); |
4e5ae09e | 62 | |
365d6070 | 63 | u = readl(&bank->gpio_config[GPIO_PORT(gpio)]); |
4e5ae09e | 64 | if (type) /* GPIO */ |
365d6070 | 65 | u |= 1 << GPIO_BIT(gpio); |
4e5ae09e | 66 | else |
365d6070 JH |
67 | u &= ~(1 << GPIO_BIT(gpio)); |
68 | writel(u, &bank->gpio_config[GPIO_PORT(gpio)]); | |
4e5ae09e TW |
69 | } |
70 | ||
365d6070 JH |
71 | /* Return GPIO pin 'gpio' direction - 0 = input or 1 = output */ |
72 | static int get_direction(unsigned gpio) | |
4e5ae09e | 73 | { |
365d6070 JH |
74 | struct gpio_ctlr *ctlr = (struct gpio_ctlr *)NV_PA_GPIO_BASE; |
75 | struct gpio_ctlr_bank *bank = &ctlr->gpio_bank[GPIO_BANK(gpio)]; | |
4e5ae09e TW |
76 | u32 u; |
77 | int dir; | |
78 | ||
365d6070 JH |
79 | u = readl(&bank->gpio_dir_out[GPIO_PORT(gpio)]); |
80 | dir = (u >> GPIO_BIT(gpio)) & 1; | |
4e5ae09e TW |
81 | |
82 | debug("get_direction: port = %d, bit = %d, %s\n", | |
365d6070 | 83 | GPIO_FULLPORT(gpio), GPIO_BIT(gpio), dir ? "OUT" : "IN"); |
4e5ae09e TW |
84 | |
85 | return dir; | |
86 | } | |
87 | ||
365d6070 JH |
88 | /* Config GPIO pin 'gpio' as input or output (OE) as per 'output' */ |
89 | static void set_direction(unsigned gpio, int output) | |
4e5ae09e | 90 | { |
365d6070 JH |
91 | struct gpio_ctlr *ctlr = (struct gpio_ctlr *)NV_PA_GPIO_BASE; |
92 | struct gpio_ctlr_bank *bank = &ctlr->gpio_bank[GPIO_BANK(gpio)]; | |
4e5ae09e TW |
93 | u32 u; |
94 | ||
95 | debug("set_direction: port = %d, bit = %d, %s\n", | |
365d6070 | 96 | GPIO_FULLPORT(gpio), GPIO_BIT(gpio), output ? "OUT" : "IN"); |
4e5ae09e | 97 | |
365d6070 | 98 | u = readl(&bank->gpio_dir_out[GPIO_PORT(gpio)]); |
4e5ae09e | 99 | if (output) |
365d6070 | 100 | u |= 1 << GPIO_BIT(gpio); |
4e5ae09e | 101 | else |
365d6070 JH |
102 | u &= ~(1 << GPIO_BIT(gpio)); |
103 | writel(u, &bank->gpio_dir_out[GPIO_PORT(gpio)]); | |
4e5ae09e TW |
104 | } |
105 | ||
365d6070 JH |
106 | /* set GPIO pin 'gpio' output bit as 0 or 1 as per 'high' */ |
107 | static void set_level(unsigned gpio, int high) | |
4e5ae09e | 108 | { |
365d6070 JH |
109 | struct gpio_ctlr *ctlr = (struct gpio_ctlr *)NV_PA_GPIO_BASE; |
110 | struct gpio_ctlr_bank *bank = &ctlr->gpio_bank[GPIO_BANK(gpio)]; | |
4e5ae09e TW |
111 | u32 u; |
112 | ||
113 | debug("set_level: port = %d, bit %d == %d\n", | |
365d6070 | 114 | GPIO_FULLPORT(gpio), GPIO_BIT(gpio), high); |
4e5ae09e | 115 | |
365d6070 | 116 | u = readl(&bank->gpio_out[GPIO_PORT(gpio)]); |
4e5ae09e | 117 | if (high) |
365d6070 | 118 | u |= 1 << GPIO_BIT(gpio); |
4e5ae09e | 119 | else |
365d6070 JH |
120 | u &= ~(1 << GPIO_BIT(gpio)); |
121 | writel(u, &bank->gpio_out[GPIO_PORT(gpio)]); | |
4e5ae09e TW |
122 | } |
123 | ||
124 | /* | |
125 | * Generic_GPIO primitives. | |
126 | */ | |
127 | ||
365d6070 | 128 | int gpio_request(unsigned gpio, const char *label) |
4e5ae09e | 129 | { |
365d6070 | 130 | if (gpio >= MAX_NUM_GPIOS) |
4e5ae09e TW |
131 | return -1; |
132 | ||
5fac236a | 133 | if (label != NULL) { |
365d6070 JH |
134 | strncpy(gpio_names[gpio].name, label, GPIO_NAME_SIZE); |
135 | gpio_names[gpio].name[GPIO_NAME_SIZE - 1] = '\0'; | |
5fac236a | 136 | } |
4e5ae09e TW |
137 | |
138 | /* Configure as a GPIO */ | |
365d6070 | 139 | set_config(gpio, 1); |
4e5ae09e TW |
140 | |
141 | return 0; | |
142 | } | |
143 | ||
365d6070 | 144 | int gpio_free(unsigned gpio) |
4e5ae09e | 145 | { |
365d6070 JH |
146 | 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; | |
4e5ae09e TW |
152 | } |
153 | ||
365d6070 JH |
154 | /* read GPIO OUT value of pin 'gpio' */ |
155 | static int gpio_get_output_value(unsigned gpio) | |
4e5ae09e | 156 | { |
365d6070 JH |
157 | struct gpio_ctlr *ctlr = (struct gpio_ctlr *)NV_PA_GPIO_BASE; |
158 | struct gpio_ctlr_bank *bank = &ctlr->gpio_bank[GPIO_BANK(gpio)]; | |
4e5ae09e TW |
159 | int val; |
160 | ||
161 | debug("gpio_get_output_value: pin = %d (port %d:bit %d)\n", | |
365d6070 | 162 | gpio, GPIO_FULLPORT(gpio), GPIO_BIT(gpio)); |
4e5ae09e | 163 | |
365d6070 | 164 | val = readl(&bank->gpio_out[GPIO_PORT(gpio)]); |
4e5ae09e | 165 | |
365d6070 | 166 | return (val >> GPIO_BIT(gpio)) & 1; |
4e5ae09e TW |
167 | } |
168 | ||
365d6070 JH |
169 | /* set GPIO pin 'gpio' as an input */ |
170 | int gpio_direction_input(unsigned gpio) | |
4e5ae09e TW |
171 | { |
172 | debug("gpio_direction_input: pin = %d (port %d:bit %d)\n", | |
365d6070 | 173 | gpio, GPIO_FULLPORT(gpio), GPIO_BIT(gpio)); |
4e5ae09e TW |
174 | |
175 | /* Configure GPIO direction as input. */ | |
365d6070 | 176 | set_direction(gpio, 0); |
4e5ae09e TW |
177 | |
178 | return 0; | |
179 | } | |
180 | ||
365d6070 JH |
181 | /* set GPIO pin 'gpio' as an output, with polarity 'value' */ |
182 | int gpio_direction_output(unsigned gpio, int value) | |
4e5ae09e TW |
183 | { |
184 | debug("gpio_direction_output: pin = %d (port %d:bit %d) = %s\n", | |
365d6070 JH |
185 | gpio, GPIO_FULLPORT(gpio), GPIO_BIT(gpio), |
186 | value ? "HIGH" : "LOW"); | |
4e5ae09e TW |
187 | |
188 | /* Configure GPIO output value. */ | |
365d6070 | 189 | set_level(gpio, value); |
4e5ae09e TW |
190 | |
191 | /* Configure GPIO direction as output. */ | |
365d6070 | 192 | set_direction(gpio, 1); |
4e5ae09e TW |
193 | |
194 | return 0; | |
195 | } | |
196 | ||
365d6070 JH |
197 | /* read GPIO IN value of pin 'gpio' */ |
198 | int gpio_get_value(unsigned gpio) | |
4e5ae09e | 199 | { |
365d6070 JH |
200 | struct gpio_ctlr *ctlr = (struct gpio_ctlr *)NV_PA_GPIO_BASE; |
201 | struct gpio_ctlr_bank *bank = &ctlr->gpio_bank[GPIO_BANK(gpio)]; | |
4e5ae09e TW |
202 | int val; |
203 | ||
204 | debug("gpio_get_value: pin = %d (port %d:bit %d)\n", | |
365d6070 | 205 | gpio, GPIO_FULLPORT(gpio), GPIO_BIT(gpio)); |
4e5ae09e | 206 | |
365d6070 | 207 | val = readl(&bank->gpio_in[GPIO_PORT(gpio)]); |
4e5ae09e | 208 | |
365d6070 | 209 | return (val >> GPIO_BIT(gpio)) & 1; |
4e5ae09e TW |
210 | } |
211 | ||
365d6070 JH |
212 | /* write GPIO OUT value to pin 'gpio' */ |
213 | int gpio_set_value(unsigned gpio, int value) | |
4e5ae09e TW |
214 | { |
215 | debug("gpio_set_value: pin = %d (port %d:bit %d), value = %d\n", | |
365d6070 | 216 | gpio, GPIO_FULLPORT(gpio), GPIO_BIT(gpio), value); |
4e5ae09e TW |
217 | |
218 | /* Configure GPIO output value. */ | |
365d6070 JH |
219 | set_level(gpio, value); |
220 | ||
221 | return 0; | |
4e5ae09e TW |
222 | } |
223 | ||
224 | /* | |
225 | * Display Tegra GPIO information | |
226 | */ | |
227 | void gpio_info(void) | |
228 | { | |
365d6070 JH |
229 | unsigned c; |
230 | int type; | |
4e5ae09e TW |
231 | |
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 | } |