xref: /openbmc/u-boot/drivers/gpio/altera_pio.c (revision ee52b188)
1 /*
2  * Driver for Altera's PIO ip core
3  *
4  * Copyright (C) 2011  Missing Link Electronics
5  *                     Joachim Foerster <joachim@missinglinkelectronics.com>
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License as
9  * published by the Free Software Foundation; either version 2 of
10  * the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
20  * MA 02111-1307 USA
21  *
22  * To use this driver, in your board's config. header:
23  * #define CONFIG_ALTERA_PIO
24  * #define CONFIG_SYS_ALTERA_PIO_NUM <number-of-pio-cores>
25  * #define CONFIG_SYS_ALTERA_PIO_GPIO_NUM <total-number-of-gpios>
26  * And in your board's early setup routine:
27  * altera_pio_init(<baseaddr>, <width>, 'i'|'o'|'t',
28  *                 <reset-value>, <neg-mask>, "label");
29  *  - 'i'|'o'|'t': PIO is input-only/output-only/tri-state
30  *  - <reset-value>: for correct initial status display, output-only
31  *  - <neg-mask> is meant to be used to in cases of active-low
32  *    GPIOs, such as LEDs and buttons (on/pressed == 0). Each bit
33  *    which is 1 in <neg-mask> inverts the corresponding GPIO's value
34  *    before set/after get. So: gpio_set_value(gpio, 1) => LED on .
35  *
36  * Do NOT define CONFIG_SYS_GPIO_BASE !
37  *
38  * Optionally, in your board's config. header:
39  * - To force a GPIO numbering scheme like in Linux ...
40  * #define CONFIG_GPIO_DOWNTO_NUMBERING
41  * ... starting with 255 (default)
42  * #define CONFIG_GPIO_DOWNTO_MAX 255
43  */
44 #include <common.h>
45 #include <asm/io.h>
46 #include <asm/gpio.h>
47 
48 #ifdef CONFIG_GPIO_DOWNTO_NUMBERING
49 #ifndef CONFIG_GPIO_DOWNTO_MAX
50 #define CONFIG_GPIO_DOWNTO_MAX 255
51 #endif
52 #endif
53 
54 #define ALTERA_PIO_DATA		0x0
55 #define ALTERA_PIO_DIR		0x4
56 
57 #define GPIO_LABEL_SIZE		9
58 
59 
60 static struct altera_pio {
61 	u32 base;
62 	u8 width;
63 	char iot;
64 	u32 negmask;
65 	u32 sh_data;
66 	u32 sh_dir;
67 	int gidx;
68 	char label[GPIO_LABEL_SIZE];
69 } pios[CONFIG_SYS_ALTERA_PIO_NUM];
70 
71 static int pio_num;
72 
73 static struct altera_pio_gpio {
74 	unsigned num;
75 	struct altera_pio *pio;
76 	char reqlabel[GPIO_LABEL_SIZE];
77 } gpios[CONFIG_SYS_ALTERA_PIO_GPIO_NUM];
78 
79 static int pio_gpio_num;
80 
81 
82 static int altera_pio_gidx(unsigned gpio)
83 {
84 	int i;
85 
86 	for (i = 0; i < pio_gpio_num; ++i) {
87 		if (gpio == gpios[i].num)
88 			break;
89 	}
90 	if (i >= pio_gpio_num)
91 		return -1;
92 	return i;
93 }
94 
95 static struct altera_pio *altera_pio_get_and_mask(unsigned gpio, u32 *mask)
96 {
97 	int gidx = altera_pio_gidx(gpio);
98 	if (gidx < 0)
99 		return NULL;
100 	if (mask)
101 		*mask = 1 << (gidx - gpios[gidx].pio->gidx);
102 	return gpios[gidx].pio;
103 }
104 
105 #define altera_pio_use_gidx(_gidx, _reqlabel) \
106 	{ strncpy(gpios[_gidx].reqlabel, _reqlabel, GPIO_LABEL_SIZE); }
107 #define altera_pio_unuse_gidx(_gidx) { gpios[_gidx].reqlabel[0] = '\0'; }
108 #define altera_pio_is_gidx_used(_gidx) (gpios[_gidx].reqlabel[0] != '\0')
109 
110 static int altera_pio_gpio_init(struct altera_pio *pio, u8 width)
111 {
112 	u8 gidx = pio_gpio_num;
113 	int i;
114 
115 	if (!width)
116 		return -1;
117 	if ((pio_gpio_num + width) > CONFIG_SYS_ALTERA_PIO_GPIO_NUM)
118 		return -1;
119 
120 	for (i = 0; i < width; ++i) {
121 #ifdef CONFIG_GPIO_DOWNTO_NUMBERING
122 		gpios[pio_gpio_num + i].num = \
123 			CONFIG_GPIO_DOWNTO_MAX + 1 - gidx - width + i;
124 #else
125 		gpios[pio_gpio_num + i].num = pio_gpio_num + i;
126 #endif
127 		gpios[pio_gpio_num + i].pio = pio;
128 		altera_pio_unuse_gidx(pio_gpio_num + i);
129 	}
130 	pio_gpio_num += width;
131 	return gidx;
132 }
133 
134 int altera_pio_init(u32 base, u8 width, char iot, u32 rstval, u32 negmask,
135 		 const char *label)
136 {
137 	if (pio_num >= CONFIG_SYS_ALTERA_PIO_NUM)
138 		return -1;
139 
140 	pios[pio_num].base = base;
141 	pios[pio_num].width = width;
142 	pios[pio_num].iot = iot;
143 	switch (iot) {
144 	case 'i':
145 		/* input only */
146 		pios[pio_num].sh_dir = 0;
147 		pios[pio_num].sh_data = readl(base + ALTERA_PIO_DATA);
148 		break;
149 	case 'o':
150 		/* output only */
151 		pios[pio_num].sh_dir = 0xffffffff & ((1 << width) - 1);
152 		pios[pio_num].sh_data = rstval;
153 		break;
154 	case 't':
155 		/* bidir, tri-state */
156 		pios[pio_num].sh_dir = readl(base + ALTERA_PIO_DIR);
157 		pios[pio_num].sh_data = readl(base + ALTERA_PIO_DATA);
158 		break;
159 	default:
160 		return -1;
161 	}
162 	pios[pio_num].negmask = negmask & ((1 << width) - 1);
163 	pios[pio_num].gidx = altera_pio_gpio_init(&pios[pio_num], width);
164 	if (pios[pio_num].gidx < 0)
165 		return -1;
166 	strncpy(pios[pio_num].label, label, GPIO_LABEL_SIZE);
167 	return pio_num++;
168 }
169 
170 void altera_pio_info(void)
171 {
172 	int i;
173 	int j;
174 	int gidx;
175 	u32 mask;
176 
177 	for (i = 0; i < pio_num; ++i) {
178 		printf("Altera PIO % 2d, @0x%08x, "
179 			"width: %u, label: %s\n",
180 		       i, pios[i].base, pios[i].width, pios[i].label);
181 		gidx = pios[i].gidx;
182 		for (j = gidx; j < (gidx + pios[i].width); ++j) {
183 			mask = 1 << (j - gidx);
184 			printf("\tGPIO % 4d: %s %s [%c] %s\n",
185 				gpios[j].num,
186 				gpios[j].pio->sh_dir & mask ? "out" : " in",
187 				gpio_get_value(gpios[j].num) ? "set" : "clr",
188 				altera_pio_is_gidx_used(j) ? 'x' : ' ',
189 				gpios[j].reqlabel);
190 		}
191 	}
192 }
193 
194 
195 int gpio_request(unsigned gpio, const char *label)
196 {
197 	int gidx = altera_pio_gidx(gpio);
198 	if (gidx < 0)
199 		return gidx;
200 	if (altera_pio_is_gidx_used(gidx))
201 		return -1;
202 
203 	altera_pio_use_gidx(gidx, label);
204 	return 0;
205 }
206 
207 int gpio_free(unsigned gpio)
208 {
209 	int gidx = altera_pio_gidx(gpio);
210 	if (gidx < 0)
211 		return gidx;
212 	if (!altera_pio_is_gidx_used(gidx))
213 		return -1;
214 
215 	altera_pio_unuse_gidx(gidx);
216 	return 0;
217 }
218 
219 int gpio_direction_input(unsigned gpio)
220 {
221 	u32 mask;
222 	struct altera_pio *pio;
223 
224 	pio = altera_pio_get_and_mask(gpio, &mask);
225 	if (!pio)
226 		return -1;
227 	if (pio->iot == 'o')
228 		return -1;
229 
230 	writel(pio->sh_dir &= ~mask, pio->base + ALTERA_PIO_DIR);
231 	return 0;
232 }
233 
234 int gpio_direction_output(unsigned gpio, int value)
235 {
236 	u32 mask;
237 	struct altera_pio *pio;
238 
239 	pio = altera_pio_get_and_mask(gpio, &mask);
240 	if (!pio)
241 		return -1;
242 	if (pio->iot == 'i')
243 		return -1;
244 
245 	value = (pio->negmask & mask) ? !value : value;
246 	if (value)
247 		pio->sh_data |= mask;
248 	else
249 		pio->sh_data &= ~mask;
250 	writel(pio->sh_data, pio->base + ALTERA_PIO_DATA);
251 	writel(pio->sh_dir |= mask, pio->base + ALTERA_PIO_DIR);
252 	return 0;
253 }
254 
255 int gpio_get_value(unsigned gpio)
256 {
257 	u32 mask;
258 	struct altera_pio *pio;
259 	u32 val;
260 
261 	pio = altera_pio_get_and_mask(gpio, &mask);
262 	if (!pio)
263 		return -1;
264 
265 	if ((pio->sh_dir & mask) || (pio->iot == 'o'))
266 		val = pio->sh_data & mask;
267 	else
268 		val = readl(pio->base + ALTERA_PIO_DATA) & mask;
269 	return (pio->negmask & mask) ? !val : val;
270 }
271 
272 void gpio_set_value(unsigned gpio, int value)
273 {
274 	u32 mask;
275 	struct altera_pio *pio;
276 
277 	pio = altera_pio_get_and_mask(gpio, &mask);
278 	if (!pio)
279 		return;
280 	if (pio->iot == 'i')
281 		return;
282 
283 	value = (pio->negmask & mask) ? !value : value;
284 	if (value)
285 		pio->sh_data |= mask;
286 	else
287 		pio->sh_data &= ~mask;
288 	writel(pio->sh_data, pio->base + ALTERA_PIO_DATA);
289 	return;
290 }
291 
292 int gpio_is_valid(int number)
293 {
294 	int gidx = altera_pio_gidx(number);
295 
296 	if (gidx < 0)
297 		return 1;
298 	return 0;
299 }
300