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