blob: 9d293b6994ddbfd0e7d851d7505217e6b0320cd8 [file] [log] [blame]
Sonic Zhangda34aae2013-05-02 13:46:21 +08001/*
2 * ADI GPIO2 Abstraction Layer
3 * Support BF54x, BF60x and future processors.
4 *
5 * Copyright 2008-2013 Analog Devices Inc.
6 *
7 * Licensed under the GPL-2 or later
8 */
9
10#include <common.h>
Simon Glass336d4612020-02-03 07:36:16 -070011#include <malloc.h>
Masahiro Yamada1221ce42016-09-21 11:28:55 +090012#include <linux/errno.h>
Sonic Zhangda34aae2013-05-02 13:46:21 +080013#include <asm/gpio.h>
Sonic Zhangda34aae2013-05-02 13:46:21 +080014
15#define RESOURCE_LABEL_SIZE 16
16
17static struct str_ident {
18 char name[RESOURCE_LABEL_SIZE];
19} str_ident[MAX_RESOURCES];
20
21static void gpio_error(unsigned gpio)
22{
23 printf("adi_gpio2: GPIO %d wasn't requested!\n", gpio);
24}
25
26static void set_label(unsigned short ident, const char *label)
27{
28 if (label) {
29 strncpy(str_ident[ident].name, label,
30 RESOURCE_LABEL_SIZE);
31 str_ident[ident].name[RESOURCE_LABEL_SIZE - 1] = 0;
32 }
33}
34
35static char *get_label(unsigned short ident)
36{
37 return *str_ident[ident].name ? str_ident[ident].name : "UNKNOWN";
38}
39
40static int cmp_label(unsigned short ident, const char *label)
41{
42 if (label == NULL)
43 printf("adi_gpio2: please provide none-null label\n");
44
45 if (label)
46 return strcmp(str_ident[ident].name, label);
47 else
48 return -EINVAL;
49}
50
51#define map_entry(m, i) reserved_##m##_map[gpio_bank(i)]
52#define is_reserved(m, i, e) (map_entry(m, i) & gpio_bit(i))
53#define reserve(m, i) (map_entry(m, i) |= gpio_bit(i))
54#define unreserve(m, i) (map_entry(m, i) &= ~gpio_bit(i))
55#define DECLARE_RESERVED_MAP(m, c) unsigned short reserved_##m##_map[c]
56
57static DECLARE_RESERVED_MAP(gpio, GPIO_BANK_NUM);
58static DECLARE_RESERVED_MAP(peri, gpio_bank(MAX_RESOURCES));
59
60inline int check_gpio(unsigned gpio)
61{
62#if defined(CONFIG_BF54x)
63 if (gpio == GPIO_PB15 || gpio == GPIO_PC14 || gpio == GPIO_PC15 ||
64 gpio == GPIO_PH14 || gpio == GPIO_PH15 ||
65 gpio == GPIO_PJ14 || gpio == GPIO_PJ15)
66 return -EINVAL;
67#endif
68 if (gpio >= MAX_GPIOS)
69 return -EINVAL;
70 return 0;
71}
72
73static void port_setup(unsigned gpio, unsigned short usage)
74{
75#if defined(CONFIG_BF54x)
76 if (usage == GPIO_USAGE)
77 gpio_array[gpio_bank(gpio)]->port_fer &= ~gpio_bit(gpio);
78 else
79 gpio_array[gpio_bank(gpio)]->port_fer |= gpio_bit(gpio);
80#else
81 if (usage == GPIO_USAGE)
82 gpio_array[gpio_bank(gpio)]->port_fer_clear = gpio_bit(gpio);
83 else
84 gpio_array[gpio_bank(gpio)]->port_fer_set = gpio_bit(gpio);
85#endif
Sonic Zhangda34aae2013-05-02 13:46:21 +080086}
87
88inline void portmux_setup(unsigned short per)
89{
90 u32 pmux;
91 u16 ident = P_IDENT(per);
92 u16 function = P_FUNCT2MUX(per);
93
94 pmux = gpio_array[gpio_bank(ident)]->port_mux;
95
96 pmux &= ~(0x3 << (2 * gpio_sub_n(ident)));
97 pmux |= (function & 0x3) << (2 * gpio_sub_n(ident));
98
99 gpio_array[gpio_bank(ident)]->port_mux = pmux;
100}
101
102inline u16 get_portmux(unsigned short per)
103{
104 u32 pmux;
105 u16 ident = P_IDENT(per);
106
107 pmux = gpio_array[gpio_bank(ident)]->port_mux;
108
109 return pmux >> (2 * gpio_sub_n(ident)) & 0x3;
110}
111
112unsigned short get_gpio_dir(unsigned gpio)
113{
114 return 0x01 &
115 (gpio_array[gpio_bank(gpio)]->dir_clear >> gpio_sub_n(gpio));
116}
117
118/***********************************************************
119*
120* FUNCTIONS: Peripheral Resource Allocation
121* and PortMux Setup
122*
123* INPUTS/OUTPUTS:
124* per Peripheral Identifier
125* label String
126*
127* DESCRIPTION: Peripheral Resource Allocation and Setup API
128**************************************************************/
129
130int peripheral_request(unsigned short per, const char *label)
131{
132 unsigned short ident = P_IDENT(per);
133
134 /*
135 * Don't cares are pins with only one dedicated function
136 */
137
138 if (per & P_DONTCARE)
139 return 0;
140
141 if (!(per & P_DEFINED))
Simon Glass7c843192017-09-17 16:54:53 -0600142 return -EINVAL;
Sonic Zhangda34aae2013-05-02 13:46:21 +0800143
144 BUG_ON(ident >= MAX_RESOURCES);
145
146 /* If a pin can be muxed as either GPIO or peripheral, make
147 * sure it is not already a GPIO pin when we request it.
148 */
149 if (unlikely(!check_gpio(ident) && is_reserved(gpio, ident, 1))) {
150 printf("%s: Peripheral %d is already reserved as GPIO by %s!\n",
151 __func__, ident, get_label(ident));
152 return -EBUSY;
153 }
154
155 if (unlikely(is_reserved(peri, ident, 1))) {
156 /*
157 * Pin functions like AMC address strobes my
158 * be requested and used by several drivers
159 */
160
161 if (!((per & P_MAYSHARE) &&
162 get_portmux(per) == P_FUNCT2MUX(per))) {
163 /*
164 * Allow that the identical pin function can
165 * be requested from the same driver twice
166 */
167
168 if (cmp_label(ident, label) == 0)
169 goto anyway;
170
171 printf("%s: Peripheral %d function %d is already "
172 "reserved by %s!\n", __func__, ident,
173 P_FUNCT2MUX(per), get_label(ident));
174 return -EBUSY;
175 }
176 }
177
178 anyway:
179 reserve(peri, ident);
180
181 portmux_setup(per);
182 port_setup(ident, PERIPHERAL_USAGE);
183
184 set_label(ident, label);
185
186 return 0;
187}
188
189int peripheral_request_list(const unsigned short per[], const char *label)
190{
191 u16 cnt;
192 int ret;
193
194 for (cnt = 0; per[cnt] != 0; cnt++) {
195 ret = peripheral_request(per[cnt], label);
196
197 if (ret < 0) {
198 for (; cnt > 0; cnt--)
199 peripheral_free(per[cnt - 1]);
200
201 return ret;
202 }
203 }
204
205 return 0;
206}
207
208void peripheral_free(unsigned short per)
209{
210 unsigned short ident = P_IDENT(per);
211
212 if (per & P_DONTCARE)
213 return;
214
215 if (!(per & P_DEFINED))
216 return;
217
218 if (unlikely(!is_reserved(peri, ident, 0)))
219 return;
220
221 if (!(per & P_MAYSHARE))
222 port_setup(ident, GPIO_USAGE);
223
224 unreserve(peri, ident);
225
226 set_label(ident, "free");
227}
228
229void peripheral_free_list(const unsigned short per[])
230{
231 u16 cnt;
232 for (cnt = 0; per[cnt] != 0; cnt++)
233 peripheral_free(per[cnt]);
234}
235
236/***********************************************************
237*
238* FUNCTIONS: GPIO Driver
239*
240* INPUTS/OUTPUTS:
241* gpio PIO Number between 0 and MAX_GPIOS
242* label String
243*
244* DESCRIPTION: GPIO Driver API
245**************************************************************/
246
247int gpio_request(unsigned gpio, const char *label)
248{
249 if (check_gpio(gpio) < 0)
250 return -EINVAL;
251
252 /*
253 * Allow that the identical GPIO can
254 * be requested from the same driver twice
255 * Do nothing and return -
256 */
257
258 if (cmp_label(gpio, label) == 0)
259 return 0;
260
261 if (unlikely(is_reserved(gpio, gpio, 1))) {
262 printf("adi_gpio2: GPIO %d is already reserved by %s!\n",
263 gpio, get_label(gpio));
264 return -EBUSY;
265 }
266 if (unlikely(is_reserved(peri, gpio, 1))) {
267 printf("adi_gpio2: GPIO %d is already reserved as Peripheral "
268 "by %s!\n", gpio, get_label(gpio));
269 return -EBUSY;
270 }
271
272 reserve(gpio, gpio);
273 set_label(gpio, label);
274
275 port_setup(gpio, GPIO_USAGE);
276
277 return 0;
278}
279
280int gpio_free(unsigned gpio)
281{
282 if (check_gpio(gpio) < 0)
283 return -1;
284
285 if (unlikely(!is_reserved(gpio, gpio, 0))) {
286 gpio_error(gpio);
287 return -1;
288 }
289
290 unreserve(gpio, gpio);
291
292 set_label(gpio, "free");
293
294 return 0;
295}
296
297#ifdef ADI_SPECIAL_GPIO_BANKS
298static DECLARE_RESERVED_MAP(special_gpio, gpio_bank(MAX_RESOURCES));
299
300int special_gpio_request(unsigned gpio, const char *label)
301{
302 /*
303 * Allow that the identical GPIO can
304 * be requested from the same driver twice
305 * Do nothing and return -
306 */
307
308 if (cmp_label(gpio, label) == 0)
309 return 0;
310
311 if (unlikely(is_reserved(special_gpio, gpio, 1))) {
312 printf("adi_gpio2: GPIO %d is already reserved by %s!\n",
313 gpio, get_label(gpio));
314 return -EBUSY;
315 }
316 if (unlikely(is_reserved(peri, gpio, 1))) {
317 printf("adi_gpio2: GPIO %d is already reserved as Peripheral "
318 "by %s!\n", gpio, get_label(gpio));
319
320 return -EBUSY;
321 }
322
323 reserve(special_gpio, gpio);
324 reserve(peri, gpio);
325
326 set_label(gpio, label);
327 port_setup(gpio, GPIO_USAGE);
328
329 return 0;
330}
331
332void special_gpio_free(unsigned gpio)
333{
334 if (unlikely(!is_reserved(special_gpio, gpio, 0))) {
335 gpio_error(gpio);
336 return;
337 }
338
Axel Lin2ced7732013-06-26 10:10:04 +0800339 unreserve(special_gpio, gpio);
340 unreserve(peri, gpio);
Sonic Zhangda34aae2013-05-02 13:46:21 +0800341 set_label(gpio, "free");
342}
343#endif
344
345static inline void __gpio_direction_input(unsigned gpio)
346{
347 gpio_array[gpio_bank(gpio)]->dir_clear = gpio_bit(gpio);
348#if defined(CONFIG_BF54x)
349 gpio_array[gpio_bank(gpio)]->inen |= gpio_bit(gpio);
350#else
351 gpio_array[gpio_bank(gpio)]->inen_set = gpio_bit(gpio);
352#endif
353}
354
355int gpio_direction_input(unsigned gpio)
356{
357 unsigned long flags;
358
359 if (!is_reserved(gpio, gpio, 0)) {
360 gpio_error(gpio);
361 return -EINVAL;
362 }
363
364 local_irq_save(flags);
365 __gpio_direction_input(gpio);
366 local_irq_restore(flags);
367
368 return 0;
369}
370
371int gpio_set_value(unsigned gpio, int arg)
372{
373 if (arg)
374 gpio_array[gpio_bank(gpio)]->data_set = gpio_bit(gpio);
375 else
376 gpio_array[gpio_bank(gpio)]->data_clear = gpio_bit(gpio);
377
378 return 0;
379}
380
381int gpio_direction_output(unsigned gpio, int value)
382{
383 unsigned long flags;
384
385 if (!is_reserved(gpio, gpio, 0)) {
386 gpio_error(gpio);
387 return -EINVAL;
388 }
389
390 local_irq_save(flags);
391
392#if defined(CONFIG_BF54x)
393 gpio_array[gpio_bank(gpio)]->inen &= ~gpio_bit(gpio);
394#else
395 gpio_array[gpio_bank(gpio)]->inen_clear = gpio_bit(gpio);
396#endif
397 gpio_set_value(gpio, value);
398 gpio_array[gpio_bank(gpio)]->dir_set = gpio_bit(gpio);
399
400 local_irq_restore(flags);
401
402 return 0;
403}
404
405int gpio_get_value(unsigned gpio)
406{
407 return 1 & (gpio_array[gpio_bank(gpio)]->data >> gpio_sub_n(gpio));
408}
409
410void gpio_labels(void)
411{
412 int c, gpio;
413
414 for (c = 0; c < MAX_RESOURCES; c++) {
415 gpio = is_reserved(gpio, c, 1);
416 if (!check_gpio(c) && gpio)
417 printf("GPIO_%d:\t%s\tGPIO %s\n", c, get_label(c),
418 get_gpio_dir(c) ? "OUTPUT" : "INPUT");
419 else if (is_reserved(peri, c, 1))
420 printf("GPIO_%d:\t%s\tPeripheral\n", c, get_label(c));
421 else
422 continue;
423 }
424}