]>
Commit | Line | Data |
---|---|---|
0c872ecd TR |
1 | /* |
2 | * Copyright (c) 2009 Wind River Systems, Inc. | |
3 | * Tom Rix <Tom.Rix@windriver.com> | |
4 | * | |
bcd4d4eb | 5 | * SPDX-License-Identifier: GPL-2.0 |
0c872ecd TR |
6 | * |
7 | * This work is derived from the linux 2.6.27 kernel source | |
8 | * To fetch, use the kernel repository | |
9 | * git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git | |
10 | * Use the v2.6.27 tag. | |
11 | * | |
12 | * Below is the original's header including its copyright | |
13 | * | |
14 | * linux/arch/arm/plat-omap/gpio.c | |
15 | * | |
16 | * Support functions for OMAP GPIO | |
17 | * | |
18 | * Copyright (C) 2003-2005 Nokia Corporation | |
19 | * Written by Juha Yrjölä <juha.yrjola@nokia.com> | |
0c872ecd TR |
20 | */ |
21 | #include <common.h> | |
5915a2ad | 22 | #include <dm.h> |
365d6070 | 23 | #include <asm/gpio.h> |
0c872ecd TR |
24 | #include <asm/io.h> |
25 | #include <asm/errno.h> | |
26 | ||
81bdc155 SP |
27 | #define OMAP_GPIO_DIR_OUT 0 |
28 | #define OMAP_GPIO_DIR_IN 1 | |
29 | ||
5915a2ad SG |
30 | #ifdef CONFIG_DM_GPIO |
31 | ||
5915a2ad SG |
32 | #define GPIO_PER_BANK 32 |
33 | ||
34 | struct gpio_bank { | |
5915a2ad SG |
35 | /* TODO(sjg@chromium.org): Can we use a struct here? */ |
36 | void *base; /* address of registers in physical memory */ | |
37 | enum gpio_method method; | |
38 | }; | |
39 | ||
40 | #endif | |
41 | ||
0c872ecd TR |
42 | static inline int get_gpio_index(int gpio) |
43 | { | |
44 | return gpio & 0x1f; | |
45 | } | |
46 | ||
dcee1ab3 | 47 | int gpio_is_valid(int gpio) |
0c872ecd | 48 | { |
87bd05d7 | 49 | return (gpio >= 0) && (gpio < OMAP_MAX_GPIO); |
0c872ecd TR |
50 | } |
51 | ||
25223a68 A |
52 | static void _set_gpio_direction(const struct gpio_bank *bank, int gpio, |
53 | int is_input) | |
0c872ecd TR |
54 | { |
55 | void *reg = bank->base; | |
56 | u32 l; | |
57 | ||
58 | switch (bank->method) { | |
59 | case METHOD_GPIO_24XX: | |
25223a68 | 60 | reg += OMAP_GPIO_OE; |
0c872ecd TR |
61 | break; |
62 | default: | |
63 | return; | |
64 | } | |
65 | l = __raw_readl(reg); | |
66 | if (is_input) | |
67 | l |= 1 << gpio; | |
68 | else | |
69 | l &= ~(1 << gpio); | |
70 | __raw_writel(l, reg); | |
71 | } | |
72 | ||
81bdc155 SP |
73 | /** |
74 | * Get the direction of the GPIO by reading the GPIO_OE register | |
75 | * corresponding to the specified bank. | |
76 | */ | |
77 | static int _get_gpio_direction(const struct gpio_bank *bank, int gpio) | |
0c872ecd | 78 | { |
81bdc155 SP |
79 | void *reg = bank->base; |
80 | u32 v; | |
0c872ecd | 81 | |
81bdc155 SP |
82 | switch (bank->method) { |
83 | case METHOD_GPIO_24XX: | |
84 | reg += OMAP_GPIO_OE; | |
85 | break; | |
86 | default: | |
365d6070 | 87 | return -1; |
81bdc155 SP |
88 | } |
89 | ||
90 | v = __raw_readl(reg); | |
91 | ||
92 | if (v & (1 << gpio)) | |
93 | return OMAP_GPIO_DIR_IN; | |
94 | else | |
95 | return OMAP_GPIO_DIR_OUT; | |
0c872ecd TR |
96 | } |
97 | ||
25223a68 A |
98 | static void _set_gpio_dataout(const struct gpio_bank *bank, int gpio, |
99 | int enable) | |
0c872ecd TR |
100 | { |
101 | void *reg = bank->base; | |
102 | u32 l = 0; | |
103 | ||
104 | switch (bank->method) { | |
105 | case METHOD_GPIO_24XX: | |
106 | if (enable) | |
25223a68 | 107 | reg += OMAP_GPIO_SETDATAOUT; |
0c872ecd | 108 | else |
25223a68 | 109 | reg += OMAP_GPIO_CLEARDATAOUT; |
0c872ecd TR |
110 | l = 1 << gpio; |
111 | break; | |
112 | default: | |
113 | printf("omap3-gpio unknown bank method %s %d\n", | |
114 | __FILE__, __LINE__); | |
115 | return; | |
116 | } | |
117 | __raw_writel(l, reg); | |
118 | } | |
119 | ||
d57b6114 SG |
120 | static int _get_gpio_value(const struct gpio_bank *bank, int gpio) |
121 | { | |
122 | void *reg = bank->base; | |
123 | int input; | |
124 | ||
125 | switch (bank->method) { | |
126 | case METHOD_GPIO_24XX: | |
127 | input = _get_gpio_direction(bank, gpio); | |
128 | switch (input) { | |
129 | case OMAP_GPIO_DIR_IN: | |
130 | reg += OMAP_GPIO_DATAIN; | |
131 | break; | |
132 | case OMAP_GPIO_DIR_OUT: | |
133 | reg += OMAP_GPIO_DATAOUT; | |
134 | break; | |
135 | default: | |
136 | return -1; | |
137 | } | |
138 | break; | |
139 | default: | |
140 | return -1; | |
141 | } | |
142 | ||
143 | return (__raw_readl(reg) & (1 << gpio)) != 0; | |
144 | } | |
145 | ||
5915a2ad SG |
146 | #ifndef CONFIG_DM_GPIO |
147 | ||
d57b6114 SG |
148 | static inline const struct gpio_bank *get_gpio_bank(int gpio) |
149 | { | |
150 | return &omap_gpio_bank[gpio >> 5]; | |
151 | } | |
152 | ||
153 | static int check_gpio(int gpio) | |
154 | { | |
155 | if (!gpio_is_valid(gpio)) { | |
156 | printf("ERROR : check_gpio: invalid GPIO %d\n", gpio); | |
157 | return -1; | |
158 | } | |
159 | return 0; | |
160 | } | |
161 | ||
81bdc155 SP |
162 | /** |
163 | * Set value of the specified gpio | |
164 | */ | |
365d6070 | 165 | int gpio_set_value(unsigned gpio, int value) |
0c872ecd | 166 | { |
25223a68 | 167 | const struct gpio_bank *bank; |
0c872ecd TR |
168 | |
169 | if (check_gpio(gpio) < 0) | |
365d6070 | 170 | return -1; |
0c872ecd | 171 | bank = get_gpio_bank(gpio); |
81bdc155 | 172 | _set_gpio_dataout(bank, get_gpio_index(gpio), value); |
365d6070 JH |
173 | |
174 | return 0; | |
0c872ecd TR |
175 | } |
176 | ||
81bdc155 SP |
177 | /** |
178 | * Get value of the specified gpio | |
179 | */ | |
365d6070 | 180 | int gpio_get_value(unsigned gpio) |
0c872ecd | 181 | { |
25223a68 | 182 | const struct gpio_bank *bank; |
0c872ecd TR |
183 | |
184 | if (check_gpio(gpio) < 0) | |
365d6070 | 185 | return -1; |
0c872ecd | 186 | bank = get_gpio_bank(gpio); |
d57b6114 SG |
187 | |
188 | return _get_gpio_value(bank, get_gpio_index(gpio)); | |
0c872ecd TR |
189 | } |
190 | ||
81bdc155 SP |
191 | /** |
192 | * Set gpio direction as input | |
193 | */ | |
194 | int gpio_direction_input(unsigned gpio) | |
569919d8 | 195 | { |
81bdc155 | 196 | const struct gpio_bank *bank; |
569919d8 JF |
197 | |
198 | if (check_gpio(gpio) < 0) | |
365d6070 | 199 | return -1; |
81bdc155 | 200 | |
569919d8 | 201 | bank = get_gpio_bank(gpio); |
81bdc155 SP |
202 | _set_gpio_direction(bank, get_gpio_index(gpio), 1); |
203 | ||
204 | return 0; | |
569919d8 JF |
205 | } |
206 | ||
81bdc155 SP |
207 | /** |
208 | * Set gpio direction as output | |
209 | */ | |
210 | int gpio_direction_output(unsigned gpio, int value) | |
0c872ecd | 211 | { |
81bdc155 SP |
212 | const struct gpio_bank *bank; |
213 | ||
214 | if (check_gpio(gpio) < 0) | |
365d6070 | 215 | return -1; |
81bdc155 SP |
216 | |
217 | bank = get_gpio_bank(gpio); | |
218 | _set_gpio_dataout(bank, get_gpio_index(gpio), value); | |
219 | _set_gpio_direction(bank, get_gpio_index(gpio), 0); | |
220 | ||
221 | return 0; | |
0c872ecd TR |
222 | } |
223 | ||
81bdc155 SP |
224 | /** |
225 | * Request a gpio before using it. | |
226 | * | |
227 | * NOTE: Argument 'label' is unused. | |
228 | */ | |
365d6070 | 229 | int gpio_request(unsigned gpio, const char *label) |
0c872ecd TR |
230 | { |
231 | if (check_gpio(gpio) < 0) | |
365d6070 | 232 | return -1; |
0c872ecd TR |
233 | |
234 | return 0; | |
235 | } | |
236 | ||
81bdc155 SP |
237 | /** |
238 | * Reset and free the gpio after using it. | |
239 | */ | |
365d6070 | 240 | int gpio_free(unsigned gpio) |
0c872ecd | 241 | { |
365d6070 | 242 | return 0; |
0c872ecd | 243 | } |
5915a2ad SG |
244 | |
245 | #else /* new driver model interface CONFIG_DM_GPIO */ | |
246 | ||
5915a2ad SG |
247 | /* set GPIO pin 'gpio' as an input */ |
248 | static int omap_gpio_direction_input(struct udevice *dev, unsigned offset) | |
249 | { | |
250 | struct gpio_bank *bank = dev_get_priv(dev); | |
5915a2ad SG |
251 | |
252 | /* Configure GPIO direction as input. */ | |
253 | _set_gpio_direction(bank, offset, 1); | |
254 | ||
255 | return 0; | |
256 | } | |
257 | ||
258 | /* set GPIO pin 'gpio' as an output, with polarity 'value' */ | |
259 | static int omap_gpio_direction_output(struct udevice *dev, unsigned offset, | |
260 | int value) | |
261 | { | |
262 | struct gpio_bank *bank = dev_get_priv(dev); | |
5915a2ad SG |
263 | |
264 | _set_gpio_dataout(bank, offset, value); | |
265 | _set_gpio_direction(bank, offset, 0); | |
266 | ||
267 | return 0; | |
268 | } | |
269 | ||
270 | /* read GPIO IN value of pin 'gpio' */ | |
271 | static int omap_gpio_get_value(struct udevice *dev, unsigned offset) | |
272 | { | |
273 | struct gpio_bank *bank = dev_get_priv(dev); | |
5915a2ad SG |
274 | |
275 | return _get_gpio_value(bank, offset); | |
276 | } | |
277 | ||
278 | /* write GPIO OUT value to pin 'gpio' */ | |
279 | static int omap_gpio_set_value(struct udevice *dev, unsigned offset, | |
280 | int value) | |
281 | { | |
282 | struct gpio_bank *bank = dev_get_priv(dev); | |
5915a2ad SG |
283 | |
284 | _set_gpio_dataout(bank, offset, value); | |
285 | ||
286 | return 0; | |
287 | } | |
288 | ||
5915a2ad SG |
289 | static int omap_gpio_get_function(struct udevice *dev, unsigned offset) |
290 | { | |
291 | struct gpio_bank *bank = dev_get_priv(dev); | |
292 | ||
5915a2ad | 293 | /* GPIOF_FUNC is not implemented yet */ |
5aff3acd | 294 | if (_get_gpio_direction(bank->base, offset) == OMAP_GPIO_DIR_OUT) |
5915a2ad SG |
295 | return GPIOF_OUTPUT; |
296 | else | |
297 | return GPIOF_INPUT; | |
298 | } | |
299 | ||
300 | static const struct dm_gpio_ops gpio_omap_ops = { | |
5915a2ad SG |
301 | .direction_input = omap_gpio_direction_input, |
302 | .direction_output = omap_gpio_direction_output, | |
303 | .get_value = omap_gpio_get_value, | |
304 | .set_value = omap_gpio_set_value, | |
305 | .get_function = omap_gpio_get_function, | |
5915a2ad SG |
306 | }; |
307 | ||
308 | static int omap_gpio_probe(struct udevice *dev) | |
309 | { | |
310 | struct gpio_bank *bank = dev_get_priv(dev); | |
311 | struct omap_gpio_platdata *plat = dev_get_platdata(dev); | |
312 | struct gpio_dev_priv *uc_priv = dev->uclass_priv; | |
313 | char name[18], *str; | |
314 | ||
315 | sprintf(name, "GPIO%d_", plat->bank_index); | |
316 | str = strdup(name); | |
317 | if (!str) | |
318 | return -ENOMEM; | |
319 | uc_priv->bank_name = str; | |
320 | uc_priv->gpio_count = GPIO_PER_BANK; | |
321 | bank->base = (void *)plat->base; | |
322 | bank->method = plat->method; | |
323 | ||
324 | return 0; | |
325 | } | |
326 | ||
327 | U_BOOT_DRIVER(gpio_omap) = { | |
328 | .name = "gpio_omap", | |
329 | .id = UCLASS_GPIO, | |
330 | .ops = &gpio_omap_ops, | |
331 | .probe = omap_gpio_probe, | |
332 | .priv_auto_alloc_size = sizeof(struct gpio_bank), | |
333 | }; | |
334 | ||
335 | #endif /* CONFIG_DM_GPIO */ |